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