linux/drivers/staging/rtl8192su/r8192S_firmware.c
<<
>>
Prefs
   1/**************************************************************************************************
   2 * Procedure:    Init boot code/firmware code/data session
   3 *
   4 * Description: This routine will intialize firmware. If any error occurs during the initialization
   5 *              process, the routine shall terminate immediately and return fail.
   6 *              NIC driver should call NdisOpenFile only from MiniportInitialize.
   7 *
   8 * Arguments:   The pointer of the adapter
   9
  10 * Returns:
  11 *        NDIS_STATUS_FAILURE - the following initialization process should be terminated
  12 *        NDIS_STATUS_SUCCESS - if firmware initialization process success
  13**************************************************************************************************/
  14#include "r8192U.h"
  15#include "r8192S_firmware.h"
  16#include <linux/unistd.h>
  17
  18#include "r8192S_hw.h"
  19#include "r8192SU_HWImg.h"
  20
  21#include <linux/firmware.h>
  22
  23#define   byte(x,n)  ( (x >> (8 * n)) & 0xff  )
  24
  25//
  26// Description:   This routine will intialize firmware. If any error occurs during the initialization
  27//                              process, the routine shall terminate immediately and return fail.
  28//
  29// Arguments:   The pointer of the adapter
  30//                         Code address (Virtual address, should fill descriptor with physical address)
  31//                         Code size
  32// Created by Roger, 2008.04.10.
  33//
  34bool FirmwareDownloadCode(struct net_device *dev, u8 *  code_virtual_address,u32 buffer_len)
  35{
  36        struct r8192_priv   *priv = ieee80211_priv(dev);
  37        bool                rt_status = true;
  38        u16                 frag_threshold = MAX_FIRMWARE_CODE_SIZE; //Fragmentation might be required in 90/92 but not in 92S
  39        u16                 frag_length, frag_offset = 0;
  40        struct sk_buff      *skb;
  41        unsigned char       *seg_ptr;
  42        cb_desc             *tcb_desc;
  43        u8                          bLastIniPkt = 0;
  44        u16                         ExtraDescOffset = 0;
  45
  46
  47        RT_TRACE(COMP_FIRMWARE, "--->FirmwareDownloadCode()\n" );
  48
  49        //MAX_TRANSMIT_BUFFER_SIZE
  50        if(buffer_len >= MAX_FIRMWARE_CODE_SIZE-USB_HWDESC_HEADER_LEN)
  51        {
  52                RT_TRACE(COMP_ERR, "Size over MAX_FIRMWARE_CODE_SIZE! \n");
  53                goto cmdsend_downloadcode_fail;
  54        }
  55
  56        ExtraDescOffset = USB_HWDESC_HEADER_LEN;
  57
  58        do {
  59                if((buffer_len-frag_offset) > frag_threshold)
  60                {
  61                        frag_length = frag_threshold + ExtraDescOffset;
  62                }
  63                else
  64                {
  65                        frag_length = (u16)(buffer_len - frag_offset + ExtraDescOffset);
  66                bLastIniPkt = 1;
  67                }
  68
  69                /* Allocate skb buffer to contain firmware info and tx descriptor info. */
  70                skb  = dev_alloc_skb(frag_length);
  71                memcpy((unsigned char *)(skb->cb),&dev,sizeof(dev));
  72
  73                tcb_desc = (cb_desc*)(skb->cb + MAX_DEV_ADDR_SIZE);
  74                tcb_desc->queue_index = TXCMD_QUEUE;
  75                tcb_desc->bCmdOrInit = DESC_PACKET_TYPE_INIT;
  76                tcb_desc->bLastIniPkt = bLastIniPkt;
  77
  78                skb_reserve(skb, ExtraDescOffset);
  79                seg_ptr = (u8 *)skb_put(skb, (u32)(frag_length-ExtraDescOffset));
  80                memcpy(seg_ptr, code_virtual_address+frag_offset, (u32)(frag_length-ExtraDescOffset));
  81
  82                tcb_desc->txbuf_size= frag_length;
  83
  84                if(!priv->ieee80211->check_nic_enough_desc(dev,tcb_desc->queue_index)||
  85                        (!skb_queue_empty(&priv->ieee80211->skb_waitQ[tcb_desc->queue_index]))||\
  86                        (priv->ieee80211->queue_stop) )
  87                {
  88                        RT_TRACE(COMP_FIRMWARE,"=====================================================> tx full!\n");
  89                        skb_queue_tail(&priv->ieee80211->skb_waitQ[tcb_desc->queue_index], skb);
  90                }
  91                else
  92                {
  93                        priv->ieee80211->softmac_hard_start_xmit(skb,dev);
  94                }
  95
  96                frag_offset += (frag_length - ExtraDescOffset);
  97
  98        }while(frag_offset < buffer_len);
  99
 100        return rt_status ;
 101
 102
 103cmdsend_downloadcode_fail:
 104        rt_status = false;
 105        RT_TRACE(COMP_ERR, "CmdSendDownloadCode fail !!\n");
 106        return rt_status;
 107
 108}
 109
 110
 111RT_STATUS
 112FirmwareEnableCPU(struct net_device *dev)
 113{
 114
 115        RT_STATUS       rtStatus = RT_STATUS_SUCCESS;
 116        u8              tmpU1b, CPUStatus = 0;
 117        u16             tmpU2b;
 118        u32             iCheckTime = 200;
 119
 120        RT_TRACE(COMP_FIRMWARE, "-->FirmwareEnableCPU()\n" );
 121        // Enable CPU.
 122        tmpU1b = read_nic_byte(dev, SYS_CLKR);
 123        write_nic_byte(dev,  SYS_CLKR, (tmpU1b|SYS_CPU_CLKSEL)); //AFE source
 124
 125        tmpU2b = read_nic_word(dev, SYS_FUNC_EN);
 126        write_nic_word(dev, SYS_FUNC_EN, (tmpU2b|FEN_CPUEN));
 127
 128        //Polling IMEM Ready after CPU has refilled.
 129        do
 130        {
 131                CPUStatus = read_nic_byte(dev, TCR);
 132                if(CPUStatus& IMEM_RDY)
 133                {
 134                        RT_TRACE(COMP_FIRMWARE, "IMEM Ready after CPU has refilled.\n");
 135                        break;
 136                }
 137
 138                //usleep(100);
 139                udelay(100);
 140        }while(iCheckTime--);
 141
 142        if(!(CPUStatus & IMEM_RDY))
 143                return RT_STATUS_FAILURE;
 144
 145        RT_TRACE(COMP_FIRMWARE, "<--FirmwareEnableCPU(): rtStatus(%#x)\n", rtStatus);
 146        return rtStatus;
 147}
 148
 149FIRMWARE_8192S_STATUS
 150FirmwareGetNextStatus(FIRMWARE_8192S_STATUS FWCurrentStatus)
 151{
 152        FIRMWARE_8192S_STATUS   NextFWStatus = 0;
 153
 154        switch(FWCurrentStatus)
 155        {
 156                case FW_STATUS_INIT:
 157                        NextFWStatus = FW_STATUS_LOAD_IMEM;
 158                        break;
 159
 160                case FW_STATUS_LOAD_IMEM:
 161                        NextFWStatus = FW_STATUS_LOAD_EMEM;
 162                        break;
 163
 164                case FW_STATUS_LOAD_EMEM:
 165                        NextFWStatus = FW_STATUS_LOAD_DMEM;
 166                        break;
 167
 168                case FW_STATUS_LOAD_DMEM:
 169                        NextFWStatus = FW_STATUS_READY;
 170                        break;
 171
 172                default:
 173                        RT_TRACE(COMP_ERR,"Invalid FW Status(%#x)!!\n", FWCurrentStatus);
 174                        break;
 175        }
 176        return  NextFWStatus;
 177}
 178
 179bool
 180FirmwareCheckReady(struct net_device *dev,      u8 LoadFWStatus)
 181{
 182        struct r8192_priv       *priv = ieee80211_priv(dev);
 183        RT_STATUS       rtStatus = RT_STATUS_SUCCESS;
 184        rt_firmware     *pFirmware = priv->pFirmware;
 185        int                     PollingCnt = 1000;
 186        //u8            tmpU1b, CPUStatus = 0;
 187        u8              CPUStatus = 0;
 188        u32             tmpU4b;
 189        //bool          bOrgIMREnable;
 190
 191        RT_TRACE(COMP_FIRMWARE, "--->FirmwareCheckReady(): LoadStaus(%d),", LoadFWStatus);
 192
 193        pFirmware->FWStatus = (FIRMWARE_8192S_STATUS)LoadFWStatus;
 194        if( LoadFWStatus == FW_STATUS_LOAD_IMEM)
 195        {
 196                do
 197                {//Polling IMEM code done.
 198                        CPUStatus = read_nic_byte(dev, TCR);
 199                        if(CPUStatus& IMEM_CODE_DONE)
 200                                break;
 201
 202                        udelay(5);
 203                }while(PollingCnt--);
 204                if(!(CPUStatus & IMEM_CHK_RPT) || PollingCnt <= 0)
 205                {
 206                        RT_TRACE(COMP_ERR, "FW_STATUS_LOAD_IMEM FAIL CPU, Status=%x\r\n", CPUStatus);
 207                        return false;
 208                }
 209        }
 210        else if( LoadFWStatus == FW_STATUS_LOAD_EMEM)
 211        {//Check Put Code OK and Turn On CPU
 212                do
 213                {//Polling EMEM code done.
 214                        CPUStatus = read_nic_byte(dev, TCR);
 215                        if(CPUStatus& EMEM_CODE_DONE)
 216                                break;
 217
 218                        udelay(5);
 219                }while(PollingCnt--);
 220                if(!(CPUStatus & EMEM_CHK_RPT))
 221                {
 222                        RT_TRACE(COMP_ERR, "FW_STATUS_LOAD_EMEM FAIL CPU, Status=%x\r\n", CPUStatus);
 223                        return false;
 224                }
 225
 226                // Turn On CPU
 227                rtStatus = FirmwareEnableCPU(dev);
 228                if(rtStatus != RT_STATUS_SUCCESS)
 229                {
 230                        RT_TRACE(COMP_ERR, "Enable CPU fail ! \n" );
 231                        return false;
 232                }
 233        }
 234        else if( LoadFWStatus == FW_STATUS_LOAD_DMEM)
 235        {
 236                do
 237                {//Polling DMEM code done
 238                        CPUStatus = read_nic_byte(dev, TCR);
 239                        if(CPUStatus& DMEM_CODE_DONE)
 240                                break;
 241
 242                        udelay(5);
 243                }while(PollingCnt--);
 244
 245                if(!(CPUStatus & DMEM_CODE_DONE))
 246                {
 247                        RT_TRACE(COMP_ERR, "Polling  DMEM code done fail ! CPUStatus(%#x)\n", CPUStatus);
 248                        return false;
 249                }
 250
 251                RT_TRACE(COMP_FIRMWARE, "DMEM code download success, CPUStatus(%#x)\n", CPUStatus);
 252
 253//              PollingCnt = 100; // Set polling cycle to 10ms.
 254              PollingCnt = 10000; // Set polling cycle to 10ms.
 255
 256                do
 257                {//Polling Load Firmware ready
 258                        CPUStatus = read_nic_byte(dev, TCR);
 259                        if(CPUStatus & FWRDY)
 260                                break;
 261
 262                        udelay(100);
 263                }while(PollingCnt--);
 264
 265                RT_TRACE(COMP_FIRMWARE, "Polling Load Firmware ready, CPUStatus(%x)\n", CPUStatus);
 266
 267                //if(!(CPUStatus & LOAD_FW_READY))
 268                //if((CPUStatus & LOAD_FW_READY) != 0xff)
 269                if((CPUStatus & LOAD_FW_READY) != LOAD_FW_READY)
 270                {
 271                        RT_TRACE(COMP_ERR, "Polling Load Firmware ready fail ! CPUStatus(%x)\n", CPUStatus);
 272                        return false;
 273                }
 274
 275               //
 276              // <Roger_Notes> USB interface will update reserved followings parameters later!!
 277              // 2008.08.28.
 278              //
 279
 280               //
 281              // <Roger_Notes> If right here, we can set TCR/RCR to desired value
 282              // and config MAC lookback mode to normal mode. 2008.08.28.
 283              //
 284              tmpU4b = read_nic_dword(dev,TCR);
 285                write_nic_dword(dev, TCR, (tmpU4b&(~TCR_ICV)));
 286
 287                tmpU4b = read_nic_dword(dev, RCR);
 288                write_nic_dword(dev, RCR,
 289                        (tmpU4b|RCR_APPFCS|RCR_APP_ICV|RCR_APP_MIC));
 290
 291                RT_TRACE(COMP_FIRMWARE, "FirmwareCheckReady(): Current RCR settings(%#x)\n", tmpU4b);
 292
 293
 294                // Set to normal mode.
 295                write_nic_byte(dev, LBKMD_SEL, LBK_NORMAL);
 296
 297        }
 298
 299        RT_TRACE(COMP_FIRMWARE, "<---FirmwareCheckReady(): LoadFWStatus(%d), rtStatus(%x)\n", LoadFWStatus, rtStatus);
 300        return (rtStatus == RT_STATUS_SUCCESS) ? true:false;
 301}
 302
 303//
 304// Description:   This routine is to update the RF types in FW header partially.
 305//
 306// Created by Roger, 2008.12.24.
 307//
 308u8 FirmwareHeaderMapRfType(struct net_device *dev)
 309{
 310        struct r8192_priv       *priv = ieee80211_priv(dev);
 311        switch(priv->rf_type)
 312        {
 313                case RF_1T1R:   return 0x11;
 314                case RF_1T2R:   return 0x12;
 315                case RF_2T2R:   return 0x22;
 316                case RF_2T2R_GREEN:     return 0x92;
 317                default:
 318                        RT_TRACE(COMP_INIT, "Unknown RF type(%x)\n",priv->rf_type);
 319                        break;
 320        }
 321        return 0x22;
 322}
 323
 324
 325//
 326// Description:   This routine is to update the private parts in FW header partially.
 327//
 328// Created by Roger, 2008.12.18.
 329//
 330void FirmwareHeaderPriveUpdate(struct net_device *dev, PRT_8192S_FIRMWARE_PRIV  pFwPriv)
 331{
 332        struct r8192_priv       *priv = ieee80211_priv(dev);
 333        // Update USB endpoint number for RQPN settings.
 334        pFwPriv->usb_ep_num = priv->EEPROMUsbEndPointNumber; // endpoint number: 4, 6 and 11.
 335        RT_TRACE(COMP_INIT, "FirmwarePriveUpdate(): usb_ep_num(%#x)\n", pFwPriv->usb_ep_num);
 336
 337        // Update RF types for RATR settings.
 338        pFwPriv->rf_config = FirmwareHeaderMapRfType(dev);
 339}
 340
 341
 342
 343bool FirmwareDownload92S(struct net_device *dev)
 344{
 345        struct r8192_priv       *priv = ieee80211_priv(dev);
 346        bool                            rtStatus = true;
 347        const char              *pFwImageFileName[1] = {"RTL8192SU/rtl8192sfw.bin"};
 348        u8                              *pucMappedFile = NULL;
 349        u32                             ulFileLength, ulInitStep = 0;
 350        u8                              FwHdrSize = RT_8192S_FIRMWARE_HDR_SIZE;
 351        rt_firmware             *pFirmware = priv->pFirmware;
 352        u8                              FwStatus = FW_STATUS_INIT;
 353        PRT_8192S_FIRMWARE_HDR          pFwHdr = NULL;
 354        PRT_8192S_FIRMWARE_PRIV         pFwPriv = NULL;
 355        int                             rc;
 356        const struct firmware   *fw_entry;
 357        u32                             file_length = 0;
 358
 359        pFirmware->FWStatus = FW_STATUS_INIT;
 360
 361        RT_TRACE(COMP_FIRMWARE, " --->FirmwareDownload92S()\n");
 362
 363        //3//
 364        //3 //<1> Open Image file, and map file to contineous memory if open file success.
 365        //3  //        or read image file from array. Default load from BIN file
 366        //3//
 367        priv->firmware_source = FW_SOURCE_IMG_FILE;// We should decided by Reg.
 368
 369        switch( priv->firmware_source )
 370        {
 371                case FW_SOURCE_IMG_FILE:
 372                        if(pFirmware->szFwTmpBufferLen == 0)
 373                        {
 374
 375                                rc = request_firmware(&fw_entry, pFwImageFileName[ulInitStep],&priv->udev->dev);//===>1
 376                                if(rc < 0 ) {
 377                                        RT_TRACE(COMP_ERR, "request firmware fail!\n");
 378                                        goto DownloadFirmware_Fail;
 379                                }
 380
 381                                if(fw_entry->size > sizeof(pFirmware->szFwTmpBuffer))
 382                                {
 383                                        RT_TRACE(COMP_ERR, "img file size exceed the container buffer fail!\n");
 384                                        release_firmware(fw_entry);
 385                                        goto DownloadFirmware_Fail;
 386                                }
 387
 388                                memcpy(pFirmware->szFwTmpBuffer,fw_entry->data,fw_entry->size);
 389                                pFirmware->szFwTmpBufferLen = fw_entry->size;
 390                                release_firmware(fw_entry);
 391
 392                                pucMappedFile = pFirmware->szFwTmpBuffer;
 393                                file_length = pFirmware->szFwTmpBufferLen;
 394
 395                                //Retrieve FW header.
 396                                pFirmware->pFwHeader = (PRT_8192S_FIRMWARE_HDR) pucMappedFile;
 397                                pFwHdr = pFirmware->pFwHeader;
 398                                RT_TRACE(COMP_FIRMWARE,"signature:%x, version:%x, size:%x, imemsize:%x, sram size:%x\n", \
 399                                                pFwHdr->Signature, pFwHdr->Version, pFwHdr->DMEMSize, \
 400                                                pFwHdr->IMG_IMEM_SIZE, pFwHdr->IMG_SRAM_SIZE);
 401                                pFirmware->FirmwareVersion =  byte(pFwHdr->Version ,0);
 402                                if ((pFwHdr->IMG_IMEM_SIZE==0) || (pFwHdr->IMG_IMEM_SIZE > sizeof(pFirmware->FwIMEM)))
 403                                {
 404                                        RT_TRACE(COMP_ERR, "%s: memory for data image is less than IMEM required\n",\
 405                                                        __FUNCTION__);
 406                                        goto DownloadFirmware_Fail;
 407                                } else {
 408                                        pucMappedFile+=FwHdrSize;
 409
 410                                        //Retrieve IMEM image.
 411                                        memcpy(pFirmware->FwIMEM, pucMappedFile, pFwHdr->IMG_IMEM_SIZE);
 412                                        pFirmware->FwIMEMLen = pFwHdr->IMG_IMEM_SIZE;
 413                                }
 414
 415                                if (pFwHdr->IMG_SRAM_SIZE > sizeof(pFirmware->FwEMEM))
 416                                {
 417                                        RT_TRACE(COMP_ERR, "%s: memory for data image is less than EMEM required\n",\
 418                                                        __FUNCTION__);
 419                                        goto DownloadFirmware_Fail;
 420                                } else {
 421                                        pucMappedFile += pFirmware->FwIMEMLen;
 422
 423                                        /* Retriecve EMEM image */
 424                                        memcpy(pFirmware->FwEMEM, pucMappedFile, pFwHdr->IMG_SRAM_SIZE);//===>6
 425                                        pFirmware->FwEMEMLen = pFwHdr->IMG_SRAM_SIZE;
 426                                }
 427
 428
 429                        }
 430                        break;
 431
 432                case FW_SOURCE_HEADER_FILE:
 433#if 1
 434#define Rtl819XFwImageArray Rtl8192SUFwImgArray
 435                        //2008.11.10 Add by tynli.
 436                        pucMappedFile = Rtl819XFwImageArray;
 437                        ulFileLength = ImgArrayLength;
 438
 439                        RT_TRACE(COMP_INIT,"Fw download from header.\n");
 440                        /* Retrieve FW header*/
 441                        pFirmware->pFwHeader = (PRT_8192S_FIRMWARE_HDR) pucMappedFile;
 442                        pFwHdr = pFirmware->pFwHeader;
 443                        RT_TRACE(COMP_FIRMWARE,"signature:%x, version:%x, size:%x, imemsize:%x, sram size:%x\n", \
 444                                        pFwHdr->Signature, pFwHdr->Version, pFwHdr->DMEMSize, \
 445                                        pFwHdr->IMG_IMEM_SIZE, pFwHdr->IMG_SRAM_SIZE);
 446                        pFirmware->FirmwareVersion =  byte(pFwHdr->Version ,0);
 447
 448                        if ((pFwHdr->IMG_IMEM_SIZE==0) || (pFwHdr->IMG_IMEM_SIZE > sizeof(pFirmware->FwIMEM)))
 449                        {
 450                                printk("FirmwareDownload92S(): memory for data image is less than IMEM required\n");
 451                                goto DownloadFirmware_Fail;
 452                        } else {
 453                                pucMappedFile+=FwHdrSize;
 454                                //Retrieve IMEM image.
 455                                memcpy(pFirmware->FwIMEM, pucMappedFile, pFwHdr->IMG_IMEM_SIZE);
 456                                pFirmware->FwIMEMLen = pFwHdr->IMG_IMEM_SIZE;
 457                        }
 458
 459                        if (pFwHdr->IMG_SRAM_SIZE > sizeof(pFirmware->FwEMEM))
 460                        {
 461                                printk(" FirmwareDownload92S(): memory for data image is less than EMEM required\n");
 462                                goto DownloadFirmware_Fail;
 463                        } else {
 464                                pucMappedFile+= pFirmware->FwIMEMLen;
 465
 466                                //Retriecve EMEM image.
 467                                memcpy(pFirmware->FwEMEM, pucMappedFile, pFwHdr->IMG_SRAM_SIZE);
 468                                pFirmware->FwEMEMLen = pFwHdr->IMG_SRAM_SIZE;
 469                        }
 470#endif
 471                        break;
 472                default:
 473                        break;
 474        }
 475
 476        FwStatus = FirmwareGetNextStatus(pFirmware->FWStatus);
 477        while(FwStatus!= FW_STATUS_READY)
 478        {
 479                // Image buffer redirection.
 480                switch(FwStatus)
 481                {
 482                        case FW_STATUS_LOAD_IMEM:
 483                                pucMappedFile = pFirmware->FwIMEM;
 484                                ulFileLength = pFirmware->FwIMEMLen;
 485                                break;
 486
 487                        case FW_STATUS_LOAD_EMEM:
 488                                pucMappedFile = pFirmware->FwEMEM;
 489                                ulFileLength = pFirmware->FwEMEMLen;
 490                                break;
 491
 492                        case FW_STATUS_LOAD_DMEM:
 493                                /* <Roger_Notes> Partial update the content of header private. 2008.12.18 */
 494                                pFwHdr = pFirmware->pFwHeader;
 495                                pFwPriv = (PRT_8192S_FIRMWARE_PRIV)&pFwHdr->FWPriv;
 496                                FirmwareHeaderPriveUpdate(dev, pFwPriv);
 497                                pucMappedFile = (u8*)(pFirmware->pFwHeader)+RT_8192S_FIRMWARE_HDR_EXCLUDE_PRI_SIZE;
 498                                ulFileLength = FwHdrSize-RT_8192S_FIRMWARE_HDR_EXCLUDE_PRI_SIZE;
 499                                break;
 500
 501                        default:
 502                                RT_TRACE(COMP_ERR, "Unexpected Download step!!\n");
 503                                goto DownloadFirmware_Fail;
 504                                break;
 505                }
 506
 507                //3//
 508                //3// <2> Download image file
 509        //3     //
 510                rtStatus = FirmwareDownloadCode(dev, pucMappedFile, ulFileLength);
 511
 512                if(rtStatus != true)
 513                {
 514                        RT_TRACE(COMP_ERR, "FirmwareDownloadCode() fail ! \n" );
 515                        goto DownloadFirmware_Fail;
 516                }
 517
 518                //3//
 519                //3// <3> Check whether load FW process is ready
 520        //3     //
 521                rtStatus = FirmwareCheckReady(dev, FwStatus);
 522
 523                if(rtStatus != true)
 524                {
 525                        RT_TRACE(COMP_ERR, "FirmwareDownloadCode() fail ! \n");
 526                        goto DownloadFirmware_Fail;
 527                }
 528
 529                FwStatus = FirmwareGetNextStatus(pFirmware->FWStatus);
 530        }
 531
 532        RT_TRACE(COMP_FIRMWARE, "Firmware Download Success!!\n");
 533        return rtStatus;
 534
 535        DownloadFirmware_Fail:
 536        RT_TRACE(COMP_ERR, "Firmware Download Fail!!%x\n",read_nic_word(dev, TCR));
 537        rtStatus = false;
 538        return rtStatus;
 539}
 540
 541