]> git.ipfire.org Git - thirdparty/kernel/linux.git/blame - drivers/staging/rtl8192u/r819xU_firmware.c
License cleanup: add SPDX GPL-2.0 license identifier to files with no license
[thirdparty/kernel/linux.git] / drivers / staging / rtl8192u / r819xU_firmware.c
CommitLineData
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
22static 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
34static 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 124static 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
167CPUCheckMainCodeOKAndTurnOnCPU_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 173static 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
196CPUCheckFirmwareReady_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
203bool 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
337download_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
344MODULE_FIRMWARE("RTL8192U/boot.img");
345MODULE_FIRMWARE("RTL8192U/main.img");
346MODULE_FIRMWARE("RTL8192U/data.img");