linux/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.c
<<
>>
Prefs
   1/******************************************************************************
   2 * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
   3 *
   4 * This program is distributed in the hope that it will be useful, but WITHOUT
   5 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   6 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
   7 * more details.
   8 *
   9 * The full GNU General Public License is included in this distribution in the
  10 * file called LICENSE.
  11 *
  12 * Contact Information:
  13 * wlanfae <wlanfae@realtek.com>
  14 *****************************************************************************/
  15
  16#include "rtl_core.h"
  17#include "r8192E_hw.h"
  18#include "r8192E_hwimg.h"
  19#include "r8192E_firmware.h"
  20#include "r8192E_cmdpkt.h"
  21#include <linux/firmware.h>
  22
  23static bool _rtl92e_wait_for_fw(struct net_device *dev, u32 mask, u32 timeout)
  24{
  25        unsigned long deadline = jiffies + msecs_to_jiffies(timeout);
  26
  27        while (time_before(jiffies, deadline)) {
  28                if (rtl92e_readl(dev, CPU_GEN) & mask)
  29                        return true;
  30                mdelay(2);
  31        }
  32        return false;
  33}
  34
  35static bool _rtl92e_fw_boot_cpu(struct net_device *dev)
  36{
  37        u32             CPU_status = 0;
  38
  39        if (!_rtl92e_wait_for_fw(dev, CPU_GEN_PUT_CODE_OK, 200)) {
  40                netdev_err(dev, "Firmware download failed.\n");
  41                return false;
  42        }
  43        netdev_dbg(dev, "Download Firmware: Put code ok!\n");
  44
  45        CPU_status = rtl92e_readl(dev, CPU_GEN);
  46        rtl92e_writeb(dev, CPU_GEN,
  47                      (u8)((CPU_status|CPU_GEN_PWR_STB_CPU)&0xff));
  48        mdelay(1);
  49
  50        if (!_rtl92e_wait_for_fw(dev, CPU_GEN_BOOT_RDY, 200)) {
  51                netdev_err(dev, "Firmware boot failed.\n");
  52                return false;
  53        }
  54
  55        netdev_dbg(dev, "Download Firmware: Boot ready!\n");
  56
  57        return true;
  58}
  59
  60static bool _rtl92e_fw_check_ready(struct net_device *dev,
  61                                   u8 load_fw_status)
  62{
  63        struct r8192_priv *priv = rtllib_priv(dev);
  64        struct rt_firmware *pfirmware = priv->pFirmware;
  65        bool rt_status  = true;
  66
  67        switch (load_fw_status) {
  68        case FW_INIT_STEP0_BOOT:
  69                pfirmware->status = FW_STATUS_1_MOVE_BOOT_CODE;
  70                break;
  71
  72        case FW_INIT_STEP1_MAIN:
  73                pfirmware->status = FW_STATUS_2_MOVE_MAIN_CODE;
  74
  75                rt_status = _rtl92e_fw_boot_cpu(dev);
  76                if (rt_status)
  77                        pfirmware->status = FW_STATUS_3_TURNON_CPU;
  78                else
  79                        netdev_dbg(dev, "_rtl92e_fw_boot_cpu fail!\n");
  80
  81                break;
  82
  83        case FW_INIT_STEP2_DATA:
  84                pfirmware->status = FW_STATUS_4_MOVE_DATA_CODE;
  85                mdelay(1);
  86
  87                rt_status = _rtl92e_wait_for_fw(dev, CPU_GEN_FIRM_RDY, 20);
  88                if (rt_status)
  89                        pfirmware->status = FW_STATUS_5_READY;
  90                else
  91                        RT_TRACE(COMP_FIRMWARE,
  92                                 "_rtl92e_is_fw_ready fail(%d)!\n",
  93                                 rt_status);
  94                break;
  95        default:
  96                rt_status = false;
  97                netdev_dbg(dev, "Unknown firmware status");
  98                break;
  99        }
 100
 101        return rt_status;
 102}
 103
 104static bool _rtl92e_fw_prepare(struct net_device *dev, struct rt_fw_blob *blob,
 105                               const char *name, u8 padding)
 106{
 107        const struct firmware *fw;
 108        int rc, i;
 109        bool ret = true;
 110
 111        rc = request_firmware(&fw, name, &dev->dev);
 112        if (rc < 0)
 113                return false;
 114
 115        if (round_up(fw->size, 4) > MAX_FW_SIZE - padding) {
 116                netdev_err(dev, "Firmware image %s too big for the device.\n",
 117                           name);
 118                ret = false;
 119                goto out;
 120        }
 121
 122        if (padding)
 123                memset(blob->data, 0, padding);
 124        if (fw->size % 4)
 125                memset(blob->data + padding + fw->size, 0, 4);
 126        memcpy(blob->data + padding, fw->data, fw->size);
 127
 128        blob->size = round_up(fw->size, 4) + padding;
 129
 130        /* Swap endian - firmware is packaged in invalid endiannes*/
 131        for (i = padding; i < blob->size; i += 4) {
 132                u32 *data = (u32 *)(blob->data + i);
 133                *data = swab32p(data);
 134        }
 135out:
 136        release_firmware(fw);
 137        return ret;
 138}
 139
 140bool rtl92e_init_fw(struct net_device *dev)
 141{
 142        struct r8192_priv *priv = rtllib_priv(dev);
 143        bool                    rt_status = true;
 144
 145        u32     file_length = 0;
 146        u8      *mapped_file = NULL;
 147        u8      i = 0;
 148        enum opt_rst_type rst_opt = OPT_SYSTEM_RESET;
 149        enum firmware_init_step starting_state = FW_INIT_STEP0_BOOT;
 150
 151        struct rt_firmware *pfirmware = priv->pFirmware;
 152
 153        netdev_dbg(dev, " PlatformInitFirmware()==>\n");
 154
 155        if (pfirmware->status == FW_STATUS_0_INIT) {
 156                rst_opt = OPT_SYSTEM_RESET;
 157                starting_state = FW_INIT_STEP0_BOOT;
 158
 159        } else if (pfirmware->status == FW_STATUS_5_READY) {
 160                rst_opt = OPT_FIRMWARE_RESET;
 161                starting_state = FW_INIT_STEP2_DATA;
 162        } else {
 163                RT_TRACE(COMP_FIRMWARE,
 164                         "PlatformInitFirmware: undefined firmware state\n");
 165        }
 166
 167        for (i = starting_state; i <= FW_INIT_STEP2_DATA; i++) {
 168                if (rst_opt == OPT_SYSTEM_RESET) {
 169                        if (pfirmware->blobs[i].size == 0) {
 170                                const char *fw_name[3] = {
 171                                        RTL8192E_BOOT_IMG_FW,
 172                                        RTL8192E_MAIN_IMG_FW,
 173                                        RTL8192E_DATA_IMG_FW
 174                                };
 175                                int pad = 0;
 176
 177                                if (i == FW_INIT_STEP1_MAIN)
 178                                        pad = 128;
 179
 180                                if (!_rtl92e_fw_prepare(dev,
 181                                                        &pfirmware->blobs[i],
 182                                                        fw_name[i],
 183                                                        pad))
 184                                        goto download_firmware_fail;
 185                        }
 186                }
 187
 188                mapped_file = pfirmware->blobs[i].data;
 189                file_length = pfirmware->blobs[i].size;
 190
 191                rt_status = rtl92e_send_cmd_pkt(dev, DESC_PACKET_TYPE_INIT,
 192                                                mapped_file, file_length);
 193                if (!rt_status)
 194                        goto download_firmware_fail;
 195
 196                if (!_rtl92e_fw_check_ready(dev, i))
 197                        goto download_firmware_fail;
 198        }
 199
 200        netdev_dbg(dev, "Firmware Download Success\n");
 201        return rt_status;
 202
 203download_firmware_fail:
 204        netdev_err(dev, "%s: Failed to initialize firmware.\n", __func__);
 205        return false;
 206}
 207