blob: 04b8f5ec67e92e012d1bf40e7baff75c4a9f5830 [file] [log] [blame]
Jerry Chuang8fc85982009-11-03 07:17:11 -02001/**************************************************************************************************
2 * Procedure: Init boot code/firmware code/data session
3 *
Uwe Kleine-König9b0131c2010-09-01 15:40:25 +02004 * Description: This routine will initialize firmware. If any error occurs during the initialization
Sebastian Hahn35997ff2012-12-05 21:40:18 +01005 * process, the routine shall terminate immediately and return fail.
Jerry Chuang8fc85982009-11-03 07:17:11 -02006 * 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**************************************************************************************************/
Dave Jones2addf792010-07-02 23:04:44 -040014
Jerry Chuang8fc85982009-11-03 07:17:11 -020015#include "r8192U.h"
16#include "r8192U_hw.h"
17#include "r819xU_firmware_img.h"
18#include "r819xU_firmware.h"
Jerry Chuang8fc85982009-11-03 07:17:11 -020019#include <linux/firmware.h>
Ana Rey2cc817c2014-03-19 12:47:24 +010020
21static void firmware_init_param(struct net_device *dev)
Jerry Chuang8fc85982009-11-03 07:17:11 -020022{
Sebastian Hahn35997ff2012-12-05 21:40:18 +010023 struct r8192_priv *priv = ieee80211_priv(dev);
Jerry Chuang8fc85982009-11-03 07:17:11 -020024 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 */
Ana Rey2cc817c2014-03-19 12:47:24 +010033static bool fw_download_code(struct net_device *dev, u8 *code_virtual_address,
34 u32 buffer_len)
Jerry Chuang8fc85982009-11-03 07:17:11 -020035{
36 struct r8192_priv *priv = ieee80211_priv(dev);
Sebastian Hahn35997ff2012-12-05 21:40:18 +010037 bool rt_status = true;
Jerry Chuang8fc85982009-11-03 07:17:11 -020038 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 {
Xenia Ragiadakou14bc0d42013-05-13 20:15:56 +030053 if ((buffer_len - frag_offset) > frag_threshold) {
Jerry Chuang8fc85982009-11-03 07:17:11 -020054 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 * */
Jerry Chuang8fc85982009-11-03 07:17:11 -020066 skb = dev_alloc_skb(USB_HWDESC_HEADER_LEN + frag_length + 4);
Xenia Ragiadakouf8518ef2013-09-21 23:42:26 +030067 if (!skb)
68 return false;
Jerry Chuang8fc85982009-11-03 07:17:11 -020069 memcpy((unsigned char *)(skb->cb),&dev,sizeof(dev));
Xenia Ragiadakou12fbccb2013-05-11 17:22:21 +030070 tcb_desc = (cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE);
Jerry Chuang8fc85982009-11-03 07:17:11 -020071 tcb_desc->queue_index = TXCMD_QUEUE;
72 tcb_desc->bCmdOrInit = DESC_PACKET_TYPE_INIT;
73 tcb_desc->bLastIniPkt = bLastIniPkt;
74
Jerry Chuang8fc85982009-11-03 07:17:11 -020075 skb_reserve(skb, USB_HWDESC_HEADER_LEN);
Jerry Chuang8fc85982009-11-03 07:17:11 -020076 seg_ptr = skb->data;
77 /*
78 * Transform from little endian to big endian
Mauro Carvalho Chehabe4063222009-11-03 07:42:46 -020079 * and pending zero
Jerry Chuang8fc85982009-11-03 07:17:11 -020080 */
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
Xenia Ragiadakou14bc0d42013-05-13 20:15:56 +030090 if (!priv->ieee80211->check_nic_enough_desc(dev,tcb_desc->queue_index)||
Jerry Chuang8fc85982009-11-03 07:17:11 -020091 (!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 {
96 priv->ieee80211->softmac_hard_start_xmit(skb,dev);
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
Jerry Chuang8fc85982009-11-03 07:17:11 -0200106}
107
Jerry Chuang8fc85982009-11-03 07:17:11 -0200108//-----------------------------------------------------------------------------
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//-----------------------------------------------------------------------------
Ana Rey2cc817c2014-03-19 12:47:24 +0100121static bool CPUcheck_maincodeok_turnonCPU(struct net_device *dev)
Jerry Chuang8fc85982009-11-03 07:17:11 -0200122{
123 bool rt_status = true;
124 int check_putcodeOK_time = 200000, check_bootOk_time = 200000;
Mauro Carvalho Chehabe4063222009-11-03 07:42:46 -0200125 u32 CPU_status = 0;
Jerry Chuang8fc85982009-11-03 07:17:11 -0200126
127 /* Check whether put code OK */
128 do {
Xenia Ragiadakoub3d42bf2013-06-06 16:40:51 +0300129 read_nic_dword(dev, CPU_GEN, &CPU_status);
Jerry Chuang8fc85982009-11-03 07:17:11 -0200130
Xenia Ragiadakou14bc0d42013-05-13 20:15:56 +0300131 if (CPU_status&CPU_GEN_PUT_CODE_OK)
Jerry Chuang8fc85982009-11-03 07:17:11 -0200132 break;
133
134 }while(check_putcodeOK_time--);
135
Xenia Ragiadakou14bc0d42013-05-13 20:15:56 +0300136 if (!(CPU_status&CPU_GEN_PUT_CODE_OK)) {
Jerry Chuang8fc85982009-11-03 07:17:11 -0200137 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 */
Xenia Ragiadakoub3d42bf2013-06-06 16:40:51 +0300144 read_nic_dword(dev, CPU_GEN, &CPU_status);
Jerry Chuang8fc85982009-11-03 07:17:11 -0200145 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 {
Xenia Ragiadakoub3d42bf2013-06-06 16:40:51 +0300150 read_nic_dword(dev, CPU_GEN, &CPU_status);
Jerry Chuang8fc85982009-11-03 07:17:11 -0200151
Xenia Ragiadakou14bc0d42013-05-13 20:15:56 +0300152 if (CPU_status&CPU_GEN_BOOT_RDY)
Jerry Chuang8fc85982009-11-03 07:17:11 -0200153 break;
154 }while(check_bootOk_time--);
155
Xenia Ragiadakou14bc0d42013-05-13 20:15:56 +0300156 if (!(CPU_status&CPU_GEN_BOOT_RDY)) {
Jerry Chuang8fc85982009-11-03 07:17:11 -0200157 goto CPUCheckMainCodeOKAndTurnOnCPU_Fail;
158 } else {
159 RT_TRACE(COMP_FIRMWARE, "Download Firmware: Boot ready!\n");
160 }
161
162 return rt_status;
163
164CPUCheckMainCodeOKAndTurnOnCPU_Fail:
Joe Perchesf8628a42014-05-23 22:13:20 -0700165 RT_TRACE(COMP_ERR, "ERR in %s()\n", __func__);
Jerry Chuang8fc85982009-11-03 07:17:11 -0200166 rt_status = FALSE;
167 return rt_status;
168}
169
Ana Rey2cc817c2014-03-19 12:47:24 +0100170static bool CPUcheck_firmware_ready(struct net_device *dev)
Jerry Chuang8fc85982009-11-03 07:17:11 -0200171{
172
173 bool rt_status = true;
174 int check_time = 200000;
175 u32 CPU_status = 0;
176
177 /* Check Firmware Ready */
178 do {
Xenia Ragiadakoub3d42bf2013-06-06 16:40:51 +0300179 read_nic_dword(dev, CPU_GEN, &CPU_status);
Jerry Chuang8fc85982009-11-03 07:17:11 -0200180
Xenia Ragiadakou14bc0d42013-05-13 20:15:56 +0300181 if (CPU_status&CPU_GEN_FIRM_RDY)
Jerry Chuang8fc85982009-11-03 07:17:11 -0200182 break;
183
184 }while(check_time--);
185
Xenia Ragiadakou14bc0d42013-05-13 20:15:56 +0300186 if (!(CPU_status&CPU_GEN_FIRM_RDY))
Jerry Chuang8fc85982009-11-03 07:17:11 -0200187 goto CPUCheckFirmwareReady_Fail;
188 else
189 RT_TRACE(COMP_FIRMWARE, "Download Firmware: Firmware ready!\n");
190
191 return rt_status;
192
193CPUCheckFirmwareReady_Fail:
Joe Perchesf8628a42014-05-23 22:13:20 -0700194 RT_TRACE(COMP_ERR, "ERR in %s()\n", __func__);
Jerry Chuang8fc85982009-11-03 07:17:11 -0200195 rt_status = false;
196 return rt_status;
197
198}
199
200bool init_firmware(struct net_device *dev)
201{
Sebastian Hahn35997ff2012-12-05 21:40:18 +0100202 struct r8192_priv *priv = ieee80211_priv(dev);
Jerry Chuang8fc85982009-11-03 07:17:11 -0200203 bool rt_status = TRUE;
204
Jerry Chuang8fc85982009-11-03 07:17:11 -0200205 u32 file_length = 0;
206 u8 *mapped_file = NULL;
207 u32 init_step = 0;
208 opt_rst_type_e rst_opt = OPT_SYSTEM_RESET;
Sebastian Hahn35997ff2012-12-05 21:40:18 +0100209 firmware_init_step_e starting_state = FW_INIT_STEP0_BOOT;
Jerry Chuang8fc85982009-11-03 07:17:11 -0200210
211 rt_firmware *pfirmware = priv->pFirmware;
Sebastian Hahn35997ff2012-12-05 21:40:18 +0100212 const struct firmware *fw_entry;
Jerry Chuang8fc85982009-11-03 07:17:11 -0200213 const char *fw_name[3] = { "RTL8192U/boot.img",
Mauro Carvalho Chehabe4063222009-11-03 07:42:46 -0200214 "RTL8192U/main.img",
Jerry Chuang8fc85982009-11-03 07:17:11 -0200215 "RTL8192U/data.img"};
216 int rc;
217
218 RT_TRACE(COMP_FIRMWARE, " PlatformInitFirmware()==>\n");
219
220 if (pfirmware->firmware_status == FW_STATUS_0_INIT ) {
221 /* it is called by reset */
222 rst_opt = OPT_SYSTEM_RESET;
223 starting_state = FW_INIT_STEP0_BOOT;
224 // TODO: system reset
225
Xenia Ragiadakou14bc0d42013-05-13 20:15:56 +0300226 }else if (pfirmware->firmware_status == FW_STATUS_5_READY) {
Jerry Chuang8fc85982009-11-03 07:17:11 -0200227 /* it is called by Initialize */
228 rst_opt = OPT_FIRMWARE_RESET;
229 starting_state = FW_INIT_STEP2_DATA;
230 }else {
231 RT_TRACE(COMP_FIRMWARE, "PlatformInitFirmware: undefined firmware state\n");
232 }
233
234 /*
235 * Download boot, main, and data image for System reset.
Justin P. Mattock589b3d02012-04-30 07:41:36 -0700236 * Download data image for firmware reset
Jerry Chuang8fc85982009-11-03 07:17:11 -0200237 */
Jerry Chuang8fc85982009-11-03 07:17:11 -0200238 for(init_step = starting_state; init_step <= FW_INIT_STEP2_DATA; init_step++) {
239 /*
Justin P. Mattock8ef3a7e2012-04-30 14:39:21 -0700240 * Open image file, and map file to continuous memory if open file success.
Jerry Chuang8fc85982009-11-03 07:17:11 -0200241 * or read image file from array. Default load from IMG file
242 */
Xenia Ragiadakou14bc0d42013-05-13 20:15:56 +0300243 if (rst_opt == OPT_SYSTEM_RESET) {
Ben Hutchings0a8692b2011-01-09 04:20:04 +0000244 rc = request_firmware(&fw_entry, fw_name[init_step],&priv->udev->dev);
Xenia Ragiadakou14bc0d42013-05-13 20:15:56 +0300245 if (rc < 0 ) {
Ben Hutchings0a8692b2011-01-09 04:20:04 +0000246 RT_TRACE(COMP_ERR, "request firmware fail!\n");
247 goto download_firmware_fail;
Jerry Chuang8fc85982009-11-03 07:17:11 -0200248 }
249
Xenia Ragiadakou14bc0d42013-05-13 20:15:56 +0300250 if (fw_entry->size > sizeof(pfirmware->firmware_buf)) {
Ben Hutchings0a8692b2011-01-09 04:20:04 +0000251 RT_TRACE(COMP_ERR, "img file size exceed the container buffer fail!\n");
252 goto download_firmware_fail;
253 }
Jerry Chuang8fc85982009-11-03 07:17:11 -0200254
Xenia Ragiadakou14bc0d42013-05-13 20:15:56 +0300255 if (init_step != FW_INIT_STEP1_MAIN) {
Ben Hutchings0a8692b2011-01-09 04:20:04 +0000256 memcpy(pfirmware->firmware_buf,fw_entry->data,fw_entry->size);
257 mapped_file = pfirmware->firmware_buf;
258 file_length = fw_entry->size;
259 } else {
Ben Hutchings0a8692b2011-01-09 04:20:04 +0000260 memset(pfirmware->firmware_buf,0,128);
261 memcpy(&pfirmware->firmware_buf[128],fw_entry->data,fw_entry->size);
262 mapped_file = pfirmware->firmware_buf;
263 file_length = fw_entry->size + 128;
Ben Hutchings0a8692b2011-01-09 04:20:04 +0000264 }
265 pfirmware->firmware_buf_size = file_length;
Xenia Ragiadakou14bc0d42013-05-13 20:15:56 +0300266 }else if (rst_opt == OPT_FIRMWARE_RESET ) {
Jerry Chuang8fc85982009-11-03 07:17:11 -0200267 /* we only need to download data.img here */
268 mapped_file = pfirmware->firmware_buf;
269 file_length = pfirmware->firmware_buf_size;
270 }
271
272 /* Download image file */
273 /* The firmware download process is just as following,
274 * 1. that is each packet will be segmented and inserted to the wait queue.
275 * 2. each packet segment will be put in the skb_buff packet.
276 * 3. each skb_buff packet data content will already include the firmware info
277 * and Tx descriptor info
278 * */
279 rt_status = fw_download_code(dev,mapped_file,file_length);
Rui Miguel Silva2930d0b92014-04-28 12:12:54 +0100280 if (rst_opt == OPT_SYSTEM_RESET)
Jerry Chuang8fc85982009-11-03 07:17:11 -0200281 release_firmware(fw_entry);
Jerry Chuang8fc85982009-11-03 07:17:11 -0200282
Rui Miguel Silva2930d0b92014-04-28 12:12:54 +0100283 if (rt_status != TRUE)
Jerry Chuang8fc85982009-11-03 07:17:11 -0200284 goto download_firmware_fail;
Jerry Chuang8fc85982009-11-03 07:17:11 -0200285
Xenia Ragiadakouad638452013-05-12 03:15:08 +0300286 switch (init_step) {
Sebastian Hahn24fbe872012-12-05 21:40:22 +0100287 case FW_INIT_STEP0_BOOT:
288 /* Download boot
289 * initialize command descriptor.
290 * will set polling bit when firmware code is also configured
291 */
292 pfirmware->firmware_status = FW_STATUS_1_MOVE_BOOT_CODE;
Sebastian Hahn24fbe872012-12-05 21:40:22 +0100293 //mdelay(1000);
294 /*
295 * To initialize IMEM, CPU move code from 0x80000080,
296 * hence, we send 0x80 byte packet
297 */
298 break;
Jerry Chuang8fc85982009-11-03 07:17:11 -0200299
Sebastian Hahn24fbe872012-12-05 21:40:22 +0100300 case FW_INIT_STEP1_MAIN:
301 /* Download firmware code. Wait until Boot Ready and Turn on CPU */
302 pfirmware->firmware_status = FW_STATUS_2_MOVE_MAIN_CODE;
Jerry Chuang8fc85982009-11-03 07:17:11 -0200303
Sebastian Hahn24fbe872012-12-05 21:40:22 +0100304 /* Check Put Code OK and Turn On CPU */
305 rt_status = CPUcheck_maincodeok_turnonCPU(dev);
Xenia Ragiadakou14bc0d42013-05-13 20:15:56 +0300306 if (rt_status != TRUE) {
Sebastian Hahn24fbe872012-12-05 21:40:22 +0100307 RT_TRACE(COMP_ERR, "CPUcheck_maincodeok_turnonCPU fail!\n");
308 goto download_firmware_fail;
309 }
Jerry Chuang8fc85982009-11-03 07:17:11 -0200310
Sebastian Hahn24fbe872012-12-05 21:40:22 +0100311 pfirmware->firmware_status = FW_STATUS_3_TURNON_CPU;
312 break;
Jerry Chuang8fc85982009-11-03 07:17:11 -0200313
Sebastian Hahn24fbe872012-12-05 21:40:22 +0100314 case FW_INIT_STEP2_DATA:
315 /* download initial data code */
316 pfirmware->firmware_status = FW_STATUS_4_MOVE_DATA_CODE;
317 mdelay(1);
Jerry Chuang8fc85982009-11-03 07:17:11 -0200318
Sebastian Hahn24fbe872012-12-05 21:40:22 +0100319 rt_status = CPUcheck_firmware_ready(dev);
Xenia Ragiadakou14bc0d42013-05-13 20:15:56 +0300320 if (rt_status != TRUE) {
Sebastian Hahn24fbe872012-12-05 21:40:22 +0100321 RT_TRACE(COMP_ERR, "CPUcheck_firmware_ready fail(%d)!\n",rt_status);
322 goto download_firmware_fail;
323 }
Jerry Chuang8fc85982009-11-03 07:17:11 -0200324
Sebastian Hahn24fbe872012-12-05 21:40:22 +0100325 /* wait until data code is initialized ready.*/
326 pfirmware->firmware_status = FW_STATUS_5_READY;
327 break;
Jerry Chuang8fc85982009-11-03 07:17:11 -0200328 }
329 }
330
331 RT_TRACE(COMP_FIRMWARE, "Firmware Download Success\n");
332 //assert(pfirmware->firmware_status == FW_STATUS_5_READY, ("Firmware Download Fail\n"));
333
334 return rt_status;
335
336download_firmware_fail:
Joe Perchesf8628a42014-05-23 22:13:20 -0700337 RT_TRACE(COMP_ERR, "ERR in %s()\n", __func__);
Jerry Chuang8fc85982009-11-03 07:17:11 -0200338 rt_status = FALSE;
339 return rt_status;
340
341}
342
Stefan Lippers-Hollmann589c3ca2011-08-02 22:17:25 +0200343MODULE_FIRMWARE("RTL8192U/boot.img");
344MODULE_FIRMWARE("RTL8192U/main.img");
345MODULE_FIRMWARE("RTL8192U/data.img");