218 lines · c
1// SPDX-License-Identifier: GPL-2.02/* Copyright(c) 2009-2014 Realtek Corporation.*/3 4#include "../wifi.h"5#include "../pci.h"6#include "../base.h"7#include "../efuse.h"8#include "fw_common.h"9#include <linux/module.h>10 11void rtl8723_enable_fw_download(struct ieee80211_hw *hw, bool enable)12{13 struct rtl_priv *rtlpriv = rtl_priv(hw);14 u8 tmp;15 16 if (enable) {17 tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);18 rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1,19 tmp | 0x04);20 21 tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);22 rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp | 0x01);23 24 tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL + 2);25 rtl_write_byte(rtlpriv, REG_MCUFWDL + 2, tmp & 0xf7);26 } else {27 tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);28 rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp & 0xfe);29 30 rtl_write_byte(rtlpriv, REG_MCUFWDL + 1, 0x00);31 }32}33EXPORT_SYMBOL_GPL(rtl8723_enable_fw_download);34 35void rtl8723_write_fw(struct ieee80211_hw *hw,36 enum version_8723e version,37 u8 *buffer, u32 size, u8 max_page)38{39 struct rtl_priv *rtlpriv = rtl_priv(hw);40 u8 *bufferptr = buffer;41 u32 page_nums, remain_size;42 u32 page, offset;43 44 rtl_dbg(rtlpriv, COMP_FW, DBG_TRACE, "FW size is %d bytes,\n", size);45 46 rtl_fill_dummy(bufferptr, &size);47 48 page_nums = size / FW_8192C_PAGE_SIZE;49 remain_size = size % FW_8192C_PAGE_SIZE;50 51 if (page_nums > max_page) {52 pr_err("Page numbers should not greater than %d\n",53 max_page);54 }55 for (page = 0; page < page_nums; page++) {56 offset = page * FW_8192C_PAGE_SIZE;57 rtl_fw_page_write(hw, page, (bufferptr + offset),58 FW_8192C_PAGE_SIZE);59 }60 61 if (remain_size) {62 offset = page_nums * FW_8192C_PAGE_SIZE;63 page = page_nums;64 rtl_fw_page_write(hw, page, (bufferptr + offset), remain_size);65 }66 rtl_dbg(rtlpriv, COMP_FW, DBG_TRACE, "FW write done.\n");67}68EXPORT_SYMBOL_GPL(rtl8723_write_fw);69 70void rtl8723ae_firmware_selfreset(struct ieee80211_hw *hw)71{72 u8 u1b_tmp;73 u8 delay = 100;74 struct rtl_priv *rtlpriv = rtl_priv(hw);75 76 rtl_write_byte(rtlpriv, REG_HMETFR + 3, 0x20);77 u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);78 79 while (u1b_tmp & BIT(2)) {80 delay--;81 if (delay == 0)82 break;83 udelay(50);84 u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);85 }86 if (delay == 0) {87 u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);88 rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1,89 u1b_tmp&(~BIT(2)));90 }91}92EXPORT_SYMBOL_GPL(rtl8723ae_firmware_selfreset);93 94void rtl8723be_firmware_selfreset(struct ieee80211_hw *hw)95{96 u8 u1b_tmp;97 struct rtl_priv *rtlpriv = rtl_priv(hw);98 99 u1b_tmp = rtl_read_byte(rtlpriv, REG_RSV_CTRL + 1);100 rtl_write_byte(rtlpriv, REG_RSV_CTRL + 1, (u1b_tmp & (~BIT(0))));101 102 u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);103 rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, (u1b_tmp & (~BIT(2))));104 udelay(50);105 106 u1b_tmp = rtl_read_byte(rtlpriv, REG_RSV_CTRL + 1);107 rtl_write_byte(rtlpriv, REG_RSV_CTRL + 1, (u1b_tmp | BIT(0)));108 109 u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);110 rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, (u1b_tmp | BIT(2)));111 112 rtl_dbg(rtlpriv, COMP_INIT, DBG_LOUD,113 "_8051Reset8723be(): 8051 reset success .\n");114}115EXPORT_SYMBOL_GPL(rtl8723be_firmware_selfreset);116 117int rtl8723_fw_free_to_go(struct ieee80211_hw *hw, bool is_8723be,118 int max_count)119{120 struct rtl_priv *rtlpriv = rtl_priv(hw);121 int err = -EIO;122 u32 counter = 0;123 u32 value32;124 125 do {126 value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);127 } while ((counter++ < max_count) &&128 (!(value32 & FWDL_CHKSUM_RPT)));129 130 if (counter >= max_count) {131 pr_err("chksum report fail ! REG_MCUFWDL:0x%08x .\n",132 value32);133 goto exit;134 }135 value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL) | MCUFWDL_RDY;136 value32 &= ~WINTINI_RDY;137 rtl_write_dword(rtlpriv, REG_MCUFWDL, value32);138 139 if (is_8723be)140 rtl8723be_firmware_selfreset(hw);141 counter = 0;142 143 do {144 value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);145 if (value32 & WINTINI_RDY) {146 rtl_dbg(rtlpriv, COMP_FW, DBG_TRACE,147 "Polling FW ready success!! REG_MCUFWDL:0x%08x .\n",148 value32);149 err = 0;150 goto exit;151 }152 153 mdelay(FW_8192C_POLLING_DELAY);154 155 } while (counter++ < max_count);156 157 pr_err("Polling FW ready fail!! REG_MCUFWDL:0x%08x .\n",158 value32);159 160exit:161 return err;162}163EXPORT_SYMBOL_GPL(rtl8723_fw_free_to_go);164 165int rtl8723_download_fw(struct ieee80211_hw *hw,166 bool is_8723be, int max_count)167{168 struct rtl_priv *rtlpriv = rtl_priv(hw);169 struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));170 struct rtlwifi_firmware_header *pfwheader;171 u8 *pfwdata;172 u32 fwsize;173 int err;174 enum version_8723e version = rtlhal->version;175 int max_page;176 177 if (rtlpriv->max_fw_size == 0 || !rtlhal->pfirmware)178 return 1;179 180 pfwheader = (struct rtlwifi_firmware_header *)rtlhal->pfirmware;181 rtlhal->fw_version = le16_to_cpu(pfwheader->version);182 rtlhal->fw_subversion = pfwheader->subversion;183 pfwdata = rtlhal->pfirmware;184 fwsize = rtlhal->fwsize;185 186 if (!is_8723be)187 max_page = 6;188 else189 max_page = 8;190 if (rtlpriv->cfg->ops->is_fw_header(pfwheader)) {191 rtl_dbg(rtlpriv, COMP_FW, DBG_LOUD,192 "Firmware Version(%d), Signature(%#x), Size(%d)\n",193 pfwheader->version, pfwheader->signature,194 (int)sizeof(struct rtlwifi_firmware_header));195 196 pfwdata = pfwdata + sizeof(struct rtlwifi_firmware_header);197 fwsize = fwsize - sizeof(struct rtlwifi_firmware_header);198 }199 200 if (rtl_read_byte(rtlpriv, REG_MCUFWDL)&BIT(7)) {201 if (is_8723be)202 rtl8723be_firmware_selfreset(hw);203 else204 rtl8723ae_firmware_selfreset(hw);205 rtl_write_byte(rtlpriv, REG_MCUFWDL, 0x00);206 }207 rtl8723_enable_fw_download(hw, true);208 rtl8723_write_fw(hw, version, pfwdata, fwsize, max_page);209 rtl8723_enable_fw_download(hw, false);210 211 err = rtl8723_fw_free_to_go(hw, is_8723be, max_count);212 if (err)213 pr_err("Firmware is not ready to run!\n");214 return 0;215}216EXPORT_SYMBOL_GPL(rtl8723_download_fw);217 218