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