linux/drivers/net/wireless/realtek/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 "../efuse.h"
  30#include "fw_common.h"
  31#include <linux/module.h>
  32
  33void rtl8723_enable_fw_download(struct ieee80211_hw *hw, bool enable)
  34{
  35        struct rtl_priv *rtlpriv = rtl_priv(hw);
  36        u8 tmp;
  37
  38        if (enable) {
  39                tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
  40                rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1,
  41                               tmp | 0x04);
  42
  43                tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
  44                rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp | 0x01);
  45
  46                tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL + 2);
  47                rtl_write_byte(rtlpriv, REG_MCUFWDL + 2, tmp & 0xf7);
  48        } else {
  49                tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
  50                rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp & 0xfe);
  51
  52                rtl_write_byte(rtlpriv, REG_MCUFWDL + 1, 0x00);
  53        }
  54}
  55EXPORT_SYMBOL_GPL(rtl8723_enable_fw_download);
  56
  57void rtl8723_write_fw(struct ieee80211_hw *hw,
  58                      enum version_8723e version,
  59                      u8 *buffer, u32 size, u8 max_page)
  60{
  61        struct rtl_priv *rtlpriv = rtl_priv(hw);
  62        u8 *bufferptr = buffer;
  63        u32 page_nums, remain_size;
  64        u32 page, offset;
  65
  66        RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, "FW size is %d bytes,\n", size);
  67
  68        rtl_fill_dummy(bufferptr, &size);
  69
  70        page_nums = size / FW_8192C_PAGE_SIZE;
  71        remain_size = size % FW_8192C_PAGE_SIZE;
  72
  73        if (page_nums > max_page) {
  74                pr_err("Page numbers should not greater than %d\n",
  75                       max_page);
  76        }
  77        for (page = 0; page < page_nums; page++) {
  78                offset = page * FW_8192C_PAGE_SIZE;
  79                rtl_fw_page_write(hw, page, (bufferptr + offset),
  80                                  FW_8192C_PAGE_SIZE);
  81        }
  82
  83        if (remain_size) {
  84                offset = page_nums * FW_8192C_PAGE_SIZE;
  85                page = page_nums;
  86                rtl_fw_page_write(hw, page, (bufferptr + offset), remain_size);
  87        }
  88        RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, "FW write done.\n");
  89}
  90EXPORT_SYMBOL_GPL(rtl8723_write_fw);
  91
  92void rtl8723ae_firmware_selfreset(struct ieee80211_hw *hw)
  93{
  94        u8 u1b_tmp;
  95        u8 delay = 100;
  96        struct rtl_priv *rtlpriv = rtl_priv(hw);
  97
  98        rtl_write_byte(rtlpriv, REG_HMETFR + 3, 0x20);
  99        u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
 100
 101        while (u1b_tmp & BIT(2)) {
 102                delay--;
 103                if (delay == 0)
 104                        break;
 105                udelay(50);
 106                u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
 107        }
 108        if (delay == 0) {
 109                u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
 110                rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1,
 111                               u1b_tmp&(~BIT(2)));
 112        }
 113}
 114EXPORT_SYMBOL_GPL(rtl8723ae_firmware_selfreset);
 115
 116void rtl8723be_firmware_selfreset(struct ieee80211_hw *hw)
 117{
 118        u8 u1b_tmp;
 119        struct rtl_priv *rtlpriv = rtl_priv(hw);
 120
 121        u1b_tmp = rtl_read_byte(rtlpriv, REG_RSV_CTRL + 1);
 122        rtl_write_byte(rtlpriv, REG_RSV_CTRL + 1, (u1b_tmp & (~BIT(0))));
 123
 124        u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
 125        rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, (u1b_tmp & (~BIT(2))));
 126        udelay(50);
 127
 128        u1b_tmp = rtl_read_byte(rtlpriv, REG_RSV_CTRL + 1);
 129        rtl_write_byte(rtlpriv, REG_RSV_CTRL + 1, (u1b_tmp | BIT(0)));
 130
 131        u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
 132        rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, (u1b_tmp | BIT(2)));
 133
 134        RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
 135                 "  _8051Reset8723be(): 8051 reset success .\n");
 136}
 137EXPORT_SYMBOL_GPL(rtl8723be_firmware_selfreset);
 138
 139int rtl8723_fw_free_to_go(struct ieee80211_hw *hw, bool is_8723be,
 140                          int max_count)
 141{
 142        struct rtl_priv *rtlpriv = rtl_priv(hw);
 143        int err = -EIO;
 144        u32 counter = 0;
 145        u32 value32;
 146
 147        do {
 148                value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
 149        } while ((counter++ < max_count) &&
 150                 (!(value32 & FWDL_CHKSUM_RPT)));
 151
 152        if (counter >= max_count) {
 153                pr_err("chksum report fail ! REG_MCUFWDL:0x%08x .\n",
 154                       value32);
 155                goto exit;
 156        }
 157        value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL) | MCUFWDL_RDY;
 158        value32 &= ~WINTINI_RDY;
 159        rtl_write_dword(rtlpriv, REG_MCUFWDL, value32);
 160
 161        if (is_8723be)
 162                rtl8723be_firmware_selfreset(hw);
 163        counter = 0;
 164
 165        do {
 166                value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
 167                if (value32 & WINTINI_RDY) {
 168                        RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
 169                                 "Polling FW ready success!! REG_MCUFWDL:0x%08x .\n",
 170                                 value32);
 171                        err = 0;
 172                        goto exit;
 173                }
 174
 175                mdelay(FW_8192C_POLLING_DELAY);
 176
 177        } while (counter++ < max_count);
 178
 179        pr_err("Polling FW ready fail!! REG_MCUFWDL:0x%08x .\n",
 180               value32);
 181
 182exit:
 183        return err;
 184}
 185EXPORT_SYMBOL_GPL(rtl8723_fw_free_to_go);
 186
 187int rtl8723_download_fw(struct ieee80211_hw *hw,
 188                        bool is_8723be, int max_count)
 189{
 190        struct rtl_priv *rtlpriv = rtl_priv(hw);
 191        struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
 192        struct rtlwifi_firmware_header *pfwheader;
 193        u8 *pfwdata;
 194        u32 fwsize;
 195        int err;
 196        enum version_8723e version = rtlhal->version;
 197        int max_page;
 198
 199        if (!rtlhal->pfirmware)
 200                return 1;
 201
 202        pfwheader = (struct rtlwifi_firmware_header *)rtlhal->pfirmware;
 203        pfwdata = rtlhal->pfirmware;
 204        fwsize = rtlhal->fwsize;
 205
 206        if (!is_8723be)
 207                max_page = 6;
 208        else
 209                max_page = 8;
 210        if (rtlpriv->cfg->ops->is_fw_header(pfwheader)) {
 211                RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD,
 212                         "Firmware Version(%d), Signature(%#x), Size(%d)\n",
 213                         pfwheader->version, pfwheader->signature,
 214                         (int)sizeof(struct rtlwifi_firmware_header));
 215
 216                pfwdata = pfwdata + sizeof(struct rtlwifi_firmware_header);
 217                fwsize = fwsize - sizeof(struct rtlwifi_firmware_header);
 218        }
 219
 220        if (rtl_read_byte(rtlpriv, REG_MCUFWDL)&BIT(7)) {
 221                if (is_8723be)
 222                        rtl8723be_firmware_selfreset(hw);
 223                else
 224                        rtl8723ae_firmware_selfreset(hw);
 225                rtl_write_byte(rtlpriv, REG_MCUFWDL, 0x00);
 226        }
 227        rtl8723_enable_fw_download(hw, true);
 228        rtl8723_write_fw(hw, version, pfwdata, fwsize, max_page);
 229        rtl8723_enable_fw_download(hw, false);
 230
 231        err = rtl8723_fw_free_to_go(hw, is_8723be, max_count);
 232        if (err)
 233                pr_err("Firmware is not ready to run!\n");
 234        return 0;
 235}
 236EXPORT_SYMBOL_GPL(rtl8723_download_fw);
 237
 238bool rtl8723_cmd_send_packet(struct ieee80211_hw *hw,
 239                             struct sk_buff *skb)
 240{
 241        struct rtl_priv *rtlpriv = rtl_priv(hw);
 242        struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
 243        struct rtl8192_tx_ring *ring;
 244        struct rtl_tx_desc *pdesc;
 245        struct sk_buff *pskb = NULL;
 246        u8 own;
 247        unsigned long flags;
 248
 249        ring = &rtlpci->tx_ring[BEACON_QUEUE];
 250
 251        pskb = __skb_dequeue(&ring->queue);
 252        kfree_skb(pskb);
 253        spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags);
 254
 255        pdesc = &ring->desc[0];
 256        own = (u8) rtlpriv->cfg->ops->get_desc((u8 *)pdesc, true, HW_DESC_OWN);
 257
 258        rtlpriv->cfg->ops->fill_tx_cmddesc(hw, (u8 *)pdesc, 1, 1, skb);
 259
 260        __skb_queue_tail(&ring->queue, skb);
 261
 262        spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
 263
 264        rtlpriv->cfg->ops->tx_polling(hw, BEACON_QUEUE);
 265
 266        return true;
 267}
 268EXPORT_SYMBOL_GPL(rtl8723_cmd_send_packet);
 269