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 //==============================================================================
29 #define ATH_MODULE_NAME misc
31 #include "common_drv.h"
32 #ifdef EXPORT_HCI_BRIDGE_INTERFACE
33 #include "export_hci_transport.h"
35 #include "hci_transport_api.h"
37 #include "ar3kconfig.h"
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
50 int AthPSInitialize(AR3K_CONFIG_INFO *hdev);
52 static int SendHCICommand(AR3K_CONFIG_INFO *pConfig,
56 HTC_PACKET *pPacket = NULL;
61 pPacket = (HTC_PACKET *)A_MALLOC(sizeof(HTC_PACKET));
62 if (NULL == pPacket) {
67 A_MEMZERO(pPacket,sizeof(HTC_PACKET));
68 SET_HTC_PACKET_INFO_TX(pPacket,
73 AR6K_CONTROL_PKT_TAG);
75 /* issue synchronously */
76 status = HCI_TransportSendPkt(pConfig->pHCIDev,pPacket,TRUE);
80 if (pPacket != NULL) {
87 static int RecvHCIEvent(AR3K_CONFIG_INFO *pConfig,
92 HTC_PACKET *pRecvPacket = NULL;
96 pRecvPacket = (HTC_PACKET *)A_MALLOC(sizeof(HTC_PACKET));
97 if (NULL == pRecvPacket) {
99 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Failed to alloc HTC struct \n"));
103 A_MEMZERO(pRecvPacket,sizeof(HTC_PACKET));
105 SET_HTC_PACKET_INFO_RX_REFILL(pRecvPacket,NULL,pBuffer,*pLength,HCI_EVENT_TYPE);
107 status = HCI_TransportRecvHCIEventSync(pConfig->pHCIDev,
109 HCI_EVENT_RESP_TIMEOUTMS);
110 if (A_FAILED(status)) {
114 *pLength = pRecvPacket->ActualLength;
118 if (pRecvPacket != NULL) {
125 int SendHCICommandWaitCommandComplete(AR3K_CONFIG_INFO *pConfig,
126 A_UINT8 *pHCICommand,
128 A_UINT8 **ppEventBuffer,
129 A_UINT8 **ppBufferToFree)
132 A_UINT8 *pBuffer = NULL;
135 A_BOOL commandComplete = FALSE;
136 A_UINT8 opCodeBytes[2];
140 length = max(HCI_MAX_EVT_RECV_LENGTH,CmdLength);
141 length += pConfig->pHCIProps->HeadRoom + pConfig->pHCIProps->TailRoom;
142 length += pConfig->pHCIProps->IOBlockPad;
144 pBuffer = (A_UINT8 *)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;
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];
155 /* copy HCI command */
156 A_MEMCPY(pBuffer + pConfig->pHCIProps->HeadRoom,pHCICommand,CmdLength);
158 status = SendHCICommand(pConfig,
159 pBuffer + pConfig->pHCIProps->HeadRoom,
161 if (A_FAILED(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");
167 /* reuse buffer to capture command complete event */
168 A_MEMZERO(pBuffer,length);
169 status = RecvHCIEvent(pConfig,pBuffer,&length);
170 if (A_FAILED(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");
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;
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");
191 if (ppEventBuffer != NULL) {
192 /* caller wants to look at the event */
193 *ppEventBuffer = pTemp;
194 if (ppBufferToFree == NULL) {
198 /* caller must free the buffer */
199 *ppBufferToFree = pBuffer;
205 if (pBuffer != NULL) {
212 static int AR3KConfigureHCIBaud(AR3K_CONFIG_INFO *pConfig)
215 A_UINT8 hciBaudChangeCommand[] = {0x0c,0xfc,0x2,0,0};
217 A_UINT8 *pEvent = NULL;
218 A_UINT8 *pBufferToFree = NULL;
222 if (pConfig->Flags & AR3K_CONFIG_FLAG_SET_AR3K_BAUD) {
223 baudVal = (A_UINT16)(pConfig->AR3KBaudRate / 100);
224 hciBaudChangeCommand[3] = (A_UINT8)baudVal;
225 hciBaudChangeCommand[4] = (A_UINT8)(baudVal >> 8);
227 status = SendHCICommandWaitCommandComplete(pConfig,
228 hciBaudChangeCommand,
229 sizeof(hciBaudChangeCommand),
232 if (A_FAILED(status)) {
233 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("AR3K Config: Baud rate change failed! \n"));
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]));
245 AR_DEBUG_PRINTF(ATH_DEBUG_ANY,
246 ("AR3K Config: Baud Changed to %d \n",pConfig->AR3KBaudRate));
249 if (pConfig->Flags & AR3K_CONFIG_FLAG_AR3K_BAUD_CHANGE_DELAY) {
250 /* some versions of AR3K do not switch baud immediately, up to 300MS */
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);
258 if (A_FAILED(status)) {
259 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
260 ("AR3K Config: failed to set scale and step values: %d \n", status));
264 AR_DEBUG_PRINTF(ATH_DEBUG_ANY,
265 ("AR3K Config: Baud changed to %d for AR6K\n", pConfig->AR3KBaudRate));
270 if (pBufferToFree != NULL) {
271 A_FREE(pBufferToFree);
277 static int AR3KExitMinBoot(AR3K_CONFIG_INFO *pConfig)
280 A_CHAR exitMinBootCmd[] = {0x25,0xFC,0x0c,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
281 0x00,0x00,0x00,0x00,0x00};
282 A_UINT8 *pEvent = NULL;
283 A_UINT8 *pBufferToFree = NULL;
285 status = SendHCICommandWaitCommandComplete(pConfig,
287 sizeof(exitMinBootCmd),
291 if (A_SUCCESS(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]));
298 AR_DEBUG_PRINTF(ATH_DEBUG_INFO,
299 ("AR3K Config: MinBoot Exit Command Complete (Success) \n"));
303 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("AR3K Config: MinBoot Exit Failed! \n"));
306 if (pBufferToFree != NULL) {
307 A_FREE(pBufferToFree);
313 static int AR3KConfigureSendHCIReset(AR3K_CONFIG_INFO *pConfig)
316 A_UINT8 hciResetCommand[] = {0x03,0x0c,0x0};
317 A_UINT8 *pEvent = NULL;
318 A_UINT8 *pBufferToFree = NULL;
320 status = SendHCICommandWaitCommandComplete( pConfig,
322 sizeof(hciResetCommand),
326 if (A_FAILED(status)) {
327 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("AR3K Config: HCI reset failed! \n"));
330 if (pBufferToFree != NULL) {
331 A_FREE(pBufferToFree);
337 static int AR3KEnableTLPM(AR3K_CONFIG_INFO *pConfig)
340 /* AR3K vendor specific command for Host Wakeup Config */
341 A_CHAR hostWakeupConfig[] = {0x31,0xFC,0x18,
344 TLPM_DEFAULT_IDLE_TIMEOUT_LSB,TLPM_DEFAULT_IDLE_TIMEOUT_MSB,0x00,0x00, //idle timeout in ms
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 A_CHAR targetWakeupConfig[] = {0x31,0xFC,0x18,
352 TLPM_DEFAULT_IDLE_TIMEOUT_LSB,TLPM_DEFAULT_IDLE_TIMEOUT_MSB,0x00,0x00, //idle timeout in ms
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 A_CHAR hostWakeupEnable[] = {0x31,0xFC,0x4,
358 0x01,0x00,0x00,0x00};
359 /* AR3K vendor specific command for Target Wakeup Enable */
360 A_CHAR targetWakeupEnable[] = {0x31,0xFC,0x4,
361 0x06,0x00,0x00,0x00};
362 /* AR3K vendor specific command for Sleep Enable */
363 A_CHAR sleepEnable[] = {0x4,0xFC,0x1,
365 A_UINT8 *pEvent = NULL;
366 A_UINT8 *pBufferToFree = NULL;
368 if (0 != pConfig->IdleTimeout) {
369 A_UINT8 idle_lsb = pConfig->IdleTimeout & 0xFF;
370 A_UINT8 idle_msb = (pConfig->IdleTimeout & 0xFF00) >> 8;
371 hostWakeupConfig[11] = targetWakeupConfig[11] = idle_lsb;
372 hostWakeupConfig[12] = targetWakeupConfig[12] = idle_msb;
375 if (0 != pConfig->WakeupTimeout) {
376 hostWakeupConfig[19] = targetWakeupConfig[19] = (pConfig->WakeupTimeout & 0xFF);
379 status = SendHCICommandWaitCommandComplete(pConfig,
381 sizeof(hostWakeupConfig),
384 if (pBufferToFree != NULL) {
385 A_FREE(pBufferToFree);
387 if (A_FAILED(status)) {
388 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("HostWakeup Config Failed! \n"));
393 pBufferToFree = NULL;
394 status = SendHCICommandWaitCommandComplete(pConfig,
396 sizeof(targetWakeupConfig),
399 if (pBufferToFree != NULL) {
400 A_FREE(pBufferToFree);
402 if (A_FAILED(status)) {
403 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Target Wakeup Config Failed! \n"));
408 pBufferToFree = NULL;
409 status = SendHCICommandWaitCommandComplete(pConfig,
411 sizeof(hostWakeupEnable),
414 if (pBufferToFree != NULL) {
415 A_FREE(pBufferToFree);
417 if (A_FAILED(status)) {
418 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("HostWakeup Enable Failed! \n"));
423 pBufferToFree = NULL;
424 status = SendHCICommandWaitCommandComplete(pConfig,
426 sizeof(targetWakeupEnable),
429 if (pBufferToFree != NULL) {
430 A_FREE(pBufferToFree);
432 if (A_FAILED(status)) {
433 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Target Wakeup Enable Failed! \n"));
438 pBufferToFree = NULL;
439 status = SendHCICommandWaitCommandComplete(pConfig,
444 if (pBufferToFree != NULL) {
445 A_FREE(pBufferToFree);
447 if (A_FAILED(status)) {
448 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Sleep Enable Failed! \n"));
451 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("AR3K Config: Enable TLPM Completed (status = %d) \n",status));
456 int AR3KConfigure(AR3K_CONFIG_INFO *pConfig)
460 AR_DEBUG_PRINTF(ATH_DEBUG_INFO,("AR3K Config: Configuring AR3K ...\n"));
464 if ((pConfig->pHCIDev == NULL) || (pConfig->pHCIProps == NULL) || (pConfig->pHIFDevice == NULL)) {
469 /* disable asynchronous recv while we issue commands and receive events synchronously */
470 status = HCI_TransportEnableDisableAsyncRecv(pConfig->pHCIDev,FALSE);
471 if (A_FAILED(status)) {
475 if (pConfig->Flags & AR3K_CONFIG_FLAG_FORCE_MINBOOT_EXIT) {
476 status = AR3KExitMinBoot(pConfig);
477 if (A_FAILED(status)) {
483 /* Load patching and PST file if available*/
484 if (A_OK != AthPSInitialize(pConfig)) {
485 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Patch Download Failed!\n"));
488 /* Send HCI reset to make PS tags take effect*/
489 AR3KConfigureSendHCIReset(pConfig);
492 (AR3K_CONFIG_FLAG_SET_AR3K_BAUD | AR3K_CONFIG_FLAG_SET_AR6K_SCALE_STEP)) {
493 status = AR3KConfigureHCIBaud(pConfig);
494 if (A_FAILED(status)) {
501 if (pConfig->PwrMgmtEnabled) {
502 /* the delay is required after the previous HCI reset before further
503 * HCI commands can be issued
506 AR3KEnableTLPM(pConfig);
509 /* re-enable asynchronous recv */
510 status = HCI_TransportEnableDisableAsyncRecv(pConfig->pHCIDev,TRUE);
511 if (A_FAILED(status)) {
519 AR_DEBUG_PRINTF(ATH_DEBUG_INFO,("AR3K Config: Configuration Complete (status = %d) \n",status));
524 int AR3KConfigureExit(void *config)
527 AR3K_CONFIG_INFO *pConfig = (AR3K_CONFIG_INFO *)config;
529 AR_DEBUG_PRINTF(ATH_DEBUG_INFO,("AR3K Config: Cleaning up AR3K ...\n"));
533 if ((pConfig->pHCIDev == NULL) || (pConfig->pHCIProps == NULL) || (pConfig->pHIFDevice == NULL)) {
538 /* disable asynchronous recv while we issue commands and receive events synchronously */
539 status = HCI_TransportEnableDisableAsyncRecv(pConfig->pHCIDev,FALSE);
540 if (A_FAILED(status)) {
545 (AR3K_CONFIG_FLAG_SET_AR3K_BAUD | AR3K_CONFIG_FLAG_SET_AR6K_SCALE_STEP)) {
546 status = AR3KConfigureHCIBaud(pConfig);
547 if (A_FAILED(status)) {
552 /* re-enable asynchronous recv */
553 status = HCI_TransportEnableDisableAsyncRecv(pConfig->pHCIDev,TRUE);
554 if (A_FAILED(status)) {
562 AR_DEBUG_PRINTF(ATH_DEBUG_INFO,("AR3K Config: Cleanup Complete (status = %d) \n",status));