blob: 63bd29f070f70d91609f02dbc71ca0e83623b7f1 [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łecki29818082011-09-16 16:36:32 +020052enum lcn_sense_type {
53 B43_SENSE_TEMP,
54 B43_SENSE_VBAT,
55};
56
Rafał Miłecki1d738e62011-07-07 15:25:27 +020057/**************************************************
Rafał Miłeckidc713fb2011-08-15 18:50:56 +020058 * Radio 2064.
59 **************************************************/
60
Rafał Miłeckibce4dc42011-08-31 23:36:20 +020061/* wlc_lcnphy_radio_2064_channel_tune_4313 */
Rafał Miłecki39f7d332011-08-28 14:59:58 +020062static 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
Rafał Miłeckicf577fc2011-08-31 23:36:21 +020069 /* Channel specific values in theory, in practice always the same */
Rafał Miłecki39f7d332011-08-28 14:59:58 +020070 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
Rafał Miłeckicf577fc2011-08-31 23:36:21 +0200101 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 }
Rafał Miłecki39f7d332011-08-28 14:59:58 +0200106}
107
Rafał Miłeckibce4dc42011-08-31 23:36:20 +0200108/* wlc_radio_2064_init */
Rafał Miłeckidc713fb2011-08-15 18:50:56 +0200109static void b43_radio_2064_init(struct b43_wldev *dev)
110{
Johannes Berg57fbcce2016-04-12 15:56:15 +0200111 if (b43_current_band(dev->wl) == NL80211_BAND_2GHZ) {
Rafał Miłeckicf577fc2011-08-31 23:36:21 +0200112 b43_radio_write(dev, 0x09c, 0x0020);
113 b43_radio_write(dev, 0x105, 0x0008);
114 } else {
115 /* TODO */
116 }
Rafał Miłeckidc713fb2011-08-15 18:50:56 +0200117 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);
Rafał Miłeckicf577fc2011-08-31 23:36:21 +0200121 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 }
Rafał Miłeckidc713fb2011-08-15 18:50:56 +0200126 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);
Rafał Miłeckibd3bf692011-08-28 14:28:44 +0200132 b43_phy_maskset(dev, 0x46a, 0xff00, 0x19);
Rafał Miłeckidc713fb2011-08-15 18:50:56 +0200133
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
160/**************************************************
Rafał Miłecki78bc2462011-08-15 18:50:55 +0200161 * Various PHY ops
162 **************************************************/
163
Rafał Miłeckibce4dc42011-08-31 23:36:20 +0200164/* wlc_lcnphy_toggle_afe_pwdn */
Rafał Miłecki78bc2462011-08-15 18:50:55 +0200165static 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
Rafał Miłecki1b0a69c2011-09-16 12:34:02 +0200180/* 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
Rafał Miłeckibce4dc42011-08-31 23:36:20 +0200203/* wlc_lcnphy_clear_tx_power_offsets */
204static void b43_phy_lcn_clear_tx_power_offsets(struct b43_wldev *dev)
Rafał Miłecki78bc2462011-08-15 18:50:55 +0200205{
206 u8 i;
207
Rafał Miłeckicf577fc2011-08-31 23:36:21 +0200208 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 }
Rafał Miłecki78bc2462011-08-15 18:50:55 +0200214 }
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
Rafał Miłeckibce4dc42011-08-31 23:36:20 +0200223/* wlc_lcnphy_rev0_baseband_init */
224static void b43_phy_lcn_rev0_baseband_init(struct b43_wldev *dev)
Rafał Miłeckibd3bf692011-08-28 14:28:44 +0200225{
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
Rafał Miłeckicf577fc2011-08-31 23:36:21 +0200243 if (!(dev->dev->bus_sprom->boardflags_lo & B43_BFL_FEM))
244 ; /* TODO */
Rafał Miłeckibd3bf692011-08-28 14:28:44 +0200245 b43_phy_maskset(dev, 0x634, ~0xff, 0xc);
Rafał Miłeckicf577fc2011-08-31 23:36:21 +0200246 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 }
Rafał Miłeckibd3bf692011-08-28 14:28:44 +0200250
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);
Rafał Miłeckibce4dc42011-08-31 23:36:20 +0200256}
Rafał Miłeckibd3bf692011-08-28 14:28:44 +0200257
Rafał Miłeckibce4dc42011-08-31 23:36:20 +0200258/* wlc_lcnphy_bu_tweaks */
259static void b43_phy_lcn_bu_tweaks(struct b43_wldev *dev)
260{
Rafał Miłeckibd3bf692011-08-28 14:28:44 +0200261 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
Rafał Miłeckicf577fc2011-08-31 23:36:21 +0200277 if (dev->dev->bus_sprom->board_rev >= 0x1204)
278 b43_radio_set(dev, 0x09b, 0xf0);
Rafał Miłeckibd3bf692011-08-28 14:28:44 +0200279
280 b43_phy_write(dev, 0x7d6, 0x0902);
281
Rafał Miłeckibbb55742011-09-16 12:34:03 +0200282 b43_phy_maskset(dev, 0x429, ~0xf, 0x9);
283 b43_phy_maskset(dev, 0x429, ~(0x3f << 4), 0xe << 4);
Rafał Miłeckibce4dc42011-08-31 23:36:20 +0200284
285 if (dev->phy.rev == 1) {
Rafał Miłeckibbb55742011-09-16 12:34:03 +0200286 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);
Rafał Miłeckibce4dc42011-08-31 23:36:20 +0200302
303 b43_phy_lcn_clear_tx_power_offsets(dev);
Rafał Miłeckibbb55742011-09-16 12:34:03 +0200304
305 /* TODO: something more? */
Rafał Miłeckibce4dc42011-08-31 23:36:20 +0200306 }
Rafał Miłeckibd3bf692011-08-28 14:28:44 +0200307}
308
Rafał Miłeckibce4dc42011-08-31 23:36:20 +0200309/* wlc_lcnphy_vbat_temp_sense_setup */
Rafał Miłecki29818082011-09-16 16:36:32 +0200310static void b43_phy_lcn_sense_setup(struct b43_wldev *dev,
311 enum lcn_sense_type sense_type)
Rafał Miłecki765b07e2011-08-28 19:59:28 +0200312{
Rafał Miłecki29818082011-09-16 16:36:32 +0200313 u8 auxpga_vmidcourse, auxpga_vmidfine, auxpga_gain;
314 u16 auxpga_vmid;
315 u8 tx_pwr_idx;
Rafał Miłecki765b07e2011-08-28 19:59:28 +0200316 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
Rafał Miłecki29818082011-09-16 16:36:32 +0200330 msleep(1);
331
332 /* Save */
Rafał Miłecki765b07e2011-08-28 19:59:28 +0200333 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]);
Rafał Miłecki29818082011-09-16 16:36:32 +0200338 b43_mac_suspend(dev);
Rafał Miłecki765b07e2011-08-28 19:59:28 +0200339 save_radio_4a4 = b43_radio_read(dev, 0x4a4);
Rafał Miłecki29818082011-09-16 16:36:32 +0200340 /* wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF); */
341 tx_pwr_idx = dev->phy.lcn->tx_pwr_curr_idx;
Rafał Miłecki765b07e2011-08-28 19:59:28 +0200342
Rafał Miłecki29818082011-09-16 16:36:32 +0200343 /* 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);
Rafał Miłecki765b07e2011-08-28 19:59:28 +0200348
Rafał Miłecki29818082011-09-16 16:36:32 +0200349 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);
395
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);
402
Rafał Miłecki177c3732011-09-21 21:44:15 +0200403 b43_dummy_transmission(dev, true, false);
Rafał Miłecki29818082011-09-16 16:36:32 +0200404 /* Wait if not done */
405 if (!(b43_phy_read(dev, 0x476) & 0x8000))
406 udelay(10);
407
408 /* Restore */
Rafał Miłecki765b07e2011-08-28 19:59:28 +0200409 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]);
Rafał Miłecki29818082011-09-16 16:36:32 +0200414 /* TODO: wlc_lcnphy_set_tx_pwr_by_index(tx_pwr_idx) */
Rafał Miłecki765b07e2011-08-28 19:59:28 +0200415 b43_radio_write(dev, 0x4a4, save_radio_4a4);
Rafał Miłecki29818082011-09-16 16:36:32 +0200416
417 b43_mac_enable(dev);
418
419 msleep(1);
Rafał Miłecki765b07e2011-08-28 19:59:28 +0200420}
421
Rafał Miłecki0c5644b92011-09-16 12:34:00 +0200422static 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
Rafał Miłecki1b0a69c2011-09-16 12:34:02 +0200502/* 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) {
Johannes Berg57fbcce2016-04-12 15:56:15 +0200538 if (b43_current_band(dev->wl) == NL80211_BAND_2GHZ) {
Rafał Miłecki1b0a69c2011-09-16 12:34:02 +0200539 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);
Rafał Miłecki29818082011-09-16 16:36:32 +0200553 b43_phy_lcn_sense_setup(dev, B43_SENSE_TEMP);
Rafał Miłecki1b0a69c2011-09-16 12:34:02 +0200554 } else {
555 b43err(dev->wl, "TX power control not supported for this HW\n");
556 }
557
558 b43_mac_enable(dev);
559}
560
Rafał Miłeckiac78a522011-09-16 12:34:01 +0200561/* 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 }
Rafał Miłeckic2cb2c42014-07-17 19:31:05 +0200579 b43_mac_switch_freq(dev, enable);
Rafał Miłeckiac78a522011-09-16 12:34:01 +0200580}
581
Rafał Miłecki78bc2462011-08-15 18:50:55 +0200582/**************************************************
Rafał Miłecki39f7d332011-08-28 14:59:58 +0200583 * Channel switching ops.
584 **************************************************/
585
Rafał Miłeckib5347062011-09-16 12:33:59 +0200586/* wlc_lcnphy_set_chanspec_tweaks */
587static void b43_phy_lcn_set_channel_tweaks(struct b43_wldev *dev, int channel)
588{
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
Rafał Miłeckiac78a522011-09-16 12:34:01 +0200603 b43_phy_lcn_txrx_spur_avoidance_mode(dev, false);
Rafał Miłeckib5347062011-09-16 12:33:59 +0200604 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
Rafał Miłeckiac78a522011-09-16 12:34:01 +0200615 b43_phy_lcn_txrx_spur_avoidance_mode(dev, true);
Rafał Miłeckib5347062011-09-16 12:33:59 +0200616 b43_phy_maskset(dev, 0x424, (u16) ~0xff00, 0x1f00);
617 b43_phy_write(dev, 0x425, 0x590a);
618 }
619
620 b43_phy_set(dev, 0x44a, 0x44);
621 b43_phy_write(dev, 0x44a, 0x80);
622}
623
624/* wlc_phy_chanspec_set_lcnphy */
Rafał Miłecki39f7d332011-08-28 14:59:58 +0200625static int b43_phy_lcn_set_channel(struct b43_wldev *dev,
626 struct ieee80211_channel *channel,
627 enum nl80211_channel_type channel_type)
628{
Rafał Miłecki0c5644b92011-09-16 12:34:00 +0200629 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
Rafał Miłeckib5347062011-09-16 12:33:59 +0200635 b43_phy_lcn_set_channel_tweaks(dev, channel->hw_value);
Rafał Miłecki39f7d332011-08-28 14:59:58 +0200636
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
Rafał Miłecki0c5644b92011-09-16 12:34:00 +0200645 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);
Rafał Miłecki39f7d332011-08-28 14:59:58 +0200660
661 return 0;
662}
663
664/**************************************************
Rafał Miłeckif9286682011-08-14 23:27:28 +0200665 * 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
Rafał Miłeckibce4dc42011-08-31 23:36:20 +0200697/* wlc_phy_init_lcnphy */
Rafał Miłecki78bc2462011-08-15 18:50:55 +0200698static int b43_phy_lcn_op_init(struct b43_wldev *dev)
699{
Rafał Miłeckib5347062011-09-16 12:33:59 +0200700 struct bcma_drv_cc *cc = &dev->dev->bdev->bus->drv_cc;
701
Rafał Miłecki78bc2462011-08-15 18:50:55 +0200702 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);
Rafał Miłecki78bc2462011-08-15 18:50:55 +0200714
Rafał Miłeckibce4dc42011-08-31 23:36:20 +0200715 b43_phy_lcn_rev0_baseband_init(dev);
716 b43_phy_lcn_bu_tweaks(dev);
Rafał Miłecki78bc2462011-08-15 18:50:55 +0200717
Rafał Miłeckidc713fb2011-08-15 18:50:56 +0200718 if (dev->phy.radio_ver == 0x2064)
719 b43_radio_2064_init(dev);
720 else
721 B43_WARN_ON(1);
722
Johannes Berg57fbcce2016-04-12 15:56:15 +0200723 if (b43_current_band(dev->wl) == NL80211_BAND_2GHZ)
Rafał Miłecki1b0a69c2011-09-16 12:34:02 +0200724 b43_phy_lcn_tx_pwr_ctl_init(dev);
Rafał Miłecki765b07e2011-08-28 19:59:28 +0200725
Rafał Miłeckib5347062011-09-16 12:33:59 +0200726 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
Rafał Miłecki78bc2462011-08-15 18:50:55 +0200739 return 0;
740}
741
Rafał Miłeckiba356b52011-08-14 23:27:29 +0200742static 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 {
Rafał Miłecki78bc2462011-08-15 18:50:55 +0200759 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);
Rafał Miłeckiba356b52011-08-14 23:27:29 +0200762 }
763}
764
Rafał Miłecki7ed88522011-08-14 23:27:30 +0200765static 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
Rafał Miłecki39f7d332011-08-28 14:59:58 +0200775static int b43_phy_lcn_op_switch_channel(struct b43_wldev *dev,
776 unsigned int new_channel)
777{
Karl Beldan675a0b02013-03-25 16:26:57 +0100778 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);
Rafał Miłecki39f7d332011-08-28 14:59:58 +0200781
Johannes Berg57fbcce2016-04-12 15:56:15 +0200782 if (b43_current_band(dev->wl) == NL80211_BAND_2GHZ) {
Rafał Miłecki39f7d332011-08-28 14:59:58 +0200783 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
Rafał Miłeckif9286682011-08-14 23:27:28 +0200792static unsigned int b43_phy_lcn_op_get_default_chan(struct b43_wldev *dev)
793{
Johannes Berg57fbcce2016-04-12 15:56:15 +0200794 if (b43_current_band(dev->wl) == NL80211_BAND_2GHZ)
Rafał Miłeckif9286682011-08-14 23:27:28 +0200795 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
809/**************************************************
Rafał Miłeckif533d0f2011-08-28 14:28:43 +0200810 * R/W ops.
811 **************************************************/
812
Rafał Miłeckif533d0f2011-08-28 14:28:43 +0200813static void b43_phy_lcn_op_maskset(struct b43_wldev *dev, u16 reg, u16 mask,
814 u16 set)
815{
Rafał Miłecki25c15562014-08-07 07:45:37 +0200816 b43_write16f(dev, B43_MMIO_PHY_CONTROL, reg);
Rafał Miłeckif533d0f2011-08-28 14:28:43 +0200817 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
Rafał Miłecki25c15562014-08-07 07:45:37 +0200826 b43_write16f(dev, B43_MMIO_RADIO24_CONTROL, reg);
Rafał Miłeckif533d0f2011-08-28 14:28:43 +0200827 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{
Rafał Miłecki25c15562014-08-07 07:45:37 +0200833 b43_write16f(dev, B43_MMIO_RADIO24_CONTROL, reg);
Rafał Miłeckif533d0f2011-08-28 14:28:43 +0200834 b43_write16(dev, B43_MMIO_RADIO24_DATA, value);
835}
836
837/**************************************************
Rafał Miłecki1d738e62011-07-07 15:25:27 +0200838 * PHY ops struct.
839 **************************************************/
840
841const struct b43_phy_operations b43_phyops_lcn = {
Rafał Miłecki1d738e62011-07-07 15:25:27 +0200842 .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,
Rafał Miłecki1d738e62011-07-07 15:25:27 +0200846 .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,
Rafał Miłecki1d738e62011-07-07 15:25:27 +0200855};