16f3fcdc8SLarry Finger // SPDX-License-Identifier: GPL-2.0
26f3fcdc8SLarry Finger /* Copyright(c) 2009-2012 Realtek Corporation.*/
3f1d2b4d3SLarry Finger
4f1d2b4d3SLarry Finger #include "../wifi.h"
5f1d2b4d3SLarry Finger #include "../pci.h"
6f1d2b4d3SLarry Finger #include "../base.h"
7f1d2b4d3SLarry Finger #include "reg.h"
8f1d2b4d3SLarry Finger #include "def.h"
9f1d2b4d3SLarry Finger #include "fw.h"
10f1d2b4d3SLarry Finger
_rtl92s_fw_set_rqpn(struct ieee80211_hw * hw)11f1d2b4d3SLarry Finger static void _rtl92s_fw_set_rqpn(struct ieee80211_hw *hw)
12f1d2b4d3SLarry Finger {
13f1d2b4d3SLarry Finger struct rtl_priv *rtlpriv = rtl_priv(hw);
14f1d2b4d3SLarry Finger
15f1d2b4d3SLarry Finger rtl_write_dword(rtlpriv, RQPN, 0xffffffff);
16f1d2b4d3SLarry Finger rtl_write_dword(rtlpriv, RQPN + 4, 0xffffffff);
17f1d2b4d3SLarry Finger rtl_write_byte(rtlpriv, RQPN + 8, 0xff);
18f1d2b4d3SLarry Finger rtl_write_byte(rtlpriv, RQPN + 0xB, 0x80);
19f1d2b4d3SLarry Finger }
20f1d2b4d3SLarry Finger
_rtl92s_firmware_enable_cpu(struct ieee80211_hw * hw)21f1d2b4d3SLarry Finger static bool _rtl92s_firmware_enable_cpu(struct ieee80211_hw *hw)
22f1d2b4d3SLarry Finger {
23f1d2b4d3SLarry Finger struct rtl_priv *rtlpriv = rtl_priv(hw);
24f1d2b4d3SLarry Finger u32 ichecktime = 200;
25f1d2b4d3SLarry Finger u16 tmpu2b;
26f1d2b4d3SLarry Finger u8 tmpu1b, cpustatus = 0;
27f1d2b4d3SLarry Finger
28f1d2b4d3SLarry Finger _rtl92s_fw_set_rqpn(hw);
29f1d2b4d3SLarry Finger
30f1d2b4d3SLarry Finger /* Enable CPU. */
31f1d2b4d3SLarry Finger tmpu1b = rtl_read_byte(rtlpriv, SYS_CLKR);
32f1d2b4d3SLarry Finger /* AFE source */
33f1d2b4d3SLarry Finger rtl_write_byte(rtlpriv, SYS_CLKR, (tmpu1b | SYS_CPU_CLKSEL));
34f1d2b4d3SLarry Finger
35f1d2b4d3SLarry Finger tmpu2b = rtl_read_word(rtlpriv, REG_SYS_FUNC_EN);
36f1d2b4d3SLarry Finger rtl_write_word(rtlpriv, REG_SYS_FUNC_EN, (tmpu2b | FEN_CPUEN));
37f1d2b4d3SLarry Finger
38f1d2b4d3SLarry Finger /* Polling IMEM Ready after CPU has refilled. */
39f1d2b4d3SLarry Finger do {
40f1d2b4d3SLarry Finger cpustatus = rtl_read_byte(rtlpriv, TCR);
41f1d2b4d3SLarry Finger if (cpustatus & IMEM_RDY) {
42*fca8218dSLarry Finger rtl_dbg(rtlpriv, COMP_INIT, DBG_LOUD,
43f1d2b4d3SLarry Finger "IMEM Ready after CPU has refilled\n");
44f1d2b4d3SLarry Finger break;
45f1d2b4d3SLarry Finger }
46f1d2b4d3SLarry Finger
47f1d2b4d3SLarry Finger udelay(100);
48f1d2b4d3SLarry Finger } while (ichecktime--);
49f1d2b4d3SLarry Finger
50f1d2b4d3SLarry Finger if (!(cpustatus & IMEM_RDY))
51f1d2b4d3SLarry Finger return false;
52f1d2b4d3SLarry Finger
53f1d2b4d3SLarry Finger return true;
54f1d2b4d3SLarry Finger }
55f1d2b4d3SLarry Finger
_rtl92s_firmware_get_nextstatus(enum fw_status fw_currentstatus)56f1d2b4d3SLarry Finger static enum fw_status _rtl92s_firmware_get_nextstatus(
57f1d2b4d3SLarry Finger enum fw_status fw_currentstatus)
58f1d2b4d3SLarry Finger {
59f1d2b4d3SLarry Finger enum fw_status next_fwstatus = 0;
60f1d2b4d3SLarry Finger
61f1d2b4d3SLarry Finger switch (fw_currentstatus) {
62f1d2b4d3SLarry Finger case FW_STATUS_INIT:
63f1d2b4d3SLarry Finger next_fwstatus = FW_STATUS_LOAD_IMEM;
64f1d2b4d3SLarry Finger break;
65f1d2b4d3SLarry Finger case FW_STATUS_LOAD_IMEM:
66f1d2b4d3SLarry Finger next_fwstatus = FW_STATUS_LOAD_EMEM;
67f1d2b4d3SLarry Finger break;
68f1d2b4d3SLarry Finger case FW_STATUS_LOAD_EMEM:
69f1d2b4d3SLarry Finger next_fwstatus = FW_STATUS_LOAD_DMEM;
70f1d2b4d3SLarry Finger break;
71f1d2b4d3SLarry Finger case FW_STATUS_LOAD_DMEM:
72f1d2b4d3SLarry Finger next_fwstatus = FW_STATUS_READY;
73f1d2b4d3SLarry Finger break;
74f1d2b4d3SLarry Finger default:
75f1d2b4d3SLarry Finger break;
76f1d2b4d3SLarry Finger }
77f1d2b4d3SLarry Finger
78f1d2b4d3SLarry Finger return next_fwstatus;
79f1d2b4d3SLarry Finger }
80f1d2b4d3SLarry Finger
_rtl92s_firmware_header_map_rftype(struct ieee80211_hw * hw)81f1d2b4d3SLarry Finger static u8 _rtl92s_firmware_header_map_rftype(struct ieee80211_hw *hw)
82f1d2b4d3SLarry Finger {
83f1d2b4d3SLarry Finger struct rtl_priv *rtlpriv = rtl_priv(hw);
84f1d2b4d3SLarry Finger struct rtl_phy *rtlphy = &(rtlpriv->phy);
85f1d2b4d3SLarry Finger
86f1d2b4d3SLarry Finger switch (rtlphy->rf_type) {
87f1d2b4d3SLarry Finger case RF_1T1R:
88f1d2b4d3SLarry Finger return 0x11;
89f1d2b4d3SLarry Finger case RF_1T2R:
90f1d2b4d3SLarry Finger return 0x12;
91f1d2b4d3SLarry Finger case RF_2T2R:
92f1d2b4d3SLarry Finger return 0x22;
93f1d2b4d3SLarry Finger default:
942d15acacSLarry Finger pr_err("Unknown RF type(%x)\n", rtlphy->rf_type);
95f1d2b4d3SLarry Finger break;
96f1d2b4d3SLarry Finger }
97f1d2b4d3SLarry Finger return 0x22;
98f1d2b4d3SLarry Finger }
99f1d2b4d3SLarry Finger
_rtl92s_firmwareheader_priveupdate(struct ieee80211_hw * hw,struct fw_priv * pfw_priv)100f1d2b4d3SLarry Finger static void _rtl92s_firmwareheader_priveupdate(struct ieee80211_hw *hw,
101f1d2b4d3SLarry Finger struct fw_priv *pfw_priv)
102f1d2b4d3SLarry Finger {
103f1d2b4d3SLarry Finger /* Update RF types for RATR settings. */
104f1d2b4d3SLarry Finger pfw_priv->rf_config = _rtl92s_firmware_header_map_rftype(hw);
105f1d2b4d3SLarry Finger }
106f1d2b4d3SLarry Finger
107f1d2b4d3SLarry Finger
108f1d2b4d3SLarry Finger
_rtl92s_cmd_send_packet(struct ieee80211_hw * hw,struct sk_buff * skb,u8 last)109f1d2b4d3SLarry Finger static bool _rtl92s_cmd_send_packet(struct ieee80211_hw *hw,
110f1d2b4d3SLarry Finger struct sk_buff *skb, u8 last)
111f1d2b4d3SLarry Finger {
112f1d2b4d3SLarry Finger struct rtl_priv *rtlpriv = rtl_priv(hw);
113f1d2b4d3SLarry Finger struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
114f1d2b4d3SLarry Finger struct rtl8192_tx_ring *ring;
115f1d2b4d3SLarry Finger struct rtl_tx_desc *pdesc;
116f1d2b4d3SLarry Finger unsigned long flags;
117f1d2b4d3SLarry Finger u8 idx = 0;
118f1d2b4d3SLarry Finger
119f1d2b4d3SLarry Finger ring = &rtlpci->tx_ring[TXCMD_QUEUE];
120f1d2b4d3SLarry Finger
121f1d2b4d3SLarry Finger spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags);
122f1d2b4d3SLarry Finger
123f1d2b4d3SLarry Finger idx = (ring->idx + skb_queue_len(&ring->queue)) % ring->entries;
124f1d2b4d3SLarry Finger pdesc = &ring->desc[idx];
125f1d2b4d3SLarry Finger rtlpriv->cfg->ops->fill_tx_cmddesc(hw, (u8 *)pdesc, 1, 1, skb);
126f1d2b4d3SLarry Finger __skb_queue_tail(&ring->queue, skb);
127f1d2b4d3SLarry Finger
128f1d2b4d3SLarry Finger spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
129f1d2b4d3SLarry Finger
130f1d2b4d3SLarry Finger return true;
131f1d2b4d3SLarry Finger }
132f1d2b4d3SLarry Finger
_rtl92s_firmware_downloadcode(struct ieee80211_hw * hw,u8 * code_virtual_address,u32 buffer_len)133f1d2b4d3SLarry Finger static bool _rtl92s_firmware_downloadcode(struct ieee80211_hw *hw,
134f1d2b4d3SLarry Finger u8 *code_virtual_address, u32 buffer_len)
135f1d2b4d3SLarry Finger {
136f1d2b4d3SLarry Finger struct rtl_priv *rtlpriv = rtl_priv(hw);
137f1d2b4d3SLarry Finger struct sk_buff *skb;
138f1d2b4d3SLarry Finger struct rtl_tcb_desc *tcb_desc;
139f1d2b4d3SLarry Finger u16 frag_threshold = MAX_FIRMWARE_CODE_SIZE;
140f1d2b4d3SLarry Finger u16 frag_length, frag_offset = 0;
141f1d2b4d3SLarry Finger u16 extra_descoffset = 0;
142f1d2b4d3SLarry Finger u8 last_inipkt = 0;
143f1d2b4d3SLarry Finger
144f1d2b4d3SLarry Finger _rtl92s_fw_set_rqpn(hw);
145f1d2b4d3SLarry Finger
146f1d2b4d3SLarry Finger if (buffer_len >= MAX_FIRMWARE_CODE_SIZE) {
1472d15acacSLarry Finger pr_err("Size over FIRMWARE_CODE_SIZE!\n");
148f1d2b4d3SLarry Finger return false;
149f1d2b4d3SLarry Finger }
150f1d2b4d3SLarry Finger
151f1d2b4d3SLarry Finger extra_descoffset = 0;
152f1d2b4d3SLarry Finger
153f1d2b4d3SLarry Finger do {
154f1d2b4d3SLarry Finger if ((buffer_len - frag_offset) > frag_threshold) {
155f1d2b4d3SLarry Finger frag_length = frag_threshold + extra_descoffset;
156f1d2b4d3SLarry Finger } else {
157f1d2b4d3SLarry Finger frag_length = (u16)(buffer_len - frag_offset +
158f1d2b4d3SLarry Finger extra_descoffset);
159f1d2b4d3SLarry Finger last_inipkt = 1;
160f1d2b4d3SLarry Finger }
161f1d2b4d3SLarry Finger
162f1d2b4d3SLarry Finger /* Allocate skb buffer to contain firmware */
163f1d2b4d3SLarry Finger /* info and tx descriptor info. */
164f1d2b4d3SLarry Finger skb = dev_alloc_skb(frag_length);
165f1d2b4d3SLarry Finger if (!skb)
166f1d2b4d3SLarry Finger return false;
167f1d2b4d3SLarry Finger skb_reserve(skb, extra_descoffset);
168037e0c5dSYueHaibing skb_put_data(skb, code_virtual_address + frag_offset,
169f1d2b4d3SLarry Finger (u32)(frag_length - extra_descoffset));
170f1d2b4d3SLarry Finger
171f1d2b4d3SLarry Finger tcb_desc = (struct rtl_tcb_desc *)(skb->cb);
172f1d2b4d3SLarry Finger tcb_desc->queue_index = TXCMD_QUEUE;
173f1d2b4d3SLarry Finger tcb_desc->cmd_or_init = DESC_PACKET_TYPE_INIT;
174f1d2b4d3SLarry Finger tcb_desc->last_inipkt = last_inipkt;
175f1d2b4d3SLarry Finger
176f1d2b4d3SLarry Finger _rtl92s_cmd_send_packet(hw, skb, last_inipkt);
177f1d2b4d3SLarry Finger
178f1d2b4d3SLarry Finger frag_offset += (frag_length - extra_descoffset);
179f1d2b4d3SLarry Finger
180f1d2b4d3SLarry Finger } while (frag_offset < buffer_len);
181f1d2b4d3SLarry Finger
182f1d2b4d3SLarry Finger rtl_write_byte(rtlpriv, TP_POLL, TPPOLL_CQ);
183f1d2b4d3SLarry Finger
184f1d2b4d3SLarry Finger return true ;
185f1d2b4d3SLarry Finger }
186f1d2b4d3SLarry Finger
_rtl92s_firmware_checkready(struct ieee80211_hw * hw,u8 loadfw_status)187f1d2b4d3SLarry Finger static bool _rtl92s_firmware_checkready(struct ieee80211_hw *hw,
188f1d2b4d3SLarry Finger u8 loadfw_status)
189f1d2b4d3SLarry Finger {
190f1d2b4d3SLarry Finger struct rtl_priv *rtlpriv = rtl_priv(hw);
191f1d2b4d3SLarry Finger struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
192f1d2b4d3SLarry Finger struct rt_firmware *firmware = (struct rt_firmware *)rtlhal->pfirmware;
193f1d2b4d3SLarry Finger u32 tmpu4b;
194f1d2b4d3SLarry Finger u8 cpustatus = 0;
195f1d2b4d3SLarry Finger short pollingcnt = 1000;
196f1d2b4d3SLarry Finger bool rtstatus = true;
197f1d2b4d3SLarry Finger
198*fca8218dSLarry Finger rtl_dbg(rtlpriv, COMP_INIT, DBG_LOUD,
199f1d2b4d3SLarry Finger "LoadStaus(%d)\n", loadfw_status);
200f1d2b4d3SLarry Finger
201f1d2b4d3SLarry Finger firmware->fwstatus = (enum fw_status)loadfw_status;
202f1d2b4d3SLarry Finger
203f1d2b4d3SLarry Finger switch (loadfw_status) {
204f1d2b4d3SLarry Finger case FW_STATUS_LOAD_IMEM:
205f1d2b4d3SLarry Finger /* Polling IMEM code done. */
206f1d2b4d3SLarry Finger do {
207f1d2b4d3SLarry Finger cpustatus = rtl_read_byte(rtlpriv, TCR);
208f1d2b4d3SLarry Finger if (cpustatus & IMEM_CODE_DONE)
209f1d2b4d3SLarry Finger break;
210f1d2b4d3SLarry Finger udelay(5);
211f1d2b4d3SLarry Finger } while (pollingcnt--);
212f1d2b4d3SLarry Finger
213f1d2b4d3SLarry Finger if (!(cpustatus & IMEM_CHK_RPT) || (pollingcnt <= 0)) {
2142d15acacSLarry Finger pr_err("FW_STATUS_LOAD_IMEM FAIL CPU, Status=%x\n",
215f1d2b4d3SLarry Finger cpustatus);
216f1d2b4d3SLarry Finger goto status_check_fail;
217f1d2b4d3SLarry Finger }
218f1d2b4d3SLarry Finger break;
219f1d2b4d3SLarry Finger
220f1d2b4d3SLarry Finger case FW_STATUS_LOAD_EMEM:
221f1d2b4d3SLarry Finger /* Check Put Code OK and Turn On CPU */
222f1d2b4d3SLarry Finger /* Polling EMEM code done. */
223f1d2b4d3SLarry Finger do {
224f1d2b4d3SLarry Finger cpustatus = rtl_read_byte(rtlpriv, TCR);
225f1d2b4d3SLarry Finger if (cpustatus & EMEM_CODE_DONE)
226f1d2b4d3SLarry Finger break;
227f1d2b4d3SLarry Finger udelay(5);
228f1d2b4d3SLarry Finger } while (pollingcnt--);
229f1d2b4d3SLarry Finger
230f1d2b4d3SLarry Finger if (!(cpustatus & EMEM_CHK_RPT) || (pollingcnt <= 0)) {
2312d15acacSLarry Finger pr_err("FW_STATUS_LOAD_EMEM FAIL CPU, Status=%x\n",
232f1d2b4d3SLarry Finger cpustatus);
233f1d2b4d3SLarry Finger goto status_check_fail;
234f1d2b4d3SLarry Finger }
235f1d2b4d3SLarry Finger
236f1d2b4d3SLarry Finger /* Turn On CPU */
237f1d2b4d3SLarry Finger rtstatus = _rtl92s_firmware_enable_cpu(hw);
238f1d2b4d3SLarry Finger if (!rtstatus) {
2392d15acacSLarry Finger pr_err("Enable CPU fail!\n");
240f1d2b4d3SLarry Finger goto status_check_fail;
241f1d2b4d3SLarry Finger }
242f1d2b4d3SLarry Finger break;
243f1d2b4d3SLarry Finger
244f1d2b4d3SLarry Finger case FW_STATUS_LOAD_DMEM:
245f1d2b4d3SLarry Finger /* Polling DMEM code done */
246f1d2b4d3SLarry Finger do {
247f1d2b4d3SLarry Finger cpustatus = rtl_read_byte(rtlpriv, TCR);
248f1d2b4d3SLarry Finger if (cpustatus & DMEM_CODE_DONE)
249f1d2b4d3SLarry Finger break;
250f1d2b4d3SLarry Finger udelay(5);
251f1d2b4d3SLarry Finger } while (pollingcnt--);
252f1d2b4d3SLarry Finger
253f1d2b4d3SLarry Finger if (!(cpustatus & DMEM_CODE_DONE) || (pollingcnt <= 0)) {
2542d15acacSLarry Finger pr_err("Polling DMEM code done fail ! cpustatus(%#x)\n",
255f1d2b4d3SLarry Finger cpustatus);
256f1d2b4d3SLarry Finger goto status_check_fail;
257f1d2b4d3SLarry Finger }
258f1d2b4d3SLarry Finger
259*fca8218dSLarry Finger rtl_dbg(rtlpriv, COMP_INIT, DBG_LOUD,
260f1d2b4d3SLarry Finger "DMEM code download success, cpustatus(%#x)\n",
261f1d2b4d3SLarry Finger cpustatus);
262f1d2b4d3SLarry Finger
263f1d2b4d3SLarry Finger /* Prevent Delay too much and being scheduled out */
264f1d2b4d3SLarry Finger /* Polling Load Firmware ready */
265f1d2b4d3SLarry Finger pollingcnt = 2000;
266f1d2b4d3SLarry Finger do {
267f1d2b4d3SLarry Finger cpustatus = rtl_read_byte(rtlpriv, TCR);
268f1d2b4d3SLarry Finger if (cpustatus & FWRDY)
269f1d2b4d3SLarry Finger break;
270f1d2b4d3SLarry Finger udelay(40);
271f1d2b4d3SLarry Finger } while (pollingcnt--);
272f1d2b4d3SLarry Finger
273*fca8218dSLarry Finger rtl_dbg(rtlpriv, COMP_INIT, DBG_LOUD,
274f1d2b4d3SLarry Finger "Polling Load Firmware ready, cpustatus(%x)\n",
275f1d2b4d3SLarry Finger cpustatus);
276f1d2b4d3SLarry Finger
277f1d2b4d3SLarry Finger if (((cpustatus & LOAD_FW_READY) != LOAD_FW_READY) ||
278f1d2b4d3SLarry Finger (pollingcnt <= 0)) {
2792d15acacSLarry Finger pr_err("Polling Load Firmware ready fail ! cpustatus(%x)\n",
280f1d2b4d3SLarry Finger cpustatus);
281f1d2b4d3SLarry Finger goto status_check_fail;
282f1d2b4d3SLarry Finger }
283f1d2b4d3SLarry Finger
284f1d2b4d3SLarry Finger /* If right here, we can set TCR/RCR to desired value */
285f1d2b4d3SLarry Finger /* and config MAC lookback mode to normal mode */
286f1d2b4d3SLarry Finger tmpu4b = rtl_read_dword(rtlpriv, TCR);
287f1d2b4d3SLarry Finger rtl_write_dword(rtlpriv, TCR, (tmpu4b & (~TCR_ICV)));
288f1d2b4d3SLarry Finger
289f1d2b4d3SLarry Finger tmpu4b = rtl_read_dword(rtlpriv, RCR);
290f1d2b4d3SLarry Finger rtl_write_dword(rtlpriv, RCR, (tmpu4b | RCR_APPFCS |
291f1d2b4d3SLarry Finger RCR_APP_ICV | RCR_APP_MIC));
292f1d2b4d3SLarry Finger
293*fca8218dSLarry Finger rtl_dbg(rtlpriv, COMP_INIT, DBG_LOUD,
294f1d2b4d3SLarry Finger "Current RCR settings(%#x)\n", tmpu4b);
295f1d2b4d3SLarry Finger
296f1d2b4d3SLarry Finger /* Set to normal mode. */
297f1d2b4d3SLarry Finger rtl_write_byte(rtlpriv, LBKMD_SEL, LBK_NORMAL);
298f1d2b4d3SLarry Finger break;
299f1d2b4d3SLarry Finger
300f1d2b4d3SLarry Finger default:
3012d15acacSLarry Finger pr_err("Unknown status check!\n");
302f1d2b4d3SLarry Finger rtstatus = false;
303f1d2b4d3SLarry Finger break;
304f1d2b4d3SLarry Finger }
305f1d2b4d3SLarry Finger
306f1d2b4d3SLarry Finger status_check_fail:
307*fca8218dSLarry Finger rtl_dbg(rtlpriv, COMP_INIT, DBG_LOUD,
308f1d2b4d3SLarry Finger "loadfw_status(%d), rtstatus(%x)\n",
309f1d2b4d3SLarry Finger loadfw_status, rtstatus);
310f1d2b4d3SLarry Finger return rtstatus;
311f1d2b4d3SLarry Finger }
312f1d2b4d3SLarry Finger
rtl92s_download_fw(struct ieee80211_hw * hw)313f1d2b4d3SLarry Finger int rtl92s_download_fw(struct ieee80211_hw *hw)
314f1d2b4d3SLarry Finger {
315f1d2b4d3SLarry Finger struct rtl_priv *rtlpriv = rtl_priv(hw);
316f1d2b4d3SLarry Finger struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
317f1d2b4d3SLarry Finger struct rt_firmware *firmware = NULL;
318f1d2b4d3SLarry Finger struct fw_hdr *pfwheader;
319f1d2b4d3SLarry Finger struct fw_priv *pfw_priv = NULL;
320f1d2b4d3SLarry Finger u8 *puc_mappedfile = NULL;
321f1d2b4d3SLarry Finger u32 ul_filelength = 0;
322f1d2b4d3SLarry Finger u8 fwhdr_size = RT_8192S_FIRMWARE_HDR_SIZE;
323f1d2b4d3SLarry Finger u8 fwstatus = FW_STATUS_INIT;
324f1d2b4d3SLarry Finger bool rtstatus = true;
325f1d2b4d3SLarry Finger
326f1d2b4d3SLarry Finger if (rtlpriv->max_fw_size == 0 || !rtlhal->pfirmware)
327f1d2b4d3SLarry Finger return 1;
328f1d2b4d3SLarry Finger
329f1d2b4d3SLarry Finger firmware = (struct rt_firmware *)rtlhal->pfirmware;
330f1d2b4d3SLarry Finger firmware->fwstatus = FW_STATUS_INIT;
331f1d2b4d3SLarry Finger
332f1d2b4d3SLarry Finger puc_mappedfile = firmware->sz_fw_tmpbuffer;
333f1d2b4d3SLarry Finger
334f1d2b4d3SLarry Finger /* 1. Retrieve FW header. */
335f1d2b4d3SLarry Finger firmware->pfwheader = (struct fw_hdr *) puc_mappedfile;
336f1d2b4d3SLarry Finger pfwheader = firmware->pfwheader;
337f1d2b4d3SLarry Finger firmware->firmwareversion = byte(pfwheader->version, 0);
338f1d2b4d3SLarry Finger firmware->pfwheader->fwpriv.hci_sel = 1;/* pcie */
339f1d2b4d3SLarry Finger
340*fca8218dSLarry Finger rtl_dbg(rtlpriv, COMP_INIT, DBG_LOUD,
341f1d2b4d3SLarry Finger "signature:%x, version:%x, size:%x, imemsize:%x, sram size:%x\n",
342f1d2b4d3SLarry Finger pfwheader->signature,
343f1d2b4d3SLarry Finger pfwheader->version, pfwheader->dmem_size,
344f1d2b4d3SLarry Finger pfwheader->img_imem_size, pfwheader->img_sram_size);
345f1d2b4d3SLarry Finger
346f1d2b4d3SLarry Finger /* 2. Retrieve IMEM image. */
347f1d2b4d3SLarry Finger if ((pfwheader->img_imem_size == 0) || (pfwheader->img_imem_size >
348f1d2b4d3SLarry Finger sizeof(firmware->fw_imem))) {
3492d15acacSLarry Finger pr_err("memory for data image is less than IMEM required\n");
350f1d2b4d3SLarry Finger goto fail;
351f1d2b4d3SLarry Finger } else {
352f1d2b4d3SLarry Finger puc_mappedfile += fwhdr_size;
353f1d2b4d3SLarry Finger
354f1d2b4d3SLarry Finger memcpy(firmware->fw_imem, puc_mappedfile,
355f1d2b4d3SLarry Finger pfwheader->img_imem_size);
356f1d2b4d3SLarry Finger firmware->fw_imem_len = pfwheader->img_imem_size;
357f1d2b4d3SLarry Finger }
358f1d2b4d3SLarry Finger
359f1d2b4d3SLarry Finger /* 3. Retriecve EMEM image. */
360f1d2b4d3SLarry Finger if (pfwheader->img_sram_size > sizeof(firmware->fw_emem)) {
3612d15acacSLarry Finger pr_err("memory for data image is less than EMEM required\n");
362f1d2b4d3SLarry Finger goto fail;
363f1d2b4d3SLarry Finger } else {
364f1d2b4d3SLarry Finger puc_mappedfile += firmware->fw_imem_len;
365f1d2b4d3SLarry Finger
366f1d2b4d3SLarry Finger memcpy(firmware->fw_emem, puc_mappedfile,
367f1d2b4d3SLarry Finger pfwheader->img_sram_size);
368f1d2b4d3SLarry Finger firmware->fw_emem_len = pfwheader->img_sram_size;
369f1d2b4d3SLarry Finger }
370f1d2b4d3SLarry Finger
371f1d2b4d3SLarry Finger /* 4. download fw now */
372f1d2b4d3SLarry Finger fwstatus = _rtl92s_firmware_get_nextstatus(firmware->fwstatus);
373f1d2b4d3SLarry Finger while (fwstatus != FW_STATUS_READY) {
374f1d2b4d3SLarry Finger /* Image buffer redirection. */
375f1d2b4d3SLarry Finger switch (fwstatus) {
376f1d2b4d3SLarry Finger case FW_STATUS_LOAD_IMEM:
377f1d2b4d3SLarry Finger puc_mappedfile = firmware->fw_imem;
378f1d2b4d3SLarry Finger ul_filelength = firmware->fw_imem_len;
379f1d2b4d3SLarry Finger break;
380f1d2b4d3SLarry Finger case FW_STATUS_LOAD_EMEM:
381f1d2b4d3SLarry Finger puc_mappedfile = firmware->fw_emem;
382f1d2b4d3SLarry Finger ul_filelength = firmware->fw_emem_len;
383f1d2b4d3SLarry Finger break;
384f1d2b4d3SLarry Finger case FW_STATUS_LOAD_DMEM:
385f1d2b4d3SLarry Finger /* Partial update the content of header private. */
386f1d2b4d3SLarry Finger pfwheader = firmware->pfwheader;
387f1d2b4d3SLarry Finger pfw_priv = &pfwheader->fwpriv;
388f1d2b4d3SLarry Finger _rtl92s_firmwareheader_priveupdate(hw, pfw_priv);
389f1d2b4d3SLarry Finger puc_mappedfile = (u8 *)(firmware->pfwheader) +
390f1d2b4d3SLarry Finger RT_8192S_FIRMWARE_HDR_EXCLUDE_PRI_SIZE;
391f1d2b4d3SLarry Finger ul_filelength = fwhdr_size -
392f1d2b4d3SLarry Finger RT_8192S_FIRMWARE_HDR_EXCLUDE_PRI_SIZE;
393f1d2b4d3SLarry Finger break;
394f1d2b4d3SLarry Finger default:
3952d15acacSLarry Finger pr_err("Unexpected Download step!!\n");
396f1d2b4d3SLarry Finger goto fail;
397f1d2b4d3SLarry Finger }
398f1d2b4d3SLarry Finger
399f1d2b4d3SLarry Finger /* <2> Download image file */
400f1d2b4d3SLarry Finger rtstatus = _rtl92s_firmware_downloadcode(hw, puc_mappedfile,
401f1d2b4d3SLarry Finger ul_filelength);
402f1d2b4d3SLarry Finger
403f1d2b4d3SLarry Finger if (!rtstatus) {
4042d15acacSLarry Finger pr_err("fail!\n");
405f1d2b4d3SLarry Finger goto fail;
406f1d2b4d3SLarry Finger }
407f1d2b4d3SLarry Finger
408f1d2b4d3SLarry Finger /* <3> Check whether load FW process is ready */
409f1d2b4d3SLarry Finger rtstatus = _rtl92s_firmware_checkready(hw, fwstatus);
410f1d2b4d3SLarry Finger if (!rtstatus) {
4112d15acacSLarry Finger pr_err("rtl8192se: firmware fail!\n");
412f1d2b4d3SLarry Finger goto fail;
413f1d2b4d3SLarry Finger }
414f1d2b4d3SLarry Finger
415f1d2b4d3SLarry Finger fwstatus = _rtl92s_firmware_get_nextstatus(firmware->fwstatus);
416f1d2b4d3SLarry Finger }
417f1d2b4d3SLarry Finger
418f1d2b4d3SLarry Finger return rtstatus;
419f1d2b4d3SLarry Finger fail:
420f1d2b4d3SLarry Finger return 0;
421f1d2b4d3SLarry Finger }
422f1d2b4d3SLarry Finger
_rtl92s_fill_h2c_cmd(struct sk_buff * skb,u32 h2cbufferlen,u32 cmd_num,u32 * pelement_id,u32 * pcmd_len,u8 ** pcmb_buffer,u8 * cmd_start_seq)423f1d2b4d3SLarry Finger static u32 _rtl92s_fill_h2c_cmd(struct sk_buff *skb, u32 h2cbufferlen,
424f1d2b4d3SLarry Finger u32 cmd_num, u32 *pelement_id, u32 *pcmd_len,
425f1d2b4d3SLarry Finger u8 **pcmb_buffer, u8 *cmd_start_seq)
426f1d2b4d3SLarry Finger {
427f1d2b4d3SLarry Finger u32 totallen = 0, len = 0, tx_desclen = 0;
428f1d2b4d3SLarry Finger u32 pre_continueoffset = 0;
429f1d2b4d3SLarry Finger u8 *ph2c_buffer;
430f1d2b4d3SLarry Finger u8 i = 0;
431f1d2b4d3SLarry Finger
432f1d2b4d3SLarry Finger do {
433550116d2SMasahiro Yamada /* 8 - Byte alignment */
434f1d2b4d3SLarry Finger len = H2C_TX_CMD_HDR_LEN + N_BYTE_ALIGMENT(pcmd_len[i], 8);
435f1d2b4d3SLarry Finger
436f1d2b4d3SLarry Finger /* Buffer length is not enough */
437f1d2b4d3SLarry Finger if (h2cbufferlen < totallen + len + tx_desclen)
438f1d2b4d3SLarry Finger break;
439f1d2b4d3SLarry Finger
440f1d2b4d3SLarry Finger /* Clear content */
4414df864c1SJohannes Berg ph2c_buffer = skb_put(skb, (u32)len);
442f1d2b4d3SLarry Finger memset((ph2c_buffer + totallen + tx_desclen), 0, len);
443f1d2b4d3SLarry Finger
444f1d2b4d3SLarry Finger /* CMD len */
445c3f997f0SLarry Finger le32p_replace_bits((__le32 *)(ph2c_buffer + totallen +
446c3f997f0SLarry Finger tx_desclen), pcmd_len[i],
447c3f997f0SLarry Finger GENMASK(15, 0));
448f1d2b4d3SLarry Finger
449f1d2b4d3SLarry Finger /* CMD ID */
450c3f997f0SLarry Finger le32p_replace_bits((__le32 *)(ph2c_buffer + totallen +
451c3f997f0SLarry Finger tx_desclen), pelement_id[i],
452c3f997f0SLarry Finger GENMASK(23, 16));
453f1d2b4d3SLarry Finger
454f1d2b4d3SLarry Finger /* CMD Sequence */
455f1d2b4d3SLarry Finger *cmd_start_seq = *cmd_start_seq % 0x80;
456c3f997f0SLarry Finger le32p_replace_bits((__le32 *)(ph2c_buffer + totallen +
457c3f997f0SLarry Finger tx_desclen), *cmd_start_seq,
458c3f997f0SLarry Finger GENMASK(30, 24));
459f1d2b4d3SLarry Finger ++*cmd_start_seq;
460f1d2b4d3SLarry Finger
461f1d2b4d3SLarry Finger /* Copy memory */
462f1d2b4d3SLarry Finger memcpy((ph2c_buffer + totallen + tx_desclen +
463f1d2b4d3SLarry Finger H2C_TX_CMD_HDR_LEN), pcmb_buffer[i], pcmd_len[i]);
464f1d2b4d3SLarry Finger
465f1d2b4d3SLarry Finger /* CMD continue */
466f1d2b4d3SLarry Finger /* set the continue in prevoius cmd. */
467f1d2b4d3SLarry Finger if (i < cmd_num - 1)
468c3f997f0SLarry Finger le32p_replace_bits((__le32 *)(ph2c_buffer +
469c3f997f0SLarry Finger pre_continueoffset),
470c3f997f0SLarry Finger 1, BIT(31));
471f1d2b4d3SLarry Finger
472f1d2b4d3SLarry Finger pre_continueoffset = totallen;
473f1d2b4d3SLarry Finger
474f1d2b4d3SLarry Finger totallen += len;
475f1d2b4d3SLarry Finger } while (++i < cmd_num);
476f1d2b4d3SLarry Finger
477f1d2b4d3SLarry Finger return totallen;
478f1d2b4d3SLarry Finger }
479f1d2b4d3SLarry Finger
_rtl92s_get_h2c_cmdlen(u32 h2cbufferlen,u32 cmd_num,u32 * pcmd_len)480f1d2b4d3SLarry Finger static u32 _rtl92s_get_h2c_cmdlen(u32 h2cbufferlen, u32 cmd_num, u32 *pcmd_len)
481f1d2b4d3SLarry Finger {
482f1d2b4d3SLarry Finger u32 totallen = 0, len = 0, tx_desclen = 0;
483f1d2b4d3SLarry Finger u8 i = 0;
484f1d2b4d3SLarry Finger
485f1d2b4d3SLarry Finger do {
486550116d2SMasahiro Yamada /* 8 - Byte alignment */
487f1d2b4d3SLarry Finger len = H2C_TX_CMD_HDR_LEN + N_BYTE_ALIGMENT(pcmd_len[i], 8);
488f1d2b4d3SLarry Finger
489f1d2b4d3SLarry Finger /* Buffer length is not enough */
490f1d2b4d3SLarry Finger if (h2cbufferlen < totallen + len + tx_desclen)
491f1d2b4d3SLarry Finger break;
492f1d2b4d3SLarry Finger
493f1d2b4d3SLarry Finger totallen += len;
494f1d2b4d3SLarry Finger } while (++i < cmd_num);
495f1d2b4d3SLarry Finger
496f1d2b4d3SLarry Finger return totallen + tx_desclen;
497f1d2b4d3SLarry Finger }
498f1d2b4d3SLarry Finger
_rtl92s_firmware_set_h2c_cmd(struct ieee80211_hw * hw,u8 h2c_cmd,u8 * pcmd_buffer)499f1d2b4d3SLarry Finger static bool _rtl92s_firmware_set_h2c_cmd(struct ieee80211_hw *hw, u8 h2c_cmd,
500f1d2b4d3SLarry Finger u8 *pcmd_buffer)
501f1d2b4d3SLarry Finger {
502f1d2b4d3SLarry Finger struct rtl_priv *rtlpriv = rtl_priv(hw);
503f1d2b4d3SLarry Finger struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
504f1d2b4d3SLarry Finger struct rtl_tcb_desc *cb_desc;
505f1d2b4d3SLarry Finger struct sk_buff *skb;
506f1d2b4d3SLarry Finger u32 element_id = 0;
507f1d2b4d3SLarry Finger u32 cmd_len = 0;
508f1d2b4d3SLarry Finger u32 len;
509f1d2b4d3SLarry Finger
510f1d2b4d3SLarry Finger switch (h2c_cmd) {
511f1d2b4d3SLarry Finger case FW_H2C_SETPWRMODE:
512f1d2b4d3SLarry Finger element_id = H2C_SETPWRMODE_CMD ;
513f1d2b4d3SLarry Finger cmd_len = sizeof(struct h2c_set_pwrmode_parm);
514f1d2b4d3SLarry Finger break;
515f1d2b4d3SLarry Finger case FW_H2C_JOINBSSRPT:
516f1d2b4d3SLarry Finger element_id = H2C_JOINBSSRPT_CMD;
517f1d2b4d3SLarry Finger cmd_len = sizeof(struct h2c_joinbss_rpt_parm);
518f1d2b4d3SLarry Finger break;
519f1d2b4d3SLarry Finger case FW_H2C_WOWLAN_UPDATE_GTK:
520f1d2b4d3SLarry Finger element_id = H2C_WOWLAN_UPDATE_GTK_CMD;
521f1d2b4d3SLarry Finger cmd_len = sizeof(struct h2c_wpa_two_way_parm);
522f1d2b4d3SLarry Finger break;
523f1d2b4d3SLarry Finger case FW_H2C_WOWLAN_UPDATE_IV:
524f1d2b4d3SLarry Finger element_id = H2C_WOWLAN_UPDATE_IV_CMD;
525f1d2b4d3SLarry Finger cmd_len = sizeof(unsigned long long);
526f1d2b4d3SLarry Finger break;
527f1d2b4d3SLarry Finger case FW_H2C_WOWLAN_OFFLOAD:
528f1d2b4d3SLarry Finger element_id = H2C_WOWLAN_FW_OFFLOAD;
529f1d2b4d3SLarry Finger cmd_len = sizeof(u8);
530f1d2b4d3SLarry Finger break;
531f1d2b4d3SLarry Finger default:
532f1d2b4d3SLarry Finger break;
533f1d2b4d3SLarry Finger }
534f1d2b4d3SLarry Finger
535f1d2b4d3SLarry Finger len = _rtl92s_get_h2c_cmdlen(MAX_TRANSMIT_BUFFER_SIZE, 1, &cmd_len);
536f1d2b4d3SLarry Finger skb = dev_alloc_skb(len);
537f1d2b4d3SLarry Finger if (!skb)
538f1d2b4d3SLarry Finger return false;
539f1d2b4d3SLarry Finger cb_desc = (struct rtl_tcb_desc *)(skb->cb);
540f1d2b4d3SLarry Finger cb_desc->queue_index = TXCMD_QUEUE;
541f1d2b4d3SLarry Finger cb_desc->cmd_or_init = DESC_PACKET_TYPE_NORMAL;
542f1d2b4d3SLarry Finger cb_desc->last_inipkt = false;
543f1d2b4d3SLarry Finger
544f1d2b4d3SLarry Finger _rtl92s_fill_h2c_cmd(skb, MAX_TRANSMIT_BUFFER_SIZE, 1, &element_id,
545f1d2b4d3SLarry Finger &cmd_len, &pcmd_buffer, &rtlhal->h2c_txcmd_seq);
546f1d2b4d3SLarry Finger _rtl92s_cmd_send_packet(hw, skb, false);
547f1d2b4d3SLarry Finger rtlpriv->cfg->ops->tx_polling(hw, TXCMD_QUEUE);
548f1d2b4d3SLarry Finger
549f1d2b4d3SLarry Finger return true;
550f1d2b4d3SLarry Finger }
551f1d2b4d3SLarry Finger
rtl92s_set_fw_pwrmode_cmd(struct ieee80211_hw * hw,u8 mode)5522a83ad1fSLarry Finger void rtl92s_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode)
553f1d2b4d3SLarry Finger {
554f1d2b4d3SLarry Finger struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
555f1d2b4d3SLarry Finger struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
556f1d2b4d3SLarry Finger struct h2c_set_pwrmode_parm pwrmode;
557f1d2b4d3SLarry Finger u16 max_wakeup_period = 0;
558f1d2b4d3SLarry Finger
5592a83ad1fSLarry Finger pwrmode.mode = mode;
560f1d2b4d3SLarry Finger pwrmode.flag_low_traffic_en = 0;
561f1d2b4d3SLarry Finger pwrmode.flag_lpnav_en = 0;
562f1d2b4d3SLarry Finger pwrmode.flag_rf_low_snr_en = 0;
563f1d2b4d3SLarry Finger pwrmode.flag_dps_en = 0;
564f1d2b4d3SLarry Finger pwrmode.bcn_rx_en = 0;
565f1d2b4d3SLarry Finger pwrmode.bcn_to = 0;
566c3f997f0SLarry Finger le16p_replace_bits((__le16 *)(((u8 *)(&pwrmode) + 8)),
567c3f997f0SLarry Finger mac->vif->bss_conf.beacon_int, GENMASK(15, 0));
568f1d2b4d3SLarry Finger pwrmode.app_itv = 0;
569f1d2b4d3SLarry Finger pwrmode.awake_bcn_itvl = ppsc->reg_max_lps_awakeintvl;
570f1d2b4d3SLarry Finger pwrmode.smart_ps = 1;
571f1d2b4d3SLarry Finger pwrmode.bcn_pass_period = 10;
572f1d2b4d3SLarry Finger
573f1d2b4d3SLarry Finger /* Set beacon pass count */
574f1d2b4d3SLarry Finger if (pwrmode.mode == FW_PS_MIN_MODE)
575f1d2b4d3SLarry Finger max_wakeup_period = mac->vif->bss_conf.beacon_int;
576f1d2b4d3SLarry Finger else if (pwrmode.mode == FW_PS_MAX_MODE)
577f1d2b4d3SLarry Finger max_wakeup_period = mac->vif->bss_conf.beacon_int *
578f1d2b4d3SLarry Finger mac->vif->bss_conf.dtim_period;
579f1d2b4d3SLarry Finger
580f1d2b4d3SLarry Finger if (max_wakeup_period >= 500)
581f1d2b4d3SLarry Finger pwrmode.bcn_pass_cnt = 1;
582f1d2b4d3SLarry Finger else if ((max_wakeup_period >= 300) && (max_wakeup_period < 500))
583f1d2b4d3SLarry Finger pwrmode.bcn_pass_cnt = 2;
584f1d2b4d3SLarry Finger else if ((max_wakeup_period >= 200) && (max_wakeup_period < 300))
585f1d2b4d3SLarry Finger pwrmode.bcn_pass_cnt = 3;
586f1d2b4d3SLarry Finger else if ((max_wakeup_period >= 20) && (max_wakeup_period < 200))
587f1d2b4d3SLarry Finger pwrmode.bcn_pass_cnt = 5;
588f1d2b4d3SLarry Finger else
589f1d2b4d3SLarry Finger pwrmode.bcn_pass_cnt = 1;
590f1d2b4d3SLarry Finger
591f1d2b4d3SLarry Finger _rtl92s_firmware_set_h2c_cmd(hw, FW_H2C_SETPWRMODE, (u8 *)&pwrmode);
592f1d2b4d3SLarry Finger
593f1d2b4d3SLarry Finger }
594f1d2b4d3SLarry Finger
rtl92s_set_fw_joinbss_report_cmd(struct ieee80211_hw * hw,u8 mstatus,u8 ps_qosinfo)595f1d2b4d3SLarry Finger void rtl92s_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw,
596f1d2b4d3SLarry Finger u8 mstatus, u8 ps_qosinfo)
597f1d2b4d3SLarry Finger {
598f1d2b4d3SLarry Finger struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
599f1d2b4d3SLarry Finger struct h2c_joinbss_rpt_parm joinbss_rpt;
600f1d2b4d3SLarry Finger
601f1d2b4d3SLarry Finger joinbss_rpt.opmode = mstatus;
602f1d2b4d3SLarry Finger joinbss_rpt.ps_qos_info = ps_qosinfo;
603f1d2b4d3SLarry Finger joinbss_rpt.bssid[0] = mac->bssid[0];
604f1d2b4d3SLarry Finger joinbss_rpt.bssid[1] = mac->bssid[1];
605f1d2b4d3SLarry Finger joinbss_rpt.bssid[2] = mac->bssid[2];
606f1d2b4d3SLarry Finger joinbss_rpt.bssid[3] = mac->bssid[3];
607f1d2b4d3SLarry Finger joinbss_rpt.bssid[4] = mac->bssid[4];
608f1d2b4d3SLarry Finger joinbss_rpt.bssid[5] = mac->bssid[5];
609c3f997f0SLarry Finger le16p_replace_bits((__le16 *)(((u8 *)(&joinbss_rpt) + 8)),
610c3f997f0SLarry Finger mac->vif->bss_conf.beacon_int, GENMASK(15, 0));
611c3f997f0SLarry Finger le16p_replace_bits((__le16 *)(((u8 *)(&joinbss_rpt) + 10)),
612c3f997f0SLarry Finger mac->assoc_id, GENMASK(15, 0));
613f1d2b4d3SLarry Finger
614f1d2b4d3SLarry Finger _rtl92s_firmware_set_h2c_cmd(hw, FW_H2C_JOINBSSRPT, (u8 *)&joinbss_rpt);
615f1d2b4d3SLarry Finger }
616f1d2b4d3SLarry Finger
617