1 //------------------------------------------------------------------------------
2 // Copyright (c) 2009-2010 Atheros Corporation. All rights reserved.
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.
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.
18 //------------------------------------------------------------------------------
19 //==============================================================================
20 // AR3K configuration implementation
22 // Author(s): ="Atheros"
23 //==============================================================================
28 #define ATH_MODULE_NAME misc
30 #include "common_drv.h"
31 #ifdef EXPORT_HCI_BRIDGE_INTERFACE
32 #include "export_hci_transport.h"
34 #include "hci_transport_api.h"
36 #include "ar3kconfig.h"
39 #define BAUD_CHANGE_COMMAND_STATUS_OFFSET 5
40 #define HCI_EVENT_RESP_TIMEOUTMS 3000
41 #define HCI_CMD_OPCODE_BYTE_LOW_OFFSET 0
42 #define HCI_CMD_OPCODE_BYTE_HI_OFFSET 1
43 #define HCI_EVENT_OPCODE_BYTE_LOW 3
44 #define HCI_EVENT_OPCODE_BYTE_HI 4
45 #define HCI_CMD_COMPLETE_EVENT_CODE 0xE
46 #define HCI_MAX_EVT_RECV_LENGTH 257
47 #define EXIT_MIN_BOOT_COMMAND_STATUS_OFFSET 5
49 int AthPSInitialize(struct ar3k_config_info
*hdev
);
51 static int SendHCICommand(struct ar3k_config_info
*pConfig
,
55 struct htc_packet
*pPacket
= NULL
;
60 pPacket
= (struct htc_packet
*)A_MALLOC(sizeof(struct htc_packet
));
61 if (NULL
== pPacket
) {
66 A_MEMZERO(pPacket
,sizeof(struct htc_packet
));
67 SET_HTC_PACKET_INFO_TX(pPacket
,
72 AR6K_CONTROL_PKT_TAG
);
74 /* issue synchronously */
75 status
= HCI_TransportSendPkt(pConfig
->pHCIDev
,pPacket
,true);
79 if (pPacket
!= NULL
) {
86 static int RecvHCIEvent(struct ar3k_config_info
*pConfig
,
91 struct htc_packet
*pRecvPacket
= NULL
;
95 pRecvPacket
= (struct htc_packet
*)A_MALLOC(sizeof(struct htc_packet
));
96 if (NULL
== pRecvPacket
) {
98 AR_DEBUG_PRINTF(ATH_DEBUG_ERR
,("Failed to alloc HTC struct \n"));
102 A_MEMZERO(pRecvPacket
,sizeof(struct htc_packet
));
104 SET_HTC_PACKET_INFO_RX_REFILL(pRecvPacket
,NULL
,pBuffer
,*pLength
,HCI_EVENT_TYPE
);
106 status
= HCI_TransportRecvHCIEventSync(pConfig
->pHCIDev
,
108 HCI_EVENT_RESP_TIMEOUTMS
);
113 *pLength
= pRecvPacket
->ActualLength
;
117 if (pRecvPacket
!= NULL
) {
124 int SendHCICommandWaitCommandComplete(struct ar3k_config_info
*pConfig
,
134 bool commandComplete
= false;
139 length
= max(HCI_MAX_EVT_RECV_LENGTH
,CmdLength
);
140 length
+= pConfig
->pHCIProps
->HeadRoom
+ pConfig
->pHCIProps
->TailRoom
;
141 length
+= pConfig
->pHCIProps
->IOBlockPad
;
143 pBuffer
= (u8
*)A_MALLOC(length
);
144 if (NULL
== pBuffer
) {
145 AR_DEBUG_PRINTF(ATH_DEBUG_ERR
,("AR3K Config: Failed to allocate bt buffer \n"));
146 status
= A_NO_MEMORY
;
150 /* get the opcodes to check the command complete event */
151 opCodeBytes
[0] = pHCICommand
[HCI_CMD_OPCODE_BYTE_LOW_OFFSET
];
152 opCodeBytes
[1] = pHCICommand
[HCI_CMD_OPCODE_BYTE_HI_OFFSET
];
154 /* copy HCI command */
155 memcpy(pBuffer
+ pConfig
->pHCIProps
->HeadRoom
,pHCICommand
,CmdLength
);
157 status
= SendHCICommand(pConfig
,
158 pBuffer
+ pConfig
->pHCIProps
->HeadRoom
,
161 AR_DEBUG_PRINTF(ATH_DEBUG_ERR
,("AR3K Config: Failed to send HCI Command (%d) \n", status
));
162 AR_DEBUG_PRINTBUF(pHCICommand
,CmdLength
,"HCI Bridge Failed HCI Command");
166 /* reuse buffer to capture command complete event */
167 A_MEMZERO(pBuffer
,length
);
168 status
= RecvHCIEvent(pConfig
,pBuffer
,&length
);
170 AR_DEBUG_PRINTF(ATH_DEBUG_ERR
,("AR3K Config: HCI event recv failed \n"));
171 AR_DEBUG_PRINTBUF(pHCICommand
,CmdLength
,"HCI Bridge Failed HCI Command");
175 pTemp
= pBuffer
+ pConfig
->pHCIProps
->HeadRoom
;
176 if (pTemp
[0] == HCI_CMD_COMPLETE_EVENT_CODE
) {
177 if ((pTemp
[HCI_EVENT_OPCODE_BYTE_LOW
] == opCodeBytes
[0]) &&
178 (pTemp
[HCI_EVENT_OPCODE_BYTE_HI
] == opCodeBytes
[1])) {
179 commandComplete
= true;
183 if (!commandComplete
) {
184 AR_DEBUG_PRINTF(ATH_DEBUG_ERR
,("AR3K Config: Unexpected HCI event : %d \n",pTemp
[0]));
185 AR_DEBUG_PRINTBUF(pTemp
,pTemp
[1],"Unexpected HCI event");
190 if (ppEventBuffer
!= NULL
) {
191 /* caller wants to look at the event */
192 *ppEventBuffer
= pTemp
;
193 if (ppBufferToFree
== NULL
) {
197 /* caller must free the buffer */
198 *ppBufferToFree
= pBuffer
;
204 if (pBuffer
!= NULL
) {
211 static int AR3KConfigureHCIBaud(struct ar3k_config_info
*pConfig
)
214 u8 hciBaudChangeCommand
[] = {0x0c,0xfc,0x2,0,0};
217 u8
*pBufferToFree
= NULL
;
221 if (pConfig
->Flags
& AR3K_CONFIG_FLAG_SET_AR3K_BAUD
) {
222 baudVal
= (u16
)(pConfig
->AR3KBaudRate
/ 100);
223 hciBaudChangeCommand
[3] = (u8
)baudVal
;
224 hciBaudChangeCommand
[4] = (u8
)(baudVal
>> 8);
226 status
= SendHCICommandWaitCommandComplete(pConfig
,
227 hciBaudChangeCommand
,
228 sizeof(hciBaudChangeCommand
),
232 AR_DEBUG_PRINTF(ATH_DEBUG_ERR
,("AR3K Config: Baud rate change failed! \n"));
236 if (pEvent
[BAUD_CHANGE_COMMAND_STATUS_OFFSET
] != 0) {
237 AR_DEBUG_PRINTF(ATH_DEBUG_ERR
,
238 ("AR3K Config: Baud change command event status failed: %d \n",
239 pEvent
[BAUD_CHANGE_COMMAND_STATUS_OFFSET
]));
244 AR_DEBUG_PRINTF(ATH_DEBUG_ANY
,
245 ("AR3K Config: Baud Changed to %d \n",pConfig
->AR3KBaudRate
));
248 if (pConfig
->Flags
& AR3K_CONFIG_FLAG_AR3K_BAUD_CHANGE_DELAY
) {
249 /* some versions of AR3K do not switch baud immediately, up to 300MS */
253 if (pConfig
->Flags
& AR3K_CONFIG_FLAG_SET_AR6K_SCALE_STEP
) {
254 /* Tell target to change UART baud rate for AR6K */
255 status
= HCI_TransportSetBaudRate(pConfig
->pHCIDev
, pConfig
->AR3KBaudRate
);
258 AR_DEBUG_PRINTF(ATH_DEBUG_ERR
,
259 ("AR3K Config: failed to set scale and step values: %d \n", status
));
263 AR_DEBUG_PRINTF(ATH_DEBUG_ANY
,
264 ("AR3K Config: Baud changed to %d for AR6K\n", pConfig
->AR3KBaudRate
));
269 if (pBufferToFree
!= NULL
) {
270 kfree(pBufferToFree
);
276 static int AR3KExitMinBoot(struct ar3k_config_info
*pConfig
)
279 char exitMinBootCmd
[] = {0x25,0xFC,0x0c,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
280 0x00,0x00,0x00,0x00,0x00};
282 u8
*pBufferToFree
= NULL
;
284 status
= SendHCICommandWaitCommandComplete(pConfig
,
286 sizeof(exitMinBootCmd
),
291 if (pEvent
[EXIT_MIN_BOOT_COMMAND_STATUS_OFFSET
] != 0) {
292 AR_DEBUG_PRINTF(ATH_DEBUG_ERR
,
293 ("AR3K Config: MinBoot exit command event status failed: %d \n",
294 pEvent
[EXIT_MIN_BOOT_COMMAND_STATUS_OFFSET
]));
297 AR_DEBUG_PRINTF(ATH_DEBUG_INFO
,
298 ("AR3K Config: MinBoot Exit Command Complete (Success) \n"));
302 AR_DEBUG_PRINTF(ATH_DEBUG_ERR
,("AR3K Config: MinBoot Exit Failed! \n"));
305 if (pBufferToFree
!= NULL
) {
306 kfree(pBufferToFree
);
312 static int AR3KConfigureSendHCIReset(struct ar3k_config_info
*pConfig
)
315 u8 hciResetCommand
[] = {0x03,0x0c,0x0};
317 u8
*pBufferToFree
= NULL
;
319 status
= SendHCICommandWaitCommandComplete( pConfig
,
321 sizeof(hciResetCommand
),
326 AR_DEBUG_PRINTF(ATH_DEBUG_ERR
,("AR3K Config: HCI reset failed! \n"));
329 if (pBufferToFree
!= NULL
) {
330 kfree(pBufferToFree
);
336 static int AR3KEnableTLPM(struct ar3k_config_info
*pConfig
)
339 /* AR3K vendor specific command for Host Wakeup Config */
340 char hostWakeupConfig
[] = {0x31,0xFC,0x18,
343 TLPM_DEFAULT_IDLE_TIMEOUT_LSB
,TLPM_DEFAULT_IDLE_TIMEOUT_MSB
,0x00,0x00, //idle timeout in ms
345 TLPM_DEFAULT_WAKEUP_TIMEOUT_MS
,0x00,0x00,0x00, //wakeup timeout in ms
346 0x00,0x00,0x00,0x00};
347 /* AR3K vendor specific command for Target Wakeup Config */
348 char targetWakeupConfig
[] = {0x31,0xFC,0x18,
351 TLPM_DEFAULT_IDLE_TIMEOUT_LSB
,TLPM_DEFAULT_IDLE_TIMEOUT_MSB
,0x00,0x00, //idle timeout in ms
353 TLPM_DEFAULT_WAKEUP_TIMEOUT_MS
,0x00,0x00,0x00, //wakeup timeout in ms
354 0x00,0x00,0x00,0x00};
355 /* AR3K vendor specific command for Host Wakeup Enable */
356 char hostWakeupEnable
[] = {0x31,0xFC,0x4,
357 0x01,0x00,0x00,0x00};
358 /* AR3K vendor specific command for Target Wakeup Enable */
359 char targetWakeupEnable
[] = {0x31,0xFC,0x4,
360 0x06,0x00,0x00,0x00};
361 /* AR3K vendor specific command for Sleep Enable */
362 char sleepEnable
[] = {0x4,0xFC,0x1,
365 u8
*pBufferToFree
= NULL
;
367 if (0 != pConfig
->IdleTimeout
) {
368 u8 idle_lsb
= pConfig
->IdleTimeout
& 0xFF;
369 u8 idle_msb
= (pConfig
->IdleTimeout
& 0xFF00) >> 8;
370 hostWakeupConfig
[11] = targetWakeupConfig
[11] = idle_lsb
;
371 hostWakeupConfig
[12] = targetWakeupConfig
[12] = idle_msb
;
374 if (0 != pConfig
->WakeupTimeout
) {
375 hostWakeupConfig
[19] = targetWakeupConfig
[19] = (pConfig
->WakeupTimeout
& 0xFF);
378 status
= SendHCICommandWaitCommandComplete(pConfig
,
380 sizeof(hostWakeupConfig
),
383 if (pBufferToFree
!= NULL
) {
384 kfree(pBufferToFree
);
387 AR_DEBUG_PRINTF(ATH_DEBUG_ERR
,("HostWakeup Config Failed! \n"));
392 pBufferToFree
= NULL
;
393 status
= SendHCICommandWaitCommandComplete(pConfig
,
395 sizeof(targetWakeupConfig
),
398 if (pBufferToFree
!= NULL
) {
399 kfree(pBufferToFree
);
402 AR_DEBUG_PRINTF(ATH_DEBUG_ERR
,("Target Wakeup Config Failed! \n"));
407 pBufferToFree
= NULL
;
408 status
= SendHCICommandWaitCommandComplete(pConfig
,
410 sizeof(hostWakeupEnable
),
413 if (pBufferToFree
!= NULL
) {
414 kfree(pBufferToFree
);
417 AR_DEBUG_PRINTF(ATH_DEBUG_ERR
,("HostWakeup Enable Failed! \n"));
422 pBufferToFree
= NULL
;
423 status
= SendHCICommandWaitCommandComplete(pConfig
,
425 sizeof(targetWakeupEnable
),
428 if (pBufferToFree
!= NULL
) {
429 kfree(pBufferToFree
);
432 AR_DEBUG_PRINTF(ATH_DEBUG_ERR
,("Target Wakeup Enable Failed! \n"));
437 pBufferToFree
= NULL
;
438 status
= SendHCICommandWaitCommandComplete(pConfig
,
443 if (pBufferToFree
!= NULL
) {
444 kfree(pBufferToFree
);
447 AR_DEBUG_PRINTF(ATH_DEBUG_ERR
,("Sleep Enable Failed! \n"));
450 AR_DEBUG_PRINTF(ATH_DEBUG_ERR
,("AR3K Config: Enable TLPM Completed (status = %d) \n",status
));
455 int AR3KConfigure(struct ar3k_config_info
*pConfig
)
459 AR_DEBUG_PRINTF(ATH_DEBUG_INFO
,("AR3K Config: Configuring AR3K ...\n"));
463 if ((pConfig
->pHCIDev
== NULL
) || (pConfig
->pHCIProps
== NULL
) || (pConfig
->pHIFDevice
== NULL
)) {
468 /* disable asynchronous recv while we issue commands and receive events synchronously */
469 status
= HCI_TransportEnableDisableAsyncRecv(pConfig
->pHCIDev
,false);
474 if (pConfig
->Flags
& AR3K_CONFIG_FLAG_FORCE_MINBOOT_EXIT
) {
475 status
= AR3KExitMinBoot(pConfig
);
482 /* Load patching and PST file if available*/
483 if (0 != AthPSInitialize(pConfig
)) {
484 AR_DEBUG_PRINTF(ATH_DEBUG_ERR
,("Patch Download Failed!\n"));
487 /* Send HCI reset to make PS tags take effect*/
488 AR3KConfigureSendHCIReset(pConfig
);
491 (AR3K_CONFIG_FLAG_SET_AR3K_BAUD
| AR3K_CONFIG_FLAG_SET_AR6K_SCALE_STEP
)) {
492 status
= AR3KConfigureHCIBaud(pConfig
);
500 if (pConfig
->PwrMgmtEnabled
) {
501 /* the delay is required after the previous HCI reset before further
502 * HCI commands can be issued
505 AR3KEnableTLPM(pConfig
);
508 /* re-enable asynchronous recv */
509 status
= HCI_TransportEnableDisableAsyncRecv(pConfig
->pHCIDev
,true);
518 AR_DEBUG_PRINTF(ATH_DEBUG_INFO
,("AR3K Config: Configuration Complete (status = %d) \n",status
));
523 int AR3KConfigureExit(void *config
)
526 struct ar3k_config_info
*pConfig
= (struct ar3k_config_info
*)config
;
528 AR_DEBUG_PRINTF(ATH_DEBUG_INFO
,("AR3K Config: Cleaning up AR3K ...\n"));
532 if ((pConfig
->pHCIDev
== NULL
) || (pConfig
->pHCIProps
== NULL
) || (pConfig
->pHIFDevice
== NULL
)) {
537 /* disable asynchronous recv while we issue commands and receive events synchronously */
538 status
= HCI_TransportEnableDisableAsyncRecv(pConfig
->pHCIDev
,false);
544 (AR3K_CONFIG_FLAG_SET_AR3K_BAUD
| AR3K_CONFIG_FLAG_SET_AR6K_SCALE_STEP
)) {
545 status
= AR3KConfigureHCIBaud(pConfig
);
551 /* re-enable asynchronous recv */
552 status
= HCI_TransportEnableDisableAsyncRecv(pConfig
->pHCIDev
,true);
561 AR_DEBUG_PRINTF(ATH_DEBUG_INFO
,("AR3K Config: Cleanup Complete (status = %d) \n",status
));