linux/drivers/net/wireless/rtlwifi/rtl8723com/fw_common.c
<<
>>
Prefs
   1/******************************************************************************
   2 *
   3 * Copyright(c) 2009-2014  Realtek Corporation.
   4 *
   5 * This program is free software; you can redistribute it and/or modify it
   6 * under the terms of version 2 of the GNU General Public License as
   7 * published by the Free Software Foundation.
   8 *
   9 * This program is distributed in the hope that it will be useful, but WITHOUT
  10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  12 * more details.
  13 *
  14 * The full GNU General Public License is included in this distribution in the
  15 * file called LICENSE.
  16 *
  17 * Contact Information:
  18 * wlanfae <wlanfae@realtek.com>
  19 * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
  20 * Hsinchu 300, Taiwan.
  21 *
  22 * Larry Finger <Larry.Finger@lwfinger.net>
  23 *
  24 *****************************************************************************/
  25
  26#include "../wifi.h"
  27#include "../pci.h"
  28#include "../base.h"
  29#include "fw_common.h"
  30#include <linux/module.h>
  31
  32void rtl8723_enable_fw_download(struct ieee80211_hw *hw, bool enable)
  33{
  34        struct rtl_priv *rtlpriv = rtl_priv(hw);
  35        u8 tmp;
  36
  37        if (enable) {
  38                tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
  39                rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1,
  40                               tmp | 0x04);
  41
  42                tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
  43                rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp | 0x01);
  44
  45                tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL + 2);
  46                rtl_write_byte(rtlpriv, REG_MCUFWDL + 2, tmp & 0xf7);
  47        } else {
  48                tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
  49                rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp & 0xfe);
  50
  51                rtl_write_byte(rtlpriv, REG_MCUFWDL + 1, 0x00);
  52        }
  53}
  54EXPORT_SYMBOL_GPL(rtl8723_enable_fw_download);
  55
  56void rtl8723_fw_block_write(struct ieee80211_hw *hw,
  57                            const u8 *buffer, u32 size)
  58{
  59        struct rtl_priv *rtlpriv = rtl_priv(hw);
  60        u32 blocksize = sizeof(u32);
  61        u8 *bufferptr = (u8 *)buffer;
  62        u32 *pu4byteptr = (u32 *)buffer;
  63        u32 i, offset, blockcount, remainsize;
  64
  65        blockcount = size / blocksize;
  66        remainsize = size % blocksize;
  67
  68        for (i = 0; i < blockcount; i++) {
  69                offset = i * blocksize;
  70                rtl_write_dword(rtlpriv, (FW_8192C_START_ADDRESS + offset),
  71                                *(pu4byteptr + i));
  72        }
  73        if (remainsize) {
  74                offset = blockcount * blocksize;
  75                bufferptr += offset;
  76                for (i = 0; i < remainsize; i++) {
  77                        rtl_write_byte(rtlpriv,
  78                                       (FW_8192C_START_ADDRESS + offset + i),
  79                                       *(bufferptr + i));
  80                }
  81        }
  82}
  83EXPORT_SYMBOL_GPL(rtl8723_fw_block_write);
  84
  85void rtl8723_fw_page_write(struct ieee80211_hw *hw,
  86                           u32 page, const u8 *buffer, u32 size)
  87{
  88        struct rtl_priv *rtlpriv = rtl_priv(hw);
  89        u8 value8;
  90        u8 u8page = (u8) (page & 0x07);
  91
  92        value8 = (rtl_read_byte(rtlpriv, REG_MCUFWDL + 2) & 0xF8) | u8page;
  93
  94        rtl_write_byte(rtlpriv, (REG_MCUFWDL + 2), value8);
  95        rtl8723_fw_block_write(hw, buffer, size);
  96}
  97EXPORT_SYMBOL_GPL(rtl8723_fw_page_write);
  98
  99void rtl8723_fill_dummy(u8 *pfwbuf, u32 *pfwlen)
 100{
 101        u32 fwlen = *pfwlen;
 102        u8 remain = (u8) (fwlen % 4);
 103
 104        remain = (remain == 0) ? 0 : (4 - remain);
 105
 106        while (remain > 0) {
 107                pfwbuf[fwlen] = 0;
 108                fwlen++;
 109                remain--;
 110        }
 111        *pfwlen = fwlen;
 112}
 113EXPORT_SYMBOL(rtl8723_fill_dummy);
 114
 115void rtl8723_write_fw(struct ieee80211_hw *hw,
 116                      enum version_8723e version,
 117                      u8 *buffer, u32 size, u8 max_page)
 118{
 119        struct rtl_priv *rtlpriv = rtl_priv(hw);
 120        u8 *bufferptr = buffer;
 121        u32 page_nums, remain_size;
 122        u32 page, offset;
 123
 124        RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, "FW size is %d bytes,\n", size);
 125
 126        rtl8723_fill_dummy(bufferptr, &size);
 127
 128        page_nums = size / FW_8192C_PAGE_SIZE;
 129        remain_size = size % FW_8192C_PAGE_SIZE;
 130
 131        if (page_nums > max_page) {
 132                RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
 133                         "Page numbers should not greater than %d\n", max_page);
 134        }
 135        for (page = 0; page < page_nums; page++) {
 136                offset = page * FW_8192C_PAGE_SIZE;
 137                rtl8723_fw_page_write(hw, page, (bufferptr + offset),
 138                                      FW_8192C_PAGE_SIZE);
 139        }
 140
 141        if (remain_size) {
 142                offset = page_nums * FW_8192C_PAGE_SIZE;
 143                page = page_nums;
 144                rtl8723_fw_page_write(hw, page, (bufferptr + offset),
 145                                      remain_size);
 146        }
 147        RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, "FW write done.\n");
 148}
 149EXPORT_SYMBOL_GPL(rtl8723_write_fw);
 150
 151void rtl8723ae_firmware_selfreset(struct ieee80211_hw *hw)
 152{
 153        u8 u1b_tmp;
 154        u8 delay = 100;
 155        struct rtl_priv *rtlpriv = rtl_priv(hw);
 156
 157        rtl_write_byte(rtlpriv, REG_HMETFR + 3, 0x20);
 158        u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
 159
 160        while (u1b_tmp & BIT(2)) {
 161                delay--;
 162                if (delay == 0)
 163                        break;
 164                udelay(50);
 165                u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
 166        }
 167        if (delay == 0) {
 168                u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
 169                rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1,
 170                               u1b_tmp&(~BIT(2)));
 171        }
 172}
 173EXPORT_SYMBOL_GPL(rtl8723ae_firmware_selfreset);
 174
 175void rtl8723be_firmware_selfreset(struct ieee80211_hw *hw)
 176{
 177        u8 u1b_tmp;
 178        struct rtl_priv *rtlpriv = rtl_priv(hw);
 179
 180        u1b_tmp = rtl_read_byte(rtlpriv, REG_RSV_CTRL + 1);
 181        rtl_write_byte(rtlpriv, REG_RSV_CTRL + 1, (u1b_tmp & (~BIT(0))));
 182
 183        u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
 184        rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, (u1b_tmp & (~BIT(2))));
 185        udelay(50);
 186
 187        u1b_tmp = rtl_read_byte(rtlpriv, REG_RSV_CTRL + 1);
 188        rtl_write_byte(rtlpriv, REG_RSV_CTRL + 1, (u1b_tmp | BIT(0)));
 189
 190        u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
 191        rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, (u1b_tmp | BIT(2)));
 192
 193        RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
 194                 "  _8051Reset8723be(): 8051 reset success .\n");
 195}
 196EXPORT_SYMBOL_GPL(rtl8723be_firmware_selfreset);
 197
 198int rtl8723_fw_free_to_go(struct ieee80211_hw *hw, bool is_8723be,
 199                          int max_count)
 200{
 201        struct rtl_priv *rtlpriv = rtl_priv(hw);
 202        int err = -EIO;
 203        u32 counter = 0;
 204        u32 value32;
 205
 206        do {
 207                value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
 208        } while ((counter++ < max_count) &&
 209                 (!(value32 & FWDL_CHKSUM_RPT)));
 210
 211        if (counter >= max_count) {
 212                RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
 213                         "chksum report fail ! REG_MCUFWDL:0x%08x .\n",
 214                         value32);
 215                goto exit;
 216        }
 217        RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
 218                 "Checksum report OK ! REG_MCUFWDL:0x%08x .\n", value32);
 219
 220        value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL) | MCUFWDL_RDY;
 221        value32 &= ~WINTINI_RDY;
 222        rtl_write_dword(rtlpriv, REG_MCUFWDL, value32);
 223
 224        if (is_8723be)
 225                rtl8723be_firmware_selfreset(hw);
 226        counter = 0;
 227
 228        do {
 229                value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
 230                if (value32 & WINTINI_RDY) {
 231                        RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
 232                                 "Polling FW ready success!! REG_MCUFWDL:0x%08x .\n",
 233                                 value32);
 234                        err = 0;
 235                        goto exit;
 236                }
 237
 238                mdelay(FW_8192C_POLLING_DELAY);
 239
 240        } while (counter++ < max_count);
 241
 242        RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
 243                 "Polling FW ready fail!! REG_MCUFWDL:0x%08x .\n",
 244                 value32);
 245
 246exit:
 247        return err;
 248}
 249EXPORT_SYMBOL_GPL(rtl8723_fw_free_to_go);
 250
 251int rtl8723_download_fw(struct ieee80211_hw *hw,
 252                        bool is_8723be, int max_count)
 253{
 254        struct rtl_priv *rtlpriv = rtl_priv(hw);
 255        struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
 256        struct rtl8723e_firmware_header *pfwheader;
 257        u8 *pfwdata;
 258        u32 fwsize;
 259        int err;
 260        enum version_8723e version = rtlhal->version;
 261        int max_page;
 262
 263        if (!rtlhal->pfirmware)
 264                return 1;
 265
 266        pfwheader = (struct rtl8723e_firmware_header *)rtlhal->pfirmware;
 267        pfwdata = rtlhal->pfirmware;
 268        fwsize = rtlhal->fwsize;
 269
 270        if (!is_8723be)
 271                max_page = 6;
 272        else
 273                max_page = 8;
 274        if (rtlpriv->cfg->ops->is_fw_header(pfwheader)) {
 275                RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD,
 276                         "Firmware Version(%d), Signature(%#x), Size(%d)\n",
 277                         pfwheader->version, pfwheader->signature,
 278                         (int)sizeof(struct rtl8723e_firmware_header));
 279
 280                pfwdata = pfwdata + sizeof(struct rtl8723e_firmware_header);
 281                fwsize = fwsize - sizeof(struct rtl8723e_firmware_header);
 282        }
 283
 284        if (rtl_read_byte(rtlpriv, REG_MCUFWDL)&BIT(7)) {
 285                if (is_8723be)
 286                        rtl8723be_firmware_selfreset(hw);
 287                else
 288                        rtl8723ae_firmware_selfreset(hw);
 289                rtl_write_byte(rtlpriv, REG_MCUFWDL, 0x00);
 290        }
 291        rtl8723_enable_fw_download(hw, true);
 292        rtl8723_write_fw(hw, version, pfwdata, fwsize, max_page);
 293        rtl8723_enable_fw_download(hw, false);
 294
 295        err = rtl8723_fw_free_to_go(hw, is_8723be, max_count);
 296        if (err) {
 297                RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
 298                         "Firmware is not ready to run!\n");
 299        } else {
 300                RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
 301                         "Firmware is ready to run!\n");
 302        }
 303        return 0;
 304}
 305EXPORT_SYMBOL_GPL(rtl8723_download_fw);
 306
 307bool rtl8723_cmd_send_packet(struct ieee80211_hw *hw,
 308                             struct sk_buff *skb)
 309{
 310        struct rtl_priv *rtlpriv = rtl_priv(hw);
 311        struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
 312        struct rtl8192_tx_ring *ring;
 313        struct rtl_tx_desc *pdesc;
 314        struct sk_buff *pskb = NULL;
 315        u8 own;
 316        unsigned long flags;
 317
 318        ring = &rtlpci->tx_ring[BEACON_QUEUE];
 319
 320        pskb = __skb_dequeue(&ring->queue);
 321        if (pskb)
 322                kfree_skb(pskb);
 323
 324        spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags);
 325
 326        pdesc = &ring->desc[0];
 327        own = (u8) rtlpriv->cfg->ops->get_desc((u8 *)pdesc, true, HW_DESC_OWN);
 328
 329        rtlpriv->cfg->ops->fill_tx_cmddesc(hw, (u8 *)pdesc, 1, 1, skb);
 330
 331        __skb_queue_tail(&ring->queue, skb);
 332
 333        spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
 334
 335        rtlpriv->cfg->ops->tx_polling(hw, BEACON_QUEUE);
 336
 337        return true;
 338}
 339EXPORT_SYMBOL_GPL(rtl8723_cmd_send_packet);
 340