xref: /openbmc/linux/sound/pci/asihpi/hpi6000.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
107d7fe7bSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2719f82d3SEliot Blennerhassett /******************************************************************************
3719f82d3SEliot Blennerhassett 
4719f82d3SEliot Blennerhassett     AudioScience HPI driver
540818b62SEliot Blennerhassett     Copyright (C) 1997-2011  AudioScience Inc. <support@audioscience.com>
6719f82d3SEliot Blennerhassett 
7719f82d3SEliot Blennerhassett 
8719f82d3SEliot Blennerhassett  Hardware Programming Interface (HPI) for AudioScience ASI6200 series adapters.
9719f82d3SEliot Blennerhassett  These PCI bus adapters are based on the TI C6711 DSP.
10719f82d3SEliot Blennerhassett 
11719f82d3SEliot Blennerhassett  Exported functions:
12719f82d3SEliot Blennerhassett  void HPI_6000(struct hpi_message *phm, struct hpi_response *phr)
13719f82d3SEliot Blennerhassett 
14719f82d3SEliot Blennerhassett  #defines
15719f82d3SEliot Blennerhassett  HIDE_PCI_ASSERTS to show the PCI asserts
16719f82d3SEliot Blennerhassett  PROFILE_DSP2 get profile data from DSP2 if present (instead of DSP 1)
17719f82d3SEliot Blennerhassett 
18719f82d3SEliot Blennerhassett (C) Copyright AudioScience Inc. 1998-2003
19719f82d3SEliot Blennerhassett *******************************************************************************/
20719f82d3SEliot Blennerhassett #define SOURCEFILE_NAME "hpi6000.c"
21719f82d3SEliot Blennerhassett 
22719f82d3SEliot Blennerhassett #include "hpi_internal.h"
23719f82d3SEliot Blennerhassett #include "hpimsginit.h"
24719f82d3SEliot Blennerhassett #include "hpidebug.h"
25719f82d3SEliot Blennerhassett #include "hpi6000.h"
26719f82d3SEliot Blennerhassett #include "hpidspcd.h"
27719f82d3SEliot Blennerhassett #include "hpicmn.h"
28719f82d3SEliot Blennerhassett 
29719f82d3SEliot Blennerhassett #define HPI_HIF_BASE (0x00000200)	/* start of C67xx internal RAM */
30719f82d3SEliot Blennerhassett #define HPI_HIF_ADDR(member) \
31719f82d3SEliot Blennerhassett 	(HPI_HIF_BASE + offsetof(struct hpi_hif_6000, member))
32719f82d3SEliot Blennerhassett #define HPI_HIF_ERROR_MASK      0x4000
33719f82d3SEliot Blennerhassett 
34719f82d3SEliot Blennerhassett /* HPI6000 specific error codes */
353285ea10SEliot Blennerhassett #define HPI6000_ERROR_BASE 900	/* not actually used anywhere */
361528fbb5SEliot Blennerhassett 
373285ea10SEliot Blennerhassett /* operational/messaging errors */
38719f82d3SEliot Blennerhassett #define HPI6000_ERROR_MSG_RESP_IDLE_TIMEOUT             901
390d02e129SEliot Blennerhassett #define HPI6000_ERROR_RESP_GET_LEN                      902
40719f82d3SEliot Blennerhassett #define HPI6000_ERROR_MSG_RESP_GET_RESP_ACK             903
41719f82d3SEliot Blennerhassett #define HPI6000_ERROR_MSG_GET_ADR                       904
42719f82d3SEliot Blennerhassett #define HPI6000_ERROR_RESP_GET_ADR                      905
43719f82d3SEliot Blennerhassett #define HPI6000_ERROR_MSG_RESP_BLOCKWRITE32             906
44719f82d3SEliot Blennerhassett #define HPI6000_ERROR_MSG_RESP_BLOCKREAD32              907
453285ea10SEliot Blennerhassett 
46719f82d3SEliot Blennerhassett #define HPI6000_ERROR_CONTROL_CACHE_PARAMS              909
47719f82d3SEliot Blennerhassett 
48719f82d3SEliot Blennerhassett #define HPI6000_ERROR_SEND_DATA_IDLE_TIMEOUT            911
49719f82d3SEliot Blennerhassett #define HPI6000_ERROR_SEND_DATA_ACK                     912
50719f82d3SEliot Blennerhassett #define HPI6000_ERROR_SEND_DATA_ADR                     913
51719f82d3SEliot Blennerhassett #define HPI6000_ERROR_SEND_DATA_TIMEOUT                 914
52719f82d3SEliot Blennerhassett #define HPI6000_ERROR_SEND_DATA_CMD                     915
53719f82d3SEliot Blennerhassett #define HPI6000_ERROR_SEND_DATA_WRITE                   916
54719f82d3SEliot Blennerhassett #define HPI6000_ERROR_SEND_DATA_IDLECMD                 917
55719f82d3SEliot Blennerhassett 
56719f82d3SEliot Blennerhassett #define HPI6000_ERROR_GET_DATA_IDLE_TIMEOUT             921
57719f82d3SEliot Blennerhassett #define HPI6000_ERROR_GET_DATA_ACK                      922
58719f82d3SEliot Blennerhassett #define HPI6000_ERROR_GET_DATA_CMD                      923
59719f82d3SEliot Blennerhassett #define HPI6000_ERROR_GET_DATA_READ                     924
60719f82d3SEliot Blennerhassett #define HPI6000_ERROR_GET_DATA_IDLECMD                  925
61719f82d3SEliot Blennerhassett 
62719f82d3SEliot Blennerhassett #define HPI6000_ERROR_CONTROL_CACHE_ADDRLEN             951
63719f82d3SEliot Blennerhassett #define HPI6000_ERROR_CONTROL_CACHE_READ                952
64719f82d3SEliot Blennerhassett #define HPI6000_ERROR_CONTROL_CACHE_FLUSH               953
65719f82d3SEliot Blennerhassett 
66719f82d3SEliot Blennerhassett #define HPI6000_ERROR_MSG_RESP_GETRESPCMD               961
67719f82d3SEliot Blennerhassett #define HPI6000_ERROR_MSG_RESP_IDLECMD                  962
68719f82d3SEliot Blennerhassett 
693285ea10SEliot Blennerhassett /* Initialisation/bootload errors */
70719f82d3SEliot Blennerhassett #define HPI6000_ERROR_UNHANDLED_SUBSYS_ID               930
71719f82d3SEliot Blennerhassett 
72719f82d3SEliot Blennerhassett /* can't access PCI2040 */
73719f82d3SEliot Blennerhassett #define HPI6000_ERROR_INIT_PCI2040                      931
74719f82d3SEliot Blennerhassett /* can't access DSP HPI i/f */
75719f82d3SEliot Blennerhassett #define HPI6000_ERROR_INIT_DSPHPI                       932
76719f82d3SEliot Blennerhassett /* can't access internal DSP memory */
77719f82d3SEliot Blennerhassett #define HPI6000_ERROR_INIT_DSPINTMEM                    933
78719f82d3SEliot Blennerhassett /* can't access SDRAM - test#1 */
79719f82d3SEliot Blennerhassett #define HPI6000_ERROR_INIT_SDRAM1                       934
80719f82d3SEliot Blennerhassett /* can't access SDRAM - test#2 */
81719f82d3SEliot Blennerhassett #define HPI6000_ERROR_INIT_SDRAM2                       935
82719f82d3SEliot Blennerhassett 
83719f82d3SEliot Blennerhassett #define HPI6000_ERROR_INIT_VERIFY                       938
84719f82d3SEliot Blennerhassett 
85719f82d3SEliot Blennerhassett #define HPI6000_ERROR_INIT_NOACK                        939
86719f82d3SEliot Blennerhassett 
87719f82d3SEliot Blennerhassett #define HPI6000_ERROR_INIT_PLDTEST1                     941
88719f82d3SEliot Blennerhassett #define HPI6000_ERROR_INIT_PLDTEST2                     942
89719f82d3SEliot Blennerhassett 
90719f82d3SEliot Blennerhassett /* local defines */
91719f82d3SEliot Blennerhassett 
92719f82d3SEliot Blennerhassett #define HIDE_PCI_ASSERTS
93719f82d3SEliot Blennerhassett #define PROFILE_DSP2
94719f82d3SEliot Blennerhassett 
95719f82d3SEliot Blennerhassett /* for PCI2040 i/f chip */
96719f82d3SEliot Blennerhassett /* HPI CSR registers */
97719f82d3SEliot Blennerhassett /* word offsets from CSR base */
98719f82d3SEliot Blennerhassett /* use when io addresses defined as u32 * */
99719f82d3SEliot Blennerhassett 
100719f82d3SEliot Blennerhassett #define INTERRUPT_EVENT_SET     0
101719f82d3SEliot Blennerhassett #define INTERRUPT_EVENT_CLEAR   1
102719f82d3SEliot Blennerhassett #define INTERRUPT_MASK_SET      2
103719f82d3SEliot Blennerhassett #define INTERRUPT_MASK_CLEAR    3
104719f82d3SEliot Blennerhassett #define HPI_ERROR_REPORT        4
105719f82d3SEliot Blennerhassett #define HPI_RESET               5
106719f82d3SEliot Blennerhassett #define HPI_DATA_WIDTH          6
107719f82d3SEliot Blennerhassett 
108719f82d3SEliot Blennerhassett #define MAX_DSPS 2
109719f82d3SEliot Blennerhassett /* HPI registers, spaced 8K bytes = 2K words apart */
110719f82d3SEliot Blennerhassett #define DSP_SPACING             0x800
111719f82d3SEliot Blennerhassett 
112719f82d3SEliot Blennerhassett #define CONTROL                 0x0000
113719f82d3SEliot Blennerhassett #define ADDRESS                 0x0200
114719f82d3SEliot Blennerhassett #define DATA_AUTOINC            0x0400
115719f82d3SEliot Blennerhassett #define DATA                    0x0600
116719f82d3SEliot Blennerhassett 
117719f82d3SEliot Blennerhassett #define TIMEOUT 500000
118719f82d3SEliot Blennerhassett 
119719f82d3SEliot Blennerhassett struct dsp_obj {
120719f82d3SEliot Blennerhassett 	__iomem u32 *prHPI_control;
121719f82d3SEliot Blennerhassett 	__iomem u32 *prHPI_address;
122719f82d3SEliot Blennerhassett 	__iomem u32 *prHPI_data;
123719f82d3SEliot Blennerhassett 	__iomem u32 *prHPI_data_auto_inc;
124719f82d3SEliot Blennerhassett 	char c_dsp_rev;		/*A, B */
125719f82d3SEliot Blennerhassett 	u32 control_cache_address_on_dsp;
126719f82d3SEliot Blennerhassett 	u32 control_cache_length_on_dsp;
127719f82d3SEliot Blennerhassett 	struct hpi_adapter_obj *pa_parent_adapter;
128719f82d3SEliot Blennerhassett };
129719f82d3SEliot Blennerhassett 
130719f82d3SEliot Blennerhassett struct hpi_hw_obj {
131719f82d3SEliot Blennerhassett 	__iomem u32 *dw2040_HPICSR;
132719f82d3SEliot Blennerhassett 	__iomem u32 *dw2040_HPIDSP;
133719f82d3SEliot Blennerhassett 
134719f82d3SEliot Blennerhassett 	u16 num_dsp;
135719f82d3SEliot Blennerhassett 	struct dsp_obj ado[MAX_DSPS];
136719f82d3SEliot Blennerhassett 
137719f82d3SEliot Blennerhassett 	u32 message_buffer_address_on_dsp;
138719f82d3SEliot Blennerhassett 	u32 response_buffer_address_on_dsp;
139719f82d3SEliot Blennerhassett 	u32 pCI2040HPI_error_count;
140719f82d3SEliot Blennerhassett 
141719f82d3SEliot Blennerhassett 	struct hpi_control_cache_single control_cache[HPI_NMIXER_CONTROLS];
142719f82d3SEliot Blennerhassett 	struct hpi_control_cache *p_cache;
143719f82d3SEliot Blennerhassett };
144719f82d3SEliot Blennerhassett 
145719f82d3SEliot Blennerhassett static u16 hpi6000_dsp_block_write32(struct hpi_adapter_obj *pao,
146719f82d3SEliot Blennerhassett 	u16 dsp_index, u32 hpi_address, u32 *source, u32 count);
147719f82d3SEliot Blennerhassett static u16 hpi6000_dsp_block_read32(struct hpi_adapter_obj *pao,
148719f82d3SEliot Blennerhassett 	u16 dsp_index, u32 hpi_address, u32 *dest, u32 count);
149719f82d3SEliot Blennerhassett 
150719f82d3SEliot Blennerhassett static short hpi6000_adapter_boot_load_dsp(struct hpi_adapter_obj *pao,
151719f82d3SEliot Blennerhassett 	u32 *pos_error_code);
152719f82d3SEliot Blennerhassett static short hpi6000_check_PCI2040_error_flag(struct hpi_adapter_obj *pao,
153719f82d3SEliot Blennerhassett 	u16 read_or_write);
154719f82d3SEliot Blennerhassett #define H6READ 1
155719f82d3SEliot Blennerhassett #define H6WRITE 0
156719f82d3SEliot Blennerhassett 
157719f82d3SEliot Blennerhassett static short hpi6000_update_control_cache(struct hpi_adapter_obj *pao,
158719f82d3SEliot Blennerhassett 	struct hpi_message *phm);
159719f82d3SEliot Blennerhassett static short hpi6000_message_response_sequence(struct hpi_adapter_obj *pao,
160719f82d3SEliot Blennerhassett 	u16 dsp_index, struct hpi_message *phm, struct hpi_response *phr);
161719f82d3SEliot Blennerhassett 
162719f82d3SEliot Blennerhassett static void hw_message(struct hpi_adapter_obj *pao, struct hpi_message *phm,
163719f82d3SEliot Blennerhassett 	struct hpi_response *phr);
164719f82d3SEliot Blennerhassett 
165719f82d3SEliot Blennerhassett static short hpi6000_wait_dsp_ack(struct hpi_adapter_obj *pao, u16 dsp_index,
166719f82d3SEliot Blennerhassett 	u32 ack_value);
167719f82d3SEliot Blennerhassett 
168719f82d3SEliot Blennerhassett static short hpi6000_send_host_command(struct hpi_adapter_obj *pao,
169719f82d3SEliot Blennerhassett 	u16 dsp_index, u32 host_cmd);
170719f82d3SEliot Blennerhassett 
171719f82d3SEliot Blennerhassett static void hpi6000_send_dsp_interrupt(struct dsp_obj *pdo);
172719f82d3SEliot Blennerhassett 
173719f82d3SEliot Blennerhassett static short hpi6000_send_data(struct hpi_adapter_obj *pao, u16 dsp_index,
174719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr);
175719f82d3SEliot Blennerhassett 
176719f82d3SEliot Blennerhassett static short hpi6000_get_data(struct hpi_adapter_obj *pao, u16 dsp_index,
177719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr);
178719f82d3SEliot Blennerhassett 
179719f82d3SEliot Blennerhassett static void hpi_write_word(struct dsp_obj *pdo, u32 address, u32 data);
180719f82d3SEliot Blennerhassett 
181719f82d3SEliot Blennerhassett static u32 hpi_read_word(struct dsp_obj *pdo, u32 address);
182719f82d3SEliot Blennerhassett 
183719f82d3SEliot Blennerhassett static void hpi_write_block(struct dsp_obj *pdo, u32 address, u32 *pdata,
184719f82d3SEliot Blennerhassett 	u32 length);
185719f82d3SEliot Blennerhassett 
186719f82d3SEliot Blennerhassett static void hpi_read_block(struct dsp_obj *pdo, u32 address, u32 *pdata,
187719f82d3SEliot Blennerhassett 	u32 length);
188719f82d3SEliot Blennerhassett 
189719f82d3SEliot Blennerhassett static void subsys_create_adapter(struct hpi_message *phm,
190719f82d3SEliot Blennerhassett 	struct hpi_response *phr);
191719f82d3SEliot Blennerhassett 
1926d0b898eSEliot Blennerhassett static void adapter_delete(struct hpi_adapter_obj *pao,
1936d0b898eSEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr);
194719f82d3SEliot Blennerhassett 
195719f82d3SEliot Blennerhassett static void adapter_get_asserts(struct hpi_adapter_obj *pao,
196719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr);
197719f82d3SEliot Blennerhassett 
198719f82d3SEliot Blennerhassett static short create_adapter_obj(struct hpi_adapter_obj *pao,
199719f82d3SEliot Blennerhassett 	u32 *pos_error_code);
200719f82d3SEliot Blennerhassett 
2013285ea10SEliot Blennerhassett static void delete_adapter_obj(struct hpi_adapter_obj *pao);
2023285ea10SEliot Blennerhassett 
203719f82d3SEliot Blennerhassett /* local globals */
204719f82d3SEliot Blennerhassett 
205719f82d3SEliot Blennerhassett static u16 gw_pci_read_asserts;	/* used to count PCI2040 errors */
206719f82d3SEliot Blennerhassett static u16 gw_pci_write_asserts;	/* used to count PCI2040 errors */
207719f82d3SEliot Blennerhassett 
subsys_message(struct hpi_message * phm,struct hpi_response * phr)208719f82d3SEliot Blennerhassett static void subsys_message(struct hpi_message *phm, struct hpi_response *phr)
209719f82d3SEliot Blennerhassett {
210719f82d3SEliot Blennerhassett 	switch (phm->function) {
211719f82d3SEliot Blennerhassett 	case HPI_SUBSYS_CREATE_ADAPTER:
212719f82d3SEliot Blennerhassett 		subsys_create_adapter(phm, phr);
213719f82d3SEliot Blennerhassett 		break;
214719f82d3SEliot Blennerhassett 	default:
215719f82d3SEliot Blennerhassett 		phr->error = HPI_ERROR_INVALID_FUNC;
216719f82d3SEliot Blennerhassett 		break;
217719f82d3SEliot Blennerhassett 	}
218719f82d3SEliot Blennerhassett }
219719f82d3SEliot Blennerhassett 
control_message(struct hpi_adapter_obj * pao,struct hpi_message * phm,struct hpi_response * phr)220719f82d3SEliot Blennerhassett static void control_message(struct hpi_adapter_obj *pao,
221719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
222719f82d3SEliot Blennerhassett {
2237036b92dSEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
2247036b92dSEliot Blennerhassett 
225719f82d3SEliot Blennerhassett 	switch (phm->function) {
226719f82d3SEliot Blennerhassett 	case HPI_CONTROL_GET_STATE:
227719f82d3SEliot Blennerhassett 		if (pao->has_control_cache) {
2280a00044dSEliot Blennerhassett 			u16 err;
2290a00044dSEliot Blennerhassett 			err = hpi6000_update_control_cache(pao, phm);
230719f82d3SEliot Blennerhassett 
2310a00044dSEliot Blennerhassett 			if (err) {
2320a00044dSEliot Blennerhassett 				if (err >= HPI_ERROR_BACKEND_BASE) {
2330a00044dSEliot Blennerhassett 					phr->error =
2340a00044dSEliot Blennerhassett 						HPI_ERROR_CONTROL_CACHING;
2350a00044dSEliot Blennerhassett 					phr->specific_error = err;
2360a00044dSEliot Blennerhassett 				} else {
2370a00044dSEliot Blennerhassett 					phr->error = err;
2380a00044dSEliot Blennerhassett 				}
239719f82d3SEliot Blennerhassett 				break;
2400a00044dSEliot Blennerhassett 			}
241719f82d3SEliot Blennerhassett 
2427036b92dSEliot Blennerhassett 			if (hpi_check_control_cache(phw->p_cache, phm, phr))
243719f82d3SEliot Blennerhassett 				break;
244719f82d3SEliot Blennerhassett 		}
245719f82d3SEliot Blennerhassett 		hw_message(pao, phm, phr);
246719f82d3SEliot Blennerhassett 		break;
247719f82d3SEliot Blennerhassett 	case HPI_CONTROL_SET_STATE:
248719f82d3SEliot Blennerhassett 		hw_message(pao, phm, phr);
2497036b92dSEliot Blennerhassett 		hpi_cmn_control_cache_sync_to_msg(phw->p_cache, phm, phr);
250719f82d3SEliot Blennerhassett 		break;
2513285ea10SEliot Blennerhassett 
2523285ea10SEliot Blennerhassett 	case HPI_CONTROL_GET_INFO:
253719f82d3SEliot Blennerhassett 	default:
2543285ea10SEliot Blennerhassett 		hw_message(pao, phm, phr);
255719f82d3SEliot Blennerhassett 		break;
256719f82d3SEliot Blennerhassett 	}
257719f82d3SEliot Blennerhassett }
258719f82d3SEliot Blennerhassett 
adapter_message(struct hpi_adapter_obj * pao,struct hpi_message * phm,struct hpi_response * phr)259719f82d3SEliot Blennerhassett static void adapter_message(struct hpi_adapter_obj *pao,
260719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
261719f82d3SEliot Blennerhassett {
262719f82d3SEliot Blennerhassett 	switch (phm->function) {
263719f82d3SEliot Blennerhassett 	case HPI_ADAPTER_GET_ASSERT:
264719f82d3SEliot Blennerhassett 		adapter_get_asserts(pao, phm, phr);
265719f82d3SEliot Blennerhassett 		break;
2663285ea10SEliot Blennerhassett 
2676d0b898eSEliot Blennerhassett 	case HPI_ADAPTER_DELETE:
2686d0b898eSEliot Blennerhassett 		adapter_delete(pao, phm, phr);
2696d0b898eSEliot Blennerhassett 		break;
2706d0b898eSEliot Blennerhassett 
271719f82d3SEliot Blennerhassett 	default:
2723285ea10SEliot Blennerhassett 		hw_message(pao, phm, phr);
273719f82d3SEliot Blennerhassett 		break;
274719f82d3SEliot Blennerhassett 	}
275719f82d3SEliot Blennerhassett }
276719f82d3SEliot Blennerhassett 
outstream_message(struct hpi_adapter_obj * pao,struct hpi_message * phm,struct hpi_response * phr)277719f82d3SEliot Blennerhassett static void outstream_message(struct hpi_adapter_obj *pao,
278719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
279719f82d3SEliot Blennerhassett {
280719f82d3SEliot Blennerhassett 	switch (phm->function) {
281719f82d3SEliot Blennerhassett 	case HPI_OSTREAM_HOSTBUFFER_ALLOC:
282719f82d3SEliot Blennerhassett 	case HPI_OSTREAM_HOSTBUFFER_FREE:
283719f82d3SEliot Blennerhassett 		/* Don't let these messages go to the HW function because
2843285ea10SEliot Blennerhassett 		 * they're called without locking the spinlock.
285719f82d3SEliot Blennerhassett 		 * For the HPI6000 adapters the HW would return
286719f82d3SEliot Blennerhassett 		 * HPI_ERROR_INVALID_FUNC anyway.
287719f82d3SEliot Blennerhassett 		 */
288719f82d3SEliot Blennerhassett 		phr->error = HPI_ERROR_INVALID_FUNC;
289719f82d3SEliot Blennerhassett 		break;
290719f82d3SEliot Blennerhassett 	default:
291719f82d3SEliot Blennerhassett 		hw_message(pao, phm, phr);
292719f82d3SEliot Blennerhassett 		return;
293719f82d3SEliot Blennerhassett 	}
294719f82d3SEliot Blennerhassett }
295719f82d3SEliot Blennerhassett 
instream_message(struct hpi_adapter_obj * pao,struct hpi_message * phm,struct hpi_response * phr)296719f82d3SEliot Blennerhassett static void instream_message(struct hpi_adapter_obj *pao,
297719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
298719f82d3SEliot Blennerhassett {
299719f82d3SEliot Blennerhassett 
300719f82d3SEliot Blennerhassett 	switch (phm->function) {
301719f82d3SEliot Blennerhassett 	case HPI_ISTREAM_HOSTBUFFER_ALLOC:
302719f82d3SEliot Blennerhassett 	case HPI_ISTREAM_HOSTBUFFER_FREE:
303719f82d3SEliot Blennerhassett 		/* Don't let these messages go to the HW function because
3043285ea10SEliot Blennerhassett 		 * they're called without locking the spinlock.
305719f82d3SEliot Blennerhassett 		 * For the HPI6000 adapters the HW would return
306719f82d3SEliot Blennerhassett 		 * HPI_ERROR_INVALID_FUNC anyway.
307719f82d3SEliot Blennerhassett 		 */
308719f82d3SEliot Blennerhassett 		phr->error = HPI_ERROR_INVALID_FUNC;
309719f82d3SEliot Blennerhassett 		break;
310719f82d3SEliot Blennerhassett 	default:
311719f82d3SEliot Blennerhassett 		hw_message(pao, phm, phr);
312719f82d3SEliot Blennerhassett 		return;
313719f82d3SEliot Blennerhassett 	}
314719f82d3SEliot Blennerhassett }
315719f82d3SEliot Blennerhassett 
316719f82d3SEliot Blennerhassett /************************************************************************/
317719f82d3SEliot Blennerhassett /** HPI_6000()
318719f82d3SEliot Blennerhassett  * Entry point from HPIMAN
319719f82d3SEliot Blennerhassett  * All calls to the HPI start here
320719f82d3SEliot Blennerhassett  */
HPI_6000(struct hpi_message * phm,struct hpi_response * phr)321719f82d3SEliot Blennerhassett void HPI_6000(struct hpi_message *phm, struct hpi_response *phr)
322719f82d3SEliot Blennerhassett {
323719f82d3SEliot Blennerhassett 	struct hpi_adapter_obj *pao = NULL;
324719f82d3SEliot Blennerhassett 
325719f82d3SEliot Blennerhassett 	if (phm->object != HPI_OBJ_SUBSYSTEM) {
326719f82d3SEliot Blennerhassett 		pao = hpi_find_adapter(phm->adapter_index);
327719f82d3SEliot Blennerhassett 		if (!pao) {
3286d0b898eSEliot Blennerhassett 			hpi_init_response(phr, phm->object, phm->function,
3296d0b898eSEliot Blennerhassett 				HPI_ERROR_BAD_ADAPTER_NUMBER);
3306d0b898eSEliot Blennerhassett 			HPI_DEBUG_LOG(DEBUG, "invalid adapter index: %d \n",
3316d0b898eSEliot Blennerhassett 				phm->adapter_index);
332719f82d3SEliot Blennerhassett 			return;
333719f82d3SEliot Blennerhassett 		}
334719f82d3SEliot Blennerhassett 
3356d0b898eSEliot Blennerhassett 		/* Don't even try to communicate with crashed DSP */
336719f82d3SEliot Blennerhassett 		if (pao->dsp_crashed >= 10) {
337719f82d3SEliot Blennerhassett 			hpi_init_response(phr, phm->object, phm->function,
338719f82d3SEliot Blennerhassett 				HPI_ERROR_DSP_HARDWARE);
3396d0b898eSEliot Blennerhassett 			HPI_DEBUG_LOG(DEBUG, "adapter %d dsp crashed\n",
3406d0b898eSEliot Blennerhassett 				phm->adapter_index);
341719f82d3SEliot Blennerhassett 			return;
342719f82d3SEliot Blennerhassett 		}
343719f82d3SEliot Blennerhassett 	}
344719f82d3SEliot Blennerhassett 	/* Init default response including the size field */
345719f82d3SEliot Blennerhassett 	if (phm->function != HPI_SUBSYS_CREATE_ADAPTER)
346719f82d3SEliot Blennerhassett 		hpi_init_response(phr, phm->object, phm->function,
347719f82d3SEliot Blennerhassett 			HPI_ERROR_PROCESSING_MESSAGE);
348719f82d3SEliot Blennerhassett 
349719f82d3SEliot Blennerhassett 	switch (phm->type) {
35082b5774fSEliot Blennerhassett 	case HPI_TYPE_REQUEST:
351719f82d3SEliot Blennerhassett 		switch (phm->object) {
352719f82d3SEliot Blennerhassett 		case HPI_OBJ_SUBSYSTEM:
353719f82d3SEliot Blennerhassett 			subsys_message(phm, phr);
354719f82d3SEliot Blennerhassett 			break;
355719f82d3SEliot Blennerhassett 
356719f82d3SEliot Blennerhassett 		case HPI_OBJ_ADAPTER:
357719f82d3SEliot Blennerhassett 			phr->size =
358719f82d3SEliot Blennerhassett 				sizeof(struct hpi_response_header) +
359719f82d3SEliot Blennerhassett 				sizeof(struct hpi_adapter_res);
360719f82d3SEliot Blennerhassett 			adapter_message(pao, phm, phr);
361719f82d3SEliot Blennerhassett 			break;
362719f82d3SEliot Blennerhassett 
363719f82d3SEliot Blennerhassett 		case HPI_OBJ_CONTROL:
364719f82d3SEliot Blennerhassett 			control_message(pao, phm, phr);
365719f82d3SEliot Blennerhassett 			break;
366719f82d3SEliot Blennerhassett 
367719f82d3SEliot Blennerhassett 		case HPI_OBJ_OSTREAM:
368719f82d3SEliot Blennerhassett 			outstream_message(pao, phm, phr);
369719f82d3SEliot Blennerhassett 			break;
370719f82d3SEliot Blennerhassett 
371719f82d3SEliot Blennerhassett 		case HPI_OBJ_ISTREAM:
372719f82d3SEliot Blennerhassett 			instream_message(pao, phm, phr);
373719f82d3SEliot Blennerhassett 			break;
374719f82d3SEliot Blennerhassett 
375719f82d3SEliot Blennerhassett 		default:
376719f82d3SEliot Blennerhassett 			hw_message(pao, phm, phr);
377719f82d3SEliot Blennerhassett 			break;
378719f82d3SEliot Blennerhassett 		}
379719f82d3SEliot Blennerhassett 		break;
380719f82d3SEliot Blennerhassett 
381719f82d3SEliot Blennerhassett 	default:
382719f82d3SEliot Blennerhassett 		phr->error = HPI_ERROR_INVALID_TYPE;
383719f82d3SEliot Blennerhassett 		break;
384719f82d3SEliot Blennerhassett 	}
385719f82d3SEliot Blennerhassett }
386719f82d3SEliot Blennerhassett 
387719f82d3SEliot Blennerhassett /************************************************************************/
388719f82d3SEliot Blennerhassett /* SUBSYSTEM */
389719f82d3SEliot Blennerhassett 
390719f82d3SEliot Blennerhassett /* create an adapter object and initialise it based on resource information
391*ccc86a0aSwangjianli  * passed in the message
392719f82d3SEliot Blennerhassett  * NOTE - you cannot use this function AND the FindAdapters function at the
393719f82d3SEliot Blennerhassett  * same time, the application must use only one of them to get the adapters
394719f82d3SEliot Blennerhassett  */
subsys_create_adapter(struct hpi_message * phm,struct hpi_response * phr)395719f82d3SEliot Blennerhassett static void subsys_create_adapter(struct hpi_message *phm,
396719f82d3SEliot Blennerhassett 	struct hpi_response *phr)
397719f82d3SEliot Blennerhassett {
398719f82d3SEliot Blennerhassett 	/* create temp adapter obj, because we don't know what index yet */
399719f82d3SEliot Blennerhassett 	struct hpi_adapter_obj ao;
400719f82d3SEliot Blennerhassett 	struct hpi_adapter_obj *pao;
401719f82d3SEliot Blennerhassett 	u32 os_error_code;
4020a00044dSEliot Blennerhassett 	u16 err = 0;
403719f82d3SEliot Blennerhassett 	u32 dsp_index = 0;
404719f82d3SEliot Blennerhassett 
405719f82d3SEliot Blennerhassett 	HPI_DEBUG_LOG(VERBOSE, "subsys_create_adapter\n");
406719f82d3SEliot Blennerhassett 
407719f82d3SEliot Blennerhassett 	memset(&ao, 0, sizeof(ao));
408719f82d3SEliot Blennerhassett 
409550a8b69SJulia Lawall 	ao.priv = kzalloc(sizeof(struct hpi_hw_obj), GFP_KERNEL);
410719f82d3SEliot Blennerhassett 	if (!ao.priv) {
41125985edcSLucas De Marchi 		HPI_DEBUG_LOG(ERROR, "can't get mem for adapter object\n");
412719f82d3SEliot Blennerhassett 		phr->error = HPI_ERROR_MEMORY_ALLOC;
413719f82d3SEliot Blennerhassett 		return;
414719f82d3SEliot Blennerhassett 	}
415719f82d3SEliot Blennerhassett 
416719f82d3SEliot Blennerhassett 	/* create the adapter object based on the resource information */
417719f82d3SEliot Blennerhassett 	ao.pci = *phm->u.s.resource.r.pci;
418719f82d3SEliot Blennerhassett 
4190a00044dSEliot Blennerhassett 	err = create_adapter_obj(&ao, &os_error_code);
4200a00044dSEliot Blennerhassett 	if (err) {
4213285ea10SEliot Blennerhassett 		delete_adapter_obj(&ao);
4220a00044dSEliot Blennerhassett 		if (err >= HPI_ERROR_BACKEND_BASE) {
4230a00044dSEliot Blennerhassett 			phr->error = HPI_ERROR_DSP_BOOTLOAD;
4240a00044dSEliot Blennerhassett 			phr->specific_error = err;
4250a00044dSEliot Blennerhassett 		} else {
4260a00044dSEliot Blennerhassett 			phr->error = err;
4270a00044dSEliot Blennerhassett 		}
4280a00044dSEliot Blennerhassett 
4293285ea10SEliot Blennerhassett 		phr->u.s.data = os_error_code;
430719f82d3SEliot Blennerhassett 		return;
431719f82d3SEliot Blennerhassett 	}
432719f82d3SEliot Blennerhassett 	/* need to update paParentAdapter */
433719f82d3SEliot Blennerhassett 	pao = hpi_find_adapter(ao.index);
434719f82d3SEliot Blennerhassett 	if (!pao) {
435719f82d3SEliot Blennerhassett 		/* We just added this adapter, why can't we find it!? */
436719f82d3SEliot Blennerhassett 		HPI_DEBUG_LOG(ERROR, "lost adapter after boot\n");
4370a00044dSEliot Blennerhassett 		phr->error = HPI_ERROR_BAD_ADAPTER;
438719f82d3SEliot Blennerhassett 		return;
439719f82d3SEliot Blennerhassett 	}
440719f82d3SEliot Blennerhassett 
441719f82d3SEliot Blennerhassett 	for (dsp_index = 0; dsp_index < MAX_DSPS; dsp_index++) {
4427036b92dSEliot Blennerhassett 		struct hpi_hw_obj *phw = pao->priv;
443719f82d3SEliot Blennerhassett 		phw->ado[dsp_index].pa_parent_adapter = pao;
444719f82d3SEliot Blennerhassett 	}
445719f82d3SEliot Blennerhassett 
4467036b92dSEliot Blennerhassett 	phr->u.s.adapter_type = ao.type;
447719f82d3SEliot Blennerhassett 	phr->u.s.adapter_index = ao.index;
448719f82d3SEliot Blennerhassett 	phr->error = 0;
449719f82d3SEliot Blennerhassett }
450719f82d3SEliot Blennerhassett 
adapter_delete(struct hpi_adapter_obj * pao,struct hpi_message * phm,struct hpi_response * phr)4516d0b898eSEliot Blennerhassett static void adapter_delete(struct hpi_adapter_obj *pao,
4526d0b898eSEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
453719f82d3SEliot Blennerhassett {
4543285ea10SEliot Blennerhassett 	delete_adapter_obj(pao);
455719f82d3SEliot Blennerhassett 	hpi_delete_adapter(pao);
456719f82d3SEliot Blennerhassett 	phr->error = 0;
457719f82d3SEliot Blennerhassett }
458719f82d3SEliot Blennerhassett 
459719f82d3SEliot Blennerhassett /* this routine is called from SubSysFindAdapter and SubSysCreateAdapter */
create_adapter_obj(struct hpi_adapter_obj * pao,u32 * pos_error_code)460719f82d3SEliot Blennerhassett static short create_adapter_obj(struct hpi_adapter_obj *pao,
461719f82d3SEliot Blennerhassett 	u32 *pos_error_code)
462719f82d3SEliot Blennerhassett {
463719f82d3SEliot Blennerhassett 	short boot_error = 0;
464719f82d3SEliot Blennerhassett 	u32 dsp_index = 0;
465719f82d3SEliot Blennerhassett 	u32 control_cache_size = 0;
466719f82d3SEliot Blennerhassett 	u32 control_cache_count = 0;
4677036b92dSEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
468719f82d3SEliot Blennerhassett 
469719f82d3SEliot Blennerhassett 	/* The PCI2040 has the following address map */
470719f82d3SEliot Blennerhassett 	/* BAR0 - 4K = HPI control and status registers on PCI2040 (HPI CSR) */
471719f82d3SEliot Blennerhassett 	/* BAR1 - 32K = HPI registers on DSP */
472719f82d3SEliot Blennerhassett 	phw->dw2040_HPICSR = pao->pci.ap_mem_base[0];
473719f82d3SEliot Blennerhassett 	phw->dw2040_HPIDSP = pao->pci.ap_mem_base[1];
474719f82d3SEliot Blennerhassett 	HPI_DEBUG_LOG(VERBOSE, "csr %p, dsp %p\n", phw->dw2040_HPICSR,
475719f82d3SEliot Blennerhassett 		phw->dw2040_HPIDSP);
476719f82d3SEliot Blennerhassett 
477719f82d3SEliot Blennerhassett 	/* set addresses for the possible DSP HPI interfaces */
478719f82d3SEliot Blennerhassett 	for (dsp_index = 0; dsp_index < MAX_DSPS; dsp_index++) {
479719f82d3SEliot Blennerhassett 		phw->ado[dsp_index].prHPI_control =
480719f82d3SEliot Blennerhassett 			phw->dw2040_HPIDSP + (CONTROL +
481719f82d3SEliot Blennerhassett 			DSP_SPACING * dsp_index);
482719f82d3SEliot Blennerhassett 
483719f82d3SEliot Blennerhassett 		phw->ado[dsp_index].prHPI_address =
484719f82d3SEliot Blennerhassett 			phw->dw2040_HPIDSP + (ADDRESS +
485719f82d3SEliot Blennerhassett 			DSP_SPACING * dsp_index);
486719f82d3SEliot Blennerhassett 		phw->ado[dsp_index].prHPI_data =
487719f82d3SEliot Blennerhassett 			phw->dw2040_HPIDSP + (DATA + DSP_SPACING * dsp_index);
488719f82d3SEliot Blennerhassett 
489719f82d3SEliot Blennerhassett 		phw->ado[dsp_index].prHPI_data_auto_inc =
490719f82d3SEliot Blennerhassett 			phw->dw2040_HPIDSP + (DATA_AUTOINC +
491719f82d3SEliot Blennerhassett 			DSP_SPACING * dsp_index);
492719f82d3SEliot Blennerhassett 
493719f82d3SEliot Blennerhassett 		HPI_DEBUG_LOG(VERBOSE, "ctl %p, adr %p, dat %p, dat++ %p\n",
494719f82d3SEliot Blennerhassett 			phw->ado[dsp_index].prHPI_control,
495719f82d3SEliot Blennerhassett 			phw->ado[dsp_index].prHPI_address,
496719f82d3SEliot Blennerhassett 			phw->ado[dsp_index].prHPI_data,
497719f82d3SEliot Blennerhassett 			phw->ado[dsp_index].prHPI_data_auto_inc);
498719f82d3SEliot Blennerhassett 
499719f82d3SEliot Blennerhassett 		phw->ado[dsp_index].pa_parent_adapter = pao;
500719f82d3SEliot Blennerhassett 	}
501719f82d3SEliot Blennerhassett 
502719f82d3SEliot Blennerhassett 	phw->pCI2040HPI_error_count = 0;
503719f82d3SEliot Blennerhassett 	pao->has_control_cache = 0;
504719f82d3SEliot Blennerhassett 
505719f82d3SEliot Blennerhassett 	/* Set the default number of DSPs on this card */
506719f82d3SEliot Blennerhassett 	/* This is (conditionally) adjusted after bootloading */
507719f82d3SEliot Blennerhassett 	/* of the first DSP in the bootload section. */
508719f82d3SEliot Blennerhassett 	phw->num_dsp = 1;
509719f82d3SEliot Blennerhassett 
510719f82d3SEliot Blennerhassett 	boot_error = hpi6000_adapter_boot_load_dsp(pao, pos_error_code);
511719f82d3SEliot Blennerhassett 	if (boot_error)
512719f82d3SEliot Blennerhassett 		return boot_error;
513719f82d3SEliot Blennerhassett 
514719f82d3SEliot Blennerhassett 	HPI_DEBUG_LOG(INFO, "bootload DSP OK\n");
515719f82d3SEliot Blennerhassett 
516719f82d3SEliot Blennerhassett 	phw->message_buffer_address_on_dsp = 0L;
517719f82d3SEliot Blennerhassett 	phw->response_buffer_address_on_dsp = 0L;
518719f82d3SEliot Blennerhassett 
519719f82d3SEliot Blennerhassett 	/* get info about the adapter by asking the adapter */
520719f82d3SEliot Blennerhassett 	/* send a HPI_ADAPTER_GET_INFO message */
521719f82d3SEliot Blennerhassett 	{
5223285ea10SEliot Blennerhassett 		struct hpi_message hm;
5233285ea10SEliot Blennerhassett 		struct hpi_response hr0;	/* response from DSP 0 */
5243285ea10SEliot Blennerhassett 		struct hpi_response hr1;	/* response from DSP 1 */
525719f82d3SEliot Blennerhassett 		u16 error = 0;
526719f82d3SEliot Blennerhassett 
527719f82d3SEliot Blennerhassett 		HPI_DEBUG_LOG(VERBOSE, "send ADAPTER_GET_INFO\n");
5283285ea10SEliot Blennerhassett 		memset(&hm, 0, sizeof(hm));
52982b5774fSEliot Blennerhassett 		hm.type = HPI_TYPE_REQUEST;
5303285ea10SEliot Blennerhassett 		hm.size = sizeof(struct hpi_message);
5313285ea10SEliot Blennerhassett 		hm.object = HPI_OBJ_ADAPTER;
5323285ea10SEliot Blennerhassett 		hm.function = HPI_ADAPTER_GET_INFO;
5333285ea10SEliot Blennerhassett 		hm.adapter_index = 0;
5343285ea10SEliot Blennerhassett 		memset(&hr0, 0, sizeof(hr0));
5353285ea10SEliot Blennerhassett 		memset(&hr1, 0, sizeof(hr1));
5363285ea10SEliot Blennerhassett 		hr0.size = sizeof(hr0);
5373285ea10SEliot Blennerhassett 		hr1.size = sizeof(hr1);
538719f82d3SEliot Blennerhassett 
5393285ea10SEliot Blennerhassett 		error = hpi6000_message_response_sequence(pao, 0, &hm, &hr0);
5403285ea10SEliot Blennerhassett 		if (hr0.error) {
5413285ea10SEliot Blennerhassett 			HPI_DEBUG_LOG(DEBUG, "message error %d\n", hr0.error);
5423285ea10SEliot Blennerhassett 			return hr0.error;
543719f82d3SEliot Blennerhassett 		}
544719f82d3SEliot Blennerhassett 		if (phw->num_dsp == 2) {
5453285ea10SEliot Blennerhassett 			error = hpi6000_message_response_sequence(pao, 1, &hm,
5463285ea10SEliot Blennerhassett 				&hr1);
547719f82d3SEliot Blennerhassett 			if (error)
548719f82d3SEliot Blennerhassett 				return error;
549719f82d3SEliot Blennerhassett 		}
5507036b92dSEliot Blennerhassett 		pao->type = hr0.u.ax.info.adapter_type;
5513285ea10SEliot Blennerhassett 		pao->index = hr0.u.ax.info.adapter_index;
552719f82d3SEliot Blennerhassett 	}
553719f82d3SEliot Blennerhassett 
554719f82d3SEliot Blennerhassett 	memset(&phw->control_cache[0], 0,
555719f82d3SEliot Blennerhassett 		sizeof(struct hpi_control_cache_single) *
556719f82d3SEliot Blennerhassett 		HPI_NMIXER_CONTROLS);
557719f82d3SEliot Blennerhassett 	/* Read the control cache length to figure out if it is turned on */
558719f82d3SEliot Blennerhassett 	control_cache_size =
559719f82d3SEliot Blennerhassett 		hpi_read_word(&phw->ado[0],
560719f82d3SEliot Blennerhassett 		HPI_HIF_ADDR(control_cache_size_in_bytes));
561719f82d3SEliot Blennerhassett 	if (control_cache_size) {
562719f82d3SEliot Blennerhassett 		control_cache_count =
563719f82d3SEliot Blennerhassett 			hpi_read_word(&phw->ado[0],
564719f82d3SEliot Blennerhassett 			HPI_HIF_ADDR(control_cache_count));
565719f82d3SEliot Blennerhassett 
566719f82d3SEliot Blennerhassett 		phw->p_cache =
567719f82d3SEliot Blennerhassett 			hpi_alloc_control_cache(control_cache_count,
5683285ea10SEliot Blennerhassett 			control_cache_size, (unsigned char *)
569719f82d3SEliot Blennerhassett 			&phw->control_cache[0]
570719f82d3SEliot Blennerhassett 			);
5713285ea10SEliot Blennerhassett 		if (phw->p_cache)
5723285ea10SEliot Blennerhassett 			pao->has_control_cache = 1;
5733285ea10SEliot Blennerhassett 	}
574719f82d3SEliot Blennerhassett 
5757036b92dSEliot Blennerhassett 	HPI_DEBUG_LOG(DEBUG, "get adapter info ASI%04X index %d\n", pao->type,
5767036b92dSEliot Blennerhassett 		pao->index);
5773285ea10SEliot Blennerhassett 
578ffdb5787SEliot Blennerhassett 	if (phw->p_cache)
579ffdb5787SEliot Blennerhassett 		phw->p_cache->adap_idx = pao->index;
580ffdb5787SEliot Blennerhassett 
5813285ea10SEliot Blennerhassett 	return hpi_add_adapter(pao);
5823285ea10SEliot Blennerhassett }
5833285ea10SEliot Blennerhassett 
delete_adapter_obj(struct hpi_adapter_obj * pao)5843285ea10SEliot Blennerhassett static void delete_adapter_obj(struct hpi_adapter_obj *pao)
5853285ea10SEliot Blennerhassett {
5867036b92dSEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
5873285ea10SEliot Blennerhassett 
5883285ea10SEliot Blennerhassett 	if (pao->has_control_cache)
5893285ea10SEliot Blennerhassett 		hpi_free_control_cache(phw->p_cache);
5903285ea10SEliot Blennerhassett 
5913285ea10SEliot Blennerhassett 	/* reset DSPs on adapter */
5923285ea10SEliot Blennerhassett 	iowrite32(0x0003000F, phw->dw2040_HPICSR + HPI_RESET);
5933285ea10SEliot Blennerhassett 
5943285ea10SEliot Blennerhassett 	kfree(phw);
595719f82d3SEliot Blennerhassett }
596719f82d3SEliot Blennerhassett 
597719f82d3SEliot Blennerhassett /************************************************************************/
598719f82d3SEliot Blennerhassett /* ADAPTER */
599719f82d3SEliot Blennerhassett 
adapter_get_asserts(struct hpi_adapter_obj * pao,struct hpi_message * phm,struct hpi_response * phr)600719f82d3SEliot Blennerhassett static void adapter_get_asserts(struct hpi_adapter_obj *pao,
601719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
602719f82d3SEliot Blennerhassett {
603719f82d3SEliot Blennerhassett #ifndef HIDE_PCI_ASSERTS
604719f82d3SEliot Blennerhassett 	/* if we have PCI2040 asserts then collect them */
605719f82d3SEliot Blennerhassett 	if ((gw_pci_read_asserts > 0) || (gw_pci_write_asserts > 0)) {
6063285ea10SEliot Blennerhassett 		phr->u.ax.assert.p1 =
607719f82d3SEliot Blennerhassett 			gw_pci_read_asserts * 100 + gw_pci_write_asserts;
6083285ea10SEliot Blennerhassett 		phr->u.ax.assert.p2 = 0;
6093285ea10SEliot Blennerhassett 		phr->u.ax.assert.count = 1;	/* assert count */
6103285ea10SEliot Blennerhassett 		phr->u.ax.assert.dsp_index = -1;	/* "dsp index" */
6113285ea10SEliot Blennerhassett 		strcpy(phr->u.ax.assert.sz_message, "PCI2040 error");
6123285ea10SEliot Blennerhassett 		phr->u.ax.assert.dsp_msg_addr = 0;
613719f82d3SEliot Blennerhassett 		gw_pci_read_asserts = 0;
614719f82d3SEliot Blennerhassett 		gw_pci_write_asserts = 0;
615719f82d3SEliot Blennerhassett 		phr->error = 0;
616719f82d3SEliot Blennerhassett 	} else
617719f82d3SEliot Blennerhassett #endif
618719f82d3SEliot Blennerhassett 		hw_message(pao, phm, phr);	/*get DSP asserts */
619719f82d3SEliot Blennerhassett 
620719f82d3SEliot Blennerhassett 	return;
621719f82d3SEliot Blennerhassett }
622719f82d3SEliot Blennerhassett 
623719f82d3SEliot Blennerhassett /************************************************************************/
624719f82d3SEliot Blennerhassett /* LOW-LEVEL */
625719f82d3SEliot Blennerhassett 
hpi6000_adapter_boot_load_dsp(struct hpi_adapter_obj * pao,u32 * pos_error_code)626719f82d3SEliot Blennerhassett static short hpi6000_adapter_boot_load_dsp(struct hpi_adapter_obj *pao,
627719f82d3SEliot Blennerhassett 	u32 *pos_error_code)
628719f82d3SEliot Blennerhassett {
6297036b92dSEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
630719f82d3SEliot Blennerhassett 	short error;
631719f82d3SEliot Blennerhassett 	u32 timeout;
632719f82d3SEliot Blennerhassett 	u32 read = 0;
633719f82d3SEliot Blennerhassett 	u32 i = 0;
634719f82d3SEliot Blennerhassett 	u32 data = 0;
635719f82d3SEliot Blennerhassett 	u32 j = 0;
636719f82d3SEliot Blennerhassett 	u32 test_addr = 0x80000000;
637719f82d3SEliot Blennerhassett 	u32 test_data = 0x00000001;
638719f82d3SEliot Blennerhassett 	u32 dw2040_reset = 0;
639719f82d3SEliot Blennerhassett 	u32 dsp_index = 0;
640719f82d3SEliot Blennerhassett 	u32 endian = 0;
641719f82d3SEliot Blennerhassett 	u32 adapter_info = 0;
642719f82d3SEliot Blennerhassett 	u32 delay = 0;
643719f82d3SEliot Blennerhassett 
644719f82d3SEliot Blennerhassett 	struct dsp_code dsp_code;
645719f82d3SEliot Blennerhassett 	u16 boot_load_family = 0;
646719f82d3SEliot Blennerhassett 
647719f82d3SEliot Blennerhassett 	/* NOTE don't use wAdapterType in this routine. It is not setup yet */
648719f82d3SEliot Blennerhassett 
6493285ea10SEliot Blennerhassett 	switch (pao->pci.pci_dev->subsystem_device) {
650719f82d3SEliot Blennerhassett 	case 0x5100:
651719f82d3SEliot Blennerhassett 	case 0x5110:	/* ASI5100 revB or higher with C6711D */
6523285ea10SEliot Blennerhassett 	case 0x5200:	/* ASI5200 PCIe version of ASI5100 */
653719f82d3SEliot Blennerhassett 	case 0x6100:
654719f82d3SEliot Blennerhassett 	case 0x6200:
655719f82d3SEliot Blennerhassett 		boot_load_family = HPI_ADAPTER_FAMILY_ASI(0x6200);
656719f82d3SEliot Blennerhassett 		break;
657719f82d3SEliot Blennerhassett 	default:
658719f82d3SEliot Blennerhassett 		return HPI6000_ERROR_UNHANDLED_SUBSYS_ID;
659719f82d3SEliot Blennerhassett 	}
660719f82d3SEliot Blennerhassett 
661719f82d3SEliot Blennerhassett 	/* reset all DSPs, indicate two DSPs are present
662719f82d3SEliot Blennerhassett 	 * set RST3-=1 to disconnect HAD8 to set DSP in little endian mode
663719f82d3SEliot Blennerhassett 	 */
664719f82d3SEliot Blennerhassett 	endian = 0;
665719f82d3SEliot Blennerhassett 	dw2040_reset = 0x0003000F;
666719f82d3SEliot Blennerhassett 	iowrite32(dw2040_reset, phw->dw2040_HPICSR + HPI_RESET);
667719f82d3SEliot Blennerhassett 
668719f82d3SEliot Blennerhassett 	/* read back register to make sure PCI2040 chip is functioning
669719f82d3SEliot Blennerhassett 	 * note that bits 4..15 are read-only and so should always return zero,
670719f82d3SEliot Blennerhassett 	 * even though we wrote 1 to them
671719f82d3SEliot Blennerhassett 	 */
6723285ea10SEliot Blennerhassett 	hpios_delay_micro_seconds(1000);
673719f82d3SEliot Blennerhassett 	delay = ioread32(phw->dw2040_HPICSR + HPI_RESET);
6743285ea10SEliot Blennerhassett 
675719f82d3SEliot Blennerhassett 	if (delay != dw2040_reset) {
676719f82d3SEliot Blennerhassett 		HPI_DEBUG_LOG(ERROR, "INIT_PCI2040 %x %x\n", dw2040_reset,
677719f82d3SEliot Blennerhassett 			delay);
678719f82d3SEliot Blennerhassett 		return HPI6000_ERROR_INIT_PCI2040;
679719f82d3SEliot Blennerhassett 	}
680719f82d3SEliot Blennerhassett 
681719f82d3SEliot Blennerhassett 	/* Indicate that DSP#0,1 is a C6X */
682719f82d3SEliot Blennerhassett 	iowrite32(0x00000003, phw->dw2040_HPICSR + HPI_DATA_WIDTH);
683719f82d3SEliot Blennerhassett 	/* set Bit30 and 29 - which will prevent Target aborts from being
684719f82d3SEliot Blennerhassett 	 * issued upon HPI or GP error
685719f82d3SEliot Blennerhassett 	 */
686719f82d3SEliot Blennerhassett 	iowrite32(0x60000000, phw->dw2040_HPICSR + INTERRUPT_MASK_SET);
687719f82d3SEliot Blennerhassett 
688719f82d3SEliot Blennerhassett 	/* isolate DSP HAD8 line from PCI2040 so that
689719f82d3SEliot Blennerhassett 	 * Little endian can be set by pullup
690719f82d3SEliot Blennerhassett 	 */
691719f82d3SEliot Blennerhassett 	dw2040_reset = dw2040_reset & (~(endian << 3));
692719f82d3SEliot Blennerhassett 	iowrite32(dw2040_reset, phw->dw2040_HPICSR + HPI_RESET);
693719f82d3SEliot Blennerhassett 
694719f82d3SEliot Blennerhassett 	phw->ado[0].c_dsp_rev = 'B';	/* revB */
695719f82d3SEliot Blennerhassett 	phw->ado[1].c_dsp_rev = 'B';	/* revB */
696719f82d3SEliot Blennerhassett 
697719f82d3SEliot Blennerhassett 	/*Take both DSPs out of reset, setting HAD8 to the correct Endian */
698719f82d3SEliot Blennerhassett 	dw2040_reset = dw2040_reset & (~0x00000001);	/* start DSP 0 */
699719f82d3SEliot Blennerhassett 	iowrite32(dw2040_reset, phw->dw2040_HPICSR + HPI_RESET);
700719f82d3SEliot Blennerhassett 	dw2040_reset = dw2040_reset & (~0x00000002);	/* start DSP 1 */
701719f82d3SEliot Blennerhassett 	iowrite32(dw2040_reset, phw->dw2040_HPICSR + HPI_RESET);
702719f82d3SEliot Blennerhassett 
703719f82d3SEliot Blennerhassett 	/* set HAD8 back to PCI2040, now that DSP set to little endian mode */
704719f82d3SEliot Blennerhassett 	dw2040_reset = dw2040_reset & (~0x00000008);
705719f82d3SEliot Blennerhassett 	iowrite32(dw2040_reset, phw->dw2040_HPICSR + HPI_RESET);
706719f82d3SEliot Blennerhassett 	/*delay to allow DSP to get going */
7073285ea10SEliot Blennerhassett 	hpios_delay_micro_seconds(100);
708719f82d3SEliot Blennerhassett 
709719f82d3SEliot Blennerhassett 	/* loop through all DSPs, downloading DSP code */
710719f82d3SEliot Blennerhassett 	for (dsp_index = 0; dsp_index < phw->num_dsp; dsp_index++) {
711719f82d3SEliot Blennerhassett 		struct dsp_obj *pdo = &phw->ado[dsp_index];
712719f82d3SEliot Blennerhassett 
713719f82d3SEliot Blennerhassett 		/* configure DSP so that we download code into the SRAM */
714719f82d3SEliot Blennerhassett 		/* set control reg for little endian, HWOB=1 */
715719f82d3SEliot Blennerhassett 		iowrite32(0x00010001, pdo->prHPI_control);
716719f82d3SEliot Blennerhassett 
717719f82d3SEliot Blennerhassett 		/* test access to the HPI address register (HPIA) */
718719f82d3SEliot Blennerhassett 		test_data = 0x00000001;
719719f82d3SEliot Blennerhassett 		for (j = 0; j < 32; j++) {
720719f82d3SEliot Blennerhassett 			iowrite32(test_data, pdo->prHPI_address);
721719f82d3SEliot Blennerhassett 			data = ioread32(pdo->prHPI_address);
722719f82d3SEliot Blennerhassett 			if (data != test_data) {
723719f82d3SEliot Blennerhassett 				HPI_DEBUG_LOG(ERROR, "INIT_DSPHPI %x %x %x\n",
724719f82d3SEliot Blennerhassett 					test_data, data, dsp_index);
725719f82d3SEliot Blennerhassett 				return HPI6000_ERROR_INIT_DSPHPI;
726719f82d3SEliot Blennerhassett 			}
727719f82d3SEliot Blennerhassett 			test_data = test_data << 1;
728719f82d3SEliot Blennerhassett 		}
729719f82d3SEliot Blennerhassett 
730719f82d3SEliot Blennerhassett /* if C6713 the setup PLL to generate 225MHz from 25MHz.
731719f82d3SEliot Blennerhassett * Since the PLLDIV1 read is sometimes wrong, even on a C6713,
732719f82d3SEliot Blennerhassett * we're going to do this unconditionally
733719f82d3SEliot Blennerhassett */
734719f82d3SEliot Blennerhassett /* PLLDIV1 should have a value of 8000 after reset */
735719f82d3SEliot Blennerhassett /*
736719f82d3SEliot Blennerhassett 	if (HpiReadWord(pdo,0x01B7C118) == 0x8000)
737719f82d3SEliot Blennerhassett */
738719f82d3SEliot Blennerhassett 		{
739719f82d3SEliot Blennerhassett 			/* C6713 datasheet says we cannot program PLL from HPI,
740719f82d3SEliot Blennerhassett 			 * and indeed if we try to set the PLL multiply from the
741719f82d3SEliot Blennerhassett 			 * HPI, the PLL does not seem to lock,
742719f82d3SEliot Blennerhassett 			 * so we enable the PLL and use the default of x 7
743719f82d3SEliot Blennerhassett 			 */
744719f82d3SEliot Blennerhassett 			/* bypass PLL */
745719f82d3SEliot Blennerhassett 			hpi_write_word(pdo, 0x01B7C100, 0x0000);
7463285ea10SEliot Blennerhassett 			hpios_delay_micro_seconds(100);
747719f82d3SEliot Blennerhassett 
748719f82d3SEliot Blennerhassett 			/*  ** use default of PLL  x7 ** */
749719f82d3SEliot Blennerhassett 			/* EMIF = 225/3=75MHz */
750719f82d3SEliot Blennerhassett 			hpi_write_word(pdo, 0x01B7C120, 0x8002);
7513285ea10SEliot Blennerhassett 			hpios_delay_micro_seconds(100);
7523285ea10SEliot Blennerhassett 
753719f82d3SEliot Blennerhassett 			/* peri = 225/2 */
754719f82d3SEliot Blennerhassett 			hpi_write_word(pdo, 0x01B7C11C, 0x8001);
7553285ea10SEliot Blennerhassett 			hpios_delay_micro_seconds(100);
7563285ea10SEliot Blennerhassett 
757719f82d3SEliot Blennerhassett 			/* cpu  = 225/1 */
758719f82d3SEliot Blennerhassett 			hpi_write_word(pdo, 0x01B7C118, 0x8000);
7593285ea10SEliot Blennerhassett 
7603285ea10SEliot Blennerhassett 			/* ~2ms delay */
7613285ea10SEliot Blennerhassett 			hpios_delay_micro_seconds(2000);
7623285ea10SEliot Blennerhassett 
763719f82d3SEliot Blennerhassett 			/* PLL not bypassed */
764719f82d3SEliot Blennerhassett 			hpi_write_word(pdo, 0x01B7C100, 0x0001);
7653285ea10SEliot Blennerhassett 			/* ~2ms delay */
7663285ea10SEliot Blennerhassett 			hpios_delay_micro_seconds(2000);
767719f82d3SEliot Blennerhassett 		}
768719f82d3SEliot Blennerhassett 
769719f82d3SEliot Blennerhassett 		/* test r/w to internal DSP memory
770719f82d3SEliot Blennerhassett 		 * C6711 has L2 cache mapped to 0x0 when reset
771719f82d3SEliot Blennerhassett 		 *
772719f82d3SEliot Blennerhassett 		 *  revB - because of bug 3.0.1 last HPI read
773719f82d3SEliot Blennerhassett 		 * (before HPI address issued) must be non-autoinc
774719f82d3SEliot Blennerhassett 		 */
775719f82d3SEliot Blennerhassett 		/* test each bit in the 32bit word */
776719f82d3SEliot Blennerhassett 		for (i = 0; i < 100; i++) {
777719f82d3SEliot Blennerhassett 			test_addr = 0x00000000;
778719f82d3SEliot Blennerhassett 			test_data = 0x00000001;
779719f82d3SEliot Blennerhassett 			for (j = 0; j < 32; j++) {
780719f82d3SEliot Blennerhassett 				hpi_write_word(pdo, test_addr + i, test_data);
781719f82d3SEliot Blennerhassett 				data = hpi_read_word(pdo, test_addr + i);
782719f82d3SEliot Blennerhassett 				if (data != test_data) {
783719f82d3SEliot Blennerhassett 					HPI_DEBUG_LOG(ERROR,
784719f82d3SEliot Blennerhassett 						"DSP mem %x %x %x %x\n",
785719f82d3SEliot Blennerhassett 						test_addr + i, test_data,
786719f82d3SEliot Blennerhassett 						data, dsp_index);
787719f82d3SEliot Blennerhassett 
788719f82d3SEliot Blennerhassett 					return HPI6000_ERROR_INIT_DSPINTMEM;
789719f82d3SEliot Blennerhassett 				}
790719f82d3SEliot Blennerhassett 				test_data = test_data << 1;
791719f82d3SEliot Blennerhassett 			}
792719f82d3SEliot Blennerhassett 		}
793719f82d3SEliot Blennerhassett 
794719f82d3SEliot Blennerhassett 		/* memory map of ASI6200
795719f82d3SEliot Blennerhassett 		   00000000-0000FFFF    16Kx32 internal program
796719f82d3SEliot Blennerhassett 		   01800000-019FFFFF    Internal peripheral
797719f82d3SEliot Blennerhassett 		   80000000-807FFFFF    CE0 2Mx32 SDRAM running @ 100MHz
798719f82d3SEliot Blennerhassett 		   90000000-9000FFFF    CE1 Async peripherals:
799719f82d3SEliot Blennerhassett 
800719f82d3SEliot Blennerhassett 		   EMIF config
801719f82d3SEliot Blennerhassett 		   ------------
802719f82d3SEliot Blennerhassett 		   Global EMIF control
803719f82d3SEliot Blennerhassett 		   0 -
804719f82d3SEliot Blennerhassett 		   1 -
805719f82d3SEliot Blennerhassett 		   2 -
806719f82d3SEliot Blennerhassett 		   3 CLK2EN = 1   CLKOUT2 enabled
807719f82d3SEliot Blennerhassett 		   4 CLK1EN = 0   CLKOUT1 disabled
808719f82d3SEliot Blennerhassett 		   5 EKEN = 1 <--!! C6713 specific, enables ECLKOUT
809719f82d3SEliot Blennerhassett 		   6 -
810719f82d3SEliot Blennerhassett 		   7 NOHOLD = 1   external HOLD disabled
811719f82d3SEliot Blennerhassett 		   8 HOLDA = 0    HOLDA output is low
812719f82d3SEliot Blennerhassett 		   9 HOLD = 0             HOLD input is low
813719f82d3SEliot Blennerhassett 		   10 ARDY = 1    ARDY input is high
814719f82d3SEliot Blennerhassett 		   11 BUSREQ = 0   BUSREQ output is low
815719f82d3SEliot Blennerhassett 		   12,13 Reserved = 1
816719f82d3SEliot Blennerhassett 		 */
817719f82d3SEliot Blennerhassett 		hpi_write_word(pdo, 0x01800000, 0x34A8);
818719f82d3SEliot Blennerhassett 
819719f82d3SEliot Blennerhassett 		/* EMIF CE0 setup - 2Mx32 Sync DRAM
820719f82d3SEliot Blennerhassett 		   31..28       Wr setup
821719f82d3SEliot Blennerhassett 		   27..22       Wr strobe
822719f82d3SEliot Blennerhassett 		   21..20       Wr hold
823719f82d3SEliot Blennerhassett 		   19..16       Rd setup
824719f82d3SEliot Blennerhassett 		   15..14       -
825719f82d3SEliot Blennerhassett 		   13..8        Rd strobe
826719f82d3SEliot Blennerhassett 		   7..4         MTYPE   0011            Sync DRAM 32bits
827719f82d3SEliot Blennerhassett 		   3            Wr hold MSB
828719f82d3SEliot Blennerhassett 		   2..0         Rd hold
829719f82d3SEliot Blennerhassett 		 */
830719f82d3SEliot Blennerhassett 		hpi_write_word(pdo, 0x01800008, 0x00000030);
831719f82d3SEliot Blennerhassett 
832719f82d3SEliot Blennerhassett 		/* EMIF SDRAM Extension
833719f82d3SEliot Blennerhassett 		   31-21        0
834719f82d3SEliot Blennerhassett 		   20           WR2RD = 0
835719f82d3SEliot Blennerhassett 		   19-18        WR2DEAC = 1
836719f82d3SEliot Blennerhassett 		   17           WR2WR = 0
837719f82d3SEliot Blennerhassett 		   16-15        R2WDQM = 2
838719f82d3SEliot Blennerhassett 		   14-12        RD2WR = 4
839719f82d3SEliot Blennerhassett 		   11-10        RD2DEAC = 1
840719f82d3SEliot Blennerhassett 		   9            RD2RD = 1
841719f82d3SEliot Blennerhassett 		   8-7          THZP = 10b
842719f82d3SEliot Blennerhassett 		   6-5          TWR  = 2-1 = 01b (tWR = 10ns)
843719f82d3SEliot Blennerhassett 		   4            TRRD = 0b = 2 ECLK (tRRD = 14ns)
844719f82d3SEliot Blennerhassett 		   3-1          TRAS = 5-1 = 100b (Tras=42ns = 5 ECLK)
845719f82d3SEliot Blennerhassett 		   1            CAS latency = 3 ECLK
846719f82d3SEliot Blennerhassett 		   (for Micron 2M32-7 operating at 100Mhz)
847719f82d3SEliot Blennerhassett 		 */
848719f82d3SEliot Blennerhassett 
849719f82d3SEliot Blennerhassett 		/* need to use this else DSP code crashes */
850719f82d3SEliot Blennerhassett 		hpi_write_word(pdo, 0x01800020, 0x001BDF29);
851719f82d3SEliot Blennerhassett 
852719f82d3SEliot Blennerhassett 		/* EMIF SDRAM control - set up for a 2Mx32 SDRAM (512x32x4 bank)
853719f82d3SEliot Blennerhassett 		   31           -               -
854719f82d3SEliot Blennerhassett 		   30           SDBSZ   1               4 bank
855719f82d3SEliot Blennerhassett 		   29..28       SDRSZ   00              11 row address pins
856719f82d3SEliot Blennerhassett 		   27..26       SDCSZ   01              8 column address pins
857719f82d3SEliot Blennerhassett 		   25           RFEN    1               refersh enabled
858719f82d3SEliot Blennerhassett 		   24           INIT    1               init SDRAM
859719f82d3SEliot Blennerhassett 		   23..20       TRCD    0001
860719f82d3SEliot Blennerhassett 		   19..16       TRP             0001
861719f82d3SEliot Blennerhassett 		   15..12       TRC             0110
862719f82d3SEliot Blennerhassett 		   11..0        -               -
863719f82d3SEliot Blennerhassett 		 */
864719f82d3SEliot Blennerhassett 		/*      need to use this else DSP code crashes */
865719f82d3SEliot Blennerhassett 		hpi_write_word(pdo, 0x01800018, 0x47117000);
866719f82d3SEliot Blennerhassett 
867719f82d3SEliot Blennerhassett 		/* EMIF SDRAM Refresh Timing */
868719f82d3SEliot Blennerhassett 		hpi_write_word(pdo, 0x0180001C, 0x00000410);
869719f82d3SEliot Blennerhassett 
870719f82d3SEliot Blennerhassett 		/*MIF CE1 setup - Async peripherals
871719f82d3SEliot Blennerhassett 		   @100MHz bus speed, each cycle is 10ns,
872719f82d3SEliot Blennerhassett 		   31..28       Wr setup  = 1
873719f82d3SEliot Blennerhassett 		   27..22       Wr strobe = 3                   30ns
874719f82d3SEliot Blennerhassett 		   21..20       Wr hold = 1
875719f82d3SEliot Blennerhassett 		   19..16       Rd setup =1
876719f82d3SEliot Blennerhassett 		   15..14       Ta = 2
877719f82d3SEliot Blennerhassett 		   13..8        Rd strobe = 3                   30ns
878719f82d3SEliot Blennerhassett 		   7..4         MTYPE   0010            Async 32bits
879719f82d3SEliot Blennerhassett 		   3            Wr hold MSB =0
880719f82d3SEliot Blennerhassett 		   2..0         Rd hold = 1
881719f82d3SEliot Blennerhassett 		 */
882719f82d3SEliot Blennerhassett 		{
883719f82d3SEliot Blennerhassett 			u32 cE1 =
884719f82d3SEliot Blennerhassett 				(1L << 28) | (3L << 22) | (1L << 20) | (1L <<
885719f82d3SEliot Blennerhassett 				16) | (2L << 14) | (3L << 8) | (2L << 4) | 1L;
886719f82d3SEliot Blennerhassett 			hpi_write_word(pdo, 0x01800004, cE1);
887719f82d3SEliot Blennerhassett 		}
888719f82d3SEliot Blennerhassett 
889719f82d3SEliot Blennerhassett 		/* delay a little to allow SDRAM and DSP to "get going" */
8903285ea10SEliot Blennerhassett 		hpios_delay_micro_seconds(1000);
891719f82d3SEliot Blennerhassett 
892719f82d3SEliot Blennerhassett 		/* test access to SDRAM */
893719f82d3SEliot Blennerhassett 		{
894719f82d3SEliot Blennerhassett 			test_addr = 0x80000000;
895719f82d3SEliot Blennerhassett 			test_data = 0x00000001;
896719f82d3SEliot Blennerhassett 			/* test each bit in the 32bit word */
897719f82d3SEliot Blennerhassett 			for (j = 0; j < 32; j++) {
898719f82d3SEliot Blennerhassett 				hpi_write_word(pdo, test_addr, test_data);
899719f82d3SEliot Blennerhassett 				data = hpi_read_word(pdo, test_addr);
900719f82d3SEliot Blennerhassett 				if (data != test_data) {
901719f82d3SEliot Blennerhassett 					HPI_DEBUG_LOG(ERROR,
902719f82d3SEliot Blennerhassett 						"DSP dram %x %x %x %x\n",
903719f82d3SEliot Blennerhassett 						test_addr, test_data, data,
904719f82d3SEliot Blennerhassett 						dsp_index);
905719f82d3SEliot Blennerhassett 
906719f82d3SEliot Blennerhassett 					return HPI6000_ERROR_INIT_SDRAM1;
907719f82d3SEliot Blennerhassett 				}
908719f82d3SEliot Blennerhassett 				test_data = test_data << 1;
909719f82d3SEliot Blennerhassett 			}
910719f82d3SEliot Blennerhassett 			/* test every Nth address in the DRAM */
911719f82d3SEliot Blennerhassett #define DRAM_SIZE_WORDS 0x200000	/*2_mx32 */
912719f82d3SEliot Blennerhassett #define DRAM_INC 1024
913719f82d3SEliot Blennerhassett 			test_addr = 0x80000000;
914719f82d3SEliot Blennerhassett 			test_data = 0x0;
915719f82d3SEliot Blennerhassett 			for (i = 0; i < DRAM_SIZE_WORDS; i = i + DRAM_INC) {
916719f82d3SEliot Blennerhassett 				hpi_write_word(pdo, test_addr + i, test_data);
917719f82d3SEliot Blennerhassett 				test_data++;
918719f82d3SEliot Blennerhassett 			}
919719f82d3SEliot Blennerhassett 			test_addr = 0x80000000;
920719f82d3SEliot Blennerhassett 			test_data = 0x0;
921719f82d3SEliot Blennerhassett 			for (i = 0; i < DRAM_SIZE_WORDS; i = i + DRAM_INC) {
922719f82d3SEliot Blennerhassett 				data = hpi_read_word(pdo, test_addr + i);
923719f82d3SEliot Blennerhassett 				if (data != test_data) {
924719f82d3SEliot Blennerhassett 					HPI_DEBUG_LOG(ERROR,
925719f82d3SEliot Blennerhassett 						"DSP dram %x %x %x %x\n",
926719f82d3SEliot Blennerhassett 						test_addr + i, test_data,
927719f82d3SEliot Blennerhassett 						data, dsp_index);
928719f82d3SEliot Blennerhassett 					return HPI6000_ERROR_INIT_SDRAM2;
929719f82d3SEliot Blennerhassett 				}
930719f82d3SEliot Blennerhassett 				test_data++;
931719f82d3SEliot Blennerhassett 			}
932719f82d3SEliot Blennerhassett 
933719f82d3SEliot Blennerhassett 		}
934719f82d3SEliot Blennerhassett 
935719f82d3SEliot Blennerhassett 		/* write the DSP code down into the DSPs memory */
93695a4c6e7SEliot Blennerhassett 		error = hpi_dsp_code_open(boot_load_family, pao->pci.pci_dev,
93795a4c6e7SEliot Blennerhassett 			&dsp_code, pos_error_code);
938719f82d3SEliot Blennerhassett 
939719f82d3SEliot Blennerhassett 		if (error)
940719f82d3SEliot Blennerhassett 			return error;
941719f82d3SEliot Blennerhassett 
942719f82d3SEliot Blennerhassett 		while (1) {
943719f82d3SEliot Blennerhassett 			u32 length;
944719f82d3SEliot Blennerhassett 			u32 address;
945719f82d3SEliot Blennerhassett 			u32 type;
946719f82d3SEliot Blennerhassett 			u32 *pcode;
947719f82d3SEliot Blennerhassett 
948719f82d3SEliot Blennerhassett 			error = hpi_dsp_code_read_word(&dsp_code, &length);
949719f82d3SEliot Blennerhassett 			if (error)
950719f82d3SEliot Blennerhassett 				break;
951719f82d3SEliot Blennerhassett 			if (length == 0xFFFFFFFF)
952719f82d3SEliot Blennerhassett 				break;	/* end of code */
953719f82d3SEliot Blennerhassett 
954719f82d3SEliot Blennerhassett 			error = hpi_dsp_code_read_word(&dsp_code, &address);
955719f82d3SEliot Blennerhassett 			if (error)
956719f82d3SEliot Blennerhassett 				break;
957719f82d3SEliot Blennerhassett 			error = hpi_dsp_code_read_word(&dsp_code, &type);
958719f82d3SEliot Blennerhassett 			if (error)
959719f82d3SEliot Blennerhassett 				break;
960719f82d3SEliot Blennerhassett 			error = hpi_dsp_code_read_block(length, &dsp_code,
961719f82d3SEliot Blennerhassett 				&pcode);
962719f82d3SEliot Blennerhassett 			if (error)
963719f82d3SEliot Blennerhassett 				break;
964719f82d3SEliot Blennerhassett 			error = hpi6000_dsp_block_write32(pao, (u16)dsp_index,
965719f82d3SEliot Blennerhassett 				address, pcode, length);
966719f82d3SEliot Blennerhassett 			if (error)
967719f82d3SEliot Blennerhassett 				break;
968719f82d3SEliot Blennerhassett 		}
969719f82d3SEliot Blennerhassett 
970719f82d3SEliot Blennerhassett 		if (error) {
971719f82d3SEliot Blennerhassett 			hpi_dsp_code_close(&dsp_code);
972719f82d3SEliot Blennerhassett 			return error;
973719f82d3SEliot Blennerhassett 		}
974719f82d3SEliot Blennerhassett 		/* verify that code was written correctly */
975719f82d3SEliot Blennerhassett 		/* this time through, assume no errors in DSP code file/array */
976719f82d3SEliot Blennerhassett 		hpi_dsp_code_rewind(&dsp_code);
977719f82d3SEliot Blennerhassett 		while (1) {
978719f82d3SEliot Blennerhassett 			u32 length;
979719f82d3SEliot Blennerhassett 			u32 address;
980719f82d3SEliot Blennerhassett 			u32 type;
981719f82d3SEliot Blennerhassett 			u32 *pcode;
982719f82d3SEliot Blennerhassett 
983719f82d3SEliot Blennerhassett 			hpi_dsp_code_read_word(&dsp_code, &length);
984719f82d3SEliot Blennerhassett 			if (length == 0xFFFFFFFF)
985719f82d3SEliot Blennerhassett 				break;	/* end of code */
986719f82d3SEliot Blennerhassett 
987719f82d3SEliot Blennerhassett 			hpi_dsp_code_read_word(&dsp_code, &address);
988719f82d3SEliot Blennerhassett 			hpi_dsp_code_read_word(&dsp_code, &type);
989719f82d3SEliot Blennerhassett 			hpi_dsp_code_read_block(length, &dsp_code, &pcode);
990719f82d3SEliot Blennerhassett 
991719f82d3SEliot Blennerhassett 			for (i = 0; i < length; i++) {
992719f82d3SEliot Blennerhassett 				data = hpi_read_word(pdo, address);
993719f82d3SEliot Blennerhassett 				if (data != *pcode) {
994719f82d3SEliot Blennerhassett 					error = HPI6000_ERROR_INIT_VERIFY;
995719f82d3SEliot Blennerhassett 					HPI_DEBUG_LOG(ERROR,
996719f82d3SEliot Blennerhassett 						"DSP verify %x %x %x %x\n",
997719f82d3SEliot Blennerhassett 						address, *pcode, data,
998719f82d3SEliot Blennerhassett 						dsp_index);
999719f82d3SEliot Blennerhassett 					break;
1000719f82d3SEliot Blennerhassett 				}
1001719f82d3SEliot Blennerhassett 				pcode++;
1002719f82d3SEliot Blennerhassett 				address += 4;
1003719f82d3SEliot Blennerhassett 			}
1004719f82d3SEliot Blennerhassett 			if (error)
1005719f82d3SEliot Blennerhassett 				break;
1006719f82d3SEliot Blennerhassett 		}
1007719f82d3SEliot Blennerhassett 		hpi_dsp_code_close(&dsp_code);
1008719f82d3SEliot Blennerhassett 		if (error)
1009719f82d3SEliot Blennerhassett 			return error;
1010719f82d3SEliot Blennerhassett 
1011719f82d3SEliot Blennerhassett 		/* zero out the hostmailbox */
1012719f82d3SEliot Blennerhassett 		{
1013719f82d3SEliot Blennerhassett 			u32 address = HPI_HIF_ADDR(host_cmd);
1014719f82d3SEliot Blennerhassett 			for (i = 0; i < 4; i++) {
1015719f82d3SEliot Blennerhassett 				hpi_write_word(pdo, address, 0);
1016719f82d3SEliot Blennerhassett 				address += 4;
1017719f82d3SEliot Blennerhassett 			}
1018719f82d3SEliot Blennerhassett 		}
1019719f82d3SEliot Blennerhassett 		/* write the DSP number into the hostmailbox */
1020719f82d3SEliot Blennerhassett 		/* structure before starting the DSP */
1021719f82d3SEliot Blennerhassett 		hpi_write_word(pdo, HPI_HIF_ADDR(dsp_number), dsp_index);
1022719f82d3SEliot Blennerhassett 
1023719f82d3SEliot Blennerhassett 		/* write the DSP adapter Info into the */
1024719f82d3SEliot Blennerhassett 		/* hostmailbox before starting the DSP */
1025719f82d3SEliot Blennerhassett 		if (dsp_index > 0)
1026719f82d3SEliot Blennerhassett 			hpi_write_word(pdo, HPI_HIF_ADDR(adapter_info),
1027719f82d3SEliot Blennerhassett 				adapter_info);
1028719f82d3SEliot Blennerhassett 
1029719f82d3SEliot Blennerhassett 		/* step 3. Start code by sending interrupt */
1030719f82d3SEliot Blennerhassett 		iowrite32(0x00030003, pdo->prHPI_control);
10313285ea10SEliot Blennerhassett 		hpios_delay_micro_seconds(10000);
1032719f82d3SEliot Blennerhassett 
1033719f82d3SEliot Blennerhassett 		/* wait for a non-zero value in hostcmd -
1034719f82d3SEliot Blennerhassett 		 * indicating initialization is complete
1035719f82d3SEliot Blennerhassett 		 *
1036719f82d3SEliot Blennerhassett 		 * Init could take a while if DSP checks SDRAM memory
1037719f82d3SEliot Blennerhassett 		 * Was 200000. Increased to 2000000 for ASI8801 so we
1038719f82d3SEliot Blennerhassett 		 * don't get 938 errors.
1039719f82d3SEliot Blennerhassett 		 */
1040719f82d3SEliot Blennerhassett 		timeout = 2000000;
1041719f82d3SEliot Blennerhassett 		while (timeout) {
1042719f82d3SEliot Blennerhassett 			do {
1043719f82d3SEliot Blennerhassett 				read = hpi_read_word(pdo,
1044719f82d3SEliot Blennerhassett 					HPI_HIF_ADDR(host_cmd));
1045719f82d3SEliot Blennerhassett 			} while (--timeout
1046719f82d3SEliot Blennerhassett 				&& hpi6000_check_PCI2040_error_flag(pao,
1047719f82d3SEliot Blennerhassett 					H6READ));
1048719f82d3SEliot Blennerhassett 
1049719f82d3SEliot Blennerhassett 			if (read)
1050719f82d3SEliot Blennerhassett 				break;
1051719f82d3SEliot Blennerhassett 			/* The following is a workaround for bug #94:
1052719f82d3SEliot Blennerhassett 			 * Bluescreen on install and subsequent boots on a
1053719f82d3SEliot Blennerhassett 			 * DELL PowerEdge 600SC PC with 1.8GHz P4 and
1054719f82d3SEliot Blennerhassett 			 * ServerWorks chipset. Without this delay the system
1055719f82d3SEliot Blennerhassett 			 * locks up with a bluescreen (NOT GPF or pagefault).
1056719f82d3SEliot Blennerhassett 			 */
1057719f82d3SEliot Blennerhassett 			else
10583285ea10SEliot Blennerhassett 				hpios_delay_micro_seconds(10000);
1059719f82d3SEliot Blennerhassett 		}
1060719f82d3SEliot Blennerhassett 		if (timeout == 0)
1061719f82d3SEliot Blennerhassett 			return HPI6000_ERROR_INIT_NOACK;
1062719f82d3SEliot Blennerhassett 
1063719f82d3SEliot Blennerhassett 		/* read the DSP adapter Info from the */
1064719f82d3SEliot Blennerhassett 		/* hostmailbox structure after starting the DSP */
1065719f82d3SEliot Blennerhassett 		if (dsp_index == 0) {
1066719f82d3SEliot Blennerhassett 			/*u32 dwTestData=0; */
1067719f82d3SEliot Blennerhassett 			u32 mask = 0;
1068719f82d3SEliot Blennerhassett 
1069719f82d3SEliot Blennerhassett 			adapter_info =
1070719f82d3SEliot Blennerhassett 				hpi_read_word(pdo,
1071719f82d3SEliot Blennerhassett 				HPI_HIF_ADDR(adapter_info));
1072719f82d3SEliot Blennerhassett 			if (HPI_ADAPTER_FAMILY_ASI
1073719f82d3SEliot Blennerhassett 				(HPI_HIF_ADAPTER_INFO_EXTRACT_ADAPTER
1074719f82d3SEliot Blennerhassett 					(adapter_info)) ==
1075719f82d3SEliot Blennerhassett 				HPI_ADAPTER_FAMILY_ASI(0x6200))
1076719f82d3SEliot Blennerhassett 				/* all 6200 cards have this many DSPs */
1077719f82d3SEliot Blennerhassett 				phw->num_dsp = 2;
1078719f82d3SEliot Blennerhassett 
1079719f82d3SEliot Blennerhassett 			/* test that the PLD is programmed */
1080719f82d3SEliot Blennerhassett 			/* and we can read/write 24bits */
1081719f82d3SEliot Blennerhassett #define PLD_BASE_ADDRESS 0x90000000L	/*for ASI6100/6200/8800 */
1082719f82d3SEliot Blennerhassett 
1083719f82d3SEliot Blennerhassett 			switch (boot_load_family) {
1084719f82d3SEliot Blennerhassett 			case HPI_ADAPTER_FAMILY_ASI(0x6200):
1085719f82d3SEliot Blennerhassett 				/* ASI6100/6200 has 24bit path to FPGA */
1086719f82d3SEliot Blennerhassett 				mask = 0xFFFFFF00L;
1087719f82d3SEliot Blennerhassett 				/* ASI5100 uses AX6 code, */
1088719f82d3SEliot Blennerhassett 				/* but has no PLD r/w register to test */
10893285ea10SEliot Blennerhassett 				if (HPI_ADAPTER_FAMILY_ASI(pao->pci.pci_dev->
10903285ea10SEliot Blennerhassett 						subsystem_device) ==
1091719f82d3SEliot Blennerhassett 					HPI_ADAPTER_FAMILY_ASI(0x5100))
1092719f82d3SEliot Blennerhassett 					mask = 0x00000000L;
109338439146SEliot Blennerhassett 				/* ASI5200 uses AX6 code, */
109438439146SEliot Blennerhassett 				/* but has no PLD r/w register to test */
10953285ea10SEliot Blennerhassett 				if (HPI_ADAPTER_FAMILY_ASI(pao->pci.pci_dev->
10963285ea10SEliot Blennerhassett 						subsystem_device) ==
109738439146SEliot Blennerhassett 					HPI_ADAPTER_FAMILY_ASI(0x5200))
109838439146SEliot Blennerhassett 					mask = 0x00000000L;
1099719f82d3SEliot Blennerhassett 				break;
1100719f82d3SEliot Blennerhassett 			case HPI_ADAPTER_FAMILY_ASI(0x8800):
1101719f82d3SEliot Blennerhassett 				/* ASI8800 has 16bit path to FPGA */
1102719f82d3SEliot Blennerhassett 				mask = 0xFFFF0000L;
1103719f82d3SEliot Blennerhassett 				break;
1104719f82d3SEliot Blennerhassett 			}
1105719f82d3SEliot Blennerhassett 			test_data = 0xAAAAAA00L & mask;
1106719f82d3SEliot Blennerhassett 			/* write to 24 bit Debug register (D31-D8) */
1107719f82d3SEliot Blennerhassett 			hpi_write_word(pdo, PLD_BASE_ADDRESS + 4L, test_data);
1108719f82d3SEliot Blennerhassett 			read = hpi_read_word(pdo,
1109719f82d3SEliot Blennerhassett 				PLD_BASE_ADDRESS + 4L) & mask;
1110719f82d3SEliot Blennerhassett 			if (read != test_data) {
1111719f82d3SEliot Blennerhassett 				HPI_DEBUG_LOG(ERROR, "PLD %x %x\n", test_data,
1112719f82d3SEliot Blennerhassett 					read);
1113719f82d3SEliot Blennerhassett 				return HPI6000_ERROR_INIT_PLDTEST1;
1114719f82d3SEliot Blennerhassett 			}
1115719f82d3SEliot Blennerhassett 			test_data = 0x55555500L & mask;
1116719f82d3SEliot Blennerhassett 			hpi_write_word(pdo, PLD_BASE_ADDRESS + 4L, test_data);
1117719f82d3SEliot Blennerhassett 			read = hpi_read_word(pdo,
1118719f82d3SEliot Blennerhassett 				PLD_BASE_ADDRESS + 4L) & mask;
1119719f82d3SEliot Blennerhassett 			if (read != test_data) {
1120719f82d3SEliot Blennerhassett 				HPI_DEBUG_LOG(ERROR, "PLD %x %x\n", test_data,
1121719f82d3SEliot Blennerhassett 					read);
1122719f82d3SEliot Blennerhassett 				return HPI6000_ERROR_INIT_PLDTEST2;
1123719f82d3SEliot Blennerhassett 			}
1124719f82d3SEliot Blennerhassett 		}
1125719f82d3SEliot Blennerhassett 	}	/* for numDSP */
1126719f82d3SEliot Blennerhassett 	return 0;
1127719f82d3SEliot Blennerhassett }
1128719f82d3SEliot Blennerhassett 
1129719f82d3SEliot Blennerhassett #define PCI_TIMEOUT 100
1130719f82d3SEliot Blennerhassett 
hpi_set_address(struct dsp_obj * pdo,u32 address)1131719f82d3SEliot Blennerhassett static int hpi_set_address(struct dsp_obj *pdo, u32 address)
1132719f82d3SEliot Blennerhassett {
1133719f82d3SEliot Blennerhassett 	u32 timeout = PCI_TIMEOUT;
1134719f82d3SEliot Blennerhassett 
1135719f82d3SEliot Blennerhassett 	do {
1136719f82d3SEliot Blennerhassett 		iowrite32(address, pdo->prHPI_address);
1137719f82d3SEliot Blennerhassett 	} while (hpi6000_check_PCI2040_error_flag(pdo->pa_parent_adapter,
1138719f82d3SEliot Blennerhassett 			H6WRITE)
1139719f82d3SEliot Blennerhassett 		&& --timeout);
1140719f82d3SEliot Blennerhassett 
1141719f82d3SEliot Blennerhassett 	if (timeout)
1142719f82d3SEliot Blennerhassett 		return 0;
1143719f82d3SEliot Blennerhassett 
1144719f82d3SEliot Blennerhassett 	return 1;
1145719f82d3SEliot Blennerhassett }
1146719f82d3SEliot Blennerhassett 
1147719f82d3SEliot Blennerhassett /* write one word to the HPI port */
hpi_write_word(struct dsp_obj * pdo,u32 address,u32 data)1148719f82d3SEliot Blennerhassett static void hpi_write_word(struct dsp_obj *pdo, u32 address, u32 data)
1149719f82d3SEliot Blennerhassett {
1150719f82d3SEliot Blennerhassett 	if (hpi_set_address(pdo, address))
1151719f82d3SEliot Blennerhassett 		return;
1152719f82d3SEliot Blennerhassett 	iowrite32(data, pdo->prHPI_data);
1153719f82d3SEliot Blennerhassett }
1154719f82d3SEliot Blennerhassett 
1155719f82d3SEliot Blennerhassett /* read one word from the HPI port */
hpi_read_word(struct dsp_obj * pdo,u32 address)1156719f82d3SEliot Blennerhassett static u32 hpi_read_word(struct dsp_obj *pdo, u32 address)
1157719f82d3SEliot Blennerhassett {
1158719f82d3SEliot Blennerhassett 	u32 data = 0;
1159719f82d3SEliot Blennerhassett 
1160719f82d3SEliot Blennerhassett 	if (hpi_set_address(pdo, address))
11613285ea10SEliot Blennerhassett 		return 0;	/*? No way to return error */
1162719f82d3SEliot Blennerhassett 
1163719f82d3SEliot Blennerhassett 	/* take care of errata in revB DSP (2.0.1) */
1164719f82d3SEliot Blennerhassett 	data = ioread32(pdo->prHPI_data);
1165719f82d3SEliot Blennerhassett 	return data;
1166719f82d3SEliot Blennerhassett }
1167719f82d3SEliot Blennerhassett 
1168719f82d3SEliot Blennerhassett /* write a block of 32bit words to the DSP HPI port using auto-inc mode */
hpi_write_block(struct dsp_obj * pdo,u32 address,u32 * pdata,u32 length)1169719f82d3SEliot Blennerhassett static void hpi_write_block(struct dsp_obj *pdo, u32 address, u32 *pdata,
1170719f82d3SEliot Blennerhassett 	u32 length)
1171719f82d3SEliot Blennerhassett {
1172719f82d3SEliot Blennerhassett 	u16 length16 = length - 1;
1173719f82d3SEliot Blennerhassett 
1174719f82d3SEliot Blennerhassett 	if (length == 0)
1175719f82d3SEliot Blennerhassett 		return;
1176719f82d3SEliot Blennerhassett 
1177719f82d3SEliot Blennerhassett 	if (hpi_set_address(pdo, address))
1178719f82d3SEliot Blennerhassett 		return;
1179719f82d3SEliot Blennerhassett 
1180719f82d3SEliot Blennerhassett 	iowrite32_rep(pdo->prHPI_data_auto_inc, pdata, length16);
1181719f82d3SEliot Blennerhassett 
1182719f82d3SEliot Blennerhassett 	/* take care of errata in revB DSP (2.0.1) */
1183719f82d3SEliot Blennerhassett 	/* must end with non auto-inc */
1184719f82d3SEliot Blennerhassett 	iowrite32(*(pdata + length - 1), pdo->prHPI_data);
1185719f82d3SEliot Blennerhassett }
1186719f82d3SEliot Blennerhassett 
1187719f82d3SEliot Blennerhassett /** read a block of 32bit words from the DSP HPI port using auto-inc mode
1188719f82d3SEliot Blennerhassett  */
hpi_read_block(struct dsp_obj * pdo,u32 address,u32 * pdata,u32 length)1189719f82d3SEliot Blennerhassett static void hpi_read_block(struct dsp_obj *pdo, u32 address, u32 *pdata,
1190719f82d3SEliot Blennerhassett 	u32 length)
1191719f82d3SEliot Blennerhassett {
1192719f82d3SEliot Blennerhassett 	u16 length16 = length - 1;
1193719f82d3SEliot Blennerhassett 
1194719f82d3SEliot Blennerhassett 	if (length == 0)
1195719f82d3SEliot Blennerhassett 		return;
1196719f82d3SEliot Blennerhassett 
1197719f82d3SEliot Blennerhassett 	if (hpi_set_address(pdo, address))
1198719f82d3SEliot Blennerhassett 		return;
1199719f82d3SEliot Blennerhassett 
1200719f82d3SEliot Blennerhassett 	ioread32_rep(pdo->prHPI_data_auto_inc, pdata, length16);
1201719f82d3SEliot Blennerhassett 
1202719f82d3SEliot Blennerhassett 	/* take care of errata in revB DSP (2.0.1) */
1203719f82d3SEliot Blennerhassett 	/* must end with non auto-inc */
1204719f82d3SEliot Blennerhassett 	*(pdata + length - 1) = ioread32(pdo->prHPI_data);
1205719f82d3SEliot Blennerhassett }
1206719f82d3SEliot Blennerhassett 
hpi6000_dsp_block_write32(struct hpi_adapter_obj * pao,u16 dsp_index,u32 hpi_address,u32 * source,u32 count)1207719f82d3SEliot Blennerhassett static u16 hpi6000_dsp_block_write32(struct hpi_adapter_obj *pao,
1208719f82d3SEliot Blennerhassett 	u16 dsp_index, u32 hpi_address, u32 *source, u32 count)
1209719f82d3SEliot Blennerhassett {
12107036b92dSEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
12117036b92dSEliot Blennerhassett 	struct dsp_obj *pdo = &phw->ado[dsp_index];
1212719f82d3SEliot Blennerhassett 	u32 time_out = PCI_TIMEOUT;
1213719f82d3SEliot Blennerhassett 	int c6711_burst_size = 128;
1214719f82d3SEliot Blennerhassett 	u32 local_hpi_address = hpi_address;
1215719f82d3SEliot Blennerhassett 	int local_count = count;
1216719f82d3SEliot Blennerhassett 	int xfer_size;
1217719f82d3SEliot Blennerhassett 	u32 *pdata = source;
1218719f82d3SEliot Blennerhassett 
1219719f82d3SEliot Blennerhassett 	while (local_count) {
1220719f82d3SEliot Blennerhassett 		if (local_count > c6711_burst_size)
1221719f82d3SEliot Blennerhassett 			xfer_size = c6711_burst_size;
1222719f82d3SEliot Blennerhassett 		else
1223719f82d3SEliot Blennerhassett 			xfer_size = local_count;
1224719f82d3SEliot Blennerhassett 
1225719f82d3SEliot Blennerhassett 		time_out = PCI_TIMEOUT;
1226719f82d3SEliot Blennerhassett 		do {
1227719f82d3SEliot Blennerhassett 			hpi_write_block(pdo, local_hpi_address, pdata,
1228719f82d3SEliot Blennerhassett 				xfer_size);
1229719f82d3SEliot Blennerhassett 		} while (hpi6000_check_PCI2040_error_flag(pao, H6WRITE)
1230719f82d3SEliot Blennerhassett 			&& --time_out);
1231719f82d3SEliot Blennerhassett 
1232719f82d3SEliot Blennerhassett 		if (!time_out)
1233719f82d3SEliot Blennerhassett 			break;
1234719f82d3SEliot Blennerhassett 		pdata += xfer_size;
1235719f82d3SEliot Blennerhassett 		local_hpi_address += sizeof(u32) * xfer_size;
1236719f82d3SEliot Blennerhassett 		local_count -= xfer_size;
1237719f82d3SEliot Blennerhassett 	}
1238719f82d3SEliot Blennerhassett 
1239719f82d3SEliot Blennerhassett 	if (time_out)
1240719f82d3SEliot Blennerhassett 		return 0;
1241719f82d3SEliot Blennerhassett 	else
1242719f82d3SEliot Blennerhassett 		return 1;
1243719f82d3SEliot Blennerhassett }
1244719f82d3SEliot Blennerhassett 
hpi6000_dsp_block_read32(struct hpi_adapter_obj * pao,u16 dsp_index,u32 hpi_address,u32 * dest,u32 count)1245719f82d3SEliot Blennerhassett static u16 hpi6000_dsp_block_read32(struct hpi_adapter_obj *pao,
1246719f82d3SEliot Blennerhassett 	u16 dsp_index, u32 hpi_address, u32 *dest, u32 count)
1247719f82d3SEliot Blennerhassett {
12487036b92dSEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
12497036b92dSEliot Blennerhassett 	struct dsp_obj *pdo = &phw->ado[dsp_index];
1250719f82d3SEliot Blennerhassett 	u32 time_out = PCI_TIMEOUT;
1251719f82d3SEliot Blennerhassett 	int c6711_burst_size = 16;
1252719f82d3SEliot Blennerhassett 	u32 local_hpi_address = hpi_address;
1253719f82d3SEliot Blennerhassett 	int local_count = count;
1254719f82d3SEliot Blennerhassett 	int xfer_size;
1255719f82d3SEliot Blennerhassett 	u32 *pdata = dest;
1256719f82d3SEliot Blennerhassett 
1257719f82d3SEliot Blennerhassett 	while (local_count) {
1258719f82d3SEliot Blennerhassett 		if (local_count > c6711_burst_size)
1259719f82d3SEliot Blennerhassett 			xfer_size = c6711_burst_size;
1260719f82d3SEliot Blennerhassett 		else
1261719f82d3SEliot Blennerhassett 			xfer_size = local_count;
1262719f82d3SEliot Blennerhassett 
1263719f82d3SEliot Blennerhassett 		time_out = PCI_TIMEOUT;
1264719f82d3SEliot Blennerhassett 		do {
1265719f82d3SEliot Blennerhassett 			hpi_read_block(pdo, local_hpi_address, pdata,
1266719f82d3SEliot Blennerhassett 				xfer_size);
1267719f82d3SEliot Blennerhassett 		} while (hpi6000_check_PCI2040_error_flag(pao, H6READ)
1268719f82d3SEliot Blennerhassett 			&& --time_out);
1269719f82d3SEliot Blennerhassett 		if (!time_out)
1270719f82d3SEliot Blennerhassett 			break;
1271719f82d3SEliot Blennerhassett 
1272719f82d3SEliot Blennerhassett 		pdata += xfer_size;
1273719f82d3SEliot Blennerhassett 		local_hpi_address += sizeof(u32) * xfer_size;
1274719f82d3SEliot Blennerhassett 		local_count -= xfer_size;
1275719f82d3SEliot Blennerhassett 	}
1276719f82d3SEliot Blennerhassett 
1277719f82d3SEliot Blennerhassett 	if (time_out)
1278719f82d3SEliot Blennerhassett 		return 0;
1279719f82d3SEliot Blennerhassett 	else
1280719f82d3SEliot Blennerhassett 		return 1;
1281719f82d3SEliot Blennerhassett }
1282719f82d3SEliot Blennerhassett 
hpi6000_message_response_sequence(struct hpi_adapter_obj * pao,u16 dsp_index,struct hpi_message * phm,struct hpi_response * phr)1283719f82d3SEliot Blennerhassett static short hpi6000_message_response_sequence(struct hpi_adapter_obj *pao,
1284719f82d3SEliot Blennerhassett 	u16 dsp_index, struct hpi_message *phm, struct hpi_response *phr)
1285719f82d3SEliot Blennerhassett {
12867036b92dSEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
1287719f82d3SEliot Blennerhassett 	struct dsp_obj *pdo = &phw->ado[dsp_index];
1288719f82d3SEliot Blennerhassett 	u32 timeout;
1289719f82d3SEliot Blennerhassett 	u16 ack;
1290719f82d3SEliot Blennerhassett 	u32 address;
1291719f82d3SEliot Blennerhassett 	u32 length;
1292719f82d3SEliot Blennerhassett 	u32 *p_data;
1293719f82d3SEliot Blennerhassett 	u16 error = 0;
1294719f82d3SEliot Blennerhassett 
1295719f82d3SEliot Blennerhassett 	ack = hpi6000_wait_dsp_ack(pao, dsp_index, HPI_HIF_IDLE);
1296719f82d3SEliot Blennerhassett 	if (ack & HPI_HIF_ERROR_MASK) {
1297719f82d3SEliot Blennerhassett 		pao->dsp_crashed++;
1298719f82d3SEliot Blennerhassett 		return HPI6000_ERROR_MSG_RESP_IDLE_TIMEOUT;
1299719f82d3SEliot Blennerhassett 	}
1300719f82d3SEliot Blennerhassett 	pao->dsp_crashed = 0;
1301719f82d3SEliot Blennerhassett 
13023285ea10SEliot Blennerhassett 	/* get the message address and size */
1303719f82d3SEliot Blennerhassett 	if (phw->message_buffer_address_on_dsp == 0) {
1304719f82d3SEliot Blennerhassett 		timeout = TIMEOUT;
1305719f82d3SEliot Blennerhassett 		do {
1306719f82d3SEliot Blennerhassett 			address =
1307719f82d3SEliot Blennerhassett 				hpi_read_word(pdo,
1308719f82d3SEliot Blennerhassett 				HPI_HIF_ADDR(message_buffer_address));
1309719f82d3SEliot Blennerhassett 			phw->message_buffer_address_on_dsp = address;
1310719f82d3SEliot Blennerhassett 		} while (hpi6000_check_PCI2040_error_flag(pao, H6READ)
1311719f82d3SEliot Blennerhassett 			&& --timeout);
1312719f82d3SEliot Blennerhassett 		if (!timeout)
1313719f82d3SEliot Blennerhassett 			return HPI6000_ERROR_MSG_GET_ADR;
1314719f82d3SEliot Blennerhassett 	} else
1315719f82d3SEliot Blennerhassett 		address = phw->message_buffer_address_on_dsp;
1316719f82d3SEliot Blennerhassett 
1317719f82d3SEliot Blennerhassett 	length = phm->size;
1318719f82d3SEliot Blennerhassett 
13193285ea10SEliot Blennerhassett 	/* send the message */
1320719f82d3SEliot Blennerhassett 	p_data = (u32 *)phm;
1321719f82d3SEliot Blennerhassett 	if (hpi6000_dsp_block_write32(pao, dsp_index, address, p_data,
1322719f82d3SEliot Blennerhassett 			(u16)length / 4))
1323719f82d3SEliot Blennerhassett 		return HPI6000_ERROR_MSG_RESP_BLOCKWRITE32;
1324719f82d3SEliot Blennerhassett 
1325719f82d3SEliot Blennerhassett 	if (hpi6000_send_host_command(pao, dsp_index, HPI_HIF_GET_RESP))
1326719f82d3SEliot Blennerhassett 		return HPI6000_ERROR_MSG_RESP_GETRESPCMD;
1327719f82d3SEliot Blennerhassett 	hpi6000_send_dsp_interrupt(pdo);
1328719f82d3SEliot Blennerhassett 
1329719f82d3SEliot Blennerhassett 	ack = hpi6000_wait_dsp_ack(pao, dsp_index, HPI_HIF_GET_RESP);
1330719f82d3SEliot Blennerhassett 	if (ack & HPI_HIF_ERROR_MASK)
1331719f82d3SEliot Blennerhassett 		return HPI6000_ERROR_MSG_RESP_GET_RESP_ACK;
1332719f82d3SEliot Blennerhassett 
13333285ea10SEliot Blennerhassett 	/* get the response address */
1334719f82d3SEliot Blennerhassett 	if (phw->response_buffer_address_on_dsp == 0) {
1335719f82d3SEliot Blennerhassett 		timeout = TIMEOUT;
1336719f82d3SEliot Blennerhassett 		do {
1337719f82d3SEliot Blennerhassett 			address =
1338719f82d3SEliot Blennerhassett 				hpi_read_word(pdo,
1339719f82d3SEliot Blennerhassett 				HPI_HIF_ADDR(response_buffer_address));
1340719f82d3SEliot Blennerhassett 		} while (hpi6000_check_PCI2040_error_flag(pao, H6READ)
1341719f82d3SEliot Blennerhassett 			&& --timeout);
1342719f82d3SEliot Blennerhassett 		phw->response_buffer_address_on_dsp = address;
1343719f82d3SEliot Blennerhassett 
1344719f82d3SEliot Blennerhassett 		if (!timeout)
1345719f82d3SEliot Blennerhassett 			return HPI6000_ERROR_RESP_GET_ADR;
1346719f82d3SEliot Blennerhassett 	} else
1347719f82d3SEliot Blennerhassett 		address = phw->response_buffer_address_on_dsp;
1348719f82d3SEliot Blennerhassett 
1349719f82d3SEliot Blennerhassett 	/* read the length of the response back from the DSP */
1350719f82d3SEliot Blennerhassett 	timeout = TIMEOUT;
1351719f82d3SEliot Blennerhassett 	do {
1352719f82d3SEliot Blennerhassett 		length = hpi_read_word(pdo, HPI_HIF_ADDR(length));
1353719f82d3SEliot Blennerhassett 	} while (hpi6000_check_PCI2040_error_flag(pao, H6READ) && --timeout);
1354719f82d3SEliot Blennerhassett 	if (!timeout)
13550d02e129SEliot Blennerhassett 		return HPI6000_ERROR_RESP_GET_LEN;
13560d02e129SEliot Blennerhassett 
13570d02e129SEliot Blennerhassett 	if (length > phr->size)
13580d02e129SEliot Blennerhassett 		return HPI_ERROR_RESPONSE_BUFFER_TOO_SMALL;
1359719f82d3SEliot Blennerhassett 
13603285ea10SEliot Blennerhassett 	/* get the response */
1361719f82d3SEliot Blennerhassett 	p_data = (u32 *)phr;
1362719f82d3SEliot Blennerhassett 	if (hpi6000_dsp_block_read32(pao, dsp_index, address, p_data,
1363719f82d3SEliot Blennerhassett 			(u16)length / 4))
1364719f82d3SEliot Blennerhassett 		return HPI6000_ERROR_MSG_RESP_BLOCKREAD32;
1365719f82d3SEliot Blennerhassett 
1366719f82d3SEliot Blennerhassett 	/* set i/f back to idle */
1367719f82d3SEliot Blennerhassett 	if (hpi6000_send_host_command(pao, dsp_index, HPI_HIF_IDLE))
1368719f82d3SEliot Blennerhassett 		return HPI6000_ERROR_MSG_RESP_IDLECMD;
1369719f82d3SEliot Blennerhassett 	hpi6000_send_dsp_interrupt(pdo);
1370719f82d3SEliot Blennerhassett 
1371719f82d3SEliot Blennerhassett 	error = hpi_validate_response(phm, phr);
1372719f82d3SEliot Blennerhassett 	return error;
1373719f82d3SEliot Blennerhassett }
1374719f82d3SEliot Blennerhassett 
1375719f82d3SEliot Blennerhassett /* have to set up the below defines to match stuff in the MAP file */
1376719f82d3SEliot Blennerhassett 
1377719f82d3SEliot Blennerhassett #define MSG_ADDRESS (HPI_HIF_BASE+0x18)
1378719f82d3SEliot Blennerhassett #define MSG_LENGTH 11
1379719f82d3SEliot Blennerhassett #define RESP_ADDRESS (HPI_HIF_BASE+0x44)
1380719f82d3SEliot Blennerhassett #define RESP_LENGTH 16
1381719f82d3SEliot Blennerhassett #define QUEUE_START  (HPI_HIF_BASE+0x88)
1382719f82d3SEliot Blennerhassett #define QUEUE_SIZE 0x8000
1383719f82d3SEliot Blennerhassett 
hpi6000_send_data_check_adr(u32 address,u32 length_in_dwords)1384719f82d3SEliot Blennerhassett static short hpi6000_send_data_check_adr(u32 address, u32 length_in_dwords)
1385719f82d3SEliot Blennerhassett {
1386719f82d3SEliot Blennerhassett /*#define CHECKING       // comment this line in to enable checking */
1387719f82d3SEliot Blennerhassett #ifdef CHECKING
1388719f82d3SEliot Blennerhassett 	if (address < (u32)MSG_ADDRESS)
1389719f82d3SEliot Blennerhassett 		return 0;
1390719f82d3SEliot Blennerhassett 	if (address > (u32)(QUEUE_START + QUEUE_SIZE))
1391719f82d3SEliot Blennerhassett 		return 0;
1392719f82d3SEliot Blennerhassett 	if ((address + (length_in_dwords << 2)) >
1393719f82d3SEliot Blennerhassett 		(u32)(QUEUE_START + QUEUE_SIZE))
1394719f82d3SEliot Blennerhassett 		return 0;
1395719f82d3SEliot Blennerhassett #else
1396719f82d3SEliot Blennerhassett 	(void)address;
1397719f82d3SEliot Blennerhassett 	(void)length_in_dwords;
1398719f82d3SEliot Blennerhassett 	return 1;
1399719f82d3SEliot Blennerhassett #endif
1400719f82d3SEliot Blennerhassett }
1401719f82d3SEliot Blennerhassett 
hpi6000_send_data(struct hpi_adapter_obj * pao,u16 dsp_index,struct hpi_message * phm,struct hpi_response * phr)1402719f82d3SEliot Blennerhassett static short hpi6000_send_data(struct hpi_adapter_obj *pao, u16 dsp_index,
1403719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
1404719f82d3SEliot Blennerhassett {
14057036b92dSEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
14067036b92dSEliot Blennerhassett 	struct dsp_obj *pdo = &phw->ado[dsp_index];
1407719f82d3SEliot Blennerhassett 	u32 data_sent = 0;
1408719f82d3SEliot Blennerhassett 	u16 ack;
1409719f82d3SEliot Blennerhassett 	u32 length, address;
1410719f82d3SEliot Blennerhassett 	u32 *p_data = (u32 *)phm->u.d.u.data.pb_data;
1411719f82d3SEliot Blennerhassett 	u16 time_out = 8;
1412719f82d3SEliot Blennerhassett 
1413719f82d3SEliot Blennerhassett 	(void)phr;
1414719f82d3SEliot Blennerhassett 
1415719f82d3SEliot Blennerhassett 	/* round dwDataSize down to nearest 4 bytes */
1416719f82d3SEliot Blennerhassett 	while ((data_sent < (phm->u.d.u.data.data_size & ~3L))
1417719f82d3SEliot Blennerhassett 		&& --time_out) {
1418719f82d3SEliot Blennerhassett 		ack = hpi6000_wait_dsp_ack(pao, dsp_index, HPI_HIF_IDLE);
1419719f82d3SEliot Blennerhassett 		if (ack & HPI_HIF_ERROR_MASK)
1420719f82d3SEliot Blennerhassett 			return HPI6000_ERROR_SEND_DATA_IDLE_TIMEOUT;
1421719f82d3SEliot Blennerhassett 
1422719f82d3SEliot Blennerhassett 		if (hpi6000_send_host_command(pao, dsp_index,
1423719f82d3SEliot Blennerhassett 				HPI_HIF_SEND_DATA))
1424719f82d3SEliot Blennerhassett 			return HPI6000_ERROR_SEND_DATA_CMD;
1425719f82d3SEliot Blennerhassett 
1426719f82d3SEliot Blennerhassett 		hpi6000_send_dsp_interrupt(pdo);
1427719f82d3SEliot Blennerhassett 
1428719f82d3SEliot Blennerhassett 		ack = hpi6000_wait_dsp_ack(pao, dsp_index, HPI_HIF_SEND_DATA);
1429719f82d3SEliot Blennerhassett 
1430719f82d3SEliot Blennerhassett 		if (ack & HPI_HIF_ERROR_MASK)
1431719f82d3SEliot Blennerhassett 			return HPI6000_ERROR_SEND_DATA_ACK;
1432719f82d3SEliot Blennerhassett 
1433719f82d3SEliot Blennerhassett 		do {
1434719f82d3SEliot Blennerhassett 			/* get the address and size */
1435719f82d3SEliot Blennerhassett 			address = hpi_read_word(pdo, HPI_HIF_ADDR(address));
1436719f82d3SEliot Blennerhassett 			/* DSP returns number of DWORDS */
1437719f82d3SEliot Blennerhassett 			length = hpi_read_word(pdo, HPI_HIF_ADDR(length));
1438719f82d3SEliot Blennerhassett 		} while (hpi6000_check_PCI2040_error_flag(pao, H6READ));
1439719f82d3SEliot Blennerhassett 
1440719f82d3SEliot Blennerhassett 		if (!hpi6000_send_data_check_adr(address, length))
1441719f82d3SEliot Blennerhassett 			return HPI6000_ERROR_SEND_DATA_ADR;
1442719f82d3SEliot Blennerhassett 
1443719f82d3SEliot Blennerhassett 		/* send the data. break data into 512 DWORD blocks (2K bytes)
1444719f82d3SEliot Blennerhassett 		 * and send using block write. 2Kbytes is the max as this is the
1445719f82d3SEliot Blennerhassett 		 * memory window given to the HPI data register by the PCI2040
1446719f82d3SEliot Blennerhassett 		 */
1447719f82d3SEliot Blennerhassett 
1448719f82d3SEliot Blennerhassett 		{
1449719f82d3SEliot Blennerhassett 			u32 len = length;
1450719f82d3SEliot Blennerhassett 			u32 blk_len = 512;
1451719f82d3SEliot Blennerhassett 			while (len) {
1452719f82d3SEliot Blennerhassett 				if (len < blk_len)
1453719f82d3SEliot Blennerhassett 					blk_len = len;
1454719f82d3SEliot Blennerhassett 				if (hpi6000_dsp_block_write32(pao, dsp_index,
1455719f82d3SEliot Blennerhassett 						address, p_data, blk_len))
1456719f82d3SEliot Blennerhassett 					return HPI6000_ERROR_SEND_DATA_WRITE;
1457719f82d3SEliot Blennerhassett 				address += blk_len * 4;
1458719f82d3SEliot Blennerhassett 				p_data += blk_len;
1459719f82d3SEliot Blennerhassett 				len -= blk_len;
1460719f82d3SEliot Blennerhassett 			}
1461719f82d3SEliot Blennerhassett 		}
1462719f82d3SEliot Blennerhassett 
1463719f82d3SEliot Blennerhassett 		if (hpi6000_send_host_command(pao, dsp_index, HPI_HIF_IDLE))
1464719f82d3SEliot Blennerhassett 			return HPI6000_ERROR_SEND_DATA_IDLECMD;
1465719f82d3SEliot Blennerhassett 
1466719f82d3SEliot Blennerhassett 		hpi6000_send_dsp_interrupt(pdo);
1467719f82d3SEliot Blennerhassett 
1468719f82d3SEliot Blennerhassett 		data_sent += length * 4;
1469719f82d3SEliot Blennerhassett 	}
1470719f82d3SEliot Blennerhassett 	if (!time_out)
1471719f82d3SEliot Blennerhassett 		return HPI6000_ERROR_SEND_DATA_TIMEOUT;
1472719f82d3SEliot Blennerhassett 	return 0;
1473719f82d3SEliot Blennerhassett }
1474719f82d3SEliot Blennerhassett 
hpi6000_get_data(struct hpi_adapter_obj * pao,u16 dsp_index,struct hpi_message * phm,struct hpi_response * phr)1475719f82d3SEliot Blennerhassett static short hpi6000_get_data(struct hpi_adapter_obj *pao, u16 dsp_index,
1476719f82d3SEliot Blennerhassett 	struct hpi_message *phm, struct hpi_response *phr)
1477719f82d3SEliot Blennerhassett {
14787036b92dSEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
14797036b92dSEliot Blennerhassett 	struct dsp_obj *pdo = &phw->ado[dsp_index];
1480719f82d3SEliot Blennerhassett 	u32 data_got = 0;
1481719f82d3SEliot Blennerhassett 	u16 ack;
1482719f82d3SEliot Blennerhassett 	u32 length, address;
1483719f82d3SEliot Blennerhassett 	u32 *p_data = (u32 *)phm->u.d.u.data.pb_data;
1484719f82d3SEliot Blennerhassett 
1485719f82d3SEliot Blennerhassett 	(void)phr;	/* this parameter not used! */
1486719f82d3SEliot Blennerhassett 
1487719f82d3SEliot Blennerhassett 	/* round dwDataSize down to nearest 4 bytes */
1488719f82d3SEliot Blennerhassett 	while (data_got < (phm->u.d.u.data.data_size & ~3L)) {
1489719f82d3SEliot Blennerhassett 		ack = hpi6000_wait_dsp_ack(pao, dsp_index, HPI_HIF_IDLE);
1490719f82d3SEliot Blennerhassett 		if (ack & HPI_HIF_ERROR_MASK)
1491719f82d3SEliot Blennerhassett 			return HPI6000_ERROR_GET_DATA_IDLE_TIMEOUT;
1492719f82d3SEliot Blennerhassett 
1493719f82d3SEliot Blennerhassett 		if (hpi6000_send_host_command(pao, dsp_index,
1494719f82d3SEliot Blennerhassett 				HPI_HIF_GET_DATA))
1495719f82d3SEliot Blennerhassett 			return HPI6000_ERROR_GET_DATA_CMD;
1496719f82d3SEliot Blennerhassett 		hpi6000_send_dsp_interrupt(pdo);
1497719f82d3SEliot Blennerhassett 
1498719f82d3SEliot Blennerhassett 		ack = hpi6000_wait_dsp_ack(pao, dsp_index, HPI_HIF_GET_DATA);
1499719f82d3SEliot Blennerhassett 
1500719f82d3SEliot Blennerhassett 		if (ack & HPI_HIF_ERROR_MASK)
1501719f82d3SEliot Blennerhassett 			return HPI6000_ERROR_GET_DATA_ACK;
1502719f82d3SEliot Blennerhassett 
1503719f82d3SEliot Blennerhassett 		/* get the address and size */
1504719f82d3SEliot Blennerhassett 		do {
1505719f82d3SEliot Blennerhassett 			address = hpi_read_word(pdo, HPI_HIF_ADDR(address));
1506719f82d3SEliot Blennerhassett 			length = hpi_read_word(pdo, HPI_HIF_ADDR(length));
1507719f82d3SEliot Blennerhassett 		} while (hpi6000_check_PCI2040_error_flag(pao, H6READ));
1508719f82d3SEliot Blennerhassett 
1509719f82d3SEliot Blennerhassett 		/* read the data */
1510719f82d3SEliot Blennerhassett 		{
1511719f82d3SEliot Blennerhassett 			u32 len = length;
1512719f82d3SEliot Blennerhassett 			u32 blk_len = 512;
1513719f82d3SEliot Blennerhassett 			while (len) {
1514719f82d3SEliot Blennerhassett 				if (len < blk_len)
1515719f82d3SEliot Blennerhassett 					blk_len = len;
1516719f82d3SEliot Blennerhassett 				if (hpi6000_dsp_block_read32(pao, dsp_index,
1517719f82d3SEliot Blennerhassett 						address, p_data, blk_len))
1518719f82d3SEliot Blennerhassett 					return HPI6000_ERROR_GET_DATA_READ;
1519719f82d3SEliot Blennerhassett 				address += blk_len * 4;
1520719f82d3SEliot Blennerhassett 				p_data += blk_len;
1521719f82d3SEliot Blennerhassett 				len -= blk_len;
1522719f82d3SEliot Blennerhassett 			}
1523719f82d3SEliot Blennerhassett 		}
1524719f82d3SEliot Blennerhassett 
1525719f82d3SEliot Blennerhassett 		if (hpi6000_send_host_command(pao, dsp_index, HPI_HIF_IDLE))
1526719f82d3SEliot Blennerhassett 			return HPI6000_ERROR_GET_DATA_IDLECMD;
1527719f82d3SEliot Blennerhassett 		hpi6000_send_dsp_interrupt(pdo);
1528719f82d3SEliot Blennerhassett 
1529719f82d3SEliot Blennerhassett 		data_got += length * 4;
1530719f82d3SEliot Blennerhassett 	}
1531719f82d3SEliot Blennerhassett 	return 0;
1532719f82d3SEliot Blennerhassett }
1533719f82d3SEliot Blennerhassett 
hpi6000_send_dsp_interrupt(struct dsp_obj * pdo)1534719f82d3SEliot Blennerhassett static void hpi6000_send_dsp_interrupt(struct dsp_obj *pdo)
1535719f82d3SEliot Blennerhassett {
1536719f82d3SEliot Blennerhassett 	iowrite32(0x00030003, pdo->prHPI_control);	/* DSPINT */
1537719f82d3SEliot Blennerhassett }
1538719f82d3SEliot Blennerhassett 
hpi6000_send_host_command(struct hpi_adapter_obj * pao,u16 dsp_index,u32 host_cmd)1539719f82d3SEliot Blennerhassett static short hpi6000_send_host_command(struct hpi_adapter_obj *pao,
1540719f82d3SEliot Blennerhassett 	u16 dsp_index, u32 host_cmd)
1541719f82d3SEliot Blennerhassett {
15427036b92dSEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
15437036b92dSEliot Blennerhassett 	struct dsp_obj *pdo = &phw->ado[dsp_index];
1544719f82d3SEliot Blennerhassett 	u32 timeout = TIMEOUT;
1545719f82d3SEliot Blennerhassett 
1546719f82d3SEliot Blennerhassett 	/* set command */
1547719f82d3SEliot Blennerhassett 	do {
1548719f82d3SEliot Blennerhassett 		hpi_write_word(pdo, HPI_HIF_ADDR(host_cmd), host_cmd);
1549719f82d3SEliot Blennerhassett 		/* flush the FIFO */
1550719f82d3SEliot Blennerhassett 		hpi_set_address(pdo, HPI_HIF_ADDR(host_cmd));
1551719f82d3SEliot Blennerhassett 	} while (hpi6000_check_PCI2040_error_flag(pao, H6WRITE) && --timeout);
1552719f82d3SEliot Blennerhassett 
1553719f82d3SEliot Blennerhassett 	/* reset the interrupt bit */
1554719f82d3SEliot Blennerhassett 	iowrite32(0x00040004, pdo->prHPI_control);
1555719f82d3SEliot Blennerhassett 
1556719f82d3SEliot Blennerhassett 	if (timeout)
1557719f82d3SEliot Blennerhassett 		return 0;
1558719f82d3SEliot Blennerhassett 	else
1559719f82d3SEliot Blennerhassett 		return 1;
1560719f82d3SEliot Blennerhassett }
1561719f82d3SEliot Blennerhassett 
1562719f82d3SEliot Blennerhassett /* if the PCI2040 has recorded an HPI timeout, reset the error and return 1 */
hpi6000_check_PCI2040_error_flag(struct hpi_adapter_obj * pao,u16 read_or_write)1563719f82d3SEliot Blennerhassett static short hpi6000_check_PCI2040_error_flag(struct hpi_adapter_obj *pao,
1564719f82d3SEliot Blennerhassett 	u16 read_or_write)
1565719f82d3SEliot Blennerhassett {
1566719f82d3SEliot Blennerhassett 	u32 hPI_error;
1567719f82d3SEliot Blennerhassett 
15687036b92dSEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
1569719f82d3SEliot Blennerhassett 
1570719f82d3SEliot Blennerhassett 	/* read the error bits from the PCI2040 */
1571719f82d3SEliot Blennerhassett 	hPI_error = ioread32(phw->dw2040_HPICSR + HPI_ERROR_REPORT);
1572719f82d3SEliot Blennerhassett 	if (hPI_error) {
1573719f82d3SEliot Blennerhassett 		/* reset the error flag */
1574719f82d3SEliot Blennerhassett 		iowrite32(0L, phw->dw2040_HPICSR + HPI_ERROR_REPORT);
1575719f82d3SEliot Blennerhassett 		phw->pCI2040HPI_error_count++;
1576719f82d3SEliot Blennerhassett 		if (read_or_write == 1)
1577719f82d3SEliot Blennerhassett 			gw_pci_read_asserts++;	   /************* inc global */
1578719f82d3SEliot Blennerhassett 		else
1579719f82d3SEliot Blennerhassett 			gw_pci_write_asserts++;
1580719f82d3SEliot Blennerhassett 		return 1;
1581719f82d3SEliot Blennerhassett 	} else
1582719f82d3SEliot Blennerhassett 		return 0;
1583719f82d3SEliot Blennerhassett }
1584719f82d3SEliot Blennerhassett 
hpi6000_wait_dsp_ack(struct hpi_adapter_obj * pao,u16 dsp_index,u32 ack_value)1585719f82d3SEliot Blennerhassett static short hpi6000_wait_dsp_ack(struct hpi_adapter_obj *pao, u16 dsp_index,
1586719f82d3SEliot Blennerhassett 	u32 ack_value)
1587719f82d3SEliot Blennerhassett {
15887036b92dSEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
15897036b92dSEliot Blennerhassett 	struct dsp_obj *pdo = &phw->ado[dsp_index];
1590719f82d3SEliot Blennerhassett 	u32 ack = 0L;
1591719f82d3SEliot Blennerhassett 	u32 timeout;
1592719f82d3SEliot Blennerhassett 	u32 hPIC = 0L;
1593719f82d3SEliot Blennerhassett 
1594719f82d3SEliot Blennerhassett 	/* wait for host interrupt to signal ack is ready */
1595719f82d3SEliot Blennerhassett 	timeout = TIMEOUT;
1596719f82d3SEliot Blennerhassett 	while (--timeout) {
1597719f82d3SEliot Blennerhassett 		hPIC = ioread32(pdo->prHPI_control);
1598719f82d3SEliot Blennerhassett 		if (hPIC & 0x04)	/* 0x04 = HINT from DSP */
1599719f82d3SEliot Blennerhassett 			break;
1600719f82d3SEliot Blennerhassett 	}
1601719f82d3SEliot Blennerhassett 	if (timeout == 0)
1602719f82d3SEliot Blennerhassett 		return HPI_HIF_ERROR_MASK;
1603719f82d3SEliot Blennerhassett 
1604719f82d3SEliot Blennerhassett 	/* wait for dwAckValue */
1605719f82d3SEliot Blennerhassett 	timeout = TIMEOUT;
1606719f82d3SEliot Blennerhassett 	while (--timeout) {
1607719f82d3SEliot Blennerhassett 		/* read the ack mailbox */
1608719f82d3SEliot Blennerhassett 		ack = hpi_read_word(pdo, HPI_HIF_ADDR(dsp_ack));
1609719f82d3SEliot Blennerhassett 		if (ack == ack_value)
1610719f82d3SEliot Blennerhassett 			break;
1611719f82d3SEliot Blennerhassett 		if ((ack & HPI_HIF_ERROR_MASK)
1612719f82d3SEliot Blennerhassett 			&& !hpi6000_check_PCI2040_error_flag(pao, H6READ))
1613719f82d3SEliot Blennerhassett 			break;
1614719f82d3SEliot Blennerhassett 		/*for (i=0;i<1000;i++) */
1615719f82d3SEliot Blennerhassett 		/*      dwPause=i+1; */
1616719f82d3SEliot Blennerhassett 	}
1617719f82d3SEliot Blennerhassett 	if (ack & HPI_HIF_ERROR_MASK)
1618719f82d3SEliot Blennerhassett 		/* indicates bad read from DSP -
1619719f82d3SEliot Blennerhassett 		   typically 0xffffff is read for some reason */
1620719f82d3SEliot Blennerhassett 		ack = HPI_HIF_ERROR_MASK;
1621719f82d3SEliot Blennerhassett 
1622719f82d3SEliot Blennerhassett 	if (timeout == 0)
1623719f82d3SEliot Blennerhassett 		ack = HPI_HIF_ERROR_MASK;
1624719f82d3SEliot Blennerhassett 	return (short)ack;
1625719f82d3SEliot Blennerhassett }
1626719f82d3SEliot Blennerhassett 
hpi6000_update_control_cache(struct hpi_adapter_obj * pao,struct hpi_message * phm)1627719f82d3SEliot Blennerhassett static short hpi6000_update_control_cache(struct hpi_adapter_obj *pao,
1628719f82d3SEliot Blennerhassett 	struct hpi_message *phm)
1629719f82d3SEliot Blennerhassett {
1630719f82d3SEliot Blennerhassett 	const u16 dsp_index = 0;
16317036b92dSEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
1632719f82d3SEliot Blennerhassett 	struct dsp_obj *pdo = &phw->ado[dsp_index];
1633719f82d3SEliot Blennerhassett 	u32 timeout;
1634719f82d3SEliot Blennerhassett 	u32 cache_dirty_flag;
1635719f82d3SEliot Blennerhassett 	u16 err;
1636719f82d3SEliot Blennerhassett 
1637719f82d3SEliot Blennerhassett 	hpios_dsplock_lock(pao);
1638719f82d3SEliot Blennerhassett 
1639719f82d3SEliot Blennerhassett 	timeout = TIMEOUT;
1640719f82d3SEliot Blennerhassett 	do {
1641719f82d3SEliot Blennerhassett 		cache_dirty_flag =
1642719f82d3SEliot Blennerhassett 			hpi_read_word((struct dsp_obj *)pdo,
1643719f82d3SEliot Blennerhassett 			HPI_HIF_ADDR(control_cache_is_dirty));
1644719f82d3SEliot Blennerhassett 	} while (hpi6000_check_PCI2040_error_flag(pao, H6READ) && --timeout);
1645719f82d3SEliot Blennerhassett 	if (!timeout) {
1646719f82d3SEliot Blennerhassett 		err = HPI6000_ERROR_CONTROL_CACHE_PARAMS;
1647719f82d3SEliot Blennerhassett 		goto unlock;
1648719f82d3SEliot Blennerhassett 	}
1649719f82d3SEliot Blennerhassett 
1650719f82d3SEliot Blennerhassett 	if (cache_dirty_flag) {
1651719f82d3SEliot Blennerhassett 		/* read the cached controls */
1652719f82d3SEliot Blennerhassett 		u32 address;
1653719f82d3SEliot Blennerhassett 		u32 length;
1654719f82d3SEliot Blennerhassett 
1655719f82d3SEliot Blennerhassett 		timeout = TIMEOUT;
1656719f82d3SEliot Blennerhassett 		if (pdo->control_cache_address_on_dsp == 0) {
1657719f82d3SEliot Blennerhassett 			do {
1658719f82d3SEliot Blennerhassett 				address =
1659719f82d3SEliot Blennerhassett 					hpi_read_word((struct dsp_obj *)pdo,
1660719f82d3SEliot Blennerhassett 					HPI_HIF_ADDR(control_cache_address));
1661719f82d3SEliot Blennerhassett 
1662719f82d3SEliot Blennerhassett 				length = hpi_read_word((struct dsp_obj *)pdo,
1663719f82d3SEliot Blennerhassett 					HPI_HIF_ADDR
1664719f82d3SEliot Blennerhassett 					(control_cache_size_in_bytes));
1665719f82d3SEliot Blennerhassett 			} while (hpi6000_check_PCI2040_error_flag(pao, H6READ)
1666719f82d3SEliot Blennerhassett 				&& --timeout);
1667719f82d3SEliot Blennerhassett 			if (!timeout) {
1668719f82d3SEliot Blennerhassett 				err = HPI6000_ERROR_CONTROL_CACHE_ADDRLEN;
1669719f82d3SEliot Blennerhassett 				goto unlock;
1670719f82d3SEliot Blennerhassett 			}
1671719f82d3SEliot Blennerhassett 			pdo->control_cache_address_on_dsp = address;
1672719f82d3SEliot Blennerhassett 			pdo->control_cache_length_on_dsp = length;
1673719f82d3SEliot Blennerhassett 		} else {
1674719f82d3SEliot Blennerhassett 			address = pdo->control_cache_address_on_dsp;
1675719f82d3SEliot Blennerhassett 			length = pdo->control_cache_length_on_dsp;
1676719f82d3SEliot Blennerhassett 		}
1677719f82d3SEliot Blennerhassett 
1678719f82d3SEliot Blennerhassett 		if (hpi6000_dsp_block_read32(pao, dsp_index, address,
1679719f82d3SEliot Blennerhassett 				(u32 *)&phw->control_cache[0],
1680719f82d3SEliot Blennerhassett 				length / sizeof(u32))) {
1681719f82d3SEliot Blennerhassett 			err = HPI6000_ERROR_CONTROL_CACHE_READ;
1682719f82d3SEliot Blennerhassett 			goto unlock;
1683719f82d3SEliot Blennerhassett 		}
1684719f82d3SEliot Blennerhassett 		do {
1685719f82d3SEliot Blennerhassett 			hpi_write_word((struct dsp_obj *)pdo,
1686719f82d3SEliot Blennerhassett 				HPI_HIF_ADDR(control_cache_is_dirty), 0);
1687719f82d3SEliot Blennerhassett 			/* flush the FIFO */
1688719f82d3SEliot Blennerhassett 			hpi_set_address(pdo, HPI_HIF_ADDR(host_cmd));
1689719f82d3SEliot Blennerhassett 		} while (hpi6000_check_PCI2040_error_flag(pao, H6WRITE)
1690719f82d3SEliot Blennerhassett 			&& --timeout);
1691719f82d3SEliot Blennerhassett 		if (!timeout) {
1692719f82d3SEliot Blennerhassett 			err = HPI6000_ERROR_CONTROL_CACHE_FLUSH;
1693719f82d3SEliot Blennerhassett 			goto unlock;
1694719f82d3SEliot Blennerhassett 		}
1695719f82d3SEliot Blennerhassett 
1696719f82d3SEliot Blennerhassett 	}
1697719f82d3SEliot Blennerhassett 	err = 0;
1698719f82d3SEliot Blennerhassett 
1699719f82d3SEliot Blennerhassett unlock:
1700719f82d3SEliot Blennerhassett 	hpios_dsplock_unlock(pao);
1701719f82d3SEliot Blennerhassett 	return err;
1702719f82d3SEliot Blennerhassett }
1703719f82d3SEliot Blennerhassett 
1704719f82d3SEliot Blennerhassett /** Get dsp index for multi DSP adapters only */
get_dsp_index(struct hpi_adapter_obj * pao,struct hpi_message * phm)1705719f82d3SEliot Blennerhassett static u16 get_dsp_index(struct hpi_adapter_obj *pao, struct hpi_message *phm)
1706719f82d3SEliot Blennerhassett {
1707719f82d3SEliot Blennerhassett 	u16 ret = 0;
1708719f82d3SEliot Blennerhassett 	switch (phm->object) {
1709719f82d3SEliot Blennerhassett 	case HPI_OBJ_ISTREAM:
1710719f82d3SEliot Blennerhassett 		if (phm->obj_index < 2)
1711719f82d3SEliot Blennerhassett 			ret = 1;
1712719f82d3SEliot Blennerhassett 		break;
1713719f82d3SEliot Blennerhassett 	case HPI_OBJ_PROFILE:
1714719f82d3SEliot Blennerhassett 		ret = phm->obj_index;
1715719f82d3SEliot Blennerhassett 		break;
1716719f82d3SEliot Blennerhassett 	default:
1717719f82d3SEliot Blennerhassett 		break;
1718719f82d3SEliot Blennerhassett 	}
1719719f82d3SEliot Blennerhassett 	return ret;
1720719f82d3SEliot Blennerhassett }
1721719f82d3SEliot Blennerhassett 
1722719f82d3SEliot Blennerhassett /** Complete transaction with DSP
1723719f82d3SEliot Blennerhassett 
1724719f82d3SEliot Blennerhassett Send message, get response, send or get stream data if any.
1725719f82d3SEliot Blennerhassett */
hw_message(struct hpi_adapter_obj * pao,struct hpi_message * phm,struct hpi_response * phr)1726719f82d3SEliot Blennerhassett static void hw_message(struct hpi_adapter_obj *pao, struct hpi_message *phm,
1727719f82d3SEliot Blennerhassett 	struct hpi_response *phr)
1728719f82d3SEliot Blennerhassett {
1729719f82d3SEliot Blennerhassett 	u16 error = 0;
1730719f82d3SEliot Blennerhassett 	u16 dsp_index = 0;
17317036b92dSEliot Blennerhassett 	struct hpi_hw_obj *phw = pao->priv;
17327036b92dSEliot Blennerhassett 	u16 num_dsp = phw->num_dsp;
1733719f82d3SEliot Blennerhassett 
1734719f82d3SEliot Blennerhassett 	if (num_dsp < 2)
1735719f82d3SEliot Blennerhassett 		dsp_index = 0;
1736719f82d3SEliot Blennerhassett 	else {
1737719f82d3SEliot Blennerhassett 		dsp_index = get_dsp_index(pao, phm);
1738719f82d3SEliot Blennerhassett 
1739719f82d3SEliot Blennerhassett 		/* is this  checked on the DSP anyway? */
1740719f82d3SEliot Blennerhassett 		if ((phm->function == HPI_ISTREAM_GROUP_ADD)
1741719f82d3SEliot Blennerhassett 			|| (phm->function == HPI_OSTREAM_GROUP_ADD)) {
1742719f82d3SEliot Blennerhassett 			struct hpi_message hm;
1743719f82d3SEliot Blennerhassett 			u16 add_index;
1744719f82d3SEliot Blennerhassett 			hm.obj_index = phm->u.d.u.stream.stream_index;
1745719f82d3SEliot Blennerhassett 			hm.object = phm->u.d.u.stream.object_type;
1746719f82d3SEliot Blennerhassett 			add_index = get_dsp_index(pao, &hm);
1747719f82d3SEliot Blennerhassett 			if (add_index != dsp_index) {
1748719f82d3SEliot Blennerhassett 				phr->error = HPI_ERROR_NO_INTERDSP_GROUPS;
1749719f82d3SEliot Blennerhassett 				return;
1750719f82d3SEliot Blennerhassett 			}
1751719f82d3SEliot Blennerhassett 		}
1752719f82d3SEliot Blennerhassett 	}
1753bca516bfSEliot Blennerhassett 
1754bca516bfSEliot Blennerhassett 	hpios_dsplock_lock(pao);
1755719f82d3SEliot Blennerhassett 	error = hpi6000_message_response_sequence(pao, dsp_index, phm, phr);
1756719f82d3SEliot Blennerhassett 
17570a00044dSEliot Blennerhassett 	if (error)	/* something failed in the HPI/DSP interface */
1758719f82d3SEliot Blennerhassett 		goto err;
1759719f82d3SEliot Blennerhassett 
17600a00044dSEliot Blennerhassett 	if (phr->error)	/* something failed in the DSP */
17610a00044dSEliot Blennerhassett 		goto out;
1762719f82d3SEliot Blennerhassett 
1763719f82d3SEliot Blennerhassett 	switch (phm->function) {
1764719f82d3SEliot Blennerhassett 	case HPI_OSTREAM_WRITE:
1765719f82d3SEliot Blennerhassett 	case HPI_ISTREAM_ANC_WRITE:
1766719f82d3SEliot Blennerhassett 		error = hpi6000_send_data(pao, dsp_index, phm, phr);
1767719f82d3SEliot Blennerhassett 		break;
1768719f82d3SEliot Blennerhassett 	case HPI_ISTREAM_READ:
1769719f82d3SEliot Blennerhassett 	case HPI_OSTREAM_ANC_READ:
1770719f82d3SEliot Blennerhassett 		error = hpi6000_get_data(pao, dsp_index, phm, phr);
1771719f82d3SEliot Blennerhassett 		break;
1772719f82d3SEliot Blennerhassett 	case HPI_ADAPTER_GET_ASSERT:
17733285ea10SEliot Blennerhassett 		phr->u.ax.assert.dsp_index = 0;	/* dsp 0 default */
1774719f82d3SEliot Blennerhassett 		if (num_dsp == 2) {
17753285ea10SEliot Blennerhassett 			if (!phr->u.ax.assert.count) {
1776719f82d3SEliot Blennerhassett 				/* no assert from dsp 0, check dsp 1 */
1777719f82d3SEliot Blennerhassett 				error = hpi6000_message_response_sequence(pao,
1778719f82d3SEliot Blennerhassett 					1, phm, phr);
17793285ea10SEliot Blennerhassett 				phr->u.ax.assert.dsp_index = 1;
1780719f82d3SEliot Blennerhassett 			}
1781719f82d3SEliot Blennerhassett 		}
1782719f82d3SEliot Blennerhassett 	}
1783719f82d3SEliot Blennerhassett 
1784719f82d3SEliot Blennerhassett err:
17850a00044dSEliot Blennerhassett 	if (error) {
17860a00044dSEliot Blennerhassett 		if (error >= HPI_ERROR_BACKEND_BASE) {
17870a00044dSEliot Blennerhassett 			phr->error = HPI_ERROR_DSP_COMMUNICATION;
17880a00044dSEliot Blennerhassett 			phr->specific_error = error;
17890a00044dSEliot Blennerhassett 		} else {
17900a00044dSEliot Blennerhassett 			phr->error = error;
17910a00044dSEliot Blennerhassett 		}
17920a00044dSEliot Blennerhassett 
17930a00044dSEliot Blennerhassett 		/* just the header of the response is valid */
17940a00044dSEliot Blennerhassett 		phr->size = sizeof(struct hpi_response_header);
17950a00044dSEliot Blennerhassett 	}
17960a00044dSEliot Blennerhassett out:
1797719f82d3SEliot Blennerhassett 	hpios_dsplock_unlock(pao);
1798719f82d3SEliot Blennerhassett 	return;
1799719f82d3SEliot Blennerhassett }
1800