Commit | Line | Data |
---|---|---|
8fc8598e JC |
1 | /************************************************************************************************** |
2 | * Procedure: Init boot code/firmware code/data session | |
3 | * | |
9b0131cb | 4 | * Description: This routine will initialize firmware. If any error occurs during the initialization |
8fc8598e JC |
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 | **************************************************************************************************/ | |
2addf798 | 14 | |
8fc8598e JC |
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 | ||
8fc8598e JC |
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", | |
e406322b | 256 | "RTL8192U/main.img", |
8fc8598e JC |
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 reseta | |
279 | */ | |
8fc8598e JC |
280 | for(init_step = starting_state; init_step <= FW_INIT_STEP2_DATA; init_step++) { |
281 | /* | |
282 | * Open Image file, and map file to contineous 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) { | |
0a8692b5 BH |
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; | |
8fc8598e JC |
290 | } |
291 | ||
0a8692b5 BH |
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 | } | |
8fc8598e | 296 | |
0a8692b5 BH |
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; | |
8fc8598e JC |
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); | |
8fc8598e JC |
328 | if(rst_opt == OPT_SYSTEM_RESET) { |
329 | release_firmware(fw_entry); | |
330 | } | |
8fc8598e JC |
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 | ||
8fc8598e | 402 | |
8fc8598e | 403 | |
8fc8598e JC |
404 | |
405 | ||
8fc8598e | 406 | |
8fc8598e JC |
407 | |
408 |