1/****************************************************************************** 2 * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. 3 * 4 * This program is distributed in the hope that it will be useful, but WITHOUT 5 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 6 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 7 * more details. 8 * 9 * You should have received a copy of the GNU General Public License along with 10 * this program; if not, write to the Free Software Foundation, Inc., 11 * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA 12 * 13 * The full GNU General Public License is included in this distribution in the 14 * file called LICENSE. 15 * 16 * Contact Information: 17 * wlanfae <wlanfae@realtek.com> 18******************************************************************************/ 19 20#include "r8192U.h" 21#include "r8192S_firmware.h" 22#include <linux/unistd.h> 23 24#include "r8192S_hw.h" 25#include "r8192SU_HWImg.h" 26 27#include <linux/firmware.h> 28 29#define byte(x,n) ( (x >> (8 * n)) & 0xff ) 30 31// 32// Description: This routine will intialize firmware. If any error occurs during the initialization 33// process, the routine shall terminate immediately and return fail. 34// 35// Arguments: The pointer of the adapter 36// Code address (Virtual address, should fill descriptor with physical address) 37// Code size 38// Created by Roger, 2008.04.10. 39// 40bool FirmwareDownloadCode(struct net_device *dev, 41 u8 *code_virtual_address, 42 u32 buffer_len) 43{ 44 struct r8192_priv *priv = ieee80211_priv(dev); 45 bool rt_status = true; 46 /* Fragmentation might be required in 90/92 but not in 92S */ 47 u16 frag_threshold = MAX_FIRMWARE_CODE_SIZE; 48 u16 frag_length, frag_offset = 0; 49 struct sk_buff *skb; 50 unsigned char *seg_ptr; 51 cb_desc *tcb_desc; 52 u8 bLastIniPkt = 0; 53 u16 ExtraDescOffset = 0; 54 55 if (buffer_len >= MAX_FIRMWARE_CODE_SIZE - USB_HWDESC_HEADER_LEN) { 56 RT_TRACE(COMP_ERR, "(%s): Firmware exceeds" 57 " MAX_FIRMWARE_CODE_SIZE\n", __func__); 58 goto cmdsend_downloadcode_fail; 59 } 60 ExtraDescOffset = USB_HWDESC_HEADER_LEN; 61 do { 62 if((buffer_len-frag_offset) > frag_threshold) 63 frag_length = frag_threshold + ExtraDescOffset; 64 else { 65 frag_length = (u16)(buffer_len - 66 frag_offset + ExtraDescOffset); 67 bLastIniPkt = 1; 68 } 69 /* 70 * Allocate skb buffer to contain firmware info 71 * and tx descriptor info. 72 */ 73 skb = dev_alloc_skb(frag_length); 74 if (skb == NULL) { 75 RT_TRACE(COMP_ERR, "(%s): unable to alloc skb buffer\n", 76 __func__); 77 goto cmdsend_downloadcode_fail; 78 } 79 memcpy((unsigned char *)(skb->cb), &dev, sizeof(dev)); 80 81 tcb_desc = (cb_desc*)(skb->cb + MAX_DEV_ADDR_SIZE); 82 tcb_desc->queue_index = TXCMD_QUEUE; 83 tcb_desc->bCmdOrInit = DESC_PACKET_TYPE_INIT; 84 tcb_desc->bLastIniPkt = bLastIniPkt; 85 86 skb_reserve(skb, ExtraDescOffset); 87 88 seg_ptr = (u8 *)skb_put(skb, 89 (u32)(frag_length - ExtraDescOffset)); 90 91 memcpy(seg_ptr, code_virtual_address + frag_offset, 92 (u32)(frag_length-ExtraDescOffset)); 93 94 tcb_desc->txbuf_size = frag_length; 95 96 if (!priv->ieee80211->check_nic_enough_desc(dev, tcb_desc->queue_index) || 97 (!skb_queue_empty(&priv->ieee80211->skb_waitQ[tcb_desc->queue_index])) || 98 (priv->ieee80211->queue_stop)) { 99 RT_TRACE(COMP_FIRMWARE,"=====================================================> tx full!\n"); 100 skb_queue_tail(&priv->ieee80211->skb_waitQ[tcb_desc->queue_index], skb); 101 } else 102 priv->ieee80211->softmac_hard_start_xmit(skb, dev); 103 104 frag_offset += (frag_length - ExtraDescOffset); 105 106 } while (frag_offset < buffer_len); 107 return rt_status ; 108 109cmdsend_downloadcode_fail: 110 rt_status = false; 111 RT_TRACE(COMP_ERR, "(%s): failed\n", __func__); 112 return rt_status; 113} 114 115 116bool FirmwareEnableCPU(struct net_device *dev) 117{ 118 bool rtStatus = true; 119 u8 tmpU1b, CPUStatus = 0; 120 u16 tmpU2b; 121 u32 iCheckTime = 200; 122 123 /* Enable CPU. */ 124 tmpU1b = read_nic_byte(dev, SYS_CLKR); 125 /* AFE source */ 126 write_nic_byte(dev, SYS_CLKR, (tmpU1b|SYS_CPU_CLKSEL)); 127 tmpU2b = read_nic_word(dev, SYS_FUNC_EN); 128 write_nic_word(dev, SYS_FUNC_EN, (tmpU2b|FEN_CPUEN)); 129 /* Poll IMEM Ready after CPU has refilled. */ 130 do { 131 CPUStatus = read_nic_byte(dev, TCR); 132 if (CPUStatus & IMEM_RDY) 133 /* success */ 134 break; 135 udelay(100); 136 } while (iCheckTime--); 137 if (!(CPUStatus & IMEM_RDY)) { 138 RT_TRACE(COMP_ERR, "%s(): failed to enable CPU", __func__); 139 rtStatus = false; 140 } 141 return rtStatus; 142} 143 144FIRMWARE_8192S_STATUS 145FirmwareGetNextStatus(FIRMWARE_8192S_STATUS FWCurrentStatus) 146{ 147 FIRMWARE_8192S_STATUS NextFWStatus = 0; 148 149 switch(FWCurrentStatus) 150 { 151 case FW_STATUS_INIT: 152 NextFWStatus = FW_STATUS_LOAD_IMEM; 153 break; 154 155 case FW_STATUS_LOAD_IMEM: 156 NextFWStatus = FW_STATUS_LOAD_EMEM; 157 break; 158 159 case FW_STATUS_LOAD_EMEM: 160 NextFWStatus = FW_STATUS_LOAD_DMEM; 161 break; 162 163 case FW_STATUS_LOAD_DMEM: 164 NextFWStatus = FW_STATUS_READY; 165 break; 166 167 default: 168 RT_TRACE(COMP_ERR,"Invalid FW Status(%#x)!!\n", FWCurrentStatus); 169 break; 170 } 171 return NextFWStatus; 172} 173 174bool FirmwareCheckReady(struct net_device *dev, u8 LoadFWStatus) 175{ 176 struct r8192_priv *priv = ieee80211_priv(dev); 177 bool rtStatus = true; 178 rt_firmware *pFirmware = priv->pFirmware; 179 int PollingCnt = 1000; 180 u8 CPUStatus = 0; 181 u32 tmpU4b; 182 183 pFirmware->FWStatus = (FIRMWARE_8192S_STATUS)LoadFWStatus; 184 switch (LoadFWStatus) { 185 case FW_STATUS_LOAD_IMEM: 186 do { /* Polling IMEM code done. */ 187 CPUStatus = read_nic_byte(dev, TCR); 188 if(CPUStatus& IMEM_CODE_DONE) 189 break; 190 udelay(5); 191 } while (PollingCnt--); 192 if (!(CPUStatus & IMEM_CHK_RPT) || PollingCnt <= 0) { 193 RT_TRACE(COMP_ERR, "FW_STATUS_LOAD_IMEM FAIL CPU, Status=%x\r\n", CPUStatus); 194 goto FirmwareCheckReadyFail; 195 } 196 break; 197 case FW_STATUS_LOAD_EMEM: /* Check Put Code OK and Turn On CPU */ 198 do { /* Polling EMEM code done. */ 199 CPUStatus = read_nic_byte(dev, TCR); 200 if(CPUStatus& EMEM_CODE_DONE) 201 break; 202 udelay(5); 203 } while (PollingCnt--); 204 if (!(CPUStatus & EMEM_CHK_RPT)) { 205 RT_TRACE(COMP_ERR, "FW_STATUS_LOAD_EMEM FAIL CPU, Status=%x\r\n", CPUStatus); 206 goto FirmwareCheckReadyFail; 207 } 208 /* Turn On CPU */ 209 if (FirmwareEnableCPU(dev) != true) { 210 RT_TRACE(COMP_ERR, "%s(): failed to enable CPU", 211 __func__); 212 goto FirmwareCheckReadyFail; 213 } 214 break; 215 case FW_STATUS_LOAD_DMEM: 216 do { /* Polling DMEM code done */ 217 CPUStatus = read_nic_byte(dev, TCR); 218 if(CPUStatus& DMEM_CODE_DONE) 219 break; 220 221 udelay(5); 222 } while (PollingCnt--); 223 224 if (!(CPUStatus & DMEM_CODE_DONE)) { 225 RT_TRACE(COMP_ERR, "Polling DMEM code done fail ! CPUStatus(%#x)\n", CPUStatus); 226 goto FirmwareCheckReadyFail; 227 } 228 229 RT_TRACE(COMP_FIRMWARE, "%s(): DMEM code download success, " 230 "CPUStatus(%#x)", 231 __func__, CPUStatus); 232 233 PollingCnt = 10000; /* Set polling cycle to 10ms. */ 234 235 do { /* Polling Load Firmware ready */ 236 CPUStatus = read_nic_byte(dev, TCR); 237 if(CPUStatus & FWRDY) 238 break; 239 udelay(100); 240 } while (PollingCnt--); 241 242 RT_TRACE(COMP_FIRMWARE, "%s(): polling load firmware ready, " 243 "CPUStatus(%x)", 244 __func__, CPUStatus); 245 246 if ((CPUStatus & LOAD_FW_READY) != LOAD_FW_READY) { 247 RT_TRACE(COMP_ERR, "Polling Load Firmware ready failed " 248 "CPUStatus(%x)\n", CPUStatus); 249 goto FirmwareCheckReadyFail; 250 } 251 /* 252 * USB interface will update 253 * reserved followings parameters later 254 */ 255 256 // 257 // <Roger_Notes> If right here, we can set TCR/RCR to desired value 258 // and config MAC lookback mode to normal mode. 2008.08.28. 259 // 260 tmpU4b = read_nic_dword(dev,TCR); 261 write_nic_dword(dev, TCR, (tmpU4b&(~TCR_ICV))); 262 263 tmpU4b = read_nic_dword(dev, RCR); 264 write_nic_dword(dev, RCR, 265 (tmpU4b|RCR_APPFCS|RCR_APP_ICV|RCR_APP_MIC)); 266 267 RT_TRACE(COMP_FIRMWARE, "%s(): Current RCR settings(%#x)", 268 __func__, tmpU4b); 269 // Set to normal mode. 270 write_nic_byte(dev, LBKMD_SEL, LBK_NORMAL); 271 break; 272 default: 273 break; 274 } 275 RT_TRACE(COMP_FIRMWARE, "%s(): LoadFWStatus(%d), success", 276 __func__, LoadFWStatus); 277 return rtStatus; 278 279FirmwareCheckReadyFail: 280 rtStatus = false; 281 RT_TRACE(COMP_FIRMWARE, "%s(): LoadFWStatus(%d), failed", 282 __func__, LoadFWStatus); 283 return rtStatus; 284} 285 286// 287// Description: This routine is to update the RF types in FW header partially. 288// 289// Created by Roger, 2008.12.24. 290// 291u8 FirmwareHeaderMapRfType(struct net_device *dev) 292{ 293 struct r8192_priv *priv = ieee80211_priv(dev); 294 switch(priv->rf_type) 295 { 296 case RF_1T1R: return 0x11; 297 case RF_1T2R: return 0x12; 298 case RF_2T2R: return 0x22; 299 case RF_2T2R_GREEN: return 0x92; 300 default: 301 RT_TRACE(COMP_INIT, "Unknown RF type(%x)\n",priv->rf_type); 302 break; 303 } 304 return 0x22; 305} 306 307 308// 309// Description: This routine is to update the private parts in FW header partially. 310// 311// Created by Roger, 2008.12.18. 312// 313void FirmwareHeaderPriveUpdate(struct net_device *dev, PRT_8192S_FIRMWARE_PRIV pFwPriv) 314{ 315 struct r8192_priv *priv = ieee80211_priv(dev); 316 // Update USB endpoint number for RQPN settings. 317 pFwPriv->usb_ep_num = priv->EEPROMUsbEndPointNumber; // endpoint number: 4, 6 and 11. 318 RT_TRACE(COMP_INIT, "FirmwarePriveUpdate(): usb_ep_num(%#x)\n", pFwPriv->usb_ep_num); 319 320 // Update RF types for RATR settings. 321 pFwPriv->rf_config = FirmwareHeaderMapRfType(dev); 322} 323 324bool FirmwareRequest92S(struct net_device *dev, rt_firmware *pFirmware) 325{ 326 struct r8192_priv *priv = ieee80211_priv(dev); 327 bool rtStatus = true; 328 const char *pFwImageFileName[1] = {"RTL8192SU/rtl8192sfw.bin"}; 329 u8 *pucMappedFile = NULL; 330 u32 ulInitStep = 0; 331 u8 FwHdrSize = RT_8192S_FIRMWARE_HDR_SIZE; 332 PRT_8192S_FIRMWARE_HDR pFwHdr = NULL; 333 u32 file_length = 0; 334 int rc; 335 const struct firmware *fw_entry; 336 337 rc = request_firmware(&fw_entry, 338 pFwImageFileName[ulInitStep], 339 &priv->udev->dev); 340 if (rc < 0) 341 goto RequestFirmware_Fail; 342 343 if (fw_entry->size > sizeof(pFirmware->szFwTmpBuffer)) { 344 RT_TRACE(COMP_ERR, "%s(): image file too large" 345 "for container buffer", __func__); 346 release_firmware(fw_entry); 347 goto RequestFirmware_Fail; 348 } 349 350 memcpy(pFirmware->szFwTmpBuffer, fw_entry->data, fw_entry->size); 351 pFirmware->szFwTmpBufferLen = fw_entry->size; 352 release_firmware(fw_entry); 353 354 pucMappedFile = pFirmware->szFwTmpBuffer; 355 file_length = pFirmware->szFwTmpBufferLen; 356 357 /* Retrieve FW header. */ 358 pFirmware->pFwHeader = (PRT_8192S_FIRMWARE_HDR) pucMappedFile; 359 pFwHdr = pFirmware->pFwHeader; 360 361 RT_TRACE(COMP_FIRMWARE, "%s(): signature: %x, version: %x, " 362 "size: %x, imemsize: %x, sram size: %x", 363 __func__, pFwHdr->Signature, pFwHdr->Version, 364 pFwHdr->DMEMSize, pFwHdr->IMG_IMEM_SIZE, 365 pFwHdr->IMG_SRAM_SIZE); 366 367 pFirmware->FirmwareVersion = byte(pFwHdr->Version , 0); 368 369 if ((pFwHdr->IMG_IMEM_SIZE == 0) || 370 (pFwHdr->IMG_IMEM_SIZE > sizeof(pFirmware->FwIMEM))) { 371 RT_TRACE(COMP_ERR, "%s(): memory for data image is less than" 372 " IMEM requires", __func__); 373 goto RequestFirmware_Fail; 374 } else { 375 pucMappedFile += FwHdrSize; 376 /* Retrieve IMEM image. */ 377 memcpy(pFirmware->FwIMEM, pucMappedFile, pFwHdr->IMG_IMEM_SIZE); 378 pFirmware->FwIMEMLen = pFwHdr->IMG_IMEM_SIZE; 379 } 380 381 if (pFwHdr->IMG_SRAM_SIZE > sizeof(pFirmware->FwEMEM)) { 382 RT_TRACE(COMP_ERR, "%s(): memory for data image is less than" 383 " EMEM requires", __func__); 384 goto RequestFirmware_Fail; 385 } else { 386 pucMappedFile += pFirmware->FwIMEMLen; 387 /* Retriecve EMEM image */ 388 memcpy(pFirmware->FwEMEM, pucMappedFile, pFwHdr->IMG_SRAM_SIZE); 389 pFirmware->FwEMEMLen = pFwHdr->IMG_SRAM_SIZE; 390 } 391 return rtStatus; 392 393RequestFirmware_Fail: 394 RT_TRACE(COMP_ERR, "%s(): failed with TCR-Status: %x\n", 395 __func__, read_nic_word(dev, TCR)); 396 rtStatus = false; 397 return rtStatus; 398} 399 400bool FirmwareDownload92S(struct net_device *dev) 401{ 402 struct r8192_priv *priv = ieee80211_priv(dev); 403 bool rtStatus = true; 404 u8 *pucMappedFile = NULL; 405 u32 ulFileLength; 406 u8 FwHdrSize = RT_8192S_FIRMWARE_HDR_SIZE; 407 rt_firmware *pFirmware = priv->pFirmware; 408 u8 FwStatus = FW_STATUS_INIT; 409 PRT_8192S_FIRMWARE_HDR pFwHdr = NULL; 410 PRT_8192S_FIRMWARE_PRIV pFwPriv = NULL; 411 412 pFirmware->FWStatus = FW_STATUS_INIT; 413 /* 414 * Load the firmware from RTL8192SU/rtl8192sfw.bin if necessary 415 */ 416 if (pFirmware->szFwTmpBufferLen == 0) { 417 if (FirmwareRequest92S(dev, pFirmware) != true) 418 goto DownloadFirmware_Fail; 419 } 420 FwStatus = FirmwareGetNextStatus(pFirmware->FWStatus); 421 while (FwStatus != FW_STATUS_READY) { 422 /* Image buffer redirection. */ 423 switch (FwStatus) { 424 case FW_STATUS_LOAD_IMEM: 425 pucMappedFile = pFirmware->FwIMEM; 426 ulFileLength = pFirmware->FwIMEMLen; 427 break; 428 429 case FW_STATUS_LOAD_EMEM: 430 pucMappedFile = pFirmware->FwEMEM; 431 ulFileLength = pFirmware->FwEMEMLen; 432 break; 433 434 case FW_STATUS_LOAD_DMEM: 435 /* Partial update the content of private header */ 436 pFwHdr = pFirmware->pFwHeader; 437 pFwPriv = (PRT_8192S_FIRMWARE_PRIV)&pFwHdr->FWPriv; 438 FirmwareHeaderPriveUpdate(dev, pFwPriv); 439 pucMappedFile = (u8 *)(pFirmware->pFwHeader) + 440 RT_8192S_FIRMWARE_HDR_EXCLUDE_PRI_SIZE; 441 442 ulFileLength = FwHdrSize - 443 RT_8192S_FIRMWARE_HDR_EXCLUDE_PRI_SIZE; 444 break; 445 446 default: 447 RT_TRACE(COMP_ERR, "Unexpected Download step!!\n"); 448 goto DownloadFirmware_Fail; 449 break; 450 } 451 452 /* <2> Download image file */ 453 454 rtStatus = FirmwareDownloadCode(dev, 455 pucMappedFile, 456 ulFileLength); 457 458 if(rtStatus != true) 459 goto DownloadFirmware_Fail; 460 461 /* <3> Check whether load FW process is ready */ 462 463 rtStatus = FirmwareCheckReady(dev, FwStatus); 464 465 if(rtStatus != true) 466 goto DownloadFirmware_Fail; 467 468 FwStatus = FirmwareGetNextStatus(pFirmware->FWStatus); 469 } 470 471 RT_TRACE(COMP_FIRMWARE, "%s(): Firmware Download Success", __func__); 472 return rtStatus; 473 474DownloadFirmware_Fail: 475 RT_TRACE(COMP_ERR, "%s(): failed with TCR-Status: %x\n", 476 __func__, read_nic_word(dev, TCR)); 477 rtStatus = false; 478 return rtStatus; 479} 480 481MODULE_FIRMWARE("RTL8192SU/rtl8192sfw.bin"); 482