linux/drivers/staging/rtl8192e/r819xE_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
   5 *              during the initialization process, the routine shall terminate
   6 *              immediately and return fail.  NIC driver should call
   7 *              NdisOpenFile only from MiniportInitialize.
   8 *
   9 * Arguments:   The pointer of the adapter
  10
  11 * Returns:
  12 *              NDIS_STATUS_FAILURE - the following initialization process
  13 *                                    should be terminated
  14 *              NDIS_STATUS_SUCCESS - if firmware initialization process
  15 *                                    success
  16 */
  17#include "r8192E.h"
  18#include "r8192E_hw.h"
  19#include <linux/firmware.h>
  20
  21/* It should be double word alignment */
  22#define GET_COMMAND_PACKET_FRAG_THRESHOLD(v)    (4 * (v / 4) - 8)
  23
  24enum firmware_init_step {
  25        FW_INIT_STEP0_BOOT = 0,
  26        FW_INIT_STEP1_MAIN = 1,
  27        FW_INIT_STEP2_DATA = 2,
  28};
  29
  30enum opt_rst_type {
  31        OPT_SYSTEM_RESET = 0,
  32        OPT_FIRMWARE_RESET = 1,
  33};
  34
  35void firmware_init_param(struct net_device *dev)
  36{
  37        struct r8192_priv *priv = ieee80211_priv(dev);
  38        rt_firmware *pfirmware = priv->pFirmware;
  39
  40        pfirmware->cmdpacket_frag_thresold =
  41                GET_COMMAND_PACKET_FRAG_THRESHOLD(MAX_TRANSMIT_BUFFER_SIZE);
  42}
  43
  44/*
  45 * segment the img and use the ptr and length to remember info on each segment
  46 */
  47static bool fw_download_code(struct net_device *dev, u8 *code_virtual_address,
  48                             u32 buffer_len)
  49{
  50        struct r8192_priv   *priv = ieee80211_priv(dev);
  51        bool                rt_status = true;
  52        u16                 frag_threshold;
  53        u16                 frag_length, frag_offset = 0;
  54        int                 i;
  55
  56        rt_firmware         *pfirmware = priv->pFirmware;
  57        struct sk_buff      *skb;
  58        unsigned char       *seg_ptr;
  59        cb_desc             *tcb_desc;
  60        u8                  bLastIniPkt;
  61
  62        firmware_init_param(dev);
  63
  64        /* Fragmentation might be required */
  65        frag_threshold = pfirmware->cmdpacket_frag_thresold;
  66        do {
  67                if ((buffer_len - frag_offset) > frag_threshold) {
  68                        frag_length = frag_threshold ;
  69                        bLastIniPkt = 0;
  70                } else {
  71                        frag_length = buffer_len - frag_offset;
  72                        bLastIniPkt = 1;
  73                }
  74
  75                /*
  76                 * Allocate skb buffer to contain firmware info and tx
  77                 * descriptor info add 4 to avoid packet appending overflow.
  78                 */
  79                skb  = dev_alloc_skb(frag_length + 4);
  80                memcpy((unsigned char *)(skb->cb), &dev, sizeof(dev));
  81                tcb_desc = (cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE);
  82                tcb_desc->queue_index = TXCMD_QUEUE;
  83                tcb_desc->bCmdOrInit = DESC_PACKET_TYPE_INIT;
  84                tcb_desc->bLastIniPkt = bLastIniPkt;
  85
  86                seg_ptr = skb->data;
  87
  88                /*
  89                 * Transform from little endian to big endian and pending zero
  90                 */
  91                for (i = 0; i < frag_length; i += 4) {
  92                        *seg_ptr++ = ((i+0) < frag_length) ? code_virtual_address[i+3] : 0;
  93                        *seg_ptr++ = ((i+1) < frag_length) ? code_virtual_address[i+2] : 0;
  94                        *seg_ptr++ = ((i+2) < frag_length) ? code_virtual_address[i+1] : 0;
  95                        *seg_ptr++ = ((i+3) < frag_length) ? code_virtual_address[i+0] : 0;
  96                }
  97                tcb_desc->txbuf_size = (u16)i;
  98                skb_put(skb, i);
  99                priv->ieee80211->softmac_hard_start_xmit(skb, dev);
 100
 101                code_virtual_address += frag_length;
 102                frag_offset += frag_length;
 103
 104        } while (frag_offset < buffer_len);
 105
 106        return rt_status;
 107}
 108
 109/*
 110 * Procedure:    Check whether main code is download OK. If OK, turn on CPU
 111 *
 112 * Description:   CPU register locates in different page against general
 113 *                register.  Switch to CPU register in the begin and switch
 114 *                back before return
 115 *
 116 * Arguments:   The pointer of the adapter
 117 *
 118 * Returns:
 119 *      NDIS_STATUS_FAILURE - the following initialization process should be
 120 *                            terminated
 121 *      NDIS_STATUS_SUCCESS - if firmware initialization process success
 122 */
 123static bool CPUcheck_maincodeok_turnonCPU(struct net_device *dev)
 124{
 125        unsigned long timeout;
 126        bool rt_status = true;
 127        u32 CPU_status = 0;
 128
 129        /* Check whether put code OK */
 130        timeout = jiffies + msecs_to_jiffies(20);
 131        while (time_before(jiffies, timeout)) {
 132                CPU_status = read_nic_dword(dev, CPU_GEN);
 133
 134                if (CPU_status & CPU_GEN_PUT_CODE_OK)
 135                        break;
 136                msleep(2);
 137        }
 138
 139        if (!(CPU_status & CPU_GEN_PUT_CODE_OK)) {
 140                RT_TRACE(COMP_ERR, "Download Firmware: Put code fail!\n");
 141                goto CPUCheckMainCodeOKAndTurnOnCPU_Fail;
 142        } else {
 143                RT_TRACE(COMP_FIRMWARE, "Download Firmware: Put code ok!\n");
 144        }
 145
 146        /* Turn On CPU */
 147        CPU_status = read_nic_dword(dev, CPU_GEN);
 148        write_nic_byte(dev, CPU_GEN,
 149                       (u8)((CPU_status | CPU_GEN_PWR_STB_CPU) & 0xff));
 150        mdelay(1);
 151
 152        /* Check whether CPU boot OK */
 153        timeout = jiffies + msecs_to_jiffies(20);
 154        while (time_before(jiffies, timeout)) {
 155                CPU_status = read_nic_dword(dev, CPU_GEN);
 156
 157                if (CPU_status & CPU_GEN_BOOT_RDY)
 158                        break;
 159                msleep(2);
 160        }
 161
 162        if (!(CPU_status & CPU_GEN_BOOT_RDY))
 163                goto CPUCheckMainCodeOKAndTurnOnCPU_Fail;
 164        else
 165                RT_TRACE(COMP_FIRMWARE, "Download Firmware: Boot ready!\n");
 166
 167        return rt_status;
 168
 169CPUCheckMainCodeOKAndTurnOnCPU_Fail:
 170        RT_TRACE(COMP_ERR, "ERR in %s()\n", __func__);
 171        rt_status = FALSE;
 172        return rt_status;
 173}
 174
 175static bool CPUcheck_firmware_ready(struct net_device *dev)
 176{
 177        unsigned long timeout;
 178        bool rt_status = true;
 179        u32 CPU_status = 0;
 180
 181        /* Check Firmware Ready */
 182        timeout = jiffies + msecs_to_jiffies(20);
 183        while (time_before(jiffies, timeout)) {
 184                CPU_status = read_nic_dword(dev, CPU_GEN);
 185
 186                if (CPU_status & CPU_GEN_FIRM_RDY)
 187                        break;
 188                msleep(2);
 189        }
 190
 191        if (!(CPU_status & CPU_GEN_FIRM_RDY))
 192                goto CPUCheckFirmwareReady_Fail;
 193        else
 194                RT_TRACE(COMP_FIRMWARE, "Download Firmware: Firmware ready!\n");
 195
 196        return rt_status;
 197
 198CPUCheckFirmwareReady_Fail:
 199        RT_TRACE(COMP_ERR, "ERR in %s()\n", __func__);
 200        rt_status = false;
 201        return rt_status;
 202
 203}
 204
 205bool init_firmware(struct net_device *dev)
 206{
 207        struct r8192_priv       *priv = ieee80211_priv(dev);
 208        bool                    rt_status = TRUE;
 209        u32                     file_length = 0;
 210        u8                      *mapped_file = NULL;
 211        u32                     init_step = 0;
 212        enum opt_rst_type       rst_opt = OPT_SYSTEM_RESET;
 213        enum firmware_init_step starting_state = FW_INIT_STEP0_BOOT;
 214
 215        rt_firmware             *pfirmware = priv->pFirmware;
 216        const struct firmware   *fw_entry;
 217        const char *fw_name[3] = { "RTL8192E/boot.img",
 218                                   "RTL8192E/main.img",
 219                                   "RTL8192E/data.img"};
 220        int rc;
 221
 222        RT_TRACE(COMP_FIRMWARE, " PlatformInitFirmware()==>\n");
 223
 224        if (pfirmware->firmware_status == FW_STATUS_0_INIT) {
 225                /* it is called by reset */
 226                rst_opt = OPT_SYSTEM_RESET;
 227                starting_state = FW_INIT_STEP0_BOOT;
 228                /* TODO: system reset */
 229
 230        } else if (pfirmware->firmware_status == FW_STATUS_5_READY) {
 231                /* it is called by Initialize */
 232                rst_opt = OPT_FIRMWARE_RESET;
 233                starting_state = FW_INIT_STEP2_DATA;
 234        } else {
 235                RT_TRACE(COMP_FIRMWARE,
 236                        "PlatformInitFirmware: undefined firmware state\n");
 237        }
 238
 239        /*
 240         * Download boot, main, and data image for System reset.
 241         * Download data image for firmware reseta
 242         */
 243        for (init_step = starting_state; init_step <= FW_INIT_STEP2_DATA; init_step++) {
 244                /*
 245                 * Open Image file, and map file to contineous memory if open file success.
 246                 * or read image file from array. Default load from IMG file
 247                 */
 248                if (rst_opt == OPT_SYSTEM_RESET) {
 249                        if (pfirmware->firmware_buf_size[init_step] == 0) {
 250                                rc = request_firmware(&fw_entry, fw_name[init_step], &priv->pdev->dev);
 251                                if (rc < 0) {
 252                                        RT_TRACE(COMP_FIRMWARE, "request firmware fail!\n");
 253                                        goto download_firmware_fail;
 254                                }
 255
 256                                if (fw_entry->size > sizeof(pfirmware->firmware_buf[init_step])) {
 257                                        RT_TRACE(COMP_FIRMWARE, "img file size exceed the container buffer fail!\n");
 258                                        goto download_firmware_fail;
 259                                }
 260
 261                                if (init_step != FW_INIT_STEP1_MAIN) {
 262                                        memcpy(pfirmware->firmware_buf[init_step], fw_entry->data, fw_entry->size);
 263                                        pfirmware->firmware_buf_size[init_step] = fw_entry->size;
 264
 265                                } else {
 266                                        memset(pfirmware->firmware_buf[init_step], 0, 128);
 267                                        memcpy(&pfirmware->firmware_buf[init_step][128], fw_entry->data, fw_entry->size);
 268                                        pfirmware->firmware_buf_size[init_step] = fw_entry->size+128;
 269                                }
 270
 271                                if (rst_opt == OPT_SYSTEM_RESET)
 272                                        release_firmware(fw_entry);
 273                        }
 274                        mapped_file = pfirmware->firmware_buf[init_step];
 275                        file_length = pfirmware->firmware_buf_size[init_step];
 276                } else if (rst_opt == OPT_FIRMWARE_RESET) {
 277                        /* we only need to download data.img here */
 278                        mapped_file = pfirmware->firmware_buf[init_step];
 279                        file_length = pfirmware->firmware_buf_size[init_step];
 280                }
 281
 282                /* Download image file */
 283                /* The firmware download process is just as following,
 284                 * 1. that is each packet will be segmented and inserted to the
 285                 *    wait queue.
 286                 * 2. each packet segment will be put in the skb_buff packet.
 287                 * 3. each skb_buff packet data content will already include
 288                 *    the firmware info and Tx descriptor info
 289                 */
 290                rt_status = fw_download_code(dev, mapped_file, file_length);
 291                if (rt_status != TRUE)
 292                        goto download_firmware_fail;
 293
 294                switch (init_step) {
 295                case FW_INIT_STEP0_BOOT:
 296                        /* Download boot
 297                         * initialize command descriptor.
 298                         * will set polling bit when firmware code is also
 299                         * configured
 300                         */
 301                        pfirmware->firmware_status = FW_STATUS_1_MOVE_BOOT_CODE;
 302                        /* mdelay(1000); */
 303                        /*
 304                         * To initialize IMEM, CPU move code  from 0x80000080,
 305                         * hence, we send 0x80 byte packet
 306                         */
 307                        break;
 308
 309                case FW_INIT_STEP1_MAIN:
 310                        /* Download firmware code.
 311                         * Wait until Boot Ready and Turn on CPU */
 312                        pfirmware->firmware_status = FW_STATUS_2_MOVE_MAIN_CODE;
 313
 314                        /* Check Put Code OK and Turn On CPU */
 315                        rt_status = CPUcheck_maincodeok_turnonCPU(dev);
 316                        if (rt_status != TRUE) {
 317                                RT_TRACE(COMP_FIRMWARE,
 318                                        "CPUcheck_maincodeok_turnonCPU fail!\n");
 319                                goto download_firmware_fail;
 320                        }
 321
 322                        pfirmware->firmware_status = FW_STATUS_3_TURNON_CPU;
 323                        break;
 324
 325                case FW_INIT_STEP2_DATA:
 326                        /* download initial data code */
 327                        pfirmware->firmware_status = FW_STATUS_4_MOVE_DATA_CODE;
 328                        mdelay(1);
 329
 330                        rt_status = CPUcheck_firmware_ready(dev);
 331                        if (rt_status != TRUE) {
 332                                RT_TRACE(COMP_FIRMWARE,
 333                                        "CPUcheck_firmware_ready fail(%d)!\n",
 334                                        rt_status);
 335                                goto download_firmware_fail;
 336                        }
 337
 338                        /* wait until data code is initialized ready.*/
 339                        pfirmware->firmware_status = FW_STATUS_5_READY;
 340                        break;
 341                }
 342        }
 343
 344        RT_TRACE(COMP_FIRMWARE, "Firmware Download Success\n");
 345        return rt_status;
 346
 347download_firmware_fail:
 348        RT_TRACE(COMP_ERR, "ERR in %s()\n", __func__);
 349        rt_status = FALSE;
 350        return rt_status;
 351
 352}
 353