• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**************************************************************************************************
2  * Procedure:    Init boot code/firmware code/data session
3  *
4  * Description: This routine will initialize firmware. If any error occurs during the initialization
5  *		process, the routine shall terminate immediately and return fail.
6  *		NIC driver should call NdisOpenFile only from MiniportInitialize.
7  *
8  * Arguments:   The pointer of the adapter
9 
10  * Returns:
11  *        NDIS_STATUS_FAILURE - the following initialization process should be terminated
12  *        NDIS_STATUS_SUCCESS - if firmware initialization process success
13 **************************************************************************************************/
14 
15 #include "r8192U.h"
16 #include "r8192U_hw.h"
17 #include "r819xU_firmware_img.h"
18 #include "r819xU_firmware.h"
19 #include <linux/firmware.h>
firmware_init_param(struct net_device * dev)20 void firmware_init_param(struct net_device *dev)
21 {
22 	struct r8192_priv	*priv = ieee80211_priv(dev);
23 	rt_firmware		*pfirmware = priv->pFirmware;
24 
25 	pfirmware->cmdpacket_frag_thresold = GET_COMMAND_PACKET_FRAG_THRESHOLD(MAX_TRANSMIT_BUFFER_SIZE);
26 }
27 
28 /*
29  * segment the img and use the ptr and length to remember info on each segment
30  *
31  */
fw_download_code(struct net_device * dev,u8 * code_virtual_address,u32 buffer_len)32 bool fw_download_code(struct net_device *dev, u8 *code_virtual_address, u32 buffer_len)
33 {
34 	struct r8192_priv   *priv = ieee80211_priv(dev);
35 	bool		    rt_status = true;
36 	u16		    frag_threshold;
37 	u16		    frag_length, frag_offset = 0;
38 	//u16		    total_size;
39 	int		    i;
40 
41 	rt_firmware	    *pfirmware = priv->pFirmware;
42 	struct sk_buff	    *skb;
43 	unsigned char	    *seg_ptr;
44 	cb_desc		    *tcb_desc;
45 	u8                  bLastIniPkt;
46 
47 	firmware_init_param(dev);
48 	//Fragmentation might be required
49 	frag_threshold = pfirmware->cmdpacket_frag_thresold;
50 	do {
51 		if((buffer_len - frag_offset) > frag_threshold) {
52 			frag_length = frag_threshold ;
53 			bLastIniPkt = 0;
54 
55 		} else {
56 			frag_length = buffer_len - frag_offset;
57 			bLastIniPkt = 1;
58 
59 		}
60 
61 		/* Allocate skb buffer to contain firmware info and tx descriptor info
62 		 * add 4 to avoid packet appending overflow.
63 		 * */
64 		#ifdef RTL8192U
65 		skb  = dev_alloc_skb(USB_HWDESC_HEADER_LEN + frag_length + 4);
66 		#else
67 		skb  = dev_alloc_skb(frag_length + 4);
68 		#endif
69 		memcpy((unsigned char *)(skb->cb),&dev,sizeof(dev));
70 		tcb_desc = (cb_desc*)(skb->cb + MAX_DEV_ADDR_SIZE);
71 		tcb_desc->queue_index = TXCMD_QUEUE;
72 		tcb_desc->bCmdOrInit = DESC_PACKET_TYPE_INIT;
73 		tcb_desc->bLastIniPkt = bLastIniPkt;
74 
75 		#ifdef RTL8192U
76 		skb_reserve(skb, USB_HWDESC_HEADER_LEN);
77 		#endif
78 		seg_ptr = skb->data;
79 		/*
80 		 * Transform from little endian to big endian
81 		 * and pending  zero
82 		 */
83 		for(i=0 ; i < frag_length; i+=4) {
84 			*seg_ptr++ = ((i+0)<frag_length)?code_virtual_address[i+3]:0;
85 			*seg_ptr++ = ((i+1)<frag_length)?code_virtual_address[i+2]:0;
86 			*seg_ptr++ = ((i+2)<frag_length)?code_virtual_address[i+1]:0;
87 			*seg_ptr++ = ((i+3)<frag_length)?code_virtual_address[i+0]:0;
88 		}
89 		tcb_desc->txbuf_size= (u16)i;
90 		skb_put(skb, i);
91 
92 		if(!priv->ieee80211->check_nic_enough_desc(dev,tcb_desc->queue_index)||
93 			(!skb_queue_empty(&priv->ieee80211->skb_waitQ[tcb_desc->queue_index]))||\
94 			(priv->ieee80211->queue_stop) ) {
95 			RT_TRACE(COMP_FIRMWARE,"=====================================================> tx full!\n");
96 			skb_queue_tail(&priv->ieee80211->skb_waitQ[tcb_desc->queue_index], skb);
97 		} else {
98 			priv->ieee80211->softmac_hard_start_xmit(skb,dev);
99 		}
100 
101 		code_virtual_address += frag_length;
102 		frag_offset += frag_length;
103 
104 	}while(frag_offset < buffer_len);
105 
106 	return rt_status;
107 
108 }
109 
110 bool
fwSendNullPacket(struct net_device * dev,u32 Length)111 fwSendNullPacket(
112 	struct net_device *dev,
113 	u32			Length
114 )
115 {
116 	bool	rtStatus = true;
117 	struct r8192_priv   *priv = ieee80211_priv(dev);
118 	struct sk_buff	    *skb;
119 	cb_desc		    *tcb_desc;
120 	unsigned char	    *ptr_buf;
121 	bool	bLastInitPacket = false;
122 
123 	//PlatformAcquireSpinLock(Adapter, RT_TX_SPINLOCK);
124 
125 	//Get TCB and local buffer from common pool. (It is shared by CmdQ, MgntQ, and USB coalesce DataQ)
126 	skb  = dev_alloc_skb(Length+ 4);
127 	memcpy((unsigned char *)(skb->cb),&dev,sizeof(dev));
128 	tcb_desc = (cb_desc*)(skb->cb + MAX_DEV_ADDR_SIZE);
129 	tcb_desc->queue_index = TXCMD_QUEUE;
130 	tcb_desc->bCmdOrInit = DESC_PACKET_TYPE_INIT;
131 	tcb_desc->bLastIniPkt = bLastInitPacket;
132 	ptr_buf = skb_put(skb, Length);
133 	memset(ptr_buf,0,Length);
134 	tcb_desc->txbuf_size= (u16)Length;
135 
136 	if(!priv->ieee80211->check_nic_enough_desc(dev,tcb_desc->queue_index)||
137 			(!skb_queue_empty(&priv->ieee80211->skb_waitQ[tcb_desc->queue_index]))||\
138 			(priv->ieee80211->queue_stop) ) {
139 			RT_TRACE(COMP_FIRMWARE,"===================NULL packet==================================> tx full!\n");
140 			skb_queue_tail(&priv->ieee80211->skb_waitQ[tcb_desc->queue_index], skb);
141 		} else {
142 			priv->ieee80211->softmac_hard_start_xmit(skb,dev);
143 		}
144 
145 	//PlatformReleaseSpinLock(Adapter, RT_TX_SPINLOCK);
146 	return rtStatus;
147 }
148 
149 
150 //-----------------------------------------------------------------------------
151 // Procedure:    Check whether main code is download OK. If OK, turn on CPU
152 //
153 // Description:   CPU register locates in different page against general register.
154 //			    Switch to CPU register in the begin and switch back before return
155 //
156 //
157 // Arguments:   The pointer of the adapter
158 //
159 // Returns:
160 //        NDIS_STATUS_FAILURE - the following initialization process should be terminated
161 //        NDIS_STATUS_SUCCESS - if firmware initialization process success
162 //-----------------------------------------------------------------------------
CPUcheck_maincodeok_turnonCPU(struct net_device * dev)163 bool CPUcheck_maincodeok_turnonCPU(struct net_device *dev)
164 {
165 	bool		rt_status = true;
166 	int		check_putcodeOK_time = 200000, check_bootOk_time = 200000;
167 	u32		CPU_status = 0;
168 
169 	/* Check whether put code OK */
170 	do {
171 		CPU_status = read_nic_dword(dev, CPU_GEN);
172 
173 		if(CPU_status&CPU_GEN_PUT_CODE_OK)
174 			break;
175 
176 	}while(check_putcodeOK_time--);
177 
178 	if(!(CPU_status&CPU_GEN_PUT_CODE_OK)) {
179 		RT_TRACE(COMP_ERR, "Download Firmware: Put code fail!\n");
180 		goto CPUCheckMainCodeOKAndTurnOnCPU_Fail;
181 	} else {
182 		RT_TRACE(COMP_FIRMWARE, "Download Firmware: Put code ok!\n");
183 	}
184 
185 	/* Turn On CPU */
186 	CPU_status = read_nic_dword(dev, CPU_GEN);
187 	write_nic_byte(dev, CPU_GEN, (u8)((CPU_status|CPU_GEN_PWR_STB_CPU)&0xff));
188 	mdelay(1000);
189 
190 	/* Check whether CPU boot OK */
191 	do {
192 		CPU_status = read_nic_dword(dev, CPU_GEN);
193 
194 		if(CPU_status&CPU_GEN_BOOT_RDY)
195 			break;
196 	}while(check_bootOk_time--);
197 
198 	if(!(CPU_status&CPU_GEN_BOOT_RDY)) {
199 		goto CPUCheckMainCodeOKAndTurnOnCPU_Fail;
200 	} else {
201 		RT_TRACE(COMP_FIRMWARE, "Download Firmware: Boot ready!\n");
202 	}
203 
204 	return rt_status;
205 
206 CPUCheckMainCodeOKAndTurnOnCPU_Fail:
207 	RT_TRACE(COMP_ERR, "ERR in %s()\n", __FUNCTION__);
208 	rt_status = FALSE;
209 	return rt_status;
210 }
211 
CPUcheck_firmware_ready(struct net_device * dev)212 bool CPUcheck_firmware_ready(struct net_device *dev)
213 {
214 
215 	bool		rt_status = true;
216 	int		check_time = 200000;
217 	u32		CPU_status = 0;
218 
219 	/* Check Firmware Ready */
220 	do {
221 		CPU_status = read_nic_dword(dev, CPU_GEN);
222 
223 		if(CPU_status&CPU_GEN_FIRM_RDY)
224 			break;
225 
226 	}while(check_time--);
227 
228 	if(!(CPU_status&CPU_GEN_FIRM_RDY))
229 		goto CPUCheckFirmwareReady_Fail;
230 	else
231 		RT_TRACE(COMP_FIRMWARE, "Download Firmware: Firmware ready!\n");
232 
233 	return rt_status;
234 
235 CPUCheckFirmwareReady_Fail:
236 	RT_TRACE(COMP_ERR, "ERR in %s()\n", __FUNCTION__);
237 	rt_status = false;
238 	return rt_status;
239 
240 }
241 
init_firmware(struct net_device * dev)242 bool init_firmware(struct net_device *dev)
243 {
244 	struct r8192_priv	*priv = ieee80211_priv(dev);
245 	bool			rt_status = TRUE;
246 
247 	u32			file_length = 0;
248 	u8			*mapped_file = NULL;
249 	u32			init_step = 0;
250 	opt_rst_type_e	rst_opt = OPT_SYSTEM_RESET;
251 	firmware_init_step_e	starting_state = FW_INIT_STEP0_BOOT;
252 
253 	rt_firmware		*pfirmware = priv->pFirmware;
254 	const struct firmware	*fw_entry;
255 	const char *fw_name[3] = { "RTL8192U/boot.img",
256 			   "RTL8192U/main.img",
257 			   "RTL8192U/data.img"};
258 	int rc;
259 
260 	RT_TRACE(COMP_FIRMWARE, " PlatformInitFirmware()==>\n");
261 
262 	if (pfirmware->firmware_status == FW_STATUS_0_INIT ) {
263 		/* it is called by reset */
264 		rst_opt = OPT_SYSTEM_RESET;
265 		starting_state = FW_INIT_STEP0_BOOT;
266 		// TODO: system reset
267 
268 	}else if(pfirmware->firmware_status == FW_STATUS_5_READY) {
269 		/* it is called by Initialize */
270 		rst_opt = OPT_FIRMWARE_RESET;
271 		starting_state = FW_INIT_STEP2_DATA;
272 	}else {
273 		 RT_TRACE(COMP_FIRMWARE, "PlatformInitFirmware: undefined firmware state\n");
274 	}
275 
276 	/*
277 	 * Download boot, main, and data image for System reset.
278 	 * Download data image for firmware reset
279 	 */
280 	for(init_step = starting_state; init_step <= FW_INIT_STEP2_DATA; init_step++) {
281 		/*
282 		 * Open image file, and map file to continuous memory if open file success.
283 		 * or read image file from array. Default load from IMG file
284 		 */
285 		if(rst_opt == OPT_SYSTEM_RESET) {
286 			rc = request_firmware(&fw_entry, fw_name[init_step],&priv->udev->dev);
287 			if(rc < 0 ) {
288 				RT_TRACE(COMP_ERR, "request firmware fail!\n");
289 				goto download_firmware_fail;
290 			}
291 
292 			if(fw_entry->size > sizeof(pfirmware->firmware_buf)) {
293 				RT_TRACE(COMP_ERR, "img file size exceed the container buffer fail!\n");
294 				goto download_firmware_fail;
295 			}
296 
297 			if(init_step != FW_INIT_STEP1_MAIN) {
298 				memcpy(pfirmware->firmware_buf,fw_entry->data,fw_entry->size);
299 				mapped_file = pfirmware->firmware_buf;
300 				file_length = fw_entry->size;
301 			} else {
302 #ifdef RTL8190P
303 				memcpy(pfirmware->firmware_buf,fw_entry->data,fw_entry->size);
304 				mapped_file = pfirmware->firmware_buf;
305 				file_length = fw_entry->size;
306 #else
307 				memset(pfirmware->firmware_buf,0,128);
308 				memcpy(&pfirmware->firmware_buf[128],fw_entry->data,fw_entry->size);
309 				mapped_file = pfirmware->firmware_buf;
310 				file_length = fw_entry->size + 128;
311 #endif
312 			}
313 			pfirmware->firmware_buf_size = file_length;
314 		}else if(rst_opt == OPT_FIRMWARE_RESET ) {
315 			/* we only need to download data.img here */
316 			mapped_file = pfirmware->firmware_buf;
317 			file_length = pfirmware->firmware_buf_size;
318 		}
319 
320 		/* Download image file */
321 		/* The firmware download process is just as following,
322 		 * 1. that is each packet will be segmented and inserted to the wait queue.
323 		 * 2. each packet segment will be put in the skb_buff packet.
324 		 * 3. each skb_buff packet data content will already include the firmware info
325 		 *   and Tx descriptor info
326 		 * */
327 		rt_status = fw_download_code(dev,mapped_file,file_length);
328 		if(rst_opt == OPT_SYSTEM_RESET) {
329 			release_firmware(fw_entry);
330 		}
331 
332 		if(rt_status != TRUE) {
333 			goto download_firmware_fail;
334 		}
335 
336 		switch(init_step) {
337 		case FW_INIT_STEP0_BOOT:
338 			/* Download boot
339 			 * initialize command descriptor.
340 			 * will set polling bit when firmware code is also configured
341 			 */
342 			pfirmware->firmware_status = FW_STATUS_1_MOVE_BOOT_CODE;
343 #ifdef RTL8190P
344 			// To initialize IMEM, CPU move code  from 0x80000080, hence, we send 0x80 byte packet
345 			rt_status = fwSendNullPacket(dev, RTL8190_CPU_START_OFFSET);
346 			if(rt_status != true)
347 			{
348 				RT_TRACE(COMP_INIT, "fwSendNullPacket() fail ! \n");
349 				goto  download_firmware_fail;
350 			}
351 #endif
352 			//mdelay(1000);
353 			/*
354 			 * To initialize IMEM, CPU move code  from 0x80000080,
355 			 * hence, we send 0x80 byte packet
356 			 */
357 			break;
358 
359 		case FW_INIT_STEP1_MAIN:
360 			/* Download firmware code. Wait until Boot Ready and Turn on CPU */
361 			pfirmware->firmware_status = FW_STATUS_2_MOVE_MAIN_CODE;
362 
363 			/* Check Put Code OK and Turn On CPU */
364 			rt_status = CPUcheck_maincodeok_turnonCPU(dev);
365 			if(rt_status != TRUE) {
366 				RT_TRACE(COMP_ERR, "CPUcheck_maincodeok_turnonCPU fail!\n");
367 				goto download_firmware_fail;
368 			}
369 
370 			pfirmware->firmware_status = FW_STATUS_3_TURNON_CPU;
371 			break;
372 
373 		case FW_INIT_STEP2_DATA:
374 			/* download initial data code */
375 			pfirmware->firmware_status = FW_STATUS_4_MOVE_DATA_CODE;
376 			mdelay(1);
377 
378 			rt_status = CPUcheck_firmware_ready(dev);
379 			if(rt_status != TRUE) {
380 				RT_TRACE(COMP_ERR, "CPUcheck_firmware_ready fail(%d)!\n",rt_status);
381 				goto download_firmware_fail;
382 			}
383 
384 			/* wait until data code is initialized ready.*/
385 			pfirmware->firmware_status = FW_STATUS_5_READY;
386 			break;
387 		}
388 	}
389 
390 	RT_TRACE(COMP_FIRMWARE, "Firmware Download Success\n");
391 	//assert(pfirmware->firmware_status == FW_STATUS_5_READY, ("Firmware Download Fail\n"));
392 
393 	return rt_status;
394 
395 download_firmware_fail:
396 	RT_TRACE(COMP_ERR, "ERR in %s()\n", __FUNCTION__);
397 	rt_status = FALSE;
398 	return rt_status;
399 
400 }
401 
402 MODULE_FIRMWARE("RTL8192U/boot.img");
403 MODULE_FIRMWARE("RTL8192U/main.img");
404 MODULE_FIRMWARE("RTL8192U/data.img");
405