static A_STATUS _do_write_diag(HIF_DEVICE *hifDevice, A_UINT32 addr, A_UINT32 value) { A_STATUS status; status = ar6000_WriteRegDiag(hifDevice, &addr, &value); if (status != A_OK) { AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Cannot force Target to execute ROM!\n")); } return status; }
A_STATUS ar6000_set_uart_config(HIF_DEVICE *hifDevice, A_UINT32 scale, A_UINT32 step) { A_UINT32 regAddress; A_UINT32 regVal; A_STATUS status; regAddress = WLAN_UART_BASE_ADDRESS | UART_CLKDIV_ADDRESS; regVal = ((A_UINT32)scale << 16) | step; /* change the HCI UART scale/step values through the diagnostic window */ status = ar6000_WriteRegDiag(hifDevice, ®Address, ®Val); return status; }
int ar6000_set_uart_config(struct hif_device *hifDevice, u32 scale, u32 step) { u32 regAddress; u32 regVal; int status; regAddress = WLAN_UART_BASE_ADDRESS | UART_CLKDIV_ADDRESS; regVal = ((u32)scale << 16) | step; /* change the HCI UART scale/step values through the diagnostic window */ status = ar6000_WriteRegDiag(hifDevice, ®Address, ®Val); return status; }
A_STATUS ar6000_WriteDataDiag(HIF_DEVICE *hifDevice, A_UINT32 address, A_UCHAR *data, A_UINT32 length) { A_UINT32 count; A_STATUS status = A_OK; for (count = 0; count < length; count += 4, address += 4) { if ((status = ar6000_WriteRegDiag(hifDevice, &address, (A_UINT32 *)&data[count])) != A_OK) { break; } } return status; }
/* reset device */ A_STATUS ar6000_reset_device(HIF_DEVICE *hifDevice, A_UINT32 TargetType) { #if !defined(DWSIM) A_STATUS status = A_OK; A_UINT32 address; A_UINT32 data; do { // address = RESET_CONTROL_ADDRESS; data = RESET_CONTROL_COLD_RST_MASK; /* Hardcode the address of RESET_CONTROL_ADDRESS based on the target type */ if (TargetType == TARGET_TYPE_AR6001) { address = 0x0C000000; } else { if (TargetType == TARGET_TYPE_AR6002) { address = 0x00004000; } else { A_ASSERT(0); } } status = ar6000_WriteRegDiag(hifDevice, &address, &data); if (A_FAILED(status)) { break; } /* * Read back the RESET CAUSE register to ensure that the cold reset * went through. */ msleep(2000); /* 2 second delay to allow things to settle down */ // address = RESET_CAUSE_ADDRESS; /* Hardcode the address of RESET_CAUSE_ADDRESS based on the target type */ if (TargetType == TARGET_TYPE_AR6001) { address = 0x0C0000CC; } else { if (TargetType == TARGET_TYPE_AR6002) { address = 0x000040C0; } else { A_ASSERT(0); } } data = 0; status = ar6000_ReadRegDiag(hifDevice, &address, &data); if (A_FAILED(status)) { break; } AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Reset Cause readback: 0x%X \n",data)); data &= RESET_CAUSE_LAST_MASK; if (data != 2) { AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Unable to cold reset the target \n")); } } while (FALSE); if (A_FAILED(status)) { AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Failed to reset target \n")); } #endif return A_OK; }
A_STATUS ar6000_reset_device_skipflash(HIF_DEVICE *hifDevice) { int i; struct forceROM_s { A_UINT32 addr; A_UINT32 data; }; struct forceROM_s *ForceROM; int szForceROM; A_UINT32 instruction; static struct forceROM_s ForceROM_REV2[] = { /* NB: This works for old REV2 ROM (old). */ {0x00001ff0, 0x175b0027}, /* jump instruction at 0xa0001ff0 */ {0x00001ff4, 0x00000000}, /* nop instruction at 0xa0001ff4 */ {MC_REMAP_TARGET_ADDRESS, 0x00001ff0}, /* remap to 0xa0001ff0 */ {MC_REMAP_COMPARE_ADDRESS, 0x01000040},/* ...from 0xbfc00040 */ {MC_REMAP_SIZE_ADDRESS, 0x00000000}, /* ...1 cache line */ {MC_REMAP_VALID_ADDRESS, 0x00000001}, /* ...remap is valid */ {LOCAL_COUNT_ADDRESS+0x10, 0}, /* clear BMI credit counter */ {RESET_CONTROL_ADDRESS, RESET_CONTROL_WARM_RST_MASK}, }; static struct forceROM_s ForceROM_NEW[] = { /* NB: This works for AR6000 ROM REV3 and beyond. */ {LOCAL_SCRATCH_ADDRESS, AR6K_OPTION_IGNORE_FLASH}, {LOCAL_COUNT_ADDRESS+0x10, 0}, /* clear BMI credit counter */ {RESET_CONTROL_ADDRESS, RESET_CONTROL_WARM_RST_MASK}, }; /* * Examine a semi-arbitrary instruction that's different * in REV2 and other revisions. * NB: If a Host port does not require simultaneous support * for multiple revisions of Target ROM, this code can be elided. */ (void)ar6000_ReadDataDiag(hifDevice, 0x01000040, (A_UCHAR *)&instruction, 4); AR_DEBUG_PRINTF(ATH_LOG_ERR, ("instruction=0x%x\n", instruction)); if (instruction == 0x3c1aa200) { /* It's an old ROM */ ForceROM = ForceROM_REV2; szForceROM = sizeof(ForceROM_REV2)/sizeof(*ForceROM); AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Using OLD method\n")); } else { ForceROM = ForceROM_NEW; szForceROM = sizeof(ForceROM_NEW)/sizeof(*ForceROM); AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Using NEW method\n")); } AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Force Target to execute from ROM....\n")); for (i = 0; i < szForceROM; i++) { if (ar6000_WriteRegDiag(hifDevice, &ForceROM[i].addr, &ForceROM[i].data) != A_OK) { AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Cannot force Target to execute ROM!\n")); return A_ERROR; } } msleep(50); /* delay to allow dragon to come to BMI phase */ return A_OK; }
/* * Call this function just before the call to BMIInit * in order to force* AR6002 rev 1.x firmware to detect a Host. * THIS IS FOR USE ONLY WITH AR6002 REV 1.x. * TBDXXX: Remove this function when REV 1.x is desupported. */ A_STATUS ar6002_REV1_reset_force_host (HIF_DEVICE *hifDevice) { A_INT32 i; struct forceROM_s { A_UINT32 addr; A_UINT32 data; }; struct forceROM_s *ForceROM; A_INT32 szForceROM; A_STATUS status = A_OK; A_UINT32 address; A_UINT32 data; /* Force AR6002 REV1.x to recognize Host presence. * * Note: Use RAM at 0x52df80..0x52dfa0 with ROM Remap entry 0 * so that this workaround functions with AR6002.war1.sh. We * could fold that entire workaround into this one, but it's not * worth the effort at this point. This workaround cannot be * merged into the other workaround because this must be done * before BMI. */ static struct forceROM_s ForceROM_NEW[] = { {0x52df80, 0x20f31c07}, {0x52df84, 0x92374420}, {0x52df88, 0x1d120c03}, {0x52df8c, 0xff8216f0}, {0x52df90, 0xf01d120c}, {0x52df94, 0x81004136}, {0x52df98, 0xbc9100bd}, {0x52df9c, 0x00bba100}, {0x00008000|MC_TCAM_TARGET_ADDRESS, 0x0012dfe0}, /* Use remap entry 0 */ {0x00008000|MC_TCAM_COMPARE_ADDRESS, 0x000e2380}, {0x00008000|MC_TCAM_MASK_ADDRESS, 0x00000000}, {0x00008000|MC_TCAM_VALID_ADDRESS, 0x00000001}, {0x00018000|(LOCAL_COUNT_ADDRESS+0x10), 0}, /* clear BMI credit counter */ {0x00004000|AR6002_RESET_CONTROL_ADDRESS, RESET_CONTROL_WARM_RST_MASK}, }; address = 0x004ed4b0; /* REV1 target software ID is stored here */ status = ar6000_ReadRegDiag(hifDevice, &address, &data); if (A_FAILED(status) || (data != AR6002_VERSION_REV1)) { return A_ERROR; /* Not AR6002 REV1 */ } ForceROM = ForceROM_NEW; szForceROM = sizeof(ForceROM_NEW)/sizeof(*ForceROM); ATH_DEBUG_PRINTF (DBG_MISC_DRV, ATH_DEBUG_TRC, ("Force Target to recognize Host....\n")); for (i = 0; i < szForceROM; i++) { if (ar6000_WriteRegDiag(hifDevice, &ForceROM[i].addr, &ForceROM[i].data) != A_OK) { ATH_DEBUG_PRINTF (DBG_MISC_DRV, ATH_DEBUG_TRC, ("Cannot force Target to recognize Host!\n")); return A_ERROR; } } A_MDELAY(1000); return A_OK; }
/* reset device */ A_STATUS ar6000_reset_device(HIF_DEVICE *hifDevice, A_UINT32 TargetType, A_BOOL waitForCompletion, A_BOOL coldReset) { A_STATUS status = A_OK; A_UINT32 address; A_UINT32 data; do { // Workaround BEGIN // address = RESET_CONTROL_ADDRESS; if (coldReset) { data = RESET_CONTROL_COLD_RST_MASK; } else { data = RESET_CONTROL_MBOX_RST_MASK; } /* Hardcode the address of RESET_CONTROL_ADDRESS based on the target type */ if (TargetType == TARGET_TYPE_AR6001) { address = AR6001_RESET_CONTROL_ADDRESS; } else if (TargetType == TARGET_TYPE_AR6002) { address = AR6002_RESET_CONTROL_ADDRESS; } else if (TargetType == TARGET_TYPE_AR6003) { address = AR6003_RESET_CONTROL_ADDRESS; } else { A_ASSERT(0); } status = ar6000_WriteRegDiag(hifDevice, &address, &data); if (A_FAILED(status)) { break; } if (!waitForCompletion) { break; } #if 0 /* Up to 2 second delay to allow things to settle down */ (void)_delay_until_target_alive(hifDevice, 2000, TargetType); /* * Read back the RESET CAUSE register to ensure that the cold reset * went through. */ // address = RESET_CAUSE_ADDRESS; /* Hardcode the address of RESET_CAUSE_ADDRESS based on the target type */ if (TargetType == TARGET_TYPE_AR6001) { address = 0x0C0000CC; } else if (TargetType == TARGET_TYPE_AR6002) { address = 0x000040C0; } else if (TargetType == TARGET_TYPE_AR6003) { address = 0x000040C0; } else { A_ASSERT(0); } data = 0; status = ar6000_ReadRegDiag(hifDevice, &address, &data); if (A_FAILED(status)) { break; } AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Reset Cause readback: 0x%X \n",data)); data &= RESET_CAUSE_LAST_MASK; if (data != 2) { AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Unable to cold reset the target \n")); } #endif // Workaroud END } while (FALSE); if (A_FAILED(status)) { AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Failed to reset target \n")); } return A_OK; }
static A_STATUS ar6000_hci_transport_ready(HCI_TRANSPORT_HANDLE HCIHandle, HCI_TRANSPORT_PROPERTIES *pProps, void *pContext) { AR6K_HCI_BRIDGE_INFO *pHcidevInfo = (AR6K_HCI_BRIDGE_INFO *)pContext; A_STATUS status; AR_SOFTC_DEV_T *arDev = pHcidevInfo->ar->arDev[0]; pHcidevInfo->pHCIDev = HCIHandle; A_MEMCPY(&pHcidevInfo->HCIProps,pProps,sizeof(*pProps)); AR_DEBUG_PRINTF(ATH_DEBUG_HCI_BRIDGE,("HCI ready (hci:0x%lX, headroom:%d, tailroom:%d blockpad:%d) \n", (unsigned long)HCIHandle, pHcidevInfo->HCIProps.HeadRoom, pHcidevInfo->HCIProps.TailRoom, pHcidevInfo->HCIProps.IOBlockPad)); #ifdef EXPORT_HCI_BRIDGE_INTERFACE A_ASSERT((pProps->HeadRoom + pProps->TailRoom) <= (struct net_device *)(pHcidevInfo->HCITransHdl.netDevice)->hard_header_len); #else A_ASSERT((pProps->HeadRoom + pProps->TailRoom) <= arDev->arNetDev->hard_header_len); #endif /* provide buffers */ RefillRecvBuffers(pHcidevInfo, HCI_ACL_TYPE, MAX_ACL_RECV_BUFS); RefillRecvBuffers(pHcidevInfo, HCI_EVENT_TYPE, MAX_EVT_RECV_BUFS); do { /* start transport */ status = HCI_TransportStart(pHcidevInfo->pHCIDev); if (A_FAILED(status)) { break; } if (!pHcidevInfo->HciNormalMode) { /* in test mode, no need to go any further */ break; } /* The delay is required when AR6K is driving the BT reset line */ /* where time is needed after the BT chip is out of reset (HCI_TransportStart) */ /* and before the first HCI command is issued (AR3KConfigure) */ /* FIXME */ /* The delay should be configurable and be only applied when AR6K driving the BT */ /* reset line. This could be done by some module parameter or based on some HW config */ /* info. For now apply 100ms delay blindly */ A_MDELAY(100); A_MEMZERO(&ar3kconfig,sizeof(ar3kconfig)); ar3kconfig.pHCIDev = pHcidevInfo->pHCIDev; ar3kconfig.pHCIProps = &pHcidevInfo->HCIProps; #ifdef EXPORT_HCI_BRIDGE_INTERFACE ar3kconfig.pHIFDevice = (HIF_DEVICE *)(pHcidevInfo->HCITransHdl.hifDevice); #else ar3kconfig.pHIFDevice = pHcidevInfo->ar->arHifDevice; #endif ar3kconfig.pBtStackHCIDev = pHcidevInfo->pBtStackHCIDev; if (ar3khcibaud != 0) { /* user wants ar3k baud rate change */ ar3kconfig.Flags |= AR3K_CONFIG_FLAG_SET_AR3K_BAUD; ar3kconfig.Flags |= AR3K_CONFIG_FLAG_AR3K_BAUD_CHANGE_DELAY; ar3kconfig.AR3KBaudRate = ar3khcibaud; } if ((hciuartscale != 0) || (hciuartstep != 0)) { /* user wants to tune HCI bridge UART scale/step values */ ar3kconfig.AR6KScale = (A_UINT16)hciuartscale; ar3kconfig.AR6KStep = (A_UINT16)hciuartstep; ar3kconfig.Flags |= AR3K_CONFIG_FLAG_SET_AR6K_SCALE_STEP; } /* configure the AR3K device */ memcpy(ar3kconfig.bdaddr,arDev->bdaddr,6); status = AR3KConfigure(&ar3kconfig); if (A_FAILED(status)) { extern unsigned int setuphci; AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("HCI Bridge: Fail to configure AR3K. No device? Cleanup HCI\n")); pHcidevInfo->ar->exitCallback = NULL; ar6000_cleanup_hci(pHcidevInfo->ar); setuphci = 0; pHcidevInfo->ar->arBTSharing = 0; break; } /* Make sure both AR6K and AR3K have power management enabled */ if (ar3kconfig.PwrMgmtEnabled) { A_UINT32 address, hci_uart_pwr_mgmt_params; /* Fetch the address of the hi_hci_uart_pwr_mgmt_params instance in the host interest area */ address = TARG_VTOP(pHcidevInfo->ar->arTargetType, HOST_INTEREST_ITEM_ADDRESS(pHcidevInfo->ar->arTargetType, hi_hci_uart_pwr_mgmt_params)); status = ar6000_ReadRegDiag(pHcidevInfo->ar->arHifDevice, &address, &hci_uart_pwr_mgmt_params); hci_uart_pwr_mgmt_params &= 0xFFFF; /* wakeup timeout is [31:16] */ hci_uart_pwr_mgmt_params |= (ar3kconfig.WakeupTimeout << 16); status |= ar6000_WriteRegDiag(pHcidevInfo->ar->arHifDevice, &address, &hci_uart_pwr_mgmt_params); if (A_OK != status) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("HCI Bridge: failed to write hci_uart_pwr_mgmt_params!\n")); } /* Fetch the address of the hi_hci_uart_pwr_mgmt_params_ext instance in the host interest area */ address = TARG_VTOP(pHcidevInfo->ar->arTargetType, HOST_INTEREST_ITEM_ADDRESS(pHcidevInfo->ar->arTargetType, hi_hci_uart_pwr_mgmt_params_ext)); status = ar6000_WriteRegDiag(pHcidevInfo->ar->arHifDevice, &address, &ar3kconfig.IdleTimeout); if (A_OK != status) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("HCI Bridge: failed to write hci_uart_pwr_mgmt_params_ext!\n")); } status = HCI_TransportEnablePowerMgmt(pHcidevInfo->pHCIDev, TRUE); if (A_FAILED(status)) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("HCI Bridge: failed to enable TLPM for AR6K! \n")); } } status = bt_register_hci(pHcidevInfo); } while (FALSE); return status; }
/* reset device */ A_STATUS ar6000_reset_device(HIF_DEVICE *hifDevice, A_UINT32 TargetType, A_BOOL waitForCompletion) { A_STATUS status = A_OK; A_UINT32 address; A_UINT32 data; do { data = RESET_CONTROL_COLD_RST_MASK; if (TargetType == TARGET_TYPE_AR6001) { address = AR6001_RESET_CONTROL_ADDRESS; } else if (TargetType == TARGET_TYPE_AR6002) { address = AR6002_RESET_CONTROL_ADDRESS; } else if (TargetType == TARGET_TYPE_AR6003) { address = AR6003_RESET_CONTROL_ADDRESS; } else { A_ASSERT(0); } status = ar6000_WriteRegDiag(hifDevice, &address, &data); if (A_FAILED(status)) { break; } if (!waitForCompletion) { break; } (void)_delay_until_target_alive(hifDevice, 1800, TargetType); if (TargetType == TARGET_TYPE_AR6001) { address = 0x0C0000CC; } else if (TargetType == TARGET_TYPE_AR6002) { address = 0x000040C0; } else if (TargetType == TARGET_TYPE_AR6003) { address = 0x000040C0; } else { A_ASSERT(0); } data = 0; status = ar6000_ReadRegDiag(hifDevice, &address, &data); if (A_FAILED(status)) { break; } AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Reset Cause readback: 0x%X \n",data)); data &= RESET_CAUSE_LAST_MASK; if (data != 2) { AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Unable to cold reset the target \n")); } } while (FALSE); if (A_FAILED(status)) { AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Failed to reset target \n")); } return A_OK; }