blob: 8810bc99d28cb59fa515816db585825601bba407 [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
310 /* TODO: more ops */
Rafał Miłeckibce4dc42011-08-31 23:36:20 +0200311
312 if (dev->phy.rev == 1) {
313 /* TODO: more ops */
314
315 b43_phy_lcn_clear_tx_power_offsets(dev);
316 }
Rafał Miłeckibd3bf692011-08-28 14:28:44 +0200317}
318
Rafał Miłeckibce4dc42011-08-31 23:36:20 +0200319/* wlc_lcnphy_vbat_temp_sense_setup */
320static void b43_phy_lcn_sense_setup(struct b43_wldev *dev)
Rafał Miłecki765b07e2011-08-28 19:59:28 +0200321{
322 u8 i;
323
324 u16 save_radio_regs[6][2] = {
325 { 0x007, 0 }, { 0x0ff, 0 }, { 0x11f, 0 }, { 0x005, 0 },
326 { 0x025, 0 }, { 0x112, 0 },
327 };
328 u16 save_phy_regs[14][2] = {
329 { 0x503, 0 }, { 0x4a4, 0 }, { 0x4d0, 0 }, { 0x4d9, 0 },
330 { 0x4da, 0 }, { 0x4a6, 0 }, { 0x938, 0 }, { 0x939, 0 },
331 { 0x4d8, 0 }, { 0x4d0, 0 }, { 0x4d7, 0 }, { 0x4a5, 0 },
332 { 0x40d, 0 }, { 0x4a2, 0 },
333 };
334 u16 save_radio_4a4;
335
336 for (i = 0; i < 6; i++)
337 save_radio_regs[i][1] = b43_radio_read(dev,
338 save_radio_regs[i][0]);
339 for (i = 0; i < 14; i++)
340 save_phy_regs[i][1] = b43_phy_read(dev, save_phy_regs[i][0]);
341 save_radio_4a4 = b43_radio_read(dev, 0x4a4);
342
343 /* TODO: config sth */
344
345 for (i = 0; i < 6; i++)
346 b43_radio_write(dev, save_radio_regs[i][0],
347 save_radio_regs[i][1]);
348 for (i = 0; i < 14; i++)
349 b43_phy_write(dev, save_phy_regs[i][0], save_phy_regs[i][1]);
350 b43_radio_write(dev, 0x4a4, save_radio_4a4);
351}
352
Rafał Miłecki0c5644b92011-09-16 12:34:00 +0200353static bool b43_phy_lcn_load_tx_iir_cck_filter(struct b43_wldev *dev,
354 u8 filter_type)
355{
356 int i, j;
357 u16 phy_regs[] = { 0x910, 0x91e, 0x91f, 0x924, 0x925, 0x926, 0x920,
358 0x921, 0x927, 0x928, 0x929, 0x922, 0x923, 0x930,
359 0x931, 0x932 };
360 /* Table is from brcmsmac, values for type 25 were outdated, probably
361 * others need updating too */
362 struct lcn_tx_iir_filter tx_iir_filters_cck[] = {
363 { 0, { 1, 415, 1874, 64, 128, 64, 792, 1656, 64, 128, 64, 778,
364 1582, 64, 128, 64 } },
365 { 1, { 1, 402, 1847, 259, 59, 259, 671, 1794, 68, 54, 68, 608,
366 1863, 93, 167, 93 } },
367 { 2, { 1, 415, 1874, 64, 128, 64, 792, 1656, 192, 384, 192,
368 778, 1582, 64, 128, 64 } },
369 { 3, { 1, 302, 1841, 129, 258, 129, 658, 1720, 205, 410, 205,
370 754, 1760, 170, 340, 170 } },
371 { 20, { 1, 360, 1884, 242, 1734, 242, 752, 1720, 205, 1845, 205,
372 767, 1760, 256, 185, 256 } },
373 { 21, { 1, 360, 1884, 149, 1874, 149, 752, 1720, 205, 1883, 205,
374 767, 1760, 256, 273, 256 } },
375 { 22, { 1, 360, 1884, 98, 1948, 98, 752, 1720, 205, 1924, 205,
376 767, 1760, 256, 352, 256 } },
377 { 23, { 1, 350, 1884, 116, 1966, 116, 752, 1720, 205, 2008, 205,
378 767, 1760, 128, 233, 128 } },
379 { 24, { 1, 325, 1884, 32, 40, 32, 756, 1720, 256, 471, 256, 766,
380 1760, 256, 1881, 256 } },
381 { 25, { 1, 299, 1884, 51, 64, 51, 736, 1720, 256, 471, 256, 765,
382 1760, 262, 1878, 262 } },
383 /* brcmsmac version { 25, { 1, 299, 1884, 51, 64, 51, 736, 1720,
384 * 256, 471, 256, 765, 1760, 256, 1881, 256 } }, */
385 { 26, { 1, 277, 1943, 39, 117, 88, 637, 1838, 64, 192, 144, 614,
386 1864, 128, 384, 288 } },
387 { 27, { 1, 245, 1943, 49, 147, 110, 626, 1838, 256, 768, 576,
388 613, 1864, 128, 384, 288 } },
389 { 30, { 1, 302, 1841, 61, 122, 61, 658, 1720, 205, 410, 205,
390 754, 1760, 170, 340, 170 } },
391 };
392
393 for (i = 0; i < ARRAY_SIZE(tx_iir_filters_cck); i++) {
394 if (tx_iir_filters_cck[i].type == filter_type) {
395 for (j = 0; j < 16; j++)
396 b43_phy_write(dev, phy_regs[j],
397 tx_iir_filters_cck[i].values[j]);
398 return true;
399 }
400 }
401
402 return false;
403}
404
405static bool b43_phy_lcn_load_tx_iir_ofdm_filter(struct b43_wldev *dev,
406 u8 filter_type)
407{
408 int i, j;
409 u16 phy_regs[] = { 0x90f, 0x900, 0x901, 0x906, 0x907, 0x908, 0x902,
410 0x903, 0x909, 0x90a, 0x90b, 0x904, 0x905, 0x90c,
411 0x90d, 0x90e };
412 struct lcn_tx_iir_filter tx_iir_filters_ofdm[] = {
413 { 0, { 0, 0xa2, 0x0, 0x100, 0x100, 0x0, 0x0, 0x0, 0x100, 0x0,
414 0x0, 0x278, 0xfea0, 0x80, 0x100, 0x80 } },
415 { 1, { 0, 374, 0xFF79, 16, 32, 16, 799, 0xFE74, 50, 32, 50, 750,
416 0xFE2B, 212, 0xFFCE, 212 } },
417 { 2, { 0, 375, 0xFF16, 37, 76, 37, 799, 0xFE74, 32, 20, 32, 748,
418 0xFEF2, 128, 0xFFE2, 128 } },
419 };
420
421 for (i = 0; i < ARRAY_SIZE(tx_iir_filters_ofdm); i++) {
422 if (tx_iir_filters_ofdm[i].type == filter_type) {
423 for (j = 0; j < 16; j++)
424 b43_phy_write(dev, phy_regs[j],
425 tx_iir_filters_ofdm[i].values[j]);
426 return true;
427 }
428 }
429
430 return false;
431}
432
Rafał Miłecki1b0a69c2011-09-16 12:34:02 +0200433/* wlc_lcnphy_set_tx_gain_override */
434static void b43_phy_lcn_set_tx_gain_override(struct b43_wldev *dev, bool enable)
435{
436 b43_phy_maskset(dev, 0x4b0, ~(0x1 << 7), enable << 7);
437 b43_phy_maskset(dev, 0x4b0, ~(0x1 << 14), enable << 14);
438 b43_phy_maskset(dev, 0x43b, ~(0x1 << 6), enable << 6);
439}
440
441/* wlc_lcnphy_set_tx_gain */
442static void b43_phy_lcn_set_tx_gain(struct b43_wldev *dev,
443 struct lcn_tx_gains *target_gains)
444{
445 u16 pa_gain = b43_phy_lcn_get_pa_gain(dev);
446
447 b43_phy_write(dev, 0x4b5,
448 (target_gains->gm_gain | (target_gains->pga_gain << 8)));
449 b43_phy_maskset(dev, 0x4fb, ~0x7fff,
450 (target_gains->pad_gain | (pa_gain << 8)));
451 b43_phy_write(dev, 0x4fc,
452 (target_gains->gm_gain | (target_gains->pga_gain << 8)));
453 b43_phy_maskset(dev, 0x4fd, ~0x7fff,
454 (target_gains->pad_gain | (pa_gain << 8)));
455
456 b43_phy_lcn_set_dac_gain(dev, target_gains->dac_gain);
457 b43_phy_lcn_set_tx_gain_override(dev, true);
458}
459
460/* wlc_lcnphy_tx_pwr_ctrl_init */
461static void b43_phy_lcn_tx_pwr_ctl_init(struct b43_wldev *dev)
462{
463 struct lcn_tx_gains tx_gains;
464 u8 bbmult;
465
466 b43_mac_suspend(dev);
467
468 if (!dev->phy.lcn->hw_pwr_ctl_capable) {
469 if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
470 tx_gains.gm_gain = 4;
471 tx_gains.pga_gain = 12;
472 tx_gains.pad_gain = 12;
473 tx_gains.dac_gain = 0;
474 bbmult = 150;
475 } else {
476 tx_gains.gm_gain = 7;
477 tx_gains.pga_gain = 15;
478 tx_gains.pad_gain = 14;
479 tx_gains.dac_gain = 0;
480 bbmult = 150;
481 }
482 b43_phy_lcn_set_tx_gain(dev, &tx_gains);
483 b43_phy_lcn_set_bbmult(dev, bbmult);
484 b43_phy_lcn_sense_setup(dev); /* TODO: TEMPSENSE as arg */
485 } else {
486 b43err(dev->wl, "TX power control not supported for this HW\n");
487 }
488
489 b43_mac_enable(dev);
490}
491
Rafał Miłeckiac78a522011-09-16 12:34:01 +0200492/* wlc_lcnphy_txrx_spur_avoidance_mode */
493static void b43_phy_lcn_txrx_spur_avoidance_mode(struct b43_wldev *dev,
494 bool enable)
495{
496 if (enable) {
497 b43_phy_write(dev, 0x942, 0x7);
498 b43_phy_write(dev, 0x93b, ((1 << 13) + 23));
499 b43_phy_write(dev, 0x93c, ((1 << 13) + 1989));
500
501 b43_phy_write(dev, 0x44a, 0x084);
502 b43_phy_write(dev, 0x44a, 0x080);
503 b43_phy_write(dev, 0x6d3, 0x2222);
504 b43_phy_write(dev, 0x6d3, 0x2220);
505 } else {
506 b43_phy_write(dev, 0x942, 0x0);
507 b43_phy_write(dev, 0x93b, ((0 << 13) + 23));
508 b43_phy_write(dev, 0x93c, ((0 << 13) + 1989));
509 }
510 b43_phy_switch_macfreq(dev, enable);
511}
512
Rafał Miłecki78bc2462011-08-15 18:50:55 +0200513/**************************************************
Rafał Miłecki39f7d332011-08-28 14:59:58 +0200514 * Channel switching ops.
515 **************************************************/
516
Rafał Miłeckib5347062011-09-16 12:33:59 +0200517/* wlc_lcnphy_set_chanspec_tweaks */
518static void b43_phy_lcn_set_channel_tweaks(struct b43_wldev *dev, int channel)
519{
520 struct bcma_drv_cc *cc = &dev->dev->bdev->bus->drv_cc;
521
522 b43_phy_maskset(dev, 0x448, ~0x300, (channel == 14) ? 0x200 : 0x100);
523
524 if (channel == 1 || channel == 2 || channel == 3 || channel == 4 ||
525 channel == 9 || channel == 10 || channel == 11 || channel == 12) {
526 bcma_chipco_pll_write(cc, 0x2, 0x03000c04);
527 bcma_chipco_pll_maskset(cc, 0x3, 0x00ffffff, 0x0);
528 bcma_chipco_pll_write(cc, 0x4, 0x200005c0);
529
530 bcma_cc_set32(cc, BCMA_CC_PMU_CTL, 0x400);
531
532 b43_phy_write(dev, 0x942, 0);
533
Rafał Miłeckiac78a522011-09-16 12:34:01 +0200534 b43_phy_lcn_txrx_spur_avoidance_mode(dev, false);
Rafał Miłeckib5347062011-09-16 12:33:59 +0200535 b43_phy_maskset(dev, 0x424, (u16) ~0xff00, 0x1b00);
536 b43_phy_write(dev, 0x425, 0x5907);
537 } else {
538 bcma_chipco_pll_write(cc, 0x2, 0x03140c04);
539 bcma_chipco_pll_maskset(cc, 0x3, 0x00ffffff, 0x333333);
540 bcma_chipco_pll_write(cc, 0x4, 0x202c2820);
541
542 bcma_cc_set32(cc, BCMA_CC_PMU_CTL, 0x400);
543
544 b43_phy_write(dev, 0x942, 0);
545
Rafał Miłeckiac78a522011-09-16 12:34:01 +0200546 b43_phy_lcn_txrx_spur_avoidance_mode(dev, true);
Rafał Miłeckib5347062011-09-16 12:33:59 +0200547 b43_phy_maskset(dev, 0x424, (u16) ~0xff00, 0x1f00);
548 b43_phy_write(dev, 0x425, 0x590a);
549 }
550
551 b43_phy_set(dev, 0x44a, 0x44);
552 b43_phy_write(dev, 0x44a, 0x80);
553}
554
555/* wlc_phy_chanspec_set_lcnphy */
Rafał Miłecki39f7d332011-08-28 14:59:58 +0200556static int b43_phy_lcn_set_channel(struct b43_wldev *dev,
557 struct ieee80211_channel *channel,
558 enum nl80211_channel_type channel_type)
559{
Rafał Miłecki0c5644b92011-09-16 12:34:00 +0200560 static const u16 sfo_cfg[14][2] = {
561 {965, 1087}, {967, 1085}, {969, 1082}, {971, 1080}, {973, 1078},
562 {975, 1076}, {977, 1073}, {979, 1071}, {981, 1069}, {983, 1067},
563 {985, 1065}, {987, 1063}, {989, 1060}, {994, 1055},
564 };
565
Rafał Miłeckib5347062011-09-16 12:33:59 +0200566 b43_phy_lcn_set_channel_tweaks(dev, channel->hw_value);
Rafał Miłecki39f7d332011-08-28 14:59:58 +0200567
568 b43_phy_set(dev, 0x44a, 0x44);
569 b43_phy_write(dev, 0x44a, 0x80);
570
571 b43_radio_2064_channel_setup(dev);
572 mdelay(1);
573
574 b43_phy_lcn_afe_set_unset(dev);
575
Rafał Miłecki0c5644b92011-09-16 12:34:00 +0200576 b43_phy_write(dev, 0x657, sfo_cfg[channel->hw_value - 1][0]);
577 b43_phy_write(dev, 0x658, sfo_cfg[channel->hw_value - 1][1]);
578
579 if (channel->hw_value == 14) {
580 b43_phy_maskset(dev, 0x448, ~(0x3 << 8), (2) << 8);
581 b43_phy_lcn_load_tx_iir_cck_filter(dev, 3);
582 } else {
583 b43_phy_maskset(dev, 0x448, ~(0x3 << 8), (1) << 8);
584 /* brcmsmac uses filter_type 2, we follow wl with 25 */
585 b43_phy_lcn_load_tx_iir_cck_filter(dev, 25);
586 }
587 /* brcmsmac uses filter_type 2, we follow wl with 0 */
588 b43_phy_lcn_load_tx_iir_ofdm_filter(dev, 0);
589
590 b43_phy_maskset(dev, 0x4eb, ~(0x7 << 3), 0x1 << 3);
Rafał Miłecki39f7d332011-08-28 14:59:58 +0200591
592 return 0;
593}
594
595/**************************************************
Rafał Miłeckif9286682011-08-14 23:27:28 +0200596 * Basic PHY ops.
597 **************************************************/
598
599static int b43_phy_lcn_op_allocate(struct b43_wldev *dev)
600{
601 struct b43_phy_lcn *phy_lcn;
602
603 phy_lcn = kzalloc(sizeof(*phy_lcn), GFP_KERNEL);
604 if (!phy_lcn)
605 return -ENOMEM;
606 dev->phy.lcn = phy_lcn;
607
608 return 0;
609}
610
611static void b43_phy_lcn_op_free(struct b43_wldev *dev)
612{
613 struct b43_phy *phy = &dev->phy;
614 struct b43_phy_lcn *phy_lcn = phy->lcn;
615
616 kfree(phy_lcn);
617 phy->lcn = NULL;
618}
619
620static void b43_phy_lcn_op_prepare_structs(struct b43_wldev *dev)
621{
622 struct b43_phy *phy = &dev->phy;
623 struct b43_phy_lcn *phy_lcn = phy->lcn;
624
625 memset(phy_lcn, 0, sizeof(*phy_lcn));
626}
627
Rafał Miłeckibce4dc42011-08-31 23:36:20 +0200628/* wlc_phy_init_lcnphy */
Rafał Miłecki78bc2462011-08-15 18:50:55 +0200629static int b43_phy_lcn_op_init(struct b43_wldev *dev)
630{
Rafał Miłeckib5347062011-09-16 12:33:59 +0200631 struct bcma_drv_cc *cc = &dev->dev->bdev->bus->drv_cc;
632
Rafał Miłecki78bc2462011-08-15 18:50:55 +0200633 b43_phy_set(dev, 0x44a, 0x80);
634 b43_phy_mask(dev, 0x44a, 0x7f);
635 b43_phy_set(dev, 0x6d1, 0x80);
636 b43_phy_write(dev, 0x6d0, 0x7);
637
638 b43_phy_lcn_afe_set_unset(dev);
639
640 b43_phy_write(dev, 0x60a, 0xa0);
641 b43_phy_write(dev, 0x46a, 0x19);
642 b43_phy_maskset(dev, 0x663, 0xFF00, 0x64);
643
644 b43_phy_lcn_tables_init(dev);
Rafał Miłecki78bc2462011-08-15 18:50:55 +0200645
Rafał Miłeckibce4dc42011-08-31 23:36:20 +0200646 b43_phy_lcn_rev0_baseband_init(dev);
647 b43_phy_lcn_bu_tweaks(dev);
Rafał Miłecki78bc2462011-08-15 18:50:55 +0200648
Rafał Miłeckidc713fb2011-08-15 18:50:56 +0200649 if (dev->phy.radio_ver == 0x2064)
650 b43_radio_2064_init(dev);
651 else
652 B43_WARN_ON(1);
653
Rafał Miłecki1b0a69c2011-09-16 12:34:02 +0200654 if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
655 b43_phy_lcn_tx_pwr_ctl_init(dev);
Rafał Miłecki765b07e2011-08-28 19:59:28 +0200656
Rafał Miłeckib5347062011-09-16 12:33:59 +0200657 b43_switch_channel(dev, dev->phy.channel);
658
659 bcma_chipco_regctl_maskset(cc, 0, 0xf, 0x9);
660 bcma_chipco_chipctl_maskset(cc, 0, 0, 0x03cddddd);
661
662 /* TODO */
663
664 b43_phy_set(dev, 0x448, 0x4000);
665 udelay(100);
666 b43_phy_mask(dev, 0x448, ~0x4000);
667
668 /* TODO */
669
Rafał Miłecki78bc2462011-08-15 18:50:55 +0200670 return 0;
671}
672
Rafał Miłeckiba356b52011-08-14 23:27:29 +0200673static void b43_phy_lcn_op_software_rfkill(struct b43_wldev *dev,
674 bool blocked)
675{
676 if (b43_read32(dev, B43_MMIO_MACCTL) & B43_MACCTL_ENABLED)
677 b43err(dev->wl, "MAC not suspended\n");
678
679 if (blocked) {
680 b43_phy_mask(dev, B43_PHY_LCN_RF_CTL2, ~0x7c00);
681 b43_phy_set(dev, B43_PHY_LCN_RF_CTL1, 0x1f00);
682
683 b43_phy_mask(dev, B43_PHY_LCN_RF_CTL5, ~0x7f00);
684 b43_phy_mask(dev, B43_PHY_LCN_RF_CTL4, ~0x2);
685 b43_phy_set(dev, B43_PHY_LCN_RF_CTL3, 0x808);
686
687 b43_phy_mask(dev, B43_PHY_LCN_RF_CTL7, ~0x8);
688 b43_phy_set(dev, B43_PHY_LCN_RF_CTL6, 0x8);
689 } else {
Rafał Miłecki78bc2462011-08-15 18:50:55 +0200690 b43_phy_mask(dev, B43_PHY_LCN_RF_CTL1, ~0x1f00);
691 b43_phy_mask(dev, B43_PHY_LCN_RF_CTL3, ~0x808);
692 b43_phy_mask(dev, B43_PHY_LCN_RF_CTL6, ~0x8);
Rafał Miłeckiba356b52011-08-14 23:27:29 +0200693 }
694}
695
Rafał Miłecki7ed88522011-08-14 23:27:30 +0200696static void b43_phy_lcn_op_switch_analog(struct b43_wldev *dev, bool on)
697{
698 if (on) {
699 b43_phy_mask(dev, B43_PHY_LCN_AFE_CTL1, ~0x7);
700 } else {
701 b43_phy_set(dev, B43_PHY_LCN_AFE_CTL2, 0x7);
702 b43_phy_set(dev, B43_PHY_LCN_AFE_CTL1, 0x7);
703 }
704}
705
Rafał Miłecki39f7d332011-08-28 14:59:58 +0200706static int b43_phy_lcn_op_switch_channel(struct b43_wldev *dev,
707 unsigned int new_channel)
708{
709 struct ieee80211_channel *channel = dev->wl->hw->conf.channel;
710 enum nl80211_channel_type channel_type = dev->wl->hw->conf.channel_type;
711
712 if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
713 if ((new_channel < 1) || (new_channel > 14))
714 return -EINVAL;
715 } else {
716 return -EINVAL;
717 }
718
719 return b43_phy_lcn_set_channel(dev, channel, channel_type);
720}
721
Rafał Miłeckif9286682011-08-14 23:27:28 +0200722static unsigned int b43_phy_lcn_op_get_default_chan(struct b43_wldev *dev)
723{
724 if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
725 return 1;
726 return 36;
727}
728
729static enum b43_txpwr_result
730b43_phy_lcn_op_recalc_txpower(struct b43_wldev *dev, bool ignore_tssi)
731{
732 return B43_TXPWR_RES_DONE;
733}
734
735static void b43_phy_lcn_op_adjust_txpower(struct b43_wldev *dev)
736{
737}
738
739/**************************************************
Rafał Miłeckif533d0f2011-08-28 14:28:43 +0200740 * R/W ops.
741 **************************************************/
742
743static u16 b43_phy_lcn_op_read(struct b43_wldev *dev, u16 reg)
744{
745 b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
746 return b43_read16(dev, B43_MMIO_PHY_DATA);
747}
748
749static void b43_phy_lcn_op_write(struct b43_wldev *dev, u16 reg, u16 value)
750{
751 b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
752 b43_write16(dev, B43_MMIO_PHY_DATA, value);
753}
754
755static void b43_phy_lcn_op_maskset(struct b43_wldev *dev, u16 reg, u16 mask,
756 u16 set)
757{
758 b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
759 b43_write16(dev, B43_MMIO_PHY_DATA,
760 (b43_read16(dev, B43_MMIO_PHY_DATA) & mask) | set);
761}
762
763static u16 b43_phy_lcn_op_radio_read(struct b43_wldev *dev, u16 reg)
764{
765 /* LCN-PHY needs 0x200 for read access */
766 reg |= 0x200;
767
768 b43_write16(dev, B43_MMIO_RADIO24_CONTROL, reg);
769 return b43_read16(dev, B43_MMIO_RADIO24_DATA);
770}
771
772static void b43_phy_lcn_op_radio_write(struct b43_wldev *dev, u16 reg,
773 u16 value)
774{
775 b43_write16(dev, B43_MMIO_RADIO24_CONTROL, reg);
776 b43_write16(dev, B43_MMIO_RADIO24_DATA, value);
777}
778
779/**************************************************
Rafał Miłecki1d738e62011-07-07 15:25:27 +0200780 * PHY ops struct.
781 **************************************************/
782
783const struct b43_phy_operations b43_phyops_lcn = {
Rafał Miłecki1d738e62011-07-07 15:25:27 +0200784 .allocate = b43_phy_lcn_op_allocate,
785 .free = b43_phy_lcn_op_free,
786 .prepare_structs = b43_phy_lcn_op_prepare_structs,
787 .init = b43_phy_lcn_op_init,
788 .phy_read = b43_phy_lcn_op_read,
789 .phy_write = b43_phy_lcn_op_write,
790 .phy_maskset = b43_phy_lcn_op_maskset,
791 .radio_read = b43_phy_lcn_op_radio_read,
792 .radio_write = b43_phy_lcn_op_radio_write,
793 .software_rfkill = b43_phy_lcn_op_software_rfkill,
794 .switch_analog = b43_phy_lcn_op_switch_analog,
795 .switch_channel = b43_phy_lcn_op_switch_channel,
796 .get_default_chan = b43_phy_lcn_op_get_default_chan,
797 .recalc_txpower = b43_phy_lcn_op_recalc_txpower,
798 .adjust_txpower = b43_phy_lcn_op_adjust_txpower,
Rafał Miłecki1d738e62011-07-07 15:25:27 +0200799};