xref: /openbmc/linux/sound/pci/asihpi/hpi6205.c (revision 2a383cb3f1a571b281c2e1ace4c8491f0370e866)
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 */
41719f82d3SEliot Blennerhassett #define HPI6205_ERROR_BASE                      1000
42719f82d3SEliot Blennerhassett /*#define HPI6205_ERROR_MEM_ALLOC 1001 */
43719f82d3SEliot Blennerhassett #define HPI6205_ERROR_6205_NO_IRQ               1002
44719f82d3SEliot Blennerhassett #define HPI6205_ERROR_6205_INIT_FAILED          1003
45719f82d3SEliot Blennerhassett /*#define HPI6205_ERROR_MISSING_DSPCODE 1004 */
46719f82d3SEliot Blennerhassett #define HPI6205_ERROR_UNKNOWN_PCI_DEVICE        1005
47719f82d3SEliot Blennerhassett #define HPI6205_ERROR_6205_REG                  1006
48719f82d3SEliot Blennerhassett #define HPI6205_ERROR_6205_DSPPAGE              1007
49719f82d3SEliot Blennerhassett #define HPI6205_ERROR_BAD_DSPINDEX              1008
50719f82d3SEliot Blennerhassett #define HPI6205_ERROR_C6713_HPIC                1009
51719f82d3SEliot Blennerhassett #define HPI6205_ERROR_C6713_HPIA                1010
52719f82d3SEliot Blennerhassett #define HPI6205_ERROR_C6713_PLL                 1011
53719f82d3SEliot Blennerhassett #define HPI6205_ERROR_DSP_INTMEM                1012
54719f82d3SEliot Blennerhassett #define HPI6205_ERROR_DSP_EXTMEM                1013
55719f82d3SEliot Blennerhassett #define HPI6205_ERROR_DSP_PLD                   1014
56719f82d3SEliot Blennerhassett #define HPI6205_ERROR_MSG_RESP_IDLE_TIMEOUT     1015
57719f82d3SEliot Blennerhassett #define HPI6205_ERROR_MSG_RESP_TIMEOUT          1016
58719f82d3SEliot Blennerhassett #define HPI6205_ERROR_6205_EEPROM               1017
59719f82d3SEliot Blennerhassett #define HPI6205_ERROR_DSP_EMIF                  1018
60719f82d3SEliot Blennerhassett 
61719f82d3SEliot Blennerhassett #define hpi6205_error(dsp_index, err) (err)
62719f82d3SEliot Blennerhassett /*****************************************************************************/
63719f82d3SEliot Blennerhassett /* for C6205 PCI i/f */
64719f82d3SEliot Blennerhassett /* Host Status Register (HSR) bitfields */
65719f82d3SEliot Blennerhassett #define C6205_HSR_INTSRC        0x01
66719f82d3SEliot Blennerhassett #define C6205_HSR_INTAVAL       0x02
67719f82d3SEliot Blennerhassett #define C6205_HSR_INTAM         0x04
68719f82d3SEliot Blennerhassett #define C6205_HSR_CFGERR        0x08
69719f82d3SEliot Blennerhassett #define C6205_HSR_EEREAD        0x10
70719f82d3SEliot Blennerhassett /* Host-to-DSP Control Register (HDCR) bitfields */
71719f82d3SEliot Blennerhassett #define C6205_HDCR_WARMRESET    0x01
72719f82d3SEliot Blennerhassett #define C6205_HDCR_DSPINT       0x02
73719f82d3SEliot Blennerhassett #define C6205_HDCR_PCIBOOT      0x04
74719f82d3SEliot Blennerhassett /* DSP Page Register (DSPP) bitfields, */
75719f82d3SEliot Blennerhassett /* defines 4 Mbyte page that BAR0 points to */
76719f82d3SEliot Blennerhassett #define C6205_DSPP_MAP1         0x400
77719f82d3SEliot Blennerhassett 
78719f82d3SEliot Blennerhassett /* BAR0 maps to prefetchable 4 Mbyte memory block set by DSPP.
79719f82d3SEliot Blennerhassett  * BAR1 maps to non-prefetchable 8 Mbyte memory block
80719f82d3SEliot Blennerhassett  * of DSP memory mapped registers (starting at 0x01800000).
81719f82d3SEliot Blennerhassett  * 0x01800000 is hardcoded in the PCI i/f, so that only the offset from this
82719f82d3SEliot Blennerhassett  * needs to be added to the BAR1 base address set in the PCI config reg
83719f82d3SEliot Blennerhassett  */
84719f82d3SEliot Blennerhassett #define C6205_BAR1_PCI_IO_OFFSET (0x027FFF0L)
85719f82d3SEliot Blennerhassett #define C6205_BAR1_HSR  (C6205_BAR1_PCI_IO_OFFSET)
86719f82d3SEliot Blennerhassett #define C6205_BAR1_HDCR (C6205_BAR1_PCI_IO_OFFSET+4)
87719f82d3SEliot Blennerhassett #define C6205_BAR1_DSPP (C6205_BAR1_PCI_IO_OFFSET+8)
88719f82d3SEliot Blennerhassett 
89719f82d3SEliot Blennerhassett /* used to control LED (revA) and reset C6713 (revB) */
90719f82d3SEliot Blennerhassett #define C6205_BAR0_TIMER1_CTL (0x01980000L)
91719f82d3SEliot Blennerhassett 
92719f82d3SEliot Blennerhassett /* For first 6713 in CE1 space, using DA17,16,2 */
93719f82d3SEliot Blennerhassett #define HPICL_ADDR      0x01400000L
94719f82d3SEliot Blennerhassett #define HPICH_ADDR      0x01400004L
95719f82d3SEliot Blennerhassett #define HPIAL_ADDR      0x01410000L
96719f82d3SEliot Blennerhassett #define HPIAH_ADDR      0x01410004L
97719f82d3SEliot Blennerhassett #define HPIDIL_ADDR     0x01420000L
98719f82d3SEliot Blennerhassett #define HPIDIH_ADDR     0x01420004L
99719f82d3SEliot Blennerhassett #define HPIDL_ADDR      0x01430000L
100719f82d3SEliot Blennerhassett #define HPIDH_ADDR      0x01430004L
101719f82d3SEliot Blennerhassett 
102719f82d3SEliot Blennerhassett #define C6713_EMIF_GCTL         0x01800000
103719f82d3SEliot Blennerhassett #define C6713_EMIF_CE1          0x01800004
104719f82d3SEliot Blennerhassett #define C6713_EMIF_CE0          0x01800008
105719f82d3SEliot Blennerhassett #define C6713_EMIF_CE2          0x01800010
106719f82d3SEliot Blennerhassett #define C6713_EMIF_CE3          0x01800014
107719f82d3SEliot Blennerhassett #define C6713_EMIF_SDRAMCTL     0x01800018
108719f82d3SEliot Blennerhassett #define C6713_EMIF_SDRAMTIMING  0x0180001C
109719f82d3SEliot Blennerhassett #define C6713_EMIF_SDRAMEXT     0x01800020
110719f82d3SEliot Blennerhassett 
111719f82d3SEliot Blennerhassett struct hpi_hw_obj {
112719f82d3SEliot Blennerhassett 	/* PCI registers */
113719f82d3SEliot Blennerhassett 	__iomem u32 *prHSR;
114719f82d3SEliot Blennerhassett 	__iomem u32 *prHDCR;
115719f82d3SEliot Blennerhassett 	__iomem u32 *prDSPP;
116719f82d3SEliot Blennerhassett 
117719f82d3SEliot Blennerhassett 	u32 dsp_page;
118719f82d3SEliot Blennerhassett 
119719f82d3SEliot Blennerhassett 	struct consistent_dma_area h_locked_mem;
120719f82d3SEliot Blennerhassett 	struct bus_master_interface *p_interface_buffer;
121719f82d3SEliot Blennerhassett 
122719f82d3SEliot Blennerhassett 	u16 flag_outstream_just_reset[HPI_MAX_STREAMS];
123719f82d3SEliot Blennerhassett 	/* a non-NULL handle means there is an HPI allocated buffer */
124719f82d3SEliot Blennerhassett 	struct consistent_dma_area instream_host_buffers[HPI_MAX_STREAMS];
125719f82d3SEliot Blennerhassett 	struct consistent_dma_area outstream_host_buffers[HPI_MAX_STREAMS];
126719f82d3SEliot Blennerhassett 	/* non-zero size means a buffer exists, may be external */
127719f82d3SEliot Blennerhassett 	u32 instream_host_buffer_size[HPI_MAX_STREAMS];
128719f82d3SEliot Blennerhassett 	u32 outstream_host_buffer_size[HPI_MAX_STREAMS];
129719f82d3SEliot Blennerhassett 
130719f82d3SEliot Blennerhassett 	struct consistent_dma_area h_control_cache;
131719f82d3SEliot Blennerhassett 	struct consistent_dma_area h_async_event_buffer;
132719f82d3SEliot Blennerhassett /*      struct hpi_control_cache_single *pControlCache; */
133719f82d3SEliot Blennerhassett 	struct hpi_async_event *p_async_event_buffer;
134719f82d3SEliot Blennerhassett 	struct hpi_control_cache *p_cache;
135719f82d3SEliot Blennerhassett };
136719f82d3SEliot Blennerhassett 
137719f82d3SEliot Blennerhassett /*****************************************************************************/
138719f82d3SEliot Blennerhassett /* local prototypes */
139719f82d3SEliot Blennerhassett 
140719f82d3SEliot Blennerhassett #define check_before_bbm_copy(status, p_bbm_data, l_first_write, l_second_write)
141719f82d3SEliot Blennerhassett 
142719f82d3SEliot Blennerhassett static int wait_dsp_ack(struct hpi_hw_obj *phw, int state, int timeout_us);
143719f82d3SEliot Blennerhassett 
144719f82d3SEliot Blennerhassett static void send_dsp_command(struct hpi_hw_obj *phw, int cmd);
145719f82d3SEliot Blennerhassett 
146719f82d3SEliot Blennerhassett static u16 adapter_boot_load_dsp(struct hpi_adapter_obj *pao,
147719f82d3SEliot Blennerhassett 	u32 *pos_error_code);
148719f82d3SEliot Blennerhassett 
149719f82d3SEliot Blennerhassett static u16 message_response_sequence(struct hpi_adapter_obj *pao,
150719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr);
151719f82d3SEliot Blennerhassett 
152719f82d3SEliot Blennerhassett static void hw_message(struct hpi_adapter_obj *pao, struct hpi_message *phm,
153719f82d3SEliot Blennerhassett 	struct hpi_response *phr);
154719f82d3SEliot Blennerhassett 
155719f82d3SEliot Blennerhassett #define HPI6205_TIMEOUT 1000000
156719f82d3SEliot Blennerhassett 
157719f82d3SEliot Blennerhassett static void subsys_create_adapter(struct hpi_message *phm,
158719f82d3SEliot Blennerhassett 	struct hpi_response *phr);
159719f82d3SEliot Blennerhassett static void subsys_delete_adapter(struct hpi_message *phm,
160719f82d3SEliot Blennerhassett 	struct hpi_response *phr);
161719f82d3SEliot Blennerhassett 
162719f82d3SEliot Blennerhassett static u16 create_adapter_obj(struct hpi_adapter_obj *pao,
163719f82d3SEliot Blennerhassett 	u32 *pos_error_code);
164719f82d3SEliot Blennerhassett 
165719f82d3SEliot Blennerhassett static void delete_adapter_obj(struct hpi_adapter_obj *pao);
166719f82d3SEliot Blennerhassett 
167719f82d3SEliot Blennerhassett static void outstream_host_buffer_allocate(struct hpi_adapter_obj *pao,
168719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr);
169719f82d3SEliot Blennerhassett 
170719f82d3SEliot Blennerhassett static void outstream_host_buffer_get_info(struct hpi_adapter_obj *pao,
171719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr);
172719f82d3SEliot Blennerhassett 
173719f82d3SEliot Blennerhassett static void outstream_host_buffer_free(struct hpi_adapter_obj *pao,
174719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr);
175719f82d3SEliot Blennerhassett static void outstream_write(struct hpi_adapter_obj *pao,
176719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr);
177719f82d3SEliot Blennerhassett 
178719f82d3SEliot Blennerhassett static void outstream_get_info(struct hpi_adapter_obj *pao,
179719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr);
180719f82d3SEliot Blennerhassett 
181719f82d3SEliot Blennerhassett static void outstream_start(struct hpi_adapter_obj *pao,
182719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr);
183719f82d3SEliot Blennerhassett 
184719f82d3SEliot Blennerhassett static void outstream_open(struct hpi_adapter_obj *pao,
185719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr);
186719f82d3SEliot Blennerhassett 
187719f82d3SEliot Blennerhassett static void outstream_reset(struct hpi_adapter_obj *pao,
188719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr);
189719f82d3SEliot Blennerhassett 
190719f82d3SEliot Blennerhassett static void instream_host_buffer_allocate(struct hpi_adapter_obj *pao,
191719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr);
192719f82d3SEliot Blennerhassett 
193719f82d3SEliot Blennerhassett static void instream_host_buffer_get_info(struct hpi_adapter_obj *pao,
194719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr);
195719f82d3SEliot Blennerhassett 
196719f82d3SEliot Blennerhassett static void instream_host_buffer_free(struct hpi_adapter_obj *pao,
197719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr);
198719f82d3SEliot Blennerhassett 
199719f82d3SEliot Blennerhassett static void instream_read(struct hpi_adapter_obj *pao,
200719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr);
201719f82d3SEliot Blennerhassett 
202719f82d3SEliot Blennerhassett static void instream_get_info(struct hpi_adapter_obj *pao,
203719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr);
204719f82d3SEliot Blennerhassett 
205719f82d3SEliot Blennerhassett static void instream_start(struct hpi_adapter_obj *pao,
206719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr);
207719f82d3SEliot Blennerhassett 
208719f82d3SEliot Blennerhassett static u32 boot_loader_read_mem32(struct hpi_adapter_obj *pao, int dsp_index,
209719f82d3SEliot Blennerhassett 	u32 address);
210719f82d3SEliot Blennerhassett 
211719f82d3SEliot Blennerhassett static u16 boot_loader_write_mem32(struct hpi_adapter_obj *pao, int dsp_index,
212719f82d3SEliot Blennerhassett 	u32 address, u32 data);
213719f82d3SEliot Blennerhassett 
214719f82d3SEliot Blennerhassett static u16 boot_loader_config_emif(struct hpi_adapter_obj *pao,
215719f82d3SEliot Blennerhassett 	int dsp_index);
216719f82d3SEliot Blennerhassett 
217719f82d3SEliot Blennerhassett static u16 boot_loader_test_memory(struct hpi_adapter_obj *pao, int dsp_index,
218719f82d3SEliot Blennerhassett 	u32 address, u32 length);
219719f82d3SEliot Blennerhassett 
220719f82d3SEliot Blennerhassett static u16 boot_loader_test_internal_memory(struct hpi_adapter_obj *pao,
221719f82d3SEliot Blennerhassett 	int dsp_index);
222719f82d3SEliot Blennerhassett 
223719f82d3SEliot Blennerhassett static u16 boot_loader_test_external_memory(struct hpi_adapter_obj *pao,
224719f82d3SEliot Blennerhassett 	int dsp_index);
225719f82d3SEliot Blennerhassett 
226719f82d3SEliot Blennerhassett static u16 boot_loader_test_pld(struct hpi_adapter_obj *pao, int dsp_index);
227719f82d3SEliot Blennerhassett 
228719f82d3SEliot Blennerhassett /*****************************************************************************/
229719f82d3SEliot Blennerhassett 
230719f82d3SEliot Blennerhassett static void subsys_message(struct hpi_message *phm, struct hpi_response *phr)
231719f82d3SEliot Blennerhassett {
232719f82d3SEliot Blennerhassett 
233719f82d3SEliot Blennerhassett 	switch (phm->function) {
234719f82d3SEliot Blennerhassett 	case HPI_SUBSYS_OPEN:
235719f82d3SEliot Blennerhassett 	case HPI_SUBSYS_CLOSE:
236719f82d3SEliot Blennerhassett 	case HPI_SUBSYS_GET_INFO:
237719f82d3SEliot Blennerhassett 	case HPI_SUBSYS_DRIVER_UNLOAD:
238719f82d3SEliot Blennerhassett 	case HPI_SUBSYS_DRIVER_LOAD:
239719f82d3SEliot Blennerhassett 	case HPI_SUBSYS_FIND_ADAPTERS:
240719f82d3SEliot Blennerhassett 		/* messages that should not get here */
241719f82d3SEliot Blennerhassett 		phr->error = HPI_ERROR_UNIMPLEMENTED;
242719f82d3SEliot Blennerhassett 		break;
243719f82d3SEliot Blennerhassett 	case HPI_SUBSYS_CREATE_ADAPTER:
244719f82d3SEliot Blennerhassett 		subsys_create_adapter(phm, phr);
245719f82d3SEliot Blennerhassett 		break;
246719f82d3SEliot Blennerhassett 	case HPI_SUBSYS_DELETE_ADAPTER:
247719f82d3SEliot Blennerhassett 		subsys_delete_adapter(phm, phr);
248719f82d3SEliot Blennerhassett 		break;
249719f82d3SEliot Blennerhassett 	default:
250719f82d3SEliot Blennerhassett 		phr->error = HPI_ERROR_INVALID_FUNC;
251719f82d3SEliot Blennerhassett 		break;
252719f82d3SEliot Blennerhassett 	}
253719f82d3SEliot Blennerhassett }
254719f82d3SEliot Blennerhassett 
255719f82d3SEliot Blennerhassett static void control_message(struct hpi_adapter_obj *pao,
256719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
257719f82d3SEliot Blennerhassett {
258719f82d3SEliot Blennerhassett 
259719f82d3SEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
260719f82d3SEliot Blennerhassett 
261719f82d3SEliot Blennerhassett 	switch (phm->function) {
262719f82d3SEliot Blennerhassett 	case HPI_CONTROL_GET_STATE:
263719f82d3SEliot Blennerhassett 		if (pao->has_control_cache) {
264719f82d3SEliot Blennerhassett 			rmb();	/* make sure we see updates DM_aed from DSP */
265719f82d3SEliot Blennerhassett 			if (hpi_check_control_cache(phw->p_cache, phm, phr))
266719f82d3SEliot Blennerhassett 				break;
267719f82d3SEliot Blennerhassett 		}
268719f82d3SEliot Blennerhassett 		hw_message(pao, phm, phr);
269719f82d3SEliot Blennerhassett 		break;
270719f82d3SEliot Blennerhassett 	case HPI_CONTROL_GET_INFO:
271719f82d3SEliot Blennerhassett 		hw_message(pao, phm, phr);
272719f82d3SEliot Blennerhassett 		break;
273719f82d3SEliot Blennerhassett 	case HPI_CONTROL_SET_STATE:
274719f82d3SEliot Blennerhassett 		hw_message(pao, phm, phr);
275719f82d3SEliot Blennerhassett 		if (pao->has_control_cache)
276719f82d3SEliot Blennerhassett 			hpi_sync_control_cache(phw->p_cache, phm, phr);
277719f82d3SEliot Blennerhassett 		break;
278719f82d3SEliot Blennerhassett 	default:
279719f82d3SEliot Blennerhassett 		phr->error = HPI_ERROR_INVALID_FUNC;
280719f82d3SEliot Blennerhassett 		break;
281719f82d3SEliot Blennerhassett 	}
282719f82d3SEliot Blennerhassett }
283719f82d3SEliot Blennerhassett 
284719f82d3SEliot Blennerhassett static void adapter_message(struct hpi_adapter_obj *pao,
285719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
286719f82d3SEliot Blennerhassett {
287719f82d3SEliot Blennerhassett 	switch (phm->function) {
288719f82d3SEliot Blennerhassett 	default:
289719f82d3SEliot Blennerhassett 		hw_message(pao, phm, phr);
290719f82d3SEliot Blennerhassett 		break;
291719f82d3SEliot Blennerhassett 	}
292719f82d3SEliot Blennerhassett }
293719f82d3SEliot Blennerhassett 
294719f82d3SEliot Blennerhassett static void outstream_message(struct hpi_adapter_obj *pao,
295719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
296719f82d3SEliot Blennerhassett {
297719f82d3SEliot Blennerhassett 
298719f82d3SEliot Blennerhassett 	if (phm->obj_index >= HPI_MAX_STREAMS) {
299719f82d3SEliot Blennerhassett 		phr->error = HPI_ERROR_INVALID_STREAM;
300719f82d3SEliot Blennerhassett 		HPI_DEBUG_LOG(WARNING,
301719f82d3SEliot Blennerhassett 			"message referencing invalid stream %d "
302719f82d3SEliot Blennerhassett 			"on adapter index %d\n", phm->obj_index,
303719f82d3SEliot Blennerhassett 			phm->adapter_index);
304719f82d3SEliot Blennerhassett 		return;
305719f82d3SEliot Blennerhassett 	}
306719f82d3SEliot Blennerhassett 
307719f82d3SEliot Blennerhassett 	switch (phm->function) {
308719f82d3SEliot Blennerhassett 	case HPI_OSTREAM_WRITE:
309719f82d3SEliot Blennerhassett 		outstream_write(pao, phm, phr);
310719f82d3SEliot Blennerhassett 		break;
311719f82d3SEliot Blennerhassett 	case HPI_OSTREAM_GET_INFO:
312719f82d3SEliot Blennerhassett 		outstream_get_info(pao, phm, phr);
313719f82d3SEliot Blennerhassett 		break;
314719f82d3SEliot Blennerhassett 	case HPI_OSTREAM_HOSTBUFFER_ALLOC:
315719f82d3SEliot Blennerhassett 		outstream_host_buffer_allocate(pao, phm, phr);
316719f82d3SEliot Blennerhassett 		break;
317719f82d3SEliot Blennerhassett 	case HPI_OSTREAM_HOSTBUFFER_GET_INFO:
318719f82d3SEliot Blennerhassett 		outstream_host_buffer_get_info(pao, phm, phr);
319719f82d3SEliot Blennerhassett 		break;
320719f82d3SEliot Blennerhassett 	case HPI_OSTREAM_HOSTBUFFER_FREE:
321719f82d3SEliot Blennerhassett 		outstream_host_buffer_free(pao, phm, phr);
322719f82d3SEliot Blennerhassett 		break;
323719f82d3SEliot Blennerhassett 	case HPI_OSTREAM_START:
324719f82d3SEliot Blennerhassett 		outstream_start(pao, phm, phr);
325719f82d3SEliot Blennerhassett 		break;
326719f82d3SEliot Blennerhassett 	case HPI_OSTREAM_OPEN:
327719f82d3SEliot Blennerhassett 		outstream_open(pao, phm, phr);
328719f82d3SEliot Blennerhassett 		break;
329719f82d3SEliot Blennerhassett 	case HPI_OSTREAM_RESET:
330719f82d3SEliot Blennerhassett 		outstream_reset(pao, phm, phr);
331719f82d3SEliot Blennerhassett 		break;
332719f82d3SEliot Blennerhassett 	default:
333719f82d3SEliot Blennerhassett 		hw_message(pao, phm, phr);
334719f82d3SEliot Blennerhassett 		break;
335719f82d3SEliot Blennerhassett 	}
336719f82d3SEliot Blennerhassett }
337719f82d3SEliot Blennerhassett 
338719f82d3SEliot Blennerhassett static void instream_message(struct hpi_adapter_obj *pao,
339719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
340719f82d3SEliot Blennerhassett {
341719f82d3SEliot Blennerhassett 
342719f82d3SEliot Blennerhassett 	if (phm->obj_index >= HPI_MAX_STREAMS) {
343719f82d3SEliot Blennerhassett 		phr->error = HPI_ERROR_INVALID_STREAM;
344719f82d3SEliot Blennerhassett 		HPI_DEBUG_LOG(WARNING,
345719f82d3SEliot Blennerhassett 			"message referencing invalid stream %d "
346719f82d3SEliot Blennerhassett 			"on adapter index %d\n", phm->obj_index,
347719f82d3SEliot Blennerhassett 			phm->adapter_index);
348719f82d3SEliot Blennerhassett 		return;
349719f82d3SEliot Blennerhassett 	}
350719f82d3SEliot Blennerhassett 
351719f82d3SEliot Blennerhassett 	switch (phm->function) {
352719f82d3SEliot Blennerhassett 	case HPI_ISTREAM_READ:
353719f82d3SEliot Blennerhassett 		instream_read(pao, phm, phr);
354719f82d3SEliot Blennerhassett 		break;
355719f82d3SEliot Blennerhassett 	case HPI_ISTREAM_GET_INFO:
356719f82d3SEliot Blennerhassett 		instream_get_info(pao, phm, phr);
357719f82d3SEliot Blennerhassett 		break;
358719f82d3SEliot Blennerhassett 	case HPI_ISTREAM_HOSTBUFFER_ALLOC:
359719f82d3SEliot Blennerhassett 		instream_host_buffer_allocate(pao, phm, phr);
360719f82d3SEliot Blennerhassett 		break;
361719f82d3SEliot Blennerhassett 	case HPI_ISTREAM_HOSTBUFFER_GET_INFO:
362719f82d3SEliot Blennerhassett 		instream_host_buffer_get_info(pao, phm, phr);
363719f82d3SEliot Blennerhassett 		break;
364719f82d3SEliot Blennerhassett 	case HPI_ISTREAM_HOSTBUFFER_FREE:
365719f82d3SEliot Blennerhassett 		instream_host_buffer_free(pao, phm, phr);
366719f82d3SEliot Blennerhassett 		break;
367719f82d3SEliot Blennerhassett 	case HPI_ISTREAM_START:
368719f82d3SEliot Blennerhassett 		instream_start(pao, phm, phr);
369719f82d3SEliot Blennerhassett 		break;
370719f82d3SEliot Blennerhassett 	default:
371719f82d3SEliot Blennerhassett 		hw_message(pao, phm, phr);
372719f82d3SEliot Blennerhassett 		break;
373719f82d3SEliot Blennerhassett 	}
374719f82d3SEliot Blennerhassett }
375719f82d3SEliot Blennerhassett 
376719f82d3SEliot Blennerhassett /*****************************************************************************/
377719f82d3SEliot Blennerhassett /** Entry point to this HPI backend
378719f82d3SEliot Blennerhassett  * All calls to the HPI start here
379719f82d3SEliot Blennerhassett  */
380719f82d3SEliot Blennerhassett void HPI_6205(struct hpi_message *phm, struct hpi_response *phr)
381719f82d3SEliot Blennerhassett {
382719f82d3SEliot Blennerhassett 	struct hpi_adapter_obj *pao = NULL;
383719f82d3SEliot Blennerhassett 
384719f82d3SEliot Blennerhassett 	/* subsytem messages are processed by every HPI.
385719f82d3SEliot Blennerhassett 	 * All other messages are ignored unless the adapter index matches
386719f82d3SEliot Blennerhassett 	 * an adapter in the HPI
387719f82d3SEliot Blennerhassett 	 */
388719f82d3SEliot Blennerhassett 	HPI_DEBUG_LOG(DEBUG, "HPI obj=%d, func=%d\n", phm->object,
389719f82d3SEliot Blennerhassett 		phm->function);
390719f82d3SEliot Blennerhassett 
391719f82d3SEliot Blennerhassett 	/* if Dsp has crashed then do not communicate with it any more */
392719f82d3SEliot Blennerhassett 	if (phm->object != HPI_OBJ_SUBSYSTEM) {
393719f82d3SEliot Blennerhassett 		pao = hpi_find_adapter(phm->adapter_index);
394719f82d3SEliot Blennerhassett 		if (!pao) {
395719f82d3SEliot Blennerhassett 			HPI_DEBUG_LOG(DEBUG,
396719f82d3SEliot Blennerhassett 				" %d,%d refused, for another HPI?\n",
397719f82d3SEliot Blennerhassett 				phm->object, phm->function);
398719f82d3SEliot Blennerhassett 			return;
399719f82d3SEliot Blennerhassett 		}
400719f82d3SEliot Blennerhassett 
401719f82d3SEliot Blennerhassett 		if ((pao->dsp_crashed >= 10)
402719f82d3SEliot Blennerhassett 			&& (phm->function != HPI_ADAPTER_DEBUG_READ)) {
403719f82d3SEliot Blennerhassett 			/* allow last resort debug read even after crash */
404719f82d3SEliot Blennerhassett 			hpi_init_response(phr, phm->object, phm->function,
405719f82d3SEliot Blennerhassett 				HPI_ERROR_DSP_HARDWARE);
406719f82d3SEliot Blennerhassett 			HPI_DEBUG_LOG(WARNING, " %d,%d dsp crashed.\n",
407719f82d3SEliot Blennerhassett 				phm->object, phm->function);
408719f82d3SEliot Blennerhassett 			return;
409719f82d3SEliot Blennerhassett 		}
410719f82d3SEliot Blennerhassett 	}
411719f82d3SEliot Blennerhassett 
412719f82d3SEliot Blennerhassett 	/* Init default response  */
413719f82d3SEliot Blennerhassett 	if (phm->function != HPI_SUBSYS_CREATE_ADAPTER)
414719f82d3SEliot Blennerhassett 		hpi_init_response(phr, phm->object, phm->function,
415719f82d3SEliot Blennerhassett 			HPI_ERROR_PROCESSING_MESSAGE);
416719f82d3SEliot Blennerhassett 
417719f82d3SEliot Blennerhassett 	HPI_DEBUG_LOG(VERBOSE, "start of switch\n");
418719f82d3SEliot Blennerhassett 	switch (phm->type) {
419719f82d3SEliot Blennerhassett 	case HPI_TYPE_MESSAGE:
420719f82d3SEliot Blennerhassett 		switch (phm->object) {
421719f82d3SEliot Blennerhassett 		case HPI_OBJ_SUBSYSTEM:
422719f82d3SEliot Blennerhassett 			subsys_message(phm, phr);
423719f82d3SEliot Blennerhassett 			break;
424719f82d3SEliot Blennerhassett 
425719f82d3SEliot Blennerhassett 		case HPI_OBJ_ADAPTER:
426719f82d3SEliot Blennerhassett 			phr->size =
427719f82d3SEliot Blennerhassett 				sizeof(struct hpi_response_header) +
428719f82d3SEliot Blennerhassett 				sizeof(struct hpi_adapter_res);
429719f82d3SEliot Blennerhassett 			adapter_message(pao, phm, phr);
430719f82d3SEliot Blennerhassett 			break;
431719f82d3SEliot Blennerhassett 
432719f82d3SEliot Blennerhassett 		case HPI_OBJ_CONTROLEX:
433719f82d3SEliot Blennerhassett 		case HPI_OBJ_CONTROL:
434719f82d3SEliot Blennerhassett 			control_message(pao, phm, phr);
435719f82d3SEliot Blennerhassett 			break;
436719f82d3SEliot Blennerhassett 
437719f82d3SEliot Blennerhassett 		case HPI_OBJ_OSTREAM:
438719f82d3SEliot Blennerhassett 			outstream_message(pao, phm, phr);
439719f82d3SEliot Blennerhassett 			break;
440719f82d3SEliot Blennerhassett 
441719f82d3SEliot Blennerhassett 		case HPI_OBJ_ISTREAM:
442719f82d3SEliot Blennerhassett 			instream_message(pao, phm, phr);
443719f82d3SEliot Blennerhassett 			break;
444719f82d3SEliot Blennerhassett 
445719f82d3SEliot Blennerhassett 		default:
446719f82d3SEliot Blennerhassett 			hw_message(pao, phm, phr);
447719f82d3SEliot Blennerhassett 			break;
448719f82d3SEliot Blennerhassett 		}
449719f82d3SEliot Blennerhassett 		break;
450719f82d3SEliot Blennerhassett 
451719f82d3SEliot Blennerhassett 	default:
452719f82d3SEliot Blennerhassett 		phr->error = HPI_ERROR_INVALID_TYPE;
453719f82d3SEliot Blennerhassett 		break;
454719f82d3SEliot Blennerhassett 	}
455719f82d3SEliot Blennerhassett }
456719f82d3SEliot Blennerhassett 
457719f82d3SEliot Blennerhassett /*****************************************************************************/
458719f82d3SEliot Blennerhassett /* SUBSYSTEM */
459719f82d3SEliot Blennerhassett 
460719f82d3SEliot Blennerhassett /** Create an adapter object and initialise it based on resource information
461719f82d3SEliot Blennerhassett  * passed in in the message
462719f82d3SEliot Blennerhassett  * *** NOTE - you cannot use this function AND the FindAdapters function at the
463719f82d3SEliot Blennerhassett  * same time, the application must use only one of them to get the adapters ***
464719f82d3SEliot Blennerhassett  */
465719f82d3SEliot Blennerhassett static void subsys_create_adapter(struct hpi_message *phm,
466719f82d3SEliot Blennerhassett 	struct hpi_response *phr)
467719f82d3SEliot Blennerhassett {
468719f82d3SEliot Blennerhassett 	/* create temp adapter obj, because we don't know what index yet */
469719f82d3SEliot Blennerhassett 	struct hpi_adapter_obj ao;
470719f82d3SEliot Blennerhassett 	u32 os_error_code;
471719f82d3SEliot Blennerhassett 	u16 err;
472719f82d3SEliot Blennerhassett 
473719f82d3SEliot Blennerhassett 	HPI_DEBUG_LOG(DEBUG, " subsys_create_adapter\n");
474719f82d3SEliot Blennerhassett 
475719f82d3SEliot Blennerhassett 	memset(&ao, 0, sizeof(ao));
476719f82d3SEliot Blennerhassett 
477719f82d3SEliot Blennerhassett 	/* this HPI only creates adapters for TI/PCI devices */
478719f82d3SEliot Blennerhassett 	if (phm->u.s.resource.bus_type != HPI_BUS_PCI)
479719f82d3SEliot Blennerhassett 		return;
480719f82d3SEliot Blennerhassett 	if (phm->u.s.resource.r.pci->vendor_id != HPI_PCI_VENDOR_ID_TI)
481719f82d3SEliot Blennerhassett 		return;
482719f82d3SEliot Blennerhassett 	if (phm->u.s.resource.r.pci->device_id != HPI_PCI_DEV_ID_DSP6205)
483719f82d3SEliot Blennerhassett 		return;
484719f82d3SEliot Blennerhassett 
485550a8b69SJulia Lawall 	ao.priv = kzalloc(sizeof(struct hpi_hw_obj), GFP_KERNEL);
486719f82d3SEliot Blennerhassett 	if (!ao.priv) {
487719f82d3SEliot Blennerhassett 		HPI_DEBUG_LOG(ERROR, "cant get mem for adapter object\n");
488719f82d3SEliot Blennerhassett 		phr->error = HPI_ERROR_MEMORY_ALLOC;
489719f82d3SEliot Blennerhassett 		return;
490719f82d3SEliot Blennerhassett 	}
491719f82d3SEliot Blennerhassett 
492719f82d3SEliot Blennerhassett 	ao.pci = *phm->u.s.resource.r.pci;
493719f82d3SEliot Blennerhassett 	err = create_adapter_obj(&ao, &os_error_code);
494719f82d3SEliot Blennerhassett 	if (!err)
495719f82d3SEliot Blennerhassett 		err = hpi_add_adapter(&ao);
496719f82d3SEliot Blennerhassett 	if (err) {
497719f82d3SEliot Blennerhassett 		phr->u.s.data = os_error_code;
498719f82d3SEliot Blennerhassett 		delete_adapter_obj(&ao);
499719f82d3SEliot Blennerhassett 		phr->error = err;
500719f82d3SEliot Blennerhassett 		return;
501719f82d3SEliot Blennerhassett 	}
502719f82d3SEliot Blennerhassett 
503719f82d3SEliot Blennerhassett 	phr->u.s.aw_adapter_list[ao.index] = ao.adapter_type;
504719f82d3SEliot Blennerhassett 	phr->u.s.adapter_index = ao.index;
505719f82d3SEliot Blennerhassett 	phr->u.s.num_adapters++;
506719f82d3SEliot Blennerhassett 	phr->error = 0;
507719f82d3SEliot Blennerhassett }
508719f82d3SEliot Blennerhassett 
509719f82d3SEliot Blennerhassett /** delete an adapter - required by WDM driver */
510719f82d3SEliot Blennerhassett static void subsys_delete_adapter(struct hpi_message *phm,
511719f82d3SEliot Blennerhassett 	struct hpi_response *phr)
512719f82d3SEliot Blennerhassett {
513719f82d3SEliot Blennerhassett 	struct hpi_adapter_obj *pao;
514719f82d3SEliot Blennerhassett 	struct hpi_hw_obj *phw;
515719f82d3SEliot Blennerhassett 
516719f82d3SEliot Blennerhassett 	pao = hpi_find_adapter(phm->adapter_index);
517719f82d3SEliot Blennerhassett 	if (!pao) {
518719f82d3SEliot Blennerhassett 		phr->error = HPI_ERROR_INVALID_OBJ_INDEX;
519719f82d3SEliot Blennerhassett 		return;
520719f82d3SEliot Blennerhassett 	}
521719f82d3SEliot Blennerhassett 	phw = (struct hpi_hw_obj *)pao->priv;
522719f82d3SEliot Blennerhassett 	/* reset adapter h/w */
523719f82d3SEliot Blennerhassett 	/* Reset C6713 #1 */
524719f82d3SEliot Blennerhassett 	boot_loader_write_mem32(pao, 0, C6205_BAR0_TIMER1_CTL, 0);
525719f82d3SEliot Blennerhassett 	/* reset C6205 */
526719f82d3SEliot Blennerhassett 	iowrite32(C6205_HDCR_WARMRESET, phw->prHDCR);
527719f82d3SEliot Blennerhassett 
528719f82d3SEliot Blennerhassett 	delete_adapter_obj(pao);
529719f82d3SEliot Blennerhassett 	phr->error = 0;
530719f82d3SEliot Blennerhassett }
531719f82d3SEliot Blennerhassett 
532719f82d3SEliot Blennerhassett /** Create adapter object
533719f82d3SEliot Blennerhassett   allocate buffers, bootload DSPs, initialise control cache
534719f82d3SEliot Blennerhassett */
535719f82d3SEliot Blennerhassett static u16 create_adapter_obj(struct hpi_adapter_obj *pao,
536719f82d3SEliot Blennerhassett 	u32 *pos_error_code)
537719f82d3SEliot Blennerhassett {
538719f82d3SEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
539719f82d3SEliot Blennerhassett 	struct bus_master_interface *interface;
540719f82d3SEliot Blennerhassett 	u32 phys_addr;
541719f82d3SEliot Blennerhassett #ifndef HPI6205_NO_HSR_POLL
542719f82d3SEliot Blennerhassett 	u32 time_out = HPI6205_TIMEOUT;
543719f82d3SEliot Blennerhassett 	u32 temp1;
544719f82d3SEliot Blennerhassett #endif
545719f82d3SEliot Blennerhassett 	int i;
546719f82d3SEliot Blennerhassett 	u16 err;
547719f82d3SEliot Blennerhassett 
548719f82d3SEliot Blennerhassett 	/* init error reporting */
549719f82d3SEliot Blennerhassett 	pao->dsp_crashed = 0;
550719f82d3SEliot Blennerhassett 
551719f82d3SEliot Blennerhassett 	for (i = 0; i < HPI_MAX_STREAMS; i++)
552719f82d3SEliot Blennerhassett 		phw->flag_outstream_just_reset[i] = 1;
553719f82d3SEliot Blennerhassett 
554719f82d3SEliot Blennerhassett 	/* The C6205 memory area 1 is 8Mbyte window into DSP registers */
555719f82d3SEliot Blennerhassett 	phw->prHSR =
556719f82d3SEliot Blennerhassett 		pao->pci.ap_mem_base[1] +
557719f82d3SEliot Blennerhassett 		C6205_BAR1_HSR / sizeof(*pao->pci.ap_mem_base[1]);
558719f82d3SEliot Blennerhassett 	phw->prHDCR =
559719f82d3SEliot Blennerhassett 		pao->pci.ap_mem_base[1] +
560719f82d3SEliot Blennerhassett 		C6205_BAR1_HDCR / sizeof(*pao->pci.ap_mem_base[1]);
561719f82d3SEliot Blennerhassett 	phw->prDSPP =
562719f82d3SEliot Blennerhassett 		pao->pci.ap_mem_base[1] +
563719f82d3SEliot Blennerhassett 		C6205_BAR1_DSPP / sizeof(*pao->pci.ap_mem_base[1]);
564719f82d3SEliot Blennerhassett 
565719f82d3SEliot Blennerhassett 	pao->has_control_cache = 0;
566719f82d3SEliot Blennerhassett 
567719f82d3SEliot Blennerhassett 	if (hpios_locked_mem_alloc(&phw->h_locked_mem,
568719f82d3SEliot Blennerhassett 			sizeof(struct bus_master_interface),
569719f82d3SEliot Blennerhassett 			pao->pci.p_os_data))
570719f82d3SEliot Blennerhassett 		phw->p_interface_buffer = NULL;
571719f82d3SEliot Blennerhassett 	else if (hpios_locked_mem_get_virt_addr(&phw->h_locked_mem,
572719f82d3SEliot Blennerhassett 			(void *)&phw->p_interface_buffer))
573719f82d3SEliot Blennerhassett 		phw->p_interface_buffer = NULL;
574719f82d3SEliot Blennerhassett 
575719f82d3SEliot Blennerhassett 	HPI_DEBUG_LOG(DEBUG, "interface buffer address %p\n",
576719f82d3SEliot Blennerhassett 		phw->p_interface_buffer);
577719f82d3SEliot Blennerhassett 
578719f82d3SEliot Blennerhassett 	if (phw->p_interface_buffer) {
579719f82d3SEliot Blennerhassett 		memset((void *)phw->p_interface_buffer, 0,
580719f82d3SEliot Blennerhassett 			sizeof(struct bus_master_interface));
581719f82d3SEliot Blennerhassett 		phw->p_interface_buffer->dsp_ack = H620_HIF_UNKNOWN;
582719f82d3SEliot Blennerhassett 	}
583719f82d3SEliot Blennerhassett 
584719f82d3SEliot Blennerhassett 	err = adapter_boot_load_dsp(pao, pos_error_code);
585719f82d3SEliot Blennerhassett 	if (err)
586719f82d3SEliot Blennerhassett 		/* no need to clean up as SubSysCreateAdapter */
587719f82d3SEliot Blennerhassett 		/* calls DeleteAdapter on error. */
588719f82d3SEliot Blennerhassett 		return err;
589719f82d3SEliot Blennerhassett 
590719f82d3SEliot Blennerhassett 	HPI_DEBUG_LOG(INFO, "load DSP code OK\n");
591719f82d3SEliot Blennerhassett 
592719f82d3SEliot Blennerhassett 	/* allow boot load even if mem alloc wont work */
593719f82d3SEliot Blennerhassett 	if (!phw->p_interface_buffer)
594719f82d3SEliot Blennerhassett 		return hpi6205_error(0, HPI_ERROR_MEMORY_ALLOC);
595719f82d3SEliot Blennerhassett 
596719f82d3SEliot Blennerhassett 	interface = phw->p_interface_buffer;
597719f82d3SEliot Blennerhassett 
598719f82d3SEliot Blennerhassett #ifndef HPI6205_NO_HSR_POLL
599719f82d3SEliot Blennerhassett 	/* wait for first interrupt indicating the DSP init is done */
600719f82d3SEliot Blennerhassett 	time_out = HPI6205_TIMEOUT * 10;
601719f82d3SEliot Blennerhassett 	temp1 = 0;
602719f82d3SEliot Blennerhassett 	while (((temp1 & C6205_HSR_INTSRC) == 0) && --time_out)
603719f82d3SEliot Blennerhassett 		temp1 = ioread32(phw->prHSR);
604719f82d3SEliot Blennerhassett 
605719f82d3SEliot Blennerhassett 	if (temp1 & C6205_HSR_INTSRC)
606719f82d3SEliot Blennerhassett 		HPI_DEBUG_LOG(INFO,
607719f82d3SEliot Blennerhassett 			"interrupt confirming DSP code running OK\n");
608719f82d3SEliot Blennerhassett 	else {
609719f82d3SEliot Blennerhassett 		HPI_DEBUG_LOG(ERROR,
610719f82d3SEliot Blennerhassett 			"timed out waiting for interrupt "
611719f82d3SEliot Blennerhassett 			"confirming DSP code running\n");
612719f82d3SEliot Blennerhassett 		return hpi6205_error(0, HPI6205_ERROR_6205_NO_IRQ);
613719f82d3SEliot Blennerhassett 	}
614719f82d3SEliot Blennerhassett 
615719f82d3SEliot Blennerhassett 	/* reset the interrupt */
616719f82d3SEliot Blennerhassett 	iowrite32(C6205_HSR_INTSRC, phw->prHSR);
617719f82d3SEliot Blennerhassett #endif
618719f82d3SEliot Blennerhassett 
619719f82d3SEliot Blennerhassett 	/* make sure the DSP has started ok */
620719f82d3SEliot Blennerhassett 	if (!wait_dsp_ack(phw, H620_HIF_RESET, HPI6205_TIMEOUT * 10)) {
621719f82d3SEliot Blennerhassett 		HPI_DEBUG_LOG(ERROR, "timed out waiting reset state \n");
622719f82d3SEliot Blennerhassett 		return hpi6205_error(0, HPI6205_ERROR_6205_INIT_FAILED);
623719f82d3SEliot Blennerhassett 	}
624719f82d3SEliot Blennerhassett 	/* Note that *pao, *phw are zeroed after allocation,
625719f82d3SEliot Blennerhassett 	 * so pointers and flags are NULL by default.
626719f82d3SEliot Blennerhassett 	 * Allocate bus mastering control cache buffer and tell the DSP about it
627719f82d3SEliot Blennerhassett 	 */
628719f82d3SEliot Blennerhassett 	if (interface->control_cache.number_of_controls) {
629719f82d3SEliot Blennerhassett 		void *p_control_cache_virtual;
630719f82d3SEliot Blennerhassett 
631719f82d3SEliot Blennerhassett 		err = hpios_locked_mem_alloc(&phw->h_control_cache,
632719f82d3SEliot Blennerhassett 			interface->control_cache.size_in_bytes,
633719f82d3SEliot Blennerhassett 			pao->pci.p_os_data);
634719f82d3SEliot Blennerhassett 		if (!err)
635719f82d3SEliot Blennerhassett 			err = hpios_locked_mem_get_virt_addr(&phw->
636719f82d3SEliot Blennerhassett 				h_control_cache, &p_control_cache_virtual);
637719f82d3SEliot Blennerhassett 		if (!err) {
638719f82d3SEliot Blennerhassett 			memset(p_control_cache_virtual, 0,
639719f82d3SEliot Blennerhassett 				interface->control_cache.size_in_bytes);
640719f82d3SEliot Blennerhassett 
641719f82d3SEliot Blennerhassett 			phw->p_cache =
642719f82d3SEliot Blennerhassett 				hpi_alloc_control_cache(interface->
643719f82d3SEliot Blennerhassett 				control_cache.number_of_controls,
644719f82d3SEliot Blennerhassett 				interface->control_cache.size_in_bytes,
645719f82d3SEliot Blennerhassett 				(struct hpi_control_cache_info *)
646719f82d3SEliot Blennerhassett 				p_control_cache_virtual);
647719f82d3SEliot Blennerhassett 		}
648719f82d3SEliot Blennerhassett 		if (!err) {
649719f82d3SEliot Blennerhassett 			err = hpios_locked_mem_get_phys_addr(&phw->
650719f82d3SEliot Blennerhassett 				h_control_cache, &phys_addr);
651719f82d3SEliot Blennerhassett 			interface->control_cache.physical_address32 =
652719f82d3SEliot Blennerhassett 				phys_addr;
653719f82d3SEliot Blennerhassett 		}
654719f82d3SEliot Blennerhassett 
655719f82d3SEliot Blennerhassett 		if (!err)
656719f82d3SEliot Blennerhassett 			pao->has_control_cache = 1;
657719f82d3SEliot Blennerhassett 		else {
658719f82d3SEliot Blennerhassett 			if (hpios_locked_mem_valid(&phw->h_control_cache))
659719f82d3SEliot Blennerhassett 				hpios_locked_mem_free(&phw->h_control_cache);
660719f82d3SEliot Blennerhassett 			pao->has_control_cache = 0;
661719f82d3SEliot Blennerhassett 		}
662719f82d3SEliot Blennerhassett 	}
663719f82d3SEliot Blennerhassett 	/* allocate bus mastering async buffer and tell the DSP about it */
664719f82d3SEliot Blennerhassett 	if (interface->async_buffer.b.size) {
665719f82d3SEliot Blennerhassett 		err = hpios_locked_mem_alloc(&phw->h_async_event_buffer,
666719f82d3SEliot Blennerhassett 			interface->async_buffer.b.size *
667719f82d3SEliot Blennerhassett 			sizeof(struct hpi_async_event), pao->pci.p_os_data);
668719f82d3SEliot Blennerhassett 		if (!err)
669719f82d3SEliot Blennerhassett 			err = hpios_locked_mem_get_virt_addr
670719f82d3SEliot Blennerhassett 				(&phw->h_async_event_buffer, (void *)
671719f82d3SEliot Blennerhassett 				&phw->p_async_event_buffer);
672719f82d3SEliot Blennerhassett 		if (!err)
673719f82d3SEliot Blennerhassett 			memset((void *)phw->p_async_event_buffer, 0,
674719f82d3SEliot Blennerhassett 				interface->async_buffer.b.size *
675719f82d3SEliot Blennerhassett 				sizeof(struct hpi_async_event));
676719f82d3SEliot Blennerhassett 		if (!err) {
677719f82d3SEliot Blennerhassett 			err = hpios_locked_mem_get_phys_addr
678719f82d3SEliot Blennerhassett 				(&phw->h_async_event_buffer, &phys_addr);
679719f82d3SEliot Blennerhassett 			interface->async_buffer.physical_address32 =
680719f82d3SEliot Blennerhassett 				phys_addr;
681719f82d3SEliot Blennerhassett 		}
682719f82d3SEliot Blennerhassett 		if (err) {
683719f82d3SEliot Blennerhassett 			if (hpios_locked_mem_valid(&phw->
684719f82d3SEliot Blennerhassett 					h_async_event_buffer)) {
685719f82d3SEliot Blennerhassett 				hpios_locked_mem_free
686719f82d3SEliot Blennerhassett 					(&phw->h_async_event_buffer);
687719f82d3SEliot Blennerhassett 				phw->p_async_event_buffer = NULL;
688719f82d3SEliot Blennerhassett 			}
689719f82d3SEliot Blennerhassett 		}
690719f82d3SEliot Blennerhassett 	}
691719f82d3SEliot Blennerhassett 	send_dsp_command(phw, H620_HIF_IDLE);
692719f82d3SEliot Blennerhassett 
693719f82d3SEliot Blennerhassett 	{
694719f82d3SEliot Blennerhassett 		struct hpi_message hM;
695719f82d3SEliot Blennerhassett 		struct hpi_response hR;
696719f82d3SEliot Blennerhassett 		u32 max_streams;
697719f82d3SEliot Blennerhassett 
698719f82d3SEliot Blennerhassett 		HPI_DEBUG_LOG(VERBOSE, "init ADAPTER_GET_INFO\n");
699719f82d3SEliot Blennerhassett 		memset(&hM, 0, sizeof(hM));
700719f82d3SEliot Blennerhassett 		hM.type = HPI_TYPE_MESSAGE;
701719f82d3SEliot Blennerhassett 		hM.size = sizeof(hM);
702719f82d3SEliot Blennerhassett 		hM.object = HPI_OBJ_ADAPTER;
703719f82d3SEliot Blennerhassett 		hM.function = HPI_ADAPTER_GET_INFO;
704719f82d3SEliot Blennerhassett 		hM.adapter_index = 0;
705719f82d3SEliot Blennerhassett 		memset(&hR, 0, sizeof(hR));
706719f82d3SEliot Blennerhassett 		hR.size = sizeof(hR);
707719f82d3SEliot Blennerhassett 
708719f82d3SEliot Blennerhassett 		err = message_response_sequence(pao, &hM, &hR);
709719f82d3SEliot Blennerhassett 		if (err) {
710719f82d3SEliot Blennerhassett 			HPI_DEBUG_LOG(ERROR, "message transport error %d\n",
711719f82d3SEliot Blennerhassett 				err);
712719f82d3SEliot Blennerhassett 			return err;
713719f82d3SEliot Blennerhassett 		}
714719f82d3SEliot Blennerhassett 		if (hR.error)
715719f82d3SEliot Blennerhassett 			return hR.error;
716719f82d3SEliot Blennerhassett 
717719f82d3SEliot Blennerhassett 		pao->adapter_type = hR.u.a.adapter_type;
718719f82d3SEliot Blennerhassett 		pao->index = hR.u.a.adapter_index;
719719f82d3SEliot Blennerhassett 
720719f82d3SEliot Blennerhassett 		max_streams = hR.u.a.num_outstreams + hR.u.a.num_instreams;
721719f82d3SEliot Blennerhassett 
722719f82d3SEliot Blennerhassett 		hpios_locked_mem_prepare((max_streams * 6) / 10, max_streams,
723719f82d3SEliot Blennerhassett 			65536, pao->pci.p_os_data);
724719f82d3SEliot Blennerhassett 
725719f82d3SEliot Blennerhassett 		HPI_DEBUG_LOG(VERBOSE,
726719f82d3SEliot Blennerhassett 			"got adapter info type %x index %d serial %d\n",
727719f82d3SEliot Blennerhassett 			hR.u.a.adapter_type, hR.u.a.adapter_index,
728719f82d3SEliot Blennerhassett 			hR.u.a.serial_number);
729719f82d3SEliot Blennerhassett 	}
730719f82d3SEliot Blennerhassett 
731719f82d3SEliot Blennerhassett 	pao->open = 0;	/* upon creation the adapter is closed */
732719f82d3SEliot Blennerhassett 
733719f82d3SEliot Blennerhassett 	HPI_DEBUG_LOG(INFO, "bootload DSP OK\n");
734719f82d3SEliot Blennerhassett 	return 0;
735719f82d3SEliot Blennerhassett }
736719f82d3SEliot Blennerhassett 
737719f82d3SEliot Blennerhassett /** Free memory areas allocated by adapter
738719f82d3SEliot Blennerhassett  * this routine is called from SubSysDeleteAdapter,
739719f82d3SEliot Blennerhassett   * and SubSysCreateAdapter if duplicate index
740719f82d3SEliot Blennerhassett */
741719f82d3SEliot Blennerhassett static void delete_adapter_obj(struct hpi_adapter_obj *pao)
742719f82d3SEliot Blennerhassett {
743719f82d3SEliot Blennerhassett 	struct hpi_hw_obj *phw;
744719f82d3SEliot Blennerhassett 	int i;
745719f82d3SEliot Blennerhassett 
746719f82d3SEliot Blennerhassett 	phw = pao->priv;
747719f82d3SEliot Blennerhassett 
748719f82d3SEliot Blennerhassett 	if (hpios_locked_mem_valid(&phw->h_async_event_buffer)) {
749719f82d3SEliot Blennerhassett 		hpios_locked_mem_free(&phw->h_async_event_buffer);
750719f82d3SEliot Blennerhassett 		phw->p_async_event_buffer = NULL;
751719f82d3SEliot Blennerhassett 	}
752719f82d3SEliot Blennerhassett 
753719f82d3SEliot Blennerhassett 	if (hpios_locked_mem_valid(&phw->h_control_cache)) {
754719f82d3SEliot Blennerhassett 		hpios_locked_mem_free(&phw->h_control_cache);
755719f82d3SEliot Blennerhassett 		hpi_free_control_cache(phw->p_cache);
756719f82d3SEliot Blennerhassett 	}
757719f82d3SEliot Blennerhassett 
758719f82d3SEliot Blennerhassett 	if (hpios_locked_mem_valid(&phw->h_locked_mem)) {
759719f82d3SEliot Blennerhassett 		hpios_locked_mem_free(&phw->h_locked_mem);
760719f82d3SEliot Blennerhassett 		phw->p_interface_buffer = NULL;
761719f82d3SEliot Blennerhassett 	}
762719f82d3SEliot Blennerhassett 
763719f82d3SEliot Blennerhassett 	for (i = 0; i < HPI_MAX_STREAMS; i++)
764719f82d3SEliot Blennerhassett 		if (hpios_locked_mem_valid(&phw->instream_host_buffers[i])) {
765719f82d3SEliot Blennerhassett 			hpios_locked_mem_free(&phw->instream_host_buffers[i]);
766719f82d3SEliot Blennerhassett 			/*?phw->InStreamHostBuffers[i] = NULL; */
767719f82d3SEliot Blennerhassett 			phw->instream_host_buffer_size[i] = 0;
768719f82d3SEliot Blennerhassett 		}
769719f82d3SEliot Blennerhassett 
770719f82d3SEliot Blennerhassett 	for (i = 0; i < HPI_MAX_STREAMS; i++)
771719f82d3SEliot Blennerhassett 		if (hpios_locked_mem_valid(&phw->outstream_host_buffers[i])) {
772719f82d3SEliot Blennerhassett 			hpios_locked_mem_free(&phw->outstream_host_buffers
773719f82d3SEliot Blennerhassett 				[i]);
774719f82d3SEliot Blennerhassett 			phw->outstream_host_buffer_size[i] = 0;
775719f82d3SEliot Blennerhassett 		}
776719f82d3SEliot Blennerhassett 
777719f82d3SEliot Blennerhassett 	hpios_locked_mem_unprepare(pao->pci.p_os_data);
778719f82d3SEliot Blennerhassett 
779719f82d3SEliot Blennerhassett 	hpi_delete_adapter(pao);
780719f82d3SEliot Blennerhassett 	kfree(phw);
781719f82d3SEliot Blennerhassett }
782719f82d3SEliot Blennerhassett 
783719f82d3SEliot Blennerhassett /*****************************************************************************/
784719f82d3SEliot Blennerhassett /* OutStream Host buffer functions */
785719f82d3SEliot Blennerhassett 
786719f82d3SEliot Blennerhassett /** Allocate or attach buffer for busmastering
787719f82d3SEliot Blennerhassett */
788719f82d3SEliot Blennerhassett static void outstream_host_buffer_allocate(struct hpi_adapter_obj *pao,
789719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
790719f82d3SEliot Blennerhassett {
791719f82d3SEliot Blennerhassett 	u16 err = 0;
792719f82d3SEliot Blennerhassett 	u32 command = phm->u.d.u.buffer.command;
793719f82d3SEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
794719f82d3SEliot Blennerhassett 	struct bus_master_interface *interface = phw->p_interface_buffer;
795719f82d3SEliot Blennerhassett 
796719f82d3SEliot Blennerhassett 	hpi_init_response(phr, phm->object, phm->function, 0);
797719f82d3SEliot Blennerhassett 
798719f82d3SEliot Blennerhassett 	if (command == HPI_BUFFER_CMD_EXTERNAL
799719f82d3SEliot Blennerhassett 		|| command == HPI_BUFFER_CMD_INTERNAL_ALLOC) {
800719f82d3SEliot Blennerhassett 		/* ALLOC phase, allocate a buffer with power of 2 size,
801719f82d3SEliot Blennerhassett 		   get its bus address for PCI bus mastering
802719f82d3SEliot Blennerhassett 		 */
803719f82d3SEliot Blennerhassett 		phm->u.d.u.buffer.buffer_size =
804719f82d3SEliot Blennerhassett 			roundup_pow_of_two(phm->u.d.u.buffer.buffer_size);
805719f82d3SEliot Blennerhassett 		/* return old size and allocated size,
806719f82d3SEliot Blennerhassett 		   so caller can detect change */
807719f82d3SEliot Blennerhassett 		phr->u.d.u.stream_info.data_available =
808719f82d3SEliot Blennerhassett 			phw->outstream_host_buffer_size[phm->obj_index];
809719f82d3SEliot Blennerhassett 		phr->u.d.u.stream_info.buffer_size =
810719f82d3SEliot Blennerhassett 			phm->u.d.u.buffer.buffer_size;
811719f82d3SEliot Blennerhassett 
812719f82d3SEliot Blennerhassett 		if (phw->outstream_host_buffer_size[phm->obj_index] ==
813719f82d3SEliot Blennerhassett 			phm->u.d.u.buffer.buffer_size) {
814719f82d3SEliot Blennerhassett 			/* Same size, no action required */
815719f82d3SEliot Blennerhassett 			return;
816719f82d3SEliot Blennerhassett 		}
817719f82d3SEliot Blennerhassett 
818719f82d3SEliot Blennerhassett 		if (hpios_locked_mem_valid(&phw->outstream_host_buffers[phm->
819719f82d3SEliot Blennerhassett 					obj_index]))
820719f82d3SEliot Blennerhassett 			hpios_locked_mem_free(&phw->outstream_host_buffers
821719f82d3SEliot Blennerhassett 				[phm->obj_index]);
822719f82d3SEliot Blennerhassett 
823719f82d3SEliot Blennerhassett 		err = hpios_locked_mem_alloc(&phw->outstream_host_buffers
824719f82d3SEliot Blennerhassett 			[phm->obj_index], phm->u.d.u.buffer.buffer_size,
825719f82d3SEliot Blennerhassett 			pao->pci.p_os_data);
826719f82d3SEliot Blennerhassett 
827719f82d3SEliot Blennerhassett 		if (err) {
828719f82d3SEliot Blennerhassett 			phr->error = HPI_ERROR_INVALID_DATASIZE;
829719f82d3SEliot Blennerhassett 			phw->outstream_host_buffer_size[phm->obj_index] = 0;
830719f82d3SEliot Blennerhassett 			return;
831719f82d3SEliot Blennerhassett 		}
832719f82d3SEliot Blennerhassett 
833719f82d3SEliot Blennerhassett 		err = hpios_locked_mem_get_phys_addr
834719f82d3SEliot Blennerhassett 			(&phw->outstream_host_buffers[phm->obj_index],
835719f82d3SEliot Blennerhassett 			&phm->u.d.u.buffer.pci_address);
836719f82d3SEliot Blennerhassett 		/* get the phys addr into msg for single call alloc caller
837719f82d3SEliot Blennerhassett 		 * needs to do this for split alloc (or use the same message)
838719f82d3SEliot Blennerhassett 		 * return the phy address for split alloc in the respose too
839719f82d3SEliot Blennerhassett 		 */
840719f82d3SEliot Blennerhassett 		phr->u.d.u.stream_info.auxiliary_data_available =
841719f82d3SEliot Blennerhassett 			phm->u.d.u.buffer.pci_address;
842719f82d3SEliot Blennerhassett 
843719f82d3SEliot Blennerhassett 		if (err) {
844719f82d3SEliot Blennerhassett 			hpios_locked_mem_free(&phw->outstream_host_buffers
845719f82d3SEliot Blennerhassett 				[phm->obj_index]);
846719f82d3SEliot Blennerhassett 			phw->outstream_host_buffer_size[phm->obj_index] = 0;
847719f82d3SEliot Blennerhassett 			phr->error = HPI_ERROR_MEMORY_ALLOC;
848719f82d3SEliot Blennerhassett 			return;
849719f82d3SEliot Blennerhassett 		}
850719f82d3SEliot Blennerhassett 	}
851719f82d3SEliot Blennerhassett 
852719f82d3SEliot Blennerhassett 	if (command == HPI_BUFFER_CMD_EXTERNAL
853719f82d3SEliot Blennerhassett 		|| command == HPI_BUFFER_CMD_INTERNAL_GRANTADAPTER) {
854719f82d3SEliot Blennerhassett 		/* GRANT phase.  Set up the BBM status, tell the DSP about
855719f82d3SEliot Blennerhassett 		   the buffer so it can start using BBM.
856719f82d3SEliot Blennerhassett 		 */
857719f82d3SEliot Blennerhassett 		struct hpi_hostbuffer_status *status;
858719f82d3SEliot Blennerhassett 
859719f82d3SEliot Blennerhassett 		if (phm->u.d.u.buffer.buffer_size & (phm->u.d.u.buffer.
860719f82d3SEliot Blennerhassett 				buffer_size - 1)) {
861719f82d3SEliot Blennerhassett 			HPI_DEBUG_LOG(ERROR,
862719f82d3SEliot Blennerhassett 				"buffer size must be 2^N not %d\n",
863719f82d3SEliot Blennerhassett 				phm->u.d.u.buffer.buffer_size);
864719f82d3SEliot Blennerhassett 			phr->error = HPI_ERROR_INVALID_DATASIZE;
865719f82d3SEliot Blennerhassett 			return;
866719f82d3SEliot Blennerhassett 		}
867719f82d3SEliot Blennerhassett 		phw->outstream_host_buffer_size[phm->obj_index] =
868719f82d3SEliot Blennerhassett 			phm->u.d.u.buffer.buffer_size;
869719f82d3SEliot Blennerhassett 		status = &interface->outstream_host_buffer_status[phm->
870719f82d3SEliot Blennerhassett 			obj_index];
871719f82d3SEliot Blennerhassett 		status->samples_processed = 0;
872719f82d3SEliot Blennerhassett 		status->stream_state = HPI_STATE_STOPPED;
873719f82d3SEliot Blennerhassett 		status->dSP_index = 0;
874719f82d3SEliot Blennerhassett 		status->host_index = status->dSP_index;
875719f82d3SEliot Blennerhassett 		status->size_in_bytes = phm->u.d.u.buffer.buffer_size;
876719f82d3SEliot Blennerhassett 
877719f82d3SEliot Blennerhassett 		hw_message(pao, phm, phr);
878719f82d3SEliot Blennerhassett 
879719f82d3SEliot Blennerhassett 		if (phr->error
880719f82d3SEliot Blennerhassett 			&& hpios_locked_mem_valid(&phw->
881719f82d3SEliot Blennerhassett 				outstream_host_buffers[phm->obj_index])) {
882719f82d3SEliot Blennerhassett 			hpios_locked_mem_free(&phw->outstream_host_buffers
883719f82d3SEliot Blennerhassett 				[phm->obj_index]);
884719f82d3SEliot Blennerhassett 			phw->outstream_host_buffer_size[phm->obj_index] = 0;
885719f82d3SEliot Blennerhassett 		}
886719f82d3SEliot Blennerhassett 	}
887719f82d3SEliot Blennerhassett }
888719f82d3SEliot Blennerhassett 
889719f82d3SEliot Blennerhassett static void outstream_host_buffer_get_info(struct hpi_adapter_obj *pao,
890719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
891719f82d3SEliot Blennerhassett {
892719f82d3SEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
893719f82d3SEliot Blennerhassett 	struct bus_master_interface *interface = phw->p_interface_buffer;
894719f82d3SEliot Blennerhassett 	struct hpi_hostbuffer_status *status;
895719f82d3SEliot Blennerhassett 	u8 *p_bbm_data;
896719f82d3SEliot Blennerhassett 
897719f82d3SEliot Blennerhassett 	if (hpios_locked_mem_valid(&phw->outstream_host_buffers[phm->
898719f82d3SEliot Blennerhassett 				obj_index])) {
899719f82d3SEliot Blennerhassett 		if (hpios_locked_mem_get_virt_addr(&phw->
900719f82d3SEliot Blennerhassett 				outstream_host_buffers[phm->obj_index],
901719f82d3SEliot Blennerhassett 				(void *)&p_bbm_data)) {
902719f82d3SEliot Blennerhassett 			phr->error = HPI_ERROR_INVALID_OPERATION;
903719f82d3SEliot Blennerhassett 			return;
904719f82d3SEliot Blennerhassett 		}
905719f82d3SEliot Blennerhassett 		status = &interface->outstream_host_buffer_status[phm->
906719f82d3SEliot Blennerhassett 			obj_index];
907719f82d3SEliot Blennerhassett 		hpi_init_response(phr, HPI_OBJ_OSTREAM,
908719f82d3SEliot Blennerhassett 			HPI_OSTREAM_HOSTBUFFER_GET_INFO, 0);
909719f82d3SEliot Blennerhassett 		phr->u.d.u.hostbuffer_info.p_buffer = p_bbm_data;
910719f82d3SEliot Blennerhassett 		phr->u.d.u.hostbuffer_info.p_status = status;
911719f82d3SEliot Blennerhassett 	} else {
912719f82d3SEliot Blennerhassett 		hpi_init_response(phr, HPI_OBJ_OSTREAM,
913719f82d3SEliot Blennerhassett 			HPI_OSTREAM_HOSTBUFFER_GET_INFO,
914719f82d3SEliot Blennerhassett 			HPI_ERROR_INVALID_OPERATION);
915719f82d3SEliot Blennerhassett 	}
916719f82d3SEliot Blennerhassett }
917719f82d3SEliot Blennerhassett 
918719f82d3SEliot Blennerhassett static void outstream_host_buffer_free(struct hpi_adapter_obj *pao,
919719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
920719f82d3SEliot Blennerhassett {
921719f82d3SEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
922719f82d3SEliot Blennerhassett 	u32 command = phm->u.d.u.buffer.command;
923719f82d3SEliot Blennerhassett 
924719f82d3SEliot Blennerhassett 	if (phw->outstream_host_buffer_size[phm->obj_index]) {
925719f82d3SEliot Blennerhassett 		if (command == HPI_BUFFER_CMD_EXTERNAL
926719f82d3SEliot Blennerhassett 			|| command == HPI_BUFFER_CMD_INTERNAL_REVOKEADAPTER) {
927719f82d3SEliot Blennerhassett 			phw->outstream_host_buffer_size[phm->obj_index] = 0;
928719f82d3SEliot Blennerhassett 			hw_message(pao, phm, phr);
929719f82d3SEliot Blennerhassett 			/* Tell adapter to stop using the host buffer. */
930719f82d3SEliot Blennerhassett 		}
931719f82d3SEliot Blennerhassett 		if (command == HPI_BUFFER_CMD_EXTERNAL
932719f82d3SEliot Blennerhassett 			|| command == HPI_BUFFER_CMD_INTERNAL_FREE)
933719f82d3SEliot Blennerhassett 			hpios_locked_mem_free(&phw->outstream_host_buffers
934719f82d3SEliot Blennerhassett 				[phm->obj_index]);
935719f82d3SEliot Blennerhassett 	}
936719f82d3SEliot Blennerhassett 	/* Should HPI_ERROR_INVALID_OPERATION be returned
937719f82d3SEliot Blennerhassett 	   if no host buffer is allocated? */
938719f82d3SEliot Blennerhassett 	else
939719f82d3SEliot Blennerhassett 		hpi_init_response(phr, HPI_OBJ_OSTREAM,
940719f82d3SEliot Blennerhassett 			HPI_OSTREAM_HOSTBUFFER_FREE, 0);
941719f82d3SEliot Blennerhassett 
942719f82d3SEliot Blennerhassett }
943719f82d3SEliot Blennerhassett 
944*2a383cb3SEliot Blennerhassett static u32 outstream_get_space_available(struct hpi_hostbuffer_status
945719f82d3SEliot Blennerhassett 	*status)
946719f82d3SEliot Blennerhassett {
947*2a383cb3SEliot Blennerhassett 	return status->size_in_bytes - (status->host_index -
948*2a383cb3SEliot Blennerhassett 		status->dSP_index);
949719f82d3SEliot Blennerhassett }
950719f82d3SEliot Blennerhassett 
951719f82d3SEliot Blennerhassett static void outstream_write(struct hpi_adapter_obj *pao,
952719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
953719f82d3SEliot Blennerhassett {
954719f82d3SEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
955719f82d3SEliot Blennerhassett 	struct bus_master_interface *interface = phw->p_interface_buffer;
956719f82d3SEliot Blennerhassett 	struct hpi_hostbuffer_status *status;
957*2a383cb3SEliot Blennerhassett 	u32 space_available;
958719f82d3SEliot Blennerhassett 
959719f82d3SEliot Blennerhassett 	if (!phw->outstream_host_buffer_size[phm->obj_index]) {
960719f82d3SEliot Blennerhassett 		/* there  is no BBM buffer, write via message */
961719f82d3SEliot Blennerhassett 		hw_message(pao, phm, phr);
962719f82d3SEliot Blennerhassett 		return;
963719f82d3SEliot Blennerhassett 	}
964719f82d3SEliot Blennerhassett 
965719f82d3SEliot Blennerhassett 	hpi_init_response(phr, phm->object, phm->function, 0);
966719f82d3SEliot Blennerhassett 	status = &interface->outstream_host_buffer_status[phm->obj_index];
967719f82d3SEliot Blennerhassett 
968719f82d3SEliot Blennerhassett 	if (phw->flag_outstream_just_reset[phm->obj_index]) {
969719f82d3SEliot Blennerhassett 		/* First OutStremWrite() call following reset will write data to the
9701a59fa7cSEliot Blennerhassett 		   adapter's buffers, reducing delay before stream can start. The DSP
9711a59fa7cSEliot Blennerhassett 		   takes care of setting the stream data format using format information
9721a59fa7cSEliot Blennerhassett 		   embedded in phm.
973719f82d3SEliot Blennerhassett 		 */
974719f82d3SEliot Blennerhassett 		int partial_write = 0;
975719f82d3SEliot Blennerhassett 		unsigned int original_size = 0;
976719f82d3SEliot Blennerhassett 
9771a59fa7cSEliot Blennerhassett 		phw->flag_outstream_just_reset[phm->obj_index] = 0;
9781a59fa7cSEliot Blennerhassett 
979719f82d3SEliot Blennerhassett 		/* Send the first buffer to the DSP the old way. */
980719f82d3SEliot Blennerhassett 		/* Limit size of first transfer - */
981719f82d3SEliot Blennerhassett 		/* expect that this will not usually be triggered. */
982719f82d3SEliot Blennerhassett 		if (phm->u.d.u.data.data_size > HPI6205_SIZEOF_DATA) {
983719f82d3SEliot Blennerhassett 			partial_write = 1;
984719f82d3SEliot Blennerhassett 			original_size = phm->u.d.u.data.data_size;
985719f82d3SEliot Blennerhassett 			phm->u.d.u.data.data_size = HPI6205_SIZEOF_DATA;
986719f82d3SEliot Blennerhassett 		}
987719f82d3SEliot Blennerhassett 		/* write it */
988719f82d3SEliot Blennerhassett 		phm->function = HPI_OSTREAM_WRITE;
989719f82d3SEliot Blennerhassett 		hw_message(pao, phm, phr);
990719f82d3SEliot Blennerhassett 		/* update status information that the DSP would typically
991719f82d3SEliot Blennerhassett 		 * update (and will update next time the DSP
992719f82d3SEliot Blennerhassett 		 * buffer update task reads data from the host BBM buffer)
993719f82d3SEliot Blennerhassett 		 */
994719f82d3SEliot Blennerhassett 		status->auxiliary_data_available = phm->u.d.u.data.data_size;
995719f82d3SEliot Blennerhassett 		status->host_index += phm->u.d.u.data.data_size;
996719f82d3SEliot Blennerhassett 		status->dSP_index += phm->u.d.u.data.data_size;
997719f82d3SEliot Blennerhassett 
998719f82d3SEliot Blennerhassett 		/* if we did a full write, we can return from here. */
999719f82d3SEliot Blennerhassett 		if (!partial_write)
1000719f82d3SEliot Blennerhassett 			return;
1001719f82d3SEliot Blennerhassett 
1002719f82d3SEliot Blennerhassett 		/* tweak buffer parameters and let the rest of the */
1003719f82d3SEliot Blennerhassett 		/* buffer land in internal BBM buffer */
1004719f82d3SEliot Blennerhassett 		phm->u.d.u.data.data_size =
1005719f82d3SEliot Blennerhassett 			original_size - HPI6205_SIZEOF_DATA;
1006719f82d3SEliot Blennerhassett 		phm->u.d.u.data.pb_data += HPI6205_SIZEOF_DATA;
1007719f82d3SEliot Blennerhassett 	}
1008719f82d3SEliot Blennerhassett 
1009719f82d3SEliot Blennerhassett 	space_available = outstream_get_space_available(status);
1010*2a383cb3SEliot Blennerhassett 	if (space_available < phm->u.d.u.data.data_size) {
1011719f82d3SEliot Blennerhassett 		phr->error = HPI_ERROR_INVALID_DATASIZE;
1012719f82d3SEliot Blennerhassett 		return;
1013719f82d3SEliot Blennerhassett 	}
1014719f82d3SEliot Blennerhassett 
1015719f82d3SEliot Blennerhassett 	/* HostBuffers is used to indicate host buffer is internally allocated.
1016719f82d3SEliot Blennerhassett 	   otherwise, assumed external, data written externally */
1017719f82d3SEliot Blennerhassett 	if (phm->u.d.u.data.pb_data
1018719f82d3SEliot Blennerhassett 		&& hpios_locked_mem_valid(&phw->outstream_host_buffers[phm->
1019719f82d3SEliot Blennerhassett 				obj_index])) {
1020719f82d3SEliot Blennerhassett 		u8 *p_bbm_data;
1021*2a383cb3SEliot Blennerhassett 		u32 l_first_write;
1022719f82d3SEliot Blennerhassett 		u8 *p_app_data = (u8 *)phm->u.d.u.data.pb_data;
1023719f82d3SEliot Blennerhassett 
1024719f82d3SEliot Blennerhassett 		if (hpios_locked_mem_get_virt_addr(&phw->
1025719f82d3SEliot Blennerhassett 				outstream_host_buffers[phm->obj_index],
1026719f82d3SEliot Blennerhassett 				(void *)&p_bbm_data)) {
1027719f82d3SEliot Blennerhassett 			phr->error = HPI_ERROR_INVALID_OPERATION;
1028719f82d3SEliot Blennerhassett 			return;
1029719f82d3SEliot Blennerhassett 		}
1030719f82d3SEliot Blennerhassett 
1031719f82d3SEliot Blennerhassett 		/* either all data,
1032719f82d3SEliot Blennerhassett 		   or enough to fit from current to end of BBM buffer */
1033719f82d3SEliot Blennerhassett 		l_first_write =
1034719f82d3SEliot Blennerhassett 			min(phm->u.d.u.data.data_size,
1035719f82d3SEliot Blennerhassett 			status->size_in_bytes -
1036719f82d3SEliot Blennerhassett 			(status->host_index & (status->size_in_bytes - 1)));
1037719f82d3SEliot Blennerhassett 
1038719f82d3SEliot Blennerhassett 		memcpy(p_bbm_data +
1039719f82d3SEliot Blennerhassett 			(status->host_index & (status->size_in_bytes - 1)),
1040719f82d3SEliot Blennerhassett 			p_app_data, l_first_write);
1041719f82d3SEliot Blennerhassett 		/* remaining data if any */
1042719f82d3SEliot Blennerhassett 		memcpy(p_bbm_data, p_app_data + l_first_write,
1043719f82d3SEliot Blennerhassett 			phm->u.d.u.data.data_size - l_first_write);
1044719f82d3SEliot Blennerhassett 	}
1045719f82d3SEliot Blennerhassett 	status->host_index += phm->u.d.u.data.data_size;
1046719f82d3SEliot Blennerhassett }
1047719f82d3SEliot Blennerhassett 
1048719f82d3SEliot Blennerhassett static void outstream_get_info(struct hpi_adapter_obj *pao,
1049719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
1050719f82d3SEliot Blennerhassett {
1051719f82d3SEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
1052719f82d3SEliot Blennerhassett 	struct bus_master_interface *interface = phw->p_interface_buffer;
1053719f82d3SEliot Blennerhassett 	struct hpi_hostbuffer_status *status;
1054719f82d3SEliot Blennerhassett 
1055719f82d3SEliot Blennerhassett 	if (!phw->outstream_host_buffer_size[phm->obj_index]) {
1056719f82d3SEliot Blennerhassett 		hw_message(pao, phm, phr);
1057719f82d3SEliot Blennerhassett 		return;
1058719f82d3SEliot Blennerhassett 	}
1059719f82d3SEliot Blennerhassett 
1060719f82d3SEliot Blennerhassett 	hpi_init_response(phr, phm->object, phm->function, 0);
1061719f82d3SEliot Blennerhassett 
1062719f82d3SEliot Blennerhassett 	status = &interface->outstream_host_buffer_status[phm->obj_index];
1063719f82d3SEliot Blennerhassett 
1064719f82d3SEliot Blennerhassett 	phr->u.d.u.stream_info.state = (u16)status->stream_state;
1065719f82d3SEliot Blennerhassett 	phr->u.d.u.stream_info.samples_transferred =
1066719f82d3SEliot Blennerhassett 		status->samples_processed;
1067719f82d3SEliot Blennerhassett 	phr->u.d.u.stream_info.buffer_size = status->size_in_bytes;
1068719f82d3SEliot Blennerhassett 	phr->u.d.u.stream_info.data_available =
1069719f82d3SEliot Blennerhassett 		status->size_in_bytes - outstream_get_space_available(status);
1070719f82d3SEliot Blennerhassett 	phr->u.d.u.stream_info.auxiliary_data_available =
1071719f82d3SEliot Blennerhassett 		status->auxiliary_data_available;
1072719f82d3SEliot Blennerhassett }
1073719f82d3SEliot Blennerhassett 
1074719f82d3SEliot Blennerhassett static void outstream_start(struct hpi_adapter_obj *pao,
1075719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
1076719f82d3SEliot Blennerhassett {
1077719f82d3SEliot Blennerhassett 	hw_message(pao, phm, phr);
1078719f82d3SEliot Blennerhassett }
1079719f82d3SEliot Blennerhassett 
1080719f82d3SEliot Blennerhassett static void outstream_reset(struct hpi_adapter_obj *pao,
1081719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
1082719f82d3SEliot Blennerhassett {
1083719f82d3SEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
1084719f82d3SEliot Blennerhassett 	phw->flag_outstream_just_reset[phm->obj_index] = 1;
1085719f82d3SEliot Blennerhassett 	hw_message(pao, phm, phr);
1086719f82d3SEliot Blennerhassett }
1087719f82d3SEliot Blennerhassett 
1088719f82d3SEliot Blennerhassett static void outstream_open(struct hpi_adapter_obj *pao,
1089719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
1090719f82d3SEliot Blennerhassett {
1091719f82d3SEliot Blennerhassett 	outstream_reset(pao, phm, phr);
1092719f82d3SEliot Blennerhassett }
1093719f82d3SEliot Blennerhassett 
1094719f82d3SEliot Blennerhassett /*****************************************************************************/
1095719f82d3SEliot Blennerhassett /* InStream Host buffer functions */
1096719f82d3SEliot Blennerhassett 
1097719f82d3SEliot Blennerhassett static void instream_host_buffer_allocate(struct hpi_adapter_obj *pao,
1098719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
1099719f82d3SEliot Blennerhassett {
1100719f82d3SEliot Blennerhassett 	u16 err = 0;
1101719f82d3SEliot Blennerhassett 	u32 command = phm->u.d.u.buffer.command;
1102719f82d3SEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
1103719f82d3SEliot Blennerhassett 	struct bus_master_interface *interface = phw->p_interface_buffer;
1104719f82d3SEliot Blennerhassett 
1105719f82d3SEliot Blennerhassett 	hpi_init_response(phr, phm->object, phm->function, 0);
1106719f82d3SEliot Blennerhassett 
1107719f82d3SEliot Blennerhassett 	if (command == HPI_BUFFER_CMD_EXTERNAL
1108719f82d3SEliot Blennerhassett 		|| command == HPI_BUFFER_CMD_INTERNAL_ALLOC) {
1109719f82d3SEliot Blennerhassett 
1110719f82d3SEliot Blennerhassett 		phm->u.d.u.buffer.buffer_size =
1111719f82d3SEliot Blennerhassett 			roundup_pow_of_two(phm->u.d.u.buffer.buffer_size);
1112719f82d3SEliot Blennerhassett 		phr->u.d.u.stream_info.data_available =
1113719f82d3SEliot Blennerhassett 			phw->instream_host_buffer_size[phm->obj_index];
1114719f82d3SEliot Blennerhassett 		phr->u.d.u.stream_info.buffer_size =
1115719f82d3SEliot Blennerhassett 			phm->u.d.u.buffer.buffer_size;
1116719f82d3SEliot Blennerhassett 
1117719f82d3SEliot Blennerhassett 		if (phw->instream_host_buffer_size[phm->obj_index] ==
1118719f82d3SEliot Blennerhassett 			phm->u.d.u.buffer.buffer_size) {
1119719f82d3SEliot Blennerhassett 			/* Same size, no action required */
1120719f82d3SEliot Blennerhassett 			return;
1121719f82d3SEliot Blennerhassett 		}
1122719f82d3SEliot Blennerhassett 
1123719f82d3SEliot Blennerhassett 		if (hpios_locked_mem_valid(&phw->instream_host_buffers[phm->
1124719f82d3SEliot Blennerhassett 					obj_index]))
1125719f82d3SEliot Blennerhassett 			hpios_locked_mem_free(&phw->instream_host_buffers
1126719f82d3SEliot Blennerhassett 				[phm->obj_index]);
1127719f82d3SEliot Blennerhassett 
1128719f82d3SEliot Blennerhassett 		err = hpios_locked_mem_alloc(&phw->instream_host_buffers[phm->
1129719f82d3SEliot Blennerhassett 				obj_index], phm->u.d.u.buffer.buffer_size,
1130719f82d3SEliot Blennerhassett 			pao->pci.p_os_data);
1131719f82d3SEliot Blennerhassett 
1132719f82d3SEliot Blennerhassett 		if (err) {
1133719f82d3SEliot Blennerhassett 			phr->error = HPI_ERROR_INVALID_DATASIZE;
1134719f82d3SEliot Blennerhassett 			phw->instream_host_buffer_size[phm->obj_index] = 0;
1135719f82d3SEliot Blennerhassett 			return;
1136719f82d3SEliot Blennerhassett 		}
1137719f82d3SEliot Blennerhassett 
1138719f82d3SEliot Blennerhassett 		err = hpios_locked_mem_get_phys_addr
1139719f82d3SEliot Blennerhassett 			(&phw->instream_host_buffers[phm->obj_index],
1140719f82d3SEliot Blennerhassett 			&phm->u.d.u.buffer.pci_address);
1141719f82d3SEliot Blennerhassett 		/* get the phys addr into msg for single call alloc. Caller
1142719f82d3SEliot Blennerhassett 		   needs to do this for split alloc so return the phy address */
1143719f82d3SEliot Blennerhassett 		phr->u.d.u.stream_info.auxiliary_data_available =
1144719f82d3SEliot Blennerhassett 			phm->u.d.u.buffer.pci_address;
1145719f82d3SEliot Blennerhassett 		if (err) {
1146719f82d3SEliot Blennerhassett 			hpios_locked_mem_free(&phw->instream_host_buffers
1147719f82d3SEliot Blennerhassett 				[phm->obj_index]);
1148719f82d3SEliot Blennerhassett 			phw->instream_host_buffer_size[phm->obj_index] = 0;
1149719f82d3SEliot Blennerhassett 			phr->error = HPI_ERROR_MEMORY_ALLOC;
1150719f82d3SEliot Blennerhassett 			return;
1151719f82d3SEliot Blennerhassett 		}
1152719f82d3SEliot Blennerhassett 	}
1153719f82d3SEliot Blennerhassett 
1154719f82d3SEliot Blennerhassett 	if (command == HPI_BUFFER_CMD_EXTERNAL
1155719f82d3SEliot Blennerhassett 		|| command == HPI_BUFFER_CMD_INTERNAL_GRANTADAPTER) {
1156719f82d3SEliot Blennerhassett 		struct hpi_hostbuffer_status *status;
1157719f82d3SEliot Blennerhassett 
1158719f82d3SEliot Blennerhassett 		if (phm->u.d.u.buffer.buffer_size & (phm->u.d.u.buffer.
1159719f82d3SEliot Blennerhassett 				buffer_size - 1)) {
1160719f82d3SEliot Blennerhassett 			HPI_DEBUG_LOG(ERROR,
1161719f82d3SEliot Blennerhassett 				"buffer size must be 2^N not %d\n",
1162719f82d3SEliot Blennerhassett 				phm->u.d.u.buffer.buffer_size);
1163719f82d3SEliot Blennerhassett 			phr->error = HPI_ERROR_INVALID_DATASIZE;
1164719f82d3SEliot Blennerhassett 			return;
1165719f82d3SEliot Blennerhassett 		}
1166719f82d3SEliot Blennerhassett 
1167719f82d3SEliot Blennerhassett 		phw->instream_host_buffer_size[phm->obj_index] =
1168719f82d3SEliot Blennerhassett 			phm->u.d.u.buffer.buffer_size;
1169719f82d3SEliot Blennerhassett 		status = &interface->instream_host_buffer_status[phm->
1170719f82d3SEliot Blennerhassett 			obj_index];
1171719f82d3SEliot Blennerhassett 		status->samples_processed = 0;
1172719f82d3SEliot Blennerhassett 		status->stream_state = HPI_STATE_STOPPED;
1173719f82d3SEliot Blennerhassett 		status->dSP_index = 0;
1174719f82d3SEliot Blennerhassett 		status->host_index = status->dSP_index;
1175719f82d3SEliot Blennerhassett 		status->size_in_bytes = phm->u.d.u.buffer.buffer_size;
1176719f82d3SEliot Blennerhassett 
1177719f82d3SEliot Blennerhassett 		hw_message(pao, phm, phr);
1178719f82d3SEliot Blennerhassett 		if (phr->error
1179719f82d3SEliot Blennerhassett 			&& hpios_locked_mem_valid(&phw->
1180719f82d3SEliot Blennerhassett 				instream_host_buffers[phm->obj_index])) {
1181719f82d3SEliot Blennerhassett 			hpios_locked_mem_free(&phw->instream_host_buffers
1182719f82d3SEliot Blennerhassett 				[phm->obj_index]);
1183719f82d3SEliot Blennerhassett 			phw->instream_host_buffer_size[phm->obj_index] = 0;
1184719f82d3SEliot Blennerhassett 		}
1185719f82d3SEliot Blennerhassett 	}
1186719f82d3SEliot Blennerhassett }
1187719f82d3SEliot Blennerhassett 
1188719f82d3SEliot Blennerhassett static void instream_host_buffer_get_info(struct hpi_adapter_obj *pao,
1189719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
1190719f82d3SEliot Blennerhassett {
1191719f82d3SEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
1192719f82d3SEliot Blennerhassett 	struct bus_master_interface *interface = phw->p_interface_buffer;
1193719f82d3SEliot Blennerhassett 	struct hpi_hostbuffer_status *status;
1194719f82d3SEliot Blennerhassett 	u8 *p_bbm_data;
1195719f82d3SEliot Blennerhassett 
1196719f82d3SEliot Blennerhassett 	if (hpios_locked_mem_valid(&phw->instream_host_buffers[phm->
1197719f82d3SEliot Blennerhassett 				obj_index])) {
1198719f82d3SEliot Blennerhassett 		if (hpios_locked_mem_get_virt_addr(&phw->
1199719f82d3SEliot Blennerhassett 				instream_host_buffers[phm->obj_index],
1200719f82d3SEliot Blennerhassett 				(void *)&p_bbm_data)) {
1201719f82d3SEliot Blennerhassett 			phr->error = HPI_ERROR_INVALID_OPERATION;
1202719f82d3SEliot Blennerhassett 			return;
1203719f82d3SEliot Blennerhassett 		}
1204719f82d3SEliot Blennerhassett 		status = &interface->instream_host_buffer_status[phm->
1205719f82d3SEliot Blennerhassett 			obj_index];
1206719f82d3SEliot Blennerhassett 		hpi_init_response(phr, HPI_OBJ_ISTREAM,
1207719f82d3SEliot Blennerhassett 			HPI_ISTREAM_HOSTBUFFER_GET_INFO, 0);
1208719f82d3SEliot Blennerhassett 		phr->u.d.u.hostbuffer_info.p_buffer = p_bbm_data;
1209719f82d3SEliot Blennerhassett 		phr->u.d.u.hostbuffer_info.p_status = status;
1210719f82d3SEliot Blennerhassett 	} else {
1211719f82d3SEliot Blennerhassett 		hpi_init_response(phr, HPI_OBJ_ISTREAM,
1212719f82d3SEliot Blennerhassett 			HPI_ISTREAM_HOSTBUFFER_GET_INFO,
1213719f82d3SEliot Blennerhassett 			HPI_ERROR_INVALID_OPERATION);
1214719f82d3SEliot Blennerhassett 	}
1215719f82d3SEliot Blennerhassett }
1216719f82d3SEliot Blennerhassett 
1217719f82d3SEliot Blennerhassett static void instream_host_buffer_free(struct hpi_adapter_obj *pao,
1218719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
1219719f82d3SEliot Blennerhassett {
1220719f82d3SEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
1221719f82d3SEliot Blennerhassett 	u32 command = phm->u.d.u.buffer.command;
1222719f82d3SEliot Blennerhassett 
1223719f82d3SEliot Blennerhassett 	if (phw->instream_host_buffer_size[phm->obj_index]) {
1224719f82d3SEliot Blennerhassett 		if (command == HPI_BUFFER_CMD_EXTERNAL
1225719f82d3SEliot Blennerhassett 			|| command == HPI_BUFFER_CMD_INTERNAL_REVOKEADAPTER) {
1226719f82d3SEliot Blennerhassett 			phw->instream_host_buffer_size[phm->obj_index] = 0;
1227719f82d3SEliot Blennerhassett 			hw_message(pao, phm, phr);
1228719f82d3SEliot Blennerhassett 		}
1229719f82d3SEliot Blennerhassett 
1230719f82d3SEliot Blennerhassett 		if (command == HPI_BUFFER_CMD_EXTERNAL
1231719f82d3SEliot Blennerhassett 			|| command == HPI_BUFFER_CMD_INTERNAL_FREE)
1232719f82d3SEliot Blennerhassett 			hpios_locked_mem_free(&phw->instream_host_buffers
1233719f82d3SEliot Blennerhassett 				[phm->obj_index]);
1234719f82d3SEliot Blennerhassett 
1235719f82d3SEliot Blennerhassett 	} else {
1236719f82d3SEliot Blennerhassett 		/* Should HPI_ERROR_INVALID_OPERATION be returned
1237719f82d3SEliot Blennerhassett 		   if no host buffer is allocated? */
1238719f82d3SEliot Blennerhassett 		hpi_init_response(phr, HPI_OBJ_ISTREAM,
1239719f82d3SEliot Blennerhassett 			HPI_ISTREAM_HOSTBUFFER_FREE, 0);
1240719f82d3SEliot Blennerhassett 
1241719f82d3SEliot Blennerhassett 	}
1242719f82d3SEliot Blennerhassett 
1243719f82d3SEliot Blennerhassett }
1244719f82d3SEliot Blennerhassett 
1245719f82d3SEliot Blennerhassett static void instream_start(struct hpi_adapter_obj *pao,
1246719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
1247719f82d3SEliot Blennerhassett {
1248719f82d3SEliot Blennerhassett 	hw_message(pao, phm, phr);
1249719f82d3SEliot Blennerhassett }
1250719f82d3SEliot Blennerhassett 
1251*2a383cb3SEliot Blennerhassett static u32 instream_get_bytes_available(struct hpi_hostbuffer_status *status)
1252719f82d3SEliot Blennerhassett {
1253*2a383cb3SEliot Blennerhassett 	return status->dSP_index - status->host_index;
1254719f82d3SEliot Blennerhassett }
1255719f82d3SEliot Blennerhassett 
1256719f82d3SEliot Blennerhassett static void instream_read(struct hpi_adapter_obj *pao,
1257719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
1258719f82d3SEliot Blennerhassett {
1259719f82d3SEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
1260719f82d3SEliot Blennerhassett 	struct bus_master_interface *interface = phw->p_interface_buffer;
1261719f82d3SEliot Blennerhassett 	struct hpi_hostbuffer_status *status;
1262*2a383cb3SEliot Blennerhassett 	u32 data_available;
1263719f82d3SEliot Blennerhassett 	u8 *p_bbm_data;
1264*2a383cb3SEliot Blennerhassett 	u32 l_first_read;
1265719f82d3SEliot Blennerhassett 	u8 *p_app_data = (u8 *)phm->u.d.u.data.pb_data;
1266719f82d3SEliot Blennerhassett 
1267719f82d3SEliot Blennerhassett 	if (!phw->instream_host_buffer_size[phm->obj_index]) {
1268719f82d3SEliot Blennerhassett 		hw_message(pao, phm, phr);
1269719f82d3SEliot Blennerhassett 		return;
1270719f82d3SEliot Blennerhassett 	}
1271719f82d3SEliot Blennerhassett 	hpi_init_response(phr, phm->object, phm->function, 0);
1272719f82d3SEliot Blennerhassett 
1273719f82d3SEliot Blennerhassett 	status = &interface->instream_host_buffer_status[phm->obj_index];
1274719f82d3SEliot Blennerhassett 	data_available = instream_get_bytes_available(status);
1275*2a383cb3SEliot Blennerhassett 	if (data_available < phm->u.d.u.data.data_size) {
1276719f82d3SEliot Blennerhassett 		phr->error = HPI_ERROR_INVALID_DATASIZE;
1277719f82d3SEliot Blennerhassett 		return;
1278719f82d3SEliot Blennerhassett 	}
1279719f82d3SEliot Blennerhassett 
1280719f82d3SEliot Blennerhassett 	if (hpios_locked_mem_valid(&phw->instream_host_buffers[phm->
1281719f82d3SEliot Blennerhassett 				obj_index])) {
1282719f82d3SEliot Blennerhassett 		if (hpios_locked_mem_get_virt_addr(&phw->
1283719f82d3SEliot Blennerhassett 				instream_host_buffers[phm->obj_index],
1284719f82d3SEliot Blennerhassett 				(void *)&p_bbm_data)) {
1285719f82d3SEliot Blennerhassett 			phr->error = HPI_ERROR_INVALID_OPERATION;
1286719f82d3SEliot Blennerhassett 			return;
1287719f82d3SEliot Blennerhassett 		}
1288719f82d3SEliot Blennerhassett 
1289719f82d3SEliot Blennerhassett 		/* either all data,
1290719f82d3SEliot Blennerhassett 		   or enough to fit from current to end of BBM buffer */
1291719f82d3SEliot Blennerhassett 		l_first_read =
1292719f82d3SEliot Blennerhassett 			min(phm->u.d.u.data.data_size,
1293719f82d3SEliot Blennerhassett 			status->size_in_bytes -
1294719f82d3SEliot Blennerhassett 			(status->host_index & (status->size_in_bytes - 1)));
1295719f82d3SEliot Blennerhassett 
1296719f82d3SEliot Blennerhassett 		memcpy(p_app_data,
1297719f82d3SEliot Blennerhassett 			p_bbm_data +
1298719f82d3SEliot Blennerhassett 			(status->host_index & (status->size_in_bytes - 1)),
1299719f82d3SEliot Blennerhassett 			l_first_read);
1300719f82d3SEliot Blennerhassett 		/* remaining data if any */
1301719f82d3SEliot Blennerhassett 		memcpy(p_app_data + l_first_read, p_bbm_data,
1302719f82d3SEliot Blennerhassett 			phm->u.d.u.data.data_size - l_first_read);
1303719f82d3SEliot Blennerhassett 	}
1304719f82d3SEliot Blennerhassett 	status->host_index += phm->u.d.u.data.data_size;
1305719f82d3SEliot Blennerhassett }
1306719f82d3SEliot Blennerhassett 
1307719f82d3SEliot Blennerhassett static void instream_get_info(struct hpi_adapter_obj *pao,
1308719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
1309719f82d3SEliot Blennerhassett {
1310719f82d3SEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
1311719f82d3SEliot Blennerhassett 	struct bus_master_interface *interface = phw->p_interface_buffer;
1312719f82d3SEliot Blennerhassett 	struct hpi_hostbuffer_status *status;
1313719f82d3SEliot Blennerhassett 	if (!phw->instream_host_buffer_size[phm->obj_index]) {
1314719f82d3SEliot Blennerhassett 		hw_message(pao, phm, phr);
1315719f82d3SEliot Blennerhassett 		return;
1316719f82d3SEliot Blennerhassett 	}
1317719f82d3SEliot Blennerhassett 
1318719f82d3SEliot Blennerhassett 	status = &interface->instream_host_buffer_status[phm->obj_index];
1319719f82d3SEliot Blennerhassett 
1320719f82d3SEliot Blennerhassett 	hpi_init_response(phr, phm->object, phm->function, 0);
1321719f82d3SEliot Blennerhassett 
1322719f82d3SEliot Blennerhassett 	phr->u.d.u.stream_info.state = (u16)status->stream_state;
1323719f82d3SEliot Blennerhassett 	phr->u.d.u.stream_info.samples_transferred =
1324719f82d3SEliot Blennerhassett 		status->samples_processed;
1325719f82d3SEliot Blennerhassett 	phr->u.d.u.stream_info.buffer_size = status->size_in_bytes;
1326719f82d3SEliot Blennerhassett 	phr->u.d.u.stream_info.data_available =
1327719f82d3SEliot Blennerhassett 		instream_get_bytes_available(status);
1328719f82d3SEliot Blennerhassett 	phr->u.d.u.stream_info.auxiliary_data_available =
1329719f82d3SEliot Blennerhassett 		status->auxiliary_data_available;
1330719f82d3SEliot Blennerhassett }
1331719f82d3SEliot Blennerhassett 
1332719f82d3SEliot Blennerhassett /*****************************************************************************/
1333719f82d3SEliot Blennerhassett /* LOW-LEVEL */
1334719f82d3SEliot Blennerhassett #define HPI6205_MAX_FILES_TO_LOAD 2
1335719f82d3SEliot Blennerhassett 
1336719f82d3SEliot Blennerhassett static u16 adapter_boot_load_dsp(struct hpi_adapter_obj *pao,
1337719f82d3SEliot Blennerhassett 	u32 *pos_error_code)
1338719f82d3SEliot Blennerhassett {
1339719f82d3SEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
1340719f82d3SEliot Blennerhassett 	struct dsp_code dsp_code;
1341719f82d3SEliot Blennerhassett 	u16 boot_code_id[HPI6205_MAX_FILES_TO_LOAD];
1342719f82d3SEliot Blennerhassett 	u16 firmware_id = pao->pci.subsys_device_id;
1343719f82d3SEliot Blennerhassett 	u32 temp;
1344719f82d3SEliot Blennerhassett 	int dsp = 0, i = 0;
1345719f82d3SEliot Blennerhassett 	u16 err = 0;
1346719f82d3SEliot Blennerhassett 
1347719f82d3SEliot Blennerhassett 	boot_code_id[0] = HPI_ADAPTER_ASI(0x6205);
1348719f82d3SEliot Blennerhassett 
1349719f82d3SEliot Blennerhassett 	/* special cases where firmware_id != subsys ID */
1350719f82d3SEliot Blennerhassett 	switch (firmware_id) {
1351719f82d3SEliot Blennerhassett 	case HPI_ADAPTER_FAMILY_ASI(0x5000):
1352719f82d3SEliot Blennerhassett 		boot_code_id[0] = firmware_id;
1353719f82d3SEliot Blennerhassett 		firmware_id = 0;
1354719f82d3SEliot Blennerhassett 		break;
1355719f82d3SEliot Blennerhassett 	case HPI_ADAPTER_FAMILY_ASI(0x5300):
1356719f82d3SEliot Blennerhassett 	case HPI_ADAPTER_FAMILY_ASI(0x5400):
1357719f82d3SEliot Blennerhassett 	case HPI_ADAPTER_FAMILY_ASI(0x6300):
1358719f82d3SEliot Blennerhassett 		firmware_id = HPI_ADAPTER_FAMILY_ASI(0x6400);
1359719f82d3SEliot Blennerhassett 		break;
1360719f82d3SEliot Blennerhassett 	case HPI_ADAPTER_FAMILY_ASI(0x5600):
1361719f82d3SEliot Blennerhassett 	case HPI_ADAPTER_FAMILY_ASI(0x6500):
1362719f82d3SEliot Blennerhassett 		firmware_id = HPI_ADAPTER_FAMILY_ASI(0x6600);
1363719f82d3SEliot Blennerhassett 		break;
1364cadae428SEliot Blennerhassett 	case HPI_ADAPTER_FAMILY_ASI(0x8800):
1365cadae428SEliot Blennerhassett 		firmware_id = HPI_ADAPTER_FAMILY_ASI(0x8900);
1366cadae428SEliot Blennerhassett 		break;
1367719f82d3SEliot Blennerhassett 	}
1368719f82d3SEliot Blennerhassett 	boot_code_id[1] = firmware_id;
1369719f82d3SEliot Blennerhassett 
1370719f82d3SEliot Blennerhassett 	/* reset DSP by writing a 1 to the WARMRESET bit */
1371719f82d3SEliot Blennerhassett 	temp = C6205_HDCR_WARMRESET;
1372719f82d3SEliot Blennerhassett 	iowrite32(temp, phw->prHDCR);
1373719f82d3SEliot Blennerhassett 	hpios_delay_micro_seconds(1000);
1374719f82d3SEliot Blennerhassett 
1375719f82d3SEliot Blennerhassett 	/* check that PCI i/f was configured by EEPROM */
1376719f82d3SEliot Blennerhassett 	temp = ioread32(phw->prHSR);
1377719f82d3SEliot Blennerhassett 	if ((temp & (C6205_HSR_CFGERR | C6205_HSR_EEREAD)) !=
1378719f82d3SEliot Blennerhassett 		C6205_HSR_EEREAD)
1379719f82d3SEliot Blennerhassett 		return hpi6205_error(0, HPI6205_ERROR_6205_EEPROM);
1380719f82d3SEliot Blennerhassett 	temp |= 0x04;
1381719f82d3SEliot Blennerhassett 	/* disable PINTA interrupt */
1382719f82d3SEliot Blennerhassett 	iowrite32(temp, phw->prHSR);
1383719f82d3SEliot Blennerhassett 
1384719f82d3SEliot Blennerhassett 	/* check control register reports PCI boot mode */
1385719f82d3SEliot Blennerhassett 	temp = ioread32(phw->prHDCR);
1386719f82d3SEliot Blennerhassett 	if (!(temp & C6205_HDCR_PCIBOOT))
1387719f82d3SEliot Blennerhassett 		return hpi6205_error(0, HPI6205_ERROR_6205_REG);
1388719f82d3SEliot Blennerhassett 
1389719f82d3SEliot Blennerhassett 	/* try writing a couple of numbers to the DSP page register */
1390719f82d3SEliot Blennerhassett 	/* and reading them back. */
1391719f82d3SEliot Blennerhassett 	temp = 1;
1392719f82d3SEliot Blennerhassett 	iowrite32(temp, phw->prDSPP);
1393719f82d3SEliot Blennerhassett 	if ((temp | C6205_DSPP_MAP1) != ioread32(phw->prDSPP))
1394719f82d3SEliot Blennerhassett 		return hpi6205_error(0, HPI6205_ERROR_6205_DSPPAGE);
1395719f82d3SEliot Blennerhassett 	temp = 2;
1396719f82d3SEliot Blennerhassett 	iowrite32(temp, phw->prDSPP);
1397719f82d3SEliot Blennerhassett 	if ((temp | C6205_DSPP_MAP1) != ioread32(phw->prDSPP))
1398719f82d3SEliot Blennerhassett 		return hpi6205_error(0, HPI6205_ERROR_6205_DSPPAGE);
1399719f82d3SEliot Blennerhassett 	temp = 3;
1400719f82d3SEliot Blennerhassett 	iowrite32(temp, phw->prDSPP);
1401719f82d3SEliot Blennerhassett 	if ((temp | C6205_DSPP_MAP1) != ioread32(phw->prDSPP))
1402719f82d3SEliot Blennerhassett 		return hpi6205_error(0, HPI6205_ERROR_6205_DSPPAGE);
1403719f82d3SEliot Blennerhassett 	/* reset DSP page to the correct number */
1404719f82d3SEliot Blennerhassett 	temp = 0;
1405719f82d3SEliot Blennerhassett 	iowrite32(temp, phw->prDSPP);
1406719f82d3SEliot Blennerhassett 	if ((temp | C6205_DSPP_MAP1) != ioread32(phw->prDSPP))
1407719f82d3SEliot Blennerhassett 		return hpi6205_error(0, HPI6205_ERROR_6205_DSPPAGE);
1408719f82d3SEliot Blennerhassett 	phw->dsp_page = 0;
1409719f82d3SEliot Blennerhassett 
1410719f82d3SEliot Blennerhassett 	/* release 6713 from reset before 6205 is bootloaded.
1411719f82d3SEliot Blennerhassett 	   This ensures that the EMIF is inactive,
1412719f82d3SEliot Blennerhassett 	   and the 6713 HPI gets the correct bootmode etc
1413719f82d3SEliot Blennerhassett 	 */
1414719f82d3SEliot Blennerhassett 	if (boot_code_id[1] != 0) {
1415719f82d3SEliot Blennerhassett 		/* DSP 1 is a C6713 */
1416719f82d3SEliot Blennerhassett 		/* CLKX0 <- '1' release the C6205 bootmode pulldowns */
1417719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, 0, (0x018C0024L), 0x00002202);
1418719f82d3SEliot Blennerhassett 		hpios_delay_micro_seconds(100);
1419719f82d3SEliot Blennerhassett 		/* Reset the 6713 #1 - revB */
1420719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, 0, C6205_BAR0_TIMER1_CTL, 0);
1421719f82d3SEliot Blennerhassett 
1422719f82d3SEliot Blennerhassett 		/* dummy read every 4 words for 6205 advisory 1.4.4 */
1423719f82d3SEliot Blennerhassett 		boot_loader_read_mem32(pao, 0, 0);
1424719f82d3SEliot Blennerhassett 
1425719f82d3SEliot Blennerhassett 		hpios_delay_micro_seconds(100);
1426719f82d3SEliot Blennerhassett 		/* Release C6713 from reset - revB */
1427719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, 0, C6205_BAR0_TIMER1_CTL, 4);
1428719f82d3SEliot Blennerhassett 		hpios_delay_micro_seconds(100);
1429719f82d3SEliot Blennerhassett 	}
1430719f82d3SEliot Blennerhassett 
1431719f82d3SEliot Blennerhassett 	for (dsp = 0; dsp < HPI6205_MAX_FILES_TO_LOAD; dsp++) {
1432719f82d3SEliot Blennerhassett 		/* is there a DSP to load? */
1433719f82d3SEliot Blennerhassett 		if (boot_code_id[dsp] == 0)
1434719f82d3SEliot Blennerhassett 			continue;
1435719f82d3SEliot Blennerhassett 
1436719f82d3SEliot Blennerhassett 		err = boot_loader_config_emif(pao, dsp);
1437719f82d3SEliot Blennerhassett 		if (err)
1438719f82d3SEliot Blennerhassett 			return err;
1439719f82d3SEliot Blennerhassett 
1440719f82d3SEliot Blennerhassett 		err = boot_loader_test_internal_memory(pao, dsp);
1441719f82d3SEliot Blennerhassett 		if (err)
1442719f82d3SEliot Blennerhassett 			return err;
1443719f82d3SEliot Blennerhassett 
1444719f82d3SEliot Blennerhassett 		err = boot_loader_test_external_memory(pao, dsp);
1445719f82d3SEliot Blennerhassett 		if (err)
1446719f82d3SEliot Blennerhassett 			return err;
1447719f82d3SEliot Blennerhassett 
1448719f82d3SEliot Blennerhassett 		err = boot_loader_test_pld(pao, dsp);
1449719f82d3SEliot Blennerhassett 		if (err)
1450719f82d3SEliot Blennerhassett 			return err;
1451719f82d3SEliot Blennerhassett 
1452719f82d3SEliot Blennerhassett 		/* write the DSP code down into the DSPs memory */
1453719f82d3SEliot Blennerhassett 		dsp_code.ps_dev = pao->pci.p_os_data;
1454719f82d3SEliot Blennerhassett 		err = hpi_dsp_code_open(boot_code_id[dsp], &dsp_code,
1455719f82d3SEliot Blennerhassett 			pos_error_code);
1456719f82d3SEliot Blennerhassett 		if (err)
1457719f82d3SEliot Blennerhassett 			return err;
1458719f82d3SEliot Blennerhassett 
1459719f82d3SEliot Blennerhassett 		while (1) {
1460719f82d3SEliot Blennerhassett 			u32 length;
1461719f82d3SEliot Blennerhassett 			u32 address;
1462719f82d3SEliot Blennerhassett 			u32 type;
1463719f82d3SEliot Blennerhassett 			u32 *pcode;
1464719f82d3SEliot Blennerhassett 
1465719f82d3SEliot Blennerhassett 			err = hpi_dsp_code_read_word(&dsp_code, &length);
1466719f82d3SEliot Blennerhassett 			if (err)
1467719f82d3SEliot Blennerhassett 				break;
1468719f82d3SEliot Blennerhassett 			if (length == 0xFFFFFFFF)
1469719f82d3SEliot Blennerhassett 				break;	/* end of code */
1470719f82d3SEliot Blennerhassett 
1471719f82d3SEliot Blennerhassett 			err = hpi_dsp_code_read_word(&dsp_code, &address);
1472719f82d3SEliot Blennerhassett 			if (err)
1473719f82d3SEliot Blennerhassett 				break;
1474719f82d3SEliot Blennerhassett 			err = hpi_dsp_code_read_word(&dsp_code, &type);
1475719f82d3SEliot Blennerhassett 			if (err)
1476719f82d3SEliot Blennerhassett 				break;
1477719f82d3SEliot Blennerhassett 			err = hpi_dsp_code_read_block(length, &dsp_code,
1478719f82d3SEliot Blennerhassett 				&pcode);
1479719f82d3SEliot Blennerhassett 			if (err)
1480719f82d3SEliot Blennerhassett 				break;
1481719f82d3SEliot Blennerhassett 			for (i = 0; i < (int)length; i++) {
1482719f82d3SEliot Blennerhassett 				err = boot_loader_write_mem32(pao, dsp,
1483719f82d3SEliot Blennerhassett 					address, *pcode);
1484719f82d3SEliot Blennerhassett 				if (err)
1485719f82d3SEliot Blennerhassett 					break;
1486719f82d3SEliot Blennerhassett 				/* dummy read every 4 words */
1487719f82d3SEliot Blennerhassett 				/* for 6205 advisory 1.4.4 */
1488719f82d3SEliot Blennerhassett 				if (i % 4 == 0)
1489719f82d3SEliot Blennerhassett 					boot_loader_read_mem32(pao, dsp,
1490719f82d3SEliot Blennerhassett 						address);
1491719f82d3SEliot Blennerhassett 				pcode++;
1492719f82d3SEliot Blennerhassett 				address += 4;
1493719f82d3SEliot Blennerhassett 			}
1494719f82d3SEliot Blennerhassett 
1495719f82d3SEliot Blennerhassett 		}
1496719f82d3SEliot Blennerhassett 		if (err) {
1497719f82d3SEliot Blennerhassett 			hpi_dsp_code_close(&dsp_code);
1498719f82d3SEliot Blennerhassett 			return err;
1499719f82d3SEliot Blennerhassett 		}
1500719f82d3SEliot Blennerhassett 
1501719f82d3SEliot Blennerhassett 		/* verify code */
1502719f82d3SEliot Blennerhassett 		hpi_dsp_code_rewind(&dsp_code);
1503719f82d3SEliot Blennerhassett 		while (1) {
1504719f82d3SEliot Blennerhassett 			u32 length = 0;
1505719f82d3SEliot Blennerhassett 			u32 address = 0;
1506719f82d3SEliot Blennerhassett 			u32 type = 0;
1507719f82d3SEliot Blennerhassett 			u32 *pcode = NULL;
1508719f82d3SEliot Blennerhassett 			u32 data = 0;
1509719f82d3SEliot Blennerhassett 
1510719f82d3SEliot Blennerhassett 			hpi_dsp_code_read_word(&dsp_code, &length);
1511719f82d3SEliot Blennerhassett 			if (length == 0xFFFFFFFF)
1512719f82d3SEliot Blennerhassett 				break;	/* end of code */
1513719f82d3SEliot Blennerhassett 
1514719f82d3SEliot Blennerhassett 			hpi_dsp_code_read_word(&dsp_code, &address);
1515719f82d3SEliot Blennerhassett 			hpi_dsp_code_read_word(&dsp_code, &type);
1516719f82d3SEliot Blennerhassett 			hpi_dsp_code_read_block(length, &dsp_code, &pcode);
1517719f82d3SEliot Blennerhassett 
1518719f82d3SEliot Blennerhassett 			for (i = 0; i < (int)length; i++) {
1519719f82d3SEliot Blennerhassett 				data = boot_loader_read_mem32(pao, dsp,
1520719f82d3SEliot Blennerhassett 					address);
1521719f82d3SEliot Blennerhassett 				if (data != *pcode) {
1522719f82d3SEliot Blennerhassett 					err = 0;
1523719f82d3SEliot Blennerhassett 					break;
1524719f82d3SEliot Blennerhassett 				}
1525719f82d3SEliot Blennerhassett 				pcode++;
1526719f82d3SEliot Blennerhassett 				address += 4;
1527719f82d3SEliot Blennerhassett 			}
1528719f82d3SEliot Blennerhassett 			if (err)
1529719f82d3SEliot Blennerhassett 				break;
1530719f82d3SEliot Blennerhassett 		}
1531719f82d3SEliot Blennerhassett 		hpi_dsp_code_close(&dsp_code);
1532719f82d3SEliot Blennerhassett 		if (err)
1533719f82d3SEliot Blennerhassett 			return err;
1534719f82d3SEliot Blennerhassett 	}
1535719f82d3SEliot Blennerhassett 
1536719f82d3SEliot Blennerhassett 	/* After bootloading all DSPs, start DSP0 running
1537719f82d3SEliot Blennerhassett 	 * The DSP0 code will handle starting and synchronizing with its slaves
1538719f82d3SEliot Blennerhassett 	 */
1539719f82d3SEliot Blennerhassett 	if (phw->p_interface_buffer) {
1540719f82d3SEliot Blennerhassett 		/* we need to tell the card the physical PCI address */
1541719f82d3SEliot Blennerhassett 		u32 physicalPC_iaddress;
1542719f82d3SEliot Blennerhassett 		struct bus_master_interface *interface =
1543719f82d3SEliot Blennerhassett 			phw->p_interface_buffer;
1544719f82d3SEliot Blennerhassett 		u32 host_mailbox_address_on_dsp;
1545719f82d3SEliot Blennerhassett 		u32 physicalPC_iaddress_verify = 0;
1546719f82d3SEliot Blennerhassett 		int time_out = 10;
1547719f82d3SEliot Blennerhassett 		/* set ack so we know when DSP is ready to go */
1548719f82d3SEliot Blennerhassett 		/* (dwDspAck will be changed to HIF_RESET) */
1549719f82d3SEliot Blennerhassett 		interface->dsp_ack = H620_HIF_UNKNOWN;
1550719f82d3SEliot Blennerhassett 		wmb();	/* ensure ack is written before dsp writes back */
1551719f82d3SEliot Blennerhassett 
1552719f82d3SEliot Blennerhassett 		err = hpios_locked_mem_get_phys_addr(&phw->h_locked_mem,
1553719f82d3SEliot Blennerhassett 			&physicalPC_iaddress);
1554719f82d3SEliot Blennerhassett 
1555719f82d3SEliot Blennerhassett 		/* locate the host mailbox on the DSP. */
1556719f82d3SEliot Blennerhassett 		host_mailbox_address_on_dsp = 0x80000000;
1557719f82d3SEliot Blennerhassett 		while ((physicalPC_iaddress != physicalPC_iaddress_verify)
1558719f82d3SEliot Blennerhassett 			&& time_out--) {
1559719f82d3SEliot Blennerhassett 			err = boot_loader_write_mem32(pao, 0,
1560719f82d3SEliot Blennerhassett 				host_mailbox_address_on_dsp,
1561719f82d3SEliot Blennerhassett 				physicalPC_iaddress);
1562719f82d3SEliot Blennerhassett 			physicalPC_iaddress_verify =
1563719f82d3SEliot Blennerhassett 				boot_loader_read_mem32(pao, 0,
1564719f82d3SEliot Blennerhassett 				host_mailbox_address_on_dsp);
1565719f82d3SEliot Blennerhassett 		}
1566719f82d3SEliot Blennerhassett 	}
1567719f82d3SEliot Blennerhassett 	HPI_DEBUG_LOG(DEBUG, "starting DS_ps running\n");
1568719f82d3SEliot Blennerhassett 	/* enable interrupts */
1569719f82d3SEliot Blennerhassett 	temp = ioread32(phw->prHSR);
1570719f82d3SEliot Blennerhassett 	temp &= ~(u32)C6205_HSR_INTAM;
1571719f82d3SEliot Blennerhassett 	iowrite32(temp, phw->prHSR);
1572719f82d3SEliot Blennerhassett 
1573719f82d3SEliot Blennerhassett 	/* start code running... */
1574719f82d3SEliot Blennerhassett 	temp = ioread32(phw->prHDCR);
1575719f82d3SEliot Blennerhassett 	temp |= (u32)C6205_HDCR_DSPINT;
1576719f82d3SEliot Blennerhassett 	iowrite32(temp, phw->prHDCR);
1577719f82d3SEliot Blennerhassett 
1578719f82d3SEliot Blennerhassett 	/* give the DSP 10ms to start up */
1579719f82d3SEliot Blennerhassett 	hpios_delay_micro_seconds(10000);
1580719f82d3SEliot Blennerhassett 	return err;
1581719f82d3SEliot Blennerhassett 
1582719f82d3SEliot Blennerhassett }
1583719f82d3SEliot Blennerhassett 
1584719f82d3SEliot Blennerhassett /*****************************************************************************/
1585719f82d3SEliot Blennerhassett /* Bootloader utility functions */
1586719f82d3SEliot Blennerhassett 
1587719f82d3SEliot Blennerhassett static u32 boot_loader_read_mem32(struct hpi_adapter_obj *pao, int dsp_index,
1588719f82d3SEliot Blennerhassett 	u32 address)
1589719f82d3SEliot Blennerhassett {
1590719f82d3SEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
1591719f82d3SEliot Blennerhassett 	u32 data = 0;
1592719f82d3SEliot Blennerhassett 	__iomem u32 *p_data;
1593719f82d3SEliot Blennerhassett 
1594719f82d3SEliot Blennerhassett 	if (dsp_index == 0) {
1595719f82d3SEliot Blennerhassett 		/* DSP 0 is always C6205 */
1596719f82d3SEliot Blennerhassett 		if ((address >= 0x01800000) & (address < 0x02000000)) {
1597719f82d3SEliot Blennerhassett 			/* BAR1 register access */
1598719f82d3SEliot Blennerhassett 			p_data = pao->pci.ap_mem_base[1] +
1599719f82d3SEliot Blennerhassett 				(address & 0x007fffff) /
1600719f82d3SEliot Blennerhassett 				sizeof(*pao->pci.ap_mem_base[1]);
1601719f82d3SEliot Blennerhassett 			/* HPI_DEBUG_LOG(WARNING,
1602719f82d3SEliot Blennerhassett 			   "BAR1 access %08x\n", dwAddress); */
1603719f82d3SEliot Blennerhassett 		} else {
1604719f82d3SEliot Blennerhassett 			u32 dw4M_page = address >> 22L;
1605719f82d3SEliot Blennerhassett 			if (dw4M_page != phw->dsp_page) {
1606719f82d3SEliot Blennerhassett 				phw->dsp_page = dw4M_page;
1607719f82d3SEliot Blennerhassett 				/* *INDENT OFF* */
1608719f82d3SEliot Blennerhassett 				iowrite32(phw->dsp_page, phw->prDSPP);
1609719f82d3SEliot Blennerhassett 				/* *INDENT-ON* */
1610719f82d3SEliot Blennerhassett 			}
1611719f82d3SEliot Blennerhassett 			address &= 0x3fffff;	/* address within 4M page */
1612719f82d3SEliot Blennerhassett 			/* BAR0 memory access */
1613719f82d3SEliot Blennerhassett 			p_data = pao->pci.ap_mem_base[0] +
1614719f82d3SEliot Blennerhassett 				address / sizeof(u32);
1615719f82d3SEliot Blennerhassett 		}
1616719f82d3SEliot Blennerhassett 		data = ioread32(p_data);
1617719f82d3SEliot Blennerhassett 	} else if (dsp_index == 1) {
1618719f82d3SEliot Blennerhassett 		/* DSP 1 is a C6713 */
1619719f82d3SEliot Blennerhassett 		u32 lsb;
1620719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, 0, HPIAL_ADDR, address);
1621719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, 0, HPIAH_ADDR, address >> 16);
1622719f82d3SEliot Blennerhassett 		lsb = boot_loader_read_mem32(pao, 0, HPIDL_ADDR);
1623719f82d3SEliot Blennerhassett 		data = boot_loader_read_mem32(pao, 0, HPIDH_ADDR);
1624719f82d3SEliot Blennerhassett 		data = (data << 16) | (lsb & 0xFFFF);
1625719f82d3SEliot Blennerhassett 	}
1626719f82d3SEliot Blennerhassett 	return data;
1627719f82d3SEliot Blennerhassett }
1628719f82d3SEliot Blennerhassett 
1629719f82d3SEliot Blennerhassett static u16 boot_loader_write_mem32(struct hpi_adapter_obj *pao, int dsp_index,
1630719f82d3SEliot Blennerhassett 	u32 address, u32 data)
1631719f82d3SEliot Blennerhassett {
1632719f82d3SEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
1633719f82d3SEliot Blennerhassett 	u16 err = 0;
1634719f82d3SEliot Blennerhassett 	__iomem u32 *p_data;
1635719f82d3SEliot Blennerhassett 	/*      u32 dwVerifyData=0; */
1636719f82d3SEliot Blennerhassett 
1637719f82d3SEliot Blennerhassett 	if (dsp_index == 0) {
1638719f82d3SEliot Blennerhassett 		/* DSP 0 is always C6205 */
1639719f82d3SEliot Blennerhassett 		if ((address >= 0x01800000) & (address < 0x02000000)) {
1640719f82d3SEliot Blennerhassett 			/* BAR1 - DSP  register access using */
1641719f82d3SEliot Blennerhassett 			/* Non-prefetchable PCI access */
1642719f82d3SEliot Blennerhassett 			p_data = pao->pci.ap_mem_base[1] +
1643719f82d3SEliot Blennerhassett 				(address & 0x007fffff) /
1644719f82d3SEliot Blennerhassett 				sizeof(*pao->pci.ap_mem_base[1]);
1645719f82d3SEliot Blennerhassett 		} else {
1646719f82d3SEliot Blennerhassett 			/* BAR0 access - all of DSP memory using */
1647719f82d3SEliot Blennerhassett 			/* pre-fetchable PCI access */
1648719f82d3SEliot Blennerhassett 			u32 dw4M_page = address >> 22L;
1649719f82d3SEliot Blennerhassett 			if (dw4M_page != phw->dsp_page) {
1650719f82d3SEliot Blennerhassett 				phw->dsp_page = dw4M_page;
1651719f82d3SEliot Blennerhassett 				/* *INDENT-OFF* */
1652719f82d3SEliot Blennerhassett 				iowrite32(phw->dsp_page, phw->prDSPP);
1653719f82d3SEliot Blennerhassett 				/* *INDENT-ON* */
1654719f82d3SEliot Blennerhassett 			}
1655719f82d3SEliot Blennerhassett 			address &= 0x3fffff;	/* address within 4M page */
1656719f82d3SEliot Blennerhassett 			p_data = pao->pci.ap_mem_base[0] +
1657719f82d3SEliot Blennerhassett 				address / sizeof(u32);
1658719f82d3SEliot Blennerhassett 		}
1659719f82d3SEliot Blennerhassett 		iowrite32(data, p_data);
1660719f82d3SEliot Blennerhassett 	} else if (dsp_index == 1) {
1661719f82d3SEliot Blennerhassett 		/* DSP 1 is a C6713 */
1662719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, 0, HPIAL_ADDR, address);
1663719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, 0, HPIAH_ADDR, address >> 16);
1664719f82d3SEliot Blennerhassett 
1665719f82d3SEliot Blennerhassett 		/* dummy read every 4 words for 6205 advisory 1.4.4 */
1666719f82d3SEliot Blennerhassett 		boot_loader_read_mem32(pao, 0, 0);
1667719f82d3SEliot Blennerhassett 
1668719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, 0, HPIDL_ADDR, data);
1669719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, 0, HPIDH_ADDR, data >> 16);
1670719f82d3SEliot Blennerhassett 
1671719f82d3SEliot Blennerhassett 		/* dummy read every 4 words for 6205 advisory 1.4.4 */
1672719f82d3SEliot Blennerhassett 		boot_loader_read_mem32(pao, 0, 0);
1673719f82d3SEliot Blennerhassett 	} else
1674719f82d3SEliot Blennerhassett 		err = hpi6205_error(dsp_index, HPI6205_ERROR_BAD_DSPINDEX);
1675719f82d3SEliot Blennerhassett 	return err;
1676719f82d3SEliot Blennerhassett }
1677719f82d3SEliot Blennerhassett 
1678719f82d3SEliot Blennerhassett static u16 boot_loader_config_emif(struct hpi_adapter_obj *pao, int dsp_index)
1679719f82d3SEliot Blennerhassett {
1680719f82d3SEliot Blennerhassett 	u16 err = 0;
1681719f82d3SEliot Blennerhassett 
1682719f82d3SEliot Blennerhassett 	if (dsp_index == 0) {
1683719f82d3SEliot Blennerhassett 		u32 setting;
1684719f82d3SEliot Blennerhassett 
1685719f82d3SEliot Blennerhassett 		/* DSP 0 is always C6205 */
1686719f82d3SEliot Blennerhassett 
1687719f82d3SEliot Blennerhassett 		/* Set the EMIF */
1688719f82d3SEliot Blennerhassett 		/* memory map of C6205 */
1689719f82d3SEliot Blennerhassett 		/* 00000000-0000FFFF    16Kx32 internal program */
1690719f82d3SEliot Blennerhassett 		/* 00400000-00BFFFFF    CE0     2Mx32 SDRAM running @ 100MHz */
1691719f82d3SEliot Blennerhassett 
1692719f82d3SEliot Blennerhassett 		/* EMIF config */
1693719f82d3SEliot Blennerhassett 		/*------------ */
1694719f82d3SEliot Blennerhassett 		/* Global EMIF control */
1695719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, dsp_index, 0x01800000, 0x3779);
1696719f82d3SEliot Blennerhassett #define WS_OFS 28
1697719f82d3SEliot Blennerhassett #define WST_OFS 22
1698719f82d3SEliot Blennerhassett #define WH_OFS 20
1699719f82d3SEliot Blennerhassett #define RS_OFS 16
1700719f82d3SEliot Blennerhassett #define RST_OFS 8
1701719f82d3SEliot Blennerhassett #define MTYPE_OFS 4
1702719f82d3SEliot Blennerhassett #define RH_OFS 0
1703719f82d3SEliot Blennerhassett 
1704719f82d3SEliot Blennerhassett 		/* EMIF CE0 setup - 2Mx32 Sync DRAM on ASI5000 cards only */
1705719f82d3SEliot Blennerhassett 		setting = 0x00000030;
1706719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, dsp_index, 0x01800008, setting);
1707719f82d3SEliot Blennerhassett 		if (setting != boot_loader_read_mem32(pao, dsp_index,
1708719f82d3SEliot Blennerhassett 				0x01800008))
1709719f82d3SEliot Blennerhassett 			return hpi6205_error(dsp_index,
1710719f82d3SEliot Blennerhassett 				HPI6205_ERROR_DSP_EMIF);
1711719f82d3SEliot Blennerhassett 
1712719f82d3SEliot Blennerhassett 		/* EMIF CE1 setup - 32 bit async. This is 6713 #1 HPI, */
1713719f82d3SEliot Blennerhassett 		/* which occupies D15..0. 6713 starts at 27MHz, so need */
1714719f82d3SEliot Blennerhassett 		/* plenty of wait states. See dsn8701.rtf, and 6713 errata. */
1715719f82d3SEliot Blennerhassett 		/* WST should be 71, but 63  is max possible */
1716719f82d3SEliot Blennerhassett 		setting =
1717719f82d3SEliot Blennerhassett 			(1L << WS_OFS) | (63L << WST_OFS) | (1L << WH_OFS) |
1718719f82d3SEliot Blennerhassett 			(1L << RS_OFS) | (63L << RST_OFS) | (1L << RH_OFS) |
1719719f82d3SEliot Blennerhassett 			(2L << MTYPE_OFS);
1720719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, dsp_index, 0x01800004, setting);
1721719f82d3SEliot Blennerhassett 		if (setting != boot_loader_read_mem32(pao, dsp_index,
1722719f82d3SEliot Blennerhassett 				0x01800004))
1723719f82d3SEliot Blennerhassett 			return hpi6205_error(dsp_index,
1724719f82d3SEliot Blennerhassett 				HPI6205_ERROR_DSP_EMIF);
1725719f82d3SEliot Blennerhassett 
1726719f82d3SEliot Blennerhassett 		/* EMIF CE2 setup - 32 bit async. This is 6713 #2 HPI, */
1727719f82d3SEliot Blennerhassett 		/* which occupies D15..0. 6713 starts at 27MHz, so need */
1728719f82d3SEliot Blennerhassett 		/* plenty of wait states */
1729719f82d3SEliot Blennerhassett 		setting =
1730719f82d3SEliot Blennerhassett 			(1L << WS_OFS) | (28L << WST_OFS) | (1L << WH_OFS) |
1731719f82d3SEliot Blennerhassett 			(1L << RS_OFS) | (63L << RST_OFS) | (1L << RH_OFS) |
1732719f82d3SEliot Blennerhassett 			(2L << MTYPE_OFS);
1733719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, dsp_index, 0x01800010, setting);
1734719f82d3SEliot Blennerhassett 		if (setting != boot_loader_read_mem32(pao, dsp_index,
1735719f82d3SEliot Blennerhassett 				0x01800010))
1736719f82d3SEliot Blennerhassett 			return hpi6205_error(dsp_index,
1737719f82d3SEliot Blennerhassett 				HPI6205_ERROR_DSP_EMIF);
1738719f82d3SEliot Blennerhassett 
1739719f82d3SEliot Blennerhassett 		/* EMIF CE3 setup - 32 bit async. */
1740719f82d3SEliot Blennerhassett 		/* This is the PLD on the ASI5000 cards only */
1741719f82d3SEliot Blennerhassett 		setting =
1742719f82d3SEliot Blennerhassett 			(1L << WS_OFS) | (10L << WST_OFS) | (1L << WH_OFS) |
1743719f82d3SEliot Blennerhassett 			(1L << RS_OFS) | (10L << RST_OFS) | (1L << RH_OFS) |
1744719f82d3SEliot Blennerhassett 			(2L << MTYPE_OFS);
1745719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, dsp_index, 0x01800014, setting);
1746719f82d3SEliot Blennerhassett 		if (setting != boot_loader_read_mem32(pao, dsp_index,
1747719f82d3SEliot Blennerhassett 				0x01800014))
1748719f82d3SEliot Blennerhassett 			return hpi6205_error(dsp_index,
1749719f82d3SEliot Blennerhassett 				HPI6205_ERROR_DSP_EMIF);
1750719f82d3SEliot Blennerhassett 
1751719f82d3SEliot Blennerhassett 		/* set EMIF SDRAM control for 2Mx32 SDRAM (512x32x4 bank) */
1752719f82d3SEliot Blennerhassett 		/*  need to use this else DSP code crashes? */
1753719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, dsp_index, 0x01800018,
1754719f82d3SEliot Blennerhassett 			0x07117000);
1755719f82d3SEliot Blennerhassett 
1756719f82d3SEliot Blennerhassett 		/* EMIF SDRAM Refresh Timing */
1757719f82d3SEliot Blennerhassett 		/* EMIF SDRAM timing  (orig = 0x410, emulator = 0x61a) */
1758719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, dsp_index, 0x0180001C,
1759719f82d3SEliot Blennerhassett 			0x00000410);
1760719f82d3SEliot Blennerhassett 
1761719f82d3SEliot Blennerhassett 	} else if (dsp_index == 1) {
1762719f82d3SEliot Blennerhassett 		/* test access to the C6713s HPI registers */
1763719f82d3SEliot Blennerhassett 		u32 write_data = 0, read_data = 0, i = 0;
1764719f82d3SEliot Blennerhassett 
1765719f82d3SEliot Blennerhassett 		/* Set up HPIC for little endian, by setiing HPIC:HWOB=1 */
1766719f82d3SEliot Blennerhassett 		write_data = 1;
1767719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, 0, HPICL_ADDR, write_data);
1768719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, 0, HPICH_ADDR, write_data);
1769719f82d3SEliot Blennerhassett 		/* C67 HPI is on lower 16bits of 32bit EMIF */
1770719f82d3SEliot Blennerhassett 		read_data =
1771719f82d3SEliot Blennerhassett 			0xFFF7 & boot_loader_read_mem32(pao, 0, HPICL_ADDR);
1772719f82d3SEliot Blennerhassett 		if (write_data != read_data) {
1773719f82d3SEliot Blennerhassett 			err = hpi6205_error(dsp_index,
1774719f82d3SEliot Blennerhassett 				HPI6205_ERROR_C6713_HPIC);
1775719f82d3SEliot Blennerhassett 			HPI_DEBUG_LOG(ERROR, "HPICL %x %x\n", write_data,
1776719f82d3SEliot Blennerhassett 				read_data);
1777719f82d3SEliot Blennerhassett 
1778719f82d3SEliot Blennerhassett 			return err;
1779719f82d3SEliot Blennerhassett 		}
1780719f82d3SEliot Blennerhassett 		/* HPIA - walking ones test */
1781719f82d3SEliot Blennerhassett 		write_data = 1;
1782719f82d3SEliot Blennerhassett 		for (i = 0; i < 32; i++) {
1783719f82d3SEliot Blennerhassett 			boot_loader_write_mem32(pao, 0, HPIAL_ADDR,
1784719f82d3SEliot Blennerhassett 				write_data);
1785719f82d3SEliot Blennerhassett 			boot_loader_write_mem32(pao, 0, HPIAH_ADDR,
1786719f82d3SEliot Blennerhassett 				(write_data >> 16));
1787719f82d3SEliot Blennerhassett 			read_data =
1788719f82d3SEliot Blennerhassett 				0xFFFF & boot_loader_read_mem32(pao, 0,
1789719f82d3SEliot Blennerhassett 				HPIAL_ADDR);
1790719f82d3SEliot Blennerhassett 			read_data =
1791719f82d3SEliot Blennerhassett 				read_data | ((0xFFFF &
1792719f82d3SEliot Blennerhassett 					boot_loader_read_mem32(pao, 0,
1793719f82d3SEliot Blennerhassett 						HPIAH_ADDR))
1794719f82d3SEliot Blennerhassett 				<< 16);
1795719f82d3SEliot Blennerhassett 			if (read_data != write_data) {
1796719f82d3SEliot Blennerhassett 				err = hpi6205_error(dsp_index,
1797719f82d3SEliot Blennerhassett 					HPI6205_ERROR_C6713_HPIA);
1798719f82d3SEliot Blennerhassett 				HPI_DEBUG_LOG(ERROR, "HPIA %x %x\n",
1799719f82d3SEliot Blennerhassett 					write_data, read_data);
1800719f82d3SEliot Blennerhassett 				return err;
1801719f82d3SEliot Blennerhassett 			}
1802719f82d3SEliot Blennerhassett 			write_data = write_data << 1;
1803719f82d3SEliot Blennerhassett 		}
1804719f82d3SEliot Blennerhassett 
1805719f82d3SEliot Blennerhassett 		/* setup C67x PLL
1806719f82d3SEliot Blennerhassett 		 *  ** C6713 datasheet says we cannot program PLL from HPI,
1807719f82d3SEliot Blennerhassett 		 * and indeed if we try to set the PLL multiply from the HPI,
1808719f82d3SEliot Blennerhassett 		 * the PLL does not seem to lock, so we enable the PLL and
1809719f82d3SEliot Blennerhassett 		 * use the default multiply of x 7, which for a 27MHz clock
1810719f82d3SEliot Blennerhassett 		 * gives a DSP speed of 189MHz
1811719f82d3SEliot Blennerhassett 		 */
1812719f82d3SEliot Blennerhassett 		/* bypass PLL */
1813719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, dsp_index, 0x01B7C100, 0x0000);
1814719f82d3SEliot Blennerhassett 		hpios_delay_micro_seconds(1000);
1815719f82d3SEliot Blennerhassett 		/* EMIF = 189/3=63MHz */
1816719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, dsp_index, 0x01B7C120, 0x8002);
1817719f82d3SEliot Blennerhassett 		/* peri = 189/2 */
1818719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, dsp_index, 0x01B7C11C, 0x8001);
1819719f82d3SEliot Blennerhassett 		/* cpu  = 189/1 */
1820719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, dsp_index, 0x01B7C118, 0x8000);
1821719f82d3SEliot Blennerhassett 		hpios_delay_micro_seconds(1000);
1822719f82d3SEliot Blennerhassett 		/* ** SGT test to take GPO3 high when we start the PLL */
1823719f82d3SEliot Blennerhassett 		/* and low when the delay is completed */
1824719f82d3SEliot Blennerhassett 		/* FSX0 <- '1' (GPO3) */
1825719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, 0, (0x018C0024L), 0x00002A0A);
1826719f82d3SEliot Blennerhassett 		/* PLL not bypassed */
1827719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, dsp_index, 0x01B7C100, 0x0001);
1828719f82d3SEliot Blennerhassett 		hpios_delay_micro_seconds(1000);
1829719f82d3SEliot Blennerhassett 		/* FSX0 <- '0' (GPO3) */
1830719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, 0, (0x018C0024L), 0x00002A02);
1831719f82d3SEliot Blennerhassett 
1832719f82d3SEliot Blennerhassett 		/* 6205 EMIF CE1 resetup - 32 bit async. */
1833719f82d3SEliot Blennerhassett 		/* Now 6713 #1 is running at 189MHz can reduce waitstates */
1834719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, 0, 0x01800004,	/* CE1 */
1835719f82d3SEliot Blennerhassett 			(1L << WS_OFS) | (8L << WST_OFS) | (1L << WH_OFS) |
1836719f82d3SEliot Blennerhassett 			(1L << RS_OFS) | (12L << RST_OFS) | (1L << RH_OFS) |
1837719f82d3SEliot Blennerhassett 			(2L << MTYPE_OFS));
1838719f82d3SEliot Blennerhassett 
1839719f82d3SEliot Blennerhassett 		hpios_delay_micro_seconds(1000);
1840719f82d3SEliot Blennerhassett 
1841719f82d3SEliot Blennerhassett 		/* check that we can read one of the PLL registers */
1842719f82d3SEliot Blennerhassett 		/* PLL should not be bypassed! */
1843719f82d3SEliot Blennerhassett 		if ((boot_loader_read_mem32(pao, dsp_index, 0x01B7C100) & 0xF)
1844719f82d3SEliot Blennerhassett 			!= 0x0001) {
1845719f82d3SEliot Blennerhassett 			err = hpi6205_error(dsp_index,
1846719f82d3SEliot Blennerhassett 				HPI6205_ERROR_C6713_PLL);
1847719f82d3SEliot Blennerhassett 			return err;
1848719f82d3SEliot Blennerhassett 		}
1849719f82d3SEliot Blennerhassett 		/* setup C67x EMIF  (note this is the only use of
1850719f82d3SEliot Blennerhassett 		   BAR1 via BootLoader_WriteMem32) */
1851719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, dsp_index, C6713_EMIF_GCTL,
1852719f82d3SEliot Blennerhassett 			0x000034A8);
1853719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, dsp_index, C6713_EMIF_CE0,
1854719f82d3SEliot Blennerhassett 			0x00000030);
1855719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, dsp_index, C6713_EMIF_SDRAMEXT,
1856719f82d3SEliot Blennerhassett 			0x001BDF29);
1857719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, dsp_index, C6713_EMIF_SDRAMCTL,
1858719f82d3SEliot Blennerhassett 			0x47117000);
1859719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, dsp_index,
1860719f82d3SEliot Blennerhassett 			C6713_EMIF_SDRAMTIMING, 0x00000410);
1861719f82d3SEliot Blennerhassett 
1862719f82d3SEliot Blennerhassett 		hpios_delay_micro_seconds(1000);
1863719f82d3SEliot Blennerhassett 	} else if (dsp_index == 2) {
1864719f82d3SEliot Blennerhassett 		/* DSP 2 is a C6713 */
1865719f82d3SEliot Blennerhassett 
1866719f82d3SEliot Blennerhassett 	} else
1867719f82d3SEliot Blennerhassett 		err = hpi6205_error(dsp_index, HPI6205_ERROR_BAD_DSPINDEX);
1868719f82d3SEliot Blennerhassett 	return err;
1869719f82d3SEliot Blennerhassett }
1870719f82d3SEliot Blennerhassett 
1871719f82d3SEliot Blennerhassett static u16 boot_loader_test_memory(struct hpi_adapter_obj *pao, int dsp_index,
1872719f82d3SEliot Blennerhassett 	u32 start_address, u32 length)
1873719f82d3SEliot Blennerhassett {
1874719f82d3SEliot Blennerhassett 	u32 i = 0, j = 0;
1875719f82d3SEliot Blennerhassett 	u32 test_addr = 0;
1876719f82d3SEliot Blennerhassett 	u32 test_data = 0, data = 0;
1877719f82d3SEliot Blennerhassett 
1878719f82d3SEliot Blennerhassett 	length = 1000;
1879719f82d3SEliot Blennerhassett 
1880719f82d3SEliot Blennerhassett 	/* for 1st word, test each bit in the 32bit word, */
1881719f82d3SEliot Blennerhassett 	/* dwLength specifies number of 32bit words to test */
1882719f82d3SEliot Blennerhassett 	/*for(i=0; i<dwLength; i++) */
1883719f82d3SEliot Blennerhassett 	i = 0;
1884719f82d3SEliot Blennerhassett 	{
1885719f82d3SEliot Blennerhassett 		test_addr = start_address + i * 4;
1886719f82d3SEliot Blennerhassett 		test_data = 0x00000001;
1887719f82d3SEliot Blennerhassett 		for (j = 0; j < 32; j++) {
1888719f82d3SEliot Blennerhassett 			boot_loader_write_mem32(pao, dsp_index, test_addr,
1889719f82d3SEliot Blennerhassett 				test_data);
1890719f82d3SEliot Blennerhassett 			data = boot_loader_read_mem32(pao, dsp_index,
1891719f82d3SEliot Blennerhassett 				test_addr);
1892719f82d3SEliot Blennerhassett 			if (data != test_data) {
1893719f82d3SEliot Blennerhassett 				HPI_DEBUG_LOG(VERBOSE,
1894719f82d3SEliot Blennerhassett 					"memtest error details  "
1895719f82d3SEliot Blennerhassett 					"%08x %08x %08x %i\n", test_addr,
1896719f82d3SEliot Blennerhassett 					test_data, data, dsp_index);
1897719f82d3SEliot Blennerhassett 				return 1;	/* error */
1898719f82d3SEliot Blennerhassett 			}
1899719f82d3SEliot Blennerhassett 			test_data = test_data << 1;
1900719f82d3SEliot Blennerhassett 		}	/* for(j) */
1901719f82d3SEliot Blennerhassett 	}	/* for(i) */
1902719f82d3SEliot Blennerhassett 
1903719f82d3SEliot Blennerhassett 	/* for the next 100 locations test each location, leaving it as zero */
1904719f82d3SEliot Blennerhassett 	/* write a zero to the next word in memory before we read */
1905719f82d3SEliot Blennerhassett 	/* the previous write to make sure every memory location is unique */
1906719f82d3SEliot Blennerhassett 	for (i = 0; i < 100; i++) {
1907719f82d3SEliot Blennerhassett 		test_addr = start_address + i * 4;
1908719f82d3SEliot Blennerhassett 		test_data = 0xA5A55A5A;
1909719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, dsp_index, test_addr, test_data);
1910719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, dsp_index, test_addr + 4, 0);
1911719f82d3SEliot Blennerhassett 		data = boot_loader_read_mem32(pao, dsp_index, test_addr);
1912719f82d3SEliot Blennerhassett 		if (data != test_data) {
1913719f82d3SEliot Blennerhassett 			HPI_DEBUG_LOG(VERBOSE,
1914719f82d3SEliot Blennerhassett 				"memtest error details  "
1915719f82d3SEliot Blennerhassett 				"%08x %08x %08x %i\n", test_addr, test_data,
1916719f82d3SEliot Blennerhassett 				data, dsp_index);
1917719f82d3SEliot Blennerhassett 			return 1;	/* error */
1918719f82d3SEliot Blennerhassett 		}
1919719f82d3SEliot Blennerhassett 		/* leave location as zero */
1920719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, dsp_index, test_addr, 0x0);
1921719f82d3SEliot Blennerhassett 	}
1922719f82d3SEliot Blennerhassett 
1923719f82d3SEliot Blennerhassett 	/* zero out entire memory block */
1924719f82d3SEliot Blennerhassett 	for (i = 0; i < length; i++) {
1925719f82d3SEliot Blennerhassett 		test_addr = start_address + i * 4;
1926719f82d3SEliot Blennerhassett 		boot_loader_write_mem32(pao, dsp_index, test_addr, 0x0);
1927719f82d3SEliot Blennerhassett 	}
1928719f82d3SEliot Blennerhassett 	return 0;
1929719f82d3SEliot Blennerhassett }
1930719f82d3SEliot Blennerhassett 
1931719f82d3SEliot Blennerhassett static u16 boot_loader_test_internal_memory(struct hpi_adapter_obj *pao,
1932719f82d3SEliot Blennerhassett 	int dsp_index)
1933719f82d3SEliot Blennerhassett {
1934719f82d3SEliot Blennerhassett 	int err = 0;
1935719f82d3SEliot Blennerhassett 	if (dsp_index == 0) {
1936719f82d3SEliot Blennerhassett 		/* DSP 0 is a C6205 */
1937719f82d3SEliot Blennerhassett 		/* 64K prog mem */
1938719f82d3SEliot Blennerhassett 		err = boot_loader_test_memory(pao, dsp_index, 0x00000000,
1939719f82d3SEliot Blennerhassett 			0x10000);
1940719f82d3SEliot Blennerhassett 		if (!err)
1941719f82d3SEliot Blennerhassett 			/* 64K data mem */
1942719f82d3SEliot Blennerhassett 			err = boot_loader_test_memory(pao, dsp_index,
1943719f82d3SEliot Blennerhassett 				0x80000000, 0x10000);
1944719f82d3SEliot Blennerhassett 	} else if ((dsp_index == 1) || (dsp_index == 2)) {
1945719f82d3SEliot Blennerhassett 		/* DSP 1&2 are a C6713 */
1946719f82d3SEliot Blennerhassett 		/* 192K internal mem */
1947719f82d3SEliot Blennerhassett 		err = boot_loader_test_memory(pao, dsp_index, 0x00000000,
1948719f82d3SEliot Blennerhassett 			0x30000);
1949719f82d3SEliot Blennerhassett 		if (!err)
1950719f82d3SEliot Blennerhassett 			/* 64K internal mem / L2 cache */
1951719f82d3SEliot Blennerhassett 			err = boot_loader_test_memory(pao, dsp_index,
1952719f82d3SEliot Blennerhassett 				0x00030000, 0x10000);
1953719f82d3SEliot Blennerhassett 	} else
1954719f82d3SEliot Blennerhassett 		return hpi6205_error(dsp_index, HPI6205_ERROR_BAD_DSPINDEX);
1955719f82d3SEliot Blennerhassett 
1956719f82d3SEliot Blennerhassett 	if (err)
1957719f82d3SEliot Blennerhassett 		return hpi6205_error(dsp_index, HPI6205_ERROR_DSP_INTMEM);
1958719f82d3SEliot Blennerhassett 	else
1959719f82d3SEliot Blennerhassett 		return 0;
1960719f82d3SEliot Blennerhassett }
1961719f82d3SEliot Blennerhassett 
1962719f82d3SEliot Blennerhassett static u16 boot_loader_test_external_memory(struct hpi_adapter_obj *pao,
1963719f82d3SEliot Blennerhassett 	int dsp_index)
1964719f82d3SEliot Blennerhassett {
1965719f82d3SEliot Blennerhassett 	u32 dRAM_start_address = 0;
1966719f82d3SEliot Blennerhassett 	u32 dRAM_size = 0;
1967719f82d3SEliot Blennerhassett 
1968719f82d3SEliot Blennerhassett 	if (dsp_index == 0) {
1969719f82d3SEliot Blennerhassett 		/* only test for SDRAM if an ASI5000 card */
1970719f82d3SEliot Blennerhassett 		if (pao->pci.subsys_device_id == 0x5000) {
1971719f82d3SEliot Blennerhassett 			/* DSP 0 is always C6205 */
1972719f82d3SEliot Blennerhassett 			dRAM_start_address = 0x00400000;
1973719f82d3SEliot Blennerhassett 			dRAM_size = 0x200000;
1974719f82d3SEliot Blennerhassett 			/*dwDRAMinc=1024; */
1975719f82d3SEliot Blennerhassett 		} else
1976719f82d3SEliot Blennerhassett 			return 0;
1977719f82d3SEliot Blennerhassett 	} else if ((dsp_index == 1) || (dsp_index == 2)) {
1978719f82d3SEliot Blennerhassett 		/* DSP 1 is a C6713 */
1979719f82d3SEliot Blennerhassett 		dRAM_start_address = 0x80000000;
1980719f82d3SEliot Blennerhassett 		dRAM_size = 0x200000;
1981719f82d3SEliot Blennerhassett 		/*dwDRAMinc=1024; */
1982719f82d3SEliot Blennerhassett 	} else
1983719f82d3SEliot Blennerhassett 		return hpi6205_error(dsp_index, HPI6205_ERROR_BAD_DSPINDEX);
1984719f82d3SEliot Blennerhassett 
1985719f82d3SEliot Blennerhassett 	if (boot_loader_test_memory(pao, dsp_index, dRAM_start_address,
1986719f82d3SEliot Blennerhassett 			dRAM_size))
1987719f82d3SEliot Blennerhassett 		return hpi6205_error(dsp_index, HPI6205_ERROR_DSP_EXTMEM);
1988719f82d3SEliot Blennerhassett 	return 0;
1989719f82d3SEliot Blennerhassett }
1990719f82d3SEliot Blennerhassett 
1991719f82d3SEliot Blennerhassett static u16 boot_loader_test_pld(struct hpi_adapter_obj *pao, int dsp_index)
1992719f82d3SEliot Blennerhassett {
1993719f82d3SEliot Blennerhassett 	u32 data = 0;
1994719f82d3SEliot Blennerhassett 	if (dsp_index == 0) {
1995719f82d3SEliot Blennerhassett 		/* only test for DSP0 PLD on ASI5000 card */
1996719f82d3SEliot Blennerhassett 		if (pao->pci.subsys_device_id == 0x5000) {
1997719f82d3SEliot Blennerhassett 			/* PLD is located at CE3=0x03000000 */
1998719f82d3SEliot Blennerhassett 			data = boot_loader_read_mem32(pao, dsp_index,
1999719f82d3SEliot Blennerhassett 				0x03000008);
2000719f82d3SEliot Blennerhassett 			if ((data & 0xF) != 0x5)
2001719f82d3SEliot Blennerhassett 				return hpi6205_error(dsp_index,
2002719f82d3SEliot Blennerhassett 					HPI6205_ERROR_DSP_PLD);
2003719f82d3SEliot Blennerhassett 			data = boot_loader_read_mem32(pao, dsp_index,
2004719f82d3SEliot Blennerhassett 				0x0300000C);
2005719f82d3SEliot Blennerhassett 			if ((data & 0xF) != 0xA)
2006719f82d3SEliot Blennerhassett 				return hpi6205_error(dsp_index,
2007719f82d3SEliot Blennerhassett 					HPI6205_ERROR_DSP_PLD);
2008719f82d3SEliot Blennerhassett 		}
2009719f82d3SEliot Blennerhassett 	} else if (dsp_index == 1) {
2010719f82d3SEliot Blennerhassett 		/* DSP 1 is a C6713 */
2011719f82d3SEliot Blennerhassett 		if (pao->pci.subsys_device_id == 0x8700) {
2012719f82d3SEliot Blennerhassett 			/* PLD is located at CE1=0x90000000 */
2013719f82d3SEliot Blennerhassett 			data = boot_loader_read_mem32(pao, dsp_index,
2014719f82d3SEliot Blennerhassett 				0x90000010);
2015719f82d3SEliot Blennerhassett 			if ((data & 0xFF) != 0xAA)
2016719f82d3SEliot Blennerhassett 				return hpi6205_error(dsp_index,
2017719f82d3SEliot Blennerhassett 					HPI6205_ERROR_DSP_PLD);
2018719f82d3SEliot Blennerhassett 			/* 8713 - LED on */
2019719f82d3SEliot Blennerhassett 			boot_loader_write_mem32(pao, dsp_index, 0x90000000,
2020719f82d3SEliot Blennerhassett 				0x02);
2021719f82d3SEliot Blennerhassett 		}
2022719f82d3SEliot Blennerhassett 	}
2023719f82d3SEliot Blennerhassett 	return 0;
2024719f82d3SEliot Blennerhassett }
2025719f82d3SEliot Blennerhassett 
2026719f82d3SEliot Blennerhassett /** Transfer data to or from DSP
2027719f82d3SEliot Blennerhassett  nOperation = H620_H620_HIF_SEND_DATA or H620_HIF_GET_DATA
2028719f82d3SEliot Blennerhassett */
2029719f82d3SEliot Blennerhassett static short hpi6205_transfer_data(struct hpi_adapter_obj *pao, u8 *p_data,
2030719f82d3SEliot Blennerhassett 	u32 data_size, int operation)
2031719f82d3SEliot Blennerhassett {
2032719f82d3SEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
2033719f82d3SEliot Blennerhassett 	u32 data_transferred = 0;
2034719f82d3SEliot Blennerhassett 	u16 err = 0;
2035719f82d3SEliot Blennerhassett #ifndef HPI6205_NO_HSR_POLL
2036719f82d3SEliot Blennerhassett 	u32 time_out;
2037719f82d3SEliot Blennerhassett #endif
2038719f82d3SEliot Blennerhassett 	u32 temp2;
2039719f82d3SEliot Blennerhassett 	struct bus_master_interface *interface = phw->p_interface_buffer;
2040719f82d3SEliot Blennerhassett 
2041719f82d3SEliot Blennerhassett 	if (!p_data)
2042719f82d3SEliot Blennerhassett 		return HPI_ERROR_INVALID_DATA_TRANSFER;
2043719f82d3SEliot Blennerhassett 
2044719f82d3SEliot Blennerhassett 	data_size &= ~3L;	/* round data_size down to nearest 4 bytes */
2045719f82d3SEliot Blennerhassett 
2046719f82d3SEliot Blennerhassett 	/* make sure state is IDLE */
2047719f82d3SEliot Blennerhassett 	if (!wait_dsp_ack(phw, H620_HIF_IDLE, HPI6205_TIMEOUT))
2048719f82d3SEliot Blennerhassett 		return HPI_ERROR_DSP_HARDWARE;
2049719f82d3SEliot Blennerhassett 
2050719f82d3SEliot Blennerhassett 	while (data_transferred < data_size) {
2051719f82d3SEliot Blennerhassett 		u32 this_copy = data_size - data_transferred;
2052719f82d3SEliot Blennerhassett 
2053719f82d3SEliot Blennerhassett 		if (this_copy > HPI6205_SIZEOF_DATA)
2054719f82d3SEliot Blennerhassett 			this_copy = HPI6205_SIZEOF_DATA;
2055719f82d3SEliot Blennerhassett 
2056719f82d3SEliot Blennerhassett 		if (operation == H620_HIF_SEND_DATA)
2057719f82d3SEliot Blennerhassett 			memcpy((void *)&interface->u.b_data[0],
2058719f82d3SEliot Blennerhassett 				&p_data[data_transferred], this_copy);
2059719f82d3SEliot Blennerhassett 
2060719f82d3SEliot Blennerhassett 		interface->transfer_size_in_bytes = this_copy;
2061719f82d3SEliot Blennerhassett 
2062719f82d3SEliot Blennerhassett #ifdef HPI6205_NO_HSR_POLL
2063719f82d3SEliot Blennerhassett 		/* DSP must change this back to nOperation */
2064719f82d3SEliot Blennerhassett 		interface->dsp_ack = H620_HIF_IDLE;
2065719f82d3SEliot Blennerhassett #endif
2066719f82d3SEliot Blennerhassett 
2067719f82d3SEliot Blennerhassett 		send_dsp_command(phw, operation);
2068719f82d3SEliot Blennerhassett 
2069719f82d3SEliot Blennerhassett #ifdef HPI6205_NO_HSR_POLL
2070719f82d3SEliot Blennerhassett 		temp2 = wait_dsp_ack(phw, operation, HPI6205_TIMEOUT);
2071719f82d3SEliot Blennerhassett 		HPI_DEBUG_LOG(DEBUG, "spun %d times for data xfer of %d\n",
2072719f82d3SEliot Blennerhassett 			HPI6205_TIMEOUT - temp2, this_copy);
2073719f82d3SEliot Blennerhassett 
2074719f82d3SEliot Blennerhassett 		if (!temp2) {
2075719f82d3SEliot Blennerhassett 			/* timed out */
2076719f82d3SEliot Blennerhassett 			HPI_DEBUG_LOG(ERROR,
2077719f82d3SEliot Blennerhassett 				"timed out waiting for " "state %d got %d\n",
2078719f82d3SEliot Blennerhassett 				operation, interface->dsp_ack);
2079719f82d3SEliot Blennerhassett 
2080719f82d3SEliot Blennerhassett 			break;
2081719f82d3SEliot Blennerhassett 		}
2082719f82d3SEliot Blennerhassett #else
2083719f82d3SEliot Blennerhassett 		/* spin waiting on the result */
2084719f82d3SEliot Blennerhassett 		time_out = HPI6205_TIMEOUT;
2085719f82d3SEliot Blennerhassett 		temp2 = 0;
2086719f82d3SEliot Blennerhassett 		while ((temp2 == 0) && time_out--) {
2087719f82d3SEliot Blennerhassett 			/* give 16k bus mastering transfer time to happen */
2088719f82d3SEliot Blennerhassett 			/*(16k / 132Mbytes/s = 122usec) */
2089719f82d3SEliot Blennerhassett 			hpios_delay_micro_seconds(20);
2090719f82d3SEliot Blennerhassett 			temp2 = ioread32(phw->prHSR);
2091719f82d3SEliot Blennerhassett 			temp2 &= C6205_HSR_INTSRC;
2092719f82d3SEliot Blennerhassett 		}
2093719f82d3SEliot Blennerhassett 		HPI_DEBUG_LOG(DEBUG, "spun %d times for data xfer of %d\n",
2094719f82d3SEliot Blennerhassett 			HPI6205_TIMEOUT - time_out, this_copy);
2095719f82d3SEliot Blennerhassett 		if (temp2 == C6205_HSR_INTSRC) {
2096719f82d3SEliot Blennerhassett 			HPI_DEBUG_LOG(VERBOSE,
2097719f82d3SEliot Blennerhassett 				"interrupt from HIF <data> OK\n");
2098719f82d3SEliot Blennerhassett 			/*
2099719f82d3SEliot Blennerhassett 			   if(interface->dwDspAck != nOperation) {
2100719f82d3SEliot Blennerhassett 			   HPI_DEBUG_LOG(DEBUG("interface->dwDspAck=%d,
2101719f82d3SEliot Blennerhassett 			   expected %d \n",
2102719f82d3SEliot Blennerhassett 			   interface->dwDspAck,nOperation);
2103719f82d3SEliot Blennerhassett 			   }
2104719f82d3SEliot Blennerhassett 			 */
2105719f82d3SEliot Blennerhassett 		}
2106719f82d3SEliot Blennerhassett /* need to handle this differently... */
2107719f82d3SEliot Blennerhassett 		else {
2108719f82d3SEliot Blennerhassett 			HPI_DEBUG_LOG(ERROR,
2109719f82d3SEliot Blennerhassett 				"interrupt from HIF <data> BAD\n");
2110719f82d3SEliot Blennerhassett 			err = HPI_ERROR_DSP_HARDWARE;
2111719f82d3SEliot Blennerhassett 		}
2112719f82d3SEliot Blennerhassett 
2113719f82d3SEliot Blennerhassett 		/* reset the interrupt from the DSP */
2114719f82d3SEliot Blennerhassett 		iowrite32(C6205_HSR_INTSRC, phw->prHSR);
2115719f82d3SEliot Blennerhassett #endif
2116719f82d3SEliot Blennerhassett 		if (operation == H620_HIF_GET_DATA)
2117719f82d3SEliot Blennerhassett 			memcpy(&p_data[data_transferred],
2118719f82d3SEliot Blennerhassett 				(void *)&interface->u.b_data[0], this_copy);
2119719f82d3SEliot Blennerhassett 
2120719f82d3SEliot Blennerhassett 		data_transferred += this_copy;
2121719f82d3SEliot Blennerhassett 	}
2122719f82d3SEliot Blennerhassett 	if (interface->dsp_ack != operation)
2123719f82d3SEliot Blennerhassett 		HPI_DEBUG_LOG(DEBUG, "interface->dsp_ack=%d, expected %d\n",
2124719f82d3SEliot Blennerhassett 			interface->dsp_ack, operation);
2125719f82d3SEliot Blennerhassett 	/*                      err=HPI_ERROR_DSP_HARDWARE; */
2126719f82d3SEliot Blennerhassett 
2127719f82d3SEliot Blennerhassett 	send_dsp_command(phw, H620_HIF_IDLE);
2128719f82d3SEliot Blennerhassett 
2129719f82d3SEliot Blennerhassett 	return err;
2130719f82d3SEliot Blennerhassett }
2131719f82d3SEliot Blennerhassett 
2132719f82d3SEliot Blennerhassett /* wait for up to timeout_us microseconds for the DSP
2133719f82d3SEliot Blennerhassett    to signal state by DMA into dwDspAck
2134719f82d3SEliot Blennerhassett */
2135719f82d3SEliot Blennerhassett static int wait_dsp_ack(struct hpi_hw_obj *phw, int state, int timeout_us)
2136719f82d3SEliot Blennerhassett {
2137719f82d3SEliot Blennerhassett 	struct bus_master_interface *interface = phw->p_interface_buffer;
2138719f82d3SEliot Blennerhassett 	int t = timeout_us / 4;
2139719f82d3SEliot Blennerhassett 
2140719f82d3SEliot Blennerhassett 	rmb();	/* ensure interface->dsp_ack is up to date */
2141719f82d3SEliot Blennerhassett 	while ((interface->dsp_ack != state) && --t) {
2142719f82d3SEliot Blennerhassett 		hpios_delay_micro_seconds(4);
2143719f82d3SEliot Blennerhassett 		rmb();	/* DSP changes dsp_ack by DMA */
2144719f82d3SEliot Blennerhassett 	}
2145719f82d3SEliot Blennerhassett 
2146719f82d3SEliot Blennerhassett 	/*HPI_DEBUG_LOG(VERBOSE, "Spun %d for %d\n", timeout_us/4-t, state); */
2147719f82d3SEliot Blennerhassett 	return t * 4;
2148719f82d3SEliot Blennerhassett }
2149719f82d3SEliot Blennerhassett 
2150719f82d3SEliot Blennerhassett /* set the busmaster interface to cmd, then interrupt the DSP */
2151719f82d3SEliot Blennerhassett static void send_dsp_command(struct hpi_hw_obj *phw, int cmd)
2152719f82d3SEliot Blennerhassett {
2153719f82d3SEliot Blennerhassett 	struct bus_master_interface *interface = phw->p_interface_buffer;
2154719f82d3SEliot Blennerhassett 
2155719f82d3SEliot Blennerhassett 	u32 r;
2156719f82d3SEliot Blennerhassett 
2157719f82d3SEliot Blennerhassett 	interface->host_cmd = cmd;
2158719f82d3SEliot Blennerhassett 	wmb();	/* DSP gets state by DMA, make sure it is written to memory */
2159719f82d3SEliot Blennerhassett 	/* before we interrupt the DSP */
2160719f82d3SEliot Blennerhassett 	r = ioread32(phw->prHDCR);
2161719f82d3SEliot Blennerhassett 	r |= (u32)C6205_HDCR_DSPINT;
2162719f82d3SEliot Blennerhassett 	iowrite32(r, phw->prHDCR);
2163719f82d3SEliot Blennerhassett 	r &= ~(u32)C6205_HDCR_DSPINT;
2164719f82d3SEliot Blennerhassett 	iowrite32(r, phw->prHDCR);
2165719f82d3SEliot Blennerhassett }
2166719f82d3SEliot Blennerhassett 
2167719f82d3SEliot Blennerhassett static unsigned int message_count;
2168719f82d3SEliot Blennerhassett 
2169719f82d3SEliot Blennerhassett static u16 message_response_sequence(struct hpi_adapter_obj *pao,
2170719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
2171719f82d3SEliot Blennerhassett {
2172719f82d3SEliot Blennerhassett #ifndef HPI6205_NO_HSR_POLL
2173719f82d3SEliot Blennerhassett 	u32 temp2;
2174719f82d3SEliot Blennerhassett #endif
2175719f82d3SEliot Blennerhassett 	u32 time_out, time_out2;
2176719f82d3SEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
2177719f82d3SEliot Blennerhassett 	struct bus_master_interface *interface = phw->p_interface_buffer;
2178719f82d3SEliot Blennerhassett 	u16 err = 0;
2179719f82d3SEliot Blennerhassett 
2180719f82d3SEliot Blennerhassett 	message_count++;
2181719f82d3SEliot Blennerhassett 	/* Assume buffer of type struct bus_master_interface
2182719f82d3SEliot Blennerhassett 	   is allocated "noncacheable" */
2183719f82d3SEliot Blennerhassett 
2184719f82d3SEliot Blennerhassett 	if (!wait_dsp_ack(phw, H620_HIF_IDLE, HPI6205_TIMEOUT)) {
2185719f82d3SEliot Blennerhassett 		HPI_DEBUG_LOG(DEBUG, "timeout waiting for idle\n");
2186719f82d3SEliot Blennerhassett 		return hpi6205_error(0, HPI6205_ERROR_MSG_RESP_IDLE_TIMEOUT);
2187719f82d3SEliot Blennerhassett 	}
2188719f82d3SEliot Blennerhassett 	interface->u.message_buffer = *phm;
2189719f82d3SEliot Blennerhassett 	/* signal we want a response */
2190719f82d3SEliot Blennerhassett 	send_dsp_command(phw, H620_HIF_GET_RESP);
2191719f82d3SEliot Blennerhassett 
2192719f82d3SEliot Blennerhassett 	time_out2 = wait_dsp_ack(phw, H620_HIF_GET_RESP, HPI6205_TIMEOUT);
2193719f82d3SEliot Blennerhassett 
2194719f82d3SEliot Blennerhassett 	if (time_out2 == 0) {
2195719f82d3SEliot Blennerhassett 		HPI_DEBUG_LOG(ERROR,
2196719f82d3SEliot Blennerhassett 			"(%u) timed out waiting for " "GET_RESP state [%x]\n",
2197719f82d3SEliot Blennerhassett 			message_count, interface->dsp_ack);
2198719f82d3SEliot Blennerhassett 	} else {
2199719f82d3SEliot Blennerhassett 		HPI_DEBUG_LOG(VERBOSE,
2200719f82d3SEliot Blennerhassett 			"(%u) transition to GET_RESP after %u\n",
2201719f82d3SEliot Blennerhassett 			message_count, HPI6205_TIMEOUT - time_out2);
2202719f82d3SEliot Blennerhassett 	}
2203719f82d3SEliot Blennerhassett 	/* spin waiting on HIF interrupt flag (end of msg process) */
2204719f82d3SEliot Blennerhassett 	time_out = HPI6205_TIMEOUT;
2205719f82d3SEliot Blennerhassett 
2206719f82d3SEliot Blennerhassett #ifndef HPI6205_NO_HSR_POLL
2207719f82d3SEliot Blennerhassett 	temp2 = 0;
2208719f82d3SEliot Blennerhassett 	while ((temp2 == 0) && --time_out) {
2209719f82d3SEliot Blennerhassett 		temp2 = ioread32(phw->prHSR);
2210719f82d3SEliot Blennerhassett 		temp2 &= C6205_HSR_INTSRC;
2211719f82d3SEliot Blennerhassett 		hpios_delay_micro_seconds(1);
2212719f82d3SEliot Blennerhassett 	}
2213719f82d3SEliot Blennerhassett 	if (temp2 == C6205_HSR_INTSRC) {
2214719f82d3SEliot Blennerhassett 		rmb();	/* ensure we see latest value for dsp_ack */
2215719f82d3SEliot Blennerhassett 		if ((interface->dsp_ack != H620_HIF_GET_RESP)) {
2216719f82d3SEliot Blennerhassett 			HPI_DEBUG_LOG(DEBUG,
2217719f82d3SEliot Blennerhassett 				"(%u)interface->dsp_ack(0x%x) != "
2218719f82d3SEliot Blennerhassett 				"H620_HIF_GET_RESP, t=%u\n", message_count,
2219719f82d3SEliot Blennerhassett 				interface->dsp_ack,
2220719f82d3SEliot Blennerhassett 				HPI6205_TIMEOUT - time_out);
2221719f82d3SEliot Blennerhassett 		} else {
2222719f82d3SEliot Blennerhassett 			HPI_DEBUG_LOG(VERBOSE,
2223719f82d3SEliot Blennerhassett 				"(%u)int with GET_RESP after %u\n",
2224719f82d3SEliot Blennerhassett 				message_count, HPI6205_TIMEOUT - time_out);
2225719f82d3SEliot Blennerhassett 		}
2226719f82d3SEliot Blennerhassett 
2227719f82d3SEliot Blennerhassett 	} else {
2228719f82d3SEliot Blennerhassett 		/* can we do anything else in response to the error ? */
2229719f82d3SEliot Blennerhassett 		HPI_DEBUG_LOG(ERROR,
2230719f82d3SEliot Blennerhassett 			"interrupt from HIF module BAD (function %x)\n",
2231719f82d3SEliot Blennerhassett 			phm->function);
2232719f82d3SEliot Blennerhassett 	}
2233719f82d3SEliot Blennerhassett 
2234719f82d3SEliot Blennerhassett 	/* reset the interrupt from the DSP */
2235719f82d3SEliot Blennerhassett 	iowrite32(C6205_HSR_INTSRC, phw->prHSR);
2236719f82d3SEliot Blennerhassett #endif
2237719f82d3SEliot Blennerhassett 
2238719f82d3SEliot Blennerhassett 	/* read the result */
2239719f82d3SEliot Blennerhassett 	if (time_out != 0)
2240719f82d3SEliot Blennerhassett 		*phr = interface->u.response_buffer;
2241719f82d3SEliot Blennerhassett 
2242719f82d3SEliot Blennerhassett 	/* set interface back to idle */
2243719f82d3SEliot Blennerhassett 	send_dsp_command(phw, H620_HIF_IDLE);
2244719f82d3SEliot Blennerhassett 
2245719f82d3SEliot Blennerhassett 	if ((time_out == 0) || (time_out2 == 0)) {
2246719f82d3SEliot Blennerhassett 		HPI_DEBUG_LOG(DEBUG, "something timed out!\n");
2247719f82d3SEliot Blennerhassett 		return hpi6205_error(0, HPI6205_ERROR_MSG_RESP_TIMEOUT);
2248719f82d3SEliot Blennerhassett 	}
2249719f82d3SEliot Blennerhassett 	/* special case for adapter close - */
2250719f82d3SEliot Blennerhassett 	/* wait for the DSP to indicate it is idle */
2251719f82d3SEliot Blennerhassett 	if (phm->function == HPI_ADAPTER_CLOSE) {
2252719f82d3SEliot Blennerhassett 		if (!wait_dsp_ack(phw, H620_HIF_IDLE, HPI6205_TIMEOUT)) {
2253719f82d3SEliot Blennerhassett 			HPI_DEBUG_LOG(DEBUG,
2254719f82d3SEliot Blennerhassett 				"timeout waiting for idle "
2255719f82d3SEliot Blennerhassett 				"(on adapter_close)\n");
2256719f82d3SEliot Blennerhassett 			return hpi6205_error(0,
2257719f82d3SEliot Blennerhassett 				HPI6205_ERROR_MSG_RESP_IDLE_TIMEOUT);
2258719f82d3SEliot Blennerhassett 		}
2259719f82d3SEliot Blennerhassett 	}
2260719f82d3SEliot Blennerhassett 	err = hpi_validate_response(phm, phr);
2261719f82d3SEliot Blennerhassett 	return err;
2262719f82d3SEliot Blennerhassett }
2263719f82d3SEliot Blennerhassett 
2264719f82d3SEliot Blennerhassett static void hw_message(struct hpi_adapter_obj *pao, struct hpi_message *phm,
2265719f82d3SEliot Blennerhassett 	struct hpi_response *phr)
2266719f82d3SEliot Blennerhassett {
2267719f82d3SEliot Blennerhassett 
2268719f82d3SEliot Blennerhassett 	u16 err = 0;
2269719f82d3SEliot Blennerhassett 
2270719f82d3SEliot Blennerhassett 	hpios_dsplock_lock(pao);
2271719f82d3SEliot Blennerhassett 
2272719f82d3SEliot Blennerhassett 	err = message_response_sequence(pao, phm, phr);
2273719f82d3SEliot Blennerhassett 
2274719f82d3SEliot Blennerhassett 	/* maybe an error response */
2275719f82d3SEliot Blennerhassett 	if (err) {
2276719f82d3SEliot Blennerhassett 		/* something failed in the HPI/DSP interface */
2277719f82d3SEliot Blennerhassett 		phr->error = err;
2278719f82d3SEliot Blennerhassett 		pao->dsp_crashed++;
2279719f82d3SEliot Blennerhassett 
2280719f82d3SEliot Blennerhassett 		/* just the header of the response is valid */
2281719f82d3SEliot Blennerhassett 		phr->size = sizeof(struct hpi_response_header);
2282719f82d3SEliot Blennerhassett 		goto err;
2283719f82d3SEliot Blennerhassett 	} else
2284719f82d3SEliot Blennerhassett 		pao->dsp_crashed = 0;
2285719f82d3SEliot Blennerhassett 
2286719f82d3SEliot Blennerhassett 	if (phr->error != 0)	/* something failed in the DSP */
2287719f82d3SEliot Blennerhassett 		goto err;
2288719f82d3SEliot Blennerhassett 
2289719f82d3SEliot Blennerhassett 	switch (phm->function) {
2290719f82d3SEliot Blennerhassett 	case HPI_OSTREAM_WRITE:
2291719f82d3SEliot Blennerhassett 	case HPI_ISTREAM_ANC_WRITE:
2292719f82d3SEliot Blennerhassett 		err = hpi6205_transfer_data(pao, phm->u.d.u.data.pb_data,
2293719f82d3SEliot Blennerhassett 			phm->u.d.u.data.data_size, H620_HIF_SEND_DATA);
2294719f82d3SEliot Blennerhassett 		break;
2295719f82d3SEliot Blennerhassett 
2296719f82d3SEliot Blennerhassett 	case HPI_ISTREAM_READ:
2297719f82d3SEliot Blennerhassett 	case HPI_OSTREAM_ANC_READ:
2298719f82d3SEliot Blennerhassett 		err = hpi6205_transfer_data(pao, phm->u.d.u.data.pb_data,
2299719f82d3SEliot Blennerhassett 			phm->u.d.u.data.data_size, H620_HIF_GET_DATA);
2300719f82d3SEliot Blennerhassett 		break;
2301719f82d3SEliot Blennerhassett 
2302719f82d3SEliot Blennerhassett 	case HPI_CONTROL_SET_STATE:
2303719f82d3SEliot Blennerhassett 		if (phm->object == HPI_OBJ_CONTROLEX
2304719f82d3SEliot Blennerhassett 			&& phm->u.cx.attribute == HPI_COBRANET_SET_DATA)
2305719f82d3SEliot Blennerhassett 			err = hpi6205_transfer_data(pao,
2306719f82d3SEliot Blennerhassett 				phm->u.cx.u.cobranet_bigdata.pb_data,
2307719f82d3SEliot Blennerhassett 				phm->u.cx.u.cobranet_bigdata.byte_count,
2308719f82d3SEliot Blennerhassett 				H620_HIF_SEND_DATA);
2309719f82d3SEliot Blennerhassett 		break;
2310719f82d3SEliot Blennerhassett 
2311719f82d3SEliot Blennerhassett 	case HPI_CONTROL_GET_STATE:
2312719f82d3SEliot Blennerhassett 		if (phm->object == HPI_OBJ_CONTROLEX
2313719f82d3SEliot Blennerhassett 			&& phm->u.cx.attribute == HPI_COBRANET_GET_DATA)
2314719f82d3SEliot Blennerhassett 			err = hpi6205_transfer_data(pao,
2315719f82d3SEliot Blennerhassett 				phm->u.cx.u.cobranet_bigdata.pb_data,
2316719f82d3SEliot Blennerhassett 				phr->u.cx.u.cobranet_data.byte_count,
2317719f82d3SEliot Blennerhassett 				H620_HIF_GET_DATA);
2318719f82d3SEliot Blennerhassett 		break;
2319719f82d3SEliot Blennerhassett 	}
2320719f82d3SEliot Blennerhassett 	phr->error = err;
2321719f82d3SEliot Blennerhassett 
2322719f82d3SEliot Blennerhassett err:
2323719f82d3SEliot Blennerhassett 	hpios_dsplock_unlock(pao);
2324719f82d3SEliot Blennerhassett 
2325719f82d3SEliot Blennerhassett 	return;
2326719f82d3SEliot Blennerhassett }
2327