diff options
Diffstat (limited to 'drivers/staging/ath6kl/bmi')
-rw-r--r-- | drivers/staging/ath6kl/bmi/include/bmi_internal.h | 54 | ||||
-rw-r--r-- | drivers/staging/ath6kl/bmi/src/bmi.c | 1010 |
2 files changed, 1064 insertions, 0 deletions
diff --git a/drivers/staging/ath6kl/bmi/include/bmi_internal.h b/drivers/staging/ath6kl/bmi/include/bmi_internal.h new file mode 100644 index 00000000000..8e2577074d6 --- /dev/null +++ b/drivers/staging/ath6kl/bmi/include/bmi_internal.h | |||
@@ -0,0 +1,54 @@ | |||
1 | //------------------------------------------------------------------------------ | ||
2 | // Copyright (c) 2004-2010 Atheros Communications Inc. | ||
3 | // All rights reserved. | ||
4 | // | ||
5 | // | ||
6 | // Permission to use, copy, modify, and/or distribute this software for any | ||
7 | // purpose with or without fee is hereby granted, provided that the above | ||
8 | // copyright notice and this permission notice appear in all copies. | ||
9 | // | ||
10 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
11 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
12 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
13 | // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
14 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
15 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
16 | // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
17 | // | ||
18 | // | ||
19 | //------------------------------------------------------------------------------ | ||
20 | //============================================================================== | ||
21 | // | ||
22 | // Author(s): ="Atheros" | ||
23 | //============================================================================== | ||
24 | #ifndef BMI_INTERNAL_H | ||
25 | #define BMI_INTERNAL_H | ||
26 | |||
27 | #include "a_config.h" | ||
28 | #include "athdefs.h" | ||
29 | #include "a_osapi.h" | ||
30 | #define ATH_MODULE_NAME bmi | ||
31 | #include "a_debug.h" | ||
32 | #include "hw/mbox_host_reg.h" | ||
33 | #include "bmi_msg.h" | ||
34 | |||
35 | #define ATH_DEBUG_BMI ATH_DEBUG_MAKE_MODULE_MASK(0) | ||
36 | |||
37 | |||
38 | #define BMI_COMMUNICATION_TIMEOUT 100000 | ||
39 | |||
40 | /* ------ Global Variable Declarations ------- */ | ||
41 | static bool bmiDone; | ||
42 | |||
43 | int | ||
44 | bmiBufferSend(struct hif_device *device, | ||
45 | u8 *buffer, | ||
46 | u32 length); | ||
47 | |||
48 | int | ||
49 | bmiBufferReceive(struct hif_device *device, | ||
50 | u8 *buffer, | ||
51 | u32 length, | ||
52 | bool want_timeout); | ||
53 | |||
54 | #endif | ||
diff --git a/drivers/staging/ath6kl/bmi/src/bmi.c b/drivers/staging/ath6kl/bmi/src/bmi.c new file mode 100644 index 00000000000..f1f085eba9c --- /dev/null +++ b/drivers/staging/ath6kl/bmi/src/bmi.c | |||
@@ -0,0 +1,1010 @@ | |||
1 | //------------------------------------------------------------------------------ | ||
2 | // <copyright file="bmi.c" company="Atheros"> | ||
3 | // Copyright (c) 2004-2010 Atheros Corporation. All rights reserved. | ||
4 | // | ||
5 | // | ||
6 | // Permission to use, copy, modify, and/or distribute this software for any | ||
7 | // purpose with or without fee is hereby granted, provided that the above | ||
8 | // copyright notice and this permission notice appear in all copies. | ||
9 | // | ||
10 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
11 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
12 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
13 | // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
14 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
15 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
16 | // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
17 | // | ||
18 | // | ||
19 | //------------------------------------------------------------------------------ | ||
20 | //============================================================================== | ||
21 | // | ||
22 | // Author(s): ="Atheros" | ||
23 | //============================================================================== | ||
24 | |||
25 | |||
26 | #ifdef THREAD_X | ||
27 | #include <string.h> | ||
28 | #endif | ||
29 | |||
30 | #include "hif.h" | ||
31 | #include "bmi.h" | ||
32 | #include "htc_api.h" | ||
33 | #include "bmi_internal.h" | ||
34 | |||
35 | #ifdef ATH_DEBUG_MODULE | ||
36 | static struct ath_debug_mask_description bmi_debug_desc[] = { | ||
37 | { ATH_DEBUG_BMI , "BMI Tracing"}, | ||
38 | }; | ||
39 | |||
40 | ATH_DEBUG_INSTANTIATE_MODULE_VAR(bmi, | ||
41 | "bmi", | ||
42 | "Boot Manager Interface", | ||
43 | ATH_DEBUG_MASK_DEFAULTS, | ||
44 | ATH_DEBUG_DESCRIPTION_COUNT(bmi_debug_desc), | ||
45 | bmi_debug_desc); | ||
46 | |||
47 | #endif | ||
48 | |||
49 | /* | ||
50 | Although we had envisioned BMI to run on top of HTC, this is not how the | ||
51 | final implementation ended up. On the Target side, BMI is a part of the BSP | ||
52 | and does not use the HTC protocol nor even DMA -- it is intentionally kept | ||
53 | very simple. | ||
54 | */ | ||
55 | |||
56 | static bool pendingEventsFuncCheck = false; | ||
57 | static u32 *pBMICmdCredits; | ||
58 | static u8 *pBMICmdBuf; | ||
59 | #define MAX_BMI_CMDBUF_SZ (BMI_DATASZ_MAX + \ | ||
60 | sizeof(u32) /* cmd */ + \ | ||
61 | sizeof(u32) /* addr */ + \ | ||
62 | sizeof(u32))/* length */ | ||
63 | #define BMI_COMMAND_FITS(sz) ((sz) <= MAX_BMI_CMDBUF_SZ) | ||
64 | |||
65 | /* APIs visible to the driver */ | ||
66 | void | ||
67 | BMIInit(void) | ||
68 | { | ||
69 | bmiDone = false; | ||
70 | pendingEventsFuncCheck = false; | ||
71 | |||
72 | /* | ||
73 | * On some platforms, it's not possible to DMA to a static variable | ||
74 | * in a device driver (e.g. Linux loadable driver module). | ||
75 | * So we need to A_MALLOC space for "command credits" and for commands. | ||
76 | * | ||
77 | * Note: implicitly relies on A_MALLOC to provide a buffer that is | ||
78 | * suitable for DMA (or PIO). This buffer will be passed down the | ||
79 | * bus stack. | ||
80 | */ | ||
81 | if (!pBMICmdCredits) { | ||
82 | pBMICmdCredits = (u32 *)A_MALLOC_NOWAIT(4); | ||
83 | A_ASSERT(pBMICmdCredits); | ||
84 | } | ||
85 | |||
86 | if (!pBMICmdBuf) { | ||
87 | pBMICmdBuf = (u8 *)A_MALLOC_NOWAIT(MAX_BMI_CMDBUF_SZ); | ||
88 | A_ASSERT(pBMICmdBuf); | ||
89 | } | ||
90 | |||
91 | A_REGISTER_MODULE_DEBUG_INFO(bmi); | ||
92 | } | ||
93 | |||
94 | void | ||
95 | BMICleanup(void) | ||
96 | { | ||
97 | if (pBMICmdCredits) { | ||
98 | kfree(pBMICmdCredits); | ||
99 | pBMICmdCredits = NULL; | ||
100 | } | ||
101 | |||
102 | if (pBMICmdBuf) { | ||
103 | kfree(pBMICmdBuf); | ||
104 | pBMICmdBuf = NULL; | ||
105 | } | ||
106 | } | ||
107 | |||
108 | int | ||
109 | BMIDone(struct hif_device *device) | ||
110 | { | ||
111 | int status; | ||
112 | u32 cid; | ||
113 | |||
114 | if (bmiDone) { | ||
115 | AR_DEBUG_PRINTF (ATH_DEBUG_BMI, ("BMIDone skipped\n")); | ||
116 | return 0; | ||
117 | } | ||
118 | |||
119 | AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI Done: Enter (device: 0x%p)\n", device)); | ||
120 | bmiDone = true; | ||
121 | cid = BMI_DONE; | ||
122 | |||
123 | status = bmiBufferSend(device, (u8 *)&cid, sizeof(cid)); | ||
124 | if (status) { | ||
125 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to write to the device\n")); | ||
126 | return A_ERROR; | ||
127 | } | ||
128 | |||
129 | if (pBMICmdCredits) { | ||
130 | kfree(pBMICmdCredits); | ||
131 | pBMICmdCredits = NULL; | ||
132 | } | ||
133 | |||
134 | if (pBMICmdBuf) { | ||
135 | kfree(pBMICmdBuf); | ||
136 | pBMICmdBuf = NULL; | ||
137 | } | ||
138 | |||
139 | AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI Done: Exit\n")); | ||
140 | |||
141 | return 0; | ||
142 | } | ||
143 | |||
144 | int | ||
145 | BMIGetTargetInfo(struct hif_device *device, struct bmi_target_info *targ_info) | ||
146 | { | ||
147 | int status; | ||
148 | u32 cid; | ||
149 | |||
150 | if (bmiDone) { | ||
151 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Command disallowed\n")); | ||
152 | return A_ERROR; | ||
153 | } | ||
154 | |||
155 | AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI Get Target Info: Enter (device: 0x%p)\n", device)); | ||
156 | cid = BMI_GET_TARGET_INFO; | ||
157 | |||
158 | status = bmiBufferSend(device, (u8 *)&cid, sizeof(cid)); | ||
159 | if (status) { | ||
160 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to write to the device\n")); | ||
161 | return A_ERROR; | ||
162 | } | ||
163 | |||
164 | status = bmiBufferReceive(device, (u8 *)&targ_info->target_ver, | ||
165 | sizeof(targ_info->target_ver), true); | ||
166 | if (status) { | ||
167 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to read Target Version from the device\n")); | ||
168 | return A_ERROR; | ||
169 | } | ||
170 | |||
171 | if (targ_info->target_ver == TARGET_VERSION_SENTINAL) { | ||
172 | /* Determine how many bytes are in the Target's targ_info */ | ||
173 | status = bmiBufferReceive(device, (u8 *)&targ_info->target_info_byte_count, | ||
174 | sizeof(targ_info->target_info_byte_count), true); | ||
175 | if (status) { | ||
176 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to read Target Info Byte Count from the device\n")); | ||
177 | return A_ERROR; | ||
178 | } | ||
179 | |||
180 | /* | ||
181 | * The Target's targ_info doesn't match the Host's targ_info. | ||
182 | * We need to do some backwards compatibility work to make this OK. | ||
183 | */ | ||
184 | A_ASSERT(targ_info->target_info_byte_count == sizeof(*targ_info)); | ||
185 | |||
186 | /* Read the remainder of the targ_info */ | ||
187 | status = bmiBufferReceive(device, | ||
188 | ((u8 *)targ_info)+sizeof(targ_info->target_info_byte_count), | ||
189 | sizeof(*targ_info)-sizeof(targ_info->target_info_byte_count), true); | ||
190 | if (status) { | ||
191 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to read Target Info (%d bytes) from the device\n", | ||
192 | targ_info->target_info_byte_count)); | ||
193 | return A_ERROR; | ||
194 | } | ||
195 | } | ||
196 | |||
197 | AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI Get Target Info: Exit (ver: 0x%x type: 0x%x)\n", | ||
198 | targ_info->target_ver, targ_info->target_type)); | ||
199 | |||
200 | return 0; | ||
201 | } | ||
202 | |||
203 | int | ||
204 | BMIReadMemory(struct hif_device *device, | ||
205 | u32 address, | ||
206 | u8 *buffer, | ||
207 | u32 length) | ||
208 | { | ||
209 | u32 cid; | ||
210 | int status; | ||
211 | u32 offset; | ||
212 | u32 remaining, rxlen; | ||
213 | |||
214 | A_ASSERT(BMI_COMMAND_FITS(BMI_DATASZ_MAX + sizeof(cid) + sizeof(address) + sizeof(length))); | ||
215 | memset (pBMICmdBuf, 0, BMI_DATASZ_MAX + sizeof(cid) + sizeof(address) + sizeof(length)); | ||
216 | |||
217 | if (bmiDone) { | ||
218 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Command disallowed\n")); | ||
219 | return A_ERROR; | ||
220 | } | ||
221 | |||
222 | AR_DEBUG_PRINTF(ATH_DEBUG_BMI, | ||
223 | ("BMI Read Memory: Enter (device: 0x%p, address: 0x%x, length: %d)\n", | ||
224 | device, address, length)); | ||
225 | |||
226 | cid = BMI_READ_MEMORY; | ||
227 | |||
228 | remaining = length; | ||
229 | |||
230 | while (remaining) | ||
231 | { | ||
232 | rxlen = (remaining < BMI_DATASZ_MAX) ? remaining : BMI_DATASZ_MAX; | ||
233 | offset = 0; | ||
234 | memcpy(&(pBMICmdBuf[offset]), &cid, sizeof(cid)); | ||
235 | offset += sizeof(cid); | ||
236 | memcpy(&(pBMICmdBuf[offset]), &address, sizeof(address)); | ||
237 | offset += sizeof(address); | ||
238 | memcpy(&(pBMICmdBuf[offset]), &rxlen, sizeof(rxlen)); | ||
239 | offset += sizeof(length); | ||
240 | |||
241 | status = bmiBufferSend(device, pBMICmdBuf, offset); | ||
242 | if (status) { | ||
243 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to write to the device\n")); | ||
244 | return A_ERROR; | ||
245 | } | ||
246 | status = bmiBufferReceive(device, pBMICmdBuf, rxlen, true); | ||
247 | if (status) { | ||
248 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to read from the device\n")); | ||
249 | return A_ERROR; | ||
250 | } | ||
251 | memcpy(&buffer[length - remaining], pBMICmdBuf, rxlen); | ||
252 | remaining -= rxlen; address += rxlen; | ||
253 | } | ||
254 | |||
255 | AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI Read Memory: Exit\n")); | ||
256 | return 0; | ||
257 | } | ||
258 | |||
259 | int | ||
260 | BMIWriteMemory(struct hif_device *device, | ||
261 | u32 address, | ||
262 | u8 *buffer, | ||
263 | u32 length) | ||
264 | { | ||
265 | u32 cid; | ||
266 | int status; | ||
267 | u32 offset; | ||
268 | u32 remaining, txlen; | ||
269 | const u32 header = sizeof(cid) + sizeof(address) + sizeof(length); | ||
270 | u8 alignedBuffer[BMI_DATASZ_MAX]; | ||
271 | u8 *src; | ||
272 | |||
273 | A_ASSERT(BMI_COMMAND_FITS(BMI_DATASZ_MAX + header)); | ||
274 | memset (pBMICmdBuf, 0, BMI_DATASZ_MAX + header); | ||
275 | |||
276 | if (bmiDone) { | ||
277 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Command disallowed\n")); | ||
278 | return A_ERROR; | ||
279 | } | ||
280 | |||
281 | AR_DEBUG_PRINTF(ATH_DEBUG_BMI, | ||
282 | ("BMI Write Memory: Enter (device: 0x%p, address: 0x%x, length: %d)\n", | ||
283 | device, address, length)); | ||
284 | |||
285 | cid = BMI_WRITE_MEMORY; | ||
286 | |||
287 | remaining = length; | ||
288 | while (remaining) | ||
289 | { | ||
290 | src = &buffer[length - remaining]; | ||
291 | if (remaining < (BMI_DATASZ_MAX - header)) { | ||
292 | if (remaining & 3) { | ||
293 | /* align it with 4 bytes */ | ||
294 | remaining = remaining + (4 - (remaining & 3)); | ||
295 | memcpy(alignedBuffer, src, remaining); | ||
296 | src = alignedBuffer; | ||
297 | } | ||
298 | txlen = remaining; | ||
299 | } else { | ||
300 | txlen = (BMI_DATASZ_MAX - header); | ||
301 | } | ||
302 | offset = 0; | ||
303 | memcpy(&(pBMICmdBuf[offset]), &cid, sizeof(cid)); | ||
304 | offset += sizeof(cid); | ||
305 | memcpy(&(pBMICmdBuf[offset]), &address, sizeof(address)); | ||
306 | offset += sizeof(address); | ||
307 | memcpy(&(pBMICmdBuf[offset]), &txlen, sizeof(txlen)); | ||
308 | offset += sizeof(txlen); | ||
309 | memcpy(&(pBMICmdBuf[offset]), src, txlen); | ||
310 | offset += txlen; | ||
311 | status = bmiBufferSend(device, pBMICmdBuf, offset); | ||
312 | if (status) { | ||
313 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to write to the device\n")); | ||
314 | return A_ERROR; | ||
315 | } | ||
316 | remaining -= txlen; address += txlen; | ||
317 | } | ||
318 | |||
319 | AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI Write Memory: Exit\n")); | ||
320 | |||
321 | return 0; | ||
322 | } | ||
323 | |||
324 | int | ||
325 | BMIExecute(struct hif_device *device, | ||
326 | u32 address, | ||
327 | u32 *param) | ||
328 | { | ||
329 | u32 cid; | ||
330 | int status; | ||
331 | u32 offset; | ||
332 | |||
333 | A_ASSERT(BMI_COMMAND_FITS(sizeof(cid) + sizeof(address) + sizeof(param))); | ||
334 | memset (pBMICmdBuf, 0, sizeof(cid) + sizeof(address) + sizeof(param)); | ||
335 | |||
336 | if (bmiDone) { | ||
337 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Command disallowed\n")); | ||
338 | return A_ERROR; | ||
339 | } | ||
340 | |||
341 | AR_DEBUG_PRINTF(ATH_DEBUG_BMI, | ||
342 | ("BMI Execute: Enter (device: 0x%p, address: 0x%x, param: %d)\n", | ||
343 | device, address, *param)); | ||
344 | |||
345 | cid = BMI_EXECUTE; | ||
346 | |||
347 | offset = 0; | ||
348 | memcpy(&(pBMICmdBuf[offset]), &cid, sizeof(cid)); | ||
349 | offset += sizeof(cid); | ||
350 | memcpy(&(pBMICmdBuf[offset]), &address, sizeof(address)); | ||
351 | offset += sizeof(address); | ||
352 | memcpy(&(pBMICmdBuf[offset]), param, sizeof(*param)); | ||
353 | offset += sizeof(*param); | ||
354 | status = bmiBufferSend(device, pBMICmdBuf, offset); | ||
355 | if (status) { | ||
356 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to write to the device\n")); | ||
357 | return A_ERROR; | ||
358 | } | ||
359 | |||
360 | status = bmiBufferReceive(device, pBMICmdBuf, sizeof(*param), false); | ||
361 | if (status) { | ||
362 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to read from the device\n")); | ||
363 | return A_ERROR; | ||
364 | } | ||
365 | |||
366 | memcpy(param, pBMICmdBuf, sizeof(*param)); | ||
367 | |||
368 | AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI Execute: Exit (param: %d)\n", *param)); | ||
369 | return 0; | ||
370 | } | ||
371 | |||
372 | int | ||
373 | BMISetAppStart(struct hif_device *device, | ||
374 | u32 address) | ||
375 | { | ||
376 | u32 cid; | ||
377 | int status; | ||
378 | u32 offset; | ||
379 | |||
380 | A_ASSERT(BMI_COMMAND_FITS(sizeof(cid) + sizeof(address))); | ||
381 | memset (pBMICmdBuf, 0, sizeof(cid) + sizeof(address)); | ||
382 | |||
383 | if (bmiDone) { | ||
384 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Command disallowed\n")); | ||
385 | return A_ERROR; | ||
386 | } | ||
387 | |||
388 | AR_DEBUG_PRINTF(ATH_DEBUG_BMI, | ||
389 | ("BMI Set App Start: Enter (device: 0x%p, address: 0x%x)\n", | ||
390 | device, address)); | ||
391 | |||
392 | cid = BMI_SET_APP_START; | ||
393 | |||
394 | offset = 0; | ||
395 | memcpy(&(pBMICmdBuf[offset]), &cid, sizeof(cid)); | ||
396 | offset += sizeof(cid); | ||
397 | memcpy(&(pBMICmdBuf[offset]), &address, sizeof(address)); | ||
398 | offset += sizeof(address); | ||
399 | status = bmiBufferSend(device, pBMICmdBuf, offset); | ||
400 | if (status) { | ||
401 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to write to the device\n")); | ||
402 | return A_ERROR; | ||
403 | } | ||
404 | |||
405 | AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI Set App Start: Exit\n")); | ||
406 | return 0; | ||
407 | } | ||
408 | |||
409 | int | ||
410 | BMIReadSOCRegister(struct hif_device *device, | ||
411 | u32 address, | ||
412 | u32 *param) | ||
413 | { | ||
414 | u32 cid; | ||
415 | int status; | ||
416 | u32 offset; | ||
417 | |||
418 | A_ASSERT(BMI_COMMAND_FITS(sizeof(cid) + sizeof(address))); | ||
419 | memset (pBMICmdBuf, 0, sizeof(cid) + sizeof(address)); | ||
420 | |||
421 | if (bmiDone) { | ||
422 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Command disallowed\n")); | ||
423 | return A_ERROR; | ||
424 | } | ||
425 | |||
426 | AR_DEBUG_PRINTF(ATH_DEBUG_BMI, | ||
427 | ("BMI Read SOC Register: Enter (device: 0x%p, address: 0x%x)\n", | ||
428 | device, address)); | ||
429 | |||
430 | cid = BMI_READ_SOC_REGISTER; | ||
431 | |||
432 | offset = 0; | ||
433 | memcpy(&(pBMICmdBuf[offset]), &cid, sizeof(cid)); | ||
434 | offset += sizeof(cid); | ||
435 | memcpy(&(pBMICmdBuf[offset]), &address, sizeof(address)); | ||
436 | offset += sizeof(address); | ||
437 | |||
438 | status = bmiBufferSend(device, pBMICmdBuf, offset); | ||
439 | if (status) { | ||
440 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to write to the device\n")); | ||
441 | return A_ERROR; | ||
442 | } | ||
443 | |||
444 | status = bmiBufferReceive(device, pBMICmdBuf, sizeof(*param), true); | ||
445 | if (status) { | ||
446 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to read from the device\n")); | ||
447 | return A_ERROR; | ||
448 | } | ||
449 | memcpy(param, pBMICmdBuf, sizeof(*param)); | ||
450 | |||
451 | AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI Read SOC Register: Exit (value: %d)\n", *param)); | ||
452 | return 0; | ||
453 | } | ||
454 | |||
455 | int | ||
456 | BMIWriteSOCRegister(struct hif_device *device, | ||
457 | u32 address, | ||
458 | u32 param) | ||
459 | { | ||
460 | u32 cid; | ||
461 | int status; | ||
462 | u32 offset; | ||
463 | |||
464 | A_ASSERT(BMI_COMMAND_FITS(sizeof(cid) + sizeof(address) + sizeof(param))); | ||
465 | memset (pBMICmdBuf, 0, sizeof(cid) + sizeof(address) + sizeof(param)); | ||
466 | |||
467 | if (bmiDone) { | ||
468 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Command disallowed\n")); | ||
469 | return A_ERROR; | ||
470 | } | ||
471 | |||
472 | AR_DEBUG_PRINTF(ATH_DEBUG_BMI, | ||
473 | ("BMI Write SOC Register: Enter (device: 0x%p, address: 0x%x, param: %d)\n", | ||
474 | device, address, param)); | ||
475 | |||
476 | cid = BMI_WRITE_SOC_REGISTER; | ||
477 | |||
478 | offset = 0; | ||
479 | memcpy(&(pBMICmdBuf[offset]), &cid, sizeof(cid)); | ||
480 | offset += sizeof(cid); | ||
481 | memcpy(&(pBMICmdBuf[offset]), &address, sizeof(address)); | ||
482 | offset += sizeof(address); | ||
483 | memcpy(&(pBMICmdBuf[offset]), ¶m, sizeof(param)); | ||
484 | offset += sizeof(param); | ||
485 | status = bmiBufferSend(device, pBMICmdBuf, offset); | ||
486 | if (status) { | ||
487 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to write to the device\n")); | ||
488 | return A_ERROR; | ||
489 | } | ||
490 | |||
491 | AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI Read SOC Register: Exit\n")); | ||
492 | return 0; | ||
493 | } | ||
494 | |||
495 | int | ||
496 | BMIrompatchInstall(struct hif_device *device, | ||
497 | u32 ROM_addr, | ||
498 | u32 RAM_addr, | ||
499 | u32 nbytes, | ||
500 | u32 do_activate, | ||
501 | u32 *rompatch_id) | ||
502 | { | ||
503 | u32 cid; | ||
504 | int status; | ||
505 | u32 offset; | ||
506 | |||
507 | A_ASSERT(BMI_COMMAND_FITS(sizeof(cid) + sizeof(ROM_addr) + sizeof(RAM_addr) + | ||
508 | sizeof(nbytes) + sizeof(do_activate))); | ||
509 | memset(pBMICmdBuf, 0, sizeof(cid) + sizeof(ROM_addr) + sizeof(RAM_addr) + | ||
510 | sizeof(nbytes) + sizeof(do_activate)); | ||
511 | |||
512 | if (bmiDone) { | ||
513 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Command disallowed\n")); | ||
514 | return A_ERROR; | ||
515 | } | ||
516 | |||
517 | AR_DEBUG_PRINTF(ATH_DEBUG_BMI, | ||
518 | ("BMI rompatch Install: Enter (device: 0x%p, ROMaddr: 0x%x, RAMaddr: 0x%x length: %d activate: %d)\n", | ||
519 | device, ROM_addr, RAM_addr, nbytes, do_activate)); | ||
520 | |||
521 | cid = BMI_ROMPATCH_INSTALL; | ||
522 | |||
523 | offset = 0; | ||
524 | memcpy(&(pBMICmdBuf[offset]), &cid, sizeof(cid)); | ||
525 | offset += sizeof(cid); | ||
526 | memcpy(&(pBMICmdBuf[offset]), &ROM_addr, sizeof(ROM_addr)); | ||
527 | offset += sizeof(ROM_addr); | ||
528 | memcpy(&(pBMICmdBuf[offset]), &RAM_addr, sizeof(RAM_addr)); | ||
529 | offset += sizeof(RAM_addr); | ||
530 | memcpy(&(pBMICmdBuf[offset]), &nbytes, sizeof(nbytes)); | ||
531 | offset += sizeof(nbytes); | ||
532 | memcpy(&(pBMICmdBuf[offset]), &do_activate, sizeof(do_activate)); | ||
533 | offset += sizeof(do_activate); | ||
534 | status = bmiBufferSend(device, pBMICmdBuf, offset); | ||
535 | if (status) { | ||
536 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to write to the device\n")); | ||
537 | return A_ERROR; | ||
538 | } | ||
539 | |||
540 | status = bmiBufferReceive(device, pBMICmdBuf, sizeof(*rompatch_id), true); | ||
541 | if (status) { | ||
542 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to read from the device\n")); | ||
543 | return A_ERROR; | ||
544 | } | ||
545 | memcpy(rompatch_id, pBMICmdBuf, sizeof(*rompatch_id)); | ||
546 | |||
547 | AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI rompatch Install: (rompatch_id=%d)\n", *rompatch_id)); | ||
548 | return 0; | ||
549 | } | ||
550 | |||
551 | int | ||
552 | BMIrompatchUninstall(struct hif_device *device, | ||
553 | u32 rompatch_id) | ||
554 | { | ||
555 | u32 cid; | ||
556 | int status; | ||
557 | u32 offset; | ||
558 | |||
559 | A_ASSERT(BMI_COMMAND_FITS(sizeof(cid) + sizeof(rompatch_id))); | ||
560 | memset (pBMICmdBuf, 0, sizeof(cid) + sizeof(rompatch_id)); | ||
561 | |||
562 | if (bmiDone) { | ||
563 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Command disallowed\n")); | ||
564 | return A_ERROR; | ||
565 | } | ||
566 | |||
567 | AR_DEBUG_PRINTF(ATH_DEBUG_BMI, | ||
568 | ("BMI rompatch Uninstall: Enter (device: 0x%p, rompatch_id: %d)\n", | ||
569 | device, rompatch_id)); | ||
570 | |||
571 | cid = BMI_ROMPATCH_UNINSTALL; | ||
572 | |||
573 | offset = 0; | ||
574 | memcpy(&(pBMICmdBuf[offset]), &cid, sizeof(cid)); | ||
575 | offset += sizeof(cid); | ||
576 | memcpy(&(pBMICmdBuf[offset]), &rompatch_id, sizeof(rompatch_id)); | ||
577 | offset += sizeof(rompatch_id); | ||
578 | status = bmiBufferSend(device, pBMICmdBuf, offset); | ||
579 | if (status) { | ||
580 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to write to the device\n")); | ||
581 | return A_ERROR; | ||
582 | } | ||
583 | |||
584 | AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI rompatch UNinstall: (rompatch_id=0x%x)\n", rompatch_id)); | ||
585 | return 0; | ||
586 | } | ||
587 | |||
588 | static int | ||
589 | _BMIrompatchChangeActivation(struct hif_device *device, | ||
590 | u32 rompatch_count, | ||
591 | u32 *rompatch_list, | ||
592 | u32 do_activate) | ||
593 | { | ||
594 | u32 cid; | ||
595 | int status; | ||
596 | u32 offset; | ||
597 | u32 length; | ||
598 | |||
599 | A_ASSERT(BMI_COMMAND_FITS(BMI_DATASZ_MAX + sizeof(cid) + sizeof(rompatch_count))); | ||
600 | memset(pBMICmdBuf, 0, BMI_DATASZ_MAX + sizeof(cid) + sizeof(rompatch_count)); | ||
601 | |||
602 | if (bmiDone) { | ||
603 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Command disallowed\n")); | ||
604 | return A_ERROR; | ||
605 | } | ||
606 | |||
607 | AR_DEBUG_PRINTF(ATH_DEBUG_BMI, | ||
608 | ("BMI Change rompatch Activation: Enter (device: 0x%p, count: %d)\n", | ||
609 | device, rompatch_count)); | ||
610 | |||
611 | cid = do_activate ? BMI_ROMPATCH_ACTIVATE : BMI_ROMPATCH_DEACTIVATE; | ||
612 | |||
613 | offset = 0; | ||
614 | memcpy(&(pBMICmdBuf[offset]), &cid, sizeof(cid)); | ||
615 | offset += sizeof(cid); | ||
616 | memcpy(&(pBMICmdBuf[offset]), &rompatch_count, sizeof(rompatch_count)); | ||
617 | offset += sizeof(rompatch_count); | ||
618 | length = rompatch_count * sizeof(*rompatch_list); | ||
619 | memcpy(&(pBMICmdBuf[offset]), rompatch_list, length); | ||
620 | offset += length; | ||
621 | status = bmiBufferSend(device, pBMICmdBuf, offset); | ||
622 | if (status) { | ||
623 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to write to the device\n")); | ||
624 | return A_ERROR; | ||
625 | } | ||
626 | |||
627 | AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI Change rompatch Activation: Exit\n")); | ||
628 | |||
629 | return 0; | ||
630 | } | ||
631 | |||
632 | int | ||
633 | BMIrompatchActivate(struct hif_device *device, | ||
634 | u32 rompatch_count, | ||
635 | u32 *rompatch_list) | ||
636 | { | ||
637 | return _BMIrompatchChangeActivation(device, rompatch_count, rompatch_list, 1); | ||
638 | } | ||
639 | |||
640 | int | ||
641 | BMIrompatchDeactivate(struct hif_device *device, | ||
642 | u32 rompatch_count, | ||
643 | u32 *rompatch_list) | ||
644 | { | ||
645 | return _BMIrompatchChangeActivation(device, rompatch_count, rompatch_list, 0); | ||
646 | } | ||
647 | |||
648 | int | ||
649 | BMILZData(struct hif_device *device, | ||
650 | u8 *buffer, | ||
651 | u32 length) | ||
652 | { | ||
653 | u32 cid; | ||
654 | int status; | ||
655 | u32 offset; | ||
656 | u32 remaining, txlen; | ||
657 | const u32 header = sizeof(cid) + sizeof(length); | ||
658 | |||
659 | A_ASSERT(BMI_COMMAND_FITS(BMI_DATASZ_MAX+header)); | ||
660 | memset (pBMICmdBuf, 0, BMI_DATASZ_MAX+header); | ||
661 | |||
662 | if (bmiDone) { | ||
663 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Command disallowed\n")); | ||
664 | return A_ERROR; | ||
665 | } | ||
666 | |||
667 | AR_DEBUG_PRINTF(ATH_DEBUG_BMI, | ||
668 | ("BMI Send LZ Data: Enter (device: 0x%p, length: %d)\n", | ||
669 | device, length)); | ||
670 | |||
671 | cid = BMI_LZ_DATA; | ||
672 | |||
673 | remaining = length; | ||
674 | while (remaining) | ||
675 | { | ||
676 | txlen = (remaining < (BMI_DATASZ_MAX - header)) ? | ||
677 | remaining : (BMI_DATASZ_MAX - header); | ||
678 | offset = 0; | ||
679 | memcpy(&(pBMICmdBuf[offset]), &cid, sizeof(cid)); | ||
680 | offset += sizeof(cid); | ||
681 | memcpy(&(pBMICmdBuf[offset]), &txlen, sizeof(txlen)); | ||
682 | offset += sizeof(txlen); | ||
683 | memcpy(&(pBMICmdBuf[offset]), &buffer[length - remaining], txlen); | ||
684 | offset += txlen; | ||
685 | status = bmiBufferSend(device, pBMICmdBuf, offset); | ||
686 | if (status) { | ||
687 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to write to the device\n")); | ||
688 | return A_ERROR; | ||
689 | } | ||
690 | remaining -= txlen; | ||
691 | } | ||
692 | |||
693 | AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI LZ Data: Exit\n")); | ||
694 | |||
695 | return 0; | ||
696 | } | ||
697 | |||
698 | int | ||
699 | BMILZStreamStart(struct hif_device *device, | ||
700 | u32 address) | ||
701 | { | ||
702 | u32 cid; | ||
703 | int status; | ||
704 | u32 offset; | ||
705 | |||
706 | A_ASSERT(BMI_COMMAND_FITS(sizeof(cid) + sizeof(address))); | ||
707 | memset (pBMICmdBuf, 0, sizeof(cid) + sizeof(address)); | ||
708 | |||
709 | if (bmiDone) { | ||
710 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Command disallowed\n")); | ||
711 | return A_ERROR; | ||
712 | } | ||
713 | |||
714 | AR_DEBUG_PRINTF(ATH_DEBUG_BMI, | ||
715 | ("BMI LZ Stream Start: Enter (device: 0x%p, address: 0x%x)\n", | ||
716 | device, address)); | ||
717 | |||
718 | cid = BMI_LZ_STREAM_START; | ||
719 | offset = 0; | ||
720 | memcpy(&(pBMICmdBuf[offset]), &cid, sizeof(cid)); | ||
721 | offset += sizeof(cid); | ||
722 | memcpy(&(pBMICmdBuf[offset]), &address, sizeof(address)); | ||
723 | offset += sizeof(address); | ||
724 | status = bmiBufferSend(device, pBMICmdBuf, offset); | ||
725 | if (status) { | ||
726 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to Start LZ Stream to the device\n")); | ||
727 | return A_ERROR; | ||
728 | } | ||
729 | |||
730 | AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI LZ Stream Start: Exit\n")); | ||
731 | |||
732 | return 0; | ||
733 | } | ||
734 | |||
735 | /* BMI Access routines */ | ||
736 | int | ||
737 | bmiBufferSend(struct hif_device *device, | ||
738 | u8 *buffer, | ||
739 | u32 length) | ||
740 | { | ||
741 | int status; | ||
742 | u32 timeout; | ||
743 | u32 address; | ||
744 | u32 mboxAddress[HTC_MAILBOX_NUM_MAX]; | ||
745 | |||
746 | HIFConfigureDevice(device, HIF_DEVICE_GET_MBOX_ADDR, | ||
747 | &mboxAddress[0], sizeof(mboxAddress)); | ||
748 | |||
749 | *pBMICmdCredits = 0; | ||
750 | timeout = BMI_COMMUNICATION_TIMEOUT; | ||
751 | |||
752 | while(timeout-- && !(*pBMICmdCredits)) { | ||
753 | /* Read the counter register to get the command credits */ | ||
754 | address = COUNT_DEC_ADDRESS + (HTC_MAILBOX_NUM_MAX + ENDPOINT1) * 4; | ||
755 | /* hit the credit counter with a 4-byte access, the first byte read will hit the counter and cause | ||
756 | * a decrement, while the remaining 3 bytes has no effect. The rationale behind this is to | ||
757 | * make all HIF accesses 4-byte aligned */ | ||
758 | status = HIFReadWrite(device, address, (u8 *)pBMICmdCredits, 4, | ||
759 | HIF_RD_SYNC_BYTE_INC, NULL); | ||
760 | if (status) { | ||
761 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to decrement the command credit count register\n")); | ||
762 | return A_ERROR; | ||
763 | } | ||
764 | /* the counter is only 8=bits, ignore anything in the upper 3 bytes */ | ||
765 | (*pBMICmdCredits) &= 0xFF; | ||
766 | } | ||
767 | |||
768 | if (*pBMICmdCredits) { | ||
769 | address = mboxAddress[ENDPOINT1]; | ||
770 | status = HIFReadWrite(device, address, buffer, length, | ||
771 | HIF_WR_SYNC_BYTE_INC, NULL); | ||
772 | if (status) { | ||
773 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to send the BMI data to the device\n")); | ||
774 | return A_ERROR; | ||
775 | } | ||
776 | } else { | ||
777 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("BMI Communication timeout - bmiBufferSend\n")); | ||
778 | return A_ERROR; | ||
779 | } | ||
780 | |||
781 | return status; | ||
782 | } | ||
783 | |||
784 | int | ||
785 | bmiBufferReceive(struct hif_device *device, | ||
786 | u8 *buffer, | ||
787 | u32 length, | ||
788 | bool want_timeout) | ||
789 | { | ||
790 | int status; | ||
791 | u32 address; | ||
792 | u32 mboxAddress[HTC_MAILBOX_NUM_MAX]; | ||
793 | struct hif_pending_events_info hifPendingEvents; | ||
794 | static HIF_PENDING_EVENTS_FUNC getPendingEventsFunc = NULL; | ||
795 | |||
796 | if (!pendingEventsFuncCheck) { | ||
797 | /* see if the HIF layer implements an alternative function to get pending events | ||
798 | * do this only once! */ | ||
799 | HIFConfigureDevice(device, | ||
800 | HIF_DEVICE_GET_PENDING_EVENTS_FUNC, | ||
801 | &getPendingEventsFunc, | ||
802 | sizeof(getPendingEventsFunc)); | ||
803 | pendingEventsFuncCheck = true; | ||
804 | } | ||
805 | |||
806 | HIFConfigureDevice(device, HIF_DEVICE_GET_MBOX_ADDR, | ||
807 | &mboxAddress[0], sizeof(mboxAddress)); | ||
808 | |||
809 | /* | ||
810 | * During normal bootup, small reads may be required. | ||
811 | * Rather than issue an HIF Read and then wait as the Target | ||
812 | * adds successive bytes to the FIFO, we wait here until | ||
813 | * we know that response data is available. | ||
814 | * | ||
815 | * This allows us to cleanly timeout on an unexpected | ||
816 | * Target failure rather than risk problems at the HIF level. In | ||
817 | * particular, this avoids SDIO timeouts and possibly garbage | ||
818 | * data on some host controllers. And on an interconnect | ||
819 | * such as Compact Flash (as well as some SDIO masters) which | ||
820 | * does not provide any indication on data timeout, it avoids | ||
821 | * a potential hang or garbage response. | ||
822 | * | ||
823 | * Synchronization is more difficult for reads larger than the | ||
824 | * size of the MBOX FIFO (128B), because the Target is unable | ||
825 | * to push the 129th byte of data until AFTER the Host posts an | ||
826 | * HIF Read and removes some FIFO data. So for large reads the | ||
827 | * Host proceeds to post an HIF Read BEFORE all the data is | ||
828 | * actually available to read. Fortunately, large BMI reads do | ||
829 | * not occur in practice -- they're supported for debug/development. | ||
830 | * | ||
831 | * So Host/Target BMI synchronization is divided into these cases: | ||
832 | * CASE 1: length < 4 | ||
833 | * Should not happen | ||
834 | * | ||
835 | * CASE 2: 4 <= length <= 128 | ||
836 | * Wait for first 4 bytes to be in FIFO | ||
837 | * If CONSERVATIVE_BMI_READ is enabled, also wait for | ||
838 | * a BMI command credit, which indicates that the ENTIRE | ||
839 | * response is available in the the FIFO | ||
840 | * | ||
841 | * CASE 3: length > 128 | ||
842 | * Wait for the first 4 bytes to be in FIFO | ||
843 | * | ||
844 | * For most uses, a small timeout should be sufficient and we will | ||
845 | * usually see a response quickly; but there may be some unusual | ||
846 | * (debug) cases of BMI_EXECUTE where we want an larger timeout. | ||
847 | * For now, we use an unbounded busy loop while waiting for | ||
848 | * BMI_EXECUTE. | ||
849 | * | ||
850 | * If BMI_EXECUTE ever needs to support longer-latency execution, | ||
851 | * especially in production, this code needs to be enhanced to sleep | ||
852 | * and yield. Also note that BMI_COMMUNICATION_TIMEOUT is currently | ||
853 | * a function of Host processor speed. | ||
854 | */ | ||
855 | if (length >= 4) { /* NB: Currently, always true */ | ||
856 | /* | ||
857 | * NB: word_available is declared static for esoteric reasons | ||
858 | * having to do with protection on some OSes. | ||
859 | */ | ||
860 | static u32 word_available; | ||
861 | u32 timeout; | ||
862 | |||
863 | word_available = 0; | ||
864 | timeout = BMI_COMMUNICATION_TIMEOUT; | ||
865 | while((!want_timeout || timeout--) && !word_available) { | ||
866 | |||
867 | if (getPendingEventsFunc != NULL) { | ||
868 | status = getPendingEventsFunc(device, | ||
869 | &hifPendingEvents, | ||
870 | NULL); | ||
871 | if (status) { | ||
872 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("BMI: Failed to get pending events \n")); | ||
873 | break; | ||
874 | } | ||
875 | |||
876 | if (hifPendingEvents.AvailableRecvBytes >= sizeof(u32)) { | ||
877 | word_available = 1; | ||
878 | } | ||
879 | continue; | ||
880 | } | ||
881 | |||
882 | status = HIFReadWrite(device, RX_LOOKAHEAD_VALID_ADDRESS, (u8 *)&word_available, | ||
883 | sizeof(word_available), HIF_RD_SYNC_BYTE_INC, NULL); | ||
884 | if (status) { | ||
885 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to read RX_LOOKAHEAD_VALID register\n")); | ||
886 | return A_ERROR; | ||
887 | } | ||
888 | /* We did a 4-byte read to the same register; all we really want is one bit */ | ||
889 | word_available &= (1 << ENDPOINT1); | ||
890 | } | ||
891 | |||
892 | if (!word_available) { | ||
893 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("BMI Communication timeout - bmiBufferReceive FIFO empty\n")); | ||
894 | return A_ERROR; | ||
895 | } | ||
896 | } | ||
897 | |||
898 | #define CONSERVATIVE_BMI_READ 0 | ||
899 | #if CONSERVATIVE_BMI_READ | ||
900 | /* | ||
901 | * This is an extra-conservative CREDIT check. It guarantees | ||
902 | * that ALL data is available in the FIFO before we start to | ||
903 | * read from the interconnect. | ||
904 | * | ||
905 | * This credit check is useless when firmware chooses to | ||
906 | * allow multiple outstanding BMI Command Credits, since the next | ||
907 | * credit will already be present. To restrict the Target to one | ||
908 | * BMI Command Credit, see HI_OPTION_BMI_CRED_LIMIT. | ||
909 | * | ||
910 | * And for large reads (when HI_OPTION_BMI_CRED_LIMIT is set) | ||
911 | * we cannot wait for the next credit because the Target's FIFO | ||
912 | * will not hold the entire response. So we need the Host to | ||
913 | * start to empty the FIFO sooner. (And again, large reads are | ||
914 | * not used in practice; they are for debug/development only.) | ||
915 | * | ||
916 | * For a more conservative Host implementation (which would be | ||
917 | * safer for a Compact Flash interconnect): | ||
918 | * Set CONSERVATIVE_BMI_READ (above) to 1 | ||
919 | * Set HI_OPTION_BMI_CRED_LIMIT and | ||
920 | * reduce BMI_DATASZ_MAX to 32 or 64 | ||
921 | */ | ||
922 | if ((length > 4) && (length < 128)) { /* check against MBOX FIFO size */ | ||
923 | u32 timeout; | ||
924 | |||
925 | *pBMICmdCredits = 0; | ||
926 | timeout = BMI_COMMUNICATION_TIMEOUT; | ||
927 | while((!want_timeout || timeout--) && !(*pBMICmdCredits) { | ||
928 | /* Read the counter register to get the command credits */ | ||
929 | address = COUNT_ADDRESS + (HTC_MAILBOX_NUM_MAX + ENDPOINT1) * 1; | ||
930 | /* read the counter using a 4-byte read. Since the counter is NOT auto-decrementing, | ||
931 | * we can read this counter multiple times using a non-incrementing address mode. | ||
932 | * The rationale here is to make all HIF accesses a multiple of 4 bytes */ | ||
933 | status = HIFReadWrite(device, address, (u8 *)pBMICmdCredits, sizeof(*pBMICmdCredits), | ||
934 | HIF_RD_SYNC_BYTE_FIX, NULL); | ||
935 | if (status) { | ||
936 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to read the command credit count register\n")); | ||
937 | return A_ERROR; | ||
938 | } | ||
939 | /* we did a 4-byte read to the same count register so mask off upper bytes */ | ||
940 | (*pBMICmdCredits) &= 0xFF; | ||
941 | } | ||
942 | |||
943 | if (!(*pBMICmdCredits)) { | ||
944 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("BMI Communication timeout- bmiBufferReceive no credit\n")); | ||
945 | return A_ERROR; | ||
946 | } | ||
947 | } | ||
948 | #endif | ||
949 | |||
950 | address = mboxAddress[ENDPOINT1]; | ||
951 | status = HIFReadWrite(device, address, buffer, length, HIF_RD_SYNC_BYTE_INC, NULL); | ||
952 | if (status) { | ||
953 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to read the BMI data from the device\n")); | ||
954 | return A_ERROR; | ||
955 | } | ||
956 | |||
957 | return 0; | ||
958 | } | ||
959 | |||
960 | int | ||
961 | BMIFastDownload(struct hif_device *device, u32 address, u8 *buffer, u32 length) | ||
962 | { | ||
963 | int status = A_ERROR; | ||
964 | u32 lastWord = 0; | ||
965 | u32 lastWordOffset = length & ~0x3; | ||
966 | u32 unalignedBytes = length & 0x3; | ||
967 | |||
968 | status = BMILZStreamStart (device, address); | ||
969 | if (status) { | ||
970 | return A_ERROR; | ||
971 | } | ||
972 | |||
973 | if (unalignedBytes) { | ||
974 | /* copy the last word into a zero padded buffer */ | ||
975 | memcpy(&lastWord, &buffer[lastWordOffset], unalignedBytes); | ||
976 | } | ||
977 | |||
978 | status = BMILZData(device, buffer, lastWordOffset); | ||
979 | |||
980 | if (status) { | ||
981 | return A_ERROR; | ||
982 | } | ||
983 | |||
984 | if (unalignedBytes) { | ||
985 | status = BMILZData(device, (u8 *)&lastWord, 4); | ||
986 | } | ||
987 | |||
988 | if (!status) { | ||
989 | // | ||
990 | // Close compressed stream and open a new (fake) one. This serves mainly to flush Target caches. | ||
991 | // | ||
992 | status = BMILZStreamStart (device, 0x00); | ||
993 | if (status) { | ||
994 | return A_ERROR; | ||
995 | } | ||
996 | } | ||
997 | return status; | ||
998 | } | ||
999 | |||
1000 | int | ||
1001 | BMIRawWrite(struct hif_device *device, u8 *buffer, u32 length) | ||
1002 | { | ||
1003 | return bmiBufferSend(device, buffer, length); | ||
1004 | } | ||
1005 | |||
1006 | int | ||
1007 | BMIRawRead(struct hif_device *device, u8 *buffer, u32 length, bool want_timeout) | ||
1008 | { | ||
1009 | return bmiBufferReceive(device, buffer, length, want_timeout); | ||
1010 | } | ||