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