Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/percpu
[pandora-kernel.git] / drivers / staging / rtl8192su / r8192S_firmware.c
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 //
40 bool 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
109 cmdsend_downloadcode_fail:
110         rt_status = false;
111         RT_TRACE(COMP_ERR, "(%s): failed\n", __func__);
112         return rt_status;
113 }
114
115
116 bool 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
144 FIRMWARE_8192S_STATUS
145 FirmwareGetNextStatus(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
174 bool 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
279 FirmwareCheckReadyFail:
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 //
291 u8 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 //
313 void 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
324 bool 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
393 RequestFirmware_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
400 bool 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
474 DownloadFirmware_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
481 MODULE_FIRMWARE("RTL8192SU/rtl8192sfw.bin");