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