xref: /openbmc/linux/sound/pci/asihpi/hpi6205.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
107d7fe7bSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2719f82d3SEliot Blennerhassett /******************************************************************************
3719f82d3SEliot Blennerhassett 
4719f82d3SEliot Blennerhassett     AudioScience HPI driver
5f9a376c3SEliot Blennerhassett     Copyright (C) 1997-2014  AudioScience Inc. <support@audioscience.com>
6719f82d3SEliot Blennerhassett 
7719f82d3SEliot Blennerhassett 
8719f82d3SEliot Blennerhassett  Hardware Programming Interface (HPI) for AudioScience
9719f82d3SEliot Blennerhassett  ASI50xx, AS51xx, ASI6xxx, ASI87xx ASI89xx series adapters.
10719f82d3SEliot Blennerhassett  These PCI and PCIe bus adapters are based on a
11719f82d3SEliot Blennerhassett  TMS320C6205 PCI bus mastering DSP,
12719f82d3SEliot Blennerhassett  and (except ASI50xx) TI TMS320C6xxx floating point DSP
13719f82d3SEliot Blennerhassett 
14719f82d3SEliot Blennerhassett  Exported function:
15719f82d3SEliot Blennerhassett  void HPI_6205(struct hpi_message *phm, struct hpi_response *phr)
16719f82d3SEliot Blennerhassett 
17719f82d3SEliot Blennerhassett (C) Copyright AudioScience Inc. 1998-2010
18719f82d3SEliot Blennerhassett *******************************************************************************/
19719f82d3SEliot Blennerhassett #define SOURCEFILE_NAME "hpi6205.c"
20719f82d3SEliot Blennerhassett 
21719f82d3SEliot Blennerhassett #include "hpi_internal.h"
22719f82d3SEliot Blennerhassett #include "hpimsginit.h"
23719f82d3SEliot Blennerhassett #include "hpidebug.h"
24719f82d3SEliot Blennerhassett #include "hpi6205.h"
25719f82d3SEliot Blennerhassett #include "hpidspcd.h"
26719f82d3SEliot Blennerhassett #include "hpicmn.h"
27719f82d3SEliot Blennerhassett 
28719f82d3SEliot Blennerhassett /*****************************************************************************/
29719f82d3SEliot Blennerhassett /* HPI6205 specific error codes */
303285ea10SEliot Blennerhassett #define HPI6205_ERROR_BASE 1000	/* not actually used anywhere */
313285ea10SEliot Blennerhassett 
323285ea10SEliot Blennerhassett /* operational/messaging errors */
333285ea10SEliot Blennerhassett #define HPI6205_ERROR_MSG_RESP_IDLE_TIMEOUT     1015
343285ea10SEliot Blennerhassett #define HPI6205_ERROR_MSG_RESP_TIMEOUT          1016
353285ea10SEliot Blennerhassett 
363285ea10SEliot Blennerhassett /* initialization/bootload errors */
37719f82d3SEliot Blennerhassett #define HPI6205_ERROR_6205_NO_IRQ       1002
38719f82d3SEliot Blennerhassett #define HPI6205_ERROR_6205_INIT_FAILED  1003
39719f82d3SEliot Blennerhassett #define HPI6205_ERROR_6205_REG          1006
40719f82d3SEliot Blennerhassett #define HPI6205_ERROR_6205_DSPPAGE      1007
41719f82d3SEliot Blennerhassett #define HPI6205_ERROR_C6713_HPIC        1009
42719f82d3SEliot Blennerhassett #define HPI6205_ERROR_C6713_HPIA        1010
43719f82d3SEliot Blennerhassett #define HPI6205_ERROR_C6713_PLL         1011
44719f82d3SEliot Blennerhassett #define HPI6205_ERROR_DSP_INTMEM        1012
45719f82d3SEliot Blennerhassett #define HPI6205_ERROR_DSP_EXTMEM        1013
46719f82d3SEliot Blennerhassett #define HPI6205_ERROR_DSP_PLD           1014
47719f82d3SEliot Blennerhassett #define HPI6205_ERROR_6205_EEPROM       1017
484e225e26SEliot Blennerhassett #define HPI6205_ERROR_DSP_EMIF1         1018
494e225e26SEliot Blennerhassett #define HPI6205_ERROR_DSP_EMIF2         1019
504e225e26SEliot Blennerhassett #define HPI6205_ERROR_DSP_EMIF3         1020
514e225e26SEliot Blennerhassett #define HPI6205_ERROR_DSP_EMIF4         1021
52719f82d3SEliot Blennerhassett 
53719f82d3SEliot Blennerhassett /*****************************************************************************/
54719f82d3SEliot Blennerhassett /* for C6205 PCI i/f */
55719f82d3SEliot Blennerhassett /* Host Status Register (HSR) bitfields */
56719f82d3SEliot Blennerhassett #define C6205_HSR_INTSRC        0x01
57719f82d3SEliot Blennerhassett #define C6205_HSR_INTAVAL       0x02
58719f82d3SEliot Blennerhassett #define C6205_HSR_INTAM         0x04
59719f82d3SEliot Blennerhassett #define C6205_HSR_CFGERR        0x08
60719f82d3SEliot Blennerhassett #define C6205_HSR_EEREAD        0x10
61719f82d3SEliot Blennerhassett /* Host-to-DSP Control Register (HDCR) bitfields */
62719f82d3SEliot Blennerhassett #define C6205_HDCR_WARMRESET    0x01
63719f82d3SEliot Blennerhassett #define C6205_HDCR_DSPINT       0x02
64719f82d3SEliot Blennerhassett #define C6205_HDCR_PCIBOOT      0x04
65719f82d3SEliot Blennerhassett /* DSP Page Register (DSPP) bitfields, */
66719f82d3SEliot Blennerhassett /* defines 4 Mbyte page that BAR0 points to */
67719f82d3SEliot Blennerhassett #define C6205_DSPP_MAP1         0x400
68719f82d3SEliot Blennerhassett 
69719f82d3SEliot Blennerhassett /* BAR0 maps to prefetchable 4 Mbyte memory block set by DSPP.
70719f82d3SEliot Blennerhassett  * BAR1 maps to non-prefetchable 8 Mbyte memory block
71719f82d3SEliot Blennerhassett  * of DSP memory mapped registers (starting at 0x01800000).
72719f82d3SEliot Blennerhassett  * 0x01800000 is hardcoded in the PCI i/f, so that only the offset from this
73719f82d3SEliot Blennerhassett  * needs to be added to the BAR1 base address set in the PCI config reg
74719f82d3SEliot Blennerhassett  */
75719f82d3SEliot Blennerhassett #define C6205_BAR1_PCI_IO_OFFSET (0x027FFF0L)
76719f82d3SEliot Blennerhassett #define C6205_BAR1_HSR  (C6205_BAR1_PCI_IO_OFFSET)
77719f82d3SEliot Blennerhassett #define C6205_BAR1_HDCR (C6205_BAR1_PCI_IO_OFFSET+4)
78719f82d3SEliot Blennerhassett #define C6205_BAR1_DSPP (C6205_BAR1_PCI_IO_OFFSET+8)
79719f82d3SEliot Blennerhassett 
80719f82d3SEliot Blennerhassett /* used to control LED (revA) and reset C6713 (revB) */
81719f82d3SEliot Blennerhassett #define C6205_BAR0_TIMER1_CTL (0x01980000L)
82719f82d3SEliot Blennerhassett 
83719f82d3SEliot Blennerhassett /* For first 6713 in CE1 space, using DA17,16,2 */
84719f82d3SEliot Blennerhassett #define HPICL_ADDR      0x01400000L
85719f82d3SEliot Blennerhassett #define HPICH_ADDR      0x01400004L
86719f82d3SEliot Blennerhassett #define HPIAL_ADDR      0x01410000L
87719f82d3SEliot Blennerhassett #define HPIAH_ADDR      0x01410004L
88719f82d3SEliot Blennerhassett #define HPIDIL_ADDR     0x01420000L
89719f82d3SEliot Blennerhassett #define HPIDIH_ADDR     0x01420004L
90719f82d3SEliot Blennerhassett #define HPIDL_ADDR      0x01430000L
91719f82d3SEliot Blennerhassett #define HPIDH_ADDR      0x01430004L
92719f82d3SEliot Blennerhassett 
93719f82d3SEliot Blennerhassett #define C6713_EMIF_GCTL         0x01800000
94719f82d3SEliot Blennerhassett #define C6713_EMIF_CE1          0x01800004
95719f82d3SEliot Blennerhassett #define C6713_EMIF_CE0          0x01800008
96719f82d3SEliot Blennerhassett #define C6713_EMIF_CE2          0x01800010
97719f82d3SEliot Blennerhassett #define C6713_EMIF_CE3          0x01800014
98719f82d3SEliot Blennerhassett #define C6713_EMIF_SDRAMCTL     0x01800018
99719f82d3SEliot Blennerhassett #define C6713_EMIF_SDRAMTIMING  0x0180001C
100719f82d3SEliot Blennerhassett #define C6713_EMIF_SDRAMEXT     0x01800020
101719f82d3SEliot Blennerhassett 
102719f82d3SEliot Blennerhassett struct hpi_hw_obj {
103719f82d3SEliot Blennerhassett 	/* PCI registers */
104719f82d3SEliot Blennerhassett 	__iomem u32 *prHSR;
105719f82d3SEliot Blennerhassett 	__iomem u32 *prHDCR;
106719f82d3SEliot Blennerhassett 	__iomem u32 *prDSPP;
107719f82d3SEliot Blennerhassett 
108719f82d3SEliot Blennerhassett 	u32 dsp_page;
109719f82d3SEliot Blennerhassett 
110719f82d3SEliot Blennerhassett 	struct consistent_dma_area h_locked_mem;
111719f82d3SEliot Blennerhassett 	struct bus_master_interface *p_interface_buffer;
112719f82d3SEliot Blennerhassett 
113719f82d3SEliot Blennerhassett 	u16 flag_outstream_just_reset[HPI_MAX_STREAMS];
114719f82d3SEliot Blennerhassett 	/* a non-NULL handle means there is an HPI allocated buffer */
115719f82d3SEliot Blennerhassett 	struct consistent_dma_area instream_host_buffers[HPI_MAX_STREAMS];
116719f82d3SEliot Blennerhassett 	struct consistent_dma_area outstream_host_buffers[HPI_MAX_STREAMS];
117719f82d3SEliot Blennerhassett 	/* non-zero size means a buffer exists, may be external */
118719f82d3SEliot Blennerhassett 	u32 instream_host_buffer_size[HPI_MAX_STREAMS];
119719f82d3SEliot Blennerhassett 	u32 outstream_host_buffer_size[HPI_MAX_STREAMS];
120719f82d3SEliot Blennerhassett 
121719f82d3SEliot Blennerhassett 	struct consistent_dma_area h_control_cache;
122719f82d3SEliot Blennerhassett 	struct hpi_control_cache *p_cache;
123719f82d3SEliot Blennerhassett };
124719f82d3SEliot Blennerhassett 
125719f82d3SEliot Blennerhassett /*****************************************************************************/
126719f82d3SEliot Blennerhassett /* local prototypes */
127719f82d3SEliot Blennerhassett 
128719f82d3SEliot Blennerhassett #define check_before_bbm_copy(status, p_bbm_data, l_first_write, l_second_write)
129719f82d3SEliot Blennerhassett 
130719f82d3SEliot Blennerhassett static int wait_dsp_ack(struct hpi_hw_obj *phw, int state, int timeout_us);
131719f82d3SEliot Blennerhassett 
132719f82d3SEliot Blennerhassett static void send_dsp_command(struct hpi_hw_obj *phw, int cmd);
133719f82d3SEliot Blennerhassett 
134719f82d3SEliot Blennerhassett static u16 adapter_boot_load_dsp(struct hpi_adapter_obj *pao,
135719f82d3SEliot Blennerhassett 	u32 *pos_error_code);
136719f82d3SEliot Blennerhassett 
137719f82d3SEliot Blennerhassett static u16 message_response_sequence(struct hpi_adapter_obj *pao,
138719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr);
139719f82d3SEliot Blennerhassett 
140719f82d3SEliot Blennerhassett static void hw_message(struct hpi_adapter_obj *pao, struct hpi_message *phm,
141719f82d3SEliot Blennerhassett 	struct hpi_response *phr);
142719f82d3SEliot Blennerhassett 
143719f82d3SEliot Blennerhassett #define HPI6205_TIMEOUT 1000000
144719f82d3SEliot Blennerhassett 
145719f82d3SEliot Blennerhassett static void subsys_create_adapter(struct hpi_message *phm,
146719f82d3SEliot Blennerhassett 	struct hpi_response *phr);
1476d0b898eSEliot Blennerhassett static void adapter_delete(struct hpi_adapter_obj *pao,
1486d0b898eSEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr);
149719f82d3SEliot Blennerhassett 
150719f82d3SEliot Blennerhassett static u16 create_adapter_obj(struct hpi_adapter_obj *pao,
151719f82d3SEliot Blennerhassett 	u32 *pos_error_code);
152719f82d3SEliot Blennerhassett 
153719f82d3SEliot Blennerhassett static void delete_adapter_obj(struct hpi_adapter_obj *pao);
154719f82d3SEliot Blennerhassett 
155f9a376c3SEliot Blennerhassett static int adapter_irq_query_and_clear(struct hpi_adapter_obj *pao,
156f9a376c3SEliot Blennerhassett 	u32 message);
157f9a376c3SEliot Blennerhassett 
158719f82d3SEliot Blennerhassett static void outstream_host_buffer_allocate(struct hpi_adapter_obj *pao,
159719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr);
160719f82d3SEliot Blennerhassett 
161719f82d3SEliot Blennerhassett static void outstream_host_buffer_get_info(struct hpi_adapter_obj *pao,
162719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr);
163719f82d3SEliot Blennerhassett 
164719f82d3SEliot Blennerhassett static void outstream_host_buffer_free(struct hpi_adapter_obj *pao,
165719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr);
166719f82d3SEliot Blennerhassett static void outstream_write(struct hpi_adapter_obj *pao,
167719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr);
168719f82d3SEliot Blennerhassett 
169719f82d3SEliot Blennerhassett static void outstream_get_info(struct hpi_adapter_obj *pao,
170719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr);
171719f82d3SEliot Blennerhassett 
172719f82d3SEliot Blennerhassett static void outstream_start(struct hpi_adapter_obj *pao,
173719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr);
174719f82d3SEliot Blennerhassett 
175719f82d3SEliot Blennerhassett static void outstream_open(struct hpi_adapter_obj *pao,
176719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr);
177719f82d3SEliot Blennerhassett 
178719f82d3SEliot Blennerhassett static void outstream_reset(struct hpi_adapter_obj *pao,
179719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr);
180719f82d3SEliot Blennerhassett 
181719f82d3SEliot Blennerhassett static void instream_host_buffer_allocate(struct hpi_adapter_obj *pao,
182719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr);
183719f82d3SEliot Blennerhassett 
184719f82d3SEliot Blennerhassett static void instream_host_buffer_get_info(struct hpi_adapter_obj *pao,
185719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr);
186719f82d3SEliot Blennerhassett 
187719f82d3SEliot Blennerhassett static void instream_host_buffer_free(struct hpi_adapter_obj *pao,
188719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr);
189719f82d3SEliot Blennerhassett 
190719f82d3SEliot Blennerhassett static void instream_read(struct hpi_adapter_obj *pao,
191719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr);
192719f82d3SEliot Blennerhassett 
193719f82d3SEliot Blennerhassett static void instream_get_info(struct hpi_adapter_obj *pao,
194719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr);
195719f82d3SEliot Blennerhassett 
196719f82d3SEliot Blennerhassett static void instream_start(struct hpi_adapter_obj *pao,
197719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr);
198719f82d3SEliot Blennerhassett 
199719f82d3SEliot Blennerhassett static u32 boot_loader_read_mem32(struct hpi_adapter_obj *pao, int dsp_index,
200719f82d3SEliot Blennerhassett 	u32 address);
201719f82d3SEliot Blennerhassett 
2023285ea10SEliot Blennerhassett static void boot_loader_write_mem32(struct hpi_adapter_obj *pao,
2033285ea10SEliot Blennerhassett 	int dsp_index, u32 address, u32 data);
204719f82d3SEliot Blennerhassett 
205719f82d3SEliot Blennerhassett static u16 boot_loader_config_emif(struct hpi_adapter_obj *pao,
206719f82d3SEliot Blennerhassett 	int dsp_index);
207719f82d3SEliot Blennerhassett 
208719f82d3SEliot Blennerhassett static u16 boot_loader_test_memory(struct hpi_adapter_obj *pao, int dsp_index,
209719f82d3SEliot Blennerhassett 	u32 address, u32 length);
210719f82d3SEliot Blennerhassett 
211719f82d3SEliot Blennerhassett static u16 boot_loader_test_internal_memory(struct hpi_adapter_obj *pao,
212719f82d3SEliot Blennerhassett 	int dsp_index);
213719f82d3SEliot Blennerhassett 
214719f82d3SEliot Blennerhassett static u16 boot_loader_test_external_memory(struct hpi_adapter_obj *pao,
215719f82d3SEliot Blennerhassett 	int dsp_index);
216719f82d3SEliot Blennerhassett 
217719f82d3SEliot Blennerhassett static u16 boot_loader_test_pld(struct hpi_adapter_obj *pao, int dsp_index);
218719f82d3SEliot Blennerhassett 
219719f82d3SEliot Blennerhassett /*****************************************************************************/
220719f82d3SEliot Blennerhassett 
subsys_message(struct hpi_adapter_obj * pao,struct hpi_message * phm,struct hpi_response * phr)2216d0b898eSEliot Blennerhassett static void subsys_message(struct hpi_adapter_obj *pao,
2226d0b898eSEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
223719f82d3SEliot Blennerhassett {
224719f82d3SEliot Blennerhassett 	switch (phm->function) {
225719f82d3SEliot Blennerhassett 	case HPI_SUBSYS_CREATE_ADAPTER:
226719f82d3SEliot Blennerhassett 		subsys_create_adapter(phm, phr);
227719f82d3SEliot Blennerhassett 		break;
228719f82d3SEliot Blennerhassett 	default:
229719f82d3SEliot Blennerhassett 		phr->error = HPI_ERROR_INVALID_FUNC;
230719f82d3SEliot Blennerhassett 		break;
231719f82d3SEliot Blennerhassett 	}
232719f82d3SEliot Blennerhassett }
233719f82d3SEliot Blennerhassett 
control_message(struct hpi_adapter_obj * pao,struct hpi_message * phm,struct hpi_response * phr)234719f82d3SEliot Blennerhassett static void control_message(struct hpi_adapter_obj *pao,
235719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
236719f82d3SEliot Blennerhassett {
237719f82d3SEliot Blennerhassett 
238719f82d3SEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
2393285ea10SEliot Blennerhassett 	u16 pending_cache_error = 0;
240719f82d3SEliot Blennerhassett 
241719f82d3SEliot Blennerhassett 	switch (phm->function) {
242719f82d3SEliot Blennerhassett 	case HPI_CONTROL_GET_STATE:
243719f82d3SEliot Blennerhassett 		if (pao->has_control_cache) {
2443285ea10SEliot Blennerhassett 			rmb();	/* make sure we see updates DMAed from DSP */
2453285ea10SEliot Blennerhassett 			if (hpi_check_control_cache(phw->p_cache, phm, phr)) {
246719f82d3SEliot Blennerhassett 				break;
2473285ea10SEliot Blennerhassett 			} else if (phm->u.c.attribute == HPI_METER_PEAK) {
2483285ea10SEliot Blennerhassett 				pending_cache_error =
2493285ea10SEliot Blennerhassett 					HPI_ERROR_CONTROL_CACHING;
2503285ea10SEliot Blennerhassett 			}
251719f82d3SEliot Blennerhassett 		}
252719f82d3SEliot Blennerhassett 		hw_message(pao, phm, phr);
2533285ea10SEliot Blennerhassett 		if (pending_cache_error && !phr->error)
2543285ea10SEliot Blennerhassett 			phr->error = pending_cache_error;
255719f82d3SEliot Blennerhassett 		break;
256719f82d3SEliot Blennerhassett 	case HPI_CONTROL_GET_INFO:
257719f82d3SEliot Blennerhassett 		hw_message(pao, phm, phr);
258719f82d3SEliot Blennerhassett 		break;
259719f82d3SEliot Blennerhassett 	case HPI_CONTROL_SET_STATE:
260719f82d3SEliot Blennerhassett 		hw_message(pao, phm, phr);
261719f82d3SEliot Blennerhassett 		if (pao->has_control_cache)
2623285ea10SEliot Blennerhassett 			hpi_cmn_control_cache_sync_to_msg(phw->p_cache, phm,
2633285ea10SEliot Blennerhassett 				phr);
264719f82d3SEliot Blennerhassett 		break;
265719f82d3SEliot Blennerhassett 	default:
266719f82d3SEliot Blennerhassett 		phr->error = HPI_ERROR_INVALID_FUNC;
267719f82d3SEliot Blennerhassett 		break;
268719f82d3SEliot Blennerhassett 	}
269719f82d3SEliot Blennerhassett }
270719f82d3SEliot Blennerhassett 
adapter_message(struct hpi_adapter_obj * pao,struct hpi_message * phm,struct hpi_response * phr)271719f82d3SEliot Blennerhassett static void adapter_message(struct hpi_adapter_obj *pao,
272719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
273719f82d3SEliot Blennerhassett {
274719f82d3SEliot Blennerhassett 	switch (phm->function) {
2756d0b898eSEliot Blennerhassett 	case HPI_ADAPTER_DELETE:
2766d0b898eSEliot Blennerhassett 		adapter_delete(pao, phm, phr);
2776d0b898eSEliot Blennerhassett 		break;
278719f82d3SEliot Blennerhassett 	default:
279719f82d3SEliot Blennerhassett 		hw_message(pao, phm, phr);
280719f82d3SEliot Blennerhassett 		break;
281719f82d3SEliot Blennerhassett 	}
282719f82d3SEliot Blennerhassett }
283719f82d3SEliot Blennerhassett 
outstream_message(struct hpi_adapter_obj * pao,struct hpi_message * phm,struct hpi_response * phr)284719f82d3SEliot Blennerhassett static void outstream_message(struct hpi_adapter_obj *pao,
285719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
286719f82d3SEliot Blennerhassett {
287719f82d3SEliot Blennerhassett 
288719f82d3SEliot Blennerhassett 	if (phm->obj_index >= HPI_MAX_STREAMS) {
289deb21a23SEliot Blennerhassett 		phr->error = HPI_ERROR_INVALID_OBJ_INDEX;
290719f82d3SEliot Blennerhassett 		HPI_DEBUG_LOG(WARNING,
2913285ea10SEliot Blennerhassett 			"Message referencing invalid stream %d "
292719f82d3SEliot Blennerhassett 			"on adapter index %d\n", phm->obj_index,
293719f82d3SEliot Blennerhassett 			phm->adapter_index);
294719f82d3SEliot Blennerhassett 		return;
295719f82d3SEliot Blennerhassett 	}
296719f82d3SEliot Blennerhassett 
297719f82d3SEliot Blennerhassett 	switch (phm->function) {
298719f82d3SEliot Blennerhassett 	case HPI_OSTREAM_WRITE:
299719f82d3SEliot Blennerhassett 		outstream_write(pao, phm, phr);
300719f82d3SEliot Blennerhassett 		break;
301719f82d3SEliot Blennerhassett 	case HPI_OSTREAM_GET_INFO:
302719f82d3SEliot Blennerhassett 		outstream_get_info(pao, phm, phr);
303719f82d3SEliot Blennerhassett 		break;
304719f82d3SEliot Blennerhassett 	case HPI_OSTREAM_HOSTBUFFER_ALLOC:
305719f82d3SEliot Blennerhassett 		outstream_host_buffer_allocate(pao, phm, phr);
306719f82d3SEliot Blennerhassett 		break;
307719f82d3SEliot Blennerhassett 	case HPI_OSTREAM_HOSTBUFFER_GET_INFO:
308719f82d3SEliot Blennerhassett 		outstream_host_buffer_get_info(pao, phm, phr);
309719f82d3SEliot Blennerhassett 		break;
310719f82d3SEliot Blennerhassett 	case HPI_OSTREAM_HOSTBUFFER_FREE:
311719f82d3SEliot Blennerhassett 		outstream_host_buffer_free(pao, phm, phr);
312719f82d3SEliot Blennerhassett 		break;
313719f82d3SEliot Blennerhassett 	case HPI_OSTREAM_START:
314719f82d3SEliot Blennerhassett 		outstream_start(pao, phm, phr);
315719f82d3SEliot Blennerhassett 		break;
316719f82d3SEliot Blennerhassett 	case HPI_OSTREAM_OPEN:
317719f82d3SEliot Blennerhassett 		outstream_open(pao, phm, phr);
318719f82d3SEliot Blennerhassett 		break;
319719f82d3SEliot Blennerhassett 	case HPI_OSTREAM_RESET:
320719f82d3SEliot Blennerhassett 		outstream_reset(pao, phm, phr);
321719f82d3SEliot Blennerhassett 		break;
322719f82d3SEliot Blennerhassett 	default:
323719f82d3SEliot Blennerhassett 		hw_message(pao, phm, phr);
324719f82d3SEliot Blennerhassett 		break;
325719f82d3SEliot Blennerhassett 	}
326719f82d3SEliot Blennerhassett }
327719f82d3SEliot Blennerhassett 
instream_message(struct hpi_adapter_obj * pao,struct hpi_message * phm,struct hpi_response * phr)328719f82d3SEliot Blennerhassett static void instream_message(struct hpi_adapter_obj *pao,
329719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
330719f82d3SEliot Blennerhassett {
331719f82d3SEliot Blennerhassett 
332719f82d3SEliot Blennerhassett 	if (phm->obj_index >= HPI_MAX_STREAMS) {
333deb21a23SEliot Blennerhassett 		phr->error = HPI_ERROR_INVALID_OBJ_INDEX;
334719f82d3SEliot Blennerhassett 		HPI_DEBUG_LOG(WARNING,
3353285ea10SEliot Blennerhassett 			"Message referencing invalid stream %d "
336719f82d3SEliot Blennerhassett 			"on adapter index %d\n", phm->obj_index,
337719f82d3SEliot Blennerhassett 			phm->adapter_index);
338719f82d3SEliot Blennerhassett 		return;
339719f82d3SEliot Blennerhassett 	}
340719f82d3SEliot Blennerhassett 
341719f82d3SEliot Blennerhassett 	switch (phm->function) {
342719f82d3SEliot Blennerhassett 	case HPI_ISTREAM_READ:
343719f82d3SEliot Blennerhassett 		instream_read(pao, phm, phr);
344719f82d3SEliot Blennerhassett 		break;
345719f82d3SEliot Blennerhassett 	case HPI_ISTREAM_GET_INFO:
346719f82d3SEliot Blennerhassett 		instream_get_info(pao, phm, phr);
347719f82d3SEliot Blennerhassett 		break;
348719f82d3SEliot Blennerhassett 	case HPI_ISTREAM_HOSTBUFFER_ALLOC:
349719f82d3SEliot Blennerhassett 		instream_host_buffer_allocate(pao, phm, phr);
350719f82d3SEliot Blennerhassett 		break;
351719f82d3SEliot Blennerhassett 	case HPI_ISTREAM_HOSTBUFFER_GET_INFO:
352719f82d3SEliot Blennerhassett 		instream_host_buffer_get_info(pao, phm, phr);
353719f82d3SEliot Blennerhassett 		break;
354719f82d3SEliot Blennerhassett 	case HPI_ISTREAM_HOSTBUFFER_FREE:
355719f82d3SEliot Blennerhassett 		instream_host_buffer_free(pao, phm, phr);
356719f82d3SEliot Blennerhassett 		break;
357719f82d3SEliot Blennerhassett 	case HPI_ISTREAM_START:
358719f82d3SEliot Blennerhassett 		instream_start(pao, phm, phr);
359719f82d3SEliot Blennerhassett 		break;
360719f82d3SEliot Blennerhassett 	default:
361719f82d3SEliot Blennerhassett 		hw_message(pao, phm, phr);
362719f82d3SEliot Blennerhassett 		break;
363719f82d3SEliot Blennerhassett 	}
364719f82d3SEliot Blennerhassett }
365719f82d3SEliot Blennerhassett 
366719f82d3SEliot Blennerhassett /*****************************************************************************/
367719f82d3SEliot Blennerhassett /** Entry point to this HPI backend
368719f82d3SEliot Blennerhassett  * All calls to the HPI start here
369719f82d3SEliot Blennerhassett  */
37033162d2dSEliot Blennerhassett static
_HPI_6205(struct hpi_adapter_obj * pao,struct hpi_message * phm,struct hpi_response * phr)3716d0b898eSEliot Blennerhassett void _HPI_6205(struct hpi_adapter_obj *pao, struct hpi_message *phm,
3726d0b898eSEliot Blennerhassett 	struct hpi_response *phr)
373719f82d3SEliot Blennerhassett {
3746d0b898eSEliot Blennerhassett 	if (pao && (pao->dsp_crashed >= 10)
375719f82d3SEliot Blennerhassett 		&& (phm->function != HPI_ADAPTER_DEBUG_READ)) {
376719f82d3SEliot Blennerhassett 		/* allow last resort debug read even after crash */
377719f82d3SEliot Blennerhassett 		hpi_init_response(phr, phm->object, phm->function,
378719f82d3SEliot Blennerhassett 			HPI_ERROR_DSP_HARDWARE);
3796d0b898eSEliot Blennerhassett 		HPI_DEBUG_LOG(WARNING, " %d,%d dsp crashed.\n", phm->object,
3806d0b898eSEliot Blennerhassett 			phm->function);
381719f82d3SEliot Blennerhassett 		return;
382719f82d3SEliot Blennerhassett 	}
383719f82d3SEliot Blennerhassett 
384719f82d3SEliot Blennerhassett 	/* Init default response  */
385719f82d3SEliot Blennerhassett 	if (phm->function != HPI_SUBSYS_CREATE_ADAPTER)
3863285ea10SEliot Blennerhassett 		phr->error = HPI_ERROR_PROCESSING_MESSAGE;
387719f82d3SEliot Blennerhassett 
388719f82d3SEliot Blennerhassett 	HPI_DEBUG_LOG(VERBOSE, "start of switch\n");
389719f82d3SEliot Blennerhassett 	switch (phm->type) {
39082b5774fSEliot Blennerhassett 	case HPI_TYPE_REQUEST:
391719f82d3SEliot Blennerhassett 		switch (phm->object) {
392719f82d3SEliot Blennerhassett 		case HPI_OBJ_SUBSYSTEM:
3936d0b898eSEliot Blennerhassett 			subsys_message(pao, phm, phr);
394719f82d3SEliot Blennerhassett 			break;
395719f82d3SEliot Blennerhassett 
396719f82d3SEliot Blennerhassett 		case HPI_OBJ_ADAPTER:
397719f82d3SEliot Blennerhassett 			adapter_message(pao, phm, phr);
398719f82d3SEliot Blennerhassett 			break;
399719f82d3SEliot Blennerhassett 
400719f82d3SEliot Blennerhassett 		case HPI_OBJ_CONTROL:
401719f82d3SEliot Blennerhassett 			control_message(pao, phm, phr);
402719f82d3SEliot Blennerhassett 			break;
403719f82d3SEliot Blennerhassett 
404719f82d3SEliot Blennerhassett 		case HPI_OBJ_OSTREAM:
405719f82d3SEliot Blennerhassett 			outstream_message(pao, phm, phr);
406719f82d3SEliot Blennerhassett 			break;
407719f82d3SEliot Blennerhassett 
408719f82d3SEliot Blennerhassett 		case HPI_OBJ_ISTREAM:
409719f82d3SEliot Blennerhassett 			instream_message(pao, phm, phr);
410719f82d3SEliot Blennerhassett 			break;
411719f82d3SEliot Blennerhassett 
412719f82d3SEliot Blennerhassett 		default:
413719f82d3SEliot Blennerhassett 			hw_message(pao, phm, phr);
414719f82d3SEliot Blennerhassett 			break;
415719f82d3SEliot Blennerhassett 		}
416719f82d3SEliot Blennerhassett 		break;
417719f82d3SEliot Blennerhassett 
418719f82d3SEliot Blennerhassett 	default:
419719f82d3SEliot Blennerhassett 		phr->error = HPI_ERROR_INVALID_TYPE;
420719f82d3SEliot Blennerhassett 		break;
421719f82d3SEliot Blennerhassett 	}
422719f82d3SEliot Blennerhassett }
423719f82d3SEliot Blennerhassett 
HPI_6205(struct hpi_message * phm,struct hpi_response * phr)4246d0b898eSEliot Blennerhassett void HPI_6205(struct hpi_message *phm, struct hpi_response *phr)
4256d0b898eSEliot Blennerhassett {
4266d0b898eSEliot Blennerhassett 	struct hpi_adapter_obj *pao = NULL;
4276d0b898eSEliot Blennerhassett 
4286d0b898eSEliot Blennerhassett 	if (phm->object != HPI_OBJ_SUBSYSTEM) {
4296d0b898eSEliot Blennerhassett 		/* normal messages must have valid adapter index */
4306d0b898eSEliot Blennerhassett 		pao = hpi_find_adapter(phm->adapter_index);
4316d0b898eSEliot Blennerhassett 	} else {
4326d0b898eSEliot Blennerhassett 		/* subsys messages don't address an adapter */
433*9026c0bfSKuninori Morimoto 		phr->error = HPI_ERROR_INVALID_OBJ_INDEX;
4346d0b898eSEliot Blennerhassett 		return;
4356d0b898eSEliot Blennerhassett 	}
4366d0b898eSEliot Blennerhassett 
4376d0b898eSEliot Blennerhassett 	if (pao)
4386d0b898eSEliot Blennerhassett 		_HPI_6205(pao, phm, phr);
4396d0b898eSEliot Blennerhassett 	else
4406d0b898eSEliot Blennerhassett 		hpi_init_response(phr, phm->object, phm->function,
4416d0b898eSEliot Blennerhassett 			HPI_ERROR_BAD_ADAPTER_NUMBER);
4426d0b898eSEliot Blennerhassett }
4436d0b898eSEliot Blennerhassett 
444719f82d3SEliot Blennerhassett /*****************************************************************************/
445719f82d3SEliot Blennerhassett /* SUBSYSTEM */
446719f82d3SEliot Blennerhassett 
447719f82d3SEliot Blennerhassett /** Create an adapter object and initialise it based on resource information
44884f2a3c1Sshaomin Deng  * passed in the message
449719f82d3SEliot Blennerhassett  * *** NOTE - you cannot use this function AND the FindAdapters function at the
450719f82d3SEliot Blennerhassett  * same time, the application must use only one of them to get the adapters ***
451719f82d3SEliot Blennerhassett  */
subsys_create_adapter(struct hpi_message * phm,struct hpi_response * phr)452719f82d3SEliot Blennerhassett static void subsys_create_adapter(struct hpi_message *phm,
453719f82d3SEliot Blennerhassett 	struct hpi_response *phr)
454719f82d3SEliot Blennerhassett {
455719f82d3SEliot Blennerhassett 	/* create temp adapter obj, because we don't know what index yet */
456719f82d3SEliot Blennerhassett 	struct hpi_adapter_obj ao;
457719f82d3SEliot Blennerhassett 	u32 os_error_code;
458719f82d3SEliot Blennerhassett 	u16 err;
459719f82d3SEliot Blennerhassett 
460719f82d3SEliot Blennerhassett 	HPI_DEBUG_LOG(DEBUG, " subsys_create_adapter\n");
461719f82d3SEliot Blennerhassett 
462719f82d3SEliot Blennerhassett 	memset(&ao, 0, sizeof(ao));
463719f82d3SEliot Blennerhassett 
464550a8b69SJulia Lawall 	ao.priv = kzalloc(sizeof(struct hpi_hw_obj), GFP_KERNEL);
465719f82d3SEliot Blennerhassett 	if (!ao.priv) {
46625985edcSLucas De Marchi 		HPI_DEBUG_LOG(ERROR, "can't get mem for adapter object\n");
467719f82d3SEliot Blennerhassett 		phr->error = HPI_ERROR_MEMORY_ALLOC;
468719f82d3SEliot Blennerhassett 		return;
469719f82d3SEliot Blennerhassett 	}
470719f82d3SEliot Blennerhassett 
471719f82d3SEliot Blennerhassett 	ao.pci = *phm->u.s.resource.r.pci;
472719f82d3SEliot Blennerhassett 	err = create_adapter_obj(&ao, &os_error_code);
473719f82d3SEliot Blennerhassett 	if (err) {
474719f82d3SEliot Blennerhassett 		delete_adapter_obj(&ao);
4750a00044dSEliot Blennerhassett 		if (err >= HPI_ERROR_BACKEND_BASE) {
4760a00044dSEliot Blennerhassett 			phr->error = HPI_ERROR_DSP_BOOTLOAD;
4770a00044dSEliot Blennerhassett 			phr->specific_error = err;
4780a00044dSEliot Blennerhassett 		} else {
479719f82d3SEliot Blennerhassett 			phr->error = err;
4800a00044dSEliot Blennerhassett 		}
4813285ea10SEliot Blennerhassett 		phr->u.s.data = os_error_code;
482719f82d3SEliot Blennerhassett 		return;
483719f82d3SEliot Blennerhassett 	}
484719f82d3SEliot Blennerhassett 
4857036b92dSEliot Blennerhassett 	phr->u.s.adapter_type = ao.type;
486719f82d3SEliot Blennerhassett 	phr->u.s.adapter_index = ao.index;
487719f82d3SEliot Blennerhassett 	phr->error = 0;
488719f82d3SEliot Blennerhassett }
489719f82d3SEliot Blennerhassett 
490719f82d3SEliot Blennerhassett /** delete an adapter - required by WDM driver */
adapter_delete(struct hpi_adapter_obj * pao,struct hpi_message * phm,struct hpi_response * phr)4916d0b898eSEliot Blennerhassett static void adapter_delete(struct hpi_adapter_obj *pao,
4926d0b898eSEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
493719f82d3SEliot Blennerhassett {
494719f82d3SEliot Blennerhassett 	struct hpi_hw_obj *phw;
495719f82d3SEliot Blennerhassett 
496719f82d3SEliot Blennerhassett 	if (!pao) {
497719f82d3SEliot Blennerhassett 		phr->error = HPI_ERROR_INVALID_OBJ_INDEX;
498719f82d3SEliot Blennerhassett 		return;
499719f82d3SEliot Blennerhassett 	}
5007036b92dSEliot Blennerhassett 	phw = pao->priv;
501719f82d3SEliot Blennerhassett 	/* reset adapter h/w */
502719f82d3SEliot Blennerhassett 	/* Reset C6713 #1 */
503719f82d3SEliot Blennerhassett 	boot_loader_write_mem32(pao, 0, C6205_BAR0_TIMER1_CTL, 0);
504719f82d3SEliot Blennerhassett 	/* reset C6205 */
505719f82d3SEliot Blennerhassett 	iowrite32(C6205_HDCR_WARMRESET, phw->prHDCR);
506719f82d3SEliot Blennerhassett 
507719f82d3SEliot Blennerhassett 	delete_adapter_obj(pao);
5083285ea10SEliot Blennerhassett 	hpi_delete_adapter(pao);
509719f82d3SEliot Blennerhassett 	phr->error = 0;
510719f82d3SEliot Blennerhassett }
511719f82d3SEliot Blennerhassett 
512719f82d3SEliot Blennerhassett /** Create adapter object
513719f82d3SEliot Blennerhassett   allocate buffers, bootload DSPs, initialise control cache
514719f82d3SEliot Blennerhassett */
create_adapter_obj(struct hpi_adapter_obj * pao,u32 * pos_error_code)515719f82d3SEliot Blennerhassett static u16 create_adapter_obj(struct hpi_adapter_obj *pao,
516719f82d3SEliot Blennerhassett 	u32 *pos_error_code)
517719f82d3SEliot Blennerhassett {
518719f82d3SEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
519719f82d3SEliot Blennerhassett 	struct bus_master_interface *interface;
520719f82d3SEliot Blennerhassett 	u32 phys_addr;
521719f82d3SEliot Blennerhassett 	int i;
522719f82d3SEliot Blennerhassett 	u16 err;
523719f82d3SEliot Blennerhassett 
524719f82d3SEliot Blennerhassett 	/* init error reporting */
525719f82d3SEliot Blennerhassett 	pao->dsp_crashed = 0;
526719f82d3SEliot Blennerhassett 
527719f82d3SEliot Blennerhassett 	for (i = 0; i < HPI_MAX_STREAMS; i++)
528719f82d3SEliot Blennerhassett 		phw->flag_outstream_just_reset[i] = 1;
529719f82d3SEliot Blennerhassett 
530719f82d3SEliot Blennerhassett 	/* The C6205 memory area 1 is 8Mbyte window into DSP registers */
531719f82d3SEliot Blennerhassett 	phw->prHSR =
532719f82d3SEliot Blennerhassett 		pao->pci.ap_mem_base[1] +
533719f82d3SEliot Blennerhassett 		C6205_BAR1_HSR / sizeof(*pao->pci.ap_mem_base[1]);
534719f82d3SEliot Blennerhassett 	phw->prHDCR =
535719f82d3SEliot Blennerhassett 		pao->pci.ap_mem_base[1] +
536719f82d3SEliot Blennerhassett 		C6205_BAR1_HDCR / sizeof(*pao->pci.ap_mem_base[1]);
537719f82d3SEliot Blennerhassett 	phw->prDSPP =
538719f82d3SEliot Blennerhassett 		pao->pci.ap_mem_base[1] +
539719f82d3SEliot Blennerhassett 		C6205_BAR1_DSPP / sizeof(*pao->pci.ap_mem_base[1]);
540719f82d3SEliot Blennerhassett 
541719f82d3SEliot Blennerhassett 	pao->has_control_cache = 0;
542719f82d3SEliot Blennerhassett 
543719f82d3SEliot Blennerhassett 	if (hpios_locked_mem_alloc(&phw->h_locked_mem,
544719f82d3SEliot Blennerhassett 			sizeof(struct bus_master_interface),
5453285ea10SEliot Blennerhassett 			pao->pci.pci_dev))
546719f82d3SEliot Blennerhassett 		phw->p_interface_buffer = NULL;
547719f82d3SEliot Blennerhassett 	else if (hpios_locked_mem_get_virt_addr(&phw->h_locked_mem,
548719f82d3SEliot Blennerhassett 			(void *)&phw->p_interface_buffer))
549719f82d3SEliot Blennerhassett 		phw->p_interface_buffer = NULL;
550719f82d3SEliot Blennerhassett 
551719f82d3SEliot Blennerhassett 	HPI_DEBUG_LOG(DEBUG, "interface buffer address %p\n",
552719f82d3SEliot Blennerhassett 		phw->p_interface_buffer);
553719f82d3SEliot Blennerhassett 
554719f82d3SEliot Blennerhassett 	if (phw->p_interface_buffer) {
555719f82d3SEliot Blennerhassett 		memset((void *)phw->p_interface_buffer, 0,
556719f82d3SEliot Blennerhassett 			sizeof(struct bus_master_interface));
557719f82d3SEliot Blennerhassett 		phw->p_interface_buffer->dsp_ack = H620_HIF_UNKNOWN;
558719f82d3SEliot Blennerhassett 	}
559719f82d3SEliot Blennerhassett 
560719f82d3SEliot Blennerhassett 	err = adapter_boot_load_dsp(pao, pos_error_code);
5616d0b898eSEliot Blennerhassett 	if (err) {
5626d0b898eSEliot Blennerhassett 		HPI_DEBUG_LOG(ERROR, "DSP code load failed\n");
563719f82d3SEliot Blennerhassett 		/* no need to clean up as SubSysCreateAdapter */
564719f82d3SEliot Blennerhassett 		/* calls DeleteAdapter on error. */
565719f82d3SEliot Blennerhassett 		return err;
5666d0b898eSEliot Blennerhassett 	}
567719f82d3SEliot Blennerhassett 	HPI_DEBUG_LOG(INFO, "load DSP code OK\n");
568719f82d3SEliot Blennerhassett 
569719f82d3SEliot Blennerhassett 	/* allow boot load even if mem alloc wont work */
570719f82d3SEliot Blennerhassett 	if (!phw->p_interface_buffer)
5713285ea10SEliot Blennerhassett 		return HPI_ERROR_MEMORY_ALLOC;
572719f82d3SEliot Blennerhassett 
573719f82d3SEliot Blennerhassett 	interface = phw->p_interface_buffer;
574719f82d3SEliot Blennerhassett 
575719f82d3SEliot Blennerhassett 	/* make sure the DSP has started ok */
576719f82d3SEliot Blennerhassett 	if (!wait_dsp_ack(phw, H620_HIF_RESET, HPI6205_TIMEOUT * 10)) {
577719f82d3SEliot Blennerhassett 		HPI_DEBUG_LOG(ERROR, "timed out waiting reset state \n");
5783285ea10SEliot Blennerhassett 		return HPI6205_ERROR_6205_INIT_FAILED;
579719f82d3SEliot Blennerhassett 	}
580719f82d3SEliot Blennerhassett 	/* Note that *pao, *phw are zeroed after allocation,
581719f82d3SEliot Blennerhassett 	 * so pointers and flags are NULL by default.
582719f82d3SEliot Blennerhassett 	 * Allocate bus mastering control cache buffer and tell the DSP about it
583719f82d3SEliot Blennerhassett 	 */
584719f82d3SEliot Blennerhassett 	if (interface->control_cache.number_of_controls) {
5853285ea10SEliot Blennerhassett 		u8 *p_control_cache_virtual;
586719f82d3SEliot Blennerhassett 
587719f82d3SEliot Blennerhassett 		err = hpios_locked_mem_alloc(&phw->h_control_cache,
588719f82d3SEliot Blennerhassett 			interface->control_cache.size_in_bytes,
5893285ea10SEliot Blennerhassett 			pao->pci.pci_dev);
590719f82d3SEliot Blennerhassett 		if (!err)
591719f82d3SEliot Blennerhassett 			err = hpios_locked_mem_get_virt_addr(&phw->
5923285ea10SEliot Blennerhassett 				h_control_cache,
5933285ea10SEliot Blennerhassett 				(void *)&p_control_cache_virtual);
594719f82d3SEliot Blennerhassett 		if (!err) {
595719f82d3SEliot Blennerhassett 			memset(p_control_cache_virtual, 0,
596719f82d3SEliot Blennerhassett 				interface->control_cache.size_in_bytes);
597719f82d3SEliot Blennerhassett 
598719f82d3SEliot Blennerhassett 			phw->p_cache =
599719f82d3SEliot Blennerhassett 				hpi_alloc_control_cache(interface->
600719f82d3SEliot Blennerhassett 				control_cache.number_of_controls,
601719f82d3SEliot Blennerhassett 				interface->control_cache.size_in_bytes,
602719f82d3SEliot Blennerhassett 				p_control_cache_virtual);
6036d0b898eSEliot Blennerhassett 
604fd0977d0SJesper Juhl 			if (!phw->p_cache)
605fd0977d0SJesper Juhl 				err = HPI_ERROR_MEMORY_ALLOC;
606719f82d3SEliot Blennerhassett 		}
607719f82d3SEliot Blennerhassett 		if (!err) {
608719f82d3SEliot Blennerhassett 			err = hpios_locked_mem_get_phys_addr(&phw->
609719f82d3SEliot Blennerhassett 				h_control_cache, &phys_addr);
610719f82d3SEliot Blennerhassett 			interface->control_cache.physical_address32 =
611719f82d3SEliot Blennerhassett 				phys_addr;
612719f82d3SEliot Blennerhassett 		}
613719f82d3SEliot Blennerhassett 
614719f82d3SEliot Blennerhassett 		if (!err)
615719f82d3SEliot Blennerhassett 			pao->has_control_cache = 1;
616719f82d3SEliot Blennerhassett 		else {
617719f82d3SEliot Blennerhassett 			if (hpios_locked_mem_valid(&phw->h_control_cache))
618719f82d3SEliot Blennerhassett 				hpios_locked_mem_free(&phw->h_control_cache);
619719f82d3SEliot Blennerhassett 			pao->has_control_cache = 0;
620719f82d3SEliot Blennerhassett 		}
621719f82d3SEliot Blennerhassett 	}
622719f82d3SEliot Blennerhassett 	send_dsp_command(phw, H620_HIF_IDLE);
623719f82d3SEliot Blennerhassett 
624719f82d3SEliot Blennerhassett 	{
6253285ea10SEliot Blennerhassett 		struct hpi_message hm;
6263285ea10SEliot Blennerhassett 		struct hpi_response hr;
627719f82d3SEliot Blennerhassett 
628719f82d3SEliot Blennerhassett 		HPI_DEBUG_LOG(VERBOSE, "init ADAPTER_GET_INFO\n");
6293285ea10SEliot Blennerhassett 		memset(&hm, 0, sizeof(hm));
63082b5774fSEliot Blennerhassett 		/* wAdapterIndex == version == 0 */
63182b5774fSEliot Blennerhassett 		hm.type = HPI_TYPE_REQUEST;
6323285ea10SEliot Blennerhassett 		hm.size = sizeof(hm);
6333285ea10SEliot Blennerhassett 		hm.object = HPI_OBJ_ADAPTER;
6343285ea10SEliot Blennerhassett 		hm.function = HPI_ADAPTER_GET_INFO;
63582b5774fSEliot Blennerhassett 
6363285ea10SEliot Blennerhassett 		memset(&hr, 0, sizeof(hr));
6373285ea10SEliot Blennerhassett 		hr.size = sizeof(hr);
638719f82d3SEliot Blennerhassett 
6393285ea10SEliot Blennerhassett 		err = message_response_sequence(pao, &hm, &hr);
640719f82d3SEliot Blennerhassett 		if (err) {
641719f82d3SEliot Blennerhassett 			HPI_DEBUG_LOG(ERROR, "message transport error %d\n",
642719f82d3SEliot Blennerhassett 				err);
643719f82d3SEliot Blennerhassett 			return err;
644719f82d3SEliot Blennerhassett 		}
6453285ea10SEliot Blennerhassett 		if (hr.error)
6463285ea10SEliot Blennerhassett 			return hr.error;
647719f82d3SEliot Blennerhassett 
6487036b92dSEliot Blennerhassett 		pao->type = hr.u.ax.info.adapter_type;
6493285ea10SEliot Blennerhassett 		pao->index = hr.u.ax.info.adapter_index;
650719f82d3SEliot Blennerhassett 
651719f82d3SEliot Blennerhassett 		HPI_DEBUG_LOG(VERBOSE,
652719f82d3SEliot Blennerhassett 			"got adapter info type %x index %d serial %d\n",
6533285ea10SEliot Blennerhassett 			hr.u.ax.info.adapter_type, hr.u.ax.info.adapter_index,
6543285ea10SEliot Blennerhassett 			hr.u.ax.info.serial_number);
655719f82d3SEliot Blennerhassett 	}
656719f82d3SEliot Blennerhassett 
657ffdb5787SEliot Blennerhassett 	if (phw->p_cache)
658ffdb5787SEliot Blennerhassett 		phw->p_cache->adap_idx = pao->index;
659ffdb5787SEliot Blennerhassett 
660719f82d3SEliot Blennerhassett 	HPI_DEBUG_LOG(INFO, "bootload DSP OK\n");
6613285ea10SEliot Blennerhassett 
662f9a376c3SEliot Blennerhassett 	pao->irq_query_and_clear = adapter_irq_query_and_clear;
663f9a376c3SEliot Blennerhassett 	pao->instream_host_buffer_status =
664f9a376c3SEliot Blennerhassett 		phw->p_interface_buffer->instream_host_buffer_status;
665f9a376c3SEliot Blennerhassett 	pao->outstream_host_buffer_status =
666f9a376c3SEliot Blennerhassett 		phw->p_interface_buffer->outstream_host_buffer_status;
667f9a376c3SEliot Blennerhassett 
6683285ea10SEliot Blennerhassett 	return hpi_add_adapter(pao);
669719f82d3SEliot Blennerhassett }
670719f82d3SEliot Blennerhassett 
671719f82d3SEliot Blennerhassett /** Free memory areas allocated by adapter
6726d0b898eSEliot Blennerhassett  * this routine is called from AdapterDelete,
673719f82d3SEliot Blennerhassett   * and SubSysCreateAdapter if duplicate index
674719f82d3SEliot Blennerhassett */
delete_adapter_obj(struct hpi_adapter_obj * pao)675719f82d3SEliot Blennerhassett static void delete_adapter_obj(struct hpi_adapter_obj *pao)
676719f82d3SEliot Blennerhassett {
6776d0b898eSEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
678719f82d3SEliot Blennerhassett 	int i;
679719f82d3SEliot Blennerhassett 
680719f82d3SEliot Blennerhassett 	if (hpios_locked_mem_valid(&phw->h_control_cache)) {
681719f82d3SEliot Blennerhassett 		hpios_locked_mem_free(&phw->h_control_cache);
682719f82d3SEliot Blennerhassett 		hpi_free_control_cache(phw->p_cache);
683719f82d3SEliot Blennerhassett 	}
684719f82d3SEliot Blennerhassett 
685719f82d3SEliot Blennerhassett 	if (hpios_locked_mem_valid(&phw->h_locked_mem)) {
686719f82d3SEliot Blennerhassett 		hpios_locked_mem_free(&phw->h_locked_mem);
687719f82d3SEliot Blennerhassett 		phw->p_interface_buffer = NULL;
688719f82d3SEliot Blennerhassett 	}
689719f82d3SEliot Blennerhassett 
690719f82d3SEliot Blennerhassett 	for (i = 0; i < HPI_MAX_STREAMS; i++)
691719f82d3SEliot Blennerhassett 		if (hpios_locked_mem_valid(&phw->instream_host_buffers[i])) {
692719f82d3SEliot Blennerhassett 			hpios_locked_mem_free(&phw->instream_host_buffers[i]);
693719f82d3SEliot Blennerhassett 			/*?phw->InStreamHostBuffers[i] = NULL; */
694719f82d3SEliot Blennerhassett 			phw->instream_host_buffer_size[i] = 0;
695719f82d3SEliot Blennerhassett 		}
696719f82d3SEliot Blennerhassett 
697719f82d3SEliot Blennerhassett 	for (i = 0; i < HPI_MAX_STREAMS; i++)
698719f82d3SEliot Blennerhassett 		if (hpios_locked_mem_valid(&phw->outstream_host_buffers[i])) {
699719f82d3SEliot Blennerhassett 			hpios_locked_mem_free(&phw->outstream_host_buffers
700719f82d3SEliot Blennerhassett 				[i]);
701719f82d3SEliot Blennerhassett 			phw->outstream_host_buffer_size[i] = 0;
702719f82d3SEliot Blennerhassett 		}
703719f82d3SEliot Blennerhassett 	kfree(phw);
704719f82d3SEliot Blennerhassett }
705719f82d3SEliot Blennerhassett 
706719f82d3SEliot Blennerhassett /*****************************************************************************/
7071d595d2aSEliot Blennerhassett /* Adapter functions */
adapter_irq_query_and_clear(struct hpi_adapter_obj * pao,u32 message)708f9a376c3SEliot Blennerhassett static int adapter_irq_query_and_clear(struct hpi_adapter_obj *pao,
709f9a376c3SEliot Blennerhassett 	u32 message)
710f9a376c3SEliot Blennerhassett {
711f9a376c3SEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
712f9a376c3SEliot Blennerhassett 	u32 hsr = 0;
713f9a376c3SEliot Blennerhassett 
714f9a376c3SEliot Blennerhassett 	hsr = ioread32(phw->prHSR);
715f9a376c3SEliot Blennerhassett 	if (hsr & C6205_HSR_INTSRC) {
716f9a376c3SEliot Blennerhassett 		/* reset the interrupt from the DSP */
717f9a376c3SEliot Blennerhassett 		iowrite32(C6205_HSR_INTSRC, phw->prHSR);
718f9a376c3SEliot Blennerhassett 		return HPI_IRQ_MIXER;
719f9a376c3SEliot Blennerhassett 	}
720f9a376c3SEliot Blennerhassett 
721f9a376c3SEliot Blennerhassett 	return HPI_IRQ_NONE;
722f9a376c3SEliot Blennerhassett }
7231d595d2aSEliot Blennerhassett 
7241d595d2aSEliot Blennerhassett /*****************************************************************************/
725719f82d3SEliot Blennerhassett /* OutStream Host buffer functions */
726719f82d3SEliot Blennerhassett 
727719f82d3SEliot Blennerhassett /** Allocate or attach buffer for busmastering
728719f82d3SEliot Blennerhassett */
outstream_host_buffer_allocate(struct hpi_adapter_obj * pao,struct hpi_message * phm,struct hpi_response * phr)729719f82d3SEliot Blennerhassett static void outstream_host_buffer_allocate(struct hpi_adapter_obj *pao,
730719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
731719f82d3SEliot Blennerhassett {
732719f82d3SEliot Blennerhassett 	u16 err = 0;
733719f82d3SEliot Blennerhassett 	u32 command = phm->u.d.u.buffer.command;
734719f82d3SEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
735719f82d3SEliot Blennerhassett 	struct bus_master_interface *interface = phw->p_interface_buffer;
736719f82d3SEliot Blennerhassett 
737719f82d3SEliot Blennerhassett 	hpi_init_response(phr, phm->object, phm->function, 0);
738719f82d3SEliot Blennerhassett 
739719f82d3SEliot Blennerhassett 	if (command == HPI_BUFFER_CMD_EXTERNAL
740719f82d3SEliot Blennerhassett 		|| command == HPI_BUFFER_CMD_INTERNAL_ALLOC) {
741719f82d3SEliot Blennerhassett 		/* ALLOC phase, allocate a buffer with power of 2 size,
742719f82d3SEliot Blennerhassett 		   get its bus address for PCI bus mastering
743719f82d3SEliot Blennerhassett 		 */
744719f82d3SEliot Blennerhassett 		phm->u.d.u.buffer.buffer_size =
745719f82d3SEliot Blennerhassett 			roundup_pow_of_two(phm->u.d.u.buffer.buffer_size);
746719f82d3SEliot Blennerhassett 		/* return old size and allocated size,
747719f82d3SEliot Blennerhassett 		   so caller can detect change */
748719f82d3SEliot Blennerhassett 		phr->u.d.u.stream_info.data_available =
749719f82d3SEliot Blennerhassett 			phw->outstream_host_buffer_size[phm->obj_index];
750719f82d3SEliot Blennerhassett 		phr->u.d.u.stream_info.buffer_size =
751719f82d3SEliot Blennerhassett 			phm->u.d.u.buffer.buffer_size;
752719f82d3SEliot Blennerhassett 
753719f82d3SEliot Blennerhassett 		if (phw->outstream_host_buffer_size[phm->obj_index] ==
754719f82d3SEliot Blennerhassett 			phm->u.d.u.buffer.buffer_size) {
755719f82d3SEliot Blennerhassett 			/* Same size, no action required */
756719f82d3SEliot Blennerhassett 			return;
757719f82d3SEliot Blennerhassett 		}
758719f82d3SEliot Blennerhassett 
759719f82d3SEliot Blennerhassett 		if (hpios_locked_mem_valid(&phw->outstream_host_buffers[phm->
760719f82d3SEliot Blennerhassett 					obj_index]))
761719f82d3SEliot Blennerhassett 			hpios_locked_mem_free(&phw->outstream_host_buffers
762719f82d3SEliot Blennerhassett 				[phm->obj_index]);
763719f82d3SEliot Blennerhassett 
764719f82d3SEliot Blennerhassett 		err = hpios_locked_mem_alloc(&phw->outstream_host_buffers
765719f82d3SEliot Blennerhassett 			[phm->obj_index], phm->u.d.u.buffer.buffer_size,
7663285ea10SEliot Blennerhassett 			pao->pci.pci_dev);
767719f82d3SEliot Blennerhassett 
768719f82d3SEliot Blennerhassett 		if (err) {
769719f82d3SEliot Blennerhassett 			phr->error = HPI_ERROR_INVALID_DATASIZE;
770719f82d3SEliot Blennerhassett 			phw->outstream_host_buffer_size[phm->obj_index] = 0;
771719f82d3SEliot Blennerhassett 			return;
772719f82d3SEliot Blennerhassett 		}
773719f82d3SEliot Blennerhassett 
774719f82d3SEliot Blennerhassett 		err = hpios_locked_mem_get_phys_addr
775719f82d3SEliot Blennerhassett 			(&phw->outstream_host_buffers[phm->obj_index],
776719f82d3SEliot Blennerhassett 			&phm->u.d.u.buffer.pci_address);
777719f82d3SEliot Blennerhassett 		/* get the phys addr into msg for single call alloc caller
778719f82d3SEliot Blennerhassett 		 * needs to do this for split alloc (or use the same message)
779719f82d3SEliot Blennerhassett 		 * return the phy address for split alloc in the respose too
780719f82d3SEliot Blennerhassett 		 */
781719f82d3SEliot Blennerhassett 		phr->u.d.u.stream_info.auxiliary_data_available =
782719f82d3SEliot Blennerhassett 			phm->u.d.u.buffer.pci_address;
783719f82d3SEliot Blennerhassett 
784719f82d3SEliot Blennerhassett 		if (err) {
785719f82d3SEliot Blennerhassett 			hpios_locked_mem_free(&phw->outstream_host_buffers
786719f82d3SEliot Blennerhassett 				[phm->obj_index]);
787719f82d3SEliot Blennerhassett 			phw->outstream_host_buffer_size[phm->obj_index] = 0;
788719f82d3SEliot Blennerhassett 			phr->error = HPI_ERROR_MEMORY_ALLOC;
789719f82d3SEliot Blennerhassett 			return;
790719f82d3SEliot Blennerhassett 		}
791719f82d3SEliot Blennerhassett 	}
792719f82d3SEliot Blennerhassett 
793719f82d3SEliot Blennerhassett 	if (command == HPI_BUFFER_CMD_EXTERNAL
794719f82d3SEliot Blennerhassett 		|| command == HPI_BUFFER_CMD_INTERNAL_GRANTADAPTER) {
795719f82d3SEliot Blennerhassett 		/* GRANT phase.  Set up the BBM status, tell the DSP about
796719f82d3SEliot Blennerhassett 		   the buffer so it can start using BBM.
797719f82d3SEliot Blennerhassett 		 */
798719f82d3SEliot Blennerhassett 		struct hpi_hostbuffer_status *status;
799719f82d3SEliot Blennerhassett 
800719f82d3SEliot Blennerhassett 		if (phm->u.d.u.buffer.buffer_size & (phm->u.d.u.buffer.
801719f82d3SEliot Blennerhassett 				buffer_size - 1)) {
802719f82d3SEliot Blennerhassett 			HPI_DEBUG_LOG(ERROR,
8033285ea10SEliot Blennerhassett 				"Buffer size must be 2^N not %d\n",
804719f82d3SEliot Blennerhassett 				phm->u.d.u.buffer.buffer_size);
805719f82d3SEliot Blennerhassett 			phr->error = HPI_ERROR_INVALID_DATASIZE;
806719f82d3SEliot Blennerhassett 			return;
807719f82d3SEliot Blennerhassett 		}
808719f82d3SEliot Blennerhassett 		phw->outstream_host_buffer_size[phm->obj_index] =
809719f82d3SEliot Blennerhassett 			phm->u.d.u.buffer.buffer_size;
810719f82d3SEliot Blennerhassett 		status = &interface->outstream_host_buffer_status[phm->
811719f82d3SEliot Blennerhassett 			obj_index];
812719f82d3SEliot Blennerhassett 		status->samples_processed = 0;
813719f82d3SEliot Blennerhassett 		status->stream_state = HPI_STATE_STOPPED;
8148e0874eaSEliot Blennerhassett 		status->dsp_index = 0;
8158e0874eaSEliot Blennerhassett 		status->host_index = status->dsp_index;
816719f82d3SEliot Blennerhassett 		status->size_in_bytes = phm->u.d.u.buffer.buffer_size;
817deb21a23SEliot Blennerhassett 		status->auxiliary_data_available = 0;
818719f82d3SEliot Blennerhassett 
819719f82d3SEliot Blennerhassett 		hw_message(pao, phm, phr);
820719f82d3SEliot Blennerhassett 
821719f82d3SEliot Blennerhassett 		if (phr->error
822719f82d3SEliot Blennerhassett 			&& hpios_locked_mem_valid(&phw->
823719f82d3SEliot Blennerhassett 				outstream_host_buffers[phm->obj_index])) {
824719f82d3SEliot Blennerhassett 			hpios_locked_mem_free(&phw->outstream_host_buffers
825719f82d3SEliot Blennerhassett 				[phm->obj_index]);
826719f82d3SEliot Blennerhassett 			phw->outstream_host_buffer_size[phm->obj_index] = 0;
827719f82d3SEliot Blennerhassett 		}
828719f82d3SEliot Blennerhassett 	}
829719f82d3SEliot Blennerhassett }
830719f82d3SEliot Blennerhassett 
outstream_host_buffer_get_info(struct hpi_adapter_obj * pao,struct hpi_message * phm,struct hpi_response * phr)831719f82d3SEliot Blennerhassett static void outstream_host_buffer_get_info(struct hpi_adapter_obj *pao,
832719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
833719f82d3SEliot Blennerhassett {
834719f82d3SEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
835719f82d3SEliot Blennerhassett 	struct bus_master_interface *interface = phw->p_interface_buffer;
836719f82d3SEliot Blennerhassett 	struct hpi_hostbuffer_status *status;
837719f82d3SEliot Blennerhassett 	u8 *p_bbm_data;
838719f82d3SEliot Blennerhassett 
839719f82d3SEliot Blennerhassett 	if (hpios_locked_mem_valid(&phw->outstream_host_buffers[phm->
840719f82d3SEliot Blennerhassett 				obj_index])) {
841719f82d3SEliot Blennerhassett 		if (hpios_locked_mem_get_virt_addr(&phw->
842719f82d3SEliot Blennerhassett 				outstream_host_buffers[phm->obj_index],
843719f82d3SEliot Blennerhassett 				(void *)&p_bbm_data)) {
844719f82d3SEliot Blennerhassett 			phr->error = HPI_ERROR_INVALID_OPERATION;
845719f82d3SEliot Blennerhassett 			return;
846719f82d3SEliot Blennerhassett 		}
847719f82d3SEliot Blennerhassett 		status = &interface->outstream_host_buffer_status[phm->
848719f82d3SEliot Blennerhassett 			obj_index];
849719f82d3SEliot Blennerhassett 		hpi_init_response(phr, HPI_OBJ_OSTREAM,
850719f82d3SEliot Blennerhassett 			HPI_OSTREAM_HOSTBUFFER_GET_INFO, 0);
851719f82d3SEliot Blennerhassett 		phr->u.d.u.hostbuffer_info.p_buffer = p_bbm_data;
852719f82d3SEliot Blennerhassett 		phr->u.d.u.hostbuffer_info.p_status = status;
853719f82d3SEliot Blennerhassett 	} else {
854719f82d3SEliot Blennerhassett 		hpi_init_response(phr, HPI_OBJ_OSTREAM,
855719f82d3SEliot Blennerhassett 			HPI_OSTREAM_HOSTBUFFER_GET_INFO,
856719f82d3SEliot Blennerhassett 			HPI_ERROR_INVALID_OPERATION);
857719f82d3SEliot Blennerhassett 	}
858719f82d3SEliot Blennerhassett }
859719f82d3SEliot Blennerhassett 
outstream_host_buffer_free(struct hpi_adapter_obj * pao,struct hpi_message * phm,struct hpi_response * phr)860719f82d3SEliot Blennerhassett static void outstream_host_buffer_free(struct hpi_adapter_obj *pao,
861719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
862719f82d3SEliot Blennerhassett {
863719f82d3SEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
864719f82d3SEliot Blennerhassett 	u32 command = phm->u.d.u.buffer.command;
865719f82d3SEliot Blennerhassett 
866719f82d3SEliot Blennerhassett 	if (phw->outstream_host_buffer_size[phm->obj_index]) {
867719f82d3SEliot Blennerhassett 		if (command == HPI_BUFFER_CMD_EXTERNAL
868719f82d3SEliot Blennerhassett 			|| command == HPI_BUFFER_CMD_INTERNAL_REVOKEADAPTER) {
869719f82d3SEliot Blennerhassett 			phw->outstream_host_buffer_size[phm->obj_index] = 0;
870719f82d3SEliot Blennerhassett 			hw_message(pao, phm, phr);
871719f82d3SEliot Blennerhassett 			/* Tell adapter to stop using the host buffer. */
872719f82d3SEliot Blennerhassett 		}
873719f82d3SEliot Blennerhassett 		if (command == HPI_BUFFER_CMD_EXTERNAL
874719f82d3SEliot Blennerhassett 			|| command == HPI_BUFFER_CMD_INTERNAL_FREE)
875719f82d3SEliot Blennerhassett 			hpios_locked_mem_free(&phw->outstream_host_buffers
876719f82d3SEliot Blennerhassett 				[phm->obj_index]);
877719f82d3SEliot Blennerhassett 	}
878719f82d3SEliot Blennerhassett 	/* Should HPI_ERROR_INVALID_OPERATION be returned
879719f82d3SEliot Blennerhassett 	   if no host buffer is allocated? */
880719f82d3SEliot Blennerhassett 	else
881719f82d3SEliot Blennerhassett 		hpi_init_response(phr, HPI_OBJ_OSTREAM,
882719f82d3SEliot Blennerhassett 			HPI_OSTREAM_HOSTBUFFER_FREE, 0);
883719f82d3SEliot Blennerhassett 
884719f82d3SEliot Blennerhassett }
885719f82d3SEliot Blennerhassett 
outstream_get_space_available(struct hpi_hostbuffer_status * status)88660f1deb5SEliot Blennerhassett static u32 outstream_get_space_available(struct hpi_hostbuffer_status *status)
887719f82d3SEliot Blennerhassett {
8882a383cb3SEliot Blennerhassett 	return status->size_in_bytes - (status->host_index -
8898e0874eaSEliot Blennerhassett 		status->dsp_index);
890719f82d3SEliot Blennerhassett }
891719f82d3SEliot Blennerhassett 
outstream_write(struct hpi_adapter_obj * pao,struct hpi_message * phm,struct hpi_response * phr)892719f82d3SEliot Blennerhassett static void outstream_write(struct hpi_adapter_obj *pao,
893719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
894719f82d3SEliot Blennerhassett {
895719f82d3SEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
896719f82d3SEliot Blennerhassett 	struct bus_master_interface *interface = phw->p_interface_buffer;
897719f82d3SEliot Blennerhassett 	struct hpi_hostbuffer_status *status;
8982a383cb3SEliot Blennerhassett 	u32 space_available;
899719f82d3SEliot Blennerhassett 
900719f82d3SEliot Blennerhassett 	if (!phw->outstream_host_buffer_size[phm->obj_index]) {
901719f82d3SEliot Blennerhassett 		/* there  is no BBM buffer, write via message */
902719f82d3SEliot Blennerhassett 		hw_message(pao, phm, phr);
903719f82d3SEliot Blennerhassett 		return;
904719f82d3SEliot Blennerhassett 	}
905719f82d3SEliot Blennerhassett 
906719f82d3SEliot Blennerhassett 	hpi_init_response(phr, phm->object, phm->function, 0);
907719f82d3SEliot Blennerhassett 	status = &interface->outstream_host_buffer_status[phm->obj_index];
908719f82d3SEliot Blennerhassett 
909719f82d3SEliot Blennerhassett 	space_available = outstream_get_space_available(status);
9102a383cb3SEliot Blennerhassett 	if (space_available < phm->u.d.u.data.data_size) {
911719f82d3SEliot Blennerhassett 		phr->error = HPI_ERROR_INVALID_DATASIZE;
912719f82d3SEliot Blennerhassett 		return;
913719f82d3SEliot Blennerhassett 	}
914719f82d3SEliot Blennerhassett 
915719f82d3SEliot Blennerhassett 	/* HostBuffers is used to indicate host buffer is internally allocated.
916719f82d3SEliot Blennerhassett 	   otherwise, assumed external, data written externally */
917719f82d3SEliot Blennerhassett 	if (phm->u.d.u.data.pb_data
918719f82d3SEliot Blennerhassett 		&& hpios_locked_mem_valid(&phw->outstream_host_buffers[phm->
919719f82d3SEliot Blennerhassett 				obj_index])) {
920719f82d3SEliot Blennerhassett 		u8 *p_bbm_data;
9212a383cb3SEliot Blennerhassett 		u32 l_first_write;
922719f82d3SEliot Blennerhassett 		u8 *p_app_data = (u8 *)phm->u.d.u.data.pb_data;
923719f82d3SEliot Blennerhassett 
924719f82d3SEliot Blennerhassett 		if (hpios_locked_mem_get_virt_addr(&phw->
925719f82d3SEliot Blennerhassett 				outstream_host_buffers[phm->obj_index],
926719f82d3SEliot Blennerhassett 				(void *)&p_bbm_data)) {
927719f82d3SEliot Blennerhassett 			phr->error = HPI_ERROR_INVALID_OPERATION;
928719f82d3SEliot Blennerhassett 			return;
929719f82d3SEliot Blennerhassett 		}
930719f82d3SEliot Blennerhassett 
931719f82d3SEliot Blennerhassett 		/* either all data,
932719f82d3SEliot Blennerhassett 		   or enough to fit from current to end of BBM buffer */
933719f82d3SEliot Blennerhassett 		l_first_write =
934719f82d3SEliot Blennerhassett 			min(phm->u.d.u.data.data_size,
935719f82d3SEliot Blennerhassett 			status->size_in_bytes -
936719f82d3SEliot Blennerhassett 			(status->host_index & (status->size_in_bytes - 1)));
937719f82d3SEliot Blennerhassett 
938719f82d3SEliot Blennerhassett 		memcpy(p_bbm_data +
939719f82d3SEliot Blennerhassett 			(status->host_index & (status->size_in_bytes - 1)),
940719f82d3SEliot Blennerhassett 			p_app_data, l_first_write);
941719f82d3SEliot Blennerhassett 		/* remaining data if any */
942719f82d3SEliot Blennerhassett 		memcpy(p_bbm_data, p_app_data + l_first_write,
943719f82d3SEliot Blennerhassett 			phm->u.d.u.data.data_size - l_first_write);
944719f82d3SEliot Blennerhassett 	}
9453285ea10SEliot Blennerhassett 
9463285ea10SEliot Blennerhassett 	/*
9473285ea10SEliot Blennerhassett 	 * This version relies on the DSP code triggering an OStream buffer
9483285ea10SEliot Blennerhassett 	 * update immediately following a SET_FORMAT call. The host has
949deb21a23SEliot Blennerhassett 	 * already written data into the BBM buffer, but the DSP won't know
950deb21a23SEliot Blennerhassett 	 * about it until dwHostIndex is adjusted.
9513285ea10SEliot Blennerhassett 	 */
9523285ea10SEliot Blennerhassett 	if (phw->flag_outstream_just_reset[phm->obj_index]) {
9533285ea10SEliot Blennerhassett 		/* Format can only change after reset. Must tell DSP. */
9543285ea10SEliot Blennerhassett 		u16 function = phm->function;
9553285ea10SEliot Blennerhassett 		phw->flag_outstream_just_reset[phm->obj_index] = 0;
9563285ea10SEliot Blennerhassett 		phm->function = HPI_OSTREAM_SET_FORMAT;
9573285ea10SEliot Blennerhassett 		hw_message(pao, phm, phr);	/* send the format to the DSP */
9583285ea10SEliot Blennerhassett 		phm->function = function;
9593285ea10SEliot Blennerhassett 		if (phr->error)
9603285ea10SEliot Blennerhassett 			return;
9613285ea10SEliot Blennerhassett 	}
9623285ea10SEliot Blennerhassett 
963719f82d3SEliot Blennerhassett 	status->host_index += phm->u.d.u.data.data_size;
964719f82d3SEliot Blennerhassett }
965719f82d3SEliot Blennerhassett 
outstream_get_info(struct hpi_adapter_obj * pao,struct hpi_message * phm,struct hpi_response * phr)966719f82d3SEliot Blennerhassett static void outstream_get_info(struct hpi_adapter_obj *pao,
967719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
968719f82d3SEliot Blennerhassett {
969719f82d3SEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
970719f82d3SEliot Blennerhassett 	struct bus_master_interface *interface = phw->p_interface_buffer;
971719f82d3SEliot Blennerhassett 	struct hpi_hostbuffer_status *status;
972719f82d3SEliot Blennerhassett 
973719f82d3SEliot Blennerhassett 	if (!phw->outstream_host_buffer_size[phm->obj_index]) {
974719f82d3SEliot Blennerhassett 		hw_message(pao, phm, phr);
975719f82d3SEliot Blennerhassett 		return;
976719f82d3SEliot Blennerhassett 	}
977719f82d3SEliot Blennerhassett 
978719f82d3SEliot Blennerhassett 	hpi_init_response(phr, phm->object, phm->function, 0);
979719f82d3SEliot Blennerhassett 
980719f82d3SEliot Blennerhassett 	status = &interface->outstream_host_buffer_status[phm->obj_index];
981719f82d3SEliot Blennerhassett 
982719f82d3SEliot Blennerhassett 	phr->u.d.u.stream_info.state = (u16)status->stream_state;
983719f82d3SEliot Blennerhassett 	phr->u.d.u.stream_info.samples_transferred =
984719f82d3SEliot Blennerhassett 		status->samples_processed;
985719f82d3SEliot Blennerhassett 	phr->u.d.u.stream_info.buffer_size = status->size_in_bytes;
986719f82d3SEliot Blennerhassett 	phr->u.d.u.stream_info.data_available =
987719f82d3SEliot Blennerhassett 		status->size_in_bytes - outstream_get_space_available(status);
988719f82d3SEliot Blennerhassett 	phr->u.d.u.stream_info.auxiliary_data_available =
989719f82d3SEliot Blennerhassett 		status->auxiliary_data_available;
990719f82d3SEliot Blennerhassett }
991719f82d3SEliot Blennerhassett 
outstream_start(struct hpi_adapter_obj * pao,struct hpi_message * phm,struct hpi_response * phr)992719f82d3SEliot Blennerhassett static void outstream_start(struct hpi_adapter_obj *pao,
993719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
994719f82d3SEliot Blennerhassett {
995719f82d3SEliot Blennerhassett 	hw_message(pao, phm, phr);
996719f82d3SEliot Blennerhassett }
997719f82d3SEliot Blennerhassett 
outstream_reset(struct hpi_adapter_obj * pao,struct hpi_message * phm,struct hpi_response * phr)998719f82d3SEliot Blennerhassett static void outstream_reset(struct hpi_adapter_obj *pao,
999719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
1000719f82d3SEliot Blennerhassett {
1001719f82d3SEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
1002719f82d3SEliot Blennerhassett 	phw->flag_outstream_just_reset[phm->obj_index] = 1;
1003719f82d3SEliot Blennerhassett 	hw_message(pao, phm, phr);
1004719f82d3SEliot Blennerhassett }
1005719f82d3SEliot Blennerhassett 
outstream_open(struct hpi_adapter_obj * pao,struct hpi_message * phm,struct hpi_response * phr)1006719f82d3SEliot Blennerhassett static void outstream_open(struct hpi_adapter_obj *pao,
1007719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
1008719f82d3SEliot Blennerhassett {
1009719f82d3SEliot Blennerhassett 	outstream_reset(pao, phm, phr);
1010719f82d3SEliot Blennerhassett }
1011719f82d3SEliot Blennerhassett 
1012719f82d3SEliot Blennerhassett /*****************************************************************************/
1013719f82d3SEliot Blennerhassett /* InStream Host buffer functions */
1014719f82d3SEliot Blennerhassett 
instream_host_buffer_allocate(struct hpi_adapter_obj * pao,struct hpi_message * phm,struct hpi_response * phr)1015719f82d3SEliot Blennerhassett static void instream_host_buffer_allocate(struct hpi_adapter_obj *pao,
1016719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
1017719f82d3SEliot Blennerhassett {
1018719f82d3SEliot Blennerhassett 	u16 err = 0;
1019719f82d3SEliot Blennerhassett 	u32 command = phm->u.d.u.buffer.command;
1020719f82d3SEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
1021719f82d3SEliot Blennerhassett 	struct bus_master_interface *interface = phw->p_interface_buffer;
1022719f82d3SEliot Blennerhassett 
1023719f82d3SEliot Blennerhassett 	hpi_init_response(phr, phm->object, phm->function, 0);
1024719f82d3SEliot Blennerhassett 
1025719f82d3SEliot Blennerhassett 	if (command == HPI_BUFFER_CMD_EXTERNAL
1026719f82d3SEliot Blennerhassett 		|| command == HPI_BUFFER_CMD_INTERNAL_ALLOC) {
1027719f82d3SEliot Blennerhassett 
1028719f82d3SEliot Blennerhassett 		phm->u.d.u.buffer.buffer_size =
1029719f82d3SEliot Blennerhassett 			roundup_pow_of_two(phm->u.d.u.buffer.buffer_size);
1030719f82d3SEliot Blennerhassett 		phr->u.d.u.stream_info.data_available =
1031719f82d3SEliot Blennerhassett 			phw->instream_host_buffer_size[phm->obj_index];
1032719f82d3SEliot Blennerhassett 		phr->u.d.u.stream_info.buffer_size =
1033719f82d3SEliot Blennerhassett 			phm->u.d.u.buffer.buffer_size;
1034719f82d3SEliot Blennerhassett 
1035719f82d3SEliot Blennerhassett 		if (phw->instream_host_buffer_size[phm->obj_index] ==
1036719f82d3SEliot Blennerhassett 			phm->u.d.u.buffer.buffer_size) {
1037719f82d3SEliot Blennerhassett 			/* Same size, no action required */
1038719f82d3SEliot Blennerhassett 			return;
1039719f82d3SEliot Blennerhassett 		}
1040719f82d3SEliot Blennerhassett 
1041719f82d3SEliot Blennerhassett 		if (hpios_locked_mem_valid(&phw->instream_host_buffers[phm->
1042719f82d3SEliot Blennerhassett 					obj_index]))
1043719f82d3SEliot Blennerhassett 			hpios_locked_mem_free(&phw->instream_host_buffers
1044719f82d3SEliot Blennerhassett 				[phm->obj_index]);
1045719f82d3SEliot Blennerhassett 
1046719f82d3SEliot Blennerhassett 		err = hpios_locked_mem_alloc(&phw->instream_host_buffers[phm->
1047719f82d3SEliot Blennerhassett 				obj_index], phm->u.d.u.buffer.buffer_size,
10483285ea10SEliot Blennerhassett 			pao->pci.pci_dev);
1049719f82d3SEliot Blennerhassett 
1050719f82d3SEliot Blennerhassett 		if (err) {
1051719f82d3SEliot Blennerhassett 			phr->error = HPI_ERROR_INVALID_DATASIZE;
1052719f82d3SEliot Blennerhassett 			phw->instream_host_buffer_size[phm->obj_index] = 0;
1053719f82d3SEliot Blennerhassett 			return;
1054719f82d3SEliot Blennerhassett 		}
1055719f82d3SEliot Blennerhassett 
1056719f82d3SEliot Blennerhassett 		err = hpios_locked_mem_get_phys_addr
1057719f82d3SEliot Blennerhassett 			(&phw->instream_host_buffers[phm->obj_index],
1058719f82d3SEliot Blennerhassett 			&phm->u.d.u.buffer.pci_address);
1059719f82d3SEliot Blennerhassett 		/* get the phys addr into msg for single call alloc. Caller
1060719f82d3SEliot Blennerhassett 		   needs to do this for split alloc so return the phy address */
1061719f82d3SEliot Blennerhassett 		phr->u.d.u.stream_info.auxiliary_data_available =
1062719f82d3SEliot Blennerhassett 			phm->u.d.u.buffer.pci_address;
1063719f82d3SEliot Blennerhassett 		if (err) {
1064719f82d3SEliot Blennerhassett 			hpios_locked_mem_free(&phw->instream_host_buffers
1065719f82d3SEliot Blennerhassett 				[phm->obj_index]);
1066719f82d3SEliot Blennerhassett 			phw->instream_host_buffer_size[phm->obj_index] = 0;
1067719f82d3SEliot Blennerhassett 			phr->error = HPI_ERROR_MEMORY_ALLOC;
1068719f82d3SEliot Blennerhassett 			return;
1069719f82d3SEliot Blennerhassett 		}
1070719f82d3SEliot Blennerhassett 	}
1071719f82d3SEliot Blennerhassett 
1072719f82d3SEliot Blennerhassett 	if (command == HPI_BUFFER_CMD_EXTERNAL
1073719f82d3SEliot Blennerhassett 		|| command == HPI_BUFFER_CMD_INTERNAL_GRANTADAPTER) {
1074719f82d3SEliot Blennerhassett 		struct hpi_hostbuffer_status *status;
1075719f82d3SEliot Blennerhassett 
1076719f82d3SEliot Blennerhassett 		if (phm->u.d.u.buffer.buffer_size & (phm->u.d.u.buffer.
1077719f82d3SEliot Blennerhassett 				buffer_size - 1)) {
1078719f82d3SEliot Blennerhassett 			HPI_DEBUG_LOG(ERROR,
10793285ea10SEliot Blennerhassett 				"Buffer size must be 2^N not %d\n",
1080719f82d3SEliot Blennerhassett 				phm->u.d.u.buffer.buffer_size);
1081719f82d3SEliot Blennerhassett 			phr->error = HPI_ERROR_INVALID_DATASIZE;
1082719f82d3SEliot Blennerhassett 			return;
1083719f82d3SEliot Blennerhassett 		}
1084719f82d3SEliot Blennerhassett 
1085719f82d3SEliot Blennerhassett 		phw->instream_host_buffer_size[phm->obj_index] =
1086719f82d3SEliot Blennerhassett 			phm->u.d.u.buffer.buffer_size;
1087719f82d3SEliot Blennerhassett 		status = &interface->instream_host_buffer_status[phm->
1088719f82d3SEliot Blennerhassett 			obj_index];
1089719f82d3SEliot Blennerhassett 		status->samples_processed = 0;
1090719f82d3SEliot Blennerhassett 		status->stream_state = HPI_STATE_STOPPED;
10918e0874eaSEliot Blennerhassett 		status->dsp_index = 0;
10928e0874eaSEliot Blennerhassett 		status->host_index = status->dsp_index;
1093719f82d3SEliot Blennerhassett 		status->size_in_bytes = phm->u.d.u.buffer.buffer_size;
1094deb21a23SEliot Blennerhassett 		status->auxiliary_data_available = 0;
1095719f82d3SEliot Blennerhassett 
1096719f82d3SEliot Blennerhassett 		hw_message(pao, phm, phr);
1097ba3a9099SEliot Blennerhassett 
1098719f82d3SEliot Blennerhassett 		if (phr->error
1099719f82d3SEliot Blennerhassett 			&& hpios_locked_mem_valid(&phw->
1100719f82d3SEliot Blennerhassett 				instream_host_buffers[phm->obj_index])) {
1101719f82d3SEliot Blennerhassett 			hpios_locked_mem_free(&phw->instream_host_buffers
1102719f82d3SEliot Blennerhassett 				[phm->obj_index]);
1103719f82d3SEliot Blennerhassett 			phw->instream_host_buffer_size[phm->obj_index] = 0;
1104719f82d3SEliot Blennerhassett 		}
1105719f82d3SEliot Blennerhassett 	}
1106719f82d3SEliot Blennerhassett }
1107719f82d3SEliot Blennerhassett 
instream_host_buffer_get_info(struct hpi_adapter_obj * pao,struct hpi_message * phm,struct hpi_response * phr)1108719f82d3SEliot Blennerhassett static void instream_host_buffer_get_info(struct hpi_adapter_obj *pao,
1109719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
1110719f82d3SEliot Blennerhassett {
1111719f82d3SEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
1112719f82d3SEliot Blennerhassett 	struct bus_master_interface *interface = phw->p_interface_buffer;
1113719f82d3SEliot Blennerhassett 	struct hpi_hostbuffer_status *status;
1114719f82d3SEliot Blennerhassett 	u8 *p_bbm_data;
1115719f82d3SEliot Blennerhassett 
1116719f82d3SEliot Blennerhassett 	if (hpios_locked_mem_valid(&phw->instream_host_buffers[phm->
1117719f82d3SEliot Blennerhassett 				obj_index])) {
1118719f82d3SEliot Blennerhassett 		if (hpios_locked_mem_get_virt_addr(&phw->
1119719f82d3SEliot Blennerhassett 				instream_host_buffers[phm->obj_index],
1120719f82d3SEliot Blennerhassett 				(void *)&p_bbm_data)) {
1121719f82d3SEliot Blennerhassett 			phr->error = HPI_ERROR_INVALID_OPERATION;
1122719f82d3SEliot Blennerhassett 			return;
1123719f82d3SEliot Blennerhassett 		}
1124719f82d3SEliot Blennerhassett 		status = &interface->instream_host_buffer_status[phm->
1125719f82d3SEliot Blennerhassett 			obj_index];
1126719f82d3SEliot Blennerhassett 		hpi_init_response(phr, HPI_OBJ_ISTREAM,
1127719f82d3SEliot Blennerhassett 			HPI_ISTREAM_HOSTBUFFER_GET_INFO, 0);
1128719f82d3SEliot Blennerhassett 		phr->u.d.u.hostbuffer_info.p_buffer = p_bbm_data;
1129719f82d3SEliot Blennerhassett 		phr->u.d.u.hostbuffer_info.p_status = status;
1130719f82d3SEliot Blennerhassett 	} else {
1131719f82d3SEliot Blennerhassett 		hpi_init_response(phr, HPI_OBJ_ISTREAM,
1132719f82d3SEliot Blennerhassett 			HPI_ISTREAM_HOSTBUFFER_GET_INFO,
1133719f82d3SEliot Blennerhassett 			HPI_ERROR_INVALID_OPERATION);
1134719f82d3SEliot Blennerhassett 	}
1135719f82d3SEliot Blennerhassett }
1136719f82d3SEliot Blennerhassett 
instream_host_buffer_free(struct hpi_adapter_obj * pao,struct hpi_message * phm,struct hpi_response * phr)1137719f82d3SEliot Blennerhassett static void instream_host_buffer_free(struct hpi_adapter_obj *pao,
1138719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
1139719f82d3SEliot Blennerhassett {
1140719f82d3SEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
1141719f82d3SEliot Blennerhassett 	u32 command = phm->u.d.u.buffer.command;
1142719f82d3SEliot Blennerhassett 
1143719f82d3SEliot Blennerhassett 	if (phw->instream_host_buffer_size[phm->obj_index]) {
1144719f82d3SEliot Blennerhassett 		if (command == HPI_BUFFER_CMD_EXTERNAL
1145719f82d3SEliot Blennerhassett 			|| command == HPI_BUFFER_CMD_INTERNAL_REVOKEADAPTER) {
1146719f82d3SEliot Blennerhassett 			phw->instream_host_buffer_size[phm->obj_index] = 0;
1147719f82d3SEliot Blennerhassett 			hw_message(pao, phm, phr);
1148719f82d3SEliot Blennerhassett 		}
1149719f82d3SEliot Blennerhassett 
1150719f82d3SEliot Blennerhassett 		if (command == HPI_BUFFER_CMD_EXTERNAL
1151719f82d3SEliot Blennerhassett 			|| command == HPI_BUFFER_CMD_INTERNAL_FREE)
1152719f82d3SEliot Blennerhassett 			hpios_locked_mem_free(&phw->instream_host_buffers
1153719f82d3SEliot Blennerhassett 				[phm->obj_index]);
1154719f82d3SEliot Blennerhassett 
1155719f82d3SEliot Blennerhassett 	} else {
1156719f82d3SEliot Blennerhassett 		/* Should HPI_ERROR_INVALID_OPERATION be returned
1157719f82d3SEliot Blennerhassett 		   if no host buffer is allocated? */
1158719f82d3SEliot Blennerhassett 		hpi_init_response(phr, HPI_OBJ_ISTREAM,
1159719f82d3SEliot Blennerhassett 			HPI_ISTREAM_HOSTBUFFER_FREE, 0);
1160719f82d3SEliot Blennerhassett 
1161719f82d3SEliot Blennerhassett 	}
1162719f82d3SEliot Blennerhassett 
1163719f82d3SEliot Blennerhassett }
1164719f82d3SEliot Blennerhassett 
instream_start(struct hpi_adapter_obj * pao,struct hpi_message * phm,struct hpi_response * phr)1165719f82d3SEliot Blennerhassett static void instream_start(struct hpi_adapter_obj *pao,
1166719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
1167719f82d3SEliot Blennerhassett {
1168719f82d3SEliot Blennerhassett 	hw_message(pao, phm, phr);
1169719f82d3SEliot Blennerhassett }
1170719f82d3SEliot Blennerhassett 
instream_get_bytes_available(struct hpi_hostbuffer_status * status)11712a383cb3SEliot Blennerhassett static u32 instream_get_bytes_available(struct hpi_hostbuffer_status *status)
1172719f82d3SEliot Blennerhassett {
11738e0874eaSEliot Blennerhassett 	return status->dsp_index - status->host_index;
1174719f82d3SEliot Blennerhassett }
1175719f82d3SEliot Blennerhassett 
instream_read(struct hpi_adapter_obj * pao,struct hpi_message * phm,struct hpi_response * phr)1176719f82d3SEliot Blennerhassett static void instream_read(struct hpi_adapter_obj *pao,
1177719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
1178719f82d3SEliot Blennerhassett {
1179719f82d3SEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
1180719f82d3SEliot Blennerhassett 	struct bus_master_interface *interface = phw->p_interface_buffer;
1181719f82d3SEliot Blennerhassett 	struct hpi_hostbuffer_status *status;
11822a383cb3SEliot Blennerhassett 	u32 data_available;
1183719f82d3SEliot Blennerhassett 	u8 *p_bbm_data;
11842a383cb3SEliot Blennerhassett 	u32 l_first_read;
1185719f82d3SEliot Blennerhassett 	u8 *p_app_data = (u8 *)phm->u.d.u.data.pb_data;
1186719f82d3SEliot Blennerhassett 
1187719f82d3SEliot Blennerhassett 	if (!phw->instream_host_buffer_size[phm->obj_index]) {
1188719f82d3SEliot Blennerhassett 		hw_message(pao, phm, phr);
1189719f82d3SEliot Blennerhassett 		return;
1190719f82d3SEliot Blennerhassett 	}
1191719f82d3SEliot Blennerhassett 	hpi_init_response(phr, phm->object, phm->function, 0);
1192719f82d3SEliot Blennerhassett 
1193719f82d3SEliot Blennerhassett 	status = &interface->instream_host_buffer_status[phm->obj_index];
1194719f82d3SEliot Blennerhassett 	data_available = instream_get_bytes_available(status);
11952a383cb3SEliot Blennerhassett 	if (data_available < phm->u.d.u.data.data_size) {
1196719f82d3SEliot Blennerhassett 		phr->error = HPI_ERROR_INVALID_DATASIZE;
1197719f82d3SEliot Blennerhassett 		return;
1198719f82d3SEliot Blennerhassett 	}
1199719f82d3SEliot Blennerhassett 
1200719f82d3SEliot Blennerhassett 	if (hpios_locked_mem_valid(&phw->instream_host_buffers[phm->
1201719f82d3SEliot Blennerhassett 				obj_index])) {
1202719f82d3SEliot Blennerhassett 		if (hpios_locked_mem_get_virt_addr(&phw->
1203719f82d3SEliot Blennerhassett 				instream_host_buffers[phm->obj_index],
1204719f82d3SEliot Blennerhassett 				(void *)&p_bbm_data)) {
1205719f82d3SEliot Blennerhassett 			phr->error = HPI_ERROR_INVALID_OPERATION;
1206719f82d3SEliot Blennerhassett 			return;
1207719f82d3SEliot Blennerhassett 		}
1208719f82d3SEliot Blennerhassett 
1209719f82d3SEliot Blennerhassett 		/* either all data,
1210719f82d3SEliot Blennerhassett 		   or enough to fit from current to end of BBM buffer */
1211719f82d3SEliot Blennerhassett 		l_first_read =
1212719f82d3SEliot Blennerhassett 			min(phm->u.d.u.data.data_size,
1213719f82d3SEliot Blennerhassett 			status->size_in_bytes -
1214719f82d3SEliot Blennerhassett 			(status->host_index & (status->size_in_bytes - 1)));
1215719f82d3SEliot Blennerhassett 
1216719f82d3SEliot Blennerhassett 		memcpy(p_app_data,
1217719f82d3SEliot Blennerhassett 			p_bbm_data +
1218719f82d3SEliot Blennerhassett 			(status->host_index & (status->size_in_bytes - 1)),
1219719f82d3SEliot Blennerhassett 			l_first_read);
1220719f82d3SEliot Blennerhassett 		/* remaining data if any */
1221719f82d3SEliot Blennerhassett 		memcpy(p_app_data + l_first_read, p_bbm_data,
1222719f82d3SEliot Blennerhassett 			phm->u.d.u.data.data_size - l_first_read);
1223719f82d3SEliot Blennerhassett 	}
1224719f82d3SEliot Blennerhassett 	status->host_index += phm->u.d.u.data.data_size;
1225719f82d3SEliot Blennerhassett }
1226719f82d3SEliot Blennerhassett 
instream_get_info(struct hpi_adapter_obj * pao,struct hpi_message * phm,struct hpi_response * phr)1227719f82d3SEliot Blennerhassett static void instream_get_info(struct hpi_adapter_obj *pao,
1228719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
1229719f82d3SEliot Blennerhassett {
1230719f82d3SEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
1231719f82d3SEliot Blennerhassett 	struct bus_master_interface *interface = phw->p_interface_buffer;
1232719f82d3SEliot Blennerhassett 	struct hpi_hostbuffer_status *status;
1233719f82d3SEliot Blennerhassett 	if (!phw->instream_host_buffer_size[phm->obj_index]) {
1234719f82d3SEliot Blennerhassett 		hw_message(pao, phm, phr);
1235719f82d3SEliot Blennerhassett 		return;
1236719f82d3SEliot Blennerhassett 	}
1237719f82d3SEliot Blennerhassett 
1238719f82d3SEliot Blennerhassett 	status = &interface->instream_host_buffer_status[phm->obj_index];
1239719f82d3SEliot Blennerhassett 
1240719f82d3SEliot Blennerhassett 	hpi_init_response(phr, phm->object, phm->function, 0);
1241719f82d3SEliot Blennerhassett 
1242719f82d3SEliot Blennerhassett 	phr->u.d.u.stream_info.state = (u16)status->stream_state;
1243719f82d3SEliot Blennerhassett 	phr->u.d.u.stream_info.samples_transferred =
1244719f82d3SEliot Blennerhassett 		status->samples_processed;
1245719f82d3SEliot Blennerhassett 	phr->u.d.u.stream_info.buffer_size = status->size_in_bytes;
1246719f82d3SEliot Blennerhassett 	phr->u.d.u.stream_info.data_available =
1247719f82d3SEliot Blennerhassett 		instream_get_bytes_available(status);
1248719f82d3SEliot Blennerhassett 	phr->u.d.u.stream_info.auxiliary_data_available =
1249719f82d3SEliot Blennerhassett 		status->auxiliary_data_available;
1250719f82d3SEliot Blennerhassett }
1251719f82d3SEliot Blennerhassett 
1252719f82d3SEliot Blennerhassett /*****************************************************************************/
1253719f82d3SEliot Blennerhassett /* LOW-LEVEL */
1254719f82d3SEliot Blennerhassett #define HPI6205_MAX_FILES_TO_LOAD 2
1255719f82d3SEliot Blennerhassett 
adapter_boot_load_dsp(struct hpi_adapter_obj * pao,u32 * pos_error_code)1256719f82d3SEliot Blennerhassett static u16 adapter_boot_load_dsp(struct hpi_adapter_obj *pao,
1257719f82d3SEliot Blennerhassett 	u32 *pos_error_code)
1258719f82d3SEliot Blennerhassett {
1259719f82d3SEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
1260719f82d3SEliot Blennerhassett 	struct dsp_code dsp_code;
1261719f82d3SEliot Blennerhassett 	u16 boot_code_id[HPI6205_MAX_FILES_TO_LOAD];
1262719f82d3SEliot Blennerhassett 	u32 temp;
1263719f82d3SEliot Blennerhassett 	int dsp = 0, i = 0;
1264719f82d3SEliot Blennerhassett 	u16 err = 0;
1265719f82d3SEliot Blennerhassett 
1266719f82d3SEliot Blennerhassett 	boot_code_id[0] = HPI_ADAPTER_ASI(0x6205);
1267719f82d3SEliot Blennerhassett 
1268ee246fc0SEliot Blennerhassett 	boot_code_id[1] = pao->pci.pci_dev->subsystem_device;
1269ee246fc0SEliot Blennerhassett 	boot_code_id[1] = HPI_ADAPTER_FAMILY_ASI(boot_code_id[1]);
1270ee246fc0SEliot Blennerhassett 
1271ee246fc0SEliot Blennerhassett 	/* fix up cases where bootcode id[1] != subsys id */
1272ee246fc0SEliot Blennerhassett 	switch (boot_code_id[1]) {
1273719f82d3SEliot Blennerhassett 	case HPI_ADAPTER_FAMILY_ASI(0x5000):
1274ee246fc0SEliot Blennerhassett 		boot_code_id[0] = boot_code_id[1];
1275ee246fc0SEliot Blennerhassett 		boot_code_id[1] = 0;
1276719f82d3SEliot Blennerhassett 		break;
1277719f82d3SEliot Blennerhassett 	case HPI_ADAPTER_FAMILY_ASI(0x5300):
1278719f82d3SEliot Blennerhassett 	case HPI_ADAPTER_FAMILY_ASI(0x5400):
1279719f82d3SEliot Blennerhassett 	case HPI_ADAPTER_FAMILY_ASI(0x6300):
1280ee246fc0SEliot Blennerhassett 		boot_code_id[1] = HPI_ADAPTER_FAMILY_ASI(0x6400);
1281719f82d3SEliot Blennerhassett 		break;
12826d0b898eSEliot Blennerhassett 	case HPI_ADAPTER_FAMILY_ASI(0x5500):
1283719f82d3SEliot Blennerhassett 	case HPI_ADAPTER_FAMILY_ASI(0x5600):
1284719f82d3SEliot Blennerhassett 	case HPI_ADAPTER_FAMILY_ASI(0x6500):
1285ee246fc0SEliot Blennerhassett 		boot_code_id[1] = HPI_ADAPTER_FAMILY_ASI(0x6600);
1286719f82d3SEliot Blennerhassett 		break;
1287cadae428SEliot Blennerhassett 	case HPI_ADAPTER_FAMILY_ASI(0x8800):
1288ee246fc0SEliot Blennerhassett 		boot_code_id[1] = HPI_ADAPTER_FAMILY_ASI(0x8900);
1289ee246fc0SEliot Blennerhassett 		break;
1290ee246fc0SEliot Blennerhassett 	default:
1291cadae428SEliot Blennerhassett 		break;
1292719f82d3SEliot Blennerhassett 	}
1293719f82d3SEliot Blennerhassett 
1294719f82d3SEliot Blennerhassett 	/* reset DSP by writing a 1 to the WARMRESET bit */
1295719f82d3SEliot Blennerhassett 	temp = C6205_HDCR_WARMRESET;
1296719f82d3SEliot Blennerhassett 	iowrite32(temp, phw->prHDCR);
1297719f82d3SEliot Blennerhassett 	hpios_delay_micro_seconds(1000);
1298719f82d3SEliot Blennerhassett 
1299719f82d3SEliot Blennerhassett 	/* check that PCI i/f was configured by EEPROM */
1300719f82d3SEliot Blennerhassett 	temp = ioread32(phw->prHSR);
1301719f82d3SEliot Blennerhassett 	if ((temp & (C6205_HSR_CFGERR | C6205_HSR_EEREAD)) !=
1302719f82d3SEliot Blennerhassett 		C6205_HSR_EEREAD)
13033285ea10SEliot Blennerhassett 		return HPI6205_ERROR_6205_EEPROM;
1304719f82d3SEliot Blennerhassett 	temp |= 0x04;
1305719f82d3SEliot Blennerhassett 	/* disable PINTA interrupt */
1306719f82d3SEliot Blennerhassett 	iowrite32(temp, phw->prHSR);
1307719f82d3SEliot Blennerhassett 
1308719f82d3SEliot Blennerhassett 	/* check control register reports PCI boot mode */
1309719f82d3SEliot Blennerhassett 	temp = ioread32(phw->prHDCR);
1310719f82d3SEliot Blennerhassett 	if (!(temp & C6205_HDCR_PCIBOOT))
13113285ea10SEliot Blennerhassett 		return HPI6205_ERROR_6205_REG;
1312719f82d3SEliot Blennerhassett 
13133285ea10SEliot Blennerhassett 	/* try writing a few numbers to the DSP page register */
1314719f82d3SEliot Blennerhassett 	/* and reading them back. */
1315719f82d3SEliot Blennerhassett 	temp = 3;
1316719f82d3SEliot Blennerhassett 	iowrite32(temp, phw->prDSPP);
1317719f82d3SEliot Blennerhassett 	if ((temp | C6205_DSPP_MAP1) != ioread32(phw->prDSPP))
13183285ea10SEliot Blennerhassett 		return HPI6205_ERROR_6205_DSPPAGE;
13193285ea10SEliot Blennerhassett 	temp = 2;
13203285ea10SEliot Blennerhassett 	iowrite32(temp, phw->prDSPP);
13213285ea10SEliot Blennerhassett 	if ((temp | C6205_DSPP_MAP1) != ioread32(phw->prDSPP))
13223285ea10SEliot Blennerhassett 		return HPI6205_ERROR_6205_DSPPAGE;
13233285ea10SEliot Blennerhassett 	temp = 1;
13243285ea10SEliot Blennerhassett 	iowrite32(temp, phw->prDSPP);
13253285ea10SEliot Blennerhassett 	if ((temp | C6205_DSPP_MAP1) != ioread32(phw->prDSPP))
13263285ea10SEliot Blennerhassett 		return HPI6205_ERROR_6205_DSPPAGE;
1327719f82d3SEliot Blennerhassett 	/* reset DSP page to the correct number */
1328719f82d3SEliot Blennerhassett 	temp = 0;
1329719f82d3SEliot Blennerhassett 	iowrite32(temp, phw->prDSPP);
1330719f82d3SEliot Blennerhassett 	if ((temp | C6205_DSPP_MAP1) != ioread32(phw->prDSPP))
13313285ea10SEliot Blennerhassett 		return HPI6205_ERROR_6205_DSPPAGE;
1332719f82d3SEliot Blennerhassett 	phw->dsp_page = 0;
1333719f82d3SEliot Blennerhassett 
1334719f82d3SEliot Blennerhassett 	/* release 6713 from reset before 6205 is bootloaded.
1335719f82d3SEliot Blennerhassett 	   This ensures that the EMIF is inactive,
1336719f82d3SEliot Blennerhassett 	   and the 6713 HPI gets the correct bootmode etc
1337719f82d3SEliot Blennerhassett 	 */
1338719f82d3SEliot Blennerhassett 	if (boot_code_id[1] != 0) {
1339719f82d3SEliot Blennerhassett 		/* DSP 1 is a C6713 */
1340719f82d3SEliot Blennerhassett 		/* CLKX0 <- '1' release the C6205 bootmode pulldowns */
1341f9a376c3SEliot Blennerhassett 		boot_loader_write_mem32(pao, 0, 0x018C0024, 0x00002202);
1342719f82d3SEliot Blennerhassett 		hpios_delay_micro_seconds(100);
1343719f82d3SEliot Blennerhassett 		/* Reset the 6713 #1 - revB */
1344719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, 0, C6205_BAR0_TIMER1_CTL, 0);
1345f9a376c3SEliot Blennerhassett 		/* value of bit 3 is unknown after DSP reset, other bits shoudl be 0 */
1346f9a376c3SEliot Blennerhassett 		if (0 != (boot_loader_read_mem32(pao, 0,
1347f9a376c3SEliot Blennerhassett 					(C6205_BAR0_TIMER1_CTL)) & ~8))
1348f9a376c3SEliot Blennerhassett 			return HPI6205_ERROR_6205_REG;
1349719f82d3SEliot Blennerhassett 		hpios_delay_micro_seconds(100);
1350f9a376c3SEliot Blennerhassett 
1351719f82d3SEliot Blennerhassett 		/* Release C6713 from reset - revB */
1352719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, 0, C6205_BAR0_TIMER1_CTL, 4);
1353f9a376c3SEliot Blennerhassett 		if (4 != (boot_loader_read_mem32(pao, 0,
1354f9a376c3SEliot Blennerhassett 					(C6205_BAR0_TIMER1_CTL)) & ~8))
1355f9a376c3SEliot Blennerhassett 			return HPI6205_ERROR_6205_REG;
1356719f82d3SEliot Blennerhassett 		hpios_delay_micro_seconds(100);
1357719f82d3SEliot Blennerhassett 	}
1358719f82d3SEliot Blennerhassett 
1359719f82d3SEliot Blennerhassett 	for (dsp = 0; dsp < HPI6205_MAX_FILES_TO_LOAD; dsp++) {
1360719f82d3SEliot Blennerhassett 		/* is there a DSP to load? */
1361719f82d3SEliot Blennerhassett 		if (boot_code_id[dsp] == 0)
1362719f82d3SEliot Blennerhassett 			continue;
1363719f82d3SEliot Blennerhassett 
1364719f82d3SEliot Blennerhassett 		err = boot_loader_config_emif(pao, dsp);
1365719f82d3SEliot Blennerhassett 		if (err)
1366719f82d3SEliot Blennerhassett 			return err;
1367719f82d3SEliot Blennerhassett 
1368719f82d3SEliot Blennerhassett 		err = boot_loader_test_internal_memory(pao, dsp);
1369719f82d3SEliot Blennerhassett 		if (err)
1370719f82d3SEliot Blennerhassett 			return err;
1371719f82d3SEliot Blennerhassett 
1372719f82d3SEliot Blennerhassett 		err = boot_loader_test_external_memory(pao, dsp);
1373719f82d3SEliot Blennerhassett 		if (err)
1374719f82d3SEliot Blennerhassett 			return err;
1375719f82d3SEliot Blennerhassett 
1376719f82d3SEliot Blennerhassett 		err = boot_loader_test_pld(pao, dsp);
1377719f82d3SEliot Blennerhassett 		if (err)
1378719f82d3SEliot Blennerhassett 			return err;
1379719f82d3SEliot Blennerhassett 
1380719f82d3SEliot Blennerhassett 		/* write the DSP code down into the DSPs memory */
138195a4c6e7SEliot Blennerhassett 		err = hpi_dsp_code_open(boot_code_id[dsp], pao->pci.pci_dev,
138295a4c6e7SEliot Blennerhassett 			&dsp_code, pos_error_code);
1383719f82d3SEliot Blennerhassett 		if (err)
1384719f82d3SEliot Blennerhassett 			return err;
1385719f82d3SEliot Blennerhassett 
1386719f82d3SEliot Blennerhassett 		while (1) {
1387719f82d3SEliot Blennerhassett 			u32 length;
1388719f82d3SEliot Blennerhassett 			u32 address;
1389719f82d3SEliot Blennerhassett 			u32 type;
1390719f82d3SEliot Blennerhassett 			u32 *pcode;
1391719f82d3SEliot Blennerhassett 
1392719f82d3SEliot Blennerhassett 			err = hpi_dsp_code_read_word(&dsp_code, &length);
1393719f82d3SEliot Blennerhassett 			if (err)
1394719f82d3SEliot Blennerhassett 				break;
1395719f82d3SEliot Blennerhassett 			if (length == 0xFFFFFFFF)
1396719f82d3SEliot Blennerhassett 				break;	/* end of code */
1397719f82d3SEliot Blennerhassett 
1398719f82d3SEliot Blennerhassett 			err = hpi_dsp_code_read_word(&dsp_code, &address);
1399719f82d3SEliot Blennerhassett 			if (err)
1400719f82d3SEliot Blennerhassett 				break;
1401719f82d3SEliot Blennerhassett 			err = hpi_dsp_code_read_word(&dsp_code, &type);
1402719f82d3SEliot Blennerhassett 			if (err)
1403719f82d3SEliot Blennerhassett 				break;
1404719f82d3SEliot Blennerhassett 			err = hpi_dsp_code_read_block(length, &dsp_code,
1405719f82d3SEliot Blennerhassett 				&pcode);
1406719f82d3SEliot Blennerhassett 			if (err)
1407719f82d3SEliot Blennerhassett 				break;
1408719f82d3SEliot Blennerhassett 			for (i = 0; i < (int)length; i++) {
14093285ea10SEliot Blennerhassett 				boot_loader_write_mem32(pao, dsp, address,
14103285ea10SEliot Blennerhassett 					*pcode);
1411719f82d3SEliot Blennerhassett 				/* dummy read every 4 words */
1412719f82d3SEliot Blennerhassett 				/* for 6205 advisory 1.4.4 */
1413719f82d3SEliot Blennerhassett 				if (i % 4 == 0)
1414719f82d3SEliot Blennerhassett 					boot_loader_read_mem32(pao, dsp,
1415719f82d3SEliot Blennerhassett 						address);
1416719f82d3SEliot Blennerhassett 				pcode++;
1417719f82d3SEliot Blennerhassett 				address += 4;
1418719f82d3SEliot Blennerhassett 			}
1419719f82d3SEliot Blennerhassett 
1420719f82d3SEliot Blennerhassett 		}
1421719f82d3SEliot Blennerhassett 		if (err) {
1422719f82d3SEliot Blennerhassett 			hpi_dsp_code_close(&dsp_code);
1423719f82d3SEliot Blennerhassett 			return err;
1424719f82d3SEliot Blennerhassett 		}
1425719f82d3SEliot Blennerhassett 
1426719f82d3SEliot Blennerhassett 		/* verify code */
1427719f82d3SEliot Blennerhassett 		hpi_dsp_code_rewind(&dsp_code);
1428719f82d3SEliot Blennerhassett 		while (1) {
1429719f82d3SEliot Blennerhassett 			u32 length = 0;
1430719f82d3SEliot Blennerhassett 			u32 address = 0;
1431719f82d3SEliot Blennerhassett 			u32 type = 0;
1432719f82d3SEliot Blennerhassett 			u32 *pcode = NULL;
1433719f82d3SEliot Blennerhassett 			u32 data = 0;
1434719f82d3SEliot Blennerhassett 
1435719f82d3SEliot Blennerhassett 			hpi_dsp_code_read_word(&dsp_code, &length);
1436719f82d3SEliot Blennerhassett 			if (length == 0xFFFFFFFF)
1437719f82d3SEliot Blennerhassett 				break;	/* end of code */
1438719f82d3SEliot Blennerhassett 
1439719f82d3SEliot Blennerhassett 			hpi_dsp_code_read_word(&dsp_code, &address);
1440719f82d3SEliot Blennerhassett 			hpi_dsp_code_read_word(&dsp_code, &type);
1441719f82d3SEliot Blennerhassett 			hpi_dsp_code_read_block(length, &dsp_code, &pcode);
1442719f82d3SEliot Blennerhassett 
1443719f82d3SEliot Blennerhassett 			for (i = 0; i < (int)length; i++) {
1444719f82d3SEliot Blennerhassett 				data = boot_loader_read_mem32(pao, dsp,
1445719f82d3SEliot Blennerhassett 					address);
1446719f82d3SEliot Blennerhassett 				if (data != *pcode) {
1447719f82d3SEliot Blennerhassett 					err = 0;
1448719f82d3SEliot Blennerhassett 					break;
1449719f82d3SEliot Blennerhassett 				}
1450719f82d3SEliot Blennerhassett 				pcode++;
1451719f82d3SEliot Blennerhassett 				address += 4;
1452719f82d3SEliot Blennerhassett 			}
1453719f82d3SEliot Blennerhassett 			if (err)
1454719f82d3SEliot Blennerhassett 				break;
1455719f82d3SEliot Blennerhassett 		}
1456719f82d3SEliot Blennerhassett 		hpi_dsp_code_close(&dsp_code);
1457719f82d3SEliot Blennerhassett 		if (err)
1458719f82d3SEliot Blennerhassett 			return err;
1459719f82d3SEliot Blennerhassett 	}
1460719f82d3SEliot Blennerhassett 
1461719f82d3SEliot Blennerhassett 	/* After bootloading all DSPs, start DSP0 running
1462719f82d3SEliot Blennerhassett 	 * The DSP0 code will handle starting and synchronizing with its slaves
1463719f82d3SEliot Blennerhassett 	 */
1464719f82d3SEliot Blennerhassett 	if (phw->p_interface_buffer) {
1465719f82d3SEliot Blennerhassett 		/* we need to tell the card the physical PCI address */
1466719f82d3SEliot Blennerhassett 		u32 physicalPC_iaddress;
1467719f82d3SEliot Blennerhassett 		struct bus_master_interface *interface =
1468719f82d3SEliot Blennerhassett 			phw->p_interface_buffer;
1469719f82d3SEliot Blennerhassett 		u32 host_mailbox_address_on_dsp;
1470719f82d3SEliot Blennerhassett 		u32 physicalPC_iaddress_verify = 0;
1471719f82d3SEliot Blennerhassett 		int time_out = 10;
1472719f82d3SEliot Blennerhassett 		/* set ack so we know when DSP is ready to go */
1473719f82d3SEliot Blennerhassett 		/* (dwDspAck will be changed to HIF_RESET) */
1474719f82d3SEliot Blennerhassett 		interface->dsp_ack = H620_HIF_UNKNOWN;
1475719f82d3SEliot Blennerhassett 		wmb();	/* ensure ack is written before dsp writes back */
1476719f82d3SEliot Blennerhassett 
1477719f82d3SEliot Blennerhassett 		err = hpios_locked_mem_get_phys_addr(&phw->h_locked_mem,
1478719f82d3SEliot Blennerhassett 			&physicalPC_iaddress);
1479719f82d3SEliot Blennerhassett 
1480719f82d3SEliot Blennerhassett 		/* locate the host mailbox on the DSP. */
1481719f82d3SEliot Blennerhassett 		host_mailbox_address_on_dsp = 0x80000000;
1482719f82d3SEliot Blennerhassett 		while ((physicalPC_iaddress != physicalPC_iaddress_verify)
1483719f82d3SEliot Blennerhassett 			&& time_out--) {
14843285ea10SEliot Blennerhassett 			boot_loader_write_mem32(pao, 0,
1485719f82d3SEliot Blennerhassett 				host_mailbox_address_on_dsp,
1486719f82d3SEliot Blennerhassett 				physicalPC_iaddress);
1487719f82d3SEliot Blennerhassett 			physicalPC_iaddress_verify =
1488719f82d3SEliot Blennerhassett 				boot_loader_read_mem32(pao, 0,
1489719f82d3SEliot Blennerhassett 				host_mailbox_address_on_dsp);
1490719f82d3SEliot Blennerhassett 		}
1491719f82d3SEliot Blennerhassett 	}
1492719f82d3SEliot Blennerhassett 	HPI_DEBUG_LOG(DEBUG, "starting DS_ps running\n");
1493719f82d3SEliot Blennerhassett 	/* enable interrupts */
1494719f82d3SEliot Blennerhassett 	temp = ioread32(phw->prHSR);
1495719f82d3SEliot Blennerhassett 	temp &= ~(u32)C6205_HSR_INTAM;
1496719f82d3SEliot Blennerhassett 	iowrite32(temp, phw->prHSR);
1497719f82d3SEliot Blennerhassett 
1498719f82d3SEliot Blennerhassett 	/* start code running... */
1499719f82d3SEliot Blennerhassett 	temp = ioread32(phw->prHDCR);
1500719f82d3SEliot Blennerhassett 	temp |= (u32)C6205_HDCR_DSPINT;
1501719f82d3SEliot Blennerhassett 	iowrite32(temp, phw->prHDCR);
1502719f82d3SEliot Blennerhassett 
1503719f82d3SEliot Blennerhassett 	/* give the DSP 10ms to start up */
1504719f82d3SEliot Blennerhassett 	hpios_delay_micro_seconds(10000);
1505719f82d3SEliot Blennerhassett 	return err;
1506719f82d3SEliot Blennerhassett 
1507719f82d3SEliot Blennerhassett }
1508719f82d3SEliot Blennerhassett 
1509719f82d3SEliot Blennerhassett /*****************************************************************************/
1510719f82d3SEliot Blennerhassett /* Bootloader utility functions */
1511719f82d3SEliot Blennerhassett 
boot_loader_read_mem32(struct hpi_adapter_obj * pao,int dsp_index,u32 address)1512719f82d3SEliot Blennerhassett static u32 boot_loader_read_mem32(struct hpi_adapter_obj *pao, int dsp_index,
1513719f82d3SEliot Blennerhassett 	u32 address)
1514719f82d3SEliot Blennerhassett {
1515719f82d3SEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
1516719f82d3SEliot Blennerhassett 	u32 data = 0;
1517719f82d3SEliot Blennerhassett 	__iomem u32 *p_data;
1518719f82d3SEliot Blennerhassett 
1519719f82d3SEliot Blennerhassett 	if (dsp_index == 0) {
1520719f82d3SEliot Blennerhassett 		/* DSP 0 is always C6205 */
1521719f82d3SEliot Blennerhassett 		if ((address >= 0x01800000) & (address < 0x02000000)) {
1522719f82d3SEliot Blennerhassett 			/* BAR1 register access */
1523719f82d3SEliot Blennerhassett 			p_data = pao->pci.ap_mem_base[1] +
1524719f82d3SEliot Blennerhassett 				(address & 0x007fffff) /
1525719f82d3SEliot Blennerhassett 				sizeof(*pao->pci.ap_mem_base[1]);
1526719f82d3SEliot Blennerhassett 			/* HPI_DEBUG_LOG(WARNING,
1527719f82d3SEliot Blennerhassett 			   "BAR1 access %08x\n", dwAddress); */
1528719f82d3SEliot Blennerhassett 		} else {
1529719f82d3SEliot Blennerhassett 			u32 dw4M_page = address >> 22L;
1530719f82d3SEliot Blennerhassett 			if (dw4M_page != phw->dsp_page) {
1531719f82d3SEliot Blennerhassett 				phw->dsp_page = dw4M_page;
1532719f82d3SEliot Blennerhassett 				/* *INDENT OFF* */
1533719f82d3SEliot Blennerhassett 				iowrite32(phw->dsp_page, phw->prDSPP);
1534719f82d3SEliot Blennerhassett 				/* *INDENT-ON* */
1535719f82d3SEliot Blennerhassett 			}
1536719f82d3SEliot Blennerhassett 			address &= 0x3fffff;	/* address within 4M page */
1537719f82d3SEliot Blennerhassett 			/* BAR0 memory access */
1538719f82d3SEliot Blennerhassett 			p_data = pao->pci.ap_mem_base[0] +
1539719f82d3SEliot Blennerhassett 				address / sizeof(u32);
1540719f82d3SEliot Blennerhassett 		}
1541719f82d3SEliot Blennerhassett 		data = ioread32(p_data);
1542719f82d3SEliot Blennerhassett 	} else if (dsp_index == 1) {
1543719f82d3SEliot Blennerhassett 		/* DSP 1 is a C6713 */
1544719f82d3SEliot Blennerhassett 		u32 lsb;
1545719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, 0, HPIAL_ADDR, address);
1546719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, 0, HPIAH_ADDR, address >> 16);
1547719f82d3SEliot Blennerhassett 		lsb = boot_loader_read_mem32(pao, 0, HPIDL_ADDR);
1548719f82d3SEliot Blennerhassett 		data = boot_loader_read_mem32(pao, 0, HPIDH_ADDR);
1549719f82d3SEliot Blennerhassett 		data = (data << 16) | (lsb & 0xFFFF);
1550719f82d3SEliot Blennerhassett 	}
1551719f82d3SEliot Blennerhassett 	return data;
1552719f82d3SEliot Blennerhassett }
1553719f82d3SEliot Blennerhassett 
boot_loader_write_mem32(struct hpi_adapter_obj * pao,int dsp_index,u32 address,u32 data)15543285ea10SEliot Blennerhassett static void boot_loader_write_mem32(struct hpi_adapter_obj *pao,
15553285ea10SEliot Blennerhassett 	int dsp_index, u32 address, u32 data)
1556719f82d3SEliot Blennerhassett {
1557719f82d3SEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
1558719f82d3SEliot Blennerhassett 	__iomem u32 *p_data;
1559719f82d3SEliot Blennerhassett 	/*      u32 dwVerifyData=0; */
1560719f82d3SEliot Blennerhassett 
1561719f82d3SEliot Blennerhassett 	if (dsp_index == 0) {
1562719f82d3SEliot Blennerhassett 		/* DSP 0 is always C6205 */
1563719f82d3SEliot Blennerhassett 		if ((address >= 0x01800000) & (address < 0x02000000)) {
1564719f82d3SEliot Blennerhassett 			/* BAR1 - DSP  register access using */
1565719f82d3SEliot Blennerhassett 			/* Non-prefetchable PCI access */
1566719f82d3SEliot Blennerhassett 			p_data = pao->pci.ap_mem_base[1] +
1567719f82d3SEliot Blennerhassett 				(address & 0x007fffff) /
1568719f82d3SEliot Blennerhassett 				sizeof(*pao->pci.ap_mem_base[1]);
1569719f82d3SEliot Blennerhassett 		} else {
1570719f82d3SEliot Blennerhassett 			/* BAR0 access - all of DSP memory using */
1571719f82d3SEliot Blennerhassett 			/* pre-fetchable PCI access */
1572719f82d3SEliot Blennerhassett 			u32 dw4M_page = address >> 22L;
1573719f82d3SEliot Blennerhassett 			if (dw4M_page != phw->dsp_page) {
1574719f82d3SEliot Blennerhassett 				phw->dsp_page = dw4M_page;
1575719f82d3SEliot Blennerhassett 				/* *INDENT-OFF* */
1576719f82d3SEliot Blennerhassett 				iowrite32(phw->dsp_page, phw->prDSPP);
1577719f82d3SEliot Blennerhassett 				/* *INDENT-ON* */
1578719f82d3SEliot Blennerhassett 			}
1579719f82d3SEliot Blennerhassett 			address &= 0x3fffff;	/* address within 4M page */
1580719f82d3SEliot Blennerhassett 			p_data = pao->pci.ap_mem_base[0] +
1581719f82d3SEliot Blennerhassett 				address / sizeof(u32);
1582719f82d3SEliot Blennerhassett 		}
1583719f82d3SEliot Blennerhassett 		iowrite32(data, p_data);
1584719f82d3SEliot Blennerhassett 	} else if (dsp_index == 1) {
1585719f82d3SEliot Blennerhassett 		/* DSP 1 is a C6713 */
1586719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, 0, HPIAL_ADDR, address);
1587719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, 0, HPIAH_ADDR, address >> 16);
1588719f82d3SEliot Blennerhassett 
1589719f82d3SEliot Blennerhassett 		/* dummy read every 4 words for 6205 advisory 1.4.4 */
1590719f82d3SEliot Blennerhassett 		boot_loader_read_mem32(pao, 0, 0);
1591719f82d3SEliot Blennerhassett 
1592719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, 0, HPIDL_ADDR, data);
1593719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, 0, HPIDH_ADDR, data >> 16);
1594719f82d3SEliot Blennerhassett 
1595719f82d3SEliot Blennerhassett 		/* dummy read every 4 words for 6205 advisory 1.4.4 */
1596719f82d3SEliot Blennerhassett 		boot_loader_read_mem32(pao, 0, 0);
15973285ea10SEliot Blennerhassett 	}
1598719f82d3SEliot Blennerhassett }
1599719f82d3SEliot Blennerhassett 
boot_loader_config_emif(struct hpi_adapter_obj * pao,int dsp_index)1600719f82d3SEliot Blennerhassett static u16 boot_loader_config_emif(struct hpi_adapter_obj *pao, int dsp_index)
1601719f82d3SEliot Blennerhassett {
1602719f82d3SEliot Blennerhassett 	if (dsp_index == 0) {
1603719f82d3SEliot Blennerhassett 		u32 setting;
1604719f82d3SEliot Blennerhassett 
1605719f82d3SEliot Blennerhassett 		/* DSP 0 is always C6205 */
1606719f82d3SEliot Blennerhassett 
1607719f82d3SEliot Blennerhassett 		/* Set the EMIF */
1608719f82d3SEliot Blennerhassett 		/* memory map of C6205 */
1609719f82d3SEliot Blennerhassett 		/* 00000000-0000FFFF    16Kx32 internal program */
1610719f82d3SEliot Blennerhassett 		/* 00400000-00BFFFFF    CE0     2Mx32 SDRAM running @ 100MHz */
1611719f82d3SEliot Blennerhassett 
1612719f82d3SEliot Blennerhassett 		/* EMIF config */
1613719f82d3SEliot Blennerhassett 		/*------------ */
1614719f82d3SEliot Blennerhassett 		/* Global EMIF control */
1615719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, dsp_index, 0x01800000, 0x3779);
1616719f82d3SEliot Blennerhassett #define WS_OFS 28
1617719f82d3SEliot Blennerhassett #define WST_OFS 22
1618719f82d3SEliot Blennerhassett #define WH_OFS 20
1619719f82d3SEliot Blennerhassett #define RS_OFS 16
1620719f82d3SEliot Blennerhassett #define RST_OFS 8
1621719f82d3SEliot Blennerhassett #define MTYPE_OFS 4
1622719f82d3SEliot Blennerhassett #define RH_OFS 0
1623719f82d3SEliot Blennerhassett 
1624719f82d3SEliot Blennerhassett 		/* EMIF CE0 setup - 2Mx32 Sync DRAM on ASI5000 cards only */
1625719f82d3SEliot Blennerhassett 		setting = 0x00000030;
1626719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, dsp_index, 0x01800008, setting);
1627719f82d3SEliot Blennerhassett 		if (setting != boot_loader_read_mem32(pao, dsp_index,
1628719f82d3SEliot Blennerhassett 				0x01800008))
16294e225e26SEliot Blennerhassett 			return HPI6205_ERROR_DSP_EMIF1;
1630719f82d3SEliot Blennerhassett 
1631719f82d3SEliot Blennerhassett 		/* EMIF CE1 setup - 32 bit async. This is 6713 #1 HPI, */
1632719f82d3SEliot Blennerhassett 		/* which occupies D15..0. 6713 starts at 27MHz, so need */
1633719f82d3SEliot Blennerhassett 		/* plenty of wait states. See dsn8701.rtf, and 6713 errata. */
1634719f82d3SEliot Blennerhassett 		/* WST should be 71, but 63  is max possible */
1635719f82d3SEliot Blennerhassett 		setting =
1636719f82d3SEliot Blennerhassett 			(1L << WS_OFS) | (63L << WST_OFS) | (1L << WH_OFS) |
1637719f82d3SEliot Blennerhassett 			(1L << RS_OFS) | (63L << RST_OFS) | (1L << RH_OFS) |
1638719f82d3SEliot Blennerhassett 			(2L << MTYPE_OFS);
1639719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, dsp_index, 0x01800004, setting);
1640719f82d3SEliot Blennerhassett 		if (setting != boot_loader_read_mem32(pao, dsp_index,
1641719f82d3SEliot Blennerhassett 				0x01800004))
16424e225e26SEliot Blennerhassett 			return HPI6205_ERROR_DSP_EMIF2;
1643719f82d3SEliot Blennerhassett 
1644719f82d3SEliot Blennerhassett 		/* EMIF CE2 setup - 32 bit async. This is 6713 #2 HPI, */
1645719f82d3SEliot Blennerhassett 		/* which occupies D15..0. 6713 starts at 27MHz, so need */
1646719f82d3SEliot Blennerhassett 		/* plenty of wait states */
1647719f82d3SEliot Blennerhassett 		setting =
1648719f82d3SEliot Blennerhassett 			(1L << WS_OFS) | (28L << WST_OFS) | (1L << WH_OFS) |
1649719f82d3SEliot Blennerhassett 			(1L << RS_OFS) | (63L << RST_OFS) | (1L << RH_OFS) |
1650719f82d3SEliot Blennerhassett 			(2L << MTYPE_OFS);
1651719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, dsp_index, 0x01800010, setting);
1652719f82d3SEliot Blennerhassett 		if (setting != boot_loader_read_mem32(pao, dsp_index,
1653719f82d3SEliot Blennerhassett 				0x01800010))
16544e225e26SEliot Blennerhassett 			return HPI6205_ERROR_DSP_EMIF3;
1655719f82d3SEliot Blennerhassett 
1656719f82d3SEliot Blennerhassett 		/* EMIF CE3 setup - 32 bit async. */
1657719f82d3SEliot Blennerhassett 		/* This is the PLD on the ASI5000 cards only */
1658719f82d3SEliot Blennerhassett 		setting =
1659719f82d3SEliot Blennerhassett 			(1L << WS_OFS) | (10L << WST_OFS) | (1L << WH_OFS) |
1660719f82d3SEliot Blennerhassett 			(1L << RS_OFS) | (10L << RST_OFS) | (1L << RH_OFS) |
1661719f82d3SEliot Blennerhassett 			(2L << MTYPE_OFS);
1662719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, dsp_index, 0x01800014, setting);
1663719f82d3SEliot Blennerhassett 		if (setting != boot_loader_read_mem32(pao, dsp_index,
1664719f82d3SEliot Blennerhassett 				0x01800014))
16654e225e26SEliot Blennerhassett 			return HPI6205_ERROR_DSP_EMIF4;
1666719f82d3SEliot Blennerhassett 
1667719f82d3SEliot Blennerhassett 		/* set EMIF SDRAM control for 2Mx32 SDRAM (512x32x4 bank) */
1668719f82d3SEliot Blennerhassett 		/*  need to use this else DSP code crashes? */
1669719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, dsp_index, 0x01800018,
1670719f82d3SEliot Blennerhassett 			0x07117000);
1671719f82d3SEliot Blennerhassett 
1672719f82d3SEliot Blennerhassett 		/* EMIF SDRAM Refresh Timing */
1673719f82d3SEliot Blennerhassett 		/* EMIF SDRAM timing  (orig = 0x410, emulator = 0x61a) */
1674719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, dsp_index, 0x0180001C,
1675719f82d3SEliot Blennerhassett 			0x00000410);
1676719f82d3SEliot Blennerhassett 
1677719f82d3SEliot Blennerhassett 	} else if (dsp_index == 1) {
1678719f82d3SEliot Blennerhassett 		/* test access to the C6713s HPI registers */
1679719f82d3SEliot Blennerhassett 		u32 write_data = 0, read_data = 0, i = 0;
1680719f82d3SEliot Blennerhassett 
1681719f82d3SEliot Blennerhassett 		/* Set up HPIC for little endian, by setiing HPIC:HWOB=1 */
1682719f82d3SEliot Blennerhassett 		write_data = 1;
1683719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, 0, HPICL_ADDR, write_data);
1684719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, 0, HPICH_ADDR, write_data);
1685719f82d3SEliot Blennerhassett 		/* C67 HPI is on lower 16bits of 32bit EMIF */
1686719f82d3SEliot Blennerhassett 		read_data =
1687719f82d3SEliot Blennerhassett 			0xFFF7 & boot_loader_read_mem32(pao, 0, HPICL_ADDR);
1688719f82d3SEliot Blennerhassett 		if (write_data != read_data) {
1689719f82d3SEliot Blennerhassett 			HPI_DEBUG_LOG(ERROR, "HPICL %x %x\n", write_data,
1690719f82d3SEliot Blennerhassett 				read_data);
16913285ea10SEliot Blennerhassett 			return HPI6205_ERROR_C6713_HPIC;
1692719f82d3SEliot Blennerhassett 		}
1693719f82d3SEliot Blennerhassett 		/* HPIA - walking ones test */
1694719f82d3SEliot Blennerhassett 		write_data = 1;
1695719f82d3SEliot Blennerhassett 		for (i = 0; i < 32; i++) {
1696719f82d3SEliot Blennerhassett 			boot_loader_write_mem32(pao, 0, HPIAL_ADDR,
1697719f82d3SEliot Blennerhassett 				write_data);
1698719f82d3SEliot Blennerhassett 			boot_loader_write_mem32(pao, 0, HPIAH_ADDR,
1699719f82d3SEliot Blennerhassett 				(write_data >> 16));
1700719f82d3SEliot Blennerhassett 			read_data =
1701719f82d3SEliot Blennerhassett 				0xFFFF & boot_loader_read_mem32(pao, 0,
1702719f82d3SEliot Blennerhassett 				HPIAL_ADDR);
1703719f82d3SEliot Blennerhassett 			read_data =
1704719f82d3SEliot Blennerhassett 				read_data | ((0xFFFF &
1705719f82d3SEliot Blennerhassett 					boot_loader_read_mem32(pao, 0,
1706719f82d3SEliot Blennerhassett 						HPIAH_ADDR))
1707719f82d3SEliot Blennerhassett 				<< 16);
1708719f82d3SEliot Blennerhassett 			if (read_data != write_data) {
1709719f82d3SEliot Blennerhassett 				HPI_DEBUG_LOG(ERROR, "HPIA %x %x\n",
1710719f82d3SEliot Blennerhassett 					write_data, read_data);
17113285ea10SEliot Blennerhassett 				return HPI6205_ERROR_C6713_HPIA;
1712719f82d3SEliot Blennerhassett 			}
1713719f82d3SEliot Blennerhassett 			write_data = write_data << 1;
1714719f82d3SEliot Blennerhassett 		}
1715719f82d3SEliot Blennerhassett 
1716719f82d3SEliot Blennerhassett 		/* setup C67x PLL
1717719f82d3SEliot Blennerhassett 		 *  ** C6713 datasheet says we cannot program PLL from HPI,
1718719f82d3SEliot Blennerhassett 		 * and indeed if we try to set the PLL multiply from the HPI,
1719719f82d3SEliot Blennerhassett 		 * the PLL does not seem to lock, so we enable the PLL and
1720719f82d3SEliot Blennerhassett 		 * use the default multiply of x 7, which for a 27MHz clock
1721719f82d3SEliot Blennerhassett 		 * gives a DSP speed of 189MHz
1722719f82d3SEliot Blennerhassett 		 */
1723719f82d3SEliot Blennerhassett 		/* bypass PLL */
1724719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, dsp_index, 0x01B7C100, 0x0000);
1725719f82d3SEliot Blennerhassett 		hpios_delay_micro_seconds(1000);
1726719f82d3SEliot Blennerhassett 		/* EMIF = 189/3=63MHz */
1727719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, dsp_index, 0x01B7C120, 0x8002);
1728719f82d3SEliot Blennerhassett 		/* peri = 189/2 */
1729719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, dsp_index, 0x01B7C11C, 0x8001);
1730719f82d3SEliot Blennerhassett 		/* cpu  = 189/1 */
1731719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, dsp_index, 0x01B7C118, 0x8000);
1732719f82d3SEliot Blennerhassett 		hpios_delay_micro_seconds(1000);
1733719f82d3SEliot Blennerhassett 		/* ** SGT test to take GPO3 high when we start the PLL */
1734719f82d3SEliot Blennerhassett 		/* and low when the delay is completed */
1735719f82d3SEliot Blennerhassett 		/* FSX0 <- '1' (GPO3) */
1736719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, 0, (0x018C0024L), 0x00002A0A);
1737719f82d3SEliot Blennerhassett 		/* PLL not bypassed */
1738719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, dsp_index, 0x01B7C100, 0x0001);
1739719f82d3SEliot Blennerhassett 		hpios_delay_micro_seconds(1000);
1740719f82d3SEliot Blennerhassett 		/* FSX0 <- '0' (GPO3) */
1741719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, 0, (0x018C0024L), 0x00002A02);
1742719f82d3SEliot Blennerhassett 
1743719f82d3SEliot Blennerhassett 		/* 6205 EMIF CE1 resetup - 32 bit async. */
1744719f82d3SEliot Blennerhassett 		/* Now 6713 #1 is running at 189MHz can reduce waitstates */
1745719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, 0, 0x01800004,	/* CE1 */
1746719f82d3SEliot Blennerhassett 			(1L << WS_OFS) | (8L << WST_OFS) | (1L << WH_OFS) |
1747719f82d3SEliot Blennerhassett 			(1L << RS_OFS) | (12L << RST_OFS) | (1L << RH_OFS) |
1748719f82d3SEliot Blennerhassett 			(2L << MTYPE_OFS));
1749719f82d3SEliot Blennerhassett 
1750719f82d3SEliot Blennerhassett 		hpios_delay_micro_seconds(1000);
1751719f82d3SEliot Blennerhassett 
1752719f82d3SEliot Blennerhassett 		/* check that we can read one of the PLL registers */
1753719f82d3SEliot Blennerhassett 		/* PLL should not be bypassed! */
1754719f82d3SEliot Blennerhassett 		if ((boot_loader_read_mem32(pao, dsp_index, 0x01B7C100) & 0xF)
1755719f82d3SEliot Blennerhassett 			!= 0x0001) {
17563285ea10SEliot Blennerhassett 			return HPI6205_ERROR_C6713_PLL;
1757719f82d3SEliot Blennerhassett 		}
1758719f82d3SEliot Blennerhassett 		/* setup C67x EMIF  (note this is the only use of
1759719f82d3SEliot Blennerhassett 		   BAR1 via BootLoader_WriteMem32) */
1760719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, dsp_index, C6713_EMIF_GCTL,
1761719f82d3SEliot Blennerhassett 			0x000034A8);
17621d595d2aSEliot Blennerhassett 
17631d595d2aSEliot Blennerhassett 		/* EMIF CE0 setup - 2Mx32 Sync DRAM
17641d595d2aSEliot Blennerhassett 		   31..28       Wr setup
17651d595d2aSEliot Blennerhassett 		   27..22       Wr strobe
17661d595d2aSEliot Blennerhassett 		   21..20       Wr hold
17671d595d2aSEliot Blennerhassett 		   19..16       Rd setup
17681d595d2aSEliot Blennerhassett 		   15..14       -
17691d595d2aSEliot Blennerhassett 		   13..8        Rd strobe
17701d595d2aSEliot Blennerhassett 		   7..4         MTYPE   0011            Sync DRAM 32bits
17711d595d2aSEliot Blennerhassett 		   3            Wr hold MSB
17721d595d2aSEliot Blennerhassett 		   2..0         Rd hold
17731d595d2aSEliot Blennerhassett 		 */
1774719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, dsp_index, C6713_EMIF_CE0,
1775719f82d3SEliot Blennerhassett 			0x00000030);
17761d595d2aSEliot Blennerhassett 
17771d595d2aSEliot Blennerhassett 		/* EMIF SDRAM Extension
17781d595d2aSEliot Blennerhassett 		   0x00
17791d595d2aSEliot Blennerhassett 		   31-21        0000b 0000b 000b
17801d595d2aSEliot Blennerhassett 		   20           WR2RD = 2cycles-1  = 1b
17811d595d2aSEliot Blennerhassett 
17821d595d2aSEliot Blennerhassett 		   19-18        WR2DEAC = 3cycle-1 = 10b
17831d595d2aSEliot Blennerhassett 		   17           WR2WR = 2cycle-1   = 1b
17841d595d2aSEliot Blennerhassett 		   16-15        R2WDQM = 4cycle-1  = 11b
17851d595d2aSEliot Blennerhassett 		   14-12        RD2WR = 6cycles-1  = 101b
17861d595d2aSEliot Blennerhassett 
17871d595d2aSEliot Blennerhassett 		   11-10        RD2DEAC = 4cycle-1 = 11b
17881d595d2aSEliot Blennerhassett 		   9            RD2RD = 2cycle-1   = 1b
17891d595d2aSEliot Blennerhassett 		   8-7          THZP = 3cycle-1    = 10b
17901d595d2aSEliot Blennerhassett 		   6-5          TWR  = 2cycle-1    = 01b (tWR = 17ns)
17911d595d2aSEliot Blennerhassett 		   4            TRRD = 2cycle      = 0b  (tRRD = 14ns)
17921d595d2aSEliot Blennerhassett 		   3-1          TRAS = 5cycle-1    = 100b (Tras=42ns)
17931d595d2aSEliot Blennerhassett 		   1            CAS latency = 3cyc = 1b
17941d595d2aSEliot Blennerhassett 		   (for Micron 2M32-7 operating at 100MHz)
17951d595d2aSEliot Blennerhassett 		 */
1796719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, dsp_index, C6713_EMIF_SDRAMEXT,
1797719f82d3SEliot Blennerhassett 			0x001BDF29);
17981d595d2aSEliot Blennerhassett 
17991d595d2aSEliot Blennerhassett 		/* EMIF SDRAM control - set up for a 2Mx32 SDRAM (512x32x4 bank)
18001d595d2aSEliot Blennerhassett 		   31           -       0b       -
18011d595d2aSEliot Blennerhassett 		   30           SDBSZ   1b              4 bank
18021d595d2aSEliot Blennerhassett 		   29..28       SDRSZ   00b             11 row address pins
18031d595d2aSEliot Blennerhassett 
18041d595d2aSEliot Blennerhassett 		   27..26       SDCSZ   01b             8 column address pins
18051d595d2aSEliot Blennerhassett 		   25           RFEN    1b              refersh enabled
18061d595d2aSEliot Blennerhassett 		   24           INIT    1b              init SDRAM!
18071d595d2aSEliot Blennerhassett 
18081d595d2aSEliot Blennerhassett 		   23..20       TRCD    0001b                   (Trcd/Tcyc)-1 = (20/10)-1 = 1
18091d595d2aSEliot Blennerhassett 
18101d595d2aSEliot Blennerhassett 		   19..16       TRP     0001b                   (Trp/Tcyc)-1 = (20/10)-1 = 1
18111d595d2aSEliot Blennerhassett 
18121d595d2aSEliot Blennerhassett 		   15..12       TRC     0110b                   (Trc/Tcyc)-1 = (70/10)-1 = 6
18131d595d2aSEliot Blennerhassett 
18141d595d2aSEliot Blennerhassett 		   11..0        -       0000b 0000b 0000b
18151d595d2aSEliot Blennerhassett 		 */
1816719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, dsp_index, C6713_EMIF_SDRAMCTL,
18171d595d2aSEliot Blennerhassett 			0x47116000);
18181d595d2aSEliot Blennerhassett 
18191d595d2aSEliot Blennerhassett 		/* SDRAM refresh timing
18201d595d2aSEliot Blennerhassett 		   Need 4,096 refresh cycles every 64ms = 15.625us = 1562cycles of 100MHz = 0x61A
18211d595d2aSEliot Blennerhassett 		 */
1822719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, dsp_index,
1823719f82d3SEliot Blennerhassett 			C6713_EMIF_SDRAMTIMING, 0x00000410);
1824719f82d3SEliot Blennerhassett 
1825719f82d3SEliot Blennerhassett 		hpios_delay_micro_seconds(1000);
1826719f82d3SEliot Blennerhassett 	} else if (dsp_index == 2) {
1827719f82d3SEliot Blennerhassett 		/* DSP 2 is a C6713 */
18283285ea10SEliot Blennerhassett 	}
1829719f82d3SEliot Blennerhassett 
18303285ea10SEliot Blennerhassett 	return 0;
1831719f82d3SEliot Blennerhassett }
1832719f82d3SEliot Blennerhassett 
boot_loader_test_memory(struct hpi_adapter_obj * pao,int dsp_index,u32 start_address,u32 length)1833719f82d3SEliot Blennerhassett static u16 boot_loader_test_memory(struct hpi_adapter_obj *pao, int dsp_index,
1834719f82d3SEliot Blennerhassett 	u32 start_address, u32 length)
1835719f82d3SEliot Blennerhassett {
1836719f82d3SEliot Blennerhassett 	u32 i = 0, j = 0;
1837719f82d3SEliot Blennerhassett 	u32 test_addr = 0;
1838719f82d3SEliot Blennerhassett 	u32 test_data = 0, data = 0;
1839719f82d3SEliot Blennerhassett 
1840719f82d3SEliot Blennerhassett 	length = 1000;
1841719f82d3SEliot Blennerhassett 
1842719f82d3SEliot Blennerhassett 	/* for 1st word, test each bit in the 32bit word, */
1843719f82d3SEliot Blennerhassett 	/* dwLength specifies number of 32bit words to test */
1844719f82d3SEliot Blennerhassett 	/*for(i=0; i<dwLength; i++) */
1845719f82d3SEliot Blennerhassett 	i = 0;
1846719f82d3SEliot Blennerhassett 	{
1847719f82d3SEliot Blennerhassett 		test_addr = start_address + i * 4;
1848719f82d3SEliot Blennerhassett 		test_data = 0x00000001;
1849719f82d3SEliot Blennerhassett 		for (j = 0; j < 32; j++) {
1850719f82d3SEliot Blennerhassett 			boot_loader_write_mem32(pao, dsp_index, test_addr,
1851719f82d3SEliot Blennerhassett 				test_data);
1852719f82d3SEliot Blennerhassett 			data = boot_loader_read_mem32(pao, dsp_index,
1853719f82d3SEliot Blennerhassett 				test_addr);
1854719f82d3SEliot Blennerhassett 			if (data != test_data) {
1855719f82d3SEliot Blennerhassett 				HPI_DEBUG_LOG(VERBOSE,
18563285ea10SEliot Blennerhassett 					"Memtest error details  "
1857719f82d3SEliot Blennerhassett 					"%08x %08x %08x %i\n", test_addr,
1858719f82d3SEliot Blennerhassett 					test_data, data, dsp_index);
1859719f82d3SEliot Blennerhassett 				return 1;	/* error */
1860719f82d3SEliot Blennerhassett 			}
1861719f82d3SEliot Blennerhassett 			test_data = test_data << 1;
1862719f82d3SEliot Blennerhassett 		}	/* for(j) */
1863719f82d3SEliot Blennerhassett 	}	/* for(i) */
1864719f82d3SEliot Blennerhassett 
1865719f82d3SEliot Blennerhassett 	/* for the next 100 locations test each location, leaving it as zero */
1866719f82d3SEliot Blennerhassett 	/* write a zero to the next word in memory before we read */
1867719f82d3SEliot Blennerhassett 	/* the previous write to make sure every memory location is unique */
1868719f82d3SEliot Blennerhassett 	for (i = 0; i < 100; i++) {
1869719f82d3SEliot Blennerhassett 		test_addr = start_address + i * 4;
1870719f82d3SEliot Blennerhassett 		test_data = 0xA5A55A5A;
1871719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, dsp_index, test_addr, test_data);
1872719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, dsp_index, test_addr + 4, 0);
1873719f82d3SEliot Blennerhassett 		data = boot_loader_read_mem32(pao, dsp_index, test_addr);
1874719f82d3SEliot Blennerhassett 		if (data != test_data) {
1875719f82d3SEliot Blennerhassett 			HPI_DEBUG_LOG(VERBOSE,
18763285ea10SEliot Blennerhassett 				"Memtest error details  "
1877719f82d3SEliot Blennerhassett 				"%08x %08x %08x %i\n", test_addr, test_data,
1878719f82d3SEliot Blennerhassett 				data, dsp_index);
1879719f82d3SEliot Blennerhassett 			return 1;	/* error */
1880719f82d3SEliot Blennerhassett 		}
1881719f82d3SEliot Blennerhassett 		/* leave location as zero */
1882719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, dsp_index, test_addr, 0x0);
1883719f82d3SEliot Blennerhassett 	}
1884719f82d3SEliot Blennerhassett 
1885719f82d3SEliot Blennerhassett 	/* zero out entire memory block */
1886719f82d3SEliot Blennerhassett 	for (i = 0; i < length; i++) {
1887719f82d3SEliot Blennerhassett 		test_addr = start_address + i * 4;
1888719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, dsp_index, test_addr, 0x0);
1889719f82d3SEliot Blennerhassett 	}
1890719f82d3SEliot Blennerhassett 	return 0;
1891719f82d3SEliot Blennerhassett }
1892719f82d3SEliot Blennerhassett 
boot_loader_test_internal_memory(struct hpi_adapter_obj * pao,int dsp_index)1893719f82d3SEliot Blennerhassett static u16 boot_loader_test_internal_memory(struct hpi_adapter_obj *pao,
1894719f82d3SEliot Blennerhassett 	int dsp_index)
1895719f82d3SEliot Blennerhassett {
1896719f82d3SEliot Blennerhassett 	int err = 0;
1897719f82d3SEliot Blennerhassett 	if (dsp_index == 0) {
1898719f82d3SEliot Blennerhassett 		/* DSP 0 is a C6205 */
1899719f82d3SEliot Blennerhassett 		/* 64K prog mem */
1900719f82d3SEliot Blennerhassett 		err = boot_loader_test_memory(pao, dsp_index, 0x00000000,
1901719f82d3SEliot Blennerhassett 			0x10000);
1902719f82d3SEliot Blennerhassett 		if (!err)
1903719f82d3SEliot Blennerhassett 			/* 64K data mem */
1904719f82d3SEliot Blennerhassett 			err = boot_loader_test_memory(pao, dsp_index,
1905719f82d3SEliot Blennerhassett 				0x80000000, 0x10000);
19063285ea10SEliot Blennerhassett 	} else if (dsp_index == 1) {
19073285ea10SEliot Blennerhassett 		/* DSP 1 is a C6713 */
1908719f82d3SEliot Blennerhassett 		/* 192K internal mem */
1909719f82d3SEliot Blennerhassett 		err = boot_loader_test_memory(pao, dsp_index, 0x00000000,
1910719f82d3SEliot Blennerhassett 			0x30000);
1911719f82d3SEliot Blennerhassett 		if (!err)
1912719f82d3SEliot Blennerhassett 			/* 64K internal mem / L2 cache */
1913719f82d3SEliot Blennerhassett 			err = boot_loader_test_memory(pao, dsp_index,
1914719f82d3SEliot Blennerhassett 				0x00030000, 0x10000);
19153285ea10SEliot Blennerhassett 	}
1916719f82d3SEliot Blennerhassett 
1917719f82d3SEliot Blennerhassett 	if (err)
19183285ea10SEliot Blennerhassett 		return HPI6205_ERROR_DSP_INTMEM;
1919719f82d3SEliot Blennerhassett 	else
1920719f82d3SEliot Blennerhassett 		return 0;
1921719f82d3SEliot Blennerhassett }
1922719f82d3SEliot Blennerhassett 
boot_loader_test_external_memory(struct hpi_adapter_obj * pao,int dsp_index)1923719f82d3SEliot Blennerhassett static u16 boot_loader_test_external_memory(struct hpi_adapter_obj *pao,
1924719f82d3SEliot Blennerhassett 	int dsp_index)
1925719f82d3SEliot Blennerhassett {
1926719f82d3SEliot Blennerhassett 	u32 dRAM_start_address = 0;
1927719f82d3SEliot Blennerhassett 	u32 dRAM_size = 0;
1928719f82d3SEliot Blennerhassett 
1929719f82d3SEliot Blennerhassett 	if (dsp_index == 0) {
1930719f82d3SEliot Blennerhassett 		/* only test for SDRAM if an ASI5000 card */
19313285ea10SEliot Blennerhassett 		if (pao->pci.pci_dev->subsystem_device == 0x5000) {
1932719f82d3SEliot Blennerhassett 			/* DSP 0 is always C6205 */
1933719f82d3SEliot Blennerhassett 			dRAM_start_address = 0x00400000;
1934719f82d3SEliot Blennerhassett 			dRAM_size = 0x200000;
1935719f82d3SEliot Blennerhassett 			/*dwDRAMinc=1024; */
1936719f82d3SEliot Blennerhassett 		} else
1937719f82d3SEliot Blennerhassett 			return 0;
19383285ea10SEliot Blennerhassett 	} else if (dsp_index == 1) {
1939719f82d3SEliot Blennerhassett 		/* DSP 1 is a C6713 */
1940719f82d3SEliot Blennerhassett 		dRAM_start_address = 0x80000000;
1941719f82d3SEliot Blennerhassett 		dRAM_size = 0x200000;
1942719f82d3SEliot Blennerhassett 		/*dwDRAMinc=1024; */
19433285ea10SEliot Blennerhassett 	}
1944719f82d3SEliot Blennerhassett 
1945719f82d3SEliot Blennerhassett 	if (boot_loader_test_memory(pao, dsp_index, dRAM_start_address,
1946719f82d3SEliot Blennerhassett 			dRAM_size))
19473285ea10SEliot Blennerhassett 		return HPI6205_ERROR_DSP_EXTMEM;
1948719f82d3SEliot Blennerhassett 	return 0;
1949719f82d3SEliot Blennerhassett }
1950719f82d3SEliot Blennerhassett 
boot_loader_test_pld(struct hpi_adapter_obj * pao,int dsp_index)1951719f82d3SEliot Blennerhassett static u16 boot_loader_test_pld(struct hpi_adapter_obj *pao, int dsp_index)
1952719f82d3SEliot Blennerhassett {
1953719f82d3SEliot Blennerhassett 	u32 data = 0;
1954719f82d3SEliot Blennerhassett 	if (dsp_index == 0) {
1955719f82d3SEliot Blennerhassett 		/* only test for DSP0 PLD on ASI5000 card */
19563285ea10SEliot Blennerhassett 		if (pao->pci.pci_dev->subsystem_device == 0x5000) {
1957719f82d3SEliot Blennerhassett 			/* PLD is located at CE3=0x03000000 */
1958719f82d3SEliot Blennerhassett 			data = boot_loader_read_mem32(pao, dsp_index,
1959719f82d3SEliot Blennerhassett 				0x03000008);
1960719f82d3SEliot Blennerhassett 			if ((data & 0xF) != 0x5)
19613285ea10SEliot Blennerhassett 				return HPI6205_ERROR_DSP_PLD;
1962719f82d3SEliot Blennerhassett 			data = boot_loader_read_mem32(pao, dsp_index,
1963719f82d3SEliot Blennerhassett 				0x0300000C);
1964719f82d3SEliot Blennerhassett 			if ((data & 0xF) != 0xA)
19653285ea10SEliot Blennerhassett 				return HPI6205_ERROR_DSP_PLD;
1966719f82d3SEliot Blennerhassett 		}
1967719f82d3SEliot Blennerhassett 	} else if (dsp_index == 1) {
1968719f82d3SEliot Blennerhassett 		/* DSP 1 is a C6713 */
19693285ea10SEliot Blennerhassett 		if (pao->pci.pci_dev->subsystem_device == 0x8700) {
1970719f82d3SEliot Blennerhassett 			/* PLD is located at CE1=0x90000000 */
1971719f82d3SEliot Blennerhassett 			data = boot_loader_read_mem32(pao, dsp_index,
1972719f82d3SEliot Blennerhassett 				0x90000010);
1973719f82d3SEliot Blennerhassett 			if ((data & 0xFF) != 0xAA)
19743285ea10SEliot Blennerhassett 				return HPI6205_ERROR_DSP_PLD;
1975719f82d3SEliot Blennerhassett 			/* 8713 - LED on */
1976719f82d3SEliot Blennerhassett 			boot_loader_write_mem32(pao, dsp_index, 0x90000000,
1977719f82d3SEliot Blennerhassett 				0x02);
1978719f82d3SEliot Blennerhassett 		}
1979719f82d3SEliot Blennerhassett 	}
1980719f82d3SEliot Blennerhassett 	return 0;
1981719f82d3SEliot Blennerhassett }
1982719f82d3SEliot Blennerhassett 
1983719f82d3SEliot Blennerhassett /** Transfer data to or from DSP
1984719f82d3SEliot Blennerhassett  nOperation = H620_H620_HIF_SEND_DATA or H620_HIF_GET_DATA
1985719f82d3SEliot Blennerhassett */
hpi6205_transfer_data(struct hpi_adapter_obj * pao,u8 * p_data,u32 data_size,int operation)1986719f82d3SEliot Blennerhassett static short hpi6205_transfer_data(struct hpi_adapter_obj *pao, u8 *p_data,
1987719f82d3SEliot Blennerhassett 	u32 data_size, int operation)
1988719f82d3SEliot Blennerhassett {
1989719f82d3SEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
1990719f82d3SEliot Blennerhassett 	u32 data_transferred = 0;
1991719f82d3SEliot Blennerhassett 	u16 err = 0;
1992719f82d3SEliot Blennerhassett 	u32 temp2;
1993719f82d3SEliot Blennerhassett 	struct bus_master_interface *interface = phw->p_interface_buffer;
1994719f82d3SEliot Blennerhassett 
1995719f82d3SEliot Blennerhassett 	if (!p_data)
1996deb21a23SEliot Blennerhassett 		return HPI_ERROR_INVALID_DATA_POINTER;
1997719f82d3SEliot Blennerhassett 
1998719f82d3SEliot Blennerhassett 	data_size &= ~3L;	/* round data_size down to nearest 4 bytes */
1999719f82d3SEliot Blennerhassett 
2000719f82d3SEliot Blennerhassett 	/* make sure state is IDLE */
2001719f82d3SEliot Blennerhassett 	if (!wait_dsp_ack(phw, H620_HIF_IDLE, HPI6205_TIMEOUT))
2002719f82d3SEliot Blennerhassett 		return HPI_ERROR_DSP_HARDWARE;
2003719f82d3SEliot Blennerhassett 
2004719f82d3SEliot Blennerhassett 	while (data_transferred < data_size) {
2005719f82d3SEliot Blennerhassett 		u32 this_copy = data_size - data_transferred;
2006719f82d3SEliot Blennerhassett 
2007719f82d3SEliot Blennerhassett 		if (this_copy > HPI6205_SIZEOF_DATA)
2008719f82d3SEliot Blennerhassett 			this_copy = HPI6205_SIZEOF_DATA;
2009719f82d3SEliot Blennerhassett 
2010719f82d3SEliot Blennerhassett 		if (operation == H620_HIF_SEND_DATA)
2011719f82d3SEliot Blennerhassett 			memcpy((void *)&interface->u.b_data[0],
2012719f82d3SEliot Blennerhassett 				&p_data[data_transferred], this_copy);
2013719f82d3SEliot Blennerhassett 
2014719f82d3SEliot Blennerhassett 		interface->transfer_size_in_bytes = this_copy;
2015719f82d3SEliot Blennerhassett 
2016719f82d3SEliot Blennerhassett 		/* DSP must change this back to nOperation */
2017719f82d3SEliot Blennerhassett 		interface->dsp_ack = H620_HIF_IDLE;
2018719f82d3SEliot Blennerhassett 		send_dsp_command(phw, operation);
2019719f82d3SEliot Blennerhassett 
2020719f82d3SEliot Blennerhassett 		temp2 = wait_dsp_ack(phw, operation, HPI6205_TIMEOUT);
2021719f82d3SEliot Blennerhassett 		HPI_DEBUG_LOG(DEBUG, "spun %d times for data xfer of %d\n",
2022719f82d3SEliot Blennerhassett 			HPI6205_TIMEOUT - temp2, this_copy);
2023719f82d3SEliot Blennerhassett 
2024719f82d3SEliot Blennerhassett 		if (!temp2) {
2025719f82d3SEliot Blennerhassett 			/* timed out */
2026719f82d3SEliot Blennerhassett 			HPI_DEBUG_LOG(ERROR,
20273285ea10SEliot Blennerhassett 				"Timed out waiting for " "state %d got %d\n",
2028719f82d3SEliot Blennerhassett 				operation, interface->dsp_ack);
2029719f82d3SEliot Blennerhassett 
2030719f82d3SEliot Blennerhassett 			break;
2031719f82d3SEliot Blennerhassett 		}
2032719f82d3SEliot Blennerhassett 		if (operation == H620_HIF_GET_DATA)
2033719f82d3SEliot Blennerhassett 			memcpy(&p_data[data_transferred],
2034719f82d3SEliot Blennerhassett 				(void *)&interface->u.b_data[0], this_copy);
2035719f82d3SEliot Blennerhassett 
2036719f82d3SEliot Blennerhassett 		data_transferred += this_copy;
2037719f82d3SEliot Blennerhassett 	}
2038719f82d3SEliot Blennerhassett 	if (interface->dsp_ack != operation)
2039719f82d3SEliot Blennerhassett 		HPI_DEBUG_LOG(DEBUG, "interface->dsp_ack=%d, expected %d\n",
2040719f82d3SEliot Blennerhassett 			interface->dsp_ack, operation);
2041719f82d3SEliot Blennerhassett 	/*                      err=HPI_ERROR_DSP_HARDWARE; */
2042719f82d3SEliot Blennerhassett 
2043719f82d3SEliot Blennerhassett 	send_dsp_command(phw, H620_HIF_IDLE);
2044719f82d3SEliot Blennerhassett 
2045719f82d3SEliot Blennerhassett 	return err;
2046719f82d3SEliot Blennerhassett }
2047719f82d3SEliot Blennerhassett 
2048719f82d3SEliot Blennerhassett /* wait for up to timeout_us microseconds for the DSP
2049719f82d3SEliot Blennerhassett    to signal state by DMA into dwDspAck
2050719f82d3SEliot Blennerhassett */
wait_dsp_ack(struct hpi_hw_obj * phw,int state,int timeout_us)2051719f82d3SEliot Blennerhassett static int wait_dsp_ack(struct hpi_hw_obj *phw, int state, int timeout_us)
2052719f82d3SEliot Blennerhassett {
2053719f82d3SEliot Blennerhassett 	struct bus_master_interface *interface = phw->p_interface_buffer;
2054719f82d3SEliot Blennerhassett 	int t = timeout_us / 4;
2055719f82d3SEliot Blennerhassett 
2056719f82d3SEliot Blennerhassett 	rmb();	/* ensure interface->dsp_ack is up to date */
2057719f82d3SEliot Blennerhassett 	while ((interface->dsp_ack != state) && --t) {
2058719f82d3SEliot Blennerhassett 		hpios_delay_micro_seconds(4);
2059719f82d3SEliot Blennerhassett 		rmb();	/* DSP changes dsp_ack by DMA */
2060719f82d3SEliot Blennerhassett 	}
2061719f82d3SEliot Blennerhassett 
2062719f82d3SEliot Blennerhassett 	/*HPI_DEBUG_LOG(VERBOSE, "Spun %d for %d\n", timeout_us/4-t, state); */
2063719f82d3SEliot Blennerhassett 	return t * 4;
2064719f82d3SEliot Blennerhassett }
2065719f82d3SEliot Blennerhassett 
2066719f82d3SEliot Blennerhassett /* set the busmaster interface to cmd, then interrupt the DSP */
send_dsp_command(struct hpi_hw_obj * phw,int cmd)2067719f82d3SEliot Blennerhassett static void send_dsp_command(struct hpi_hw_obj *phw, int cmd)
2068719f82d3SEliot Blennerhassett {
2069719f82d3SEliot Blennerhassett 	struct bus_master_interface *interface = phw->p_interface_buffer;
2070719f82d3SEliot Blennerhassett 	u32 r;
2071719f82d3SEliot Blennerhassett 
2072719f82d3SEliot Blennerhassett 	interface->host_cmd = cmd;
2073719f82d3SEliot Blennerhassett 	wmb();	/* DSP gets state by DMA, make sure it is written to memory */
2074719f82d3SEliot Blennerhassett 	/* before we interrupt the DSP */
2075719f82d3SEliot Blennerhassett 	r = ioread32(phw->prHDCR);
2076719f82d3SEliot Blennerhassett 	r |= (u32)C6205_HDCR_DSPINT;
2077719f82d3SEliot Blennerhassett 	iowrite32(r, phw->prHDCR);
2078719f82d3SEliot Blennerhassett 	r &= ~(u32)C6205_HDCR_DSPINT;
2079719f82d3SEliot Blennerhassett 	iowrite32(r, phw->prHDCR);
2080719f82d3SEliot Blennerhassett }
2081719f82d3SEliot Blennerhassett 
2082719f82d3SEliot Blennerhassett static unsigned int message_count;
2083719f82d3SEliot Blennerhassett 
message_response_sequence(struct hpi_adapter_obj * pao,struct hpi_message * phm,struct hpi_response * phr)2084719f82d3SEliot Blennerhassett static u16 message_response_sequence(struct hpi_adapter_obj *pao,
2085719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
2086719f82d3SEliot Blennerhassett {
2087719f82d3SEliot Blennerhassett 	u32 time_out, time_out2;
2088719f82d3SEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
2089719f82d3SEliot Blennerhassett 	struct bus_master_interface *interface = phw->p_interface_buffer;
2090719f82d3SEliot Blennerhassett 	u16 err = 0;
2091719f82d3SEliot Blennerhassett 
2092719f82d3SEliot Blennerhassett 	message_count++;
2093c6c2c9abSEliot Blennerhassett 	if (phm->size > sizeof(interface->u.message_buffer)) {
2094deb21a23SEliot Blennerhassett 		phr->error = HPI_ERROR_MESSAGE_BUFFER_TOO_SMALL;
2095c6c2c9abSEliot Blennerhassett 		phr->specific_error = sizeof(interface->u.message_buffer);
20963285ea10SEliot Blennerhassett 		phr->size = sizeof(struct hpi_response_header);
20973285ea10SEliot Blennerhassett 		HPI_DEBUG_LOG(ERROR,
2098a2800300STakashi Iwai 			"message len %d too big for buffer %zd \n", phm->size,
2099c6c2c9abSEliot Blennerhassett 			sizeof(interface->u.message_buffer));
21003285ea10SEliot Blennerhassett 		return 0;
21013285ea10SEliot Blennerhassett 	}
21023285ea10SEliot Blennerhassett 
2103f9a376c3SEliot Blennerhassett 	/* Assume buffer of type struct bus_master_interface_62
2104719f82d3SEliot Blennerhassett 	   is allocated "noncacheable" */
2105719f82d3SEliot Blennerhassett 
2106719f82d3SEliot Blennerhassett 	if (!wait_dsp_ack(phw, H620_HIF_IDLE, HPI6205_TIMEOUT)) {
2107719f82d3SEliot Blennerhassett 		HPI_DEBUG_LOG(DEBUG, "timeout waiting for idle\n");
21083285ea10SEliot Blennerhassett 		return HPI6205_ERROR_MSG_RESP_IDLE_TIMEOUT;
2109719f82d3SEliot Blennerhassett 	}
21103285ea10SEliot Blennerhassett 
21113285ea10SEliot Blennerhassett 	memcpy(&interface->u.message_buffer, phm, phm->size);
2112719f82d3SEliot Blennerhassett 	/* signal we want a response */
2113719f82d3SEliot Blennerhassett 	send_dsp_command(phw, H620_HIF_GET_RESP);
2114719f82d3SEliot Blennerhassett 
2115719f82d3SEliot Blennerhassett 	time_out2 = wait_dsp_ack(phw, H620_HIF_GET_RESP, HPI6205_TIMEOUT);
2116719f82d3SEliot Blennerhassett 
21173285ea10SEliot Blennerhassett 	if (!time_out2) {
2118719f82d3SEliot Blennerhassett 		HPI_DEBUG_LOG(ERROR,
21193285ea10SEliot Blennerhassett 			"(%u) Timed out waiting for " "GET_RESP state [%x]\n",
2120719f82d3SEliot Blennerhassett 			message_count, interface->dsp_ack);
2121719f82d3SEliot Blennerhassett 	} else {
2122719f82d3SEliot Blennerhassett 		HPI_DEBUG_LOG(VERBOSE,
2123719f82d3SEliot Blennerhassett 			"(%u) transition to GET_RESP after %u\n",
2124719f82d3SEliot Blennerhassett 			message_count, HPI6205_TIMEOUT - time_out2);
2125719f82d3SEliot Blennerhassett 	}
2126719f82d3SEliot Blennerhassett 	/* spin waiting on HIF interrupt flag (end of msg process) */
2127719f82d3SEliot Blennerhassett 	time_out = HPI6205_TIMEOUT;
2128719f82d3SEliot Blennerhassett 
2129719f82d3SEliot Blennerhassett 	/* read the result */
21303285ea10SEliot Blennerhassett 	if (time_out) {
2131c6c2c9abSEliot Blennerhassett 		if (interface->u.response_buffer.response.size <= phr->size)
21323285ea10SEliot Blennerhassett 			memcpy(phr, &interface->u.response_buffer,
2133c6c2c9abSEliot Blennerhassett 				interface->u.response_buffer.response.size);
21343285ea10SEliot Blennerhassett 		else {
21353285ea10SEliot Blennerhassett 			HPI_DEBUG_LOG(ERROR,
21363285ea10SEliot Blennerhassett 				"response len %d too big for buffer %d\n",
2137c6c2c9abSEliot Blennerhassett 				interface->u.response_buffer.response.size,
2138c6c2c9abSEliot Blennerhassett 				phr->size);
21393285ea10SEliot Blennerhassett 			memcpy(phr, &interface->u.response_buffer,
21403285ea10SEliot Blennerhassett 				sizeof(struct hpi_response_header));
21413285ea10SEliot Blennerhassett 			phr->error = HPI_ERROR_RESPONSE_BUFFER_TOO_SMALL;
21423285ea10SEliot Blennerhassett 			phr->specific_error =
2143c6c2c9abSEliot Blennerhassett 				interface->u.response_buffer.response.size;
21443285ea10SEliot Blennerhassett 			phr->size = sizeof(struct hpi_response_header);
21453285ea10SEliot Blennerhassett 		}
21463285ea10SEliot Blennerhassett 	}
2147719f82d3SEliot Blennerhassett 	/* set interface back to idle */
2148719f82d3SEliot Blennerhassett 	send_dsp_command(phw, H620_HIF_IDLE);
2149719f82d3SEliot Blennerhassett 
21503285ea10SEliot Blennerhassett 	if (!time_out || !time_out2) {
2151719f82d3SEliot Blennerhassett 		HPI_DEBUG_LOG(DEBUG, "something timed out!\n");
21523285ea10SEliot Blennerhassett 		return HPI6205_ERROR_MSG_RESP_TIMEOUT;
2153719f82d3SEliot Blennerhassett 	}
2154719f82d3SEliot Blennerhassett 	/* special case for adapter close - */
2155719f82d3SEliot Blennerhassett 	/* wait for the DSP to indicate it is idle */
2156719f82d3SEliot Blennerhassett 	if (phm->function == HPI_ADAPTER_CLOSE) {
2157719f82d3SEliot Blennerhassett 		if (!wait_dsp_ack(phw, H620_HIF_IDLE, HPI6205_TIMEOUT)) {
2158719f82d3SEliot Blennerhassett 			HPI_DEBUG_LOG(DEBUG,
21593285ea10SEliot Blennerhassett 				"Timeout waiting for idle "
2160719f82d3SEliot Blennerhassett 				"(on adapter_close)\n");
21613285ea10SEliot Blennerhassett 			return HPI6205_ERROR_MSG_RESP_IDLE_TIMEOUT;
2162719f82d3SEliot Blennerhassett 		}
2163719f82d3SEliot Blennerhassett 	}
2164719f82d3SEliot Blennerhassett 	err = hpi_validate_response(phm, phr);
2165719f82d3SEliot Blennerhassett 	return err;
2166719f82d3SEliot Blennerhassett }
2167719f82d3SEliot Blennerhassett 
hw_message(struct hpi_adapter_obj * pao,struct hpi_message * phm,struct hpi_response * phr)2168719f82d3SEliot Blennerhassett static void hw_message(struct hpi_adapter_obj *pao, struct hpi_message *phm,
2169719f82d3SEliot Blennerhassett 	struct hpi_response *phr)
2170719f82d3SEliot Blennerhassett {
2171719f82d3SEliot Blennerhassett 
2172719f82d3SEliot Blennerhassett 	u16 err = 0;
2173719f82d3SEliot Blennerhassett 
2174719f82d3SEliot Blennerhassett 	hpios_dsplock_lock(pao);
2175719f82d3SEliot Blennerhassett 
2176719f82d3SEliot Blennerhassett 	err = message_response_sequence(pao, phm, phr);
2177719f82d3SEliot Blennerhassett 
2178719f82d3SEliot Blennerhassett 	/* maybe an error response */
2179719f82d3SEliot Blennerhassett 	if (err) {
2180719f82d3SEliot Blennerhassett 		/* something failed in the HPI/DSP interface */
21810a00044dSEliot Blennerhassett 		if (err >= HPI_ERROR_BACKEND_BASE) {
21820a00044dSEliot Blennerhassett 			phr->error = HPI_ERROR_DSP_COMMUNICATION;
21830a00044dSEliot Blennerhassett 			phr->specific_error = err;
21840a00044dSEliot Blennerhassett 		} else {
2185719f82d3SEliot Blennerhassett 			phr->error = err;
21860a00044dSEliot Blennerhassett 		}
21870a00044dSEliot Blennerhassett 
2188719f82d3SEliot Blennerhassett 		pao->dsp_crashed++;
2189719f82d3SEliot Blennerhassett 
2190719f82d3SEliot Blennerhassett 		/* just the header of the response is valid */
2191719f82d3SEliot Blennerhassett 		phr->size = sizeof(struct hpi_response_header);
2192719f82d3SEliot Blennerhassett 		goto err;
2193719f82d3SEliot Blennerhassett 	} else
2194719f82d3SEliot Blennerhassett 		pao->dsp_crashed = 0;
2195719f82d3SEliot Blennerhassett 
2196719f82d3SEliot Blennerhassett 	if (phr->error != 0)	/* something failed in the DSP */
2197719f82d3SEliot Blennerhassett 		goto err;
2198719f82d3SEliot Blennerhassett 
2199719f82d3SEliot Blennerhassett 	switch (phm->function) {
2200719f82d3SEliot Blennerhassett 	case HPI_OSTREAM_WRITE:
2201719f82d3SEliot Blennerhassett 	case HPI_ISTREAM_ANC_WRITE:
2202719f82d3SEliot Blennerhassett 		err = hpi6205_transfer_data(pao, phm->u.d.u.data.pb_data,
2203719f82d3SEliot Blennerhassett 			phm->u.d.u.data.data_size, H620_HIF_SEND_DATA);
2204719f82d3SEliot Blennerhassett 		break;
2205719f82d3SEliot Blennerhassett 
2206719f82d3SEliot Blennerhassett 	case HPI_ISTREAM_READ:
2207719f82d3SEliot Blennerhassett 	case HPI_OSTREAM_ANC_READ:
2208719f82d3SEliot Blennerhassett 		err = hpi6205_transfer_data(pao, phm->u.d.u.data.pb_data,
2209719f82d3SEliot Blennerhassett 			phm->u.d.u.data.data_size, H620_HIF_GET_DATA);
2210719f82d3SEliot Blennerhassett 		break;
2211719f82d3SEliot Blennerhassett 
2212719f82d3SEliot Blennerhassett 	}
2213719f82d3SEliot Blennerhassett 	phr->error = err;
2214719f82d3SEliot Blennerhassett 
2215719f82d3SEliot Blennerhassett err:
2216719f82d3SEliot Blennerhassett 	hpios_dsplock_unlock(pao);
2217719f82d3SEliot Blennerhassett 
2218719f82d3SEliot Blennerhassett 	return;
2219719f82d3SEliot Blennerhassett }
2220