blob: 3ac235770863719614ad71df591527c67d7a96f3 [file] [log] [blame]
Rafał Miłecki1d738e62011-07-07 15:25:27 +02001/*
2
3 Broadcom B43 wireless driver
4 IEEE 802.11n LCN-PHY support
5
Rafał Miłecki108f4f32011-09-03 21:01:02 +02006 Copyright (c) 2011 Rafał Miłecki <zajec5@gmail.com>
7
Rafał Miłecki1d738e62011-07-07 15:25:27 +02008 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; see the file COPYING. If not, write to
20 the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
21 Boston, MA 02110-1301, USA.
22
Rafał Miłeckib5347062011-09-16 12:33:59 +020023 This file incorporates work covered by the following copyright and
24 permission notice:
25
26 Copyright (c) 2010 Broadcom Corporation
27
28 Permission to use, copy, modify, and/or distribute this software for any
29 purpose with or without fee is hereby granted, provided that the above
30 copyright notice and this permission notice appear in all copies.
Rafał Miłecki1d738e62011-07-07 15:25:27 +020031*/
32
33#include <linux/slab.h>
34
35#include "b43.h"
36#include "phy_lcn.h"
37#include "tables_phy_lcn.h"
38#include "main.h"
39
Rafał Miłecki1b0a69c2011-09-16 12:34:02 +020040struct lcn_tx_gains {
41 u16 gm_gain;
42 u16 pga_gain;
43 u16 pad_gain;
44 u16 dac_gain;
45};
46
Rafał Miłecki0c5644b92011-09-16 12:34:00 +020047struct lcn_tx_iir_filter {
48 u8 type;
49 u16 values[16];
50};
51
Rafał Miłeckiac78a522011-09-16 12:34:01 +020052/* In theory it's PHY common function, move if needed */
53/* brcms_b_switch_macfreq */
54static void b43_phy_switch_macfreq(struct b43_wldev *dev, u8 spurmode)
55{
56 if (dev->dev->chip_id == 43224 || dev->dev->chip_id == 43225) {
57 switch (spurmode) {
58 case 2: /* 126 Mhz */
59 b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_LOW, 0x2082);
60 b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_HIGH, 0x8);
61 break;
62 case 1: /* 123 Mhz */
63 b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_LOW, 0x5341);
64 b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_HIGH, 0x8);
65 break;
66 default: /* 120 Mhz */
67 b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_LOW, 0x8889);
68 b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_HIGH, 0x8);
69 break;
70 }
71 } else if (dev->phy.type == B43_PHYTYPE_LCN) {
72 switch (spurmode) {
73 case 1: /* 82 Mhz */
74 b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_LOW, 0x7CE0);
75 b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_HIGH, 0xC);
76 break;
77 default: /* 80 Mhz */
78 b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_LOW, 0xCCCD);
79 b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_HIGH, 0xC);
80 break;
81 }
82 }
83}
84
Rafał Miłecki1d738e62011-07-07 15:25:27 +020085/**************************************************
Rafał Miłeckidc713fb2011-08-15 18:50:56 +020086 * Radio 2064.
87 **************************************************/
88
Rafał Miłeckibce4dc42011-08-31 23:36:20 +020089/* wlc_lcnphy_radio_2064_channel_tune_4313 */
Rafał Miłecki39f7d332011-08-28 14:59:58 +020090static void b43_radio_2064_channel_setup(struct b43_wldev *dev)
91{
92 u16 save[2];
93
94 b43_radio_set(dev, 0x09d, 0x4);
95 b43_radio_write(dev, 0x09e, 0xf);
96
Rafał Miłeckicf577fc2011-08-31 23:36:21 +020097 /* Channel specific values in theory, in practice always the same */
Rafał Miłecki39f7d332011-08-28 14:59:58 +020098 b43_radio_write(dev, 0x02a, 0xb);
99 b43_radio_maskset(dev, 0x030, ~0x3, 0xa);
100 b43_radio_maskset(dev, 0x091, ~0x3, 0);
101 b43_radio_maskset(dev, 0x038, ~0xf, 0x7);
102 b43_radio_maskset(dev, 0x030, ~0xc, 0x8);
103 b43_radio_maskset(dev, 0x05e, ~0xf, 0x8);
104 b43_radio_maskset(dev, 0x05e, ~0xf0, 0x80);
105 b43_radio_write(dev, 0x06c, 0x80);
106
107 save[0] = b43_radio_read(dev, 0x044);
108 save[1] = b43_radio_read(dev, 0x12b);
109
110 b43_radio_set(dev, 0x044, 0x7);
111 b43_radio_set(dev, 0x12b, 0xe);
112
113 /* TODO */
114
115 b43_radio_write(dev, 0x040, 0xfb);
116
117 b43_radio_write(dev, 0x041, 0x9a);
118 b43_radio_write(dev, 0x042, 0xa3);
119 b43_radio_write(dev, 0x043, 0x0c);
120
121 /* TODO */
122
123 b43_radio_set(dev, 0x044, 0x0c);
124 udelay(1);
125
126 b43_radio_write(dev, 0x044, save[0]);
127 b43_radio_write(dev, 0x12b, save[1]);
128
Rafał Miłeckicf577fc2011-08-31 23:36:21 +0200129 if (dev->phy.rev == 1) {
130 /* brcmsmac uses outdated 0x3 for 0x038 */
131 b43_radio_write(dev, 0x038, 0x0);
132 b43_radio_write(dev, 0x091, 0x7);
133 }
Rafał Miłecki39f7d332011-08-28 14:59:58 +0200134}
135
Rafał Miłeckibce4dc42011-08-31 23:36:20 +0200136/* wlc_radio_2064_init */
Rafał Miłeckidc713fb2011-08-15 18:50:56 +0200137static void b43_radio_2064_init(struct b43_wldev *dev)
138{
Rafał Miłeckicf577fc2011-08-31 23:36:21 +0200139 if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
140 b43_radio_write(dev, 0x09c, 0x0020);
141 b43_radio_write(dev, 0x105, 0x0008);
142 } else {
143 /* TODO */
144 }
Rafał Miłeckidc713fb2011-08-15 18:50:56 +0200145 b43_radio_write(dev, 0x032, 0x0062);
146 b43_radio_write(dev, 0x033, 0x0019);
147 b43_radio_write(dev, 0x090, 0x0010);
148 b43_radio_write(dev, 0x010, 0x0000);
Rafał Miłeckicf577fc2011-08-31 23:36:21 +0200149 if (dev->phy.rev == 1) {
150 b43_radio_write(dev, 0x060, 0x007f);
151 b43_radio_write(dev, 0x061, 0x0072);
152 b43_radio_write(dev, 0x062, 0x007f);
153 }
Rafał Miłeckidc713fb2011-08-15 18:50:56 +0200154 b43_radio_write(dev, 0x01d, 0x0002);
155 b43_radio_write(dev, 0x01e, 0x0006);
156
157 b43_phy_write(dev, 0x4ea, 0x4688);
158 b43_phy_maskset(dev, 0x4eb, ~0x7, 0x2);
159 b43_phy_mask(dev, 0x4eb, ~0x01c0);
Rafał Miłeckibd3bf692011-08-28 14:28:44 +0200160 b43_phy_maskset(dev, 0x46a, 0xff00, 0x19);
Rafał Miłeckidc713fb2011-08-15 18:50:56 +0200161
162 b43_lcntab_write(dev, B43_LCNTAB16(0x00, 0x55), 0);
163
164 b43_radio_mask(dev, 0x05b, (u16) ~0xff02);
165 b43_radio_set(dev, 0x004, 0x40);
166 b43_radio_set(dev, 0x120, 0x10);
167 b43_radio_set(dev, 0x078, 0x80);
168 b43_radio_set(dev, 0x129, 0x2);
169 b43_radio_set(dev, 0x057, 0x1);
170 b43_radio_set(dev, 0x05b, 0x2);
171
172 /* TODO: wait for some bit to be set */
173 b43_radio_read(dev, 0x05c);
174
175 b43_radio_mask(dev, 0x05b, (u16) ~0xff02);
176 b43_radio_mask(dev, 0x057, (u16) ~0xff01);
177
178 b43_phy_write(dev, 0x933, 0x2d6b);
179 b43_phy_write(dev, 0x934, 0x2d6b);
180 b43_phy_write(dev, 0x935, 0x2d6b);
181 b43_phy_write(dev, 0x936, 0x2d6b);
182 b43_phy_write(dev, 0x937, 0x016b);
183
184 b43_radio_mask(dev, 0x057, (u16) ~0xff02);
185 b43_radio_write(dev, 0x0c2, 0x006f);
186}
187
188/**************************************************
Rafał Miłecki78bc2462011-08-15 18:50:55 +0200189 * Various PHY ops
190 **************************************************/
191
Rafał Miłeckibce4dc42011-08-31 23:36:20 +0200192/* wlc_lcnphy_toggle_afe_pwdn */
Rafał Miłecki78bc2462011-08-15 18:50:55 +0200193static void b43_phy_lcn_afe_set_unset(struct b43_wldev *dev)
194{
195 u16 afe_ctl2 = b43_phy_read(dev, B43_PHY_LCN_AFE_CTL2);
196 u16 afe_ctl1 = b43_phy_read(dev, B43_PHY_LCN_AFE_CTL1);
197
198 b43_phy_write(dev, B43_PHY_LCN_AFE_CTL2, afe_ctl2 | 0x1);
199 b43_phy_write(dev, B43_PHY_LCN_AFE_CTL1, afe_ctl1 | 0x1);
200
201 b43_phy_write(dev, B43_PHY_LCN_AFE_CTL2, afe_ctl2 & ~0x1);
202 b43_phy_write(dev, B43_PHY_LCN_AFE_CTL1, afe_ctl1 & ~0x1);
203
204 b43_phy_write(dev, B43_PHY_LCN_AFE_CTL2, afe_ctl2);
205 b43_phy_write(dev, B43_PHY_LCN_AFE_CTL1, afe_ctl1);
206}
207
Rafał Miłecki1b0a69c2011-09-16 12:34:02 +0200208/* wlc_lcnphy_get_pa_gain */
209static u16 b43_phy_lcn_get_pa_gain(struct b43_wldev *dev)
210{
211 return (b43_phy_read(dev, 0x4fb) & 0x7f00) >> 8;
212}
213
214/* wlc_lcnphy_set_dac_gain */
215static void b43_phy_lcn_set_dac_gain(struct b43_wldev *dev, u16 dac_gain)
216{
217 u16 dac_ctrl;
218
219 dac_ctrl = b43_phy_read(dev, 0x439);
220 dac_ctrl = dac_ctrl & 0xc7f;
221 dac_ctrl = dac_ctrl | (dac_gain << 7);
222 b43_phy_maskset(dev, 0x439, ~0xfff, dac_ctrl);
223}
224
225/* wlc_lcnphy_set_bbmult */
226static void b43_phy_lcn_set_bbmult(struct b43_wldev *dev, u8 m0)
227{
228 b43_lcntab_write(dev, B43_LCNTAB16(0x00, 0x57), m0 << 8);
229}
230
Rafał Miłeckibce4dc42011-08-31 23:36:20 +0200231/* wlc_lcnphy_clear_tx_power_offsets */
232static void b43_phy_lcn_clear_tx_power_offsets(struct b43_wldev *dev)
Rafał Miłecki78bc2462011-08-15 18:50:55 +0200233{
234 u8 i;
235
Rafał Miłeckicf577fc2011-08-31 23:36:21 +0200236 if (1) { /* FIXME */
237 b43_phy_write(dev, B43_PHY_LCN_TABLE_ADDR, (0x7 << 10) | 0x340);
238 for (i = 0; i < 30; i++) {
239 b43_phy_write(dev, B43_PHY_LCN_TABLE_DATAHI, 0);
240 b43_phy_write(dev, B43_PHY_LCN_TABLE_DATALO, 0);
241 }
Rafał Miłecki78bc2462011-08-15 18:50:55 +0200242 }
243
244 b43_phy_write(dev, B43_PHY_LCN_TABLE_ADDR, (0x7 << 10) | 0x80);
245 for (i = 0; i < 64; i++) {
246 b43_phy_write(dev, B43_PHY_LCN_TABLE_DATAHI, 0);
247 b43_phy_write(dev, B43_PHY_LCN_TABLE_DATALO, 0);
248 }
249}
250
Rafał Miłeckibce4dc42011-08-31 23:36:20 +0200251/* wlc_lcnphy_rev0_baseband_init */
252static void b43_phy_lcn_rev0_baseband_init(struct b43_wldev *dev)
Rafał Miłeckibd3bf692011-08-28 14:28:44 +0200253{
254 b43_radio_write(dev, 0x11c, 0);
255
256 b43_phy_write(dev, 0x43b, 0);
257 b43_phy_write(dev, 0x43c, 0);
258 b43_phy_write(dev, 0x44c, 0);
259 b43_phy_write(dev, 0x4e6, 0);
260 b43_phy_write(dev, 0x4f9, 0);
261 b43_phy_write(dev, 0x4b0, 0);
262 b43_phy_write(dev, 0x938, 0);
263 b43_phy_write(dev, 0x4b0, 0);
264 b43_phy_write(dev, 0x44e, 0);
265
266 b43_phy_set(dev, 0x567, 0x03);
267
268 b43_phy_set(dev, 0x44a, 0x44);
269 b43_phy_write(dev, 0x44a, 0x80);
270
Rafał Miłeckicf577fc2011-08-31 23:36:21 +0200271 if (!(dev->dev->bus_sprom->boardflags_lo & B43_BFL_FEM))
272 ; /* TODO */
Rafał Miłeckibd3bf692011-08-28 14:28:44 +0200273 b43_phy_maskset(dev, 0x634, ~0xff, 0xc);
Rafał Miłeckicf577fc2011-08-31 23:36:21 +0200274 if (dev->dev->bus_sprom->boardflags_lo & B43_BFL_FEM) {
275 b43_phy_maskset(dev, 0x634, ~0xff, 0xa);
276 b43_phy_write(dev, 0x910, 0x1);
277 }
Rafał Miłeckibd3bf692011-08-28 14:28:44 +0200278
279 b43_phy_write(dev, 0x910, 0x1);
280
281 b43_phy_maskset(dev, 0x448, ~0x300, 0x100);
282 b43_phy_maskset(dev, 0x608, ~0xff, 0x17);
283 b43_phy_maskset(dev, 0x604, ~0x7ff, 0x3ea);
Rafał Miłeckibce4dc42011-08-31 23:36:20 +0200284}
Rafał Miłeckibd3bf692011-08-28 14:28:44 +0200285
Rafał Miłeckibce4dc42011-08-31 23:36:20 +0200286/* wlc_lcnphy_bu_tweaks */
287static void b43_phy_lcn_bu_tweaks(struct b43_wldev *dev)
288{
Rafał Miłeckibd3bf692011-08-28 14:28:44 +0200289 b43_phy_set(dev, 0x805, 0x1);
290
291 b43_phy_maskset(dev, 0x42f, ~0x7, 0x3);
292 b43_phy_maskset(dev, 0x030, ~0x7, 0x3);
293
294 b43_phy_write(dev, 0x414, 0x1e10);
295 b43_phy_write(dev, 0x415, 0x0640);
296
297 b43_phy_maskset(dev, 0x4df, (u16) ~0xff00, 0xf700);
298
299 b43_phy_set(dev, 0x44a, 0x44);
300 b43_phy_write(dev, 0x44a, 0x80);
301
302 b43_phy_maskset(dev, 0x434, ~0xff, 0xfd);
303 b43_phy_maskset(dev, 0x420, ~0xff, 0x10);
304
Rafał Miłeckicf577fc2011-08-31 23:36:21 +0200305 if (dev->dev->bus_sprom->board_rev >= 0x1204)
306 b43_radio_set(dev, 0x09b, 0xf0);
Rafał Miłeckibd3bf692011-08-28 14:28:44 +0200307
308 b43_phy_write(dev, 0x7d6, 0x0902);
309
Rafał Miłeckibbb55742011-09-16 12:34:03 +0200310 b43_phy_maskset(dev, 0x429, ~0xf, 0x9);
311 b43_phy_maskset(dev, 0x429, ~(0x3f << 4), 0xe << 4);
Rafał Miłeckibce4dc42011-08-31 23:36:20 +0200312
313 if (dev->phy.rev == 1) {
Rafał Miłeckibbb55742011-09-16 12:34:03 +0200314 b43_phy_maskset(dev, 0x423, ~0xff, 0x46);
315 b43_phy_maskset(dev, 0x411, ~0xff, 1);
316 b43_phy_set(dev, 0x434, 0xff); /* FIXME: update to wl */
317
318 /* TODO: wl operates on PHY 0x416, brcmsmac is outdated here */
319
320 b43_phy_maskset(dev, 0x656, ~0xf, 2);
321 b43_phy_set(dev, 0x44d, 4);
322
323 b43_radio_set(dev, 0x0f7, 0x4);
324 b43_radio_mask(dev, 0x0f1, ~0x3);
325 b43_radio_maskset(dev, 0x0f2, ~0xf8, 0x90);
326 b43_radio_maskset(dev, 0x0f3, ~0x3, 0x2);
327 b43_radio_maskset(dev, 0x0f3, ~0xf0, 0xa0);
328
329 b43_radio_set(dev, 0x11f, 0x2);
Rafał Miłeckibce4dc42011-08-31 23:36:20 +0200330
331 b43_phy_lcn_clear_tx_power_offsets(dev);
Rafał Miłeckibbb55742011-09-16 12:34:03 +0200332
333 /* TODO: something more? */
Rafał Miłeckibce4dc42011-08-31 23:36:20 +0200334 }
Rafał Miłeckibd3bf692011-08-28 14:28:44 +0200335}
336
Rafał Miłeckibce4dc42011-08-31 23:36:20 +0200337/* wlc_lcnphy_vbat_temp_sense_setup */
338static void b43_phy_lcn_sense_setup(struct b43_wldev *dev)
Rafał Miłecki765b07e2011-08-28 19:59:28 +0200339{
340 u8 i;
341
342 u16 save_radio_regs[6][2] = {
343 { 0x007, 0 }, { 0x0ff, 0 }, { 0x11f, 0 }, { 0x005, 0 },
344 { 0x025, 0 }, { 0x112, 0 },
345 };
346 u16 save_phy_regs[14][2] = {
347 { 0x503, 0 }, { 0x4a4, 0 }, { 0x4d0, 0 }, { 0x4d9, 0 },
348 { 0x4da, 0 }, { 0x4a6, 0 }, { 0x938, 0 }, { 0x939, 0 },
349 { 0x4d8, 0 }, { 0x4d0, 0 }, { 0x4d7, 0 }, { 0x4a5, 0 },
350 { 0x40d, 0 }, { 0x4a2, 0 },
351 };
352 u16 save_radio_4a4;
353
354 for (i = 0; i < 6; i++)
355 save_radio_regs[i][1] = b43_radio_read(dev,
356 save_radio_regs[i][0]);
357 for (i = 0; i < 14; i++)
358 save_phy_regs[i][1] = b43_phy_read(dev, save_phy_regs[i][0]);
359 save_radio_4a4 = b43_radio_read(dev, 0x4a4);
360
361 /* TODO: config sth */
362
363 for (i = 0; i < 6; i++)
364 b43_radio_write(dev, save_radio_regs[i][0],
365 save_radio_regs[i][1]);
366 for (i = 0; i < 14; i++)
367 b43_phy_write(dev, save_phy_regs[i][0], save_phy_regs[i][1]);
368 b43_radio_write(dev, 0x4a4, save_radio_4a4);
369}
370
Rafał Miłecki0c5644b92011-09-16 12:34:00 +0200371static bool b43_phy_lcn_load_tx_iir_cck_filter(struct b43_wldev *dev,
372 u8 filter_type)
373{
374 int i, j;
375 u16 phy_regs[] = { 0x910, 0x91e, 0x91f, 0x924, 0x925, 0x926, 0x920,
376 0x921, 0x927, 0x928, 0x929, 0x922, 0x923, 0x930,
377 0x931, 0x932 };
378 /* Table is from brcmsmac, values for type 25 were outdated, probably
379 * others need updating too */
380 struct lcn_tx_iir_filter tx_iir_filters_cck[] = {
381 { 0, { 1, 415, 1874, 64, 128, 64, 792, 1656, 64, 128, 64, 778,
382 1582, 64, 128, 64 } },
383 { 1, { 1, 402, 1847, 259, 59, 259, 671, 1794, 68, 54, 68, 608,
384 1863, 93, 167, 93 } },
385 { 2, { 1, 415, 1874, 64, 128, 64, 792, 1656, 192, 384, 192,
386 778, 1582, 64, 128, 64 } },
387 { 3, { 1, 302, 1841, 129, 258, 129, 658, 1720, 205, 410, 205,
388 754, 1760, 170, 340, 170 } },
389 { 20, { 1, 360, 1884, 242, 1734, 242, 752, 1720, 205, 1845, 205,
390 767, 1760, 256, 185, 256 } },
391 { 21, { 1, 360, 1884, 149, 1874, 149, 752, 1720, 205, 1883, 205,
392 767, 1760, 256, 273, 256 } },
393 { 22, { 1, 360, 1884, 98, 1948, 98, 752, 1720, 205, 1924, 205,
394 767, 1760, 256, 352, 256 } },
395 { 23, { 1, 350, 1884, 116, 1966, 116, 752, 1720, 205, 2008, 205,
396 767, 1760, 128, 233, 128 } },
397 { 24, { 1, 325, 1884, 32, 40, 32, 756, 1720, 256, 471, 256, 766,
398 1760, 256, 1881, 256 } },
399 { 25, { 1, 299, 1884, 51, 64, 51, 736, 1720, 256, 471, 256, 765,
400 1760, 262, 1878, 262 } },
401 /* brcmsmac version { 25, { 1, 299, 1884, 51, 64, 51, 736, 1720,
402 * 256, 471, 256, 765, 1760, 256, 1881, 256 } }, */
403 { 26, { 1, 277, 1943, 39, 117, 88, 637, 1838, 64, 192, 144, 614,
404 1864, 128, 384, 288 } },
405 { 27, { 1, 245, 1943, 49, 147, 110, 626, 1838, 256, 768, 576,
406 613, 1864, 128, 384, 288 } },
407 { 30, { 1, 302, 1841, 61, 122, 61, 658, 1720, 205, 410, 205,
408 754, 1760, 170, 340, 170 } },
409 };
410
411 for (i = 0; i < ARRAY_SIZE(tx_iir_filters_cck); i++) {
412 if (tx_iir_filters_cck[i].type == filter_type) {
413 for (j = 0; j < 16; j++)
414 b43_phy_write(dev, phy_regs[j],
415 tx_iir_filters_cck[i].values[j]);
416 return true;
417 }
418 }
419
420 return false;
421}
422
423static bool b43_phy_lcn_load_tx_iir_ofdm_filter(struct b43_wldev *dev,
424 u8 filter_type)
425{
426 int i, j;
427 u16 phy_regs[] = { 0x90f, 0x900, 0x901, 0x906, 0x907, 0x908, 0x902,
428 0x903, 0x909, 0x90a, 0x90b, 0x904, 0x905, 0x90c,
429 0x90d, 0x90e };
430 struct lcn_tx_iir_filter tx_iir_filters_ofdm[] = {
431 { 0, { 0, 0xa2, 0x0, 0x100, 0x100, 0x0, 0x0, 0x0, 0x100, 0x0,
432 0x0, 0x278, 0xfea0, 0x80, 0x100, 0x80 } },
433 { 1, { 0, 374, 0xFF79, 16, 32, 16, 799, 0xFE74, 50, 32, 50, 750,
434 0xFE2B, 212, 0xFFCE, 212 } },
435 { 2, { 0, 375, 0xFF16, 37, 76, 37, 799, 0xFE74, 32, 20, 32, 748,
436 0xFEF2, 128, 0xFFE2, 128 } },
437 };
438
439 for (i = 0; i < ARRAY_SIZE(tx_iir_filters_ofdm); i++) {
440 if (tx_iir_filters_ofdm[i].type == filter_type) {
441 for (j = 0; j < 16; j++)
442 b43_phy_write(dev, phy_regs[j],
443 tx_iir_filters_ofdm[i].values[j]);
444 return true;
445 }
446 }
447
448 return false;
449}
450
Rafał Miłecki1b0a69c2011-09-16 12:34:02 +0200451/* wlc_lcnphy_set_tx_gain_override */
452static void b43_phy_lcn_set_tx_gain_override(struct b43_wldev *dev, bool enable)
453{
454 b43_phy_maskset(dev, 0x4b0, ~(0x1 << 7), enable << 7);
455 b43_phy_maskset(dev, 0x4b0, ~(0x1 << 14), enable << 14);
456 b43_phy_maskset(dev, 0x43b, ~(0x1 << 6), enable << 6);
457}
458
459/* wlc_lcnphy_set_tx_gain */
460static void b43_phy_lcn_set_tx_gain(struct b43_wldev *dev,
461 struct lcn_tx_gains *target_gains)
462{
463 u16 pa_gain = b43_phy_lcn_get_pa_gain(dev);
464
465 b43_phy_write(dev, 0x4b5,
466 (target_gains->gm_gain | (target_gains->pga_gain << 8)));
467 b43_phy_maskset(dev, 0x4fb, ~0x7fff,
468 (target_gains->pad_gain | (pa_gain << 8)));
469 b43_phy_write(dev, 0x4fc,
470 (target_gains->gm_gain | (target_gains->pga_gain << 8)));
471 b43_phy_maskset(dev, 0x4fd, ~0x7fff,
472 (target_gains->pad_gain | (pa_gain << 8)));
473
474 b43_phy_lcn_set_dac_gain(dev, target_gains->dac_gain);
475 b43_phy_lcn_set_tx_gain_override(dev, true);
476}
477
478/* wlc_lcnphy_tx_pwr_ctrl_init */
479static void b43_phy_lcn_tx_pwr_ctl_init(struct b43_wldev *dev)
480{
481 struct lcn_tx_gains tx_gains;
482 u8 bbmult;
483
484 b43_mac_suspend(dev);
485
486 if (!dev->phy.lcn->hw_pwr_ctl_capable) {
487 if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
488 tx_gains.gm_gain = 4;
489 tx_gains.pga_gain = 12;
490 tx_gains.pad_gain = 12;
491 tx_gains.dac_gain = 0;
492 bbmult = 150;
493 } else {
494 tx_gains.gm_gain = 7;
495 tx_gains.pga_gain = 15;
496 tx_gains.pad_gain = 14;
497 tx_gains.dac_gain = 0;
498 bbmult = 150;
499 }
500 b43_phy_lcn_set_tx_gain(dev, &tx_gains);
501 b43_phy_lcn_set_bbmult(dev, bbmult);
502 b43_phy_lcn_sense_setup(dev); /* TODO: TEMPSENSE as arg */
503 } else {
504 b43err(dev->wl, "TX power control not supported for this HW\n");
505 }
506
507 b43_mac_enable(dev);
508}
509
Rafał Miłeckiac78a522011-09-16 12:34:01 +0200510/* wlc_lcnphy_txrx_spur_avoidance_mode */
511static void b43_phy_lcn_txrx_spur_avoidance_mode(struct b43_wldev *dev,
512 bool enable)
513{
514 if (enable) {
515 b43_phy_write(dev, 0x942, 0x7);
516 b43_phy_write(dev, 0x93b, ((1 << 13) + 23));
517 b43_phy_write(dev, 0x93c, ((1 << 13) + 1989));
518
519 b43_phy_write(dev, 0x44a, 0x084);
520 b43_phy_write(dev, 0x44a, 0x080);
521 b43_phy_write(dev, 0x6d3, 0x2222);
522 b43_phy_write(dev, 0x6d3, 0x2220);
523 } else {
524 b43_phy_write(dev, 0x942, 0x0);
525 b43_phy_write(dev, 0x93b, ((0 << 13) + 23));
526 b43_phy_write(dev, 0x93c, ((0 << 13) + 1989));
527 }
528 b43_phy_switch_macfreq(dev, enable);
529}
530
Rafał Miłecki78bc2462011-08-15 18:50:55 +0200531/**************************************************
Rafał Miłecki39f7d332011-08-28 14:59:58 +0200532 * Channel switching ops.
533 **************************************************/
534
Rafał Miłeckib5347062011-09-16 12:33:59 +0200535/* wlc_lcnphy_set_chanspec_tweaks */
536static void b43_phy_lcn_set_channel_tweaks(struct b43_wldev *dev, int channel)
537{
538 struct bcma_drv_cc *cc = &dev->dev->bdev->bus->drv_cc;
539
540 b43_phy_maskset(dev, 0x448, ~0x300, (channel == 14) ? 0x200 : 0x100);
541
542 if (channel == 1 || channel == 2 || channel == 3 || channel == 4 ||
543 channel == 9 || channel == 10 || channel == 11 || channel == 12) {
544 bcma_chipco_pll_write(cc, 0x2, 0x03000c04);
545 bcma_chipco_pll_maskset(cc, 0x3, 0x00ffffff, 0x0);
546 bcma_chipco_pll_write(cc, 0x4, 0x200005c0);
547
548 bcma_cc_set32(cc, BCMA_CC_PMU_CTL, 0x400);
549
550 b43_phy_write(dev, 0x942, 0);
551
Rafał Miłeckiac78a522011-09-16 12:34:01 +0200552 b43_phy_lcn_txrx_spur_avoidance_mode(dev, false);
Rafał Miłeckib5347062011-09-16 12:33:59 +0200553 b43_phy_maskset(dev, 0x424, (u16) ~0xff00, 0x1b00);
554 b43_phy_write(dev, 0x425, 0x5907);
555 } else {
556 bcma_chipco_pll_write(cc, 0x2, 0x03140c04);
557 bcma_chipco_pll_maskset(cc, 0x3, 0x00ffffff, 0x333333);
558 bcma_chipco_pll_write(cc, 0x4, 0x202c2820);
559
560 bcma_cc_set32(cc, BCMA_CC_PMU_CTL, 0x400);
561
562 b43_phy_write(dev, 0x942, 0);
563
Rafał Miłeckiac78a522011-09-16 12:34:01 +0200564 b43_phy_lcn_txrx_spur_avoidance_mode(dev, true);
Rafał Miłeckib5347062011-09-16 12:33:59 +0200565 b43_phy_maskset(dev, 0x424, (u16) ~0xff00, 0x1f00);
566 b43_phy_write(dev, 0x425, 0x590a);
567 }
568
569 b43_phy_set(dev, 0x44a, 0x44);
570 b43_phy_write(dev, 0x44a, 0x80);
571}
572
573/* wlc_phy_chanspec_set_lcnphy */
Rafał Miłecki39f7d332011-08-28 14:59:58 +0200574static int b43_phy_lcn_set_channel(struct b43_wldev *dev,
575 struct ieee80211_channel *channel,
576 enum nl80211_channel_type channel_type)
577{
Rafał Miłecki0c5644b92011-09-16 12:34:00 +0200578 static const u16 sfo_cfg[14][2] = {
579 {965, 1087}, {967, 1085}, {969, 1082}, {971, 1080}, {973, 1078},
580 {975, 1076}, {977, 1073}, {979, 1071}, {981, 1069}, {983, 1067},
581 {985, 1065}, {987, 1063}, {989, 1060}, {994, 1055},
582 };
583
Rafał Miłeckib5347062011-09-16 12:33:59 +0200584 b43_phy_lcn_set_channel_tweaks(dev, channel->hw_value);
Rafał Miłecki39f7d332011-08-28 14:59:58 +0200585
586 b43_phy_set(dev, 0x44a, 0x44);
587 b43_phy_write(dev, 0x44a, 0x80);
588
589 b43_radio_2064_channel_setup(dev);
590 mdelay(1);
591
592 b43_phy_lcn_afe_set_unset(dev);
593
Rafał Miłecki0c5644b92011-09-16 12:34:00 +0200594 b43_phy_write(dev, 0x657, sfo_cfg[channel->hw_value - 1][0]);
595 b43_phy_write(dev, 0x658, sfo_cfg[channel->hw_value - 1][1]);
596
597 if (channel->hw_value == 14) {
598 b43_phy_maskset(dev, 0x448, ~(0x3 << 8), (2) << 8);
599 b43_phy_lcn_load_tx_iir_cck_filter(dev, 3);
600 } else {
601 b43_phy_maskset(dev, 0x448, ~(0x3 << 8), (1) << 8);
602 /* brcmsmac uses filter_type 2, we follow wl with 25 */
603 b43_phy_lcn_load_tx_iir_cck_filter(dev, 25);
604 }
605 /* brcmsmac uses filter_type 2, we follow wl with 0 */
606 b43_phy_lcn_load_tx_iir_ofdm_filter(dev, 0);
607
608 b43_phy_maskset(dev, 0x4eb, ~(0x7 << 3), 0x1 << 3);
Rafał Miłecki39f7d332011-08-28 14:59:58 +0200609
610 return 0;
611}
612
613/**************************************************
Rafał Miłeckif9286682011-08-14 23:27:28 +0200614 * Basic PHY ops.
615 **************************************************/
616
617static int b43_phy_lcn_op_allocate(struct b43_wldev *dev)
618{
619 struct b43_phy_lcn *phy_lcn;
620
621 phy_lcn = kzalloc(sizeof(*phy_lcn), GFP_KERNEL);
622 if (!phy_lcn)
623 return -ENOMEM;
624 dev->phy.lcn = phy_lcn;
625
626 return 0;
627}
628
629static void b43_phy_lcn_op_free(struct b43_wldev *dev)
630{
631 struct b43_phy *phy = &dev->phy;
632 struct b43_phy_lcn *phy_lcn = phy->lcn;
633
634 kfree(phy_lcn);
635 phy->lcn = NULL;
636}
637
638static void b43_phy_lcn_op_prepare_structs(struct b43_wldev *dev)
639{
640 struct b43_phy *phy = &dev->phy;
641 struct b43_phy_lcn *phy_lcn = phy->lcn;
642
643 memset(phy_lcn, 0, sizeof(*phy_lcn));
644}
645
Rafał Miłeckibce4dc42011-08-31 23:36:20 +0200646/* wlc_phy_init_lcnphy */
Rafał Miłecki78bc2462011-08-15 18:50:55 +0200647static int b43_phy_lcn_op_init(struct b43_wldev *dev)
648{
Rafał Miłeckib5347062011-09-16 12:33:59 +0200649 struct bcma_drv_cc *cc = &dev->dev->bdev->bus->drv_cc;
650
Rafał Miłecki78bc2462011-08-15 18:50:55 +0200651 b43_phy_set(dev, 0x44a, 0x80);
652 b43_phy_mask(dev, 0x44a, 0x7f);
653 b43_phy_set(dev, 0x6d1, 0x80);
654 b43_phy_write(dev, 0x6d0, 0x7);
655
656 b43_phy_lcn_afe_set_unset(dev);
657
658 b43_phy_write(dev, 0x60a, 0xa0);
659 b43_phy_write(dev, 0x46a, 0x19);
660 b43_phy_maskset(dev, 0x663, 0xFF00, 0x64);
661
662 b43_phy_lcn_tables_init(dev);
Rafał Miłecki78bc2462011-08-15 18:50:55 +0200663
Rafał Miłeckibce4dc42011-08-31 23:36:20 +0200664 b43_phy_lcn_rev0_baseband_init(dev);
665 b43_phy_lcn_bu_tweaks(dev);
Rafał Miłecki78bc2462011-08-15 18:50:55 +0200666
Rafał Miłeckidc713fb2011-08-15 18:50:56 +0200667 if (dev->phy.radio_ver == 0x2064)
668 b43_radio_2064_init(dev);
669 else
670 B43_WARN_ON(1);
671
Rafał Miłecki1b0a69c2011-09-16 12:34:02 +0200672 if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
673 b43_phy_lcn_tx_pwr_ctl_init(dev);
Rafał Miłecki765b07e2011-08-28 19:59:28 +0200674
Rafał Miłeckib5347062011-09-16 12:33:59 +0200675 b43_switch_channel(dev, dev->phy.channel);
676
677 bcma_chipco_regctl_maskset(cc, 0, 0xf, 0x9);
678 bcma_chipco_chipctl_maskset(cc, 0, 0, 0x03cddddd);
679
680 /* TODO */
681
682 b43_phy_set(dev, 0x448, 0x4000);
683 udelay(100);
684 b43_phy_mask(dev, 0x448, ~0x4000);
685
686 /* TODO */
687
Rafał Miłecki78bc2462011-08-15 18:50:55 +0200688 return 0;
689}
690
Rafał Miłeckiba356b52011-08-14 23:27:29 +0200691static void b43_phy_lcn_op_software_rfkill(struct b43_wldev *dev,
692 bool blocked)
693{
694 if (b43_read32(dev, B43_MMIO_MACCTL) & B43_MACCTL_ENABLED)
695 b43err(dev->wl, "MAC not suspended\n");
696
697 if (blocked) {
698 b43_phy_mask(dev, B43_PHY_LCN_RF_CTL2, ~0x7c00);
699 b43_phy_set(dev, B43_PHY_LCN_RF_CTL1, 0x1f00);
700
701 b43_phy_mask(dev, B43_PHY_LCN_RF_CTL5, ~0x7f00);
702 b43_phy_mask(dev, B43_PHY_LCN_RF_CTL4, ~0x2);
703 b43_phy_set(dev, B43_PHY_LCN_RF_CTL3, 0x808);
704
705 b43_phy_mask(dev, B43_PHY_LCN_RF_CTL7, ~0x8);
706 b43_phy_set(dev, B43_PHY_LCN_RF_CTL6, 0x8);
707 } else {
Rafał Miłecki78bc2462011-08-15 18:50:55 +0200708 b43_phy_mask(dev, B43_PHY_LCN_RF_CTL1, ~0x1f00);
709 b43_phy_mask(dev, B43_PHY_LCN_RF_CTL3, ~0x808);
710 b43_phy_mask(dev, B43_PHY_LCN_RF_CTL6, ~0x8);
Rafał Miłeckiba356b52011-08-14 23:27:29 +0200711 }
712}
713
Rafał Miłecki7ed88522011-08-14 23:27:30 +0200714static void b43_phy_lcn_op_switch_analog(struct b43_wldev *dev, bool on)
715{
716 if (on) {
717 b43_phy_mask(dev, B43_PHY_LCN_AFE_CTL1, ~0x7);
718 } else {
719 b43_phy_set(dev, B43_PHY_LCN_AFE_CTL2, 0x7);
720 b43_phy_set(dev, B43_PHY_LCN_AFE_CTL1, 0x7);
721 }
722}
723
Rafał Miłecki39f7d332011-08-28 14:59:58 +0200724static int b43_phy_lcn_op_switch_channel(struct b43_wldev *dev,
725 unsigned int new_channel)
726{
727 struct ieee80211_channel *channel = dev->wl->hw->conf.channel;
728 enum nl80211_channel_type channel_type = dev->wl->hw->conf.channel_type;
729
730 if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
731 if ((new_channel < 1) || (new_channel > 14))
732 return -EINVAL;
733 } else {
734 return -EINVAL;
735 }
736
737 return b43_phy_lcn_set_channel(dev, channel, channel_type);
738}
739
Rafał Miłeckif9286682011-08-14 23:27:28 +0200740static unsigned int b43_phy_lcn_op_get_default_chan(struct b43_wldev *dev)
741{
742 if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
743 return 1;
744 return 36;
745}
746
747static enum b43_txpwr_result
748b43_phy_lcn_op_recalc_txpower(struct b43_wldev *dev, bool ignore_tssi)
749{
750 return B43_TXPWR_RES_DONE;
751}
752
753static void b43_phy_lcn_op_adjust_txpower(struct b43_wldev *dev)
754{
755}
756
757/**************************************************
Rafał Miłeckif533d0f2011-08-28 14:28:43 +0200758 * R/W ops.
759 **************************************************/
760
761static u16 b43_phy_lcn_op_read(struct b43_wldev *dev, u16 reg)
762{
763 b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
764 return b43_read16(dev, B43_MMIO_PHY_DATA);
765}
766
767static void b43_phy_lcn_op_write(struct b43_wldev *dev, u16 reg, u16 value)
768{
769 b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
770 b43_write16(dev, B43_MMIO_PHY_DATA, value);
771}
772
773static void b43_phy_lcn_op_maskset(struct b43_wldev *dev, u16 reg, u16 mask,
774 u16 set)
775{
776 b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
777 b43_write16(dev, B43_MMIO_PHY_DATA,
778 (b43_read16(dev, B43_MMIO_PHY_DATA) & mask) | set);
779}
780
781static u16 b43_phy_lcn_op_radio_read(struct b43_wldev *dev, u16 reg)
782{
783 /* LCN-PHY needs 0x200 for read access */
784 reg |= 0x200;
785
786 b43_write16(dev, B43_MMIO_RADIO24_CONTROL, reg);
787 return b43_read16(dev, B43_MMIO_RADIO24_DATA);
788}
789
790static void b43_phy_lcn_op_radio_write(struct b43_wldev *dev, u16 reg,
791 u16 value)
792{
793 b43_write16(dev, B43_MMIO_RADIO24_CONTROL, reg);
794 b43_write16(dev, B43_MMIO_RADIO24_DATA, value);
795}
796
797/**************************************************
Rafał Miłecki1d738e62011-07-07 15:25:27 +0200798 * PHY ops struct.
799 **************************************************/
800
801const struct b43_phy_operations b43_phyops_lcn = {
Rafał Miłecki1d738e62011-07-07 15:25:27 +0200802 .allocate = b43_phy_lcn_op_allocate,
803 .free = b43_phy_lcn_op_free,
804 .prepare_structs = b43_phy_lcn_op_prepare_structs,
805 .init = b43_phy_lcn_op_init,
806 .phy_read = b43_phy_lcn_op_read,
807 .phy_write = b43_phy_lcn_op_write,
808 .phy_maskset = b43_phy_lcn_op_maskset,
809 .radio_read = b43_phy_lcn_op_radio_read,
810 .radio_write = b43_phy_lcn_op_radio_write,
811 .software_rfkill = b43_phy_lcn_op_software_rfkill,
812 .switch_analog = b43_phy_lcn_op_switch_analog,
813 .switch_channel = b43_phy_lcn_op_switch_channel,
814 .get_default_chan = b43_phy_lcn_op_get_default_chan,
815 .recalc_txpower = b43_phy_lcn_op_recalc_txpower,
816 .adjust_txpower = b43_phy_lcn_op_adjust_txpower,
Rafał Miłecki1d738e62011-07-07 15:25:27 +0200817};