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