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