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