1 //------------------------------------------------------------------------------
2 // Copyright (c) 2009-2010 Atheros Corporation. All rights reserved.
3 //
4 //
5 // Permission to use, copy, modify, and/or distribute this software for any
6 // purpose with or without fee is hereby granted, provided that the above
7 // copyright notice and this permission notice appear in all copies.
8 //
9 // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 //
17 //
18 //------------------------------------------------------------------------------
19 //==============================================================================
20 // AR3K configuration implementation
21 //
22 // Author(s): ="Atheros"
23 //==============================================================================
24
25 #include "a_config.h"
26 #include "athdefs.h"
27 #include "a_types.h"
28 #include "a_osapi.h"
29 #define ATH_MODULE_NAME misc
30 #include "a_debug.h"
31 #include "common_drv.h"
32 #ifdef EXPORT_HCI_BRIDGE_INTERFACE
33 #include "export_hci_transport.h"
34 #else
35 #include "hci_transport_api.h"
36 #endif
37 #include "ar3kconfig.h"
38 #include "tlpm.h"
39
40 #define BAUD_CHANGE_COMMAND_STATUS_OFFSET 5
41 #define HCI_EVENT_RESP_TIMEOUTMS 3000
42 #define HCI_CMD_OPCODE_BYTE_LOW_OFFSET 0
43 #define HCI_CMD_OPCODE_BYTE_HI_OFFSET 1
44 #define HCI_EVENT_OPCODE_BYTE_LOW 3
45 #define HCI_EVENT_OPCODE_BYTE_HI 4
46 #define HCI_CMD_COMPLETE_EVENT_CODE 0xE
47 #define HCI_MAX_EVT_RECV_LENGTH 257
48 #define EXIT_MIN_BOOT_COMMAND_STATUS_OFFSET 5
49
50 int AthPSInitialize(struct ar3k_config_info *hdev);
51
SendHCICommand(struct ar3k_config_info * pConfig,u8 * pBuffer,int Length)52 static int SendHCICommand(struct ar3k_config_info *pConfig,
53 u8 *pBuffer,
54 int Length)
55 {
56 struct htc_packet *pPacket = NULL;
57 int status = 0;
58
59 do {
60
61 pPacket = (struct htc_packet *)A_MALLOC(sizeof(struct htc_packet));
62 if (NULL == pPacket) {
63 status = A_NO_MEMORY;
64 break;
65 }
66
67 A_MEMZERO(pPacket,sizeof(struct htc_packet));
68 SET_HTC_PACKET_INFO_TX(pPacket,
69 NULL,
70 pBuffer,
71 Length,
72 HCI_COMMAND_TYPE,
73 AR6K_CONTROL_PKT_TAG);
74
75 /* issue synchronously */
76 status = HCI_TransportSendPkt(pConfig->pHCIDev,pPacket,true);
77
78 } while (false);
79
80 if (pPacket != NULL) {
81 A_FREE(pPacket);
82 }
83
84 return status;
85 }
86
RecvHCIEvent(struct ar3k_config_info * pConfig,u8 * pBuffer,int * pLength)87 static int RecvHCIEvent(struct ar3k_config_info *pConfig,
88 u8 *pBuffer,
89 int *pLength)
90 {
91 int status = 0;
92 struct htc_packet *pRecvPacket = NULL;
93
94 do {
95
96 pRecvPacket = (struct htc_packet *)A_MALLOC(sizeof(struct htc_packet));
97 if (NULL == pRecvPacket) {
98 status = A_NO_MEMORY;
99 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Failed to alloc HTC struct \n"));
100 break;
101 }
102
103 A_MEMZERO(pRecvPacket,sizeof(struct htc_packet));
104
105 SET_HTC_PACKET_INFO_RX_REFILL(pRecvPacket,NULL,pBuffer,*pLength,HCI_EVENT_TYPE);
106
107 status = HCI_TransportRecvHCIEventSync(pConfig->pHCIDev,
108 pRecvPacket,
109 HCI_EVENT_RESP_TIMEOUTMS);
110 if (status) {
111 break;
112 }
113
114 *pLength = pRecvPacket->ActualLength;
115
116 } while (false);
117
118 if (pRecvPacket != NULL) {
119 A_FREE(pRecvPacket);
120 }
121
122 return status;
123 }
124
SendHCICommandWaitCommandComplete(struct ar3k_config_info * pConfig,u8 * pHCICommand,int CmdLength,u8 ** ppEventBuffer,u8 ** ppBufferToFree)125 int SendHCICommandWaitCommandComplete(struct ar3k_config_info *pConfig,
126 u8 *pHCICommand,
127 int CmdLength,
128 u8 **ppEventBuffer,
129 u8 **ppBufferToFree)
130 {
131 int status = 0;
132 u8 *pBuffer = NULL;
133 u8 *pTemp;
134 int length;
135 bool commandComplete = false;
136 u8 opCodeBytes[2];
137
138 do {
139
140 length = max(HCI_MAX_EVT_RECV_LENGTH,CmdLength);
141 length += pConfig->pHCIProps->HeadRoom + pConfig->pHCIProps->TailRoom;
142 length += pConfig->pHCIProps->IOBlockPad;
143
144 pBuffer = (u8 *)A_MALLOC(length);
145 if (NULL == pBuffer) {
146 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("AR3K Config: Failed to allocate bt buffer \n"));
147 status = A_NO_MEMORY;
148 break;
149 }
150
151 /* get the opcodes to check the command complete event */
152 opCodeBytes[0] = pHCICommand[HCI_CMD_OPCODE_BYTE_LOW_OFFSET];
153 opCodeBytes[1] = pHCICommand[HCI_CMD_OPCODE_BYTE_HI_OFFSET];
154
155 /* copy HCI command */
156 memcpy(pBuffer + pConfig->pHCIProps->HeadRoom,pHCICommand,CmdLength);
157 /* send command */
158 status = SendHCICommand(pConfig,
159 pBuffer + pConfig->pHCIProps->HeadRoom,
160 CmdLength);
161 if (status) {
162 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("AR3K Config: Failed to send HCI Command (%d) \n", status));
163 AR_DEBUG_PRINTBUF(pHCICommand,CmdLength,"HCI Bridge Failed HCI Command");
164 break;
165 }
166
167 /* reuse buffer to capture command complete event */
168 A_MEMZERO(pBuffer,length);
169 status = RecvHCIEvent(pConfig,pBuffer,&length);
170 if (status) {
171 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("AR3K Config: HCI event recv failed \n"));
172 AR_DEBUG_PRINTBUF(pHCICommand,CmdLength,"HCI Bridge Failed HCI Command");
173 break;
174 }
175
176 pTemp = pBuffer + pConfig->pHCIProps->HeadRoom;
177 if (pTemp[0] == HCI_CMD_COMPLETE_EVENT_CODE) {
178 if ((pTemp[HCI_EVENT_OPCODE_BYTE_LOW] == opCodeBytes[0]) &&
179 (pTemp[HCI_EVENT_OPCODE_BYTE_HI] == opCodeBytes[1])) {
180 commandComplete = true;
181 }
182 }
183
184 if (!commandComplete) {
185 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("AR3K Config: Unexpected HCI event : %d \n",pTemp[0]));
186 AR_DEBUG_PRINTBUF(pTemp,pTemp[1],"Unexpected HCI event");
187 status = A_ECOMM;
188 break;
189 }
190
191 if (ppEventBuffer != NULL) {
192 /* caller wants to look at the event */
193 *ppEventBuffer = pTemp;
194 if (ppBufferToFree == NULL) {
195 status = A_EINVAL;
196 break;
197 }
198 /* caller must free the buffer */
199 *ppBufferToFree = pBuffer;
200 pBuffer = NULL;
201 }
202
203 } while (false);
204
205 if (pBuffer != NULL) {
206 A_FREE(pBuffer);
207 }
208
209 return status;
210 }
211
AR3KConfigureHCIBaud(struct ar3k_config_info * pConfig)212 static int AR3KConfigureHCIBaud(struct ar3k_config_info *pConfig)
213 {
214 int status = 0;
215 u8 hciBaudChangeCommand[] = {0x0c,0xfc,0x2,0,0};
216 u16 baudVal;
217 u8 *pEvent = NULL;
218 u8 *pBufferToFree = NULL;
219
220 do {
221
222 if (pConfig->Flags & AR3K_CONFIG_FLAG_SET_AR3K_BAUD) {
223 baudVal = (u16)(pConfig->AR3KBaudRate / 100);
224 hciBaudChangeCommand[3] = (u8)baudVal;
225 hciBaudChangeCommand[4] = (u8)(baudVal >> 8);
226
227 status = SendHCICommandWaitCommandComplete(pConfig,
228 hciBaudChangeCommand,
229 sizeof(hciBaudChangeCommand),
230 &pEvent,
231 &pBufferToFree);
232 if (status) {
233 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("AR3K Config: Baud rate change failed! \n"));
234 break;
235 }
236
237 if (pEvent[BAUD_CHANGE_COMMAND_STATUS_OFFSET] != 0) {
238 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
239 ("AR3K Config: Baud change command event status failed: %d \n",
240 pEvent[BAUD_CHANGE_COMMAND_STATUS_OFFSET]));
241 status = A_ECOMM;
242 break;
243 }
244
245 AR_DEBUG_PRINTF(ATH_DEBUG_ANY,
246 ("AR3K Config: Baud Changed to %d \n",pConfig->AR3KBaudRate));
247 }
248
249 if (pConfig->Flags & AR3K_CONFIG_FLAG_AR3K_BAUD_CHANGE_DELAY) {
250 /* some versions of AR3K do not switch baud immediately, up to 300MS */
251 A_MDELAY(325);
252 }
253
254 if (pConfig->Flags & AR3K_CONFIG_FLAG_SET_AR6K_SCALE_STEP) {
255 /* Tell target to change UART baud rate for AR6K */
256 status = HCI_TransportSetBaudRate(pConfig->pHCIDev, pConfig->AR3KBaudRate);
257
258 if (status) {
259 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
260 ("AR3K Config: failed to set scale and step values: %d \n", status));
261 break;
262 }
263
264 AR_DEBUG_PRINTF(ATH_DEBUG_ANY,
265 ("AR3K Config: Baud changed to %d for AR6K\n", pConfig->AR3KBaudRate));
266 }
267
268 } while (false);
269
270 if (pBufferToFree != NULL) {
271 A_FREE(pBufferToFree);
272 }
273
274 return status;
275 }
276
AR3KExitMinBoot(struct ar3k_config_info * pConfig)277 static int AR3KExitMinBoot(struct ar3k_config_info *pConfig)
278 {
279 int status;
280 char exitMinBootCmd[] = {0x25,0xFC,0x0c,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
281 0x00,0x00,0x00,0x00,0x00};
282 u8 *pEvent = NULL;
283 u8 *pBufferToFree = NULL;
284
285 status = SendHCICommandWaitCommandComplete(pConfig,
286 exitMinBootCmd,
287 sizeof(exitMinBootCmd),
288 &pEvent,
289 &pBufferToFree);
290
291 if (!status) {
292 if (pEvent[EXIT_MIN_BOOT_COMMAND_STATUS_OFFSET] != 0) {
293 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
294 ("AR3K Config: MinBoot exit command event status failed: %d \n",
295 pEvent[EXIT_MIN_BOOT_COMMAND_STATUS_OFFSET]));
296 status = A_ECOMM;
297 } else {
298 AR_DEBUG_PRINTF(ATH_DEBUG_INFO,
299 ("AR3K Config: MinBoot Exit Command Complete (Success) \n"));
300 A_MDELAY(1);
301 }
302 } else {
303 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("AR3K Config: MinBoot Exit Failed! \n"));
304 }
305
306 if (pBufferToFree != NULL) {
307 A_FREE(pBufferToFree);
308 }
309
310 return status;
311 }
312
AR3KConfigureSendHCIReset(struct ar3k_config_info * pConfig)313 static int AR3KConfigureSendHCIReset(struct ar3k_config_info *pConfig)
314 {
315 int status = 0;
316 u8 hciResetCommand[] = {0x03,0x0c,0x0};
317 u8 *pEvent = NULL;
318 u8 *pBufferToFree = NULL;
319
320 status = SendHCICommandWaitCommandComplete( pConfig,
321 hciResetCommand,
322 sizeof(hciResetCommand),
323 &pEvent,
324 &pBufferToFree );
325
326 if (status) {
327 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("AR3K Config: HCI reset failed! \n"));
328 }
329
330 if (pBufferToFree != NULL) {
331 A_FREE(pBufferToFree);
332 }
333
334 return status;
335 }
336
AR3KEnableTLPM(struct ar3k_config_info * pConfig)337 static int AR3KEnableTLPM(struct ar3k_config_info *pConfig)
338 {
339 int status;
340 /* AR3K vendor specific command for Host Wakeup Config */
341 char hostWakeupConfig[] = {0x31,0xFC,0x18,
342 0x02,0x00,0x00,0x00,
343 0x01,0x00,0x00,0x00,
344 TLPM_DEFAULT_IDLE_TIMEOUT_LSB,TLPM_DEFAULT_IDLE_TIMEOUT_MSB,0x00,0x00, //idle timeout in ms
345 0x00,0x00,0x00,0x00,
346 TLPM_DEFAULT_WAKEUP_TIMEOUT_MS,0x00,0x00,0x00, //wakeup timeout in ms
347 0x00,0x00,0x00,0x00};
348 /* AR3K vendor specific command for Target Wakeup Config */
349 char targetWakeupConfig[] = {0x31,0xFC,0x18,
350 0x04,0x00,0x00,0x00,
351 0x01,0x00,0x00,0x00,
352 TLPM_DEFAULT_IDLE_TIMEOUT_LSB,TLPM_DEFAULT_IDLE_TIMEOUT_MSB,0x00,0x00, //idle timeout in ms
353 0x00,0x00,0x00,0x00,
354 TLPM_DEFAULT_WAKEUP_TIMEOUT_MS,0x00,0x00,0x00, //wakeup timeout in ms
355 0x00,0x00,0x00,0x00};
356 /* AR3K vendor specific command for Host Wakeup Enable */
357 char hostWakeupEnable[] = {0x31,0xFC,0x4,
358 0x01,0x00,0x00,0x00};
359 /* AR3K vendor specific command for Target Wakeup Enable */
360 char targetWakeupEnable[] = {0x31,0xFC,0x4,
361 0x06,0x00,0x00,0x00};
362 /* AR3K vendor specific command for Sleep Enable */
363 char sleepEnable[] = {0x4,0xFC,0x1,
364 0x1};
365 u8 *pEvent = NULL;
366 u8 *pBufferToFree = NULL;
367
368 if (0 != pConfig->IdleTimeout) {
369 u8 idle_lsb = pConfig->IdleTimeout & 0xFF;
370 u8 idle_msb = (pConfig->IdleTimeout & 0xFF00) >> 8;
371 hostWakeupConfig[11] = targetWakeupConfig[11] = idle_lsb;
372 hostWakeupConfig[12] = targetWakeupConfig[12] = idle_msb;
373 }
374
375 if (0 != pConfig->WakeupTimeout) {
376 hostWakeupConfig[19] = targetWakeupConfig[19] = (pConfig->WakeupTimeout & 0xFF);
377 }
378
379 status = SendHCICommandWaitCommandComplete(pConfig,
380 hostWakeupConfig,
381 sizeof(hostWakeupConfig),
382 &pEvent,
383 &pBufferToFree);
384 if (pBufferToFree != NULL) {
385 A_FREE(pBufferToFree);
386 }
387 if (status) {
388 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("HostWakeup Config Failed! \n"));
389 return status;
390 }
391
392 pEvent = NULL;
393 pBufferToFree = NULL;
394 status = SendHCICommandWaitCommandComplete(pConfig,
395 targetWakeupConfig,
396 sizeof(targetWakeupConfig),
397 &pEvent,
398 &pBufferToFree);
399 if (pBufferToFree != NULL) {
400 A_FREE(pBufferToFree);
401 }
402 if (status) {
403 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Target Wakeup Config Failed! \n"));
404 return status;
405 }
406
407 pEvent = NULL;
408 pBufferToFree = NULL;
409 status = SendHCICommandWaitCommandComplete(pConfig,
410 hostWakeupEnable,
411 sizeof(hostWakeupEnable),
412 &pEvent,
413 &pBufferToFree);
414 if (pBufferToFree != NULL) {
415 A_FREE(pBufferToFree);
416 }
417 if (status) {
418 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("HostWakeup Enable Failed! \n"));
419 return status;
420 }
421
422 pEvent = NULL;
423 pBufferToFree = NULL;
424 status = SendHCICommandWaitCommandComplete(pConfig,
425 targetWakeupEnable,
426 sizeof(targetWakeupEnable),
427 &pEvent,
428 &pBufferToFree);
429 if (pBufferToFree != NULL) {
430 A_FREE(pBufferToFree);
431 }
432 if (status) {
433 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Target Wakeup Enable Failed! \n"));
434 return status;
435 }
436
437 pEvent = NULL;
438 pBufferToFree = NULL;
439 status = SendHCICommandWaitCommandComplete(pConfig,
440 sleepEnable,
441 sizeof(sleepEnable),
442 &pEvent,
443 &pBufferToFree);
444 if (pBufferToFree != NULL) {
445 A_FREE(pBufferToFree);
446 }
447 if (status) {
448 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Sleep Enable Failed! \n"));
449 }
450
451 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("AR3K Config: Enable TLPM Completed (status = %d) \n",status));
452
453 return status;
454 }
455
AR3KConfigure(struct ar3k_config_info * pConfig)456 int AR3KConfigure(struct ar3k_config_info *pConfig)
457 {
458 int status = 0;
459
460 AR_DEBUG_PRINTF(ATH_DEBUG_INFO,("AR3K Config: Configuring AR3K ...\n"));
461
462 do {
463
464 if ((pConfig->pHCIDev == NULL) || (pConfig->pHCIProps == NULL) || (pConfig->pHIFDevice == NULL)) {
465 status = A_EINVAL;
466 break;
467 }
468
469 /* disable asynchronous recv while we issue commands and receive events synchronously */
470 status = HCI_TransportEnableDisableAsyncRecv(pConfig->pHCIDev,false);
471 if (status) {
472 break;
473 }
474
475 if (pConfig->Flags & AR3K_CONFIG_FLAG_FORCE_MINBOOT_EXIT) {
476 status = AR3KExitMinBoot(pConfig);
477 if (status) {
478 break;
479 }
480 }
481
482
483 /* Load patching and PST file if available*/
484 if (0 != AthPSInitialize(pConfig)) {
485 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Patch Download Failed!\n"));
486 }
487
488 /* Send HCI reset to make PS tags take effect*/
489 AR3KConfigureSendHCIReset(pConfig);
490
491 if (pConfig->Flags &
492 (AR3K_CONFIG_FLAG_SET_AR3K_BAUD | AR3K_CONFIG_FLAG_SET_AR6K_SCALE_STEP)) {
493 status = AR3KConfigureHCIBaud(pConfig);
494 if (status) {
495 break;
496 }
497 }
498
499
500
501 if (pConfig->PwrMgmtEnabled) {
502 /* the delay is required after the previous HCI reset before further
503 * HCI commands can be issued
504 */
505 A_MDELAY(200);
506 AR3KEnableTLPM(pConfig);
507 }
508
509 /* re-enable asynchronous recv */
510 status = HCI_TransportEnableDisableAsyncRecv(pConfig->pHCIDev,true);
511 if (status) {
512 break;
513 }
514
515
516 } while (false);
517
518
519 AR_DEBUG_PRINTF(ATH_DEBUG_INFO,("AR3K Config: Configuration Complete (status = %d) \n",status));
520
521 return status;
522 }
523
AR3KConfigureExit(void * config)524 int AR3KConfigureExit(void *config)
525 {
526 int status = 0;
527 struct ar3k_config_info *pConfig = (struct ar3k_config_info *)config;
528
529 AR_DEBUG_PRINTF(ATH_DEBUG_INFO,("AR3K Config: Cleaning up AR3K ...\n"));
530
531 do {
532
533 if ((pConfig->pHCIDev == NULL) || (pConfig->pHCIProps == NULL) || (pConfig->pHIFDevice == NULL)) {
534 status = A_EINVAL;
535 break;
536 }
537
538 /* disable asynchronous recv while we issue commands and receive events synchronously */
539 status = HCI_TransportEnableDisableAsyncRecv(pConfig->pHCIDev,false);
540 if (status) {
541 break;
542 }
543
544 if (pConfig->Flags &
545 (AR3K_CONFIG_FLAG_SET_AR3K_BAUD | AR3K_CONFIG_FLAG_SET_AR6K_SCALE_STEP)) {
546 status = AR3KConfigureHCIBaud(pConfig);
547 if (status) {
548 break;
549 }
550 }
551
552 /* re-enable asynchronous recv */
553 status = HCI_TransportEnableDisableAsyncRecv(pConfig->pHCIDev,true);
554 if (status) {
555 break;
556 }
557
558
559 } while (false);
560
561
562 AR_DEBUG_PRINTF(ATH_DEBUG_INFO,("AR3K Config: Cleanup Complete (status = %d) \n",status));
563
564 return status;
565 }
566
567