1 /******************************************************************************
3 * Copyright(c) 2009-2014 Realtek Corporation.
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.
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
14 * The full GNU General Public License is included in this distribution in the
15 * file called LICENSE.
17 * Contact Information:
18 * wlanfae <wlanfae@realtek.com>
19 * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
20 * Hsinchu 300, Taiwan.
22 * Larry Finger <Larry.Finger@lwfinger.net>
24 *****************************************************************************/
29 #include "fw_common.h"
30 #include <linux/module.h>
32 void rtl8723_enable_fw_download(struct ieee80211_hw
*hw
, bool enable
)
34 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
38 tmp
= rtl_read_byte(rtlpriv
, REG_SYS_FUNC_EN
+ 1);
39 rtl_write_byte(rtlpriv
, REG_SYS_FUNC_EN
+ 1, tmp
| 0x04);
41 tmp
= rtl_read_byte(rtlpriv
, REG_MCUFWDL
);
42 rtl_write_byte(rtlpriv
, REG_MCUFWDL
, tmp
| 0x01);
44 tmp
= rtl_read_byte(rtlpriv
, REG_MCUFWDL
+ 2);
45 rtl_write_byte(rtlpriv
, REG_MCUFWDL
+ 2, tmp
& 0xf7);
47 tmp
= rtl_read_byte(rtlpriv
, REG_MCUFWDL
);
48 rtl_write_byte(rtlpriv
, REG_MCUFWDL
, tmp
& 0xfe);
50 rtl_write_byte(rtlpriv
, REG_MCUFWDL
+ 1, 0x00);
53 EXPORT_SYMBOL_GPL(rtl8723_enable_fw_download
);
55 void rtl8723_fw_block_write(struct ieee80211_hw
*hw
,
56 const u8
*buffer
, u32 size
)
58 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
59 u32 blocksize
= sizeof(u32
);
60 u8
*bufferptr
= (u8
*)buffer
;
61 u32
*pu4byteptr
= (u32
*)buffer
;
62 u32 i
, offset
, blockcount
, remainsize
;
64 blockcount
= size
/ blocksize
;
65 remainsize
= size
% blocksize
;
67 for (i
= 0; i
< blockcount
; i
++) {
68 offset
= i
* blocksize
;
69 rtl_write_dword(rtlpriv
, (FW_8192C_START_ADDRESS
+ offset
),
73 offset
= blockcount
* blocksize
;
75 for (i
= 0; i
< remainsize
; i
++) {
76 rtl_write_byte(rtlpriv
,
77 (FW_8192C_START_ADDRESS
+ offset
+ i
),
82 EXPORT_SYMBOL_GPL(rtl8723_fw_block_write
);
84 void rtl8723_fw_page_write(struct ieee80211_hw
*hw
,
85 u32 page
, const u8
*buffer
, u32 size
)
87 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
89 u8 u8page
= (u8
) (page
& 0x07);
91 value8
= (rtl_read_byte(rtlpriv
, REG_MCUFWDL
+ 2) & 0xF8) | u8page
;
93 rtl_write_byte(rtlpriv
, (REG_MCUFWDL
+ 2), value8
);
94 rtl8723_fw_block_write(hw
, buffer
, size
);
96 EXPORT_SYMBOL_GPL(rtl8723_fw_page_write
);
98 static void rtl8723_fill_dummy(u8
*pfwbuf
, u32
*pfwlen
)
101 u8 remain
= (u8
) (fwlen
% 4);
103 remain
= (remain
== 0) ? 0 : (4 - remain
);
113 void rtl8723_write_fw(struct ieee80211_hw
*hw
,
114 enum version_8723e version
,
115 u8
*buffer
, u32 size
)
117 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
118 u8
*bufferptr
= buffer
;
119 u32 pagenums
, remainsize
;
122 RT_TRACE(rtlpriv
, COMP_FW
, DBG_LOUD
, "FW size is %d bytes,\n", size
);
124 rtl8723_fill_dummy(bufferptr
, &size
);
126 pagenums
= size
/ FW_8192C_PAGE_SIZE
;
127 remainsize
= size
% FW_8192C_PAGE_SIZE
;
130 RT_TRACE(rtlpriv
, COMP_ERR
, DBG_EMERG
,
131 "Page numbers should not greater then 8\n");
133 for (page
= 0; page
< pagenums
; page
++) {
134 offset
= page
* FW_8192C_PAGE_SIZE
;
135 rtl8723_fw_page_write(hw
, page
, (bufferptr
+ offset
),
139 offset
= pagenums
* FW_8192C_PAGE_SIZE
;
141 rtl8723_fw_page_write(hw
, page
, (bufferptr
+ offset
),
145 EXPORT_SYMBOL_GPL(rtl8723_write_fw
);
147 void rtl8723ae_firmware_selfreset(struct ieee80211_hw
*hw
)
151 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
153 rtl_write_byte(rtlpriv
, REG_HMETFR
+ 3, 0x20);
154 u1tmp
= rtl_read_byte(rtlpriv
, REG_SYS_FUNC_EN
+ 1);
156 while (u1tmp
& BIT(2)) {
161 u1tmp
= rtl_read_byte(rtlpriv
, REG_SYS_FUNC_EN
+ 1);
164 u1tmp
= rtl_read_byte(rtlpriv
, REG_SYS_FUNC_EN
+ 1);
165 rtl_write_byte(rtlpriv
, REG_SYS_FUNC_EN
+ 1, u1tmp
&(~BIT(2)));
168 EXPORT_SYMBOL_GPL(rtl8723ae_firmware_selfreset
);
170 void rtl8723be_firmware_selfreset(struct ieee80211_hw
*hw
)
173 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
175 u1b_tmp
= rtl_read_byte(rtlpriv
, REG_RSV_CTRL
+ 1);
176 rtl_write_byte(rtlpriv
, REG_RSV_CTRL
+ 1, (u1b_tmp
& (~BIT(0))));
178 u1b_tmp
= rtl_read_byte(rtlpriv
, REG_SYS_FUNC_EN
+ 1);
179 rtl_write_byte(rtlpriv
, REG_SYS_FUNC_EN
+ 1, (u1b_tmp
& (~BIT(2))));
182 u1b_tmp
= rtl_read_byte(rtlpriv
, REG_RSV_CTRL
+ 1);
183 rtl_write_byte(rtlpriv
, REG_RSV_CTRL
+ 1, (u1b_tmp
| BIT(0)));
185 u1b_tmp
= rtl_read_byte(rtlpriv
, REG_SYS_FUNC_EN
+ 1);
186 rtl_write_byte(rtlpriv
, REG_SYS_FUNC_EN
+ 1, (u1b_tmp
| BIT(2)));
188 RT_TRACE(rtlpriv
, COMP_INIT
, DBG_LOUD
,
189 " _8051Reset8723be(): 8051 reset success .\n");
191 EXPORT_SYMBOL_GPL(rtl8723be_firmware_selfreset
);
193 int rtl8723_fw_free_to_go(struct ieee80211_hw
*hw
, bool is_8723be
)
195 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
201 value32
= rtl_read_dword(rtlpriv
, REG_MCUFWDL
);
202 } while ((counter
++ < FW_8192C_POLLING_TIMEOUT_COUNT
) &&
203 (!(value32
& FWDL_CHKSUM_RPT
)));
205 if (counter
>= FW_8192C_POLLING_TIMEOUT_COUNT
) {
206 RT_TRACE(rtlpriv
, COMP_ERR
, DBG_EMERG
,
207 "chksum report fail ! REG_MCUFWDL:0x%08x .\n",
211 RT_TRACE(rtlpriv
, COMP_FW
, DBG_TRACE
,
212 "Checksum report OK ! REG_MCUFWDL:0x%08x .\n", value32
);
214 value32
= rtl_read_dword(rtlpriv
, REG_MCUFWDL
) | MCUFWDL_RDY
;
215 value32
&= ~WINTINI_RDY
;
216 rtl_write_dword(rtlpriv
, REG_MCUFWDL
, value32
);
219 rtl8723be_firmware_selfreset(hw
);
223 value32
= rtl_read_dword(rtlpriv
, REG_MCUFWDL
);
224 if (value32
& WINTINI_RDY
) {
225 RT_TRACE(rtlpriv
, COMP_FW
, DBG_TRACE
,
226 "Polling FW ready success!! "
227 "REG_MCUFWDL:0x%08x .\n",
232 udelay(FW_8192C_POLLING_DELAY
);
234 } while (counter
++ < FW_8192C_POLLING_TIMEOUT_COUNT
);
236 RT_TRACE(rtlpriv
, COMP_ERR
, DBG_EMERG
,
237 "Polling FW ready fail!! REG_MCUFWDL:0x%08x .\n",
243 EXPORT_SYMBOL_GPL(rtl8723_fw_free_to_go
);
245 int rtl8723_download_fw(struct ieee80211_hw
*hw
,
248 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
249 struct rtl_hal
*rtlhal
= rtl_hal(rtl_priv(hw
));
250 struct rtl92c_firmware_header
*pfwheader
;
254 enum version_8723e version
= rtlhal
->version
;
256 if (!rtlhal
->pfirmware
)
259 pfwheader
= (struct rtl92c_firmware_header
*)rtlhal
->pfirmware
;
260 pfwdata
= rtlhal
->pfirmware
;
261 fwsize
= rtlhal
->fwsize
;
262 RT_TRACE(rtlpriv
, COMP_FW
, DBG_DMESG
,
263 "normal Firmware SIZE %d\n", fwsize
);
265 if (rtlpriv
->cfg
->ops
->is_fw_header(pfwheader
)) {
266 RT_TRACE(rtlpriv
, COMP_FW
, DBG_LOUD
,
267 "Firmware Version(%d), Signature(%#x), Size(%d)\n",
268 pfwheader
->version
, pfwheader
->signature
,
269 (int)sizeof(struct rtl92c_firmware_header
));
271 pfwdata
= pfwdata
+ sizeof(struct rtl92c_firmware_header
);
272 fwsize
= fwsize
- sizeof(struct rtl92c_firmware_header
);
274 if (rtl_read_byte(rtlpriv
, REG_MCUFWDL
) & BIT(7)) {
275 rtl_write_byte(rtlpriv
, REG_MCUFWDL
, 0);
277 rtl8723be_firmware_selfreset(hw
);
279 rtl8723ae_firmware_selfreset(hw
);
281 rtl8723_enable_fw_download(hw
, true);
282 rtl8723_write_fw(hw
, version
, pfwdata
, fwsize
);
283 rtl8723_enable_fw_download(hw
, false);
285 err
= rtl8723_fw_free_to_go(hw
, is_8723be
);
287 RT_TRACE(rtlpriv
, COMP_ERR
, DBG_EMERG
,
288 "Firmware is not ready to run!\n");
290 RT_TRACE(rtlpriv
, COMP_FW
, DBG_LOUD
,
291 "Firmware is ready to run!\n");
295 EXPORT_SYMBOL_GPL(rtl8723_download_fw
);
297 bool rtl8723_cmd_send_packet(struct ieee80211_hw
*hw
,
300 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
301 struct rtl_pci
*rtlpci
= rtl_pcidev(rtl_pcipriv(hw
));
302 struct rtl8192_tx_ring
*ring
;
303 struct rtl_tx_desc
*pdesc
;
304 struct sk_buff
*pskb
= NULL
;
308 ring
= &rtlpci
->tx_ring
[BEACON_QUEUE
];
310 pskb
= __skb_dequeue(&ring
->queue
);
314 spin_lock_irqsave(&rtlpriv
->locks
.irq_th_lock
, flags
);
316 pdesc
= &ring
->desc
[0];
317 own
= (u8
) rtlpriv
->cfg
->ops
->get_desc((u8
*)pdesc
, true, HW_DESC_OWN
);
319 rtlpriv
->cfg
->ops
->fill_tx_cmddesc(hw
, (u8
*)pdesc
, 1, 1, skb
);
321 __skb_queue_tail(&ring
->queue
, skb
);
323 spin_unlock_irqrestore(&rtlpriv
->locks
.irq_th_lock
, flags
);
325 rtlpriv
->cfg
->ops
->tx_polling(hw
, BEACON_QUEUE
);
329 EXPORT_SYMBOL_GPL(rtl8723_cmd_send_packet
);