xref: /openbmc/linux/sound/pci/asihpi/hpi6205.c (revision 7036b92d303a01477e27a5a9b2d582a5df3cc8ef)
1719f82d3SEliot Blennerhassett /******************************************************************************
2719f82d3SEliot Blennerhassett 
3719f82d3SEliot Blennerhassett     AudioScience HPI driver
440818b62SEliot Blennerhassett     Copyright (C) 1997-2011  AudioScience Inc. <support@audioscience.com>
5719f82d3SEliot Blennerhassett 
6719f82d3SEliot Blennerhassett     This program is free software; you can redistribute it and/or modify
7719f82d3SEliot Blennerhassett     it under the terms of version 2 of the GNU General Public License as
8719f82d3SEliot Blennerhassett     published by the Free Software Foundation;
9719f82d3SEliot Blennerhassett 
10719f82d3SEliot Blennerhassett     This program is distributed in the hope that it will be useful,
11719f82d3SEliot Blennerhassett     but WITHOUT ANY WARRANTY; without even the implied warranty of
12719f82d3SEliot Blennerhassett     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13719f82d3SEliot Blennerhassett     GNU General Public License for more details.
14719f82d3SEliot Blennerhassett 
15719f82d3SEliot Blennerhassett     You should have received a copy of the GNU General Public License
16719f82d3SEliot Blennerhassett     along with this program; if not, write to the Free Software
17719f82d3SEliot Blennerhassett     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18719f82d3SEliot Blennerhassett 
19719f82d3SEliot Blennerhassett  Hardware Programming Interface (HPI) for AudioScience
20719f82d3SEliot Blennerhassett  ASI50xx, AS51xx, ASI6xxx, ASI87xx ASI89xx series adapters.
21719f82d3SEliot Blennerhassett  These PCI and PCIe bus adapters are based on a
22719f82d3SEliot Blennerhassett  TMS320C6205 PCI bus mastering DSP,
23719f82d3SEliot Blennerhassett  and (except ASI50xx) TI TMS320C6xxx floating point DSP
24719f82d3SEliot Blennerhassett 
25719f82d3SEliot Blennerhassett  Exported function:
26719f82d3SEliot Blennerhassett  void HPI_6205(struct hpi_message *phm, struct hpi_response *phr)
27719f82d3SEliot Blennerhassett 
28719f82d3SEliot Blennerhassett (C) Copyright AudioScience Inc. 1998-2010
29719f82d3SEliot Blennerhassett *******************************************************************************/
30719f82d3SEliot Blennerhassett #define SOURCEFILE_NAME "hpi6205.c"
31719f82d3SEliot Blennerhassett 
32719f82d3SEliot Blennerhassett #include "hpi_internal.h"
33719f82d3SEliot Blennerhassett #include "hpimsginit.h"
34719f82d3SEliot Blennerhassett #include "hpidebug.h"
35719f82d3SEliot Blennerhassett #include "hpi6205.h"
36719f82d3SEliot Blennerhassett #include "hpidspcd.h"
37719f82d3SEliot Blennerhassett #include "hpicmn.h"
38719f82d3SEliot Blennerhassett 
39719f82d3SEliot Blennerhassett /*****************************************************************************/
40719f82d3SEliot Blennerhassett /* HPI6205 specific error codes */
413285ea10SEliot Blennerhassett #define HPI6205_ERROR_BASE 1000	/* not actually used anywhere */
423285ea10SEliot Blennerhassett 
433285ea10SEliot Blennerhassett /* operational/messaging errors */
443285ea10SEliot Blennerhassett #define HPI6205_ERROR_MSG_RESP_IDLE_TIMEOUT     1015
453285ea10SEliot Blennerhassett #define HPI6205_ERROR_MSG_RESP_TIMEOUT          1016
463285ea10SEliot Blennerhassett 
473285ea10SEliot Blennerhassett /* initialization/bootload errors */
48719f82d3SEliot Blennerhassett #define HPI6205_ERROR_6205_NO_IRQ               1002
49719f82d3SEliot Blennerhassett #define HPI6205_ERROR_6205_INIT_FAILED          1003
50719f82d3SEliot Blennerhassett #define HPI6205_ERROR_6205_REG                  1006
51719f82d3SEliot Blennerhassett #define HPI6205_ERROR_6205_DSPPAGE              1007
52719f82d3SEliot Blennerhassett #define HPI6205_ERROR_C6713_HPIC                1009
53719f82d3SEliot Blennerhassett #define HPI6205_ERROR_C6713_HPIA                1010
54719f82d3SEliot Blennerhassett #define HPI6205_ERROR_C6713_PLL                 1011
55719f82d3SEliot Blennerhassett #define HPI6205_ERROR_DSP_INTMEM                1012
56719f82d3SEliot Blennerhassett #define HPI6205_ERROR_DSP_EXTMEM                1013
57719f82d3SEliot Blennerhassett #define HPI6205_ERROR_DSP_PLD                   1014
58719f82d3SEliot Blennerhassett #define HPI6205_ERROR_6205_EEPROM               1017
59719f82d3SEliot Blennerhassett #define HPI6205_ERROR_DSP_EMIF                  1018
60719f82d3SEliot Blennerhassett 
61719f82d3SEliot Blennerhassett /*****************************************************************************/
62719f82d3SEliot Blennerhassett /* for C6205 PCI i/f */
63719f82d3SEliot Blennerhassett /* Host Status Register (HSR) bitfields */
64719f82d3SEliot Blennerhassett #define C6205_HSR_INTSRC        0x01
65719f82d3SEliot Blennerhassett #define C6205_HSR_INTAVAL       0x02
66719f82d3SEliot Blennerhassett #define C6205_HSR_INTAM         0x04
67719f82d3SEliot Blennerhassett #define C6205_HSR_CFGERR        0x08
68719f82d3SEliot Blennerhassett #define C6205_HSR_EEREAD        0x10
69719f82d3SEliot Blennerhassett /* Host-to-DSP Control Register (HDCR) bitfields */
70719f82d3SEliot Blennerhassett #define C6205_HDCR_WARMRESET    0x01
71719f82d3SEliot Blennerhassett #define C6205_HDCR_DSPINT       0x02
72719f82d3SEliot Blennerhassett #define C6205_HDCR_PCIBOOT      0x04
73719f82d3SEliot Blennerhassett /* DSP Page Register (DSPP) bitfields, */
74719f82d3SEliot Blennerhassett /* defines 4 Mbyte page that BAR0 points to */
75719f82d3SEliot Blennerhassett #define C6205_DSPP_MAP1         0x400
76719f82d3SEliot Blennerhassett 
77719f82d3SEliot Blennerhassett /* BAR0 maps to prefetchable 4 Mbyte memory block set by DSPP.
78719f82d3SEliot Blennerhassett  * BAR1 maps to non-prefetchable 8 Mbyte memory block
79719f82d3SEliot Blennerhassett  * of DSP memory mapped registers (starting at 0x01800000).
80719f82d3SEliot Blennerhassett  * 0x01800000 is hardcoded in the PCI i/f, so that only the offset from this
81719f82d3SEliot Blennerhassett  * needs to be added to the BAR1 base address set in the PCI config reg
82719f82d3SEliot Blennerhassett  */
83719f82d3SEliot Blennerhassett #define C6205_BAR1_PCI_IO_OFFSET (0x027FFF0L)
84719f82d3SEliot Blennerhassett #define C6205_BAR1_HSR  (C6205_BAR1_PCI_IO_OFFSET)
85719f82d3SEliot Blennerhassett #define C6205_BAR1_HDCR (C6205_BAR1_PCI_IO_OFFSET+4)
86719f82d3SEliot Blennerhassett #define C6205_BAR1_DSPP (C6205_BAR1_PCI_IO_OFFSET+8)
87719f82d3SEliot Blennerhassett 
88719f82d3SEliot Blennerhassett /* used to control LED (revA) and reset C6713 (revB) */
89719f82d3SEliot Blennerhassett #define C6205_BAR0_TIMER1_CTL (0x01980000L)
90719f82d3SEliot Blennerhassett 
91719f82d3SEliot Blennerhassett /* For first 6713 in CE1 space, using DA17,16,2 */
92719f82d3SEliot Blennerhassett #define HPICL_ADDR      0x01400000L
93719f82d3SEliot Blennerhassett #define HPICH_ADDR      0x01400004L
94719f82d3SEliot Blennerhassett #define HPIAL_ADDR      0x01410000L
95719f82d3SEliot Blennerhassett #define HPIAH_ADDR      0x01410004L
96719f82d3SEliot Blennerhassett #define HPIDIL_ADDR     0x01420000L
97719f82d3SEliot Blennerhassett #define HPIDIH_ADDR     0x01420004L
98719f82d3SEliot Blennerhassett #define HPIDL_ADDR      0x01430000L
99719f82d3SEliot Blennerhassett #define HPIDH_ADDR      0x01430004L
100719f82d3SEliot Blennerhassett 
101719f82d3SEliot Blennerhassett #define C6713_EMIF_GCTL         0x01800000
102719f82d3SEliot Blennerhassett #define C6713_EMIF_CE1          0x01800004
103719f82d3SEliot Blennerhassett #define C6713_EMIF_CE0          0x01800008
104719f82d3SEliot Blennerhassett #define C6713_EMIF_CE2          0x01800010
105719f82d3SEliot Blennerhassett #define C6713_EMIF_CE3          0x01800014
106719f82d3SEliot Blennerhassett #define C6713_EMIF_SDRAMCTL     0x01800018
107719f82d3SEliot Blennerhassett #define C6713_EMIF_SDRAMTIMING  0x0180001C
108719f82d3SEliot Blennerhassett #define C6713_EMIF_SDRAMEXT     0x01800020
109719f82d3SEliot Blennerhassett 
110719f82d3SEliot Blennerhassett struct hpi_hw_obj {
111719f82d3SEliot Blennerhassett 	/* PCI registers */
112719f82d3SEliot Blennerhassett 	__iomem u32 *prHSR;
113719f82d3SEliot Blennerhassett 	__iomem u32 *prHDCR;
114719f82d3SEliot Blennerhassett 	__iomem u32 *prDSPP;
115719f82d3SEliot Blennerhassett 
116719f82d3SEliot Blennerhassett 	u32 dsp_page;
117719f82d3SEliot Blennerhassett 
118719f82d3SEliot Blennerhassett 	struct consistent_dma_area h_locked_mem;
119719f82d3SEliot Blennerhassett 	struct bus_master_interface *p_interface_buffer;
120719f82d3SEliot Blennerhassett 
121719f82d3SEliot Blennerhassett 	u16 flag_outstream_just_reset[HPI_MAX_STREAMS];
122719f82d3SEliot Blennerhassett 	/* a non-NULL handle means there is an HPI allocated buffer */
123719f82d3SEliot Blennerhassett 	struct consistent_dma_area instream_host_buffers[HPI_MAX_STREAMS];
124719f82d3SEliot Blennerhassett 	struct consistent_dma_area outstream_host_buffers[HPI_MAX_STREAMS];
125719f82d3SEliot Blennerhassett 	/* non-zero size means a buffer exists, may be external */
126719f82d3SEliot Blennerhassett 	u32 instream_host_buffer_size[HPI_MAX_STREAMS];
127719f82d3SEliot Blennerhassett 	u32 outstream_host_buffer_size[HPI_MAX_STREAMS];
128719f82d3SEliot Blennerhassett 
129719f82d3SEliot Blennerhassett 	struct consistent_dma_area h_control_cache;
130719f82d3SEliot Blennerhassett 	struct hpi_control_cache *p_cache;
131719f82d3SEliot Blennerhassett };
132719f82d3SEliot Blennerhassett 
133719f82d3SEliot Blennerhassett /*****************************************************************************/
134719f82d3SEliot Blennerhassett /* local prototypes */
135719f82d3SEliot Blennerhassett 
136719f82d3SEliot Blennerhassett #define check_before_bbm_copy(status, p_bbm_data, l_first_write, l_second_write)
137719f82d3SEliot Blennerhassett 
138719f82d3SEliot Blennerhassett static int wait_dsp_ack(struct hpi_hw_obj *phw, int state, int timeout_us);
139719f82d3SEliot Blennerhassett 
140719f82d3SEliot Blennerhassett static void send_dsp_command(struct hpi_hw_obj *phw, int cmd);
141719f82d3SEliot Blennerhassett 
142719f82d3SEliot Blennerhassett static u16 adapter_boot_load_dsp(struct hpi_adapter_obj *pao,
143719f82d3SEliot Blennerhassett 	u32 *pos_error_code);
144719f82d3SEliot Blennerhassett 
145719f82d3SEliot Blennerhassett static u16 message_response_sequence(struct hpi_adapter_obj *pao,
146719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr);
147719f82d3SEliot Blennerhassett 
148719f82d3SEliot Blennerhassett static void hw_message(struct hpi_adapter_obj *pao, struct hpi_message *phm,
149719f82d3SEliot Blennerhassett 	struct hpi_response *phr);
150719f82d3SEliot Blennerhassett 
151719f82d3SEliot Blennerhassett #define HPI6205_TIMEOUT 1000000
152719f82d3SEliot Blennerhassett 
153719f82d3SEliot Blennerhassett static void subsys_create_adapter(struct hpi_message *phm,
154719f82d3SEliot Blennerhassett 	struct hpi_response *phr);
1556d0b898eSEliot Blennerhassett static void adapter_delete(struct hpi_adapter_obj *pao,
1566d0b898eSEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr);
157719f82d3SEliot Blennerhassett 
158719f82d3SEliot Blennerhassett static u16 create_adapter_obj(struct hpi_adapter_obj *pao,
159719f82d3SEliot Blennerhassett 	u32 *pos_error_code);
160719f82d3SEliot Blennerhassett 
161719f82d3SEliot Blennerhassett static void delete_adapter_obj(struct hpi_adapter_obj *pao);
162719f82d3SEliot Blennerhassett 
163719f82d3SEliot Blennerhassett static void outstream_host_buffer_allocate(struct hpi_adapter_obj *pao,
164719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr);
165719f82d3SEliot Blennerhassett 
166719f82d3SEliot Blennerhassett static void outstream_host_buffer_get_info(struct hpi_adapter_obj *pao,
167719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr);
168719f82d3SEliot Blennerhassett 
169719f82d3SEliot Blennerhassett static void outstream_host_buffer_free(struct hpi_adapter_obj *pao,
170719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr);
171719f82d3SEliot Blennerhassett static void outstream_write(struct hpi_adapter_obj *pao,
172719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr);
173719f82d3SEliot Blennerhassett 
174719f82d3SEliot Blennerhassett static void outstream_get_info(struct hpi_adapter_obj *pao,
175719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr);
176719f82d3SEliot Blennerhassett 
177719f82d3SEliot Blennerhassett static void outstream_start(struct hpi_adapter_obj *pao,
178719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr);
179719f82d3SEliot Blennerhassett 
180719f82d3SEliot Blennerhassett static void outstream_open(struct hpi_adapter_obj *pao,
181719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr);
182719f82d3SEliot Blennerhassett 
183719f82d3SEliot Blennerhassett static void outstream_reset(struct hpi_adapter_obj *pao,
184719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr);
185719f82d3SEliot Blennerhassett 
186719f82d3SEliot Blennerhassett static void instream_host_buffer_allocate(struct hpi_adapter_obj *pao,
187719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr);
188719f82d3SEliot Blennerhassett 
189719f82d3SEliot Blennerhassett static void instream_host_buffer_get_info(struct hpi_adapter_obj *pao,
190719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr);
191719f82d3SEliot Blennerhassett 
192719f82d3SEliot Blennerhassett static void instream_host_buffer_free(struct hpi_adapter_obj *pao,
193719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr);
194719f82d3SEliot Blennerhassett 
195719f82d3SEliot Blennerhassett static void instream_read(struct hpi_adapter_obj *pao,
196719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr);
197719f82d3SEliot Blennerhassett 
198719f82d3SEliot Blennerhassett static void instream_get_info(struct hpi_adapter_obj *pao,
199719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr);
200719f82d3SEliot Blennerhassett 
201719f82d3SEliot Blennerhassett static void instream_start(struct hpi_adapter_obj *pao,
202719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr);
203719f82d3SEliot Blennerhassett 
204719f82d3SEliot Blennerhassett static u32 boot_loader_read_mem32(struct hpi_adapter_obj *pao, int dsp_index,
205719f82d3SEliot Blennerhassett 	u32 address);
206719f82d3SEliot Blennerhassett 
2073285ea10SEliot Blennerhassett static void boot_loader_write_mem32(struct hpi_adapter_obj *pao,
2083285ea10SEliot Blennerhassett 	int dsp_index, u32 address, u32 data);
209719f82d3SEliot Blennerhassett 
210719f82d3SEliot Blennerhassett static u16 boot_loader_config_emif(struct hpi_adapter_obj *pao,
211719f82d3SEliot Blennerhassett 	int dsp_index);
212719f82d3SEliot Blennerhassett 
213719f82d3SEliot Blennerhassett static u16 boot_loader_test_memory(struct hpi_adapter_obj *pao, int dsp_index,
214719f82d3SEliot Blennerhassett 	u32 address, u32 length);
215719f82d3SEliot Blennerhassett 
216719f82d3SEliot Blennerhassett static u16 boot_loader_test_internal_memory(struct hpi_adapter_obj *pao,
217719f82d3SEliot Blennerhassett 	int dsp_index);
218719f82d3SEliot Blennerhassett 
219719f82d3SEliot Blennerhassett static u16 boot_loader_test_external_memory(struct hpi_adapter_obj *pao,
220719f82d3SEliot Blennerhassett 	int dsp_index);
221719f82d3SEliot Blennerhassett 
222719f82d3SEliot Blennerhassett static u16 boot_loader_test_pld(struct hpi_adapter_obj *pao, int dsp_index);
223719f82d3SEliot Blennerhassett 
224719f82d3SEliot Blennerhassett /*****************************************************************************/
225719f82d3SEliot Blennerhassett 
2266d0b898eSEliot Blennerhassett static void subsys_message(struct hpi_adapter_obj *pao,
2276d0b898eSEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
228719f82d3SEliot Blennerhassett {
229719f82d3SEliot Blennerhassett 	switch (phm->function) {
230719f82d3SEliot Blennerhassett 	case HPI_SUBSYS_CREATE_ADAPTER:
231719f82d3SEliot Blennerhassett 		subsys_create_adapter(phm, phr);
232719f82d3SEliot Blennerhassett 		break;
233719f82d3SEliot Blennerhassett 	default:
234719f82d3SEliot Blennerhassett 		phr->error = HPI_ERROR_INVALID_FUNC;
235719f82d3SEliot Blennerhassett 		break;
236719f82d3SEliot Blennerhassett 	}
237719f82d3SEliot Blennerhassett }
238719f82d3SEliot Blennerhassett 
239719f82d3SEliot Blennerhassett static void control_message(struct hpi_adapter_obj *pao,
240719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
241719f82d3SEliot Blennerhassett {
242719f82d3SEliot Blennerhassett 
243719f82d3SEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
2443285ea10SEliot Blennerhassett 	u16 pending_cache_error = 0;
245719f82d3SEliot Blennerhassett 
246719f82d3SEliot Blennerhassett 	switch (phm->function) {
247719f82d3SEliot Blennerhassett 	case HPI_CONTROL_GET_STATE:
248719f82d3SEliot Blennerhassett 		if (pao->has_control_cache) {
2493285ea10SEliot Blennerhassett 			rmb();	/* make sure we see updates DMAed from DSP */
2503285ea10SEliot Blennerhassett 			if (hpi_check_control_cache(phw->p_cache, phm, phr)) {
251719f82d3SEliot Blennerhassett 				break;
2523285ea10SEliot Blennerhassett 			} else if (phm->u.c.attribute == HPI_METER_PEAK) {
2533285ea10SEliot Blennerhassett 				pending_cache_error =
2543285ea10SEliot Blennerhassett 					HPI_ERROR_CONTROL_CACHING;
2553285ea10SEliot Blennerhassett 			}
256719f82d3SEliot Blennerhassett 		}
257719f82d3SEliot Blennerhassett 		hw_message(pao, phm, phr);
2583285ea10SEliot Blennerhassett 		if (pending_cache_error && !phr->error)
2593285ea10SEliot Blennerhassett 			phr->error = pending_cache_error;
260719f82d3SEliot Blennerhassett 		break;
261719f82d3SEliot Blennerhassett 	case HPI_CONTROL_GET_INFO:
262719f82d3SEliot Blennerhassett 		hw_message(pao, phm, phr);
263719f82d3SEliot Blennerhassett 		break;
264719f82d3SEliot Blennerhassett 	case HPI_CONTROL_SET_STATE:
265719f82d3SEliot Blennerhassett 		hw_message(pao, phm, phr);
266719f82d3SEliot Blennerhassett 		if (pao->has_control_cache)
2673285ea10SEliot Blennerhassett 			hpi_cmn_control_cache_sync_to_msg(phw->p_cache, phm,
2683285ea10SEliot Blennerhassett 				phr);
269719f82d3SEliot Blennerhassett 		break;
270719f82d3SEliot Blennerhassett 	default:
271719f82d3SEliot Blennerhassett 		phr->error = HPI_ERROR_INVALID_FUNC;
272719f82d3SEliot Blennerhassett 		break;
273719f82d3SEliot Blennerhassett 	}
274719f82d3SEliot Blennerhassett }
275719f82d3SEliot Blennerhassett 
276719f82d3SEliot Blennerhassett static void adapter_message(struct hpi_adapter_obj *pao,
277719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
278719f82d3SEliot Blennerhassett {
279719f82d3SEliot Blennerhassett 	switch (phm->function) {
2806d0b898eSEliot Blennerhassett 	case HPI_ADAPTER_DELETE:
2816d0b898eSEliot Blennerhassett 		adapter_delete(pao, phm, phr);
2826d0b898eSEliot Blennerhassett 		break;
2836d0b898eSEliot Blennerhassett 
284719f82d3SEliot Blennerhassett 	default:
285719f82d3SEliot Blennerhassett 		hw_message(pao, phm, phr);
286719f82d3SEliot Blennerhassett 		break;
287719f82d3SEliot Blennerhassett 	}
288719f82d3SEliot Blennerhassett }
289719f82d3SEliot Blennerhassett 
290719f82d3SEliot Blennerhassett static void outstream_message(struct hpi_adapter_obj *pao,
291719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
292719f82d3SEliot Blennerhassett {
293719f82d3SEliot Blennerhassett 
294719f82d3SEliot Blennerhassett 	if (phm->obj_index >= HPI_MAX_STREAMS) {
295deb21a23SEliot Blennerhassett 		phr->error = HPI_ERROR_INVALID_OBJ_INDEX;
296719f82d3SEliot Blennerhassett 		HPI_DEBUG_LOG(WARNING,
2973285ea10SEliot Blennerhassett 			"Message referencing invalid stream %d "
298719f82d3SEliot Blennerhassett 			"on adapter index %d\n", phm->obj_index,
299719f82d3SEliot Blennerhassett 			phm->adapter_index);
300719f82d3SEliot Blennerhassett 		return;
301719f82d3SEliot Blennerhassett 	}
302719f82d3SEliot Blennerhassett 
303719f82d3SEliot Blennerhassett 	switch (phm->function) {
304719f82d3SEliot Blennerhassett 	case HPI_OSTREAM_WRITE:
305719f82d3SEliot Blennerhassett 		outstream_write(pao, phm, phr);
306719f82d3SEliot Blennerhassett 		break;
307719f82d3SEliot Blennerhassett 	case HPI_OSTREAM_GET_INFO:
308719f82d3SEliot Blennerhassett 		outstream_get_info(pao, phm, phr);
309719f82d3SEliot Blennerhassett 		break;
310719f82d3SEliot Blennerhassett 	case HPI_OSTREAM_HOSTBUFFER_ALLOC:
311719f82d3SEliot Blennerhassett 		outstream_host_buffer_allocate(pao, phm, phr);
312719f82d3SEliot Blennerhassett 		break;
313719f82d3SEliot Blennerhassett 	case HPI_OSTREAM_HOSTBUFFER_GET_INFO:
314719f82d3SEliot Blennerhassett 		outstream_host_buffer_get_info(pao, phm, phr);
315719f82d3SEliot Blennerhassett 		break;
316719f82d3SEliot Blennerhassett 	case HPI_OSTREAM_HOSTBUFFER_FREE:
317719f82d3SEliot Blennerhassett 		outstream_host_buffer_free(pao, phm, phr);
318719f82d3SEliot Blennerhassett 		break;
319719f82d3SEliot Blennerhassett 	case HPI_OSTREAM_START:
320719f82d3SEliot Blennerhassett 		outstream_start(pao, phm, phr);
321719f82d3SEliot Blennerhassett 		break;
322719f82d3SEliot Blennerhassett 	case HPI_OSTREAM_OPEN:
323719f82d3SEliot Blennerhassett 		outstream_open(pao, phm, phr);
324719f82d3SEliot Blennerhassett 		break;
325719f82d3SEliot Blennerhassett 	case HPI_OSTREAM_RESET:
326719f82d3SEliot Blennerhassett 		outstream_reset(pao, phm, phr);
327719f82d3SEliot Blennerhassett 		break;
328719f82d3SEliot Blennerhassett 	default:
329719f82d3SEliot Blennerhassett 		hw_message(pao, phm, phr);
330719f82d3SEliot Blennerhassett 		break;
331719f82d3SEliot Blennerhassett 	}
332719f82d3SEliot Blennerhassett }
333719f82d3SEliot Blennerhassett 
334719f82d3SEliot Blennerhassett static void instream_message(struct hpi_adapter_obj *pao,
335719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
336719f82d3SEliot Blennerhassett {
337719f82d3SEliot Blennerhassett 
338719f82d3SEliot Blennerhassett 	if (phm->obj_index >= HPI_MAX_STREAMS) {
339deb21a23SEliot Blennerhassett 		phr->error = HPI_ERROR_INVALID_OBJ_INDEX;
340719f82d3SEliot Blennerhassett 		HPI_DEBUG_LOG(WARNING,
3413285ea10SEliot Blennerhassett 			"Message referencing invalid stream %d "
342719f82d3SEliot Blennerhassett 			"on adapter index %d\n", phm->obj_index,
343719f82d3SEliot Blennerhassett 			phm->adapter_index);
344719f82d3SEliot Blennerhassett 		return;
345719f82d3SEliot Blennerhassett 	}
346719f82d3SEliot Blennerhassett 
347719f82d3SEliot Blennerhassett 	switch (phm->function) {
348719f82d3SEliot Blennerhassett 	case HPI_ISTREAM_READ:
349719f82d3SEliot Blennerhassett 		instream_read(pao, phm, phr);
350719f82d3SEliot Blennerhassett 		break;
351719f82d3SEliot Blennerhassett 	case HPI_ISTREAM_GET_INFO:
352719f82d3SEliot Blennerhassett 		instream_get_info(pao, phm, phr);
353719f82d3SEliot Blennerhassett 		break;
354719f82d3SEliot Blennerhassett 	case HPI_ISTREAM_HOSTBUFFER_ALLOC:
355719f82d3SEliot Blennerhassett 		instream_host_buffer_allocate(pao, phm, phr);
356719f82d3SEliot Blennerhassett 		break;
357719f82d3SEliot Blennerhassett 	case HPI_ISTREAM_HOSTBUFFER_GET_INFO:
358719f82d3SEliot Blennerhassett 		instream_host_buffer_get_info(pao, phm, phr);
359719f82d3SEliot Blennerhassett 		break;
360719f82d3SEliot Blennerhassett 	case HPI_ISTREAM_HOSTBUFFER_FREE:
361719f82d3SEliot Blennerhassett 		instream_host_buffer_free(pao, phm, phr);
362719f82d3SEliot Blennerhassett 		break;
363719f82d3SEliot Blennerhassett 	case HPI_ISTREAM_START:
364719f82d3SEliot Blennerhassett 		instream_start(pao, phm, phr);
365719f82d3SEliot Blennerhassett 		break;
366719f82d3SEliot Blennerhassett 	default:
367719f82d3SEliot Blennerhassett 		hw_message(pao, phm, phr);
368719f82d3SEliot Blennerhassett 		break;
369719f82d3SEliot Blennerhassett 	}
370719f82d3SEliot Blennerhassett }
371719f82d3SEliot Blennerhassett 
372719f82d3SEliot Blennerhassett /*****************************************************************************/
373719f82d3SEliot Blennerhassett /** Entry point to this HPI backend
374719f82d3SEliot Blennerhassett  * All calls to the HPI start here
375719f82d3SEliot Blennerhassett  */
37633162d2dSEliot Blennerhassett static
3776d0b898eSEliot Blennerhassett void _HPI_6205(struct hpi_adapter_obj *pao, struct hpi_message *phm,
3786d0b898eSEliot Blennerhassett 	struct hpi_response *phr)
379719f82d3SEliot Blennerhassett {
3806d0b898eSEliot Blennerhassett 	if (pao && (pao->dsp_crashed >= 10)
381719f82d3SEliot Blennerhassett 		&& (phm->function != HPI_ADAPTER_DEBUG_READ)) {
382719f82d3SEliot Blennerhassett 		/* allow last resort debug read even after crash */
383719f82d3SEliot Blennerhassett 		hpi_init_response(phr, phm->object, phm->function,
384719f82d3SEliot Blennerhassett 			HPI_ERROR_DSP_HARDWARE);
3856d0b898eSEliot Blennerhassett 		HPI_DEBUG_LOG(WARNING, " %d,%d dsp crashed.\n", phm->object,
3866d0b898eSEliot Blennerhassett 			phm->function);
387719f82d3SEliot Blennerhassett 		return;
388719f82d3SEliot Blennerhassett 	}
389719f82d3SEliot Blennerhassett 
390719f82d3SEliot Blennerhassett 	/* Init default response  */
391719f82d3SEliot Blennerhassett 	if (phm->function != HPI_SUBSYS_CREATE_ADAPTER)
3923285ea10SEliot Blennerhassett 		phr->error = HPI_ERROR_PROCESSING_MESSAGE;
393719f82d3SEliot Blennerhassett 
394719f82d3SEliot Blennerhassett 	HPI_DEBUG_LOG(VERBOSE, "start of switch\n");
395719f82d3SEliot Blennerhassett 	switch (phm->type) {
39682b5774fSEliot Blennerhassett 	case HPI_TYPE_REQUEST:
397719f82d3SEliot Blennerhassett 		switch (phm->object) {
398719f82d3SEliot Blennerhassett 		case HPI_OBJ_SUBSYSTEM:
3996d0b898eSEliot Blennerhassett 			subsys_message(pao, phm, phr);
400719f82d3SEliot Blennerhassett 			break;
401719f82d3SEliot Blennerhassett 
402719f82d3SEliot Blennerhassett 		case HPI_OBJ_ADAPTER:
403719f82d3SEliot Blennerhassett 			adapter_message(pao, phm, phr);
404719f82d3SEliot Blennerhassett 			break;
405719f82d3SEliot Blennerhassett 
406719f82d3SEliot Blennerhassett 		case HPI_OBJ_CONTROL:
407719f82d3SEliot Blennerhassett 			control_message(pao, phm, phr);
408719f82d3SEliot Blennerhassett 			break;
409719f82d3SEliot Blennerhassett 
410719f82d3SEliot Blennerhassett 		case HPI_OBJ_OSTREAM:
411719f82d3SEliot Blennerhassett 			outstream_message(pao, phm, phr);
412719f82d3SEliot Blennerhassett 			break;
413719f82d3SEliot Blennerhassett 
414719f82d3SEliot Blennerhassett 		case HPI_OBJ_ISTREAM:
415719f82d3SEliot Blennerhassett 			instream_message(pao, phm, phr);
416719f82d3SEliot Blennerhassett 			break;
417719f82d3SEliot Blennerhassett 
418719f82d3SEliot Blennerhassett 		default:
419719f82d3SEliot Blennerhassett 			hw_message(pao, phm, phr);
420719f82d3SEliot Blennerhassett 			break;
421719f82d3SEliot Blennerhassett 		}
422719f82d3SEliot Blennerhassett 		break;
423719f82d3SEliot Blennerhassett 
424719f82d3SEliot Blennerhassett 	default:
425719f82d3SEliot Blennerhassett 		phr->error = HPI_ERROR_INVALID_TYPE;
426719f82d3SEliot Blennerhassett 		break;
427719f82d3SEliot Blennerhassett 	}
428719f82d3SEliot Blennerhassett }
429719f82d3SEliot Blennerhassett 
4306d0b898eSEliot Blennerhassett void HPI_6205(struct hpi_message *phm, struct hpi_response *phr)
4316d0b898eSEliot Blennerhassett {
4326d0b898eSEliot Blennerhassett 	struct hpi_adapter_obj *pao = NULL;
4336d0b898eSEliot Blennerhassett 
4346d0b898eSEliot Blennerhassett 	if (phm->object != HPI_OBJ_SUBSYSTEM) {
4356d0b898eSEliot Blennerhassett 		/* normal messages must have valid adapter index */
4366d0b898eSEliot Blennerhassett 		pao = hpi_find_adapter(phm->adapter_index);
4376d0b898eSEliot Blennerhassett 	} else {
4386d0b898eSEliot Blennerhassett 		/* subsys messages don't address an adapter */
4396d0b898eSEliot Blennerhassett 		_HPI_6205(NULL, phm, phr);
4406d0b898eSEliot Blennerhassett 		return;
4416d0b898eSEliot Blennerhassett 	}
4426d0b898eSEliot Blennerhassett 
4436d0b898eSEliot Blennerhassett 	if (pao)
4446d0b898eSEliot Blennerhassett 		_HPI_6205(pao, phm, phr);
4456d0b898eSEliot Blennerhassett 	else
4466d0b898eSEliot Blennerhassett 		hpi_init_response(phr, phm->object, phm->function,
4476d0b898eSEliot Blennerhassett 			HPI_ERROR_BAD_ADAPTER_NUMBER);
4486d0b898eSEliot Blennerhassett }
4496d0b898eSEliot Blennerhassett 
450719f82d3SEliot Blennerhassett /*****************************************************************************/
451719f82d3SEliot Blennerhassett /* SUBSYSTEM */
452719f82d3SEliot Blennerhassett 
453719f82d3SEliot Blennerhassett /** Create an adapter object and initialise it based on resource information
454719f82d3SEliot Blennerhassett  * passed in in the message
455719f82d3SEliot Blennerhassett  * *** NOTE - you cannot use this function AND the FindAdapters function at the
456719f82d3SEliot Blennerhassett  * same time, the application must use only one of them to get the adapters ***
457719f82d3SEliot Blennerhassett  */
458719f82d3SEliot Blennerhassett static void subsys_create_adapter(struct hpi_message *phm,
459719f82d3SEliot Blennerhassett 	struct hpi_response *phr)
460719f82d3SEliot Blennerhassett {
461719f82d3SEliot Blennerhassett 	/* create temp adapter obj, because we don't know what index yet */
462719f82d3SEliot Blennerhassett 	struct hpi_adapter_obj ao;
463719f82d3SEliot Blennerhassett 	u32 os_error_code;
464719f82d3SEliot Blennerhassett 	u16 err;
465719f82d3SEliot Blennerhassett 
466719f82d3SEliot Blennerhassett 	HPI_DEBUG_LOG(DEBUG, " subsys_create_adapter\n");
467719f82d3SEliot Blennerhassett 
468719f82d3SEliot Blennerhassett 	memset(&ao, 0, sizeof(ao));
469719f82d3SEliot Blennerhassett 
470550a8b69SJulia Lawall 	ao.priv = kzalloc(sizeof(struct hpi_hw_obj), GFP_KERNEL);
471719f82d3SEliot Blennerhassett 	if (!ao.priv) {
47225985edcSLucas De Marchi 		HPI_DEBUG_LOG(ERROR, "can't get mem for adapter object\n");
473719f82d3SEliot Blennerhassett 		phr->error = HPI_ERROR_MEMORY_ALLOC;
474719f82d3SEliot Blennerhassett 		return;
475719f82d3SEliot Blennerhassett 	}
476719f82d3SEliot Blennerhassett 
477719f82d3SEliot Blennerhassett 	ao.pci = *phm->u.s.resource.r.pci;
478719f82d3SEliot Blennerhassett 	err = create_adapter_obj(&ao, &os_error_code);
479719f82d3SEliot Blennerhassett 	if (err) {
480719f82d3SEliot Blennerhassett 		delete_adapter_obj(&ao);
4810a00044dSEliot Blennerhassett 		if (err >= HPI_ERROR_BACKEND_BASE) {
4820a00044dSEliot Blennerhassett 			phr->error = HPI_ERROR_DSP_BOOTLOAD;
4830a00044dSEliot Blennerhassett 			phr->specific_error = err;
4840a00044dSEliot Blennerhassett 		} else {
485719f82d3SEliot Blennerhassett 			phr->error = err;
4860a00044dSEliot Blennerhassett 		}
4873285ea10SEliot Blennerhassett 		phr->u.s.data = os_error_code;
488719f82d3SEliot Blennerhassett 		return;
489719f82d3SEliot Blennerhassett 	}
490719f82d3SEliot Blennerhassett 
491*7036b92dSEliot Blennerhassett 	phr->u.s.adapter_type = ao.type;
492719f82d3SEliot Blennerhassett 	phr->u.s.adapter_index = ao.index;
493719f82d3SEliot Blennerhassett 	phr->error = 0;
494719f82d3SEliot Blennerhassett }
495719f82d3SEliot Blennerhassett 
496719f82d3SEliot Blennerhassett /** delete an adapter - required by WDM driver */
4976d0b898eSEliot Blennerhassett static void adapter_delete(struct hpi_adapter_obj *pao,
4986d0b898eSEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
499719f82d3SEliot Blennerhassett {
500719f82d3SEliot Blennerhassett 	struct hpi_hw_obj *phw;
501719f82d3SEliot Blennerhassett 
502719f82d3SEliot Blennerhassett 	if (!pao) {
503719f82d3SEliot Blennerhassett 		phr->error = HPI_ERROR_INVALID_OBJ_INDEX;
504719f82d3SEliot Blennerhassett 		return;
505719f82d3SEliot Blennerhassett 	}
506*7036b92dSEliot Blennerhassett 	phw = pao->priv;
507719f82d3SEliot Blennerhassett 	/* reset adapter h/w */
508719f82d3SEliot Blennerhassett 	/* Reset C6713 #1 */
509719f82d3SEliot Blennerhassett 	boot_loader_write_mem32(pao, 0, C6205_BAR0_TIMER1_CTL, 0);
510719f82d3SEliot Blennerhassett 	/* reset C6205 */
511719f82d3SEliot Blennerhassett 	iowrite32(C6205_HDCR_WARMRESET, phw->prHDCR);
512719f82d3SEliot Blennerhassett 
513719f82d3SEliot Blennerhassett 	delete_adapter_obj(pao);
5143285ea10SEliot Blennerhassett 	hpi_delete_adapter(pao);
515719f82d3SEliot Blennerhassett 	phr->error = 0;
516719f82d3SEliot Blennerhassett }
517719f82d3SEliot Blennerhassett 
518719f82d3SEliot Blennerhassett /** Create adapter object
519719f82d3SEliot Blennerhassett   allocate buffers, bootload DSPs, initialise control cache
520719f82d3SEliot Blennerhassett */
521719f82d3SEliot Blennerhassett static u16 create_adapter_obj(struct hpi_adapter_obj *pao,
522719f82d3SEliot Blennerhassett 	u32 *pos_error_code)
523719f82d3SEliot Blennerhassett {
524719f82d3SEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
525719f82d3SEliot Blennerhassett 	struct bus_master_interface *interface;
526719f82d3SEliot Blennerhassett 	u32 phys_addr;
527719f82d3SEliot Blennerhassett 	int i;
528719f82d3SEliot Blennerhassett 	u16 err;
529719f82d3SEliot Blennerhassett 
530719f82d3SEliot Blennerhassett 	/* init error reporting */
531719f82d3SEliot Blennerhassett 	pao->dsp_crashed = 0;
532719f82d3SEliot Blennerhassett 
533719f82d3SEliot Blennerhassett 	for (i = 0; i < HPI_MAX_STREAMS; i++)
534719f82d3SEliot Blennerhassett 		phw->flag_outstream_just_reset[i] = 1;
535719f82d3SEliot Blennerhassett 
536719f82d3SEliot Blennerhassett 	/* The C6205 memory area 1 is 8Mbyte window into DSP registers */
537719f82d3SEliot Blennerhassett 	phw->prHSR =
538719f82d3SEliot Blennerhassett 		pao->pci.ap_mem_base[1] +
539719f82d3SEliot Blennerhassett 		C6205_BAR1_HSR / sizeof(*pao->pci.ap_mem_base[1]);
540719f82d3SEliot Blennerhassett 	phw->prHDCR =
541719f82d3SEliot Blennerhassett 		pao->pci.ap_mem_base[1] +
542719f82d3SEliot Blennerhassett 		C6205_BAR1_HDCR / sizeof(*pao->pci.ap_mem_base[1]);
543719f82d3SEliot Blennerhassett 	phw->prDSPP =
544719f82d3SEliot Blennerhassett 		pao->pci.ap_mem_base[1] +
545719f82d3SEliot Blennerhassett 		C6205_BAR1_DSPP / sizeof(*pao->pci.ap_mem_base[1]);
546719f82d3SEliot Blennerhassett 
547719f82d3SEliot Blennerhassett 	pao->has_control_cache = 0;
548719f82d3SEliot Blennerhassett 
549719f82d3SEliot Blennerhassett 	if (hpios_locked_mem_alloc(&phw->h_locked_mem,
550719f82d3SEliot Blennerhassett 			sizeof(struct bus_master_interface),
5513285ea10SEliot Blennerhassett 			pao->pci.pci_dev))
552719f82d3SEliot Blennerhassett 		phw->p_interface_buffer = NULL;
553719f82d3SEliot Blennerhassett 	else if (hpios_locked_mem_get_virt_addr(&phw->h_locked_mem,
554719f82d3SEliot Blennerhassett 			(void *)&phw->p_interface_buffer))
555719f82d3SEliot Blennerhassett 		phw->p_interface_buffer = NULL;
556719f82d3SEliot Blennerhassett 
557719f82d3SEliot Blennerhassett 	HPI_DEBUG_LOG(DEBUG, "interface buffer address %p\n",
558719f82d3SEliot Blennerhassett 		phw->p_interface_buffer);
559719f82d3SEliot Blennerhassett 
560719f82d3SEliot Blennerhassett 	if (phw->p_interface_buffer) {
561719f82d3SEliot Blennerhassett 		memset((void *)phw->p_interface_buffer, 0,
562719f82d3SEliot Blennerhassett 			sizeof(struct bus_master_interface));
563719f82d3SEliot Blennerhassett 		phw->p_interface_buffer->dsp_ack = H620_HIF_UNKNOWN;
564719f82d3SEliot Blennerhassett 	}
565719f82d3SEliot Blennerhassett 
566719f82d3SEliot Blennerhassett 	err = adapter_boot_load_dsp(pao, pos_error_code);
5676d0b898eSEliot Blennerhassett 	if (err) {
5686d0b898eSEliot Blennerhassett 		HPI_DEBUG_LOG(ERROR, "DSP code load failed\n");
569719f82d3SEliot Blennerhassett 		/* no need to clean up as SubSysCreateAdapter */
570719f82d3SEliot Blennerhassett 		/* calls DeleteAdapter on error. */
571719f82d3SEliot Blennerhassett 		return err;
5726d0b898eSEliot Blennerhassett 	}
573719f82d3SEliot Blennerhassett 	HPI_DEBUG_LOG(INFO, "load DSP code OK\n");
574719f82d3SEliot Blennerhassett 
575719f82d3SEliot Blennerhassett 	/* allow boot load even if mem alloc wont work */
576719f82d3SEliot Blennerhassett 	if (!phw->p_interface_buffer)
5773285ea10SEliot Blennerhassett 		return HPI_ERROR_MEMORY_ALLOC;
578719f82d3SEliot Blennerhassett 
579719f82d3SEliot Blennerhassett 	interface = phw->p_interface_buffer;
580719f82d3SEliot Blennerhassett 
581719f82d3SEliot Blennerhassett 	/* make sure the DSP has started ok */
582719f82d3SEliot Blennerhassett 	if (!wait_dsp_ack(phw, H620_HIF_RESET, HPI6205_TIMEOUT * 10)) {
583719f82d3SEliot Blennerhassett 		HPI_DEBUG_LOG(ERROR, "timed out waiting reset state \n");
5843285ea10SEliot Blennerhassett 		return HPI6205_ERROR_6205_INIT_FAILED;
585719f82d3SEliot Blennerhassett 	}
586719f82d3SEliot Blennerhassett 	/* Note that *pao, *phw are zeroed after allocation,
587719f82d3SEliot Blennerhassett 	 * so pointers and flags are NULL by default.
588719f82d3SEliot Blennerhassett 	 * Allocate bus mastering control cache buffer and tell the DSP about it
589719f82d3SEliot Blennerhassett 	 */
590719f82d3SEliot Blennerhassett 	if (interface->control_cache.number_of_controls) {
5913285ea10SEliot Blennerhassett 		u8 *p_control_cache_virtual;
592719f82d3SEliot Blennerhassett 
593719f82d3SEliot Blennerhassett 		err = hpios_locked_mem_alloc(&phw->h_control_cache,
594719f82d3SEliot Blennerhassett 			interface->control_cache.size_in_bytes,
5953285ea10SEliot Blennerhassett 			pao->pci.pci_dev);
596719f82d3SEliot Blennerhassett 		if (!err)
597719f82d3SEliot Blennerhassett 			err = hpios_locked_mem_get_virt_addr(&phw->
5983285ea10SEliot Blennerhassett 				h_control_cache,
5993285ea10SEliot Blennerhassett 				(void *)&p_control_cache_virtual);
600719f82d3SEliot Blennerhassett 		if (!err) {
601719f82d3SEliot Blennerhassett 			memset(p_control_cache_virtual, 0,
602719f82d3SEliot Blennerhassett 				interface->control_cache.size_in_bytes);
603719f82d3SEliot Blennerhassett 
604719f82d3SEliot Blennerhassett 			phw->p_cache =
605719f82d3SEliot Blennerhassett 				hpi_alloc_control_cache(interface->
606719f82d3SEliot Blennerhassett 				control_cache.number_of_controls,
607719f82d3SEliot Blennerhassett 				interface->control_cache.size_in_bytes,
608719f82d3SEliot Blennerhassett 				p_control_cache_virtual);
6096d0b898eSEliot Blennerhassett 
610fd0977d0SJesper Juhl 			if (!phw->p_cache)
611fd0977d0SJesper Juhl 				err = HPI_ERROR_MEMORY_ALLOC;
612719f82d3SEliot Blennerhassett 		}
613719f82d3SEliot Blennerhassett 		if (!err) {
614719f82d3SEliot Blennerhassett 			err = hpios_locked_mem_get_phys_addr(&phw->
615719f82d3SEliot Blennerhassett 				h_control_cache, &phys_addr);
616719f82d3SEliot Blennerhassett 			interface->control_cache.physical_address32 =
617719f82d3SEliot Blennerhassett 				phys_addr;
618719f82d3SEliot Blennerhassett 		}
619719f82d3SEliot Blennerhassett 
620719f82d3SEliot Blennerhassett 		if (!err)
621719f82d3SEliot Blennerhassett 			pao->has_control_cache = 1;
622719f82d3SEliot Blennerhassett 		else {
623719f82d3SEliot Blennerhassett 			if (hpios_locked_mem_valid(&phw->h_control_cache))
624719f82d3SEliot Blennerhassett 				hpios_locked_mem_free(&phw->h_control_cache);
625719f82d3SEliot Blennerhassett 			pao->has_control_cache = 0;
626719f82d3SEliot Blennerhassett 		}
627719f82d3SEliot Blennerhassett 	}
628719f82d3SEliot Blennerhassett 	send_dsp_command(phw, H620_HIF_IDLE);
629719f82d3SEliot Blennerhassett 
630719f82d3SEliot Blennerhassett 	{
6313285ea10SEliot Blennerhassett 		struct hpi_message hm;
6323285ea10SEliot Blennerhassett 		struct hpi_response hr;
633719f82d3SEliot Blennerhassett 		u32 max_streams;
634719f82d3SEliot Blennerhassett 
635719f82d3SEliot Blennerhassett 		HPI_DEBUG_LOG(VERBOSE, "init ADAPTER_GET_INFO\n");
6363285ea10SEliot Blennerhassett 		memset(&hm, 0, sizeof(hm));
63782b5774fSEliot Blennerhassett 		/* wAdapterIndex == version == 0 */
63882b5774fSEliot Blennerhassett 		hm.type = HPI_TYPE_REQUEST;
6393285ea10SEliot Blennerhassett 		hm.size = sizeof(hm);
6403285ea10SEliot Blennerhassett 		hm.object = HPI_OBJ_ADAPTER;
6413285ea10SEliot Blennerhassett 		hm.function = HPI_ADAPTER_GET_INFO;
64282b5774fSEliot Blennerhassett 
6433285ea10SEliot Blennerhassett 		memset(&hr, 0, sizeof(hr));
6443285ea10SEliot Blennerhassett 		hr.size = sizeof(hr);
645719f82d3SEliot Blennerhassett 
6463285ea10SEliot Blennerhassett 		err = message_response_sequence(pao, &hm, &hr);
647719f82d3SEliot Blennerhassett 		if (err) {
648719f82d3SEliot Blennerhassett 			HPI_DEBUG_LOG(ERROR, "message transport error %d\n",
649719f82d3SEliot Blennerhassett 				err);
650719f82d3SEliot Blennerhassett 			return err;
651719f82d3SEliot Blennerhassett 		}
6523285ea10SEliot Blennerhassett 		if (hr.error)
6533285ea10SEliot Blennerhassett 			return hr.error;
654719f82d3SEliot Blennerhassett 
655*7036b92dSEliot Blennerhassett 		pao->type = hr.u.ax.info.adapter_type;
6563285ea10SEliot Blennerhassett 		pao->index = hr.u.ax.info.adapter_index;
657719f82d3SEliot Blennerhassett 
6583285ea10SEliot Blennerhassett 		max_streams =
6593285ea10SEliot Blennerhassett 			hr.u.ax.info.num_outstreams +
6603285ea10SEliot Blennerhassett 			hr.u.ax.info.num_instreams;
661719f82d3SEliot Blennerhassett 
662719f82d3SEliot Blennerhassett 		HPI_DEBUG_LOG(VERBOSE,
663719f82d3SEliot Blennerhassett 			"got adapter info type %x index %d serial %d\n",
6643285ea10SEliot Blennerhassett 			hr.u.ax.info.adapter_type, hr.u.ax.info.adapter_index,
6653285ea10SEliot Blennerhassett 			hr.u.ax.info.serial_number);
666719f82d3SEliot Blennerhassett 	}
667719f82d3SEliot Blennerhassett 
668ffdb5787SEliot Blennerhassett 	if (phw->p_cache)
669ffdb5787SEliot Blennerhassett 		phw->p_cache->adap_idx = pao->index;
670ffdb5787SEliot Blennerhassett 
671719f82d3SEliot Blennerhassett 	HPI_DEBUG_LOG(INFO, "bootload DSP OK\n");
6723285ea10SEliot Blennerhassett 
6733285ea10SEliot Blennerhassett 	return hpi_add_adapter(pao);
674719f82d3SEliot Blennerhassett }
675719f82d3SEliot Blennerhassett 
676719f82d3SEliot Blennerhassett /** Free memory areas allocated by adapter
6776d0b898eSEliot Blennerhassett  * this routine is called from AdapterDelete,
678719f82d3SEliot Blennerhassett   * and SubSysCreateAdapter if duplicate index
679719f82d3SEliot Blennerhassett */
680719f82d3SEliot Blennerhassett static void delete_adapter_obj(struct hpi_adapter_obj *pao)
681719f82d3SEliot Blennerhassett {
6826d0b898eSEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
683719f82d3SEliot Blennerhassett 	int i;
684719f82d3SEliot Blennerhassett 
685719f82d3SEliot Blennerhassett 	if (hpios_locked_mem_valid(&phw->h_control_cache)) {
686719f82d3SEliot Blennerhassett 		hpios_locked_mem_free(&phw->h_control_cache);
687719f82d3SEliot Blennerhassett 		hpi_free_control_cache(phw->p_cache);
688719f82d3SEliot Blennerhassett 	}
689719f82d3SEliot Blennerhassett 
690719f82d3SEliot Blennerhassett 	if (hpios_locked_mem_valid(&phw->h_locked_mem)) {
691719f82d3SEliot Blennerhassett 		hpios_locked_mem_free(&phw->h_locked_mem);
692719f82d3SEliot Blennerhassett 		phw->p_interface_buffer = NULL;
693719f82d3SEliot Blennerhassett 	}
694719f82d3SEliot Blennerhassett 
695719f82d3SEliot Blennerhassett 	for (i = 0; i < HPI_MAX_STREAMS; i++)
696719f82d3SEliot Blennerhassett 		if (hpios_locked_mem_valid(&phw->instream_host_buffers[i])) {
697719f82d3SEliot Blennerhassett 			hpios_locked_mem_free(&phw->instream_host_buffers[i]);
698719f82d3SEliot Blennerhassett 			/*?phw->InStreamHostBuffers[i] = NULL; */
699719f82d3SEliot Blennerhassett 			phw->instream_host_buffer_size[i] = 0;
700719f82d3SEliot Blennerhassett 		}
701719f82d3SEliot Blennerhassett 
702719f82d3SEliot Blennerhassett 	for (i = 0; i < HPI_MAX_STREAMS; i++)
703719f82d3SEliot Blennerhassett 		if (hpios_locked_mem_valid(&phw->outstream_host_buffers[i])) {
704719f82d3SEliot Blennerhassett 			hpios_locked_mem_free(&phw->outstream_host_buffers
705719f82d3SEliot Blennerhassett 				[i]);
706719f82d3SEliot Blennerhassett 			phw->outstream_host_buffer_size[i] = 0;
707719f82d3SEliot Blennerhassett 		}
708719f82d3SEliot Blennerhassett 	kfree(phw);
709719f82d3SEliot Blennerhassett }
710719f82d3SEliot Blennerhassett 
711719f82d3SEliot Blennerhassett /*****************************************************************************/
7121d595d2aSEliot Blennerhassett /* Adapter functions */
7131d595d2aSEliot Blennerhassett 
7141d595d2aSEliot Blennerhassett /*****************************************************************************/
715719f82d3SEliot Blennerhassett /* OutStream Host buffer functions */
716719f82d3SEliot Blennerhassett 
717719f82d3SEliot Blennerhassett /** Allocate or attach buffer for busmastering
718719f82d3SEliot Blennerhassett */
719719f82d3SEliot Blennerhassett static void outstream_host_buffer_allocate(struct hpi_adapter_obj *pao,
720719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
721719f82d3SEliot Blennerhassett {
722719f82d3SEliot Blennerhassett 	u16 err = 0;
723719f82d3SEliot Blennerhassett 	u32 command = phm->u.d.u.buffer.command;
724719f82d3SEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
725719f82d3SEliot Blennerhassett 	struct bus_master_interface *interface = phw->p_interface_buffer;
726719f82d3SEliot Blennerhassett 
727719f82d3SEliot Blennerhassett 	hpi_init_response(phr, phm->object, phm->function, 0);
728719f82d3SEliot Blennerhassett 
729719f82d3SEliot Blennerhassett 	if (command == HPI_BUFFER_CMD_EXTERNAL
730719f82d3SEliot Blennerhassett 		|| command == HPI_BUFFER_CMD_INTERNAL_ALLOC) {
731719f82d3SEliot Blennerhassett 		/* ALLOC phase, allocate a buffer with power of 2 size,
732719f82d3SEliot Blennerhassett 		   get its bus address for PCI bus mastering
733719f82d3SEliot Blennerhassett 		 */
734719f82d3SEliot Blennerhassett 		phm->u.d.u.buffer.buffer_size =
735719f82d3SEliot Blennerhassett 			roundup_pow_of_two(phm->u.d.u.buffer.buffer_size);
736719f82d3SEliot Blennerhassett 		/* return old size and allocated size,
737719f82d3SEliot Blennerhassett 		   so caller can detect change */
738719f82d3SEliot Blennerhassett 		phr->u.d.u.stream_info.data_available =
739719f82d3SEliot Blennerhassett 			phw->outstream_host_buffer_size[phm->obj_index];
740719f82d3SEliot Blennerhassett 		phr->u.d.u.stream_info.buffer_size =
741719f82d3SEliot Blennerhassett 			phm->u.d.u.buffer.buffer_size;
742719f82d3SEliot Blennerhassett 
743719f82d3SEliot Blennerhassett 		if (phw->outstream_host_buffer_size[phm->obj_index] ==
744719f82d3SEliot Blennerhassett 			phm->u.d.u.buffer.buffer_size) {
745719f82d3SEliot Blennerhassett 			/* Same size, no action required */
746719f82d3SEliot Blennerhassett 			return;
747719f82d3SEliot Blennerhassett 		}
748719f82d3SEliot Blennerhassett 
749719f82d3SEliot Blennerhassett 		if (hpios_locked_mem_valid(&phw->outstream_host_buffers[phm->
750719f82d3SEliot Blennerhassett 					obj_index]))
751719f82d3SEliot Blennerhassett 			hpios_locked_mem_free(&phw->outstream_host_buffers
752719f82d3SEliot Blennerhassett 				[phm->obj_index]);
753719f82d3SEliot Blennerhassett 
754719f82d3SEliot Blennerhassett 		err = hpios_locked_mem_alloc(&phw->outstream_host_buffers
755719f82d3SEliot Blennerhassett 			[phm->obj_index], phm->u.d.u.buffer.buffer_size,
7563285ea10SEliot Blennerhassett 			pao->pci.pci_dev);
757719f82d3SEliot Blennerhassett 
758719f82d3SEliot Blennerhassett 		if (err) {
759719f82d3SEliot Blennerhassett 			phr->error = HPI_ERROR_INVALID_DATASIZE;
760719f82d3SEliot Blennerhassett 			phw->outstream_host_buffer_size[phm->obj_index] = 0;
761719f82d3SEliot Blennerhassett 			return;
762719f82d3SEliot Blennerhassett 		}
763719f82d3SEliot Blennerhassett 
764719f82d3SEliot Blennerhassett 		err = hpios_locked_mem_get_phys_addr
765719f82d3SEliot Blennerhassett 			(&phw->outstream_host_buffers[phm->obj_index],
766719f82d3SEliot Blennerhassett 			&phm->u.d.u.buffer.pci_address);
767719f82d3SEliot Blennerhassett 		/* get the phys addr into msg for single call alloc caller
768719f82d3SEliot Blennerhassett 		 * needs to do this for split alloc (or use the same message)
769719f82d3SEliot Blennerhassett 		 * return the phy address for split alloc in the respose too
770719f82d3SEliot Blennerhassett 		 */
771719f82d3SEliot Blennerhassett 		phr->u.d.u.stream_info.auxiliary_data_available =
772719f82d3SEliot Blennerhassett 			phm->u.d.u.buffer.pci_address;
773719f82d3SEliot Blennerhassett 
774719f82d3SEliot Blennerhassett 		if (err) {
775719f82d3SEliot Blennerhassett 			hpios_locked_mem_free(&phw->outstream_host_buffers
776719f82d3SEliot Blennerhassett 				[phm->obj_index]);
777719f82d3SEliot Blennerhassett 			phw->outstream_host_buffer_size[phm->obj_index] = 0;
778719f82d3SEliot Blennerhassett 			phr->error = HPI_ERROR_MEMORY_ALLOC;
779719f82d3SEliot Blennerhassett 			return;
780719f82d3SEliot Blennerhassett 		}
781719f82d3SEliot Blennerhassett 	}
782719f82d3SEliot Blennerhassett 
783719f82d3SEliot Blennerhassett 	if (command == HPI_BUFFER_CMD_EXTERNAL
784719f82d3SEliot Blennerhassett 		|| command == HPI_BUFFER_CMD_INTERNAL_GRANTADAPTER) {
785719f82d3SEliot Blennerhassett 		/* GRANT phase.  Set up the BBM status, tell the DSP about
786719f82d3SEliot Blennerhassett 		   the buffer so it can start using BBM.
787719f82d3SEliot Blennerhassett 		 */
788719f82d3SEliot Blennerhassett 		struct hpi_hostbuffer_status *status;
789719f82d3SEliot Blennerhassett 
790719f82d3SEliot Blennerhassett 		if (phm->u.d.u.buffer.buffer_size & (phm->u.d.u.buffer.
791719f82d3SEliot Blennerhassett 				buffer_size - 1)) {
792719f82d3SEliot Blennerhassett 			HPI_DEBUG_LOG(ERROR,
7933285ea10SEliot Blennerhassett 				"Buffer size must be 2^N not %d\n",
794719f82d3SEliot Blennerhassett 				phm->u.d.u.buffer.buffer_size);
795719f82d3SEliot Blennerhassett 			phr->error = HPI_ERROR_INVALID_DATASIZE;
796719f82d3SEliot Blennerhassett 			return;
797719f82d3SEliot Blennerhassett 		}
798719f82d3SEliot Blennerhassett 		phw->outstream_host_buffer_size[phm->obj_index] =
799719f82d3SEliot Blennerhassett 			phm->u.d.u.buffer.buffer_size;
800719f82d3SEliot Blennerhassett 		status = &interface->outstream_host_buffer_status[phm->
801719f82d3SEliot Blennerhassett 			obj_index];
802719f82d3SEliot Blennerhassett 		status->samples_processed = 0;
803719f82d3SEliot Blennerhassett 		status->stream_state = HPI_STATE_STOPPED;
8048e0874eaSEliot Blennerhassett 		status->dsp_index = 0;
8058e0874eaSEliot Blennerhassett 		status->host_index = status->dsp_index;
806719f82d3SEliot Blennerhassett 		status->size_in_bytes = phm->u.d.u.buffer.buffer_size;
807deb21a23SEliot Blennerhassett 		status->auxiliary_data_available = 0;
808719f82d3SEliot Blennerhassett 
809719f82d3SEliot Blennerhassett 		hw_message(pao, phm, phr);
810719f82d3SEliot Blennerhassett 
811719f82d3SEliot Blennerhassett 		if (phr->error
812719f82d3SEliot Blennerhassett 			&& hpios_locked_mem_valid(&phw->
813719f82d3SEliot Blennerhassett 				outstream_host_buffers[phm->obj_index])) {
814719f82d3SEliot Blennerhassett 			hpios_locked_mem_free(&phw->outstream_host_buffers
815719f82d3SEliot Blennerhassett 				[phm->obj_index]);
816719f82d3SEliot Blennerhassett 			phw->outstream_host_buffer_size[phm->obj_index] = 0;
817719f82d3SEliot Blennerhassett 		}
818719f82d3SEliot Blennerhassett 	}
819719f82d3SEliot Blennerhassett }
820719f82d3SEliot Blennerhassett 
821719f82d3SEliot Blennerhassett static void outstream_host_buffer_get_info(struct hpi_adapter_obj *pao,
822719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
823719f82d3SEliot Blennerhassett {
824719f82d3SEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
825719f82d3SEliot Blennerhassett 	struct bus_master_interface *interface = phw->p_interface_buffer;
826719f82d3SEliot Blennerhassett 	struct hpi_hostbuffer_status *status;
827719f82d3SEliot Blennerhassett 	u8 *p_bbm_data;
828719f82d3SEliot Blennerhassett 
829719f82d3SEliot Blennerhassett 	if (hpios_locked_mem_valid(&phw->outstream_host_buffers[phm->
830719f82d3SEliot Blennerhassett 				obj_index])) {
831719f82d3SEliot Blennerhassett 		if (hpios_locked_mem_get_virt_addr(&phw->
832719f82d3SEliot Blennerhassett 				outstream_host_buffers[phm->obj_index],
833719f82d3SEliot Blennerhassett 				(void *)&p_bbm_data)) {
834719f82d3SEliot Blennerhassett 			phr->error = HPI_ERROR_INVALID_OPERATION;
835719f82d3SEliot Blennerhassett 			return;
836719f82d3SEliot Blennerhassett 		}
837719f82d3SEliot Blennerhassett 		status = &interface->outstream_host_buffer_status[phm->
838719f82d3SEliot Blennerhassett 			obj_index];
839719f82d3SEliot Blennerhassett 		hpi_init_response(phr, HPI_OBJ_OSTREAM,
840719f82d3SEliot Blennerhassett 			HPI_OSTREAM_HOSTBUFFER_GET_INFO, 0);
841719f82d3SEliot Blennerhassett 		phr->u.d.u.hostbuffer_info.p_buffer = p_bbm_data;
842719f82d3SEliot Blennerhassett 		phr->u.d.u.hostbuffer_info.p_status = status;
843719f82d3SEliot Blennerhassett 	} else {
844719f82d3SEliot Blennerhassett 		hpi_init_response(phr, HPI_OBJ_OSTREAM,
845719f82d3SEliot Blennerhassett 			HPI_OSTREAM_HOSTBUFFER_GET_INFO,
846719f82d3SEliot Blennerhassett 			HPI_ERROR_INVALID_OPERATION);
847719f82d3SEliot Blennerhassett 	}
848719f82d3SEliot Blennerhassett }
849719f82d3SEliot Blennerhassett 
850719f82d3SEliot Blennerhassett static void outstream_host_buffer_free(struct hpi_adapter_obj *pao,
851719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
852719f82d3SEliot Blennerhassett {
853719f82d3SEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
854719f82d3SEliot Blennerhassett 	u32 command = phm->u.d.u.buffer.command;
855719f82d3SEliot Blennerhassett 
856719f82d3SEliot Blennerhassett 	if (phw->outstream_host_buffer_size[phm->obj_index]) {
857719f82d3SEliot Blennerhassett 		if (command == HPI_BUFFER_CMD_EXTERNAL
858719f82d3SEliot Blennerhassett 			|| command == HPI_BUFFER_CMD_INTERNAL_REVOKEADAPTER) {
859719f82d3SEliot Blennerhassett 			phw->outstream_host_buffer_size[phm->obj_index] = 0;
860719f82d3SEliot Blennerhassett 			hw_message(pao, phm, phr);
861719f82d3SEliot Blennerhassett 			/* Tell adapter to stop using the host buffer. */
862719f82d3SEliot Blennerhassett 		}
863719f82d3SEliot Blennerhassett 		if (command == HPI_BUFFER_CMD_EXTERNAL
864719f82d3SEliot Blennerhassett 			|| command == HPI_BUFFER_CMD_INTERNAL_FREE)
865719f82d3SEliot Blennerhassett 			hpios_locked_mem_free(&phw->outstream_host_buffers
866719f82d3SEliot Blennerhassett 				[phm->obj_index]);
867719f82d3SEliot Blennerhassett 	}
868719f82d3SEliot Blennerhassett 	/* Should HPI_ERROR_INVALID_OPERATION be returned
869719f82d3SEliot Blennerhassett 	   if no host buffer is allocated? */
870719f82d3SEliot Blennerhassett 	else
871719f82d3SEliot Blennerhassett 		hpi_init_response(phr, HPI_OBJ_OSTREAM,
872719f82d3SEliot Blennerhassett 			HPI_OSTREAM_HOSTBUFFER_FREE, 0);
873719f82d3SEliot Blennerhassett 
874719f82d3SEliot Blennerhassett }
875719f82d3SEliot Blennerhassett 
87660f1deb5SEliot Blennerhassett static u32 outstream_get_space_available(struct hpi_hostbuffer_status *status)
877719f82d3SEliot Blennerhassett {
8782a383cb3SEliot Blennerhassett 	return status->size_in_bytes - (status->host_index -
8798e0874eaSEliot Blennerhassett 		status->dsp_index);
880719f82d3SEliot Blennerhassett }
881719f82d3SEliot Blennerhassett 
882719f82d3SEliot Blennerhassett static void outstream_write(struct hpi_adapter_obj *pao,
883719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
884719f82d3SEliot Blennerhassett {
885719f82d3SEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
886719f82d3SEliot Blennerhassett 	struct bus_master_interface *interface = phw->p_interface_buffer;
887719f82d3SEliot Blennerhassett 	struct hpi_hostbuffer_status *status;
8882a383cb3SEliot Blennerhassett 	u32 space_available;
889719f82d3SEliot Blennerhassett 
890719f82d3SEliot Blennerhassett 	if (!phw->outstream_host_buffer_size[phm->obj_index]) {
891719f82d3SEliot Blennerhassett 		/* there  is no BBM buffer, write via message */
892719f82d3SEliot Blennerhassett 		hw_message(pao, phm, phr);
893719f82d3SEliot Blennerhassett 		return;
894719f82d3SEliot Blennerhassett 	}
895719f82d3SEliot Blennerhassett 
896719f82d3SEliot Blennerhassett 	hpi_init_response(phr, phm->object, phm->function, 0);
897719f82d3SEliot Blennerhassett 	status = &interface->outstream_host_buffer_status[phm->obj_index];
898719f82d3SEliot Blennerhassett 
899719f82d3SEliot Blennerhassett 	space_available = outstream_get_space_available(status);
9002a383cb3SEliot Blennerhassett 	if (space_available < phm->u.d.u.data.data_size) {
901719f82d3SEliot Blennerhassett 		phr->error = HPI_ERROR_INVALID_DATASIZE;
902719f82d3SEliot Blennerhassett 		return;
903719f82d3SEliot Blennerhassett 	}
904719f82d3SEliot Blennerhassett 
905719f82d3SEliot Blennerhassett 	/* HostBuffers is used to indicate host buffer is internally allocated.
906719f82d3SEliot Blennerhassett 	   otherwise, assumed external, data written externally */
907719f82d3SEliot Blennerhassett 	if (phm->u.d.u.data.pb_data
908719f82d3SEliot Blennerhassett 		&& hpios_locked_mem_valid(&phw->outstream_host_buffers[phm->
909719f82d3SEliot Blennerhassett 				obj_index])) {
910719f82d3SEliot Blennerhassett 		u8 *p_bbm_data;
9112a383cb3SEliot Blennerhassett 		u32 l_first_write;
912719f82d3SEliot Blennerhassett 		u8 *p_app_data = (u8 *)phm->u.d.u.data.pb_data;
913719f82d3SEliot Blennerhassett 
914719f82d3SEliot Blennerhassett 		if (hpios_locked_mem_get_virt_addr(&phw->
915719f82d3SEliot Blennerhassett 				outstream_host_buffers[phm->obj_index],
916719f82d3SEliot Blennerhassett 				(void *)&p_bbm_data)) {
917719f82d3SEliot Blennerhassett 			phr->error = HPI_ERROR_INVALID_OPERATION;
918719f82d3SEliot Blennerhassett 			return;
919719f82d3SEliot Blennerhassett 		}
920719f82d3SEliot Blennerhassett 
921719f82d3SEliot Blennerhassett 		/* either all data,
922719f82d3SEliot Blennerhassett 		   or enough to fit from current to end of BBM buffer */
923719f82d3SEliot Blennerhassett 		l_first_write =
924719f82d3SEliot Blennerhassett 			min(phm->u.d.u.data.data_size,
925719f82d3SEliot Blennerhassett 			status->size_in_bytes -
926719f82d3SEliot Blennerhassett 			(status->host_index & (status->size_in_bytes - 1)));
927719f82d3SEliot Blennerhassett 
928719f82d3SEliot Blennerhassett 		memcpy(p_bbm_data +
929719f82d3SEliot Blennerhassett 			(status->host_index & (status->size_in_bytes - 1)),
930719f82d3SEliot Blennerhassett 			p_app_data, l_first_write);
931719f82d3SEliot Blennerhassett 		/* remaining data if any */
932719f82d3SEliot Blennerhassett 		memcpy(p_bbm_data, p_app_data + l_first_write,
933719f82d3SEliot Blennerhassett 			phm->u.d.u.data.data_size - l_first_write);
934719f82d3SEliot Blennerhassett 	}
9353285ea10SEliot Blennerhassett 
9363285ea10SEliot Blennerhassett 	/*
9373285ea10SEliot Blennerhassett 	 * This version relies on the DSP code triggering an OStream buffer
9383285ea10SEliot Blennerhassett 	 * update immediately following a SET_FORMAT call. The host has
939deb21a23SEliot Blennerhassett 	 * already written data into the BBM buffer, but the DSP won't know
940deb21a23SEliot Blennerhassett 	 * about it until dwHostIndex is adjusted.
9413285ea10SEliot Blennerhassett 	 */
9423285ea10SEliot Blennerhassett 	if (phw->flag_outstream_just_reset[phm->obj_index]) {
9433285ea10SEliot Blennerhassett 		/* Format can only change after reset. Must tell DSP. */
9443285ea10SEliot Blennerhassett 		u16 function = phm->function;
9453285ea10SEliot Blennerhassett 		phw->flag_outstream_just_reset[phm->obj_index] = 0;
9463285ea10SEliot Blennerhassett 		phm->function = HPI_OSTREAM_SET_FORMAT;
9473285ea10SEliot Blennerhassett 		hw_message(pao, phm, phr);	/* send the format to the DSP */
9483285ea10SEliot Blennerhassett 		phm->function = function;
9493285ea10SEliot Blennerhassett 		if (phr->error)
9503285ea10SEliot Blennerhassett 			return;
9513285ea10SEliot Blennerhassett 	}
9523285ea10SEliot Blennerhassett 
953719f82d3SEliot Blennerhassett 	status->host_index += phm->u.d.u.data.data_size;
954719f82d3SEliot Blennerhassett }
955719f82d3SEliot Blennerhassett 
956719f82d3SEliot Blennerhassett static void outstream_get_info(struct hpi_adapter_obj *pao,
957719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
958719f82d3SEliot Blennerhassett {
959719f82d3SEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
960719f82d3SEliot Blennerhassett 	struct bus_master_interface *interface = phw->p_interface_buffer;
961719f82d3SEliot Blennerhassett 	struct hpi_hostbuffer_status *status;
962719f82d3SEliot Blennerhassett 
963719f82d3SEliot Blennerhassett 	if (!phw->outstream_host_buffer_size[phm->obj_index]) {
964719f82d3SEliot Blennerhassett 		hw_message(pao, phm, phr);
965719f82d3SEliot Blennerhassett 		return;
966719f82d3SEliot Blennerhassett 	}
967719f82d3SEliot Blennerhassett 
968719f82d3SEliot Blennerhassett 	hpi_init_response(phr, phm->object, phm->function, 0);
969719f82d3SEliot Blennerhassett 
970719f82d3SEliot Blennerhassett 	status = &interface->outstream_host_buffer_status[phm->obj_index];
971719f82d3SEliot Blennerhassett 
972719f82d3SEliot Blennerhassett 	phr->u.d.u.stream_info.state = (u16)status->stream_state;
973719f82d3SEliot Blennerhassett 	phr->u.d.u.stream_info.samples_transferred =
974719f82d3SEliot Blennerhassett 		status->samples_processed;
975719f82d3SEliot Blennerhassett 	phr->u.d.u.stream_info.buffer_size = status->size_in_bytes;
976719f82d3SEliot Blennerhassett 	phr->u.d.u.stream_info.data_available =
977719f82d3SEliot Blennerhassett 		status->size_in_bytes - outstream_get_space_available(status);
978719f82d3SEliot Blennerhassett 	phr->u.d.u.stream_info.auxiliary_data_available =
979719f82d3SEliot Blennerhassett 		status->auxiliary_data_available;
980719f82d3SEliot Blennerhassett }
981719f82d3SEliot Blennerhassett 
982719f82d3SEliot Blennerhassett static void outstream_start(struct hpi_adapter_obj *pao,
983719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
984719f82d3SEliot Blennerhassett {
985719f82d3SEliot Blennerhassett 	hw_message(pao, phm, phr);
986719f82d3SEliot Blennerhassett }
987719f82d3SEliot Blennerhassett 
988719f82d3SEliot Blennerhassett static void outstream_reset(struct hpi_adapter_obj *pao,
989719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
990719f82d3SEliot Blennerhassett {
991719f82d3SEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
992719f82d3SEliot Blennerhassett 	phw->flag_outstream_just_reset[phm->obj_index] = 1;
993719f82d3SEliot Blennerhassett 	hw_message(pao, phm, phr);
994719f82d3SEliot Blennerhassett }
995719f82d3SEliot Blennerhassett 
996719f82d3SEliot Blennerhassett static void outstream_open(struct hpi_adapter_obj *pao,
997719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
998719f82d3SEliot Blennerhassett {
999719f82d3SEliot Blennerhassett 	outstream_reset(pao, phm, phr);
1000719f82d3SEliot Blennerhassett }
1001719f82d3SEliot Blennerhassett 
1002719f82d3SEliot Blennerhassett /*****************************************************************************/
1003719f82d3SEliot Blennerhassett /* InStream Host buffer functions */
1004719f82d3SEliot Blennerhassett 
1005719f82d3SEliot Blennerhassett static void instream_host_buffer_allocate(struct hpi_adapter_obj *pao,
1006719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
1007719f82d3SEliot Blennerhassett {
1008719f82d3SEliot Blennerhassett 	u16 err = 0;
1009719f82d3SEliot Blennerhassett 	u32 command = phm->u.d.u.buffer.command;
1010719f82d3SEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
1011719f82d3SEliot Blennerhassett 	struct bus_master_interface *interface = phw->p_interface_buffer;
1012719f82d3SEliot Blennerhassett 
1013719f82d3SEliot Blennerhassett 	hpi_init_response(phr, phm->object, phm->function, 0);
1014719f82d3SEliot Blennerhassett 
1015719f82d3SEliot Blennerhassett 	if (command == HPI_BUFFER_CMD_EXTERNAL
1016719f82d3SEliot Blennerhassett 		|| command == HPI_BUFFER_CMD_INTERNAL_ALLOC) {
1017719f82d3SEliot Blennerhassett 
1018719f82d3SEliot Blennerhassett 		phm->u.d.u.buffer.buffer_size =
1019719f82d3SEliot Blennerhassett 			roundup_pow_of_two(phm->u.d.u.buffer.buffer_size);
1020719f82d3SEliot Blennerhassett 		phr->u.d.u.stream_info.data_available =
1021719f82d3SEliot Blennerhassett 			phw->instream_host_buffer_size[phm->obj_index];
1022719f82d3SEliot Blennerhassett 		phr->u.d.u.stream_info.buffer_size =
1023719f82d3SEliot Blennerhassett 			phm->u.d.u.buffer.buffer_size;
1024719f82d3SEliot Blennerhassett 
1025719f82d3SEliot Blennerhassett 		if (phw->instream_host_buffer_size[phm->obj_index] ==
1026719f82d3SEliot Blennerhassett 			phm->u.d.u.buffer.buffer_size) {
1027719f82d3SEliot Blennerhassett 			/* Same size, no action required */
1028719f82d3SEliot Blennerhassett 			return;
1029719f82d3SEliot Blennerhassett 		}
1030719f82d3SEliot Blennerhassett 
1031719f82d3SEliot Blennerhassett 		if (hpios_locked_mem_valid(&phw->instream_host_buffers[phm->
1032719f82d3SEliot Blennerhassett 					obj_index]))
1033719f82d3SEliot Blennerhassett 			hpios_locked_mem_free(&phw->instream_host_buffers
1034719f82d3SEliot Blennerhassett 				[phm->obj_index]);
1035719f82d3SEliot Blennerhassett 
1036719f82d3SEliot Blennerhassett 		err = hpios_locked_mem_alloc(&phw->instream_host_buffers[phm->
1037719f82d3SEliot Blennerhassett 				obj_index], phm->u.d.u.buffer.buffer_size,
10383285ea10SEliot Blennerhassett 			pao->pci.pci_dev);
1039719f82d3SEliot Blennerhassett 
1040719f82d3SEliot Blennerhassett 		if (err) {
1041719f82d3SEliot Blennerhassett 			phr->error = HPI_ERROR_INVALID_DATASIZE;
1042719f82d3SEliot Blennerhassett 			phw->instream_host_buffer_size[phm->obj_index] = 0;
1043719f82d3SEliot Blennerhassett 			return;
1044719f82d3SEliot Blennerhassett 		}
1045719f82d3SEliot Blennerhassett 
1046719f82d3SEliot Blennerhassett 		err = hpios_locked_mem_get_phys_addr
1047719f82d3SEliot Blennerhassett 			(&phw->instream_host_buffers[phm->obj_index],
1048719f82d3SEliot Blennerhassett 			&phm->u.d.u.buffer.pci_address);
1049719f82d3SEliot Blennerhassett 		/* get the phys addr into msg for single call alloc. Caller
1050719f82d3SEliot Blennerhassett 		   needs to do this for split alloc so return the phy address */
1051719f82d3SEliot Blennerhassett 		phr->u.d.u.stream_info.auxiliary_data_available =
1052719f82d3SEliot Blennerhassett 			phm->u.d.u.buffer.pci_address;
1053719f82d3SEliot Blennerhassett 		if (err) {
1054719f82d3SEliot Blennerhassett 			hpios_locked_mem_free(&phw->instream_host_buffers
1055719f82d3SEliot Blennerhassett 				[phm->obj_index]);
1056719f82d3SEliot Blennerhassett 			phw->instream_host_buffer_size[phm->obj_index] = 0;
1057719f82d3SEliot Blennerhassett 			phr->error = HPI_ERROR_MEMORY_ALLOC;
1058719f82d3SEliot Blennerhassett 			return;
1059719f82d3SEliot Blennerhassett 		}
1060719f82d3SEliot Blennerhassett 	}
1061719f82d3SEliot Blennerhassett 
1062719f82d3SEliot Blennerhassett 	if (command == HPI_BUFFER_CMD_EXTERNAL
1063719f82d3SEliot Blennerhassett 		|| command == HPI_BUFFER_CMD_INTERNAL_GRANTADAPTER) {
1064719f82d3SEliot Blennerhassett 		struct hpi_hostbuffer_status *status;
1065719f82d3SEliot Blennerhassett 
1066719f82d3SEliot Blennerhassett 		if (phm->u.d.u.buffer.buffer_size & (phm->u.d.u.buffer.
1067719f82d3SEliot Blennerhassett 				buffer_size - 1)) {
1068719f82d3SEliot Blennerhassett 			HPI_DEBUG_LOG(ERROR,
10693285ea10SEliot Blennerhassett 				"Buffer size must be 2^N not %d\n",
1070719f82d3SEliot Blennerhassett 				phm->u.d.u.buffer.buffer_size);
1071719f82d3SEliot Blennerhassett 			phr->error = HPI_ERROR_INVALID_DATASIZE;
1072719f82d3SEliot Blennerhassett 			return;
1073719f82d3SEliot Blennerhassett 		}
1074719f82d3SEliot Blennerhassett 
1075719f82d3SEliot Blennerhassett 		phw->instream_host_buffer_size[phm->obj_index] =
1076719f82d3SEliot Blennerhassett 			phm->u.d.u.buffer.buffer_size;
1077719f82d3SEliot Blennerhassett 		status = &interface->instream_host_buffer_status[phm->
1078719f82d3SEliot Blennerhassett 			obj_index];
1079719f82d3SEliot Blennerhassett 		status->samples_processed = 0;
1080719f82d3SEliot Blennerhassett 		status->stream_state = HPI_STATE_STOPPED;
10818e0874eaSEliot Blennerhassett 		status->dsp_index = 0;
10828e0874eaSEliot Blennerhassett 		status->host_index = status->dsp_index;
1083719f82d3SEliot Blennerhassett 		status->size_in_bytes = phm->u.d.u.buffer.buffer_size;
1084deb21a23SEliot Blennerhassett 		status->auxiliary_data_available = 0;
1085719f82d3SEliot Blennerhassett 
1086719f82d3SEliot Blennerhassett 		hw_message(pao, phm, phr);
1087ba3a9099SEliot Blennerhassett 
1088719f82d3SEliot Blennerhassett 		if (phr->error
1089719f82d3SEliot Blennerhassett 			&& hpios_locked_mem_valid(&phw->
1090719f82d3SEliot Blennerhassett 				instream_host_buffers[phm->obj_index])) {
1091719f82d3SEliot Blennerhassett 			hpios_locked_mem_free(&phw->instream_host_buffers
1092719f82d3SEliot Blennerhassett 				[phm->obj_index]);
1093719f82d3SEliot Blennerhassett 			phw->instream_host_buffer_size[phm->obj_index] = 0;
1094719f82d3SEliot Blennerhassett 		}
1095719f82d3SEliot Blennerhassett 	}
1096719f82d3SEliot Blennerhassett }
1097719f82d3SEliot Blennerhassett 
1098719f82d3SEliot Blennerhassett static void instream_host_buffer_get_info(struct hpi_adapter_obj *pao,
1099719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
1100719f82d3SEliot Blennerhassett {
1101719f82d3SEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
1102719f82d3SEliot Blennerhassett 	struct bus_master_interface *interface = phw->p_interface_buffer;
1103719f82d3SEliot Blennerhassett 	struct hpi_hostbuffer_status *status;
1104719f82d3SEliot Blennerhassett 	u8 *p_bbm_data;
1105719f82d3SEliot Blennerhassett 
1106719f82d3SEliot Blennerhassett 	if (hpios_locked_mem_valid(&phw->instream_host_buffers[phm->
1107719f82d3SEliot Blennerhassett 				obj_index])) {
1108719f82d3SEliot Blennerhassett 		if (hpios_locked_mem_get_virt_addr(&phw->
1109719f82d3SEliot Blennerhassett 				instream_host_buffers[phm->obj_index],
1110719f82d3SEliot Blennerhassett 				(void *)&p_bbm_data)) {
1111719f82d3SEliot Blennerhassett 			phr->error = HPI_ERROR_INVALID_OPERATION;
1112719f82d3SEliot Blennerhassett 			return;
1113719f82d3SEliot Blennerhassett 		}
1114719f82d3SEliot Blennerhassett 		status = &interface->instream_host_buffer_status[phm->
1115719f82d3SEliot Blennerhassett 			obj_index];
1116719f82d3SEliot Blennerhassett 		hpi_init_response(phr, HPI_OBJ_ISTREAM,
1117719f82d3SEliot Blennerhassett 			HPI_ISTREAM_HOSTBUFFER_GET_INFO, 0);
1118719f82d3SEliot Blennerhassett 		phr->u.d.u.hostbuffer_info.p_buffer = p_bbm_data;
1119719f82d3SEliot Blennerhassett 		phr->u.d.u.hostbuffer_info.p_status = status;
1120719f82d3SEliot Blennerhassett 	} else {
1121719f82d3SEliot Blennerhassett 		hpi_init_response(phr, HPI_OBJ_ISTREAM,
1122719f82d3SEliot Blennerhassett 			HPI_ISTREAM_HOSTBUFFER_GET_INFO,
1123719f82d3SEliot Blennerhassett 			HPI_ERROR_INVALID_OPERATION);
1124719f82d3SEliot Blennerhassett 	}
1125719f82d3SEliot Blennerhassett }
1126719f82d3SEliot Blennerhassett 
1127719f82d3SEliot Blennerhassett static void instream_host_buffer_free(struct hpi_adapter_obj *pao,
1128719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
1129719f82d3SEliot Blennerhassett {
1130719f82d3SEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
1131719f82d3SEliot Blennerhassett 	u32 command = phm->u.d.u.buffer.command;
1132719f82d3SEliot Blennerhassett 
1133719f82d3SEliot Blennerhassett 	if (phw->instream_host_buffer_size[phm->obj_index]) {
1134719f82d3SEliot Blennerhassett 		if (command == HPI_BUFFER_CMD_EXTERNAL
1135719f82d3SEliot Blennerhassett 			|| command == HPI_BUFFER_CMD_INTERNAL_REVOKEADAPTER) {
1136719f82d3SEliot Blennerhassett 			phw->instream_host_buffer_size[phm->obj_index] = 0;
1137719f82d3SEliot Blennerhassett 			hw_message(pao, phm, phr);
1138719f82d3SEliot Blennerhassett 		}
1139719f82d3SEliot Blennerhassett 
1140719f82d3SEliot Blennerhassett 		if (command == HPI_BUFFER_CMD_EXTERNAL
1141719f82d3SEliot Blennerhassett 			|| command == HPI_BUFFER_CMD_INTERNAL_FREE)
1142719f82d3SEliot Blennerhassett 			hpios_locked_mem_free(&phw->instream_host_buffers
1143719f82d3SEliot Blennerhassett 				[phm->obj_index]);
1144719f82d3SEliot Blennerhassett 
1145719f82d3SEliot Blennerhassett 	} else {
1146719f82d3SEliot Blennerhassett 		/* Should HPI_ERROR_INVALID_OPERATION be returned
1147719f82d3SEliot Blennerhassett 		   if no host buffer is allocated? */
1148719f82d3SEliot Blennerhassett 		hpi_init_response(phr, HPI_OBJ_ISTREAM,
1149719f82d3SEliot Blennerhassett 			HPI_ISTREAM_HOSTBUFFER_FREE, 0);
1150719f82d3SEliot Blennerhassett 
1151719f82d3SEliot Blennerhassett 	}
1152719f82d3SEliot Blennerhassett 
1153719f82d3SEliot Blennerhassett }
1154719f82d3SEliot Blennerhassett 
1155719f82d3SEliot Blennerhassett static void instream_start(struct hpi_adapter_obj *pao,
1156719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
1157719f82d3SEliot Blennerhassett {
1158719f82d3SEliot Blennerhassett 	hw_message(pao, phm, phr);
1159719f82d3SEliot Blennerhassett }
1160719f82d3SEliot Blennerhassett 
11612a383cb3SEliot Blennerhassett static u32 instream_get_bytes_available(struct hpi_hostbuffer_status *status)
1162719f82d3SEliot Blennerhassett {
11638e0874eaSEliot Blennerhassett 	return status->dsp_index - status->host_index;
1164719f82d3SEliot Blennerhassett }
1165719f82d3SEliot Blennerhassett 
1166719f82d3SEliot Blennerhassett static void instream_read(struct hpi_adapter_obj *pao,
1167719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
1168719f82d3SEliot Blennerhassett {
1169719f82d3SEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
1170719f82d3SEliot Blennerhassett 	struct bus_master_interface *interface = phw->p_interface_buffer;
1171719f82d3SEliot Blennerhassett 	struct hpi_hostbuffer_status *status;
11722a383cb3SEliot Blennerhassett 	u32 data_available;
1173719f82d3SEliot Blennerhassett 	u8 *p_bbm_data;
11742a383cb3SEliot Blennerhassett 	u32 l_first_read;
1175719f82d3SEliot Blennerhassett 	u8 *p_app_data = (u8 *)phm->u.d.u.data.pb_data;
1176719f82d3SEliot Blennerhassett 
1177719f82d3SEliot Blennerhassett 	if (!phw->instream_host_buffer_size[phm->obj_index]) {
1178719f82d3SEliot Blennerhassett 		hw_message(pao, phm, phr);
1179719f82d3SEliot Blennerhassett 		return;
1180719f82d3SEliot Blennerhassett 	}
1181719f82d3SEliot Blennerhassett 	hpi_init_response(phr, phm->object, phm->function, 0);
1182719f82d3SEliot Blennerhassett 
1183719f82d3SEliot Blennerhassett 	status = &interface->instream_host_buffer_status[phm->obj_index];
1184719f82d3SEliot Blennerhassett 	data_available = instream_get_bytes_available(status);
11852a383cb3SEliot Blennerhassett 	if (data_available < phm->u.d.u.data.data_size) {
1186719f82d3SEliot Blennerhassett 		phr->error = HPI_ERROR_INVALID_DATASIZE;
1187719f82d3SEliot Blennerhassett 		return;
1188719f82d3SEliot Blennerhassett 	}
1189719f82d3SEliot Blennerhassett 
1190719f82d3SEliot Blennerhassett 	if (hpios_locked_mem_valid(&phw->instream_host_buffers[phm->
1191719f82d3SEliot Blennerhassett 				obj_index])) {
1192719f82d3SEliot Blennerhassett 		if (hpios_locked_mem_get_virt_addr(&phw->
1193719f82d3SEliot Blennerhassett 				instream_host_buffers[phm->obj_index],
1194719f82d3SEliot Blennerhassett 				(void *)&p_bbm_data)) {
1195719f82d3SEliot Blennerhassett 			phr->error = HPI_ERROR_INVALID_OPERATION;
1196719f82d3SEliot Blennerhassett 			return;
1197719f82d3SEliot Blennerhassett 		}
1198719f82d3SEliot Blennerhassett 
1199719f82d3SEliot Blennerhassett 		/* either all data,
1200719f82d3SEliot Blennerhassett 		   or enough to fit from current to end of BBM buffer */
1201719f82d3SEliot Blennerhassett 		l_first_read =
1202719f82d3SEliot Blennerhassett 			min(phm->u.d.u.data.data_size,
1203719f82d3SEliot Blennerhassett 			status->size_in_bytes -
1204719f82d3SEliot Blennerhassett 			(status->host_index & (status->size_in_bytes - 1)));
1205719f82d3SEliot Blennerhassett 
1206719f82d3SEliot Blennerhassett 		memcpy(p_app_data,
1207719f82d3SEliot Blennerhassett 			p_bbm_data +
1208719f82d3SEliot Blennerhassett 			(status->host_index & (status->size_in_bytes - 1)),
1209719f82d3SEliot Blennerhassett 			l_first_read);
1210719f82d3SEliot Blennerhassett 		/* remaining data if any */
1211719f82d3SEliot Blennerhassett 		memcpy(p_app_data + l_first_read, p_bbm_data,
1212719f82d3SEliot Blennerhassett 			phm->u.d.u.data.data_size - l_first_read);
1213719f82d3SEliot Blennerhassett 	}
1214719f82d3SEliot Blennerhassett 	status->host_index += phm->u.d.u.data.data_size;
1215719f82d3SEliot Blennerhassett }
1216719f82d3SEliot Blennerhassett 
1217719f82d3SEliot Blennerhassett static void instream_get_info(struct hpi_adapter_obj *pao,
1218719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
1219719f82d3SEliot Blennerhassett {
1220719f82d3SEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
1221719f82d3SEliot Blennerhassett 	struct bus_master_interface *interface = phw->p_interface_buffer;
1222719f82d3SEliot Blennerhassett 	struct hpi_hostbuffer_status *status;
1223719f82d3SEliot Blennerhassett 	if (!phw->instream_host_buffer_size[phm->obj_index]) {
1224719f82d3SEliot Blennerhassett 		hw_message(pao, phm, phr);
1225719f82d3SEliot Blennerhassett 		return;
1226719f82d3SEliot Blennerhassett 	}
1227719f82d3SEliot Blennerhassett 
1228719f82d3SEliot Blennerhassett 	status = &interface->instream_host_buffer_status[phm->obj_index];
1229719f82d3SEliot Blennerhassett 
1230719f82d3SEliot Blennerhassett 	hpi_init_response(phr, phm->object, phm->function, 0);
1231719f82d3SEliot Blennerhassett 
1232719f82d3SEliot Blennerhassett 	phr->u.d.u.stream_info.state = (u16)status->stream_state;
1233719f82d3SEliot Blennerhassett 	phr->u.d.u.stream_info.samples_transferred =
1234719f82d3SEliot Blennerhassett 		status->samples_processed;
1235719f82d3SEliot Blennerhassett 	phr->u.d.u.stream_info.buffer_size = status->size_in_bytes;
1236719f82d3SEliot Blennerhassett 	phr->u.d.u.stream_info.data_available =
1237719f82d3SEliot Blennerhassett 		instream_get_bytes_available(status);
1238719f82d3SEliot Blennerhassett 	phr->u.d.u.stream_info.auxiliary_data_available =
1239719f82d3SEliot Blennerhassett 		status->auxiliary_data_available;
1240719f82d3SEliot Blennerhassett }
1241719f82d3SEliot Blennerhassett 
1242719f82d3SEliot Blennerhassett /*****************************************************************************/
1243719f82d3SEliot Blennerhassett /* LOW-LEVEL */
1244719f82d3SEliot Blennerhassett #define HPI6205_MAX_FILES_TO_LOAD 2
1245719f82d3SEliot Blennerhassett 
1246719f82d3SEliot Blennerhassett static u16 adapter_boot_load_dsp(struct hpi_adapter_obj *pao,
1247719f82d3SEliot Blennerhassett 	u32 *pos_error_code)
1248719f82d3SEliot Blennerhassett {
1249719f82d3SEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
1250719f82d3SEliot Blennerhassett 	struct dsp_code dsp_code;
1251719f82d3SEliot Blennerhassett 	u16 boot_code_id[HPI6205_MAX_FILES_TO_LOAD];
1252719f82d3SEliot Blennerhassett 	u32 temp;
1253719f82d3SEliot Blennerhassett 	int dsp = 0, i = 0;
1254719f82d3SEliot Blennerhassett 	u16 err = 0;
1255719f82d3SEliot Blennerhassett 
1256719f82d3SEliot Blennerhassett 	boot_code_id[0] = HPI_ADAPTER_ASI(0x6205);
1257719f82d3SEliot Blennerhassett 
1258ee246fc0SEliot Blennerhassett 	boot_code_id[1] = pao->pci.pci_dev->subsystem_device;
1259ee246fc0SEliot Blennerhassett 	boot_code_id[1] = HPI_ADAPTER_FAMILY_ASI(boot_code_id[1]);
1260ee246fc0SEliot Blennerhassett 
1261ee246fc0SEliot Blennerhassett 	/* fix up cases where bootcode id[1] != subsys id */
1262ee246fc0SEliot Blennerhassett 	switch (boot_code_id[1]) {
1263719f82d3SEliot Blennerhassett 	case HPI_ADAPTER_FAMILY_ASI(0x5000):
1264ee246fc0SEliot Blennerhassett 		boot_code_id[0] = boot_code_id[1];
1265ee246fc0SEliot Blennerhassett 		boot_code_id[1] = 0;
1266719f82d3SEliot Blennerhassett 		break;
1267719f82d3SEliot Blennerhassett 	case HPI_ADAPTER_FAMILY_ASI(0x5300):
1268719f82d3SEliot Blennerhassett 	case HPI_ADAPTER_FAMILY_ASI(0x5400):
1269719f82d3SEliot Blennerhassett 	case HPI_ADAPTER_FAMILY_ASI(0x6300):
1270ee246fc0SEliot Blennerhassett 		boot_code_id[1] = HPI_ADAPTER_FAMILY_ASI(0x6400);
1271719f82d3SEliot Blennerhassett 		break;
12726d0b898eSEliot Blennerhassett 	case HPI_ADAPTER_FAMILY_ASI(0x5500):
1273719f82d3SEliot Blennerhassett 	case HPI_ADAPTER_FAMILY_ASI(0x5600):
1274719f82d3SEliot Blennerhassett 	case HPI_ADAPTER_FAMILY_ASI(0x6500):
1275ee246fc0SEliot Blennerhassett 		boot_code_id[1] = HPI_ADAPTER_FAMILY_ASI(0x6600);
1276719f82d3SEliot Blennerhassett 		break;
1277cadae428SEliot Blennerhassett 	case HPI_ADAPTER_FAMILY_ASI(0x8800):
1278ee246fc0SEliot Blennerhassett 		boot_code_id[1] = HPI_ADAPTER_FAMILY_ASI(0x8900);
1279ee246fc0SEliot Blennerhassett 		break;
1280ee246fc0SEliot Blennerhassett 	default:
1281cadae428SEliot Blennerhassett 		break;
1282719f82d3SEliot Blennerhassett 	}
1283719f82d3SEliot Blennerhassett 
1284719f82d3SEliot Blennerhassett 	/* reset DSP by writing a 1 to the WARMRESET bit */
1285719f82d3SEliot Blennerhassett 	temp = C6205_HDCR_WARMRESET;
1286719f82d3SEliot Blennerhassett 	iowrite32(temp, phw->prHDCR);
1287719f82d3SEliot Blennerhassett 	hpios_delay_micro_seconds(1000);
1288719f82d3SEliot Blennerhassett 
1289719f82d3SEliot Blennerhassett 	/* check that PCI i/f was configured by EEPROM */
1290719f82d3SEliot Blennerhassett 	temp = ioread32(phw->prHSR);
1291719f82d3SEliot Blennerhassett 	if ((temp & (C6205_HSR_CFGERR | C6205_HSR_EEREAD)) !=
1292719f82d3SEliot Blennerhassett 		C6205_HSR_EEREAD)
12933285ea10SEliot Blennerhassett 		return HPI6205_ERROR_6205_EEPROM;
1294719f82d3SEliot Blennerhassett 	temp |= 0x04;
1295719f82d3SEliot Blennerhassett 	/* disable PINTA interrupt */
1296719f82d3SEliot Blennerhassett 	iowrite32(temp, phw->prHSR);
1297719f82d3SEliot Blennerhassett 
1298719f82d3SEliot Blennerhassett 	/* check control register reports PCI boot mode */
1299719f82d3SEliot Blennerhassett 	temp = ioread32(phw->prHDCR);
1300719f82d3SEliot Blennerhassett 	if (!(temp & C6205_HDCR_PCIBOOT))
13013285ea10SEliot Blennerhassett 		return HPI6205_ERROR_6205_REG;
1302719f82d3SEliot Blennerhassett 
13033285ea10SEliot Blennerhassett 	/* try writing a few numbers to the DSP page register */
1304719f82d3SEliot Blennerhassett 	/* and reading them back. */
1305719f82d3SEliot Blennerhassett 	temp = 3;
1306719f82d3SEliot Blennerhassett 	iowrite32(temp, phw->prDSPP);
1307719f82d3SEliot Blennerhassett 	if ((temp | C6205_DSPP_MAP1) != ioread32(phw->prDSPP))
13083285ea10SEliot Blennerhassett 		return HPI6205_ERROR_6205_DSPPAGE;
13093285ea10SEliot Blennerhassett 	temp = 2;
13103285ea10SEliot Blennerhassett 	iowrite32(temp, phw->prDSPP);
13113285ea10SEliot Blennerhassett 	if ((temp | C6205_DSPP_MAP1) != ioread32(phw->prDSPP))
13123285ea10SEliot Blennerhassett 		return HPI6205_ERROR_6205_DSPPAGE;
13133285ea10SEliot Blennerhassett 	temp = 1;
13143285ea10SEliot Blennerhassett 	iowrite32(temp, phw->prDSPP);
13153285ea10SEliot Blennerhassett 	if ((temp | C6205_DSPP_MAP1) != ioread32(phw->prDSPP))
13163285ea10SEliot Blennerhassett 		return HPI6205_ERROR_6205_DSPPAGE;
1317719f82d3SEliot Blennerhassett 	/* reset DSP page to the correct number */
1318719f82d3SEliot Blennerhassett 	temp = 0;
1319719f82d3SEliot Blennerhassett 	iowrite32(temp, phw->prDSPP);
1320719f82d3SEliot Blennerhassett 	if ((temp | C6205_DSPP_MAP1) != ioread32(phw->prDSPP))
13213285ea10SEliot Blennerhassett 		return HPI6205_ERROR_6205_DSPPAGE;
1322719f82d3SEliot Blennerhassett 	phw->dsp_page = 0;
1323719f82d3SEliot Blennerhassett 
1324719f82d3SEliot Blennerhassett 	/* release 6713 from reset before 6205 is bootloaded.
1325719f82d3SEliot Blennerhassett 	   This ensures that the EMIF is inactive,
1326719f82d3SEliot Blennerhassett 	   and the 6713 HPI gets the correct bootmode etc
1327719f82d3SEliot Blennerhassett 	 */
1328719f82d3SEliot Blennerhassett 	if (boot_code_id[1] != 0) {
1329719f82d3SEliot Blennerhassett 		/* DSP 1 is a C6713 */
1330719f82d3SEliot Blennerhassett 		/* CLKX0 <- '1' release the C6205 bootmode pulldowns */
1331719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, 0, (0x018C0024L), 0x00002202);
1332719f82d3SEliot Blennerhassett 		hpios_delay_micro_seconds(100);
1333719f82d3SEliot Blennerhassett 		/* Reset the 6713 #1 - revB */
1334719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, 0, C6205_BAR0_TIMER1_CTL, 0);
1335719f82d3SEliot Blennerhassett 
1336719f82d3SEliot Blennerhassett 		/* dummy read every 4 words for 6205 advisory 1.4.4 */
1337719f82d3SEliot Blennerhassett 		boot_loader_read_mem32(pao, 0, 0);
1338719f82d3SEliot Blennerhassett 
1339719f82d3SEliot Blennerhassett 		hpios_delay_micro_seconds(100);
1340719f82d3SEliot Blennerhassett 		/* Release C6713 from reset - revB */
1341719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, 0, C6205_BAR0_TIMER1_CTL, 4);
1342719f82d3SEliot Blennerhassett 		hpios_delay_micro_seconds(100);
1343719f82d3SEliot Blennerhassett 	}
1344719f82d3SEliot Blennerhassett 
1345719f82d3SEliot Blennerhassett 	for (dsp = 0; dsp < HPI6205_MAX_FILES_TO_LOAD; dsp++) {
1346719f82d3SEliot Blennerhassett 		/* is there a DSP to load? */
1347719f82d3SEliot Blennerhassett 		if (boot_code_id[dsp] == 0)
1348719f82d3SEliot Blennerhassett 			continue;
1349719f82d3SEliot Blennerhassett 
1350719f82d3SEliot Blennerhassett 		err = boot_loader_config_emif(pao, dsp);
1351719f82d3SEliot Blennerhassett 		if (err)
1352719f82d3SEliot Blennerhassett 			return err;
1353719f82d3SEliot Blennerhassett 
1354719f82d3SEliot Blennerhassett 		err = boot_loader_test_internal_memory(pao, dsp);
1355719f82d3SEliot Blennerhassett 		if (err)
1356719f82d3SEliot Blennerhassett 			return err;
1357719f82d3SEliot Blennerhassett 
1358719f82d3SEliot Blennerhassett 		err = boot_loader_test_external_memory(pao, dsp);
1359719f82d3SEliot Blennerhassett 		if (err)
1360719f82d3SEliot Blennerhassett 			return err;
1361719f82d3SEliot Blennerhassett 
1362719f82d3SEliot Blennerhassett 		err = boot_loader_test_pld(pao, dsp);
1363719f82d3SEliot Blennerhassett 		if (err)
1364719f82d3SEliot Blennerhassett 			return err;
1365719f82d3SEliot Blennerhassett 
1366719f82d3SEliot Blennerhassett 		/* write the DSP code down into the DSPs memory */
136795a4c6e7SEliot Blennerhassett 		err = hpi_dsp_code_open(boot_code_id[dsp], pao->pci.pci_dev,
136895a4c6e7SEliot Blennerhassett 			&dsp_code, pos_error_code);
1369719f82d3SEliot Blennerhassett 		if (err)
1370719f82d3SEliot Blennerhassett 			return err;
1371719f82d3SEliot Blennerhassett 
1372719f82d3SEliot Blennerhassett 		while (1) {
1373719f82d3SEliot Blennerhassett 			u32 length;
1374719f82d3SEliot Blennerhassett 			u32 address;
1375719f82d3SEliot Blennerhassett 			u32 type;
1376719f82d3SEliot Blennerhassett 			u32 *pcode;
1377719f82d3SEliot Blennerhassett 
1378719f82d3SEliot Blennerhassett 			err = hpi_dsp_code_read_word(&dsp_code, &length);
1379719f82d3SEliot Blennerhassett 			if (err)
1380719f82d3SEliot Blennerhassett 				break;
1381719f82d3SEliot Blennerhassett 			if (length == 0xFFFFFFFF)
1382719f82d3SEliot Blennerhassett 				break;	/* end of code */
1383719f82d3SEliot Blennerhassett 
1384719f82d3SEliot Blennerhassett 			err = hpi_dsp_code_read_word(&dsp_code, &address);
1385719f82d3SEliot Blennerhassett 			if (err)
1386719f82d3SEliot Blennerhassett 				break;
1387719f82d3SEliot Blennerhassett 			err = hpi_dsp_code_read_word(&dsp_code, &type);
1388719f82d3SEliot Blennerhassett 			if (err)
1389719f82d3SEliot Blennerhassett 				break;
1390719f82d3SEliot Blennerhassett 			err = hpi_dsp_code_read_block(length, &dsp_code,
1391719f82d3SEliot Blennerhassett 				&pcode);
1392719f82d3SEliot Blennerhassett 			if (err)
1393719f82d3SEliot Blennerhassett 				break;
1394719f82d3SEliot Blennerhassett 			for (i = 0; i < (int)length; i++) {
13953285ea10SEliot Blennerhassett 				boot_loader_write_mem32(pao, dsp, address,
13963285ea10SEliot Blennerhassett 					*pcode);
1397719f82d3SEliot Blennerhassett 				/* dummy read every 4 words */
1398719f82d3SEliot Blennerhassett 				/* for 6205 advisory 1.4.4 */
1399719f82d3SEliot Blennerhassett 				if (i % 4 == 0)
1400719f82d3SEliot Blennerhassett 					boot_loader_read_mem32(pao, dsp,
1401719f82d3SEliot Blennerhassett 						address);
1402719f82d3SEliot Blennerhassett 				pcode++;
1403719f82d3SEliot Blennerhassett 				address += 4;
1404719f82d3SEliot Blennerhassett 			}
1405719f82d3SEliot Blennerhassett 
1406719f82d3SEliot Blennerhassett 		}
1407719f82d3SEliot Blennerhassett 		if (err) {
1408719f82d3SEliot Blennerhassett 			hpi_dsp_code_close(&dsp_code);
1409719f82d3SEliot Blennerhassett 			return err;
1410719f82d3SEliot Blennerhassett 		}
1411719f82d3SEliot Blennerhassett 
1412719f82d3SEliot Blennerhassett 		/* verify code */
1413719f82d3SEliot Blennerhassett 		hpi_dsp_code_rewind(&dsp_code);
1414719f82d3SEliot Blennerhassett 		while (1) {
1415719f82d3SEliot Blennerhassett 			u32 length = 0;
1416719f82d3SEliot Blennerhassett 			u32 address = 0;
1417719f82d3SEliot Blennerhassett 			u32 type = 0;
1418719f82d3SEliot Blennerhassett 			u32 *pcode = NULL;
1419719f82d3SEliot Blennerhassett 			u32 data = 0;
1420719f82d3SEliot Blennerhassett 
1421719f82d3SEliot Blennerhassett 			hpi_dsp_code_read_word(&dsp_code, &length);
1422719f82d3SEliot Blennerhassett 			if (length == 0xFFFFFFFF)
1423719f82d3SEliot Blennerhassett 				break;	/* end of code */
1424719f82d3SEliot Blennerhassett 
1425719f82d3SEliot Blennerhassett 			hpi_dsp_code_read_word(&dsp_code, &address);
1426719f82d3SEliot Blennerhassett 			hpi_dsp_code_read_word(&dsp_code, &type);
1427719f82d3SEliot Blennerhassett 			hpi_dsp_code_read_block(length, &dsp_code, &pcode);
1428719f82d3SEliot Blennerhassett 
1429719f82d3SEliot Blennerhassett 			for (i = 0; i < (int)length; i++) {
1430719f82d3SEliot Blennerhassett 				data = boot_loader_read_mem32(pao, dsp,
1431719f82d3SEliot Blennerhassett 					address);
1432719f82d3SEliot Blennerhassett 				if (data != *pcode) {
1433719f82d3SEliot Blennerhassett 					err = 0;
1434719f82d3SEliot Blennerhassett 					break;
1435719f82d3SEliot Blennerhassett 				}
1436719f82d3SEliot Blennerhassett 				pcode++;
1437719f82d3SEliot Blennerhassett 				address += 4;
1438719f82d3SEliot Blennerhassett 			}
1439719f82d3SEliot Blennerhassett 			if (err)
1440719f82d3SEliot Blennerhassett 				break;
1441719f82d3SEliot Blennerhassett 		}
1442719f82d3SEliot Blennerhassett 		hpi_dsp_code_close(&dsp_code);
1443719f82d3SEliot Blennerhassett 		if (err)
1444719f82d3SEliot Blennerhassett 			return err;
1445719f82d3SEliot Blennerhassett 	}
1446719f82d3SEliot Blennerhassett 
1447719f82d3SEliot Blennerhassett 	/* After bootloading all DSPs, start DSP0 running
1448719f82d3SEliot Blennerhassett 	 * The DSP0 code will handle starting and synchronizing with its slaves
1449719f82d3SEliot Blennerhassett 	 */
1450719f82d3SEliot Blennerhassett 	if (phw->p_interface_buffer) {
1451719f82d3SEliot Blennerhassett 		/* we need to tell the card the physical PCI address */
1452719f82d3SEliot Blennerhassett 		u32 physicalPC_iaddress;
1453719f82d3SEliot Blennerhassett 		struct bus_master_interface *interface =
1454719f82d3SEliot Blennerhassett 			phw->p_interface_buffer;
1455719f82d3SEliot Blennerhassett 		u32 host_mailbox_address_on_dsp;
1456719f82d3SEliot Blennerhassett 		u32 physicalPC_iaddress_verify = 0;
1457719f82d3SEliot Blennerhassett 		int time_out = 10;
1458719f82d3SEliot Blennerhassett 		/* set ack so we know when DSP is ready to go */
1459719f82d3SEliot Blennerhassett 		/* (dwDspAck will be changed to HIF_RESET) */
1460719f82d3SEliot Blennerhassett 		interface->dsp_ack = H620_HIF_UNKNOWN;
1461719f82d3SEliot Blennerhassett 		wmb();	/* ensure ack is written before dsp writes back */
1462719f82d3SEliot Blennerhassett 
1463719f82d3SEliot Blennerhassett 		err = hpios_locked_mem_get_phys_addr(&phw->h_locked_mem,
1464719f82d3SEliot Blennerhassett 			&physicalPC_iaddress);
1465719f82d3SEliot Blennerhassett 
1466719f82d3SEliot Blennerhassett 		/* locate the host mailbox on the DSP. */
1467719f82d3SEliot Blennerhassett 		host_mailbox_address_on_dsp = 0x80000000;
1468719f82d3SEliot Blennerhassett 		while ((physicalPC_iaddress != physicalPC_iaddress_verify)
1469719f82d3SEliot Blennerhassett 			&& time_out--) {
14703285ea10SEliot Blennerhassett 			boot_loader_write_mem32(pao, 0,
1471719f82d3SEliot Blennerhassett 				host_mailbox_address_on_dsp,
1472719f82d3SEliot Blennerhassett 				physicalPC_iaddress);
1473719f82d3SEliot Blennerhassett 			physicalPC_iaddress_verify =
1474719f82d3SEliot Blennerhassett 				boot_loader_read_mem32(pao, 0,
1475719f82d3SEliot Blennerhassett 				host_mailbox_address_on_dsp);
1476719f82d3SEliot Blennerhassett 		}
1477719f82d3SEliot Blennerhassett 	}
1478719f82d3SEliot Blennerhassett 	HPI_DEBUG_LOG(DEBUG, "starting DS_ps running\n");
1479719f82d3SEliot Blennerhassett 	/* enable interrupts */
1480719f82d3SEliot Blennerhassett 	temp = ioread32(phw->prHSR);
1481719f82d3SEliot Blennerhassett 	temp &= ~(u32)C6205_HSR_INTAM;
1482719f82d3SEliot Blennerhassett 	iowrite32(temp, phw->prHSR);
1483719f82d3SEliot Blennerhassett 
1484719f82d3SEliot Blennerhassett 	/* start code running... */
1485719f82d3SEliot Blennerhassett 	temp = ioread32(phw->prHDCR);
1486719f82d3SEliot Blennerhassett 	temp |= (u32)C6205_HDCR_DSPINT;
1487719f82d3SEliot Blennerhassett 	iowrite32(temp, phw->prHDCR);
1488719f82d3SEliot Blennerhassett 
1489719f82d3SEliot Blennerhassett 	/* give the DSP 10ms to start up */
1490719f82d3SEliot Blennerhassett 	hpios_delay_micro_seconds(10000);
1491719f82d3SEliot Blennerhassett 	return err;
1492719f82d3SEliot Blennerhassett 
1493719f82d3SEliot Blennerhassett }
1494719f82d3SEliot Blennerhassett 
1495719f82d3SEliot Blennerhassett /*****************************************************************************/
1496719f82d3SEliot Blennerhassett /* Bootloader utility functions */
1497719f82d3SEliot Blennerhassett 
1498719f82d3SEliot Blennerhassett static u32 boot_loader_read_mem32(struct hpi_adapter_obj *pao, int dsp_index,
1499719f82d3SEliot Blennerhassett 	u32 address)
1500719f82d3SEliot Blennerhassett {
1501719f82d3SEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
1502719f82d3SEliot Blennerhassett 	u32 data = 0;
1503719f82d3SEliot Blennerhassett 	__iomem u32 *p_data;
1504719f82d3SEliot Blennerhassett 
1505719f82d3SEliot Blennerhassett 	if (dsp_index == 0) {
1506719f82d3SEliot Blennerhassett 		/* DSP 0 is always C6205 */
1507719f82d3SEliot Blennerhassett 		if ((address >= 0x01800000) & (address < 0x02000000)) {
1508719f82d3SEliot Blennerhassett 			/* BAR1 register access */
1509719f82d3SEliot Blennerhassett 			p_data = pao->pci.ap_mem_base[1] +
1510719f82d3SEliot Blennerhassett 				(address & 0x007fffff) /
1511719f82d3SEliot Blennerhassett 				sizeof(*pao->pci.ap_mem_base[1]);
1512719f82d3SEliot Blennerhassett 			/* HPI_DEBUG_LOG(WARNING,
1513719f82d3SEliot Blennerhassett 			   "BAR1 access %08x\n", dwAddress); */
1514719f82d3SEliot Blennerhassett 		} else {
1515719f82d3SEliot Blennerhassett 			u32 dw4M_page = address >> 22L;
1516719f82d3SEliot Blennerhassett 			if (dw4M_page != phw->dsp_page) {
1517719f82d3SEliot Blennerhassett 				phw->dsp_page = dw4M_page;
1518719f82d3SEliot Blennerhassett 				/* *INDENT OFF* */
1519719f82d3SEliot Blennerhassett 				iowrite32(phw->dsp_page, phw->prDSPP);
1520719f82d3SEliot Blennerhassett 				/* *INDENT-ON* */
1521719f82d3SEliot Blennerhassett 			}
1522719f82d3SEliot Blennerhassett 			address &= 0x3fffff;	/* address within 4M page */
1523719f82d3SEliot Blennerhassett 			/* BAR0 memory access */
1524719f82d3SEliot Blennerhassett 			p_data = pao->pci.ap_mem_base[0] +
1525719f82d3SEliot Blennerhassett 				address / sizeof(u32);
1526719f82d3SEliot Blennerhassett 		}
1527719f82d3SEliot Blennerhassett 		data = ioread32(p_data);
1528719f82d3SEliot Blennerhassett 	} else if (dsp_index == 1) {
1529719f82d3SEliot Blennerhassett 		/* DSP 1 is a C6713 */
1530719f82d3SEliot Blennerhassett 		u32 lsb;
1531719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, 0, HPIAL_ADDR, address);
1532719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, 0, HPIAH_ADDR, address >> 16);
1533719f82d3SEliot Blennerhassett 		lsb = boot_loader_read_mem32(pao, 0, HPIDL_ADDR);
1534719f82d3SEliot Blennerhassett 		data = boot_loader_read_mem32(pao, 0, HPIDH_ADDR);
1535719f82d3SEliot Blennerhassett 		data = (data << 16) | (lsb & 0xFFFF);
1536719f82d3SEliot Blennerhassett 	}
1537719f82d3SEliot Blennerhassett 	return data;
1538719f82d3SEliot Blennerhassett }
1539719f82d3SEliot Blennerhassett 
15403285ea10SEliot Blennerhassett static void boot_loader_write_mem32(struct hpi_adapter_obj *pao,
15413285ea10SEliot Blennerhassett 	int dsp_index, u32 address, u32 data)
1542719f82d3SEliot Blennerhassett {
1543719f82d3SEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
1544719f82d3SEliot Blennerhassett 	__iomem u32 *p_data;
1545719f82d3SEliot Blennerhassett 	/*      u32 dwVerifyData=0; */
1546719f82d3SEliot Blennerhassett 
1547719f82d3SEliot Blennerhassett 	if (dsp_index == 0) {
1548719f82d3SEliot Blennerhassett 		/* DSP 0 is always C6205 */
1549719f82d3SEliot Blennerhassett 		if ((address >= 0x01800000) & (address < 0x02000000)) {
1550719f82d3SEliot Blennerhassett 			/* BAR1 - DSP  register access using */
1551719f82d3SEliot Blennerhassett 			/* Non-prefetchable PCI access */
1552719f82d3SEliot Blennerhassett 			p_data = pao->pci.ap_mem_base[1] +
1553719f82d3SEliot Blennerhassett 				(address & 0x007fffff) /
1554719f82d3SEliot Blennerhassett 				sizeof(*pao->pci.ap_mem_base[1]);
1555719f82d3SEliot Blennerhassett 		} else {
1556719f82d3SEliot Blennerhassett 			/* BAR0 access - all of DSP memory using */
1557719f82d3SEliot Blennerhassett 			/* pre-fetchable PCI access */
1558719f82d3SEliot Blennerhassett 			u32 dw4M_page = address >> 22L;
1559719f82d3SEliot Blennerhassett 			if (dw4M_page != phw->dsp_page) {
1560719f82d3SEliot Blennerhassett 				phw->dsp_page = dw4M_page;
1561719f82d3SEliot Blennerhassett 				/* *INDENT-OFF* */
1562719f82d3SEliot Blennerhassett 				iowrite32(phw->dsp_page, phw->prDSPP);
1563719f82d3SEliot Blennerhassett 				/* *INDENT-ON* */
1564719f82d3SEliot Blennerhassett 			}
1565719f82d3SEliot Blennerhassett 			address &= 0x3fffff;	/* address within 4M page */
1566719f82d3SEliot Blennerhassett 			p_data = pao->pci.ap_mem_base[0] +
1567719f82d3SEliot Blennerhassett 				address / sizeof(u32);
1568719f82d3SEliot Blennerhassett 		}
1569719f82d3SEliot Blennerhassett 		iowrite32(data, p_data);
1570719f82d3SEliot Blennerhassett 	} else if (dsp_index == 1) {
1571719f82d3SEliot Blennerhassett 		/* DSP 1 is a C6713 */
1572719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, 0, HPIAL_ADDR, address);
1573719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, 0, HPIAH_ADDR, address >> 16);
1574719f82d3SEliot Blennerhassett 
1575719f82d3SEliot Blennerhassett 		/* dummy read every 4 words for 6205 advisory 1.4.4 */
1576719f82d3SEliot Blennerhassett 		boot_loader_read_mem32(pao, 0, 0);
1577719f82d3SEliot Blennerhassett 
1578719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, 0, HPIDL_ADDR, data);
1579719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, 0, HPIDH_ADDR, data >> 16);
1580719f82d3SEliot Blennerhassett 
1581719f82d3SEliot Blennerhassett 		/* dummy read every 4 words for 6205 advisory 1.4.4 */
1582719f82d3SEliot Blennerhassett 		boot_loader_read_mem32(pao, 0, 0);
15833285ea10SEliot Blennerhassett 	}
1584719f82d3SEliot Blennerhassett }
1585719f82d3SEliot Blennerhassett 
1586719f82d3SEliot Blennerhassett static u16 boot_loader_config_emif(struct hpi_adapter_obj *pao, int dsp_index)
1587719f82d3SEliot Blennerhassett {
1588719f82d3SEliot Blennerhassett 	if (dsp_index == 0) {
1589719f82d3SEliot Blennerhassett 		u32 setting;
1590719f82d3SEliot Blennerhassett 
1591719f82d3SEliot Blennerhassett 		/* DSP 0 is always C6205 */
1592719f82d3SEliot Blennerhassett 
1593719f82d3SEliot Blennerhassett 		/* Set the EMIF */
1594719f82d3SEliot Blennerhassett 		/* memory map of C6205 */
1595719f82d3SEliot Blennerhassett 		/* 00000000-0000FFFF    16Kx32 internal program */
1596719f82d3SEliot Blennerhassett 		/* 00400000-00BFFFFF    CE0     2Mx32 SDRAM running @ 100MHz */
1597719f82d3SEliot Blennerhassett 
1598719f82d3SEliot Blennerhassett 		/* EMIF config */
1599719f82d3SEliot Blennerhassett 		/*------------ */
1600719f82d3SEliot Blennerhassett 		/* Global EMIF control */
1601719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, dsp_index, 0x01800000, 0x3779);
1602719f82d3SEliot Blennerhassett #define WS_OFS 28
1603719f82d3SEliot Blennerhassett #define WST_OFS 22
1604719f82d3SEliot Blennerhassett #define WH_OFS 20
1605719f82d3SEliot Blennerhassett #define RS_OFS 16
1606719f82d3SEliot Blennerhassett #define RST_OFS 8
1607719f82d3SEliot Blennerhassett #define MTYPE_OFS 4
1608719f82d3SEliot Blennerhassett #define RH_OFS 0
1609719f82d3SEliot Blennerhassett 
1610719f82d3SEliot Blennerhassett 		/* EMIF CE0 setup - 2Mx32 Sync DRAM on ASI5000 cards only */
1611719f82d3SEliot Blennerhassett 		setting = 0x00000030;
1612719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, dsp_index, 0x01800008, setting);
1613719f82d3SEliot Blennerhassett 		if (setting != boot_loader_read_mem32(pao, dsp_index,
1614719f82d3SEliot Blennerhassett 				0x01800008))
16153285ea10SEliot Blennerhassett 			return HPI6205_ERROR_DSP_EMIF;
1616719f82d3SEliot Blennerhassett 
1617719f82d3SEliot Blennerhassett 		/* EMIF CE1 setup - 32 bit async. This is 6713 #1 HPI, */
1618719f82d3SEliot Blennerhassett 		/* which occupies D15..0. 6713 starts at 27MHz, so need */
1619719f82d3SEliot Blennerhassett 		/* plenty of wait states. See dsn8701.rtf, and 6713 errata. */
1620719f82d3SEliot Blennerhassett 		/* WST should be 71, but 63  is max possible */
1621719f82d3SEliot Blennerhassett 		setting =
1622719f82d3SEliot Blennerhassett 			(1L << WS_OFS) | (63L << WST_OFS) | (1L << WH_OFS) |
1623719f82d3SEliot Blennerhassett 			(1L << RS_OFS) | (63L << RST_OFS) | (1L << RH_OFS) |
1624719f82d3SEliot Blennerhassett 			(2L << MTYPE_OFS);
1625719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, dsp_index, 0x01800004, setting);
1626719f82d3SEliot Blennerhassett 		if (setting != boot_loader_read_mem32(pao, dsp_index,
1627719f82d3SEliot Blennerhassett 				0x01800004))
16283285ea10SEliot Blennerhassett 			return HPI6205_ERROR_DSP_EMIF;
1629719f82d3SEliot Blennerhassett 
1630719f82d3SEliot Blennerhassett 		/* EMIF CE2 setup - 32 bit async. This is 6713 #2 HPI, */
1631719f82d3SEliot Blennerhassett 		/* which occupies D15..0. 6713 starts at 27MHz, so need */
1632719f82d3SEliot Blennerhassett 		/* plenty of wait states */
1633719f82d3SEliot Blennerhassett 		setting =
1634719f82d3SEliot Blennerhassett 			(1L << WS_OFS) | (28L << WST_OFS) | (1L << WH_OFS) |
1635719f82d3SEliot Blennerhassett 			(1L << RS_OFS) | (63L << RST_OFS) | (1L << RH_OFS) |
1636719f82d3SEliot Blennerhassett 			(2L << MTYPE_OFS);
1637719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, dsp_index, 0x01800010, setting);
1638719f82d3SEliot Blennerhassett 		if (setting != boot_loader_read_mem32(pao, dsp_index,
1639719f82d3SEliot Blennerhassett 				0x01800010))
16403285ea10SEliot Blennerhassett 			return HPI6205_ERROR_DSP_EMIF;
1641719f82d3SEliot Blennerhassett 
1642719f82d3SEliot Blennerhassett 		/* EMIF CE3 setup - 32 bit async. */
1643719f82d3SEliot Blennerhassett 		/* This is the PLD on the ASI5000 cards only */
1644719f82d3SEliot Blennerhassett 		setting =
1645719f82d3SEliot Blennerhassett 			(1L << WS_OFS) | (10L << WST_OFS) | (1L << WH_OFS) |
1646719f82d3SEliot Blennerhassett 			(1L << RS_OFS) | (10L << RST_OFS) | (1L << RH_OFS) |
1647719f82d3SEliot Blennerhassett 			(2L << MTYPE_OFS);
1648719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, dsp_index, 0x01800014, setting);
1649719f82d3SEliot Blennerhassett 		if (setting != boot_loader_read_mem32(pao, dsp_index,
1650719f82d3SEliot Blennerhassett 				0x01800014))
16513285ea10SEliot Blennerhassett 			return HPI6205_ERROR_DSP_EMIF;
1652719f82d3SEliot Blennerhassett 
1653719f82d3SEliot Blennerhassett 		/* set EMIF SDRAM control for 2Mx32 SDRAM (512x32x4 bank) */
1654719f82d3SEliot Blennerhassett 		/*  need to use this else DSP code crashes? */
1655719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, dsp_index, 0x01800018,
1656719f82d3SEliot Blennerhassett 			0x07117000);
1657719f82d3SEliot Blennerhassett 
1658719f82d3SEliot Blennerhassett 		/* EMIF SDRAM Refresh Timing */
1659719f82d3SEliot Blennerhassett 		/* EMIF SDRAM timing  (orig = 0x410, emulator = 0x61a) */
1660719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, dsp_index, 0x0180001C,
1661719f82d3SEliot Blennerhassett 			0x00000410);
1662719f82d3SEliot Blennerhassett 
1663719f82d3SEliot Blennerhassett 	} else if (dsp_index == 1) {
1664719f82d3SEliot Blennerhassett 		/* test access to the C6713s HPI registers */
1665719f82d3SEliot Blennerhassett 		u32 write_data = 0, read_data = 0, i = 0;
1666719f82d3SEliot Blennerhassett 
1667719f82d3SEliot Blennerhassett 		/* Set up HPIC for little endian, by setiing HPIC:HWOB=1 */
1668719f82d3SEliot Blennerhassett 		write_data = 1;
1669719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, 0, HPICL_ADDR, write_data);
1670719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, 0, HPICH_ADDR, write_data);
1671719f82d3SEliot Blennerhassett 		/* C67 HPI is on lower 16bits of 32bit EMIF */
1672719f82d3SEliot Blennerhassett 		read_data =
1673719f82d3SEliot Blennerhassett 			0xFFF7 & boot_loader_read_mem32(pao, 0, HPICL_ADDR);
1674719f82d3SEliot Blennerhassett 		if (write_data != read_data) {
1675719f82d3SEliot Blennerhassett 			HPI_DEBUG_LOG(ERROR, "HPICL %x %x\n", write_data,
1676719f82d3SEliot Blennerhassett 				read_data);
16773285ea10SEliot Blennerhassett 			return HPI6205_ERROR_C6713_HPIC;
1678719f82d3SEliot Blennerhassett 		}
1679719f82d3SEliot Blennerhassett 		/* HPIA - walking ones test */
1680719f82d3SEliot Blennerhassett 		write_data = 1;
1681719f82d3SEliot Blennerhassett 		for (i = 0; i < 32; i++) {
1682719f82d3SEliot Blennerhassett 			boot_loader_write_mem32(pao, 0, HPIAL_ADDR,
1683719f82d3SEliot Blennerhassett 				write_data);
1684719f82d3SEliot Blennerhassett 			boot_loader_write_mem32(pao, 0, HPIAH_ADDR,
1685719f82d3SEliot Blennerhassett 				(write_data >> 16));
1686719f82d3SEliot Blennerhassett 			read_data =
1687719f82d3SEliot Blennerhassett 				0xFFFF & boot_loader_read_mem32(pao, 0,
1688719f82d3SEliot Blennerhassett 				HPIAL_ADDR);
1689719f82d3SEliot Blennerhassett 			read_data =
1690719f82d3SEliot Blennerhassett 				read_data | ((0xFFFF &
1691719f82d3SEliot Blennerhassett 					boot_loader_read_mem32(pao, 0,
1692719f82d3SEliot Blennerhassett 						HPIAH_ADDR))
1693719f82d3SEliot Blennerhassett 				<< 16);
1694719f82d3SEliot Blennerhassett 			if (read_data != write_data) {
1695719f82d3SEliot Blennerhassett 				HPI_DEBUG_LOG(ERROR, "HPIA %x %x\n",
1696719f82d3SEliot Blennerhassett 					write_data, read_data);
16973285ea10SEliot Blennerhassett 				return HPI6205_ERROR_C6713_HPIA;
1698719f82d3SEliot Blennerhassett 			}
1699719f82d3SEliot Blennerhassett 			write_data = write_data << 1;
1700719f82d3SEliot Blennerhassett 		}
1701719f82d3SEliot Blennerhassett 
1702719f82d3SEliot Blennerhassett 		/* setup C67x PLL
1703719f82d3SEliot Blennerhassett 		 *  ** C6713 datasheet says we cannot program PLL from HPI,
1704719f82d3SEliot Blennerhassett 		 * and indeed if we try to set the PLL multiply from the HPI,
1705719f82d3SEliot Blennerhassett 		 * the PLL does not seem to lock, so we enable the PLL and
1706719f82d3SEliot Blennerhassett 		 * use the default multiply of x 7, which for a 27MHz clock
1707719f82d3SEliot Blennerhassett 		 * gives a DSP speed of 189MHz
1708719f82d3SEliot Blennerhassett 		 */
1709719f82d3SEliot Blennerhassett 		/* bypass PLL */
1710719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, dsp_index, 0x01B7C100, 0x0000);
1711719f82d3SEliot Blennerhassett 		hpios_delay_micro_seconds(1000);
1712719f82d3SEliot Blennerhassett 		/* EMIF = 189/3=63MHz */
1713719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, dsp_index, 0x01B7C120, 0x8002);
1714719f82d3SEliot Blennerhassett 		/* peri = 189/2 */
1715719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, dsp_index, 0x01B7C11C, 0x8001);
1716719f82d3SEliot Blennerhassett 		/* cpu  = 189/1 */
1717719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, dsp_index, 0x01B7C118, 0x8000);
1718719f82d3SEliot Blennerhassett 		hpios_delay_micro_seconds(1000);
1719719f82d3SEliot Blennerhassett 		/* ** SGT test to take GPO3 high when we start the PLL */
1720719f82d3SEliot Blennerhassett 		/* and low when the delay is completed */
1721719f82d3SEliot Blennerhassett 		/* FSX0 <- '1' (GPO3) */
1722719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, 0, (0x018C0024L), 0x00002A0A);
1723719f82d3SEliot Blennerhassett 		/* PLL not bypassed */
1724719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, dsp_index, 0x01B7C100, 0x0001);
1725719f82d3SEliot Blennerhassett 		hpios_delay_micro_seconds(1000);
1726719f82d3SEliot Blennerhassett 		/* FSX0 <- '0' (GPO3) */
1727719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, 0, (0x018C0024L), 0x00002A02);
1728719f82d3SEliot Blennerhassett 
1729719f82d3SEliot Blennerhassett 		/* 6205 EMIF CE1 resetup - 32 bit async. */
1730719f82d3SEliot Blennerhassett 		/* Now 6713 #1 is running at 189MHz can reduce waitstates */
1731719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, 0, 0x01800004,	/* CE1 */
1732719f82d3SEliot Blennerhassett 			(1L << WS_OFS) | (8L << WST_OFS) | (1L << WH_OFS) |
1733719f82d3SEliot Blennerhassett 			(1L << RS_OFS) | (12L << RST_OFS) | (1L << RH_OFS) |
1734719f82d3SEliot Blennerhassett 			(2L << MTYPE_OFS));
1735719f82d3SEliot Blennerhassett 
1736719f82d3SEliot Blennerhassett 		hpios_delay_micro_seconds(1000);
1737719f82d3SEliot Blennerhassett 
1738719f82d3SEliot Blennerhassett 		/* check that we can read one of the PLL registers */
1739719f82d3SEliot Blennerhassett 		/* PLL should not be bypassed! */
1740719f82d3SEliot Blennerhassett 		if ((boot_loader_read_mem32(pao, dsp_index, 0x01B7C100) & 0xF)
1741719f82d3SEliot Blennerhassett 			!= 0x0001) {
17423285ea10SEliot Blennerhassett 			return HPI6205_ERROR_C6713_PLL;
1743719f82d3SEliot Blennerhassett 		}
1744719f82d3SEliot Blennerhassett 		/* setup C67x EMIF  (note this is the only use of
1745719f82d3SEliot Blennerhassett 		   BAR1 via BootLoader_WriteMem32) */
1746719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, dsp_index, C6713_EMIF_GCTL,
1747719f82d3SEliot Blennerhassett 			0x000034A8);
17481d595d2aSEliot Blennerhassett 
17491d595d2aSEliot Blennerhassett 		/* EMIF CE0 setup - 2Mx32 Sync DRAM
17501d595d2aSEliot Blennerhassett 		   31..28       Wr setup
17511d595d2aSEliot Blennerhassett 		   27..22       Wr strobe
17521d595d2aSEliot Blennerhassett 		   21..20       Wr hold
17531d595d2aSEliot Blennerhassett 		   19..16       Rd setup
17541d595d2aSEliot Blennerhassett 		   15..14       -
17551d595d2aSEliot Blennerhassett 		   13..8        Rd strobe
17561d595d2aSEliot Blennerhassett 		   7..4         MTYPE   0011            Sync DRAM 32bits
17571d595d2aSEliot Blennerhassett 		   3            Wr hold MSB
17581d595d2aSEliot Blennerhassett 		   2..0         Rd hold
17591d595d2aSEliot Blennerhassett 		 */
1760719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, dsp_index, C6713_EMIF_CE0,
1761719f82d3SEliot Blennerhassett 			0x00000030);
17621d595d2aSEliot Blennerhassett 
17631d595d2aSEliot Blennerhassett 		/* EMIF SDRAM Extension
17641d595d2aSEliot Blennerhassett 		   0x00
17651d595d2aSEliot Blennerhassett 		   31-21        0000b 0000b 000b
17661d595d2aSEliot Blennerhassett 		   20           WR2RD = 2cycles-1  = 1b
17671d595d2aSEliot Blennerhassett 
17681d595d2aSEliot Blennerhassett 		   19-18        WR2DEAC = 3cycle-1 = 10b
17691d595d2aSEliot Blennerhassett 		   17           WR2WR = 2cycle-1   = 1b
17701d595d2aSEliot Blennerhassett 		   16-15        R2WDQM = 4cycle-1  = 11b
17711d595d2aSEliot Blennerhassett 		   14-12        RD2WR = 6cycles-1  = 101b
17721d595d2aSEliot Blennerhassett 
17731d595d2aSEliot Blennerhassett 		   11-10        RD2DEAC = 4cycle-1 = 11b
17741d595d2aSEliot Blennerhassett 		   9            RD2RD = 2cycle-1   = 1b
17751d595d2aSEliot Blennerhassett 		   8-7          THZP = 3cycle-1    = 10b
17761d595d2aSEliot Blennerhassett 		   6-5          TWR  = 2cycle-1    = 01b (tWR = 17ns)
17771d595d2aSEliot Blennerhassett 		   4            TRRD = 2cycle      = 0b  (tRRD = 14ns)
17781d595d2aSEliot Blennerhassett 		   3-1          TRAS = 5cycle-1    = 100b (Tras=42ns)
17791d595d2aSEliot Blennerhassett 		   1            CAS latency = 3cyc = 1b
17801d595d2aSEliot Blennerhassett 		   (for Micron 2M32-7 operating at 100MHz)
17811d595d2aSEliot Blennerhassett 		 */
1782719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, dsp_index, C6713_EMIF_SDRAMEXT,
1783719f82d3SEliot Blennerhassett 			0x001BDF29);
17841d595d2aSEliot Blennerhassett 
17851d595d2aSEliot Blennerhassett 		/* EMIF SDRAM control - set up for a 2Mx32 SDRAM (512x32x4 bank)
17861d595d2aSEliot Blennerhassett 		   31           -       0b       -
17871d595d2aSEliot Blennerhassett 		   30           SDBSZ   1b              4 bank
17881d595d2aSEliot Blennerhassett 		   29..28       SDRSZ   00b             11 row address pins
17891d595d2aSEliot Blennerhassett 
17901d595d2aSEliot Blennerhassett 		   27..26       SDCSZ   01b             8 column address pins
17911d595d2aSEliot Blennerhassett 		   25           RFEN    1b              refersh enabled
17921d595d2aSEliot Blennerhassett 		   24           INIT    1b              init SDRAM!
17931d595d2aSEliot Blennerhassett 
17941d595d2aSEliot Blennerhassett 		   23..20       TRCD    0001b                   (Trcd/Tcyc)-1 = (20/10)-1 = 1
17951d595d2aSEliot Blennerhassett 
17961d595d2aSEliot Blennerhassett 		   19..16       TRP     0001b                   (Trp/Tcyc)-1 = (20/10)-1 = 1
17971d595d2aSEliot Blennerhassett 
17981d595d2aSEliot Blennerhassett 		   15..12       TRC     0110b                   (Trc/Tcyc)-1 = (70/10)-1 = 6
17991d595d2aSEliot Blennerhassett 
18001d595d2aSEliot Blennerhassett 		   11..0        -       0000b 0000b 0000b
18011d595d2aSEliot Blennerhassett 		 */
1802719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, dsp_index, C6713_EMIF_SDRAMCTL,
18031d595d2aSEliot Blennerhassett 			0x47116000);
18041d595d2aSEliot Blennerhassett 
18051d595d2aSEliot Blennerhassett 		/* SDRAM refresh timing
18061d595d2aSEliot Blennerhassett 		   Need 4,096 refresh cycles every 64ms = 15.625us = 1562cycles of 100MHz = 0x61A
18071d595d2aSEliot Blennerhassett 		 */
1808719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, dsp_index,
1809719f82d3SEliot Blennerhassett 			C6713_EMIF_SDRAMTIMING, 0x00000410);
1810719f82d3SEliot Blennerhassett 
1811719f82d3SEliot Blennerhassett 		hpios_delay_micro_seconds(1000);
1812719f82d3SEliot Blennerhassett 	} else if (dsp_index == 2) {
1813719f82d3SEliot Blennerhassett 		/* DSP 2 is a C6713 */
18143285ea10SEliot Blennerhassett 	}
1815719f82d3SEliot Blennerhassett 
18163285ea10SEliot Blennerhassett 	return 0;
1817719f82d3SEliot Blennerhassett }
1818719f82d3SEliot Blennerhassett 
1819719f82d3SEliot Blennerhassett static u16 boot_loader_test_memory(struct hpi_adapter_obj *pao, int dsp_index,
1820719f82d3SEliot Blennerhassett 	u32 start_address, u32 length)
1821719f82d3SEliot Blennerhassett {
1822719f82d3SEliot Blennerhassett 	u32 i = 0, j = 0;
1823719f82d3SEliot Blennerhassett 	u32 test_addr = 0;
1824719f82d3SEliot Blennerhassett 	u32 test_data = 0, data = 0;
1825719f82d3SEliot Blennerhassett 
1826719f82d3SEliot Blennerhassett 	length = 1000;
1827719f82d3SEliot Blennerhassett 
1828719f82d3SEliot Blennerhassett 	/* for 1st word, test each bit in the 32bit word, */
1829719f82d3SEliot Blennerhassett 	/* dwLength specifies number of 32bit words to test */
1830719f82d3SEliot Blennerhassett 	/*for(i=0; i<dwLength; i++) */
1831719f82d3SEliot Blennerhassett 	i = 0;
1832719f82d3SEliot Blennerhassett 	{
1833719f82d3SEliot Blennerhassett 		test_addr = start_address + i * 4;
1834719f82d3SEliot Blennerhassett 		test_data = 0x00000001;
1835719f82d3SEliot Blennerhassett 		for (j = 0; j < 32; j++) {
1836719f82d3SEliot Blennerhassett 			boot_loader_write_mem32(pao, dsp_index, test_addr,
1837719f82d3SEliot Blennerhassett 				test_data);
1838719f82d3SEliot Blennerhassett 			data = boot_loader_read_mem32(pao, dsp_index,
1839719f82d3SEliot Blennerhassett 				test_addr);
1840719f82d3SEliot Blennerhassett 			if (data != test_data) {
1841719f82d3SEliot Blennerhassett 				HPI_DEBUG_LOG(VERBOSE,
18423285ea10SEliot Blennerhassett 					"Memtest error details  "
1843719f82d3SEliot Blennerhassett 					"%08x %08x %08x %i\n", test_addr,
1844719f82d3SEliot Blennerhassett 					test_data, data, dsp_index);
1845719f82d3SEliot Blennerhassett 				return 1;	/* error */
1846719f82d3SEliot Blennerhassett 			}
1847719f82d3SEliot Blennerhassett 			test_data = test_data << 1;
1848719f82d3SEliot Blennerhassett 		}	/* for(j) */
1849719f82d3SEliot Blennerhassett 	}	/* for(i) */
1850719f82d3SEliot Blennerhassett 
1851719f82d3SEliot Blennerhassett 	/* for the next 100 locations test each location, leaving it as zero */
1852719f82d3SEliot Blennerhassett 	/* write a zero to the next word in memory before we read */
1853719f82d3SEliot Blennerhassett 	/* the previous write to make sure every memory location is unique */
1854719f82d3SEliot Blennerhassett 	for (i = 0; i < 100; i++) {
1855719f82d3SEliot Blennerhassett 		test_addr = start_address + i * 4;
1856719f82d3SEliot Blennerhassett 		test_data = 0xA5A55A5A;
1857719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, dsp_index, test_addr, test_data);
1858719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, dsp_index, test_addr + 4, 0);
1859719f82d3SEliot Blennerhassett 		data = boot_loader_read_mem32(pao, dsp_index, test_addr);
1860719f82d3SEliot Blennerhassett 		if (data != test_data) {
1861719f82d3SEliot Blennerhassett 			HPI_DEBUG_LOG(VERBOSE,
18623285ea10SEliot Blennerhassett 				"Memtest error details  "
1863719f82d3SEliot Blennerhassett 				"%08x %08x %08x %i\n", test_addr, test_data,
1864719f82d3SEliot Blennerhassett 				data, dsp_index);
1865719f82d3SEliot Blennerhassett 			return 1;	/* error */
1866719f82d3SEliot Blennerhassett 		}
1867719f82d3SEliot Blennerhassett 		/* leave location as zero */
1868719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, dsp_index, test_addr, 0x0);
1869719f82d3SEliot Blennerhassett 	}
1870719f82d3SEliot Blennerhassett 
1871719f82d3SEliot Blennerhassett 	/* zero out entire memory block */
1872719f82d3SEliot Blennerhassett 	for (i = 0; i < length; i++) {
1873719f82d3SEliot Blennerhassett 		test_addr = start_address + i * 4;
1874719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, dsp_index, test_addr, 0x0);
1875719f82d3SEliot Blennerhassett 	}
1876719f82d3SEliot Blennerhassett 	return 0;
1877719f82d3SEliot Blennerhassett }
1878719f82d3SEliot Blennerhassett 
1879719f82d3SEliot Blennerhassett static u16 boot_loader_test_internal_memory(struct hpi_adapter_obj *pao,
1880719f82d3SEliot Blennerhassett 	int dsp_index)
1881719f82d3SEliot Blennerhassett {
1882719f82d3SEliot Blennerhassett 	int err = 0;
1883719f82d3SEliot Blennerhassett 	if (dsp_index == 0) {
1884719f82d3SEliot Blennerhassett 		/* DSP 0 is a C6205 */
1885719f82d3SEliot Blennerhassett 		/* 64K prog mem */
1886719f82d3SEliot Blennerhassett 		err = boot_loader_test_memory(pao, dsp_index, 0x00000000,
1887719f82d3SEliot Blennerhassett 			0x10000);
1888719f82d3SEliot Blennerhassett 		if (!err)
1889719f82d3SEliot Blennerhassett 			/* 64K data mem */
1890719f82d3SEliot Blennerhassett 			err = boot_loader_test_memory(pao, dsp_index,
1891719f82d3SEliot Blennerhassett 				0x80000000, 0x10000);
18923285ea10SEliot Blennerhassett 	} else if (dsp_index == 1) {
18933285ea10SEliot Blennerhassett 		/* DSP 1 is a C6713 */
1894719f82d3SEliot Blennerhassett 		/* 192K internal mem */
1895719f82d3SEliot Blennerhassett 		err = boot_loader_test_memory(pao, dsp_index, 0x00000000,
1896719f82d3SEliot Blennerhassett 			0x30000);
1897719f82d3SEliot Blennerhassett 		if (!err)
1898719f82d3SEliot Blennerhassett 			/* 64K internal mem / L2 cache */
1899719f82d3SEliot Blennerhassett 			err = boot_loader_test_memory(pao, dsp_index,
1900719f82d3SEliot Blennerhassett 				0x00030000, 0x10000);
19013285ea10SEliot Blennerhassett 	}
1902719f82d3SEliot Blennerhassett 
1903719f82d3SEliot Blennerhassett 	if (err)
19043285ea10SEliot Blennerhassett 		return HPI6205_ERROR_DSP_INTMEM;
1905719f82d3SEliot Blennerhassett 	else
1906719f82d3SEliot Blennerhassett 		return 0;
1907719f82d3SEliot Blennerhassett }
1908719f82d3SEliot Blennerhassett 
1909719f82d3SEliot Blennerhassett static u16 boot_loader_test_external_memory(struct hpi_adapter_obj *pao,
1910719f82d3SEliot Blennerhassett 	int dsp_index)
1911719f82d3SEliot Blennerhassett {
1912719f82d3SEliot Blennerhassett 	u32 dRAM_start_address = 0;
1913719f82d3SEliot Blennerhassett 	u32 dRAM_size = 0;
1914719f82d3SEliot Blennerhassett 
1915719f82d3SEliot Blennerhassett 	if (dsp_index == 0) {
1916719f82d3SEliot Blennerhassett 		/* only test for SDRAM if an ASI5000 card */
19173285ea10SEliot Blennerhassett 		if (pao->pci.pci_dev->subsystem_device == 0x5000) {
1918719f82d3SEliot Blennerhassett 			/* DSP 0 is always C6205 */
1919719f82d3SEliot Blennerhassett 			dRAM_start_address = 0x00400000;
1920719f82d3SEliot Blennerhassett 			dRAM_size = 0x200000;
1921719f82d3SEliot Blennerhassett 			/*dwDRAMinc=1024; */
1922719f82d3SEliot Blennerhassett 		} else
1923719f82d3SEliot Blennerhassett 			return 0;
19243285ea10SEliot Blennerhassett 	} else if (dsp_index == 1) {
1925719f82d3SEliot Blennerhassett 		/* DSP 1 is a C6713 */
1926719f82d3SEliot Blennerhassett 		dRAM_start_address = 0x80000000;
1927719f82d3SEliot Blennerhassett 		dRAM_size = 0x200000;
1928719f82d3SEliot Blennerhassett 		/*dwDRAMinc=1024; */
19293285ea10SEliot Blennerhassett 	}
1930719f82d3SEliot Blennerhassett 
1931719f82d3SEliot Blennerhassett 	if (boot_loader_test_memory(pao, dsp_index, dRAM_start_address,
1932719f82d3SEliot Blennerhassett 			dRAM_size))
19333285ea10SEliot Blennerhassett 		return HPI6205_ERROR_DSP_EXTMEM;
1934719f82d3SEliot Blennerhassett 	return 0;
1935719f82d3SEliot Blennerhassett }
1936719f82d3SEliot Blennerhassett 
1937719f82d3SEliot Blennerhassett static u16 boot_loader_test_pld(struct hpi_adapter_obj *pao, int dsp_index)
1938719f82d3SEliot Blennerhassett {
1939719f82d3SEliot Blennerhassett 	u32 data = 0;
1940719f82d3SEliot Blennerhassett 	if (dsp_index == 0) {
1941719f82d3SEliot Blennerhassett 		/* only test for DSP0 PLD on ASI5000 card */
19423285ea10SEliot Blennerhassett 		if (pao->pci.pci_dev->subsystem_device == 0x5000) {
1943719f82d3SEliot Blennerhassett 			/* PLD is located at CE3=0x03000000 */
1944719f82d3SEliot Blennerhassett 			data = boot_loader_read_mem32(pao, dsp_index,
1945719f82d3SEliot Blennerhassett 				0x03000008);
1946719f82d3SEliot Blennerhassett 			if ((data & 0xF) != 0x5)
19473285ea10SEliot Blennerhassett 				return HPI6205_ERROR_DSP_PLD;
1948719f82d3SEliot Blennerhassett 			data = boot_loader_read_mem32(pao, dsp_index,
1949719f82d3SEliot Blennerhassett 				0x0300000C);
1950719f82d3SEliot Blennerhassett 			if ((data & 0xF) != 0xA)
19513285ea10SEliot Blennerhassett 				return HPI6205_ERROR_DSP_PLD;
1952719f82d3SEliot Blennerhassett 		}
1953719f82d3SEliot Blennerhassett 	} else if (dsp_index == 1) {
1954719f82d3SEliot Blennerhassett 		/* DSP 1 is a C6713 */
19553285ea10SEliot Blennerhassett 		if (pao->pci.pci_dev->subsystem_device == 0x8700) {
1956719f82d3SEliot Blennerhassett 			/* PLD is located at CE1=0x90000000 */
1957719f82d3SEliot Blennerhassett 			data = boot_loader_read_mem32(pao, dsp_index,
1958719f82d3SEliot Blennerhassett 				0x90000010);
1959719f82d3SEliot Blennerhassett 			if ((data & 0xFF) != 0xAA)
19603285ea10SEliot Blennerhassett 				return HPI6205_ERROR_DSP_PLD;
1961719f82d3SEliot Blennerhassett 			/* 8713 - LED on */
1962719f82d3SEliot Blennerhassett 			boot_loader_write_mem32(pao, dsp_index, 0x90000000,
1963719f82d3SEliot Blennerhassett 				0x02);
1964719f82d3SEliot Blennerhassett 		}
1965719f82d3SEliot Blennerhassett 	}
1966719f82d3SEliot Blennerhassett 	return 0;
1967719f82d3SEliot Blennerhassett }
1968719f82d3SEliot Blennerhassett 
1969719f82d3SEliot Blennerhassett /** Transfer data to or from DSP
1970719f82d3SEliot Blennerhassett  nOperation = H620_H620_HIF_SEND_DATA or H620_HIF_GET_DATA
1971719f82d3SEliot Blennerhassett */
1972719f82d3SEliot Blennerhassett static short hpi6205_transfer_data(struct hpi_adapter_obj *pao, u8 *p_data,
1973719f82d3SEliot Blennerhassett 	u32 data_size, int operation)
1974719f82d3SEliot Blennerhassett {
1975719f82d3SEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
1976719f82d3SEliot Blennerhassett 	u32 data_transferred = 0;
1977719f82d3SEliot Blennerhassett 	u16 err = 0;
1978719f82d3SEliot Blennerhassett 	u32 temp2;
1979719f82d3SEliot Blennerhassett 	struct bus_master_interface *interface = phw->p_interface_buffer;
1980719f82d3SEliot Blennerhassett 
1981719f82d3SEliot Blennerhassett 	if (!p_data)
1982deb21a23SEliot Blennerhassett 		return HPI_ERROR_INVALID_DATA_POINTER;
1983719f82d3SEliot Blennerhassett 
1984719f82d3SEliot Blennerhassett 	data_size &= ~3L;	/* round data_size down to nearest 4 bytes */
1985719f82d3SEliot Blennerhassett 
1986719f82d3SEliot Blennerhassett 	/* make sure state is IDLE */
1987719f82d3SEliot Blennerhassett 	if (!wait_dsp_ack(phw, H620_HIF_IDLE, HPI6205_TIMEOUT))
1988719f82d3SEliot Blennerhassett 		return HPI_ERROR_DSP_HARDWARE;
1989719f82d3SEliot Blennerhassett 
1990719f82d3SEliot Blennerhassett 	while (data_transferred < data_size) {
1991719f82d3SEliot Blennerhassett 		u32 this_copy = data_size - data_transferred;
1992719f82d3SEliot Blennerhassett 
1993719f82d3SEliot Blennerhassett 		if (this_copy > HPI6205_SIZEOF_DATA)
1994719f82d3SEliot Blennerhassett 			this_copy = HPI6205_SIZEOF_DATA;
1995719f82d3SEliot Blennerhassett 
1996719f82d3SEliot Blennerhassett 		if (operation == H620_HIF_SEND_DATA)
1997719f82d3SEliot Blennerhassett 			memcpy((void *)&interface->u.b_data[0],
1998719f82d3SEliot Blennerhassett 				&p_data[data_transferred], this_copy);
1999719f82d3SEliot Blennerhassett 
2000719f82d3SEliot Blennerhassett 		interface->transfer_size_in_bytes = this_copy;
2001719f82d3SEliot Blennerhassett 
2002719f82d3SEliot Blennerhassett 		/* DSP must change this back to nOperation */
2003719f82d3SEliot Blennerhassett 		interface->dsp_ack = H620_HIF_IDLE;
2004719f82d3SEliot Blennerhassett 		send_dsp_command(phw, operation);
2005719f82d3SEliot Blennerhassett 
2006719f82d3SEliot Blennerhassett 		temp2 = wait_dsp_ack(phw, operation, HPI6205_TIMEOUT);
2007719f82d3SEliot Blennerhassett 		HPI_DEBUG_LOG(DEBUG, "spun %d times for data xfer of %d\n",
2008719f82d3SEliot Blennerhassett 			HPI6205_TIMEOUT - temp2, this_copy);
2009719f82d3SEliot Blennerhassett 
2010719f82d3SEliot Blennerhassett 		if (!temp2) {
2011719f82d3SEliot Blennerhassett 			/* timed out */
2012719f82d3SEliot Blennerhassett 			HPI_DEBUG_LOG(ERROR,
20133285ea10SEliot Blennerhassett 				"Timed out waiting for " "state %d got %d\n",
2014719f82d3SEliot Blennerhassett 				operation, interface->dsp_ack);
2015719f82d3SEliot Blennerhassett 
2016719f82d3SEliot Blennerhassett 			break;
2017719f82d3SEliot Blennerhassett 		}
2018719f82d3SEliot Blennerhassett 		if (operation == H620_HIF_GET_DATA)
2019719f82d3SEliot Blennerhassett 			memcpy(&p_data[data_transferred],
2020719f82d3SEliot Blennerhassett 				(void *)&interface->u.b_data[0], this_copy);
2021719f82d3SEliot Blennerhassett 
2022719f82d3SEliot Blennerhassett 		data_transferred += this_copy;
2023719f82d3SEliot Blennerhassett 	}
2024719f82d3SEliot Blennerhassett 	if (interface->dsp_ack != operation)
2025719f82d3SEliot Blennerhassett 		HPI_DEBUG_LOG(DEBUG, "interface->dsp_ack=%d, expected %d\n",
2026719f82d3SEliot Blennerhassett 			interface->dsp_ack, operation);
2027719f82d3SEliot Blennerhassett 	/*                      err=HPI_ERROR_DSP_HARDWARE; */
2028719f82d3SEliot Blennerhassett 
2029719f82d3SEliot Blennerhassett 	send_dsp_command(phw, H620_HIF_IDLE);
2030719f82d3SEliot Blennerhassett 
2031719f82d3SEliot Blennerhassett 	return err;
2032719f82d3SEliot Blennerhassett }
2033719f82d3SEliot Blennerhassett 
2034719f82d3SEliot Blennerhassett /* wait for up to timeout_us microseconds for the DSP
2035719f82d3SEliot Blennerhassett    to signal state by DMA into dwDspAck
2036719f82d3SEliot Blennerhassett */
2037719f82d3SEliot Blennerhassett static int wait_dsp_ack(struct hpi_hw_obj *phw, int state, int timeout_us)
2038719f82d3SEliot Blennerhassett {
2039719f82d3SEliot Blennerhassett 	struct bus_master_interface *interface = phw->p_interface_buffer;
2040719f82d3SEliot Blennerhassett 	int t = timeout_us / 4;
2041719f82d3SEliot Blennerhassett 
2042719f82d3SEliot Blennerhassett 	rmb();	/* ensure interface->dsp_ack is up to date */
2043719f82d3SEliot Blennerhassett 	while ((interface->dsp_ack != state) && --t) {
2044719f82d3SEliot Blennerhassett 		hpios_delay_micro_seconds(4);
2045719f82d3SEliot Blennerhassett 		rmb();	/* DSP changes dsp_ack by DMA */
2046719f82d3SEliot Blennerhassett 	}
2047719f82d3SEliot Blennerhassett 
2048719f82d3SEliot Blennerhassett 	/*HPI_DEBUG_LOG(VERBOSE, "Spun %d for %d\n", timeout_us/4-t, state); */
2049719f82d3SEliot Blennerhassett 	return t * 4;
2050719f82d3SEliot Blennerhassett }
2051719f82d3SEliot Blennerhassett 
2052719f82d3SEliot Blennerhassett /* set the busmaster interface to cmd, then interrupt the DSP */
2053719f82d3SEliot Blennerhassett static void send_dsp_command(struct hpi_hw_obj *phw, int cmd)
2054719f82d3SEliot Blennerhassett {
2055719f82d3SEliot Blennerhassett 	struct bus_master_interface *interface = phw->p_interface_buffer;
2056719f82d3SEliot Blennerhassett 	u32 r;
2057719f82d3SEliot Blennerhassett 
2058719f82d3SEliot Blennerhassett 	interface->host_cmd = cmd;
2059719f82d3SEliot Blennerhassett 	wmb();	/* DSP gets state by DMA, make sure it is written to memory */
2060719f82d3SEliot Blennerhassett 	/* before we interrupt the DSP */
2061719f82d3SEliot Blennerhassett 	r = ioread32(phw->prHDCR);
2062719f82d3SEliot Blennerhassett 	r |= (u32)C6205_HDCR_DSPINT;
2063719f82d3SEliot Blennerhassett 	iowrite32(r, phw->prHDCR);
2064719f82d3SEliot Blennerhassett 	r &= ~(u32)C6205_HDCR_DSPINT;
2065719f82d3SEliot Blennerhassett 	iowrite32(r, phw->prHDCR);
2066719f82d3SEliot Blennerhassett }
2067719f82d3SEliot Blennerhassett 
2068719f82d3SEliot Blennerhassett static unsigned int message_count;
2069719f82d3SEliot Blennerhassett 
2070719f82d3SEliot Blennerhassett static u16 message_response_sequence(struct hpi_adapter_obj *pao,
2071719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
2072719f82d3SEliot Blennerhassett {
2073719f82d3SEliot Blennerhassett 	u32 time_out, time_out2;
2074719f82d3SEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
2075719f82d3SEliot Blennerhassett 	struct bus_master_interface *interface = phw->p_interface_buffer;
2076719f82d3SEliot Blennerhassett 	u16 err = 0;
2077719f82d3SEliot Blennerhassett 
2078719f82d3SEliot Blennerhassett 	message_count++;
2079c6c2c9abSEliot Blennerhassett 	if (phm->size > sizeof(interface->u.message_buffer)) {
2080deb21a23SEliot Blennerhassett 		phr->error = HPI_ERROR_MESSAGE_BUFFER_TOO_SMALL;
2081c6c2c9abSEliot Blennerhassett 		phr->specific_error = sizeof(interface->u.message_buffer);
20823285ea10SEliot Blennerhassett 		phr->size = sizeof(struct hpi_response_header);
20833285ea10SEliot Blennerhassett 		HPI_DEBUG_LOG(ERROR,
2084a2800300STakashi Iwai 			"message len %d too big for buffer %zd \n", phm->size,
2085c6c2c9abSEliot Blennerhassett 			sizeof(interface->u.message_buffer));
20863285ea10SEliot Blennerhassett 		return 0;
20873285ea10SEliot Blennerhassett 	}
20883285ea10SEliot Blennerhassett 
2089719f82d3SEliot Blennerhassett 	/* Assume buffer of type struct bus_master_interface
2090719f82d3SEliot Blennerhassett 	   is allocated "noncacheable" */
2091719f82d3SEliot Blennerhassett 
2092719f82d3SEliot Blennerhassett 	if (!wait_dsp_ack(phw, H620_HIF_IDLE, HPI6205_TIMEOUT)) {
2093719f82d3SEliot Blennerhassett 		HPI_DEBUG_LOG(DEBUG, "timeout waiting for idle\n");
20943285ea10SEliot Blennerhassett 		return HPI6205_ERROR_MSG_RESP_IDLE_TIMEOUT;
2095719f82d3SEliot Blennerhassett 	}
20963285ea10SEliot Blennerhassett 
20973285ea10SEliot Blennerhassett 	memcpy(&interface->u.message_buffer, phm, phm->size);
2098719f82d3SEliot Blennerhassett 	/* signal we want a response */
2099719f82d3SEliot Blennerhassett 	send_dsp_command(phw, H620_HIF_GET_RESP);
2100719f82d3SEliot Blennerhassett 
2101719f82d3SEliot Blennerhassett 	time_out2 = wait_dsp_ack(phw, H620_HIF_GET_RESP, HPI6205_TIMEOUT);
2102719f82d3SEliot Blennerhassett 
21033285ea10SEliot Blennerhassett 	if (!time_out2) {
2104719f82d3SEliot Blennerhassett 		HPI_DEBUG_LOG(ERROR,
21053285ea10SEliot Blennerhassett 			"(%u) Timed out waiting for " "GET_RESP state [%x]\n",
2106719f82d3SEliot Blennerhassett 			message_count, interface->dsp_ack);
2107719f82d3SEliot Blennerhassett 	} else {
2108719f82d3SEliot Blennerhassett 		HPI_DEBUG_LOG(VERBOSE,
2109719f82d3SEliot Blennerhassett 			"(%u) transition to GET_RESP after %u\n",
2110719f82d3SEliot Blennerhassett 			message_count, HPI6205_TIMEOUT - time_out2);
2111719f82d3SEliot Blennerhassett 	}
2112719f82d3SEliot Blennerhassett 	/* spin waiting on HIF interrupt flag (end of msg process) */
2113719f82d3SEliot Blennerhassett 	time_out = HPI6205_TIMEOUT;
2114719f82d3SEliot Blennerhassett 
2115719f82d3SEliot Blennerhassett 	/* read the result */
21163285ea10SEliot Blennerhassett 	if (time_out) {
2117c6c2c9abSEliot Blennerhassett 		if (interface->u.response_buffer.response.size <= phr->size)
21183285ea10SEliot Blennerhassett 			memcpy(phr, &interface->u.response_buffer,
2119c6c2c9abSEliot Blennerhassett 				interface->u.response_buffer.response.size);
21203285ea10SEliot Blennerhassett 		else {
21213285ea10SEliot Blennerhassett 			HPI_DEBUG_LOG(ERROR,
21223285ea10SEliot Blennerhassett 				"response len %d too big for buffer %d\n",
2123c6c2c9abSEliot Blennerhassett 				interface->u.response_buffer.response.size,
2124c6c2c9abSEliot Blennerhassett 				phr->size);
21253285ea10SEliot Blennerhassett 			memcpy(phr, &interface->u.response_buffer,
21263285ea10SEliot Blennerhassett 				sizeof(struct hpi_response_header));
21273285ea10SEliot Blennerhassett 			phr->error = HPI_ERROR_RESPONSE_BUFFER_TOO_SMALL;
21283285ea10SEliot Blennerhassett 			phr->specific_error =
2129c6c2c9abSEliot Blennerhassett 				interface->u.response_buffer.response.size;
21303285ea10SEliot Blennerhassett 			phr->size = sizeof(struct hpi_response_header);
21313285ea10SEliot Blennerhassett 		}
21323285ea10SEliot Blennerhassett 	}
2133719f82d3SEliot Blennerhassett 	/* set interface back to idle */
2134719f82d3SEliot Blennerhassett 	send_dsp_command(phw, H620_HIF_IDLE);
2135719f82d3SEliot Blennerhassett 
21363285ea10SEliot Blennerhassett 	if (!time_out || !time_out2) {
2137719f82d3SEliot Blennerhassett 		HPI_DEBUG_LOG(DEBUG, "something timed out!\n");
21383285ea10SEliot Blennerhassett 		return HPI6205_ERROR_MSG_RESP_TIMEOUT;
2139719f82d3SEliot Blennerhassett 	}
2140719f82d3SEliot Blennerhassett 	/* special case for adapter close - */
2141719f82d3SEliot Blennerhassett 	/* wait for the DSP to indicate it is idle */
2142719f82d3SEliot Blennerhassett 	if (phm->function == HPI_ADAPTER_CLOSE) {
2143719f82d3SEliot Blennerhassett 		if (!wait_dsp_ack(phw, H620_HIF_IDLE, HPI6205_TIMEOUT)) {
2144719f82d3SEliot Blennerhassett 			HPI_DEBUG_LOG(DEBUG,
21453285ea10SEliot Blennerhassett 				"Timeout waiting for idle "
2146719f82d3SEliot Blennerhassett 				"(on adapter_close)\n");
21473285ea10SEliot Blennerhassett 			return HPI6205_ERROR_MSG_RESP_IDLE_TIMEOUT;
2148719f82d3SEliot Blennerhassett 		}
2149719f82d3SEliot Blennerhassett 	}
2150719f82d3SEliot Blennerhassett 	err = hpi_validate_response(phm, phr);
2151719f82d3SEliot Blennerhassett 	return err;
2152719f82d3SEliot Blennerhassett }
2153719f82d3SEliot Blennerhassett 
2154719f82d3SEliot Blennerhassett static void hw_message(struct hpi_adapter_obj *pao, struct hpi_message *phm,
2155719f82d3SEliot Blennerhassett 	struct hpi_response *phr)
2156719f82d3SEliot Blennerhassett {
2157719f82d3SEliot Blennerhassett 
2158719f82d3SEliot Blennerhassett 	u16 err = 0;
2159719f82d3SEliot Blennerhassett 
2160719f82d3SEliot Blennerhassett 	hpios_dsplock_lock(pao);
2161719f82d3SEliot Blennerhassett 
2162719f82d3SEliot Blennerhassett 	err = message_response_sequence(pao, phm, phr);
2163719f82d3SEliot Blennerhassett 
2164719f82d3SEliot Blennerhassett 	/* maybe an error response */
2165719f82d3SEliot Blennerhassett 	if (err) {
2166719f82d3SEliot Blennerhassett 		/* something failed in the HPI/DSP interface */
21670a00044dSEliot Blennerhassett 		if (err >= HPI_ERROR_BACKEND_BASE) {
21680a00044dSEliot Blennerhassett 			phr->error = HPI_ERROR_DSP_COMMUNICATION;
21690a00044dSEliot Blennerhassett 			phr->specific_error = err;
21700a00044dSEliot Blennerhassett 		} else {
2171719f82d3SEliot Blennerhassett 			phr->error = err;
21720a00044dSEliot Blennerhassett 		}
21730a00044dSEliot Blennerhassett 
2174719f82d3SEliot Blennerhassett 		pao->dsp_crashed++;
2175719f82d3SEliot Blennerhassett 
2176719f82d3SEliot Blennerhassett 		/* just the header of the response is valid */
2177719f82d3SEliot Blennerhassett 		phr->size = sizeof(struct hpi_response_header);
2178719f82d3SEliot Blennerhassett 		goto err;
2179719f82d3SEliot Blennerhassett 	} else
2180719f82d3SEliot Blennerhassett 		pao->dsp_crashed = 0;
2181719f82d3SEliot Blennerhassett 
2182719f82d3SEliot Blennerhassett 	if (phr->error != 0)	/* something failed in the DSP */
2183719f82d3SEliot Blennerhassett 		goto err;
2184719f82d3SEliot Blennerhassett 
2185719f82d3SEliot Blennerhassett 	switch (phm->function) {
2186719f82d3SEliot Blennerhassett 	case HPI_OSTREAM_WRITE:
2187719f82d3SEliot Blennerhassett 	case HPI_ISTREAM_ANC_WRITE:
2188719f82d3SEliot Blennerhassett 		err = hpi6205_transfer_data(pao, phm->u.d.u.data.pb_data,
2189719f82d3SEliot Blennerhassett 			phm->u.d.u.data.data_size, H620_HIF_SEND_DATA);
2190719f82d3SEliot Blennerhassett 		break;
2191719f82d3SEliot Blennerhassett 
2192719f82d3SEliot Blennerhassett 	case HPI_ISTREAM_READ:
2193719f82d3SEliot Blennerhassett 	case HPI_OSTREAM_ANC_READ:
2194719f82d3SEliot Blennerhassett 		err = hpi6205_transfer_data(pao, phm->u.d.u.data.pb_data,
2195719f82d3SEliot Blennerhassett 			phm->u.d.u.data.data_size, H620_HIF_GET_DATA);
2196719f82d3SEliot Blennerhassett 		break;
2197719f82d3SEliot Blennerhassett 
2198719f82d3SEliot Blennerhassett 	}
2199719f82d3SEliot Blennerhassett 	phr->error = err;
2200719f82d3SEliot Blennerhassett 
2201719f82d3SEliot Blennerhassett err:
2202719f82d3SEliot Blennerhassett 	hpios_dsplock_unlock(pao);
2203719f82d3SEliot Blennerhassett 
2204719f82d3SEliot Blennerhassett 	return;
2205719f82d3SEliot Blennerhassett }
2206