1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright(c) 2009-2012 Realtek Corporation.*/
3
4 #include "../wifi.h"
5 #include "../pci.h"
6 #include "../base.h"
7 #include "../efuse.h"
8 #include "def.h"
9 #include "reg.h"
10 #include "fw_common.h"
11
rtl92d_is_fw_downloaded(struct rtl_priv * rtlpriv)12 bool rtl92d_is_fw_downloaded(struct rtl_priv *rtlpriv)
13 {
14 return !!(rtl_read_dword(rtlpriv, REG_MCUFWDL) & MCUFWDL_RDY);
15 }
16 EXPORT_SYMBOL_GPL(rtl92d_is_fw_downloaded);
17
rtl92d_enable_fw_download(struct ieee80211_hw * hw,bool enable)18 void rtl92d_enable_fw_download(struct ieee80211_hw *hw, bool enable)
19 {
20 struct rtl_priv *rtlpriv = rtl_priv(hw);
21 u8 tmp;
22
23 if (enable) {
24 tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
25 rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, tmp | 0x04);
26 tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
27 rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp | 0x01);
28 tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL + 2);
29 rtl_write_byte(rtlpriv, REG_MCUFWDL + 2, tmp & 0xf7);
30 } else {
31 tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
32 rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp & 0xfe);
33 /* Reserved for fw extension.
34 * 0x81[7] is used for mac0 status ,
35 * so don't write this reg here
36 * rtl_write_byte(rtlpriv, REG_MCUFWDL + 1, 0x00);
37 */
38 }
39 }
40 EXPORT_SYMBOL_GPL(rtl92d_enable_fw_download);
41
rtl92d_write_fw(struct ieee80211_hw * hw,enum version_8192d version,u8 * buffer,u32 size)42 void rtl92d_write_fw(struct ieee80211_hw *hw,
43 enum version_8192d version, u8 *buffer, u32 size)
44 {
45 struct rtl_priv *rtlpriv = rtl_priv(hw);
46 struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
47 u8 *bufferptr = buffer;
48 u32 pagenums, remainsize;
49 u32 page, offset;
50
51 rtl_dbg(rtlpriv, COMP_FW, DBG_TRACE, "FW size is %d bytes,\n", size);
52
53 if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192DE)
54 rtl_fill_dummy(bufferptr, &size);
55
56 pagenums = size / FW_8192D_PAGE_SIZE;
57 remainsize = size % FW_8192D_PAGE_SIZE;
58
59 if (pagenums > 8)
60 pr_err("Page numbers should not greater then 8\n");
61
62 for (page = 0; page < pagenums; page++) {
63 offset = page * FW_8192D_PAGE_SIZE;
64 rtl_fw_page_write(hw, page, (bufferptr + offset),
65 FW_8192D_PAGE_SIZE);
66 }
67
68 if (remainsize) {
69 offset = pagenums * FW_8192D_PAGE_SIZE;
70 page = pagenums;
71 rtl_fw_page_write(hw, page, (bufferptr + offset), remainsize);
72 }
73 }
74 EXPORT_SYMBOL_GPL(rtl92d_write_fw);
75
rtl92d_fw_free_to_go(struct ieee80211_hw * hw)76 int rtl92d_fw_free_to_go(struct ieee80211_hw *hw)
77 {
78 struct rtl_priv *rtlpriv = rtl_priv(hw);
79 u32 counter = 0;
80 u32 value32;
81
82 do {
83 value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
84 } while ((counter++ < FW_8192D_POLLING_TIMEOUT_COUNT) &&
85 (!(value32 & FWDL_CHKSUM_RPT)));
86
87 if (counter >= FW_8192D_POLLING_TIMEOUT_COUNT) {
88 pr_err("chksum report fail! REG_MCUFWDL:0x%08x\n",
89 value32);
90 return -EIO;
91 }
92
93 value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
94 value32 |= MCUFWDL_RDY;
95 rtl_write_dword(rtlpriv, REG_MCUFWDL, value32);
96
97 return 0;
98 }
99 EXPORT_SYMBOL_GPL(rtl92d_fw_free_to_go);
100
101 #define RTL_USB_DELAY_FACTOR 60
102
rtl92d_firmware_selfreset(struct ieee80211_hw * hw)103 void rtl92d_firmware_selfreset(struct ieee80211_hw *hw)
104 {
105 struct rtl_priv *rtlpriv = rtl_priv(hw);
106 struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
107 u8 u1b_tmp;
108 u8 delay = 100;
109
110 if (rtlhal->interface == INTF_USB) {
111 delay *= RTL_USB_DELAY_FACTOR;
112
113 rtl_write_byte(rtlpriv, REG_FSIMR, 0);
114
115 /* We need to disable other HRCV INT to influence 8051 reset. */
116 rtl_write_byte(rtlpriv, REG_FWIMR, 0x20);
117
118 /* Close mask to prevent incorrect FW write operation. */
119 rtl_write_byte(rtlpriv, REG_FTIMR, 0);
120 }
121
122 /* Set (REG_HMETFR + 3) to 0x20 is reset 8051 */
123 rtl_write_byte(rtlpriv, REG_HMETFR + 3, 0x20);
124
125 u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
126
127 while (u1b_tmp & (FEN_CPUEN >> 8)) {
128 delay--;
129 if (delay == 0)
130 break;
131 udelay(50);
132 u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
133 }
134
135 if (rtlhal->interface == INTF_USB) {
136 if ((u1b_tmp & (FEN_CPUEN >> 8)) && delay == 0)
137 rtl_write_byte(rtlpriv, REG_FWIMR, 0);
138 }
139
140 WARN_ONCE((delay <= 0), "rtl8192de: 8051 reset failed!\n");
141 rtl_dbg(rtlpriv, COMP_FW, DBG_DMESG,
142 "=====> 8051 reset success (%d)\n", delay);
143 }
144 EXPORT_SYMBOL_GPL(rtl92d_firmware_selfreset);
145
rtl92d_fw_init(struct ieee80211_hw * hw)146 int rtl92d_fw_init(struct ieee80211_hw *hw)
147 {
148 struct rtl_priv *rtlpriv = rtl_priv(hw);
149 struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
150 u32 counter;
151
152 rtl_dbg(rtlpriv, COMP_FW, DBG_DMESG, "FW already have download\n");
153 /* polling for FW ready */
154 counter = 0;
155 do {
156 if (rtlhal->interfaceindex == 0) {
157 if (rtl_read_byte(rtlpriv, FW_MAC0_READY) &
158 MAC0_READY) {
159 rtl_dbg(rtlpriv, COMP_FW, DBG_DMESG,
160 "Polling FW ready success!! REG_MCUFWDL: 0x%x\n",
161 rtl_read_byte(rtlpriv,
162 FW_MAC0_READY));
163 return 0;
164 }
165 udelay(5);
166 } else {
167 if (rtl_read_byte(rtlpriv, FW_MAC1_READY) &
168 MAC1_READY) {
169 rtl_dbg(rtlpriv, COMP_FW, DBG_DMESG,
170 "Polling FW ready success!! REG_MCUFWDL: 0x%x\n",
171 rtl_read_byte(rtlpriv,
172 FW_MAC1_READY));
173 return 0;
174 }
175 udelay(5);
176 }
177 } while (counter++ < POLLING_READY_TIMEOUT_COUNT);
178
179 if (rtlhal->interfaceindex == 0) {
180 rtl_dbg(rtlpriv, COMP_FW, DBG_DMESG,
181 "Polling FW ready fail!! MAC0 FW init not ready: 0x%x\n",
182 rtl_read_byte(rtlpriv, FW_MAC0_READY));
183 } else {
184 rtl_dbg(rtlpriv, COMP_FW, DBG_DMESG,
185 "Polling FW ready fail!! MAC1 FW init not ready: 0x%x\n",
186 rtl_read_byte(rtlpriv, FW_MAC1_READY));
187 }
188 rtl_dbg(rtlpriv, COMP_FW, DBG_DMESG,
189 "Polling FW ready fail!! REG_MCUFWDL:0x%08x\n",
190 rtl_read_dword(rtlpriv, REG_MCUFWDL));
191 return -1;
192 }
193 EXPORT_SYMBOL_GPL(rtl92d_fw_init);
194
_rtl92d_check_fw_read_last_h2c(struct ieee80211_hw * hw,u8 boxnum)195 static bool _rtl92d_check_fw_read_last_h2c(struct ieee80211_hw *hw, u8 boxnum)
196 {
197 struct rtl_priv *rtlpriv = rtl_priv(hw);
198 u8 val_hmetfr;
199 bool result = false;
200
201 val_hmetfr = rtl_read_byte(rtlpriv, REG_HMETFR);
202 if (((val_hmetfr >> boxnum) & BIT(0)) == 0)
203 result = true;
204 return result;
205 }
206
rtl92d_fill_h2c_cmd(struct ieee80211_hw * hw,u8 element_id,u32 cmd_len,u8 * cmdbuffer)207 void rtl92d_fill_h2c_cmd(struct ieee80211_hw *hw,
208 u8 element_id, u32 cmd_len, u8 *cmdbuffer)
209 {
210 struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
211 struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
212 struct rtl_priv *rtlpriv = rtl_priv(hw);
213 u8 boxcontent[4], boxextcontent[2];
214 u16 box_reg = 0, box_extreg = 0;
215 u8 wait_writeh2c_limmit = 100;
216 bool bwrite_success = false;
217 u8 wait_h2c_limmit = 100;
218 u32 h2c_waitcounter = 0;
219 bool isfw_read = false;
220 unsigned long flag;
221 u8 u1b_tmp;
222 u8 boxnum;
223 u8 idx;
224
225 if (ppsc->rfpwr_state == ERFOFF || ppsc->inactive_pwrstate == ERFOFF) {
226 rtl_dbg(rtlpriv, COMP_CMD, DBG_LOUD,
227 "Return as RF is off!!!\n");
228 return;
229 }
230
231 rtl_dbg(rtlpriv, COMP_CMD, DBG_LOUD, "come in\n");
232
233 while (true) {
234 spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
235 if (rtlhal->h2c_setinprogress) {
236 rtl_dbg(rtlpriv, COMP_CMD, DBG_LOUD,
237 "H2C set in progress! Wait to set..element_id(%d)\n",
238 element_id);
239
240 while (rtlhal->h2c_setinprogress) {
241 spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock,
242 flag);
243 h2c_waitcounter++;
244 rtl_dbg(rtlpriv, COMP_CMD, DBG_LOUD,
245 "Wait 100 us (%d times)...\n",
246 h2c_waitcounter);
247 udelay(100);
248
249 if (h2c_waitcounter > 1000)
250 return;
251
252 spin_lock_irqsave(&rtlpriv->locks.h2c_lock,
253 flag);
254 }
255 spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
256 } else {
257 rtlhal->h2c_setinprogress = true;
258 spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
259 break;
260 }
261 }
262
263 while (!bwrite_success) {
264 wait_writeh2c_limmit--;
265 if (wait_writeh2c_limmit == 0) {
266 pr_err("Write H2C fail because no trigger for FW INT!\n");
267 break;
268 }
269
270 boxnum = rtlhal->last_hmeboxnum;
271 if (boxnum > 3) {
272 pr_err("boxnum %#x too big\n", boxnum);
273 break;
274 }
275
276 box_reg = REG_HMEBOX_0 + boxnum * SIZE_OF_REG_HMEBOX;
277 box_extreg = REG_HMEBOX_EXT_0 + boxnum * SIZE_OF_REG_HMEBOX_EXT;
278
279 isfw_read = _rtl92d_check_fw_read_last_h2c(hw, boxnum);
280 while (!isfw_read) {
281 wait_h2c_limmit--;
282 if (wait_h2c_limmit == 0) {
283 rtl_dbg(rtlpriv, COMP_CMD, DBG_LOUD,
284 "Waiting too long for FW read clear HMEBox(%d)!\n",
285 boxnum);
286 break;
287 }
288
289 udelay(10);
290
291 isfw_read = _rtl92d_check_fw_read_last_h2c(hw, boxnum);
292 u1b_tmp = rtl_read_byte(rtlpriv, 0x1BF);
293 rtl_dbg(rtlpriv, COMP_CMD, DBG_LOUD,
294 "Waiting for FW read clear HMEBox(%d)!!! 0x1BF = %2x\n",
295 boxnum, u1b_tmp);
296 }
297
298 if (!isfw_read) {
299 rtl_dbg(rtlpriv, COMP_CMD, DBG_LOUD,
300 "Write H2C register BOX[%d] fail!!!!! Fw do not read.\n",
301 boxnum);
302 break;
303 }
304
305 memset(boxcontent, 0, sizeof(boxcontent));
306 memset(boxextcontent, 0, sizeof(boxextcontent));
307 boxcontent[0] = element_id;
308
309 rtl_dbg(rtlpriv, COMP_CMD, DBG_LOUD,
310 "Write element_id box_reg(%4x) = %2x\n",
311 box_reg, element_id);
312
313 switch (cmd_len) {
314 case 1 ... 3:
315 /* BOX: | ID | A0 | A1 | A2 |
316 * BOX_EXT: --- N/A ------
317 */
318 boxcontent[0] &= ~BIT(7);
319 memcpy(boxcontent + 1, cmdbuffer, cmd_len);
320
321 for (idx = 0; idx < 4; idx++)
322 rtl_write_byte(rtlpriv, box_reg + idx,
323 boxcontent[idx]);
324 break;
325 case 4 ... 5:
326 /* * ID ext = ID | BIT(7)
327 * BOX: | ID ext | A2 | A3 | A4 |
328 * BOX_EXT: | A0 | A1 |
329 */
330 boxcontent[0] |= BIT(7);
331 memcpy(boxextcontent, cmdbuffer, 2);
332 memcpy(boxcontent + 1, cmdbuffer + 2, cmd_len - 2);
333
334 for (idx = 0; idx < 2; idx++)
335 rtl_write_byte(rtlpriv, box_extreg + idx,
336 boxextcontent[idx]);
337
338 for (idx = 0; idx < 4; idx++)
339 rtl_write_byte(rtlpriv, box_reg + idx,
340 boxcontent[idx]);
341 break;
342 default:
343 pr_err("switch case %#x not processed\n", cmd_len);
344 break;
345 }
346
347 bwrite_success = true;
348 rtlhal->last_hmeboxnum = boxnum + 1;
349 if (rtlhal->last_hmeboxnum == 4)
350 rtlhal->last_hmeboxnum = 0;
351
352 rtl_dbg(rtlpriv, COMP_CMD, DBG_LOUD,
353 "pHalData->last_hmeboxnum = %d\n",
354 rtlhal->last_hmeboxnum);
355 }
356 spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
357 rtlhal->h2c_setinprogress = false;
358 spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
359 rtl_dbg(rtlpriv, COMP_CMD, DBG_LOUD, "go out\n");
360 }
361 EXPORT_SYMBOL_GPL(rtl92d_fill_h2c_cmd);
362
rtl92d_set_fw_joinbss_report_cmd(struct ieee80211_hw * hw,u8 mstatus)363 void rtl92d_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus)
364 {
365 u8 u1_joinbssrpt_parm[1] = {0};
366
367 u1_joinbssrpt_parm[0] = mstatus;
368 rtl92d_fill_h2c_cmd(hw, H2C_JOINBSSRPT, 1, u1_joinbssrpt_parm);
369 }
370 EXPORT_SYMBOL_GPL(rtl92d_set_fw_joinbss_report_cmd);
371