blob: 1c0fe238d995326b81d026abe69bd1f251b8ae3e [file] [log] [blame]
Michael Wuf6532112007-10-14 14:43:16 -04001
2/*
3 * Radio tuning for RTL8225 on RTL8180
4 *
5 * Copyright 2007 Michael Wu <flamingice@sourmilk.net>
Andrea Merello93ba2a82013-08-26 13:53:30 +02006 * Copyright 2007 Andrea Merello <andrea.merello@gmail.com>
Michael Wuf6532112007-10-14 14:43:16 -04007 *
8 * Based on the r8180 driver, which is:
Andrea Merello93ba2a82013-08-26 13:53:30 +02009 * Copyright 2005 Andrea Merello <andrea.merello@gmail.com>, et al.
Michael Wuf6532112007-10-14 14:43:16 -040010 *
11 * Thanks to Realtek for their support!
12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License version 2 as
15 * published by the Free Software Foundation.
16 */
17
Michael Wuf6532112007-10-14 14:43:16 -040018#include <linux/pci.h>
19#include <linux/delay.h>
20#include <net/mac80211.h>
21
22#include "rtl8180.h"
John W. Linville3cfeb0c2010-12-20 15:16:53 -050023#include "rtl8225.h"
Michael Wuf6532112007-10-14 14:43:16 -040024
25static void rtl8225_write(struct ieee80211_hw *dev, u8 addr, u16 data)
26{
27 struct rtl8180_priv *priv = dev->priv;
28 u16 reg80, reg84, reg82;
29 u32 bangdata;
30 int i;
31
32 bangdata = (data << 4) | (addr & 0xf);
33
34 reg80 = rtl818x_ioread16(priv, &priv->map->RFPinsOutput) & 0xfff3;
35 reg82 = rtl818x_ioread16(priv, &priv->map->RFPinsEnable);
36
37 rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, reg82 | 0x7);
38
39 reg84 = rtl818x_ioread16(priv, &priv->map->RFPinsSelect);
40 rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84 | 0x7 | 0x400);
41 rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
42 udelay(10);
43
44 rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2));
45 rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
46 udelay(2);
47 rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80);
48 rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
49 udelay(10);
50
51 for (i = 15; i >= 0; i--) {
John W. Linville28eb3e52010-07-21 16:36:06 -040052 u16 reg = reg80;
53
54 if (bangdata & (1 << i))
55 reg |= 1;
Michael Wuf6532112007-10-14 14:43:16 -040056
57 if (i & 1)
58 rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg);
59
60 rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg | (1 << 1));
61 rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg | (1 << 1));
62
63 if (!(i & 1))
64 rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg);
65 }
66
67 rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2));
68 rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
69 udelay(10);
70
71 rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2));
72 rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84 | 0x400);
73 rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF);
74}
75
76static u16 rtl8225_read(struct ieee80211_hw *dev, u8 addr)
77{
78 struct rtl8180_priv *priv = dev->priv;
79 u16 reg80, reg82, reg84, out;
80 int i;
81
82 reg80 = rtl818x_ioread16(priv, &priv->map->RFPinsOutput);
83 reg82 = rtl818x_ioread16(priv, &priv->map->RFPinsEnable);
84 reg84 = rtl818x_ioread16(priv, &priv->map->RFPinsSelect) | 0x400;
85
86 reg80 &= ~0xF;
87
88 rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, reg82 | 0x000F);
89 rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84 | 0x000F);
90
91 rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2));
92 rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
93 udelay(4);
94 rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80);
95 rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
96 udelay(5);
97
98 for (i = 4; i >= 0; i--) {
99 u16 reg = reg80 | ((addr >> i) & 1);
100
101 if (!(i & 1)) {
102 rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg);
103 rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
104 udelay(1);
105 }
106
107 rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
108 reg | (1 << 1));
109 rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
110 udelay(2);
111 rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
112 reg | (1 << 1));
113 rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
114 udelay(2);
115
116 if (i & 1) {
117 rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg);
118 rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
119 udelay(1);
120 }
121 }
122
123 rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x000E);
124 rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0x040E);
125 rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
126 rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
127 reg80 | (1 << 3) | (1 << 1));
128 rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
129 udelay(2);
130 rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
131 reg80 | (1 << 3));
132 rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
133 udelay(2);
134 rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
135 reg80 | (1 << 3));
136 rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
137 udelay(2);
138
139 out = 0;
140 for (i = 11; i >= 0; i--) {
141 rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
142 reg80 | (1 << 3));
143 rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
144 udelay(1);
145 rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
146 reg80 | (1 << 3) | (1 << 1));
147 rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
148 udelay(2);
149 rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
150 reg80 | (1 << 3) | (1 << 1));
151 rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
152 udelay(2);
153 rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
154 reg80 | (1 << 3) | (1 << 1));
155 rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
156 udelay(2);
157
158 if (rtl818x_ioread16(priv, &priv->map->RFPinsInput) & (1 << 1))
159 out |= 1 << i;
160
161 rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
162 reg80 | (1 << 3));
163 rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
164 udelay(2);
165 }
166
167 rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
168 reg80 | (1 << 3) | (1 << 2));
169 rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
170 udelay(2);
171
172 rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, reg82);
173 rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84);
174 rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, 0x03A0);
175
176 return out;
177}
178
179static const u16 rtl8225bcd_rxgain[] = {
180 0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0408, 0x0409,
181 0x040a, 0x040b, 0x0502, 0x0503, 0x0504, 0x0505, 0x0540, 0x0541,
182 0x0542, 0x0543, 0x0544, 0x0545, 0x0580, 0x0581, 0x0582, 0x0583,
183 0x0584, 0x0585, 0x0588, 0x0589, 0x058a, 0x058b, 0x0643, 0x0644,
184 0x0645, 0x0680, 0x0681, 0x0682, 0x0683, 0x0684, 0x0685, 0x0688,
185 0x0689, 0x068a, 0x068b, 0x068c, 0x0742, 0x0743, 0x0744, 0x0745,
186 0x0780, 0x0781, 0x0782, 0x0783, 0x0784, 0x0785, 0x0788, 0x0789,
187 0x078a, 0x078b, 0x078c, 0x078d, 0x0790, 0x0791, 0x0792, 0x0793,
188 0x0794, 0x0795, 0x0798, 0x0799, 0x079a, 0x079b, 0x079c, 0x079d,
189 0x07a0, 0x07a1, 0x07a2, 0x07a3, 0x07a4, 0x07a5, 0x07a8, 0x07a9,
190 0x07aa, 0x07ab, 0x07ac, 0x07ad, 0x07b0, 0x07b1, 0x07b2, 0x07b3,
191 0x07b4, 0x07b5, 0x07b8, 0x07b9, 0x07ba, 0x07bb, 0x07bb
192};
193
194static const u8 rtl8225_agc[] = {
195 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e,
196 0x9d, 0x9c, 0x9b, 0x9a, 0x99, 0x98, 0x97, 0x96,
197 0x95, 0x94, 0x93, 0x92, 0x91, 0x90, 0x8f, 0x8e,
198 0x8d, 0x8c, 0x8b, 0x8a, 0x89, 0x88, 0x87, 0x86,
199 0x85, 0x84, 0x83, 0x82, 0x81, 0x80, 0x3f, 0x3e,
200 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38, 0x37, 0x36,
201 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x2f, 0x2e,
202 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 0x27, 0x26,
203 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x1f, 0x1e,
204 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18, 0x17, 0x16,
205 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0f, 0x0e,
206 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06,
207 0x05, 0x04, 0x03, 0x02, 0x01, 0x01, 0x01, 0x01,
208 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
209 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
210 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01
211};
212
213static const u8 rtl8225_gain[] = {
214 0x23, 0x88, 0x7c, 0xa5, /* -82dbm */
215 0x23, 0x88, 0x7c, 0xb5, /* -82dbm */
216 0x23, 0x88, 0x7c, 0xc5, /* -82dbm */
217 0x33, 0x80, 0x79, 0xc5, /* -78dbm */
218 0x43, 0x78, 0x76, 0xc5, /* -74dbm */
219 0x53, 0x60, 0x73, 0xc5, /* -70dbm */
220 0x63, 0x58, 0x70, 0xc5, /* -66dbm */
221};
222
223static const u8 rtl8225_threshold[] = {
224 0x8d, 0x8d, 0x8d, 0x8d, 0x9d, 0xad, 0xbd
225};
226
227static const u8 rtl8225_tx_gain_cck_ofdm[] = {
228 0x02, 0x06, 0x0e, 0x1e, 0x3e, 0x7e
229};
230
231static const u8 rtl8225_tx_power_cck[] = {
232 0x18, 0x17, 0x15, 0x11, 0x0c, 0x08, 0x04, 0x02,
233 0x1b, 0x1a, 0x17, 0x13, 0x0e, 0x09, 0x04, 0x02,
234 0x1f, 0x1e, 0x1a, 0x15, 0x10, 0x0a, 0x05, 0x02,
235 0x22, 0x21, 0x1d, 0x18, 0x11, 0x0b, 0x06, 0x02,
236 0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03,
237 0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03
238};
239
240static const u8 rtl8225_tx_power_cck_ch14[] = {
241 0x18, 0x17, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00,
242 0x1b, 0x1a, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00,
243 0x1f, 0x1e, 0x1a, 0x0f, 0x00, 0x00, 0x00, 0x00,
244 0x22, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x00, 0x00,
245 0x26, 0x25, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00,
246 0x2b, 0x2a, 0x25, 0x15, 0x00, 0x00, 0x00, 0x00
247};
248
249static const u8 rtl8225_tx_power_ofdm[] = {
250 0x80, 0x90, 0xa2, 0xb5, 0xcb, 0xe4
251};
252
253static const u32 rtl8225_chan[] = {
254 0x085c, 0x08dc, 0x095c, 0x09dc, 0x0a5c, 0x0adc, 0x0b5c,
255 0x0bdc, 0x0c5c, 0x0cdc, 0x0d5c, 0x0ddc, 0x0e5c, 0x0f72
256};
257
258static void rtl8225_rf_set_tx_power(struct ieee80211_hw *dev, int channel)
259{
260 struct rtl8180_priv *priv = dev->priv;
261 u8 cck_power, ofdm_power;
262 const u8 *tmp;
263 u32 reg;
264 int i;
265
Johannes Berg8318d782008-01-24 19:38:38 +0100266 cck_power = priv->channels[channel - 1].hw_value & 0xFF;
267 ofdm_power = priv->channels[channel - 1].hw_value >> 8;
Michael Wuf6532112007-10-14 14:43:16 -0400268
269 cck_power = min(cck_power, (u8)35);
270 ofdm_power = min(ofdm_power, (u8)35);
271
272 rtl818x_iowrite8(priv, &priv->map->TX_GAIN_CCK,
273 rtl8225_tx_gain_cck_ofdm[cck_power / 6] >> 1);
274
275 if (channel == 14)
276 tmp = &rtl8225_tx_power_cck_ch14[(cck_power % 6) * 8];
277 else
278 tmp = &rtl8225_tx_power_cck[(cck_power % 6) * 8];
279
280 for (i = 0; i < 8; i++)
281 rtl8225_write_phy_cck(dev, 0x44 + i, *tmp++);
282
283 msleep(1); /* FIXME: optional? */
284
285 /* anaparam2 on */
286 rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
287 reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
288 rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | RTL818X_CONFIG3_ANAPARAM_WRITE);
289 rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, RTL8225_ANAPARAM2_ON);
290 rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE);
291 rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
292
293 rtl818x_iowrite8(priv, &priv->map->TX_GAIN_OFDM,
294 rtl8225_tx_gain_cck_ofdm[ofdm_power/6] >> 1);
295
296 tmp = &rtl8225_tx_power_ofdm[ofdm_power % 6];
297
298 rtl8225_write_phy_ofdm(dev, 5, *tmp);
299 rtl8225_write_phy_ofdm(dev, 7, *tmp);
300
301 msleep(1);
302}
303
304static void rtl8225_rf_init(struct ieee80211_hw *dev)
305{
306 struct rtl8180_priv *priv = dev->priv;
307 int i;
308
309 rtl8180_set_anaparam(priv, RTL8225_ANAPARAM_ON);
310
311 /* host_pci_init */
312 rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, 0x0480);
313 rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF);
314 rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0x0488);
315 rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0);
316 rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
317 msleep(200); /* FIXME: ehh?? */
318 rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0xFF & ~(1 << 6));
319
320 rtl818x_iowrite32(priv, &priv->map->RF_TIMING, 0x000a8008);
321
322 /* TODO: check if we need really to change BRSR to do RF config */
323 rtl818x_ioread16(priv, &priv->map->BRSR);
324 rtl818x_iowrite16(priv, &priv->map->BRSR, 0xFFFF);
325 rtl818x_iowrite32(priv, &priv->map->RF_PARA, 0x00100044);
326 rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
327 rtl818x_iowrite8(priv, &priv->map->CONFIG3, 0x44);
328 rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
329
330 rtl8225_write(dev, 0x0, 0x067);
331 rtl8225_write(dev, 0x1, 0xFE0);
332 rtl8225_write(dev, 0x2, 0x44D);
333 rtl8225_write(dev, 0x3, 0x441);
334 rtl8225_write(dev, 0x4, 0x8BE);
335 rtl8225_write(dev, 0x5, 0xBF0); /* TODO: minipci */
336 rtl8225_write(dev, 0x6, 0xAE6);
337 rtl8225_write(dev, 0x7, rtl8225_chan[0]);
338 rtl8225_write(dev, 0x8, 0x01F);
339 rtl8225_write(dev, 0x9, 0x334);
340 rtl8225_write(dev, 0xA, 0xFD4);
341 rtl8225_write(dev, 0xB, 0x391);
342 rtl8225_write(dev, 0xC, 0x050);
343 rtl8225_write(dev, 0xD, 0x6DB);
344 rtl8225_write(dev, 0xE, 0x029);
345 rtl8225_write(dev, 0xF, 0x914); msleep(1);
346
347 rtl8225_write(dev, 0x2, 0xC4D); msleep(100);
348
349 rtl8225_write(dev, 0x0, 0x127);
350
351 for (i = 0; i < ARRAY_SIZE(rtl8225bcd_rxgain); i++) {
352 rtl8225_write(dev, 0x1, i + 1);
353 rtl8225_write(dev, 0x2, rtl8225bcd_rxgain[i]);
354 }
355
356 rtl8225_write(dev, 0x0, 0x027);
357 rtl8225_write(dev, 0x0, 0x22F);
358 rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF);
359
360 for (i = 0; i < ARRAY_SIZE(rtl8225_agc); i++) {
361 rtl8225_write_phy_ofdm(dev, 0xB, rtl8225_agc[i]);
362 msleep(1);
363 rtl8225_write_phy_ofdm(dev, 0xA, 0x80 + i);
364 msleep(1);
365 }
366
367 msleep(1);
368
369 rtl8225_write_phy_ofdm(dev, 0x00, 0x01); msleep(1);
370 rtl8225_write_phy_ofdm(dev, 0x01, 0x02); msleep(1);
371 rtl8225_write_phy_ofdm(dev, 0x02, 0x62); msleep(1);
372 rtl8225_write_phy_ofdm(dev, 0x03, 0x00); msleep(1);
373 rtl8225_write_phy_ofdm(dev, 0x04, 0x00); msleep(1);
374 rtl8225_write_phy_ofdm(dev, 0x05, 0x00); msleep(1);
375 rtl8225_write_phy_ofdm(dev, 0x06, 0x00); msleep(1);
376 rtl8225_write_phy_ofdm(dev, 0x07, 0x00); msleep(1);
377 rtl8225_write_phy_ofdm(dev, 0x08, 0x00); msleep(1);
378 rtl8225_write_phy_ofdm(dev, 0x09, 0xfe); msleep(1);
379 rtl8225_write_phy_ofdm(dev, 0x0a, 0x09); msleep(1);
380 rtl8225_write_phy_ofdm(dev, 0x0b, 0x80); msleep(1);
381 rtl8225_write_phy_ofdm(dev, 0x0c, 0x01); msleep(1);
382 rtl8225_write_phy_ofdm(dev, 0x0e, 0xd3); msleep(1);
383 rtl8225_write_phy_ofdm(dev, 0x0f, 0x38); msleep(1);
384 rtl8225_write_phy_ofdm(dev, 0x10, 0x84); msleep(1);
385 rtl8225_write_phy_ofdm(dev, 0x11, 0x03); msleep(1);
386 rtl8225_write_phy_ofdm(dev, 0x12, 0x20); msleep(1);
387 rtl8225_write_phy_ofdm(dev, 0x13, 0x20); msleep(1);
388 rtl8225_write_phy_ofdm(dev, 0x14, 0x00); msleep(1);
389 rtl8225_write_phy_ofdm(dev, 0x15, 0x40); msleep(1);
390 rtl8225_write_phy_ofdm(dev, 0x16, 0x00); msleep(1);
391 rtl8225_write_phy_ofdm(dev, 0x17, 0x40); msleep(1);
392 rtl8225_write_phy_ofdm(dev, 0x18, 0xef); msleep(1);
393 rtl8225_write_phy_ofdm(dev, 0x19, 0x19); msleep(1);
394 rtl8225_write_phy_ofdm(dev, 0x1a, 0x20); msleep(1);
395 rtl8225_write_phy_ofdm(dev, 0x1b, 0x76); msleep(1);
396 rtl8225_write_phy_ofdm(dev, 0x1c, 0x04); msleep(1);
397 rtl8225_write_phy_ofdm(dev, 0x1e, 0x95); msleep(1);
398 rtl8225_write_phy_ofdm(dev, 0x1f, 0x75); msleep(1);
399 rtl8225_write_phy_ofdm(dev, 0x20, 0x1f); msleep(1);
400 rtl8225_write_phy_ofdm(dev, 0x21, 0x27); msleep(1);
401 rtl8225_write_phy_ofdm(dev, 0x22, 0x16); msleep(1);
402 rtl8225_write_phy_ofdm(dev, 0x24, 0x46); msleep(1);
403 rtl8225_write_phy_ofdm(dev, 0x25, 0x20); msleep(1);
404 rtl8225_write_phy_ofdm(dev, 0x26, 0x90); msleep(1);
405 rtl8225_write_phy_ofdm(dev, 0x27, 0x88); msleep(1);
406
407 rtl8225_write_phy_cck(dev, 0x00, 0x98); msleep(1);
408 rtl8225_write_phy_cck(dev, 0x03, 0x20); msleep(1);
409 rtl8225_write_phy_cck(dev, 0x04, 0x7e); msleep(1);
410 rtl8225_write_phy_cck(dev, 0x05, 0x12); msleep(1);
411 rtl8225_write_phy_cck(dev, 0x06, 0xfc); msleep(1);
412 rtl8225_write_phy_cck(dev, 0x07, 0x78); msleep(1);
413 rtl8225_write_phy_cck(dev, 0x08, 0x2e); msleep(1);
414 rtl8225_write_phy_cck(dev, 0x10, 0x93); msleep(1);
415 rtl8225_write_phy_cck(dev, 0x11, 0x88); msleep(1);
416 rtl8225_write_phy_cck(dev, 0x12, 0x47); msleep(1);
417 rtl8225_write_phy_cck(dev, 0x13, 0xd0);
418 rtl8225_write_phy_cck(dev, 0x19, 0x00);
419 rtl8225_write_phy_cck(dev, 0x1a, 0xa0);
420 rtl8225_write_phy_cck(dev, 0x1b, 0x08);
421 rtl8225_write_phy_cck(dev, 0x40, 0x86);
422 rtl8225_write_phy_cck(dev, 0x41, 0x8d); msleep(1);
423 rtl8225_write_phy_cck(dev, 0x42, 0x15); msleep(1);
424 rtl8225_write_phy_cck(dev, 0x43, 0x18); msleep(1);
425 rtl8225_write_phy_cck(dev, 0x44, 0x1f); msleep(1);
426 rtl8225_write_phy_cck(dev, 0x45, 0x1e); msleep(1);
427 rtl8225_write_phy_cck(dev, 0x46, 0x1a); msleep(1);
428 rtl8225_write_phy_cck(dev, 0x47, 0x15); msleep(1);
429 rtl8225_write_phy_cck(dev, 0x48, 0x10); msleep(1);
430 rtl8225_write_phy_cck(dev, 0x49, 0x0a); msleep(1);
431 rtl8225_write_phy_cck(dev, 0x4a, 0x05); msleep(1);
432 rtl8225_write_phy_cck(dev, 0x4b, 0x02); msleep(1);
433 rtl8225_write_phy_cck(dev, 0x4c, 0x05); msleep(1);
434
435 rtl818x_iowrite8(priv, &priv->map->TESTR, 0x0D); msleep(1);
436
437 rtl8225_rf_set_tx_power(dev, 1);
438
439 /* RX antenna default to A */
440 rtl8225_write_phy_cck(dev, 0x10, 0x9b); msleep(1); /* B: 0xDB */
441 rtl8225_write_phy_ofdm(dev, 0x26, 0x90); msleep(1); /* B: 0x10 */
442
443 rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x03); /* B: 0x00 */
444 msleep(1);
445 rtl818x_iowrite32(priv, (__le32 __iomem *)((void __iomem *)priv->map + 0x94), 0x15c00002);
446 rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF);
447
448 rtl8225_write(dev, 0x0c, 0x50);
449 /* set OFDM initial gain */
450 rtl8225_write_phy_ofdm(dev, 0x0d, rtl8225_gain[4 * 4]);
451 rtl8225_write_phy_ofdm(dev, 0x23, rtl8225_gain[4 * 4 + 1]);
452 rtl8225_write_phy_ofdm(dev, 0x1b, rtl8225_gain[4 * 4 + 2]);
453 rtl8225_write_phy_ofdm(dev, 0x1d, rtl8225_gain[4 * 4 + 3]);
454 /* set CCK threshold */
455 rtl8225_write_phy_cck(dev, 0x41, rtl8225_threshold[0]);
456}
457
458static const u8 rtl8225z2_tx_power_cck_ch14[] = {
459 0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00
460};
461
462static const u8 rtl8225z2_tx_power_cck_B[] = {
463 0x30, 0x2f, 0x29, 0x21, 0x19, 0x10, 0x08, 0x04
464};
465
466static const u8 rtl8225z2_tx_power_cck_A[] = {
467 0x33, 0x32, 0x2b, 0x23, 0x1a, 0x11, 0x08, 0x04
468};
469
470static const u8 rtl8225z2_tx_power_cck[] = {
471 0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04
472};
473
474static void rtl8225z2_rf_set_tx_power(struct ieee80211_hw *dev, int channel)
475{
476 struct rtl8180_priv *priv = dev->priv;
477 u8 cck_power, ofdm_power;
478 const u8 *tmp;
479 int i;
480
Johannes Berg8318d782008-01-24 19:38:38 +0100481 cck_power = priv->channels[channel - 1].hw_value & 0xFF;
482 ofdm_power = priv->channels[channel - 1].hw_value >> 8;
Michael Wuf6532112007-10-14 14:43:16 -0400483
484 if (channel == 14)
485 tmp = rtl8225z2_tx_power_cck_ch14;
486 else if (cck_power == 12)
487 tmp = rtl8225z2_tx_power_cck_B;
488 else if (cck_power == 13)
489 tmp = rtl8225z2_tx_power_cck_A;
490 else
491 tmp = rtl8225z2_tx_power_cck;
492
493 for (i = 0; i < 8; i++)
494 rtl8225_write_phy_cck(dev, 0x44 + i, *tmp++);
495
496 cck_power = min(cck_power, (u8)35);
497 if (cck_power == 13 || cck_power == 14)
498 cck_power = 12;
499 if (cck_power >= 15)
500 cck_power -= 2;
501
502 rtl818x_iowrite8(priv, &priv->map->TX_GAIN_CCK, cck_power);
503 rtl818x_ioread8(priv, &priv->map->TX_GAIN_CCK);
504 msleep(1);
505
506 ofdm_power = min(ofdm_power, (u8)35);
507 rtl818x_iowrite8(priv, &priv->map->TX_GAIN_OFDM, ofdm_power);
508
509 rtl8225_write_phy_ofdm(dev, 2, 0x62);
510 rtl8225_write_phy_ofdm(dev, 5, 0x00);
511 rtl8225_write_phy_ofdm(dev, 6, 0x40);
512 rtl8225_write_phy_ofdm(dev, 7, 0x00);
513 rtl8225_write_phy_ofdm(dev, 8, 0x40);
514
515 msleep(1);
516}
517
518static const u16 rtl8225z2_rxgain[] = {
519 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0008, 0x0009,
520 0x000a, 0x000b, 0x0102, 0x0103, 0x0104, 0x0105, 0x0140, 0x0141,
521 0x0142, 0x0143, 0x0144, 0x0145, 0x0180, 0x0181, 0x0182, 0x0183,
522 0x0184, 0x0185, 0x0188, 0x0189, 0x018a, 0x018b, 0x0243, 0x0244,
523 0x0245, 0x0280, 0x0281, 0x0282, 0x0283, 0x0284, 0x0285, 0x0288,
524 0x0289, 0x028a, 0x028b, 0x028c, 0x0342, 0x0343, 0x0344, 0x0345,
525 0x0380, 0x0381, 0x0382, 0x0383, 0x0384, 0x0385, 0x0388, 0x0389,
526 0x038a, 0x038b, 0x038c, 0x038d, 0x0390, 0x0391, 0x0392, 0x0393,
527 0x0394, 0x0395, 0x0398, 0x0399, 0x039a, 0x039b, 0x039c, 0x039d,
528 0x03a0, 0x03a1, 0x03a2, 0x03a3, 0x03a4, 0x03a5, 0x03a8, 0x03a9,
529 0x03aa, 0x03ab, 0x03ac, 0x03ad, 0x03b0, 0x03b1, 0x03b2, 0x03b3,
530 0x03b4, 0x03b5, 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bb
531};
532
533static void rtl8225z2_rf_init(struct ieee80211_hw *dev)
534{
535 struct rtl8180_priv *priv = dev->priv;
536 int i;
537
538 rtl8180_set_anaparam(priv, RTL8225_ANAPARAM_ON);
539
540 /* host_pci_init */
541 rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, 0x0480);
542 rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF);
543 rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0x0488);
544 rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0);
545 rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
546 msleep(200); /* FIXME: ehh?? */
547 rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0xFF & ~(1 << 6));
548
549 rtl818x_iowrite32(priv, &priv->map->RF_TIMING, 0x00088008);
550
551 /* TODO: check if we need really to change BRSR to do RF config */
552 rtl818x_ioread16(priv, &priv->map->BRSR);
553 rtl818x_iowrite16(priv, &priv->map->BRSR, 0xFFFF);
554 rtl818x_iowrite32(priv, &priv->map->RF_PARA, 0x00100044);
555 rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
556 rtl818x_iowrite8(priv, &priv->map->CONFIG3, 0x44);
557 rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
558
559 rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF);
560
561 rtl8225_write(dev, 0x0, 0x0B7); msleep(1);
562 rtl8225_write(dev, 0x1, 0xEE0); msleep(1);
563 rtl8225_write(dev, 0x2, 0x44D); msleep(1);
564 rtl8225_write(dev, 0x3, 0x441); msleep(1);
565 rtl8225_write(dev, 0x4, 0x8C3); msleep(1);
566 rtl8225_write(dev, 0x5, 0xC72); msleep(1);
567 rtl8225_write(dev, 0x6, 0x0E6); msleep(1);
568 rtl8225_write(dev, 0x7, 0x82A); msleep(1);
569 rtl8225_write(dev, 0x8, 0x03F); msleep(1);
570 rtl8225_write(dev, 0x9, 0x335); msleep(1);
571 rtl8225_write(dev, 0xa, 0x9D4); msleep(1);
572 rtl8225_write(dev, 0xb, 0x7BB); msleep(1);
573 rtl8225_write(dev, 0xc, 0x850); msleep(1);
574 rtl8225_write(dev, 0xd, 0xCDF); msleep(1);
575 rtl8225_write(dev, 0xe, 0x02B); msleep(1);
576 rtl8225_write(dev, 0xf, 0x114); msleep(100);
577
578 if (!(rtl8225_read(dev, 6) & (1 << 7))) {
579 rtl8225_write(dev, 0x02, 0x0C4D);
580 msleep(200);
581 rtl8225_write(dev, 0x02, 0x044D);
582 msleep(100);
583 /* TODO: readd calibration failure message when the calibration
584 check works */
585 }
586
587 rtl8225_write(dev, 0x0, 0x1B7);
588 rtl8225_write(dev, 0x3, 0x002);
589 rtl8225_write(dev, 0x5, 0x004);
590
591 for (i = 0; i < ARRAY_SIZE(rtl8225z2_rxgain); i++) {
592 rtl8225_write(dev, 0x1, i + 1);
593 rtl8225_write(dev, 0x2, rtl8225z2_rxgain[i]);
594 }
595
596 rtl8225_write(dev, 0x0, 0x0B7); msleep(100);
597 rtl8225_write(dev, 0x2, 0xC4D);
598
599 msleep(200);
600 rtl8225_write(dev, 0x2, 0x44D);
601 msleep(100);
602
603 rtl8225_write(dev, 0x00, 0x2BF);
604 rtl8225_write(dev, 0xFF, 0xFFFF);
605
606 rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF);
607
608 for (i = 0; i < ARRAY_SIZE(rtl8225_agc); i++) {
609 rtl8225_write_phy_ofdm(dev, 0xB, rtl8225_agc[i]);
610 msleep(1);
611 rtl8225_write_phy_ofdm(dev, 0xA, 0x80 + i);
612 msleep(1);
613 }
614
615 msleep(1);
616
617 rtl8225_write_phy_ofdm(dev, 0x00, 0x01); msleep(1);
618 rtl8225_write_phy_ofdm(dev, 0x01, 0x02); msleep(1);
619 rtl8225_write_phy_ofdm(dev, 0x02, 0x62); msleep(1);
620 rtl8225_write_phy_ofdm(dev, 0x03, 0x00); msleep(1);
621 rtl8225_write_phy_ofdm(dev, 0x04, 0x00); msleep(1);
622 rtl8225_write_phy_ofdm(dev, 0x05, 0x00); msleep(1);
623 rtl8225_write_phy_ofdm(dev, 0x06, 0x40); msleep(1);
624 rtl8225_write_phy_ofdm(dev, 0x07, 0x00); msleep(1);
625 rtl8225_write_phy_ofdm(dev, 0x08, 0x40); msleep(1);
626 rtl8225_write_phy_ofdm(dev, 0x09, 0xfe); msleep(1);
627 rtl8225_write_phy_ofdm(dev, 0x0a, 0x09); msleep(1);
628 rtl8225_write_phy_ofdm(dev, 0x18, 0xef); msleep(1);
629 rtl8225_write_phy_ofdm(dev, 0x0b, 0x80); msleep(1);
630 rtl8225_write_phy_ofdm(dev, 0x0c, 0x01); msleep(1);
631 rtl8225_write_phy_ofdm(dev, 0x0d, 0x43);
632 rtl8225_write_phy_ofdm(dev, 0x0e, 0xd3); msleep(1);
633 rtl8225_write_phy_ofdm(dev, 0x0f, 0x38); msleep(1);
634 rtl8225_write_phy_ofdm(dev, 0x10, 0x84); msleep(1);
635 rtl8225_write_phy_ofdm(dev, 0x11, 0x06); msleep(1);
636 rtl8225_write_phy_ofdm(dev, 0x12, 0x20); msleep(1);
637 rtl8225_write_phy_ofdm(dev, 0x13, 0x20); msleep(1);
638 rtl8225_write_phy_ofdm(dev, 0x14, 0x00); msleep(1);
639 rtl8225_write_phy_ofdm(dev, 0x15, 0x40); msleep(1);
640 rtl8225_write_phy_ofdm(dev, 0x16, 0x00); msleep(1);
641 rtl8225_write_phy_ofdm(dev, 0x17, 0x40); msleep(1);
642 rtl8225_write_phy_ofdm(dev, 0x18, 0xef); msleep(1);
643 rtl8225_write_phy_ofdm(dev, 0x19, 0x19); msleep(1);
644 rtl8225_write_phy_ofdm(dev, 0x1a, 0x20); msleep(1);
645 rtl8225_write_phy_ofdm(dev, 0x1b, 0x11); msleep(1);
646 rtl8225_write_phy_ofdm(dev, 0x1c, 0x04); msleep(1);
647 rtl8225_write_phy_ofdm(dev, 0x1d, 0xc5); msleep(1);
648 rtl8225_write_phy_ofdm(dev, 0x1e, 0xb3); msleep(1);
649 rtl8225_write_phy_ofdm(dev, 0x1f, 0x75); msleep(1);
650 rtl8225_write_phy_ofdm(dev, 0x20, 0x1f); msleep(1);
651 rtl8225_write_phy_ofdm(dev, 0x21, 0x27); msleep(1);
652 rtl8225_write_phy_ofdm(dev, 0x22, 0x16); msleep(1);
653 rtl8225_write_phy_ofdm(dev, 0x23, 0x80); msleep(1); /* FIXME: not needed? */
654 rtl8225_write_phy_ofdm(dev, 0x24, 0x46); msleep(1);
655 rtl8225_write_phy_ofdm(dev, 0x25, 0x20); msleep(1);
656 rtl8225_write_phy_ofdm(dev, 0x26, 0x90); msleep(1);
657 rtl8225_write_phy_ofdm(dev, 0x27, 0x88); msleep(1);
658
659 rtl8225_write_phy_cck(dev, 0x00, 0x98); msleep(1);
660 rtl8225_write_phy_cck(dev, 0x03, 0x20); msleep(1);
661 rtl8225_write_phy_cck(dev, 0x04, 0x7e); msleep(1);
662 rtl8225_write_phy_cck(dev, 0x05, 0x12); msleep(1);
663 rtl8225_write_phy_cck(dev, 0x06, 0xfc); msleep(1);
664 rtl8225_write_phy_cck(dev, 0x07, 0x78); msleep(1);
665 rtl8225_write_phy_cck(dev, 0x08, 0x2e); msleep(1);
666 rtl8225_write_phy_cck(dev, 0x10, 0x93); msleep(1);
667 rtl8225_write_phy_cck(dev, 0x11, 0x88); msleep(1);
668 rtl8225_write_phy_cck(dev, 0x12, 0x47); msleep(1);
669 rtl8225_write_phy_cck(dev, 0x13, 0xd0);
670 rtl8225_write_phy_cck(dev, 0x19, 0x00);
671 rtl8225_write_phy_cck(dev, 0x1a, 0xa0);
672 rtl8225_write_phy_cck(dev, 0x1b, 0x08);
673 rtl8225_write_phy_cck(dev, 0x40, 0x86);
674 rtl8225_write_phy_cck(dev, 0x41, 0x8a); msleep(1);
675 rtl8225_write_phy_cck(dev, 0x42, 0x15); msleep(1);
676 rtl8225_write_phy_cck(dev, 0x43, 0x18); msleep(1);
677 rtl8225_write_phy_cck(dev, 0x44, 0x36); msleep(1);
678 rtl8225_write_phy_cck(dev, 0x45, 0x35); msleep(1);
679 rtl8225_write_phy_cck(dev, 0x46, 0x2e); msleep(1);
680 rtl8225_write_phy_cck(dev, 0x47, 0x25); msleep(1);
681 rtl8225_write_phy_cck(dev, 0x48, 0x1c); msleep(1);
682 rtl8225_write_phy_cck(dev, 0x49, 0x12); msleep(1);
683 rtl8225_write_phy_cck(dev, 0x4a, 0x09); msleep(1);
684 rtl8225_write_phy_cck(dev, 0x4b, 0x04); msleep(1);
685 rtl8225_write_phy_cck(dev, 0x4c, 0x05); msleep(1);
686
687 rtl818x_iowrite8(priv, (u8 __iomem *)((void __iomem *)priv->map + 0x5B), 0x0D); msleep(1);
688
689 rtl8225z2_rf_set_tx_power(dev, 1);
690
691 /* RX antenna default to A */
692 rtl8225_write_phy_cck(dev, 0x10, 0x9b); msleep(1); /* B: 0xDB */
693 rtl8225_write_phy_ofdm(dev, 0x26, 0x90); msleep(1); /* B: 0x10 */
694
695 rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x03); /* B: 0x00 */
696 msleep(1);
697 rtl818x_iowrite32(priv, (__le32 __iomem *)((void __iomem *)priv->map + 0x94), 0x15c00002);
698 rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF);
699}
700
701static void rtl8225_rf_stop(struct ieee80211_hw *dev)
702{
703 struct rtl8180_priv *priv = dev->priv;
704 u8 reg;
705
706 rtl8225_write(dev, 0x4, 0x1f); msleep(1);
707
708 rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
709 reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
710 rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | RTL818X_CONFIG3_ANAPARAM_WRITE);
711 rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, RTL8225_ANAPARAM2_OFF);
712 rtl818x_iowrite32(priv, &priv->map->ANAPARAM, RTL8225_ANAPARAM_OFF);
713 rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE);
714 rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
715}
716
717static void rtl8225_rf_set_channel(struct ieee80211_hw *dev,
718 struct ieee80211_conf *conf)
719{
720 struct rtl8180_priv *priv = dev->priv;
Karl Beldan675a0b02013-03-25 16:26:57 +0100721 int chan =
722 ieee80211_frequency_to_channel(conf->chandef.chan->center_freq);
Michael Wuf6532112007-10-14 14:43:16 -0400723
724 if (priv->rf->init == rtl8225_rf_init)
Johannes Berg8318d782008-01-24 19:38:38 +0100725 rtl8225_rf_set_tx_power(dev, chan);
Michael Wuf6532112007-10-14 14:43:16 -0400726 else
Johannes Berg8318d782008-01-24 19:38:38 +0100727 rtl8225z2_rf_set_tx_power(dev, chan);
Michael Wuf6532112007-10-14 14:43:16 -0400728
Johannes Berg8318d782008-01-24 19:38:38 +0100729 rtl8225_write(dev, 0x7, rtl8225_chan[chan - 1]);
Michael Wuf6532112007-10-14 14:43:16 -0400730 msleep(10);
John W. Linvilleda81ded2008-11-12 14:37:11 -0500731}
Michael Wuf6532112007-10-14 14:43:16 -0400732
Michael Wuf6532112007-10-14 14:43:16 -0400733static const struct rtl818x_rf_ops rtl8225_ops = {
734 .name = "rtl8225",
735 .init = rtl8225_rf_init,
736 .stop = rtl8225_rf_stop,
John W. Linvilleda81ded2008-11-12 14:37:11 -0500737 .set_chan = rtl8225_rf_set_channel,
Michael Wuf6532112007-10-14 14:43:16 -0400738};
739
740static const struct rtl818x_rf_ops rtl8225z2_ops = {
741 .name = "rtl8225z2",
742 .init = rtl8225z2_rf_init,
743 .stop = rtl8225_rf_stop,
John W. Linvilleda81ded2008-11-12 14:37:11 -0500744 .set_chan = rtl8225_rf_set_channel,
Michael Wuf6532112007-10-14 14:43:16 -0400745};
746
747const struct rtl818x_rf_ops * rtl8180_detect_rf(struct ieee80211_hw *dev)
748{
749 struct rtl8180_priv *priv = dev->priv;
750 u16 reg8, reg9;
751
752 rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, 0x0480);
753 rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0x0488);
754 rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF);
755 rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
756 msleep(100);
757
758 rtl8225_write(dev, 0, 0x1B7);
759
760 reg8 = rtl8225_read(dev, 8);
761 reg9 = rtl8225_read(dev, 9);
762
763 rtl8225_write(dev, 0, 0x0B7);
764
765 if (reg8 != 0x588 || reg9 != 0x700)
766 return &rtl8225_ops;
767
768 return &rtl8225z2_ops;
769}