aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging/rtl8712/hal_init.c
diff options
context:
space:
mode:
authorLarry Finger <Larry.Finger@lwfinger.net>2010-08-20 11:15:30 -0400
committerLarry Finger <Larry.Finger@lwfinger.net>2010-08-20 11:15:30 -0400
commit2865d42c78a9121caad52cb02d1fbb7f5cdbc4ef (patch)
tree430b79f753b0e1cec6379b9a4208a716c914ac65 /drivers/staging/rtl8712/hal_init.c
parent763008c4357b73c8d18396dfd8d79dc58fa3f99d (diff)
staging: r8712u: Add the new driver to the mainline kernel
This code is for a completely new version of the Realtek 8192 USB devices such as the D-Link DWA-130. The Realtek code, which was originally for Linux, Windows XP and Windows CE, has been stripped of all code not needed for Linux. In addition, only one additional configuration variable, which enables AP mode, remains. Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net> Signed-off-by: Florian Schilhabel <florian.c.schilhabel@googlemail.com> Tested-by: Frederic Leroy <fredo@starox.org>
Diffstat (limited to 'drivers/staging/rtl8712/hal_init.c')
-rw-r--r--drivers/staging/rtl8712/hal_init.c356
1 files changed, 356 insertions, 0 deletions
diff --git a/drivers/staging/rtl8712/hal_init.c b/drivers/staging/rtl8712/hal_init.c
new file mode 100644
index 00000000000..29bcbea0f7e
--- /dev/null
+++ b/drivers/staging/rtl8712/hal_init.c
@@ -0,0 +1,356 @@
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 <wlanfae@realtek.com>.
25 * Larry Finger <Larry.Finger@lwfinger.net>
26 *
27 ******************************************************************************/
28
29#define _HAL_INIT_C_
30
31#include "osdep_service.h"
32#include "drv_types.h"
33#include "rtl871x_byteorder.h"
34#include "farray.h"
35
36#define FWBUFF_ALIGN_SZ 512
37#define MAX_DUMP_FWSZ 49152 /*default = 49152 (48k)*/
38
39static u32 rtl871x_open_fw(struct _adapter *padapter, void **pphfwfile_hdl,
40 const u8 **ppmappedfw)
41{
42 u32 len;
43
44 *ppmappedfw = f_array;
45 len = sizeof(f_array);
46 return len;
47}
48
49static void fill_fwpriv(struct _adapter *padapter, struct fw_priv *pfwpriv)
50{
51 struct dvobj_priv *pdvobj = (struct dvobj_priv *)&padapter->dvobjpriv;
52 struct registry_priv *pregpriv = &padapter->registrypriv;
53
54 memset(pfwpriv, 0, sizeof(struct fw_priv));
55 /* todo: check if needs endian conversion */
56 pfwpriv->hci_sel = RTL8712_HCI_TYPE_72USB;
57 pfwpriv->usb_ep_num = (u8)pdvobj->nr_endpoint;
58 pfwpriv->bw_40MHz_en = pregpriv->cbw40_enable;
59 switch (pregpriv->rf_config) {
60 case RTL8712_RF_1T1R:
61 pfwpriv->rf_config = RTL8712_RFC_1T1R;
62 break;
63 case RTL8712_RF_2T2R:
64 pfwpriv->rf_config = RTL8712_RFC_2T2R;
65 break;
66 case RTL8712_RF_1T2R:
67 default:
68 pfwpriv->rf_config = RTL8712_RFC_1T2R;
69 }
70 pfwpriv->mp_mode = (pregpriv->mp_mode == 1) ? 1 : 0;
71 pfwpriv->vcsType = pregpriv->vrtl_carrier_sense; /* 0:off 1:on 2:auto */
72 pfwpriv->vcsMode = pregpriv->vcs_type; /* 1:RTS/CTS 2:CTS to self */
73 pfwpriv->turboMode = 1; /* default enable it */
74 pfwpriv->lowPowerMode = pregpriv->low_power;
75}
76
77static void update_fwhdr(struct fw_hdr *pfwhdr, const u8 *pmappedfw)
78{
79 pfwhdr->signature = le16_to_cpu(*(u16 *)pmappedfw);
80 pfwhdr->version = le16_to_cpu(*(u16 *)(pmappedfw+2));
81 /* define the size of boot loader */
82 pfwhdr->dmem_size = le32_to_cpu(*(uint *)(pmappedfw+4));
83 /* define the size of FW in IMEM */
84 pfwhdr->img_IMEM_size = le32_to_cpu(*(uint *)(pmappedfw+8));
85 /* define the size of FW in SRAM */
86 pfwhdr->img_SRAM_size = le32_to_cpu(*(uint *)(pmappedfw+12));
87 /* define the size of DMEM variable */
88 pfwhdr->fw_priv_sz = le32_to_cpu(*(uint *)(pmappedfw+16));
89}
90
91static u8 chk_fwhdr(struct fw_hdr *pfwhdr, u32 ulfilelength)
92{
93 u32 fwhdrsz, fw_sz;
94 u8 intf, rfconf;
95
96 /* check signature */
97 if ((pfwhdr->signature != 0x8712) && (pfwhdr->signature != 0x8192))
98 return _FAIL;
99 /* check interface */
100 intf = (u8)((pfwhdr->version&0x3000) >> 12);
101 /* check rf_conf */
102 rfconf = (u8)((pfwhdr->version&0xC000) >> 14);
103 /* check fw_priv_sze & sizeof(struct fw_priv) */
104 if (pfwhdr->fw_priv_sz != sizeof(struct fw_priv))
105 return _FAIL;
106 /* check fw_sz & image_fw_sz */
107 fwhdrsz = FIELD_OFFSET(struct fw_hdr, fwpriv) + pfwhdr->fw_priv_sz;
108 fw_sz = fwhdrsz + pfwhdr->img_IMEM_size + pfwhdr->img_SRAM_size +
109 pfwhdr->dmem_size;
110 if (fw_sz != ulfilelength)
111 return _FAIL;
112 return _SUCCESS;
113}
114
115static u8 rtl8712_dl_fw(struct _adapter *padapter)
116{
117 sint i;
118 u8 tmp8, tmp8_a;
119 u16 tmp16;
120 u32 maxlen = 0, tmp32; /* for compare usage */
121 uint dump_imem_sz, imem_sz, dump_emem_sz, emem_sz; /* max = 49152; */
122 struct fw_hdr fwhdr;
123 u32 ulfilelength; /* FW file size */
124 void *phfwfile_hdl = NULL;
125 const u8 *pmappedfw = NULL;
126 u8 *ptmpchar = NULL, *ppayload, *ptr;
127 struct tx_desc *ptx_desc;
128 u32 txdscp_sz = sizeof(struct tx_desc);
129
130 ulfilelength = rtl871x_open_fw(padapter, &phfwfile_hdl, &pmappedfw);
131 if (pmappedfw && (ulfilelength > 0)) {
132 update_fwhdr(&fwhdr, pmappedfw);
133 if (chk_fwhdr(&fwhdr, ulfilelength) == _FAIL)
134 goto exit_fail;
135 fill_fwpriv(padapter, &fwhdr.fwpriv);
136 /* firmware check ok */
137 maxlen = (fwhdr.img_IMEM_size > fwhdr.img_SRAM_size) ?
138 fwhdr.img_IMEM_size : fwhdr.img_SRAM_size;
139 maxlen += txdscp_sz;
140 ptmpchar = _malloc(maxlen + FWBUFF_ALIGN_SZ);
141 if (ptmpchar == NULL)
142 return _FAIL;
143
144 ptx_desc = (struct tx_desc *)(ptmpchar + FWBUFF_ALIGN_SZ -
145 ((addr_t)(ptmpchar) & (FWBUFF_ALIGN_SZ - 1)));
146 ppayload = (u8 *)(ptx_desc) + txdscp_sz;
147 ptr = (u8 *)pmappedfw + FIELD_OFFSET(struct fw_hdr, fwpriv) +
148 fwhdr.fw_priv_sz;
149 /* Download FirmWare */
150 /* 1. determine IMEM code size and Load IMEM Code Section */
151 imem_sz = fwhdr.img_IMEM_size;
152 do {
153 memset(ptx_desc, 0, TXDESC_SIZE);
154 if (imem_sz > MAX_DUMP_FWSZ/*49152*/)
155 dump_imem_sz = MAX_DUMP_FWSZ;
156 else {
157 dump_imem_sz = imem_sz;
158 ptx_desc->txdw0 |= cpu_to_le32(BIT(28));
159 }
160 ptx_desc->txdw0 |= cpu_to_le32(dump_imem_sz &
161 0x0000ffff);
162 memcpy(ppayload, ptr, dump_imem_sz);
163 r8712_write_mem(padapter, RTL8712_DMA_VOQ,
164 dump_imem_sz + TXDESC_SIZE,
165 (u8 *)ptx_desc);
166 ptr += dump_imem_sz;
167 imem_sz -= dump_imem_sz;
168 } while (imem_sz > 0);
169 i = 10;
170 tmp16 = r8712_read16(padapter, TCR);
171 while (((tmp16 & _IMEM_CODE_DONE) == 0) && (i > 0)) {
172 udelay(10);
173 tmp16 = r8712_read16(padapter, TCR);
174 i--;
175 }
176 if (i == 0 || (tmp16 & _IMEM_CHK_RPT) == 0)
177 goto exit_fail;
178
179 /* 2.Download EMEM code size and Load EMEM Code Section */
180 emem_sz = fwhdr.img_SRAM_size;
181 do {
182 memset(ptx_desc, 0, TXDESC_SIZE);
183 if (emem_sz > MAX_DUMP_FWSZ) /* max=48k */
184 dump_emem_sz = MAX_DUMP_FWSZ;
185 else {
186 dump_emem_sz = emem_sz;
187 ptx_desc->txdw0 |= cpu_to_le32(BIT(28));
188 }
189 ptx_desc->txdw0 |= cpu_to_le32(dump_emem_sz &
190 0x0000ffff);
191 memcpy(ppayload, ptr, dump_emem_sz);
192 r8712_write_mem(padapter, RTL8712_DMA_VOQ,
193 dump_emem_sz+TXDESC_SIZE, (u8 *)ptx_desc);
194 ptr += dump_emem_sz;
195 emem_sz -= dump_emem_sz;
196 } while (emem_sz > 0);
197 i = 5;
198 tmp16 = r8712_read16(padapter, TCR);
199 while (((tmp16 & _EMEM_CODE_DONE) == 0) && (i > 0)) {
200 udelay(10);
201 tmp16 = r8712_read16(padapter, TCR);
202 i--;
203 }
204 if (i == 0 || (tmp16 & _EMEM_CHK_RPT) == 0)
205 goto exit_fail;
206
207 /* 3.Enable CPU */
208 tmp8 = r8712_read8(padapter, SYS_CLKR);
209 r8712_write8(padapter, SYS_CLKR, tmp8|BIT(2));
210 tmp8_a = r8712_read8(padapter, SYS_CLKR);
211 if (tmp8_a != (tmp8|BIT(2)))
212 goto exit_fail;
213
214 tmp8 = r8712_read8(padapter, SYS_FUNC_EN + 1);
215 r8712_write8(padapter, SYS_FUNC_EN+1, tmp8|BIT(2));
216 tmp8_a = r8712_read8(padapter, SYS_FUNC_EN + 1);
217 if (tmp8_a != (tmp8|BIT(2)))
218 goto exit_fail;
219
220 tmp32 = r8712_read32(padapter, TCR);
221
222 /* 4.polling IMEM Ready */
223 i = 100;
224 tmp16 = r8712_read16(padapter, TCR);
225 while (((tmp16 & _IMEM_RDY) == 0) && (i > 0)) {
226 msleep(20);
227 tmp16 = r8712_read16(padapter, TCR);
228 i--;
229 }
230 if (i == 0) {
231 r8712_write16(padapter, 0x10250348, 0xc000);
232 r8712_write16(padapter, 0x10250348, 0xc001);
233 r8712_write16(padapter, 0x10250348, 0x2000);
234 r8712_write16(padapter, 0x10250348, 0x2001);
235 r8712_write16(padapter, 0x10250348, 0x2002);
236 r8712_write16(padapter, 0x10250348, 0x2003);
237 goto exit_fail;
238 }
239 /* 5.Download DMEM code size and Load EMEM Code Section */
240 memset(ptx_desc, 0, TXDESC_SIZE);
241 ptx_desc->txdw0 |= cpu_to_le32(fwhdr.fw_priv_sz&0x0000ffff);
242 ptx_desc->txdw0 |= cpu_to_le32(BIT(28));
243 memcpy(ppayload, &fwhdr.fwpriv, fwhdr.fw_priv_sz);
244 r8712_write_mem(padapter, RTL8712_DMA_VOQ,
245 fwhdr.fw_priv_sz + TXDESC_SIZE, (u8 *)ptx_desc);
246
247 /* polling dmem code done */
248 i = 100;
249 tmp16 = r8712_read16(padapter, TCR);
250 while (((tmp16 & _DMEM_CODE_DONE) == 0) && (i > 0)) {
251 msleep(20);
252 tmp16 = r8712_read16(padapter, TCR);
253 i--;
254 }
255 if (i == 0)
256 goto exit_fail;
257
258 tmp8 = r8712_read8(padapter, 0x1025000A);
259 if (tmp8 & BIT(4)) /* When boot from EEPROM,
260 & FW need more time to read EEPROM */
261 i = 60;
262 else /* boot from EFUSE */
263 i = 30;
264 tmp16 = r8712_read16(padapter, TCR);
265 while (((tmp16 & _FWRDY) == 0) && (i > 0)) {
266 msleep(100);
267 tmp16 = r8712_read16(padapter, TCR);
268 i--;
269 }
270 if (i == 0)
271 goto exit_fail;
272 } else
273 goto exit_fail;
274 return _SUCCESS;
275
276exit_fail:
277 kfree(ptmpchar);
278 return _FAIL;
279}
280
281uint rtl8712_hal_init(struct _adapter *padapter)
282{
283 u32 val32;
284 int i;
285
286 /* r8712 firmware download */
287 if (rtl8712_dl_fw(padapter) != _SUCCESS)
288 return _FAIL;
289
290 printk(KERN_INFO "r8712u: 1 RCR=0x%x\n", r8712_read32(padapter, RCR));
291 val32 = r8712_read32(padapter, RCR);
292 r8712_write32(padapter, RCR, (val32 | BIT(26))); /* Enable RX TCP
293 Checksum offload */
294 printk(KERN_INFO "r8712u: 2 RCR=0x%x\n", r8712_read32(padapter, RCR));
295 val32 = r8712_read32(padapter, RCR);
296 r8712_write32(padapter, RCR, (val32|BIT(25))); /* Append PHY status */
297 val32 = 0;
298 val32 = r8712_read32(padapter, 0x10250040);
299 r8712_write32(padapter, 0x10250040, (val32&0x00FFFFFF));
300 /* for usb rx aggregation */
301 r8712_write8(padapter, 0x102500B5, r8712_read8(padapter, 0x102500B5) |
302 BIT(0)); /* page = 128bytes */
303 r8712_write8(padapter, 0x102500BD, r8712_read8(padapter, 0x102500BD) |
304 BIT(7)); /* enable usb rx aggregation */
305 r8712_write8(padapter, 0x102500D9, 1); /* TH=1 => means that invalidate
306 * usb rx aggregation */
307 r8712_write8(padapter, 0x1025FE5B, 0x04); /* 1.7ms/4 */
308 /* Fix the RX FIFO issue(USB error) */
309 r8712_write8(padapter, 0x1025fe5C, r8712_read8(padapter, 0x1025fe5C)
310 | BIT(7));
311 for (i = 0; i < 6; i++)
312 padapter->eeprompriv.mac_addr[i] = r8712_read8(padapter,
313 MACID + i);
314 return _SUCCESS;
315}
316
317uint rtl8712_hal_deinit(struct _adapter *padapter)
318{
319 r8712_write8(padapter, RF_CTRL, 0x00);
320 /* Turn off BB */
321 msleep(20);
322 /* Turn off MAC */
323 r8712_write8(padapter, SYS_CLKR+1, 0x38); /* Switch Control Path */
324 r8712_write8(padapter, SYS_FUNC_EN+1, 0x70);
325 r8712_write8(padapter, PMC_FSM, 0x06); /* Enable Loader Data Keep */
326 r8712_write8(padapter, SYS_ISO_CTRL, 0xF9); /* Isolation signals from
327 * CORE, PLL */
328 r8712_write8(padapter, SYS_ISO_CTRL+1, 0xe8); /* Enable EFUSE 1.2V */
329 r8712_write8(padapter, AFE_PLL_CTRL, 0x00); /* Disable AFE PLL. */
330 r8712_write8(padapter, LDOA15_CTRL, 0x54); /* Disable A15V */
331 r8712_write8(padapter, SYS_FUNC_EN+1, 0x50); /* Disable E-Fuse 1.2V */
332 r8712_write8(padapter, LDOV12D_CTRL, 0x24); /* Disable LDO12(for CE) */
333 r8712_write8(padapter, AFE_MISC, 0x30); /* Disable AFE BG&MB */
334 /* Option for Disable 1.6V LDO. */
335 r8712_write8(padapter, SPS0_CTRL, 0x56); /* Disable 1.6V LDO */
336 r8712_write8(padapter, SPS0_CTRL+1, 0x43); /* Set SW PFM */
337 return _SUCCESS;
338}
339
340uint rtl871x_hal_init(struct _adapter *padapter)
341{
342 padapter->hw_init_completed = false;
343 if (padapter->halpriv.hal_bus_init == NULL)
344 return _FAIL;
345 else {
346 if (padapter->halpriv.hal_bus_init(padapter) != _SUCCESS)
347 return _FAIL;
348 }
349 if (rtl8712_hal_init(padapter) == _SUCCESS)
350 padapter->hw_init_completed = true;
351 else {
352 padapter->hw_init_completed = false;
353 return _FAIL;
354 }
355 return _SUCCESS;
356}