1/************************************************************************************************** 2 * Procedure: Init boot code/firmware code/data session 3 * 4 * Description: This routine will initialize firmware. If any error occurs during the initialization 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**************************************************************************************************/ 14 15#include "r8192U.h" 16#include "r8192U_hw.h" 17#include "r819xU_firmware_img.h" 18#include "r819xU_firmware.h" 19#include <linux/firmware.h> 20void 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 */ 32bool 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 81 * and pending zero 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 108} 109 110bool 111fwSendNullPacket( 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 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//----------------------------------------------------------------------------- 163bool CPUcheck_maincodeok_turnonCPU(struct net_device *dev) 164{ 165 bool rt_status = true; 166 int check_putcodeOK_time = 200000, check_bootOk_time = 200000; 167 u32 CPU_status = 0; 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 206CPUCheckMainCodeOKAndTurnOnCPU_Fail: 207 RT_TRACE(COMP_ERR, "ERR in %s()\n", __FUNCTION__); 208 rt_status = FALSE; 209 return rt_status; 210} 211 212bool 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 235CPUCheckFirmwareReady_Fail: 236 RT_TRACE(COMP_ERR, "ERR in %s()\n", __FUNCTION__); 237 rt_status = false; 238 return rt_status; 239 240} 241 242bool init_firmware(struct net_device *dev) 243{ 244 struct r8192_priv *priv = ieee80211_priv(dev); 245 bool rt_status = TRUE; 246 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", 256 "RTL8192U/main.img", 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 */ 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) { 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; 290 } 291 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 } 296 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; 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); 328 if(rst_opt == OPT_SYSTEM_RESET) { 329 release_firmware(fw_entry); 330 } 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 395download_firmware_fail: 396 RT_TRACE(COMP_ERR, "ERR in %s()\n", __FUNCTION__); 397 rt_status = FALSE; 398 return rt_status; 399 400} 401 402MODULE_FIRMWARE("RTL8192U/boot.img"); 403MODULE_FIRMWARE("RTL8192U/main.img"); 404MODULE_FIRMWARE("RTL8192U/data.img"); 405 406