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