2010-04-21 18:17:39 +02:00
/******************************************************************************
AudioScience HPI driver
Copyright ( C ) 1997 - 2010 AudioScience Inc . < support @ audioscience . com >
This program is free software ; you can redistribute it and / or modify
it under the terms of version 2 of the GNU General Public License as
published by the Free Software Foundation ;
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
Hardware Programming Interface ( HPI ) for AudioScience ASI6200 series adapters .
These PCI bus adapters are based on the TI C6711 DSP .
Exported functions :
void HPI_6000 ( struct hpi_message * phm , struct hpi_response * phr )
# defines
HIDE_PCI_ASSERTS to show the PCI asserts
PROFILE_DSP2 get profile data from DSP2 if present ( instead of DSP 1 )
( C ) Copyright AudioScience Inc . 1998 - 2003
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# define SOURCEFILE_NAME "hpi6000.c"
# include "hpi_internal.h"
# include "hpimsginit.h"
# include "hpidebug.h"
# include "hpi6000.h"
# include "hpidspcd.h"
# include "hpicmn.h"
# define HPI_HIF_BASE (0x00000200) /* start of C67xx internal RAM */
# define HPI_HIF_ADDR(member) \
( HPI_HIF_BASE + offsetof ( struct hpi_hif_6000 , member ) )
# define HPI_HIF_ERROR_MASK 0x4000
/* HPI6000 specific error codes */
2011-02-10 17:25:58 +13:00
# define HPI6000_ERROR_BASE 900 /* not actually used anywhere */
/* operational/messaging errors */
2010-04-21 18:17:39 +02:00
# define HPI6000_ERROR_MSG_RESP_IDLE_TIMEOUT 901
2011-02-10 17:25:58 +13:00
2010-04-21 18:17:39 +02:00
# define HPI6000_ERROR_MSG_RESP_GET_RESP_ACK 903
# define HPI6000_ERROR_MSG_GET_ADR 904
# define HPI6000_ERROR_RESP_GET_ADR 905
# define HPI6000_ERROR_MSG_RESP_BLOCKWRITE32 906
# define HPI6000_ERROR_MSG_RESP_BLOCKREAD32 907
2011-02-10 17:25:58 +13:00
2010-04-21 18:17:39 +02:00
# define HPI6000_ERROR_CONTROL_CACHE_PARAMS 909
# define HPI6000_ERROR_SEND_DATA_IDLE_TIMEOUT 911
# define HPI6000_ERROR_SEND_DATA_ACK 912
# define HPI6000_ERROR_SEND_DATA_ADR 913
# define HPI6000_ERROR_SEND_DATA_TIMEOUT 914
# define HPI6000_ERROR_SEND_DATA_CMD 915
# define HPI6000_ERROR_SEND_DATA_WRITE 916
# define HPI6000_ERROR_SEND_DATA_IDLECMD 917
# define HPI6000_ERROR_GET_DATA_IDLE_TIMEOUT 921
# define HPI6000_ERROR_GET_DATA_ACK 922
# define HPI6000_ERROR_GET_DATA_CMD 923
# define HPI6000_ERROR_GET_DATA_READ 924
# define HPI6000_ERROR_GET_DATA_IDLECMD 925
# define HPI6000_ERROR_CONTROL_CACHE_ADDRLEN 951
# define HPI6000_ERROR_CONTROL_CACHE_READ 952
# define HPI6000_ERROR_CONTROL_CACHE_FLUSH 953
# define HPI6000_ERROR_MSG_RESP_GETRESPCMD 961
# define HPI6000_ERROR_MSG_RESP_IDLECMD 962
2011-02-10 17:25:58 +13:00
/* Initialisation/bootload errors */
2010-04-21 18:17:39 +02:00
# define HPI6000_ERROR_UNHANDLED_SUBSYS_ID 930
/* can't access PCI2040 */
# define HPI6000_ERROR_INIT_PCI2040 931
/* can't access DSP HPI i/f */
# define HPI6000_ERROR_INIT_DSPHPI 932
/* can't access internal DSP memory */
# define HPI6000_ERROR_INIT_DSPINTMEM 933
/* can't access SDRAM - test#1 */
# define HPI6000_ERROR_INIT_SDRAM1 934
/* can't access SDRAM - test#2 */
# define HPI6000_ERROR_INIT_SDRAM2 935
# define HPI6000_ERROR_INIT_VERIFY 938
# define HPI6000_ERROR_INIT_NOACK 939
# define HPI6000_ERROR_INIT_PLDTEST1 941
# define HPI6000_ERROR_INIT_PLDTEST2 942
/* local defines */
# define HIDE_PCI_ASSERTS
# define PROFILE_DSP2
/* for PCI2040 i/f chip */
/* HPI CSR registers */
/* word offsets from CSR base */
/* use when io addresses defined as u32 * */
# define INTERRUPT_EVENT_SET 0
# define INTERRUPT_EVENT_CLEAR 1
# define INTERRUPT_MASK_SET 2
# define INTERRUPT_MASK_CLEAR 3
# define HPI_ERROR_REPORT 4
# define HPI_RESET 5
# define HPI_DATA_WIDTH 6
# define MAX_DSPS 2
/* HPI registers, spaced 8K bytes = 2K words apart */
# define DSP_SPACING 0x800
# define CONTROL 0x0000
# define ADDRESS 0x0200
# define DATA_AUTOINC 0x0400
# define DATA 0x0600
# define TIMEOUT 500000
struct dsp_obj {
__iomem u32 * prHPI_control ;
__iomem u32 * prHPI_address ;
__iomem u32 * prHPI_data ;
__iomem u32 * prHPI_data_auto_inc ;
char c_dsp_rev ; /*A, B */
u32 control_cache_address_on_dsp ;
u32 control_cache_length_on_dsp ;
struct hpi_adapter_obj * pa_parent_adapter ;
} ;
struct hpi_hw_obj {
__iomem u32 * dw2040_HPICSR ;
__iomem u32 * dw2040_HPIDSP ;
u16 num_dsp ;
struct dsp_obj ado [ MAX_DSPS ] ;
u32 message_buffer_address_on_dsp ;
u32 response_buffer_address_on_dsp ;
u32 pCI2040HPI_error_count ;
struct hpi_control_cache_single control_cache [ HPI_NMIXER_CONTROLS ] ;
struct hpi_control_cache * p_cache ;
} ;
static u16 hpi6000_dsp_block_write32 ( struct hpi_adapter_obj * pao ,
u16 dsp_index , u32 hpi_address , u32 * source , u32 count ) ;
static u16 hpi6000_dsp_block_read32 ( struct hpi_adapter_obj * pao ,
u16 dsp_index , u32 hpi_address , u32 * dest , u32 count ) ;
static short hpi6000_adapter_boot_load_dsp ( struct hpi_adapter_obj * pao ,
u32 * pos_error_code ) ;
static short hpi6000_check_PCI2040_error_flag ( struct hpi_adapter_obj * pao ,
u16 read_or_write ) ;
# define H6READ 1
# define H6WRITE 0
static short hpi6000_update_control_cache ( struct hpi_adapter_obj * pao ,
struct hpi_message * phm ) ;
static short hpi6000_message_response_sequence ( struct hpi_adapter_obj * pao ,
u16 dsp_index , struct hpi_message * phm , struct hpi_response * phr ) ;
static void hw_message ( struct hpi_adapter_obj * pao , struct hpi_message * phm ,
struct hpi_response * phr ) ;
static short hpi6000_wait_dsp_ack ( struct hpi_adapter_obj * pao , u16 dsp_index ,
u32 ack_value ) ;
static short hpi6000_send_host_command ( struct hpi_adapter_obj * pao ,
u16 dsp_index , u32 host_cmd ) ;
static void hpi6000_send_dsp_interrupt ( struct dsp_obj * pdo ) ;
static short hpi6000_send_data ( struct hpi_adapter_obj * pao , u16 dsp_index ,
struct hpi_message * phm , struct hpi_response * phr ) ;
static short hpi6000_get_data ( struct hpi_adapter_obj * pao , u16 dsp_index ,
struct hpi_message * phm , struct hpi_response * phr ) ;
static void hpi_write_word ( struct dsp_obj * pdo , u32 address , u32 data ) ;
static u32 hpi_read_word ( struct dsp_obj * pdo , u32 address ) ;
static void hpi_write_block ( struct dsp_obj * pdo , u32 address , u32 * pdata ,
u32 length ) ;
static void hpi_read_block ( struct dsp_obj * pdo , u32 address , u32 * pdata ,
u32 length ) ;
static void subsys_create_adapter ( struct hpi_message * phm ,
struct hpi_response * phr ) ;
static void subsys_delete_adapter ( struct hpi_message * phm ,
struct hpi_response * phr ) ;
static void adapter_get_asserts ( struct hpi_adapter_obj * pao ,
struct hpi_message * phm , struct hpi_response * phr ) ;
static short create_adapter_obj ( struct hpi_adapter_obj * pao ,
u32 * pos_error_code ) ;
2011-02-10 17:25:58 +13:00
static void delete_adapter_obj ( struct hpi_adapter_obj * pao ) ;
2010-04-21 18:17:39 +02:00
/* local globals */
static u16 gw_pci_read_asserts ; /* used to count PCI2040 errors */
static u16 gw_pci_write_asserts ; /* used to count PCI2040 errors */
static void subsys_message ( struct hpi_message * phm , struct hpi_response * phr )
{
switch ( phm - > function ) {
case HPI_SUBSYS_CREATE_ADAPTER :
subsys_create_adapter ( phm , phr ) ;
break ;
case HPI_SUBSYS_DELETE_ADAPTER :
subsys_delete_adapter ( phm , phr ) ;
break ;
default :
phr - > error = HPI_ERROR_INVALID_FUNC ;
break ;
}
}
static void control_message ( struct hpi_adapter_obj * pao ,
struct hpi_message * phm , struct hpi_response * phr )
{
switch ( phm - > function ) {
case HPI_CONTROL_GET_STATE :
if ( pao - > has_control_cache ) {
2011-02-10 17:25:58 +13:00
phr - > error = hpi6000_update_control_cache ( pao , phm ) ;
2010-04-21 18:17:39 +02:00
2011-02-10 17:25:58 +13:00
if ( phr - > error )
2010-04-21 18:17:39 +02:00
break ;
if ( hpi_check_control_cache ( ( ( struct hpi_hw_obj * )
pao - > priv ) - > p_cache , phm ,
phr ) )
break ;
}
hw_message ( pao , phm , phr ) ;
break ;
case HPI_CONTROL_SET_STATE :
hw_message ( pao , phm , phr ) ;
2011-02-10 17:25:58 +13:00
hpi_cmn_control_cache_sync_to_msg ( ( ( struct hpi_hw_obj * ) pao - >
priv ) - > p_cache , phm , phr ) ;
2010-04-21 18:17:39 +02:00
break ;
2011-02-10 17:25:58 +13:00
case HPI_CONTROL_GET_INFO :
2010-04-21 18:17:39 +02:00
default :
2011-02-10 17:25:58 +13:00
hw_message ( pao , phm , phr ) ;
2010-04-21 18:17:39 +02:00
break ;
}
}
static void adapter_message ( struct hpi_adapter_obj * pao ,
struct hpi_message * phm , struct hpi_response * phr )
{
switch ( phm - > function ) {
case HPI_ADAPTER_GET_ASSERT :
adapter_get_asserts ( pao , phm , phr ) ;
break ;
2011-02-10 17:25:58 +13:00
2010-04-21 18:17:39 +02:00
default :
2011-02-10 17:25:58 +13:00
hw_message ( pao , phm , phr ) ;
2010-04-21 18:17:39 +02:00
break ;
}
}
static void outstream_message ( struct hpi_adapter_obj * pao ,
struct hpi_message * phm , struct hpi_response * phr )
{
switch ( phm - > function ) {
case HPI_OSTREAM_HOSTBUFFER_ALLOC :
case HPI_OSTREAM_HOSTBUFFER_FREE :
/* Don't let these messages go to the HW function because
2011-02-10 17:25:58 +13:00
* they ' re called without locking the spinlock .
2010-04-21 18:17:39 +02:00
* For the HPI6000 adapters the HW would return
* HPI_ERROR_INVALID_FUNC anyway .
*/
phr - > error = HPI_ERROR_INVALID_FUNC ;
break ;
default :
hw_message ( pao , phm , phr ) ;
return ;
}
}
static void instream_message ( struct hpi_adapter_obj * pao ,
struct hpi_message * phm , struct hpi_response * phr )
{
switch ( phm - > function ) {
case HPI_ISTREAM_HOSTBUFFER_ALLOC :
case HPI_ISTREAM_HOSTBUFFER_FREE :
/* Don't let these messages go to the HW function because
2011-02-10 17:25:58 +13:00
* they ' re called without locking the spinlock .
2010-04-21 18:17:39 +02:00
* For the HPI6000 adapters the HW would return
* HPI_ERROR_INVALID_FUNC anyway .
*/
phr - > error = HPI_ERROR_INVALID_FUNC ;
break ;
default :
hw_message ( pao , phm , phr ) ;
return ;
}
}
/************************************************************************/
/** HPI_6000()
* Entry point from HPIMAN
* All calls to the HPI start here
*/
void HPI_6000 ( struct hpi_message * phm , struct hpi_response * phr )
{
struct hpi_adapter_obj * pao = NULL ;
/* subsytem messages get executed by every HPI. */
/* All other messages are ignored unless the adapter index matches */
/* an adapter in the HPI */
2011-02-10 17:25:58 +13:00
/*HPI_DEBUG_LOG(DEBUG, "O %d,F %x\n", phm->wObject, phm->wFunction); */
2010-04-21 18:17:39 +02:00
/* if Dsp has crashed then do not communicate with it any more */
if ( phm - > object ! = HPI_OBJ_SUBSYSTEM ) {
pao = hpi_find_adapter ( phm - > adapter_index ) ;
if ( ! pao ) {
HPI_DEBUG_LOG ( DEBUG ,
" %d,%d refused, for another HPI? \n " ,
phm - > object , phm - > function ) ;
return ;
}
if ( pao - > dsp_crashed > = 10 ) {
hpi_init_response ( phr , phm - > object , phm - > function ,
HPI_ERROR_DSP_HARDWARE ) ;
HPI_DEBUG_LOG ( DEBUG , " %d,%d dsp crashed. \n " ,
phm - > object , phm - > function ) ;
return ;
}
}
/* Init default response including the size field */
if ( phm - > function ! = HPI_SUBSYS_CREATE_ADAPTER )
hpi_init_response ( phr , phm - > object , phm - > function ,
HPI_ERROR_PROCESSING_MESSAGE ) ;
switch ( phm - > type ) {
case HPI_TYPE_MESSAGE :
switch ( phm - > object ) {
case HPI_OBJ_SUBSYSTEM :
subsys_message ( phm , phr ) ;
break ;
case HPI_OBJ_ADAPTER :
phr - > size =
sizeof ( struct hpi_response_header ) +
sizeof ( struct hpi_adapter_res ) ;
adapter_message ( pao , phm , phr ) ;
break ;
case HPI_OBJ_CONTROL :
control_message ( pao , phm , phr ) ;
break ;
case HPI_OBJ_OSTREAM :
outstream_message ( pao , phm , phr ) ;
break ;
case HPI_OBJ_ISTREAM :
instream_message ( pao , phm , phr ) ;
break ;
default :
hw_message ( pao , phm , phr ) ;
break ;
}
break ;
default :
phr - > error = HPI_ERROR_INVALID_TYPE ;
break ;
}
}
/************************************************************************/
/* SUBSYSTEM */
/* create an adapter object and initialise it based on resource information
* passed in in the message
* NOTE - you cannot use this function AND the FindAdapters function at the
* same time , the application must use only one of them to get the adapters
*/
static void subsys_create_adapter ( struct hpi_message * phm ,
struct hpi_response * phr )
{
/* create temp adapter obj, because we don't know what index yet */
struct hpi_adapter_obj ao ;
struct hpi_adapter_obj * pao ;
u32 os_error_code ;
short error = 0 ;
u32 dsp_index = 0 ;
HPI_DEBUG_LOG ( VERBOSE , " subsys_create_adapter \n " ) ;
memset ( & ao , 0 , sizeof ( ao ) ) ;
2010-05-13 21:58:37 +02:00
ao . priv = kzalloc ( sizeof ( struct hpi_hw_obj ) , GFP_KERNEL ) ;
2010-04-21 18:17:39 +02:00
if ( ! ao . priv ) {
HPI_DEBUG_LOG ( ERROR , " cant get mem for adapter object \n " ) ;
phr - > error = HPI_ERROR_MEMORY_ALLOC ;
return ;
}
/* create the adapter object based on the resource information */
ao . pci = * phm - > u . s . resource . r . pci ;
error = create_adapter_obj ( & ao , & os_error_code ) ;
if ( error ) {
2011-02-10 17:25:58 +13:00
delete_adapter_obj ( & ao ) ;
2010-04-21 18:17:39 +02:00
phr - > error = error ;
2011-02-10 17:25:58 +13:00
phr - > u . s . data = os_error_code ;
2010-04-21 18:17:39 +02:00
return ;
}
/* need to update paParentAdapter */
pao = hpi_find_adapter ( ao . index ) ;
if ( ! pao ) {
/* We just added this adapter, why can't we find it!? */
HPI_DEBUG_LOG ( ERROR , " lost adapter after boot \n " ) ;
phr - > error = 950 ;
return ;
}
for ( dsp_index = 0 ; dsp_index < MAX_DSPS ; dsp_index + + ) {
struct hpi_hw_obj * phw = ( struct hpi_hw_obj * ) pao - > priv ;
phw - > ado [ dsp_index ] . pa_parent_adapter = pao ;
}
phr - > u . s . aw_adapter_list [ ao . index ] = ao . adapter_type ;
phr - > u . s . adapter_index = ao . index ;
phr - > u . s . num_adapters + + ;
phr - > error = 0 ;
}
static void subsys_delete_adapter ( struct hpi_message * phm ,
struct hpi_response * phr )
{
struct hpi_adapter_obj * pao = NULL ;
2011-02-10 17:25:58 +13:00
pao = hpi_find_adapter ( phm - > obj_index ) ;
2010-04-21 18:17:39 +02:00
if ( ! pao )
return ;
2011-02-10 17:25:58 +13:00
delete_adapter_obj ( pao ) ;
2010-04-21 18:17:39 +02:00
hpi_delete_adapter ( pao ) ;
phr - > error = 0 ;
}
/* this routine is called from SubSysFindAdapter and SubSysCreateAdapter */
static short create_adapter_obj ( struct hpi_adapter_obj * pao ,
u32 * pos_error_code )
{
short boot_error = 0 ;
u32 dsp_index = 0 ;
u32 control_cache_size = 0 ;
u32 control_cache_count = 0 ;
struct hpi_hw_obj * phw = ( struct hpi_hw_obj * ) pao - > priv ;
/* The PCI2040 has the following address map */
/* BAR0 - 4K = HPI control and status registers on PCI2040 (HPI CSR) */
/* BAR1 - 32K = HPI registers on DSP */
phw - > dw2040_HPICSR = pao - > pci . ap_mem_base [ 0 ] ;
phw - > dw2040_HPIDSP = pao - > pci . ap_mem_base [ 1 ] ;
HPI_DEBUG_LOG ( VERBOSE , " csr %p, dsp %p \n " , phw - > dw2040_HPICSR ,
phw - > dw2040_HPIDSP ) ;
/* set addresses for the possible DSP HPI interfaces */
for ( dsp_index = 0 ; dsp_index < MAX_DSPS ; dsp_index + + ) {
phw - > ado [ dsp_index ] . prHPI_control =
phw - > dw2040_HPIDSP + ( CONTROL +
DSP_SPACING * dsp_index ) ;
phw - > ado [ dsp_index ] . prHPI_address =
phw - > dw2040_HPIDSP + ( ADDRESS +
DSP_SPACING * dsp_index ) ;
phw - > ado [ dsp_index ] . prHPI_data =
phw - > dw2040_HPIDSP + ( DATA + DSP_SPACING * dsp_index ) ;
phw - > ado [ dsp_index ] . prHPI_data_auto_inc =
phw - > dw2040_HPIDSP + ( DATA_AUTOINC +
DSP_SPACING * dsp_index ) ;
HPI_DEBUG_LOG ( VERBOSE , " ctl %p, adr %p, dat %p, dat++ %p \n " ,
phw - > ado [ dsp_index ] . prHPI_control ,
phw - > ado [ dsp_index ] . prHPI_address ,
phw - > ado [ dsp_index ] . prHPI_data ,
phw - > ado [ dsp_index ] . prHPI_data_auto_inc ) ;
phw - > ado [ dsp_index ] . pa_parent_adapter = pao ;
}
phw - > pCI2040HPI_error_count = 0 ;
pao - > has_control_cache = 0 ;
/* Set the default number of DSPs on this card */
/* This is (conditionally) adjusted after bootloading */
/* of the first DSP in the bootload section. */
phw - > num_dsp = 1 ;
boot_error = hpi6000_adapter_boot_load_dsp ( pao , pos_error_code ) ;
if ( boot_error )
return boot_error ;
HPI_DEBUG_LOG ( INFO , " bootload DSP OK \n " ) ;
phw - > message_buffer_address_on_dsp = 0L ;
phw - > response_buffer_address_on_dsp = 0L ;
/* get info about the adapter by asking the adapter */
/* send a HPI_ADAPTER_GET_INFO message */
{
2011-02-10 17:25:58 +13:00
struct hpi_message hm ;
struct hpi_response hr0 ; /* response from DSP 0 */
struct hpi_response hr1 ; /* response from DSP 1 */
2010-04-21 18:17:39 +02:00
u16 error = 0 ;
HPI_DEBUG_LOG ( VERBOSE , " send ADAPTER_GET_INFO \n " ) ;
2011-02-10 17:25:58 +13:00
memset ( & hm , 0 , sizeof ( hm ) ) ;
hm . type = HPI_TYPE_MESSAGE ;
hm . size = sizeof ( struct hpi_message ) ;
hm . object = HPI_OBJ_ADAPTER ;
hm . function = HPI_ADAPTER_GET_INFO ;
hm . adapter_index = 0 ;
memset ( & hr0 , 0 , sizeof ( hr0 ) ) ;
memset ( & hr1 , 0 , sizeof ( hr1 ) ) ;
hr0 . size = sizeof ( hr0 ) ;
hr1 . size = sizeof ( hr1 ) ;
error = hpi6000_message_response_sequence ( pao , 0 , & hm , & hr0 ) ;
if ( hr0 . error ) {
HPI_DEBUG_LOG ( DEBUG , " message error %d \n " , hr0 . error ) ;
return hr0 . error ;
2010-04-21 18:17:39 +02:00
}
if ( phw - > num_dsp = = 2 ) {
2011-02-10 17:25:58 +13:00
error = hpi6000_message_response_sequence ( pao , 1 , & hm ,
& hr1 ) ;
2010-04-21 18:17:39 +02:00
if ( error )
return error ;
}
2011-02-10 17:25:58 +13:00
pao - > adapter_type = hr0 . u . ax . info . adapter_type ;
pao - > index = hr0 . u . ax . info . adapter_index ;
2010-04-21 18:17:39 +02:00
}
memset ( & phw - > control_cache [ 0 ] , 0 ,
sizeof ( struct hpi_control_cache_single ) *
HPI_NMIXER_CONTROLS ) ;
/* Read the control cache length to figure out if it is turned on */
control_cache_size =
hpi_read_word ( & phw - > ado [ 0 ] ,
HPI_HIF_ADDR ( control_cache_size_in_bytes ) ) ;
if ( control_cache_size ) {
control_cache_count =
hpi_read_word ( & phw - > ado [ 0 ] ,
HPI_HIF_ADDR ( control_cache_count ) ) ;
phw - > p_cache =
hpi_alloc_control_cache ( control_cache_count ,
2011-02-10 17:25:58 +13:00
control_cache_size , ( unsigned char * )
2010-04-21 18:17:39 +02:00
& phw - > control_cache [ 0 ]
) ;
2011-02-10 17:25:58 +13:00
if ( phw - > p_cache )
pao - > has_control_cache = 1 ;
}
2010-04-21 18:17:39 +02:00
HPI_DEBUG_LOG ( DEBUG , " get adapter info ASI%04X index %d \n " ,
pao - > adapter_type , pao - > index ) ;
pao - > open = 0 ; /* upon creation the adapter is closed */
2011-02-10 17:25:58 +13:00
2011-02-10 17:26:00 +13:00
if ( phw - > p_cache )
phw - > p_cache - > adap_idx = pao - > index ;
2011-02-10 17:25:58 +13:00
return hpi_add_adapter ( pao ) ;
}
static void delete_adapter_obj ( struct hpi_adapter_obj * pao )
{
struct hpi_hw_obj * phw = ( struct hpi_hw_obj * ) pao - > priv ;
if ( pao - > has_control_cache )
hpi_free_control_cache ( phw - > p_cache ) ;
/* reset DSPs on adapter */
iowrite32 ( 0x0003000F , phw - > dw2040_HPICSR + HPI_RESET ) ;
kfree ( phw ) ;
2010-04-21 18:17:39 +02:00
}
/************************************************************************/
/* ADAPTER */
static void adapter_get_asserts ( struct hpi_adapter_obj * pao ,
struct hpi_message * phm , struct hpi_response * phr )
{
# ifndef HIDE_PCI_ASSERTS
/* if we have PCI2040 asserts then collect them */
if ( ( gw_pci_read_asserts > 0 ) | | ( gw_pci_write_asserts > 0 ) ) {
2011-02-10 17:25:58 +13:00
phr - > u . ax . assert . p1 =
2010-04-21 18:17:39 +02:00
gw_pci_read_asserts * 100 + gw_pci_write_asserts ;
2011-02-10 17:25:58 +13:00
phr - > u . ax . assert . p2 = 0 ;
phr - > u . ax . assert . count = 1 ; /* assert count */
phr - > u . ax . assert . dsp_index = - 1 ; /* "dsp index" */
strcpy ( phr - > u . ax . assert . sz_message , " PCI2040 error " ) ;
phr - > u . ax . assert . dsp_msg_addr = 0 ;
2010-04-21 18:17:39 +02:00
gw_pci_read_asserts = 0 ;
gw_pci_write_asserts = 0 ;
phr - > error = 0 ;
} else
# endif
hw_message ( pao , phm , phr ) ; /*get DSP asserts */
return ;
}
/************************************************************************/
/* LOW-LEVEL */
static short hpi6000_adapter_boot_load_dsp ( struct hpi_adapter_obj * pao ,
u32 * pos_error_code )
{
struct hpi_hw_obj * phw = ( struct hpi_hw_obj * ) pao - > priv ;
short error ;
u32 timeout ;
u32 read = 0 ;
u32 i = 0 ;
u32 data = 0 ;
u32 j = 0 ;
u32 test_addr = 0x80000000 ;
u32 test_data = 0x00000001 ;
u32 dw2040_reset = 0 ;
u32 dsp_index = 0 ;
u32 endian = 0 ;
u32 adapter_info = 0 ;
u32 delay = 0 ;
struct dsp_code dsp_code ;
u16 boot_load_family = 0 ;
/* NOTE don't use wAdapterType in this routine. It is not setup yet */
2011-02-10 17:25:58 +13:00
switch ( pao - > pci . pci_dev - > subsystem_device ) {
2010-04-21 18:17:39 +02:00
case 0x5100 :
case 0x5110 : /* ASI5100 revB or higher with C6711D */
2011-02-10 17:25:58 +13:00
case 0x5200 : /* ASI5200 PCIe version of ASI5100 */
2010-04-21 18:17:39 +02:00
case 0x6100 :
case 0x6200 :
boot_load_family = HPI_ADAPTER_FAMILY_ASI ( 0x6200 ) ;
break ;
default :
return HPI6000_ERROR_UNHANDLED_SUBSYS_ID ;
}
/* reset all DSPs, indicate two DSPs are present
* set RST3 - = 1 to disconnect HAD8 to set DSP in little endian mode
*/
endian = 0 ;
dw2040_reset = 0x0003000F ;
iowrite32 ( dw2040_reset , phw - > dw2040_HPICSR + HPI_RESET ) ;
/* read back register to make sure PCI2040 chip is functioning
* note that bits 4. .15 are read - only and so should always return zero ,
* even though we wrote 1 to them
*/
2011-02-10 17:25:58 +13:00
hpios_delay_micro_seconds ( 1000 ) ;
delay = ioread32 ( phw - > dw2040_HPICSR + HPI_RESET ) ;
2010-04-21 18:17:39 +02:00
if ( delay ! = dw2040_reset ) {
HPI_DEBUG_LOG ( ERROR , " INIT_PCI2040 %x %x \n " , dw2040_reset ,
delay ) ;
return HPI6000_ERROR_INIT_PCI2040 ;
}
/* Indicate that DSP#0,1 is a C6X */
iowrite32 ( 0x00000003 , phw - > dw2040_HPICSR + HPI_DATA_WIDTH ) ;
/* set Bit30 and 29 - which will prevent Target aborts from being
* issued upon HPI or GP error
*/
iowrite32 ( 0x60000000 , phw - > dw2040_HPICSR + INTERRUPT_MASK_SET ) ;
/* isolate DSP HAD8 line from PCI2040 so that
* Little endian can be set by pullup
*/
dw2040_reset = dw2040_reset & ( ~ ( endian < < 3 ) ) ;
iowrite32 ( dw2040_reset , phw - > dw2040_HPICSR + HPI_RESET ) ;
phw - > ado [ 0 ] . c_dsp_rev = ' B ' ; /* revB */
phw - > ado [ 1 ] . c_dsp_rev = ' B ' ; /* revB */
/*Take both DSPs out of reset, setting HAD8 to the correct Endian */
dw2040_reset = dw2040_reset & ( ~ 0x00000001 ) ; /* start DSP 0 */
iowrite32 ( dw2040_reset , phw - > dw2040_HPICSR + HPI_RESET ) ;
dw2040_reset = dw2040_reset & ( ~ 0x00000002 ) ; /* start DSP 1 */
iowrite32 ( dw2040_reset , phw - > dw2040_HPICSR + HPI_RESET ) ;
/* set HAD8 back to PCI2040, now that DSP set to little endian mode */
dw2040_reset = dw2040_reset & ( ~ 0x00000008 ) ;
iowrite32 ( dw2040_reset , phw - > dw2040_HPICSR + HPI_RESET ) ;
/*delay to allow DSP to get going */
2011-02-10 17:25:58 +13:00
hpios_delay_micro_seconds ( 100 ) ;
2010-04-21 18:17:39 +02:00
/* loop through all DSPs, downloading DSP code */
for ( dsp_index = 0 ; dsp_index < phw - > num_dsp ; dsp_index + + ) {
struct dsp_obj * pdo = & phw - > ado [ dsp_index ] ;
/* configure DSP so that we download code into the SRAM */
/* set control reg for little endian, HWOB=1 */
iowrite32 ( 0x00010001 , pdo - > prHPI_control ) ;
/* test access to the HPI address register (HPIA) */
test_data = 0x00000001 ;
for ( j = 0 ; j < 32 ; j + + ) {
iowrite32 ( test_data , pdo - > prHPI_address ) ;
data = ioread32 ( pdo - > prHPI_address ) ;
if ( data ! = test_data ) {
HPI_DEBUG_LOG ( ERROR , " INIT_DSPHPI %x %x %x \n " ,
test_data , data , dsp_index ) ;
return HPI6000_ERROR_INIT_DSPHPI ;
}
test_data = test_data < < 1 ;
}
/* if C6713 the setup PLL to generate 225MHz from 25MHz.
* Since the PLLDIV1 read is sometimes wrong , even on a C6713 ,
* we ' re going to do this unconditionally
*/
/* PLLDIV1 should have a value of 8000 after reset */
/*
if ( HpiReadWord ( pdo , 0x01B7C118 ) = = 0x8000 )
*/
{
/* C6713 datasheet says we cannot program PLL from HPI,
* and indeed if we try to set the PLL multiply from the
* HPI , the PLL does not seem to lock ,
* so we enable the PLL and use the default of x 7
*/
/* bypass PLL */
hpi_write_word ( pdo , 0x01B7C100 , 0x0000 ) ;
2011-02-10 17:25:58 +13:00
hpios_delay_micro_seconds ( 100 ) ;
2010-04-21 18:17:39 +02:00
/* ** use default of PLL x7 ** */
/* EMIF = 225/3=75MHz */
hpi_write_word ( pdo , 0x01B7C120 , 0x8002 ) ;
2011-02-10 17:25:58 +13:00
hpios_delay_micro_seconds ( 100 ) ;
2010-04-21 18:17:39 +02:00
/* peri = 225/2 */
hpi_write_word ( pdo , 0x01B7C11C , 0x8001 ) ;
2011-02-10 17:25:58 +13:00
hpios_delay_micro_seconds ( 100 ) ;
2010-04-21 18:17:39 +02:00
/* cpu = 225/1 */
hpi_write_word ( pdo , 0x01B7C118 , 0x8000 ) ;
2011-02-10 17:25:58 +13:00
/* ~2ms delay */
hpios_delay_micro_seconds ( 2000 ) ;
2010-04-21 18:17:39 +02:00
/* PLL not bypassed */
hpi_write_word ( pdo , 0x01B7C100 , 0x0001 ) ;
2011-02-10 17:25:58 +13:00
/* ~2ms delay */
hpios_delay_micro_seconds ( 2000 ) ;
2010-04-21 18:17:39 +02:00
}
/* test r/w to internal DSP memory
* C6711 has L2 cache mapped to 0x0 when reset
*
* revB - because of bug 3.0 .1 last HPI read
* ( before HPI address issued ) must be non - autoinc
*/
/* test each bit in the 32bit word */
for ( i = 0 ; i < 100 ; i + + ) {
test_addr = 0x00000000 ;
test_data = 0x00000001 ;
for ( j = 0 ; j < 32 ; j + + ) {
hpi_write_word ( pdo , test_addr + i , test_data ) ;
data = hpi_read_word ( pdo , test_addr + i ) ;
if ( data ! = test_data ) {
HPI_DEBUG_LOG ( ERROR ,
" DSP mem %x %x %x %x \n " ,
test_addr + i , test_data ,
data , dsp_index ) ;
return HPI6000_ERROR_INIT_DSPINTMEM ;
}
test_data = test_data < < 1 ;
}
}
/* memory map of ASI6200
00000000 - 0000FF FF 16 Kx32 internal program
01 800000 - 019FF FFF Internal peripheral
80000000 - 807FF FFF CE0 2 Mx32 SDRAM running @ 100 MHz
90000000 - 9000FF FF CE1 Async peripherals :
EMIF config
- - - - - - - - - - - -
Global EMIF control
0 -
1 -
2 -
3 CLK2EN = 1 CLKOUT2 enabled
4 CLK1EN = 0 CLKOUT1 disabled
5 EKEN = 1 < - - ! ! C6713 specific , enables ECLKOUT
6 -
7 NOHOLD = 1 external HOLD disabled
8 HOLDA = 0 HOLDA output is low
9 HOLD = 0 HOLD input is low
10 ARDY = 1 ARDY input is high
11 BUSREQ = 0 BUSREQ output is low
12 , 13 Reserved = 1
*/
hpi_write_word ( pdo , 0x01800000 , 0x34A8 ) ;
/* EMIF CE0 setup - 2Mx32 Sync DRAM
31. .28 Wr setup
27. .22 Wr strobe
21. .20 Wr hold
19. .16 Rd setup
15. .14 -
13. .8 Rd strobe
7. .4 MTYPE 0011 Sync DRAM 32 bits
3 Wr hold MSB
2. .0 Rd hold
*/
hpi_write_word ( pdo , 0x01800008 , 0x00000030 ) ;
/* EMIF SDRAM Extension
31 - 21 0
20 WR2RD = 0
19 - 18 WR2DEAC = 1
17 WR2WR = 0
16 - 15 R2WDQM = 2
14 - 12 RD2WR = 4
11 - 10 RD2DEAC = 1
9 RD2RD = 1
8 - 7 THZP = 10 b
6 - 5 TWR = 2 - 1 = 01 b ( tWR = 10 ns )
4 TRRD = 0 b = 2 ECLK ( tRRD = 14 ns )
3 - 1 TRAS = 5 - 1 = 100 b ( Tras = 42 ns = 5 ECLK )
1 CAS latency = 3 ECLK
( for Micron 2 M32 - 7 operating at 100 Mhz )
*/
/* need to use this else DSP code crashes */
hpi_write_word ( pdo , 0x01800020 , 0x001BDF29 ) ;
/* EMIF SDRAM control - set up for a 2Mx32 SDRAM (512x32x4 bank)
31 - -
30 SDBSZ 1 4 bank
29. .28 SDRSZ 00 11 row address pins
27. .26 SDCSZ 01 8 column address pins
25 RFEN 1 refersh enabled
24 INIT 1 init SDRAM
23. .20 TRCD 0001
19. .16 TRP 0001
15. .12 TRC 0110
11. .0 - -
*/
/* need to use this else DSP code crashes */
hpi_write_word ( pdo , 0x01800018 , 0x47117000 ) ;
/* EMIF SDRAM Refresh Timing */
hpi_write_word ( pdo , 0x0180001C , 0x00000410 ) ;
/*MIF CE1 setup - Async peripherals
@ 100 MHz bus speed , each cycle is 10 ns ,
31. .28 Wr setup = 1
27. .22 Wr strobe = 3 30 ns
21. .20 Wr hold = 1
19. .16 Rd setup = 1
15. .14 Ta = 2
13. .8 Rd strobe = 3 30 ns
7. .4 MTYPE 0010 Async 32 bits
3 Wr hold MSB = 0
2. .0 Rd hold = 1
*/
{
u32 cE1 =
( 1L < < 28 ) | ( 3L < < 22 ) | ( 1L < < 20 ) | ( 1L < <
16 ) | ( 2L < < 14 ) | ( 3L < < 8 ) | ( 2L < < 4 ) | 1L ;
hpi_write_word ( pdo , 0x01800004 , cE1 ) ;
}
/* delay a little to allow SDRAM and DSP to "get going" */
2011-02-10 17:25:58 +13:00
hpios_delay_micro_seconds ( 1000 ) ;
2010-04-21 18:17:39 +02:00
/* test access to SDRAM */
{
test_addr = 0x80000000 ;
test_data = 0x00000001 ;
/* test each bit in the 32bit word */
for ( j = 0 ; j < 32 ; j + + ) {
hpi_write_word ( pdo , test_addr , test_data ) ;
data = hpi_read_word ( pdo , test_addr ) ;
if ( data ! = test_data ) {
HPI_DEBUG_LOG ( ERROR ,
" DSP dram %x %x %x %x \n " ,
test_addr , test_data , data ,
dsp_index ) ;
return HPI6000_ERROR_INIT_SDRAM1 ;
}
test_data = test_data < < 1 ;
}
/* test every Nth address in the DRAM */
# define DRAM_SIZE_WORDS 0x200000 /*2_mx32 */
# define DRAM_INC 1024
test_addr = 0x80000000 ;
test_data = 0x0 ;
for ( i = 0 ; i < DRAM_SIZE_WORDS ; i = i + DRAM_INC ) {
hpi_write_word ( pdo , test_addr + i , test_data ) ;
test_data + + ;
}
test_addr = 0x80000000 ;
test_data = 0x0 ;
for ( i = 0 ; i < DRAM_SIZE_WORDS ; i = i + DRAM_INC ) {
data = hpi_read_word ( pdo , test_addr + i ) ;
if ( data ! = test_data ) {
HPI_DEBUG_LOG ( ERROR ,
" DSP dram %x %x %x %x \n " ,
test_addr + i , test_data ,
data , dsp_index ) ;
return HPI6000_ERROR_INIT_SDRAM2 ;
}
test_data + + ;
}
}
/* write the DSP code down into the DSPs memory */
/*HpiDspCode_Open(nBootLoadFamily,&DspCode,pdwOsErrorCode); */
2011-02-10 17:25:58 +13:00
dsp_code . ps_dev = pao - > pci . pci_dev ;
2010-04-21 18:17:39 +02:00
error = hpi_dsp_code_open ( boot_load_family , & dsp_code ,
pos_error_code ) ;
if ( error )
return error ;
while ( 1 ) {
u32 length ;
u32 address ;
u32 type ;
u32 * pcode ;
error = hpi_dsp_code_read_word ( & dsp_code , & length ) ;
if ( error )
break ;
if ( length = = 0xFFFFFFFF )
break ; /* end of code */
error = hpi_dsp_code_read_word ( & dsp_code , & address ) ;
if ( error )
break ;
error = hpi_dsp_code_read_word ( & dsp_code , & type ) ;
if ( error )
break ;
error = hpi_dsp_code_read_block ( length , & dsp_code ,
& pcode ) ;
if ( error )
break ;
error = hpi6000_dsp_block_write32 ( pao , ( u16 ) dsp_index ,
address , pcode , length ) ;
if ( error )
break ;
}
if ( error ) {
hpi_dsp_code_close ( & dsp_code ) ;
return error ;
}
/* verify that code was written correctly */
/* this time through, assume no errors in DSP code file/array */
hpi_dsp_code_rewind ( & dsp_code ) ;
while ( 1 ) {
u32 length ;
u32 address ;
u32 type ;
u32 * pcode ;
hpi_dsp_code_read_word ( & dsp_code , & length ) ;
if ( length = = 0xFFFFFFFF )
break ; /* end of code */
hpi_dsp_code_read_word ( & dsp_code , & address ) ;
hpi_dsp_code_read_word ( & dsp_code , & type ) ;
hpi_dsp_code_read_block ( length , & dsp_code , & pcode ) ;
for ( i = 0 ; i < length ; i + + ) {
data = hpi_read_word ( pdo , address ) ;
if ( data ! = * pcode ) {
error = HPI6000_ERROR_INIT_VERIFY ;
HPI_DEBUG_LOG ( ERROR ,
" DSP verify %x %x %x %x \n " ,
address , * pcode , data ,
dsp_index ) ;
break ;
}
pcode + + ;
address + = 4 ;
}
if ( error )
break ;
}
hpi_dsp_code_close ( & dsp_code ) ;
if ( error )
return error ;
/* zero out the hostmailbox */
{
u32 address = HPI_HIF_ADDR ( host_cmd ) ;
for ( i = 0 ; i < 4 ; i + + ) {
hpi_write_word ( pdo , address , 0 ) ;
address + = 4 ;
}
}
/* write the DSP number into the hostmailbox */
/* structure before starting the DSP */
hpi_write_word ( pdo , HPI_HIF_ADDR ( dsp_number ) , dsp_index ) ;
/* write the DSP adapter Info into the */
/* hostmailbox before starting the DSP */
if ( dsp_index > 0 )
hpi_write_word ( pdo , HPI_HIF_ADDR ( adapter_info ) ,
adapter_info ) ;
/* step 3. Start code by sending interrupt */
iowrite32 ( 0x00030003 , pdo - > prHPI_control ) ;
2011-02-10 17:25:58 +13:00
hpios_delay_micro_seconds ( 10000 ) ;
2010-04-21 18:17:39 +02:00
/* wait for a non-zero value in hostcmd -
* indicating initialization is complete
*
* Init could take a while if DSP checks SDRAM memory
* Was 200000. Increased to 2000000 for ASI8801 so we
* don ' t get 938 errors .
*/
timeout = 2000000 ;
while ( timeout ) {
do {
read = hpi_read_word ( pdo ,
HPI_HIF_ADDR ( host_cmd ) ) ;
} while ( - - timeout
& & hpi6000_check_PCI2040_error_flag ( pao ,
H6READ ) ) ;
if ( read )
break ;
/* The following is a workaround for bug #94:
* Bluescreen on install and subsequent boots on a
* DELL PowerEdge 600 SC PC with 1.8 GHz P4 and
* ServerWorks chipset . Without this delay the system
* locks up with a bluescreen ( NOT GPF or pagefault ) .
*/
else
2011-02-10 17:25:58 +13:00
hpios_delay_micro_seconds ( 10000 ) ;
2010-04-21 18:17:39 +02:00
}
if ( timeout = = 0 )
return HPI6000_ERROR_INIT_NOACK ;
/* read the DSP adapter Info from the */
/* hostmailbox structure after starting the DSP */
if ( dsp_index = = 0 ) {
/*u32 dwTestData=0; */
u32 mask = 0 ;
adapter_info =
hpi_read_word ( pdo ,
HPI_HIF_ADDR ( adapter_info ) ) ;
if ( HPI_ADAPTER_FAMILY_ASI
( HPI_HIF_ADAPTER_INFO_EXTRACT_ADAPTER
( adapter_info ) ) = =
HPI_ADAPTER_FAMILY_ASI ( 0x6200 ) )
/* all 6200 cards have this many DSPs */
phw - > num_dsp = 2 ;
/* test that the PLD is programmed */
/* and we can read/write 24bits */
# define PLD_BASE_ADDRESS 0x90000000L /*for ASI6100/6200/8800 */
switch ( boot_load_family ) {
case HPI_ADAPTER_FAMILY_ASI ( 0x6200 ) :
/* ASI6100/6200 has 24bit path to FPGA */
mask = 0xFFFFFF00L ;
/* ASI5100 uses AX6 code, */
/* but has no PLD r/w register to test */
2011-02-10 17:25:58 +13:00
if ( HPI_ADAPTER_FAMILY_ASI ( pao - > pci . pci_dev - >
subsystem_device ) = =
2010-04-21 18:17:39 +02:00
HPI_ADAPTER_FAMILY_ASI ( 0x5100 ) )
mask = 0x00000000L ;
2010-07-06 08:37:08 +12:00
/* ASI5200 uses AX6 code, */
/* but has no PLD r/w register to test */
2011-02-10 17:25:58 +13:00
if ( HPI_ADAPTER_FAMILY_ASI ( pao - > pci . pci_dev - >
subsystem_device ) = =
2010-07-06 08:37:08 +12:00
HPI_ADAPTER_FAMILY_ASI ( 0x5200 ) )
mask = 0x00000000L ;
2010-04-21 18:17:39 +02:00
break ;
case HPI_ADAPTER_FAMILY_ASI ( 0x8800 ) :
/* ASI8800 has 16bit path to FPGA */
mask = 0xFFFF0000L ;
break ;
}
test_data = 0xAAAAAA00L & mask ;
/* write to 24 bit Debug register (D31-D8) */
hpi_write_word ( pdo , PLD_BASE_ADDRESS + 4L , test_data ) ;
read = hpi_read_word ( pdo ,
PLD_BASE_ADDRESS + 4L ) & mask ;
if ( read ! = test_data ) {
HPI_DEBUG_LOG ( ERROR , " PLD %x %x \n " , test_data ,
read ) ;
return HPI6000_ERROR_INIT_PLDTEST1 ;
}
test_data = 0x55555500L & mask ;
hpi_write_word ( pdo , PLD_BASE_ADDRESS + 4L , test_data ) ;
read = hpi_read_word ( pdo ,
PLD_BASE_ADDRESS + 4L ) & mask ;
if ( read ! = test_data ) {
HPI_DEBUG_LOG ( ERROR , " PLD %x %x \n " , test_data ,
read ) ;
return HPI6000_ERROR_INIT_PLDTEST2 ;
}
}
} /* for numDSP */
return 0 ;
}
# define PCI_TIMEOUT 100
static int hpi_set_address ( struct dsp_obj * pdo , u32 address )
{
u32 timeout = PCI_TIMEOUT ;
do {
iowrite32 ( address , pdo - > prHPI_address ) ;
} while ( hpi6000_check_PCI2040_error_flag ( pdo - > pa_parent_adapter ,
H6WRITE )
& & - - timeout ) ;
if ( timeout )
return 0 ;
return 1 ;
}
/* write one word to the HPI port */
static void hpi_write_word ( struct dsp_obj * pdo , u32 address , u32 data )
{
if ( hpi_set_address ( pdo , address ) )
return ;
iowrite32 ( data , pdo - > prHPI_data ) ;
}
/* read one word from the HPI port */
static u32 hpi_read_word ( struct dsp_obj * pdo , u32 address )
{
u32 data = 0 ;
if ( hpi_set_address ( pdo , address ) )
2011-02-10 17:25:58 +13:00
return 0 ; /*? No way to return error */
2010-04-21 18:17:39 +02:00
/* take care of errata in revB DSP (2.0.1) */
data = ioread32 ( pdo - > prHPI_data ) ;
return data ;
}
/* write a block of 32bit words to the DSP HPI port using auto-inc mode */
static void hpi_write_block ( struct dsp_obj * pdo , u32 address , u32 * pdata ,
u32 length )
{
u16 length16 = length - 1 ;
if ( length = = 0 )
return ;
if ( hpi_set_address ( pdo , address ) )
return ;
iowrite32_rep ( pdo - > prHPI_data_auto_inc , pdata , length16 ) ;
/* take care of errata in revB DSP (2.0.1) */
/* must end with non auto-inc */
iowrite32 ( * ( pdata + length - 1 ) , pdo - > prHPI_data ) ;
}
/** read a block of 32bit words from the DSP HPI port using auto-inc mode
*/
static void hpi_read_block ( struct dsp_obj * pdo , u32 address , u32 * pdata ,
u32 length )
{
u16 length16 = length - 1 ;
if ( length = = 0 )
return ;
if ( hpi_set_address ( pdo , address ) )
return ;
ioread32_rep ( pdo - > prHPI_data_auto_inc , pdata , length16 ) ;
/* take care of errata in revB DSP (2.0.1) */
/* must end with non auto-inc */
* ( pdata + length - 1 ) = ioread32 ( pdo - > prHPI_data ) ;
}
static u16 hpi6000_dsp_block_write32 ( struct hpi_adapter_obj * pao ,
u16 dsp_index , u32 hpi_address , u32 * source , u32 count )
{
struct dsp_obj * pdo =
& ( * ( struct hpi_hw_obj * ) pao - > priv ) . ado [ dsp_index ] ;
u32 time_out = PCI_TIMEOUT ;
int c6711_burst_size = 128 ;
u32 local_hpi_address = hpi_address ;
int local_count = count ;
int xfer_size ;
u32 * pdata = source ;
while ( local_count ) {
if ( local_count > c6711_burst_size )
xfer_size = c6711_burst_size ;
else
xfer_size = local_count ;
time_out = PCI_TIMEOUT ;
do {
hpi_write_block ( pdo , local_hpi_address , pdata ,
xfer_size ) ;
} while ( hpi6000_check_PCI2040_error_flag ( pao , H6WRITE )
& & - - time_out ) ;
if ( ! time_out )
break ;
pdata + = xfer_size ;
local_hpi_address + = sizeof ( u32 ) * xfer_size ;
local_count - = xfer_size ;
}
if ( time_out )
return 0 ;
else
return 1 ;
}
static u16 hpi6000_dsp_block_read32 ( struct hpi_adapter_obj * pao ,
u16 dsp_index , u32 hpi_address , u32 * dest , u32 count )
{
struct dsp_obj * pdo =
& ( * ( struct hpi_hw_obj * ) pao - > priv ) . ado [ dsp_index ] ;
u32 time_out = PCI_TIMEOUT ;
int c6711_burst_size = 16 ;
u32 local_hpi_address = hpi_address ;
int local_count = count ;
int xfer_size ;
u32 * pdata = dest ;
u32 loop_count = 0 ;
while ( local_count ) {
if ( local_count > c6711_burst_size )
xfer_size = c6711_burst_size ;
else
xfer_size = local_count ;
time_out = PCI_TIMEOUT ;
do {
hpi_read_block ( pdo , local_hpi_address , pdata ,
xfer_size ) ;
} while ( hpi6000_check_PCI2040_error_flag ( pao , H6READ )
& & - - time_out ) ;
if ( ! time_out )
break ;
pdata + = xfer_size ;
local_hpi_address + = sizeof ( u32 ) * xfer_size ;
local_count - = xfer_size ;
loop_count + + ;
}
if ( time_out )
return 0 ;
else
return 1 ;
}
static short hpi6000_message_response_sequence ( struct hpi_adapter_obj * pao ,
u16 dsp_index , struct hpi_message * phm , struct hpi_response * phr )
{
struct hpi_hw_obj * phw = ( struct hpi_hw_obj * ) pao - > priv ;
struct dsp_obj * pdo = & phw - > ado [ dsp_index ] ;
u32 timeout ;
u16 ack ;
u32 address ;
u32 length ;
u32 * p_data ;
u16 error = 0 ;
ack = hpi6000_wait_dsp_ack ( pao , dsp_index , HPI_HIF_IDLE ) ;
if ( ack & HPI_HIF_ERROR_MASK ) {
pao - > dsp_crashed + + ;
return HPI6000_ERROR_MSG_RESP_IDLE_TIMEOUT ;
}
pao - > dsp_crashed = 0 ;
2011-02-10 17:25:58 +13:00
/* get the message address and size */
2010-04-21 18:17:39 +02:00
if ( phw - > message_buffer_address_on_dsp = = 0 ) {
timeout = TIMEOUT ;
do {
address =
hpi_read_word ( pdo ,
HPI_HIF_ADDR ( message_buffer_address ) ) ;
phw - > message_buffer_address_on_dsp = address ;
} while ( hpi6000_check_PCI2040_error_flag ( pao , H6READ )
& & - - timeout ) ;
if ( ! timeout )
return HPI6000_ERROR_MSG_GET_ADR ;
} else
address = phw - > message_buffer_address_on_dsp ;
length = phm - > size ;
2011-02-10 17:25:58 +13:00
/* send the message */
2010-04-21 18:17:39 +02:00
p_data = ( u32 * ) phm ;
if ( hpi6000_dsp_block_write32 ( pao , dsp_index , address , p_data ,
( u16 ) length / 4 ) )
return HPI6000_ERROR_MSG_RESP_BLOCKWRITE32 ;
if ( hpi6000_send_host_command ( pao , dsp_index , HPI_HIF_GET_RESP ) )
return HPI6000_ERROR_MSG_RESP_GETRESPCMD ;
hpi6000_send_dsp_interrupt ( pdo ) ;
ack = hpi6000_wait_dsp_ack ( pao , dsp_index , HPI_HIF_GET_RESP ) ;
if ( ack & HPI_HIF_ERROR_MASK )
return HPI6000_ERROR_MSG_RESP_GET_RESP_ACK ;
2011-02-10 17:25:58 +13:00
/* get the response address */
2010-04-21 18:17:39 +02:00
if ( phw - > response_buffer_address_on_dsp = = 0 ) {
timeout = TIMEOUT ;
do {
address =
hpi_read_word ( pdo ,
HPI_HIF_ADDR ( response_buffer_address ) ) ;
} while ( hpi6000_check_PCI2040_error_flag ( pao , H6READ )
& & - - timeout ) ;
phw - > response_buffer_address_on_dsp = address ;
if ( ! timeout )
return HPI6000_ERROR_RESP_GET_ADR ;
} else
address = phw - > response_buffer_address_on_dsp ;
/* read the length of the response back from the DSP */
timeout = TIMEOUT ;
do {
length = hpi_read_word ( pdo , HPI_HIF_ADDR ( length ) ) ;
} while ( hpi6000_check_PCI2040_error_flag ( pao , H6READ ) & & - - timeout ) ;
if ( ! timeout )
length = sizeof ( struct hpi_response ) ;
2011-02-10 17:25:58 +13:00
/* get the response */
2010-04-21 18:17:39 +02:00
p_data = ( u32 * ) phr ;
if ( hpi6000_dsp_block_read32 ( pao , dsp_index , address , p_data ,
( u16 ) length / 4 ) )
return HPI6000_ERROR_MSG_RESP_BLOCKREAD32 ;
/* set i/f back to idle */
if ( hpi6000_send_host_command ( pao , dsp_index , HPI_HIF_IDLE ) )
return HPI6000_ERROR_MSG_RESP_IDLECMD ;
hpi6000_send_dsp_interrupt ( pdo ) ;
error = hpi_validate_response ( phm , phr ) ;
return error ;
}
/* have to set up the below defines to match stuff in the MAP file */
# define MSG_ADDRESS (HPI_HIF_BASE+0x18)
# define MSG_LENGTH 11
# define RESP_ADDRESS (HPI_HIF_BASE+0x44)
# define RESP_LENGTH 16
# define QUEUE_START (HPI_HIF_BASE+0x88)
# define QUEUE_SIZE 0x8000
static short hpi6000_send_data_check_adr ( u32 address , u32 length_in_dwords )
{
/*#define CHECKING // comment this line in to enable checking */
# ifdef CHECKING
if ( address < ( u32 ) MSG_ADDRESS )
return 0 ;
if ( address > ( u32 ) ( QUEUE_START + QUEUE_SIZE ) )
return 0 ;
if ( ( address + ( length_in_dwords < < 2 ) ) >
( u32 ) ( QUEUE_START + QUEUE_SIZE ) )
return 0 ;
# else
( void ) address ;
( void ) length_in_dwords ;
return 1 ;
# endif
}
static short hpi6000_send_data ( struct hpi_adapter_obj * pao , u16 dsp_index ,
struct hpi_message * phm , struct hpi_response * phr )
{
struct dsp_obj * pdo =
& ( * ( struct hpi_hw_obj * ) pao - > priv ) . ado [ dsp_index ] ;
u32 data_sent = 0 ;
u16 ack ;
u32 length , address ;
u32 * p_data = ( u32 * ) phm - > u . d . u . data . pb_data ;
u16 time_out = 8 ;
( void ) phr ;
/* round dwDataSize down to nearest 4 bytes */
while ( ( data_sent < ( phm - > u . d . u . data . data_size & ~ 3L ) )
& & - - time_out ) {
ack = hpi6000_wait_dsp_ack ( pao , dsp_index , HPI_HIF_IDLE ) ;
if ( ack & HPI_HIF_ERROR_MASK )
return HPI6000_ERROR_SEND_DATA_IDLE_TIMEOUT ;
if ( hpi6000_send_host_command ( pao , dsp_index ,
HPI_HIF_SEND_DATA ) )
return HPI6000_ERROR_SEND_DATA_CMD ;
hpi6000_send_dsp_interrupt ( pdo ) ;
ack = hpi6000_wait_dsp_ack ( pao , dsp_index , HPI_HIF_SEND_DATA ) ;
if ( ack & HPI_HIF_ERROR_MASK )
return HPI6000_ERROR_SEND_DATA_ACK ;
do {
/* get the address and size */
address = hpi_read_word ( pdo , HPI_HIF_ADDR ( address ) ) ;
/* DSP returns number of DWORDS */
length = hpi_read_word ( pdo , HPI_HIF_ADDR ( length ) ) ;
} while ( hpi6000_check_PCI2040_error_flag ( pao , H6READ ) ) ;
if ( ! hpi6000_send_data_check_adr ( address , length ) )
return HPI6000_ERROR_SEND_DATA_ADR ;
/* send the data. break data into 512 DWORD blocks (2K bytes)
* and send using block write . 2 Kbytes is the max as this is the
* memory window given to the HPI data register by the PCI2040
*/
{
u32 len = length ;
u32 blk_len = 512 ;
while ( len ) {
if ( len < blk_len )
blk_len = len ;
if ( hpi6000_dsp_block_write32 ( pao , dsp_index ,
address , p_data , blk_len ) )
return HPI6000_ERROR_SEND_DATA_WRITE ;
address + = blk_len * 4 ;
p_data + = blk_len ;
len - = blk_len ;
}
}
if ( hpi6000_send_host_command ( pao , dsp_index , HPI_HIF_IDLE ) )
return HPI6000_ERROR_SEND_DATA_IDLECMD ;
hpi6000_send_dsp_interrupt ( pdo ) ;
data_sent + = length * 4 ;
}
if ( ! time_out )
return HPI6000_ERROR_SEND_DATA_TIMEOUT ;
return 0 ;
}
static short hpi6000_get_data ( struct hpi_adapter_obj * pao , u16 dsp_index ,
struct hpi_message * phm , struct hpi_response * phr )
{
struct dsp_obj * pdo =
& ( * ( struct hpi_hw_obj * ) pao - > priv ) . ado [ dsp_index ] ;
u32 data_got = 0 ;
u16 ack ;
u32 length , address ;
u32 * p_data = ( u32 * ) phm - > u . d . u . data . pb_data ;
( void ) phr ; /* this parameter not used! */
/* round dwDataSize down to nearest 4 bytes */
while ( data_got < ( phm - > u . d . u . data . data_size & ~ 3L ) ) {
ack = hpi6000_wait_dsp_ack ( pao , dsp_index , HPI_HIF_IDLE ) ;
if ( ack & HPI_HIF_ERROR_MASK )
return HPI6000_ERROR_GET_DATA_IDLE_TIMEOUT ;
if ( hpi6000_send_host_command ( pao , dsp_index ,
HPI_HIF_GET_DATA ) )
return HPI6000_ERROR_GET_DATA_CMD ;
hpi6000_send_dsp_interrupt ( pdo ) ;
ack = hpi6000_wait_dsp_ack ( pao , dsp_index , HPI_HIF_GET_DATA ) ;
if ( ack & HPI_HIF_ERROR_MASK )
return HPI6000_ERROR_GET_DATA_ACK ;
/* get the address and size */
do {
address = hpi_read_word ( pdo , HPI_HIF_ADDR ( address ) ) ;
length = hpi_read_word ( pdo , HPI_HIF_ADDR ( length ) ) ;
} while ( hpi6000_check_PCI2040_error_flag ( pao , H6READ ) ) ;
/* read the data */
{
u32 len = length ;
u32 blk_len = 512 ;
while ( len ) {
if ( len < blk_len )
blk_len = len ;
if ( hpi6000_dsp_block_read32 ( pao , dsp_index ,
address , p_data , blk_len ) )
return HPI6000_ERROR_GET_DATA_READ ;
address + = blk_len * 4 ;
p_data + = blk_len ;
len - = blk_len ;
}
}
if ( hpi6000_send_host_command ( pao , dsp_index , HPI_HIF_IDLE ) )
return HPI6000_ERROR_GET_DATA_IDLECMD ;
hpi6000_send_dsp_interrupt ( pdo ) ;
data_got + = length * 4 ;
}
return 0 ;
}
static void hpi6000_send_dsp_interrupt ( struct dsp_obj * pdo )
{
iowrite32 ( 0x00030003 , pdo - > prHPI_control ) ; /* DSPINT */
}
static short hpi6000_send_host_command ( struct hpi_adapter_obj * pao ,
u16 dsp_index , u32 host_cmd )
{
struct dsp_obj * pdo =
& ( * ( struct hpi_hw_obj * ) pao - > priv ) . ado [ dsp_index ] ;
u32 timeout = TIMEOUT ;
/* set command */
do {
hpi_write_word ( pdo , HPI_HIF_ADDR ( host_cmd ) , host_cmd ) ;
/* flush the FIFO */
hpi_set_address ( pdo , HPI_HIF_ADDR ( host_cmd ) ) ;
} while ( hpi6000_check_PCI2040_error_flag ( pao , H6WRITE ) & & - - timeout ) ;
/* reset the interrupt bit */
iowrite32 ( 0x00040004 , pdo - > prHPI_control ) ;
if ( timeout )
return 0 ;
else
return 1 ;
}
/* if the PCI2040 has recorded an HPI timeout, reset the error and return 1 */
static short hpi6000_check_PCI2040_error_flag ( struct hpi_adapter_obj * pao ,
u16 read_or_write )
{
u32 hPI_error ;
struct hpi_hw_obj * phw = ( struct hpi_hw_obj * ) pao - > priv ;
/* read the error bits from the PCI2040 */
hPI_error = ioread32 ( phw - > dw2040_HPICSR + HPI_ERROR_REPORT ) ;
if ( hPI_error ) {
/* reset the error flag */
iowrite32 ( 0L , phw - > dw2040_HPICSR + HPI_ERROR_REPORT ) ;
phw - > pCI2040HPI_error_count + + ;
if ( read_or_write = = 1 )
gw_pci_read_asserts + + ; /************* inc global */
else
gw_pci_write_asserts + + ;
return 1 ;
} else
return 0 ;
}
static short hpi6000_wait_dsp_ack ( struct hpi_adapter_obj * pao , u16 dsp_index ,
u32 ack_value )
{
struct dsp_obj * pdo =
& ( * ( struct hpi_hw_obj * ) pao - > priv ) . ado [ dsp_index ] ;
u32 ack = 0L ;
u32 timeout ;
u32 hPIC = 0L ;
/* wait for host interrupt to signal ack is ready */
timeout = TIMEOUT ;
while ( - - timeout ) {
hPIC = ioread32 ( pdo - > prHPI_control ) ;
if ( hPIC & 0x04 ) /* 0x04 = HINT from DSP */
break ;
}
if ( timeout = = 0 )
return HPI_HIF_ERROR_MASK ;
/* wait for dwAckValue */
timeout = TIMEOUT ;
while ( - - timeout ) {
/* read the ack mailbox */
ack = hpi_read_word ( pdo , HPI_HIF_ADDR ( dsp_ack ) ) ;
if ( ack = = ack_value )
break ;
if ( ( ack & HPI_HIF_ERROR_MASK )
& & ! hpi6000_check_PCI2040_error_flag ( pao , H6READ ) )
break ;
/*for (i=0;i<1000;i++) */
/* dwPause=i+1; */
}
if ( ack & HPI_HIF_ERROR_MASK )
/* indicates bad read from DSP -
typically 0xffffff is read for some reason */
ack = HPI_HIF_ERROR_MASK ;
if ( timeout = = 0 )
ack = HPI_HIF_ERROR_MASK ;
return ( short ) ack ;
}
static short hpi6000_update_control_cache ( struct hpi_adapter_obj * pao ,
struct hpi_message * phm )
{
const u16 dsp_index = 0 ;
struct hpi_hw_obj * phw = ( struct hpi_hw_obj * ) pao - > priv ;
struct dsp_obj * pdo = & phw - > ado [ dsp_index ] ;
u32 timeout ;
u32 cache_dirty_flag ;
u16 err ;
hpios_dsplock_lock ( pao ) ;
timeout = TIMEOUT ;
do {
cache_dirty_flag =
hpi_read_word ( ( struct dsp_obj * ) pdo ,
HPI_HIF_ADDR ( control_cache_is_dirty ) ) ;
} while ( hpi6000_check_PCI2040_error_flag ( pao , H6READ ) & & - - timeout ) ;
if ( ! timeout ) {
err = HPI6000_ERROR_CONTROL_CACHE_PARAMS ;
goto unlock ;
}
if ( cache_dirty_flag ) {
/* read the cached controls */
u32 address ;
u32 length ;
timeout = TIMEOUT ;
if ( pdo - > control_cache_address_on_dsp = = 0 ) {
do {
address =
hpi_read_word ( ( struct dsp_obj * ) pdo ,
HPI_HIF_ADDR ( control_cache_address ) ) ;
length = hpi_read_word ( ( struct dsp_obj * ) pdo ,
HPI_HIF_ADDR
( control_cache_size_in_bytes ) ) ;
} while ( hpi6000_check_PCI2040_error_flag ( pao , H6READ )
& & - - timeout ) ;
if ( ! timeout ) {
err = HPI6000_ERROR_CONTROL_CACHE_ADDRLEN ;
goto unlock ;
}
pdo - > control_cache_address_on_dsp = address ;
pdo - > control_cache_length_on_dsp = length ;
} else {
address = pdo - > control_cache_address_on_dsp ;
length = pdo - > control_cache_length_on_dsp ;
}
if ( hpi6000_dsp_block_read32 ( pao , dsp_index , address ,
( u32 * ) & phw - > control_cache [ 0 ] ,
length / sizeof ( u32 ) ) ) {
err = HPI6000_ERROR_CONTROL_CACHE_READ ;
goto unlock ;
}
do {
hpi_write_word ( ( struct dsp_obj * ) pdo ,
HPI_HIF_ADDR ( control_cache_is_dirty ) , 0 ) ;
/* flush the FIFO */
hpi_set_address ( pdo , HPI_HIF_ADDR ( host_cmd ) ) ;
} while ( hpi6000_check_PCI2040_error_flag ( pao , H6WRITE )
& & - - timeout ) ;
if ( ! timeout ) {
err = HPI6000_ERROR_CONTROL_CACHE_FLUSH ;
goto unlock ;
}
}
err = 0 ;
unlock :
hpios_dsplock_unlock ( pao ) ;
return err ;
}
/** Get dsp index for multi DSP adapters only */
static u16 get_dsp_index ( struct hpi_adapter_obj * pao , struct hpi_message * phm )
{
u16 ret = 0 ;
switch ( phm - > object ) {
case HPI_OBJ_ISTREAM :
if ( phm - > obj_index < 2 )
ret = 1 ;
break ;
case HPI_OBJ_PROFILE :
ret = phm - > obj_index ;
break ;
default :
break ;
}
return ret ;
}
/** Complete transaction with DSP
Send message , get response , send or get stream data if any .
*/
static void hw_message ( struct hpi_adapter_obj * pao , struct hpi_message * phm ,
struct hpi_response * phr )
{
u16 error = 0 ;
u16 dsp_index = 0 ;
u16 num_dsp = ( ( struct hpi_hw_obj * ) pao - > priv ) - > num_dsp ;
if ( num_dsp < 2 )
dsp_index = 0 ;
else {
dsp_index = get_dsp_index ( pao , phm ) ;
/* is this checked on the DSP anyway? */
if ( ( phm - > function = = HPI_ISTREAM_GROUP_ADD )
| | ( phm - > function = = HPI_OSTREAM_GROUP_ADD ) ) {
struct hpi_message hm ;
u16 add_index ;
hm . obj_index = phm - > u . d . u . stream . stream_index ;
hm . object = phm - > u . d . u . stream . object_type ;
add_index = get_dsp_index ( pao , & hm ) ;
if ( add_index ! = dsp_index ) {
phr - > error = HPI_ERROR_NO_INTERDSP_GROUPS ;
return ;
}
}
}
2010-05-27 17:53:53 +12:00
hpios_dsplock_lock ( pao ) ;
2010-04-21 18:17:39 +02:00
error = hpi6000_message_response_sequence ( pao , dsp_index , phm , phr ) ;
/* maybe an error response */
if ( error ) {
/* something failed in the HPI/DSP interface */
phr - > error = error ;
/* just the header of the response is valid */
phr - > size = sizeof ( struct hpi_response_header ) ;
goto err ;
}
if ( phr - > error ! = 0 ) /* something failed in the DSP */
goto err ;
switch ( phm - > function ) {
case HPI_OSTREAM_WRITE :
case HPI_ISTREAM_ANC_WRITE :
error = hpi6000_send_data ( pao , dsp_index , phm , phr ) ;
break ;
case HPI_ISTREAM_READ :
case HPI_OSTREAM_ANC_READ :
error = hpi6000_get_data ( pao , dsp_index , phm , phr ) ;
break ;
case HPI_ADAPTER_GET_ASSERT :
2011-02-10 17:25:58 +13:00
phr - > u . ax . assert . dsp_index = 0 ; /* dsp 0 default */
2010-04-21 18:17:39 +02:00
if ( num_dsp = = 2 ) {
2011-02-10 17:25:58 +13:00
if ( ! phr - > u . ax . assert . count ) {
2010-04-21 18:17:39 +02:00
/* no assert from dsp 0, check dsp 1 */
error = hpi6000_message_response_sequence ( pao ,
1 , phm , phr ) ;
2011-02-10 17:25:58 +13:00
phr - > u . ax . assert . dsp_index = 1 ;
2010-04-21 18:17:39 +02:00
}
}
}
if ( error )
phr - > error = error ;
err :
hpios_dsplock_unlock ( pao ) ;
return ;
}