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