[x86] add rootwait option to the kernel command line (#6209)
[openwrt.git] / target / linux / s3c24xx / files-2.6.31 / drivers / ar6000 / hif / hif.c
1 /*
2 * @file: hif.c
3 *
4 * @abstract: HIF layer reference implementation for Atheros SDIO stack
5 *
6 * @notice: Copyright (c) 2004-2006 Atheros Communications Inc.
7 *
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation;
12 *
13 * Software distributed under the License is distributed on an "AS
14 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
15 * implied. See the License for the specific language governing
16 * rights and limitations under the License.
17 *
18 *
19 *
20 */
21
22 #include "hif_internal.h"
23
24 /* ------ Static Variables ------ */
25
26 /* ------ Global Variable Declarations ------- */
27 SD_PNP_INFO Ids[] = {
28 {
29 .SDIO_ManufacturerID = MANUFACTURER_ID_AR6001_BASE | 0xB,
30 .SDIO_ManufacturerCode = MANUFACTURER_CODE,
31 .SDIO_FunctionClass = FUNCTION_CLASS,
32 .SDIO_FunctionNo = 1
33 },
34 {
35 .SDIO_ManufacturerID = MANUFACTURER_ID_AR6001_BASE | 0xA,
36 .SDIO_ManufacturerCode = MANUFACTURER_CODE,
37 .SDIO_FunctionClass = FUNCTION_CLASS,
38 .SDIO_FunctionNo = 1
39 },
40 {
41 .SDIO_ManufacturerID = MANUFACTURER_ID_AR6001_BASE | 0x9,
42 .SDIO_ManufacturerCode = MANUFACTURER_CODE,
43 .SDIO_FunctionClass = FUNCTION_CLASS,
44 .SDIO_FunctionNo = 1
45 },
46 {
47 .SDIO_ManufacturerID = MANUFACTURER_ID_AR6001_BASE | 0x8,
48 .SDIO_ManufacturerCode = MANUFACTURER_CODE,
49 .SDIO_FunctionClass = FUNCTION_CLASS,
50 .SDIO_FunctionNo = 1
51 },
52 {
53 .SDIO_ManufacturerID = MANUFACTURER_ID_AR6002_BASE | 0x0,
54 .SDIO_ManufacturerCode = MANUFACTURER_CODE,
55 .SDIO_FunctionClass = FUNCTION_CLASS,
56 .SDIO_FunctionNo = 1
57 },
58 {
59 .SDIO_ManufacturerID = MANUFACTURER_ID_AR6002_BASE | 0x1,
60 .SDIO_ManufacturerCode = MANUFACTURER_CODE,
61 .SDIO_FunctionClass = FUNCTION_CLASS,
62 .SDIO_FunctionNo = 1
63 },
64 {
65 } //list is null termintaed
66 };
67
68 TARGET_FUNCTION_CONTEXT FunctionContext = {
69 .function.Version = CT_SDIO_STACK_VERSION_CODE,
70 .function.pName = "sdio_wlan",
71 .function.MaxDevices = 1,
72 .function.NumDevices = 0,
73 .function.pIds = Ids,
74 .function.pProbe = hifDeviceInserted,
75 .function.pRemove = hifDeviceRemoved,
76 .function.pSuspend = NULL,
77 .function.pResume = NULL,
78 .function.pWake = NULL,
79 .function.pContext = &FunctionContext,
80 };
81
82 HIF_DEVICE hifDevice[HIF_MAX_DEVICES];
83 HTC_CALLBACKS htcCallbacks;
84 BUS_REQUEST busRequest[BUS_REQUEST_MAX_NUM];
85 static BUS_REQUEST *s_busRequestFreeQueue = NULL;
86 OS_CRITICALSECTION lock;
87 extern A_UINT32 onebitmode;
88 extern A_UINT32 busspeedlow;
89
90 #ifdef DEBUG
91 extern A_UINT32 debughif;
92 #define ATH_DEBUG_ERROR 1
93 #define ATH_DEBUG_WARN 2
94 #define ATH_DEBUG_TRACE 3
95 #define _AR_DEBUG_PRINTX_ARG(arg...) arg
96 #define AR_DEBUG_PRINTF(lvl, args)\
97 {if (lvl <= debughif)\
98 A_PRINTF(KERN_ALERT _AR_DEBUG_PRINTX_ARG args);\
99 }
100 #else
101 #define AR_DEBUG_PRINTF(lvl, args)
102 #endif
103
104 static BUS_REQUEST *hifAllocateBusRequest(void);
105 static void hifFreeBusRequest(BUS_REQUEST *busrequest);
106 static THREAD_RETURN insert_helper_func(POSKERNEL_HELPER pHelper);
107 static void ResetAllCards(void);
108
109 /* ------ Functions ------ */
110 int HIFInit(HTC_CALLBACKS *callbacks)
111 {
112 SDIO_STATUS status;
113 DBG_ASSERT(callbacks != NULL);
114
115 /* Store the callback and event handlers */
116 htcCallbacks.deviceInsertedHandler = callbacks->deviceInsertedHandler;
117 htcCallbacks.deviceRemovedHandler = callbacks->deviceRemovedHandler;
118 htcCallbacks.deviceSuspendHandler = callbacks->deviceSuspendHandler;
119 htcCallbacks.deviceResumeHandler = callbacks->deviceResumeHandler;
120 htcCallbacks.deviceWakeupHandler = callbacks->deviceWakeupHandler;
121 htcCallbacks.rwCompletionHandler = callbacks->rwCompletionHandler;
122 htcCallbacks.dsrHandler = callbacks->dsrHandler;
123
124 CriticalSectionInit(&lock);
125
126 /* Register with bus driver core */
127 status = SDIO_RegisterFunction(&FunctionContext.function);
128 DBG_ASSERT(SDIO_SUCCESS(status));
129
130 return(0);
131 }
132
133 A_STATUS
134 HIFReadWrite(HIF_DEVICE *device,
135 A_UINT32 address,
136 A_UCHAR *buffer,
137 A_UINT32 length,
138 A_UINT32 request,
139 void *context)
140 {
141 A_UINT8 rw;
142 A_UINT8 mode;
143 A_UINT8 funcNo;
144 A_UINT8 opcode;
145 A_UINT16 count;
146 SDREQUEST *sdrequest;
147 SDIO_STATUS sdiostatus;
148 BUS_REQUEST *busrequest;
149 A_STATUS status = A_OK;
150
151 DBG_ASSERT(device != NULL);
152 DBG_ASSERT(device->handle != NULL);
153
154 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("Device: %p\n", device));
155
156 do {
157 busrequest = hifAllocateBusRequest();
158 if (busrequest == NULL) {
159 AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, ("HIF Unable to allocate bus request\n"));
160 status = A_NO_RESOURCE;
161 break;
162 }
163
164 sdrequest = busrequest->request;
165 busrequest->context = context;
166
167 sdrequest->pDataBuffer = buffer;
168 if (request & HIF_SYNCHRONOUS) {
169 sdrequest->Flags = SDREQ_FLAGS_RESP_SDIO_R5 | SDREQ_FLAGS_DATA_TRANS;
170 sdrequest->pCompleteContext = NULL;
171 sdrequest->pCompletion = NULL;
172 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("Execution mode: Synchronous\n"));
173 } else if (request & HIF_ASYNCHRONOUS) {
174 sdrequest->Flags = SDREQ_FLAGS_RESP_SDIO_R5 | SDREQ_FLAGS_DATA_TRANS |
175 SDREQ_FLAGS_TRANS_ASYNC;
176 sdrequest->pCompleteContext = busrequest;
177 sdrequest->pCompletion = hifRWCompletionHandler;
178 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("Execution mode: Asynchronous\n"));
179 } else {
180 AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
181 ("Invalid execution mode: 0x%08x\n", request));
182 status = A_EINVAL;
183 break;
184 }
185
186 if (request & HIF_EXTENDED_IO) {
187 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("Command type: CMD53\n"));
188 sdrequest->Command = CMD53;
189 } else {
190 AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
191 ("Invalid command type: 0x%08x\n", request));
192 status = A_EINVAL;
193 break;
194 }
195
196 if (request & HIF_BLOCK_BASIS) {
197 mode = CMD53_BLOCK_BASIS;
198 sdrequest->BlockLen = HIF_MBOX_BLOCK_SIZE;
199 sdrequest->BlockCount = length / HIF_MBOX_BLOCK_SIZE;
200 count = sdrequest->BlockCount;
201 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,
202 ("Block mode (BlockLen: %d, BlockCount: %d)\n",
203 sdrequest->BlockLen, sdrequest->BlockCount));
204 } else if (request & HIF_BYTE_BASIS) {
205 mode = CMD53_BYTE_BASIS;
206 sdrequest->BlockLen = length;
207 sdrequest->BlockCount = 1;
208 count = sdrequest->BlockLen;
209 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,
210 ("Byte mode (BlockLen: %d, BlockCount: %d)\n",
211 sdrequest->BlockLen, sdrequest->BlockCount));
212 } else {
213 AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
214 ("Invalid data mode: 0x%08x\n", request));
215 status = A_EINVAL;
216 break;
217 }
218
219 #if 0
220 /* useful for checking register accesses */
221 if (length & 0x3) {
222 A_PRINTF(KERN_ALERT"HIF (%s) is not a multiple of 4 bytes, addr:0x%X, len:%d\n",
223 request & HIF_WRITE ? "write":"read", address, length);
224 }
225 #endif
226
227 if ((address >= HIF_MBOX_START_ADDR(0)) &&
228 (address <= HIF_MBOX_END_ADDR(3)))
229 {
230
231 DBG_ASSERT(length <= HIF_MBOX_WIDTH);
232
233 /*
234 * Mailbox write. Adjust the address so that the last byte
235 * falls on the EOM address.
236 */
237 address += (HIF_MBOX_WIDTH - length);
238 }
239
240
241
242 if (request & HIF_WRITE) {
243 rw = CMD53_WRITE;
244 sdrequest->Flags |= SDREQ_FLAGS_DATA_WRITE;
245 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("Direction: Write\n"));
246 } else if (request & HIF_READ) {
247 rw = CMD53_READ;
248 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("Direction: Read\n"));
249 } else {
250 AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
251 ("Invalid direction: 0x%08x\n", request));
252 status = A_EINVAL;
253 break;
254 }
255
256 if (request & HIF_FIXED_ADDRESS) {
257 opcode = CMD53_FIXED_ADDRESS;
258 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("Address mode: Fixed\n"));
259 } else if (request & HIF_INCREMENTAL_ADDRESS) {
260 opcode = CMD53_INCR_ADDRESS;
261 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("Address mode: Incremental\n"));
262 } else {
263 AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
264 ("Invalid address mode: 0x%08x\n", request));
265 status = A_EINVAL;
266 break;
267 }
268
269 funcNo = SDDEVICE_GET_SDIO_FUNCNO(device->handle);
270 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("Function number: %d\n", funcNo));
271 SDIO_SET_CMD53_ARG(sdrequest->Argument, rw, funcNo,
272 mode, opcode, address, count);
273
274 /* Send the command out */
275 sdiostatus = SDDEVICE_CALL_REQUEST_FUNC(device->handle, sdrequest);
276
277 if (!SDIO_SUCCESS(sdiostatus)) {
278 status = A_ERROR;
279 }
280
281 } while (FALSE);
282
283 if (A_FAILED(status) || (request & HIF_SYNCHRONOUS)) {
284 if (busrequest != NULL) {
285 hifFreeBusRequest(busrequest);
286 }
287 }
288
289 if (A_FAILED(status) && (request & HIF_ASYNCHRONOUS)) {
290 /* call back async handler on failure */
291 htcCallbacks.rwCompletionHandler(context, status);
292 }
293
294 return status;
295 }
296
297 A_STATUS
298 HIFConfigureDevice(HIF_DEVICE *device, HIF_DEVICE_CONFIG_OPCODE opcode,
299 void *config, A_UINT32 configLen)
300 {
301 A_UINT32 count;
302
303 switch(opcode) {
304 case HIF_DEVICE_GET_MBOX_BLOCK_SIZE:
305 ((A_UINT32 *)config)[0] = HIF_MBOX0_BLOCK_SIZE;
306 ((A_UINT32 *)config)[1] = HIF_MBOX1_BLOCK_SIZE;
307 ((A_UINT32 *)config)[2] = HIF_MBOX2_BLOCK_SIZE;
308 ((A_UINT32 *)config)[3] = HIF_MBOX3_BLOCK_SIZE;
309 break;
310
311 case HIF_DEVICE_GET_MBOX_ADDR:
312 for (count = 0; count < 4; count ++) {
313 ((A_UINT32 *)config)[count] = HIF_MBOX_START_ADDR(count);
314 }
315 break;
316 case HIF_DEVICE_GET_IRQ_PROC_MODE:
317 /* the SDIO stack allows the interrupts to be processed either way, ASYNC or SYNC */
318 *((HIF_DEVICE_IRQ_PROCESSING_MODE *)config) = HIF_DEVICE_IRQ_ASYNC_SYNC;
319 break;
320 default:
321 AR_DEBUG_PRINTF(ATH_DEBUG_WARN,
322 ("Unsupported configuration opcode: %d\n", opcode));
323 return A_ERROR;
324 }
325
326 return A_OK;
327 }
328
329 void
330 HIFShutDownDevice(HIF_DEVICE *device)
331 {
332 A_UINT8 data;
333 A_UINT32 count;
334 SDIO_STATUS status;
335 SDCONFIG_BUS_MODE_DATA busSettings;
336 SDCONFIG_FUNC_ENABLE_DISABLE_DATA fData;
337
338 if (device != NULL) {
339 DBG_ASSERT(device->handle != NULL);
340
341 /* Remove the allocated current if any */
342 status = SDLIB_IssueConfig(device->handle,
343 SDCONFIG_FUNC_FREE_SLOT_CURRENT, NULL, 0);
344 DBG_ASSERT(SDIO_SUCCESS(status));
345
346 /* Disable the card */
347 fData.EnableFlags = SDCONFIG_DISABLE_FUNC;
348 fData.TimeOut = 1;
349 status = SDLIB_IssueConfig(device->handle, SDCONFIG_FUNC_ENABLE_DISABLE,
350 &fData, sizeof(fData));
351 DBG_ASSERT(SDIO_SUCCESS(status));
352
353 /* Perform a soft I/O reset */
354 data = SDIO_IO_RESET;
355 status = SDLIB_IssueCMD52(device->handle, 0, SDIO_IO_ABORT_REG,
356 &data, 1, 1);
357 DBG_ASSERT(SDIO_SUCCESS(status));
358
359 /*
360 * WAR - Codetelligence driver does not seem to shutdown correctly in 1
361 * bit mode. By default it configures the HC in the 4 bit. Its later in
362 * our driver that we switch to 1 bit mode. If we try to shutdown, the
363 * driver hangs so we revert to 4 bit mode, to be transparent to the
364 * underlying bus driver.
365 */
366 if (onebitmode) {
367 ZERO_OBJECT(busSettings);
368 busSettings.BusModeFlags = SDDEVICE_GET_BUSMODE_FLAGS(device->handle);
369 SDCONFIG_SET_BUS_WIDTH(busSettings.BusModeFlags,
370 SDCONFIG_BUS_WIDTH_4_BIT);
371
372 /* Issue config request to change the bus width to 4 bit */
373 status = SDLIB_IssueConfig(device->handle, SDCONFIG_BUS_MODE_CTRL,
374 &busSettings,
375 sizeof(SDCONFIG_BUS_MODE_DATA));
376 DBG_ASSERT(SDIO_SUCCESS(status));
377 }
378
379 /* Free the bus requests */
380 for (count = 0; count < BUS_REQUEST_MAX_NUM; count ++) {
381 SDDeviceFreeRequest(device->handle, busRequest[count].request);
382 }
383 /* Clean up the queue */
384 s_busRequestFreeQueue = NULL;
385 } else {
386 /* since we are unloading the driver anyways, reset all cards in case the SDIO card
387 * is externally powered and we are unloading the SDIO stack. This avoids the problem when
388 * the SDIO stack is reloaded and attempts are made to re-enumerate a card that is already
389 * enumerated */
390 ResetAllCards();
391 /* Unregister with bus driver core */
392 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,
393 ("Unregistering with the bus driver\n"));
394 status = SDIO_UnregisterFunction(&FunctionContext.function);
395 DBG_ASSERT(SDIO_SUCCESS(status));
396 }
397 }
398
399 void
400 hifRWCompletionHandler(SDREQUEST *request)
401 {
402 A_STATUS status;
403 void *context;
404 BUS_REQUEST *busrequest;
405
406 if (SDIO_SUCCESS(request->Status)) {
407 status = A_OK;
408 } else {
409 status = A_ERROR;
410 }
411
412 DBG_ASSERT(status == A_OK);
413 busrequest = (BUS_REQUEST *) request->pCompleteContext;
414 context = (void *) busrequest->context;
415 /* free the request before calling the callback, in case the
416 * callback submits another request, this guarantees that
417 * there is at least 1 free request available everytime the callback
418 * is invoked */
419 hifFreeBusRequest(busrequest);
420 htcCallbacks.rwCompletionHandler(context, status);
421 }
422
423 void
424 hifIRQHandler(void *context)
425 {
426 A_STATUS status;
427 HIF_DEVICE *device;
428
429 device = (HIF_DEVICE *)context;
430 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("Device: %p\n", device));
431 status = htcCallbacks.dsrHandler(device->htc_handle);
432 DBG_ASSERT(status == A_OK);
433 }
434
435 BOOL
436 hifDeviceInserted(SDFUNCTION *function, SDDEVICE *handle)
437 {
438 BOOL enabled;
439 A_UINT8 data;
440 A_UINT32 count;
441 HIF_DEVICE *device;
442 SDIO_STATUS status;
443 A_UINT16 maxBlocks;
444 A_UINT16 maxBlockSize;
445 SDCONFIG_BUS_MODE_DATA busSettings;
446 SDCONFIG_FUNC_ENABLE_DISABLE_DATA fData;
447 TARGET_FUNCTION_CONTEXT *functionContext;
448 SDCONFIG_FUNC_SLOT_CURRENT_DATA slotCurrent;
449 SD_BUSCLOCK_RATE currentBusClock;
450
451 DBG_ASSERT(function != NULL);
452 DBG_ASSERT(handle != NULL);
453
454 device = addHifDevice(handle);
455 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("Device: %p\n", device));
456 functionContext = (TARGET_FUNCTION_CONTEXT *)function->pContext;
457
458 /*
459 * Issue commands to get the manufacturer ID and stuff and compare it
460 * against the rev Id derived from the ID registered during the
461 * initialization process. Report the device only in the case there
462 * is a match. In the case od SDIO, the bus driver has already queried
463 * these details so we just need to use their data structures to get the
464 * relevant values. Infact, the driver has already matched it against
465 * the Ids that we registered with it so we dont need to the step here.
466 */
467
468 /* Configure the SDIO Bus Width */
469 if (onebitmode) {
470 data = SDIO_BUS_WIDTH_1_BIT;
471 status = SDLIB_IssueCMD52(handle, 0, SDIO_BUS_IF_REG, &data, 1, 1);
472 if (!SDIO_SUCCESS(status)) {
473 AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
474 ("Unable to set the bus width to 1 bit\n"));
475 return FALSE;
476 }
477 }
478
479 /* Get current bus flags */
480 ZERO_OBJECT(busSettings);
481
482 busSettings.BusModeFlags = SDDEVICE_GET_BUSMODE_FLAGS(handle);
483 if (onebitmode) {
484 SDCONFIG_SET_BUS_WIDTH(busSettings.BusModeFlags,
485 SDCONFIG_BUS_WIDTH_1_BIT);
486 }
487
488 /* get the current operating clock, the bus driver sets us up based
489 * on what our CIS reports and what the host controller can handle
490 * we can use this to determine whether we want to drop our clock rate
491 * down */
492 currentBusClock = SDDEVICE_GET_OPER_CLOCK(handle);
493 busSettings.ClockRate = currentBusClock;
494
495 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,
496 ("HIF currently running at: %d \n",currentBusClock));
497
498 /* see if HIF wants to run at a lower clock speed, we may already be
499 * at that lower clock speed */
500 if (currentBusClock > (SDIO_CLOCK_FREQUENCY_DEFAULT >> busspeedlow)) {
501 busSettings.ClockRate = SDIO_CLOCK_FREQUENCY_DEFAULT >> busspeedlow;
502 AR_DEBUG_PRINTF(ATH_DEBUG_WARN,
503 ("HIF overriding clock to %d \n",busSettings.ClockRate));
504 }
505
506 /* Issue config request to override clock rate */
507 status = SDLIB_IssueConfig(handle, SDCONFIG_FUNC_CHANGE_BUS_MODE, &busSettings,
508 sizeof(SDCONFIG_BUS_MODE_DATA));
509 if (!SDIO_SUCCESS(status)) {
510 AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
511 ("Unable to configure the host clock\n"));
512 return FALSE;
513 } else {
514 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,
515 ("Configured clock: %d, Maximum clock: %d\n",
516 busSettings.ActualClockRate,
517 SDDEVICE_GET_MAX_CLOCK(handle)));
518 }
519
520 /*
521 * Check if the target supports block mode. This result of this check
522 * can be used to implement the HIFReadWrite API.
523 */
524 if (SDDEVICE_GET_SDIO_FUNC_MAXBLKSIZE(handle)) {
525 /* Limit block size to operational block limit or card function
526 capability */
527 maxBlockSize = min(SDDEVICE_GET_OPER_BLOCK_LEN(handle),
528 SDDEVICE_GET_SDIO_FUNC_MAXBLKSIZE(handle));
529
530 /* check if the card support multi-block transfers */
531 if (!(SDDEVICE_GET_SDIOCARD_CAPS(handle) & SDIO_CAPS_MULTI_BLOCK)) {
532 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("Byte basis only\n"));
533
534 /* Limit block size to max byte basis */
535 maxBlockSize = min(maxBlockSize,
536 (A_UINT16)SDIO_MAX_LENGTH_BYTE_BASIS);
537 maxBlocks = 1;
538 } else {
539 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("Multi-block capable\n"));
540 maxBlocks = SDDEVICE_GET_OPER_BLOCKS(handle);
541 status = SDLIB_SetFunctionBlockSize(handle, HIF_MBOX_BLOCK_SIZE);
542 if (!SDIO_SUCCESS(status)) {
543 AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
544 ("Failed to set block size. Err:%d\n", status));
545 return FALSE;
546 }
547 }
548
549 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,
550 ("Bytes Per Block: %d bytes, Block Count:%d \n",
551 maxBlockSize, maxBlocks));
552 } else {
553 AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
554 ("Function does not support Block Mode!\n"));
555 return FALSE;
556 }
557
558 /* Allocate the slot current */
559 status = SDLIB_GetDefaultOpCurrent(handle, &slotCurrent.SlotCurrent);
560 if (SDIO_SUCCESS(status)) {
561 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("Allocating Slot current: %d mA\n",
562 slotCurrent.SlotCurrent));
563 status = SDLIB_IssueConfig(handle, SDCONFIG_FUNC_ALLOC_SLOT_CURRENT,
564 &slotCurrent, sizeof(slotCurrent));
565 if (!SDIO_SUCCESS(status)) {
566 AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
567 ("Failed to allocate slot current %d\n", status));
568 return FALSE;
569 }
570 }
571
572 /* Enable the dragon function */
573 count = 0;
574 enabled = FALSE;
575 fData.TimeOut = 1;
576 fData.EnableFlags = SDCONFIG_ENABLE_FUNC;
577 while ((count++ < SDWLAN_ENABLE_DISABLE_TIMEOUT) && !enabled)
578 {
579 /* Enable dragon */
580 status = SDLIB_IssueConfig(handle, SDCONFIG_FUNC_ENABLE_DISABLE,
581 &fData, sizeof(fData));
582 if (!SDIO_SUCCESS(status)) {
583 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,
584 ("Attempting to enable the card again\n"));
585 continue;
586 }
587
588 /* Mark the status as enabled */
589 enabled = TRUE;
590 }
591
592 /* Check if we were succesful in enabling the target */
593 if (!enabled) {
594 AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
595 ("Failed to communicate with the target\n"));
596 return FALSE;
597 }
598
599 /* Allocate the bus requests to be used later */
600 A_MEMZERO(busRequest, sizeof(busRequest));
601 for (count = 0; count < BUS_REQUEST_MAX_NUM; count ++) {
602 if ((busRequest[count].request = SDDeviceAllocRequest(handle)) == NULL){
603 AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, ("Unable to allocate memory\n"));
604 /* TODO: Free the memory that has already been allocated */
605 return FALSE;
606 }
607 hifFreeBusRequest(&busRequest[count]);
608
609 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,
610 ("0x%08x = busRequest[%d].request = 0x%08x\n",
611 (unsigned int) &busRequest[count], count,
612 (unsigned int) busRequest[count].request));
613 }
614
615 /* Schedule a worker to handle device inserted, this is a temporary workaround
616 * to fix a deadlock if the device fails to intialize in the insertion handler
617 * The failure causes the instance to shutdown the HIF layer and unregister the
618 * function driver within the busdriver probe context which can deadlock
619 *
620 * NOTE: we cannot use the default work queue because that would block
621 * SD bus request processing for all synchronous I/O. We must use a kernel
622 * thread that is creating using the helper library.
623 * */
624
625 if (SDIO_SUCCESS(SDLIB_OSCreateHelper(&device->insert_helper,
626 insert_helper_func,
627 device))) {
628 device->helper_started = TRUE;
629 }
630
631 return TRUE;
632 }
633
634 static THREAD_RETURN insert_helper_func(POSKERNEL_HELPER pHelper)
635 {
636
637 /*
638 * Adding a wait of around a second before we issue the very first
639 * command to dragon. During the process of loading/unloading the
640 * driver repeatedly it was observed that we get a data timeout
641 * while accessing function 1 registers in the chip. The theory at
642 * this point is that some initialization delay in dragon is
643 * causing the SDIO state in dragon core to be not ready even after
644 * the ready bit indicates that function 1 is ready. Accomodating
645 * for this behavior by adding some delay in the driver before it
646 * issues the first command after switching on dragon. Need to
647 * investigate this a bit more - TODO
648 */
649
650 A_MDELAY(1000);
651 /* Inform HTC */
652 if ((htcCallbacks.deviceInsertedHandler(SD_GET_OS_HELPER_CONTEXT(pHelper))) != A_OK) {
653 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("Device rejected\n"));
654 }
655
656 return 0;
657 }
658
659 void
660 HIFAckInterrupt(HIF_DEVICE *device)
661 {
662 SDIO_STATUS status;
663 DBG_ASSERT(device != NULL);
664 DBG_ASSERT(device->handle != NULL);
665
666 /* Acknowledge our function IRQ */
667 status = SDLIB_IssueConfig(device->handle, SDCONFIG_FUNC_ACK_IRQ,
668 NULL, 0);
669 DBG_ASSERT(SDIO_SUCCESS(status));
670 }
671
672 void
673 HIFUnMaskInterrupt(HIF_DEVICE *device)
674 {
675 SDIO_STATUS status;
676
677 DBG_ASSERT(device != NULL);
678 DBG_ASSERT(device->handle != NULL);
679
680 /* Register the IRQ Handler */
681 SDDEVICE_SET_IRQ_HANDLER(device->handle, hifIRQHandler, device);
682
683 /* Unmask our function IRQ */
684 status = SDLIB_IssueConfig(device->handle, SDCONFIG_FUNC_UNMASK_IRQ,
685 NULL, 0);
686 DBG_ASSERT(SDIO_SUCCESS(status));
687 }
688
689 void HIFMaskInterrupt(HIF_DEVICE *device)
690 {
691 SDIO_STATUS status;
692 DBG_ASSERT(device != NULL);
693 DBG_ASSERT(device->handle != NULL);
694
695 /* Mask our function IRQ */
696 status = SDLIB_IssueConfig(device->handle, SDCONFIG_FUNC_MASK_IRQ,
697 NULL, 0);
698 DBG_ASSERT(SDIO_SUCCESS(status));
699
700 /* Unregister the IRQ Handler */
701 SDDEVICE_SET_IRQ_HANDLER(device->handle, NULL, NULL);
702 }
703
704 static BUS_REQUEST *hifAllocateBusRequest(void)
705 {
706 BUS_REQUEST *busrequest;
707
708 /* Acquire lock */
709 CriticalSectionAcquire(&lock);
710
711 /* Remove first in list */
712 if((busrequest = s_busRequestFreeQueue) != NULL)
713 {
714 s_busRequestFreeQueue = busrequest->next;
715 }
716
717 /* Release lock */
718 CriticalSectionRelease(&lock);
719
720 return busrequest;
721 }
722
723 static void
724 hifFreeBusRequest(BUS_REQUEST *busrequest)
725 {
726 DBG_ASSERT(busrequest != NULL);
727
728 /* Acquire lock */
729 CriticalSectionAcquire(&lock);
730
731 /* Insert first in list */
732 busrequest->next = s_busRequestFreeQueue;
733 s_busRequestFreeQueue = busrequest;
734
735 /* Release lock */
736 CriticalSectionRelease(&lock);
737 }
738
739 void
740 hifDeviceRemoved(SDFUNCTION *function, SDDEVICE *handle)
741 {
742 A_STATUS status;
743 HIF_DEVICE *device;
744 DBG_ASSERT(function != NULL);
745 DBG_ASSERT(handle != NULL);
746
747 device = getHifDevice(handle);
748 status = htcCallbacks.deviceRemovedHandler(device->htc_handle, A_OK);
749
750 /* cleanup the helper thread */
751 if (device->helper_started) {
752 SDLIB_OSDeleteHelper(&device->insert_helper);
753 device->helper_started = FALSE;
754 }
755
756 delHifDevice(handle);
757 DBG_ASSERT(status == A_OK);
758 }
759
760 HIF_DEVICE *
761 addHifDevice(SDDEVICE *handle)
762 {
763 DBG_ASSERT(handle != NULL);
764 hifDevice[0].handle = handle;
765 return &hifDevice[0];
766 }
767
768 HIF_DEVICE *
769 getHifDevice(SDDEVICE *handle)
770 {
771 DBG_ASSERT(handle != NULL);
772 return &hifDevice[0];
773 }
774
775 void
776 delHifDevice(SDDEVICE *handle)
777 {
778 DBG_ASSERT(handle != NULL);
779 hifDevice[0].handle = NULL;
780 }
781
782 struct device*
783 HIFGetOSDevice(HIF_DEVICE *device)
784 {
785 return &device->handle->Device->dev;
786 }
787
788 static void ResetAllCards(void)
789 {
790 UINT8 data;
791 SDIO_STATUS status;
792 int i;
793
794 data = SDIO_IO_RESET;
795
796 /* set the I/O CARD reset bit:
797 * NOTE: we are exploiting a "feature" of the SDIO core that resets the core when you
798 * set the RES bit in the SDIO_IO_ABORT register. This bit however "normally" resets the
799 * I/O functions leaving the SDIO core in the same state (as per SDIO spec).
800 * In this design, this reset can be used to reset the SDIO core itself */
801 for (i = 0; i < HIF_MAX_DEVICES; i++) {
802 if (hifDevice[i].handle != NULL) {
803 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,
804 ("Issuing I/O Card reset for instance: %d \n",i));
805 /* set the I/O Card reset bit */
806 status = SDLIB_IssueCMD52(hifDevice[i].handle,
807 0, /* function 0 space */
808 SDIO_IO_ABORT_REG,
809 &data,
810 1, /* 1 byte */
811 TRUE); /* write */
812 }
813 }
814
815 }
816
817 void HIFSetHandle(void *hif_handle, void *handle)
818 {
819 HIF_DEVICE *device = (HIF_DEVICE *) hif_handle;
820
821 device->htc_handle = handle;
822
823 return;
824 }
This page took 0.110435 seconds and 5 git commands to generate.