blob: 57936ba86038f177bc22173e1f65914b9c61db62 [file] [log] [blame]
/*
* HwInit.c
*
* Copyright(c) 1998 - 2009 Texas Instruments. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name Texas Instruments nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*******************************************************************************/
/* */
/* MODULE: HwInit.c */
/* PURPOSE: HwInit module manages the init process of the TNETW, included */
/* firmware download process. It shall perform Hard Reset the chip */
/* if possible (this will require a Reset line to be connected to */
/* the host); Start InterfaceCtrl; Download NVS and FW */
/* */
/* */
/*******************************************************************************/
#define __FILE_ID__ FILE_ID_105
#include "tidef.h"
#include "osApi.h"
#include "report.h"
#include "HwInit_api.h"
#include "FwEvent_api.h"
#include "TwIf.h"
#include "TWDriver.h"
#include "TWDriverInternal.h"
#include "eventMbox_api.h"
#include "CmdBld.h"
#include "CmdMBox_api.h"
#ifdef TI_RANDOM_DEFAULT_MAC
#include <linux/random.h>
#include <linux/jiffies.h>
#endif
/* remove the chipID check when WL6-PG1.0 becomes obsolete (temporary global variable!!) */
TI_BOOL bChipIs1273Pg10 = TI_TRUE;
extern void TWD_FinalizeOnFailure (TI_HANDLE hTWD);
extern void cmdBld_FinalizeDownload (TI_HANDLE hCmdBld, TBootAttr *pBootAttr, FwStaticData_t *pFwInfo);
/************************************************************************
* Defines
************************************************************************/
/* Download phase partition */
#define PARTITION_DOWN_MEM_ADDR 0
#define PARTITION_DOWN_MEM_SIZE 0x177C0
#define PARTITION_DOWN_REG_ADDR REGISTERS_BASE
#define PARTITION_DOWN_REG_SIZE 0x8800
/* Working phase partition */
#define PARTITION_WORK_MEM_ADDR1 0x40000
#define PARTITION_WORK_MEM_SIZE1 0x14FC0
#define PARTITION_WORK_MEM_ADDR2 REGISTERS_BASE
#define PARTITION_WORK_MEM_SIZE2 0xA000
#define PARTITION_WORK_MEM_ADDR3 0x3004F8
#define PARTITION_WORK_MEM_SIZE3 0x4
#define PARTITION_WORK_MEM_ADDR4 0x40404
/* DRPW setting partition */
#define PARTITION_DRPW_MEM_ADDR 0x40000
#define PARTITION_DRPW_MEM_SIZE 0x14FC0
#define PARTITION_DRPW_REG_ADDR DRPW_BASE
#define PARTITION_DRPW_REG_SIZE 0x6000
/* Total range of bus addresses range */
#define PARTITION_TOTAL_ADDR_RANGE 0x1FFC0
/* Maximal block size in a single SDIO transfer --> Firmware image load chunk size */
#ifdef _VLCT_
#define MAX_SDIO_BLOCK (4000)
#else
#define MAX_SDIO_BLOCK (500)
#endif
#define ACX_EEPROMLESS_IND_REG (SCR_PAD4)
#define USE_EEPROM (0)
#define SOFT_RESET_MAX_TIME (1000000)
#define SOFT_RESET_STALL_TIME (1000)
#define NVS_DATA_BUNDARY_ALIGNMENT (4)
#define MAX_HW_INIT_CONSECUTIVE_TXN 15
#define WORD_SIZE 4
#define WORD_ALIGNMENT_MASK 0x3
#define DEF_NVS_SIZE ((NVS_PRE_PARAMETERS_LENGTH) + (NVS_TX_TYPE_INDEX) + 4)
#define RADIO_SM_WAIT_LOOP 32
#define FREF_CLK_FREQ_MASK 0x7
#define FREF_CLK_TYPE_MASK BIT_3
#define FREF_CLK_POLARITY_MASK BIT_4
#define FREF_CLK_TYPE_BITS 0xfffffe7f
#define CLK_REQ_PRCM 0x100
#define FREF_CLK_POLARITY_BITS 0xfffff8ff
#define CLK_REQ_OUTN_SEL 0x700
/************************************************************************
* Macros
************************************************************************/
#define SET_DEF_NVS(aNVS) aNVS[0]=0x01; aNVS[1]=0x6d; aNVS[2]=0x54; aNVS[3]=0x56; aNVS[4]=0x34; \
aNVS[5]=0x12; aNVS[6]=0x28; aNVS[7]=0x01; aNVS[8]=0x71; aNVS[9]=0x54; \
aNVS[10]=0x00; aNVS[11]=0x08; aNVS[12]=0x00; aNVS[13]=0x00; aNVS[14]=0x00; \
aNVS[15]=0x00; aNVS[16]=0x00; aNVS[17]=0x00; aNVS[18]=0x00; aNVS[19]=0x00; \
aNVS[20]=0x00; aNVS[21]=0x00; aNVS[22]=0x00; aNVS[23]=0x00; aNVS[24]=eNVS_NON_FILE;\
aNVS[25]=0x00; aNVS[26]=0x00; aNVS[27]=0x00;
#define SET_PARTITION(pPartition,uAddr1,uMemSize1,uAddr2,uMemSize2,uAddr3,uMemSize3,uAddr4) \
((TPartition*)pPartition)[0].uMemAdrr = uAddr1; \
((TPartition*)pPartition)[0].uMemSize = uMemSize1; \
((TPartition*)pPartition)[1].uMemAdrr = uAddr2; \
((TPartition*)pPartition)[1].uMemSize = uMemSize2; \
((TPartition*)pPartition)[2].uMemAdrr = uAddr3; \
((TPartition*)pPartition)[2].uMemSize = uMemSize3; \
((TPartition*)pPartition)[3].uMemAdrr = uAddr4;
#define HW_INIT_PTXN_SET(pHwInit, pTxn) pTxn = (TTxnStruct*)&(pHwInit->aHwInitTxn[pHwInit->uTxnIndex].tTxnStruct);
#define BUILD_HW_INIT_TXN_DATA(pHwInit, pTxn, uAddr, uVal, uSize, direction, fCB, hCB) \
HW_INIT_PTXN_SET(pHwInit, pTxn) \
TXN_PARAM_SET_DIRECTION(pTxn, direction); \
pHwInit->aHwInitTxn[pHwInit->uTxnIndex].uData = (TI_UINT32)uVal; \
BUILD_TTxnStruct(pTxn, uAddr, &(pHwInit->aHwInitTxn[pHwInit->uTxnIndex].uData), uSize, fCB, hCB)
#define BUILD_HW_INIT_FW_STATIC_TXN(pHwInit, pTxn, uAddr, fCB, hCB) \
HW_INIT_PTXN_SET(pHwInit, pTxn) \
TXN_PARAM_SET_DIRECTION(pTxn, TXN_DIRECTION_READ); \
BUILD_TTxnStruct(pTxn, uAddr, &(pHwInit->tFwStaticTxn.tFwStaticInfo), sizeof(FwStaticData_t), fCB, hCB)
#define BUILD_HW_INIT_FW_DL_TXN(pHwInit, pTxn, uAddr, uVal, uSize, direction, fCB, hCB) \
HW_INIT_PTXN_SET(pHwInit, pTxn) \
TXN_PARAM_SET_DIRECTION(pTxn, direction); \
BUILD_TTxnStruct(pTxn, uAddr, uVal, uSize, fCB, hCB)
#define SET_DRP_PARTITION(pPartition)\
SET_PARTITION(pPartition, PARTITION_DRPW_MEM_ADDR, PARTITION_DRPW_MEM_SIZE, PARTITION_DRPW_REG_ADDR, PARTITION_DRPW_REG_SIZE, 0, 0, 0)
#define SET_FW_LOAD_PARTITION(pPartition,uFwAddress)\
SET_PARTITION(pPartition,uFwAddress,PARTITION_DOWN_MEM_SIZE, PARTITION_DOWN_REG_ADDR, PARTITION_DOWN_REG_SIZE,0,0,0)
#define SET_WORK_PARTITION(pPartition)\
SET_PARTITION(pPartition,PARTITION_WORK_MEM_ADDR1, PARTITION_WORK_MEM_SIZE1, PARTITION_WORK_MEM_ADDR2, PARTITION_WORK_MEM_SIZE2, PARTITION_WORK_MEM_ADDR3, PARTITION_WORK_MEM_SIZE3, PARTITION_WORK_MEM_ADDR4)
/* Handle return status inside a state machine */
#define EXCEPT(phwinit,status) \
switch (status) { \
case TI_OK: \
case TXN_STATUS_OK: \
case TXN_STATUS_COMPLETE: \
break; \
case TXN_STATUS_PENDING: \
return TXN_STATUS_PENDING; \
default: \
TWD_FinalizeOnFailure (phwinit->hTWD); \
return TXN_STATUS_ERROR; \
}
/* Handle return status inside an init sequence state machine */
#define EXCEPT_I(phwinit,status) \
switch (status) { \
case TI_OK: \
case TXN_STATUS_COMPLETE: \
break; \
case TXN_STATUS_PENDING: \
phwinit->uInitSeqStatus = status; \
return TXN_STATUS_PENDING; \
default: \
TWD_FinalizeOnFailure (phwinit->hTWD); \
return TXN_STATUS_ERROR; \
}
/* Handle return status inside a load image state machine */
#define EXCEPT_L(phwinit,status) \
switch (status) { \
case TXN_STATUS_OK: \
case TXN_STATUS_COMPLETE: \
break; \
case TXN_STATUS_PENDING: \
phwinit->DownloadStatus = status; \
return TXN_STATUS_PENDING; \
default: \
phwinit->DownloadStatus = status; \
TWD_FinalizeOnFailure (phwinit->hTWD); \
return TXN_STATUS_ERROR; \
}
/************************************************************************
* Types
************************************************************************/
enum
{
REF_FREQ_19_2 = 0,
REF_FREQ_26_0 = 1,
REF_FREQ_38_4 = 2,
REF_FREQ_40_0 = 3,
REF_FREQ_33_6 = 4,
REF_FREQ_NUM = 5
};
enum
{
LUT_PARAM_INTEGER_DIVIDER = 0,
LUT_PARAM_FRACTIONAL_DIVIDER = 1,
LUT_PARAM_ATTN_BB = 2,
LUT_PARAM_ALPHA_BB = 3,
LUT_PARAM_STOP_TIME_BB = 4,
LUT_PARAM_BB_PLL_LOOP_FILTER = 5,
LUT_PARAM_NUM = 6
};
typedef struct
{
TTxnStruct tTxnStruct;
TI_UINT32 uData;
} THwInitTxn;
typedef struct
{
TTxnStruct tTxnStruct;
FwStaticData_t tFwStaticInfo;
} TFwStaticTxn;
/* The HW Init module object */
typedef struct
{
/* Handles */
TI_HANDLE hOs;
TI_HANDLE hReport;
TI_HANDLE hTWD;
TI_HANDLE hBusTxn;
TI_HANDLE hTwIf;
TI_HANDLE hFileInfo; /* holds parameters of FW Image Portion - for DW Download */
TEndOfHwInitCb fInitHwCb;
/* Firmware image ptr */
TI_UINT8 *pFwBuf;
/* Firmware image length */
TI_UINT32 uFwLength;
TI_UINT32 uFwAddress;
TI_UINT32 bFwBufLast;
TI_UINT32 uFwLastAddr;
/* EEPROM image ptr */
TI_UINT8 *pEEPROMBuf;
/* EEPROM image length */
TI_UINT32 uEEPROMLen;
TI_UINT8 *pEEPROMCurPtr;
TI_UINT32 uEEPROMCurLen;
TBootAttr tBootAttr;
TI_HANDLE hHwCtrl;
ETxnStatus DownloadStatus;
/* Upper module callback for the init stage */
fnotify_t fCb;
/* Upper module handle for the init stage */
TI_HANDLE hCb;
/* Init stage */
TI_UINT32 uInitStage;
/* Reset statge */
TI_UINT32 uResetStage;
/* EEPROM burst stage */
TI_UINT32 uEEPROMStage;
/* Init state machine temporary data */
TI_UINT32 uInitData;
/* ELP command image */
TI_UINT32 uElpCmd;
/* Chip ID */
TI_UINT32 uChipId;
/* Boot state machine temporary data */
TI_UINT32 uBootData;
TI_UINT32 uSelfClearTime;
TI_UINT8 uEEPROMBurstLen;
TI_UINT8 uEEPROMBurstLoop;
TI_UINT32 uEEPROMRegAddr;
TI_STATUS uEEPROMStatus;
TI_UINT32 uNVSStartAddr;
TI_UINT32 uNVSNumChar;
TI_UINT32 uNVSNumByte;
TI_STATUS uNVSStatus;
TI_UINT32 uScrPad6;
TI_UINT32 uRefFreq;
TI_UINT32 uInitSeqStage;
TI_STATUS uInitSeqStatus;
TI_UINT32 uLoadStage;
TI_UINT32 uBlockReadNum;
TI_UINT32 uBlockWriteNum;
TI_UINT32 uPartitionLimit;
TI_UINT32 uFinStage;
TI_UINT32 uFinData;
TI_UINT32 uFinLoop;
TI_UINT32 uRegStage;
TI_UINT32 uRegLoop;
TI_UINT32 uRegSeqStage;
TI_UINT32 uRegData;
/* Top register Read/Write SM temporary data*/
TI_UINT32 uTopRegAddr;
TI_UINT32 uTopRegValue;
TI_UINT32 uTopRegMask;
TI_UINT32 uTopRegUpdateValue;
TI_UINT32 uTopStage;
TI_UINT8 auFwTmpBuf [WSPI_PAD_LEN_WRITE + MAX_SDIO_BLOCK];
TFinalizeCb fFinalizeDownload;
TI_HANDLE hFinalizeDownload;
/* Size of the Fw image, retrieved from the image itself */
TI_UINT32 uFwDataLen;
TI_UINT8 aDefaultNVS[DEF_NVS_SIZE];
TI_UINT8 uTxnIndex;
THwInitTxn aHwInitTxn[MAX_HW_INIT_CONSECUTIVE_TXN];
TFwStaticTxn tFwStaticTxn;
TI_UINT32 uSavedDataForWspiHdr; /* For saving the 4 bytes before the NVS data for WSPI case
where they are overrun by the WSPI BusDrv */
TPartition aPartition[NUM_OF_PARTITION];
} THwInit;
/************************************************************************
* Local Functions Prototypes
************************************************************************/
static void hwInit_SetPartition (THwInit *pHwInit,
TPartition *pPartition);
static TI_STATUS hwInit_BootSm (TI_HANDLE hHwInit);
static TI_STATUS hwInit_ResetSm (TI_HANDLE hHwInit);
static TI_STATUS hwInit_EepromlessStartBurstSm (TI_HANDLE hHwInit);
static TI_STATUS hwInit_LoadFwImageSm (TI_HANDLE hHwInit);
static TI_STATUS hwInit_FinalizeDownloadSm (TI_HANDLE hHwInit);
static TI_STATUS hwInit_TopRegisterRead(TI_HANDLE hHwInit);
static TI_STATUS hwInit_InitTopRegisterRead(TI_HANDLE hHwInit, TI_UINT32 uAddress);
static TI_STATUS hwInit_TopRegisterWrite(TI_HANDLE hHwInit);
static TI_STATUS hwInit_InitTopRegisterWrite(TI_HANDLE hHwInit, TI_UINT32 uAddress, TI_UINT32 uValue);
/*******************************************************************************
* PUBLIC FUNCTIONS IMPLEMENTATION *
********************************************************************************/
/*************************************************************************
* hwInit_Create *
**************************************************************************
* DESCRIPTION: This function initializes the HwInit module.
*
* INPUT: hOs - handle to Os Abstraction Layer
*
* RETURN: Handle to the allocated HwInit module
*************************************************************************/
TI_HANDLE hwInit_Create (TI_HANDLE hOs)
{
THwInit *pHwInit;
/* Allocate HwInit module */
pHwInit = os_memoryAlloc (hOs, sizeof(THwInit));
if (pHwInit == NULL)
{
WLAN_OS_REPORT(("Error allocating the HwInit Module\n"));
return NULL;
}
/* Reset HwInit module */
os_memoryZero (hOs, pHwInit, sizeof(THwInit));
pHwInit->hOs = hOs;
return (TI_HANDLE)pHwInit;
}
/***************************************************************************
* hwInit_Destroy *
****************************************************************************
* DESCRIPTION: This function unload the HwInit module.
*
* INPUTS: hHwInit - the object
*
* OUTPUT:
*
* RETURNS: TI_OK - Unload succesfull
* TI_NOK - Unload unsuccesfull
***************************************************************************/
TI_STATUS hwInit_Destroy (TI_HANDLE hHwInit)
{
THwInit *pHwInit = (THwInit *)hHwInit;
/* Free HwInit Module */
os_memoryFree (pHwInit->hOs, pHwInit, sizeof(THwInit));
return TI_OK;
}
/***************************************************************************
* hwInit_Init *
****************************************************************************
* DESCRIPTION: This function configures the hwInit module
*
* RETURNS: TI_OK - Configuration successful
* TI_NOK - Configuration unsuccessful
***************************************************************************/
TI_STATUS hwInit_Init (TI_HANDLE hHwInit,
TI_HANDLE hReport,
TI_HANDLE hTWD,
TI_HANDLE hFinalizeDownload,
TFinalizeCb fFinalizeDownload,
TEndOfHwInitCb fInitHwCb)
{
THwInit *pHwInit = (THwInit *)hHwInit;
TTxnStruct* pTxn;
#ifdef TI_RANDOM_DEFAULT_MAC
u32 rand_mac;
#endif
/* Configure modules handles */
pHwInit->hReport = hReport;
pHwInit->hTWD = hTWD;
pHwInit->hTwIf = ((TTwd *)hTWD)->hTwIf;
pHwInit->hOs = ((TTwd *)hTWD)->hOs;
pHwInit->fInitHwCb = fInitHwCb;
pHwInit->fFinalizeDownload = fFinalizeDownload;
pHwInit->hFinalizeDownload = hFinalizeDownload;
SET_DEF_NVS(pHwInit->aDefaultNVS)
#ifdef TI_RANDOM_DEFAULT_MAC
/* Create random MAC address: offset 3, 4 and 5 */
srandom32((u32)jiffies);
rand_mac = random32();
pHwInit->aDefaultNVS[3] = (u8)rand_mac;
pHwInit->aDefaultNVS[4] = (u8)(rand_mac >> 8);
pHwInit->aDefaultNVS[5] = (u8)(rand_mac >> 16);
#endif
for (pHwInit->uTxnIndex=0;pHwInit->uTxnIndex<MAX_HW_INIT_CONSECUTIVE_TXN;pHwInit->uTxnIndex++)
{
HW_INIT_PTXN_SET(pHwInit, pTxn)
/* Setting write as default transaction */
TXN_PARAM_SET(pTxn, TXN_LOW_PRIORITY, TXN_FUNC_ID_WLAN, TXN_DIRECTION_WRITE, TXN_INC_ADDR)
}
TRACE0(pHwInit->hReport, REPORT_SEVERITY_INIT, ".....HwInit configured successfully\n");
return TI_OK;
}
TI_STATUS hwInit_SetNvsImage (TI_HANDLE hHwInit, TI_UINT8 *pbuf, TI_UINT32 length)
{
THwInit *pHwInit = (THwInit *)hHwInit;
pHwInit->pEEPROMBuf = pbuf;
pHwInit->uEEPROMLen = length;
return TI_OK;
}
TI_STATUS hwInit_SetFwImage (TI_HANDLE hHwInit, TFileInfo *pFileInfo)
{
THwInit *pHwInit = (THwInit *)hHwInit;
if ((hHwInit == NULL) || (pFileInfo == NULL))
{
return TI_NOK;
}
pHwInit->pFwBuf = pFileInfo->pBuffer;
pHwInit->uFwLength = pFileInfo->uLength;
pHwInit->uFwAddress = pFileInfo->uAddress;
pHwInit->bFwBufLast = pFileInfo->bLast;
return TI_OK;
}
/**
* \fn hwInit_SetPartition
* \brief Set HW addresses partition
*
* Set the HW address ranges for download or working memory and registers access.
* Generate and configure the bus access address mapping table.
* The partition is split between register (fixed partition of 24KB size, exists in all modes),
* and memory (dynamically changed during init and gets constant value in run-time, 104KB size).
* The TwIf configures the memory mapping table on the device by issuing write transaction to
* table address (note that the TxnQ and bus driver see this as a regular transaction).
*
* \note In future versions, a specific bus may not support partitioning (as in wUART),
* In this case the HwInit module shall not call this function (will learn the bus
* configuration from the INI file).
*
* \param pHwInit - The module's object
* \param pPartition - all partition base address
* \return void
* \sa
*/
static void hwInit_SetPartition (THwInit *pHwInit,
TPartition *pPartition)
{
TRACE7(pHwInit->hReport, REPORT_SEVERITY_INFORMATION, "hwInit_SetPartition: uMemAddr1=0x%x, MemSize1=0x%x uMemAddr2=0x%x, MemSize2=0x%x, uMemAddr3=0x%x, MemSize3=0x%x, uMemAddr4=0x%x, MemSize4=0x%x\n",pPartition[0].uMemAdrr, pPartition[0].uMemSize,pPartition[1].uMemAdrr, pPartition[1].uMemSize,pPartition[2].uMemAdrr, pPartition[2].uMemSize,pPartition[3].uMemAdrr );
/* Prepare partition Txn data and send to HW */
twIf_SetPartition (pHwInit->hTwIf,pPartition);
}
/****************************************************************************
* hwInit_Boot()
****************************************************************************
* DESCRIPTION: Start HW init sequence which writes and reads some HW registers
* that are needed prior to FW download.
*
* INPUTS: None
*
* OUTPUT: None
*
* RETURNS: TI_OK or TI_NOK
****************************************************************************/
TI_STATUS hwInit_Boot (TI_HANDLE hHwInit)
{
THwInit *pHwInit = (THwInit *)hHwInit;
TTwd *pTWD = (TTwd *)pHwInit->hTWD;
TWlanParams *pWlanParams = &DB_WLAN(pTWD->hCmdBld);
TBootAttr tBootAttr;
tBootAttr.MacClock = pWlanParams->MacClock;
tBootAttr.ArmClock = pWlanParams->ArmClock;
/*
* Initialize the status of download to pending
* It will be set to TXN_STATUS_COMPLETE at the FinalizeDownload function
*/
pHwInit->DownloadStatus = TXN_STATUS_PENDING;
/* Call the boot sequence state machine */
pHwInit->uInitStage = 0;
os_memoryCopy (pHwInit->hOs, &pHwInit->tBootAttr, &tBootAttr, sizeof(TBootAttr));
hwInit_BootSm (hHwInit);
/*
* If it returns the status of the StartInstance only then we can here query for the download status
* and then return the status up to the TNETW_Driver.
* This return value will go back up to the TNETW Driver layer so that the init from OS will know
* if to wait for the InitComplte or not in case of TXN_STATUS_ERROR.
* This value will always be pending since the SPI is ASYNC
* and in SDIOa timer is set so it will be ASync also in anyway.
*/
return pHwInit->DownloadStatus;
}
/****************************************************************************
* DESCRIPTION: Firmware boot state machine
*
* INPUTS:
*
* OUTPUT: None
*
* RETURNS: TI_OK
****************************************************************************/
static TI_STATUS hwInit_BootSm (TI_HANDLE hHwInit)
{
THwInit *pHwInit = (THwInit *)hHwInit;
TI_STATUS status = 0;
TTxnStruct *pTxn;
TI_UINT32 uData;
TTwd *pTWD = (TTwd *) pHwInit->hTWD;
IniFileGeneralParam *pGenParams = &DB_GEN(pTWD->hCmdBld);
TI_UINT32 clkVal = 0x3;
switch (pHwInit->uInitStage)
{
case 0:
pHwInit->uInitStage++;
pHwInit->uTxnIndex = 0;
/* Set the bus addresses partition to its "running" mode */
SET_WORK_PARTITION(pHwInit->aPartition)
hwInit_SetPartition (pHwInit,pHwInit->aPartition);
#ifdef _VLCT_
/* Set FW to test mode */
BUILD_HW_INIT_TXN_DATA(pHwInit, pTxn, SCR_PAD8, 0xBABABABE,
REGISTER_SIZE, TXN_DIRECTION_WRITE, NULL, NULL)
twIf_Transact(pHwInit->hTwIf, pTxn);
pHwInit->uTxnIndex++;
#endif
if (( 0 == (pGenParams->RefClk & FREF_CLK_FREQ_MASK)) || (2 == (pGenParams->RefClk & FREF_CLK_FREQ_MASK))
|| (4 == (pGenParams->RefClk & FREF_CLK_FREQ_MASK)))
{/* ref clk: 19.2/38.4/38.4-XTAL */
clkVal = 0x3;
}
if ((1 == (pGenParams->RefClk & FREF_CLK_FREQ_MASK)) || (3 == (pGenParams->RefClk & FREF_CLK_FREQ_MASK)))
{/* ref clk: 26/52 */
clkVal = 0x5;
}
WLAN_OS_REPORT(("CHIP VERSION... set 1273 chip top registers\n"));
/* set the reference clock freq' to be used (pll_selinpfref field) */
BUILD_HW_INIT_TXN_DATA(pHwInit, pTxn, PLL_PARAMETERS, clkVal,
REGISTER_SIZE, TXN_DIRECTION_WRITE, NULL, NULL)
twIf_Transact(pHwInit->hTwIf, pTxn);
pHwInit->uTxnIndex++;
/* read the PAUSE value to highest threshold */
BUILD_HW_INIT_TXN_DATA(pHwInit, pTxn, PLL_PARAMETERS, 0,
REGISTER_SIZE, TXN_DIRECTION_READ, (TTxnDoneCb)hwInit_BootSm, hHwInit)
status = twIf_Transact(pHwInit->hTwIf, pTxn);
EXCEPT (pHwInit, status)
case 1:
pHwInit->uInitStage ++;
/* We don't zero pHwInit->uTxnIndex at the begining because we need it's value to the next transaction */
uData = pHwInit->aHwInitTxn[pHwInit->uTxnIndex].uData;
uData &= ~(0x3ff);
/* Now we can zero the index */
pHwInit->uTxnIndex = 0;
/* set the the PAUSE value to highest threshold */
uData |= WU_COUNTER_PAUSE_VAL;
BUILD_HW_INIT_TXN_DATA(pHwInit, pTxn, WU_COUNTER_PAUSE, uData,
REGISTER_SIZE, TXN_DIRECTION_WRITE, NULL, NULL)
twIf_Transact(pHwInit->hTwIf, pTxn);
pHwInit->uTxnIndex++;
/* Continue the ELP wake up sequence */
BUILD_HW_INIT_TXN_DATA(pHwInit, pTxn, WELP_ARM_COMMAND, WELP_ARM_COMMAND_VAL,
REGISTER_SIZE, TXN_DIRECTION_WRITE, NULL, NULL)
twIf_Transact(pHwInit->hTwIf, pTxn);
/* Wait 500uS */
os_StalluSec (pHwInit->hOs, 500);
/* Set the bus addresses partition to DRPw registers region */
SET_DRP_PARTITION(pHwInit->aPartition)
hwInit_SetPartition (pHwInit,pHwInit->aPartition);
pHwInit->uTxnIndex++;
/* Read-modify-write DRPW_SCRATCH_START register (see next state) to be used by DRPw FW.
The RTRIM value will be added by the FW before taking DRPw out of reset */
BUILD_HW_INIT_TXN_DATA(pHwInit, pTxn, DRPW_SCRATCH_START, 0,
REGISTER_SIZE, TXN_DIRECTION_READ,(TTxnDoneCb)hwInit_BootSm, hHwInit)
status = twIf_Transact(pHwInit->hTwIf, pTxn);
EXCEPT (pHwInit, status)
case 2:
pHwInit->uInitStage ++;
/* multiply fref value by 2, so that {0,1,2,3} values will become {0,2,4,6} */
/* Then, move it 4 places to the right, to alter Fref relevant bits in register 0x2c */
clkVal = pHwInit->aHwInitTxn[pHwInit->uTxnIndex].uData;
pHwInit->uTxnIndex = 0; /* Reset index only after getting the last read value! */
clkVal |= (pGenParams->RefClk << 1) << 4;
BUILD_HW_INIT_TXN_DATA(pHwInit, pTxn, DRPW_SCRATCH_START, clkVal,
REGISTER_SIZE, TXN_DIRECTION_WRITE, NULL, NULL)
twIf_Transact(pHwInit->hTwIf, pTxn);
pHwInit->uTxnIndex++;
/* Set the bus addresses partition back to its "running" mode */
SET_WORK_PARTITION(pHwInit->aPartition)
hwInit_SetPartition (pHwInit,pHwInit->aPartition);
/*
* end of CHIP init seq.
*/
/* Disable interrupts */
BUILD_HW_INIT_TXN_DATA(pHwInit, pTxn, ACX_REG_INTERRUPT_MASK, ACX_INTR_ALL,
REGISTER_SIZE, TXN_DIRECTION_WRITE, NULL, NULL)
twIf_Transact(pHwInit->hTwIf, pTxn);
pHwInit->uTxnIndex++;
/* Read the CHIP ID to get an indication that the bus is TI_OK */
BUILD_HW_INIT_TXN_DATA(pHwInit, pTxn, CHIP_ID, 0,
REGISTER_SIZE, TXN_DIRECTION_READ,(TTxnDoneCb)hwInit_BootSm, hHwInit)
status = twIf_Transact(pHwInit->hTwIf, pTxn);
EXCEPT (pHwInit, status)
case 3:
pHwInit->uInitStage ++;
/* We don't zero pHwInit->uTxnIndex at the begining because we need it's value to the next transaction */
pHwInit->uChipId = pHwInit->aHwInitTxn[pHwInit->uTxnIndex].uData;
/* This is only sanity check that the HW exists, we can continue and fail on FwLoad */
if (pHwInit->uChipId == CHIP_ID_1273_PG10)
{
WLAN_OS_REPORT(("Working on a 1273 PG 1.0 board.\n"));
bChipIs1273Pg10 = TI_TRUE;
}
else if (pHwInit->uChipId == CHIP_ID_1273_PG20)
{
WLAN_OS_REPORT(("Working on a 1273 PG 2.0 board.\n"));
bChipIs1273Pg10 = TI_FALSE;
}
else
{
WLAN_OS_REPORT (("Error!! Found unknown Chip Id = 0x%x\n", pHwInit->uChipId));
bChipIs1273Pg10 = TI_FALSE;
/*
* NOTE: no exception because of forward compatibility
*/
}
/*
* Soft reset
*/
pHwInit->uResetStage = 0;
pHwInit->uSelfClearTime = 0;
pHwInit->uBootData = 0;
status = hwInit_ResetSm (pHwInit);
EXCEPT (pHwInit, status)
case 4:
pHwInit->uInitStage ++;
TRACE0(pHwInit->hReport, REPORT_SEVERITY_INIT , "TNET SOFT-RESET\n");
WLAN_OS_REPORT(("Starting to process NVS...\n"));
/*
* Start EEPROM/NVS burst
*/
if (pHwInit->pEEPROMBuf)
{
/* NVS file exists (EEPROM-less support) */
pHwInit->uEEPROMCurLen = pHwInit->uEEPROMLen;
TRACE2(pHwInit->hReport, REPORT_SEVERITY_INIT , "EEPROM Image addr=0x%x, EEPROM Len=0x0x%x\n", pHwInit->pEEPROMBuf, pHwInit->uEEPROMLen);
WLAN_OS_REPORT (("NVS found, EEPROM Image addr=0x%x, EEPROM Len=0x0x%x\n",
pHwInit->pEEPROMBuf, pHwInit->uEEPROMLen));
}
else
{
WLAN_OS_REPORT (("No Nvs, Setting default MAC address\n"));
pHwInit->uEEPROMCurLen = DEF_NVS_SIZE;
pHwInit->pEEPROMBuf = (TI_UINT8*)(&pHwInit->aDefaultNVS[0]);
WLAN_OS_REPORT (("pHwInit->uEEPROMCurLen: %x\n", pHwInit->uEEPROMCurLen));
WLAN_OS_REPORT (("ERROR: If you are not calibating the device, you will soon get errors !!!\n"));
}
pHwInit->pEEPROMCurPtr = pHwInit->pEEPROMBuf;
pHwInit->uEEPROMStage = 0;
status = hwInit_EepromlessStartBurstSm (hHwInit);
EXCEPT (pHwInit, status)
case 5:
pHwInit->uInitStage ++;
pHwInit->uTxnIndex = 0;
if (pHwInit->pEEPROMBuf)
{
/* Signal FW that we are eeprom less */
BUILD_HW_INIT_TXN_DATA(pHwInit, pTxn, ACX_EEPROMLESS_IND_REG, ACX_EEPROMLESS_IND_REG,
REGISTER_SIZE, TXN_DIRECTION_WRITE, NULL, NULL)
twIf_Transact(pHwInit->hTwIf, pTxn);
TRACE0(pHwInit->hReport, REPORT_SEVERITY_INIT , "DRIVER NVS BURST-READ\n");
}
else
{
/* 1273 - EEPROM is not support by FPGA yet */
/*
* Start ACX EEPROM
*/
/*pHwInit->uRegister = START_EEPROM_MGR;
TXN_PARAM_SET(pTxn, TXN_LOW_PRIORITY, TXN_FUNC_ID_WLAN, TXN_DIRECTION_WRITE, TXN_INC_ADDR)
BUILD_TTxnStruct(pTxn, ACX_REG_EE_START, &pHwInit->uRegister, REGISTER_SIZE, 0, NULL, NULL)
twIf_Transact(pHwInit->hTwIf, pTxn);*/
/*
* The stall is needed so the EEPROM NVS burst read will complete
*/
os_StalluSec (pHwInit->hOs, 40000);
BUILD_HW_INIT_TXN_DATA(pHwInit, pTxn, ACX_EEPROMLESS_IND_REG, USE_EEPROM,
REGISTER_SIZE, TXN_DIRECTION_WRITE, NULL, NULL)
twIf_Transact(pHwInit->hTwIf, pTxn);
TRACE0(pHwInit->hReport, REPORT_SEVERITY_INIT , "STARTING EEPROM NVS BURST-READ\n");
}
pHwInit->uTxnIndex++;
/* Read Chip ID */
BUILD_HW_INIT_TXN_DATA(pHwInit, pTxn, CHIP_ID, 0,
REGISTER_SIZE, TXN_DIRECTION_READ,(TTxnDoneCb)hwInit_BootSm, hHwInit)
status = twIf_Transact(pHwInit->hTwIf, pTxn);
EXCEPT (pHwInit, status)
case 6:
pHwInit->uInitStage ++;
/* We don't zero pHwInit->uTxnIndex at the begining because we need it's value to the next transaction */
pHwInit->uBootData = pHwInit->aHwInitTxn[pHwInit->uTxnIndex].uData;
/* Now we can zero the index */
pHwInit->uTxnIndex = 0;
WLAN_OS_REPORT(("Chip ID is 0x%X.\n", pHwInit->uBootData));
/* if the WLAN_EN is ON but MainClock is problamtic the chip-id will be zero*/
if (pHwInit->uBootData == 0)
{
WLAN_OS_REPORT(("Cannot read ChipID stopping\n", pHwInit->uBootData));
TWD_FinalizeOnFailure (pHwInit->hTWD);
return TXN_STATUS_ERROR;
}
/* Read Scr2 to verify that the HW is ready */
BUILD_HW_INIT_TXN_DATA(pHwInit, pTxn, SCR_PAD2, 0,
REGISTER_SIZE, TXN_DIRECTION_READ,(TTxnDoneCb)hwInit_BootSm, hHwInit)
status = twIf_Transact(pHwInit->hTwIf, pTxn);
EXCEPT (pHwInit, status)
case 7:
pHwInit->uInitStage ++;
/* We don't zero pHwInit->uTxnIndex at the begining because we need it's value to the next transaction */
pHwInit->uBootData = pHwInit->aHwInitTxn[pHwInit->uTxnIndex].uData;
if (pHwInit->uBootData == 0xffffffff)
{
TRACE0(pHwInit->hReport, REPORT_SEVERITY_FATAL_ERROR , "Error in SCR_PAD2 register\n");
EXCEPT (pHwInit, TXN_STATUS_ERROR)
}
/* Call the restart sequence */
pHwInit->uInitSeqStage = 0;
pHwInit->uInitSeqStatus = TXN_STATUS_COMPLETE;
EXCEPT (pHwInit, status)
case 8:
pHwInit->uInitStage++;
if ((pGenParams->RefClk & FREF_CLK_TYPE_MASK) != 0x0)
{
status = hwInit_InitTopRegisterRead(hHwInit, 0x448);
EXCEPT (pHwInit, status)
}
case 9:
pHwInit->uInitStage++;
if ((pGenParams->RefClk & FREF_CLK_TYPE_MASK) != 0x0)
{
pHwInit->uTopRegValue &= FREF_CLK_TYPE_BITS;
pHwInit->uTopRegValue |= CLK_REQ_PRCM;
status = hwInit_InitTopRegisterWrite( hHwInit, 0x448, pHwInit->uTopRegValue);
EXCEPT (pHwInit, status)
}
case 10:
pHwInit->uInitStage++;
if ((pGenParams->RefClk & FREF_CLK_POLARITY_MASK) == 0x0)
{
status = hwInit_InitTopRegisterRead(hHwInit, 0xCB2);
EXCEPT (pHwInit, status)
}
case 11:
pHwInit->uInitStage++;
if ((pGenParams->RefClk & FREF_CLK_POLARITY_MASK) == 0x0)
{
pHwInit->uTopRegValue &= FREF_CLK_POLARITY_BITS;
pHwInit->uTopRegValue |= CLK_REQ_OUTN_SEL;
status = hwInit_InitTopRegisterWrite( hHwInit, 0xCB2, pHwInit->uTopRegValue);
EXCEPT (pHwInit, status)
}
case 12:
pHwInit->uInitStage = 0;
/* Set the Download Status to COMPLETE */
pHwInit->DownloadStatus = TXN_STATUS_COMPLETE;
/* Call upper layer callback */
if (pHwInit->fInitHwCb)
{
(*pHwInit->fInitHwCb) (pHwInit->hTWD);
}
return TI_OK;
}
return TI_OK;
}
TI_STATUS hwInit_LoadFw (TI_HANDLE hHwInit)
{
THwInit *pHwInit = (THwInit *)hHwInit;
TI_STATUS status;
/* check parameters */
if (hHwInit == NULL)
{
EXCEPT (pHwInit, TXN_STATUS_ERROR)
}
if (pHwInit->pFwBuf)
{
TRACE0(pHwInit->hReport, REPORT_SEVERITY_INIT , "CPU halt -> download code\n");
/* Load firmware image */
pHwInit->uLoadStage = 0;
status = hwInit_LoadFwImageSm (pHwInit);
switch (status)
{
case TI_OK:
case TXN_STATUS_OK:
case TXN_STATUS_COMPLETE:
WLAN_OS_REPORT (("Firmware successfully downloaded.\n"));
break;
case TXN_STATUS_PENDING:
WLAN_OS_REPORT (("Starting to download firmware...\n"));
break;
default:
TRACE0(pHwInit->hReport, REPORT_SEVERITY_ERROR , "Firmware download failed!\n");
break;
}
EXCEPT (pHwInit, status);
}
else
{
TRACE0(pHwInit->hReport, REPORT_SEVERITY_INIT , "Firmware not downloaded...\n");
EXCEPT (pHwInit, TXN_STATUS_ERROR)
}
WLAN_OS_REPORT (("FW download OK...\n"));
return TI_OK;
}
/****************************************************************************
* hwInit_FinalizeDownloadSm()
****************************************************************************
* DESCRIPTION: Run the Hardware firmware
* Wait for Init Complete
* Configure the Bus Access with Addresses available on the scratch pad register
* Change the SDIO/SPI partitions to be able to see all the memory addresses
*
* INPUTS: None
*
* OUTPUT: None
*
* RETURNS: None
****************************************************************************/
static TI_STATUS hwInit_FinalizeDownloadSm (TI_HANDLE hHwInit)
{
THwInit *pHwInit = (THwInit *)hHwInit;
TTwd *pTWD = (TTwd *)pHwInit->hTWD;
TI_STATUS status = TI_OK;
TI_UINT32 uIntVect;
TTxnStruct* pTxn;
#ifdef _VLCT_
#define FIN_LOOP 10
#else
#define FIN_LOOP 20000
#endif
while (TI_TRUE)
{
switch (pHwInit->uFinStage)
{
case 0:
pHwInit->uFinStage = 1;
pHwInit->uTxnIndex = 0;
/*
* Run the firmware (I) - Read current value from ECPU Control Reg.
*/
BUILD_HW_INIT_TXN_DATA(pHwInit, pTxn, ACX_REG_ECPU_CONTROL, 0,
REGISTER_SIZE, TXN_DIRECTION_READ, (TTxnDoneCb)hwInit_FinalizeDownloadSm, hHwInit)
status = twIf_Transact(pHwInit->hTwIf, pTxn);
EXCEPT (pHwInit, status)
case 1:
pHwInit->uFinStage ++;
/* We don't zero pHwInit->uTxnIndex at the begining because we need it's value to the next transaction */
pHwInit->uFinData = pHwInit->aHwInitTxn[pHwInit->uTxnIndex].uData;
/* Now we can zero the index */
pHwInit->uTxnIndex = 0;
/*
* Run the firmware (II) - Take HW out of reset (write ECPU_CONTROL_HALT to ECPU Control Reg.)
*/
BUILD_HW_INIT_TXN_DATA(pHwInit, pTxn, ACX_REG_ECPU_CONTROL, (pHwInit->uFinData | ECPU_CONTROL_HALT),
REGISTER_SIZE, TXN_DIRECTION_WRITE, NULL, NULL)
twIf_Transact(pHwInit->hTwIf, pTxn);
WLAN_OS_REPORT (("Firmware running.\n"));
/*
* CHIP ID Debug
*/
pHwInit->uTxnIndex++;
BUILD_HW_INIT_TXN_DATA(pHwInit, pTxn, CHIP_ID, 0,
REGISTER_SIZE, TXN_DIRECTION_READ, (TTxnDoneCb)hwInit_FinalizeDownloadSm, hHwInit)
status = twIf_Transact(pHwInit->hTwIf, pTxn);
EXCEPT (pHwInit, status)
case 2:
pHwInit->uFinStage ++;
pHwInit->uFinLoop = 0;
/* We don't zero pHwInit->uTxnIndex at the begining because we need it's value to the next transaction */
pHwInit->uFinData = pHwInit->aHwInitTxn[pHwInit->uTxnIndex].uData;
TRACE1(pHwInit->hReport, REPORT_SEVERITY_INIT , "CHIP ID IS %x\n", pHwInit->uFinData);
TRACE0(pHwInit->hReport, REPORT_SEVERITY_INIT , "Wait init complete\n");
case 3:
pHwInit->uTxnIndex = 0;
/*
* Wait for init complete
*/
if (pHwInit->uFinLoop < FIN_LOOP)
{
pHwInit->uFinStage = 4;
os_StalluSec (pHwInit->hOs, 50);
/* Read interrupt status register */
BUILD_HW_INIT_TXN_DATA(pHwInit, pTxn, ACX_REG_INTERRUPT_NO_CLEAR, 0,
REGISTER_SIZE, TXN_DIRECTION_READ, (TTxnDoneCb)hwInit_FinalizeDownloadSm, hHwInit)
status = twIf_Transact(pHwInit->hTwIf, pTxn);
EXCEPT (pHwInit, status)
}
else
{
pHwInit->uFinStage = 5;
}
continue;
case 4:
/* We don't zero pHwInit->uTxnIndex at the begining because we need it's value to the next transaction */
pHwInit->uFinData = pHwInit->aHwInitTxn[pHwInit->uTxnIndex].uData;
/* Now we can zero the index */
pHwInit->uTxnIndex = 0;
if (pHwInit->uFinData == 0xffffffff) /* error */
{
TRACE0(pHwInit->hReport, REPORT_SEVERITY_ERROR , "Error reading hardware complete init indication\n");
pHwInit->DownloadStatus = TXN_STATUS_ERROR;
EXCEPT (pHwInit, TXN_STATUS_ERROR)
}
if (IS_MASK_ON (pHwInit->uFinData, ACX_INTR_INIT_COMPLETE))
{
pHwInit->uFinStage = 5;
/* Interrupt ACK */
BUILD_HW_INIT_TXN_DATA(pHwInit, pTxn, ACX_REG_INTERRUPT_ACK, ACX_INTR_INIT_COMPLETE,
REGISTER_SIZE, TXN_DIRECTION_WRITE, NULL, NULL)
twIf_Transact(pHwInit->hTwIf, pTxn);
break;
}
else
{
pHwInit->uFinStage = 3;
pHwInit->uFinLoop ++;
}
continue;
case 5:
pHwInit->uFinStage++;
if (pHwInit->uFinLoop >= FIN_LOOP)
{
TRACE0(pHwInit->hReport, REPORT_SEVERITY_ERROR , "Timeout waiting for the hardware to complete initialization\n");
pHwInit->DownloadStatus = TXN_STATUS_ERROR;
EXCEPT (pHwInit, TXN_STATUS_ERROR);
}
TRACE0(pHwInit->hReport, REPORT_SEVERITY_INIT , "Firmware init complete...\n");
/*
* There are valid addresses of the command and event mailbox
* on the scratch pad registers
*/
/* Hardware config command mail box */
status = cmdMbox_ConfigHw (pTWD->hCmdMbox,
(fnotify_t)hwInit_FinalizeDownloadSm,
hHwInit);
EXCEPT (pHwInit, status)
case 6:
pHwInit->uFinStage++;
/* Hardware config event mail box */
status = eventMbox_InitMboxAddr (pTWD->hEventMbox,
(fnotify_t)hwInit_FinalizeDownloadSm,
hHwInit);
EXCEPT (pHwInit, status);
case 7:
pHwInit->uFinStage++;
pHwInit->uTxnIndex = 0;
SET_WORK_PARTITION(pHwInit->aPartition)
/* Set the bus addresses partition to its "running" mode */
SET_WORK_PARTITION(pHwInit->aPartition)
hwInit_SetPartition (pHwInit,pHwInit->aPartition);
/*
* In case of full asynchronous mode the firmware event must be ready
* to receive event from the command mailbox, so enable FW interrupts.
*/
/* Clear the FW interrupt sources needed for init phase */
uIntVect = fwEvent_GetInitMask (pTWD->hFwEvent);
BUILD_HW_INIT_TXN_DATA(pHwInit, pTxn, ACX_REG_INTERRUPT_MASK, (~uIntVect),
REGISTER_SIZE, TXN_DIRECTION_WRITE, NULL, NULL)
twIf_Transact(pHwInit->hTwIf, pTxn);
pHwInit->uTxnIndex++;
/* Read static FW information from Cmd-Mbox */
BUILD_HW_INIT_FW_STATIC_TXN(pHwInit, pTxn, cmdMbox_GetMboxAddress (pTWD->hCmdMbox),
(TTxnDoneCb)hwInit_FinalizeDownloadSm, hHwInit)
status = twIf_Transact(pHwInit->hTwIf, pTxn);
EXCEPT (pHwInit, status);
continue;
case 8:
pHwInit->uFinStage = 0;
cmdBld_FinalizeDownload (pTWD->hCmdBld, &pHwInit->tBootAttr, &(pHwInit->tFwStaticTxn.tFwStaticInfo));
/* Set the Download Status to COMPLETE */
pHwInit->DownloadStatus = TXN_STATUS_COMPLETE;
return TXN_STATUS_COMPLETE;
} /* End switch */
} /* End while */
}
/****************************************************************************
* hwInit_ResetSm()
****************************************************************************
* DESCRIPTION: Reset hardware state machine
*
* INPUTS: None
*
* OUTPUT: None
*
* RETURNS: TI_OK or TI_NOK
****************************************************************************/
static TI_STATUS hwInit_ResetSm (TI_HANDLE hHwInit)
{
THwInit *pHwInit = (THwInit *)hHwInit;
TI_STATUS status = TI_OK;
TTxnStruct* pTxn;
pHwInit->uTxnIndex = 0;
/* Disable Rx/Tx */
BUILD_HW_INIT_TXN_DATA(pHwInit, pTxn, REG_ENABLE_TX_RX, 0x0,
REGISTER_SIZE, TXN_DIRECTION_WRITE, NULL, NULL)
twIf_Transact(pHwInit->hTwIf, pTxn);
pHwInit->uTxnIndex++;
/* Disable auto calibration on start */
BUILD_HW_INIT_TXN_DATA(pHwInit, pTxn, SPARE_A2, 0xFFFF,
REGISTER_SIZE, TXN_DIRECTION_WRITE,(TTxnDoneCb)hwInit_BootSm, hHwInit)
status = twIf_Transact(pHwInit->hTwIf, pTxn);
return status;
}
/****************************************************************************
* hwInit_EepromlessStartBurstSm()
****************************************************************************
* DESCRIPTION: prepare eepromless configuration before boot
*
* INPUTS:
*
* OUTPUT:
*
* RETURNS:
****************************************************************************/
static TI_STATUS hwInit_EepromlessStartBurstSm (TI_HANDLE hHwInit)
{
THwInit *pHwInit = (THwInit *)hHwInit;
TI_STATUS status = TI_OK;
TI_UINT8 *uAddr;
TI_UINT32 uDeltaLength;
TTxnStruct* pTxn;
pHwInit->uTxnIndex = 0;
while (TI_TRUE)
{
switch (pHwInit->uEEPROMStage)
{
/*
* Stages 0, 1 handles the eeprom format parameters:
* ------------------------------------------------
* Length - 8bit --> The length is counted in 32bit words
* Address - 16bit
* Data - (Length * 4) bytes
*
* Note: The nvs is in big endian format and we need to change it to little endian
*/
case 0:
/* Check if address LSB = 1 --> Register address */
if ((pHwInit->uEEPROMRegAddr = pHwInit->pEEPROMCurPtr[1]) & 1)
{
/* Mask the register's address LSB before writing to it */
pHwInit->uEEPROMRegAddr &= 0xfe;
/* Change the address's endian */
pHwInit->uEEPROMRegAddr |= (TI_UINT32)pHwInit->pEEPROMCurPtr[2] << 8;
/* Length of burst data */
pHwInit->uEEPROMBurstLen = pHwInit->pEEPROMCurPtr[0];
pHwInit->pEEPROMCurPtr += 3;
pHwInit->uEEPROMBurstLoop = 0;
/*
* We've finished reading the burst information.
* Go to stage 1 in order to write it
*/
pHwInit->uEEPROMStage = 1;
}
/* If address LSB = 0 --> We're not in the burst section */
else
{
/* End of Burst transaction: we should see 7 zeroed bytes */
if (pHwInit->pEEPROMCurPtr[0] == 0)
{
pHwInit->pEEPROMCurPtr += 7;
}
pHwInit->uEEPROMCurLen -= (pHwInit->pEEPROMCurPtr - pHwInit->pEEPROMBuf + 1);
pHwInit->uEEPROMCurLen = (pHwInit->uEEPROMCurLen + NVS_DATA_BUNDARY_ALIGNMENT - 1) & 0xfffffffc;
/* End of Burst transaction, go to TLV section */
pHwInit->uEEPROMStage = 2;
}
continue;
case 1:
if (pHwInit->uEEPROMBurstLoop < pHwInit->uEEPROMBurstLen)
{
/* Change the data's endian */
TI_UINT32 val = (pHwInit->pEEPROMCurPtr[0] |
(pHwInit->pEEPROMCurPtr[1] << 8) |
(pHwInit->pEEPROMCurPtr[2] << 16) |
(pHwInit->pEEPROMCurPtr[3] << 24));
TRACE2(pHwInit->hReport, REPORT_SEVERITY_INIT , "NVS::BurstRead: *(%08x) = %x\n", pHwInit->uEEPROMRegAddr, val);
BUILD_HW_INIT_TXN_DATA(pHwInit, pTxn, (REGISTERS_BASE+pHwInit->uEEPROMRegAddr), val,
REGISTER_SIZE, TXN_DIRECTION_WRITE, (TTxnDoneCb)hwInit_EepromlessStartBurstSm, hHwInit)
status = twIf_Transact(pHwInit->hTwIf, pTxn);
pHwInit->uEEPROMStatus = status;
pHwInit->uEEPROMRegAddr += WORD_SIZE;
pHwInit->pEEPROMCurPtr += WORD_SIZE;
/* While not end of burst, we stay in stage 1 */
pHwInit->uEEPROMStage = 1;
pHwInit->uEEPROMBurstLoop ++;
EXCEPT (pHwInit, status);
}
else
{
/* If end of burst return to stage 0 to read the next one */
pHwInit->uEEPROMStage = 0;
}
continue;
case 2:
pHwInit->uEEPROMStage = 3;
/* Set the bus addresses partition to its "running" mode */
SET_WORK_PARTITION(pHwInit->aPartition)
hwInit_SetPartition (pHwInit,pHwInit->aPartition);
continue;
case 3:
TRACE0(pHwInit->hReport, REPORT_SEVERITY_INIT , "Reached TLV section\n");
/* Align the host address */
if (((TI_UINT32)pHwInit->pEEPROMCurPtr & WORD_ALIGNMENT_MASK) && (pHwInit->uEEPROMCurLen > 0) )
{
uAddr = (TI_UINT8*)(((TI_UINT32)pHwInit->pEEPROMCurPtr & 0xFFFFFFFC)+WORD_SIZE);
uDeltaLength = uAddr - pHwInit->pEEPROMCurPtr + 1;
pHwInit->pEEPROMCurPtr = uAddr;
pHwInit->uEEPROMCurLen-= uDeltaLength;
}
TRACE2(pHwInit->hReport, REPORT_SEVERITY_INIT , "NVS::WriteTLV: pEEPROMCurPtr= %x, Length=%d\n", pHwInit->pEEPROMCurPtr, pHwInit->uEEPROMCurLen);
if (pHwInit->uEEPROMCurLen)
{
/* Save the 4 bytes before the NVS data for WSPI case where they are overrun by the WSPI BusDrv */
pHwInit->uSavedDataForWspiHdr = *(TI_UINT32 *)(pHwInit->pEEPROMCurPtr - WSPI_PAD_LEN_WRITE);
/* Prepare the Txn structure for the NVS transaction to the CMD_MBOX */
HW_INIT_PTXN_SET(pHwInit, pTxn)
TXN_PARAM_SET_DIRECTION(pTxn, TXN_DIRECTION_WRITE);
BUILD_TTxnStruct(pTxn, CMD_MBOX_ADDRESS, pHwInit->pEEPROMCurPtr, pHwInit->uEEPROMCurLen,
(TTxnDoneCb)hwInit_EepromlessStartBurstSm, hHwInit)
/* Transact the NVS data to the CMD_MBOX */
status = twIf_Transact(pHwInit->hTwIf, pTxn);
pHwInit->uEEPROMCurLen = 0;
pHwInit->uNVSStatus = status;
EXCEPT (pHwInit, status);
}
else
{
/* Restore the 4 bytes before the NVS data for WSPI case were they are overrun by the WSPI BusDrv */
*(TI_UINT32 *)(pHwInit->pEEPROMCurPtr - WSPI_PAD_LEN_WRITE) = pHwInit->uSavedDataForWspiHdr;
/* Call the upper level state machine */
if (pHwInit->uEEPROMStatus == TXN_STATUS_PENDING ||
pHwInit->uNVSStatus == TXN_STATUS_PENDING)
{
hwInit_BootSm (hHwInit);
}
return TXN_STATUS_COMPLETE;
}
} /* End switch */
} /* End while */
}
/****************************************************************************
* hwInit_LoadFwImageSm()
****************************************************************************
* DESCRIPTION: Load image from the host and download into the hardware
*
* INPUTS: None
*
* OUTPUT: None
*
* RETURNS: TI_OK or TI_NOK
****************************************************************************/
#define ADDRESS_SIZE (sizeof(TI_INT32))
static TI_STATUS hwInit_LoadFwImageSm (TI_HANDLE hHwInit)
{
THwInit *pHwInit = (THwInit *)hHwInit;
TI_STATUS status = TI_OK;
ETxnStatus TxnStatus;
TI_UINT32 uMaxPartitionSize = PARTITION_DOWN_MEM_SIZE;
TTxnStruct* pTxn;
pHwInit->uTxnIndex = 0;
while (TI_TRUE)
{
switch (pHwInit->uLoadStage)
{
case 0:
pHwInit->uLoadStage = 1;
/* Check the Downloaded FW alignment */
if ((pHwInit->uFwLength % ADDRESS_SIZE) != 0)
{
TRACE1(pHwInit->hReport, REPORT_SEVERITY_ERROR , "Length of downloaded Portion (%d) is not aligned\n",pHwInit->uFwLength);
EXCEPT_L (pHwInit, TXN_STATUS_ERROR);
}
TRACE2(pHwInit->hReport, REPORT_SEVERITY_INIT , "Image addr=0x%x, Len=0x%x\n", pHwInit->pFwBuf, pHwInit->uFwLength);
/* Set bus memory partition to current download area */
SET_FW_LOAD_PARTITION(pHwInit->aPartition,pHwInit->uFwAddress)
hwInit_SetPartition (pHwInit,pHwInit->aPartition);
status = TI_OK;
break;
case 1:
pHwInit->uLoadStage = 2;
/* if initial size is smaller than MAX_SDIO_BLOCK - go strait to stage 4 to write partial block */
if (pHwInit->uFwLength < MAX_SDIO_BLOCK)
{
pHwInit->uLoadStage = 4;
}
pHwInit->uBlockReadNum = 0;
pHwInit->uBlockWriteNum = 0;
pHwInit->uPartitionLimit = pHwInit->uFwAddress + uMaxPartitionSize;
continue;
case 2:
/* Load firmware by blocks */
if (pHwInit->uBlockReadNum < (pHwInit->uFwLength / MAX_SDIO_BLOCK))
{
pHwInit->uLoadStage = 3;
/* Change partition */
/* The +2 is for the last block and the block remainder */
if ( ((pHwInit->uBlockWriteNum + 2) * MAX_SDIO_BLOCK + pHwInit->uFwAddress) > pHwInit->uPartitionLimit)
{
pHwInit->uFwAddress += pHwInit->uBlockWriteNum * MAX_SDIO_BLOCK;
/* update uPartitionLimit */
pHwInit->uPartitionLimit = pHwInit->uFwAddress + uMaxPartitionSize;
/* Set bus memory partition to current download area */
SET_FW_LOAD_PARTITION(pHwInit->aPartition,pHwInit->uFwAddress)
hwInit_SetPartition (pHwInit,pHwInit->aPartition);
TxnStatus = TXN_STATUS_OK;
pHwInit->uBlockWriteNum = 0;
TRACE1(pHwInit->hReport, REPORT_SEVERITY_INIT , "Change partition to address offset = 0x%x\n", pHwInit->uFwAddress + pHwInit->uBlockWriteNum * MAX_SDIO_BLOCK);
EXCEPT_L (pHwInit, TxnStatus);
}
}
else
{
pHwInit->uLoadStage = 4;
TRACE0(pHwInit->hReport, REPORT_SEVERITY_INIT , "Load firmware with Portions\n");
}
continue;
case 3:
pHwInit->uLoadStage = 2;
pHwInit->uTxnIndex = 0;
/* Copy image block to temporary buffer */
os_memoryCopy (pHwInit->hOs,
(void *)&pHwInit->auFwTmpBuf[WSPI_PAD_LEN_WRITE],
(void *)(pHwInit->pFwBuf + pHwInit->uBlockReadNum * MAX_SDIO_BLOCK),
MAX_SDIO_BLOCK);
/* Load the block. Save WSPI_PAD_LEN_WRITE space for WSPI bus command */
BUILD_HW_INIT_FW_DL_TXN(pHwInit, pTxn, (pHwInit->uFwAddress + pHwInit->uBlockWriteNum * MAX_SDIO_BLOCK),
(pHwInit->auFwTmpBuf + WSPI_PAD_LEN_WRITE), MAX_SDIO_BLOCK, TXN_DIRECTION_WRITE,
(TTxnDoneCb)hwInit_LoadFwImageSm, hHwInit)
TxnStatus = twIf_Transact(pHwInit->hTwIf, pTxn);
/* Log ERROR if the transaction returned ERROR */
if (TxnStatus == TXN_STATUS_ERROR)
{
TRACE1(pHwInit->hReport, REPORT_SEVERITY_ERROR , "hwInit_LoadFwImageSm: twIf_Transact retruned status=0x%x\n", TxnStatus);
}
pHwInit->uBlockWriteNum ++;
pHwInit->uBlockReadNum ++;
EXCEPT_L (pHwInit, TxnStatus);
continue;
case 4:
pHwInit->uLoadStage = 5;
pHwInit->uTxnIndex = 0;
/* If No Last block to write */
if ( pHwInit->uFwLength % MAX_SDIO_BLOCK == 0 )
{
continue;
}
/* Copy the last image block */
os_memoryCopy (pHwInit->hOs,
(void *)&pHwInit->auFwTmpBuf[WSPI_PAD_LEN_WRITE],
(void *)(pHwInit->pFwBuf + pHwInit->uBlockReadNum * MAX_SDIO_BLOCK),
pHwInit->uFwLength % MAX_SDIO_BLOCK);
/* Load the last block */
BUILD_HW_INIT_FW_DL_TXN(pHwInit, pTxn, (pHwInit->uFwAddress + pHwInit->uBlockWriteNum * MAX_SDIO_BLOCK),
(pHwInit->auFwTmpBuf + WSPI_PAD_LEN_WRITE), (pHwInit->uFwLength % MAX_SDIO_BLOCK), TXN_DIRECTION_WRITE,
(TTxnDoneCb)hwInit_LoadFwImageSm, hHwInit)
TxnStatus = twIf_Transact(pHwInit->hTwIf, pTxn);
if (TxnStatus == TXN_STATUS_ERROR)
{
TRACE1(pHwInit->hReport, REPORT_SEVERITY_ERROR , "hwInit_LoadFwImageSm: last block retruned status=0x%x\n", TxnStatus);
}
EXCEPT_L (pHwInit, TxnStatus);
continue;
case 5:
pHwInit->uLoadStage = 0;
/*If end of overall FW Download Process: Finalize download (run firmware)*/
if ( pHwInit->bFwBufLast == TI_TRUE )
{
/* The download has completed */
WLAN_OS_REPORT (("Finished downloading firmware.\n"));
status = hwInit_FinalizeDownloadSm (hHwInit);
}
/* Have to wait to more FW Portions */
else
{
/* Call the upper layer callback */
if ( pHwInit->fFinalizeDownload != NULL )
{
(pHwInit->fFinalizeDownload) (pHwInit->hFinalizeDownload);
}
status = TI_OK;
}
return status;
} /* End switch */
} /* End while */
} /* hwInit_LoadFwImageSm() */
#define READ_TOP_REG_LOOP 32
/****************************************************************************
* hwInit_ReadRadioParamsSm ()
****************************************************************************
* DESCRIPTION: hwInit_ReadRadioParamsSm
* INPUTS: None
*
* OUTPUT: None
*
* RETURNS: TI_OK or TI_NOK
****************************************************************************/
TI_STATUS hwInit_ReadRadioParamsSm (TI_HANDLE hHwInit)
{
THwInit *pHwInit = (THwInit *)hHwInit;
TTwd *pTWD = (TTwd *)pHwInit->hTWD;
IniFileGeneralParam *pGenParams = &DB_GEN(pTWD->hCmdBld);
TI_UINT32 val= 0, value;
TI_UINT32 add = FUNC7_SEL;
TI_UINT32 retAddress;
TTxnStruct *pTxn;
TI_STATUS status = 0;
while (TI_TRUE)
{
switch (pHwInit->uRegStage)
{
case 0:
pHwInit->uRegStage = 1;
pHwInit->uTxnIndex++;
/*
* Select GPIO over Debug for BT_FUNC7 clear bit 17
*/
BUILD_HW_INIT_TXN_DATA(pHwInit, pTxn, GPIO_SELECT, 0,
REGISTER_SIZE, TXN_DIRECTION_READ, (TTxnDoneCb)hwInit_ReadRadioParamsSm, hHwInit)
status = twIf_Transact(pHwInit->hTwIf, pTxn);
EXCEPT (pHwInit, status)
case 1:
pHwInit->uRegStage ++;
pHwInit->uRegLoop = 0;
/* We don't zero pHwInit->uTxnIndex at the begining because we need it's value to the next transaction */
val = (pHwInit->aHwInitTxn[pHwInit->uTxnIndex].uData);
val &= 0xFFFDFFFF; /*clear bit 17*/
/* Now we can zero the index */
pHwInit->uTxnIndex = 0;
BUILD_HW_INIT_TXN_DATA(pHwInit, pTxn, GPIO_SELECT, val,
REGISTER_SIZE, TXN_DIRECTION_WRITE, NULL, NULL)
twIf_Transact(pHwInit->hTwIf, pTxn);
pHwInit->uTxnIndex++;
pHwInit->uRegData = FUNC7_SEL;
continue;
case 2:
pHwInit->uRegStage ++;
add = pHwInit->uRegData;
/* Select GPIO over Debug for BT_FUNC7*/
retAddress = (TI_UINT32)(add / 2);
val = (retAddress & 0x7FF);
val |= BIT_16 | BIT_17;
BUILD_HW_INIT_TXN_DATA(pHwInit, pTxn, OCP_POR_CTR, val,
REGISTER_SIZE, TXN_DIRECTION_WRITE, NULL, NULL)
twIf_Transact(pHwInit->hTwIf, pTxn);
pHwInit->uTxnIndex++;
BUILD_HW_INIT_TXN_DATA(pHwInit, pTxn, OCP_CMD, 0x2,
REGISTER_SIZE, TXN_DIRECTION_WRITE, NULL, NULL)
twIf_Transact(pHwInit->hTwIf, pTxn);
continue;
case 3:
pHwInit->uRegStage ++;
pHwInit->uTxnIndex++;
BUILD_HW_INIT_TXN_DATA(pHwInit, pTxn, OCP_DATA_RD, 0,
REGISTER_SIZE, TXN_DIRECTION_READ, (TTxnDoneCb)hwInit_ReadRadioParamsSm, hHwInit)
status = twIf_Transact(pHwInit->hTwIf, pTxn);
EXCEPT (pHwInit, status)
case 4:
val = (pHwInit->aHwInitTxn[pHwInit->uTxnIndex].uData);
pHwInit->uTxnIndex = 0;
if (val & BIT_18)
{
if ((val & BIT_16) && (!(val & BIT_17)))
{
pHwInit->uRegStage ++;
pHwInit->uRegLoop = 0;
}
else
{
TRACE0(pHwInit->hReport, REPORT_SEVERITY_ERROR , "can't writing bt_func7_sel\n");
TWD_FinalizeFEMRead(pHwInit->hTWD);
return TI_NOK;
}
}
else
{
if (pHwInit->uRegLoop < READ_TOP_REG_LOOP)
{
pHwInit->uRegStage = 3;
pHwInit->uRegLoop++;
}
else
{
TRACE0(pHwInit->hReport, REPORT_SEVERITY_ERROR , "Timeout waiting for writing bt_func7_sel\n");
TWD_FinalizeFEMRead(pHwInit->hTWD);
return TI_NOK;
}
}
continue;
case 5:
pHwInit->uRegStage ++;
add = pHwInit->uRegData;
retAddress = (TI_UINT32)(add / 2);
value = (retAddress & 0x7FF);
value |= BIT_16 | BIT_17;
BUILD_HW_INIT_TXN_DATA(pHwInit, pTxn, OCP_POR_CTR, value,
REGISTER_SIZE, TXN_DIRECTION_WRITE, NULL, NULL)
twIf_Transact(pHwInit->hTwIf, pTxn);
pHwInit->uTxnIndex++;
if (pHwInit->uRegSeqStage == 0)
{
if (pHwInit->uRegData == FUNC7_SEL)
value = (val | 0x600);
else
value = (val | 0x1000);
}
else
{
if (pHwInit->uRegData == FUNC7_SEL)
value = (val & 0xF8FF);
else
value = (val & 0xCFFF);
}
value &= 0xFFFF;
BUILD_HW_INIT_TXN_DATA(pHwInit, pTxn, OCP_POR_WDATA, value,
REGISTER_SIZE, TXN_DIRECTION_WRITE, NULL, NULL)
twIf_Transact(pHwInit->hTwIf, pTxn);
pHwInit->uTxnIndex++;
BUILD_HW_INIT_TXN_DATA(pHwInit, pTxn, OCP_CMD, 0x1,
REGISTER_SIZE, TXN_DIRECTION_WRITE, (TTxnDoneCb)hwInit_ReadRadioParamsSm, hHwInit)
/*BUILD_HW_INIT_TXN_DATA(pHwInit, pTxn, INDIRECT_REG5, 0x1,
REGISTER_SIZE, TXN_DIRECTION_WRITE, NULL, NULL) */
status = twIf_Transact(pHwInit->hTwIf, pTxn);
pHwInit->uTxnIndex++;
if ((pHwInit->uRegData == FUNC7_SEL)&& (pHwInit->uRegSeqStage == 0))
{
pHwInit->uRegData = FUNC7_PULL;
pHwInit->uRegStage = 2;
}
else
{
if ((pHwInit->uRegData == FUNC7_PULL)&& (pHwInit->uRegSeqStage == 1))
{
pHwInit->uRegData = FUNC7_SEL;
pHwInit->uRegStage = 2;
}
}
EXCEPT (pHwInit, status)
continue;
case 6:
if (pHwInit->uRegSeqStage == 1)
{
pHwInit->uRegStage = 8;
}
else
{
pHwInit->uRegStage ++;
pHwInit->uTxnIndex++;
BUILD_HW_INIT_TXN_DATA(pHwInit, pTxn, GPIO_OE_RADIO, 0,
REGISTER_SIZE, TXN_DIRECTION_READ, (TTxnDoneCb)hwInit_ReadRadioParamsSm, hHwInit)
status = twIf_Transact(pHwInit->hTwIf, pTxn);
EXCEPT (pHwInit, status)
}
continue;
case 7:
pHwInit->uRegStage ++;
/* We don't zero pHwInit->uTxnIndex at the begining because we need it's value to the next transaction */
val = (pHwInit->aHwInitTxn[pHwInit->uTxnIndex].uData);
val |= 0x00020000;
pHwInit->uTxnIndex = 0;
BUILD_HW_INIT_TXN_DATA(pHwInit, pTxn, GPIO_OE_RADIO, val,
REGISTER_SIZE, TXN_DIRECTION_WRITE, NULL, NULL)
twIf_Transact(pHwInit->hTwIf, pTxn);
pHwInit->uTxnIndex++;
BUILD_HW_INIT_TXN_DATA(pHwInit, pTxn, GPIO_IN, 0,
REGISTER_SIZE, TXN_DIRECTION_READ, (TTxnDoneCb)hwInit_ReadRadioParamsSm, hHwInit)
status = twIf_Transact(pHwInit->hTwIf, pTxn);
EXCEPT (pHwInit, status)
case 8:
if (pHwInit->uRegSeqStage == 0)
{
val = (pHwInit->aHwInitTxn[pHwInit->uTxnIndex].uData);
val &= 0x20000;
if(val)
{
pGenParams->TXBiPFEMManufacturer = FEM_TRIQUINT_TYPE_E;
}
else
{
pGenParams->TXBiPFEMManufacturer = FEM_RFMD_TYPE_E;
}
WLAN_OS_REPORT (("FEM Type %d \n",pGenParams->TXBiPFEMManufacturer));
pHwInit->uTxnIndex = 0;
pHwInit->uRegSeqStage = 1;
pHwInit->uRegStage = 2;
pHwInit->uRegData = FUNC7_PULL;
continue;
}
else
{
TRACE0(pHwInit->hReport, REPORT_SEVERITY_INFORMATION, "hwInit_ReadRadioParamsSm Ended Successfully\n");
TWD_FinalizeFEMRead(pHwInit->hTWD);
return TI_OK;
}
} /* End switch */
} /* End while */
}
/****************************************************************************
* hwInit_ReadRadioParams()
****************************************************************************
* DESCRIPTION: hwInit_ReadRadioParamsSm
* initalizie hwInit_ReadRadioParamsSm parmaeters
****************************************************************************/
TI_STATUS hwInit_ReadRadioParams (TI_HANDLE hHwInit)
{
THwInit *pHwInit = (THwInit *)hHwInit;
pHwInit->uRegStage = 0;
pHwInit->uRegSeqStage = 0;
return hwInit_ReadRadioParamsSm (hHwInit);
}
/****************************************************************************
* hwInit_InitPoalrity()
****************************************************************************
* DESCRIPTION: hwInit_ReadRadioParamsSm
* initalizie hwInit_ReadRadioParamsSm parmaeters
****************************************************************************/
TI_STATUS hwInit_InitPolarity(TI_HANDLE hHwInit)
{
THwInit *pHwInit = (THwInit *)hHwInit;
pHwInit->uRegStage = 0;
pHwInit->uRegSeqStage = 0;
return hwInit_WriteIRQPolarity (hHwInit);
}
/****************************************************************************
* hwInit_WriteIRQPolarity ()
****************************************************************************
* DESCRIPTION: hwInit_WriteIRQPolarity
* INPUTS: None
*
* OUTPUT: None
*
* RETURNS: TI_OK or TI_NOK
****************************************************************************/
TI_STATUS hwInit_WriteIRQPolarity(TI_HANDLE hHwInit)
{
THwInit *pHwInit = (THwInit *)hHwInit;
TI_UINT32 Address,value;
TI_UINT32 val=0;
TTxnStruct *pTxn;
TI_STATUS status = 0;
/* To write to a top level address from the WLAN IP:
Write the top level address to the OCP_POR_CTR register.
Divide the top address by 2, and add 0x30000 to the result – for example for top address 0xC00, write to the OCP_POR_CTR 0x30600
Write the data to the OCP_POR_WDATA register
Write 0x1 to the OCP_CMD register.
To read from a top level address:
Write the top level address to the OCP_POR_CTR register.
Divide the top address by 2, and add 0x30000 to the result – for example for top address 0xC00, write to the OCP_POR_CTR 0x30600
Write 0x2 to the OCP_CMD register.
Poll bit [18] of OCP_DATA_RD for data valid indication
Check bits 17:16 of OCP_DATA_RD:
00 – no response
01 – data valid / accept
10 – request failed
11 – response error
Read the data from the OCP_DATA_RD register
*/
while (TI_TRUE)
{
switch (pHwInit->uRegStage)
{
case 0:
pHwInit->uRegStage = 1;
pHwInit->uTxnIndex++;
pHwInit->uRegLoop = 0;
/* first read the IRQ Polarity register*/
Address = (TI_UINT32)(FN0_CCCR_REG_32 / 2);
val = (Address & 0x7FF);
val |= BIT_16 | BIT_17;
/* Write IRQ Polarity address register to OCP_POR_CTR*/
BUILD_HW_INIT_TXN_DATA(pHwInit, pTxn, OCP_POR_CTR, val,
REGISTER_SIZE, TXN_DIRECTION_WRITE, NULL, NULL)
twIf_Transact(pHwInit->hTwIf, pTxn);
pHwInit->uTxnIndex++;
/* Write read (2)command to the OCP_CMD register. */
BUILD_HW_INIT_TXN_DATA(pHwInit, pTxn, OCP_CMD, 0x2,
REGISTER_SIZE, TXN_DIRECTION_WRITE, NULL, NULL)
twIf_Transact(pHwInit->hTwIf, pTxn);
continue;
case 1:
pHwInit->uRegStage ++;
pHwInit->uTxnIndex++;
BUILD_HW_INIT_TXN_DATA(pHwInit, pTxn, OCP_DATA_RD, 0,
REGISTER_SIZE, TXN_DIRECTION_READ, (TTxnDoneCb)hwInit_WriteIRQPolarity, hHwInit)
status = twIf_Transact(pHwInit->hTwIf, pTxn);
EXCEPT (pHwInit, status)
case 2:
/* get the value from IRQ Polarity register*/
val = pHwInit->aHwInitTxn[pHwInit->uTxnIndex].uData;
pHwInit->uTxnIndex = 0;
/*Poll bit 18 of OCP_DATA_RD for data valid indication*/
if (val & BIT_18)
{
if ((val & BIT_16) && (!(val & BIT_17)))
{
pHwInit->uRegStage ++;
pHwInit->uRegLoop = 0;
}
else
{
TRACE0(pHwInit->hReport, REPORT_SEVERITY_ERROR , "can't writing bt_func7_sel\n");
TWD_FinalizePolarityRead(pHwInit->hTWD);
return TI_NOK;
}
}
else
{
if (pHwInit->uRegLoop < READ_TOP_REG_LOOP)
{
pHwInit->uRegStage = 1;
pHwInit->uRegLoop++;
}
else
{
TRACE0(pHwInit->hReport, REPORT_SEVERITY_ERROR , "Timeout waiting for writing bt_func7_sel\n");
TWD_FinalizePolarityRead(pHwInit->hTWD);
return TI_NOK;
}
}
continue;
case 3:
/* second, write new value of IRQ polarity due to complation flag 1 - active low, 0 - active high*/
pHwInit->uRegStage ++;
Address = (TI_UINT32)(FN0_CCCR_REG_32 / 2);
value = (Address & 0x7FF);
value |= BIT_16 | BIT_17;
/* Write IRQ Polarity address register to OCP_POR_CTR*/
BUILD_HW_INIT_TXN_DATA(pHwInit, pTxn, OCP_POR_CTR, value,
REGISTER_SIZE, TXN_DIRECTION_WRITE, NULL, NULL)
twIf_Transact(pHwInit->hTwIf, pTxn);
pHwInit->uTxnIndex++;
#ifdef USE_IRQ_ACTIVE_HIGH
TRACE0(pHwInit->hReport, REPORT_SEVERITY_INFORMATION , "Hwinit IRQ polarity active high\n");
val |= 0x0<<1;
#else
TRACE0(pHwInit->hReport, REPORT_SEVERITY_INFORMATION , "Hwinit IRQ polarity active low\n");
val |= 0x01<<1;
#endif
/* Write the new IRQ polarity value to the OCP_POR_WDATA register */
BUILD_HW_INIT_TXN_DATA(pHwInit, pTxn, OCP_POR_WDATA, val,
REGISTER_SIZE, TXN_DIRECTION_WRITE, NULL, NULL)
twIf_Transact(pHwInit->hTwIf, pTxn);
pHwInit->uTxnIndex++;
/* Write write (1)command to the OCP_CMD register. */
BUILD_HW_INIT_TXN_DATA(pHwInit, pTxn, OCP_CMD, 0x1,
REGISTER_SIZE, TXN_DIRECTION_WRITE, (TTxnDoneCb)hwInit_WriteIRQPolarity, hHwInit)
status = twIf_Transact(pHwInit->hTwIf, pTxn);
pHwInit->uTxnIndex++;
EXCEPT (pHwInit, status)
continue;
case 4:
TWD_FinalizePolarityRead(pHwInit->hTWD);
return TI_OK;
} /* End switch */
} /* End while */
}
/****************************************************************************
* hwInit_InitTopRegisterWrite()
****************************************************************************
* DESCRIPTION: hwInit_InitTopRegisterWrite
* initalizie hwInit_TopRegisterWrite SM parmaeters
****************************************************************************/
TI_STATUS hwInit_InitTopRegisterWrite(TI_HANDLE hHwInit, TI_UINT32 uAddress, TI_UINT32 uValue)
{
THwInit *pHwInit = (THwInit *)hHwInit;
pHwInit->uTopStage = 0;
uAddress = (TI_UINT32)(uAddress / 2);
uAddress = (uAddress & 0x7FF);
uAddress|= BIT_16 | BIT_17;
pHwInit->uTopRegAddr = uAddress;
pHwInit->uTopRegValue = uValue & 0xffff;
return hwInit_TopRegisterWrite (hHwInit);
}
/****************************************************************************
* hwInit_WriteTopRegister ()
****************************************************************************
* DESCRIPTION: Generic function that writes to the top registers area
* INPUTS: None
*
* OUTPUT: None
*
* RETURNS: TI_OK or TI_NOK
****************************************************************************/
TI_STATUS hwInit_TopRegisterWrite(TI_HANDLE hHwInit)
{
/* To write to a top level address from the WLAN IP:
Write the top level address to the OCP_POR_CTR register.
Divide the top address by 2, and add 0x30000 to the result – for example for top address 0xC00, write to the OCP_POR_CTR 0x30600
Write the data to the OCP_POR_WDATA register
Write 0x1 to the OCP_CMD register.
*/
THwInit *pHwInit = (THwInit *)hHwInit;
TTxnStruct *pTxn;
TI_STATUS status = 0;
while (TI_TRUE)
{
switch (pHwInit->uTopStage)
{
case 0:
pHwInit->uTopStage = 1;
pHwInit->uTxnIndex++;
/* Write the address to OCP_POR_CTR*/
BUILD_HW_INIT_TXN_DATA(pHwInit, pTxn, OCP_POR_CTR, pHwInit->uTopRegAddr,
REGISTER_SIZE, TXN_DIRECTION_WRITE, NULL, NULL)
twIf_Transact(pHwInit->hTwIf, pTxn);
pHwInit->uTxnIndex++;
/* Write the new value to the OCP_POR_WDATA register */
BUILD_HW_INIT_TXN_DATA(pHwInit, pTxn, OCP_POR_WDATA, pHwInit->uTopRegValue,
REGISTER_SIZE, TXN_DIRECTION_WRITE, NULL, NULL)
twIf_Transact(pHwInit->hTwIf, pTxn);
pHwInit->uTxnIndex++;
/* Write write (1)command to the OCP_CMD register. */
BUILD_HW_INIT_TXN_DATA(pHwInit, pTxn, OCP_CMD, 0x1,
REGISTER_SIZE, TXN_DIRECTION_WRITE, (TTxnDoneCb)hwInit_TopRegisterWrite, hHwInit)
status = twIf_Transact(pHwInit->hTwIf, pTxn);
pHwInit->uTxnIndex++;
EXCEPT (pHwInit, status)
continue;
case 1:
pHwInit->uTxnIndex = 0;
return TI_OK;
} /* End switch */
} /* End while */
}
/****************************************************************************
* hwInit_InitTopRegisterWrite()
****************************************************************************
* DESCRIPTION: hwInit_InitTopRegisterWrite
* initalizie hwInit_TopRegisterWrite SM parmaeters
****************************************************************************/
TI_STATUS hwInit_InitTopRegisterRead(TI_HANDLE hHwInit, TI_UINT32 uAddress)
{
THwInit *pHwInit = (THwInit *)hHwInit;
pHwInit->uTopStage = 0;
uAddress = (TI_UINT32)(uAddress / 2);
uAddress = (uAddress & 0x7FF);
uAddress|= BIT_16 | BIT_17;
pHwInit->uTopRegAddr = uAddress;
return hwInit_TopRegisterRead (hHwInit);
}
/****************************************************************************
* hwInit_WriteTopRegister ()
****************************************************************************
* DESCRIPTION: Generic function that writes to the top registers area
* INPUTS: None
*
* OUTPUT: None
*
* RETURNS: TI_OK or TI_NOK
****************************************************************************/
TI_STATUS hwInit_TopRegisterRead(TI_HANDLE hHwInit)
{
/*
To read from a top level address:
Write the top level address to the OCP_POR_CTR register.
Divide the top address by 2, and add 0x30000 to the result – for example for top address 0xC00, write to the OCP_POR_CTR 0x30600
Write 0x2 to the OCP_CMD register.
Poll bit [18] of OCP_DATA_RD for data valid indication
Check bits 17:16 of OCP_DATA_RD:
00 – no response
01 – data valid / accept
10 – request failed
11 – response error
Read the data from the OCP_DATA_RD register
*/
THwInit *pHwInit = (THwInit *)hHwInit;
TTxnStruct *pTxn;
TI_STATUS status = 0;
while (TI_TRUE)
{
switch (pHwInit->uTopStage)
{
case 0:
pHwInit->uTopStage = 1;
pHwInit->uTxnIndex++;
pHwInit->uRegLoop = 0;
/* Write the address to OCP_POR_CTR*/
BUILD_HW_INIT_TXN_DATA(pHwInit, pTxn, OCP_POR_CTR, pHwInit->uTopRegAddr,
REGISTER_SIZE, TXN_DIRECTION_WRITE, NULL, NULL)
twIf_Transact(pHwInit->hTwIf, pTxn);
pHwInit->uTxnIndex++;
BUILD_HW_INIT_TXN_DATA(pHwInit, pTxn, OCP_CMD, 0x2,
REGISTER_SIZE, TXN_DIRECTION_WRITE, NULL, NULL)
twIf_Transact(pHwInit->hTwIf, pTxn);
continue;
case 1:
pHwInit->uTopStage ++;
pHwInit->uTxnIndex++;
BUILD_HW_INIT_TXN_DATA(pHwInit, pTxn, OCP_DATA_RD, 0,
REGISTER_SIZE, TXN_DIRECTION_READ, (TTxnDoneCb)hwInit_TopRegisterRead, hHwInit)
status = twIf_Transact(pHwInit->hTwIf, pTxn);
EXCEPT (pHwInit, status)
case 2:
/* get the value from IRQ Polarity register*/
pHwInit->uTopRegValue = pHwInit->aHwInitTxn[pHwInit->uTxnIndex].uData;
pHwInit->uTxnIndex = 0;
/*Poll bit 18 of OCP_DATA_RD for data valid indication*/
if (pHwInit->uTopRegValue & BIT_18)
{
if ((pHwInit->uTopRegValue & BIT_16) && (!(pHwInit->uTopRegValue & BIT_17)))
{
pHwInit->uTopRegValue &= 0xffff;
pHwInit->uTxnIndex = 0;
pHwInit->uRegLoop = 0;
return TI_OK;
}
else
{
TRACE0(pHwInit->hReport, REPORT_SEVERITY_ERROR , "can't writing bt_func7_sel\n");
return TI_NOK;
}
}
else
{
if (pHwInit->uRegLoop < READ_TOP_REG_LOOP)
{
pHwInit->uTopStage = 1;
pHwInit->uRegLoop++;
}
else
{
TRACE0(pHwInit->hReport, REPORT_SEVERITY_ERROR , "Timeout waiting for writing bt_func7_sel\n");
return TI_NOK;
}
}
continue;
} /* End switch */
} /* End while */
}