18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/****************************************************************************** 38c2ecf20Sopenharmony_ci 48c2ecf20Sopenharmony_ci AudioScience HPI driver 58c2ecf20Sopenharmony_ci Copyright (C) 1997-2014 AudioScience Inc. <support@audioscience.com> 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci Hardware Programming Interface (HPI) for AudioScience 98c2ecf20Sopenharmony_ci ASI50xx, AS51xx, ASI6xxx, ASI87xx ASI89xx series adapters. 108c2ecf20Sopenharmony_ci These PCI and PCIe bus adapters are based on a 118c2ecf20Sopenharmony_ci TMS320C6205 PCI bus mastering DSP, 128c2ecf20Sopenharmony_ci and (except ASI50xx) TI TMS320C6xxx floating point DSP 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci Exported function: 158c2ecf20Sopenharmony_ci void HPI_6205(struct hpi_message *phm, struct hpi_response *phr) 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci(C) Copyright AudioScience Inc. 1998-2010 188c2ecf20Sopenharmony_ci*******************************************************************************/ 198c2ecf20Sopenharmony_ci#define SOURCEFILE_NAME "hpi6205.c" 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include "hpi_internal.h" 228c2ecf20Sopenharmony_ci#include "hpimsginit.h" 238c2ecf20Sopenharmony_ci#include "hpidebug.h" 248c2ecf20Sopenharmony_ci#include "hpi6205.h" 258c2ecf20Sopenharmony_ci#include "hpidspcd.h" 268c2ecf20Sopenharmony_ci#include "hpicmn.h" 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci/*****************************************************************************/ 298c2ecf20Sopenharmony_ci/* HPI6205 specific error codes */ 308c2ecf20Sopenharmony_ci#define HPI6205_ERROR_BASE 1000 /* not actually used anywhere */ 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci/* operational/messaging errors */ 338c2ecf20Sopenharmony_ci#define HPI6205_ERROR_MSG_RESP_IDLE_TIMEOUT 1015 348c2ecf20Sopenharmony_ci#define HPI6205_ERROR_MSG_RESP_TIMEOUT 1016 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci/* initialization/bootload errors */ 378c2ecf20Sopenharmony_ci#define HPI6205_ERROR_6205_NO_IRQ 1002 388c2ecf20Sopenharmony_ci#define HPI6205_ERROR_6205_INIT_FAILED 1003 398c2ecf20Sopenharmony_ci#define HPI6205_ERROR_6205_REG 1006 408c2ecf20Sopenharmony_ci#define HPI6205_ERROR_6205_DSPPAGE 1007 418c2ecf20Sopenharmony_ci#define HPI6205_ERROR_C6713_HPIC 1009 428c2ecf20Sopenharmony_ci#define HPI6205_ERROR_C6713_HPIA 1010 438c2ecf20Sopenharmony_ci#define HPI6205_ERROR_C6713_PLL 1011 448c2ecf20Sopenharmony_ci#define HPI6205_ERROR_DSP_INTMEM 1012 458c2ecf20Sopenharmony_ci#define HPI6205_ERROR_DSP_EXTMEM 1013 468c2ecf20Sopenharmony_ci#define HPI6205_ERROR_DSP_PLD 1014 478c2ecf20Sopenharmony_ci#define HPI6205_ERROR_6205_EEPROM 1017 488c2ecf20Sopenharmony_ci#define HPI6205_ERROR_DSP_EMIF1 1018 498c2ecf20Sopenharmony_ci#define HPI6205_ERROR_DSP_EMIF2 1019 508c2ecf20Sopenharmony_ci#define HPI6205_ERROR_DSP_EMIF3 1020 518c2ecf20Sopenharmony_ci#define HPI6205_ERROR_DSP_EMIF4 1021 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci/*****************************************************************************/ 548c2ecf20Sopenharmony_ci/* for C6205 PCI i/f */ 558c2ecf20Sopenharmony_ci/* Host Status Register (HSR) bitfields */ 568c2ecf20Sopenharmony_ci#define C6205_HSR_INTSRC 0x01 578c2ecf20Sopenharmony_ci#define C6205_HSR_INTAVAL 0x02 588c2ecf20Sopenharmony_ci#define C6205_HSR_INTAM 0x04 598c2ecf20Sopenharmony_ci#define C6205_HSR_CFGERR 0x08 608c2ecf20Sopenharmony_ci#define C6205_HSR_EEREAD 0x10 618c2ecf20Sopenharmony_ci/* Host-to-DSP Control Register (HDCR) bitfields */ 628c2ecf20Sopenharmony_ci#define C6205_HDCR_WARMRESET 0x01 638c2ecf20Sopenharmony_ci#define C6205_HDCR_DSPINT 0x02 648c2ecf20Sopenharmony_ci#define C6205_HDCR_PCIBOOT 0x04 658c2ecf20Sopenharmony_ci/* DSP Page Register (DSPP) bitfields, */ 668c2ecf20Sopenharmony_ci/* defines 4 Mbyte page that BAR0 points to */ 678c2ecf20Sopenharmony_ci#define C6205_DSPP_MAP1 0x400 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci/* BAR0 maps to prefetchable 4 Mbyte memory block set by DSPP. 708c2ecf20Sopenharmony_ci * BAR1 maps to non-prefetchable 8 Mbyte memory block 718c2ecf20Sopenharmony_ci * of DSP memory mapped registers (starting at 0x01800000). 728c2ecf20Sopenharmony_ci * 0x01800000 is hardcoded in the PCI i/f, so that only the offset from this 738c2ecf20Sopenharmony_ci * needs to be added to the BAR1 base address set in the PCI config reg 748c2ecf20Sopenharmony_ci */ 758c2ecf20Sopenharmony_ci#define C6205_BAR1_PCI_IO_OFFSET (0x027FFF0L) 768c2ecf20Sopenharmony_ci#define C6205_BAR1_HSR (C6205_BAR1_PCI_IO_OFFSET) 778c2ecf20Sopenharmony_ci#define C6205_BAR1_HDCR (C6205_BAR1_PCI_IO_OFFSET+4) 788c2ecf20Sopenharmony_ci#define C6205_BAR1_DSPP (C6205_BAR1_PCI_IO_OFFSET+8) 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci/* used to control LED (revA) and reset C6713 (revB) */ 818c2ecf20Sopenharmony_ci#define C6205_BAR0_TIMER1_CTL (0x01980000L) 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci/* For first 6713 in CE1 space, using DA17,16,2 */ 848c2ecf20Sopenharmony_ci#define HPICL_ADDR 0x01400000L 858c2ecf20Sopenharmony_ci#define HPICH_ADDR 0x01400004L 868c2ecf20Sopenharmony_ci#define HPIAL_ADDR 0x01410000L 878c2ecf20Sopenharmony_ci#define HPIAH_ADDR 0x01410004L 888c2ecf20Sopenharmony_ci#define HPIDIL_ADDR 0x01420000L 898c2ecf20Sopenharmony_ci#define HPIDIH_ADDR 0x01420004L 908c2ecf20Sopenharmony_ci#define HPIDL_ADDR 0x01430000L 918c2ecf20Sopenharmony_ci#define HPIDH_ADDR 0x01430004L 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci#define C6713_EMIF_GCTL 0x01800000 948c2ecf20Sopenharmony_ci#define C6713_EMIF_CE1 0x01800004 958c2ecf20Sopenharmony_ci#define C6713_EMIF_CE0 0x01800008 968c2ecf20Sopenharmony_ci#define C6713_EMIF_CE2 0x01800010 978c2ecf20Sopenharmony_ci#define C6713_EMIF_CE3 0x01800014 988c2ecf20Sopenharmony_ci#define C6713_EMIF_SDRAMCTL 0x01800018 998c2ecf20Sopenharmony_ci#define C6713_EMIF_SDRAMTIMING 0x0180001C 1008c2ecf20Sopenharmony_ci#define C6713_EMIF_SDRAMEXT 0x01800020 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_cistruct hpi_hw_obj { 1038c2ecf20Sopenharmony_ci /* PCI registers */ 1048c2ecf20Sopenharmony_ci __iomem u32 *prHSR; 1058c2ecf20Sopenharmony_ci __iomem u32 *prHDCR; 1068c2ecf20Sopenharmony_ci __iomem u32 *prDSPP; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci u32 dsp_page; 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci struct consistent_dma_area h_locked_mem; 1118c2ecf20Sopenharmony_ci struct bus_master_interface *p_interface_buffer; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci u16 flag_outstream_just_reset[HPI_MAX_STREAMS]; 1148c2ecf20Sopenharmony_ci /* a non-NULL handle means there is an HPI allocated buffer */ 1158c2ecf20Sopenharmony_ci struct consistent_dma_area instream_host_buffers[HPI_MAX_STREAMS]; 1168c2ecf20Sopenharmony_ci struct consistent_dma_area outstream_host_buffers[HPI_MAX_STREAMS]; 1178c2ecf20Sopenharmony_ci /* non-zero size means a buffer exists, may be external */ 1188c2ecf20Sopenharmony_ci u32 instream_host_buffer_size[HPI_MAX_STREAMS]; 1198c2ecf20Sopenharmony_ci u32 outstream_host_buffer_size[HPI_MAX_STREAMS]; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci struct consistent_dma_area h_control_cache; 1228c2ecf20Sopenharmony_ci struct hpi_control_cache *p_cache; 1238c2ecf20Sopenharmony_ci}; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci/*****************************************************************************/ 1268c2ecf20Sopenharmony_ci/* local prototypes */ 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci#define check_before_bbm_copy(status, p_bbm_data, l_first_write, l_second_write) 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_cistatic int wait_dsp_ack(struct hpi_hw_obj *phw, int state, int timeout_us); 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_cistatic void send_dsp_command(struct hpi_hw_obj *phw, int cmd); 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_cistatic u16 adapter_boot_load_dsp(struct hpi_adapter_obj *pao, 1358c2ecf20Sopenharmony_ci u32 *pos_error_code); 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_cistatic u16 message_response_sequence(struct hpi_adapter_obj *pao, 1388c2ecf20Sopenharmony_ci struct hpi_message *phm, struct hpi_response *phr); 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_cistatic void hw_message(struct hpi_adapter_obj *pao, struct hpi_message *phm, 1418c2ecf20Sopenharmony_ci struct hpi_response *phr); 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci#define HPI6205_TIMEOUT 1000000 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_cistatic void subsys_create_adapter(struct hpi_message *phm, 1468c2ecf20Sopenharmony_ci struct hpi_response *phr); 1478c2ecf20Sopenharmony_cistatic void adapter_delete(struct hpi_adapter_obj *pao, 1488c2ecf20Sopenharmony_ci struct hpi_message *phm, struct hpi_response *phr); 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_cistatic u16 create_adapter_obj(struct hpi_adapter_obj *pao, 1518c2ecf20Sopenharmony_ci u32 *pos_error_code); 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_cistatic void delete_adapter_obj(struct hpi_adapter_obj *pao); 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_cistatic int adapter_irq_query_and_clear(struct hpi_adapter_obj *pao, 1568c2ecf20Sopenharmony_ci u32 message); 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_cistatic void outstream_host_buffer_allocate(struct hpi_adapter_obj *pao, 1598c2ecf20Sopenharmony_ci struct hpi_message *phm, struct hpi_response *phr); 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_cistatic void outstream_host_buffer_get_info(struct hpi_adapter_obj *pao, 1628c2ecf20Sopenharmony_ci struct hpi_message *phm, struct hpi_response *phr); 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_cistatic void outstream_host_buffer_free(struct hpi_adapter_obj *pao, 1658c2ecf20Sopenharmony_ci struct hpi_message *phm, struct hpi_response *phr); 1668c2ecf20Sopenharmony_cistatic void outstream_write(struct hpi_adapter_obj *pao, 1678c2ecf20Sopenharmony_ci struct hpi_message *phm, struct hpi_response *phr); 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_cistatic void outstream_get_info(struct hpi_adapter_obj *pao, 1708c2ecf20Sopenharmony_ci struct hpi_message *phm, struct hpi_response *phr); 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_cistatic void outstream_start(struct hpi_adapter_obj *pao, 1738c2ecf20Sopenharmony_ci struct hpi_message *phm, struct hpi_response *phr); 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_cistatic void outstream_open(struct hpi_adapter_obj *pao, 1768c2ecf20Sopenharmony_ci struct hpi_message *phm, struct hpi_response *phr); 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_cistatic void outstream_reset(struct hpi_adapter_obj *pao, 1798c2ecf20Sopenharmony_ci struct hpi_message *phm, struct hpi_response *phr); 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_cistatic void instream_host_buffer_allocate(struct hpi_adapter_obj *pao, 1828c2ecf20Sopenharmony_ci struct hpi_message *phm, struct hpi_response *phr); 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_cistatic void instream_host_buffer_get_info(struct hpi_adapter_obj *pao, 1858c2ecf20Sopenharmony_ci struct hpi_message *phm, struct hpi_response *phr); 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_cistatic void instream_host_buffer_free(struct hpi_adapter_obj *pao, 1888c2ecf20Sopenharmony_ci struct hpi_message *phm, struct hpi_response *phr); 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_cistatic void instream_read(struct hpi_adapter_obj *pao, 1918c2ecf20Sopenharmony_ci struct hpi_message *phm, struct hpi_response *phr); 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_cistatic void instream_get_info(struct hpi_adapter_obj *pao, 1948c2ecf20Sopenharmony_ci struct hpi_message *phm, struct hpi_response *phr); 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_cistatic void instream_start(struct hpi_adapter_obj *pao, 1978c2ecf20Sopenharmony_ci struct hpi_message *phm, struct hpi_response *phr); 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_cistatic u32 boot_loader_read_mem32(struct hpi_adapter_obj *pao, int dsp_index, 2008c2ecf20Sopenharmony_ci u32 address); 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_cistatic void boot_loader_write_mem32(struct hpi_adapter_obj *pao, 2038c2ecf20Sopenharmony_ci int dsp_index, u32 address, u32 data); 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_cistatic u16 boot_loader_config_emif(struct hpi_adapter_obj *pao, 2068c2ecf20Sopenharmony_ci int dsp_index); 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_cistatic u16 boot_loader_test_memory(struct hpi_adapter_obj *pao, int dsp_index, 2098c2ecf20Sopenharmony_ci u32 address, u32 length); 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_cistatic u16 boot_loader_test_internal_memory(struct hpi_adapter_obj *pao, 2128c2ecf20Sopenharmony_ci int dsp_index); 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_cistatic u16 boot_loader_test_external_memory(struct hpi_adapter_obj *pao, 2158c2ecf20Sopenharmony_ci int dsp_index); 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_cistatic u16 boot_loader_test_pld(struct hpi_adapter_obj *pao, int dsp_index); 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci/*****************************************************************************/ 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_cistatic void subsys_message(struct hpi_adapter_obj *pao, 2228c2ecf20Sopenharmony_ci struct hpi_message *phm, struct hpi_response *phr) 2238c2ecf20Sopenharmony_ci{ 2248c2ecf20Sopenharmony_ci switch (phm->function) { 2258c2ecf20Sopenharmony_ci case HPI_SUBSYS_CREATE_ADAPTER: 2268c2ecf20Sopenharmony_ci subsys_create_adapter(phm, phr); 2278c2ecf20Sopenharmony_ci break; 2288c2ecf20Sopenharmony_ci default: 2298c2ecf20Sopenharmony_ci phr->error = HPI_ERROR_INVALID_FUNC; 2308c2ecf20Sopenharmony_ci break; 2318c2ecf20Sopenharmony_ci } 2328c2ecf20Sopenharmony_ci} 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_cistatic void control_message(struct hpi_adapter_obj *pao, 2358c2ecf20Sopenharmony_ci struct hpi_message *phm, struct hpi_response *phr) 2368c2ecf20Sopenharmony_ci{ 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci struct hpi_hw_obj *phw = pao->priv; 2398c2ecf20Sopenharmony_ci u16 pending_cache_error = 0; 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci switch (phm->function) { 2428c2ecf20Sopenharmony_ci case HPI_CONTROL_GET_STATE: 2438c2ecf20Sopenharmony_ci if (pao->has_control_cache) { 2448c2ecf20Sopenharmony_ci rmb(); /* make sure we see updates DMAed from DSP */ 2458c2ecf20Sopenharmony_ci if (hpi_check_control_cache(phw->p_cache, phm, phr)) { 2468c2ecf20Sopenharmony_ci break; 2478c2ecf20Sopenharmony_ci } else if (phm->u.c.attribute == HPI_METER_PEAK) { 2488c2ecf20Sopenharmony_ci pending_cache_error = 2498c2ecf20Sopenharmony_ci HPI_ERROR_CONTROL_CACHING; 2508c2ecf20Sopenharmony_ci } 2518c2ecf20Sopenharmony_ci } 2528c2ecf20Sopenharmony_ci hw_message(pao, phm, phr); 2538c2ecf20Sopenharmony_ci if (pending_cache_error && !phr->error) 2548c2ecf20Sopenharmony_ci phr->error = pending_cache_error; 2558c2ecf20Sopenharmony_ci break; 2568c2ecf20Sopenharmony_ci case HPI_CONTROL_GET_INFO: 2578c2ecf20Sopenharmony_ci hw_message(pao, phm, phr); 2588c2ecf20Sopenharmony_ci break; 2598c2ecf20Sopenharmony_ci case HPI_CONTROL_SET_STATE: 2608c2ecf20Sopenharmony_ci hw_message(pao, phm, phr); 2618c2ecf20Sopenharmony_ci if (pao->has_control_cache) 2628c2ecf20Sopenharmony_ci hpi_cmn_control_cache_sync_to_msg(phw->p_cache, phm, 2638c2ecf20Sopenharmony_ci phr); 2648c2ecf20Sopenharmony_ci break; 2658c2ecf20Sopenharmony_ci default: 2668c2ecf20Sopenharmony_ci phr->error = HPI_ERROR_INVALID_FUNC; 2678c2ecf20Sopenharmony_ci break; 2688c2ecf20Sopenharmony_ci } 2698c2ecf20Sopenharmony_ci} 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_cistatic void adapter_message(struct hpi_adapter_obj *pao, 2728c2ecf20Sopenharmony_ci struct hpi_message *phm, struct hpi_response *phr) 2738c2ecf20Sopenharmony_ci{ 2748c2ecf20Sopenharmony_ci switch (phm->function) { 2758c2ecf20Sopenharmony_ci case HPI_ADAPTER_DELETE: 2768c2ecf20Sopenharmony_ci adapter_delete(pao, phm, phr); 2778c2ecf20Sopenharmony_ci break; 2788c2ecf20Sopenharmony_ci default: 2798c2ecf20Sopenharmony_ci hw_message(pao, phm, phr); 2808c2ecf20Sopenharmony_ci break; 2818c2ecf20Sopenharmony_ci } 2828c2ecf20Sopenharmony_ci} 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_cistatic void outstream_message(struct hpi_adapter_obj *pao, 2858c2ecf20Sopenharmony_ci struct hpi_message *phm, struct hpi_response *phr) 2868c2ecf20Sopenharmony_ci{ 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci if (phm->obj_index >= HPI_MAX_STREAMS) { 2898c2ecf20Sopenharmony_ci phr->error = HPI_ERROR_INVALID_OBJ_INDEX; 2908c2ecf20Sopenharmony_ci HPI_DEBUG_LOG(WARNING, 2918c2ecf20Sopenharmony_ci "Message referencing invalid stream %d " 2928c2ecf20Sopenharmony_ci "on adapter index %d\n", phm->obj_index, 2938c2ecf20Sopenharmony_ci phm->adapter_index); 2948c2ecf20Sopenharmony_ci return; 2958c2ecf20Sopenharmony_ci } 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci switch (phm->function) { 2988c2ecf20Sopenharmony_ci case HPI_OSTREAM_WRITE: 2998c2ecf20Sopenharmony_ci outstream_write(pao, phm, phr); 3008c2ecf20Sopenharmony_ci break; 3018c2ecf20Sopenharmony_ci case HPI_OSTREAM_GET_INFO: 3028c2ecf20Sopenharmony_ci outstream_get_info(pao, phm, phr); 3038c2ecf20Sopenharmony_ci break; 3048c2ecf20Sopenharmony_ci case HPI_OSTREAM_HOSTBUFFER_ALLOC: 3058c2ecf20Sopenharmony_ci outstream_host_buffer_allocate(pao, phm, phr); 3068c2ecf20Sopenharmony_ci break; 3078c2ecf20Sopenharmony_ci case HPI_OSTREAM_HOSTBUFFER_GET_INFO: 3088c2ecf20Sopenharmony_ci outstream_host_buffer_get_info(pao, phm, phr); 3098c2ecf20Sopenharmony_ci break; 3108c2ecf20Sopenharmony_ci case HPI_OSTREAM_HOSTBUFFER_FREE: 3118c2ecf20Sopenharmony_ci outstream_host_buffer_free(pao, phm, phr); 3128c2ecf20Sopenharmony_ci break; 3138c2ecf20Sopenharmony_ci case HPI_OSTREAM_START: 3148c2ecf20Sopenharmony_ci outstream_start(pao, phm, phr); 3158c2ecf20Sopenharmony_ci break; 3168c2ecf20Sopenharmony_ci case HPI_OSTREAM_OPEN: 3178c2ecf20Sopenharmony_ci outstream_open(pao, phm, phr); 3188c2ecf20Sopenharmony_ci break; 3198c2ecf20Sopenharmony_ci case HPI_OSTREAM_RESET: 3208c2ecf20Sopenharmony_ci outstream_reset(pao, phm, phr); 3218c2ecf20Sopenharmony_ci break; 3228c2ecf20Sopenharmony_ci default: 3238c2ecf20Sopenharmony_ci hw_message(pao, phm, phr); 3248c2ecf20Sopenharmony_ci break; 3258c2ecf20Sopenharmony_ci } 3268c2ecf20Sopenharmony_ci} 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_cistatic void instream_message(struct hpi_adapter_obj *pao, 3298c2ecf20Sopenharmony_ci struct hpi_message *phm, struct hpi_response *phr) 3308c2ecf20Sopenharmony_ci{ 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci if (phm->obj_index >= HPI_MAX_STREAMS) { 3338c2ecf20Sopenharmony_ci phr->error = HPI_ERROR_INVALID_OBJ_INDEX; 3348c2ecf20Sopenharmony_ci HPI_DEBUG_LOG(WARNING, 3358c2ecf20Sopenharmony_ci "Message referencing invalid stream %d " 3368c2ecf20Sopenharmony_ci "on adapter index %d\n", phm->obj_index, 3378c2ecf20Sopenharmony_ci phm->adapter_index); 3388c2ecf20Sopenharmony_ci return; 3398c2ecf20Sopenharmony_ci } 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci switch (phm->function) { 3428c2ecf20Sopenharmony_ci case HPI_ISTREAM_READ: 3438c2ecf20Sopenharmony_ci instream_read(pao, phm, phr); 3448c2ecf20Sopenharmony_ci break; 3458c2ecf20Sopenharmony_ci case HPI_ISTREAM_GET_INFO: 3468c2ecf20Sopenharmony_ci instream_get_info(pao, phm, phr); 3478c2ecf20Sopenharmony_ci break; 3488c2ecf20Sopenharmony_ci case HPI_ISTREAM_HOSTBUFFER_ALLOC: 3498c2ecf20Sopenharmony_ci instream_host_buffer_allocate(pao, phm, phr); 3508c2ecf20Sopenharmony_ci break; 3518c2ecf20Sopenharmony_ci case HPI_ISTREAM_HOSTBUFFER_GET_INFO: 3528c2ecf20Sopenharmony_ci instream_host_buffer_get_info(pao, phm, phr); 3538c2ecf20Sopenharmony_ci break; 3548c2ecf20Sopenharmony_ci case HPI_ISTREAM_HOSTBUFFER_FREE: 3558c2ecf20Sopenharmony_ci instream_host_buffer_free(pao, phm, phr); 3568c2ecf20Sopenharmony_ci break; 3578c2ecf20Sopenharmony_ci case HPI_ISTREAM_START: 3588c2ecf20Sopenharmony_ci instream_start(pao, phm, phr); 3598c2ecf20Sopenharmony_ci break; 3608c2ecf20Sopenharmony_ci default: 3618c2ecf20Sopenharmony_ci hw_message(pao, phm, phr); 3628c2ecf20Sopenharmony_ci break; 3638c2ecf20Sopenharmony_ci } 3648c2ecf20Sopenharmony_ci} 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci/*****************************************************************************/ 3678c2ecf20Sopenharmony_ci/** Entry point to this HPI backend 3688c2ecf20Sopenharmony_ci * All calls to the HPI start here 3698c2ecf20Sopenharmony_ci */ 3708c2ecf20Sopenharmony_cistatic 3718c2ecf20Sopenharmony_civoid _HPI_6205(struct hpi_adapter_obj *pao, struct hpi_message *phm, 3728c2ecf20Sopenharmony_ci struct hpi_response *phr) 3738c2ecf20Sopenharmony_ci{ 3748c2ecf20Sopenharmony_ci if (pao && (pao->dsp_crashed >= 10) 3758c2ecf20Sopenharmony_ci && (phm->function != HPI_ADAPTER_DEBUG_READ)) { 3768c2ecf20Sopenharmony_ci /* allow last resort debug read even after crash */ 3778c2ecf20Sopenharmony_ci hpi_init_response(phr, phm->object, phm->function, 3788c2ecf20Sopenharmony_ci HPI_ERROR_DSP_HARDWARE); 3798c2ecf20Sopenharmony_ci HPI_DEBUG_LOG(WARNING, " %d,%d dsp crashed.\n", phm->object, 3808c2ecf20Sopenharmony_ci phm->function); 3818c2ecf20Sopenharmony_ci return; 3828c2ecf20Sopenharmony_ci } 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci /* Init default response */ 3858c2ecf20Sopenharmony_ci if (phm->function != HPI_SUBSYS_CREATE_ADAPTER) 3868c2ecf20Sopenharmony_ci phr->error = HPI_ERROR_PROCESSING_MESSAGE; 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci HPI_DEBUG_LOG(VERBOSE, "start of switch\n"); 3898c2ecf20Sopenharmony_ci switch (phm->type) { 3908c2ecf20Sopenharmony_ci case HPI_TYPE_REQUEST: 3918c2ecf20Sopenharmony_ci switch (phm->object) { 3928c2ecf20Sopenharmony_ci case HPI_OBJ_SUBSYSTEM: 3938c2ecf20Sopenharmony_ci subsys_message(pao, phm, phr); 3948c2ecf20Sopenharmony_ci break; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci case HPI_OBJ_ADAPTER: 3978c2ecf20Sopenharmony_ci adapter_message(pao, phm, phr); 3988c2ecf20Sopenharmony_ci break; 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci case HPI_OBJ_CONTROL: 4018c2ecf20Sopenharmony_ci control_message(pao, phm, phr); 4028c2ecf20Sopenharmony_ci break; 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci case HPI_OBJ_OSTREAM: 4058c2ecf20Sopenharmony_ci outstream_message(pao, phm, phr); 4068c2ecf20Sopenharmony_ci break; 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci case HPI_OBJ_ISTREAM: 4098c2ecf20Sopenharmony_ci instream_message(pao, phm, phr); 4108c2ecf20Sopenharmony_ci break; 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci default: 4138c2ecf20Sopenharmony_ci hw_message(pao, phm, phr); 4148c2ecf20Sopenharmony_ci break; 4158c2ecf20Sopenharmony_ci } 4168c2ecf20Sopenharmony_ci break; 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci default: 4198c2ecf20Sopenharmony_ci phr->error = HPI_ERROR_INVALID_TYPE; 4208c2ecf20Sopenharmony_ci break; 4218c2ecf20Sopenharmony_ci } 4228c2ecf20Sopenharmony_ci} 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_civoid HPI_6205(struct hpi_message *phm, struct hpi_response *phr) 4258c2ecf20Sopenharmony_ci{ 4268c2ecf20Sopenharmony_ci struct hpi_adapter_obj *pao = NULL; 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci if (phm->object != HPI_OBJ_SUBSYSTEM) { 4298c2ecf20Sopenharmony_ci /* normal messages must have valid adapter index */ 4308c2ecf20Sopenharmony_ci pao = hpi_find_adapter(phm->adapter_index); 4318c2ecf20Sopenharmony_ci } else { 4328c2ecf20Sopenharmony_ci /* subsys messages don't address an adapter */ 4338c2ecf20Sopenharmony_ci phr->error = HPI_ERROR_INVALID_OBJ_INDEX; 4348c2ecf20Sopenharmony_ci return; 4358c2ecf20Sopenharmony_ci } 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci if (pao) 4388c2ecf20Sopenharmony_ci _HPI_6205(pao, phm, phr); 4398c2ecf20Sopenharmony_ci else 4408c2ecf20Sopenharmony_ci hpi_init_response(phr, phm->object, phm->function, 4418c2ecf20Sopenharmony_ci HPI_ERROR_BAD_ADAPTER_NUMBER); 4428c2ecf20Sopenharmony_ci} 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci/*****************************************************************************/ 4458c2ecf20Sopenharmony_ci/* SUBSYSTEM */ 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci/** Create an adapter object and initialise it based on resource information 4488c2ecf20Sopenharmony_ci * passed in in the message 4498c2ecf20Sopenharmony_ci * *** NOTE - you cannot use this function AND the FindAdapters function at the 4508c2ecf20Sopenharmony_ci * same time, the application must use only one of them to get the adapters *** 4518c2ecf20Sopenharmony_ci */ 4528c2ecf20Sopenharmony_cistatic void subsys_create_adapter(struct hpi_message *phm, 4538c2ecf20Sopenharmony_ci struct hpi_response *phr) 4548c2ecf20Sopenharmony_ci{ 4558c2ecf20Sopenharmony_ci /* create temp adapter obj, because we don't know what index yet */ 4568c2ecf20Sopenharmony_ci struct hpi_adapter_obj ao; 4578c2ecf20Sopenharmony_ci u32 os_error_code; 4588c2ecf20Sopenharmony_ci u16 err; 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci HPI_DEBUG_LOG(DEBUG, " subsys_create_adapter\n"); 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci memset(&ao, 0, sizeof(ao)); 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci ao.priv = kzalloc(sizeof(struct hpi_hw_obj), GFP_KERNEL); 4658c2ecf20Sopenharmony_ci if (!ao.priv) { 4668c2ecf20Sopenharmony_ci HPI_DEBUG_LOG(ERROR, "can't get mem for adapter object\n"); 4678c2ecf20Sopenharmony_ci phr->error = HPI_ERROR_MEMORY_ALLOC; 4688c2ecf20Sopenharmony_ci return; 4698c2ecf20Sopenharmony_ci } 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci ao.pci = *phm->u.s.resource.r.pci; 4728c2ecf20Sopenharmony_ci err = create_adapter_obj(&ao, &os_error_code); 4738c2ecf20Sopenharmony_ci if (err) { 4748c2ecf20Sopenharmony_ci delete_adapter_obj(&ao); 4758c2ecf20Sopenharmony_ci if (err >= HPI_ERROR_BACKEND_BASE) { 4768c2ecf20Sopenharmony_ci phr->error = HPI_ERROR_DSP_BOOTLOAD; 4778c2ecf20Sopenharmony_ci phr->specific_error = err; 4788c2ecf20Sopenharmony_ci } else { 4798c2ecf20Sopenharmony_ci phr->error = err; 4808c2ecf20Sopenharmony_ci } 4818c2ecf20Sopenharmony_ci phr->u.s.data = os_error_code; 4828c2ecf20Sopenharmony_ci return; 4838c2ecf20Sopenharmony_ci } 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci phr->u.s.adapter_type = ao.type; 4868c2ecf20Sopenharmony_ci phr->u.s.adapter_index = ao.index; 4878c2ecf20Sopenharmony_ci phr->error = 0; 4888c2ecf20Sopenharmony_ci} 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci/** delete an adapter - required by WDM driver */ 4918c2ecf20Sopenharmony_cistatic void adapter_delete(struct hpi_adapter_obj *pao, 4928c2ecf20Sopenharmony_ci struct hpi_message *phm, struct hpi_response *phr) 4938c2ecf20Sopenharmony_ci{ 4948c2ecf20Sopenharmony_ci struct hpi_hw_obj *phw; 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci if (!pao) { 4978c2ecf20Sopenharmony_ci phr->error = HPI_ERROR_INVALID_OBJ_INDEX; 4988c2ecf20Sopenharmony_ci return; 4998c2ecf20Sopenharmony_ci } 5008c2ecf20Sopenharmony_ci phw = pao->priv; 5018c2ecf20Sopenharmony_ci /* reset adapter h/w */ 5028c2ecf20Sopenharmony_ci /* Reset C6713 #1 */ 5038c2ecf20Sopenharmony_ci boot_loader_write_mem32(pao, 0, C6205_BAR0_TIMER1_CTL, 0); 5048c2ecf20Sopenharmony_ci /* reset C6205 */ 5058c2ecf20Sopenharmony_ci iowrite32(C6205_HDCR_WARMRESET, phw->prHDCR); 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci delete_adapter_obj(pao); 5088c2ecf20Sopenharmony_ci hpi_delete_adapter(pao); 5098c2ecf20Sopenharmony_ci phr->error = 0; 5108c2ecf20Sopenharmony_ci} 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci/** Create adapter object 5138c2ecf20Sopenharmony_ci allocate buffers, bootload DSPs, initialise control cache 5148c2ecf20Sopenharmony_ci*/ 5158c2ecf20Sopenharmony_cistatic u16 create_adapter_obj(struct hpi_adapter_obj *pao, 5168c2ecf20Sopenharmony_ci u32 *pos_error_code) 5178c2ecf20Sopenharmony_ci{ 5188c2ecf20Sopenharmony_ci struct hpi_hw_obj *phw = pao->priv; 5198c2ecf20Sopenharmony_ci struct bus_master_interface *interface; 5208c2ecf20Sopenharmony_ci u32 phys_addr; 5218c2ecf20Sopenharmony_ci int i; 5228c2ecf20Sopenharmony_ci u16 err; 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci /* init error reporting */ 5258c2ecf20Sopenharmony_ci pao->dsp_crashed = 0; 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci for (i = 0; i < HPI_MAX_STREAMS; i++) 5288c2ecf20Sopenharmony_ci phw->flag_outstream_just_reset[i] = 1; 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci /* The C6205 memory area 1 is 8Mbyte window into DSP registers */ 5318c2ecf20Sopenharmony_ci phw->prHSR = 5328c2ecf20Sopenharmony_ci pao->pci.ap_mem_base[1] + 5338c2ecf20Sopenharmony_ci C6205_BAR1_HSR / sizeof(*pao->pci.ap_mem_base[1]); 5348c2ecf20Sopenharmony_ci phw->prHDCR = 5358c2ecf20Sopenharmony_ci pao->pci.ap_mem_base[1] + 5368c2ecf20Sopenharmony_ci C6205_BAR1_HDCR / sizeof(*pao->pci.ap_mem_base[1]); 5378c2ecf20Sopenharmony_ci phw->prDSPP = 5388c2ecf20Sopenharmony_ci pao->pci.ap_mem_base[1] + 5398c2ecf20Sopenharmony_ci C6205_BAR1_DSPP / sizeof(*pao->pci.ap_mem_base[1]); 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci pao->has_control_cache = 0; 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci if (hpios_locked_mem_alloc(&phw->h_locked_mem, 5448c2ecf20Sopenharmony_ci sizeof(struct bus_master_interface), 5458c2ecf20Sopenharmony_ci pao->pci.pci_dev)) 5468c2ecf20Sopenharmony_ci phw->p_interface_buffer = NULL; 5478c2ecf20Sopenharmony_ci else if (hpios_locked_mem_get_virt_addr(&phw->h_locked_mem, 5488c2ecf20Sopenharmony_ci (void *)&phw->p_interface_buffer)) 5498c2ecf20Sopenharmony_ci phw->p_interface_buffer = NULL; 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci HPI_DEBUG_LOG(DEBUG, "interface buffer address %p\n", 5528c2ecf20Sopenharmony_ci phw->p_interface_buffer); 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci if (phw->p_interface_buffer) { 5558c2ecf20Sopenharmony_ci memset((void *)phw->p_interface_buffer, 0, 5568c2ecf20Sopenharmony_ci sizeof(struct bus_master_interface)); 5578c2ecf20Sopenharmony_ci phw->p_interface_buffer->dsp_ack = H620_HIF_UNKNOWN; 5588c2ecf20Sopenharmony_ci } 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci err = adapter_boot_load_dsp(pao, pos_error_code); 5618c2ecf20Sopenharmony_ci if (err) { 5628c2ecf20Sopenharmony_ci HPI_DEBUG_LOG(ERROR, "DSP code load failed\n"); 5638c2ecf20Sopenharmony_ci /* no need to clean up as SubSysCreateAdapter */ 5648c2ecf20Sopenharmony_ci /* calls DeleteAdapter on error. */ 5658c2ecf20Sopenharmony_ci return err; 5668c2ecf20Sopenharmony_ci } 5678c2ecf20Sopenharmony_ci HPI_DEBUG_LOG(INFO, "load DSP code OK\n"); 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci /* allow boot load even if mem alloc wont work */ 5708c2ecf20Sopenharmony_ci if (!phw->p_interface_buffer) 5718c2ecf20Sopenharmony_ci return HPI_ERROR_MEMORY_ALLOC; 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci interface = phw->p_interface_buffer; 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci /* make sure the DSP has started ok */ 5768c2ecf20Sopenharmony_ci if (!wait_dsp_ack(phw, H620_HIF_RESET, HPI6205_TIMEOUT * 10)) { 5778c2ecf20Sopenharmony_ci HPI_DEBUG_LOG(ERROR, "timed out waiting reset state \n"); 5788c2ecf20Sopenharmony_ci return HPI6205_ERROR_6205_INIT_FAILED; 5798c2ecf20Sopenharmony_ci } 5808c2ecf20Sopenharmony_ci /* Note that *pao, *phw are zeroed after allocation, 5818c2ecf20Sopenharmony_ci * so pointers and flags are NULL by default. 5828c2ecf20Sopenharmony_ci * Allocate bus mastering control cache buffer and tell the DSP about it 5838c2ecf20Sopenharmony_ci */ 5848c2ecf20Sopenharmony_ci if (interface->control_cache.number_of_controls) { 5858c2ecf20Sopenharmony_ci u8 *p_control_cache_virtual; 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci err = hpios_locked_mem_alloc(&phw->h_control_cache, 5888c2ecf20Sopenharmony_ci interface->control_cache.size_in_bytes, 5898c2ecf20Sopenharmony_ci pao->pci.pci_dev); 5908c2ecf20Sopenharmony_ci if (!err) 5918c2ecf20Sopenharmony_ci err = hpios_locked_mem_get_virt_addr(&phw-> 5928c2ecf20Sopenharmony_ci h_control_cache, 5938c2ecf20Sopenharmony_ci (void *)&p_control_cache_virtual); 5948c2ecf20Sopenharmony_ci if (!err) { 5958c2ecf20Sopenharmony_ci memset(p_control_cache_virtual, 0, 5968c2ecf20Sopenharmony_ci interface->control_cache.size_in_bytes); 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci phw->p_cache = 5998c2ecf20Sopenharmony_ci hpi_alloc_control_cache(interface-> 6008c2ecf20Sopenharmony_ci control_cache.number_of_controls, 6018c2ecf20Sopenharmony_ci interface->control_cache.size_in_bytes, 6028c2ecf20Sopenharmony_ci p_control_cache_virtual); 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci if (!phw->p_cache) 6058c2ecf20Sopenharmony_ci err = HPI_ERROR_MEMORY_ALLOC; 6068c2ecf20Sopenharmony_ci } 6078c2ecf20Sopenharmony_ci if (!err) { 6088c2ecf20Sopenharmony_ci err = hpios_locked_mem_get_phys_addr(&phw-> 6098c2ecf20Sopenharmony_ci h_control_cache, &phys_addr); 6108c2ecf20Sopenharmony_ci interface->control_cache.physical_address32 = 6118c2ecf20Sopenharmony_ci phys_addr; 6128c2ecf20Sopenharmony_ci } 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci if (!err) 6158c2ecf20Sopenharmony_ci pao->has_control_cache = 1; 6168c2ecf20Sopenharmony_ci else { 6178c2ecf20Sopenharmony_ci if (hpios_locked_mem_valid(&phw->h_control_cache)) 6188c2ecf20Sopenharmony_ci hpios_locked_mem_free(&phw->h_control_cache); 6198c2ecf20Sopenharmony_ci pao->has_control_cache = 0; 6208c2ecf20Sopenharmony_ci } 6218c2ecf20Sopenharmony_ci } 6228c2ecf20Sopenharmony_ci send_dsp_command(phw, H620_HIF_IDLE); 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci { 6258c2ecf20Sopenharmony_ci struct hpi_message hm; 6268c2ecf20Sopenharmony_ci struct hpi_response hr; 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci HPI_DEBUG_LOG(VERBOSE, "init ADAPTER_GET_INFO\n"); 6298c2ecf20Sopenharmony_ci memset(&hm, 0, sizeof(hm)); 6308c2ecf20Sopenharmony_ci /* wAdapterIndex == version == 0 */ 6318c2ecf20Sopenharmony_ci hm.type = HPI_TYPE_REQUEST; 6328c2ecf20Sopenharmony_ci hm.size = sizeof(hm); 6338c2ecf20Sopenharmony_ci hm.object = HPI_OBJ_ADAPTER; 6348c2ecf20Sopenharmony_ci hm.function = HPI_ADAPTER_GET_INFO; 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci memset(&hr, 0, sizeof(hr)); 6378c2ecf20Sopenharmony_ci hr.size = sizeof(hr); 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci err = message_response_sequence(pao, &hm, &hr); 6408c2ecf20Sopenharmony_ci if (err) { 6418c2ecf20Sopenharmony_ci HPI_DEBUG_LOG(ERROR, "message transport error %d\n", 6428c2ecf20Sopenharmony_ci err); 6438c2ecf20Sopenharmony_ci return err; 6448c2ecf20Sopenharmony_ci } 6458c2ecf20Sopenharmony_ci if (hr.error) 6468c2ecf20Sopenharmony_ci return hr.error; 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci pao->type = hr.u.ax.info.adapter_type; 6498c2ecf20Sopenharmony_ci pao->index = hr.u.ax.info.adapter_index; 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci HPI_DEBUG_LOG(VERBOSE, 6528c2ecf20Sopenharmony_ci "got adapter info type %x index %d serial %d\n", 6538c2ecf20Sopenharmony_ci hr.u.ax.info.adapter_type, hr.u.ax.info.adapter_index, 6548c2ecf20Sopenharmony_ci hr.u.ax.info.serial_number); 6558c2ecf20Sopenharmony_ci } 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci if (phw->p_cache) 6588c2ecf20Sopenharmony_ci phw->p_cache->adap_idx = pao->index; 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci HPI_DEBUG_LOG(INFO, "bootload DSP OK\n"); 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci pao->irq_query_and_clear = adapter_irq_query_and_clear; 6638c2ecf20Sopenharmony_ci pao->instream_host_buffer_status = 6648c2ecf20Sopenharmony_ci phw->p_interface_buffer->instream_host_buffer_status; 6658c2ecf20Sopenharmony_ci pao->outstream_host_buffer_status = 6668c2ecf20Sopenharmony_ci phw->p_interface_buffer->outstream_host_buffer_status; 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci return hpi_add_adapter(pao); 6698c2ecf20Sopenharmony_ci} 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ci/** Free memory areas allocated by adapter 6728c2ecf20Sopenharmony_ci * this routine is called from AdapterDelete, 6738c2ecf20Sopenharmony_ci * and SubSysCreateAdapter if duplicate index 6748c2ecf20Sopenharmony_ci*/ 6758c2ecf20Sopenharmony_cistatic void delete_adapter_obj(struct hpi_adapter_obj *pao) 6768c2ecf20Sopenharmony_ci{ 6778c2ecf20Sopenharmony_ci struct hpi_hw_obj *phw = pao->priv; 6788c2ecf20Sopenharmony_ci int i; 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci if (hpios_locked_mem_valid(&phw->h_control_cache)) { 6818c2ecf20Sopenharmony_ci hpios_locked_mem_free(&phw->h_control_cache); 6828c2ecf20Sopenharmony_ci hpi_free_control_cache(phw->p_cache); 6838c2ecf20Sopenharmony_ci } 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci if (hpios_locked_mem_valid(&phw->h_locked_mem)) { 6868c2ecf20Sopenharmony_ci hpios_locked_mem_free(&phw->h_locked_mem); 6878c2ecf20Sopenharmony_ci phw->p_interface_buffer = NULL; 6888c2ecf20Sopenharmony_ci } 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci for (i = 0; i < HPI_MAX_STREAMS; i++) 6918c2ecf20Sopenharmony_ci if (hpios_locked_mem_valid(&phw->instream_host_buffers[i])) { 6928c2ecf20Sopenharmony_ci hpios_locked_mem_free(&phw->instream_host_buffers[i]); 6938c2ecf20Sopenharmony_ci /*?phw->InStreamHostBuffers[i] = NULL; */ 6948c2ecf20Sopenharmony_ci phw->instream_host_buffer_size[i] = 0; 6958c2ecf20Sopenharmony_ci } 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci for (i = 0; i < HPI_MAX_STREAMS; i++) 6988c2ecf20Sopenharmony_ci if (hpios_locked_mem_valid(&phw->outstream_host_buffers[i])) { 6998c2ecf20Sopenharmony_ci hpios_locked_mem_free(&phw->outstream_host_buffers 7008c2ecf20Sopenharmony_ci [i]); 7018c2ecf20Sopenharmony_ci phw->outstream_host_buffer_size[i] = 0; 7028c2ecf20Sopenharmony_ci } 7038c2ecf20Sopenharmony_ci kfree(phw); 7048c2ecf20Sopenharmony_ci} 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci/*****************************************************************************/ 7078c2ecf20Sopenharmony_ci/* Adapter functions */ 7088c2ecf20Sopenharmony_cistatic int adapter_irq_query_and_clear(struct hpi_adapter_obj *pao, 7098c2ecf20Sopenharmony_ci u32 message) 7108c2ecf20Sopenharmony_ci{ 7118c2ecf20Sopenharmony_ci struct hpi_hw_obj *phw = pao->priv; 7128c2ecf20Sopenharmony_ci u32 hsr = 0; 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ci hsr = ioread32(phw->prHSR); 7158c2ecf20Sopenharmony_ci if (hsr & C6205_HSR_INTSRC) { 7168c2ecf20Sopenharmony_ci /* reset the interrupt from the DSP */ 7178c2ecf20Sopenharmony_ci iowrite32(C6205_HSR_INTSRC, phw->prHSR); 7188c2ecf20Sopenharmony_ci return HPI_IRQ_MIXER; 7198c2ecf20Sopenharmony_ci } 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci return HPI_IRQ_NONE; 7228c2ecf20Sopenharmony_ci} 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci/*****************************************************************************/ 7258c2ecf20Sopenharmony_ci/* OutStream Host buffer functions */ 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci/** Allocate or attach buffer for busmastering 7288c2ecf20Sopenharmony_ci*/ 7298c2ecf20Sopenharmony_cistatic void outstream_host_buffer_allocate(struct hpi_adapter_obj *pao, 7308c2ecf20Sopenharmony_ci struct hpi_message *phm, struct hpi_response *phr) 7318c2ecf20Sopenharmony_ci{ 7328c2ecf20Sopenharmony_ci u16 err = 0; 7338c2ecf20Sopenharmony_ci u32 command = phm->u.d.u.buffer.command; 7348c2ecf20Sopenharmony_ci struct hpi_hw_obj *phw = pao->priv; 7358c2ecf20Sopenharmony_ci struct bus_master_interface *interface = phw->p_interface_buffer; 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci hpi_init_response(phr, phm->object, phm->function, 0); 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci if (command == HPI_BUFFER_CMD_EXTERNAL 7408c2ecf20Sopenharmony_ci || command == HPI_BUFFER_CMD_INTERNAL_ALLOC) { 7418c2ecf20Sopenharmony_ci /* ALLOC phase, allocate a buffer with power of 2 size, 7428c2ecf20Sopenharmony_ci get its bus address for PCI bus mastering 7438c2ecf20Sopenharmony_ci */ 7448c2ecf20Sopenharmony_ci phm->u.d.u.buffer.buffer_size = 7458c2ecf20Sopenharmony_ci roundup_pow_of_two(phm->u.d.u.buffer.buffer_size); 7468c2ecf20Sopenharmony_ci /* return old size and allocated size, 7478c2ecf20Sopenharmony_ci so caller can detect change */ 7488c2ecf20Sopenharmony_ci phr->u.d.u.stream_info.data_available = 7498c2ecf20Sopenharmony_ci phw->outstream_host_buffer_size[phm->obj_index]; 7508c2ecf20Sopenharmony_ci phr->u.d.u.stream_info.buffer_size = 7518c2ecf20Sopenharmony_ci phm->u.d.u.buffer.buffer_size; 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_ci if (phw->outstream_host_buffer_size[phm->obj_index] == 7548c2ecf20Sopenharmony_ci phm->u.d.u.buffer.buffer_size) { 7558c2ecf20Sopenharmony_ci /* Same size, no action required */ 7568c2ecf20Sopenharmony_ci return; 7578c2ecf20Sopenharmony_ci } 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci if (hpios_locked_mem_valid(&phw->outstream_host_buffers[phm-> 7608c2ecf20Sopenharmony_ci obj_index])) 7618c2ecf20Sopenharmony_ci hpios_locked_mem_free(&phw->outstream_host_buffers 7628c2ecf20Sopenharmony_ci [phm->obj_index]); 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci err = hpios_locked_mem_alloc(&phw->outstream_host_buffers 7658c2ecf20Sopenharmony_ci [phm->obj_index], phm->u.d.u.buffer.buffer_size, 7668c2ecf20Sopenharmony_ci pao->pci.pci_dev); 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci if (err) { 7698c2ecf20Sopenharmony_ci phr->error = HPI_ERROR_INVALID_DATASIZE; 7708c2ecf20Sopenharmony_ci phw->outstream_host_buffer_size[phm->obj_index] = 0; 7718c2ecf20Sopenharmony_ci return; 7728c2ecf20Sopenharmony_ci } 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci err = hpios_locked_mem_get_phys_addr 7758c2ecf20Sopenharmony_ci (&phw->outstream_host_buffers[phm->obj_index], 7768c2ecf20Sopenharmony_ci &phm->u.d.u.buffer.pci_address); 7778c2ecf20Sopenharmony_ci /* get the phys addr into msg for single call alloc caller 7788c2ecf20Sopenharmony_ci * needs to do this for split alloc (or use the same message) 7798c2ecf20Sopenharmony_ci * return the phy address for split alloc in the respose too 7808c2ecf20Sopenharmony_ci */ 7818c2ecf20Sopenharmony_ci phr->u.d.u.stream_info.auxiliary_data_available = 7828c2ecf20Sopenharmony_ci phm->u.d.u.buffer.pci_address; 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci if (err) { 7858c2ecf20Sopenharmony_ci hpios_locked_mem_free(&phw->outstream_host_buffers 7868c2ecf20Sopenharmony_ci [phm->obj_index]); 7878c2ecf20Sopenharmony_ci phw->outstream_host_buffer_size[phm->obj_index] = 0; 7888c2ecf20Sopenharmony_ci phr->error = HPI_ERROR_MEMORY_ALLOC; 7898c2ecf20Sopenharmony_ci return; 7908c2ecf20Sopenharmony_ci } 7918c2ecf20Sopenharmony_ci } 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_ci if (command == HPI_BUFFER_CMD_EXTERNAL 7948c2ecf20Sopenharmony_ci || command == HPI_BUFFER_CMD_INTERNAL_GRANTADAPTER) { 7958c2ecf20Sopenharmony_ci /* GRANT phase. Set up the BBM status, tell the DSP about 7968c2ecf20Sopenharmony_ci the buffer so it can start using BBM. 7978c2ecf20Sopenharmony_ci */ 7988c2ecf20Sopenharmony_ci struct hpi_hostbuffer_status *status; 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci if (phm->u.d.u.buffer.buffer_size & (phm->u.d.u.buffer. 8018c2ecf20Sopenharmony_ci buffer_size - 1)) { 8028c2ecf20Sopenharmony_ci HPI_DEBUG_LOG(ERROR, 8038c2ecf20Sopenharmony_ci "Buffer size must be 2^N not %d\n", 8048c2ecf20Sopenharmony_ci phm->u.d.u.buffer.buffer_size); 8058c2ecf20Sopenharmony_ci phr->error = HPI_ERROR_INVALID_DATASIZE; 8068c2ecf20Sopenharmony_ci return; 8078c2ecf20Sopenharmony_ci } 8088c2ecf20Sopenharmony_ci phw->outstream_host_buffer_size[phm->obj_index] = 8098c2ecf20Sopenharmony_ci phm->u.d.u.buffer.buffer_size; 8108c2ecf20Sopenharmony_ci status = &interface->outstream_host_buffer_status[phm-> 8118c2ecf20Sopenharmony_ci obj_index]; 8128c2ecf20Sopenharmony_ci status->samples_processed = 0; 8138c2ecf20Sopenharmony_ci status->stream_state = HPI_STATE_STOPPED; 8148c2ecf20Sopenharmony_ci status->dsp_index = 0; 8158c2ecf20Sopenharmony_ci status->host_index = status->dsp_index; 8168c2ecf20Sopenharmony_ci status->size_in_bytes = phm->u.d.u.buffer.buffer_size; 8178c2ecf20Sopenharmony_ci status->auxiliary_data_available = 0; 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci hw_message(pao, phm, phr); 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_ci if (phr->error 8228c2ecf20Sopenharmony_ci && hpios_locked_mem_valid(&phw-> 8238c2ecf20Sopenharmony_ci outstream_host_buffers[phm->obj_index])) { 8248c2ecf20Sopenharmony_ci hpios_locked_mem_free(&phw->outstream_host_buffers 8258c2ecf20Sopenharmony_ci [phm->obj_index]); 8268c2ecf20Sopenharmony_ci phw->outstream_host_buffer_size[phm->obj_index] = 0; 8278c2ecf20Sopenharmony_ci } 8288c2ecf20Sopenharmony_ci } 8298c2ecf20Sopenharmony_ci} 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_cistatic void outstream_host_buffer_get_info(struct hpi_adapter_obj *pao, 8328c2ecf20Sopenharmony_ci struct hpi_message *phm, struct hpi_response *phr) 8338c2ecf20Sopenharmony_ci{ 8348c2ecf20Sopenharmony_ci struct hpi_hw_obj *phw = pao->priv; 8358c2ecf20Sopenharmony_ci struct bus_master_interface *interface = phw->p_interface_buffer; 8368c2ecf20Sopenharmony_ci struct hpi_hostbuffer_status *status; 8378c2ecf20Sopenharmony_ci u8 *p_bbm_data; 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_ci if (hpios_locked_mem_valid(&phw->outstream_host_buffers[phm-> 8408c2ecf20Sopenharmony_ci obj_index])) { 8418c2ecf20Sopenharmony_ci if (hpios_locked_mem_get_virt_addr(&phw-> 8428c2ecf20Sopenharmony_ci outstream_host_buffers[phm->obj_index], 8438c2ecf20Sopenharmony_ci (void *)&p_bbm_data)) { 8448c2ecf20Sopenharmony_ci phr->error = HPI_ERROR_INVALID_OPERATION; 8458c2ecf20Sopenharmony_ci return; 8468c2ecf20Sopenharmony_ci } 8478c2ecf20Sopenharmony_ci status = &interface->outstream_host_buffer_status[phm-> 8488c2ecf20Sopenharmony_ci obj_index]; 8498c2ecf20Sopenharmony_ci hpi_init_response(phr, HPI_OBJ_OSTREAM, 8508c2ecf20Sopenharmony_ci HPI_OSTREAM_HOSTBUFFER_GET_INFO, 0); 8518c2ecf20Sopenharmony_ci phr->u.d.u.hostbuffer_info.p_buffer = p_bbm_data; 8528c2ecf20Sopenharmony_ci phr->u.d.u.hostbuffer_info.p_status = status; 8538c2ecf20Sopenharmony_ci } else { 8548c2ecf20Sopenharmony_ci hpi_init_response(phr, HPI_OBJ_OSTREAM, 8558c2ecf20Sopenharmony_ci HPI_OSTREAM_HOSTBUFFER_GET_INFO, 8568c2ecf20Sopenharmony_ci HPI_ERROR_INVALID_OPERATION); 8578c2ecf20Sopenharmony_ci } 8588c2ecf20Sopenharmony_ci} 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_cistatic void outstream_host_buffer_free(struct hpi_adapter_obj *pao, 8618c2ecf20Sopenharmony_ci struct hpi_message *phm, struct hpi_response *phr) 8628c2ecf20Sopenharmony_ci{ 8638c2ecf20Sopenharmony_ci struct hpi_hw_obj *phw = pao->priv; 8648c2ecf20Sopenharmony_ci u32 command = phm->u.d.u.buffer.command; 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci if (phw->outstream_host_buffer_size[phm->obj_index]) { 8678c2ecf20Sopenharmony_ci if (command == HPI_BUFFER_CMD_EXTERNAL 8688c2ecf20Sopenharmony_ci || command == HPI_BUFFER_CMD_INTERNAL_REVOKEADAPTER) { 8698c2ecf20Sopenharmony_ci phw->outstream_host_buffer_size[phm->obj_index] = 0; 8708c2ecf20Sopenharmony_ci hw_message(pao, phm, phr); 8718c2ecf20Sopenharmony_ci /* Tell adapter to stop using the host buffer. */ 8728c2ecf20Sopenharmony_ci } 8738c2ecf20Sopenharmony_ci if (command == HPI_BUFFER_CMD_EXTERNAL 8748c2ecf20Sopenharmony_ci || command == HPI_BUFFER_CMD_INTERNAL_FREE) 8758c2ecf20Sopenharmony_ci hpios_locked_mem_free(&phw->outstream_host_buffers 8768c2ecf20Sopenharmony_ci [phm->obj_index]); 8778c2ecf20Sopenharmony_ci } 8788c2ecf20Sopenharmony_ci /* Should HPI_ERROR_INVALID_OPERATION be returned 8798c2ecf20Sopenharmony_ci if no host buffer is allocated? */ 8808c2ecf20Sopenharmony_ci else 8818c2ecf20Sopenharmony_ci hpi_init_response(phr, HPI_OBJ_OSTREAM, 8828c2ecf20Sopenharmony_ci HPI_OSTREAM_HOSTBUFFER_FREE, 0); 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_ci} 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_cistatic u32 outstream_get_space_available(struct hpi_hostbuffer_status *status) 8878c2ecf20Sopenharmony_ci{ 8888c2ecf20Sopenharmony_ci return status->size_in_bytes - (status->host_index - 8898c2ecf20Sopenharmony_ci status->dsp_index); 8908c2ecf20Sopenharmony_ci} 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_cistatic void outstream_write(struct hpi_adapter_obj *pao, 8938c2ecf20Sopenharmony_ci struct hpi_message *phm, struct hpi_response *phr) 8948c2ecf20Sopenharmony_ci{ 8958c2ecf20Sopenharmony_ci struct hpi_hw_obj *phw = pao->priv; 8968c2ecf20Sopenharmony_ci struct bus_master_interface *interface = phw->p_interface_buffer; 8978c2ecf20Sopenharmony_ci struct hpi_hostbuffer_status *status; 8988c2ecf20Sopenharmony_ci u32 space_available; 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci if (!phw->outstream_host_buffer_size[phm->obj_index]) { 9018c2ecf20Sopenharmony_ci /* there is no BBM buffer, write via message */ 9028c2ecf20Sopenharmony_ci hw_message(pao, phm, phr); 9038c2ecf20Sopenharmony_ci return; 9048c2ecf20Sopenharmony_ci } 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_ci hpi_init_response(phr, phm->object, phm->function, 0); 9078c2ecf20Sopenharmony_ci status = &interface->outstream_host_buffer_status[phm->obj_index]; 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_ci space_available = outstream_get_space_available(status); 9108c2ecf20Sopenharmony_ci if (space_available < phm->u.d.u.data.data_size) { 9118c2ecf20Sopenharmony_ci phr->error = HPI_ERROR_INVALID_DATASIZE; 9128c2ecf20Sopenharmony_ci return; 9138c2ecf20Sopenharmony_ci } 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_ci /* HostBuffers is used to indicate host buffer is internally allocated. 9168c2ecf20Sopenharmony_ci otherwise, assumed external, data written externally */ 9178c2ecf20Sopenharmony_ci if (phm->u.d.u.data.pb_data 9188c2ecf20Sopenharmony_ci && hpios_locked_mem_valid(&phw->outstream_host_buffers[phm-> 9198c2ecf20Sopenharmony_ci obj_index])) { 9208c2ecf20Sopenharmony_ci u8 *p_bbm_data; 9218c2ecf20Sopenharmony_ci u32 l_first_write; 9228c2ecf20Sopenharmony_ci u8 *p_app_data = (u8 *)phm->u.d.u.data.pb_data; 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_ci if (hpios_locked_mem_get_virt_addr(&phw-> 9258c2ecf20Sopenharmony_ci outstream_host_buffers[phm->obj_index], 9268c2ecf20Sopenharmony_ci (void *)&p_bbm_data)) { 9278c2ecf20Sopenharmony_ci phr->error = HPI_ERROR_INVALID_OPERATION; 9288c2ecf20Sopenharmony_ci return; 9298c2ecf20Sopenharmony_ci } 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_ci /* either all data, 9328c2ecf20Sopenharmony_ci or enough to fit from current to end of BBM buffer */ 9338c2ecf20Sopenharmony_ci l_first_write = 9348c2ecf20Sopenharmony_ci min(phm->u.d.u.data.data_size, 9358c2ecf20Sopenharmony_ci status->size_in_bytes - 9368c2ecf20Sopenharmony_ci (status->host_index & (status->size_in_bytes - 1))); 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_ci memcpy(p_bbm_data + 9398c2ecf20Sopenharmony_ci (status->host_index & (status->size_in_bytes - 1)), 9408c2ecf20Sopenharmony_ci p_app_data, l_first_write); 9418c2ecf20Sopenharmony_ci /* remaining data if any */ 9428c2ecf20Sopenharmony_ci memcpy(p_bbm_data, p_app_data + l_first_write, 9438c2ecf20Sopenharmony_ci phm->u.d.u.data.data_size - l_first_write); 9448c2ecf20Sopenharmony_ci } 9458c2ecf20Sopenharmony_ci 9468c2ecf20Sopenharmony_ci /* 9478c2ecf20Sopenharmony_ci * This version relies on the DSP code triggering an OStream buffer 9488c2ecf20Sopenharmony_ci * update immediately following a SET_FORMAT call. The host has 9498c2ecf20Sopenharmony_ci * already written data into the BBM buffer, but the DSP won't know 9508c2ecf20Sopenharmony_ci * about it until dwHostIndex is adjusted. 9518c2ecf20Sopenharmony_ci */ 9528c2ecf20Sopenharmony_ci if (phw->flag_outstream_just_reset[phm->obj_index]) { 9538c2ecf20Sopenharmony_ci /* Format can only change after reset. Must tell DSP. */ 9548c2ecf20Sopenharmony_ci u16 function = phm->function; 9558c2ecf20Sopenharmony_ci phw->flag_outstream_just_reset[phm->obj_index] = 0; 9568c2ecf20Sopenharmony_ci phm->function = HPI_OSTREAM_SET_FORMAT; 9578c2ecf20Sopenharmony_ci hw_message(pao, phm, phr); /* send the format to the DSP */ 9588c2ecf20Sopenharmony_ci phm->function = function; 9598c2ecf20Sopenharmony_ci if (phr->error) 9608c2ecf20Sopenharmony_ci return; 9618c2ecf20Sopenharmony_ci } 9628c2ecf20Sopenharmony_ci 9638c2ecf20Sopenharmony_ci status->host_index += phm->u.d.u.data.data_size; 9648c2ecf20Sopenharmony_ci} 9658c2ecf20Sopenharmony_ci 9668c2ecf20Sopenharmony_cistatic void outstream_get_info(struct hpi_adapter_obj *pao, 9678c2ecf20Sopenharmony_ci struct hpi_message *phm, struct hpi_response *phr) 9688c2ecf20Sopenharmony_ci{ 9698c2ecf20Sopenharmony_ci struct hpi_hw_obj *phw = pao->priv; 9708c2ecf20Sopenharmony_ci struct bus_master_interface *interface = phw->p_interface_buffer; 9718c2ecf20Sopenharmony_ci struct hpi_hostbuffer_status *status; 9728c2ecf20Sopenharmony_ci 9738c2ecf20Sopenharmony_ci if (!phw->outstream_host_buffer_size[phm->obj_index]) { 9748c2ecf20Sopenharmony_ci hw_message(pao, phm, phr); 9758c2ecf20Sopenharmony_ci return; 9768c2ecf20Sopenharmony_ci } 9778c2ecf20Sopenharmony_ci 9788c2ecf20Sopenharmony_ci hpi_init_response(phr, phm->object, phm->function, 0); 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ci status = &interface->outstream_host_buffer_status[phm->obj_index]; 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_ci phr->u.d.u.stream_info.state = (u16)status->stream_state; 9838c2ecf20Sopenharmony_ci phr->u.d.u.stream_info.samples_transferred = 9848c2ecf20Sopenharmony_ci status->samples_processed; 9858c2ecf20Sopenharmony_ci phr->u.d.u.stream_info.buffer_size = status->size_in_bytes; 9868c2ecf20Sopenharmony_ci phr->u.d.u.stream_info.data_available = 9878c2ecf20Sopenharmony_ci status->size_in_bytes - outstream_get_space_available(status); 9888c2ecf20Sopenharmony_ci phr->u.d.u.stream_info.auxiliary_data_available = 9898c2ecf20Sopenharmony_ci status->auxiliary_data_available; 9908c2ecf20Sopenharmony_ci} 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_cistatic void outstream_start(struct hpi_adapter_obj *pao, 9938c2ecf20Sopenharmony_ci struct hpi_message *phm, struct hpi_response *phr) 9948c2ecf20Sopenharmony_ci{ 9958c2ecf20Sopenharmony_ci hw_message(pao, phm, phr); 9968c2ecf20Sopenharmony_ci} 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_cistatic void outstream_reset(struct hpi_adapter_obj *pao, 9998c2ecf20Sopenharmony_ci struct hpi_message *phm, struct hpi_response *phr) 10008c2ecf20Sopenharmony_ci{ 10018c2ecf20Sopenharmony_ci struct hpi_hw_obj *phw = pao->priv; 10028c2ecf20Sopenharmony_ci phw->flag_outstream_just_reset[phm->obj_index] = 1; 10038c2ecf20Sopenharmony_ci hw_message(pao, phm, phr); 10048c2ecf20Sopenharmony_ci} 10058c2ecf20Sopenharmony_ci 10068c2ecf20Sopenharmony_cistatic void outstream_open(struct hpi_adapter_obj *pao, 10078c2ecf20Sopenharmony_ci struct hpi_message *phm, struct hpi_response *phr) 10088c2ecf20Sopenharmony_ci{ 10098c2ecf20Sopenharmony_ci outstream_reset(pao, phm, phr); 10108c2ecf20Sopenharmony_ci} 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_ci/*****************************************************************************/ 10138c2ecf20Sopenharmony_ci/* InStream Host buffer functions */ 10148c2ecf20Sopenharmony_ci 10158c2ecf20Sopenharmony_cistatic void instream_host_buffer_allocate(struct hpi_adapter_obj *pao, 10168c2ecf20Sopenharmony_ci struct hpi_message *phm, struct hpi_response *phr) 10178c2ecf20Sopenharmony_ci{ 10188c2ecf20Sopenharmony_ci u16 err = 0; 10198c2ecf20Sopenharmony_ci u32 command = phm->u.d.u.buffer.command; 10208c2ecf20Sopenharmony_ci struct hpi_hw_obj *phw = pao->priv; 10218c2ecf20Sopenharmony_ci struct bus_master_interface *interface = phw->p_interface_buffer; 10228c2ecf20Sopenharmony_ci 10238c2ecf20Sopenharmony_ci hpi_init_response(phr, phm->object, phm->function, 0); 10248c2ecf20Sopenharmony_ci 10258c2ecf20Sopenharmony_ci if (command == HPI_BUFFER_CMD_EXTERNAL 10268c2ecf20Sopenharmony_ci || command == HPI_BUFFER_CMD_INTERNAL_ALLOC) { 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_ci phm->u.d.u.buffer.buffer_size = 10298c2ecf20Sopenharmony_ci roundup_pow_of_two(phm->u.d.u.buffer.buffer_size); 10308c2ecf20Sopenharmony_ci phr->u.d.u.stream_info.data_available = 10318c2ecf20Sopenharmony_ci phw->instream_host_buffer_size[phm->obj_index]; 10328c2ecf20Sopenharmony_ci phr->u.d.u.stream_info.buffer_size = 10338c2ecf20Sopenharmony_ci phm->u.d.u.buffer.buffer_size; 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_ci if (phw->instream_host_buffer_size[phm->obj_index] == 10368c2ecf20Sopenharmony_ci phm->u.d.u.buffer.buffer_size) { 10378c2ecf20Sopenharmony_ci /* Same size, no action required */ 10388c2ecf20Sopenharmony_ci return; 10398c2ecf20Sopenharmony_ci } 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_ci if (hpios_locked_mem_valid(&phw->instream_host_buffers[phm-> 10428c2ecf20Sopenharmony_ci obj_index])) 10438c2ecf20Sopenharmony_ci hpios_locked_mem_free(&phw->instream_host_buffers 10448c2ecf20Sopenharmony_ci [phm->obj_index]); 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_ci err = hpios_locked_mem_alloc(&phw->instream_host_buffers[phm-> 10478c2ecf20Sopenharmony_ci obj_index], phm->u.d.u.buffer.buffer_size, 10488c2ecf20Sopenharmony_ci pao->pci.pci_dev); 10498c2ecf20Sopenharmony_ci 10508c2ecf20Sopenharmony_ci if (err) { 10518c2ecf20Sopenharmony_ci phr->error = HPI_ERROR_INVALID_DATASIZE; 10528c2ecf20Sopenharmony_ci phw->instream_host_buffer_size[phm->obj_index] = 0; 10538c2ecf20Sopenharmony_ci return; 10548c2ecf20Sopenharmony_ci } 10558c2ecf20Sopenharmony_ci 10568c2ecf20Sopenharmony_ci err = hpios_locked_mem_get_phys_addr 10578c2ecf20Sopenharmony_ci (&phw->instream_host_buffers[phm->obj_index], 10588c2ecf20Sopenharmony_ci &phm->u.d.u.buffer.pci_address); 10598c2ecf20Sopenharmony_ci /* get the phys addr into msg for single call alloc. Caller 10608c2ecf20Sopenharmony_ci needs to do this for split alloc so return the phy address */ 10618c2ecf20Sopenharmony_ci phr->u.d.u.stream_info.auxiliary_data_available = 10628c2ecf20Sopenharmony_ci phm->u.d.u.buffer.pci_address; 10638c2ecf20Sopenharmony_ci if (err) { 10648c2ecf20Sopenharmony_ci hpios_locked_mem_free(&phw->instream_host_buffers 10658c2ecf20Sopenharmony_ci [phm->obj_index]); 10668c2ecf20Sopenharmony_ci phw->instream_host_buffer_size[phm->obj_index] = 0; 10678c2ecf20Sopenharmony_ci phr->error = HPI_ERROR_MEMORY_ALLOC; 10688c2ecf20Sopenharmony_ci return; 10698c2ecf20Sopenharmony_ci } 10708c2ecf20Sopenharmony_ci } 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_ci if (command == HPI_BUFFER_CMD_EXTERNAL 10738c2ecf20Sopenharmony_ci || command == HPI_BUFFER_CMD_INTERNAL_GRANTADAPTER) { 10748c2ecf20Sopenharmony_ci struct hpi_hostbuffer_status *status; 10758c2ecf20Sopenharmony_ci 10768c2ecf20Sopenharmony_ci if (phm->u.d.u.buffer.buffer_size & (phm->u.d.u.buffer. 10778c2ecf20Sopenharmony_ci buffer_size - 1)) { 10788c2ecf20Sopenharmony_ci HPI_DEBUG_LOG(ERROR, 10798c2ecf20Sopenharmony_ci "Buffer size must be 2^N not %d\n", 10808c2ecf20Sopenharmony_ci phm->u.d.u.buffer.buffer_size); 10818c2ecf20Sopenharmony_ci phr->error = HPI_ERROR_INVALID_DATASIZE; 10828c2ecf20Sopenharmony_ci return; 10838c2ecf20Sopenharmony_ci } 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_ci phw->instream_host_buffer_size[phm->obj_index] = 10868c2ecf20Sopenharmony_ci phm->u.d.u.buffer.buffer_size; 10878c2ecf20Sopenharmony_ci status = &interface->instream_host_buffer_status[phm-> 10888c2ecf20Sopenharmony_ci obj_index]; 10898c2ecf20Sopenharmony_ci status->samples_processed = 0; 10908c2ecf20Sopenharmony_ci status->stream_state = HPI_STATE_STOPPED; 10918c2ecf20Sopenharmony_ci status->dsp_index = 0; 10928c2ecf20Sopenharmony_ci status->host_index = status->dsp_index; 10938c2ecf20Sopenharmony_ci status->size_in_bytes = phm->u.d.u.buffer.buffer_size; 10948c2ecf20Sopenharmony_ci status->auxiliary_data_available = 0; 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_ci hw_message(pao, phm, phr); 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_ci if (phr->error 10998c2ecf20Sopenharmony_ci && hpios_locked_mem_valid(&phw-> 11008c2ecf20Sopenharmony_ci instream_host_buffers[phm->obj_index])) { 11018c2ecf20Sopenharmony_ci hpios_locked_mem_free(&phw->instream_host_buffers 11028c2ecf20Sopenharmony_ci [phm->obj_index]); 11038c2ecf20Sopenharmony_ci phw->instream_host_buffer_size[phm->obj_index] = 0; 11048c2ecf20Sopenharmony_ci } 11058c2ecf20Sopenharmony_ci } 11068c2ecf20Sopenharmony_ci} 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_cistatic void instream_host_buffer_get_info(struct hpi_adapter_obj *pao, 11098c2ecf20Sopenharmony_ci struct hpi_message *phm, struct hpi_response *phr) 11108c2ecf20Sopenharmony_ci{ 11118c2ecf20Sopenharmony_ci struct hpi_hw_obj *phw = pao->priv; 11128c2ecf20Sopenharmony_ci struct bus_master_interface *interface = phw->p_interface_buffer; 11138c2ecf20Sopenharmony_ci struct hpi_hostbuffer_status *status; 11148c2ecf20Sopenharmony_ci u8 *p_bbm_data; 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_ci if (hpios_locked_mem_valid(&phw->instream_host_buffers[phm-> 11178c2ecf20Sopenharmony_ci obj_index])) { 11188c2ecf20Sopenharmony_ci if (hpios_locked_mem_get_virt_addr(&phw-> 11198c2ecf20Sopenharmony_ci instream_host_buffers[phm->obj_index], 11208c2ecf20Sopenharmony_ci (void *)&p_bbm_data)) { 11218c2ecf20Sopenharmony_ci phr->error = HPI_ERROR_INVALID_OPERATION; 11228c2ecf20Sopenharmony_ci return; 11238c2ecf20Sopenharmony_ci } 11248c2ecf20Sopenharmony_ci status = &interface->instream_host_buffer_status[phm-> 11258c2ecf20Sopenharmony_ci obj_index]; 11268c2ecf20Sopenharmony_ci hpi_init_response(phr, HPI_OBJ_ISTREAM, 11278c2ecf20Sopenharmony_ci HPI_ISTREAM_HOSTBUFFER_GET_INFO, 0); 11288c2ecf20Sopenharmony_ci phr->u.d.u.hostbuffer_info.p_buffer = p_bbm_data; 11298c2ecf20Sopenharmony_ci phr->u.d.u.hostbuffer_info.p_status = status; 11308c2ecf20Sopenharmony_ci } else { 11318c2ecf20Sopenharmony_ci hpi_init_response(phr, HPI_OBJ_ISTREAM, 11328c2ecf20Sopenharmony_ci HPI_ISTREAM_HOSTBUFFER_GET_INFO, 11338c2ecf20Sopenharmony_ci HPI_ERROR_INVALID_OPERATION); 11348c2ecf20Sopenharmony_ci } 11358c2ecf20Sopenharmony_ci} 11368c2ecf20Sopenharmony_ci 11378c2ecf20Sopenharmony_cistatic void instream_host_buffer_free(struct hpi_adapter_obj *pao, 11388c2ecf20Sopenharmony_ci struct hpi_message *phm, struct hpi_response *phr) 11398c2ecf20Sopenharmony_ci{ 11408c2ecf20Sopenharmony_ci struct hpi_hw_obj *phw = pao->priv; 11418c2ecf20Sopenharmony_ci u32 command = phm->u.d.u.buffer.command; 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_ci if (phw->instream_host_buffer_size[phm->obj_index]) { 11448c2ecf20Sopenharmony_ci if (command == HPI_BUFFER_CMD_EXTERNAL 11458c2ecf20Sopenharmony_ci || command == HPI_BUFFER_CMD_INTERNAL_REVOKEADAPTER) { 11468c2ecf20Sopenharmony_ci phw->instream_host_buffer_size[phm->obj_index] = 0; 11478c2ecf20Sopenharmony_ci hw_message(pao, phm, phr); 11488c2ecf20Sopenharmony_ci } 11498c2ecf20Sopenharmony_ci 11508c2ecf20Sopenharmony_ci if (command == HPI_BUFFER_CMD_EXTERNAL 11518c2ecf20Sopenharmony_ci || command == HPI_BUFFER_CMD_INTERNAL_FREE) 11528c2ecf20Sopenharmony_ci hpios_locked_mem_free(&phw->instream_host_buffers 11538c2ecf20Sopenharmony_ci [phm->obj_index]); 11548c2ecf20Sopenharmony_ci 11558c2ecf20Sopenharmony_ci } else { 11568c2ecf20Sopenharmony_ci /* Should HPI_ERROR_INVALID_OPERATION be returned 11578c2ecf20Sopenharmony_ci if no host buffer is allocated? */ 11588c2ecf20Sopenharmony_ci hpi_init_response(phr, HPI_OBJ_ISTREAM, 11598c2ecf20Sopenharmony_ci HPI_ISTREAM_HOSTBUFFER_FREE, 0); 11608c2ecf20Sopenharmony_ci 11618c2ecf20Sopenharmony_ci } 11628c2ecf20Sopenharmony_ci 11638c2ecf20Sopenharmony_ci} 11648c2ecf20Sopenharmony_ci 11658c2ecf20Sopenharmony_cistatic void instream_start(struct hpi_adapter_obj *pao, 11668c2ecf20Sopenharmony_ci struct hpi_message *phm, struct hpi_response *phr) 11678c2ecf20Sopenharmony_ci{ 11688c2ecf20Sopenharmony_ci hw_message(pao, phm, phr); 11698c2ecf20Sopenharmony_ci} 11708c2ecf20Sopenharmony_ci 11718c2ecf20Sopenharmony_cistatic u32 instream_get_bytes_available(struct hpi_hostbuffer_status *status) 11728c2ecf20Sopenharmony_ci{ 11738c2ecf20Sopenharmony_ci return status->dsp_index - status->host_index; 11748c2ecf20Sopenharmony_ci} 11758c2ecf20Sopenharmony_ci 11768c2ecf20Sopenharmony_cistatic void instream_read(struct hpi_adapter_obj *pao, 11778c2ecf20Sopenharmony_ci struct hpi_message *phm, struct hpi_response *phr) 11788c2ecf20Sopenharmony_ci{ 11798c2ecf20Sopenharmony_ci struct hpi_hw_obj *phw = pao->priv; 11808c2ecf20Sopenharmony_ci struct bus_master_interface *interface = phw->p_interface_buffer; 11818c2ecf20Sopenharmony_ci struct hpi_hostbuffer_status *status; 11828c2ecf20Sopenharmony_ci u32 data_available; 11838c2ecf20Sopenharmony_ci u8 *p_bbm_data; 11848c2ecf20Sopenharmony_ci u32 l_first_read; 11858c2ecf20Sopenharmony_ci u8 *p_app_data = (u8 *)phm->u.d.u.data.pb_data; 11868c2ecf20Sopenharmony_ci 11878c2ecf20Sopenharmony_ci if (!phw->instream_host_buffer_size[phm->obj_index]) { 11888c2ecf20Sopenharmony_ci hw_message(pao, phm, phr); 11898c2ecf20Sopenharmony_ci return; 11908c2ecf20Sopenharmony_ci } 11918c2ecf20Sopenharmony_ci hpi_init_response(phr, phm->object, phm->function, 0); 11928c2ecf20Sopenharmony_ci 11938c2ecf20Sopenharmony_ci status = &interface->instream_host_buffer_status[phm->obj_index]; 11948c2ecf20Sopenharmony_ci data_available = instream_get_bytes_available(status); 11958c2ecf20Sopenharmony_ci if (data_available < phm->u.d.u.data.data_size) { 11968c2ecf20Sopenharmony_ci phr->error = HPI_ERROR_INVALID_DATASIZE; 11978c2ecf20Sopenharmony_ci return; 11988c2ecf20Sopenharmony_ci } 11998c2ecf20Sopenharmony_ci 12008c2ecf20Sopenharmony_ci if (hpios_locked_mem_valid(&phw->instream_host_buffers[phm-> 12018c2ecf20Sopenharmony_ci obj_index])) { 12028c2ecf20Sopenharmony_ci if (hpios_locked_mem_get_virt_addr(&phw-> 12038c2ecf20Sopenharmony_ci instream_host_buffers[phm->obj_index], 12048c2ecf20Sopenharmony_ci (void *)&p_bbm_data)) { 12058c2ecf20Sopenharmony_ci phr->error = HPI_ERROR_INVALID_OPERATION; 12068c2ecf20Sopenharmony_ci return; 12078c2ecf20Sopenharmony_ci } 12088c2ecf20Sopenharmony_ci 12098c2ecf20Sopenharmony_ci /* either all data, 12108c2ecf20Sopenharmony_ci or enough to fit from current to end of BBM buffer */ 12118c2ecf20Sopenharmony_ci l_first_read = 12128c2ecf20Sopenharmony_ci min(phm->u.d.u.data.data_size, 12138c2ecf20Sopenharmony_ci status->size_in_bytes - 12148c2ecf20Sopenharmony_ci (status->host_index & (status->size_in_bytes - 1))); 12158c2ecf20Sopenharmony_ci 12168c2ecf20Sopenharmony_ci memcpy(p_app_data, 12178c2ecf20Sopenharmony_ci p_bbm_data + 12188c2ecf20Sopenharmony_ci (status->host_index & (status->size_in_bytes - 1)), 12198c2ecf20Sopenharmony_ci l_first_read); 12208c2ecf20Sopenharmony_ci /* remaining data if any */ 12218c2ecf20Sopenharmony_ci memcpy(p_app_data + l_first_read, p_bbm_data, 12228c2ecf20Sopenharmony_ci phm->u.d.u.data.data_size - l_first_read); 12238c2ecf20Sopenharmony_ci } 12248c2ecf20Sopenharmony_ci status->host_index += phm->u.d.u.data.data_size; 12258c2ecf20Sopenharmony_ci} 12268c2ecf20Sopenharmony_ci 12278c2ecf20Sopenharmony_cistatic void instream_get_info(struct hpi_adapter_obj *pao, 12288c2ecf20Sopenharmony_ci struct hpi_message *phm, struct hpi_response *phr) 12298c2ecf20Sopenharmony_ci{ 12308c2ecf20Sopenharmony_ci struct hpi_hw_obj *phw = pao->priv; 12318c2ecf20Sopenharmony_ci struct bus_master_interface *interface = phw->p_interface_buffer; 12328c2ecf20Sopenharmony_ci struct hpi_hostbuffer_status *status; 12338c2ecf20Sopenharmony_ci if (!phw->instream_host_buffer_size[phm->obj_index]) { 12348c2ecf20Sopenharmony_ci hw_message(pao, phm, phr); 12358c2ecf20Sopenharmony_ci return; 12368c2ecf20Sopenharmony_ci } 12378c2ecf20Sopenharmony_ci 12388c2ecf20Sopenharmony_ci status = &interface->instream_host_buffer_status[phm->obj_index]; 12398c2ecf20Sopenharmony_ci 12408c2ecf20Sopenharmony_ci hpi_init_response(phr, phm->object, phm->function, 0); 12418c2ecf20Sopenharmony_ci 12428c2ecf20Sopenharmony_ci phr->u.d.u.stream_info.state = (u16)status->stream_state; 12438c2ecf20Sopenharmony_ci phr->u.d.u.stream_info.samples_transferred = 12448c2ecf20Sopenharmony_ci status->samples_processed; 12458c2ecf20Sopenharmony_ci phr->u.d.u.stream_info.buffer_size = status->size_in_bytes; 12468c2ecf20Sopenharmony_ci phr->u.d.u.stream_info.data_available = 12478c2ecf20Sopenharmony_ci instream_get_bytes_available(status); 12488c2ecf20Sopenharmony_ci phr->u.d.u.stream_info.auxiliary_data_available = 12498c2ecf20Sopenharmony_ci status->auxiliary_data_available; 12508c2ecf20Sopenharmony_ci} 12518c2ecf20Sopenharmony_ci 12528c2ecf20Sopenharmony_ci/*****************************************************************************/ 12538c2ecf20Sopenharmony_ci/* LOW-LEVEL */ 12548c2ecf20Sopenharmony_ci#define HPI6205_MAX_FILES_TO_LOAD 2 12558c2ecf20Sopenharmony_ci 12568c2ecf20Sopenharmony_cistatic u16 adapter_boot_load_dsp(struct hpi_adapter_obj *pao, 12578c2ecf20Sopenharmony_ci u32 *pos_error_code) 12588c2ecf20Sopenharmony_ci{ 12598c2ecf20Sopenharmony_ci struct hpi_hw_obj *phw = pao->priv; 12608c2ecf20Sopenharmony_ci struct dsp_code dsp_code; 12618c2ecf20Sopenharmony_ci u16 boot_code_id[HPI6205_MAX_FILES_TO_LOAD]; 12628c2ecf20Sopenharmony_ci u32 temp; 12638c2ecf20Sopenharmony_ci int dsp = 0, i = 0; 12648c2ecf20Sopenharmony_ci u16 err = 0; 12658c2ecf20Sopenharmony_ci 12668c2ecf20Sopenharmony_ci boot_code_id[0] = HPI_ADAPTER_ASI(0x6205); 12678c2ecf20Sopenharmony_ci 12688c2ecf20Sopenharmony_ci boot_code_id[1] = pao->pci.pci_dev->subsystem_device; 12698c2ecf20Sopenharmony_ci boot_code_id[1] = HPI_ADAPTER_FAMILY_ASI(boot_code_id[1]); 12708c2ecf20Sopenharmony_ci 12718c2ecf20Sopenharmony_ci /* fix up cases where bootcode id[1] != subsys id */ 12728c2ecf20Sopenharmony_ci switch (boot_code_id[1]) { 12738c2ecf20Sopenharmony_ci case HPI_ADAPTER_FAMILY_ASI(0x5000): 12748c2ecf20Sopenharmony_ci boot_code_id[0] = boot_code_id[1]; 12758c2ecf20Sopenharmony_ci boot_code_id[1] = 0; 12768c2ecf20Sopenharmony_ci break; 12778c2ecf20Sopenharmony_ci case HPI_ADAPTER_FAMILY_ASI(0x5300): 12788c2ecf20Sopenharmony_ci case HPI_ADAPTER_FAMILY_ASI(0x5400): 12798c2ecf20Sopenharmony_ci case HPI_ADAPTER_FAMILY_ASI(0x6300): 12808c2ecf20Sopenharmony_ci boot_code_id[1] = HPI_ADAPTER_FAMILY_ASI(0x6400); 12818c2ecf20Sopenharmony_ci break; 12828c2ecf20Sopenharmony_ci case HPI_ADAPTER_FAMILY_ASI(0x5500): 12838c2ecf20Sopenharmony_ci case HPI_ADAPTER_FAMILY_ASI(0x5600): 12848c2ecf20Sopenharmony_ci case HPI_ADAPTER_FAMILY_ASI(0x6500): 12858c2ecf20Sopenharmony_ci boot_code_id[1] = HPI_ADAPTER_FAMILY_ASI(0x6600); 12868c2ecf20Sopenharmony_ci break; 12878c2ecf20Sopenharmony_ci case HPI_ADAPTER_FAMILY_ASI(0x8800): 12888c2ecf20Sopenharmony_ci boot_code_id[1] = HPI_ADAPTER_FAMILY_ASI(0x8900); 12898c2ecf20Sopenharmony_ci break; 12908c2ecf20Sopenharmony_ci default: 12918c2ecf20Sopenharmony_ci break; 12928c2ecf20Sopenharmony_ci } 12938c2ecf20Sopenharmony_ci 12948c2ecf20Sopenharmony_ci /* reset DSP by writing a 1 to the WARMRESET bit */ 12958c2ecf20Sopenharmony_ci temp = C6205_HDCR_WARMRESET; 12968c2ecf20Sopenharmony_ci iowrite32(temp, phw->prHDCR); 12978c2ecf20Sopenharmony_ci hpios_delay_micro_seconds(1000); 12988c2ecf20Sopenharmony_ci 12998c2ecf20Sopenharmony_ci /* check that PCI i/f was configured by EEPROM */ 13008c2ecf20Sopenharmony_ci temp = ioread32(phw->prHSR); 13018c2ecf20Sopenharmony_ci if ((temp & (C6205_HSR_CFGERR | C6205_HSR_EEREAD)) != 13028c2ecf20Sopenharmony_ci C6205_HSR_EEREAD) 13038c2ecf20Sopenharmony_ci return HPI6205_ERROR_6205_EEPROM; 13048c2ecf20Sopenharmony_ci temp |= 0x04; 13058c2ecf20Sopenharmony_ci /* disable PINTA interrupt */ 13068c2ecf20Sopenharmony_ci iowrite32(temp, phw->prHSR); 13078c2ecf20Sopenharmony_ci 13088c2ecf20Sopenharmony_ci /* check control register reports PCI boot mode */ 13098c2ecf20Sopenharmony_ci temp = ioread32(phw->prHDCR); 13108c2ecf20Sopenharmony_ci if (!(temp & C6205_HDCR_PCIBOOT)) 13118c2ecf20Sopenharmony_ci return HPI6205_ERROR_6205_REG; 13128c2ecf20Sopenharmony_ci 13138c2ecf20Sopenharmony_ci /* try writing a few numbers to the DSP page register */ 13148c2ecf20Sopenharmony_ci /* and reading them back. */ 13158c2ecf20Sopenharmony_ci temp = 3; 13168c2ecf20Sopenharmony_ci iowrite32(temp, phw->prDSPP); 13178c2ecf20Sopenharmony_ci if ((temp | C6205_DSPP_MAP1) != ioread32(phw->prDSPP)) 13188c2ecf20Sopenharmony_ci return HPI6205_ERROR_6205_DSPPAGE; 13198c2ecf20Sopenharmony_ci temp = 2; 13208c2ecf20Sopenharmony_ci iowrite32(temp, phw->prDSPP); 13218c2ecf20Sopenharmony_ci if ((temp | C6205_DSPP_MAP1) != ioread32(phw->prDSPP)) 13228c2ecf20Sopenharmony_ci return HPI6205_ERROR_6205_DSPPAGE; 13238c2ecf20Sopenharmony_ci temp = 1; 13248c2ecf20Sopenharmony_ci iowrite32(temp, phw->prDSPP); 13258c2ecf20Sopenharmony_ci if ((temp | C6205_DSPP_MAP1) != ioread32(phw->prDSPP)) 13268c2ecf20Sopenharmony_ci return HPI6205_ERROR_6205_DSPPAGE; 13278c2ecf20Sopenharmony_ci /* reset DSP page to the correct number */ 13288c2ecf20Sopenharmony_ci temp = 0; 13298c2ecf20Sopenharmony_ci iowrite32(temp, phw->prDSPP); 13308c2ecf20Sopenharmony_ci if ((temp | C6205_DSPP_MAP1) != ioread32(phw->prDSPP)) 13318c2ecf20Sopenharmony_ci return HPI6205_ERROR_6205_DSPPAGE; 13328c2ecf20Sopenharmony_ci phw->dsp_page = 0; 13338c2ecf20Sopenharmony_ci 13348c2ecf20Sopenharmony_ci /* release 6713 from reset before 6205 is bootloaded. 13358c2ecf20Sopenharmony_ci This ensures that the EMIF is inactive, 13368c2ecf20Sopenharmony_ci and the 6713 HPI gets the correct bootmode etc 13378c2ecf20Sopenharmony_ci */ 13388c2ecf20Sopenharmony_ci if (boot_code_id[1] != 0) { 13398c2ecf20Sopenharmony_ci /* DSP 1 is a C6713 */ 13408c2ecf20Sopenharmony_ci /* CLKX0 <- '1' release the C6205 bootmode pulldowns */ 13418c2ecf20Sopenharmony_ci boot_loader_write_mem32(pao, 0, 0x018C0024, 0x00002202); 13428c2ecf20Sopenharmony_ci hpios_delay_micro_seconds(100); 13438c2ecf20Sopenharmony_ci /* Reset the 6713 #1 - revB */ 13448c2ecf20Sopenharmony_ci boot_loader_write_mem32(pao, 0, C6205_BAR0_TIMER1_CTL, 0); 13458c2ecf20Sopenharmony_ci /* value of bit 3 is unknown after DSP reset, other bits shoudl be 0 */ 13468c2ecf20Sopenharmony_ci if (0 != (boot_loader_read_mem32(pao, 0, 13478c2ecf20Sopenharmony_ci (C6205_BAR0_TIMER1_CTL)) & ~8)) 13488c2ecf20Sopenharmony_ci return HPI6205_ERROR_6205_REG; 13498c2ecf20Sopenharmony_ci hpios_delay_micro_seconds(100); 13508c2ecf20Sopenharmony_ci 13518c2ecf20Sopenharmony_ci /* Release C6713 from reset - revB */ 13528c2ecf20Sopenharmony_ci boot_loader_write_mem32(pao, 0, C6205_BAR0_TIMER1_CTL, 4); 13538c2ecf20Sopenharmony_ci if (4 != (boot_loader_read_mem32(pao, 0, 13548c2ecf20Sopenharmony_ci (C6205_BAR0_TIMER1_CTL)) & ~8)) 13558c2ecf20Sopenharmony_ci return HPI6205_ERROR_6205_REG; 13568c2ecf20Sopenharmony_ci hpios_delay_micro_seconds(100); 13578c2ecf20Sopenharmony_ci } 13588c2ecf20Sopenharmony_ci 13598c2ecf20Sopenharmony_ci for (dsp = 0; dsp < HPI6205_MAX_FILES_TO_LOAD; dsp++) { 13608c2ecf20Sopenharmony_ci /* is there a DSP to load? */ 13618c2ecf20Sopenharmony_ci if (boot_code_id[dsp] == 0) 13628c2ecf20Sopenharmony_ci continue; 13638c2ecf20Sopenharmony_ci 13648c2ecf20Sopenharmony_ci err = boot_loader_config_emif(pao, dsp); 13658c2ecf20Sopenharmony_ci if (err) 13668c2ecf20Sopenharmony_ci return err; 13678c2ecf20Sopenharmony_ci 13688c2ecf20Sopenharmony_ci err = boot_loader_test_internal_memory(pao, dsp); 13698c2ecf20Sopenharmony_ci if (err) 13708c2ecf20Sopenharmony_ci return err; 13718c2ecf20Sopenharmony_ci 13728c2ecf20Sopenharmony_ci err = boot_loader_test_external_memory(pao, dsp); 13738c2ecf20Sopenharmony_ci if (err) 13748c2ecf20Sopenharmony_ci return err; 13758c2ecf20Sopenharmony_ci 13768c2ecf20Sopenharmony_ci err = boot_loader_test_pld(pao, dsp); 13778c2ecf20Sopenharmony_ci if (err) 13788c2ecf20Sopenharmony_ci return err; 13798c2ecf20Sopenharmony_ci 13808c2ecf20Sopenharmony_ci /* write the DSP code down into the DSPs memory */ 13818c2ecf20Sopenharmony_ci err = hpi_dsp_code_open(boot_code_id[dsp], pao->pci.pci_dev, 13828c2ecf20Sopenharmony_ci &dsp_code, pos_error_code); 13838c2ecf20Sopenharmony_ci if (err) 13848c2ecf20Sopenharmony_ci return err; 13858c2ecf20Sopenharmony_ci 13868c2ecf20Sopenharmony_ci while (1) { 13878c2ecf20Sopenharmony_ci u32 length; 13888c2ecf20Sopenharmony_ci u32 address; 13898c2ecf20Sopenharmony_ci u32 type; 13908c2ecf20Sopenharmony_ci u32 *pcode; 13918c2ecf20Sopenharmony_ci 13928c2ecf20Sopenharmony_ci err = hpi_dsp_code_read_word(&dsp_code, &length); 13938c2ecf20Sopenharmony_ci if (err) 13948c2ecf20Sopenharmony_ci break; 13958c2ecf20Sopenharmony_ci if (length == 0xFFFFFFFF) 13968c2ecf20Sopenharmony_ci break; /* end of code */ 13978c2ecf20Sopenharmony_ci 13988c2ecf20Sopenharmony_ci err = hpi_dsp_code_read_word(&dsp_code, &address); 13998c2ecf20Sopenharmony_ci if (err) 14008c2ecf20Sopenharmony_ci break; 14018c2ecf20Sopenharmony_ci err = hpi_dsp_code_read_word(&dsp_code, &type); 14028c2ecf20Sopenharmony_ci if (err) 14038c2ecf20Sopenharmony_ci break; 14048c2ecf20Sopenharmony_ci err = hpi_dsp_code_read_block(length, &dsp_code, 14058c2ecf20Sopenharmony_ci &pcode); 14068c2ecf20Sopenharmony_ci if (err) 14078c2ecf20Sopenharmony_ci break; 14088c2ecf20Sopenharmony_ci for (i = 0; i < (int)length; i++) { 14098c2ecf20Sopenharmony_ci boot_loader_write_mem32(pao, dsp, address, 14108c2ecf20Sopenharmony_ci *pcode); 14118c2ecf20Sopenharmony_ci /* dummy read every 4 words */ 14128c2ecf20Sopenharmony_ci /* for 6205 advisory 1.4.4 */ 14138c2ecf20Sopenharmony_ci if (i % 4 == 0) 14148c2ecf20Sopenharmony_ci boot_loader_read_mem32(pao, dsp, 14158c2ecf20Sopenharmony_ci address); 14168c2ecf20Sopenharmony_ci pcode++; 14178c2ecf20Sopenharmony_ci address += 4; 14188c2ecf20Sopenharmony_ci } 14198c2ecf20Sopenharmony_ci 14208c2ecf20Sopenharmony_ci } 14218c2ecf20Sopenharmony_ci if (err) { 14228c2ecf20Sopenharmony_ci hpi_dsp_code_close(&dsp_code); 14238c2ecf20Sopenharmony_ci return err; 14248c2ecf20Sopenharmony_ci } 14258c2ecf20Sopenharmony_ci 14268c2ecf20Sopenharmony_ci /* verify code */ 14278c2ecf20Sopenharmony_ci hpi_dsp_code_rewind(&dsp_code); 14288c2ecf20Sopenharmony_ci while (1) { 14298c2ecf20Sopenharmony_ci u32 length = 0; 14308c2ecf20Sopenharmony_ci u32 address = 0; 14318c2ecf20Sopenharmony_ci u32 type = 0; 14328c2ecf20Sopenharmony_ci u32 *pcode = NULL; 14338c2ecf20Sopenharmony_ci u32 data = 0; 14348c2ecf20Sopenharmony_ci 14358c2ecf20Sopenharmony_ci hpi_dsp_code_read_word(&dsp_code, &length); 14368c2ecf20Sopenharmony_ci if (length == 0xFFFFFFFF) 14378c2ecf20Sopenharmony_ci break; /* end of code */ 14388c2ecf20Sopenharmony_ci 14398c2ecf20Sopenharmony_ci hpi_dsp_code_read_word(&dsp_code, &address); 14408c2ecf20Sopenharmony_ci hpi_dsp_code_read_word(&dsp_code, &type); 14418c2ecf20Sopenharmony_ci hpi_dsp_code_read_block(length, &dsp_code, &pcode); 14428c2ecf20Sopenharmony_ci 14438c2ecf20Sopenharmony_ci for (i = 0; i < (int)length; i++) { 14448c2ecf20Sopenharmony_ci data = boot_loader_read_mem32(pao, dsp, 14458c2ecf20Sopenharmony_ci address); 14468c2ecf20Sopenharmony_ci if (data != *pcode) { 14478c2ecf20Sopenharmony_ci err = 0; 14488c2ecf20Sopenharmony_ci break; 14498c2ecf20Sopenharmony_ci } 14508c2ecf20Sopenharmony_ci pcode++; 14518c2ecf20Sopenharmony_ci address += 4; 14528c2ecf20Sopenharmony_ci } 14538c2ecf20Sopenharmony_ci if (err) 14548c2ecf20Sopenharmony_ci break; 14558c2ecf20Sopenharmony_ci } 14568c2ecf20Sopenharmony_ci hpi_dsp_code_close(&dsp_code); 14578c2ecf20Sopenharmony_ci if (err) 14588c2ecf20Sopenharmony_ci return err; 14598c2ecf20Sopenharmony_ci } 14608c2ecf20Sopenharmony_ci 14618c2ecf20Sopenharmony_ci /* After bootloading all DSPs, start DSP0 running 14628c2ecf20Sopenharmony_ci * The DSP0 code will handle starting and synchronizing with its slaves 14638c2ecf20Sopenharmony_ci */ 14648c2ecf20Sopenharmony_ci if (phw->p_interface_buffer) { 14658c2ecf20Sopenharmony_ci /* we need to tell the card the physical PCI address */ 14668c2ecf20Sopenharmony_ci u32 physicalPC_iaddress; 14678c2ecf20Sopenharmony_ci struct bus_master_interface *interface = 14688c2ecf20Sopenharmony_ci phw->p_interface_buffer; 14698c2ecf20Sopenharmony_ci u32 host_mailbox_address_on_dsp; 14708c2ecf20Sopenharmony_ci u32 physicalPC_iaddress_verify = 0; 14718c2ecf20Sopenharmony_ci int time_out = 10; 14728c2ecf20Sopenharmony_ci /* set ack so we know when DSP is ready to go */ 14738c2ecf20Sopenharmony_ci /* (dwDspAck will be changed to HIF_RESET) */ 14748c2ecf20Sopenharmony_ci interface->dsp_ack = H620_HIF_UNKNOWN; 14758c2ecf20Sopenharmony_ci wmb(); /* ensure ack is written before dsp writes back */ 14768c2ecf20Sopenharmony_ci 14778c2ecf20Sopenharmony_ci err = hpios_locked_mem_get_phys_addr(&phw->h_locked_mem, 14788c2ecf20Sopenharmony_ci &physicalPC_iaddress); 14798c2ecf20Sopenharmony_ci 14808c2ecf20Sopenharmony_ci /* locate the host mailbox on the DSP. */ 14818c2ecf20Sopenharmony_ci host_mailbox_address_on_dsp = 0x80000000; 14828c2ecf20Sopenharmony_ci while ((physicalPC_iaddress != physicalPC_iaddress_verify) 14838c2ecf20Sopenharmony_ci && time_out--) { 14848c2ecf20Sopenharmony_ci boot_loader_write_mem32(pao, 0, 14858c2ecf20Sopenharmony_ci host_mailbox_address_on_dsp, 14868c2ecf20Sopenharmony_ci physicalPC_iaddress); 14878c2ecf20Sopenharmony_ci physicalPC_iaddress_verify = 14888c2ecf20Sopenharmony_ci boot_loader_read_mem32(pao, 0, 14898c2ecf20Sopenharmony_ci host_mailbox_address_on_dsp); 14908c2ecf20Sopenharmony_ci } 14918c2ecf20Sopenharmony_ci } 14928c2ecf20Sopenharmony_ci HPI_DEBUG_LOG(DEBUG, "starting DS_ps running\n"); 14938c2ecf20Sopenharmony_ci /* enable interrupts */ 14948c2ecf20Sopenharmony_ci temp = ioread32(phw->prHSR); 14958c2ecf20Sopenharmony_ci temp &= ~(u32)C6205_HSR_INTAM; 14968c2ecf20Sopenharmony_ci iowrite32(temp, phw->prHSR); 14978c2ecf20Sopenharmony_ci 14988c2ecf20Sopenharmony_ci /* start code running... */ 14998c2ecf20Sopenharmony_ci temp = ioread32(phw->prHDCR); 15008c2ecf20Sopenharmony_ci temp |= (u32)C6205_HDCR_DSPINT; 15018c2ecf20Sopenharmony_ci iowrite32(temp, phw->prHDCR); 15028c2ecf20Sopenharmony_ci 15038c2ecf20Sopenharmony_ci /* give the DSP 10ms to start up */ 15048c2ecf20Sopenharmony_ci hpios_delay_micro_seconds(10000); 15058c2ecf20Sopenharmony_ci return err; 15068c2ecf20Sopenharmony_ci 15078c2ecf20Sopenharmony_ci} 15088c2ecf20Sopenharmony_ci 15098c2ecf20Sopenharmony_ci/*****************************************************************************/ 15108c2ecf20Sopenharmony_ci/* Bootloader utility functions */ 15118c2ecf20Sopenharmony_ci 15128c2ecf20Sopenharmony_cistatic u32 boot_loader_read_mem32(struct hpi_adapter_obj *pao, int dsp_index, 15138c2ecf20Sopenharmony_ci u32 address) 15148c2ecf20Sopenharmony_ci{ 15158c2ecf20Sopenharmony_ci struct hpi_hw_obj *phw = pao->priv; 15168c2ecf20Sopenharmony_ci u32 data = 0; 15178c2ecf20Sopenharmony_ci __iomem u32 *p_data; 15188c2ecf20Sopenharmony_ci 15198c2ecf20Sopenharmony_ci if (dsp_index == 0) { 15208c2ecf20Sopenharmony_ci /* DSP 0 is always C6205 */ 15218c2ecf20Sopenharmony_ci if ((address >= 0x01800000) & (address < 0x02000000)) { 15228c2ecf20Sopenharmony_ci /* BAR1 register access */ 15238c2ecf20Sopenharmony_ci p_data = pao->pci.ap_mem_base[1] + 15248c2ecf20Sopenharmony_ci (address & 0x007fffff) / 15258c2ecf20Sopenharmony_ci sizeof(*pao->pci.ap_mem_base[1]); 15268c2ecf20Sopenharmony_ci /* HPI_DEBUG_LOG(WARNING, 15278c2ecf20Sopenharmony_ci "BAR1 access %08x\n", dwAddress); */ 15288c2ecf20Sopenharmony_ci } else { 15298c2ecf20Sopenharmony_ci u32 dw4M_page = address >> 22L; 15308c2ecf20Sopenharmony_ci if (dw4M_page != phw->dsp_page) { 15318c2ecf20Sopenharmony_ci phw->dsp_page = dw4M_page; 15328c2ecf20Sopenharmony_ci /* *INDENT OFF* */ 15338c2ecf20Sopenharmony_ci iowrite32(phw->dsp_page, phw->prDSPP); 15348c2ecf20Sopenharmony_ci /* *INDENT-ON* */ 15358c2ecf20Sopenharmony_ci } 15368c2ecf20Sopenharmony_ci address &= 0x3fffff; /* address within 4M page */ 15378c2ecf20Sopenharmony_ci /* BAR0 memory access */ 15388c2ecf20Sopenharmony_ci p_data = pao->pci.ap_mem_base[0] + 15398c2ecf20Sopenharmony_ci address / sizeof(u32); 15408c2ecf20Sopenharmony_ci } 15418c2ecf20Sopenharmony_ci data = ioread32(p_data); 15428c2ecf20Sopenharmony_ci } else if (dsp_index == 1) { 15438c2ecf20Sopenharmony_ci /* DSP 1 is a C6713 */ 15448c2ecf20Sopenharmony_ci u32 lsb; 15458c2ecf20Sopenharmony_ci boot_loader_write_mem32(pao, 0, HPIAL_ADDR, address); 15468c2ecf20Sopenharmony_ci boot_loader_write_mem32(pao, 0, HPIAH_ADDR, address >> 16); 15478c2ecf20Sopenharmony_ci lsb = boot_loader_read_mem32(pao, 0, HPIDL_ADDR); 15488c2ecf20Sopenharmony_ci data = boot_loader_read_mem32(pao, 0, HPIDH_ADDR); 15498c2ecf20Sopenharmony_ci data = (data << 16) | (lsb & 0xFFFF); 15508c2ecf20Sopenharmony_ci } 15518c2ecf20Sopenharmony_ci return data; 15528c2ecf20Sopenharmony_ci} 15538c2ecf20Sopenharmony_ci 15548c2ecf20Sopenharmony_cistatic void boot_loader_write_mem32(struct hpi_adapter_obj *pao, 15558c2ecf20Sopenharmony_ci int dsp_index, u32 address, u32 data) 15568c2ecf20Sopenharmony_ci{ 15578c2ecf20Sopenharmony_ci struct hpi_hw_obj *phw = pao->priv; 15588c2ecf20Sopenharmony_ci __iomem u32 *p_data; 15598c2ecf20Sopenharmony_ci /* u32 dwVerifyData=0; */ 15608c2ecf20Sopenharmony_ci 15618c2ecf20Sopenharmony_ci if (dsp_index == 0) { 15628c2ecf20Sopenharmony_ci /* DSP 0 is always C6205 */ 15638c2ecf20Sopenharmony_ci if ((address >= 0x01800000) & (address < 0x02000000)) { 15648c2ecf20Sopenharmony_ci /* BAR1 - DSP register access using */ 15658c2ecf20Sopenharmony_ci /* Non-prefetchable PCI access */ 15668c2ecf20Sopenharmony_ci p_data = pao->pci.ap_mem_base[1] + 15678c2ecf20Sopenharmony_ci (address & 0x007fffff) / 15688c2ecf20Sopenharmony_ci sizeof(*pao->pci.ap_mem_base[1]); 15698c2ecf20Sopenharmony_ci } else { 15708c2ecf20Sopenharmony_ci /* BAR0 access - all of DSP memory using */ 15718c2ecf20Sopenharmony_ci /* pre-fetchable PCI access */ 15728c2ecf20Sopenharmony_ci u32 dw4M_page = address >> 22L; 15738c2ecf20Sopenharmony_ci if (dw4M_page != phw->dsp_page) { 15748c2ecf20Sopenharmony_ci phw->dsp_page = dw4M_page; 15758c2ecf20Sopenharmony_ci /* *INDENT-OFF* */ 15768c2ecf20Sopenharmony_ci iowrite32(phw->dsp_page, phw->prDSPP); 15778c2ecf20Sopenharmony_ci /* *INDENT-ON* */ 15788c2ecf20Sopenharmony_ci } 15798c2ecf20Sopenharmony_ci address &= 0x3fffff; /* address within 4M page */ 15808c2ecf20Sopenharmony_ci p_data = pao->pci.ap_mem_base[0] + 15818c2ecf20Sopenharmony_ci address / sizeof(u32); 15828c2ecf20Sopenharmony_ci } 15838c2ecf20Sopenharmony_ci iowrite32(data, p_data); 15848c2ecf20Sopenharmony_ci } else if (dsp_index == 1) { 15858c2ecf20Sopenharmony_ci /* DSP 1 is a C6713 */ 15868c2ecf20Sopenharmony_ci boot_loader_write_mem32(pao, 0, HPIAL_ADDR, address); 15878c2ecf20Sopenharmony_ci boot_loader_write_mem32(pao, 0, HPIAH_ADDR, address >> 16); 15888c2ecf20Sopenharmony_ci 15898c2ecf20Sopenharmony_ci /* dummy read every 4 words for 6205 advisory 1.4.4 */ 15908c2ecf20Sopenharmony_ci boot_loader_read_mem32(pao, 0, 0); 15918c2ecf20Sopenharmony_ci 15928c2ecf20Sopenharmony_ci boot_loader_write_mem32(pao, 0, HPIDL_ADDR, data); 15938c2ecf20Sopenharmony_ci boot_loader_write_mem32(pao, 0, HPIDH_ADDR, data >> 16); 15948c2ecf20Sopenharmony_ci 15958c2ecf20Sopenharmony_ci /* dummy read every 4 words for 6205 advisory 1.4.4 */ 15968c2ecf20Sopenharmony_ci boot_loader_read_mem32(pao, 0, 0); 15978c2ecf20Sopenharmony_ci } 15988c2ecf20Sopenharmony_ci} 15998c2ecf20Sopenharmony_ci 16008c2ecf20Sopenharmony_cistatic u16 boot_loader_config_emif(struct hpi_adapter_obj *pao, int dsp_index) 16018c2ecf20Sopenharmony_ci{ 16028c2ecf20Sopenharmony_ci if (dsp_index == 0) { 16038c2ecf20Sopenharmony_ci u32 setting; 16048c2ecf20Sopenharmony_ci 16058c2ecf20Sopenharmony_ci /* DSP 0 is always C6205 */ 16068c2ecf20Sopenharmony_ci 16078c2ecf20Sopenharmony_ci /* Set the EMIF */ 16088c2ecf20Sopenharmony_ci /* memory map of C6205 */ 16098c2ecf20Sopenharmony_ci /* 00000000-0000FFFF 16Kx32 internal program */ 16108c2ecf20Sopenharmony_ci /* 00400000-00BFFFFF CE0 2Mx32 SDRAM running @ 100MHz */ 16118c2ecf20Sopenharmony_ci 16128c2ecf20Sopenharmony_ci /* EMIF config */ 16138c2ecf20Sopenharmony_ci /*------------ */ 16148c2ecf20Sopenharmony_ci /* Global EMIF control */ 16158c2ecf20Sopenharmony_ci boot_loader_write_mem32(pao, dsp_index, 0x01800000, 0x3779); 16168c2ecf20Sopenharmony_ci#define WS_OFS 28 16178c2ecf20Sopenharmony_ci#define WST_OFS 22 16188c2ecf20Sopenharmony_ci#define WH_OFS 20 16198c2ecf20Sopenharmony_ci#define RS_OFS 16 16208c2ecf20Sopenharmony_ci#define RST_OFS 8 16218c2ecf20Sopenharmony_ci#define MTYPE_OFS 4 16228c2ecf20Sopenharmony_ci#define RH_OFS 0 16238c2ecf20Sopenharmony_ci 16248c2ecf20Sopenharmony_ci /* EMIF CE0 setup - 2Mx32 Sync DRAM on ASI5000 cards only */ 16258c2ecf20Sopenharmony_ci setting = 0x00000030; 16268c2ecf20Sopenharmony_ci boot_loader_write_mem32(pao, dsp_index, 0x01800008, setting); 16278c2ecf20Sopenharmony_ci if (setting != boot_loader_read_mem32(pao, dsp_index, 16288c2ecf20Sopenharmony_ci 0x01800008)) 16298c2ecf20Sopenharmony_ci return HPI6205_ERROR_DSP_EMIF1; 16308c2ecf20Sopenharmony_ci 16318c2ecf20Sopenharmony_ci /* EMIF CE1 setup - 32 bit async. This is 6713 #1 HPI, */ 16328c2ecf20Sopenharmony_ci /* which occupies D15..0. 6713 starts at 27MHz, so need */ 16338c2ecf20Sopenharmony_ci /* plenty of wait states. See dsn8701.rtf, and 6713 errata. */ 16348c2ecf20Sopenharmony_ci /* WST should be 71, but 63 is max possible */ 16358c2ecf20Sopenharmony_ci setting = 16368c2ecf20Sopenharmony_ci (1L << WS_OFS) | (63L << WST_OFS) | (1L << WH_OFS) | 16378c2ecf20Sopenharmony_ci (1L << RS_OFS) | (63L << RST_OFS) | (1L << RH_OFS) | 16388c2ecf20Sopenharmony_ci (2L << MTYPE_OFS); 16398c2ecf20Sopenharmony_ci boot_loader_write_mem32(pao, dsp_index, 0x01800004, setting); 16408c2ecf20Sopenharmony_ci if (setting != boot_loader_read_mem32(pao, dsp_index, 16418c2ecf20Sopenharmony_ci 0x01800004)) 16428c2ecf20Sopenharmony_ci return HPI6205_ERROR_DSP_EMIF2; 16438c2ecf20Sopenharmony_ci 16448c2ecf20Sopenharmony_ci /* EMIF CE2 setup - 32 bit async. This is 6713 #2 HPI, */ 16458c2ecf20Sopenharmony_ci /* which occupies D15..0. 6713 starts at 27MHz, so need */ 16468c2ecf20Sopenharmony_ci /* plenty of wait states */ 16478c2ecf20Sopenharmony_ci setting = 16488c2ecf20Sopenharmony_ci (1L << WS_OFS) | (28L << WST_OFS) | (1L << WH_OFS) | 16498c2ecf20Sopenharmony_ci (1L << RS_OFS) | (63L << RST_OFS) | (1L << RH_OFS) | 16508c2ecf20Sopenharmony_ci (2L << MTYPE_OFS); 16518c2ecf20Sopenharmony_ci boot_loader_write_mem32(pao, dsp_index, 0x01800010, setting); 16528c2ecf20Sopenharmony_ci if (setting != boot_loader_read_mem32(pao, dsp_index, 16538c2ecf20Sopenharmony_ci 0x01800010)) 16548c2ecf20Sopenharmony_ci return HPI6205_ERROR_DSP_EMIF3; 16558c2ecf20Sopenharmony_ci 16568c2ecf20Sopenharmony_ci /* EMIF CE3 setup - 32 bit async. */ 16578c2ecf20Sopenharmony_ci /* This is the PLD on the ASI5000 cards only */ 16588c2ecf20Sopenharmony_ci setting = 16598c2ecf20Sopenharmony_ci (1L << WS_OFS) | (10L << WST_OFS) | (1L << WH_OFS) | 16608c2ecf20Sopenharmony_ci (1L << RS_OFS) | (10L << RST_OFS) | (1L << RH_OFS) | 16618c2ecf20Sopenharmony_ci (2L << MTYPE_OFS); 16628c2ecf20Sopenharmony_ci boot_loader_write_mem32(pao, dsp_index, 0x01800014, setting); 16638c2ecf20Sopenharmony_ci if (setting != boot_loader_read_mem32(pao, dsp_index, 16648c2ecf20Sopenharmony_ci 0x01800014)) 16658c2ecf20Sopenharmony_ci return HPI6205_ERROR_DSP_EMIF4; 16668c2ecf20Sopenharmony_ci 16678c2ecf20Sopenharmony_ci /* set EMIF SDRAM control for 2Mx32 SDRAM (512x32x4 bank) */ 16688c2ecf20Sopenharmony_ci /* need to use this else DSP code crashes? */ 16698c2ecf20Sopenharmony_ci boot_loader_write_mem32(pao, dsp_index, 0x01800018, 16708c2ecf20Sopenharmony_ci 0x07117000); 16718c2ecf20Sopenharmony_ci 16728c2ecf20Sopenharmony_ci /* EMIF SDRAM Refresh Timing */ 16738c2ecf20Sopenharmony_ci /* EMIF SDRAM timing (orig = 0x410, emulator = 0x61a) */ 16748c2ecf20Sopenharmony_ci boot_loader_write_mem32(pao, dsp_index, 0x0180001C, 16758c2ecf20Sopenharmony_ci 0x00000410); 16768c2ecf20Sopenharmony_ci 16778c2ecf20Sopenharmony_ci } else if (dsp_index == 1) { 16788c2ecf20Sopenharmony_ci /* test access to the C6713s HPI registers */ 16798c2ecf20Sopenharmony_ci u32 write_data = 0, read_data = 0, i = 0; 16808c2ecf20Sopenharmony_ci 16818c2ecf20Sopenharmony_ci /* Set up HPIC for little endian, by setiing HPIC:HWOB=1 */ 16828c2ecf20Sopenharmony_ci write_data = 1; 16838c2ecf20Sopenharmony_ci boot_loader_write_mem32(pao, 0, HPICL_ADDR, write_data); 16848c2ecf20Sopenharmony_ci boot_loader_write_mem32(pao, 0, HPICH_ADDR, write_data); 16858c2ecf20Sopenharmony_ci /* C67 HPI is on lower 16bits of 32bit EMIF */ 16868c2ecf20Sopenharmony_ci read_data = 16878c2ecf20Sopenharmony_ci 0xFFF7 & boot_loader_read_mem32(pao, 0, HPICL_ADDR); 16888c2ecf20Sopenharmony_ci if (write_data != read_data) { 16898c2ecf20Sopenharmony_ci HPI_DEBUG_LOG(ERROR, "HPICL %x %x\n", write_data, 16908c2ecf20Sopenharmony_ci read_data); 16918c2ecf20Sopenharmony_ci return HPI6205_ERROR_C6713_HPIC; 16928c2ecf20Sopenharmony_ci } 16938c2ecf20Sopenharmony_ci /* HPIA - walking ones test */ 16948c2ecf20Sopenharmony_ci write_data = 1; 16958c2ecf20Sopenharmony_ci for (i = 0; i < 32; i++) { 16968c2ecf20Sopenharmony_ci boot_loader_write_mem32(pao, 0, HPIAL_ADDR, 16978c2ecf20Sopenharmony_ci write_data); 16988c2ecf20Sopenharmony_ci boot_loader_write_mem32(pao, 0, HPIAH_ADDR, 16998c2ecf20Sopenharmony_ci (write_data >> 16)); 17008c2ecf20Sopenharmony_ci read_data = 17018c2ecf20Sopenharmony_ci 0xFFFF & boot_loader_read_mem32(pao, 0, 17028c2ecf20Sopenharmony_ci HPIAL_ADDR); 17038c2ecf20Sopenharmony_ci read_data = 17048c2ecf20Sopenharmony_ci read_data | ((0xFFFF & 17058c2ecf20Sopenharmony_ci boot_loader_read_mem32(pao, 0, 17068c2ecf20Sopenharmony_ci HPIAH_ADDR)) 17078c2ecf20Sopenharmony_ci << 16); 17088c2ecf20Sopenharmony_ci if (read_data != write_data) { 17098c2ecf20Sopenharmony_ci HPI_DEBUG_LOG(ERROR, "HPIA %x %x\n", 17108c2ecf20Sopenharmony_ci write_data, read_data); 17118c2ecf20Sopenharmony_ci return HPI6205_ERROR_C6713_HPIA; 17128c2ecf20Sopenharmony_ci } 17138c2ecf20Sopenharmony_ci write_data = write_data << 1; 17148c2ecf20Sopenharmony_ci } 17158c2ecf20Sopenharmony_ci 17168c2ecf20Sopenharmony_ci /* setup C67x PLL 17178c2ecf20Sopenharmony_ci * ** C6713 datasheet says we cannot program PLL from HPI, 17188c2ecf20Sopenharmony_ci * and indeed if we try to set the PLL multiply from the HPI, 17198c2ecf20Sopenharmony_ci * the PLL does not seem to lock, so we enable the PLL and 17208c2ecf20Sopenharmony_ci * use the default multiply of x 7, which for a 27MHz clock 17218c2ecf20Sopenharmony_ci * gives a DSP speed of 189MHz 17228c2ecf20Sopenharmony_ci */ 17238c2ecf20Sopenharmony_ci /* bypass PLL */ 17248c2ecf20Sopenharmony_ci boot_loader_write_mem32(pao, dsp_index, 0x01B7C100, 0x0000); 17258c2ecf20Sopenharmony_ci hpios_delay_micro_seconds(1000); 17268c2ecf20Sopenharmony_ci /* EMIF = 189/3=63MHz */ 17278c2ecf20Sopenharmony_ci boot_loader_write_mem32(pao, dsp_index, 0x01B7C120, 0x8002); 17288c2ecf20Sopenharmony_ci /* peri = 189/2 */ 17298c2ecf20Sopenharmony_ci boot_loader_write_mem32(pao, dsp_index, 0x01B7C11C, 0x8001); 17308c2ecf20Sopenharmony_ci /* cpu = 189/1 */ 17318c2ecf20Sopenharmony_ci boot_loader_write_mem32(pao, dsp_index, 0x01B7C118, 0x8000); 17328c2ecf20Sopenharmony_ci hpios_delay_micro_seconds(1000); 17338c2ecf20Sopenharmony_ci /* ** SGT test to take GPO3 high when we start the PLL */ 17348c2ecf20Sopenharmony_ci /* and low when the delay is completed */ 17358c2ecf20Sopenharmony_ci /* FSX0 <- '1' (GPO3) */ 17368c2ecf20Sopenharmony_ci boot_loader_write_mem32(pao, 0, (0x018C0024L), 0x00002A0A); 17378c2ecf20Sopenharmony_ci /* PLL not bypassed */ 17388c2ecf20Sopenharmony_ci boot_loader_write_mem32(pao, dsp_index, 0x01B7C100, 0x0001); 17398c2ecf20Sopenharmony_ci hpios_delay_micro_seconds(1000); 17408c2ecf20Sopenharmony_ci /* FSX0 <- '0' (GPO3) */ 17418c2ecf20Sopenharmony_ci boot_loader_write_mem32(pao, 0, (0x018C0024L), 0x00002A02); 17428c2ecf20Sopenharmony_ci 17438c2ecf20Sopenharmony_ci /* 6205 EMIF CE1 resetup - 32 bit async. */ 17448c2ecf20Sopenharmony_ci /* Now 6713 #1 is running at 189MHz can reduce waitstates */ 17458c2ecf20Sopenharmony_ci boot_loader_write_mem32(pao, 0, 0x01800004, /* CE1 */ 17468c2ecf20Sopenharmony_ci (1L << WS_OFS) | (8L << WST_OFS) | (1L << WH_OFS) | 17478c2ecf20Sopenharmony_ci (1L << RS_OFS) | (12L << RST_OFS) | (1L << RH_OFS) | 17488c2ecf20Sopenharmony_ci (2L << MTYPE_OFS)); 17498c2ecf20Sopenharmony_ci 17508c2ecf20Sopenharmony_ci hpios_delay_micro_seconds(1000); 17518c2ecf20Sopenharmony_ci 17528c2ecf20Sopenharmony_ci /* check that we can read one of the PLL registers */ 17538c2ecf20Sopenharmony_ci /* PLL should not be bypassed! */ 17548c2ecf20Sopenharmony_ci if ((boot_loader_read_mem32(pao, dsp_index, 0x01B7C100) & 0xF) 17558c2ecf20Sopenharmony_ci != 0x0001) { 17568c2ecf20Sopenharmony_ci return HPI6205_ERROR_C6713_PLL; 17578c2ecf20Sopenharmony_ci } 17588c2ecf20Sopenharmony_ci /* setup C67x EMIF (note this is the only use of 17598c2ecf20Sopenharmony_ci BAR1 via BootLoader_WriteMem32) */ 17608c2ecf20Sopenharmony_ci boot_loader_write_mem32(pao, dsp_index, C6713_EMIF_GCTL, 17618c2ecf20Sopenharmony_ci 0x000034A8); 17628c2ecf20Sopenharmony_ci 17638c2ecf20Sopenharmony_ci /* EMIF CE0 setup - 2Mx32 Sync DRAM 17648c2ecf20Sopenharmony_ci 31..28 Wr setup 17658c2ecf20Sopenharmony_ci 27..22 Wr strobe 17668c2ecf20Sopenharmony_ci 21..20 Wr hold 17678c2ecf20Sopenharmony_ci 19..16 Rd setup 17688c2ecf20Sopenharmony_ci 15..14 - 17698c2ecf20Sopenharmony_ci 13..8 Rd strobe 17708c2ecf20Sopenharmony_ci 7..4 MTYPE 0011 Sync DRAM 32bits 17718c2ecf20Sopenharmony_ci 3 Wr hold MSB 17728c2ecf20Sopenharmony_ci 2..0 Rd hold 17738c2ecf20Sopenharmony_ci */ 17748c2ecf20Sopenharmony_ci boot_loader_write_mem32(pao, dsp_index, C6713_EMIF_CE0, 17758c2ecf20Sopenharmony_ci 0x00000030); 17768c2ecf20Sopenharmony_ci 17778c2ecf20Sopenharmony_ci /* EMIF SDRAM Extension 17788c2ecf20Sopenharmony_ci 0x00 17798c2ecf20Sopenharmony_ci 31-21 0000b 0000b 000b 17808c2ecf20Sopenharmony_ci 20 WR2RD = 2cycles-1 = 1b 17818c2ecf20Sopenharmony_ci 17828c2ecf20Sopenharmony_ci 19-18 WR2DEAC = 3cycle-1 = 10b 17838c2ecf20Sopenharmony_ci 17 WR2WR = 2cycle-1 = 1b 17848c2ecf20Sopenharmony_ci 16-15 R2WDQM = 4cycle-1 = 11b 17858c2ecf20Sopenharmony_ci 14-12 RD2WR = 6cycles-1 = 101b 17868c2ecf20Sopenharmony_ci 17878c2ecf20Sopenharmony_ci 11-10 RD2DEAC = 4cycle-1 = 11b 17888c2ecf20Sopenharmony_ci 9 RD2RD = 2cycle-1 = 1b 17898c2ecf20Sopenharmony_ci 8-7 THZP = 3cycle-1 = 10b 17908c2ecf20Sopenharmony_ci 6-5 TWR = 2cycle-1 = 01b (tWR = 17ns) 17918c2ecf20Sopenharmony_ci 4 TRRD = 2cycle = 0b (tRRD = 14ns) 17928c2ecf20Sopenharmony_ci 3-1 TRAS = 5cycle-1 = 100b (Tras=42ns) 17938c2ecf20Sopenharmony_ci 1 CAS latency = 3cyc = 1b 17948c2ecf20Sopenharmony_ci (for Micron 2M32-7 operating at 100MHz) 17958c2ecf20Sopenharmony_ci */ 17968c2ecf20Sopenharmony_ci boot_loader_write_mem32(pao, dsp_index, C6713_EMIF_SDRAMEXT, 17978c2ecf20Sopenharmony_ci 0x001BDF29); 17988c2ecf20Sopenharmony_ci 17998c2ecf20Sopenharmony_ci /* EMIF SDRAM control - set up for a 2Mx32 SDRAM (512x32x4 bank) 18008c2ecf20Sopenharmony_ci 31 - 0b - 18018c2ecf20Sopenharmony_ci 30 SDBSZ 1b 4 bank 18028c2ecf20Sopenharmony_ci 29..28 SDRSZ 00b 11 row address pins 18038c2ecf20Sopenharmony_ci 18048c2ecf20Sopenharmony_ci 27..26 SDCSZ 01b 8 column address pins 18058c2ecf20Sopenharmony_ci 25 RFEN 1b refersh enabled 18068c2ecf20Sopenharmony_ci 24 INIT 1b init SDRAM! 18078c2ecf20Sopenharmony_ci 18088c2ecf20Sopenharmony_ci 23..20 TRCD 0001b (Trcd/Tcyc)-1 = (20/10)-1 = 1 18098c2ecf20Sopenharmony_ci 18108c2ecf20Sopenharmony_ci 19..16 TRP 0001b (Trp/Tcyc)-1 = (20/10)-1 = 1 18118c2ecf20Sopenharmony_ci 18128c2ecf20Sopenharmony_ci 15..12 TRC 0110b (Trc/Tcyc)-1 = (70/10)-1 = 6 18138c2ecf20Sopenharmony_ci 18148c2ecf20Sopenharmony_ci 11..0 - 0000b 0000b 0000b 18158c2ecf20Sopenharmony_ci */ 18168c2ecf20Sopenharmony_ci boot_loader_write_mem32(pao, dsp_index, C6713_EMIF_SDRAMCTL, 18178c2ecf20Sopenharmony_ci 0x47116000); 18188c2ecf20Sopenharmony_ci 18198c2ecf20Sopenharmony_ci /* SDRAM refresh timing 18208c2ecf20Sopenharmony_ci Need 4,096 refresh cycles every 64ms = 15.625us = 1562cycles of 100MHz = 0x61A 18218c2ecf20Sopenharmony_ci */ 18228c2ecf20Sopenharmony_ci boot_loader_write_mem32(pao, dsp_index, 18238c2ecf20Sopenharmony_ci C6713_EMIF_SDRAMTIMING, 0x00000410); 18248c2ecf20Sopenharmony_ci 18258c2ecf20Sopenharmony_ci hpios_delay_micro_seconds(1000); 18268c2ecf20Sopenharmony_ci } else if (dsp_index == 2) { 18278c2ecf20Sopenharmony_ci /* DSP 2 is a C6713 */ 18288c2ecf20Sopenharmony_ci } 18298c2ecf20Sopenharmony_ci 18308c2ecf20Sopenharmony_ci return 0; 18318c2ecf20Sopenharmony_ci} 18328c2ecf20Sopenharmony_ci 18338c2ecf20Sopenharmony_cistatic u16 boot_loader_test_memory(struct hpi_adapter_obj *pao, int dsp_index, 18348c2ecf20Sopenharmony_ci u32 start_address, u32 length) 18358c2ecf20Sopenharmony_ci{ 18368c2ecf20Sopenharmony_ci u32 i = 0, j = 0; 18378c2ecf20Sopenharmony_ci u32 test_addr = 0; 18388c2ecf20Sopenharmony_ci u32 test_data = 0, data = 0; 18398c2ecf20Sopenharmony_ci 18408c2ecf20Sopenharmony_ci length = 1000; 18418c2ecf20Sopenharmony_ci 18428c2ecf20Sopenharmony_ci /* for 1st word, test each bit in the 32bit word, */ 18438c2ecf20Sopenharmony_ci /* dwLength specifies number of 32bit words to test */ 18448c2ecf20Sopenharmony_ci /*for(i=0; i<dwLength; i++) */ 18458c2ecf20Sopenharmony_ci i = 0; 18468c2ecf20Sopenharmony_ci { 18478c2ecf20Sopenharmony_ci test_addr = start_address + i * 4; 18488c2ecf20Sopenharmony_ci test_data = 0x00000001; 18498c2ecf20Sopenharmony_ci for (j = 0; j < 32; j++) { 18508c2ecf20Sopenharmony_ci boot_loader_write_mem32(pao, dsp_index, test_addr, 18518c2ecf20Sopenharmony_ci test_data); 18528c2ecf20Sopenharmony_ci data = boot_loader_read_mem32(pao, dsp_index, 18538c2ecf20Sopenharmony_ci test_addr); 18548c2ecf20Sopenharmony_ci if (data != test_data) { 18558c2ecf20Sopenharmony_ci HPI_DEBUG_LOG(VERBOSE, 18568c2ecf20Sopenharmony_ci "Memtest error details " 18578c2ecf20Sopenharmony_ci "%08x %08x %08x %i\n", test_addr, 18588c2ecf20Sopenharmony_ci test_data, data, dsp_index); 18598c2ecf20Sopenharmony_ci return 1; /* error */ 18608c2ecf20Sopenharmony_ci } 18618c2ecf20Sopenharmony_ci test_data = test_data << 1; 18628c2ecf20Sopenharmony_ci } /* for(j) */ 18638c2ecf20Sopenharmony_ci } /* for(i) */ 18648c2ecf20Sopenharmony_ci 18658c2ecf20Sopenharmony_ci /* for the next 100 locations test each location, leaving it as zero */ 18668c2ecf20Sopenharmony_ci /* write a zero to the next word in memory before we read */ 18678c2ecf20Sopenharmony_ci /* the previous write to make sure every memory location is unique */ 18688c2ecf20Sopenharmony_ci for (i = 0; i < 100; i++) { 18698c2ecf20Sopenharmony_ci test_addr = start_address + i * 4; 18708c2ecf20Sopenharmony_ci test_data = 0xA5A55A5A; 18718c2ecf20Sopenharmony_ci boot_loader_write_mem32(pao, dsp_index, test_addr, test_data); 18728c2ecf20Sopenharmony_ci boot_loader_write_mem32(pao, dsp_index, test_addr + 4, 0); 18738c2ecf20Sopenharmony_ci data = boot_loader_read_mem32(pao, dsp_index, test_addr); 18748c2ecf20Sopenharmony_ci if (data != test_data) { 18758c2ecf20Sopenharmony_ci HPI_DEBUG_LOG(VERBOSE, 18768c2ecf20Sopenharmony_ci "Memtest error details " 18778c2ecf20Sopenharmony_ci "%08x %08x %08x %i\n", test_addr, test_data, 18788c2ecf20Sopenharmony_ci data, dsp_index); 18798c2ecf20Sopenharmony_ci return 1; /* error */ 18808c2ecf20Sopenharmony_ci } 18818c2ecf20Sopenharmony_ci /* leave location as zero */ 18828c2ecf20Sopenharmony_ci boot_loader_write_mem32(pao, dsp_index, test_addr, 0x0); 18838c2ecf20Sopenharmony_ci } 18848c2ecf20Sopenharmony_ci 18858c2ecf20Sopenharmony_ci /* zero out entire memory block */ 18868c2ecf20Sopenharmony_ci for (i = 0; i < length; i++) { 18878c2ecf20Sopenharmony_ci test_addr = start_address + i * 4; 18888c2ecf20Sopenharmony_ci boot_loader_write_mem32(pao, dsp_index, test_addr, 0x0); 18898c2ecf20Sopenharmony_ci } 18908c2ecf20Sopenharmony_ci return 0; 18918c2ecf20Sopenharmony_ci} 18928c2ecf20Sopenharmony_ci 18938c2ecf20Sopenharmony_cistatic u16 boot_loader_test_internal_memory(struct hpi_adapter_obj *pao, 18948c2ecf20Sopenharmony_ci int dsp_index) 18958c2ecf20Sopenharmony_ci{ 18968c2ecf20Sopenharmony_ci int err = 0; 18978c2ecf20Sopenharmony_ci if (dsp_index == 0) { 18988c2ecf20Sopenharmony_ci /* DSP 0 is a C6205 */ 18998c2ecf20Sopenharmony_ci /* 64K prog mem */ 19008c2ecf20Sopenharmony_ci err = boot_loader_test_memory(pao, dsp_index, 0x00000000, 19018c2ecf20Sopenharmony_ci 0x10000); 19028c2ecf20Sopenharmony_ci if (!err) 19038c2ecf20Sopenharmony_ci /* 64K data mem */ 19048c2ecf20Sopenharmony_ci err = boot_loader_test_memory(pao, dsp_index, 19058c2ecf20Sopenharmony_ci 0x80000000, 0x10000); 19068c2ecf20Sopenharmony_ci } else if (dsp_index == 1) { 19078c2ecf20Sopenharmony_ci /* DSP 1 is a C6713 */ 19088c2ecf20Sopenharmony_ci /* 192K internal mem */ 19098c2ecf20Sopenharmony_ci err = boot_loader_test_memory(pao, dsp_index, 0x00000000, 19108c2ecf20Sopenharmony_ci 0x30000); 19118c2ecf20Sopenharmony_ci if (!err) 19128c2ecf20Sopenharmony_ci /* 64K internal mem / L2 cache */ 19138c2ecf20Sopenharmony_ci err = boot_loader_test_memory(pao, dsp_index, 19148c2ecf20Sopenharmony_ci 0x00030000, 0x10000); 19158c2ecf20Sopenharmony_ci } 19168c2ecf20Sopenharmony_ci 19178c2ecf20Sopenharmony_ci if (err) 19188c2ecf20Sopenharmony_ci return HPI6205_ERROR_DSP_INTMEM; 19198c2ecf20Sopenharmony_ci else 19208c2ecf20Sopenharmony_ci return 0; 19218c2ecf20Sopenharmony_ci} 19228c2ecf20Sopenharmony_ci 19238c2ecf20Sopenharmony_cistatic u16 boot_loader_test_external_memory(struct hpi_adapter_obj *pao, 19248c2ecf20Sopenharmony_ci int dsp_index) 19258c2ecf20Sopenharmony_ci{ 19268c2ecf20Sopenharmony_ci u32 dRAM_start_address = 0; 19278c2ecf20Sopenharmony_ci u32 dRAM_size = 0; 19288c2ecf20Sopenharmony_ci 19298c2ecf20Sopenharmony_ci if (dsp_index == 0) { 19308c2ecf20Sopenharmony_ci /* only test for SDRAM if an ASI5000 card */ 19318c2ecf20Sopenharmony_ci if (pao->pci.pci_dev->subsystem_device == 0x5000) { 19328c2ecf20Sopenharmony_ci /* DSP 0 is always C6205 */ 19338c2ecf20Sopenharmony_ci dRAM_start_address = 0x00400000; 19348c2ecf20Sopenharmony_ci dRAM_size = 0x200000; 19358c2ecf20Sopenharmony_ci /*dwDRAMinc=1024; */ 19368c2ecf20Sopenharmony_ci } else 19378c2ecf20Sopenharmony_ci return 0; 19388c2ecf20Sopenharmony_ci } else if (dsp_index == 1) { 19398c2ecf20Sopenharmony_ci /* DSP 1 is a C6713 */ 19408c2ecf20Sopenharmony_ci dRAM_start_address = 0x80000000; 19418c2ecf20Sopenharmony_ci dRAM_size = 0x200000; 19428c2ecf20Sopenharmony_ci /*dwDRAMinc=1024; */ 19438c2ecf20Sopenharmony_ci } 19448c2ecf20Sopenharmony_ci 19458c2ecf20Sopenharmony_ci if (boot_loader_test_memory(pao, dsp_index, dRAM_start_address, 19468c2ecf20Sopenharmony_ci dRAM_size)) 19478c2ecf20Sopenharmony_ci return HPI6205_ERROR_DSP_EXTMEM; 19488c2ecf20Sopenharmony_ci return 0; 19498c2ecf20Sopenharmony_ci} 19508c2ecf20Sopenharmony_ci 19518c2ecf20Sopenharmony_cistatic u16 boot_loader_test_pld(struct hpi_adapter_obj *pao, int dsp_index) 19528c2ecf20Sopenharmony_ci{ 19538c2ecf20Sopenharmony_ci u32 data = 0; 19548c2ecf20Sopenharmony_ci if (dsp_index == 0) { 19558c2ecf20Sopenharmony_ci /* only test for DSP0 PLD on ASI5000 card */ 19568c2ecf20Sopenharmony_ci if (pao->pci.pci_dev->subsystem_device == 0x5000) { 19578c2ecf20Sopenharmony_ci /* PLD is located at CE3=0x03000000 */ 19588c2ecf20Sopenharmony_ci data = boot_loader_read_mem32(pao, dsp_index, 19598c2ecf20Sopenharmony_ci 0x03000008); 19608c2ecf20Sopenharmony_ci if ((data & 0xF) != 0x5) 19618c2ecf20Sopenharmony_ci return HPI6205_ERROR_DSP_PLD; 19628c2ecf20Sopenharmony_ci data = boot_loader_read_mem32(pao, dsp_index, 19638c2ecf20Sopenharmony_ci 0x0300000C); 19648c2ecf20Sopenharmony_ci if ((data & 0xF) != 0xA) 19658c2ecf20Sopenharmony_ci return HPI6205_ERROR_DSP_PLD; 19668c2ecf20Sopenharmony_ci } 19678c2ecf20Sopenharmony_ci } else if (dsp_index == 1) { 19688c2ecf20Sopenharmony_ci /* DSP 1 is a C6713 */ 19698c2ecf20Sopenharmony_ci if (pao->pci.pci_dev->subsystem_device == 0x8700) { 19708c2ecf20Sopenharmony_ci /* PLD is located at CE1=0x90000000 */ 19718c2ecf20Sopenharmony_ci data = boot_loader_read_mem32(pao, dsp_index, 19728c2ecf20Sopenharmony_ci 0x90000010); 19738c2ecf20Sopenharmony_ci if ((data & 0xFF) != 0xAA) 19748c2ecf20Sopenharmony_ci return HPI6205_ERROR_DSP_PLD; 19758c2ecf20Sopenharmony_ci /* 8713 - LED on */ 19768c2ecf20Sopenharmony_ci boot_loader_write_mem32(pao, dsp_index, 0x90000000, 19778c2ecf20Sopenharmony_ci 0x02); 19788c2ecf20Sopenharmony_ci } 19798c2ecf20Sopenharmony_ci } 19808c2ecf20Sopenharmony_ci return 0; 19818c2ecf20Sopenharmony_ci} 19828c2ecf20Sopenharmony_ci 19838c2ecf20Sopenharmony_ci/** Transfer data to or from DSP 19848c2ecf20Sopenharmony_ci nOperation = H620_H620_HIF_SEND_DATA or H620_HIF_GET_DATA 19858c2ecf20Sopenharmony_ci*/ 19868c2ecf20Sopenharmony_cistatic short hpi6205_transfer_data(struct hpi_adapter_obj *pao, u8 *p_data, 19878c2ecf20Sopenharmony_ci u32 data_size, int operation) 19888c2ecf20Sopenharmony_ci{ 19898c2ecf20Sopenharmony_ci struct hpi_hw_obj *phw = pao->priv; 19908c2ecf20Sopenharmony_ci u32 data_transferred = 0; 19918c2ecf20Sopenharmony_ci u16 err = 0; 19928c2ecf20Sopenharmony_ci u32 temp2; 19938c2ecf20Sopenharmony_ci struct bus_master_interface *interface = phw->p_interface_buffer; 19948c2ecf20Sopenharmony_ci 19958c2ecf20Sopenharmony_ci if (!p_data) 19968c2ecf20Sopenharmony_ci return HPI_ERROR_INVALID_DATA_POINTER; 19978c2ecf20Sopenharmony_ci 19988c2ecf20Sopenharmony_ci data_size &= ~3L; /* round data_size down to nearest 4 bytes */ 19998c2ecf20Sopenharmony_ci 20008c2ecf20Sopenharmony_ci /* make sure state is IDLE */ 20018c2ecf20Sopenharmony_ci if (!wait_dsp_ack(phw, H620_HIF_IDLE, HPI6205_TIMEOUT)) 20028c2ecf20Sopenharmony_ci return HPI_ERROR_DSP_HARDWARE; 20038c2ecf20Sopenharmony_ci 20048c2ecf20Sopenharmony_ci while (data_transferred < data_size) { 20058c2ecf20Sopenharmony_ci u32 this_copy = data_size - data_transferred; 20068c2ecf20Sopenharmony_ci 20078c2ecf20Sopenharmony_ci if (this_copy > HPI6205_SIZEOF_DATA) 20088c2ecf20Sopenharmony_ci this_copy = HPI6205_SIZEOF_DATA; 20098c2ecf20Sopenharmony_ci 20108c2ecf20Sopenharmony_ci if (operation == H620_HIF_SEND_DATA) 20118c2ecf20Sopenharmony_ci memcpy((void *)&interface->u.b_data[0], 20128c2ecf20Sopenharmony_ci &p_data[data_transferred], this_copy); 20138c2ecf20Sopenharmony_ci 20148c2ecf20Sopenharmony_ci interface->transfer_size_in_bytes = this_copy; 20158c2ecf20Sopenharmony_ci 20168c2ecf20Sopenharmony_ci /* DSP must change this back to nOperation */ 20178c2ecf20Sopenharmony_ci interface->dsp_ack = H620_HIF_IDLE; 20188c2ecf20Sopenharmony_ci send_dsp_command(phw, operation); 20198c2ecf20Sopenharmony_ci 20208c2ecf20Sopenharmony_ci temp2 = wait_dsp_ack(phw, operation, HPI6205_TIMEOUT); 20218c2ecf20Sopenharmony_ci HPI_DEBUG_LOG(DEBUG, "spun %d times for data xfer of %d\n", 20228c2ecf20Sopenharmony_ci HPI6205_TIMEOUT - temp2, this_copy); 20238c2ecf20Sopenharmony_ci 20248c2ecf20Sopenharmony_ci if (!temp2) { 20258c2ecf20Sopenharmony_ci /* timed out */ 20268c2ecf20Sopenharmony_ci HPI_DEBUG_LOG(ERROR, 20278c2ecf20Sopenharmony_ci "Timed out waiting for " "state %d got %d\n", 20288c2ecf20Sopenharmony_ci operation, interface->dsp_ack); 20298c2ecf20Sopenharmony_ci 20308c2ecf20Sopenharmony_ci break; 20318c2ecf20Sopenharmony_ci } 20328c2ecf20Sopenharmony_ci if (operation == H620_HIF_GET_DATA) 20338c2ecf20Sopenharmony_ci memcpy(&p_data[data_transferred], 20348c2ecf20Sopenharmony_ci (void *)&interface->u.b_data[0], this_copy); 20358c2ecf20Sopenharmony_ci 20368c2ecf20Sopenharmony_ci data_transferred += this_copy; 20378c2ecf20Sopenharmony_ci } 20388c2ecf20Sopenharmony_ci if (interface->dsp_ack != operation) 20398c2ecf20Sopenharmony_ci HPI_DEBUG_LOG(DEBUG, "interface->dsp_ack=%d, expected %d\n", 20408c2ecf20Sopenharmony_ci interface->dsp_ack, operation); 20418c2ecf20Sopenharmony_ci /* err=HPI_ERROR_DSP_HARDWARE; */ 20428c2ecf20Sopenharmony_ci 20438c2ecf20Sopenharmony_ci send_dsp_command(phw, H620_HIF_IDLE); 20448c2ecf20Sopenharmony_ci 20458c2ecf20Sopenharmony_ci return err; 20468c2ecf20Sopenharmony_ci} 20478c2ecf20Sopenharmony_ci 20488c2ecf20Sopenharmony_ci/* wait for up to timeout_us microseconds for the DSP 20498c2ecf20Sopenharmony_ci to signal state by DMA into dwDspAck 20508c2ecf20Sopenharmony_ci*/ 20518c2ecf20Sopenharmony_cistatic int wait_dsp_ack(struct hpi_hw_obj *phw, int state, int timeout_us) 20528c2ecf20Sopenharmony_ci{ 20538c2ecf20Sopenharmony_ci struct bus_master_interface *interface = phw->p_interface_buffer; 20548c2ecf20Sopenharmony_ci int t = timeout_us / 4; 20558c2ecf20Sopenharmony_ci 20568c2ecf20Sopenharmony_ci rmb(); /* ensure interface->dsp_ack is up to date */ 20578c2ecf20Sopenharmony_ci while ((interface->dsp_ack != state) && --t) { 20588c2ecf20Sopenharmony_ci hpios_delay_micro_seconds(4); 20598c2ecf20Sopenharmony_ci rmb(); /* DSP changes dsp_ack by DMA */ 20608c2ecf20Sopenharmony_ci } 20618c2ecf20Sopenharmony_ci 20628c2ecf20Sopenharmony_ci /*HPI_DEBUG_LOG(VERBOSE, "Spun %d for %d\n", timeout_us/4-t, state); */ 20638c2ecf20Sopenharmony_ci return t * 4; 20648c2ecf20Sopenharmony_ci} 20658c2ecf20Sopenharmony_ci 20668c2ecf20Sopenharmony_ci/* set the busmaster interface to cmd, then interrupt the DSP */ 20678c2ecf20Sopenharmony_cistatic void send_dsp_command(struct hpi_hw_obj *phw, int cmd) 20688c2ecf20Sopenharmony_ci{ 20698c2ecf20Sopenharmony_ci struct bus_master_interface *interface = phw->p_interface_buffer; 20708c2ecf20Sopenharmony_ci u32 r; 20718c2ecf20Sopenharmony_ci 20728c2ecf20Sopenharmony_ci interface->host_cmd = cmd; 20738c2ecf20Sopenharmony_ci wmb(); /* DSP gets state by DMA, make sure it is written to memory */ 20748c2ecf20Sopenharmony_ci /* before we interrupt the DSP */ 20758c2ecf20Sopenharmony_ci r = ioread32(phw->prHDCR); 20768c2ecf20Sopenharmony_ci r |= (u32)C6205_HDCR_DSPINT; 20778c2ecf20Sopenharmony_ci iowrite32(r, phw->prHDCR); 20788c2ecf20Sopenharmony_ci r &= ~(u32)C6205_HDCR_DSPINT; 20798c2ecf20Sopenharmony_ci iowrite32(r, phw->prHDCR); 20808c2ecf20Sopenharmony_ci} 20818c2ecf20Sopenharmony_ci 20828c2ecf20Sopenharmony_cistatic unsigned int message_count; 20838c2ecf20Sopenharmony_ci 20848c2ecf20Sopenharmony_cistatic u16 message_response_sequence(struct hpi_adapter_obj *pao, 20858c2ecf20Sopenharmony_ci struct hpi_message *phm, struct hpi_response *phr) 20868c2ecf20Sopenharmony_ci{ 20878c2ecf20Sopenharmony_ci u32 time_out, time_out2; 20888c2ecf20Sopenharmony_ci struct hpi_hw_obj *phw = pao->priv; 20898c2ecf20Sopenharmony_ci struct bus_master_interface *interface = phw->p_interface_buffer; 20908c2ecf20Sopenharmony_ci u16 err = 0; 20918c2ecf20Sopenharmony_ci 20928c2ecf20Sopenharmony_ci message_count++; 20938c2ecf20Sopenharmony_ci if (phm->size > sizeof(interface->u.message_buffer)) { 20948c2ecf20Sopenharmony_ci phr->error = HPI_ERROR_MESSAGE_BUFFER_TOO_SMALL; 20958c2ecf20Sopenharmony_ci phr->specific_error = sizeof(interface->u.message_buffer); 20968c2ecf20Sopenharmony_ci phr->size = sizeof(struct hpi_response_header); 20978c2ecf20Sopenharmony_ci HPI_DEBUG_LOG(ERROR, 20988c2ecf20Sopenharmony_ci "message len %d too big for buffer %zd \n", phm->size, 20998c2ecf20Sopenharmony_ci sizeof(interface->u.message_buffer)); 21008c2ecf20Sopenharmony_ci return 0; 21018c2ecf20Sopenharmony_ci } 21028c2ecf20Sopenharmony_ci 21038c2ecf20Sopenharmony_ci /* Assume buffer of type struct bus_master_interface_62 21048c2ecf20Sopenharmony_ci is allocated "noncacheable" */ 21058c2ecf20Sopenharmony_ci 21068c2ecf20Sopenharmony_ci if (!wait_dsp_ack(phw, H620_HIF_IDLE, HPI6205_TIMEOUT)) { 21078c2ecf20Sopenharmony_ci HPI_DEBUG_LOG(DEBUG, "timeout waiting for idle\n"); 21088c2ecf20Sopenharmony_ci return HPI6205_ERROR_MSG_RESP_IDLE_TIMEOUT; 21098c2ecf20Sopenharmony_ci } 21108c2ecf20Sopenharmony_ci 21118c2ecf20Sopenharmony_ci memcpy(&interface->u.message_buffer, phm, phm->size); 21128c2ecf20Sopenharmony_ci /* signal we want a response */ 21138c2ecf20Sopenharmony_ci send_dsp_command(phw, H620_HIF_GET_RESP); 21148c2ecf20Sopenharmony_ci 21158c2ecf20Sopenharmony_ci time_out2 = wait_dsp_ack(phw, H620_HIF_GET_RESP, HPI6205_TIMEOUT); 21168c2ecf20Sopenharmony_ci 21178c2ecf20Sopenharmony_ci if (!time_out2) { 21188c2ecf20Sopenharmony_ci HPI_DEBUG_LOG(ERROR, 21198c2ecf20Sopenharmony_ci "(%u) Timed out waiting for " "GET_RESP state [%x]\n", 21208c2ecf20Sopenharmony_ci message_count, interface->dsp_ack); 21218c2ecf20Sopenharmony_ci } else { 21228c2ecf20Sopenharmony_ci HPI_DEBUG_LOG(VERBOSE, 21238c2ecf20Sopenharmony_ci "(%u) transition to GET_RESP after %u\n", 21248c2ecf20Sopenharmony_ci message_count, HPI6205_TIMEOUT - time_out2); 21258c2ecf20Sopenharmony_ci } 21268c2ecf20Sopenharmony_ci /* spin waiting on HIF interrupt flag (end of msg process) */ 21278c2ecf20Sopenharmony_ci time_out = HPI6205_TIMEOUT; 21288c2ecf20Sopenharmony_ci 21298c2ecf20Sopenharmony_ci /* read the result */ 21308c2ecf20Sopenharmony_ci if (time_out) { 21318c2ecf20Sopenharmony_ci if (interface->u.response_buffer.response.size <= phr->size) 21328c2ecf20Sopenharmony_ci memcpy(phr, &interface->u.response_buffer, 21338c2ecf20Sopenharmony_ci interface->u.response_buffer.response.size); 21348c2ecf20Sopenharmony_ci else { 21358c2ecf20Sopenharmony_ci HPI_DEBUG_LOG(ERROR, 21368c2ecf20Sopenharmony_ci "response len %d too big for buffer %d\n", 21378c2ecf20Sopenharmony_ci interface->u.response_buffer.response.size, 21388c2ecf20Sopenharmony_ci phr->size); 21398c2ecf20Sopenharmony_ci memcpy(phr, &interface->u.response_buffer, 21408c2ecf20Sopenharmony_ci sizeof(struct hpi_response_header)); 21418c2ecf20Sopenharmony_ci phr->error = HPI_ERROR_RESPONSE_BUFFER_TOO_SMALL; 21428c2ecf20Sopenharmony_ci phr->specific_error = 21438c2ecf20Sopenharmony_ci interface->u.response_buffer.response.size; 21448c2ecf20Sopenharmony_ci phr->size = sizeof(struct hpi_response_header); 21458c2ecf20Sopenharmony_ci } 21468c2ecf20Sopenharmony_ci } 21478c2ecf20Sopenharmony_ci /* set interface back to idle */ 21488c2ecf20Sopenharmony_ci send_dsp_command(phw, H620_HIF_IDLE); 21498c2ecf20Sopenharmony_ci 21508c2ecf20Sopenharmony_ci if (!time_out || !time_out2) { 21518c2ecf20Sopenharmony_ci HPI_DEBUG_LOG(DEBUG, "something timed out!\n"); 21528c2ecf20Sopenharmony_ci return HPI6205_ERROR_MSG_RESP_TIMEOUT; 21538c2ecf20Sopenharmony_ci } 21548c2ecf20Sopenharmony_ci /* special case for adapter close - */ 21558c2ecf20Sopenharmony_ci /* wait for the DSP to indicate it is idle */ 21568c2ecf20Sopenharmony_ci if (phm->function == HPI_ADAPTER_CLOSE) { 21578c2ecf20Sopenharmony_ci if (!wait_dsp_ack(phw, H620_HIF_IDLE, HPI6205_TIMEOUT)) { 21588c2ecf20Sopenharmony_ci HPI_DEBUG_LOG(DEBUG, 21598c2ecf20Sopenharmony_ci "Timeout waiting for idle " 21608c2ecf20Sopenharmony_ci "(on adapter_close)\n"); 21618c2ecf20Sopenharmony_ci return HPI6205_ERROR_MSG_RESP_IDLE_TIMEOUT; 21628c2ecf20Sopenharmony_ci } 21638c2ecf20Sopenharmony_ci } 21648c2ecf20Sopenharmony_ci err = hpi_validate_response(phm, phr); 21658c2ecf20Sopenharmony_ci return err; 21668c2ecf20Sopenharmony_ci} 21678c2ecf20Sopenharmony_ci 21688c2ecf20Sopenharmony_cistatic void hw_message(struct hpi_adapter_obj *pao, struct hpi_message *phm, 21698c2ecf20Sopenharmony_ci struct hpi_response *phr) 21708c2ecf20Sopenharmony_ci{ 21718c2ecf20Sopenharmony_ci 21728c2ecf20Sopenharmony_ci u16 err = 0; 21738c2ecf20Sopenharmony_ci 21748c2ecf20Sopenharmony_ci hpios_dsplock_lock(pao); 21758c2ecf20Sopenharmony_ci 21768c2ecf20Sopenharmony_ci err = message_response_sequence(pao, phm, phr); 21778c2ecf20Sopenharmony_ci 21788c2ecf20Sopenharmony_ci /* maybe an error response */ 21798c2ecf20Sopenharmony_ci if (err) { 21808c2ecf20Sopenharmony_ci /* something failed in the HPI/DSP interface */ 21818c2ecf20Sopenharmony_ci if (err >= HPI_ERROR_BACKEND_BASE) { 21828c2ecf20Sopenharmony_ci phr->error = HPI_ERROR_DSP_COMMUNICATION; 21838c2ecf20Sopenharmony_ci phr->specific_error = err; 21848c2ecf20Sopenharmony_ci } else { 21858c2ecf20Sopenharmony_ci phr->error = err; 21868c2ecf20Sopenharmony_ci } 21878c2ecf20Sopenharmony_ci 21888c2ecf20Sopenharmony_ci pao->dsp_crashed++; 21898c2ecf20Sopenharmony_ci 21908c2ecf20Sopenharmony_ci /* just the header of the response is valid */ 21918c2ecf20Sopenharmony_ci phr->size = sizeof(struct hpi_response_header); 21928c2ecf20Sopenharmony_ci goto err; 21938c2ecf20Sopenharmony_ci } else 21948c2ecf20Sopenharmony_ci pao->dsp_crashed = 0; 21958c2ecf20Sopenharmony_ci 21968c2ecf20Sopenharmony_ci if (phr->error != 0) /* something failed in the DSP */ 21978c2ecf20Sopenharmony_ci goto err; 21988c2ecf20Sopenharmony_ci 21998c2ecf20Sopenharmony_ci switch (phm->function) { 22008c2ecf20Sopenharmony_ci case HPI_OSTREAM_WRITE: 22018c2ecf20Sopenharmony_ci case HPI_ISTREAM_ANC_WRITE: 22028c2ecf20Sopenharmony_ci err = hpi6205_transfer_data(pao, phm->u.d.u.data.pb_data, 22038c2ecf20Sopenharmony_ci phm->u.d.u.data.data_size, H620_HIF_SEND_DATA); 22048c2ecf20Sopenharmony_ci break; 22058c2ecf20Sopenharmony_ci 22068c2ecf20Sopenharmony_ci case HPI_ISTREAM_READ: 22078c2ecf20Sopenharmony_ci case HPI_OSTREAM_ANC_READ: 22088c2ecf20Sopenharmony_ci err = hpi6205_transfer_data(pao, phm->u.d.u.data.pb_data, 22098c2ecf20Sopenharmony_ci phm->u.d.u.data.data_size, H620_HIF_GET_DATA); 22108c2ecf20Sopenharmony_ci break; 22118c2ecf20Sopenharmony_ci 22128c2ecf20Sopenharmony_ci } 22138c2ecf20Sopenharmony_ci phr->error = err; 22148c2ecf20Sopenharmony_ci 22158c2ecf20Sopenharmony_cierr: 22168c2ecf20Sopenharmony_ci hpios_dsplock_unlock(pao); 22178c2ecf20Sopenharmony_ci 22188c2ecf20Sopenharmony_ci return; 22198c2ecf20Sopenharmony_ci} 2220