Commit | Line | Data |
---|---|---|
8fc8598e JC |
1 | /************************************************************************************************** |
2 | * Procedure: Init boot code/firmware code/data session | |
3 | * | |
4 | * Description: This routine will intialize 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 | //#include "ieee80211.h" | |
15 | #include "r8192U.h" | |
16 | #include "r8192U_hw.h" | |
17 | #include "r819xU_firmware_img.h" | |
18 | #include "r819xU_firmware.h" | |
8fc8598e | 19 | #include <linux/firmware.h> |
8fc8598e JC |
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 | */ | |
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 | |
e406322b | 81 | * and pending zero |
8fc8598e JC |
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 | ||
8fc8598e JC |
108 | } |
109 | ||
110 | bool | |
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 | ||
8fc8598e JC |
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 | //----------------------------------------------------------------------------- | |
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; | |
e406322b | 167 | u32 CPU_status = 0; |
8fc8598e JC |
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 | ||
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 | ||
242 | bool init_firmware(struct net_device *dev) | |
243 | { | |
244 | struct r8192_priv *priv = ieee80211_priv(dev); | |
245 | bool rt_status = TRUE; | |
246 | ||
247 | u8 *firmware_img_buf[3] = { &rtl8190_fwboot_array[0], | |
e406322b MCC |
248 | &rtl8190_fwmain_array[0], |
249 | &rtl8190_fwdata_array[0]}; | |
8fc8598e JC |
250 | |
251 | u32 firmware_img_len[3] = { sizeof(rtl8190_fwboot_array), | |
e406322b MCC |
252 | sizeof(rtl8190_fwmain_array), |
253 | sizeof(rtl8190_fwdata_array)}; | |
8fc8598e JC |
254 | u32 file_length = 0; |
255 | u8 *mapped_file = NULL; | |
256 | u32 init_step = 0; | |
257 | opt_rst_type_e rst_opt = OPT_SYSTEM_RESET; | |
258 | firmware_init_step_e starting_state = FW_INIT_STEP0_BOOT; | |
259 | ||
260 | rt_firmware *pfirmware = priv->pFirmware; | |
261 | const struct firmware *fw_entry; | |
262 | const char *fw_name[3] = { "RTL8192U/boot.img", | |
e406322b | 263 | "RTL8192U/main.img", |
8fc8598e JC |
264 | "RTL8192U/data.img"}; |
265 | int rc; | |
266 | ||
267 | RT_TRACE(COMP_FIRMWARE, " PlatformInitFirmware()==>\n"); | |
268 | ||
269 | if (pfirmware->firmware_status == FW_STATUS_0_INIT ) { | |
270 | /* it is called by reset */ | |
271 | rst_opt = OPT_SYSTEM_RESET; | |
272 | starting_state = FW_INIT_STEP0_BOOT; | |
273 | // TODO: system reset | |
274 | ||
275 | }else if(pfirmware->firmware_status == FW_STATUS_5_READY) { | |
276 | /* it is called by Initialize */ | |
277 | rst_opt = OPT_FIRMWARE_RESET; | |
278 | starting_state = FW_INIT_STEP2_DATA; | |
279 | }else { | |
280 | RT_TRACE(COMP_FIRMWARE, "PlatformInitFirmware: undefined firmware state\n"); | |
281 | } | |
282 | ||
283 | /* | |
284 | * Download boot, main, and data image for System reset. | |
285 | * Download data image for firmware reseta | |
286 | */ | |
8fc8598e | 287 | priv->firmware_source = FW_SOURCE_IMG_FILE; |
8fc8598e JC |
288 | for(init_step = starting_state; init_step <= FW_INIT_STEP2_DATA; init_step++) { |
289 | /* | |
290 | * Open Image file, and map file to contineous memory if open file success. | |
291 | * or read image file from array. Default load from IMG file | |
292 | */ | |
293 | if(rst_opt == OPT_SYSTEM_RESET) { | |
294 | switch(priv->firmware_source) { | |
295 | case FW_SOURCE_IMG_FILE: | |
8fc8598e JC |
296 | rc = request_firmware(&fw_entry, fw_name[init_step],&priv->udev->dev); |
297 | if(rc < 0 ) { | |
298 | RT_TRACE(COMP_ERR, "request firmware fail!\n"); | |
299 | goto download_firmware_fail; | |
300 | } | |
301 | ||
302 | if(fw_entry->size > sizeof(pfirmware->firmware_buf)) { | |
303 | RT_TRACE(COMP_ERR, "img file size exceed the container buffer fail!\n"); | |
304 | goto download_firmware_fail; | |
305 | } | |
306 | ||
307 | if(init_step != FW_INIT_STEP1_MAIN) { | |
308 | memcpy(pfirmware->firmware_buf,fw_entry->data,fw_entry->size); | |
309 | mapped_file = pfirmware->firmware_buf; | |
310 | file_length = fw_entry->size; | |
311 | } else { | |
312 | #ifdef RTL8190P | |
313 | memcpy(pfirmware->firmware_buf,fw_entry->data,fw_entry->size); | |
314 | mapped_file = pfirmware->firmware_buf; | |
315 | file_length = fw_entry->size; | |
316 | #else | |
317 | memset(pfirmware->firmware_buf,0,128); | |
318 | memcpy(&pfirmware->firmware_buf[128],fw_entry->data,fw_entry->size); | |
319 | mapped_file = pfirmware->firmware_buf; | |
320 | file_length = fw_entry->size + 128; | |
321 | #endif | |
322 | } | |
323 | pfirmware->firmware_buf_size = file_length; | |
8fc8598e JC |
324 | break; |
325 | ||
326 | case FW_SOURCE_HEADER_FILE: | |
327 | mapped_file = firmware_img_buf[init_step]; | |
328 | file_length = firmware_img_len[init_step]; | |
329 | if(init_step == FW_INIT_STEP2_DATA) { | |
330 | memcpy(pfirmware->firmware_buf, mapped_file, file_length); | |
331 | pfirmware->firmware_buf_size = file_length; | |
332 | } | |
333 | break; | |
334 | ||
335 | default: | |
336 | break; | |
337 | } | |
338 | ||
339 | ||
340 | }else if(rst_opt == OPT_FIRMWARE_RESET ) { | |
341 | /* we only need to download data.img here */ | |
342 | mapped_file = pfirmware->firmware_buf; | |
343 | file_length = pfirmware->firmware_buf_size; | |
344 | } | |
345 | ||
346 | /* Download image file */ | |
347 | /* The firmware download process is just as following, | |
348 | * 1. that is each packet will be segmented and inserted to the wait queue. | |
349 | * 2. each packet segment will be put in the skb_buff packet. | |
350 | * 3. each skb_buff packet data content will already include the firmware info | |
351 | * and Tx descriptor info | |
352 | * */ | |
353 | rt_status = fw_download_code(dev,mapped_file,file_length); | |
8fc8598e JC |
354 | if(rst_opt == OPT_SYSTEM_RESET) { |
355 | release_firmware(fw_entry); | |
356 | } | |
8fc8598e JC |
357 | |
358 | if(rt_status != TRUE) { | |
359 | goto download_firmware_fail; | |
360 | } | |
361 | ||
362 | switch(init_step) { | |
363 | case FW_INIT_STEP0_BOOT: | |
364 | /* Download boot | |
365 | * initialize command descriptor. | |
366 | * will set polling bit when firmware code is also configured | |
367 | */ | |
368 | pfirmware->firmware_status = FW_STATUS_1_MOVE_BOOT_CODE; | |
369 | #ifdef RTL8190P | |
370 | // To initialize IMEM, CPU move code from 0x80000080, hence, we send 0x80 byte packet | |
371 | rt_status = fwSendNullPacket(dev, RTL8190_CPU_START_OFFSET); | |
372 | if(rt_status != true) | |
373 | { | |
374 | RT_TRACE(COMP_INIT, "fwSendNullPacket() fail ! \n"); | |
375 | goto download_firmware_fail; | |
376 | } | |
377 | #endif | |
378 | //mdelay(1000); | |
379 | /* | |
380 | * To initialize IMEM, CPU move code from 0x80000080, | |
381 | * hence, we send 0x80 byte packet | |
382 | */ | |
383 | break; | |
384 | ||
385 | case FW_INIT_STEP1_MAIN: | |
386 | /* Download firmware code. Wait until Boot Ready and Turn on CPU */ | |
387 | pfirmware->firmware_status = FW_STATUS_2_MOVE_MAIN_CODE; | |
388 | ||
389 | /* Check Put Code OK and Turn On CPU */ | |
390 | rt_status = CPUcheck_maincodeok_turnonCPU(dev); | |
391 | if(rt_status != TRUE) { | |
392 | RT_TRACE(COMP_ERR, "CPUcheck_maincodeok_turnonCPU fail!\n"); | |
393 | goto download_firmware_fail; | |
394 | } | |
395 | ||
396 | pfirmware->firmware_status = FW_STATUS_3_TURNON_CPU; | |
397 | break; | |
398 | ||
399 | case FW_INIT_STEP2_DATA: | |
400 | /* download initial data code */ | |
401 | pfirmware->firmware_status = FW_STATUS_4_MOVE_DATA_CODE; | |
402 | mdelay(1); | |
403 | ||
404 | rt_status = CPUcheck_firmware_ready(dev); | |
405 | if(rt_status != TRUE) { | |
406 | RT_TRACE(COMP_ERR, "CPUcheck_firmware_ready fail(%d)!\n",rt_status); | |
407 | goto download_firmware_fail; | |
408 | } | |
409 | ||
410 | /* wait until data code is initialized ready.*/ | |
411 | pfirmware->firmware_status = FW_STATUS_5_READY; | |
412 | break; | |
413 | } | |
414 | } | |
415 | ||
416 | RT_TRACE(COMP_FIRMWARE, "Firmware Download Success\n"); | |
417 | //assert(pfirmware->firmware_status == FW_STATUS_5_READY, ("Firmware Download Fail\n")); | |
418 | ||
419 | return rt_status; | |
420 | ||
421 | download_firmware_fail: | |
422 | RT_TRACE(COMP_ERR, "ERR in %s()\n", __FUNCTION__); | |
423 | rt_status = FALSE; | |
424 | return rt_status; | |
425 | ||
426 | } | |
427 | ||
8fc8598e | 428 | |
8fc8598e | 429 | |
8fc8598e JC |
430 | |
431 | ||
8fc8598e | 432 | |
8fc8598e JC |
433 | |
434 |