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