xref: /openbmc/linux/sound/pci/asihpi/hpi6205.c (revision 0a00044d26489c1907b9e8b3e633e6b9a6d2200e)
1719f82d3SEliot Blennerhassett /******************************************************************************
2719f82d3SEliot Blennerhassett 
3719f82d3SEliot Blennerhassett     AudioScience HPI driver
4719f82d3SEliot Blennerhassett     Copyright (C) 1997-2010  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 consistent_dma_area h_async_event_buffer;
131719f82d3SEliot Blennerhassett /*      struct hpi_control_cache_single *pControlCache; */
132719f82d3SEliot Blennerhassett 	struct hpi_async_event *p_async_event_buffer;
133719f82d3SEliot Blennerhassett 	struct hpi_control_cache *p_cache;
134719f82d3SEliot Blennerhassett };
135719f82d3SEliot Blennerhassett 
136719f82d3SEliot Blennerhassett /*****************************************************************************/
137719f82d3SEliot Blennerhassett /* local prototypes */
138719f82d3SEliot Blennerhassett 
139719f82d3SEliot Blennerhassett #define check_before_bbm_copy(status, p_bbm_data, l_first_write, l_second_write)
140719f82d3SEliot Blennerhassett 
141719f82d3SEliot Blennerhassett static int wait_dsp_ack(struct hpi_hw_obj *phw, int state, int timeout_us);
142719f82d3SEliot Blennerhassett 
143719f82d3SEliot Blennerhassett static void send_dsp_command(struct hpi_hw_obj *phw, int cmd);
144719f82d3SEliot Blennerhassett 
145719f82d3SEliot Blennerhassett static u16 adapter_boot_load_dsp(struct hpi_adapter_obj *pao,
146719f82d3SEliot Blennerhassett 	u32 *pos_error_code);
147719f82d3SEliot Blennerhassett 
148719f82d3SEliot Blennerhassett static u16 message_response_sequence(struct hpi_adapter_obj *pao,
149719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr);
150719f82d3SEliot Blennerhassett 
151719f82d3SEliot Blennerhassett static void hw_message(struct hpi_adapter_obj *pao, struct hpi_message *phm,
152719f82d3SEliot Blennerhassett 	struct hpi_response *phr);
153719f82d3SEliot Blennerhassett 
154719f82d3SEliot Blennerhassett #define HPI6205_TIMEOUT 1000000
155719f82d3SEliot Blennerhassett 
156719f82d3SEliot Blennerhassett static void subsys_create_adapter(struct hpi_message *phm,
157719f82d3SEliot Blennerhassett 	struct hpi_response *phr);
158719f82d3SEliot Blennerhassett static void subsys_delete_adapter(struct hpi_message *phm,
159719f82d3SEliot Blennerhassett 	struct hpi_response *phr);
160719f82d3SEliot Blennerhassett 
161719f82d3SEliot Blennerhassett static u16 create_adapter_obj(struct hpi_adapter_obj *pao,
162719f82d3SEliot Blennerhassett 	u32 *pos_error_code);
163719f82d3SEliot Blennerhassett 
164719f82d3SEliot Blennerhassett static void delete_adapter_obj(struct hpi_adapter_obj *pao);
165719f82d3SEliot Blennerhassett 
166719f82d3SEliot Blennerhassett static void outstream_host_buffer_allocate(struct hpi_adapter_obj *pao,
167719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr);
168719f82d3SEliot Blennerhassett 
169719f82d3SEliot Blennerhassett static void outstream_host_buffer_get_info(struct hpi_adapter_obj *pao,
170719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr);
171719f82d3SEliot Blennerhassett 
172719f82d3SEliot Blennerhassett static void outstream_host_buffer_free(struct hpi_adapter_obj *pao,
173719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr);
174719f82d3SEliot Blennerhassett static void outstream_write(struct hpi_adapter_obj *pao,
175719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr);
176719f82d3SEliot Blennerhassett 
177719f82d3SEliot Blennerhassett static void outstream_get_info(struct hpi_adapter_obj *pao,
178719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr);
179719f82d3SEliot Blennerhassett 
180719f82d3SEliot Blennerhassett static void outstream_start(struct hpi_adapter_obj *pao,
181719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr);
182719f82d3SEliot Blennerhassett 
183719f82d3SEliot Blennerhassett static void outstream_open(struct hpi_adapter_obj *pao,
184719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr);
185719f82d3SEliot Blennerhassett 
186719f82d3SEliot Blennerhassett static void outstream_reset(struct hpi_adapter_obj *pao,
187719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr);
188719f82d3SEliot Blennerhassett 
189719f82d3SEliot Blennerhassett static void instream_host_buffer_allocate(struct hpi_adapter_obj *pao,
190719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr);
191719f82d3SEliot Blennerhassett 
192719f82d3SEliot Blennerhassett static void instream_host_buffer_get_info(struct hpi_adapter_obj *pao,
193719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr);
194719f82d3SEliot Blennerhassett 
195719f82d3SEliot Blennerhassett static void instream_host_buffer_free(struct hpi_adapter_obj *pao,
196719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr);
197719f82d3SEliot Blennerhassett 
198719f82d3SEliot Blennerhassett static void instream_read(struct hpi_adapter_obj *pao,
199719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr);
200719f82d3SEliot Blennerhassett 
201719f82d3SEliot Blennerhassett static void instream_get_info(struct hpi_adapter_obj *pao,
202719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr);
203719f82d3SEliot Blennerhassett 
204719f82d3SEliot Blennerhassett static void instream_start(struct hpi_adapter_obj *pao,
205719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr);
206719f82d3SEliot Blennerhassett 
207719f82d3SEliot Blennerhassett static u32 boot_loader_read_mem32(struct hpi_adapter_obj *pao, int dsp_index,
208719f82d3SEliot Blennerhassett 	u32 address);
209719f82d3SEliot Blennerhassett 
2103285ea10SEliot Blennerhassett static void boot_loader_write_mem32(struct hpi_adapter_obj *pao,
2113285ea10SEliot Blennerhassett 	int dsp_index, u32 address, u32 data);
212719f82d3SEliot Blennerhassett 
213719f82d3SEliot Blennerhassett static u16 boot_loader_config_emif(struct hpi_adapter_obj *pao,
214719f82d3SEliot Blennerhassett 	int dsp_index);
215719f82d3SEliot Blennerhassett 
216719f82d3SEliot Blennerhassett static u16 boot_loader_test_memory(struct hpi_adapter_obj *pao, int dsp_index,
217719f82d3SEliot Blennerhassett 	u32 address, u32 length);
218719f82d3SEliot Blennerhassett 
219719f82d3SEliot Blennerhassett static u16 boot_loader_test_internal_memory(struct hpi_adapter_obj *pao,
220719f82d3SEliot Blennerhassett 	int dsp_index);
221719f82d3SEliot Blennerhassett 
222719f82d3SEliot Blennerhassett static u16 boot_loader_test_external_memory(struct hpi_adapter_obj *pao,
223719f82d3SEliot Blennerhassett 	int dsp_index);
224719f82d3SEliot Blennerhassett 
225719f82d3SEliot Blennerhassett static u16 boot_loader_test_pld(struct hpi_adapter_obj *pao, int dsp_index);
226719f82d3SEliot Blennerhassett 
227719f82d3SEliot Blennerhassett /*****************************************************************************/
228719f82d3SEliot Blennerhassett 
229719f82d3SEliot Blennerhassett static void subsys_message(struct hpi_message *phm, struct hpi_response *phr)
230719f82d3SEliot Blennerhassett {
231719f82d3SEliot Blennerhassett 	switch (phm->function) {
232719f82d3SEliot Blennerhassett 	case HPI_SUBSYS_CREATE_ADAPTER:
233719f82d3SEliot Blennerhassett 		subsys_create_adapter(phm, phr);
234719f82d3SEliot Blennerhassett 		break;
235719f82d3SEliot Blennerhassett 	case HPI_SUBSYS_DELETE_ADAPTER:
236719f82d3SEliot Blennerhassett 		subsys_delete_adapter(phm, phr);
237719f82d3SEliot Blennerhassett 		break;
238719f82d3SEliot Blennerhassett 	default:
239719f82d3SEliot Blennerhassett 		phr->error = HPI_ERROR_INVALID_FUNC;
240719f82d3SEliot Blennerhassett 		break;
241719f82d3SEliot Blennerhassett 	}
242719f82d3SEliot Blennerhassett }
243719f82d3SEliot Blennerhassett 
244719f82d3SEliot Blennerhassett static void control_message(struct hpi_adapter_obj *pao,
245719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
246719f82d3SEliot Blennerhassett {
247719f82d3SEliot Blennerhassett 
248719f82d3SEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
2493285ea10SEliot Blennerhassett 	u16 pending_cache_error = 0;
250719f82d3SEliot Blennerhassett 
251719f82d3SEliot Blennerhassett 	switch (phm->function) {
252719f82d3SEliot Blennerhassett 	case HPI_CONTROL_GET_STATE:
253719f82d3SEliot Blennerhassett 		if (pao->has_control_cache) {
2543285ea10SEliot Blennerhassett 			rmb();	/* make sure we see updates DMAed from DSP */
2553285ea10SEliot Blennerhassett 			if (hpi_check_control_cache(phw->p_cache, phm, phr)) {
256719f82d3SEliot Blennerhassett 				break;
2573285ea10SEliot Blennerhassett 			} else if (phm->u.c.attribute == HPI_METER_PEAK) {
2583285ea10SEliot Blennerhassett 				pending_cache_error =
2593285ea10SEliot Blennerhassett 					HPI_ERROR_CONTROL_CACHING;
2603285ea10SEliot Blennerhassett 			}
261719f82d3SEliot Blennerhassett 		}
262719f82d3SEliot Blennerhassett 		hw_message(pao, phm, phr);
2633285ea10SEliot Blennerhassett 		if (pending_cache_error && !phr->error)
2643285ea10SEliot Blennerhassett 			phr->error = pending_cache_error;
265719f82d3SEliot Blennerhassett 		break;
266719f82d3SEliot Blennerhassett 	case HPI_CONTROL_GET_INFO:
267719f82d3SEliot Blennerhassett 		hw_message(pao, phm, phr);
268719f82d3SEliot Blennerhassett 		break;
269719f82d3SEliot Blennerhassett 	case HPI_CONTROL_SET_STATE:
270719f82d3SEliot Blennerhassett 		hw_message(pao, phm, phr);
271719f82d3SEliot Blennerhassett 		if (pao->has_control_cache)
2723285ea10SEliot Blennerhassett 			hpi_cmn_control_cache_sync_to_msg(phw->p_cache, phm,
2733285ea10SEliot Blennerhassett 				phr);
274719f82d3SEliot Blennerhassett 		break;
275719f82d3SEliot Blennerhassett 	default:
276719f82d3SEliot Blennerhassett 		phr->error = HPI_ERROR_INVALID_FUNC;
277719f82d3SEliot Blennerhassett 		break;
278719f82d3SEliot Blennerhassett 	}
279719f82d3SEliot Blennerhassett }
280719f82d3SEliot Blennerhassett 
281719f82d3SEliot Blennerhassett static void adapter_message(struct hpi_adapter_obj *pao,
282719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
283719f82d3SEliot Blennerhassett {
284719f82d3SEliot Blennerhassett 	switch (phm->function) {
285719f82d3SEliot Blennerhassett 	default:
286719f82d3SEliot Blennerhassett 		hw_message(pao, phm, phr);
287719f82d3SEliot Blennerhassett 		break;
288719f82d3SEliot Blennerhassett 	}
289719f82d3SEliot Blennerhassett }
290719f82d3SEliot Blennerhassett 
291719f82d3SEliot Blennerhassett static void outstream_message(struct hpi_adapter_obj *pao,
292719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
293719f82d3SEliot Blennerhassett {
294719f82d3SEliot Blennerhassett 
295719f82d3SEliot Blennerhassett 	if (phm->obj_index >= HPI_MAX_STREAMS) {
296deb21a23SEliot Blennerhassett 		phr->error = HPI_ERROR_INVALID_OBJ_INDEX;
297719f82d3SEliot Blennerhassett 		HPI_DEBUG_LOG(WARNING,
2983285ea10SEliot Blennerhassett 			"Message referencing invalid stream %d "
299719f82d3SEliot Blennerhassett 			"on adapter index %d\n", phm->obj_index,
300719f82d3SEliot Blennerhassett 			phm->adapter_index);
301719f82d3SEliot Blennerhassett 		return;
302719f82d3SEliot Blennerhassett 	}
303719f82d3SEliot Blennerhassett 
304719f82d3SEliot Blennerhassett 	switch (phm->function) {
305719f82d3SEliot Blennerhassett 	case HPI_OSTREAM_WRITE:
306719f82d3SEliot Blennerhassett 		outstream_write(pao, phm, phr);
307719f82d3SEliot Blennerhassett 		break;
308719f82d3SEliot Blennerhassett 	case HPI_OSTREAM_GET_INFO:
309719f82d3SEliot Blennerhassett 		outstream_get_info(pao, phm, phr);
310719f82d3SEliot Blennerhassett 		break;
311719f82d3SEliot Blennerhassett 	case HPI_OSTREAM_HOSTBUFFER_ALLOC:
312719f82d3SEliot Blennerhassett 		outstream_host_buffer_allocate(pao, phm, phr);
313719f82d3SEliot Blennerhassett 		break;
314719f82d3SEliot Blennerhassett 	case HPI_OSTREAM_HOSTBUFFER_GET_INFO:
315719f82d3SEliot Blennerhassett 		outstream_host_buffer_get_info(pao, phm, phr);
316719f82d3SEliot Blennerhassett 		break;
317719f82d3SEliot Blennerhassett 	case HPI_OSTREAM_HOSTBUFFER_FREE:
318719f82d3SEliot Blennerhassett 		outstream_host_buffer_free(pao, phm, phr);
319719f82d3SEliot Blennerhassett 		break;
320719f82d3SEliot Blennerhassett 	case HPI_OSTREAM_START:
321719f82d3SEliot Blennerhassett 		outstream_start(pao, phm, phr);
322719f82d3SEliot Blennerhassett 		break;
323719f82d3SEliot Blennerhassett 	case HPI_OSTREAM_OPEN:
324719f82d3SEliot Blennerhassett 		outstream_open(pao, phm, phr);
325719f82d3SEliot Blennerhassett 		break;
326719f82d3SEliot Blennerhassett 	case HPI_OSTREAM_RESET:
327719f82d3SEliot Blennerhassett 		outstream_reset(pao, phm, phr);
328719f82d3SEliot Blennerhassett 		break;
329719f82d3SEliot Blennerhassett 	default:
330719f82d3SEliot Blennerhassett 		hw_message(pao, phm, phr);
331719f82d3SEliot Blennerhassett 		break;
332719f82d3SEliot Blennerhassett 	}
333719f82d3SEliot Blennerhassett }
334719f82d3SEliot Blennerhassett 
335719f82d3SEliot Blennerhassett static void instream_message(struct hpi_adapter_obj *pao,
336719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
337719f82d3SEliot Blennerhassett {
338719f82d3SEliot Blennerhassett 
339719f82d3SEliot Blennerhassett 	if (phm->obj_index >= HPI_MAX_STREAMS) {
340deb21a23SEliot Blennerhassett 		phr->error = HPI_ERROR_INVALID_OBJ_INDEX;
341719f82d3SEliot Blennerhassett 		HPI_DEBUG_LOG(WARNING,
3423285ea10SEliot Blennerhassett 			"Message referencing invalid stream %d "
343719f82d3SEliot Blennerhassett 			"on adapter index %d\n", phm->obj_index,
344719f82d3SEliot Blennerhassett 			phm->adapter_index);
345719f82d3SEliot Blennerhassett 		return;
346719f82d3SEliot Blennerhassett 	}
347719f82d3SEliot Blennerhassett 
348719f82d3SEliot Blennerhassett 	switch (phm->function) {
349719f82d3SEliot Blennerhassett 	case HPI_ISTREAM_READ:
350719f82d3SEliot Blennerhassett 		instream_read(pao, phm, phr);
351719f82d3SEliot Blennerhassett 		break;
352719f82d3SEliot Blennerhassett 	case HPI_ISTREAM_GET_INFO:
353719f82d3SEliot Blennerhassett 		instream_get_info(pao, phm, phr);
354719f82d3SEliot Blennerhassett 		break;
355719f82d3SEliot Blennerhassett 	case HPI_ISTREAM_HOSTBUFFER_ALLOC:
356719f82d3SEliot Blennerhassett 		instream_host_buffer_allocate(pao, phm, phr);
357719f82d3SEliot Blennerhassett 		break;
358719f82d3SEliot Blennerhassett 	case HPI_ISTREAM_HOSTBUFFER_GET_INFO:
359719f82d3SEliot Blennerhassett 		instream_host_buffer_get_info(pao, phm, phr);
360719f82d3SEliot Blennerhassett 		break;
361719f82d3SEliot Blennerhassett 	case HPI_ISTREAM_HOSTBUFFER_FREE:
362719f82d3SEliot Blennerhassett 		instream_host_buffer_free(pao, phm, phr);
363719f82d3SEliot Blennerhassett 		break;
364719f82d3SEliot Blennerhassett 	case HPI_ISTREAM_START:
365719f82d3SEliot Blennerhassett 		instream_start(pao, phm, phr);
366719f82d3SEliot Blennerhassett 		break;
367719f82d3SEliot Blennerhassett 	default:
368719f82d3SEliot Blennerhassett 		hw_message(pao, phm, phr);
369719f82d3SEliot Blennerhassett 		break;
370719f82d3SEliot Blennerhassett 	}
371719f82d3SEliot Blennerhassett }
372719f82d3SEliot Blennerhassett 
373719f82d3SEliot Blennerhassett /*****************************************************************************/
374719f82d3SEliot Blennerhassett /** Entry point to this HPI backend
375719f82d3SEliot Blennerhassett  * All calls to the HPI start here
376719f82d3SEliot Blennerhassett  */
377719f82d3SEliot Blennerhassett void HPI_6205(struct hpi_message *phm, struct hpi_response *phr)
378719f82d3SEliot Blennerhassett {
379719f82d3SEliot Blennerhassett 	struct hpi_adapter_obj *pao = NULL;
380719f82d3SEliot Blennerhassett 
381719f82d3SEliot Blennerhassett 	/* subsytem messages are processed by every HPI.
382719f82d3SEliot Blennerhassett 	 * All other messages are ignored unless the adapter index matches
383719f82d3SEliot Blennerhassett 	 * an adapter in the HPI
384719f82d3SEliot Blennerhassett 	 */
3853285ea10SEliot Blennerhassett 	/* HPI_DEBUG_LOG(DEBUG, "HPI Obj=%d, Func=%d\n", phm->wObject,
3863285ea10SEliot Blennerhassett 	   phm->wFunction); */
387719f82d3SEliot Blennerhassett 
388719f82d3SEliot Blennerhassett 	/* if Dsp has crashed then do not communicate with it any more */
389719f82d3SEliot Blennerhassett 	if (phm->object != HPI_OBJ_SUBSYSTEM) {
390719f82d3SEliot Blennerhassett 		pao = hpi_find_adapter(phm->adapter_index);
391719f82d3SEliot Blennerhassett 		if (!pao) {
392719f82d3SEliot Blennerhassett 			HPI_DEBUG_LOG(DEBUG,
393719f82d3SEliot Blennerhassett 				" %d,%d refused, for another HPI?\n",
394719f82d3SEliot Blennerhassett 				phm->object, phm->function);
395719f82d3SEliot Blennerhassett 			return;
396719f82d3SEliot Blennerhassett 		}
397719f82d3SEliot Blennerhassett 
398719f82d3SEliot Blennerhassett 		if ((pao->dsp_crashed >= 10)
399719f82d3SEliot Blennerhassett 			&& (phm->function != HPI_ADAPTER_DEBUG_READ)) {
400719f82d3SEliot Blennerhassett 			/* allow last resort debug read even after crash */
401719f82d3SEliot Blennerhassett 			hpi_init_response(phr, phm->object, phm->function,
402719f82d3SEliot Blennerhassett 				HPI_ERROR_DSP_HARDWARE);
403719f82d3SEliot Blennerhassett 			HPI_DEBUG_LOG(WARNING, " %d,%d dsp crashed.\n",
404719f82d3SEliot Blennerhassett 				phm->object, phm->function);
405719f82d3SEliot Blennerhassett 			return;
406719f82d3SEliot Blennerhassett 		}
407719f82d3SEliot Blennerhassett 	}
408719f82d3SEliot Blennerhassett 
409719f82d3SEliot Blennerhassett 	/* Init default response  */
410719f82d3SEliot Blennerhassett 	if (phm->function != HPI_SUBSYS_CREATE_ADAPTER)
4113285ea10SEliot Blennerhassett 		phr->error = HPI_ERROR_PROCESSING_MESSAGE;
412719f82d3SEliot Blennerhassett 
413719f82d3SEliot Blennerhassett 	HPI_DEBUG_LOG(VERBOSE, "start of switch\n");
414719f82d3SEliot Blennerhassett 	switch (phm->type) {
415719f82d3SEliot Blennerhassett 	case HPI_TYPE_MESSAGE:
416719f82d3SEliot Blennerhassett 		switch (phm->object) {
417719f82d3SEliot Blennerhassett 		case HPI_OBJ_SUBSYSTEM:
418719f82d3SEliot Blennerhassett 			subsys_message(phm, phr);
419719f82d3SEliot Blennerhassett 			break;
420719f82d3SEliot Blennerhassett 
421719f82d3SEliot Blennerhassett 		case HPI_OBJ_ADAPTER:
422719f82d3SEliot Blennerhassett 			adapter_message(pao, phm, phr);
423719f82d3SEliot Blennerhassett 			break;
424719f82d3SEliot Blennerhassett 
425719f82d3SEliot Blennerhassett 		case HPI_OBJ_CONTROLEX:
426719f82d3SEliot Blennerhassett 		case HPI_OBJ_CONTROL:
427719f82d3SEliot Blennerhassett 			control_message(pao, phm, phr);
428719f82d3SEliot Blennerhassett 			break;
429719f82d3SEliot Blennerhassett 
430719f82d3SEliot Blennerhassett 		case HPI_OBJ_OSTREAM:
431719f82d3SEliot Blennerhassett 			outstream_message(pao, phm, phr);
432719f82d3SEliot Blennerhassett 			break;
433719f82d3SEliot Blennerhassett 
434719f82d3SEliot Blennerhassett 		case HPI_OBJ_ISTREAM:
435719f82d3SEliot Blennerhassett 			instream_message(pao, phm, phr);
436719f82d3SEliot Blennerhassett 			break;
437719f82d3SEliot Blennerhassett 
438719f82d3SEliot Blennerhassett 		default:
439719f82d3SEliot Blennerhassett 			hw_message(pao, phm, phr);
440719f82d3SEliot Blennerhassett 			break;
441719f82d3SEliot Blennerhassett 		}
442719f82d3SEliot Blennerhassett 		break;
443719f82d3SEliot Blennerhassett 
444719f82d3SEliot Blennerhassett 	default:
445719f82d3SEliot Blennerhassett 		phr->error = HPI_ERROR_INVALID_TYPE;
446719f82d3SEliot Blennerhassett 		break;
447719f82d3SEliot Blennerhassett 	}
448719f82d3SEliot Blennerhassett }
449719f82d3SEliot 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) {
472719f82d3SEliot Blennerhassett 		HPI_DEBUG_LOG(ERROR, "cant 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);
481*0a00044dSEliot Blennerhassett 		if (err >= HPI_ERROR_BACKEND_BASE) {
482*0a00044dSEliot Blennerhassett 			phr->error = HPI_ERROR_DSP_BOOTLOAD;
483*0a00044dSEliot Blennerhassett 			phr->specific_error = err;
484*0a00044dSEliot Blennerhassett 		} else {
485719f82d3SEliot Blennerhassett 			phr->error = err;
486*0a00044dSEliot Blennerhassett 		}
4873285ea10SEliot Blennerhassett 		phr->u.s.data = os_error_code;
488719f82d3SEliot Blennerhassett 		return;
489719f82d3SEliot Blennerhassett 	}
490719f82d3SEliot Blennerhassett 
491719f82d3SEliot Blennerhassett 	phr->u.s.aw_adapter_list[ao.index] = ao.adapter_type;
492719f82d3SEliot Blennerhassett 	phr->u.s.adapter_index = ao.index;
493719f82d3SEliot Blennerhassett 	phr->u.s.num_adapters++;
494719f82d3SEliot Blennerhassett 	phr->error = 0;
495719f82d3SEliot Blennerhassett }
496719f82d3SEliot Blennerhassett 
497719f82d3SEliot Blennerhassett /** delete an adapter - required by WDM driver */
498719f82d3SEliot Blennerhassett static void subsys_delete_adapter(struct hpi_message *phm,
499719f82d3SEliot Blennerhassett 	struct hpi_response *phr)
500719f82d3SEliot Blennerhassett {
501719f82d3SEliot Blennerhassett 	struct hpi_adapter_obj *pao;
502719f82d3SEliot Blennerhassett 	struct hpi_hw_obj *phw;
503719f82d3SEliot Blennerhassett 
5043285ea10SEliot Blennerhassett 	pao = hpi_find_adapter(phm->obj_index);
505719f82d3SEliot Blennerhassett 	if (!pao) {
506719f82d3SEliot Blennerhassett 		phr->error = HPI_ERROR_INVALID_OBJ_INDEX;
507719f82d3SEliot Blennerhassett 		return;
508719f82d3SEliot Blennerhassett 	}
509719f82d3SEliot Blennerhassett 	phw = (struct hpi_hw_obj *)pao->priv;
510719f82d3SEliot Blennerhassett 	/* reset adapter h/w */
511719f82d3SEliot Blennerhassett 	/* Reset C6713 #1 */
512719f82d3SEliot Blennerhassett 	boot_loader_write_mem32(pao, 0, C6205_BAR0_TIMER1_CTL, 0);
513719f82d3SEliot Blennerhassett 	/* reset C6205 */
514719f82d3SEliot Blennerhassett 	iowrite32(C6205_HDCR_WARMRESET, phw->prHDCR);
515719f82d3SEliot Blennerhassett 
516719f82d3SEliot Blennerhassett 	delete_adapter_obj(pao);
5173285ea10SEliot Blennerhassett 	hpi_delete_adapter(pao);
518719f82d3SEliot Blennerhassett 	phr->error = 0;
519719f82d3SEliot Blennerhassett }
520719f82d3SEliot Blennerhassett 
521719f82d3SEliot Blennerhassett /** Create adapter object
522719f82d3SEliot Blennerhassett   allocate buffers, bootload DSPs, initialise control cache
523719f82d3SEliot Blennerhassett */
524719f82d3SEliot Blennerhassett static u16 create_adapter_obj(struct hpi_adapter_obj *pao,
525719f82d3SEliot Blennerhassett 	u32 *pos_error_code)
526719f82d3SEliot Blennerhassett {
527719f82d3SEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
528719f82d3SEliot Blennerhassett 	struct bus_master_interface *interface;
529719f82d3SEliot Blennerhassett 	u32 phys_addr;
530719f82d3SEliot Blennerhassett #ifndef HPI6205_NO_HSR_POLL
531719f82d3SEliot Blennerhassett 	u32 time_out = HPI6205_TIMEOUT;
532719f82d3SEliot Blennerhassett 	u32 temp1;
533719f82d3SEliot Blennerhassett #endif
534719f82d3SEliot Blennerhassett 	int i;
535719f82d3SEliot Blennerhassett 	u16 err;
536719f82d3SEliot Blennerhassett 
537719f82d3SEliot Blennerhassett 	/* init error reporting */
538719f82d3SEliot Blennerhassett 	pao->dsp_crashed = 0;
539719f82d3SEliot Blennerhassett 
540719f82d3SEliot Blennerhassett 	for (i = 0; i < HPI_MAX_STREAMS; i++)
541719f82d3SEliot Blennerhassett 		phw->flag_outstream_just_reset[i] = 1;
542719f82d3SEliot Blennerhassett 
543719f82d3SEliot Blennerhassett 	/* The C6205 memory area 1 is 8Mbyte window into DSP registers */
544719f82d3SEliot Blennerhassett 	phw->prHSR =
545719f82d3SEliot Blennerhassett 		pao->pci.ap_mem_base[1] +
546719f82d3SEliot Blennerhassett 		C6205_BAR1_HSR / sizeof(*pao->pci.ap_mem_base[1]);
547719f82d3SEliot Blennerhassett 	phw->prHDCR =
548719f82d3SEliot Blennerhassett 		pao->pci.ap_mem_base[1] +
549719f82d3SEliot Blennerhassett 		C6205_BAR1_HDCR / sizeof(*pao->pci.ap_mem_base[1]);
550719f82d3SEliot Blennerhassett 	phw->prDSPP =
551719f82d3SEliot Blennerhassett 		pao->pci.ap_mem_base[1] +
552719f82d3SEliot Blennerhassett 		C6205_BAR1_DSPP / sizeof(*pao->pci.ap_mem_base[1]);
553719f82d3SEliot Blennerhassett 
554719f82d3SEliot Blennerhassett 	pao->has_control_cache = 0;
555719f82d3SEliot Blennerhassett 
556719f82d3SEliot Blennerhassett 	if (hpios_locked_mem_alloc(&phw->h_locked_mem,
557719f82d3SEliot Blennerhassett 			sizeof(struct bus_master_interface),
5583285ea10SEliot Blennerhassett 			pao->pci.pci_dev))
559719f82d3SEliot Blennerhassett 		phw->p_interface_buffer = NULL;
560719f82d3SEliot Blennerhassett 	else if (hpios_locked_mem_get_virt_addr(&phw->h_locked_mem,
561719f82d3SEliot Blennerhassett 			(void *)&phw->p_interface_buffer))
562719f82d3SEliot Blennerhassett 		phw->p_interface_buffer = NULL;
563719f82d3SEliot Blennerhassett 
564719f82d3SEliot Blennerhassett 	HPI_DEBUG_LOG(DEBUG, "interface buffer address %p\n",
565719f82d3SEliot Blennerhassett 		phw->p_interface_buffer);
566719f82d3SEliot Blennerhassett 
567719f82d3SEliot Blennerhassett 	if (phw->p_interface_buffer) {
568719f82d3SEliot Blennerhassett 		memset((void *)phw->p_interface_buffer, 0,
569719f82d3SEliot Blennerhassett 			sizeof(struct bus_master_interface));
570719f82d3SEliot Blennerhassett 		phw->p_interface_buffer->dsp_ack = H620_HIF_UNKNOWN;
571719f82d3SEliot Blennerhassett 	}
572719f82d3SEliot Blennerhassett 
573719f82d3SEliot Blennerhassett 	err = adapter_boot_load_dsp(pao, pos_error_code);
574719f82d3SEliot Blennerhassett 	if (err)
575719f82d3SEliot Blennerhassett 		/* no need to clean up as SubSysCreateAdapter */
576719f82d3SEliot Blennerhassett 		/* calls DeleteAdapter on error. */
577719f82d3SEliot Blennerhassett 		return err;
578719f82d3SEliot Blennerhassett 
579719f82d3SEliot Blennerhassett 	HPI_DEBUG_LOG(INFO, "load DSP code OK\n");
580719f82d3SEliot Blennerhassett 
581719f82d3SEliot Blennerhassett 	/* allow boot load even if mem alloc wont work */
582719f82d3SEliot Blennerhassett 	if (!phw->p_interface_buffer)
5833285ea10SEliot Blennerhassett 		return HPI_ERROR_MEMORY_ALLOC;
584719f82d3SEliot Blennerhassett 
585719f82d3SEliot Blennerhassett 	interface = phw->p_interface_buffer;
586719f82d3SEliot Blennerhassett 
587719f82d3SEliot Blennerhassett #ifndef HPI6205_NO_HSR_POLL
588719f82d3SEliot Blennerhassett 	/* wait for first interrupt indicating the DSP init is done */
589719f82d3SEliot Blennerhassett 	time_out = HPI6205_TIMEOUT * 10;
590719f82d3SEliot Blennerhassett 	temp1 = 0;
591719f82d3SEliot Blennerhassett 	while (((temp1 & C6205_HSR_INTSRC) == 0) && --time_out)
592719f82d3SEliot Blennerhassett 		temp1 = ioread32(phw->prHSR);
593719f82d3SEliot Blennerhassett 
594719f82d3SEliot Blennerhassett 	if (temp1 & C6205_HSR_INTSRC)
595719f82d3SEliot Blennerhassett 		HPI_DEBUG_LOG(INFO,
5963285ea10SEliot Blennerhassett 			"Interrupt confirming DSP code running OK\n");
597719f82d3SEliot Blennerhassett 	else {
598719f82d3SEliot Blennerhassett 		HPI_DEBUG_LOG(ERROR,
5993285ea10SEliot Blennerhassett 			"Timed out waiting for interrupt "
600719f82d3SEliot Blennerhassett 			"confirming DSP code running\n");
6013285ea10SEliot Blennerhassett 		return HPI6205_ERROR_6205_NO_IRQ;
602719f82d3SEliot Blennerhassett 	}
603719f82d3SEliot Blennerhassett 
604719f82d3SEliot Blennerhassett 	/* reset the interrupt */
605719f82d3SEliot Blennerhassett 	iowrite32(C6205_HSR_INTSRC, phw->prHSR);
606719f82d3SEliot Blennerhassett #endif
607719f82d3SEliot Blennerhassett 
608719f82d3SEliot Blennerhassett 	/* make sure the DSP has started ok */
609719f82d3SEliot Blennerhassett 	if (!wait_dsp_ack(phw, H620_HIF_RESET, HPI6205_TIMEOUT * 10)) {
610719f82d3SEliot Blennerhassett 		HPI_DEBUG_LOG(ERROR, "timed out waiting reset state \n");
6113285ea10SEliot Blennerhassett 		return HPI6205_ERROR_6205_INIT_FAILED;
612719f82d3SEliot Blennerhassett 	}
613719f82d3SEliot Blennerhassett 	/* Note that *pao, *phw are zeroed after allocation,
614719f82d3SEliot Blennerhassett 	 * so pointers and flags are NULL by default.
615719f82d3SEliot Blennerhassett 	 * Allocate bus mastering control cache buffer and tell the DSP about it
616719f82d3SEliot Blennerhassett 	 */
617719f82d3SEliot Blennerhassett 	if (interface->control_cache.number_of_controls) {
6183285ea10SEliot Blennerhassett 		u8 *p_control_cache_virtual;
619719f82d3SEliot Blennerhassett 
620719f82d3SEliot Blennerhassett 		err = hpios_locked_mem_alloc(&phw->h_control_cache,
621719f82d3SEliot Blennerhassett 			interface->control_cache.size_in_bytes,
6223285ea10SEliot Blennerhassett 			pao->pci.pci_dev);
623719f82d3SEliot Blennerhassett 		if (!err)
624719f82d3SEliot Blennerhassett 			err = hpios_locked_mem_get_virt_addr(&phw->
6253285ea10SEliot Blennerhassett 				h_control_cache,
6263285ea10SEliot Blennerhassett 				(void *)&p_control_cache_virtual);
627719f82d3SEliot Blennerhassett 		if (!err) {
628719f82d3SEliot Blennerhassett 			memset(p_control_cache_virtual, 0,
629719f82d3SEliot Blennerhassett 				interface->control_cache.size_in_bytes);
630719f82d3SEliot Blennerhassett 
631719f82d3SEliot Blennerhassett 			phw->p_cache =
632719f82d3SEliot Blennerhassett 				hpi_alloc_control_cache(interface->
633719f82d3SEliot Blennerhassett 				control_cache.number_of_controls,
634719f82d3SEliot Blennerhassett 				interface->control_cache.size_in_bytes,
635719f82d3SEliot Blennerhassett 				p_control_cache_virtual);
636fd0977d0SJesper Juhl 			if (!phw->p_cache)
637fd0977d0SJesper Juhl 				err = HPI_ERROR_MEMORY_ALLOC;
638719f82d3SEliot Blennerhassett 		}
639719f82d3SEliot Blennerhassett 		if (!err) {
640719f82d3SEliot Blennerhassett 			err = hpios_locked_mem_get_phys_addr(&phw->
641719f82d3SEliot Blennerhassett 				h_control_cache, &phys_addr);
642719f82d3SEliot Blennerhassett 			interface->control_cache.physical_address32 =
643719f82d3SEliot Blennerhassett 				phys_addr;
644719f82d3SEliot Blennerhassett 		}
645719f82d3SEliot Blennerhassett 
646719f82d3SEliot Blennerhassett 		if (!err)
647719f82d3SEliot Blennerhassett 			pao->has_control_cache = 1;
648719f82d3SEliot Blennerhassett 		else {
649719f82d3SEliot Blennerhassett 			if (hpios_locked_mem_valid(&phw->h_control_cache))
650719f82d3SEliot Blennerhassett 				hpios_locked_mem_free(&phw->h_control_cache);
651719f82d3SEliot Blennerhassett 			pao->has_control_cache = 0;
652719f82d3SEliot Blennerhassett 		}
653719f82d3SEliot Blennerhassett 	}
654719f82d3SEliot Blennerhassett 	/* allocate bus mastering async buffer and tell the DSP about it */
655719f82d3SEliot Blennerhassett 	if (interface->async_buffer.b.size) {
656719f82d3SEliot Blennerhassett 		err = hpios_locked_mem_alloc(&phw->h_async_event_buffer,
657719f82d3SEliot Blennerhassett 			interface->async_buffer.b.size *
6583285ea10SEliot Blennerhassett 			sizeof(struct hpi_async_event), pao->pci.pci_dev);
659719f82d3SEliot Blennerhassett 		if (!err)
660719f82d3SEliot Blennerhassett 			err = hpios_locked_mem_get_virt_addr
661719f82d3SEliot Blennerhassett 				(&phw->h_async_event_buffer, (void *)
662719f82d3SEliot Blennerhassett 				&phw->p_async_event_buffer);
663719f82d3SEliot Blennerhassett 		if (!err)
664719f82d3SEliot Blennerhassett 			memset((void *)phw->p_async_event_buffer, 0,
665719f82d3SEliot Blennerhassett 				interface->async_buffer.b.size *
666719f82d3SEliot Blennerhassett 				sizeof(struct hpi_async_event));
667719f82d3SEliot Blennerhassett 		if (!err) {
668719f82d3SEliot Blennerhassett 			err = hpios_locked_mem_get_phys_addr
669719f82d3SEliot Blennerhassett 				(&phw->h_async_event_buffer, &phys_addr);
670719f82d3SEliot Blennerhassett 			interface->async_buffer.physical_address32 =
671719f82d3SEliot Blennerhassett 				phys_addr;
672719f82d3SEliot Blennerhassett 		}
673719f82d3SEliot Blennerhassett 		if (err) {
674719f82d3SEliot Blennerhassett 			if (hpios_locked_mem_valid(&phw->
675719f82d3SEliot Blennerhassett 					h_async_event_buffer)) {
676719f82d3SEliot Blennerhassett 				hpios_locked_mem_free
677719f82d3SEliot Blennerhassett 					(&phw->h_async_event_buffer);
678719f82d3SEliot Blennerhassett 				phw->p_async_event_buffer = NULL;
679719f82d3SEliot Blennerhassett 			}
680719f82d3SEliot Blennerhassett 		}
681719f82d3SEliot Blennerhassett 	}
682719f82d3SEliot Blennerhassett 	send_dsp_command(phw, H620_HIF_IDLE);
683719f82d3SEliot Blennerhassett 
684719f82d3SEliot Blennerhassett 	{
6853285ea10SEliot Blennerhassett 		struct hpi_message hm;
6863285ea10SEliot Blennerhassett 		struct hpi_response hr;
687719f82d3SEliot Blennerhassett 		u32 max_streams;
688719f82d3SEliot Blennerhassett 
689719f82d3SEliot Blennerhassett 		HPI_DEBUG_LOG(VERBOSE, "init ADAPTER_GET_INFO\n");
6903285ea10SEliot Blennerhassett 		memset(&hm, 0, sizeof(hm));
6913285ea10SEliot Blennerhassett 		hm.type = HPI_TYPE_MESSAGE;
6923285ea10SEliot Blennerhassett 		hm.size = sizeof(hm);
6933285ea10SEliot Blennerhassett 		hm.object = HPI_OBJ_ADAPTER;
6943285ea10SEliot Blennerhassett 		hm.function = HPI_ADAPTER_GET_INFO;
6953285ea10SEliot Blennerhassett 		hm.adapter_index = 0;
6963285ea10SEliot Blennerhassett 		memset(&hr, 0, sizeof(hr));
6973285ea10SEliot Blennerhassett 		hr.size = sizeof(hr);
698719f82d3SEliot Blennerhassett 
6993285ea10SEliot Blennerhassett 		err = message_response_sequence(pao, &hm, &hr);
700719f82d3SEliot Blennerhassett 		if (err) {
701719f82d3SEliot Blennerhassett 			HPI_DEBUG_LOG(ERROR, "message transport error %d\n",
702719f82d3SEliot Blennerhassett 				err);
703719f82d3SEliot Blennerhassett 			return err;
704719f82d3SEliot Blennerhassett 		}
7053285ea10SEliot Blennerhassett 		if (hr.error)
7063285ea10SEliot Blennerhassett 			return hr.error;
707719f82d3SEliot Blennerhassett 
7083285ea10SEliot Blennerhassett 		pao->adapter_type = hr.u.ax.info.adapter_type;
7093285ea10SEliot Blennerhassett 		pao->index = hr.u.ax.info.adapter_index;
710719f82d3SEliot Blennerhassett 
7113285ea10SEliot Blennerhassett 		max_streams =
7123285ea10SEliot Blennerhassett 			hr.u.ax.info.num_outstreams +
7133285ea10SEliot Blennerhassett 			hr.u.ax.info.num_instreams;
714719f82d3SEliot Blennerhassett 
715719f82d3SEliot Blennerhassett 		hpios_locked_mem_prepare((max_streams * 6) / 10, max_streams,
7163285ea10SEliot Blennerhassett 			65536, pao->pci.pci_dev);
717719f82d3SEliot Blennerhassett 
718719f82d3SEliot Blennerhassett 		HPI_DEBUG_LOG(VERBOSE,
719719f82d3SEliot Blennerhassett 			"got adapter info type %x index %d serial %d\n",
7203285ea10SEliot Blennerhassett 			hr.u.ax.info.adapter_type, hr.u.ax.info.adapter_index,
7213285ea10SEliot Blennerhassett 			hr.u.ax.info.serial_number);
722719f82d3SEliot Blennerhassett 	}
723719f82d3SEliot Blennerhassett 
724719f82d3SEliot Blennerhassett 	pao->open = 0;	/* upon creation the adapter is closed */
725719f82d3SEliot Blennerhassett 
726ffdb5787SEliot Blennerhassett 	if (phw->p_cache)
727ffdb5787SEliot Blennerhassett 		phw->p_cache->adap_idx = pao->index;
728ffdb5787SEliot Blennerhassett 
729719f82d3SEliot Blennerhassett 	HPI_DEBUG_LOG(INFO, "bootload DSP OK\n");
7303285ea10SEliot Blennerhassett 
7313285ea10SEliot Blennerhassett 	return hpi_add_adapter(pao);
732719f82d3SEliot Blennerhassett }
733719f82d3SEliot Blennerhassett 
734719f82d3SEliot Blennerhassett /** Free memory areas allocated by adapter
735719f82d3SEliot Blennerhassett  * this routine is called from SubSysDeleteAdapter,
736719f82d3SEliot Blennerhassett   * and SubSysCreateAdapter if duplicate index
737719f82d3SEliot Blennerhassett */
738719f82d3SEliot Blennerhassett static void delete_adapter_obj(struct hpi_adapter_obj *pao)
739719f82d3SEliot Blennerhassett {
740719f82d3SEliot Blennerhassett 	struct hpi_hw_obj *phw;
741719f82d3SEliot Blennerhassett 	int i;
742719f82d3SEliot Blennerhassett 
743719f82d3SEliot Blennerhassett 	phw = pao->priv;
744719f82d3SEliot Blennerhassett 
745719f82d3SEliot Blennerhassett 	if (hpios_locked_mem_valid(&phw->h_async_event_buffer)) {
746719f82d3SEliot Blennerhassett 		hpios_locked_mem_free(&phw->h_async_event_buffer);
747719f82d3SEliot Blennerhassett 		phw->p_async_event_buffer = NULL;
748719f82d3SEliot Blennerhassett 	}
749719f82d3SEliot Blennerhassett 
750719f82d3SEliot Blennerhassett 	if (hpios_locked_mem_valid(&phw->h_control_cache)) {
751719f82d3SEliot Blennerhassett 		hpios_locked_mem_free(&phw->h_control_cache);
752719f82d3SEliot Blennerhassett 		hpi_free_control_cache(phw->p_cache);
753719f82d3SEliot Blennerhassett 	}
754719f82d3SEliot Blennerhassett 
755719f82d3SEliot Blennerhassett 	if (hpios_locked_mem_valid(&phw->h_locked_mem)) {
756719f82d3SEliot Blennerhassett 		hpios_locked_mem_free(&phw->h_locked_mem);
757719f82d3SEliot Blennerhassett 		phw->p_interface_buffer = NULL;
758719f82d3SEliot Blennerhassett 	}
759719f82d3SEliot Blennerhassett 
760719f82d3SEliot Blennerhassett 	for (i = 0; i < HPI_MAX_STREAMS; i++)
761719f82d3SEliot Blennerhassett 		if (hpios_locked_mem_valid(&phw->instream_host_buffers[i])) {
762719f82d3SEliot Blennerhassett 			hpios_locked_mem_free(&phw->instream_host_buffers[i]);
763719f82d3SEliot Blennerhassett 			/*?phw->InStreamHostBuffers[i] = NULL; */
764719f82d3SEliot Blennerhassett 			phw->instream_host_buffer_size[i] = 0;
765719f82d3SEliot Blennerhassett 		}
766719f82d3SEliot Blennerhassett 
767719f82d3SEliot Blennerhassett 	for (i = 0; i < HPI_MAX_STREAMS; i++)
768719f82d3SEliot Blennerhassett 		if (hpios_locked_mem_valid(&phw->outstream_host_buffers[i])) {
769719f82d3SEliot Blennerhassett 			hpios_locked_mem_free(&phw->outstream_host_buffers
770719f82d3SEliot Blennerhassett 				[i]);
771719f82d3SEliot Blennerhassett 			phw->outstream_host_buffer_size[i] = 0;
772719f82d3SEliot Blennerhassett 		}
773719f82d3SEliot Blennerhassett 
7743285ea10SEliot Blennerhassett 	hpios_locked_mem_unprepare(pao->pci.pci_dev);
775719f82d3SEliot Blennerhassett 
776719f82d3SEliot Blennerhassett 	kfree(phw);
777719f82d3SEliot Blennerhassett }
778719f82d3SEliot Blennerhassett 
779719f82d3SEliot Blennerhassett /*****************************************************************************/
780719f82d3SEliot Blennerhassett /* OutStream Host buffer functions */
781719f82d3SEliot Blennerhassett 
782719f82d3SEliot Blennerhassett /** Allocate or attach buffer for busmastering
783719f82d3SEliot Blennerhassett */
784719f82d3SEliot Blennerhassett static void outstream_host_buffer_allocate(struct hpi_adapter_obj *pao,
785719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
786719f82d3SEliot Blennerhassett {
787719f82d3SEliot Blennerhassett 	u16 err = 0;
788719f82d3SEliot Blennerhassett 	u32 command = phm->u.d.u.buffer.command;
789719f82d3SEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
790719f82d3SEliot Blennerhassett 	struct bus_master_interface *interface = phw->p_interface_buffer;
791719f82d3SEliot Blennerhassett 
792719f82d3SEliot Blennerhassett 	hpi_init_response(phr, phm->object, phm->function, 0);
793719f82d3SEliot Blennerhassett 
794719f82d3SEliot Blennerhassett 	if (command == HPI_BUFFER_CMD_EXTERNAL
795719f82d3SEliot Blennerhassett 		|| command == HPI_BUFFER_CMD_INTERNAL_ALLOC) {
796719f82d3SEliot Blennerhassett 		/* ALLOC phase, allocate a buffer with power of 2 size,
797719f82d3SEliot Blennerhassett 		   get its bus address for PCI bus mastering
798719f82d3SEliot Blennerhassett 		 */
799719f82d3SEliot Blennerhassett 		phm->u.d.u.buffer.buffer_size =
800719f82d3SEliot Blennerhassett 			roundup_pow_of_two(phm->u.d.u.buffer.buffer_size);
801719f82d3SEliot Blennerhassett 		/* return old size and allocated size,
802719f82d3SEliot Blennerhassett 		   so caller can detect change */
803719f82d3SEliot Blennerhassett 		phr->u.d.u.stream_info.data_available =
804719f82d3SEliot Blennerhassett 			phw->outstream_host_buffer_size[phm->obj_index];
805719f82d3SEliot Blennerhassett 		phr->u.d.u.stream_info.buffer_size =
806719f82d3SEliot Blennerhassett 			phm->u.d.u.buffer.buffer_size;
807719f82d3SEliot Blennerhassett 
808719f82d3SEliot Blennerhassett 		if (phw->outstream_host_buffer_size[phm->obj_index] ==
809719f82d3SEliot Blennerhassett 			phm->u.d.u.buffer.buffer_size) {
810719f82d3SEliot Blennerhassett 			/* Same size, no action required */
811719f82d3SEliot Blennerhassett 			return;
812719f82d3SEliot Blennerhassett 		}
813719f82d3SEliot Blennerhassett 
814719f82d3SEliot Blennerhassett 		if (hpios_locked_mem_valid(&phw->outstream_host_buffers[phm->
815719f82d3SEliot Blennerhassett 					obj_index]))
816719f82d3SEliot Blennerhassett 			hpios_locked_mem_free(&phw->outstream_host_buffers
817719f82d3SEliot Blennerhassett 				[phm->obj_index]);
818719f82d3SEliot Blennerhassett 
819719f82d3SEliot Blennerhassett 		err = hpios_locked_mem_alloc(&phw->outstream_host_buffers
820719f82d3SEliot Blennerhassett 			[phm->obj_index], phm->u.d.u.buffer.buffer_size,
8213285ea10SEliot Blennerhassett 			pao->pci.pci_dev);
822719f82d3SEliot Blennerhassett 
823719f82d3SEliot Blennerhassett 		if (err) {
824719f82d3SEliot Blennerhassett 			phr->error = HPI_ERROR_INVALID_DATASIZE;
825719f82d3SEliot Blennerhassett 			phw->outstream_host_buffer_size[phm->obj_index] = 0;
826719f82d3SEliot Blennerhassett 			return;
827719f82d3SEliot Blennerhassett 		}
828719f82d3SEliot Blennerhassett 
829719f82d3SEliot Blennerhassett 		err = hpios_locked_mem_get_phys_addr
830719f82d3SEliot Blennerhassett 			(&phw->outstream_host_buffers[phm->obj_index],
831719f82d3SEliot Blennerhassett 			&phm->u.d.u.buffer.pci_address);
832719f82d3SEliot Blennerhassett 		/* get the phys addr into msg for single call alloc caller
833719f82d3SEliot Blennerhassett 		 * needs to do this for split alloc (or use the same message)
834719f82d3SEliot Blennerhassett 		 * return the phy address for split alloc in the respose too
835719f82d3SEliot Blennerhassett 		 */
836719f82d3SEliot Blennerhassett 		phr->u.d.u.stream_info.auxiliary_data_available =
837719f82d3SEliot Blennerhassett 			phm->u.d.u.buffer.pci_address;
838719f82d3SEliot Blennerhassett 
839719f82d3SEliot Blennerhassett 		if (err) {
840719f82d3SEliot Blennerhassett 			hpios_locked_mem_free(&phw->outstream_host_buffers
841719f82d3SEliot Blennerhassett 				[phm->obj_index]);
842719f82d3SEliot Blennerhassett 			phw->outstream_host_buffer_size[phm->obj_index] = 0;
843719f82d3SEliot Blennerhassett 			phr->error = HPI_ERROR_MEMORY_ALLOC;
844719f82d3SEliot Blennerhassett 			return;
845719f82d3SEliot Blennerhassett 		}
846719f82d3SEliot Blennerhassett 	}
847719f82d3SEliot Blennerhassett 
848719f82d3SEliot Blennerhassett 	if (command == HPI_BUFFER_CMD_EXTERNAL
849719f82d3SEliot Blennerhassett 		|| command == HPI_BUFFER_CMD_INTERNAL_GRANTADAPTER) {
850719f82d3SEliot Blennerhassett 		/* GRANT phase.  Set up the BBM status, tell the DSP about
851719f82d3SEliot Blennerhassett 		   the buffer so it can start using BBM.
852719f82d3SEliot Blennerhassett 		 */
853719f82d3SEliot Blennerhassett 		struct hpi_hostbuffer_status *status;
854719f82d3SEliot Blennerhassett 
855719f82d3SEliot Blennerhassett 		if (phm->u.d.u.buffer.buffer_size & (phm->u.d.u.buffer.
856719f82d3SEliot Blennerhassett 				buffer_size - 1)) {
857719f82d3SEliot Blennerhassett 			HPI_DEBUG_LOG(ERROR,
8583285ea10SEliot Blennerhassett 				"Buffer size must be 2^N not %d\n",
859719f82d3SEliot Blennerhassett 				phm->u.d.u.buffer.buffer_size);
860719f82d3SEliot Blennerhassett 			phr->error = HPI_ERROR_INVALID_DATASIZE;
861719f82d3SEliot Blennerhassett 			return;
862719f82d3SEliot Blennerhassett 		}
863719f82d3SEliot Blennerhassett 		phw->outstream_host_buffer_size[phm->obj_index] =
864719f82d3SEliot Blennerhassett 			phm->u.d.u.buffer.buffer_size;
865719f82d3SEliot Blennerhassett 		status = &interface->outstream_host_buffer_status[phm->
866719f82d3SEliot Blennerhassett 			obj_index];
867719f82d3SEliot Blennerhassett 		status->samples_processed = 0;
868719f82d3SEliot Blennerhassett 		status->stream_state = HPI_STATE_STOPPED;
869719f82d3SEliot Blennerhassett 		status->dSP_index = 0;
870719f82d3SEliot Blennerhassett 		status->host_index = status->dSP_index;
871719f82d3SEliot Blennerhassett 		status->size_in_bytes = phm->u.d.u.buffer.buffer_size;
872deb21a23SEliot Blennerhassett 		status->auxiliary_data_available = 0;
873719f82d3SEliot Blennerhassett 
874719f82d3SEliot Blennerhassett 		hw_message(pao, phm, phr);
875719f82d3SEliot Blennerhassett 
876719f82d3SEliot Blennerhassett 		if (phr->error
877719f82d3SEliot Blennerhassett 			&& hpios_locked_mem_valid(&phw->
878719f82d3SEliot Blennerhassett 				outstream_host_buffers[phm->obj_index])) {
879719f82d3SEliot Blennerhassett 			hpios_locked_mem_free(&phw->outstream_host_buffers
880719f82d3SEliot Blennerhassett 				[phm->obj_index]);
881719f82d3SEliot Blennerhassett 			phw->outstream_host_buffer_size[phm->obj_index] = 0;
882719f82d3SEliot Blennerhassett 		}
883719f82d3SEliot Blennerhassett 	}
884719f82d3SEliot Blennerhassett }
885719f82d3SEliot Blennerhassett 
886719f82d3SEliot Blennerhassett static void outstream_host_buffer_get_info(struct hpi_adapter_obj *pao,
887719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
888719f82d3SEliot Blennerhassett {
889719f82d3SEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
890719f82d3SEliot Blennerhassett 	struct bus_master_interface *interface = phw->p_interface_buffer;
891719f82d3SEliot Blennerhassett 	struct hpi_hostbuffer_status *status;
892719f82d3SEliot Blennerhassett 	u8 *p_bbm_data;
893719f82d3SEliot Blennerhassett 
894719f82d3SEliot Blennerhassett 	if (hpios_locked_mem_valid(&phw->outstream_host_buffers[phm->
895719f82d3SEliot Blennerhassett 				obj_index])) {
896719f82d3SEliot Blennerhassett 		if (hpios_locked_mem_get_virt_addr(&phw->
897719f82d3SEliot Blennerhassett 				outstream_host_buffers[phm->obj_index],
898719f82d3SEliot Blennerhassett 				(void *)&p_bbm_data)) {
899719f82d3SEliot Blennerhassett 			phr->error = HPI_ERROR_INVALID_OPERATION;
900719f82d3SEliot Blennerhassett 			return;
901719f82d3SEliot Blennerhassett 		}
902719f82d3SEliot Blennerhassett 		status = &interface->outstream_host_buffer_status[phm->
903719f82d3SEliot Blennerhassett 			obj_index];
904719f82d3SEliot Blennerhassett 		hpi_init_response(phr, HPI_OBJ_OSTREAM,
905719f82d3SEliot Blennerhassett 			HPI_OSTREAM_HOSTBUFFER_GET_INFO, 0);
906719f82d3SEliot Blennerhassett 		phr->u.d.u.hostbuffer_info.p_buffer = p_bbm_data;
907719f82d3SEliot Blennerhassett 		phr->u.d.u.hostbuffer_info.p_status = status;
908719f82d3SEliot Blennerhassett 	} else {
909719f82d3SEliot Blennerhassett 		hpi_init_response(phr, HPI_OBJ_OSTREAM,
910719f82d3SEliot Blennerhassett 			HPI_OSTREAM_HOSTBUFFER_GET_INFO,
911719f82d3SEliot Blennerhassett 			HPI_ERROR_INVALID_OPERATION);
912719f82d3SEliot Blennerhassett 	}
913719f82d3SEliot Blennerhassett }
914719f82d3SEliot Blennerhassett 
915719f82d3SEliot Blennerhassett static void outstream_host_buffer_free(struct hpi_adapter_obj *pao,
916719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
917719f82d3SEliot Blennerhassett {
918719f82d3SEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
919719f82d3SEliot Blennerhassett 	u32 command = phm->u.d.u.buffer.command;
920719f82d3SEliot Blennerhassett 
921719f82d3SEliot Blennerhassett 	if (phw->outstream_host_buffer_size[phm->obj_index]) {
922719f82d3SEliot Blennerhassett 		if (command == HPI_BUFFER_CMD_EXTERNAL
923719f82d3SEliot Blennerhassett 			|| command == HPI_BUFFER_CMD_INTERNAL_REVOKEADAPTER) {
924719f82d3SEliot Blennerhassett 			phw->outstream_host_buffer_size[phm->obj_index] = 0;
925719f82d3SEliot Blennerhassett 			hw_message(pao, phm, phr);
926719f82d3SEliot Blennerhassett 			/* Tell adapter to stop using the host buffer. */
927719f82d3SEliot Blennerhassett 		}
928719f82d3SEliot Blennerhassett 		if (command == HPI_BUFFER_CMD_EXTERNAL
929719f82d3SEliot Blennerhassett 			|| command == HPI_BUFFER_CMD_INTERNAL_FREE)
930719f82d3SEliot Blennerhassett 			hpios_locked_mem_free(&phw->outstream_host_buffers
931719f82d3SEliot Blennerhassett 				[phm->obj_index]);
932719f82d3SEliot Blennerhassett 	}
933719f82d3SEliot Blennerhassett 	/* Should HPI_ERROR_INVALID_OPERATION be returned
934719f82d3SEliot Blennerhassett 	   if no host buffer is allocated? */
935719f82d3SEliot Blennerhassett 	else
936719f82d3SEliot Blennerhassett 		hpi_init_response(phr, HPI_OBJ_OSTREAM,
937719f82d3SEliot Blennerhassett 			HPI_OSTREAM_HOSTBUFFER_FREE, 0);
938719f82d3SEliot Blennerhassett 
939719f82d3SEliot Blennerhassett }
940719f82d3SEliot Blennerhassett 
94160f1deb5SEliot Blennerhassett static u32 outstream_get_space_available(struct hpi_hostbuffer_status *status)
942719f82d3SEliot Blennerhassett {
9432a383cb3SEliot Blennerhassett 	return status->size_in_bytes - (status->host_index -
9442a383cb3SEliot Blennerhassett 		status->dSP_index);
945719f82d3SEliot Blennerhassett }
946719f82d3SEliot Blennerhassett 
947719f82d3SEliot Blennerhassett static void outstream_write(struct hpi_adapter_obj *pao,
948719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
949719f82d3SEliot Blennerhassett {
950719f82d3SEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
951719f82d3SEliot Blennerhassett 	struct bus_master_interface *interface = phw->p_interface_buffer;
952719f82d3SEliot Blennerhassett 	struct hpi_hostbuffer_status *status;
9532a383cb3SEliot Blennerhassett 	u32 space_available;
954719f82d3SEliot Blennerhassett 
955719f82d3SEliot Blennerhassett 	if (!phw->outstream_host_buffer_size[phm->obj_index]) {
956719f82d3SEliot Blennerhassett 		/* there  is no BBM buffer, write via message */
957719f82d3SEliot Blennerhassett 		hw_message(pao, phm, phr);
958719f82d3SEliot Blennerhassett 		return;
959719f82d3SEliot Blennerhassett 	}
960719f82d3SEliot Blennerhassett 
961719f82d3SEliot Blennerhassett 	hpi_init_response(phr, phm->object, phm->function, 0);
962719f82d3SEliot Blennerhassett 	status = &interface->outstream_host_buffer_status[phm->obj_index];
963719f82d3SEliot Blennerhassett 
964719f82d3SEliot Blennerhassett 	space_available = outstream_get_space_available(status);
9652a383cb3SEliot Blennerhassett 	if (space_available < phm->u.d.u.data.data_size) {
966719f82d3SEliot Blennerhassett 		phr->error = HPI_ERROR_INVALID_DATASIZE;
967719f82d3SEliot Blennerhassett 		return;
968719f82d3SEliot Blennerhassett 	}
969719f82d3SEliot Blennerhassett 
970719f82d3SEliot Blennerhassett 	/* HostBuffers is used to indicate host buffer is internally allocated.
971719f82d3SEliot Blennerhassett 	   otherwise, assumed external, data written externally */
972719f82d3SEliot Blennerhassett 	if (phm->u.d.u.data.pb_data
973719f82d3SEliot Blennerhassett 		&& hpios_locked_mem_valid(&phw->outstream_host_buffers[phm->
974719f82d3SEliot Blennerhassett 				obj_index])) {
975719f82d3SEliot Blennerhassett 		u8 *p_bbm_data;
9762a383cb3SEliot Blennerhassett 		u32 l_first_write;
977719f82d3SEliot Blennerhassett 		u8 *p_app_data = (u8 *)phm->u.d.u.data.pb_data;
978719f82d3SEliot Blennerhassett 
979719f82d3SEliot Blennerhassett 		if (hpios_locked_mem_get_virt_addr(&phw->
980719f82d3SEliot Blennerhassett 				outstream_host_buffers[phm->obj_index],
981719f82d3SEliot Blennerhassett 				(void *)&p_bbm_data)) {
982719f82d3SEliot Blennerhassett 			phr->error = HPI_ERROR_INVALID_OPERATION;
983719f82d3SEliot Blennerhassett 			return;
984719f82d3SEliot Blennerhassett 		}
985719f82d3SEliot Blennerhassett 
986719f82d3SEliot Blennerhassett 		/* either all data,
987719f82d3SEliot Blennerhassett 		   or enough to fit from current to end of BBM buffer */
988719f82d3SEliot Blennerhassett 		l_first_write =
989719f82d3SEliot Blennerhassett 			min(phm->u.d.u.data.data_size,
990719f82d3SEliot Blennerhassett 			status->size_in_bytes -
991719f82d3SEliot Blennerhassett 			(status->host_index & (status->size_in_bytes - 1)));
992719f82d3SEliot Blennerhassett 
993719f82d3SEliot Blennerhassett 		memcpy(p_bbm_data +
994719f82d3SEliot Blennerhassett 			(status->host_index & (status->size_in_bytes - 1)),
995719f82d3SEliot Blennerhassett 			p_app_data, l_first_write);
996719f82d3SEliot Blennerhassett 		/* remaining data if any */
997719f82d3SEliot Blennerhassett 		memcpy(p_bbm_data, p_app_data + l_first_write,
998719f82d3SEliot Blennerhassett 			phm->u.d.u.data.data_size - l_first_write);
999719f82d3SEliot Blennerhassett 	}
10003285ea10SEliot Blennerhassett 
10013285ea10SEliot Blennerhassett 	/*
10023285ea10SEliot Blennerhassett 	 * This version relies on the DSP code triggering an OStream buffer
10033285ea10SEliot Blennerhassett 	 * update immediately following a SET_FORMAT call. The host has
1004deb21a23SEliot Blennerhassett 	 * already written data into the BBM buffer, but the DSP won't know
1005deb21a23SEliot Blennerhassett 	 * about it until dwHostIndex is adjusted.
10063285ea10SEliot Blennerhassett 	 */
10073285ea10SEliot Blennerhassett 	if (phw->flag_outstream_just_reset[phm->obj_index]) {
10083285ea10SEliot Blennerhassett 		/* Format can only change after reset. Must tell DSP. */
10093285ea10SEliot Blennerhassett 		u16 function = phm->function;
10103285ea10SEliot Blennerhassett 		phw->flag_outstream_just_reset[phm->obj_index] = 0;
10113285ea10SEliot Blennerhassett 		phm->function = HPI_OSTREAM_SET_FORMAT;
10123285ea10SEliot Blennerhassett 		hw_message(pao, phm, phr);	/* send the format to the DSP */
10133285ea10SEliot Blennerhassett 		phm->function = function;
10143285ea10SEliot Blennerhassett 		if (phr->error)
10153285ea10SEliot Blennerhassett 			return;
10163285ea10SEliot Blennerhassett 	}
10173285ea10SEliot Blennerhassett 
1018719f82d3SEliot Blennerhassett 	status->host_index += phm->u.d.u.data.data_size;
1019719f82d3SEliot Blennerhassett }
1020719f82d3SEliot Blennerhassett 
1021719f82d3SEliot Blennerhassett static void outstream_get_info(struct hpi_adapter_obj *pao,
1022719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
1023719f82d3SEliot Blennerhassett {
1024719f82d3SEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
1025719f82d3SEliot Blennerhassett 	struct bus_master_interface *interface = phw->p_interface_buffer;
1026719f82d3SEliot Blennerhassett 	struct hpi_hostbuffer_status *status;
1027719f82d3SEliot Blennerhassett 
1028719f82d3SEliot Blennerhassett 	if (!phw->outstream_host_buffer_size[phm->obj_index]) {
1029719f82d3SEliot Blennerhassett 		hw_message(pao, phm, phr);
1030719f82d3SEliot Blennerhassett 		return;
1031719f82d3SEliot Blennerhassett 	}
1032719f82d3SEliot Blennerhassett 
1033719f82d3SEliot Blennerhassett 	hpi_init_response(phr, phm->object, phm->function, 0);
1034719f82d3SEliot Blennerhassett 
1035719f82d3SEliot Blennerhassett 	status = &interface->outstream_host_buffer_status[phm->obj_index];
1036719f82d3SEliot Blennerhassett 
1037719f82d3SEliot Blennerhassett 	phr->u.d.u.stream_info.state = (u16)status->stream_state;
1038719f82d3SEliot Blennerhassett 	phr->u.d.u.stream_info.samples_transferred =
1039719f82d3SEliot Blennerhassett 		status->samples_processed;
1040719f82d3SEliot Blennerhassett 	phr->u.d.u.stream_info.buffer_size = status->size_in_bytes;
1041719f82d3SEliot Blennerhassett 	phr->u.d.u.stream_info.data_available =
1042719f82d3SEliot Blennerhassett 		status->size_in_bytes - outstream_get_space_available(status);
1043719f82d3SEliot Blennerhassett 	phr->u.d.u.stream_info.auxiliary_data_available =
1044719f82d3SEliot Blennerhassett 		status->auxiliary_data_available;
1045719f82d3SEliot Blennerhassett }
1046719f82d3SEliot Blennerhassett 
1047719f82d3SEliot Blennerhassett static void outstream_start(struct hpi_adapter_obj *pao,
1048719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
1049719f82d3SEliot Blennerhassett {
1050719f82d3SEliot Blennerhassett 	hw_message(pao, phm, phr);
1051719f82d3SEliot Blennerhassett }
1052719f82d3SEliot Blennerhassett 
1053719f82d3SEliot Blennerhassett static void outstream_reset(struct hpi_adapter_obj *pao,
1054719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
1055719f82d3SEliot Blennerhassett {
1056719f82d3SEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
1057719f82d3SEliot Blennerhassett 	phw->flag_outstream_just_reset[phm->obj_index] = 1;
1058719f82d3SEliot Blennerhassett 	hw_message(pao, phm, phr);
1059719f82d3SEliot Blennerhassett }
1060719f82d3SEliot Blennerhassett 
1061719f82d3SEliot Blennerhassett static void outstream_open(struct hpi_adapter_obj *pao,
1062719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
1063719f82d3SEliot Blennerhassett {
1064719f82d3SEliot Blennerhassett 	outstream_reset(pao, phm, phr);
1065719f82d3SEliot Blennerhassett }
1066719f82d3SEliot Blennerhassett 
1067719f82d3SEliot Blennerhassett /*****************************************************************************/
1068719f82d3SEliot Blennerhassett /* InStream Host buffer functions */
1069719f82d3SEliot Blennerhassett 
1070719f82d3SEliot Blennerhassett static void instream_host_buffer_allocate(struct hpi_adapter_obj *pao,
1071719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
1072719f82d3SEliot Blennerhassett {
1073719f82d3SEliot Blennerhassett 	u16 err = 0;
1074719f82d3SEliot Blennerhassett 	u32 command = phm->u.d.u.buffer.command;
1075719f82d3SEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
1076719f82d3SEliot Blennerhassett 	struct bus_master_interface *interface = phw->p_interface_buffer;
1077719f82d3SEliot Blennerhassett 
1078719f82d3SEliot Blennerhassett 	hpi_init_response(phr, phm->object, phm->function, 0);
1079719f82d3SEliot Blennerhassett 
1080719f82d3SEliot Blennerhassett 	if (command == HPI_BUFFER_CMD_EXTERNAL
1081719f82d3SEliot Blennerhassett 		|| command == HPI_BUFFER_CMD_INTERNAL_ALLOC) {
1082719f82d3SEliot Blennerhassett 
1083719f82d3SEliot Blennerhassett 		phm->u.d.u.buffer.buffer_size =
1084719f82d3SEliot Blennerhassett 			roundup_pow_of_two(phm->u.d.u.buffer.buffer_size);
1085719f82d3SEliot Blennerhassett 		phr->u.d.u.stream_info.data_available =
1086719f82d3SEliot Blennerhassett 			phw->instream_host_buffer_size[phm->obj_index];
1087719f82d3SEliot Blennerhassett 		phr->u.d.u.stream_info.buffer_size =
1088719f82d3SEliot Blennerhassett 			phm->u.d.u.buffer.buffer_size;
1089719f82d3SEliot Blennerhassett 
1090719f82d3SEliot Blennerhassett 		if (phw->instream_host_buffer_size[phm->obj_index] ==
1091719f82d3SEliot Blennerhassett 			phm->u.d.u.buffer.buffer_size) {
1092719f82d3SEliot Blennerhassett 			/* Same size, no action required */
1093719f82d3SEliot Blennerhassett 			return;
1094719f82d3SEliot Blennerhassett 		}
1095719f82d3SEliot Blennerhassett 
1096719f82d3SEliot Blennerhassett 		if (hpios_locked_mem_valid(&phw->instream_host_buffers[phm->
1097719f82d3SEliot Blennerhassett 					obj_index]))
1098719f82d3SEliot Blennerhassett 			hpios_locked_mem_free(&phw->instream_host_buffers
1099719f82d3SEliot Blennerhassett 				[phm->obj_index]);
1100719f82d3SEliot Blennerhassett 
1101719f82d3SEliot Blennerhassett 		err = hpios_locked_mem_alloc(&phw->instream_host_buffers[phm->
1102719f82d3SEliot Blennerhassett 				obj_index], phm->u.d.u.buffer.buffer_size,
11033285ea10SEliot Blennerhassett 			pao->pci.pci_dev);
1104719f82d3SEliot Blennerhassett 
1105719f82d3SEliot Blennerhassett 		if (err) {
1106719f82d3SEliot Blennerhassett 			phr->error = HPI_ERROR_INVALID_DATASIZE;
1107719f82d3SEliot Blennerhassett 			phw->instream_host_buffer_size[phm->obj_index] = 0;
1108719f82d3SEliot Blennerhassett 			return;
1109719f82d3SEliot Blennerhassett 		}
1110719f82d3SEliot Blennerhassett 
1111719f82d3SEliot Blennerhassett 		err = hpios_locked_mem_get_phys_addr
1112719f82d3SEliot Blennerhassett 			(&phw->instream_host_buffers[phm->obj_index],
1113719f82d3SEliot Blennerhassett 			&phm->u.d.u.buffer.pci_address);
1114719f82d3SEliot Blennerhassett 		/* get the phys addr into msg for single call alloc. Caller
1115719f82d3SEliot Blennerhassett 		   needs to do this for split alloc so return the phy address */
1116719f82d3SEliot Blennerhassett 		phr->u.d.u.stream_info.auxiliary_data_available =
1117719f82d3SEliot Blennerhassett 			phm->u.d.u.buffer.pci_address;
1118719f82d3SEliot Blennerhassett 		if (err) {
1119719f82d3SEliot Blennerhassett 			hpios_locked_mem_free(&phw->instream_host_buffers
1120719f82d3SEliot Blennerhassett 				[phm->obj_index]);
1121719f82d3SEliot Blennerhassett 			phw->instream_host_buffer_size[phm->obj_index] = 0;
1122719f82d3SEliot Blennerhassett 			phr->error = HPI_ERROR_MEMORY_ALLOC;
1123719f82d3SEliot Blennerhassett 			return;
1124719f82d3SEliot Blennerhassett 		}
1125719f82d3SEliot Blennerhassett 	}
1126719f82d3SEliot Blennerhassett 
1127719f82d3SEliot Blennerhassett 	if (command == HPI_BUFFER_CMD_EXTERNAL
1128719f82d3SEliot Blennerhassett 		|| command == HPI_BUFFER_CMD_INTERNAL_GRANTADAPTER) {
1129719f82d3SEliot Blennerhassett 		struct hpi_hostbuffer_status *status;
1130719f82d3SEliot Blennerhassett 
1131719f82d3SEliot Blennerhassett 		if (phm->u.d.u.buffer.buffer_size & (phm->u.d.u.buffer.
1132719f82d3SEliot Blennerhassett 				buffer_size - 1)) {
1133719f82d3SEliot Blennerhassett 			HPI_DEBUG_LOG(ERROR,
11343285ea10SEliot Blennerhassett 				"Buffer size must be 2^N not %d\n",
1135719f82d3SEliot Blennerhassett 				phm->u.d.u.buffer.buffer_size);
1136719f82d3SEliot Blennerhassett 			phr->error = HPI_ERROR_INVALID_DATASIZE;
1137719f82d3SEliot Blennerhassett 			return;
1138719f82d3SEliot Blennerhassett 		}
1139719f82d3SEliot Blennerhassett 
1140719f82d3SEliot Blennerhassett 		phw->instream_host_buffer_size[phm->obj_index] =
1141719f82d3SEliot Blennerhassett 			phm->u.d.u.buffer.buffer_size;
1142719f82d3SEliot Blennerhassett 		status = &interface->instream_host_buffer_status[phm->
1143719f82d3SEliot Blennerhassett 			obj_index];
1144719f82d3SEliot Blennerhassett 		status->samples_processed = 0;
1145719f82d3SEliot Blennerhassett 		status->stream_state = HPI_STATE_STOPPED;
1146719f82d3SEliot Blennerhassett 		status->dSP_index = 0;
1147719f82d3SEliot Blennerhassett 		status->host_index = status->dSP_index;
1148719f82d3SEliot Blennerhassett 		status->size_in_bytes = phm->u.d.u.buffer.buffer_size;
1149deb21a23SEliot Blennerhassett 		status->auxiliary_data_available = 0;
1150719f82d3SEliot Blennerhassett 
1151719f82d3SEliot Blennerhassett 		hw_message(pao, phm, phr);
1152719f82d3SEliot Blennerhassett 		if (phr->error
1153719f82d3SEliot Blennerhassett 			&& hpios_locked_mem_valid(&phw->
1154719f82d3SEliot Blennerhassett 				instream_host_buffers[phm->obj_index])) {
1155719f82d3SEliot Blennerhassett 			hpios_locked_mem_free(&phw->instream_host_buffers
1156719f82d3SEliot Blennerhassett 				[phm->obj_index]);
1157719f82d3SEliot Blennerhassett 			phw->instream_host_buffer_size[phm->obj_index] = 0;
1158719f82d3SEliot Blennerhassett 		}
1159719f82d3SEliot Blennerhassett 	}
1160719f82d3SEliot Blennerhassett }
1161719f82d3SEliot Blennerhassett 
1162719f82d3SEliot Blennerhassett static void instream_host_buffer_get_info(struct hpi_adapter_obj *pao,
1163719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
1164719f82d3SEliot Blennerhassett {
1165719f82d3SEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
1166719f82d3SEliot Blennerhassett 	struct bus_master_interface *interface = phw->p_interface_buffer;
1167719f82d3SEliot Blennerhassett 	struct hpi_hostbuffer_status *status;
1168719f82d3SEliot Blennerhassett 	u8 *p_bbm_data;
1169719f82d3SEliot Blennerhassett 
1170719f82d3SEliot Blennerhassett 	if (hpios_locked_mem_valid(&phw->instream_host_buffers[phm->
1171719f82d3SEliot Blennerhassett 				obj_index])) {
1172719f82d3SEliot Blennerhassett 		if (hpios_locked_mem_get_virt_addr(&phw->
1173719f82d3SEliot Blennerhassett 				instream_host_buffers[phm->obj_index],
1174719f82d3SEliot Blennerhassett 				(void *)&p_bbm_data)) {
1175719f82d3SEliot Blennerhassett 			phr->error = HPI_ERROR_INVALID_OPERATION;
1176719f82d3SEliot Blennerhassett 			return;
1177719f82d3SEliot Blennerhassett 		}
1178719f82d3SEliot Blennerhassett 		status = &interface->instream_host_buffer_status[phm->
1179719f82d3SEliot Blennerhassett 			obj_index];
1180719f82d3SEliot Blennerhassett 		hpi_init_response(phr, HPI_OBJ_ISTREAM,
1181719f82d3SEliot Blennerhassett 			HPI_ISTREAM_HOSTBUFFER_GET_INFO, 0);
1182719f82d3SEliot Blennerhassett 		phr->u.d.u.hostbuffer_info.p_buffer = p_bbm_data;
1183719f82d3SEliot Blennerhassett 		phr->u.d.u.hostbuffer_info.p_status = status;
1184719f82d3SEliot Blennerhassett 	} else {
1185719f82d3SEliot Blennerhassett 		hpi_init_response(phr, HPI_OBJ_ISTREAM,
1186719f82d3SEliot Blennerhassett 			HPI_ISTREAM_HOSTBUFFER_GET_INFO,
1187719f82d3SEliot Blennerhassett 			HPI_ERROR_INVALID_OPERATION);
1188719f82d3SEliot Blennerhassett 	}
1189719f82d3SEliot Blennerhassett }
1190719f82d3SEliot Blennerhassett 
1191719f82d3SEliot Blennerhassett static void instream_host_buffer_free(struct hpi_adapter_obj *pao,
1192719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
1193719f82d3SEliot Blennerhassett {
1194719f82d3SEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
1195719f82d3SEliot Blennerhassett 	u32 command = phm->u.d.u.buffer.command;
1196719f82d3SEliot Blennerhassett 
1197719f82d3SEliot Blennerhassett 	if (phw->instream_host_buffer_size[phm->obj_index]) {
1198719f82d3SEliot Blennerhassett 		if (command == HPI_BUFFER_CMD_EXTERNAL
1199719f82d3SEliot Blennerhassett 			|| command == HPI_BUFFER_CMD_INTERNAL_REVOKEADAPTER) {
1200719f82d3SEliot Blennerhassett 			phw->instream_host_buffer_size[phm->obj_index] = 0;
1201719f82d3SEliot Blennerhassett 			hw_message(pao, phm, phr);
1202719f82d3SEliot Blennerhassett 		}
1203719f82d3SEliot Blennerhassett 
1204719f82d3SEliot Blennerhassett 		if (command == HPI_BUFFER_CMD_EXTERNAL
1205719f82d3SEliot Blennerhassett 			|| command == HPI_BUFFER_CMD_INTERNAL_FREE)
1206719f82d3SEliot Blennerhassett 			hpios_locked_mem_free(&phw->instream_host_buffers
1207719f82d3SEliot Blennerhassett 				[phm->obj_index]);
1208719f82d3SEliot Blennerhassett 
1209719f82d3SEliot Blennerhassett 	} else {
1210719f82d3SEliot Blennerhassett 		/* Should HPI_ERROR_INVALID_OPERATION be returned
1211719f82d3SEliot Blennerhassett 		   if no host buffer is allocated? */
1212719f82d3SEliot Blennerhassett 		hpi_init_response(phr, HPI_OBJ_ISTREAM,
1213719f82d3SEliot Blennerhassett 			HPI_ISTREAM_HOSTBUFFER_FREE, 0);
1214719f82d3SEliot Blennerhassett 
1215719f82d3SEliot Blennerhassett 	}
1216719f82d3SEliot Blennerhassett 
1217719f82d3SEliot Blennerhassett }
1218719f82d3SEliot Blennerhassett 
1219719f82d3SEliot Blennerhassett static void instream_start(struct hpi_adapter_obj *pao,
1220719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
1221719f82d3SEliot Blennerhassett {
1222719f82d3SEliot Blennerhassett 	hw_message(pao, phm, phr);
1223719f82d3SEliot Blennerhassett }
1224719f82d3SEliot Blennerhassett 
12252a383cb3SEliot Blennerhassett static u32 instream_get_bytes_available(struct hpi_hostbuffer_status *status)
1226719f82d3SEliot Blennerhassett {
12272a383cb3SEliot Blennerhassett 	return status->dSP_index - status->host_index;
1228719f82d3SEliot Blennerhassett }
1229719f82d3SEliot Blennerhassett 
1230719f82d3SEliot Blennerhassett static void instream_read(struct hpi_adapter_obj *pao,
1231719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
1232719f82d3SEliot Blennerhassett {
1233719f82d3SEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
1234719f82d3SEliot Blennerhassett 	struct bus_master_interface *interface = phw->p_interface_buffer;
1235719f82d3SEliot Blennerhassett 	struct hpi_hostbuffer_status *status;
12362a383cb3SEliot Blennerhassett 	u32 data_available;
1237719f82d3SEliot Blennerhassett 	u8 *p_bbm_data;
12382a383cb3SEliot Blennerhassett 	u32 l_first_read;
1239719f82d3SEliot Blennerhassett 	u8 *p_app_data = (u8 *)phm->u.d.u.data.pb_data;
1240719f82d3SEliot Blennerhassett 
1241719f82d3SEliot Blennerhassett 	if (!phw->instream_host_buffer_size[phm->obj_index]) {
1242719f82d3SEliot Blennerhassett 		hw_message(pao, phm, phr);
1243719f82d3SEliot Blennerhassett 		return;
1244719f82d3SEliot Blennerhassett 	}
1245719f82d3SEliot Blennerhassett 	hpi_init_response(phr, phm->object, phm->function, 0);
1246719f82d3SEliot Blennerhassett 
1247719f82d3SEliot Blennerhassett 	status = &interface->instream_host_buffer_status[phm->obj_index];
1248719f82d3SEliot Blennerhassett 	data_available = instream_get_bytes_available(status);
12492a383cb3SEliot Blennerhassett 	if (data_available < phm->u.d.u.data.data_size) {
1250719f82d3SEliot Blennerhassett 		phr->error = HPI_ERROR_INVALID_DATASIZE;
1251719f82d3SEliot Blennerhassett 		return;
1252719f82d3SEliot Blennerhassett 	}
1253719f82d3SEliot Blennerhassett 
1254719f82d3SEliot Blennerhassett 	if (hpios_locked_mem_valid(&phw->instream_host_buffers[phm->
1255719f82d3SEliot Blennerhassett 				obj_index])) {
1256719f82d3SEliot Blennerhassett 		if (hpios_locked_mem_get_virt_addr(&phw->
1257719f82d3SEliot Blennerhassett 				instream_host_buffers[phm->obj_index],
1258719f82d3SEliot Blennerhassett 				(void *)&p_bbm_data)) {
1259719f82d3SEliot Blennerhassett 			phr->error = HPI_ERROR_INVALID_OPERATION;
1260719f82d3SEliot Blennerhassett 			return;
1261719f82d3SEliot Blennerhassett 		}
1262719f82d3SEliot Blennerhassett 
1263719f82d3SEliot Blennerhassett 		/* either all data,
1264719f82d3SEliot Blennerhassett 		   or enough to fit from current to end of BBM buffer */
1265719f82d3SEliot Blennerhassett 		l_first_read =
1266719f82d3SEliot Blennerhassett 			min(phm->u.d.u.data.data_size,
1267719f82d3SEliot Blennerhassett 			status->size_in_bytes -
1268719f82d3SEliot Blennerhassett 			(status->host_index & (status->size_in_bytes - 1)));
1269719f82d3SEliot Blennerhassett 
1270719f82d3SEliot Blennerhassett 		memcpy(p_app_data,
1271719f82d3SEliot Blennerhassett 			p_bbm_data +
1272719f82d3SEliot Blennerhassett 			(status->host_index & (status->size_in_bytes - 1)),
1273719f82d3SEliot Blennerhassett 			l_first_read);
1274719f82d3SEliot Blennerhassett 		/* remaining data if any */
1275719f82d3SEliot Blennerhassett 		memcpy(p_app_data + l_first_read, p_bbm_data,
1276719f82d3SEliot Blennerhassett 			phm->u.d.u.data.data_size - l_first_read);
1277719f82d3SEliot Blennerhassett 	}
1278719f82d3SEliot Blennerhassett 	status->host_index += phm->u.d.u.data.data_size;
1279719f82d3SEliot Blennerhassett }
1280719f82d3SEliot Blennerhassett 
1281719f82d3SEliot Blennerhassett static void instream_get_info(struct hpi_adapter_obj *pao,
1282719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
1283719f82d3SEliot Blennerhassett {
1284719f82d3SEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
1285719f82d3SEliot Blennerhassett 	struct bus_master_interface *interface = phw->p_interface_buffer;
1286719f82d3SEliot Blennerhassett 	struct hpi_hostbuffer_status *status;
1287719f82d3SEliot Blennerhassett 	if (!phw->instream_host_buffer_size[phm->obj_index]) {
1288719f82d3SEliot Blennerhassett 		hw_message(pao, phm, phr);
1289719f82d3SEliot Blennerhassett 		return;
1290719f82d3SEliot Blennerhassett 	}
1291719f82d3SEliot Blennerhassett 
1292719f82d3SEliot Blennerhassett 	status = &interface->instream_host_buffer_status[phm->obj_index];
1293719f82d3SEliot Blennerhassett 
1294719f82d3SEliot Blennerhassett 	hpi_init_response(phr, phm->object, phm->function, 0);
1295719f82d3SEliot Blennerhassett 
1296719f82d3SEliot Blennerhassett 	phr->u.d.u.stream_info.state = (u16)status->stream_state;
1297719f82d3SEliot Blennerhassett 	phr->u.d.u.stream_info.samples_transferred =
1298719f82d3SEliot Blennerhassett 		status->samples_processed;
1299719f82d3SEliot Blennerhassett 	phr->u.d.u.stream_info.buffer_size = status->size_in_bytes;
1300719f82d3SEliot Blennerhassett 	phr->u.d.u.stream_info.data_available =
1301719f82d3SEliot Blennerhassett 		instream_get_bytes_available(status);
1302719f82d3SEliot Blennerhassett 	phr->u.d.u.stream_info.auxiliary_data_available =
1303719f82d3SEliot Blennerhassett 		status->auxiliary_data_available;
1304719f82d3SEliot Blennerhassett }
1305719f82d3SEliot Blennerhassett 
1306719f82d3SEliot Blennerhassett /*****************************************************************************/
1307719f82d3SEliot Blennerhassett /* LOW-LEVEL */
1308719f82d3SEliot Blennerhassett #define HPI6205_MAX_FILES_TO_LOAD 2
1309719f82d3SEliot Blennerhassett 
1310719f82d3SEliot Blennerhassett static u16 adapter_boot_load_dsp(struct hpi_adapter_obj *pao,
1311719f82d3SEliot Blennerhassett 	u32 *pos_error_code)
1312719f82d3SEliot Blennerhassett {
1313719f82d3SEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
1314719f82d3SEliot Blennerhassett 	struct dsp_code dsp_code;
1315719f82d3SEliot Blennerhassett 	u16 boot_code_id[HPI6205_MAX_FILES_TO_LOAD];
13163285ea10SEliot Blennerhassett 	u16 firmware_id = pao->pci.pci_dev->subsystem_device;
1317719f82d3SEliot Blennerhassett 	u32 temp;
1318719f82d3SEliot Blennerhassett 	int dsp = 0, i = 0;
1319719f82d3SEliot Blennerhassett 	u16 err = 0;
1320719f82d3SEliot Blennerhassett 
1321719f82d3SEliot Blennerhassett 	boot_code_id[0] = HPI_ADAPTER_ASI(0x6205);
1322719f82d3SEliot Blennerhassett 
1323719f82d3SEliot Blennerhassett 	/* special cases where firmware_id != subsys ID */
1324719f82d3SEliot Blennerhassett 	switch (firmware_id) {
1325719f82d3SEliot Blennerhassett 	case HPI_ADAPTER_FAMILY_ASI(0x5000):
1326719f82d3SEliot Blennerhassett 		boot_code_id[0] = firmware_id;
1327719f82d3SEliot Blennerhassett 		firmware_id = 0;
1328719f82d3SEliot Blennerhassett 		break;
1329719f82d3SEliot Blennerhassett 	case HPI_ADAPTER_FAMILY_ASI(0x5300):
1330719f82d3SEliot Blennerhassett 	case HPI_ADAPTER_FAMILY_ASI(0x5400):
1331719f82d3SEliot Blennerhassett 	case HPI_ADAPTER_FAMILY_ASI(0x6300):
1332719f82d3SEliot Blennerhassett 		firmware_id = HPI_ADAPTER_FAMILY_ASI(0x6400);
1333719f82d3SEliot Blennerhassett 		break;
1334719f82d3SEliot Blennerhassett 	case HPI_ADAPTER_FAMILY_ASI(0x5600):
1335719f82d3SEliot Blennerhassett 	case HPI_ADAPTER_FAMILY_ASI(0x6500):
1336719f82d3SEliot Blennerhassett 		firmware_id = HPI_ADAPTER_FAMILY_ASI(0x6600);
1337719f82d3SEliot Blennerhassett 		break;
1338cadae428SEliot Blennerhassett 	case HPI_ADAPTER_FAMILY_ASI(0x8800):
1339cadae428SEliot Blennerhassett 		firmware_id = HPI_ADAPTER_FAMILY_ASI(0x8900);
1340cadae428SEliot Blennerhassett 		break;
1341719f82d3SEliot Blennerhassett 	}
1342719f82d3SEliot Blennerhassett 	boot_code_id[1] = firmware_id;
1343719f82d3SEliot Blennerhassett 
1344719f82d3SEliot Blennerhassett 	/* reset DSP by writing a 1 to the WARMRESET bit */
1345719f82d3SEliot Blennerhassett 	temp = C6205_HDCR_WARMRESET;
1346719f82d3SEliot Blennerhassett 	iowrite32(temp, phw->prHDCR);
1347719f82d3SEliot Blennerhassett 	hpios_delay_micro_seconds(1000);
1348719f82d3SEliot Blennerhassett 
1349719f82d3SEliot Blennerhassett 	/* check that PCI i/f was configured by EEPROM */
1350719f82d3SEliot Blennerhassett 	temp = ioread32(phw->prHSR);
1351719f82d3SEliot Blennerhassett 	if ((temp & (C6205_HSR_CFGERR | C6205_HSR_EEREAD)) !=
1352719f82d3SEliot Blennerhassett 		C6205_HSR_EEREAD)
13533285ea10SEliot Blennerhassett 		return HPI6205_ERROR_6205_EEPROM;
1354719f82d3SEliot Blennerhassett 	temp |= 0x04;
1355719f82d3SEliot Blennerhassett 	/* disable PINTA interrupt */
1356719f82d3SEliot Blennerhassett 	iowrite32(temp, phw->prHSR);
1357719f82d3SEliot Blennerhassett 
1358719f82d3SEliot Blennerhassett 	/* check control register reports PCI boot mode */
1359719f82d3SEliot Blennerhassett 	temp = ioread32(phw->prHDCR);
1360719f82d3SEliot Blennerhassett 	if (!(temp & C6205_HDCR_PCIBOOT))
13613285ea10SEliot Blennerhassett 		return HPI6205_ERROR_6205_REG;
1362719f82d3SEliot Blennerhassett 
13633285ea10SEliot Blennerhassett 	/* try writing a few numbers to the DSP page register */
1364719f82d3SEliot Blennerhassett 	/* and reading them back. */
1365719f82d3SEliot Blennerhassett 	temp = 3;
1366719f82d3SEliot Blennerhassett 	iowrite32(temp, phw->prDSPP);
1367719f82d3SEliot Blennerhassett 	if ((temp | C6205_DSPP_MAP1) != ioread32(phw->prDSPP))
13683285ea10SEliot Blennerhassett 		return HPI6205_ERROR_6205_DSPPAGE;
13693285ea10SEliot Blennerhassett 	temp = 2;
13703285ea10SEliot Blennerhassett 	iowrite32(temp, phw->prDSPP);
13713285ea10SEliot Blennerhassett 	if ((temp | C6205_DSPP_MAP1) != ioread32(phw->prDSPP))
13723285ea10SEliot Blennerhassett 		return HPI6205_ERROR_6205_DSPPAGE;
13733285ea10SEliot Blennerhassett 	temp = 1;
13743285ea10SEliot Blennerhassett 	iowrite32(temp, phw->prDSPP);
13753285ea10SEliot Blennerhassett 	if ((temp | C6205_DSPP_MAP1) != ioread32(phw->prDSPP))
13763285ea10SEliot Blennerhassett 		return HPI6205_ERROR_6205_DSPPAGE;
1377719f82d3SEliot Blennerhassett 	/* reset DSP page to the correct number */
1378719f82d3SEliot Blennerhassett 	temp = 0;
1379719f82d3SEliot Blennerhassett 	iowrite32(temp, phw->prDSPP);
1380719f82d3SEliot Blennerhassett 	if ((temp | C6205_DSPP_MAP1) != ioread32(phw->prDSPP))
13813285ea10SEliot Blennerhassett 		return HPI6205_ERROR_6205_DSPPAGE;
1382719f82d3SEliot Blennerhassett 	phw->dsp_page = 0;
1383719f82d3SEliot Blennerhassett 
1384719f82d3SEliot Blennerhassett 	/* release 6713 from reset before 6205 is bootloaded.
1385719f82d3SEliot Blennerhassett 	   This ensures that the EMIF is inactive,
1386719f82d3SEliot Blennerhassett 	   and the 6713 HPI gets the correct bootmode etc
1387719f82d3SEliot Blennerhassett 	 */
1388719f82d3SEliot Blennerhassett 	if (boot_code_id[1] != 0) {
1389719f82d3SEliot Blennerhassett 		/* DSP 1 is a C6713 */
1390719f82d3SEliot Blennerhassett 		/* CLKX0 <- '1' release the C6205 bootmode pulldowns */
1391719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, 0, (0x018C0024L), 0x00002202);
1392719f82d3SEliot Blennerhassett 		hpios_delay_micro_seconds(100);
1393719f82d3SEliot Blennerhassett 		/* Reset the 6713 #1 - revB */
1394719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, 0, C6205_BAR0_TIMER1_CTL, 0);
1395719f82d3SEliot Blennerhassett 
1396719f82d3SEliot Blennerhassett 		/* dummy read every 4 words for 6205 advisory 1.4.4 */
1397719f82d3SEliot Blennerhassett 		boot_loader_read_mem32(pao, 0, 0);
1398719f82d3SEliot Blennerhassett 
1399719f82d3SEliot Blennerhassett 		hpios_delay_micro_seconds(100);
1400719f82d3SEliot Blennerhassett 		/* Release C6713 from reset - revB */
1401719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, 0, C6205_BAR0_TIMER1_CTL, 4);
1402719f82d3SEliot Blennerhassett 		hpios_delay_micro_seconds(100);
1403719f82d3SEliot Blennerhassett 	}
1404719f82d3SEliot Blennerhassett 
1405719f82d3SEliot Blennerhassett 	for (dsp = 0; dsp < HPI6205_MAX_FILES_TO_LOAD; dsp++) {
1406719f82d3SEliot Blennerhassett 		/* is there a DSP to load? */
1407719f82d3SEliot Blennerhassett 		if (boot_code_id[dsp] == 0)
1408719f82d3SEliot Blennerhassett 			continue;
1409719f82d3SEliot Blennerhassett 
1410719f82d3SEliot Blennerhassett 		err = boot_loader_config_emif(pao, dsp);
1411719f82d3SEliot Blennerhassett 		if (err)
1412719f82d3SEliot Blennerhassett 			return err;
1413719f82d3SEliot Blennerhassett 
1414719f82d3SEliot Blennerhassett 		err = boot_loader_test_internal_memory(pao, dsp);
1415719f82d3SEliot Blennerhassett 		if (err)
1416719f82d3SEliot Blennerhassett 			return err;
1417719f82d3SEliot Blennerhassett 
1418719f82d3SEliot Blennerhassett 		err = boot_loader_test_external_memory(pao, dsp);
1419719f82d3SEliot Blennerhassett 		if (err)
1420719f82d3SEliot Blennerhassett 			return err;
1421719f82d3SEliot Blennerhassett 
1422719f82d3SEliot Blennerhassett 		err = boot_loader_test_pld(pao, dsp);
1423719f82d3SEliot Blennerhassett 		if (err)
1424719f82d3SEliot Blennerhassett 			return err;
1425719f82d3SEliot Blennerhassett 
1426719f82d3SEliot Blennerhassett 		/* write the DSP code down into the DSPs memory */
14273285ea10SEliot Blennerhassett 		dsp_code.ps_dev = pao->pci.pci_dev;
1428719f82d3SEliot Blennerhassett 		err = hpi_dsp_code_open(boot_code_id[dsp], &dsp_code,
1429719f82d3SEliot Blennerhassett 			pos_error_code);
1430719f82d3SEliot Blennerhassett 		if (err)
1431719f82d3SEliot Blennerhassett 			return err;
1432719f82d3SEliot Blennerhassett 
1433719f82d3SEliot Blennerhassett 		while (1) {
1434719f82d3SEliot Blennerhassett 			u32 length;
1435719f82d3SEliot Blennerhassett 			u32 address;
1436719f82d3SEliot Blennerhassett 			u32 type;
1437719f82d3SEliot Blennerhassett 			u32 *pcode;
1438719f82d3SEliot Blennerhassett 
1439719f82d3SEliot Blennerhassett 			err = hpi_dsp_code_read_word(&dsp_code, &length);
1440719f82d3SEliot Blennerhassett 			if (err)
1441719f82d3SEliot Blennerhassett 				break;
1442719f82d3SEliot Blennerhassett 			if (length == 0xFFFFFFFF)
1443719f82d3SEliot Blennerhassett 				break;	/* end of code */
1444719f82d3SEliot Blennerhassett 
1445719f82d3SEliot Blennerhassett 			err = hpi_dsp_code_read_word(&dsp_code, &address);
1446719f82d3SEliot Blennerhassett 			if (err)
1447719f82d3SEliot Blennerhassett 				break;
1448719f82d3SEliot Blennerhassett 			err = hpi_dsp_code_read_word(&dsp_code, &type);
1449719f82d3SEliot Blennerhassett 			if (err)
1450719f82d3SEliot Blennerhassett 				break;
1451719f82d3SEliot Blennerhassett 			err = hpi_dsp_code_read_block(length, &dsp_code,
1452719f82d3SEliot Blennerhassett 				&pcode);
1453719f82d3SEliot Blennerhassett 			if (err)
1454719f82d3SEliot Blennerhassett 				break;
1455719f82d3SEliot Blennerhassett 			for (i = 0; i < (int)length; i++) {
14563285ea10SEliot Blennerhassett 				boot_loader_write_mem32(pao, dsp, address,
14573285ea10SEliot Blennerhassett 					*pcode);
1458719f82d3SEliot Blennerhassett 				/* dummy read every 4 words */
1459719f82d3SEliot Blennerhassett 				/* for 6205 advisory 1.4.4 */
1460719f82d3SEliot Blennerhassett 				if (i % 4 == 0)
1461719f82d3SEliot Blennerhassett 					boot_loader_read_mem32(pao, dsp,
1462719f82d3SEliot Blennerhassett 						address);
1463719f82d3SEliot Blennerhassett 				pcode++;
1464719f82d3SEliot Blennerhassett 				address += 4;
1465719f82d3SEliot Blennerhassett 			}
1466719f82d3SEliot Blennerhassett 
1467719f82d3SEliot Blennerhassett 		}
1468719f82d3SEliot Blennerhassett 		if (err) {
1469719f82d3SEliot Blennerhassett 			hpi_dsp_code_close(&dsp_code);
1470719f82d3SEliot Blennerhassett 			return err;
1471719f82d3SEliot Blennerhassett 		}
1472719f82d3SEliot Blennerhassett 
1473719f82d3SEliot Blennerhassett 		/* verify code */
1474719f82d3SEliot Blennerhassett 		hpi_dsp_code_rewind(&dsp_code);
1475719f82d3SEliot Blennerhassett 		while (1) {
1476719f82d3SEliot Blennerhassett 			u32 length = 0;
1477719f82d3SEliot Blennerhassett 			u32 address = 0;
1478719f82d3SEliot Blennerhassett 			u32 type = 0;
1479719f82d3SEliot Blennerhassett 			u32 *pcode = NULL;
1480719f82d3SEliot Blennerhassett 			u32 data = 0;
1481719f82d3SEliot Blennerhassett 
1482719f82d3SEliot Blennerhassett 			hpi_dsp_code_read_word(&dsp_code, &length);
1483719f82d3SEliot Blennerhassett 			if (length == 0xFFFFFFFF)
1484719f82d3SEliot Blennerhassett 				break;	/* end of code */
1485719f82d3SEliot Blennerhassett 
1486719f82d3SEliot Blennerhassett 			hpi_dsp_code_read_word(&dsp_code, &address);
1487719f82d3SEliot Blennerhassett 			hpi_dsp_code_read_word(&dsp_code, &type);
1488719f82d3SEliot Blennerhassett 			hpi_dsp_code_read_block(length, &dsp_code, &pcode);
1489719f82d3SEliot Blennerhassett 
1490719f82d3SEliot Blennerhassett 			for (i = 0; i < (int)length; i++) {
1491719f82d3SEliot Blennerhassett 				data = boot_loader_read_mem32(pao, dsp,
1492719f82d3SEliot Blennerhassett 					address);
1493719f82d3SEliot Blennerhassett 				if (data != *pcode) {
1494719f82d3SEliot Blennerhassett 					err = 0;
1495719f82d3SEliot Blennerhassett 					break;
1496719f82d3SEliot Blennerhassett 				}
1497719f82d3SEliot Blennerhassett 				pcode++;
1498719f82d3SEliot Blennerhassett 				address += 4;
1499719f82d3SEliot Blennerhassett 			}
1500719f82d3SEliot Blennerhassett 			if (err)
1501719f82d3SEliot Blennerhassett 				break;
1502719f82d3SEliot Blennerhassett 		}
1503719f82d3SEliot Blennerhassett 		hpi_dsp_code_close(&dsp_code);
1504719f82d3SEliot Blennerhassett 		if (err)
1505719f82d3SEliot Blennerhassett 			return err;
1506719f82d3SEliot Blennerhassett 	}
1507719f82d3SEliot Blennerhassett 
1508719f82d3SEliot Blennerhassett 	/* After bootloading all DSPs, start DSP0 running
1509719f82d3SEliot Blennerhassett 	 * The DSP0 code will handle starting and synchronizing with its slaves
1510719f82d3SEliot Blennerhassett 	 */
1511719f82d3SEliot Blennerhassett 	if (phw->p_interface_buffer) {
1512719f82d3SEliot Blennerhassett 		/* we need to tell the card the physical PCI address */
1513719f82d3SEliot Blennerhassett 		u32 physicalPC_iaddress;
1514719f82d3SEliot Blennerhassett 		struct bus_master_interface *interface =
1515719f82d3SEliot Blennerhassett 			phw->p_interface_buffer;
1516719f82d3SEliot Blennerhassett 		u32 host_mailbox_address_on_dsp;
1517719f82d3SEliot Blennerhassett 		u32 physicalPC_iaddress_verify = 0;
1518719f82d3SEliot Blennerhassett 		int time_out = 10;
1519719f82d3SEliot Blennerhassett 		/* set ack so we know when DSP is ready to go */
1520719f82d3SEliot Blennerhassett 		/* (dwDspAck will be changed to HIF_RESET) */
1521719f82d3SEliot Blennerhassett 		interface->dsp_ack = H620_HIF_UNKNOWN;
1522719f82d3SEliot Blennerhassett 		wmb();	/* ensure ack is written before dsp writes back */
1523719f82d3SEliot Blennerhassett 
1524719f82d3SEliot Blennerhassett 		err = hpios_locked_mem_get_phys_addr(&phw->h_locked_mem,
1525719f82d3SEliot Blennerhassett 			&physicalPC_iaddress);
1526719f82d3SEliot Blennerhassett 
1527719f82d3SEliot Blennerhassett 		/* locate the host mailbox on the DSP. */
1528719f82d3SEliot Blennerhassett 		host_mailbox_address_on_dsp = 0x80000000;
1529719f82d3SEliot Blennerhassett 		while ((physicalPC_iaddress != physicalPC_iaddress_verify)
1530719f82d3SEliot Blennerhassett 			&& time_out--) {
15313285ea10SEliot Blennerhassett 			boot_loader_write_mem32(pao, 0,
1532719f82d3SEliot Blennerhassett 				host_mailbox_address_on_dsp,
1533719f82d3SEliot Blennerhassett 				physicalPC_iaddress);
1534719f82d3SEliot Blennerhassett 			physicalPC_iaddress_verify =
1535719f82d3SEliot Blennerhassett 				boot_loader_read_mem32(pao, 0,
1536719f82d3SEliot Blennerhassett 				host_mailbox_address_on_dsp);
1537719f82d3SEliot Blennerhassett 		}
1538719f82d3SEliot Blennerhassett 	}
1539719f82d3SEliot Blennerhassett 	HPI_DEBUG_LOG(DEBUG, "starting DS_ps running\n");
1540719f82d3SEliot Blennerhassett 	/* enable interrupts */
1541719f82d3SEliot Blennerhassett 	temp = ioread32(phw->prHSR);
1542719f82d3SEliot Blennerhassett 	temp &= ~(u32)C6205_HSR_INTAM;
1543719f82d3SEliot Blennerhassett 	iowrite32(temp, phw->prHSR);
1544719f82d3SEliot Blennerhassett 
1545719f82d3SEliot Blennerhassett 	/* start code running... */
1546719f82d3SEliot Blennerhassett 	temp = ioread32(phw->prHDCR);
1547719f82d3SEliot Blennerhassett 	temp |= (u32)C6205_HDCR_DSPINT;
1548719f82d3SEliot Blennerhassett 	iowrite32(temp, phw->prHDCR);
1549719f82d3SEliot Blennerhassett 
1550719f82d3SEliot Blennerhassett 	/* give the DSP 10ms to start up */
1551719f82d3SEliot Blennerhassett 	hpios_delay_micro_seconds(10000);
1552719f82d3SEliot Blennerhassett 	return err;
1553719f82d3SEliot Blennerhassett 
1554719f82d3SEliot Blennerhassett }
1555719f82d3SEliot Blennerhassett 
1556719f82d3SEliot Blennerhassett /*****************************************************************************/
1557719f82d3SEliot Blennerhassett /* Bootloader utility functions */
1558719f82d3SEliot Blennerhassett 
1559719f82d3SEliot Blennerhassett static u32 boot_loader_read_mem32(struct hpi_adapter_obj *pao, int dsp_index,
1560719f82d3SEliot Blennerhassett 	u32 address)
1561719f82d3SEliot Blennerhassett {
1562719f82d3SEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
1563719f82d3SEliot Blennerhassett 	u32 data = 0;
1564719f82d3SEliot Blennerhassett 	__iomem u32 *p_data;
1565719f82d3SEliot Blennerhassett 
1566719f82d3SEliot Blennerhassett 	if (dsp_index == 0) {
1567719f82d3SEliot Blennerhassett 		/* DSP 0 is always C6205 */
1568719f82d3SEliot Blennerhassett 		if ((address >= 0x01800000) & (address < 0x02000000)) {
1569719f82d3SEliot Blennerhassett 			/* BAR1 register access */
1570719f82d3SEliot Blennerhassett 			p_data = pao->pci.ap_mem_base[1] +
1571719f82d3SEliot Blennerhassett 				(address & 0x007fffff) /
1572719f82d3SEliot Blennerhassett 				sizeof(*pao->pci.ap_mem_base[1]);
1573719f82d3SEliot Blennerhassett 			/* HPI_DEBUG_LOG(WARNING,
1574719f82d3SEliot Blennerhassett 			   "BAR1 access %08x\n", dwAddress); */
1575719f82d3SEliot Blennerhassett 		} else {
1576719f82d3SEliot Blennerhassett 			u32 dw4M_page = address >> 22L;
1577719f82d3SEliot Blennerhassett 			if (dw4M_page != phw->dsp_page) {
1578719f82d3SEliot Blennerhassett 				phw->dsp_page = dw4M_page;
1579719f82d3SEliot Blennerhassett 				/* *INDENT OFF* */
1580719f82d3SEliot Blennerhassett 				iowrite32(phw->dsp_page, phw->prDSPP);
1581719f82d3SEliot Blennerhassett 				/* *INDENT-ON* */
1582719f82d3SEliot Blennerhassett 			}
1583719f82d3SEliot Blennerhassett 			address &= 0x3fffff;	/* address within 4M page */
1584719f82d3SEliot Blennerhassett 			/* BAR0 memory access */
1585719f82d3SEliot Blennerhassett 			p_data = pao->pci.ap_mem_base[0] +
1586719f82d3SEliot Blennerhassett 				address / sizeof(u32);
1587719f82d3SEliot Blennerhassett 		}
1588719f82d3SEliot Blennerhassett 		data = ioread32(p_data);
1589719f82d3SEliot Blennerhassett 	} else if (dsp_index == 1) {
1590719f82d3SEliot Blennerhassett 		/* DSP 1 is a C6713 */
1591719f82d3SEliot Blennerhassett 		u32 lsb;
1592719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, 0, HPIAL_ADDR, address);
1593719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, 0, HPIAH_ADDR, address >> 16);
1594719f82d3SEliot Blennerhassett 		lsb = boot_loader_read_mem32(pao, 0, HPIDL_ADDR);
1595719f82d3SEliot Blennerhassett 		data = boot_loader_read_mem32(pao, 0, HPIDH_ADDR);
1596719f82d3SEliot Blennerhassett 		data = (data << 16) | (lsb & 0xFFFF);
1597719f82d3SEliot Blennerhassett 	}
1598719f82d3SEliot Blennerhassett 	return data;
1599719f82d3SEliot Blennerhassett }
1600719f82d3SEliot Blennerhassett 
16013285ea10SEliot Blennerhassett static void boot_loader_write_mem32(struct hpi_adapter_obj *pao,
16023285ea10SEliot Blennerhassett 	int dsp_index, u32 address, u32 data)
1603719f82d3SEliot Blennerhassett {
1604719f82d3SEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
1605719f82d3SEliot Blennerhassett 	__iomem u32 *p_data;
1606719f82d3SEliot Blennerhassett 	/*      u32 dwVerifyData=0; */
1607719f82d3SEliot Blennerhassett 
1608719f82d3SEliot Blennerhassett 	if (dsp_index == 0) {
1609719f82d3SEliot Blennerhassett 		/* DSP 0 is always C6205 */
1610719f82d3SEliot Blennerhassett 		if ((address >= 0x01800000) & (address < 0x02000000)) {
1611719f82d3SEliot Blennerhassett 			/* BAR1 - DSP  register access using */
1612719f82d3SEliot Blennerhassett 			/* Non-prefetchable PCI access */
1613719f82d3SEliot Blennerhassett 			p_data = pao->pci.ap_mem_base[1] +
1614719f82d3SEliot Blennerhassett 				(address & 0x007fffff) /
1615719f82d3SEliot Blennerhassett 				sizeof(*pao->pci.ap_mem_base[1]);
1616719f82d3SEliot Blennerhassett 		} else {
1617719f82d3SEliot Blennerhassett 			/* BAR0 access - all of DSP memory using */
1618719f82d3SEliot Blennerhassett 			/* pre-fetchable PCI access */
1619719f82d3SEliot Blennerhassett 			u32 dw4M_page = address >> 22L;
1620719f82d3SEliot Blennerhassett 			if (dw4M_page != phw->dsp_page) {
1621719f82d3SEliot Blennerhassett 				phw->dsp_page = dw4M_page;
1622719f82d3SEliot Blennerhassett 				/* *INDENT-OFF* */
1623719f82d3SEliot Blennerhassett 				iowrite32(phw->dsp_page, phw->prDSPP);
1624719f82d3SEliot Blennerhassett 				/* *INDENT-ON* */
1625719f82d3SEliot Blennerhassett 			}
1626719f82d3SEliot Blennerhassett 			address &= 0x3fffff;	/* address within 4M page */
1627719f82d3SEliot Blennerhassett 			p_data = pao->pci.ap_mem_base[0] +
1628719f82d3SEliot Blennerhassett 				address / sizeof(u32);
1629719f82d3SEliot Blennerhassett 		}
1630719f82d3SEliot Blennerhassett 		iowrite32(data, p_data);
1631719f82d3SEliot Blennerhassett 	} else if (dsp_index == 1) {
1632719f82d3SEliot Blennerhassett 		/* DSP 1 is a C6713 */
1633719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, 0, HPIAL_ADDR, address);
1634719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, 0, HPIAH_ADDR, address >> 16);
1635719f82d3SEliot Blennerhassett 
1636719f82d3SEliot Blennerhassett 		/* dummy read every 4 words for 6205 advisory 1.4.4 */
1637719f82d3SEliot Blennerhassett 		boot_loader_read_mem32(pao, 0, 0);
1638719f82d3SEliot Blennerhassett 
1639719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, 0, HPIDL_ADDR, data);
1640719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, 0, HPIDH_ADDR, data >> 16);
1641719f82d3SEliot Blennerhassett 
1642719f82d3SEliot Blennerhassett 		/* dummy read every 4 words for 6205 advisory 1.4.4 */
1643719f82d3SEliot Blennerhassett 		boot_loader_read_mem32(pao, 0, 0);
16443285ea10SEliot Blennerhassett 	}
1645719f82d3SEliot Blennerhassett }
1646719f82d3SEliot Blennerhassett 
1647719f82d3SEliot Blennerhassett static u16 boot_loader_config_emif(struct hpi_adapter_obj *pao, int dsp_index)
1648719f82d3SEliot Blennerhassett {
1649719f82d3SEliot Blennerhassett 	if (dsp_index == 0) {
1650719f82d3SEliot Blennerhassett 		u32 setting;
1651719f82d3SEliot Blennerhassett 
1652719f82d3SEliot Blennerhassett 		/* DSP 0 is always C6205 */
1653719f82d3SEliot Blennerhassett 
1654719f82d3SEliot Blennerhassett 		/* Set the EMIF */
1655719f82d3SEliot Blennerhassett 		/* memory map of C6205 */
1656719f82d3SEliot Blennerhassett 		/* 00000000-0000FFFF    16Kx32 internal program */
1657719f82d3SEliot Blennerhassett 		/* 00400000-00BFFFFF    CE0     2Mx32 SDRAM running @ 100MHz */
1658719f82d3SEliot Blennerhassett 
1659719f82d3SEliot Blennerhassett 		/* EMIF config */
1660719f82d3SEliot Blennerhassett 		/*------------ */
1661719f82d3SEliot Blennerhassett 		/* Global EMIF control */
1662719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, dsp_index, 0x01800000, 0x3779);
1663719f82d3SEliot Blennerhassett #define WS_OFS 28
1664719f82d3SEliot Blennerhassett #define WST_OFS 22
1665719f82d3SEliot Blennerhassett #define WH_OFS 20
1666719f82d3SEliot Blennerhassett #define RS_OFS 16
1667719f82d3SEliot Blennerhassett #define RST_OFS 8
1668719f82d3SEliot Blennerhassett #define MTYPE_OFS 4
1669719f82d3SEliot Blennerhassett #define RH_OFS 0
1670719f82d3SEliot Blennerhassett 
1671719f82d3SEliot Blennerhassett 		/* EMIF CE0 setup - 2Mx32 Sync DRAM on ASI5000 cards only */
1672719f82d3SEliot Blennerhassett 		setting = 0x00000030;
1673719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, dsp_index, 0x01800008, setting);
1674719f82d3SEliot Blennerhassett 		if (setting != boot_loader_read_mem32(pao, dsp_index,
1675719f82d3SEliot Blennerhassett 				0x01800008))
16763285ea10SEliot Blennerhassett 			return HPI6205_ERROR_DSP_EMIF;
1677719f82d3SEliot Blennerhassett 
1678719f82d3SEliot Blennerhassett 		/* EMIF CE1 setup - 32 bit async. This is 6713 #1 HPI, */
1679719f82d3SEliot Blennerhassett 		/* which occupies D15..0. 6713 starts at 27MHz, so need */
1680719f82d3SEliot Blennerhassett 		/* plenty of wait states. See dsn8701.rtf, and 6713 errata. */
1681719f82d3SEliot Blennerhassett 		/* WST should be 71, but 63  is max possible */
1682719f82d3SEliot Blennerhassett 		setting =
1683719f82d3SEliot Blennerhassett 			(1L << WS_OFS) | (63L << WST_OFS) | (1L << WH_OFS) |
1684719f82d3SEliot Blennerhassett 			(1L << RS_OFS) | (63L << RST_OFS) | (1L << RH_OFS) |
1685719f82d3SEliot Blennerhassett 			(2L << MTYPE_OFS);
1686719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, dsp_index, 0x01800004, setting);
1687719f82d3SEliot Blennerhassett 		if (setting != boot_loader_read_mem32(pao, dsp_index,
1688719f82d3SEliot Blennerhassett 				0x01800004))
16893285ea10SEliot Blennerhassett 			return HPI6205_ERROR_DSP_EMIF;
1690719f82d3SEliot Blennerhassett 
1691719f82d3SEliot Blennerhassett 		/* EMIF CE2 setup - 32 bit async. This is 6713 #2 HPI, */
1692719f82d3SEliot Blennerhassett 		/* which occupies D15..0. 6713 starts at 27MHz, so need */
1693719f82d3SEliot Blennerhassett 		/* plenty of wait states */
1694719f82d3SEliot Blennerhassett 		setting =
1695719f82d3SEliot Blennerhassett 			(1L << WS_OFS) | (28L << WST_OFS) | (1L << WH_OFS) |
1696719f82d3SEliot Blennerhassett 			(1L << RS_OFS) | (63L << RST_OFS) | (1L << RH_OFS) |
1697719f82d3SEliot Blennerhassett 			(2L << MTYPE_OFS);
1698719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, dsp_index, 0x01800010, setting);
1699719f82d3SEliot Blennerhassett 		if (setting != boot_loader_read_mem32(pao, dsp_index,
1700719f82d3SEliot Blennerhassett 				0x01800010))
17013285ea10SEliot Blennerhassett 			return HPI6205_ERROR_DSP_EMIF;
1702719f82d3SEliot Blennerhassett 
1703719f82d3SEliot Blennerhassett 		/* EMIF CE3 setup - 32 bit async. */
1704719f82d3SEliot Blennerhassett 		/* This is the PLD on the ASI5000 cards only */
1705719f82d3SEliot Blennerhassett 		setting =
1706719f82d3SEliot Blennerhassett 			(1L << WS_OFS) | (10L << WST_OFS) | (1L << WH_OFS) |
1707719f82d3SEliot Blennerhassett 			(1L << RS_OFS) | (10L << RST_OFS) | (1L << RH_OFS) |
1708719f82d3SEliot Blennerhassett 			(2L << MTYPE_OFS);
1709719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, dsp_index, 0x01800014, setting);
1710719f82d3SEliot Blennerhassett 		if (setting != boot_loader_read_mem32(pao, dsp_index,
1711719f82d3SEliot Blennerhassett 				0x01800014))
17123285ea10SEliot Blennerhassett 			return HPI6205_ERROR_DSP_EMIF;
1713719f82d3SEliot Blennerhassett 
1714719f82d3SEliot Blennerhassett 		/* set EMIF SDRAM control for 2Mx32 SDRAM (512x32x4 bank) */
1715719f82d3SEliot Blennerhassett 		/*  need to use this else DSP code crashes? */
1716719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, dsp_index, 0x01800018,
1717719f82d3SEliot Blennerhassett 			0x07117000);
1718719f82d3SEliot Blennerhassett 
1719719f82d3SEliot Blennerhassett 		/* EMIF SDRAM Refresh Timing */
1720719f82d3SEliot Blennerhassett 		/* EMIF SDRAM timing  (orig = 0x410, emulator = 0x61a) */
1721719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, dsp_index, 0x0180001C,
1722719f82d3SEliot Blennerhassett 			0x00000410);
1723719f82d3SEliot Blennerhassett 
1724719f82d3SEliot Blennerhassett 	} else if (dsp_index == 1) {
1725719f82d3SEliot Blennerhassett 		/* test access to the C6713s HPI registers */
1726719f82d3SEliot Blennerhassett 		u32 write_data = 0, read_data = 0, i = 0;
1727719f82d3SEliot Blennerhassett 
1728719f82d3SEliot Blennerhassett 		/* Set up HPIC for little endian, by setiing HPIC:HWOB=1 */
1729719f82d3SEliot Blennerhassett 		write_data = 1;
1730719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, 0, HPICL_ADDR, write_data);
1731719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, 0, HPICH_ADDR, write_data);
1732719f82d3SEliot Blennerhassett 		/* C67 HPI is on lower 16bits of 32bit EMIF */
1733719f82d3SEliot Blennerhassett 		read_data =
1734719f82d3SEliot Blennerhassett 			0xFFF7 & boot_loader_read_mem32(pao, 0, HPICL_ADDR);
1735719f82d3SEliot Blennerhassett 		if (write_data != read_data) {
1736719f82d3SEliot Blennerhassett 			HPI_DEBUG_LOG(ERROR, "HPICL %x %x\n", write_data,
1737719f82d3SEliot Blennerhassett 				read_data);
17383285ea10SEliot Blennerhassett 			return HPI6205_ERROR_C6713_HPIC;
1739719f82d3SEliot Blennerhassett 		}
1740719f82d3SEliot Blennerhassett 		/* HPIA - walking ones test */
1741719f82d3SEliot Blennerhassett 		write_data = 1;
1742719f82d3SEliot Blennerhassett 		for (i = 0; i < 32; i++) {
1743719f82d3SEliot Blennerhassett 			boot_loader_write_mem32(pao, 0, HPIAL_ADDR,
1744719f82d3SEliot Blennerhassett 				write_data);
1745719f82d3SEliot Blennerhassett 			boot_loader_write_mem32(pao, 0, HPIAH_ADDR,
1746719f82d3SEliot Blennerhassett 				(write_data >> 16));
1747719f82d3SEliot Blennerhassett 			read_data =
1748719f82d3SEliot Blennerhassett 				0xFFFF & boot_loader_read_mem32(pao, 0,
1749719f82d3SEliot Blennerhassett 				HPIAL_ADDR);
1750719f82d3SEliot Blennerhassett 			read_data =
1751719f82d3SEliot Blennerhassett 				read_data | ((0xFFFF &
1752719f82d3SEliot Blennerhassett 					boot_loader_read_mem32(pao, 0,
1753719f82d3SEliot Blennerhassett 						HPIAH_ADDR))
1754719f82d3SEliot Blennerhassett 				<< 16);
1755719f82d3SEliot Blennerhassett 			if (read_data != write_data) {
1756719f82d3SEliot Blennerhassett 				HPI_DEBUG_LOG(ERROR, "HPIA %x %x\n",
1757719f82d3SEliot Blennerhassett 					write_data, read_data);
17583285ea10SEliot Blennerhassett 				return HPI6205_ERROR_C6713_HPIA;
1759719f82d3SEliot Blennerhassett 			}
1760719f82d3SEliot Blennerhassett 			write_data = write_data << 1;
1761719f82d3SEliot Blennerhassett 		}
1762719f82d3SEliot Blennerhassett 
1763719f82d3SEliot Blennerhassett 		/* setup C67x PLL
1764719f82d3SEliot Blennerhassett 		 *  ** C6713 datasheet says we cannot program PLL from HPI,
1765719f82d3SEliot Blennerhassett 		 * and indeed if we try to set the PLL multiply from the HPI,
1766719f82d3SEliot Blennerhassett 		 * the PLL does not seem to lock, so we enable the PLL and
1767719f82d3SEliot Blennerhassett 		 * use the default multiply of x 7, which for a 27MHz clock
1768719f82d3SEliot Blennerhassett 		 * gives a DSP speed of 189MHz
1769719f82d3SEliot Blennerhassett 		 */
1770719f82d3SEliot Blennerhassett 		/* bypass PLL */
1771719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, dsp_index, 0x01B7C100, 0x0000);
1772719f82d3SEliot Blennerhassett 		hpios_delay_micro_seconds(1000);
1773719f82d3SEliot Blennerhassett 		/* EMIF = 189/3=63MHz */
1774719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, dsp_index, 0x01B7C120, 0x8002);
1775719f82d3SEliot Blennerhassett 		/* peri = 189/2 */
1776719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, dsp_index, 0x01B7C11C, 0x8001);
1777719f82d3SEliot Blennerhassett 		/* cpu  = 189/1 */
1778719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, dsp_index, 0x01B7C118, 0x8000);
1779719f82d3SEliot Blennerhassett 		hpios_delay_micro_seconds(1000);
1780719f82d3SEliot Blennerhassett 		/* ** SGT test to take GPO3 high when we start the PLL */
1781719f82d3SEliot Blennerhassett 		/* and low when the delay is completed */
1782719f82d3SEliot Blennerhassett 		/* FSX0 <- '1' (GPO3) */
1783719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, 0, (0x018C0024L), 0x00002A0A);
1784719f82d3SEliot Blennerhassett 		/* PLL not bypassed */
1785719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, dsp_index, 0x01B7C100, 0x0001);
1786719f82d3SEliot Blennerhassett 		hpios_delay_micro_seconds(1000);
1787719f82d3SEliot Blennerhassett 		/* FSX0 <- '0' (GPO3) */
1788719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, 0, (0x018C0024L), 0x00002A02);
1789719f82d3SEliot Blennerhassett 
1790719f82d3SEliot Blennerhassett 		/* 6205 EMIF CE1 resetup - 32 bit async. */
1791719f82d3SEliot Blennerhassett 		/* Now 6713 #1 is running at 189MHz can reduce waitstates */
1792719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, 0, 0x01800004,	/* CE1 */
1793719f82d3SEliot Blennerhassett 			(1L << WS_OFS) | (8L << WST_OFS) | (1L << WH_OFS) |
1794719f82d3SEliot Blennerhassett 			(1L << RS_OFS) | (12L << RST_OFS) | (1L << RH_OFS) |
1795719f82d3SEliot Blennerhassett 			(2L << MTYPE_OFS));
1796719f82d3SEliot Blennerhassett 
1797719f82d3SEliot Blennerhassett 		hpios_delay_micro_seconds(1000);
1798719f82d3SEliot Blennerhassett 
1799719f82d3SEliot Blennerhassett 		/* check that we can read one of the PLL registers */
1800719f82d3SEliot Blennerhassett 		/* PLL should not be bypassed! */
1801719f82d3SEliot Blennerhassett 		if ((boot_loader_read_mem32(pao, dsp_index, 0x01B7C100) & 0xF)
1802719f82d3SEliot Blennerhassett 			!= 0x0001) {
18033285ea10SEliot Blennerhassett 			return HPI6205_ERROR_C6713_PLL;
1804719f82d3SEliot Blennerhassett 		}
1805719f82d3SEliot Blennerhassett 		/* setup C67x EMIF  (note this is the only use of
1806719f82d3SEliot Blennerhassett 		   BAR1 via BootLoader_WriteMem32) */
1807719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, dsp_index, C6713_EMIF_GCTL,
1808719f82d3SEliot Blennerhassett 			0x000034A8);
1809719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, dsp_index, C6713_EMIF_CE0,
1810719f82d3SEliot Blennerhassett 			0x00000030);
1811719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, dsp_index, C6713_EMIF_SDRAMEXT,
1812719f82d3SEliot Blennerhassett 			0x001BDF29);
1813719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, dsp_index, C6713_EMIF_SDRAMCTL,
1814719f82d3SEliot Blennerhassett 			0x47117000);
1815719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, dsp_index,
1816719f82d3SEliot Blennerhassett 			C6713_EMIF_SDRAMTIMING, 0x00000410);
1817719f82d3SEliot Blennerhassett 
1818719f82d3SEliot Blennerhassett 		hpios_delay_micro_seconds(1000);
1819719f82d3SEliot Blennerhassett 	} else if (dsp_index == 2) {
1820719f82d3SEliot Blennerhassett 		/* DSP 2 is a C6713 */
18213285ea10SEliot Blennerhassett 	}
1822719f82d3SEliot Blennerhassett 
18233285ea10SEliot Blennerhassett 	return 0;
1824719f82d3SEliot Blennerhassett }
1825719f82d3SEliot Blennerhassett 
1826719f82d3SEliot Blennerhassett static u16 boot_loader_test_memory(struct hpi_adapter_obj *pao, int dsp_index,
1827719f82d3SEliot Blennerhassett 	u32 start_address, u32 length)
1828719f82d3SEliot Blennerhassett {
1829719f82d3SEliot Blennerhassett 	u32 i = 0, j = 0;
1830719f82d3SEliot Blennerhassett 	u32 test_addr = 0;
1831719f82d3SEliot Blennerhassett 	u32 test_data = 0, data = 0;
1832719f82d3SEliot Blennerhassett 
1833719f82d3SEliot Blennerhassett 	length = 1000;
1834719f82d3SEliot Blennerhassett 
1835719f82d3SEliot Blennerhassett 	/* for 1st word, test each bit in the 32bit word, */
1836719f82d3SEliot Blennerhassett 	/* dwLength specifies number of 32bit words to test */
1837719f82d3SEliot Blennerhassett 	/*for(i=0; i<dwLength; i++) */
1838719f82d3SEliot Blennerhassett 	i = 0;
1839719f82d3SEliot Blennerhassett 	{
1840719f82d3SEliot Blennerhassett 		test_addr = start_address + i * 4;
1841719f82d3SEliot Blennerhassett 		test_data = 0x00000001;
1842719f82d3SEliot Blennerhassett 		for (j = 0; j < 32; j++) {
1843719f82d3SEliot Blennerhassett 			boot_loader_write_mem32(pao, dsp_index, test_addr,
1844719f82d3SEliot Blennerhassett 				test_data);
1845719f82d3SEliot Blennerhassett 			data = boot_loader_read_mem32(pao, dsp_index,
1846719f82d3SEliot Blennerhassett 				test_addr);
1847719f82d3SEliot Blennerhassett 			if (data != test_data) {
1848719f82d3SEliot Blennerhassett 				HPI_DEBUG_LOG(VERBOSE,
18493285ea10SEliot Blennerhassett 					"Memtest error details  "
1850719f82d3SEliot Blennerhassett 					"%08x %08x %08x %i\n", test_addr,
1851719f82d3SEliot Blennerhassett 					test_data, data, dsp_index);
1852719f82d3SEliot Blennerhassett 				return 1;	/* error */
1853719f82d3SEliot Blennerhassett 			}
1854719f82d3SEliot Blennerhassett 			test_data = test_data << 1;
1855719f82d3SEliot Blennerhassett 		}	/* for(j) */
1856719f82d3SEliot Blennerhassett 	}	/* for(i) */
1857719f82d3SEliot Blennerhassett 
1858719f82d3SEliot Blennerhassett 	/* for the next 100 locations test each location, leaving it as zero */
1859719f82d3SEliot Blennerhassett 	/* write a zero to the next word in memory before we read */
1860719f82d3SEliot Blennerhassett 	/* the previous write to make sure every memory location is unique */
1861719f82d3SEliot Blennerhassett 	for (i = 0; i < 100; i++) {
1862719f82d3SEliot Blennerhassett 		test_addr = start_address + i * 4;
1863719f82d3SEliot Blennerhassett 		test_data = 0xA5A55A5A;
1864719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, dsp_index, test_addr, test_data);
1865719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, dsp_index, test_addr + 4, 0);
1866719f82d3SEliot Blennerhassett 		data = boot_loader_read_mem32(pao, dsp_index, test_addr);
1867719f82d3SEliot Blennerhassett 		if (data != test_data) {
1868719f82d3SEliot Blennerhassett 			HPI_DEBUG_LOG(VERBOSE,
18693285ea10SEliot Blennerhassett 				"Memtest error details  "
1870719f82d3SEliot Blennerhassett 				"%08x %08x %08x %i\n", test_addr, test_data,
1871719f82d3SEliot Blennerhassett 				data, dsp_index);
1872719f82d3SEliot Blennerhassett 			return 1;	/* error */
1873719f82d3SEliot Blennerhassett 		}
1874719f82d3SEliot Blennerhassett 		/* leave location as zero */
1875719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, dsp_index, test_addr, 0x0);
1876719f82d3SEliot Blennerhassett 	}
1877719f82d3SEliot Blennerhassett 
1878719f82d3SEliot Blennerhassett 	/* zero out entire memory block */
1879719f82d3SEliot Blennerhassett 	for (i = 0; i < length; i++) {
1880719f82d3SEliot Blennerhassett 		test_addr = start_address + i * 4;
1881719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, dsp_index, test_addr, 0x0);
1882719f82d3SEliot Blennerhassett 	}
1883719f82d3SEliot Blennerhassett 	return 0;
1884719f82d3SEliot Blennerhassett }
1885719f82d3SEliot Blennerhassett 
1886719f82d3SEliot Blennerhassett static u16 boot_loader_test_internal_memory(struct hpi_adapter_obj *pao,
1887719f82d3SEliot Blennerhassett 	int dsp_index)
1888719f82d3SEliot Blennerhassett {
1889719f82d3SEliot Blennerhassett 	int err = 0;
1890719f82d3SEliot Blennerhassett 	if (dsp_index == 0) {
1891719f82d3SEliot Blennerhassett 		/* DSP 0 is a C6205 */
1892719f82d3SEliot Blennerhassett 		/* 64K prog mem */
1893719f82d3SEliot Blennerhassett 		err = boot_loader_test_memory(pao, dsp_index, 0x00000000,
1894719f82d3SEliot Blennerhassett 			0x10000);
1895719f82d3SEliot Blennerhassett 		if (!err)
1896719f82d3SEliot Blennerhassett 			/* 64K data mem */
1897719f82d3SEliot Blennerhassett 			err = boot_loader_test_memory(pao, dsp_index,
1898719f82d3SEliot Blennerhassett 				0x80000000, 0x10000);
18993285ea10SEliot Blennerhassett 	} else if (dsp_index == 1) {
19003285ea10SEliot Blennerhassett 		/* DSP 1 is a C6713 */
1901719f82d3SEliot Blennerhassett 		/* 192K internal mem */
1902719f82d3SEliot Blennerhassett 		err = boot_loader_test_memory(pao, dsp_index, 0x00000000,
1903719f82d3SEliot Blennerhassett 			0x30000);
1904719f82d3SEliot Blennerhassett 		if (!err)
1905719f82d3SEliot Blennerhassett 			/* 64K internal mem / L2 cache */
1906719f82d3SEliot Blennerhassett 			err = boot_loader_test_memory(pao, dsp_index,
1907719f82d3SEliot Blennerhassett 				0x00030000, 0x10000);
19083285ea10SEliot Blennerhassett 	}
1909719f82d3SEliot Blennerhassett 
1910719f82d3SEliot Blennerhassett 	if (err)
19113285ea10SEliot Blennerhassett 		return HPI6205_ERROR_DSP_INTMEM;
1912719f82d3SEliot Blennerhassett 	else
1913719f82d3SEliot Blennerhassett 		return 0;
1914719f82d3SEliot Blennerhassett }
1915719f82d3SEliot Blennerhassett 
1916719f82d3SEliot Blennerhassett static u16 boot_loader_test_external_memory(struct hpi_adapter_obj *pao,
1917719f82d3SEliot Blennerhassett 	int dsp_index)
1918719f82d3SEliot Blennerhassett {
1919719f82d3SEliot Blennerhassett 	u32 dRAM_start_address = 0;
1920719f82d3SEliot Blennerhassett 	u32 dRAM_size = 0;
1921719f82d3SEliot Blennerhassett 
1922719f82d3SEliot Blennerhassett 	if (dsp_index == 0) {
1923719f82d3SEliot Blennerhassett 		/* only test for SDRAM if an ASI5000 card */
19243285ea10SEliot Blennerhassett 		if (pao->pci.pci_dev->subsystem_device == 0x5000) {
1925719f82d3SEliot Blennerhassett 			/* DSP 0 is always C6205 */
1926719f82d3SEliot Blennerhassett 			dRAM_start_address = 0x00400000;
1927719f82d3SEliot Blennerhassett 			dRAM_size = 0x200000;
1928719f82d3SEliot Blennerhassett 			/*dwDRAMinc=1024; */
1929719f82d3SEliot Blennerhassett 		} else
1930719f82d3SEliot Blennerhassett 			return 0;
19313285ea10SEliot Blennerhassett 	} else if (dsp_index == 1) {
1932719f82d3SEliot Blennerhassett 		/* DSP 1 is a C6713 */
1933719f82d3SEliot Blennerhassett 		dRAM_start_address = 0x80000000;
1934719f82d3SEliot Blennerhassett 		dRAM_size = 0x200000;
1935719f82d3SEliot Blennerhassett 		/*dwDRAMinc=1024; */
19363285ea10SEliot Blennerhassett 	}
1937719f82d3SEliot Blennerhassett 
1938719f82d3SEliot Blennerhassett 	if (boot_loader_test_memory(pao, dsp_index, dRAM_start_address,
1939719f82d3SEliot Blennerhassett 			dRAM_size))
19403285ea10SEliot Blennerhassett 		return HPI6205_ERROR_DSP_EXTMEM;
1941719f82d3SEliot Blennerhassett 	return 0;
1942719f82d3SEliot Blennerhassett }
1943719f82d3SEliot Blennerhassett 
1944719f82d3SEliot Blennerhassett static u16 boot_loader_test_pld(struct hpi_adapter_obj *pao, int dsp_index)
1945719f82d3SEliot Blennerhassett {
1946719f82d3SEliot Blennerhassett 	u32 data = 0;
1947719f82d3SEliot Blennerhassett 	if (dsp_index == 0) {
1948719f82d3SEliot Blennerhassett 		/* only test for DSP0 PLD on ASI5000 card */
19493285ea10SEliot Blennerhassett 		if (pao->pci.pci_dev->subsystem_device == 0x5000) {
1950719f82d3SEliot Blennerhassett 			/* PLD is located at CE3=0x03000000 */
1951719f82d3SEliot Blennerhassett 			data = boot_loader_read_mem32(pao, dsp_index,
1952719f82d3SEliot Blennerhassett 				0x03000008);
1953719f82d3SEliot Blennerhassett 			if ((data & 0xF) != 0x5)
19543285ea10SEliot Blennerhassett 				return HPI6205_ERROR_DSP_PLD;
1955719f82d3SEliot Blennerhassett 			data = boot_loader_read_mem32(pao, dsp_index,
1956719f82d3SEliot Blennerhassett 				0x0300000C);
1957719f82d3SEliot Blennerhassett 			if ((data & 0xF) != 0xA)
19583285ea10SEliot Blennerhassett 				return HPI6205_ERROR_DSP_PLD;
1959719f82d3SEliot Blennerhassett 		}
1960719f82d3SEliot Blennerhassett 	} else if (dsp_index == 1) {
1961719f82d3SEliot Blennerhassett 		/* DSP 1 is a C6713 */
19623285ea10SEliot Blennerhassett 		if (pao->pci.pci_dev->subsystem_device == 0x8700) {
1963719f82d3SEliot Blennerhassett 			/* PLD is located at CE1=0x90000000 */
1964719f82d3SEliot Blennerhassett 			data = boot_loader_read_mem32(pao, dsp_index,
1965719f82d3SEliot Blennerhassett 				0x90000010);
1966719f82d3SEliot Blennerhassett 			if ((data & 0xFF) != 0xAA)
19673285ea10SEliot Blennerhassett 				return HPI6205_ERROR_DSP_PLD;
1968719f82d3SEliot Blennerhassett 			/* 8713 - LED on */
1969719f82d3SEliot Blennerhassett 			boot_loader_write_mem32(pao, dsp_index, 0x90000000,
1970719f82d3SEliot Blennerhassett 				0x02);
1971719f82d3SEliot Blennerhassett 		}
1972719f82d3SEliot Blennerhassett 	}
1973719f82d3SEliot Blennerhassett 	return 0;
1974719f82d3SEliot Blennerhassett }
1975719f82d3SEliot Blennerhassett 
1976719f82d3SEliot Blennerhassett /** Transfer data to or from DSP
1977719f82d3SEliot Blennerhassett  nOperation = H620_H620_HIF_SEND_DATA or H620_HIF_GET_DATA
1978719f82d3SEliot Blennerhassett */
1979719f82d3SEliot Blennerhassett static short hpi6205_transfer_data(struct hpi_adapter_obj *pao, u8 *p_data,
1980719f82d3SEliot Blennerhassett 	u32 data_size, int operation)
1981719f82d3SEliot Blennerhassett {
1982719f82d3SEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
1983719f82d3SEliot Blennerhassett 	u32 data_transferred = 0;
1984719f82d3SEliot Blennerhassett 	u16 err = 0;
1985719f82d3SEliot Blennerhassett #ifndef HPI6205_NO_HSR_POLL
1986719f82d3SEliot Blennerhassett 	u32 time_out;
1987719f82d3SEliot Blennerhassett #endif
1988719f82d3SEliot Blennerhassett 	u32 temp2;
1989719f82d3SEliot Blennerhassett 	struct bus_master_interface *interface = phw->p_interface_buffer;
1990719f82d3SEliot Blennerhassett 
1991719f82d3SEliot Blennerhassett 	if (!p_data)
1992deb21a23SEliot Blennerhassett 		return HPI_ERROR_INVALID_DATA_POINTER;
1993719f82d3SEliot Blennerhassett 
1994719f82d3SEliot Blennerhassett 	data_size &= ~3L;	/* round data_size down to nearest 4 bytes */
1995719f82d3SEliot Blennerhassett 
1996719f82d3SEliot Blennerhassett 	/* make sure state is IDLE */
1997719f82d3SEliot Blennerhassett 	if (!wait_dsp_ack(phw, H620_HIF_IDLE, HPI6205_TIMEOUT))
1998719f82d3SEliot Blennerhassett 		return HPI_ERROR_DSP_HARDWARE;
1999719f82d3SEliot Blennerhassett 
2000719f82d3SEliot Blennerhassett 	while (data_transferred < data_size) {
2001719f82d3SEliot Blennerhassett 		u32 this_copy = data_size - data_transferred;
2002719f82d3SEliot Blennerhassett 
2003719f82d3SEliot Blennerhassett 		if (this_copy > HPI6205_SIZEOF_DATA)
2004719f82d3SEliot Blennerhassett 			this_copy = HPI6205_SIZEOF_DATA;
2005719f82d3SEliot Blennerhassett 
2006719f82d3SEliot Blennerhassett 		if (operation == H620_HIF_SEND_DATA)
2007719f82d3SEliot Blennerhassett 			memcpy((void *)&interface->u.b_data[0],
2008719f82d3SEliot Blennerhassett 				&p_data[data_transferred], this_copy);
2009719f82d3SEliot Blennerhassett 
2010719f82d3SEliot Blennerhassett 		interface->transfer_size_in_bytes = this_copy;
2011719f82d3SEliot Blennerhassett 
2012719f82d3SEliot Blennerhassett #ifdef HPI6205_NO_HSR_POLL
2013719f82d3SEliot Blennerhassett 		/* DSP must change this back to nOperation */
2014719f82d3SEliot Blennerhassett 		interface->dsp_ack = H620_HIF_IDLE;
2015719f82d3SEliot Blennerhassett #endif
2016719f82d3SEliot Blennerhassett 
2017719f82d3SEliot Blennerhassett 		send_dsp_command(phw, operation);
2018719f82d3SEliot Blennerhassett 
2019719f82d3SEliot Blennerhassett #ifdef HPI6205_NO_HSR_POLL
2020719f82d3SEliot Blennerhassett 		temp2 = wait_dsp_ack(phw, operation, HPI6205_TIMEOUT);
2021719f82d3SEliot Blennerhassett 		HPI_DEBUG_LOG(DEBUG, "spun %d times for data xfer of %d\n",
2022719f82d3SEliot Blennerhassett 			HPI6205_TIMEOUT - temp2, this_copy);
2023719f82d3SEliot Blennerhassett 
2024719f82d3SEliot Blennerhassett 		if (!temp2) {
2025719f82d3SEliot Blennerhassett 			/* timed out */
2026719f82d3SEliot Blennerhassett 			HPI_DEBUG_LOG(ERROR,
20273285ea10SEliot Blennerhassett 				"Timed out waiting for " "state %d got %d\n",
2028719f82d3SEliot Blennerhassett 				operation, interface->dsp_ack);
2029719f82d3SEliot Blennerhassett 
2030719f82d3SEliot Blennerhassett 			break;
2031719f82d3SEliot Blennerhassett 		}
2032719f82d3SEliot Blennerhassett #else
2033719f82d3SEliot Blennerhassett 		/* spin waiting on the result */
2034719f82d3SEliot Blennerhassett 		time_out = HPI6205_TIMEOUT;
2035719f82d3SEliot Blennerhassett 		temp2 = 0;
2036719f82d3SEliot Blennerhassett 		while ((temp2 == 0) && time_out--) {
2037719f82d3SEliot Blennerhassett 			/* give 16k bus mastering transfer time to happen */
2038719f82d3SEliot Blennerhassett 			/*(16k / 132Mbytes/s = 122usec) */
2039719f82d3SEliot Blennerhassett 			hpios_delay_micro_seconds(20);
2040719f82d3SEliot Blennerhassett 			temp2 = ioread32(phw->prHSR);
2041719f82d3SEliot Blennerhassett 			temp2 &= C6205_HSR_INTSRC;
2042719f82d3SEliot Blennerhassett 		}
2043719f82d3SEliot Blennerhassett 		HPI_DEBUG_LOG(DEBUG, "spun %d times for data xfer of %d\n",
2044719f82d3SEliot Blennerhassett 			HPI6205_TIMEOUT - time_out, this_copy);
2045719f82d3SEliot Blennerhassett 		if (temp2 == C6205_HSR_INTSRC) {
2046719f82d3SEliot Blennerhassett 			HPI_DEBUG_LOG(VERBOSE,
20473285ea10SEliot Blennerhassett 				"Interrupt from HIF <data> OK\n");
2048719f82d3SEliot Blennerhassett 			/*
2049719f82d3SEliot Blennerhassett 			   if(interface->dwDspAck != nOperation) {
2050719f82d3SEliot Blennerhassett 			   HPI_DEBUG_LOG(DEBUG("interface->dwDspAck=%d,
2051719f82d3SEliot Blennerhassett 			   expected %d \n",
2052719f82d3SEliot Blennerhassett 			   interface->dwDspAck,nOperation);
2053719f82d3SEliot Blennerhassett 			   }
2054719f82d3SEliot Blennerhassett 			 */
2055719f82d3SEliot Blennerhassett 		}
2056719f82d3SEliot Blennerhassett /* need to handle this differently... */
2057719f82d3SEliot Blennerhassett 		else {
2058719f82d3SEliot Blennerhassett 			HPI_DEBUG_LOG(ERROR,
20593285ea10SEliot Blennerhassett 				"Interrupt from HIF <data> BAD\n");
2060719f82d3SEliot Blennerhassett 			err = HPI_ERROR_DSP_HARDWARE;
2061719f82d3SEliot Blennerhassett 		}
2062719f82d3SEliot Blennerhassett 
2063719f82d3SEliot Blennerhassett 		/* reset the interrupt from the DSP */
2064719f82d3SEliot Blennerhassett 		iowrite32(C6205_HSR_INTSRC, phw->prHSR);
2065719f82d3SEliot Blennerhassett #endif
2066719f82d3SEliot Blennerhassett 		if (operation == H620_HIF_GET_DATA)
2067719f82d3SEliot Blennerhassett 			memcpy(&p_data[data_transferred],
2068719f82d3SEliot Blennerhassett 				(void *)&interface->u.b_data[0], this_copy);
2069719f82d3SEliot Blennerhassett 
2070719f82d3SEliot Blennerhassett 		data_transferred += this_copy;
2071719f82d3SEliot Blennerhassett 	}
2072719f82d3SEliot Blennerhassett 	if (interface->dsp_ack != operation)
2073719f82d3SEliot Blennerhassett 		HPI_DEBUG_LOG(DEBUG, "interface->dsp_ack=%d, expected %d\n",
2074719f82d3SEliot Blennerhassett 			interface->dsp_ack, operation);
2075719f82d3SEliot Blennerhassett 	/*                      err=HPI_ERROR_DSP_HARDWARE; */
2076719f82d3SEliot Blennerhassett 
2077719f82d3SEliot Blennerhassett 	send_dsp_command(phw, H620_HIF_IDLE);
2078719f82d3SEliot Blennerhassett 
2079719f82d3SEliot Blennerhassett 	return err;
2080719f82d3SEliot Blennerhassett }
2081719f82d3SEliot Blennerhassett 
2082719f82d3SEliot Blennerhassett /* wait for up to timeout_us microseconds for the DSP
2083719f82d3SEliot Blennerhassett    to signal state by DMA into dwDspAck
2084719f82d3SEliot Blennerhassett */
2085719f82d3SEliot Blennerhassett static int wait_dsp_ack(struct hpi_hw_obj *phw, int state, int timeout_us)
2086719f82d3SEliot Blennerhassett {
2087719f82d3SEliot Blennerhassett 	struct bus_master_interface *interface = phw->p_interface_buffer;
2088719f82d3SEliot Blennerhassett 	int t = timeout_us / 4;
2089719f82d3SEliot Blennerhassett 
2090719f82d3SEliot Blennerhassett 	rmb();	/* ensure interface->dsp_ack is up to date */
2091719f82d3SEliot Blennerhassett 	while ((interface->dsp_ack != state) && --t) {
2092719f82d3SEliot Blennerhassett 		hpios_delay_micro_seconds(4);
2093719f82d3SEliot Blennerhassett 		rmb();	/* DSP changes dsp_ack by DMA */
2094719f82d3SEliot Blennerhassett 	}
2095719f82d3SEliot Blennerhassett 
2096719f82d3SEliot Blennerhassett 	/*HPI_DEBUG_LOG(VERBOSE, "Spun %d for %d\n", timeout_us/4-t, state); */
2097719f82d3SEliot Blennerhassett 	return t * 4;
2098719f82d3SEliot Blennerhassett }
2099719f82d3SEliot Blennerhassett 
2100719f82d3SEliot Blennerhassett /* set the busmaster interface to cmd, then interrupt the DSP */
2101719f82d3SEliot Blennerhassett static void send_dsp_command(struct hpi_hw_obj *phw, int cmd)
2102719f82d3SEliot Blennerhassett {
2103719f82d3SEliot Blennerhassett 	struct bus_master_interface *interface = phw->p_interface_buffer;
2104719f82d3SEliot Blennerhassett 
2105719f82d3SEliot Blennerhassett 	u32 r;
2106719f82d3SEliot Blennerhassett 
2107719f82d3SEliot Blennerhassett 	interface->host_cmd = cmd;
2108719f82d3SEliot Blennerhassett 	wmb();	/* DSP gets state by DMA, make sure it is written to memory */
2109719f82d3SEliot Blennerhassett 	/* before we interrupt the DSP */
2110719f82d3SEliot Blennerhassett 	r = ioread32(phw->prHDCR);
2111719f82d3SEliot Blennerhassett 	r |= (u32)C6205_HDCR_DSPINT;
2112719f82d3SEliot Blennerhassett 	iowrite32(r, phw->prHDCR);
2113719f82d3SEliot Blennerhassett 	r &= ~(u32)C6205_HDCR_DSPINT;
2114719f82d3SEliot Blennerhassett 	iowrite32(r, phw->prHDCR);
2115719f82d3SEliot Blennerhassett }
2116719f82d3SEliot Blennerhassett 
2117719f82d3SEliot Blennerhassett static unsigned int message_count;
2118719f82d3SEliot Blennerhassett 
2119719f82d3SEliot Blennerhassett static u16 message_response_sequence(struct hpi_adapter_obj *pao,
2120719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
2121719f82d3SEliot Blennerhassett {
2122719f82d3SEliot Blennerhassett #ifndef HPI6205_NO_HSR_POLL
2123719f82d3SEliot Blennerhassett 	u32 temp2;
2124719f82d3SEliot Blennerhassett #endif
2125719f82d3SEliot Blennerhassett 	u32 time_out, time_out2;
2126719f82d3SEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
2127719f82d3SEliot Blennerhassett 	struct bus_master_interface *interface = phw->p_interface_buffer;
2128719f82d3SEliot Blennerhassett 	u16 err = 0;
2129719f82d3SEliot Blennerhassett 
2130719f82d3SEliot Blennerhassett 	message_count++;
21313285ea10SEliot Blennerhassett 	if (phm->size > sizeof(interface->u)) {
2132deb21a23SEliot Blennerhassett 		phr->error = HPI_ERROR_MESSAGE_BUFFER_TOO_SMALL;
21333285ea10SEliot Blennerhassett 		phr->specific_error = sizeof(interface->u);
21343285ea10SEliot Blennerhassett 		phr->size = sizeof(struct hpi_response_header);
21353285ea10SEliot Blennerhassett 		HPI_DEBUG_LOG(ERROR,
21363285ea10SEliot Blennerhassett 			"message len %d too big for buffer %ld \n", phm->size,
21373285ea10SEliot Blennerhassett 			sizeof(interface->u));
21383285ea10SEliot Blennerhassett 		return 0;
21393285ea10SEliot Blennerhassett 	}
21403285ea10SEliot Blennerhassett 
2141719f82d3SEliot Blennerhassett 	/* Assume buffer of type struct bus_master_interface
2142719f82d3SEliot Blennerhassett 	   is allocated "noncacheable" */
2143719f82d3SEliot Blennerhassett 
2144719f82d3SEliot Blennerhassett 	if (!wait_dsp_ack(phw, H620_HIF_IDLE, HPI6205_TIMEOUT)) {
2145719f82d3SEliot Blennerhassett 		HPI_DEBUG_LOG(DEBUG, "timeout waiting for idle\n");
21463285ea10SEliot Blennerhassett 		return HPI6205_ERROR_MSG_RESP_IDLE_TIMEOUT;
2147719f82d3SEliot Blennerhassett 	}
21483285ea10SEliot Blennerhassett 
21493285ea10SEliot Blennerhassett 	memcpy(&interface->u.message_buffer, phm, phm->size);
2150719f82d3SEliot Blennerhassett 	/* signal we want a response */
2151719f82d3SEliot Blennerhassett 	send_dsp_command(phw, H620_HIF_GET_RESP);
2152719f82d3SEliot Blennerhassett 
2153719f82d3SEliot Blennerhassett 	time_out2 = wait_dsp_ack(phw, H620_HIF_GET_RESP, HPI6205_TIMEOUT);
2154719f82d3SEliot Blennerhassett 
21553285ea10SEliot Blennerhassett 	if (!time_out2) {
2156719f82d3SEliot Blennerhassett 		HPI_DEBUG_LOG(ERROR,
21573285ea10SEliot Blennerhassett 			"(%u) Timed out waiting for " "GET_RESP state [%x]\n",
2158719f82d3SEliot Blennerhassett 			message_count, interface->dsp_ack);
2159719f82d3SEliot Blennerhassett 	} else {
2160719f82d3SEliot Blennerhassett 		HPI_DEBUG_LOG(VERBOSE,
2161719f82d3SEliot Blennerhassett 			"(%u) transition to GET_RESP after %u\n",
2162719f82d3SEliot Blennerhassett 			message_count, HPI6205_TIMEOUT - time_out2);
2163719f82d3SEliot Blennerhassett 	}
2164719f82d3SEliot Blennerhassett 	/* spin waiting on HIF interrupt flag (end of msg process) */
2165719f82d3SEliot Blennerhassett 	time_out = HPI6205_TIMEOUT;
2166719f82d3SEliot Blennerhassett 
2167719f82d3SEliot Blennerhassett #ifndef HPI6205_NO_HSR_POLL
2168719f82d3SEliot Blennerhassett 	temp2 = 0;
2169719f82d3SEliot Blennerhassett 	while ((temp2 == 0) && --time_out) {
2170719f82d3SEliot Blennerhassett 		temp2 = ioread32(phw->prHSR);
2171719f82d3SEliot Blennerhassett 		temp2 &= C6205_HSR_INTSRC;
2172719f82d3SEliot Blennerhassett 		hpios_delay_micro_seconds(1);
2173719f82d3SEliot Blennerhassett 	}
2174719f82d3SEliot Blennerhassett 	if (temp2 == C6205_HSR_INTSRC) {
2175719f82d3SEliot Blennerhassett 		rmb();	/* ensure we see latest value for dsp_ack */
2176719f82d3SEliot Blennerhassett 		if ((interface->dsp_ack != H620_HIF_GET_RESP)) {
2177719f82d3SEliot Blennerhassett 			HPI_DEBUG_LOG(DEBUG,
2178719f82d3SEliot Blennerhassett 				"(%u)interface->dsp_ack(0x%x) != "
2179719f82d3SEliot Blennerhassett 				"H620_HIF_GET_RESP, t=%u\n", message_count,
2180719f82d3SEliot Blennerhassett 				interface->dsp_ack,
2181719f82d3SEliot Blennerhassett 				HPI6205_TIMEOUT - time_out);
2182719f82d3SEliot Blennerhassett 		} else {
2183719f82d3SEliot Blennerhassett 			HPI_DEBUG_LOG(VERBOSE,
2184719f82d3SEliot Blennerhassett 				"(%u)int with GET_RESP after %u\n",
2185719f82d3SEliot Blennerhassett 				message_count, HPI6205_TIMEOUT - time_out);
2186719f82d3SEliot Blennerhassett 		}
2187719f82d3SEliot Blennerhassett 
2188719f82d3SEliot Blennerhassett 	} else {
2189719f82d3SEliot Blennerhassett 		/* can we do anything else in response to the error ? */
2190719f82d3SEliot Blennerhassett 		HPI_DEBUG_LOG(ERROR,
21913285ea10SEliot Blennerhassett 			"Interrupt from HIF module BAD (function %x)\n",
2192719f82d3SEliot Blennerhassett 			phm->function);
2193719f82d3SEliot Blennerhassett 	}
2194719f82d3SEliot Blennerhassett 
2195719f82d3SEliot Blennerhassett 	/* reset the interrupt from the DSP */
2196719f82d3SEliot Blennerhassett 	iowrite32(C6205_HSR_INTSRC, phw->prHSR);
2197719f82d3SEliot Blennerhassett #endif
2198719f82d3SEliot Blennerhassett 
2199719f82d3SEliot Blennerhassett 	/* read the result */
22003285ea10SEliot Blennerhassett 	if (time_out) {
22013285ea10SEliot Blennerhassett 		if (interface->u.response_buffer.size <= phr->size)
22023285ea10SEliot Blennerhassett 			memcpy(phr, &interface->u.response_buffer,
22033285ea10SEliot Blennerhassett 				interface->u.response_buffer.size);
22043285ea10SEliot Blennerhassett 		else {
22053285ea10SEliot Blennerhassett 			HPI_DEBUG_LOG(ERROR,
22063285ea10SEliot Blennerhassett 				"response len %d too big for buffer %d\n",
22073285ea10SEliot Blennerhassett 				interface->u.response_buffer.size, phr->size);
22083285ea10SEliot Blennerhassett 			memcpy(phr, &interface->u.response_buffer,
22093285ea10SEliot Blennerhassett 				sizeof(struct hpi_response_header));
22103285ea10SEliot Blennerhassett 			phr->error = HPI_ERROR_RESPONSE_BUFFER_TOO_SMALL;
22113285ea10SEliot Blennerhassett 			phr->specific_error =
22123285ea10SEliot Blennerhassett 				interface->u.response_buffer.size;
22133285ea10SEliot Blennerhassett 			phr->size = sizeof(struct hpi_response_header);
22143285ea10SEliot Blennerhassett 		}
22153285ea10SEliot Blennerhassett 	}
2216719f82d3SEliot Blennerhassett 	/* set interface back to idle */
2217719f82d3SEliot Blennerhassett 	send_dsp_command(phw, H620_HIF_IDLE);
2218719f82d3SEliot Blennerhassett 
22193285ea10SEliot Blennerhassett 	if (!time_out || !time_out2) {
2220719f82d3SEliot Blennerhassett 		HPI_DEBUG_LOG(DEBUG, "something timed out!\n");
22213285ea10SEliot Blennerhassett 		return HPI6205_ERROR_MSG_RESP_TIMEOUT;
2222719f82d3SEliot Blennerhassett 	}
2223719f82d3SEliot Blennerhassett 	/* special case for adapter close - */
2224719f82d3SEliot Blennerhassett 	/* wait for the DSP to indicate it is idle */
2225719f82d3SEliot Blennerhassett 	if (phm->function == HPI_ADAPTER_CLOSE) {
2226719f82d3SEliot Blennerhassett 		if (!wait_dsp_ack(phw, H620_HIF_IDLE, HPI6205_TIMEOUT)) {
2227719f82d3SEliot Blennerhassett 			HPI_DEBUG_LOG(DEBUG,
22283285ea10SEliot Blennerhassett 				"Timeout waiting for idle "
2229719f82d3SEliot Blennerhassett 				"(on adapter_close)\n");
22303285ea10SEliot Blennerhassett 			return HPI6205_ERROR_MSG_RESP_IDLE_TIMEOUT;
2231719f82d3SEliot Blennerhassett 		}
2232719f82d3SEliot Blennerhassett 	}
2233719f82d3SEliot Blennerhassett 	err = hpi_validate_response(phm, phr);
2234719f82d3SEliot Blennerhassett 	return err;
2235719f82d3SEliot Blennerhassett }
2236719f82d3SEliot Blennerhassett 
2237719f82d3SEliot Blennerhassett static void hw_message(struct hpi_adapter_obj *pao, struct hpi_message *phm,
2238719f82d3SEliot Blennerhassett 	struct hpi_response *phr)
2239719f82d3SEliot Blennerhassett {
2240719f82d3SEliot Blennerhassett 
2241719f82d3SEliot Blennerhassett 	u16 err = 0;
2242719f82d3SEliot Blennerhassett 
2243719f82d3SEliot Blennerhassett 	hpios_dsplock_lock(pao);
2244719f82d3SEliot Blennerhassett 
2245719f82d3SEliot Blennerhassett 	err = message_response_sequence(pao, phm, phr);
2246719f82d3SEliot Blennerhassett 
2247719f82d3SEliot Blennerhassett 	/* maybe an error response */
2248719f82d3SEliot Blennerhassett 	if (err) {
2249719f82d3SEliot Blennerhassett 		/* something failed in the HPI/DSP interface */
2250*0a00044dSEliot Blennerhassett 		if (err >= HPI_ERROR_BACKEND_BASE) {
2251*0a00044dSEliot Blennerhassett 			phr->error = HPI_ERROR_DSP_COMMUNICATION;
2252*0a00044dSEliot Blennerhassett 			phr->specific_error = err;
2253*0a00044dSEliot Blennerhassett 		} else {
2254719f82d3SEliot Blennerhassett 			phr->error = err;
2255*0a00044dSEliot Blennerhassett 		}
2256*0a00044dSEliot Blennerhassett 
2257719f82d3SEliot Blennerhassett 		pao->dsp_crashed++;
2258719f82d3SEliot Blennerhassett 
2259719f82d3SEliot Blennerhassett 		/* just the header of the response is valid */
2260719f82d3SEliot Blennerhassett 		phr->size = sizeof(struct hpi_response_header);
2261719f82d3SEliot Blennerhassett 		goto err;
2262719f82d3SEliot Blennerhassett 	} else
2263719f82d3SEliot Blennerhassett 		pao->dsp_crashed = 0;
2264719f82d3SEliot Blennerhassett 
2265719f82d3SEliot Blennerhassett 	if (phr->error != 0)	/* something failed in the DSP */
2266719f82d3SEliot Blennerhassett 		goto err;
2267719f82d3SEliot Blennerhassett 
2268719f82d3SEliot Blennerhassett 	switch (phm->function) {
2269719f82d3SEliot Blennerhassett 	case HPI_OSTREAM_WRITE:
2270719f82d3SEliot Blennerhassett 	case HPI_ISTREAM_ANC_WRITE:
2271719f82d3SEliot Blennerhassett 		err = hpi6205_transfer_data(pao, phm->u.d.u.data.pb_data,
2272719f82d3SEliot Blennerhassett 			phm->u.d.u.data.data_size, H620_HIF_SEND_DATA);
2273719f82d3SEliot Blennerhassett 		break;
2274719f82d3SEliot Blennerhassett 
2275719f82d3SEliot Blennerhassett 	case HPI_ISTREAM_READ:
2276719f82d3SEliot Blennerhassett 	case HPI_OSTREAM_ANC_READ:
2277719f82d3SEliot Blennerhassett 		err = hpi6205_transfer_data(pao, phm->u.d.u.data.pb_data,
2278719f82d3SEliot Blennerhassett 			phm->u.d.u.data.data_size, H620_HIF_GET_DATA);
2279719f82d3SEliot Blennerhassett 		break;
2280719f82d3SEliot Blennerhassett 
2281719f82d3SEliot Blennerhassett 	case HPI_CONTROL_SET_STATE:
2282719f82d3SEliot Blennerhassett 		if (phm->object == HPI_OBJ_CONTROLEX
2283719f82d3SEliot Blennerhassett 			&& phm->u.cx.attribute == HPI_COBRANET_SET_DATA)
2284719f82d3SEliot Blennerhassett 			err = hpi6205_transfer_data(pao,
2285719f82d3SEliot Blennerhassett 				phm->u.cx.u.cobranet_bigdata.pb_data,
2286719f82d3SEliot Blennerhassett 				phm->u.cx.u.cobranet_bigdata.byte_count,
2287719f82d3SEliot Blennerhassett 				H620_HIF_SEND_DATA);
2288719f82d3SEliot Blennerhassett 		break;
2289719f82d3SEliot Blennerhassett 
2290719f82d3SEliot Blennerhassett 	case HPI_CONTROL_GET_STATE:
2291719f82d3SEliot Blennerhassett 		if (phm->object == HPI_OBJ_CONTROLEX
2292719f82d3SEliot Blennerhassett 			&& phm->u.cx.attribute == HPI_COBRANET_GET_DATA)
2293719f82d3SEliot Blennerhassett 			err = hpi6205_transfer_data(pao,
2294719f82d3SEliot Blennerhassett 				phm->u.cx.u.cobranet_bigdata.pb_data,
2295719f82d3SEliot Blennerhassett 				phr->u.cx.u.cobranet_data.byte_count,
2296719f82d3SEliot Blennerhassett 				H620_HIF_GET_DATA);
2297719f82d3SEliot Blennerhassett 		break;
2298719f82d3SEliot Blennerhassett 	}
2299719f82d3SEliot Blennerhassett 	phr->error = err;
2300719f82d3SEliot Blennerhassett 
2301719f82d3SEliot Blennerhassett err:
2302719f82d3SEliot Blennerhassett 	hpios_dsplock_unlock(pao);
2303719f82d3SEliot Blennerhassett 
2304719f82d3SEliot Blennerhassett 	return;
2305719f82d3SEliot Blennerhassett }
2306