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