/*
 * HwInit.c
 *
 * Copyright(c) 1998 - 2010 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 "timer.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


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

#define DRPw_MASK_CHECK  0xc0
#define DRPw_MASK_SET    0x2000000

/* time to wait till we check if fw is running */
#define STALL_TIMEOUT   7

#ifdef DOWNLOAD_TIMER_REQUIERD
#define FIN_LOOP 10
#endif


#ifdef _VLCT_
#define FIN_LOOP 10
#else
#define FIN_LOOP 20000
#endif


/************************************************************************
 * 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;
	TI_HANDLE               hStallTimer;

    /* Top register Read/Write SM temporary data*/
    TI_UINT32               uTopRegAddr;
    TI_UINT32               uTopRegValue;
    TI_UINT32               uTopRegMask;
    TI_UINT32               uTopRegUpdateValue;
    TI_UINT32               uTopStage;
    TI_STATUS               uTopStatus;

    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);
#ifdef DOWNLOAD_TIMER_REQUIERD
static void      hwInit_StallTimerCb                (TI_HANDLE hHwInit, TI_BOOL bTwdInitOccured);
#endif


/*******************************************************************************
*                       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;

    if (pHwInit->hStallTimer)
    {
#ifdef DOWNLOAD_TIMER_REQUIERD
		tmr_DestroyTimer (pHwInit->hStallTimer);
#endif
    }        

    /* 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      hTimer,
                       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)
    }

#ifdef DOWNLOAD_TIMER_REQUIERD
	pHwInit->hStallTimer = tmr_CreateTimer (hTimer);
	if (pHwInit->hStallTimer == NULL) 
	{
		return TI_NOK;
	}
#endif

    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;
        if ((pGenParams->GeneralSettings & DRPw_MASK_CHECK) > 0)
        {
            clkVal |= DRPw_MASK_SET;
        }
        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(("Error!!  1273 PG 1.0 is not supported anymore!!.\n"));
        }
		else if (pHwInit->uChipId == CHIP_ID_1273_PG20)
        {
            WLAN_OS_REPORT(("Working on a 1273 PG 2.0 board.\n"));
        }
        else 
        {
            WLAN_OS_REPORT (("Error!! Found unknown Chip Id = 0x%x\n", pHwInit->uChipId));

            /*
             * 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;
    TTxnStruct* pTxn;


    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;

#ifndef DOWNLOAD_TIMER_REQUIERD
				os_StalluSec (pHwInit->hOs, 50);
#endif

                /* 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 ++;

#ifdef DOWNLOAD_TIMER_REQUIERD
                tmr_StartTimer (pHwInit->hStallTimer, hwInit_StallTimerCb, hHwInit, STALL_TIMEOUT, TI_FALSE);
                return TXN_STATUS_PENDING;
#endif
            }
#ifndef DOWNLOAD_TIMER_REQUIERD
            continue;
#endif

        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);

            /* Unmask interrupts needed in the FW configuration phase */
            fwEvent_SetInitMask (pTWD->hFwEvent);

            /* Get FW static information from mailbox area */
            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)
    status = twIf_Transact(pHwInit->hTwIf, pTxn);
	pHwInit->uTxnIndex++;
	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_TopRegisterWrite ()
 ****************************************************************************
 * 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;

     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)
             pHwInit->uTopStatus = twIf_Transact(pHwInit->hTwIf, pTxn);

             pHwInit->uTxnIndex++;

             EXCEPT (pHwInit, pHwInit->uTopStatus)              
             continue;

         case 1:

             pHwInit->uTxnIndex = 0;
             
             if (pHwInit->uTopStatus == TXN_STATUS_PENDING) 
             {
                 hwInit_BootSm (hHwInit);
             }
             
             return TI_OK;

         } /* End switch */

     } /* End while */

 }


 /****************************************************************************
 *                      hwInit_InitTopRegisterRead()
 ****************************************************************************
 * DESCRIPTION: hwInit_InitTopRegisterRead 
 * initalizie hwInit_InitTopRegisterRead 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_TopRegisterRead ()
 ****************************************************************************
 * DESCRIPTION: Generic function that reads 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;

     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)
             pHwInit->uTopStatus = twIf_Transact(pHwInit->hTwIf, pTxn);

             EXCEPT (pHwInit, pHwInit->uTopStatus)

         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;
                   if (pHwInit->uTopStatus == TXN_STATUS_PENDING) 
                   {
                       hwInit_BootSm (hHwInit);
                   }
                   return TI_OK;
               }
               else
               {
                 TRACE0(pHwInit->hReport, REPORT_SEVERITY_ERROR , "can't write bt_func7_sel\n");                 
                 if (pHwInit->uTopStatus == TXN_STATUS_PENDING) 
                 {
                       hwInit_BootSm (hHwInit);
                 }
                 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");
                 if (pHwInit->uTopStatus == TXN_STATUS_PENDING) 
                 {
                       hwInit_BootSm (hHwInit);
                 }
                 return TI_NOK;
               }
              }

             continue;

         } /* End switch */

     } /* End while */

 }


/****************************************************************************
*                      hwInit_StallTimerCb ()
****************************************************************************
* DESCRIPTION: CB timer function in fTimerFunction format that calls hwInit_StallTimerCb
* INPUTS:  TI_HANDLE hHwInit    
* 
* OUTPUT:  None
* 
* RETURNS: None
****************************************************************************/
#ifdef DOWNLOAD_TIMER_REQUIERD
 static void hwInit_StallTimerCb (TI_HANDLE hHwInit, TI_BOOL bTwdInitOccured)
{
	hwInit_FinalizeDownloadSm (hHwInit);
}
#endif
