Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
hal_init.c
Go to the documentation of this file.
1 /******************************************************************************
2  * hal_init.c
3  *
4  * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
5  * Linux device driver for RTL8192SU
6  *
7  * This program is free software; you can redistribute it and/or modify it
8  * under the terms of version 2 of the GNU General Public License as
9  * published by the Free Software Foundation.
10  *
11  * This program is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14  * more details.
15  *
16  * You should have received a copy of the GNU General Public License along with
17  * this program; if not, write to the Free Software Foundation, Inc.,
18  * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
19  *
20  * Modifications for inclusion into the Linux staging tree are
21  * Copyright(c) 2010 Larry Finger. All rights reserved.
22  *
23  * Contact information:
24  * WLAN FAE <[email protected]>.
25  * Larry Finger <[email protected]>
26  *
27  ******************************************************************************/
28 
29 #define _HAL_INIT_C_
30 
31 #include <linux/usb.h>
32 #include <linux/device.h>
33 #include <linux/usb/ch9.h>
34 #include <linux/firmware.h>
35 #include <linux/module.h>
36 
37 #include "osdep_service.h"
38 #include "drv_types.h"
39 #include "usb_osintf.h"
40 
41 #define FWBUFF_ALIGN_SZ 512
42 #define MAX_DUMP_FWSZ 49152 /*default = 49152 (48k)*/
43 
44 static void rtl871x_load_fw_cb(const struct firmware *firmware, void *context)
45 {
46  struct _adapter *padapter = context;
47 
48  complete(&padapter->rtl8712_fw_ready);
49  if (!firmware) {
50  struct usb_device *udev = padapter->dvobjpriv.pusbdev;
51  struct usb_interface *pusb_intf = padapter->pusb_intf;
52  printk(KERN_ERR "r8712u: Firmware request failed\n");
53  padapter->fw_found = false;
54  usb_put_dev(udev);
55  usb_set_intfdata(pusb_intf, NULL);
56  return;
57  }
58  padapter->fw = firmware;
59  padapter->fw_found = true;
60  /* firmware available - start netdev */
61  register_netdev(padapter->pnetdev);
62 }
63 
64 static const char firmware_file[] = "rtlwifi/rtl8712u.bin";
65 
66 int rtl871x_load_fw(struct _adapter *padapter)
67 {
68  struct device *dev = &padapter->dvobjpriv.pusbdev->dev;
69  int rc;
70 
71  init_completion(&padapter->rtl8712_fw_ready);
72  printk(KERN_INFO "r8712u: Loading firmware from \"%s\"\n",
73  firmware_file);
74  rc = request_firmware_nowait(THIS_MODULE, 1, firmware_file, dev,
75  GFP_KERNEL, padapter, rtl871x_load_fw_cb);
76  if (rc)
77  printk(KERN_ERR "r8712u: Firmware request error %d\n", rc);
78  return rc;
79 }
80 MODULE_FIRMWARE("rtlwifi/rtl8712u.bin");
81 
82 static u32 rtl871x_open_fw(struct _adapter *padapter, const u8 **ppmappedfw)
83 {
84  const struct firmware **praw = &padapter->fw;
85 
86  if (padapter->fw->size > 200000) {
87  printk(KERN_ERR "r8172u: Badfw->size of %d\n",
88  (int)padapter->fw->size);
89  return 0;
90  }
91  *ppmappedfw = (u8 *)((*praw)->data);
92  return (*praw)->size;
93 }
94 
95 static void fill_fwpriv(struct _adapter *padapter, struct fw_priv *pfwpriv)
96 {
97  struct dvobj_priv *pdvobj = (struct dvobj_priv *)&padapter->dvobjpriv;
98  struct registry_priv *pregpriv = &padapter->registrypriv;
99 
100  memset(pfwpriv, 0, sizeof(struct fw_priv));
101  /* todo: check if needs endian conversion */
102  pfwpriv->hci_sel = RTL8712_HCI_TYPE_72USB;
103  pfwpriv->usb_ep_num = (u8)pdvobj->nr_endpoint;
104  pfwpriv->bw_40MHz_en = pregpriv->cbw40_enable;
105  switch (pregpriv->rf_config) {
106  case RTL8712_RF_1T1R:
107  pfwpriv->rf_config = RTL8712_RFC_1T1R;
108  break;
109  case RTL8712_RF_2T2R:
110  pfwpriv->rf_config = RTL8712_RFC_2T2R;
111  break;
112  case RTL8712_RF_1T2R:
113  default:
114  pfwpriv->rf_config = RTL8712_RFC_1T2R;
115  }
116  pfwpriv->mp_mode = (pregpriv->mp_mode == 1) ? 1 : 0;
117  pfwpriv->vcsType = pregpriv->vrtl_carrier_sense; /* 0:off 1:on 2:auto */
118  pfwpriv->vcsMode = pregpriv->vcs_type; /* 1:RTS/CTS 2:CTS to self */
119  /* default enable turboMode */
120  pfwpriv->turboMode = ((pregpriv->wifi_test == 1) ? 0 : 1);
121  pfwpriv->lowPowerMode = pregpriv->low_power;
122 }
123 
124 static void update_fwhdr(struct fw_hdr *pfwhdr, const u8 *pmappedfw)
125 {
126  pfwhdr->signature = le16_to_cpu(*(u16 *)pmappedfw);
127  pfwhdr->version = le16_to_cpu(*(u16 *)(pmappedfw+2));
128  /* define the size of boot loader */
129  pfwhdr->dmem_size = le32_to_cpu(*(uint *)(pmappedfw+4));
130  /* define the size of FW in IMEM */
131  pfwhdr->img_IMEM_size = le32_to_cpu(*(uint *)(pmappedfw+8));
132  /* define the size of FW in SRAM */
133  pfwhdr->img_SRAM_size = le32_to_cpu(*(uint *)(pmappedfw+12));
134  /* define the size of DMEM variable */
135  pfwhdr->fw_priv_sz = le32_to_cpu(*(uint *)(pmappedfw+16));
136 }
137 
138 static u8 chk_fwhdr(struct fw_hdr *pfwhdr, u32 ulfilelength)
139 {
140  u32 fwhdrsz, fw_sz;
141  u8 intf, rfconf;
142 
143  /* check signature */
144  if ((pfwhdr->signature != 0x8712) && (pfwhdr->signature != 0x8192))
145  return _FAIL;
146  /* check interface */
147  intf = (u8)((pfwhdr->version&0x3000) >> 12);
148  /* check rf_conf */
149  rfconf = (u8)((pfwhdr->version&0xC000) >> 14);
150  /* check fw_priv_sze & sizeof(struct fw_priv) */
151  if (pfwhdr->fw_priv_sz != sizeof(struct fw_priv))
152  return _FAIL;
153  /* check fw_sz & image_fw_sz */
154  fwhdrsz = FIELD_OFFSET(struct fw_hdr, fwpriv) + pfwhdr->fw_priv_sz;
155  fw_sz = fwhdrsz + pfwhdr->img_IMEM_size + pfwhdr->img_SRAM_size +
156  pfwhdr->dmem_size;
157  if (fw_sz != ulfilelength)
158  return _FAIL;
159  return _SUCCESS;
160 }
161 
162 static u8 rtl8712_dl_fw(struct _adapter *padapter)
163 {
164  sint i;
165  u8 tmp8, tmp8_a;
166  u16 tmp16;
167  u32 maxlen = 0, tmp32; /* for compare usage */
168  uint dump_imem_sz, imem_sz, dump_emem_sz, emem_sz; /* max = 49152; */
169  struct fw_hdr fwhdr;
170  u32 ulfilelength; /* FW file size */
171  const u8 *pmappedfw = NULL;
172  u8 *ptmpchar = NULL, *ppayload, *ptr;
173  struct tx_desc *ptx_desc;
174  u32 txdscp_sz = sizeof(struct tx_desc);
175  u8 ret = _FAIL;
176 
177  ulfilelength = rtl871x_open_fw(padapter, &pmappedfw);
178  if (pmappedfw && (ulfilelength > 0)) {
179  update_fwhdr(&fwhdr, pmappedfw);
180  if (chk_fwhdr(&fwhdr, ulfilelength) == _FAIL)
181  return ret;
182  fill_fwpriv(padapter, &fwhdr.fwpriv);
183  /* firmware check ok */
184  maxlen = (fwhdr.img_IMEM_size > fwhdr.img_SRAM_size) ?
185  fwhdr.img_IMEM_size : fwhdr.img_SRAM_size;
186  maxlen += txdscp_sz;
187  ptmpchar = _malloc(maxlen + FWBUFF_ALIGN_SZ);
188  if (ptmpchar == NULL)
189  return ret;
190 
191  ptx_desc = (struct tx_desc *)(ptmpchar + FWBUFF_ALIGN_SZ -
192  ((addr_t)(ptmpchar) & (FWBUFF_ALIGN_SZ - 1)));
193  ppayload = (u8 *)(ptx_desc) + txdscp_sz;
194  ptr = (u8 *)pmappedfw + FIELD_OFFSET(struct fw_hdr, fwpriv) +
195  fwhdr.fw_priv_sz;
196  /* Download FirmWare */
197  /* 1. determine IMEM code size and Load IMEM Code Section */
198  imem_sz = fwhdr.img_IMEM_size;
199  do {
200  memset(ptx_desc, 0, TXDESC_SIZE);
201  if (imem_sz > MAX_DUMP_FWSZ/*49152*/)
202  dump_imem_sz = MAX_DUMP_FWSZ;
203  else {
204  dump_imem_sz = imem_sz;
205  ptx_desc->txdw0 |= cpu_to_le32(BIT(28));
206  }
207  ptx_desc->txdw0 |= cpu_to_le32(dump_imem_sz &
208  0x0000ffff);
209  memcpy(ppayload, ptr, dump_imem_sz);
211  dump_imem_sz + TXDESC_SIZE,
212  (u8 *)ptx_desc);
213  ptr += dump_imem_sz;
214  imem_sz -= dump_imem_sz;
215  } while (imem_sz > 0);
216  i = 10;
217  tmp16 = r8712_read16(padapter, TCR);
218  while (((tmp16 & _IMEM_CODE_DONE) == 0) && (i > 0)) {
219  udelay(10);
220  tmp16 = r8712_read16(padapter, TCR);
221  i--;
222  }
223  if (i == 0 || (tmp16 & _IMEM_CHK_RPT) == 0)
224  goto exit_fail;
225 
226  /* 2.Download EMEM code size and Load EMEM Code Section */
227  emem_sz = fwhdr.img_SRAM_size;
228  do {
229  memset(ptx_desc, 0, TXDESC_SIZE);
230  if (emem_sz > MAX_DUMP_FWSZ) /* max=48k */
231  dump_emem_sz = MAX_DUMP_FWSZ;
232  else {
233  dump_emem_sz = emem_sz;
234  ptx_desc->txdw0 |= cpu_to_le32(BIT(28));
235  }
236  ptx_desc->txdw0 |= cpu_to_le32(dump_emem_sz &
237  0x0000ffff);
238  memcpy(ppayload, ptr, dump_emem_sz);
240  dump_emem_sz+TXDESC_SIZE, (u8 *)ptx_desc);
241  ptr += dump_emem_sz;
242  emem_sz -= dump_emem_sz;
243  } while (emem_sz > 0);
244  i = 5;
245  tmp16 = r8712_read16(padapter, TCR);
246  while (((tmp16 & _EMEM_CODE_DONE) == 0) && (i > 0)) {
247  udelay(10);
248  tmp16 = r8712_read16(padapter, TCR);
249  i--;
250  }
251  if (i == 0 || (tmp16 & _EMEM_CHK_RPT) == 0)
252  goto exit_fail;
253 
254  /* 3.Enable CPU */
255  tmp8 = r8712_read8(padapter, SYS_CLKR);
256  r8712_write8(padapter, SYS_CLKR, tmp8|BIT(2));
257  tmp8_a = r8712_read8(padapter, SYS_CLKR);
258  if (tmp8_a != (tmp8|BIT(2)))
259  goto exit_fail;
260 
261  tmp8 = r8712_read8(padapter, SYS_FUNC_EN + 1);
262  r8712_write8(padapter, SYS_FUNC_EN+1, tmp8|BIT(2));
263  tmp8_a = r8712_read8(padapter, SYS_FUNC_EN + 1);
264  if (tmp8_a != (tmp8|BIT(2)))
265  goto exit_fail;
266 
267  tmp32 = r8712_read32(padapter, TCR);
268 
269  /* 4.polling IMEM Ready */
270  i = 100;
271  tmp16 = r8712_read16(padapter, TCR);
272  while (((tmp16 & _IMEM_RDY) == 0) && (i > 0)) {
273  msleep(20);
274  tmp16 = r8712_read16(padapter, TCR);
275  i--;
276  }
277  if (i == 0) {
278  r8712_write16(padapter, 0x10250348, 0xc000);
279  r8712_write16(padapter, 0x10250348, 0xc001);
280  r8712_write16(padapter, 0x10250348, 0x2000);
281  r8712_write16(padapter, 0x10250348, 0x2001);
282  r8712_write16(padapter, 0x10250348, 0x2002);
283  r8712_write16(padapter, 0x10250348, 0x2003);
284  goto exit_fail;
285  }
286  /* 5.Download DMEM code size and Load EMEM Code Section */
287  memset(ptx_desc, 0, TXDESC_SIZE);
288  ptx_desc->txdw0 |= cpu_to_le32(fwhdr.fw_priv_sz&0x0000ffff);
289  ptx_desc->txdw0 |= cpu_to_le32(BIT(28));
290  memcpy(ppayload, &fwhdr.fwpriv, fwhdr.fw_priv_sz);
292  fwhdr.fw_priv_sz + TXDESC_SIZE, (u8 *)ptx_desc);
293 
294  /* polling dmem code done */
295  i = 100;
296  tmp16 = r8712_read16(padapter, TCR);
297  while (((tmp16 & _DMEM_CODE_DONE) == 0) && (i > 0)) {
298  msleep(20);
299  tmp16 = r8712_read16(padapter, TCR);
300  i--;
301  }
302  if (i == 0)
303  goto exit_fail;
304 
305  tmp8 = r8712_read8(padapter, 0x1025000A);
306  if (tmp8 & BIT(4)) /* When boot from EEPROM,
307  & FW need more time to read EEPROM */
308  i = 60;
309  else /* boot from EFUSE */
310  i = 30;
311  tmp16 = r8712_read16(padapter, TCR);
312  while (((tmp16 & _FWRDY) == 0) && (i > 0)) {
313  msleep(100);
314  tmp16 = r8712_read16(padapter, TCR);
315  i--;
316  }
317  if (i == 0)
318  goto exit_fail;
319  } else
320  goto exit_fail;
321  ret = _SUCCESS;
322 
323 exit_fail:
324  kfree(ptmpchar);
325  return ret;
326 }
327 
328 uint rtl8712_hal_init(struct _adapter *padapter)
329 {
330  u32 val32;
331  int i;
332 
333  /* r8712 firmware download */
334  if (rtl8712_dl_fw(padapter) != _SUCCESS)
335  return _FAIL;
336 
337  printk(KERN_INFO "r8712u: 1 RCR=0x%x\n", r8712_read32(padapter, RCR));
338  val32 = r8712_read32(padapter, RCR);
339  r8712_write32(padapter, RCR, (val32 | BIT(26))); /* Enable RX TCP
340  Checksum offload */
341  printk(KERN_INFO "r8712u: 2 RCR=0x%x\n", r8712_read32(padapter, RCR));
342  val32 = r8712_read32(padapter, RCR);
343  r8712_write32(padapter, RCR, (val32|BIT(25))); /* Append PHY status */
344  val32 = 0;
345  val32 = r8712_read32(padapter, 0x10250040);
346  r8712_write32(padapter, 0x10250040, (val32&0x00FFFFFF));
347  /* for usb rx aggregation */
348  r8712_write8(padapter, 0x102500B5, r8712_read8(padapter, 0x102500B5) |
349  BIT(0)); /* page = 128bytes */
350  r8712_write8(padapter, 0x102500BD, r8712_read8(padapter, 0x102500BD) |
351  BIT(7)); /* enable usb rx aggregation */
352  r8712_write8(padapter, 0x102500D9, 1); /* TH=1 => means that invalidate
353  * usb rx aggregation */
354  r8712_write8(padapter, 0x1025FE5B, 0x04); /* 1.7ms/4 */
355  /* Fix the RX FIFO issue(USB error) */
356  r8712_write8(padapter, 0x1025fe5C, r8712_read8(padapter, 0x1025fe5C)
357  | BIT(7));
358  for (i = 0; i < 6; i++)
359  padapter->eeprompriv.mac_addr[i] = r8712_read8(padapter,
360  MACID + i);
361  return _SUCCESS;
362 }
363 
365 {
366  r8712_write8(padapter, RF_CTRL, 0x00);
367  /* Turn off BB */
368  msleep(20);
369  /* Turn off MAC */
370  r8712_write8(padapter, SYS_CLKR+1, 0x38); /* Switch Control Path */
371  r8712_write8(padapter, SYS_FUNC_EN+1, 0x70);
372  r8712_write8(padapter, PMC_FSM, 0x06); /* Enable Loader Data Keep */
373  r8712_write8(padapter, SYS_ISO_CTRL, 0xF9); /* Isolation signals from
374  * CORE, PLL */
375  r8712_write8(padapter, SYS_ISO_CTRL+1, 0xe8); /* Enable EFUSE 1.2V */
376  r8712_write8(padapter, AFE_PLL_CTRL, 0x00); /* Disable AFE PLL. */
377  r8712_write8(padapter, LDOA15_CTRL, 0x54); /* Disable A15V */
378  r8712_write8(padapter, SYS_FUNC_EN+1, 0x50); /* Disable E-Fuse 1.2V */
379  r8712_write8(padapter, LDOV12D_CTRL, 0x24); /* Disable LDO12(for CE) */
380  r8712_write8(padapter, AFE_MISC, 0x30); /* Disable AFE BG&MB */
381  /* Option for Disable 1.6V LDO. */
382  r8712_write8(padapter, SPS0_CTRL, 0x56); /* Disable 1.6V LDO */
383  r8712_write8(padapter, SPS0_CTRL+1, 0x43); /* Set SW PFM */
384  return _SUCCESS;
385 }
386 
387 uint rtl871x_hal_init(struct _adapter *padapter)
388 {
389  padapter->hw_init_completed = false;
390  if (padapter->halpriv.hal_bus_init == NULL)
391  return _FAIL;
392  else {
393  if (padapter->halpriv.hal_bus_init(padapter) != _SUCCESS)
394  return _FAIL;
395  }
396  if (rtl8712_hal_init(padapter) == _SUCCESS)
397  padapter->hw_init_completed = true;
398  else {
399  padapter->hw_init_completed = false;
400  return _FAIL;
401  }
402  return _SUCCESS;
403 }