/* set HTC/Mbox operational parameters, this can only be called when the target is in the * BMI phase */ A_STATUS ar6000_set_htc_params(HIF_DEVICE *hifDevice, A_UINT32 TargetType, A_UINT32 MboxIsrYieldValue, A_UINT8 HtcControlBuffers) { A_STATUS status; A_UINT32 blocksizes[HTC_MAILBOX_NUM_MAX]; do { /* get the block sizes */ status = HIFConfigureDevice(hifDevice, HIF_DEVICE_GET_MBOX_BLOCK_SIZE, blocksizes, sizeof(blocksizes)); if (A_FAILED(status)) { AR_DEBUG_PRINTF(ATH_LOG_ERR,("Failed to get block size info from HIF layer...\n")); break; } /* note: we actually get the block size for mailbox 1, for SDIO the block * size on mailbox 0 is artificially set to 1 */ /* must be a power of 2 */ A_ASSERT((blocksizes[1] & (blocksizes[1] - 1)) == 0); if (HtcControlBuffers != 0) { /* set override for number of control buffers to use */ blocksizes[1] |= ((A_UINT32)HtcControlBuffers) << 16; } /* set the host interest area for the block size */ status = BMIWriteMemory(hifDevice, HOST_INTEREST_ITEM_ADDRESS(TargetType, hi_mbox_io_block_sz), (A_UCHAR *)&blocksizes[1], 4); if (A_FAILED(status)) { AR_DEBUG_PRINTF(ATH_LOG_ERR,("BMIWriteMemory for IO block size failed \n")); break; } AR_DEBUG_PRINTF(ATH_LOG_INF,("Block Size Set: %d (target address:0x%X)\n", blocksizes[1], HOST_INTEREST_ITEM_ADDRESS(TargetType, hi_mbox_io_block_sz))); if (MboxIsrYieldValue != 0) { /* set the host interest area for the mbox ISR yield limit */ status = BMIWriteMemory(hifDevice, HOST_INTEREST_ITEM_ADDRESS(TargetType, hi_mbox_isr_yield_limit), (A_UCHAR *)&MboxIsrYieldValue, 4); if (A_FAILED(status)) { AR_DEBUG_PRINTF(ATH_LOG_ERR,("BMIWriteMemory for yield limit failed \n")); break; } } } while (FALSE); return status; }
/* can only be called during bmi init stage */ A_STATUS ar6000_set_hci_bridge_flags(HIF_DEVICE *hifDevice, A_UINT32 TargetType, A_UINT32 Flags) { A_STATUS status = A_OK; do { if (TargetType != TARGET_TYPE_AR6003) { AR_DEBUG_PRINTF(ATH_DEBUG_WARN, ("Target Type:%d, does not support HCI bridging! \n", TargetType)); break; } /* set hci bridge flags */ status = BMIWriteMemory(hifDevice, HOST_INTEREST_ITEM_ADDRESS(TargetType, hi_hci_bridge_flags), (A_UCHAR *)&Flags, 4); } while (FALSE); return status; }
static A_STATUS prepare_MCKINLEY(HIF_DEVICE *hifDevice, A_UINT32 TargetVersion) { A_STATUS status = A_OK; A_UINT32 value = 0; /* force the setting to disable sleep for Bringup FIXME_MK */ value |= WLAN_SYSTEM_SLEEP_DISABLE_MASK; status = BMIWriteMemory(hifDevice, HOST_INTEREST_ITEM_ADDRESS(TARGET_TYPE_AR6002, hi_system_sleep_setting), (A_UCHAR *)&value, 4); return status; }
/* Modules for firmware download */ A_STATUS configure_ar6000(HIF_DEVICE *hifDevice, A_UINT32 TargetType, A_UINT32 TargetVersion, A_BOOL enableUART, A_BOOL timerWAR, A_UINT32 clkFreq, wchar_t *fileName, wchar_t *fileRoot, A_BOOL bCompressed, A_BOOL isColdBoot, wchar_t *eepromFile) { A_STATUS status = A_OK; A_UINT32 value = 0; A_UINT32 oldSleep = 0; /* do any target-specific preparation that can be done through BMI */ do { if (enableUART) { A_UINT32 uartparam; uartparam = 1; status = BMIWriteMemory(hifDevice, HOST_INTEREST_ITEM_ADDRESS(TargetType, hi_serial_enable), (A_UCHAR *)&uartparam, 4); if (status != A_OK) { break; } } value = HTC_PROTOCOL_VERSION; status = BMIWriteMemory (hifDevice, HOST_INTEREST_ITEM_ADDRESS (TargetType, hi_app_host_interest), (A_UCHAR *)&value, 4); if (status != A_OK) { break; } /* Selectively enable/disable the WAR for Timer Hang Symptom in the * firmware by setting a bit in the AR6K Scratch register. The firmware will * read this during init and appropriately enable/disable the WAR. * This setting will be retained in the firmware till target reset. */ if (timerWAR) { A_UINT32 timerparam; status = BMIReadMemory(hifDevice, HOST_INTEREST_ITEM_ADDRESS(TargetType, hi_option_flag), (A_UCHAR *)&timerparam, 4); if (status != A_OK) { break; } timerparam |= HI_OPTION_TIMER_WAR; status = BMIWriteMemory(hifDevice, HOST_INTEREST_ITEM_ADDRESS(TargetType, hi_option_flag), (A_UCHAR *)&timerparam, 4); if (status != A_OK) { break; } } if (TargetType == TARGET_TYPE_AR6001) { #ifdef FLASH_18V // Change the flash access time for 1.8V flash to 150ns status = BMIWriteSOCRegister (hifDevice, 0xac004004, 0x920100d1); if (status != A_OK) { break; } #endif } /* set the firmware mode to AP */ { A_UINT32 param; A_UINT32 fwmode = HI_OPTION_FW_MODE_BSS_STA; if (BMIReadMemory(hifDevice, HOST_INTEREST_ITEM_ADDRESS(TargetType, hi_option_flag), (A_UCHAR *)¶m,4)!= A_OK) { return -1; } param |= (fwmode << HI_OPTION_FW_MODE_SHIFT); if (BMIWriteMemory(hifDevice, HOST_INTEREST_ITEM_ADDRESS(TargetType, hi_option_flag), (A_UCHAR *)¶m,4) != A_OK) { return -1; } } if (TargetType == TARGET_TYPE_AR6002) { // Store the value of sleep oldSleep = 0x0; status = BMIReadSOCRegister (hifDevice, 0x40C4, &oldSleep); if (status != A_OK) { break; } // disable sleep status = BMIWriteSOCRegister (hifDevice, 0x40C4, oldSleep | 0x1); if (status != A_OK) { break; } status = ar6002_download_image(hifDevice, TargetVersion, fileName, fileRoot, bCompressed,isColdBoot); if (status != A_OK) { break; } // Restore the value of sleep status = BMIWriteSOCRegister (hifDevice, 0x40C4, oldSleep); if (status != A_OK) { break; } if ((TargetVersion == AR6002_VERSION_REV2) && (AR6002_REV2_APP_START_OVERRIDE != 0)) { /* override default app start address known to ROM */ status = BMISetAppStart(hifDevice, AR6002_REV2_APP_START_OVERRIDE); if (status != A_OK) { break; } } } status = ar6000_configure_clock (hifDevice, TargetType, TargetVersion, clkFreq); if (status != A_OK) { break; } status = eeprom_ar6000_transfer (hifDevice, TargetType, fileRoot, eepromFile); if (status != A_OK) { break; } } while (FALSE); return status; }
A_STATUS ar6002_download_image(HIF_DEVICE *hifDevice, A_UINT32 TargetVersion, wchar_t *fileName, wchar_t *fileRoot, A_BOOL bCompressed, A_BOOL isColdBoot) { A_UINT32 address = 0; A_STATUS status = A_OK; A_UINT32 ini_patch_address = 0; do { address = AR6002_ATHWLAN_REV2_ADDRESS; if (isColdBoot) { #ifdef EMBEDDED_AR6K_FIRMWARE if (!wcscmp(fileName, TCMD_BINARY_REV2_STR)) { #ifdef CONFIG_HOST_TCMD_SUPPORT status = download_binary (hifDevice, address, fileName, fileRoot, bCompressed, GET_TCMD_CACHE_INFO()); #endif } else if (!wcscmp(fileName, ART_BINARY_REV2_STR)) { #ifdef WINCE_ART status = download_binary (hifDevice, address, fileName, fileRoot, bCompressed, GET_ART_CACHE_INFO()); #endif } else { status = download_binary (hifDevice, address, fileName, fileRoot, bCompressed, GET_FIRMWARE_CACHE_INFO()); } #else status = download_binary (hifDevice, address, fileName, fileRoot, bCompressed, GET_FIRMWARE_CACHE_INFO()); #endif if (status != A_OK) { break; } #ifdef EMBEDDED_AR6K_FIRMWARE #ifdef AR6K_ROMPATCH_APPLY status = apply_patch (hifDevice, TargetVersion, WLAN_PATCH_REV2_STR, fileRoot, GET_ROMPATCH_CACHE_INFO()); if (status != A_OK) { break; } #endif #else status = apply_patch (hifDevice, TargetVersion, WLAN_PATCH_REV2_STR, fileRoot, GET_ROMPATCH_CACHE_INFO()); if (status != A_OK) { break; } #endif // Download INI Patch address = AR6002_INIPATCH_REV2_ADDRESS; status = download_binary(hifDevice, address, INIPATCH_REV2_STR, fileRoot, FALSE, GET_DATAPATCH_CACHE_INFO()); if (status != A_OK) { break; } } address = AR6002_INIPATCH_REV2_ADDRESS; status = BMIWriteMemory(hifDevice, AR6002_HOST_INTEREST_ITEM_ADDRESS(hi_dset_list_head), (A_UCHAR *)&address, 4); if (status != A_OK) { break; } } while (FALSE); return status; }
A_STATUS apply_patch (HIF_DEVICE *hifDevice, A_UINT32 TargetVersion, wchar_t *patchFile, wchar_t *fileRoot, AR6K_BIN_CACHE_INFO *pRomCache) { A_STATUS status = A_OK; HANDLE fd = INVALID_HANDLE_VALUE; wchar_t filePath[128]; A_UINT32 ret = 0; A_UINT32 id = 0; A_UINT32 tpid = 0; A_UINT32 chkSum = 0; A_UINT32 count = 0; A_UINT32 max = 0; A_UINT32 cmd = 0; A_UINT32 romAddr = 0; A_UINT32 ramAddr = 0; A_UINT32 reMapSz = 0; A_UCHAR *buffer = NULL; A_UINT32 length = 0; A_UINT32 i = 0; BY_HANDLE_FILE_INFORMATION finfo; A_UINT32 fileSize = 0; do { if (pRomCache->Valid) { buffer = pRomCache->pData; fileSize = pRomCache->ActualLength; } else { if ( wcslen(patchFile) + wcslen(fileRoot) > 127 ) { ATHR_DISPLAY_MSG (L"CAR6K::WARNING!!!! :: File Name Very Long :: ====>"); return A_ERROR; } wcscpy(filePath,fileRoot); wcscat(filePath,patchFile); ATHR_DISPLAY_MSG (L"file %s \n",filePath); //Read the patch distribution file if ( (fd = CreateFile (filePath, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE) { ATHR_DISPLAY_MSG (L"CAR6K:: No Patch File :: ====> %s", filePath); break; } if (!GetFileInformationByHandle(fd, &finfo)) { ATHR_DISPLAY_MSG (L"CAR6K::WARNING!!!! :: File Size Error :: ====> %s", filePath); status = A_ERROR; break; } fileSize = finfo.nFileSizeLow; if ((buffer=A_MALLOC(fileSize)) == NULL) { ATHR_DISPLAY_MSG (L"CAR6K::WARNING!!!! :: Unable allocated memory :: ====> %d",fileSize); status = A_ERROR; break; } if ( !ReadFile(fd, buffer, fileSize, &ret, NULL) || (ret != fileSize)) { ATHR_DISPLAY_MSG (L"CAR6K::WARNING!!!! :: Unable to read rpdf ID from :: ====> %s",filePath); status = A_ERROR; break; } if (pRomCache->Static) { pRomCache->Valid = TRUE; pRomCache->pData = buffer; pRomCache->ActualLength = fileSize; pRomCache->MaxLength = fileSize; } } id = *((A_UINT32 *)buffer); buffer += sizeof(id); chkSum = *((A_UINT32 *)buffer); buffer += sizeof(chkSum); count = *((A_UINT32 *)buffer); buffer += sizeof(count); if ( TargetVersion == AR6002_VERSION_REV2 ) { max = AR6002_REV2_MAX_PATCHES; } if (count > max) { ATHR_DISPLAY_MSG (L"CAR6K::WARNING!!!! :: Maximum patches supported :: %d ====> %d",max,count); status = A_ERROR; break; } for (; count; count--) { cmd = 0; romAddr = 0; ramAddr = 0; reMapSz = 0; length = 0; tpid = 0; cmd = *((A_UINT32 *)buffer); buffer += sizeof(cmd); if ( cmd != RPDF_CMD_INSTALL && cmd != RPDF_CMD_INST_ACT ) { ATHR_DISPLAY_MSG (L"CAR6K::WARNING!!!! :: Unknown command in patch specification :: ====> %d",cmd); status = A_ERROR; break; } reMapSz= *((A_UINT32 *)buffer); buffer += sizeof(reMapSz); if ( reMapSz == 0 || reMapSz & (reMapSz-1) ) { ATHR_DISPLAY_MSG (L"CAR6K::WARNING!!!! :: Invalid remap size :: ====> 0x%x",reMapSz); status = A_ERROR; break; } romAddr= *((A_UINT32 *)buffer); buffer += sizeof(romAddr); ramAddr= *((A_UINT32 *)buffer); buffer += sizeof(ramAddr); length= *((A_UINT32 *)buffer); buffer += sizeof(length); if (length > 0) { status = BMIWriteMemory(hifDevice, ramAddr, buffer, length); if (status != A_OK) { ATHR_DISPLAY_MSG (L"CAR6K::WARNING!!!! :: Unable write patch to target :: ====> "); break; } buffer += length; } if (cmd == RPDF_CMD_INST_ACT || cmd == RPDF_CMD_INSTALL) { status = BMIrompatchInstall(hifDevice, romAddr, ramAddr, reMapSz, 0, &tpid); if (status != A_OK) { ATHR_DISPLAY_MSG (L"CAR6K::WARNING!!!! :: Unable write patch registers in target :: ====> "); break; } InstalledPatches[NumPatches++] = tpid; } if (cmd == RPDF_CMD_INST_ACT && NumPatches) { status = BMIrompatchActivate(hifDevice, NumPatches, InstalledPatches); if (status != A_OK) { ATHR_DISPLAY_MSG (L"CAR6K::WARNING!!!! :: Unable activate patch in target :: ====> "); break; } } } } while (FALSE); if ((!pRomCache->Valid) && (buffer)) { A_FREE(buffer); } if (fd) { CloseHandle (fd); } NumPatches = 0; return status; }
A_STATUS download_binary (HIF_DEVICE *hifDevice, A_UINT32 address, wchar_t *fileName, wchar_t *fileRoot, A_BOOL bCompressed, AR6K_BIN_CACHE_INFO *pBinCache) { A_STATUS status = A_OK; A_UCHAR *buffer = NULL; A_UINT32 length = 0; A_UINT32 fileSize = 0; A_UINT32 next_address=0; A_INT32 file_left = 0; size_t nSize; wchar_t filePath[128]; HANDLE fd = NULL; BY_HANDLE_FILE_INFORMATION finfo; A_BOOL fillCache = FALSE; A_MEMZERO(&finfo, sizeof(finfo)); if ( wcslen(fileName) + wcslen(fileRoot) > 127 ) { ATHR_DISPLAY_MSG (L"CAR6K::WARNING!!!! :: File Name Very Long :: ====>"); return A_ERROR; } wcscpy(filePath,fileRoot); wcscat(filePath,fileName); ATHR_DISPLAY_MSG (L"file %s \n",filePath); do { if (pBinCache->Valid) { /* binary cache is valid */ if (bCompressed) { status = BMILZStreamStart (hifDevice, address); if (A_FAILED(status)) { break; } } if (bCompressed) { A_UINT32 lastWord = 0; A_UINT32 lastWordOffset = pBinCache->ActualLength & ~0x3; A_UINT32 unalignedBytes = pBinCache->ActualLength & 0x3; if (unalignedBytes) { /* copy the last word into a zero padded buffer */ A_MEMCPY(&lastWord, &pBinCache->pData[lastWordOffset], unalignedBytes); } status = BMILZData(hifDevice, pBinCache->pData, lastWordOffset); if (A_FAILED(status)) { break; } if (unalignedBytes) { status = BMILZData(hifDevice, (A_UINT8 *)&lastWord, 4); } } else { status = BMIWriteMemory(hifDevice, address, pBinCache->pData, A_ROUND_UP(pBinCache->ActualLength,4)); } if (bCompressed && A_SUCCESS(status)) { // // Close compressed stream and open a new (fake) one. This serves mainly to flush Target caches. // status = BMILZStreamStart (hifDevice, 0x00); if (A_FAILED(status)) { break; } } /* all done */ break; } //Determine the length of the file if ( (fd = CreateFile (filePath, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE) { status = A_ERROR; ATHR_DISPLAY_MSG (L"CAR6K::WARNING!!!! :: File Not Found :: ====> %s", filePath); break; } if (!GetFileInformationByHandle(fd, &finfo)) { ATHR_DISPLAY_MSG (L"CAR6K::WARNING!!!! :: File Size Error :: ====> %s", filePath); status = A_ERROR; break; } fileSize = finfo.nFileSizeLow; file_left = fileSize; if ((pBinCache->pData != NULL) && (!pBinCache->Static)) { /* binary caching is supported */ A_ASSERT(!pBinCache->Valid); if (fileSize <= pBinCache->MaxLength) { /* size if good, flag to cache this binary when read from the filesystem */ fillCache = TRUE; pBinCache->ActualLength = 0; /* reset */ } else { /* cache is not big enough to hold data */ A_ASSERT(FALSE); ATHR_DISPLAY_MSG (L"AR6K::WARNING!!!! :: File :%s (%d bytes) too big for cache (max=%d)", filePath, fileSize, pBinCache->MaxLength); } } // // zero data buffer and init length // buffer = (A_UCHAR *)A_MALLOC(MAX_BUF); if (NULL == buffer) { status = A_ERROR; break; } if (bCompressed) { status = BMILZStreamStart (hifDevice, address); if (status != A_OK) { break; } } while (file_left) { length = (file_left < (MAX_BUF)) ? file_left : MAX_BUF; if (bCompressed) { // // 0 pad last word of data to avoid messy uncompression // ((A_UINT32 *)buffer)[((length-1)/4)] = 0; } if (!ReadFile( fd, buffer, length, &nSize, NULL) || nSize != length) { ATHR_DISPLAY_MSG (L"CAR6K::WARNING!!!! :: ReadFile Error :: ====>"); status = A_ERROR; break; } next_address = address + fileSize - file_left; // // We round up the requested length because some SDIO Host controllers can't handle other lengths. // This generally isn't a problem for users, but it's something to be aware of. // length = A_ROUND_UP(length, 4); if (bCompressed) { status = BMILZData(hifDevice, buffer, length); } else { status = BMIWriteMemory(hifDevice, next_address, buffer, length); } if (status != A_OK) { break; } if (fillCache) { CopyChunkToBinCache(pBinCache, buffer, length); } if (file_left >= MAX_BUF) { file_left = file_left - MAX_BUF; } else { file_left = 0; } }; if (status != A_OK) { break; } if (fillCache) { /* cache was filled, mark it valid */ pBinCache->Valid = TRUE; } if (bCompressed) { // // Close compressed stream and open a new (fake) one. This serves mainly to flush Target caches. // status = BMILZStreamStart (hifDevice, 0x00); if (status != A_OK) { break; } } } while (FALSE); if (buffer) { free (buffer); buffer = NULL; } if (fd) { CloseHandle (fd); } return status; }
static A_STATUS ar6000_configure_clock (HIF_DEVICE *hifDevice, A_UINT32 TargetType, A_UINT32 TargetVersion, A_UINT32 clkFreq) { A_UINT32 ext_clk_detected = 0; A_STATUS status = A_OK; do { if (TargetType == TARGET_TYPE_AR6001) { status = BMIWriteSOCRegister(hifDevice, 0xAC000020, 0x203); if (status != A_OK) { break; } status = BMIWriteSOCRegister (hifDevice, 0xAC000024, 0x203); if (status != A_OK) { break; } } if (TargetType == TARGET_TYPE_AR6002) { if (TargetVersion == AR6002_VERSION_REV2) { status = BMIReadMemory(hifDevice, HOST_INTEREST_ITEM_ADDRESS(TargetType, hi_ext_clk_detected), (A_UCHAR *)&ext_clk_detected, 4); if (status != A_OK) { break; } #ifdef FORCE_INTERNAL_CLOCK status = BMIWriteSOCRegister (hifDevice, 0x40E0, 0x10000); if (status != A_OK) { break; } status = BMIWriteSOCRegister (hifDevice, 0x4028, 0x0); if (status != A_OK) { break; } #else // LPO_CAL.Enable for internal clock if (ext_clk_detected == 0x0) { status = BMIWriteSOCRegister (hifDevice, 0x40E0, 0x10000); if (status != A_OK) { break; } } #endif // Run at 40/44 MHz clock status = BMIWriteSOCRegister (hifDevice, 0x4020, 0x0); if (status != A_OK) { break; } } // Write refclk status = BMIWriteMemory(hifDevice, HOST_INTEREST_ITEM_ADDRESS(TargetType, hi_refclk_hz), (A_UCHAR *)&clkFreq, 4); if (status != A_OK) { break; } } } while (FALSE); return status; }