Merge tag 'md/3.20-fixes' of git://neil.brown.name/md
[deliverable/linux.git] / drivers / net / wireless / b43 / phy_lcn.c
CommitLineData
1d738e64
RM
1/*
2
3 Broadcom B43 wireless driver
4 IEEE 802.11n LCN-PHY support
5
108f4f3c
RM
6 Copyright (c) 2011 Rafał Miłecki <zajec5@gmail.com>
7
1d738e64
RM
8 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
b534706a
RM
23 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.
1d738e64
RM
31*/
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
1b0a69c1
RM
40struct lcn_tx_gains {
41 u16 gm_gain;
42 u16 pga_gain;
43 u16 pad_gain;
44 u16 dac_gain;
45};
46
0c5644b9
RM
47struct lcn_tx_iir_filter {
48 u8 type;
49 u16 values[16];
50};
51
29818082
RM
52enum lcn_sense_type {
53 B43_SENSE_TEMP,
54 B43_SENSE_VBAT,
55};
56
dc713fb2
RM
57/**************************************************
58 * Radio 2064.
59 **************************************************/
60
bce4dc4a 61/* wlc_lcnphy_radio_2064_channel_tune_4313 */
39f7d33c
RM
62static void b43_radio_2064_channel_setup(struct b43_wldev *dev)
63{
64 u16 save[2];
65
66 b43_radio_set(dev, 0x09d, 0x4);
67 b43_radio_write(dev, 0x09e, 0xf);
68
cf577fc2 69 /* Channel specific values in theory, in practice always the same */
39f7d33c
RM
70 b43_radio_write(dev, 0x02a, 0xb);
71 b43_radio_maskset(dev, 0x030, ~0x3, 0xa);
72 b43_radio_maskset(dev, 0x091, ~0x3, 0);
73 b43_radio_maskset(dev, 0x038, ~0xf, 0x7);
74 b43_radio_maskset(dev, 0x030, ~0xc, 0x8);
75 b43_radio_maskset(dev, 0x05e, ~0xf, 0x8);
76 b43_radio_maskset(dev, 0x05e, ~0xf0, 0x80);
77 b43_radio_write(dev, 0x06c, 0x80);
78
79 save[0] = b43_radio_read(dev, 0x044);
80 save[1] = b43_radio_read(dev, 0x12b);
81
82 b43_radio_set(dev, 0x044, 0x7);
83 b43_radio_set(dev, 0x12b, 0xe);
84
85 /* TODO */
86
87 b43_radio_write(dev, 0x040, 0xfb);
88
89 b43_radio_write(dev, 0x041, 0x9a);
90 b43_radio_write(dev, 0x042, 0xa3);
91 b43_radio_write(dev, 0x043, 0x0c);
92
93 /* TODO */
94
95 b43_radio_set(dev, 0x044, 0x0c);
96 udelay(1);
97
98 b43_radio_write(dev, 0x044, save[0]);
99 b43_radio_write(dev, 0x12b, save[1]);
100
cf577fc2
RM
101 if (dev->phy.rev == 1) {
102 /* brcmsmac uses outdated 0x3 for 0x038 */
103 b43_radio_write(dev, 0x038, 0x0);
104 b43_radio_write(dev, 0x091, 0x7);
105 }
39f7d33c
RM
106}
107
bce4dc4a 108/* wlc_radio_2064_init */
dc713fb2
RM
109static void b43_radio_2064_init(struct b43_wldev *dev)
110{
cf577fc2
RM
111 if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
112 b43_radio_write(dev, 0x09c, 0x0020);
113 b43_radio_write(dev, 0x105, 0x0008);
114 } else {
115 /* TODO */
116 }
dc713fb2
RM
117 b43_radio_write(dev, 0x032, 0x0062);
118 b43_radio_write(dev, 0x033, 0x0019);
119 b43_radio_write(dev, 0x090, 0x0010);
120 b43_radio_write(dev, 0x010, 0x0000);
cf577fc2
RM
121 if (dev->phy.rev == 1) {
122 b43_radio_write(dev, 0x060, 0x007f);
123 b43_radio_write(dev, 0x061, 0x0072);
124 b43_radio_write(dev, 0x062, 0x007f);
125 }
dc713fb2
RM
126 b43_radio_write(dev, 0x01d, 0x0002);
127 b43_radio_write(dev, 0x01e, 0x0006);
128
129 b43_phy_write(dev, 0x4ea, 0x4688);
130 b43_phy_maskset(dev, 0x4eb, ~0x7, 0x2);
131 b43_phy_mask(dev, 0x4eb, ~0x01c0);
bd3bf693 132 b43_phy_maskset(dev, 0x46a, 0xff00, 0x19);
dc713fb2
RM
133
134 b43_lcntab_write(dev, B43_LCNTAB16(0x00, 0x55), 0);
135
136 b43_radio_mask(dev, 0x05b, (u16) ~0xff02);
137 b43_radio_set(dev, 0x004, 0x40);
138 b43_radio_set(dev, 0x120, 0x10);
139 b43_radio_set(dev, 0x078, 0x80);
140 b43_radio_set(dev, 0x129, 0x2);
141 b43_radio_set(dev, 0x057, 0x1);
142 b43_radio_set(dev, 0x05b, 0x2);
143
144 /* TODO: wait for some bit to be set */
145 b43_radio_read(dev, 0x05c);
146
147 b43_radio_mask(dev, 0x05b, (u16) ~0xff02);
148 b43_radio_mask(dev, 0x057, (u16) ~0xff01);
149
150 b43_phy_write(dev, 0x933, 0x2d6b);
151 b43_phy_write(dev, 0x934, 0x2d6b);
152 b43_phy_write(dev, 0x935, 0x2d6b);
153 b43_phy_write(dev, 0x936, 0x2d6b);
154 b43_phy_write(dev, 0x937, 0x016b);
155
156 b43_radio_mask(dev, 0x057, (u16) ~0xff02);
157 b43_radio_write(dev, 0x0c2, 0x006f);
158}
159
78bc2463
RM
160/**************************************************
161 * Various PHY ops
162 **************************************************/
163
bce4dc4a 164/* wlc_lcnphy_toggle_afe_pwdn */
78bc2463
RM
165static void b43_phy_lcn_afe_set_unset(struct b43_wldev *dev)
166{
167 u16 afe_ctl2 = b43_phy_read(dev, B43_PHY_LCN_AFE_CTL2);
168 u16 afe_ctl1 = b43_phy_read(dev, B43_PHY_LCN_AFE_CTL1);
169
170 b43_phy_write(dev, B43_PHY_LCN_AFE_CTL2, afe_ctl2 | 0x1);
171 b43_phy_write(dev, B43_PHY_LCN_AFE_CTL1, afe_ctl1 | 0x1);
172
173 b43_phy_write(dev, B43_PHY_LCN_AFE_CTL2, afe_ctl2 & ~0x1);
174 b43_phy_write(dev, B43_PHY_LCN_AFE_CTL1, afe_ctl1 & ~0x1);
175
176 b43_phy_write(dev, B43_PHY_LCN_AFE_CTL2, afe_ctl2);
177 b43_phy_write(dev, B43_PHY_LCN_AFE_CTL1, afe_ctl1);
178}
179
1b0a69c1
RM
180/* wlc_lcnphy_get_pa_gain */
181static u16 b43_phy_lcn_get_pa_gain(struct b43_wldev *dev)
182{
183 return (b43_phy_read(dev, 0x4fb) & 0x7f00) >> 8;
184}
185
186/* wlc_lcnphy_set_dac_gain */
187static void b43_phy_lcn_set_dac_gain(struct b43_wldev *dev, u16 dac_gain)
188{
189 u16 dac_ctrl;
190
191 dac_ctrl = b43_phy_read(dev, 0x439);
192 dac_ctrl = dac_ctrl & 0xc7f;
193 dac_ctrl = dac_ctrl | (dac_gain << 7);
194 b43_phy_maskset(dev, 0x439, ~0xfff, dac_ctrl);
195}
196
197/* wlc_lcnphy_set_bbmult */
198static void b43_phy_lcn_set_bbmult(struct b43_wldev *dev, u8 m0)
199{
200 b43_lcntab_write(dev, B43_LCNTAB16(0x00, 0x57), m0 << 8);
201}
202
bce4dc4a
RM
203/* wlc_lcnphy_clear_tx_power_offsets */
204static void b43_phy_lcn_clear_tx_power_offsets(struct b43_wldev *dev)
78bc2463
RM
205{
206 u8 i;
207
cf577fc2
RM
208 if (1) { /* FIXME */
209 b43_phy_write(dev, B43_PHY_LCN_TABLE_ADDR, (0x7 << 10) | 0x340);
210 for (i = 0; i < 30; i++) {
211 b43_phy_write(dev, B43_PHY_LCN_TABLE_DATAHI, 0);
212 b43_phy_write(dev, B43_PHY_LCN_TABLE_DATALO, 0);
213 }
78bc2463
RM
214 }
215
216 b43_phy_write(dev, B43_PHY_LCN_TABLE_ADDR, (0x7 << 10) | 0x80);
217 for (i = 0; i < 64; i++) {
218 b43_phy_write(dev, B43_PHY_LCN_TABLE_DATAHI, 0);
219 b43_phy_write(dev, B43_PHY_LCN_TABLE_DATALO, 0);
220 }
221}
222
bce4dc4a
RM
223/* wlc_lcnphy_rev0_baseband_init */
224static void b43_phy_lcn_rev0_baseband_init(struct b43_wldev *dev)
bd3bf693
RM
225{
226 b43_radio_write(dev, 0x11c, 0);
227
228 b43_phy_write(dev, 0x43b, 0);
229 b43_phy_write(dev, 0x43c, 0);
230 b43_phy_write(dev, 0x44c, 0);
231 b43_phy_write(dev, 0x4e6, 0);
232 b43_phy_write(dev, 0x4f9, 0);
233 b43_phy_write(dev, 0x4b0, 0);
234 b43_phy_write(dev, 0x938, 0);
235 b43_phy_write(dev, 0x4b0, 0);
236 b43_phy_write(dev, 0x44e, 0);
237
238 b43_phy_set(dev, 0x567, 0x03);
239
240 b43_phy_set(dev, 0x44a, 0x44);
241 b43_phy_write(dev, 0x44a, 0x80);
242
cf577fc2
RM
243 if (!(dev->dev->bus_sprom->boardflags_lo & B43_BFL_FEM))
244 ; /* TODO */
bd3bf693 245 b43_phy_maskset(dev, 0x634, ~0xff, 0xc);
cf577fc2
RM
246 if (dev->dev->bus_sprom->boardflags_lo & B43_BFL_FEM) {
247 b43_phy_maskset(dev, 0x634, ~0xff, 0xa);
248 b43_phy_write(dev, 0x910, 0x1);
249 }
bd3bf693
RM
250
251 b43_phy_write(dev, 0x910, 0x1);
252
253 b43_phy_maskset(dev, 0x448, ~0x300, 0x100);
254 b43_phy_maskset(dev, 0x608, ~0xff, 0x17);
255 b43_phy_maskset(dev, 0x604, ~0x7ff, 0x3ea);
bce4dc4a 256}
bd3bf693 257
bce4dc4a
RM
258/* wlc_lcnphy_bu_tweaks */
259static void b43_phy_lcn_bu_tweaks(struct b43_wldev *dev)
260{
bd3bf693
RM
261 b43_phy_set(dev, 0x805, 0x1);
262
263 b43_phy_maskset(dev, 0x42f, ~0x7, 0x3);
264 b43_phy_maskset(dev, 0x030, ~0x7, 0x3);
265
266 b43_phy_write(dev, 0x414, 0x1e10);
267 b43_phy_write(dev, 0x415, 0x0640);
268
269 b43_phy_maskset(dev, 0x4df, (u16) ~0xff00, 0xf700);
270
271 b43_phy_set(dev, 0x44a, 0x44);
272 b43_phy_write(dev, 0x44a, 0x80);
273
274 b43_phy_maskset(dev, 0x434, ~0xff, 0xfd);
275 b43_phy_maskset(dev, 0x420, ~0xff, 0x10);
276
cf577fc2
RM
277 if (dev->dev->bus_sprom->board_rev >= 0x1204)
278 b43_radio_set(dev, 0x09b, 0xf0);
bd3bf693
RM
279
280 b43_phy_write(dev, 0x7d6, 0x0902);
281
bbb55742
RM
282 b43_phy_maskset(dev, 0x429, ~0xf, 0x9);
283 b43_phy_maskset(dev, 0x429, ~(0x3f << 4), 0xe << 4);
bce4dc4a
RM
284
285 if (dev->phy.rev == 1) {
bbb55742
RM
286 b43_phy_maskset(dev, 0x423, ~0xff, 0x46);
287 b43_phy_maskset(dev, 0x411, ~0xff, 1);
288 b43_phy_set(dev, 0x434, 0xff); /* FIXME: update to wl */
289
290 /* TODO: wl operates on PHY 0x416, brcmsmac is outdated here */
291
292 b43_phy_maskset(dev, 0x656, ~0xf, 2);
293 b43_phy_set(dev, 0x44d, 4);
294
295 b43_radio_set(dev, 0x0f7, 0x4);
296 b43_radio_mask(dev, 0x0f1, ~0x3);
297 b43_radio_maskset(dev, 0x0f2, ~0xf8, 0x90);
298 b43_radio_maskset(dev, 0x0f3, ~0x3, 0x2);
299 b43_radio_maskset(dev, 0x0f3, ~0xf0, 0xa0);
300
301 b43_radio_set(dev, 0x11f, 0x2);
bce4dc4a
RM
302
303 b43_phy_lcn_clear_tx_power_offsets(dev);
bbb55742
RM
304
305 /* TODO: something more? */
bce4dc4a 306 }
bd3bf693
RM
307}
308
bce4dc4a 309/* wlc_lcnphy_vbat_temp_sense_setup */
29818082
RM
310static void b43_phy_lcn_sense_setup(struct b43_wldev *dev,
311 enum lcn_sense_type sense_type)
765b07e4 312{
29818082
RM
313 u8 auxpga_vmidcourse, auxpga_vmidfine, auxpga_gain;
314 u16 auxpga_vmid;
315 u8 tx_pwr_idx;
765b07e4
RM
316 u8 i;
317
318 u16 save_radio_regs[6][2] = {
319 { 0x007, 0 }, { 0x0ff, 0 }, { 0x11f, 0 }, { 0x005, 0 },
320 { 0x025, 0 }, { 0x112, 0 },
321 };
322 u16 save_phy_regs[14][2] = {
323 { 0x503, 0 }, { 0x4a4, 0 }, { 0x4d0, 0 }, { 0x4d9, 0 },
324 { 0x4da, 0 }, { 0x4a6, 0 }, { 0x938, 0 }, { 0x939, 0 },
325 { 0x4d8, 0 }, { 0x4d0, 0 }, { 0x4d7, 0 }, { 0x4a5, 0 },
326 { 0x40d, 0 }, { 0x4a2, 0 },
327 };
328 u16 save_radio_4a4;
329
29818082
RM
330 msleep(1);
331
332 /* Save */
765b07e4
RM
333 for (i = 0; i < 6; i++)
334 save_radio_regs[i][1] = b43_radio_read(dev,
335 save_radio_regs[i][0]);
336 for (i = 0; i < 14; i++)
337 save_phy_regs[i][1] = b43_phy_read(dev, save_phy_regs[i][0]);
29818082 338 b43_mac_suspend(dev);
765b07e4 339 save_radio_4a4 = b43_radio_read(dev, 0x4a4);
29818082
RM
340 /* wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF); */
341 tx_pwr_idx = dev->phy.lcn->tx_pwr_curr_idx;
342
343 /* Setup */
344 /* TODO: wlc_lcnphy_set_tx_pwr_by_index(pi, 127); */
345 b43_radio_set(dev, 0x007, 0x1);
346 b43_radio_set(dev, 0x0ff, 0x10);
347 b43_radio_set(dev, 0x11f, 0x4);
348
349 b43_phy_mask(dev, 0x503, ~0x1);
350 b43_phy_mask(dev, 0x503, ~0x4);
351 b43_phy_mask(dev, 0x4a4, ~0x4000);
352 b43_phy_mask(dev, 0x4a4, (u16) ~0x8000);
353 b43_phy_mask(dev, 0x4d0, ~0x20);
354 b43_phy_set(dev, 0x4a5, 0xff);
355 b43_phy_maskset(dev, 0x4a5, ~0x7000, 0x5000);
356 b43_phy_mask(dev, 0x4a5, ~0x700);
357 b43_phy_maskset(dev, 0x40d, ~0xff, 64);
358 b43_phy_maskset(dev, 0x40d, ~0x700, 0x600);
359 b43_phy_maskset(dev, 0x4a2, ~0xff, 64);
360 b43_phy_maskset(dev, 0x4a2, ~0x700, 0x600);
361 b43_phy_maskset(dev, 0x4d9, ~0x70, 0x20);
362 b43_phy_maskset(dev, 0x4d9, ~0x700, 0x300);
363 b43_phy_maskset(dev, 0x4d9, ~0x7000, 0x1000);
364 b43_phy_mask(dev, 0x4da, ~0x1000);
365 b43_phy_set(dev, 0x4da, 0x2000);
366 b43_phy_set(dev, 0x4a6, 0x8000);
367
368 b43_radio_write(dev, 0x025, 0xc);
369 b43_radio_set(dev, 0x005, 0x8);
370 b43_phy_set(dev, 0x938, 0x4);
371 b43_phy_set(dev, 0x939, 0x4);
372 b43_phy_set(dev, 0x4a4, 0x1000);
373
374 /* FIXME: don't hardcode */
375 b43_lcntab_write(dev, B43_LCNTAB16(0x8, 0x6), 0x640);
376
377 switch (sense_type) {
378 case B43_SENSE_TEMP:
379 b43_phy_set(dev, 0x4d7, 0x8);
380 b43_phy_maskset(dev, 0x4d7, ~0x7000, 0x1000);
381 auxpga_vmidcourse = 8;
382 auxpga_vmidfine = 0x4;
383 auxpga_gain = 2;
384 b43_radio_set(dev, 0x082, 0x20);
385 break;
386 case B43_SENSE_VBAT:
387 b43_phy_set(dev, 0x4d7, 0x8);
388 b43_phy_maskset(dev, 0x4d7, ~0x7000, 0x3000);
389 auxpga_vmidcourse = 7;
390 auxpga_vmidfine = 0xa;
391 auxpga_gain = 2;
392 break;
393 }
394 auxpga_vmid = (0x200 | (auxpga_vmidcourse << 4) | auxpga_vmidfine);
765b07e4 395
29818082
RM
396 b43_phy_set(dev, 0x4d8, 0x1);
397 b43_phy_maskset(dev, 0x4d8, ~(0x3ff << 2), auxpga_vmid << 2);
398 b43_phy_set(dev, 0x4d8, 0x2);
399 b43_phy_maskset(dev, 0x4d8, ~(0x7 << 12), auxpga_gain << 12);
400 b43_phy_set(dev, 0x4d0, 0x20);
401 b43_radio_write(dev, 0x112, 0x6);
765b07e4 402
177c3732 403 b43_dummy_transmission(dev, true, false);
29818082
RM
404 /* Wait if not done */
405 if (!(b43_phy_read(dev, 0x476) & 0x8000))
406 udelay(10);
407
408 /* Restore */
765b07e4
RM
409 for (i = 0; i < 6; i++)
410 b43_radio_write(dev, save_radio_regs[i][0],
411 save_radio_regs[i][1]);
412 for (i = 0; i < 14; i++)
413 b43_phy_write(dev, save_phy_regs[i][0], save_phy_regs[i][1]);
29818082 414 /* TODO: wlc_lcnphy_set_tx_pwr_by_index(tx_pwr_idx) */
765b07e4 415 b43_radio_write(dev, 0x4a4, save_radio_4a4);
29818082
RM
416
417 b43_mac_enable(dev);
418
419 msleep(1);
765b07e4
RM
420}
421
0c5644b9
RM
422static bool b43_phy_lcn_load_tx_iir_cck_filter(struct b43_wldev *dev,
423 u8 filter_type)
424{
425 int i, j;
426 u16 phy_regs[] = { 0x910, 0x91e, 0x91f, 0x924, 0x925, 0x926, 0x920,
427 0x921, 0x927, 0x928, 0x929, 0x922, 0x923, 0x930,
428 0x931, 0x932 };
429 /* Table is from brcmsmac, values for type 25 were outdated, probably
430 * others need updating too */
431 struct lcn_tx_iir_filter tx_iir_filters_cck[] = {
432 { 0, { 1, 415, 1874, 64, 128, 64, 792, 1656, 64, 128, 64, 778,
433 1582, 64, 128, 64 } },
434 { 1, { 1, 402, 1847, 259, 59, 259, 671, 1794, 68, 54, 68, 608,
435 1863, 93, 167, 93 } },
436 { 2, { 1, 415, 1874, 64, 128, 64, 792, 1656, 192, 384, 192,
437 778, 1582, 64, 128, 64 } },
438 { 3, { 1, 302, 1841, 129, 258, 129, 658, 1720, 205, 410, 205,
439 754, 1760, 170, 340, 170 } },
440 { 20, { 1, 360, 1884, 242, 1734, 242, 752, 1720, 205, 1845, 205,
441 767, 1760, 256, 185, 256 } },
442 { 21, { 1, 360, 1884, 149, 1874, 149, 752, 1720, 205, 1883, 205,
443 767, 1760, 256, 273, 256 } },
444 { 22, { 1, 360, 1884, 98, 1948, 98, 752, 1720, 205, 1924, 205,
445 767, 1760, 256, 352, 256 } },
446 { 23, { 1, 350, 1884, 116, 1966, 116, 752, 1720, 205, 2008, 205,
447 767, 1760, 128, 233, 128 } },
448 { 24, { 1, 325, 1884, 32, 40, 32, 756, 1720, 256, 471, 256, 766,
449 1760, 256, 1881, 256 } },
450 { 25, { 1, 299, 1884, 51, 64, 51, 736, 1720, 256, 471, 256, 765,
451 1760, 262, 1878, 262 } },
452 /* brcmsmac version { 25, { 1, 299, 1884, 51, 64, 51, 736, 1720,
453 * 256, 471, 256, 765, 1760, 256, 1881, 256 } }, */
454 { 26, { 1, 277, 1943, 39, 117, 88, 637, 1838, 64, 192, 144, 614,
455 1864, 128, 384, 288 } },
456 { 27, { 1, 245, 1943, 49, 147, 110, 626, 1838, 256, 768, 576,
457 613, 1864, 128, 384, 288 } },
458 { 30, { 1, 302, 1841, 61, 122, 61, 658, 1720, 205, 410, 205,
459 754, 1760, 170, 340, 170 } },
460 };
461
462 for (i = 0; i < ARRAY_SIZE(tx_iir_filters_cck); i++) {
463 if (tx_iir_filters_cck[i].type == filter_type) {
464 for (j = 0; j < 16; j++)
465 b43_phy_write(dev, phy_regs[j],
466 tx_iir_filters_cck[i].values[j]);
467 return true;
468 }
469 }
470
471 return false;
472}
473
474static bool b43_phy_lcn_load_tx_iir_ofdm_filter(struct b43_wldev *dev,
475 u8 filter_type)
476{
477 int i, j;
478 u16 phy_regs[] = { 0x90f, 0x900, 0x901, 0x906, 0x907, 0x908, 0x902,
479 0x903, 0x909, 0x90a, 0x90b, 0x904, 0x905, 0x90c,
480 0x90d, 0x90e };
481 struct lcn_tx_iir_filter tx_iir_filters_ofdm[] = {
482 { 0, { 0, 0xa2, 0x0, 0x100, 0x100, 0x0, 0x0, 0x0, 0x100, 0x0,
483 0x0, 0x278, 0xfea0, 0x80, 0x100, 0x80 } },
484 { 1, { 0, 374, 0xFF79, 16, 32, 16, 799, 0xFE74, 50, 32, 50, 750,
485 0xFE2B, 212, 0xFFCE, 212 } },
486 { 2, { 0, 375, 0xFF16, 37, 76, 37, 799, 0xFE74, 32, 20, 32, 748,
487 0xFEF2, 128, 0xFFE2, 128 } },
488 };
489
490 for (i = 0; i < ARRAY_SIZE(tx_iir_filters_ofdm); i++) {
491 if (tx_iir_filters_ofdm[i].type == filter_type) {
492 for (j = 0; j < 16; j++)
493 b43_phy_write(dev, phy_regs[j],
494 tx_iir_filters_ofdm[i].values[j]);
495 return true;
496 }
497 }
498
499 return false;
500}
501
1b0a69c1
RM
502/* wlc_lcnphy_set_tx_gain_override */
503static void b43_phy_lcn_set_tx_gain_override(struct b43_wldev *dev, bool enable)
504{
505 b43_phy_maskset(dev, 0x4b0, ~(0x1 << 7), enable << 7);
506 b43_phy_maskset(dev, 0x4b0, ~(0x1 << 14), enable << 14);
507 b43_phy_maskset(dev, 0x43b, ~(0x1 << 6), enable << 6);
508}
509
510/* wlc_lcnphy_set_tx_gain */
511static void b43_phy_lcn_set_tx_gain(struct b43_wldev *dev,
512 struct lcn_tx_gains *target_gains)
513{
514 u16 pa_gain = b43_phy_lcn_get_pa_gain(dev);
515
516 b43_phy_write(dev, 0x4b5,
517 (target_gains->gm_gain | (target_gains->pga_gain << 8)));
518 b43_phy_maskset(dev, 0x4fb, ~0x7fff,
519 (target_gains->pad_gain | (pa_gain << 8)));
520 b43_phy_write(dev, 0x4fc,
521 (target_gains->gm_gain | (target_gains->pga_gain << 8)));
522 b43_phy_maskset(dev, 0x4fd, ~0x7fff,
523 (target_gains->pad_gain | (pa_gain << 8)));
524
525 b43_phy_lcn_set_dac_gain(dev, target_gains->dac_gain);
526 b43_phy_lcn_set_tx_gain_override(dev, true);
527}
528
529/* wlc_lcnphy_tx_pwr_ctrl_init */
530static void b43_phy_lcn_tx_pwr_ctl_init(struct b43_wldev *dev)
531{
532 struct lcn_tx_gains tx_gains;
533 u8 bbmult;
534
535 b43_mac_suspend(dev);
536
537 if (!dev->phy.lcn->hw_pwr_ctl_capable) {
538 if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
539 tx_gains.gm_gain = 4;
540 tx_gains.pga_gain = 12;
541 tx_gains.pad_gain = 12;
542 tx_gains.dac_gain = 0;
543 bbmult = 150;
544 } else {
545 tx_gains.gm_gain = 7;
546 tx_gains.pga_gain = 15;
547 tx_gains.pad_gain = 14;
548 tx_gains.dac_gain = 0;
549 bbmult = 150;
550 }
551 b43_phy_lcn_set_tx_gain(dev, &tx_gains);
552 b43_phy_lcn_set_bbmult(dev, bbmult);
29818082 553 b43_phy_lcn_sense_setup(dev, B43_SENSE_TEMP);
1b0a69c1
RM
554 } else {
555 b43err(dev->wl, "TX power control not supported for this HW\n");
556 }
557
558 b43_mac_enable(dev);
559}
560
ac78a52f
RM
561/* wlc_lcnphy_txrx_spur_avoidance_mode */
562static void b43_phy_lcn_txrx_spur_avoidance_mode(struct b43_wldev *dev,
563 bool enable)
564{
565 if (enable) {
566 b43_phy_write(dev, 0x942, 0x7);
567 b43_phy_write(dev, 0x93b, ((1 << 13) + 23));
568 b43_phy_write(dev, 0x93c, ((1 << 13) + 1989));
569
570 b43_phy_write(dev, 0x44a, 0x084);
571 b43_phy_write(dev, 0x44a, 0x080);
572 b43_phy_write(dev, 0x6d3, 0x2222);
573 b43_phy_write(dev, 0x6d3, 0x2220);
574 } else {
575 b43_phy_write(dev, 0x942, 0x0);
576 b43_phy_write(dev, 0x93b, ((0 << 13) + 23));
577 b43_phy_write(dev, 0x93c, ((0 << 13) + 1989));
578 }
c2cb2c4c 579 b43_mac_switch_freq(dev, enable);
ac78a52f
RM
580}
581
39f7d33c
RM
582/**************************************************
583 * Channel switching ops.
584 **************************************************/
585
b534706a
RM
586/* wlc_lcnphy_set_chanspec_tweaks */
587static void b43_phy_lcn_set_channel_tweaks(struct b43_wldev *dev, int channel)
39f7d33c 588{
b534706a
RM
589 struct bcma_drv_cc *cc = &dev->dev->bdev->bus->drv_cc;
590
591 b43_phy_maskset(dev, 0x448, ~0x300, (channel == 14) ? 0x200 : 0x100);
592
593 if (channel == 1 || channel == 2 || channel == 3 || channel == 4 ||
594 channel == 9 || channel == 10 || channel == 11 || channel == 12) {
595 bcma_chipco_pll_write(cc, 0x2, 0x03000c04);
596 bcma_chipco_pll_maskset(cc, 0x3, 0x00ffffff, 0x0);
597 bcma_chipco_pll_write(cc, 0x4, 0x200005c0);
598
599 bcma_cc_set32(cc, BCMA_CC_PMU_CTL, 0x400);
600
601 b43_phy_write(dev, 0x942, 0);
602
ac78a52f 603 b43_phy_lcn_txrx_spur_avoidance_mode(dev, false);
b534706a
RM
604 b43_phy_maskset(dev, 0x424, (u16) ~0xff00, 0x1b00);
605 b43_phy_write(dev, 0x425, 0x5907);
606 } else {
607 bcma_chipco_pll_write(cc, 0x2, 0x03140c04);
608 bcma_chipco_pll_maskset(cc, 0x3, 0x00ffffff, 0x333333);
609 bcma_chipco_pll_write(cc, 0x4, 0x202c2820);
610
611 bcma_cc_set32(cc, BCMA_CC_PMU_CTL, 0x400);
612
613 b43_phy_write(dev, 0x942, 0);
614
ac78a52f 615 b43_phy_lcn_txrx_spur_avoidance_mode(dev, true);
b534706a
RM
616 b43_phy_maskset(dev, 0x424, (u16) ~0xff00, 0x1f00);
617 b43_phy_write(dev, 0x425, 0x590a);
618 }
39f7d33c
RM
619
620 b43_phy_set(dev, 0x44a, 0x44);
621 b43_phy_write(dev, 0x44a, 0x80);
b534706a
RM
622}
623
624/* wlc_phy_chanspec_set_lcnphy */
625static int b43_phy_lcn_set_channel(struct b43_wldev *dev,
626 struct ieee80211_channel *channel,
627 enum nl80211_channel_type channel_type)
628{
0c5644b9
RM
629 static const u16 sfo_cfg[14][2] = {
630 {965, 1087}, {967, 1085}, {969, 1082}, {971, 1080}, {973, 1078},
631 {975, 1076}, {977, 1073}, {979, 1071}, {981, 1069}, {983, 1067},
632 {985, 1065}, {987, 1063}, {989, 1060}, {994, 1055},
633 };
634
b534706a 635 b43_phy_lcn_set_channel_tweaks(dev, channel->hw_value);
39f7d33c
RM
636
637 b43_phy_set(dev, 0x44a, 0x44);
638 b43_phy_write(dev, 0x44a, 0x80);
639
640 b43_radio_2064_channel_setup(dev);
641 mdelay(1);
642
643 b43_phy_lcn_afe_set_unset(dev);
644
0c5644b9
RM
645 b43_phy_write(dev, 0x657, sfo_cfg[channel->hw_value - 1][0]);
646 b43_phy_write(dev, 0x658, sfo_cfg[channel->hw_value - 1][1]);
647
648 if (channel->hw_value == 14) {
649 b43_phy_maskset(dev, 0x448, ~(0x3 << 8), (2) << 8);
650 b43_phy_lcn_load_tx_iir_cck_filter(dev, 3);
651 } else {
652 b43_phy_maskset(dev, 0x448, ~(0x3 << 8), (1) << 8);
653 /* brcmsmac uses filter_type 2, we follow wl with 25 */
654 b43_phy_lcn_load_tx_iir_cck_filter(dev, 25);
655 }
656 /* brcmsmac uses filter_type 2, we follow wl with 0 */
657 b43_phy_lcn_load_tx_iir_ofdm_filter(dev, 0);
658
659 b43_phy_maskset(dev, 0x4eb, ~(0x7 << 3), 0x1 << 3);
39f7d33c
RM
660
661 return 0;
662}
663
f928668f
RM
664/**************************************************
665 * Basic PHY ops.
666 **************************************************/
667
668static int b43_phy_lcn_op_allocate(struct b43_wldev *dev)
669{
670 struct b43_phy_lcn *phy_lcn;
671
672 phy_lcn = kzalloc(sizeof(*phy_lcn), GFP_KERNEL);
673 if (!phy_lcn)
674 return -ENOMEM;
675 dev->phy.lcn = phy_lcn;
676
677 return 0;
678}
679
680static void b43_phy_lcn_op_free(struct b43_wldev *dev)
681{
682 struct b43_phy *phy = &dev->phy;
683 struct b43_phy_lcn *phy_lcn = phy->lcn;
684
685 kfree(phy_lcn);
686 phy->lcn = NULL;
687}
688
689static void b43_phy_lcn_op_prepare_structs(struct b43_wldev *dev)
690{
691 struct b43_phy *phy = &dev->phy;
692 struct b43_phy_lcn *phy_lcn = phy->lcn;
693
694 memset(phy_lcn, 0, sizeof(*phy_lcn));
695}
696
bce4dc4a 697/* wlc_phy_init_lcnphy */
78bc2463
RM
698static int b43_phy_lcn_op_init(struct b43_wldev *dev)
699{
b534706a
RM
700 struct bcma_drv_cc *cc = &dev->dev->bdev->bus->drv_cc;
701
78bc2463
RM
702 b43_phy_set(dev, 0x44a, 0x80);
703 b43_phy_mask(dev, 0x44a, 0x7f);
704 b43_phy_set(dev, 0x6d1, 0x80);
705 b43_phy_write(dev, 0x6d0, 0x7);
706
707 b43_phy_lcn_afe_set_unset(dev);
708
709 b43_phy_write(dev, 0x60a, 0xa0);
710 b43_phy_write(dev, 0x46a, 0x19);
711 b43_phy_maskset(dev, 0x663, 0xFF00, 0x64);
712
713 b43_phy_lcn_tables_init(dev);
78bc2463 714
bce4dc4a
RM
715 b43_phy_lcn_rev0_baseband_init(dev);
716 b43_phy_lcn_bu_tweaks(dev);
78bc2463 717
dc713fb2
RM
718 if (dev->phy.radio_ver == 0x2064)
719 b43_radio_2064_init(dev);
720 else
721 B43_WARN_ON(1);
722
1b0a69c1
RM
723 if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
724 b43_phy_lcn_tx_pwr_ctl_init(dev);
765b07e4 725
b534706a
RM
726 b43_switch_channel(dev, dev->phy.channel);
727
728 bcma_chipco_regctl_maskset(cc, 0, 0xf, 0x9);
729 bcma_chipco_chipctl_maskset(cc, 0, 0, 0x03cddddd);
730
731 /* TODO */
732
733 b43_phy_set(dev, 0x448, 0x4000);
734 udelay(100);
735 b43_phy_mask(dev, 0x448, ~0x4000);
736
737 /* TODO */
738
78bc2463
RM
739 return 0;
740}
741
ba356b56
RM
742static void b43_phy_lcn_op_software_rfkill(struct b43_wldev *dev,
743 bool blocked)
744{
745 if (b43_read32(dev, B43_MMIO_MACCTL) & B43_MACCTL_ENABLED)
746 b43err(dev->wl, "MAC not suspended\n");
747
748 if (blocked) {
749 b43_phy_mask(dev, B43_PHY_LCN_RF_CTL2, ~0x7c00);
750 b43_phy_set(dev, B43_PHY_LCN_RF_CTL1, 0x1f00);
751
752 b43_phy_mask(dev, B43_PHY_LCN_RF_CTL5, ~0x7f00);
753 b43_phy_mask(dev, B43_PHY_LCN_RF_CTL4, ~0x2);
754 b43_phy_set(dev, B43_PHY_LCN_RF_CTL3, 0x808);
755
756 b43_phy_mask(dev, B43_PHY_LCN_RF_CTL7, ~0x8);
757 b43_phy_set(dev, B43_PHY_LCN_RF_CTL6, 0x8);
758 } else {
78bc2463
RM
759 b43_phy_mask(dev, B43_PHY_LCN_RF_CTL1, ~0x1f00);
760 b43_phy_mask(dev, B43_PHY_LCN_RF_CTL3, ~0x808);
761 b43_phy_mask(dev, B43_PHY_LCN_RF_CTL6, ~0x8);
ba356b56
RM
762 }
763}
764
7ed88528
RM
765static void b43_phy_lcn_op_switch_analog(struct b43_wldev *dev, bool on)
766{
767 if (on) {
768 b43_phy_mask(dev, B43_PHY_LCN_AFE_CTL1, ~0x7);
769 } else {
770 b43_phy_set(dev, B43_PHY_LCN_AFE_CTL2, 0x7);
771 b43_phy_set(dev, B43_PHY_LCN_AFE_CTL1, 0x7);
772 }
773}
774
39f7d33c
RM
775static int b43_phy_lcn_op_switch_channel(struct b43_wldev *dev,
776 unsigned int new_channel)
777{
675a0b04
KB
778 struct ieee80211_channel *channel = dev->wl->hw->conf.chandef.chan;
779 enum nl80211_channel_type channel_type =
780 cfg80211_get_chandef_type(&dev->wl->hw->conf.chandef);
39f7d33c
RM
781
782 if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
783 if ((new_channel < 1) || (new_channel > 14))
784 return -EINVAL;
785 } else {
786 return -EINVAL;
787 }
788
789 return b43_phy_lcn_set_channel(dev, channel, channel_type);
790}
791
f928668f
RM
792static unsigned int b43_phy_lcn_op_get_default_chan(struct b43_wldev *dev)
793{
794 if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
795 return 1;
796 return 36;
797}
798
799static enum b43_txpwr_result
800b43_phy_lcn_op_recalc_txpower(struct b43_wldev *dev, bool ignore_tssi)
801{
802 return B43_TXPWR_RES_DONE;
803}
804
805static void b43_phy_lcn_op_adjust_txpower(struct b43_wldev *dev)
806{
807}
808
f533d0fa
RM
809/**************************************************
810 * R/W ops.
811 **************************************************/
812
f533d0fa
RM
813static void b43_phy_lcn_op_maskset(struct b43_wldev *dev, u16 reg, u16 mask,
814 u16 set)
815{
25c15566 816 b43_write16f(dev, B43_MMIO_PHY_CONTROL, reg);
f533d0fa
RM
817 b43_write16(dev, B43_MMIO_PHY_DATA,
818 (b43_read16(dev, B43_MMIO_PHY_DATA) & mask) | set);
819}
820
821static u16 b43_phy_lcn_op_radio_read(struct b43_wldev *dev, u16 reg)
822{
823 /* LCN-PHY needs 0x200 for read access */
824 reg |= 0x200;
825
25c15566 826 b43_write16f(dev, B43_MMIO_RADIO24_CONTROL, reg);
f533d0fa
RM
827 return b43_read16(dev, B43_MMIO_RADIO24_DATA);
828}
829
830static void b43_phy_lcn_op_radio_write(struct b43_wldev *dev, u16 reg,
831 u16 value)
832{
25c15566 833 b43_write16f(dev, B43_MMIO_RADIO24_CONTROL, reg);
f533d0fa
RM
834 b43_write16(dev, B43_MMIO_RADIO24_DATA, value);
835}
836
1d738e64
RM
837/**************************************************
838 * PHY ops struct.
839 **************************************************/
840
841const struct b43_phy_operations b43_phyops_lcn = {
1d738e64
RM
842 .allocate = b43_phy_lcn_op_allocate,
843 .free = b43_phy_lcn_op_free,
844 .prepare_structs = b43_phy_lcn_op_prepare_structs,
845 .init = b43_phy_lcn_op_init,
1d738e64
RM
846 .phy_maskset = b43_phy_lcn_op_maskset,
847 .radio_read = b43_phy_lcn_op_radio_read,
848 .radio_write = b43_phy_lcn_op_radio_write,
849 .software_rfkill = b43_phy_lcn_op_software_rfkill,
850 .switch_analog = b43_phy_lcn_op_switch_analog,
851 .switch_channel = b43_phy_lcn_op_switch_channel,
852 .get_default_chan = b43_phy_lcn_op_get_default_chan,
853 .recalc_txpower = b43_phy_lcn_op_recalc_txpower,
854 .adjust_txpower = b43_phy_lcn_op_adjust_txpower,
1d738e64 855};
This page took 0.275425 seconds and 5 git commands to generate.