Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/contrib/dev/broadcom/brcm80211/brcmsmac/phy/phy_lcn.c
178703 views
1
// SPDX-License-Identifier: ISC
2
/*
3
* Copyright (c) 2010 Broadcom Corporation
4
*/
5
6
#include <linux/kernel.h>
7
#include <linux/delay.h>
8
#include <linux/cordic.h>
9
10
#include <pmu.h>
11
#include <d11.h>
12
#include <phy_shim.h>
13
#include "phy_qmath.h"
14
#include "phy_hal.h"
15
#include "phy_radio.h"
16
#include "phytbl_lcn.h"
17
#include "phy_lcn.h"
18
19
#define PLL_2064_NDIV 90
20
#define PLL_2064_LOW_END_VCO 3000
21
#define PLL_2064_LOW_END_KVCO 27
22
#define PLL_2064_HIGH_END_VCO 4200
23
#define PLL_2064_HIGH_END_KVCO 68
24
#define PLL_2064_LOOP_BW_DOUBLER 200
25
#define PLL_2064_D30_DOUBLER 10500
26
#define PLL_2064_LOOP_BW 260
27
#define PLL_2064_D30 8000
28
#define PLL_2064_CAL_REF_TO 8
29
#define PLL_2064_MHZ 1000000
30
#define PLL_2064_OPEN_LOOP_DELAY 5
31
32
#define TEMPSENSE 1
33
#define VBATSENSE 2
34
35
#define NOISE_IF_UPD_CHK_INTERVAL 1
36
#define NOISE_IF_UPD_RST_INTERVAL 60
37
#define NOISE_IF_UPD_THRESHOLD_CNT 1
38
#define NOISE_IF_UPD_TRHRESHOLD 50
39
#define NOISE_IF_UPD_TIMEOUT 1000
40
#define NOISE_IF_OFF 0
41
#define NOISE_IF_CHK 1
42
#define NOISE_IF_ON 2
43
44
#define PAPD_BLANKING_PROFILE 3
45
#define PAPD2LUT 0
46
#define PAPD_CORR_NORM 0
47
#define PAPD_BLANKING_THRESHOLD 0
48
#define PAPD_STOP_AFTER_LAST_UPDATE 0
49
50
#define LCN_TARGET_PWR 60
51
52
#define LCN_VBAT_OFFSET_433X 34649679
53
#define LCN_VBAT_SLOPE_433X 8258032
54
55
#define LCN_VBAT_SCALE_NOM 53
56
#define LCN_VBAT_SCALE_DEN 432
57
58
#define LCN_TEMPSENSE_OFFSET 80812
59
#define LCN_TEMPSENSE_DEN 2647
60
61
#define LCN_BW_LMT 200
62
#define LCN_CUR_LMT 1250
63
#define LCN_MULT 1
64
#define LCN_VCO_DIV 30
65
#define LCN_OFFSET 680
66
#define LCN_FACT 490
67
#define LCN_CUR_DIV 2640
68
69
#define LCNPHY_txgainctrlovrval1_pagain_ovr_val1_SHIFT \
70
(0 + 8)
71
#define LCNPHY_txgainctrlovrval1_pagain_ovr_val1_MASK \
72
(0x7f << LCNPHY_txgainctrlovrval1_pagain_ovr_val1_SHIFT)
73
74
#define LCNPHY_stxtxgainctrlovrval1_pagain_ovr_val1_SHIFT \
75
(0 + 8)
76
#define LCNPHY_stxtxgainctrlovrval1_pagain_ovr_val1_MASK \
77
(0x7f << LCNPHY_stxtxgainctrlovrval1_pagain_ovr_val1_SHIFT)
78
79
#define wlc_lcnphy_enable_tx_gain_override(pi) \
80
wlc_lcnphy_set_tx_gain_override(pi, true)
81
#define wlc_lcnphy_disable_tx_gain_override(pi) \
82
wlc_lcnphy_set_tx_gain_override(pi, false)
83
84
#define wlc_lcnphy_iqcal_active(pi) \
85
(read_phy_reg((pi), 0x451) & \
86
((0x1 << 15) | (0x1 << 14)))
87
88
#define txpwrctrl_off(pi) (0x7 != ((read_phy_reg(pi, 0x4a4) & 0xE000) >> 13))
89
#define wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi) \
90
(pi->temppwrctrl_capable)
91
#define wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi) \
92
(pi->hwpwrctrl_capable)
93
94
#define SWCTRL_BT_TX 0x18
95
#define SWCTRL_OVR_DISABLE 0x40
96
97
#define AFE_CLK_INIT_MODE_TXRX2X 1
98
#define AFE_CLK_INIT_MODE_PAPD 0
99
100
#define LCNPHY_TBL_ID_IQLOCAL 0x00
101
102
#define LCNPHY_TBL_ID_RFSEQ 0x08
103
#define LCNPHY_TBL_ID_GAIN_IDX 0x0d
104
#define LCNPHY_TBL_ID_SW_CTRL 0x0f
105
#define LCNPHY_TBL_ID_GAIN_TBL 0x12
106
#define LCNPHY_TBL_ID_SPUR 0x14
107
#define LCNPHY_TBL_ID_SAMPLEPLAY 0x15
108
#define LCNPHY_TBL_ID_SAMPLEPLAY1 0x16
109
110
#define LCNPHY_TX_PWR_CTRL_RATE_OFFSET 832
111
#define LCNPHY_TX_PWR_CTRL_MAC_OFFSET 128
112
#define LCNPHY_TX_PWR_CTRL_GAIN_OFFSET 192
113
#define LCNPHY_TX_PWR_CTRL_IQ_OFFSET 320
114
#define LCNPHY_TX_PWR_CTRL_LO_OFFSET 448
115
#define LCNPHY_TX_PWR_CTRL_PWR_OFFSET 576
116
117
#define LCNPHY_TX_PWR_CTRL_START_INDEX_2G_4313 140
118
119
#define LCNPHY_TX_PWR_CTRL_START_NPT 1
120
#define LCNPHY_TX_PWR_CTRL_MAX_NPT 7
121
122
#define LCNPHY_NOISE_SAMPLES_DEFAULT 5000
123
124
#define LCNPHY_ACI_DETECT_START 1
125
#define LCNPHY_ACI_DETECT_PROGRESS 2
126
#define LCNPHY_ACI_DETECT_STOP 3
127
128
#define LCNPHY_ACI_CRSHIFRMLO_TRSH 100
129
#define LCNPHY_ACI_GLITCH_TRSH 2000
130
#define LCNPHY_ACI_TMOUT 250
131
#define LCNPHY_ACI_DETECT_TIMEOUT 2
132
#define LCNPHY_ACI_START_DELAY 0
133
134
#define wlc_lcnphy_tx_gain_override_enabled(pi) \
135
(0 != (read_phy_reg((pi), 0x43b) & (0x1 << 6)))
136
137
#define wlc_lcnphy_total_tx_frames(pi) \
138
wlapi_bmac_read_shm((pi)->sh->physhim, M_UCODE_MACSTAT + \
139
offsetof(struct macstat, txallfrm))
140
141
struct lcnphy_txgains {
142
u16 gm_gain;
143
u16 pga_gain;
144
u16 pad_gain;
145
u16 dac_gain;
146
};
147
148
enum lcnphy_cal_mode {
149
LCNPHY_CAL_FULL,
150
LCNPHY_CAL_RECAL,
151
LCNPHY_CAL_CURRECAL,
152
LCNPHY_CAL_DIGCAL,
153
LCNPHY_CAL_GCTRL
154
};
155
156
struct lcnphy_rx_iqcomp {
157
u8 chan;
158
s16 a;
159
s16 b;
160
};
161
162
struct lcnphy_spb_tone {
163
s16 re;
164
s16 im;
165
};
166
167
struct lcnphy_unsign16_struct {
168
u16 re;
169
u16 im;
170
};
171
172
struct lcnphy_iq_est {
173
u32 iq_prod;
174
u32 i_pwr;
175
u32 q_pwr;
176
};
177
178
struct lcnphy_sfo_cfg {
179
u16 ptcentreTs20;
180
u16 ptcentreFactor;
181
};
182
183
enum lcnphy_papd_cal_type {
184
LCNPHY_PAPD_CAL_CW,
185
LCNPHY_PAPD_CAL_OFDM
186
};
187
188
typedef u16 iqcal_gain_params_lcnphy[9];
189
190
static const iqcal_gain_params_lcnphy tbl_iqcal_gainparams_lcnphy_2G[] = {
191
{0, 0, 0, 0, 0, 0, 0, 0, 0},
192
};
193
194
static const iqcal_gain_params_lcnphy *tbl_iqcal_gainparams_lcnphy[1] = {
195
tbl_iqcal_gainparams_lcnphy_2G,
196
};
197
198
static const u16 iqcal_gainparams_numgains_lcnphy[1] = {
199
ARRAY_SIZE(tbl_iqcal_gainparams_lcnphy_2G),
200
};
201
202
static const struct lcnphy_sfo_cfg lcnphy_sfo_cfg[] = {
203
{965, 1087},
204
{967, 1085},
205
{969, 1082},
206
{971, 1080},
207
{973, 1078},
208
{975, 1076},
209
{977, 1073},
210
{979, 1071},
211
{981, 1069},
212
{983, 1067},
213
{985, 1065},
214
{987, 1063},
215
{989, 1060},
216
{994, 1055}
217
};
218
219
static const
220
u16 lcnphy_iqcal_loft_gainladder[] = {
221
((2 << 8) | 0),
222
((3 << 8) | 0),
223
((4 << 8) | 0),
224
((6 << 8) | 0),
225
((8 << 8) | 0),
226
((11 << 8) | 0),
227
((16 << 8) | 0),
228
((16 << 8) | 1),
229
((16 << 8) | 2),
230
((16 << 8) | 3),
231
((16 << 8) | 4),
232
((16 << 8) | 5),
233
((16 << 8) | 6),
234
((16 << 8) | 7),
235
((23 << 8) | 7),
236
((32 << 8) | 7),
237
((45 << 8) | 7),
238
((64 << 8) | 7),
239
((91 << 8) | 7),
240
((128 << 8) | 7)
241
};
242
243
static const
244
u16 lcnphy_iqcal_ir_gainladder[] = {
245
((1 << 8) | 0),
246
((2 << 8) | 0),
247
((4 << 8) | 0),
248
((6 << 8) | 0),
249
((8 << 8) | 0),
250
((11 << 8) | 0),
251
((16 << 8) | 0),
252
((23 << 8) | 0),
253
((32 << 8) | 0),
254
((45 << 8) | 0),
255
((64 << 8) | 0),
256
((64 << 8) | 1),
257
((64 << 8) | 2),
258
((64 << 8) | 3),
259
((64 << 8) | 4),
260
((64 << 8) | 5),
261
((64 << 8) | 6),
262
((64 << 8) | 7),
263
((91 << 8) | 7),
264
((128 << 8) | 7)
265
};
266
267
static const
268
struct lcnphy_spb_tone lcnphy_spb_tone_3750[] = {
269
{88, 0},
270
{73, 49},
271
{34, 81},
272
{-17, 86},
273
{-62, 62},
274
{-86, 17},
275
{-81, -34},
276
{-49, -73},
277
{0, -88},
278
{49, -73},
279
{81, -34},
280
{86, 17},
281
{62, 62},
282
{17, 86},
283
{-34, 81},
284
{-73, 49},
285
{-88, 0},
286
{-73, -49},
287
{-34, -81},
288
{17, -86},
289
{62, -62},
290
{86, -17},
291
{81, 34},
292
{49, 73},
293
{0, 88},
294
{-49, 73},
295
{-81, 34},
296
{-86, -17},
297
{-62, -62},
298
{-17, -86},
299
{34, -81},
300
{73, -49},
301
};
302
303
static const
304
u16 iqlo_loopback_rf_regs[20] = {
305
RADIO_2064_REG036,
306
RADIO_2064_REG11A,
307
RADIO_2064_REG03A,
308
RADIO_2064_REG025,
309
RADIO_2064_REG028,
310
RADIO_2064_REG005,
311
RADIO_2064_REG112,
312
RADIO_2064_REG0FF,
313
RADIO_2064_REG11F,
314
RADIO_2064_REG00B,
315
RADIO_2064_REG113,
316
RADIO_2064_REG007,
317
RADIO_2064_REG0FC,
318
RADIO_2064_REG0FD,
319
RADIO_2064_REG012,
320
RADIO_2064_REG057,
321
RADIO_2064_REG059,
322
RADIO_2064_REG05C,
323
RADIO_2064_REG078,
324
RADIO_2064_REG092,
325
};
326
327
static const
328
u16 tempsense_phy_regs[14] = {
329
0x503,
330
0x4a4,
331
0x4d0,
332
0x4d9,
333
0x4da,
334
0x4a6,
335
0x938,
336
0x939,
337
0x4d8,
338
0x4d0,
339
0x4d7,
340
0x4a5,
341
0x40d,
342
0x4a2,
343
};
344
345
static const
346
u16 rxiq_cal_rf_reg[11] = {
347
RADIO_2064_REG098,
348
RADIO_2064_REG116,
349
RADIO_2064_REG12C,
350
RADIO_2064_REG06A,
351
RADIO_2064_REG00B,
352
RADIO_2064_REG01B,
353
RADIO_2064_REG113,
354
RADIO_2064_REG01D,
355
RADIO_2064_REG114,
356
RADIO_2064_REG02E,
357
RADIO_2064_REG12A,
358
};
359
360
static const u32 lcnphy_23bitgaincode_table[] = {
361
0x200100,
362
0x200200,
363
0x200004,
364
0x200014,
365
0x200024,
366
0x200034,
367
0x200134,
368
0x200234,
369
0x200334,
370
0x200434,
371
0x200037,
372
0x200137,
373
0x200237,
374
0x200337,
375
0x200437,
376
0x000035,
377
0x000135,
378
0x000235,
379
0x000037,
380
0x000137,
381
0x000237,
382
0x000337,
383
0x00013f,
384
0x00023f,
385
0x00033f,
386
0x00034f,
387
0x00044f,
388
0x00144f,
389
0x00244f,
390
0x00254f,
391
0x00354f,
392
0x00454f,
393
0x00464f,
394
0x01464f,
395
0x02464f,
396
0x03464f,
397
0x04464f,
398
};
399
400
static const s8 lcnphy_gain_table[] = {
401
-16,
402
-13,
403
10,
404
7,
405
4,
406
0,
407
3,
408
6,
409
9,
410
12,
411
15,
412
18,
413
21,
414
24,
415
27,
416
30,
417
33,
418
36,
419
39,
420
42,
421
45,
422
48,
423
50,
424
53,
425
56,
426
59,
427
62,
428
65,
429
68,
430
71,
431
74,
432
77,
433
80,
434
83,
435
86,
436
89,
437
92,
438
};
439
440
static const s8 lcnphy_gain_index_offset_for_rssi[] = {
441
7,
442
7,
443
7,
444
7,
445
7,
446
7,
447
7,
448
8,
449
7,
450
7,
451
6,
452
7,
453
7,
454
4,
455
4,
456
4,
457
4,
458
4,
459
4,
460
4,
461
4,
462
3,
463
3,
464
3,
465
3,
466
3,
467
3,
468
4,
469
2,
470
2,
471
2,
472
2,
473
2,
474
2,
475
-1,
476
-2,
477
-2,
478
-2
479
};
480
481
struct chan_info_2064_lcnphy {
482
uint chan;
483
uint freq;
484
u8 logen_buftune;
485
u8 logen_rccr_tx;
486
u8 txrf_mix_tune_ctrl;
487
u8 pa_input_tune_g;
488
u8 logen_rccr_rx;
489
u8 pa_rxrf_lna1_freq_tune;
490
u8 pa_rxrf_lna2_freq_tune;
491
u8 rxrf_rxrf_spare1;
492
};
493
494
static const struct chan_info_2064_lcnphy chan_info_2064_lcnphy[] = {
495
{1, 2412, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
496
{2, 2417, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
497
{3, 2422, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
498
{4, 2427, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
499
{5, 2432, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
500
{6, 2437, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
501
{7, 2442, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
502
{8, 2447, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
503
{9, 2452, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
504
{10, 2457, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
505
{11, 2462, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
506
{12, 2467, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
507
{13, 2472, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
508
{14, 2484, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
509
};
510
511
static const struct lcnphy_radio_regs lcnphy_radio_regs_2064[] = {
512
{0x00, 0, 0, 0, 0},
513
{0x01, 0x64, 0x64, 0, 0},
514
{0x02, 0x20, 0x20, 0, 0},
515
{0x03, 0x66, 0x66, 0, 0},
516
{0x04, 0xf8, 0xf8, 0, 0},
517
{0x05, 0, 0, 0, 0},
518
{0x06, 0x10, 0x10, 0, 0},
519
{0x07, 0, 0, 0, 0},
520
{0x08, 0, 0, 0, 0},
521
{0x09, 0, 0, 0, 0},
522
{0x0A, 0x37, 0x37, 0, 0},
523
{0x0B, 0x6, 0x6, 0, 0},
524
{0x0C, 0x55, 0x55, 0, 0},
525
{0x0D, 0x8b, 0x8b, 0, 0},
526
{0x0E, 0, 0, 0, 0},
527
{0x0F, 0x5, 0x5, 0, 0},
528
{0x10, 0, 0, 0, 0},
529
{0x11, 0xe, 0xe, 0, 0},
530
{0x12, 0, 0, 0, 0},
531
{0x13, 0xb, 0xb, 0, 0},
532
{0x14, 0x2, 0x2, 0, 0},
533
{0x15, 0x12, 0x12, 0, 0},
534
{0x16, 0x12, 0x12, 0, 0},
535
{0x17, 0xc, 0xc, 0, 0},
536
{0x18, 0xc, 0xc, 0, 0},
537
{0x19, 0xc, 0xc, 0, 0},
538
{0x1A, 0x8, 0x8, 0, 0},
539
{0x1B, 0x2, 0x2, 0, 0},
540
{0x1C, 0, 0, 0, 0},
541
{0x1D, 0x1, 0x1, 0, 0},
542
{0x1E, 0x12, 0x12, 0, 0},
543
{0x1F, 0x6e, 0x6e, 0, 0},
544
{0x20, 0x2, 0x2, 0, 0},
545
{0x21, 0x23, 0x23, 0, 0},
546
{0x22, 0x8, 0x8, 0, 0},
547
{0x23, 0, 0, 0, 0},
548
{0x24, 0, 0, 0, 0},
549
{0x25, 0xc, 0xc, 0, 0},
550
{0x26, 0x33, 0x33, 0, 0},
551
{0x27, 0x55, 0x55, 0, 0},
552
{0x28, 0, 0, 0, 0},
553
{0x29, 0x30, 0x30, 0, 0},
554
{0x2A, 0xb, 0xb, 0, 0},
555
{0x2B, 0x1b, 0x1b, 0, 0},
556
{0x2C, 0x3, 0x3, 0, 0},
557
{0x2D, 0x1b, 0x1b, 0, 0},
558
{0x2E, 0, 0, 0, 0},
559
{0x2F, 0x20, 0x20, 0, 0},
560
{0x30, 0xa, 0xa, 0, 0},
561
{0x31, 0, 0, 0, 0},
562
{0x32, 0x62, 0x62, 0, 0},
563
{0x33, 0x19, 0x19, 0, 0},
564
{0x34, 0x33, 0x33, 0, 0},
565
{0x35, 0x77, 0x77, 0, 0},
566
{0x36, 0, 0, 0, 0},
567
{0x37, 0x70, 0x70, 0, 0},
568
{0x38, 0x3, 0x3, 0, 0},
569
{0x39, 0xf, 0xf, 0, 0},
570
{0x3A, 0x6, 0x6, 0, 0},
571
{0x3B, 0xcf, 0xcf, 0, 0},
572
{0x3C, 0x1a, 0x1a, 0, 0},
573
{0x3D, 0x6, 0x6, 0, 0},
574
{0x3E, 0x42, 0x42, 0, 0},
575
{0x3F, 0, 0, 0, 0},
576
{0x40, 0xfb, 0xfb, 0, 0},
577
{0x41, 0x9a, 0x9a, 0, 0},
578
{0x42, 0x7a, 0x7a, 0, 0},
579
{0x43, 0x29, 0x29, 0, 0},
580
{0x44, 0, 0, 0, 0},
581
{0x45, 0x8, 0x8, 0, 0},
582
{0x46, 0xce, 0xce, 0, 0},
583
{0x47, 0x27, 0x27, 0, 0},
584
{0x48, 0x62, 0x62, 0, 0},
585
{0x49, 0x6, 0x6, 0, 0},
586
{0x4A, 0x58, 0x58, 0, 0},
587
{0x4B, 0xf7, 0xf7, 0, 0},
588
{0x4C, 0, 0, 0, 0},
589
{0x4D, 0xb3, 0xb3, 0, 0},
590
{0x4E, 0, 0, 0, 0},
591
{0x4F, 0x2, 0x2, 0, 0},
592
{0x50, 0, 0, 0, 0},
593
{0x51, 0x9, 0x9, 0, 0},
594
{0x52, 0x5, 0x5, 0, 0},
595
{0x53, 0x17, 0x17, 0, 0},
596
{0x54, 0x38, 0x38, 0, 0},
597
{0x55, 0, 0, 0, 0},
598
{0x56, 0, 0, 0, 0},
599
{0x57, 0xb, 0xb, 0, 0},
600
{0x58, 0, 0, 0, 0},
601
{0x59, 0, 0, 0, 0},
602
{0x5A, 0, 0, 0, 0},
603
{0x5B, 0, 0, 0, 0},
604
{0x5C, 0, 0, 0, 0},
605
{0x5D, 0, 0, 0, 0},
606
{0x5E, 0x88, 0x88, 0, 0},
607
{0x5F, 0xcc, 0xcc, 0, 0},
608
{0x60, 0x74, 0x74, 0, 0},
609
{0x61, 0x74, 0x74, 0, 0},
610
{0x62, 0x74, 0x74, 0, 0},
611
{0x63, 0x44, 0x44, 0, 0},
612
{0x64, 0x77, 0x77, 0, 0},
613
{0x65, 0x44, 0x44, 0, 0},
614
{0x66, 0x77, 0x77, 0, 0},
615
{0x67, 0x55, 0x55, 0, 0},
616
{0x68, 0x77, 0x77, 0, 0},
617
{0x69, 0x77, 0x77, 0, 0},
618
{0x6A, 0, 0, 0, 0},
619
{0x6B, 0x7f, 0x7f, 0, 0},
620
{0x6C, 0x8, 0x8, 0, 0},
621
{0x6D, 0, 0, 0, 0},
622
{0x6E, 0x88, 0x88, 0, 0},
623
{0x6F, 0x66, 0x66, 0, 0},
624
{0x70, 0x66, 0x66, 0, 0},
625
{0x71, 0x28, 0x28, 0, 0},
626
{0x72, 0x55, 0x55, 0, 0},
627
{0x73, 0x4, 0x4, 0, 0},
628
{0x74, 0, 0, 0, 0},
629
{0x75, 0, 0, 0, 0},
630
{0x76, 0, 0, 0, 0},
631
{0x77, 0x1, 0x1, 0, 0},
632
{0x78, 0xd6, 0xd6, 0, 0},
633
{0x79, 0, 0, 0, 0},
634
{0x7A, 0, 0, 0, 0},
635
{0x7B, 0, 0, 0, 0},
636
{0x7C, 0, 0, 0, 0},
637
{0x7D, 0, 0, 0, 0},
638
{0x7E, 0, 0, 0, 0},
639
{0x7F, 0, 0, 0, 0},
640
{0x80, 0, 0, 0, 0},
641
{0x81, 0, 0, 0, 0},
642
{0x82, 0, 0, 0, 0},
643
{0x83, 0xb4, 0xb4, 0, 0},
644
{0x84, 0x1, 0x1, 0, 0},
645
{0x85, 0x20, 0x20, 0, 0},
646
{0x86, 0x5, 0x5, 0, 0},
647
{0x87, 0xff, 0xff, 0, 0},
648
{0x88, 0x7, 0x7, 0, 0},
649
{0x89, 0x77, 0x77, 0, 0},
650
{0x8A, 0x77, 0x77, 0, 0},
651
{0x8B, 0x77, 0x77, 0, 0},
652
{0x8C, 0x77, 0x77, 0, 0},
653
{0x8D, 0x8, 0x8, 0, 0},
654
{0x8E, 0xa, 0xa, 0, 0},
655
{0x8F, 0x8, 0x8, 0, 0},
656
{0x90, 0x18, 0x18, 0, 0},
657
{0x91, 0x5, 0x5, 0, 0},
658
{0x92, 0x1f, 0x1f, 0, 0},
659
{0x93, 0x10, 0x10, 0, 0},
660
{0x94, 0x3, 0x3, 0, 0},
661
{0x95, 0, 0, 0, 0},
662
{0x96, 0, 0, 0, 0},
663
{0x97, 0xaa, 0xaa, 0, 0},
664
{0x98, 0, 0, 0, 0},
665
{0x99, 0x23, 0x23, 0, 0},
666
{0x9A, 0x7, 0x7, 0, 0},
667
{0x9B, 0xf, 0xf, 0, 0},
668
{0x9C, 0x10, 0x10, 0, 0},
669
{0x9D, 0x3, 0x3, 0, 0},
670
{0x9E, 0x4, 0x4, 0, 0},
671
{0x9F, 0x20, 0x20, 0, 0},
672
{0xA0, 0, 0, 0, 0},
673
{0xA1, 0, 0, 0, 0},
674
{0xA2, 0, 0, 0, 0},
675
{0xA3, 0, 0, 0, 0},
676
{0xA4, 0x1, 0x1, 0, 0},
677
{0xA5, 0x77, 0x77, 0, 0},
678
{0xA6, 0x77, 0x77, 0, 0},
679
{0xA7, 0x77, 0x77, 0, 0},
680
{0xA8, 0x77, 0x77, 0, 0},
681
{0xA9, 0x8c, 0x8c, 0, 0},
682
{0xAA, 0x88, 0x88, 0, 0},
683
{0xAB, 0x78, 0x78, 0, 0},
684
{0xAC, 0x57, 0x57, 0, 0},
685
{0xAD, 0x88, 0x88, 0, 0},
686
{0xAE, 0, 0, 0, 0},
687
{0xAF, 0x8, 0x8, 0, 0},
688
{0xB0, 0x88, 0x88, 0, 0},
689
{0xB1, 0, 0, 0, 0},
690
{0xB2, 0x1b, 0x1b, 0, 0},
691
{0xB3, 0x3, 0x3, 0, 0},
692
{0xB4, 0x24, 0x24, 0, 0},
693
{0xB5, 0x3, 0x3, 0, 0},
694
{0xB6, 0x1b, 0x1b, 0, 0},
695
{0xB7, 0x24, 0x24, 0, 0},
696
{0xB8, 0x3, 0x3, 0, 0},
697
{0xB9, 0, 0, 0, 0},
698
{0xBA, 0xaa, 0xaa, 0, 0},
699
{0xBB, 0, 0, 0, 0},
700
{0xBC, 0x4, 0x4, 0, 0},
701
{0xBD, 0, 0, 0, 0},
702
{0xBE, 0x8, 0x8, 0, 0},
703
{0xBF, 0x11, 0x11, 0, 0},
704
{0xC0, 0, 0, 0, 0},
705
{0xC1, 0, 0, 0, 0},
706
{0xC2, 0x62, 0x62, 0, 0},
707
{0xC3, 0x1e, 0x1e, 0, 0},
708
{0xC4, 0x33, 0x33, 0, 0},
709
{0xC5, 0x37, 0x37, 0, 0},
710
{0xC6, 0, 0, 0, 0},
711
{0xC7, 0x70, 0x70, 0, 0},
712
{0xC8, 0x1e, 0x1e, 0, 0},
713
{0xC9, 0x6, 0x6, 0, 0},
714
{0xCA, 0x4, 0x4, 0, 0},
715
{0xCB, 0x2f, 0x2f, 0, 0},
716
{0xCC, 0xf, 0xf, 0, 0},
717
{0xCD, 0, 0, 0, 0},
718
{0xCE, 0xff, 0xff, 0, 0},
719
{0xCF, 0x8, 0x8, 0, 0},
720
{0xD0, 0x3f, 0x3f, 0, 0},
721
{0xD1, 0x3f, 0x3f, 0, 0},
722
{0xD2, 0x3f, 0x3f, 0, 0},
723
{0xD3, 0, 0, 0, 0},
724
{0xD4, 0, 0, 0, 0},
725
{0xD5, 0, 0, 0, 0},
726
{0xD6, 0xcc, 0xcc, 0, 0},
727
{0xD7, 0, 0, 0, 0},
728
{0xD8, 0x8, 0x8, 0, 0},
729
{0xD9, 0x8, 0x8, 0, 0},
730
{0xDA, 0x8, 0x8, 0, 0},
731
{0xDB, 0x11, 0x11, 0, 0},
732
{0xDC, 0, 0, 0, 0},
733
{0xDD, 0x87, 0x87, 0, 0},
734
{0xDE, 0x88, 0x88, 0, 0},
735
{0xDF, 0x8, 0x8, 0, 0},
736
{0xE0, 0x8, 0x8, 0, 0},
737
{0xE1, 0x8, 0x8, 0, 0},
738
{0xE2, 0, 0, 0, 0},
739
{0xE3, 0, 0, 0, 0},
740
{0xE4, 0, 0, 0, 0},
741
{0xE5, 0xf5, 0xf5, 0, 0},
742
{0xE6, 0x30, 0x30, 0, 0},
743
{0xE7, 0x1, 0x1, 0, 0},
744
{0xE8, 0, 0, 0, 0},
745
{0xE9, 0xff, 0xff, 0, 0},
746
{0xEA, 0, 0, 0, 0},
747
{0xEB, 0, 0, 0, 0},
748
{0xEC, 0x22, 0x22, 0, 0},
749
{0xED, 0, 0, 0, 0},
750
{0xEE, 0, 0, 0, 0},
751
{0xEF, 0, 0, 0, 0},
752
{0xF0, 0x3, 0x3, 0, 0},
753
{0xF1, 0x1, 0x1, 0, 0},
754
{0xF2, 0, 0, 0, 0},
755
{0xF3, 0, 0, 0, 0},
756
{0xF4, 0, 0, 0, 0},
757
{0xF5, 0, 0, 0, 0},
758
{0xF6, 0, 0, 0, 0},
759
{0xF7, 0x6, 0x6, 0, 0},
760
{0xF8, 0, 0, 0, 0},
761
{0xF9, 0, 0, 0, 0},
762
{0xFA, 0x40, 0x40, 0, 0},
763
{0xFB, 0, 0, 0, 0},
764
{0xFC, 0x1, 0x1, 0, 0},
765
{0xFD, 0x80, 0x80, 0, 0},
766
{0xFE, 0x2, 0x2, 0, 0},
767
{0xFF, 0x10, 0x10, 0, 0},
768
{0x100, 0x2, 0x2, 0, 0},
769
{0x101, 0x1e, 0x1e, 0, 0},
770
{0x102, 0x1e, 0x1e, 0, 0},
771
{0x103, 0, 0, 0, 0},
772
{0x104, 0x1f, 0x1f, 0, 0},
773
{0x105, 0, 0x8, 0, 1},
774
{0x106, 0x2a, 0x2a, 0, 0},
775
{0x107, 0xf, 0xf, 0, 0},
776
{0x108, 0, 0, 0, 0},
777
{0x109, 0, 0, 0, 0},
778
{0x10A, 0, 0, 0, 0},
779
{0x10B, 0, 0, 0, 0},
780
{0x10C, 0, 0, 0, 0},
781
{0x10D, 0, 0, 0, 0},
782
{0x10E, 0, 0, 0, 0},
783
{0x10F, 0, 0, 0, 0},
784
{0x110, 0, 0, 0, 0},
785
{0x111, 0, 0, 0, 0},
786
{0x112, 0, 0, 0, 0},
787
{0x113, 0, 0, 0, 0},
788
{0x114, 0, 0, 0, 0},
789
{0x115, 0, 0, 0, 0},
790
{0x116, 0, 0, 0, 0},
791
{0x117, 0, 0, 0, 0},
792
{0x118, 0, 0, 0, 0},
793
{0x119, 0, 0, 0, 0},
794
{0x11A, 0, 0, 0, 0},
795
{0x11B, 0, 0, 0, 0},
796
{0x11C, 0x1, 0x1, 0, 0},
797
{0x11D, 0, 0, 0, 0},
798
{0x11E, 0, 0, 0, 0},
799
{0x11F, 0, 0, 0, 0},
800
{0x120, 0, 0, 0, 0},
801
{0x121, 0, 0, 0, 0},
802
{0x122, 0x80, 0x80, 0, 0},
803
{0x123, 0, 0, 0, 0},
804
{0x124, 0xf8, 0xf8, 0, 0},
805
{0x125, 0, 0, 0, 0},
806
{0x126, 0, 0, 0, 0},
807
{0x127, 0, 0, 0, 0},
808
{0x128, 0, 0, 0, 0},
809
{0x129, 0, 0, 0, 0},
810
{0x12A, 0, 0, 0, 0},
811
{0x12B, 0, 0, 0, 0},
812
{0x12C, 0, 0, 0, 0},
813
{0x12D, 0, 0, 0, 0},
814
{0x12E, 0, 0, 0, 0},
815
{0x12F, 0, 0, 0, 0},
816
{0x130, 0, 0, 0, 0},
817
{0xFFFF, 0, 0, 0, 0}
818
};
819
820
#define LCNPHY_NUM_DIG_FILT_COEFFS 16
821
#define LCNPHY_NUM_TX_DIG_FILTERS_CCK 13
822
823
static const u16 LCNPHY_txdigfiltcoeffs_cck[LCNPHY_NUM_TX_DIG_FILTERS_CCK]
824
[LCNPHY_NUM_DIG_FILT_COEFFS + 1] = {
825
{0, 1, 415, 1874, 64, 128, 64, 792, 1656, 64, 128, 64, 778, 1582, 64,
826
128, 64,},
827
{1, 1, 402, 1847, 259, 59, 259, 671, 1794, 68, 54, 68, 608, 1863, 93,
828
167, 93,},
829
{2, 1, 415, 1874, 64, 128, 64, 792, 1656, 192, 384, 192, 778, 1582, 64,
830
128, 64,},
831
{3, 1, 302, 1841, 129, 258, 129, 658, 1720, 205, 410, 205, 754, 1760,
832
170, 340, 170,},
833
{20, 1, 360, 1884, 242, 1734, 242, 752, 1720, 205, 1845, 205, 767, 1760,
834
256, 185, 256,},
835
{21, 1, 360, 1884, 149, 1874, 149, 752, 1720, 205, 1883, 205, 767, 1760,
836
256, 273, 256,},
837
{22, 1, 360, 1884, 98, 1948, 98, 752, 1720, 205, 1924, 205, 767, 1760,
838
256, 352, 256,},
839
{23, 1, 350, 1884, 116, 1966, 116, 752, 1720, 205, 2008, 205, 767, 1760,
840
128, 233, 128,},
841
{24, 1, 325, 1884, 32, 40, 32, 756, 1720, 256, 471, 256, 766, 1760, 256,
842
1881, 256,},
843
{25, 1, 299, 1884, 51, 64, 51, 736, 1720, 256, 471, 256, 765, 1760, 256,
844
1881, 256,},
845
{26, 1, 277, 1943, 39, 117, 88, 637, 1838, 64, 192, 144, 614, 1864, 128,
846
384, 288,},
847
{27, 1, 245, 1943, 49, 147, 110, 626, 1838, 256, 768, 576, 613, 1864,
848
128, 384, 288,},
849
{30, 1, 302, 1841, 61, 122, 61, 658, 1720, 205, 410, 205, 754, 1760,
850
170, 340, 170,},
851
};
852
853
#define LCNPHY_NUM_TX_DIG_FILTERS_OFDM 3
854
static const u16 LCNPHY_txdigfiltcoeffs_ofdm[LCNPHY_NUM_TX_DIG_FILTERS_OFDM]
855
[LCNPHY_NUM_DIG_FILT_COEFFS + 1] = {
856
{0, 0, 0xa2, 0x0, 0x100, 0x100, 0x0, 0x0, 0x0, 0x100, 0x0, 0x0,
857
0x278, 0xfea0, 0x80, 0x100, 0x80,},
858
{1, 0, 374, 0xFF79, 16, 32, 16, 799, 0xFE74, 50, 32, 50,
859
750, 0xFE2B, 212, 0xFFCE, 212,},
860
{2, 0, 375, 0xFF16, 37, 76, 37, 799, 0xFE74, 32, 20, 32, 748,
861
0xFEF2, 128, 0xFFE2, 128}
862
};
863
864
#define wlc_lcnphy_set_start_tx_pwr_idx(pi, idx) \
865
mod_phy_reg(pi, 0x4a4, \
866
(0x1ff << 0), \
867
(u16)(idx) << 0)
868
869
#define wlc_lcnphy_set_tx_pwr_npt(pi, npt) \
870
mod_phy_reg(pi, 0x4a5, \
871
(0x7 << 8), \
872
(u16)(npt) << 8)
873
874
#define wlc_lcnphy_get_tx_pwr_ctrl(pi) \
875
(read_phy_reg((pi), 0x4a4) & \
876
((0x1 << 15) | \
877
(0x1 << 14) | \
878
(0x1 << 13)))
879
880
#define wlc_lcnphy_get_tx_pwr_npt(pi) \
881
((read_phy_reg(pi, 0x4a5) & \
882
(0x7 << 8)) >> \
883
8)
884
885
#define wlc_lcnphy_get_current_tx_pwr_idx_if_pwrctrl_on(pi) \
886
(read_phy_reg(pi, 0x473) & 0x1ff)
887
888
#define wlc_lcnphy_get_target_tx_pwr(pi) \
889
((read_phy_reg(pi, 0x4a7) & \
890
(0xff << 0)) >> \
891
0)
892
893
#define wlc_lcnphy_set_target_tx_pwr(pi, target) \
894
mod_phy_reg(pi, 0x4a7, \
895
(0xff << 0), \
896
(u16)(target) << 0)
897
898
#define wlc_radio_2064_rcal_done(pi) \
899
(0 != (read_radio_reg(pi, RADIO_2064_REG05C) & 0x20))
900
901
#define tempsense_done(pi) \
902
(0x8000 == (read_phy_reg(pi, 0x476) & 0x8000))
903
904
#define LCNPHY_IQLOCC_READ(val) \
905
((u8)(-(s8)(((val) & 0xf0) >> 4) + (s8)((val) & 0x0f)))
906
907
#define FIXED_TXPWR 78
908
#define LCNPHY_TEMPSENSE(val) ((s16)((val > 255) ? (val - 512) : val))
909
910
void wlc_lcnphy_write_table(struct brcms_phy *pi, const struct phytbl_info *pti)
911
{
912
wlc_phy_write_table(pi, pti, 0x455, 0x457, 0x456);
913
}
914
915
void wlc_lcnphy_read_table(struct brcms_phy *pi, struct phytbl_info *pti)
916
{
917
wlc_phy_read_table(pi, pti, 0x455, 0x457, 0x456);
918
}
919
920
static void
921
wlc_lcnphy_common_read_table(struct brcms_phy *pi, u32 tbl_id,
922
u16 *tbl_ptr, u32 tbl_len,
923
u32 tbl_width, u32 tbl_offset)
924
{
925
struct phytbl_info tab;
926
tab.tbl_id = tbl_id;
927
tab.tbl_ptr = tbl_ptr;
928
tab.tbl_len = tbl_len;
929
tab.tbl_width = tbl_width;
930
tab.tbl_offset = tbl_offset;
931
wlc_lcnphy_read_table(pi, &tab);
932
}
933
934
static void
935
wlc_lcnphy_common_write_table(struct brcms_phy *pi, u32 tbl_id,
936
const u16 *tbl_ptr, u32 tbl_len,
937
u32 tbl_width, u32 tbl_offset)
938
{
939
940
struct phytbl_info tab;
941
tab.tbl_id = tbl_id;
942
tab.tbl_ptr = tbl_ptr;
943
tab.tbl_len = tbl_len;
944
tab.tbl_width = tbl_width;
945
tab.tbl_offset = tbl_offset;
946
wlc_lcnphy_write_table(pi, &tab);
947
}
948
949
static u32
950
wlc_lcnphy_qdiv_roundup(u32 dividend, u32 divisor, u8 precision)
951
{
952
u32 quotient, remainder, roundup, rbit;
953
954
quotient = dividend / divisor;
955
remainder = dividend % divisor;
956
rbit = divisor & 1;
957
roundup = (divisor >> 1) + rbit;
958
959
while (precision--) {
960
quotient <<= 1;
961
if (remainder >= roundup) {
962
quotient++;
963
remainder = ((remainder - roundup) << 1) + rbit;
964
} else {
965
remainder <<= 1;
966
}
967
}
968
969
if (remainder >= roundup)
970
quotient++;
971
972
return quotient;
973
}
974
975
static int wlc_lcnphy_calc_floor(s16 coeff_x, int type)
976
{
977
int k;
978
k = 0;
979
if (type == 0) {
980
if (coeff_x < 0)
981
k = (coeff_x - 1) / 2;
982
else
983
k = coeff_x / 2;
984
}
985
986
if (type == 1) {
987
if ((coeff_x + 1) < 0)
988
k = (coeff_x) / 2;
989
else
990
k = (coeff_x + 1) / 2;
991
}
992
return k;
993
}
994
995
static void
996
wlc_lcnphy_get_tx_gain(struct brcms_phy *pi, struct lcnphy_txgains *gains)
997
{
998
u16 dac_gain, rfgain0, rfgain1;
999
1000
dac_gain = read_phy_reg(pi, 0x439) >> 0;
1001
gains->dac_gain = (dac_gain & 0x380) >> 7;
1002
1003
rfgain0 = (read_phy_reg(pi, 0x4b5) & (0xffff << 0)) >> 0;
1004
rfgain1 = (read_phy_reg(pi, 0x4fb) & (0x7fff << 0)) >> 0;
1005
1006
gains->gm_gain = rfgain0 & 0xff;
1007
gains->pga_gain = (rfgain0 >> 8) & 0xff;
1008
gains->pad_gain = rfgain1 & 0xff;
1009
}
1010
1011
1012
static void wlc_lcnphy_set_dac_gain(struct brcms_phy *pi, u16 dac_gain)
1013
{
1014
u16 dac_ctrl;
1015
1016
dac_ctrl = (read_phy_reg(pi, 0x439) >> 0);
1017
dac_ctrl = dac_ctrl & 0xc7f;
1018
dac_ctrl = dac_ctrl | (dac_gain << 7);
1019
mod_phy_reg(pi, 0x439, (0xfff << 0), (dac_ctrl) << 0);
1020
1021
}
1022
1023
static void wlc_lcnphy_set_tx_gain_override(struct brcms_phy *pi, bool bEnable)
1024
{
1025
u16 bit = bEnable ? 1 : 0;
1026
1027
mod_phy_reg(pi, 0x4b0, (0x1 << 7), bit << 7);
1028
1029
mod_phy_reg(pi, 0x4b0, (0x1 << 14), bit << 14);
1030
1031
mod_phy_reg(pi, 0x43b, (0x1 << 6), bit << 6);
1032
}
1033
1034
static void
1035
wlc_lcnphy_rx_gain_override_enable(struct brcms_phy *pi, bool enable)
1036
{
1037
u16 ebit = enable ? 1 : 0;
1038
1039
mod_phy_reg(pi, 0x4b0, (0x1 << 8), ebit << 8);
1040
1041
mod_phy_reg(pi, 0x44c, (0x1 << 0), ebit << 0);
1042
1043
if (LCNREV_LT(pi->pubpi.phy_rev, 2)) {
1044
mod_phy_reg(pi, 0x44c, (0x1 << 4), ebit << 4);
1045
mod_phy_reg(pi, 0x44c, (0x1 << 6), ebit << 6);
1046
mod_phy_reg(pi, 0x4b0, (0x1 << 5), ebit << 5);
1047
mod_phy_reg(pi, 0x4b0, (0x1 << 6), ebit << 6);
1048
} else {
1049
mod_phy_reg(pi, 0x4b0, (0x1 << 12), ebit << 12);
1050
mod_phy_reg(pi, 0x4b0, (0x1 << 13), ebit << 13);
1051
mod_phy_reg(pi, 0x4b0, (0x1 << 5), ebit << 5);
1052
}
1053
1054
if (CHSPEC_IS2G(pi->radio_chanspec)) {
1055
mod_phy_reg(pi, 0x4b0, (0x1 << 10), ebit << 10);
1056
mod_phy_reg(pi, 0x4e5, (0x1 << 3), ebit << 3);
1057
}
1058
}
1059
1060
static void
1061
wlc_lcnphy_set_rx_gain_by_distribution(struct brcms_phy *pi,
1062
u16 trsw,
1063
u16 ext_lna,
1064
u16 biq2,
1065
u16 biq1,
1066
u16 tia, u16 lna2, u16 lna1)
1067
{
1068
u16 gain0_15, gain16_19;
1069
1070
gain16_19 = biq2 & 0xf;
1071
gain0_15 = ((biq1 & 0xf) << 12) |
1072
((tia & 0xf) << 8) |
1073
((lna2 & 0x3) << 6) |
1074
((lna2 & 0x3) << 4) |
1075
((lna1 & 0x3) << 2) |
1076
((lna1 & 0x3) << 0);
1077
1078
mod_phy_reg(pi, 0x4b6, (0xffff << 0), gain0_15 << 0);
1079
mod_phy_reg(pi, 0x4b7, (0xf << 0), gain16_19 << 0);
1080
mod_phy_reg(pi, 0x4b1, (0x3 << 11), lna1 << 11);
1081
1082
if (LCNREV_LT(pi->pubpi.phy_rev, 2)) {
1083
mod_phy_reg(pi, 0x4b1, (0x1 << 9), ext_lna << 9);
1084
mod_phy_reg(pi, 0x4b1, (0x1 << 10), ext_lna << 10);
1085
} else {
1086
mod_phy_reg(pi, 0x4b1, (0x1 << 10), 0 << 10);
1087
1088
mod_phy_reg(pi, 0x4b1, (0x1 << 15), 0 << 15);
1089
1090
mod_phy_reg(pi, 0x4b1, (0x1 << 9), ext_lna << 9);
1091
}
1092
1093
mod_phy_reg(pi, 0x44d, (0x1 << 0), (!trsw) << 0);
1094
1095
}
1096
1097
static void wlc_lcnphy_set_trsw_override(struct brcms_phy *pi, bool tx, bool rx)
1098
{
1099
1100
mod_phy_reg(pi, 0x44d,
1101
(0x1 << 1) |
1102
(0x1 << 0), (tx ? (0x1 << 1) : 0) | (rx ? (0x1 << 0) : 0));
1103
1104
or_phy_reg(pi, 0x44c, (0x1 << 1) | (0x1 << 0));
1105
}
1106
1107
static void wlc_lcnphy_clear_trsw_override(struct brcms_phy *pi)
1108
{
1109
1110
and_phy_reg(pi, 0x44c, (u16) ~((0x1 << 1) | (0x1 << 0)));
1111
}
1112
1113
static void wlc_lcnphy_set_rx_iq_comp(struct brcms_phy *pi, u16 a, u16 b)
1114
{
1115
mod_phy_reg(pi, 0x645, (0x3ff << 0), (a) << 0);
1116
1117
mod_phy_reg(pi, 0x646, (0x3ff << 0), (b) << 0);
1118
1119
mod_phy_reg(pi, 0x647, (0x3ff << 0), (a) << 0);
1120
1121
mod_phy_reg(pi, 0x648, (0x3ff << 0), (b) << 0);
1122
1123
mod_phy_reg(pi, 0x649, (0x3ff << 0), (a) << 0);
1124
1125
mod_phy_reg(pi, 0x64a, (0x3ff << 0), (b) << 0);
1126
1127
}
1128
1129
static bool
1130
wlc_lcnphy_rx_iq_est(struct brcms_phy *pi,
1131
u16 num_samps,
1132
u8 wait_time, struct lcnphy_iq_est *iq_est)
1133
{
1134
int wait_count = 0;
1135
bool result = true;
1136
1137
mod_phy_reg(pi, 0x6da, (0x1 << 5), (1) << 5);
1138
1139
mod_phy_reg(pi, 0x410, (0x1 << 3), (0) << 3);
1140
1141
mod_phy_reg(pi, 0x482, (0xffff << 0), (num_samps) << 0);
1142
1143
mod_phy_reg(pi, 0x481, (0xff << 0), ((u16) wait_time) << 0);
1144
1145
mod_phy_reg(pi, 0x481, (0x1 << 8), (0) << 8);
1146
1147
mod_phy_reg(pi, 0x481, (0x1 << 9), (1) << 9);
1148
1149
while (read_phy_reg(pi, 0x481) & (0x1 << 9)) {
1150
1151
if (wait_count > (10 * 500)) {
1152
result = false;
1153
goto cleanup;
1154
}
1155
udelay(100);
1156
wait_count++;
1157
}
1158
1159
iq_est->iq_prod = ((u32) read_phy_reg(pi, 0x483) << 16) |
1160
(u32) read_phy_reg(pi, 0x484);
1161
iq_est->i_pwr = ((u32) read_phy_reg(pi, 0x485) << 16) |
1162
(u32) read_phy_reg(pi, 0x486);
1163
iq_est->q_pwr = ((u32) read_phy_reg(pi, 0x487) << 16) |
1164
(u32) read_phy_reg(pi, 0x488);
1165
1166
cleanup:
1167
mod_phy_reg(pi, 0x410, (0x1 << 3), (1) << 3);
1168
1169
mod_phy_reg(pi, 0x6da, (0x1 << 5), (0) << 5);
1170
1171
return result;
1172
}
1173
1174
static bool wlc_lcnphy_calc_rx_iq_comp(struct brcms_phy *pi, u16 num_samps)
1175
{
1176
#define LCNPHY_MIN_RXIQ_PWR 2
1177
bool result;
1178
u16 a0_new, b0_new;
1179
struct lcnphy_iq_est iq_est = { 0, 0, 0 };
1180
s32 a, b, temp;
1181
s16 iq_nbits, qq_nbits, arsh, brsh;
1182
s32 iq;
1183
u32 ii, qq;
1184
struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
1185
1186
a0_new = ((read_phy_reg(pi, 0x645) & (0x3ff << 0)) >> 0);
1187
b0_new = ((read_phy_reg(pi, 0x646) & (0x3ff << 0)) >> 0);
1188
mod_phy_reg(pi, 0x6d1, (0x1 << 2), (0) << 2);
1189
1190
mod_phy_reg(pi, 0x64b, (0x1 << 6), (1) << 6);
1191
1192
wlc_lcnphy_set_rx_iq_comp(pi, 0, 0);
1193
1194
result = wlc_lcnphy_rx_iq_est(pi, num_samps, 32, &iq_est);
1195
if (!result)
1196
goto cleanup;
1197
1198
iq = (s32) iq_est.iq_prod;
1199
ii = iq_est.i_pwr;
1200
qq = iq_est.q_pwr;
1201
1202
if ((ii + qq) < LCNPHY_MIN_RXIQ_PWR) {
1203
result = false;
1204
goto cleanup;
1205
}
1206
1207
iq_nbits = wlc_phy_nbits(iq);
1208
qq_nbits = wlc_phy_nbits(qq);
1209
1210
arsh = 10 - (30 - iq_nbits);
1211
if (arsh >= 0) {
1212
a = (-(iq << (30 - iq_nbits)) + (ii >> (1 + arsh)));
1213
temp = (s32) (ii >> arsh);
1214
if (temp == 0)
1215
return false;
1216
} else {
1217
a = (-(iq << (30 - iq_nbits)) + (ii << (-1 - arsh)));
1218
temp = (s32) (ii << -arsh);
1219
if (temp == 0)
1220
return false;
1221
}
1222
a /= temp;
1223
brsh = qq_nbits - 31 + 20;
1224
if (brsh >= 0) {
1225
b = (qq << (31 - qq_nbits));
1226
temp = (s32) (ii >> brsh);
1227
if (temp == 0)
1228
return false;
1229
} else {
1230
b = (qq << (31 - qq_nbits));
1231
temp = (s32) (ii << -brsh);
1232
if (temp == 0)
1233
return false;
1234
}
1235
b /= temp;
1236
b -= a * a;
1237
b = (s32) int_sqrt((unsigned long) b);
1238
b -= (1 << 10);
1239
a0_new = (u16) (a & 0x3ff);
1240
b0_new = (u16) (b & 0x3ff);
1241
cleanup:
1242
1243
wlc_lcnphy_set_rx_iq_comp(pi, a0_new, b0_new);
1244
1245
mod_phy_reg(pi, 0x64b, (0x1 << 0), (1) << 0);
1246
1247
mod_phy_reg(pi, 0x64b, (0x1 << 3), (1) << 3);
1248
1249
pi_lcn->lcnphy_cal_results.rxiqcal_coeff_a0 = a0_new;
1250
pi_lcn->lcnphy_cal_results.rxiqcal_coeff_b0 = b0_new;
1251
1252
return result;
1253
}
1254
1255
static u32 wlc_lcnphy_measure_digital_power(struct brcms_phy *pi, u16 nsamples)
1256
{
1257
struct lcnphy_iq_est iq_est = { 0, 0, 0 };
1258
1259
if (!wlc_lcnphy_rx_iq_est(pi, nsamples, 32, &iq_est))
1260
return 0;
1261
return (iq_est.i_pwr + iq_est.q_pwr) / nsamples;
1262
}
1263
1264
static bool wlc_lcnphy_rx_iq_cal_gain(struct brcms_phy *pi, u16 biq1_gain,
1265
u16 tia_gain, u16 lna2_gain)
1266
{
1267
u32 i_thresh_l, q_thresh_l;
1268
u32 i_thresh_h, q_thresh_h;
1269
struct lcnphy_iq_est iq_est_h, iq_est_l;
1270
1271
wlc_lcnphy_set_rx_gain_by_distribution(pi, 0, 0, 0, biq1_gain, tia_gain,
1272
lna2_gain, 0);
1273
1274
wlc_lcnphy_rx_gain_override_enable(pi, true);
1275
wlc_lcnphy_start_tx_tone(pi, 2000, (40 >> 1), 0);
1276
udelay(500);
1277
write_radio_reg(pi, RADIO_2064_REG112, 0);
1278
if (!wlc_lcnphy_rx_iq_est(pi, 1024, 32, &iq_est_l))
1279
return false;
1280
1281
wlc_lcnphy_start_tx_tone(pi, 2000, 40, 0);
1282
udelay(500);
1283
write_radio_reg(pi, RADIO_2064_REG112, 0);
1284
if (!wlc_lcnphy_rx_iq_est(pi, 1024, 32, &iq_est_h))
1285
return false;
1286
1287
i_thresh_l = (iq_est_l.i_pwr << 1);
1288
i_thresh_h = (iq_est_l.i_pwr << 2) + iq_est_l.i_pwr;
1289
1290
q_thresh_l = (iq_est_l.q_pwr << 1);
1291
q_thresh_h = (iq_est_l.q_pwr << 2) + iq_est_l.q_pwr;
1292
if ((iq_est_h.i_pwr > i_thresh_l) &&
1293
(iq_est_h.i_pwr < i_thresh_h) &&
1294
(iq_est_h.q_pwr > q_thresh_l) &&
1295
(iq_est_h.q_pwr < q_thresh_h))
1296
return true;
1297
1298
return false;
1299
}
1300
1301
static bool
1302
wlc_lcnphy_rx_iq_cal(struct brcms_phy *pi,
1303
const struct lcnphy_rx_iqcomp *iqcomp,
1304
int iqcomp_sz, bool tx_switch, bool rx_switch, int module,
1305
int tx_gain_idx)
1306
{
1307
struct lcnphy_txgains old_gains;
1308
u16 tx_pwr_ctrl;
1309
u8 tx_gain_index_old = 0;
1310
bool result = false, tx_gain_override_old = false;
1311
u16 i, Core1TxControl_old,
1312
RFOverrideVal0_old, rfoverride2_old, rfoverride2val_old,
1313
rfoverride3_old, rfoverride3val_old, rfoverride4_old,
1314
rfoverride4val_old, afectrlovr_old, afectrlovrval_old;
1315
int tia_gain, lna2_gain, biq1_gain;
1316
bool set_gain;
1317
u16 old_sslpnCalibClkEnCtrl, old_sslpnRxFeClkEnCtrl;
1318
u16 values_to_save[11];
1319
s16 *ptr;
1320
struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
1321
1322
ptr = kmalloc_array(131, sizeof(s16), GFP_ATOMIC);
1323
if (NULL == ptr)
1324
return false;
1325
if (module == 2) {
1326
while (iqcomp_sz--) {
1327
if (iqcomp[iqcomp_sz].chan ==
1328
CHSPEC_CHANNEL(pi->radio_chanspec)) {
1329
wlc_lcnphy_set_rx_iq_comp(pi,
1330
(u16)
1331
iqcomp[iqcomp_sz].a,
1332
(u16)
1333
iqcomp[iqcomp_sz].b);
1334
result = true;
1335
break;
1336
}
1337
}
1338
goto cal_done;
1339
}
1340
1341
WARN_ON(module != 1);
1342
tx_pwr_ctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
1343
wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
1344
1345
for (i = 0; i < 11; i++)
1346
values_to_save[i] =
1347
read_radio_reg(pi, rxiq_cal_rf_reg[i]);
1348
Core1TxControl_old = read_phy_reg(pi, 0x631);
1349
1350
or_phy_reg(pi, 0x631, 0x0015);
1351
1352
read_phy_reg(pi, 0x44c); /* RFOverride0_old */
1353
RFOverrideVal0_old = read_phy_reg(pi, 0x44d);
1354
rfoverride2_old = read_phy_reg(pi, 0x4b0);
1355
rfoverride2val_old = read_phy_reg(pi, 0x4b1);
1356
rfoverride3_old = read_phy_reg(pi, 0x4f9);
1357
rfoverride3val_old = read_phy_reg(pi, 0x4fa);
1358
rfoverride4_old = read_phy_reg(pi, 0x938);
1359
rfoverride4val_old = read_phy_reg(pi, 0x939);
1360
afectrlovr_old = read_phy_reg(pi, 0x43b);
1361
afectrlovrval_old = read_phy_reg(pi, 0x43c);
1362
old_sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da);
1363
old_sslpnRxFeClkEnCtrl = read_phy_reg(pi, 0x6db);
1364
1365
tx_gain_override_old = wlc_lcnphy_tx_gain_override_enabled(pi);
1366
if (tx_gain_override_old) {
1367
wlc_lcnphy_get_tx_gain(pi, &old_gains);
1368
tx_gain_index_old = pi_lcn->lcnphy_current_index;
1369
}
1370
1371
wlc_lcnphy_set_tx_pwr_by_index(pi, tx_gain_idx);
1372
1373
mod_phy_reg(pi, 0x4f9, (0x1 << 0), 1 << 0);
1374
mod_phy_reg(pi, 0x4fa, (0x1 << 0), 0 << 0);
1375
1376
mod_phy_reg(pi, 0x43b, (0x1 << 1), 1 << 1);
1377
mod_phy_reg(pi, 0x43c, (0x1 << 1), 0 << 1);
1378
1379
write_radio_reg(pi, RADIO_2064_REG116, 0x06);
1380
write_radio_reg(pi, RADIO_2064_REG12C, 0x07);
1381
write_radio_reg(pi, RADIO_2064_REG06A, 0xd3);
1382
write_radio_reg(pi, RADIO_2064_REG098, 0x03);
1383
write_radio_reg(pi, RADIO_2064_REG00B, 0x7);
1384
mod_radio_reg(pi, RADIO_2064_REG113, 1 << 4, 1 << 4);
1385
write_radio_reg(pi, RADIO_2064_REG01D, 0x01);
1386
write_radio_reg(pi, RADIO_2064_REG114, 0x01);
1387
write_radio_reg(pi, RADIO_2064_REG02E, 0x10);
1388
write_radio_reg(pi, RADIO_2064_REG12A, 0x08);
1389
1390
mod_phy_reg(pi, 0x938, (0x1 << 0), 1 << 0);
1391
mod_phy_reg(pi, 0x939, (0x1 << 0), 0 << 0);
1392
mod_phy_reg(pi, 0x938, (0x1 << 1), 1 << 1);
1393
mod_phy_reg(pi, 0x939, (0x1 << 1), 1 << 1);
1394
mod_phy_reg(pi, 0x938, (0x1 << 2), 1 << 2);
1395
mod_phy_reg(pi, 0x939, (0x1 << 2), 1 << 2);
1396
mod_phy_reg(pi, 0x938, (0x1 << 3), 1 << 3);
1397
mod_phy_reg(pi, 0x939, (0x1 << 3), 1 << 3);
1398
mod_phy_reg(pi, 0x938, (0x1 << 5), 1 << 5);
1399
mod_phy_reg(pi, 0x939, (0x1 << 5), 0 << 5);
1400
1401
mod_phy_reg(pi, 0x43b, (0x1 << 0), 1 << 0);
1402
mod_phy_reg(pi, 0x43c, (0x1 << 0), 0 << 0);
1403
1404
write_phy_reg(pi, 0x6da, 0xffff);
1405
or_phy_reg(pi, 0x6db, 0x3);
1406
1407
wlc_lcnphy_set_trsw_override(pi, tx_switch, rx_switch);
1408
for (lna2_gain = 3; lna2_gain >= 0; lna2_gain--) {
1409
for (tia_gain = 4; tia_gain >= 0; tia_gain--) {
1410
for (biq1_gain = 6; biq1_gain >= 0; biq1_gain--) {
1411
set_gain = wlc_lcnphy_rx_iq_cal_gain(pi,
1412
(u16)
1413
biq1_gain,
1414
(u16)
1415
tia_gain,
1416
(u16)
1417
lna2_gain);
1418
if (!set_gain)
1419
continue;
1420
1421
result = wlc_lcnphy_calc_rx_iq_comp(pi, 1024);
1422
goto stop_tone;
1423
}
1424
}
1425
}
1426
1427
stop_tone:
1428
wlc_lcnphy_stop_tx_tone(pi);
1429
1430
write_phy_reg(pi, 0x631, Core1TxControl_old);
1431
1432
write_phy_reg(pi, 0x44c, RFOverrideVal0_old);
1433
write_phy_reg(pi, 0x44d, RFOverrideVal0_old);
1434
write_phy_reg(pi, 0x4b0, rfoverride2_old);
1435
write_phy_reg(pi, 0x4b1, rfoverride2val_old);
1436
write_phy_reg(pi, 0x4f9, rfoverride3_old);
1437
write_phy_reg(pi, 0x4fa, rfoverride3val_old);
1438
write_phy_reg(pi, 0x938, rfoverride4_old);
1439
write_phy_reg(pi, 0x939, rfoverride4val_old);
1440
write_phy_reg(pi, 0x43b, afectrlovr_old);
1441
write_phy_reg(pi, 0x43c, afectrlovrval_old);
1442
write_phy_reg(pi, 0x6da, old_sslpnCalibClkEnCtrl);
1443
write_phy_reg(pi, 0x6db, old_sslpnRxFeClkEnCtrl);
1444
1445
wlc_lcnphy_clear_trsw_override(pi);
1446
1447
mod_phy_reg(pi, 0x44c, (0x1 << 2), 0 << 2);
1448
1449
for (i = 0; i < 11; i++)
1450
write_radio_reg(pi, rxiq_cal_rf_reg[i],
1451
values_to_save[i]);
1452
1453
if (tx_gain_override_old)
1454
wlc_lcnphy_set_tx_pwr_by_index(pi, tx_gain_index_old);
1455
else
1456
wlc_lcnphy_disable_tx_gain_override(pi);
1457
1458
wlc_lcnphy_set_tx_pwr_ctrl(pi, tx_pwr_ctrl);
1459
wlc_lcnphy_rx_gain_override_enable(pi, false);
1460
1461
cal_done:
1462
kfree(ptr);
1463
return result;
1464
}
1465
1466
s8 wlc_lcnphy_get_current_tx_pwr_idx(struct brcms_phy *pi)
1467
{
1468
s8 index;
1469
struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
1470
1471
if (txpwrctrl_off(pi))
1472
index = pi_lcn->lcnphy_current_index;
1473
else if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi))
1474
index = (s8) (wlc_lcnphy_get_current_tx_pwr_idx_if_pwrctrl_on(
1475
pi) / 2);
1476
else
1477
index = pi_lcn->lcnphy_current_index;
1478
return index;
1479
}
1480
1481
void wlc_lcnphy_crsuprs(struct brcms_phy *pi, int channel)
1482
{
1483
u16 afectrlovr, afectrlovrval;
1484
afectrlovr = read_phy_reg(pi, 0x43b);
1485
afectrlovrval = read_phy_reg(pi, 0x43c);
1486
if (channel != 0) {
1487
mod_phy_reg(pi, 0x43b, (0x1 << 1), (1) << 1);
1488
1489
mod_phy_reg(pi, 0x43c, (0x1 << 1), (0) << 1);
1490
1491
mod_phy_reg(pi, 0x43b, (0x1 << 4), (1) << 4);
1492
1493
mod_phy_reg(pi, 0x43c, (0x1 << 6), (0) << 6);
1494
1495
write_phy_reg(pi, 0x44b, 0xffff);
1496
wlc_lcnphy_tx_pu(pi, 1);
1497
1498
mod_phy_reg(pi, 0x634, (0xff << 8), (0) << 8);
1499
1500
or_phy_reg(pi, 0x6da, 0x0080);
1501
1502
or_phy_reg(pi, 0x00a, 0x228);
1503
} else {
1504
and_phy_reg(pi, 0x00a, ~(0x228));
1505
1506
and_phy_reg(pi, 0x6da, 0xFF7F);
1507
write_phy_reg(pi, 0x43b, afectrlovr);
1508
write_phy_reg(pi, 0x43c, afectrlovrval);
1509
}
1510
}
1511
1512
static void wlc_lcnphy_toggle_afe_pwdn(struct brcms_phy *pi)
1513
{
1514
u16 save_AfeCtrlOvrVal, save_AfeCtrlOvr;
1515
1516
save_AfeCtrlOvrVal = read_phy_reg(pi, 0x43c);
1517
save_AfeCtrlOvr = read_phy_reg(pi, 0x43b);
1518
1519
write_phy_reg(pi, 0x43c, save_AfeCtrlOvrVal | 0x1);
1520
write_phy_reg(pi, 0x43b, save_AfeCtrlOvr | 0x1);
1521
1522
write_phy_reg(pi, 0x43c, save_AfeCtrlOvrVal & 0xfffe);
1523
write_phy_reg(pi, 0x43b, save_AfeCtrlOvr & 0xfffe);
1524
1525
write_phy_reg(pi, 0x43c, save_AfeCtrlOvrVal);
1526
write_phy_reg(pi, 0x43b, save_AfeCtrlOvr);
1527
}
1528
1529
static void
1530
wlc_lcnphy_txrx_spur_avoidance_mode(struct brcms_phy *pi, bool enable)
1531
{
1532
if (enable) {
1533
write_phy_reg(pi, 0x942, 0x7);
1534
write_phy_reg(pi, 0x93b, ((1 << 13) + 23));
1535
write_phy_reg(pi, 0x93c, ((1 << 13) + 1989));
1536
1537
write_phy_reg(pi, 0x44a, 0x084);
1538
write_phy_reg(pi, 0x44a, 0x080);
1539
write_phy_reg(pi, 0x6d3, 0x2222);
1540
write_phy_reg(pi, 0x6d3, 0x2220);
1541
} else {
1542
write_phy_reg(pi, 0x942, 0x0);
1543
write_phy_reg(pi, 0x93b, ((0 << 13) + 23));
1544
write_phy_reg(pi, 0x93c, ((0 << 13) + 1989));
1545
}
1546
wlapi_switch_macfreq(pi->sh->physhim, enable);
1547
}
1548
1549
static void
1550
wlc_lcnphy_set_chanspec_tweaks(struct brcms_phy *pi, u16 chanspec)
1551
{
1552
u8 channel = CHSPEC_CHANNEL(chanspec);
1553
struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
1554
1555
if (channel == 14)
1556
mod_phy_reg(pi, 0x448, (0x3 << 8), (2) << 8);
1557
else
1558
mod_phy_reg(pi, 0x448, (0x3 << 8), (1) << 8);
1559
1560
pi_lcn->lcnphy_bandedge_corr = 2;
1561
if (channel == 1)
1562
pi_lcn->lcnphy_bandedge_corr = 4;
1563
1564
if (channel == 1 || channel == 2 || channel == 3 ||
1565
channel == 4 || channel == 9 ||
1566
channel == 10 || channel == 11 || channel == 12) {
1567
bcma_chipco_pll_write(&pi->d11core->bus->drv_cc, 0x2,
1568
0x03000c04);
1569
bcma_chipco_pll_maskset(&pi->d11core->bus->drv_cc, 0x3,
1570
~0x00ffffff, 0x0);
1571
bcma_chipco_pll_write(&pi->d11core->bus->drv_cc, 0x4,
1572
0x200005c0);
1573
1574
bcma_cc_set32(&pi->d11core->bus->drv_cc, BCMA_CC_PMU_CTL,
1575
BCMA_CC_PMU_CTL_PLL_UPD);
1576
write_phy_reg(pi, 0x942, 0);
1577
wlc_lcnphy_txrx_spur_avoidance_mode(pi, false);
1578
pi_lcn->lcnphy_spurmod = false;
1579
mod_phy_reg(pi, 0x424, (0xff << 8), (0x1b) << 8);
1580
1581
write_phy_reg(pi, 0x425, 0x5907);
1582
} else {
1583
bcma_chipco_pll_write(&pi->d11core->bus->drv_cc, 0x2,
1584
0x03140c04);
1585
bcma_chipco_pll_maskset(&pi->d11core->bus->drv_cc, 0x3,
1586
~0x00ffffff, 0x333333);
1587
bcma_chipco_pll_write(&pi->d11core->bus->drv_cc, 0x4,
1588
0x202c2820);
1589
1590
bcma_cc_set32(&pi->d11core->bus->drv_cc, BCMA_CC_PMU_CTL,
1591
BCMA_CC_PMU_CTL_PLL_UPD);
1592
write_phy_reg(pi, 0x942, 0);
1593
wlc_lcnphy_txrx_spur_avoidance_mode(pi, true);
1594
1595
pi_lcn->lcnphy_spurmod = false;
1596
mod_phy_reg(pi, 0x424, (0xff << 8), (0x1f) << 8);
1597
1598
write_phy_reg(pi, 0x425, 0x590a);
1599
}
1600
1601
or_phy_reg(pi, 0x44a, 0x44);
1602
write_phy_reg(pi, 0x44a, 0x80);
1603
}
1604
1605
static void
1606
wlc_lcnphy_radio_2064_channel_tune_4313(struct brcms_phy *pi, u8 channel)
1607
{
1608
uint i;
1609
const struct chan_info_2064_lcnphy *ci;
1610
u8 rfpll_doubler = 0;
1611
u8 pll_pwrup, pll_pwrup_ovr;
1612
s32 qFcal;
1613
u8 d15, d16, f16, e44, e45;
1614
u32 div_int, div_frac, fvco3, fpfd, fref3, fcal_div;
1615
u16 loop_bw, d30, setCount;
1616
1617
u8 h29, h28_ten, e30, h30_ten, cp_current;
1618
u16 g30, d28;
1619
1620
ci = &chan_info_2064_lcnphy[0];
1621
rfpll_doubler = 1;
1622
1623
mod_radio_reg(pi, RADIO_2064_REG09D, 0x4, 0x1 << 2);
1624
1625
write_radio_reg(pi, RADIO_2064_REG09E, 0xf);
1626
if (!rfpll_doubler) {
1627
loop_bw = PLL_2064_LOOP_BW;
1628
d30 = PLL_2064_D30;
1629
} else {
1630
loop_bw = PLL_2064_LOOP_BW_DOUBLER;
1631
d30 = PLL_2064_D30_DOUBLER;
1632
}
1633
1634
if (CHSPEC_IS2G(pi->radio_chanspec)) {
1635
for (i = 0; i < ARRAY_SIZE(chan_info_2064_lcnphy); i++)
1636
if (chan_info_2064_lcnphy[i].chan == channel)
1637
break;
1638
1639
if (i >= ARRAY_SIZE(chan_info_2064_lcnphy))
1640
return;
1641
1642
ci = &chan_info_2064_lcnphy[i];
1643
}
1644
1645
write_radio_reg(pi, RADIO_2064_REG02A, ci->logen_buftune);
1646
1647
mod_radio_reg(pi, RADIO_2064_REG030, 0x3, ci->logen_rccr_tx);
1648
1649
mod_radio_reg(pi, RADIO_2064_REG091, 0x3, ci->txrf_mix_tune_ctrl);
1650
1651
mod_radio_reg(pi, RADIO_2064_REG038, 0xf, ci->pa_input_tune_g);
1652
1653
mod_radio_reg(pi, RADIO_2064_REG030, 0x3 << 2,
1654
(ci->logen_rccr_rx) << 2);
1655
1656
mod_radio_reg(pi, RADIO_2064_REG05E, 0xf, ci->pa_rxrf_lna1_freq_tune);
1657
1658
mod_radio_reg(pi, RADIO_2064_REG05E, (0xf) << 4,
1659
(ci->pa_rxrf_lna2_freq_tune) << 4);
1660
1661
write_radio_reg(pi, RADIO_2064_REG06C, ci->rxrf_rxrf_spare1);
1662
1663
pll_pwrup = (u8) read_radio_reg(pi, RADIO_2064_REG044);
1664
pll_pwrup_ovr = (u8) read_radio_reg(pi, RADIO_2064_REG12B);
1665
1666
or_radio_reg(pi, RADIO_2064_REG044, 0x07);
1667
1668
or_radio_reg(pi, RADIO_2064_REG12B, (0x07) << 1);
1669
e44 = 0;
1670
e45 = 0;
1671
1672
fpfd = rfpll_doubler ? (pi->xtalfreq << 1) : (pi->xtalfreq);
1673
if (pi->xtalfreq > 26000000)
1674
e44 = 1;
1675
if (pi->xtalfreq > 52000000)
1676
e45 = 1;
1677
if (e44 == 0)
1678
fcal_div = 1;
1679
else if (e45 == 0)
1680
fcal_div = 2;
1681
else
1682
fcal_div = 4;
1683
fvco3 = (ci->freq * 3);
1684
fref3 = 2 * fpfd;
1685
1686
qFcal = pi->xtalfreq * fcal_div / PLL_2064_MHZ;
1687
1688
write_radio_reg(pi, RADIO_2064_REG04F, 0x02);
1689
1690
d15 = (pi->xtalfreq * fcal_div * 4 / 5) / PLL_2064_MHZ - 1;
1691
write_radio_reg(pi, RADIO_2064_REG052, (0x07 & (d15 >> 2)));
1692
write_radio_reg(pi, RADIO_2064_REG053, (d15 & 0x3) << 5);
1693
1694
d16 = (qFcal * 8 / (d15 + 1)) - 1;
1695
write_radio_reg(pi, RADIO_2064_REG051, d16);
1696
1697
f16 = ((d16 + 1) * (d15 + 1)) / qFcal;
1698
setCount = f16 * 3 * (ci->freq) / 32 - 1;
1699
mod_radio_reg(pi, RADIO_2064_REG053, (0x0f << 0),
1700
(u8) (setCount >> 8));
1701
1702
or_radio_reg(pi, RADIO_2064_REG053, 0x10);
1703
write_radio_reg(pi, RADIO_2064_REG054, (u8) (setCount & 0xff));
1704
1705
div_int = ((fvco3 * (PLL_2064_MHZ >> 4)) / fref3) << 4;
1706
1707
div_frac = ((fvco3 * (PLL_2064_MHZ >> 4)) % fref3) << 4;
1708
while (div_frac >= fref3) {
1709
div_int++;
1710
div_frac -= fref3;
1711
}
1712
div_frac = wlc_lcnphy_qdiv_roundup(div_frac, fref3, 20);
1713
1714
mod_radio_reg(pi, RADIO_2064_REG045, (0x1f << 0),
1715
(u8) (div_int >> 4));
1716
mod_radio_reg(pi, RADIO_2064_REG046, (0x1f << 4),
1717
(u8) (div_int << 4));
1718
mod_radio_reg(pi, RADIO_2064_REG046, (0x0f << 0),
1719
(u8) (div_frac >> 16));
1720
write_radio_reg(pi, RADIO_2064_REG047, (u8) (div_frac >> 8) & 0xff);
1721
write_radio_reg(pi, RADIO_2064_REG048, (u8) div_frac & 0xff);
1722
1723
write_radio_reg(pi, RADIO_2064_REG040, 0xfb);
1724
1725
write_radio_reg(pi, RADIO_2064_REG041, 0x9A);
1726
write_radio_reg(pi, RADIO_2064_REG042, 0xA3);
1727
write_radio_reg(pi, RADIO_2064_REG043, 0x0C);
1728
1729
h29 = LCN_BW_LMT / loop_bw;
1730
d28 = (((PLL_2064_HIGH_END_KVCO - PLL_2064_LOW_END_KVCO) *
1731
(fvco3 / 2 - PLL_2064_LOW_END_VCO)) /
1732
(PLL_2064_HIGH_END_VCO - PLL_2064_LOW_END_VCO))
1733
+ PLL_2064_LOW_END_KVCO;
1734
h28_ten = (d28 * 10) / LCN_VCO_DIV;
1735
e30 = (d30 - LCN_OFFSET) / LCN_FACT;
1736
g30 = LCN_OFFSET + (e30 * LCN_FACT);
1737
h30_ten = (g30 * 10) / LCN_CUR_DIV;
1738
cp_current = ((LCN_CUR_LMT * h29 * LCN_MULT * 100) / h28_ten) / h30_ten;
1739
mod_radio_reg(pi, RADIO_2064_REG03C, 0x3f, cp_current);
1740
1741
if (channel >= 1 && channel <= 5)
1742
write_radio_reg(pi, RADIO_2064_REG03C, 0x8);
1743
else
1744
write_radio_reg(pi, RADIO_2064_REG03C, 0x7);
1745
write_radio_reg(pi, RADIO_2064_REG03D, 0x3);
1746
1747
mod_radio_reg(pi, RADIO_2064_REG044, 0x0c, 0x0c);
1748
udelay(1);
1749
1750
wlc_2064_vco_cal(pi);
1751
1752
write_radio_reg(pi, RADIO_2064_REG044, pll_pwrup);
1753
write_radio_reg(pi, RADIO_2064_REG12B, pll_pwrup_ovr);
1754
if (LCNREV_IS(pi->pubpi.phy_rev, 1)) {
1755
write_radio_reg(pi, RADIO_2064_REG038, 3);
1756
write_radio_reg(pi, RADIO_2064_REG091, 7);
1757
}
1758
1759
if (!(pi->sh->boardflags & BFL_FEM)) {
1760
static const u8 reg038[14] = {
1761
0xd, 0xe, 0xd, 0xd, 0xd, 0xc, 0xa,
1762
0xb, 0xb, 0x3, 0x3, 0x2, 0x0, 0x0
1763
};
1764
1765
write_radio_reg(pi, RADIO_2064_REG02A, 0xf);
1766
write_radio_reg(pi, RADIO_2064_REG091, 0x3);
1767
write_radio_reg(pi, RADIO_2064_REG038, 0x3);
1768
1769
write_radio_reg(pi, RADIO_2064_REG038, reg038[channel - 1]);
1770
}
1771
}
1772
1773
static int
1774
wlc_lcnphy_load_tx_iir_filter(struct brcms_phy *pi, bool is_ofdm, s16 filt_type)
1775
{
1776
s16 filt_index = -1;
1777
int j;
1778
1779
u16 addr[] = {
1780
0x910,
1781
0x91e,
1782
0x91f,
1783
0x924,
1784
0x925,
1785
0x926,
1786
0x920,
1787
0x921,
1788
0x927,
1789
0x928,
1790
0x929,
1791
0x922,
1792
0x923,
1793
0x930,
1794
0x931,
1795
0x932
1796
};
1797
1798
u16 addr_ofdm[] = {
1799
0x90f,
1800
0x900,
1801
0x901,
1802
0x906,
1803
0x907,
1804
0x908,
1805
0x902,
1806
0x903,
1807
0x909,
1808
0x90a,
1809
0x90b,
1810
0x904,
1811
0x905,
1812
0x90c,
1813
0x90d,
1814
0x90e
1815
};
1816
1817
if (!is_ofdm) {
1818
for (j = 0; j < LCNPHY_NUM_TX_DIG_FILTERS_CCK; j++) {
1819
if (filt_type == LCNPHY_txdigfiltcoeffs_cck[j][0]) {
1820
filt_index = (s16) j;
1821
break;
1822
}
1823
}
1824
1825
if (filt_index != -1) {
1826
for (j = 0; j < LCNPHY_NUM_DIG_FILT_COEFFS; j++)
1827
write_phy_reg(pi, addr[j],
1828
LCNPHY_txdigfiltcoeffs_cck
1829
[filt_index][j + 1]);
1830
}
1831
} else {
1832
for (j = 0; j < LCNPHY_NUM_TX_DIG_FILTERS_OFDM; j++) {
1833
if (filt_type == LCNPHY_txdigfiltcoeffs_ofdm[j][0]) {
1834
filt_index = (s16) j;
1835
break;
1836
}
1837
}
1838
1839
if (filt_index != -1) {
1840
for (j = 0; j < LCNPHY_NUM_DIG_FILT_COEFFS; j++)
1841
write_phy_reg(pi, addr_ofdm[j],
1842
LCNPHY_txdigfiltcoeffs_ofdm
1843
[filt_index][j + 1]);
1844
}
1845
}
1846
1847
return (filt_index != -1) ? 0 : -1;
1848
}
1849
1850
static u16 wlc_lcnphy_get_pa_gain(struct brcms_phy *pi)
1851
{
1852
u16 pa_gain;
1853
1854
pa_gain = (read_phy_reg(pi, 0x4fb) &
1855
LCNPHY_txgainctrlovrval1_pagain_ovr_val1_MASK) >>
1856
LCNPHY_txgainctrlovrval1_pagain_ovr_val1_SHIFT;
1857
1858
return pa_gain;
1859
}
1860
1861
static void wlc_lcnphy_set_tx_gain(struct brcms_phy *pi,
1862
struct lcnphy_txgains *target_gains)
1863
{
1864
u16 pa_gain = wlc_lcnphy_get_pa_gain(pi);
1865
1866
mod_phy_reg(
1867
pi, 0x4b5,
1868
(0xffff << 0),
1869
((target_gains->gm_gain) |
1870
(target_gains->pga_gain << 8)) <<
1871
0);
1872
mod_phy_reg(pi, 0x4fb,
1873
(0x7fff << 0),
1874
((target_gains->pad_gain) | (pa_gain << 8)) << 0);
1875
1876
mod_phy_reg(
1877
pi, 0x4fc,
1878
(0xffff << 0),
1879
((target_gains->gm_gain) |
1880
(target_gains->pga_gain << 8)) <<
1881
0);
1882
mod_phy_reg(pi, 0x4fd,
1883
(0x7fff << 0),
1884
((target_gains->pad_gain) | (pa_gain << 8)) << 0);
1885
1886
wlc_lcnphy_set_dac_gain(pi, target_gains->dac_gain);
1887
1888
wlc_lcnphy_enable_tx_gain_override(pi);
1889
}
1890
1891
static u8 wlc_lcnphy_get_bbmult(struct brcms_phy *pi)
1892
{
1893
u16 m0m1;
1894
struct phytbl_info tab;
1895
1896
tab.tbl_ptr = &m0m1;
1897
tab.tbl_len = 1;
1898
tab.tbl_id = LCNPHY_TBL_ID_IQLOCAL;
1899
tab.tbl_offset = 87;
1900
tab.tbl_width = 16;
1901
wlc_lcnphy_read_table(pi, &tab);
1902
1903
return (u8) ((m0m1 & 0xff00) >> 8);
1904
}
1905
1906
static void wlc_lcnphy_set_bbmult(struct brcms_phy *pi, u8 m0)
1907
{
1908
u16 m0m1 = (u16) m0 << 8;
1909
struct phytbl_info tab;
1910
1911
tab.tbl_ptr = &m0m1;
1912
tab.tbl_len = 1;
1913
tab.tbl_id = LCNPHY_TBL_ID_IQLOCAL;
1914
tab.tbl_offset = 87;
1915
tab.tbl_width = 16;
1916
wlc_lcnphy_write_table(pi, &tab);
1917
}
1918
1919
static void wlc_lcnphy_clear_tx_power_offsets(struct brcms_phy *pi)
1920
{
1921
u32 data_buf[64];
1922
struct phytbl_info tab;
1923
1924
memset(data_buf, 0, sizeof(data_buf));
1925
1926
tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
1927
tab.tbl_width = 32;
1928
tab.tbl_ptr = data_buf;
1929
1930
if (!wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) {
1931
1932
tab.tbl_len = 30;
1933
tab.tbl_offset = LCNPHY_TX_PWR_CTRL_RATE_OFFSET;
1934
wlc_lcnphy_write_table(pi, &tab);
1935
}
1936
1937
tab.tbl_len = 64;
1938
tab.tbl_offset = LCNPHY_TX_PWR_CTRL_MAC_OFFSET;
1939
wlc_lcnphy_write_table(pi, &tab);
1940
}
1941
1942
enum lcnphy_tssi_mode {
1943
LCNPHY_TSSI_PRE_PA,
1944
LCNPHY_TSSI_POST_PA,
1945
LCNPHY_TSSI_EXT
1946
};
1947
1948
static void
1949
wlc_lcnphy_set_tssi_mux(struct brcms_phy *pi, enum lcnphy_tssi_mode pos)
1950
{
1951
mod_phy_reg(pi, 0x4d7, (0x1 << 0), (0x1) << 0);
1952
1953
mod_phy_reg(pi, 0x4d7, (0x1 << 6), (1) << 6);
1954
1955
if (LCNPHY_TSSI_POST_PA == pos) {
1956
mod_phy_reg(pi, 0x4d9, (0x1 << 2), (0) << 2);
1957
1958
mod_phy_reg(pi, 0x4d9, (0x1 << 3), (1) << 3);
1959
1960
if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
1961
mod_radio_reg(pi, RADIO_2064_REG086, 0x4, 0x4);
1962
} else {
1963
mod_radio_reg(pi, RADIO_2064_REG03A, 1, 0x1);
1964
mod_radio_reg(pi, RADIO_2064_REG11A, 0x8, 0x8);
1965
mod_radio_reg(pi, RADIO_2064_REG028, 0x1, 0x0);
1966
mod_radio_reg(pi, RADIO_2064_REG11A, 0x4, 1<<2);
1967
mod_radio_reg(pi, RADIO_2064_REG036, 0x10, 0x0);
1968
mod_radio_reg(pi, RADIO_2064_REG11A, 0x10, 1<<4);
1969
mod_radio_reg(pi, RADIO_2064_REG036, 0x3, 0x0);
1970
mod_radio_reg(pi, RADIO_2064_REG035, 0xff, 0x77);
1971
mod_radio_reg(pi, RADIO_2064_REG028, 0x1e, 0xe<<1);
1972
mod_radio_reg(pi, RADIO_2064_REG112, 0x80, 1<<7);
1973
mod_radio_reg(pi, RADIO_2064_REG005, 0x7, 1<<1);
1974
mod_radio_reg(pi, RADIO_2064_REG029, 0xf0, 0<<4);
1975
}
1976
} else {
1977
mod_phy_reg(pi, 0x4d9, (0x1 << 2), (0x1) << 2);
1978
1979
mod_phy_reg(pi, 0x4d9, (0x1 << 3), (0) << 3);
1980
1981
if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
1982
mod_radio_reg(pi, RADIO_2064_REG086, 0x4, 0x4);
1983
} else {
1984
mod_radio_reg(pi, RADIO_2064_REG03A, 1, 0);
1985
mod_radio_reg(pi, RADIO_2064_REG11A, 0x8, 0x8);
1986
}
1987
}
1988
mod_phy_reg(pi, 0x637, (0x3 << 14), (0) << 14);
1989
1990
if (LCNPHY_TSSI_EXT == pos) {
1991
write_radio_reg(pi, RADIO_2064_REG07F, 1);
1992
mod_radio_reg(pi, RADIO_2064_REG005, 0x7, 0x2);
1993
mod_radio_reg(pi, RADIO_2064_REG112, 0x80, 0x1 << 7);
1994
mod_radio_reg(pi, RADIO_2064_REG028, 0x1f, 0x3);
1995
}
1996
}
1997
1998
static u16 wlc_lcnphy_rfseq_tbl_adc_pwrup(struct brcms_phy *pi)
1999
{
2000
u16 N1, N2, N3, N4, N5, N6, N;
2001
N1 = ((read_phy_reg(pi, 0x4a5) & (0xff << 0))
2002
>> 0);
2003
N2 = 1 << ((read_phy_reg(pi, 0x4a5) & (0x7 << 12))
2004
>> 12);
2005
N3 = ((read_phy_reg(pi, 0x40d) & (0xff << 0))
2006
>> 0);
2007
N4 = 1 << ((read_phy_reg(pi, 0x40d) & (0x7 << 8))
2008
>> 8);
2009
N5 = ((read_phy_reg(pi, 0x4a2) & (0xff << 0))
2010
>> 0);
2011
N6 = 1 << ((read_phy_reg(pi, 0x4a2) & (0x7 << 8))
2012
>> 8);
2013
N = 2 * (N1 + N2 + N3 + N4 + 2 * (N5 + N6)) + 80;
2014
if (N < 1600)
2015
N = 1600;
2016
return N;
2017
}
2018
2019
static void wlc_lcnphy_pwrctrl_rssiparams(struct brcms_phy *pi)
2020
{
2021
u16 auxpga_vmid, auxpga_vmid_temp, auxpga_gain_temp;
2022
struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
2023
2024
auxpga_vmid = (2 << 8) |
2025
(pi_lcn->lcnphy_rssi_vc << 4) | pi_lcn->lcnphy_rssi_vf;
2026
auxpga_vmid_temp = (2 << 8) | (8 << 4) | 4;
2027
auxpga_gain_temp = 2;
2028
2029
mod_phy_reg(pi, 0x4d8, (0x1 << 0), (0) << 0);
2030
2031
mod_phy_reg(pi, 0x4d8, (0x1 << 1), (0) << 1);
2032
2033
mod_phy_reg(pi, 0x4d7, (0x1 << 3), (0) << 3);
2034
2035
mod_phy_reg(pi, 0x4db,
2036
(0x3ff << 0) |
2037
(0x7 << 12),
2038
(auxpga_vmid << 0) | (pi_lcn->lcnphy_rssi_gs << 12));
2039
2040
mod_phy_reg(pi, 0x4dc,
2041
(0x3ff << 0) |
2042
(0x7 << 12),
2043
(auxpga_vmid << 0) | (pi_lcn->lcnphy_rssi_gs << 12));
2044
2045
mod_phy_reg(pi, 0x40a,
2046
(0x3ff << 0) |
2047
(0x7 << 12),
2048
(auxpga_vmid << 0) | (pi_lcn->lcnphy_rssi_gs << 12));
2049
2050
mod_phy_reg(pi, 0x40b,
2051
(0x3ff << 0) |
2052
(0x7 << 12),
2053
(auxpga_vmid_temp << 0) | (auxpga_gain_temp << 12));
2054
2055
mod_phy_reg(pi, 0x40c,
2056
(0x3ff << 0) |
2057
(0x7 << 12),
2058
(auxpga_vmid_temp << 0) | (auxpga_gain_temp << 12));
2059
2060
mod_radio_reg(pi, RADIO_2064_REG082, (1 << 5), (1 << 5));
2061
mod_radio_reg(pi, RADIO_2064_REG07C, (1 << 0), (1 << 0));
2062
}
2063
2064
static void wlc_lcnphy_tssi_setup(struct brcms_phy *pi)
2065
{
2066
struct phytbl_info tab;
2067
u32 rfseq, ind;
2068
enum lcnphy_tssi_mode mode;
2069
u8 tssi_sel;
2070
2071
if (pi->sh->boardflags & BFL_FEM) {
2072
tssi_sel = 0x1;
2073
mode = LCNPHY_TSSI_EXT;
2074
} else {
2075
tssi_sel = 0xe;
2076
mode = LCNPHY_TSSI_POST_PA;
2077
}
2078
tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
2079
tab.tbl_width = 32;
2080
tab.tbl_ptr = &ind;
2081
tab.tbl_len = 1;
2082
tab.tbl_offset = 0;
2083
for (ind = 0; ind < 128; ind++) {
2084
wlc_lcnphy_write_table(pi, &tab);
2085
tab.tbl_offset++;
2086
}
2087
tab.tbl_offset = 704;
2088
for (ind = 0; ind < 128; ind++) {
2089
wlc_lcnphy_write_table(pi, &tab);
2090
tab.tbl_offset++;
2091
}
2092
mod_phy_reg(pi, 0x503, (0x1 << 0), (0) << 0);
2093
2094
mod_phy_reg(pi, 0x503, (0x1 << 2), (0) << 2);
2095
2096
mod_phy_reg(pi, 0x503, (0x1 << 4), (1) << 4);
2097
2098
wlc_lcnphy_set_tssi_mux(pi, mode);
2099
mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0) << 14);
2100
2101
mod_phy_reg(pi, 0x4a4, (0x1 << 15), (1) << 15);
2102
2103
mod_phy_reg(pi, 0x4d0, (0x1 << 5), (0) << 5);
2104
2105
mod_phy_reg(pi, 0x4a4, (0x1ff << 0), (0) << 0);
2106
2107
mod_phy_reg(pi, 0x4a5, (0xff << 0), (255) << 0);
2108
2109
mod_phy_reg(pi, 0x4a5, (0x7 << 12), (5) << 12);
2110
2111
mod_phy_reg(pi, 0x4a5, (0x7 << 8), (0) << 8);
2112
2113
mod_phy_reg(pi, 0x40d, (0xff << 0), (64) << 0);
2114
2115
mod_phy_reg(pi, 0x40d, (0x7 << 8), (4) << 8);
2116
2117
mod_phy_reg(pi, 0x4a2, (0xff << 0), (64) << 0);
2118
2119
mod_phy_reg(pi, 0x4a2, (0x7 << 8), (4) << 8);
2120
2121
mod_phy_reg(pi, 0x4d0, (0x1ff << 6), (0) << 6);
2122
2123
mod_phy_reg(pi, 0x4a8, (0xff << 0), (0x1) << 0);
2124
2125
wlc_lcnphy_clear_tx_power_offsets(pi);
2126
2127
mod_phy_reg(pi, 0x4a6, (0x1 << 15), (1) << 15);
2128
2129
mod_phy_reg(pi, 0x4a6, (0x1ff << 0), (0xff) << 0);
2130
2131
mod_phy_reg(pi, 0x49a, (0x1ff << 0), (0xff) << 0);
2132
2133
if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
2134
mod_radio_reg(pi, RADIO_2064_REG028, 0xf, tssi_sel);
2135
mod_radio_reg(pi, RADIO_2064_REG086, 0x4, 0x4);
2136
} else {
2137
mod_radio_reg(pi, RADIO_2064_REG028, 0x1e, tssi_sel << 1);
2138
mod_radio_reg(pi, RADIO_2064_REG03A, 0x1, 1);
2139
mod_radio_reg(pi, RADIO_2064_REG11A, 0x8, 1 << 3);
2140
}
2141
2142
write_radio_reg(pi, RADIO_2064_REG025, 0xc);
2143
2144
if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
2145
mod_radio_reg(pi, RADIO_2064_REG03A, 0x1, 1);
2146
} else {
2147
if (CHSPEC_IS2G(pi->radio_chanspec))
2148
mod_radio_reg(pi, RADIO_2064_REG03A, 0x2, 1 << 1);
2149
else
2150
mod_radio_reg(pi, RADIO_2064_REG03A, 0x2, 0 << 1);
2151
}
2152
2153
if (LCNREV_IS(pi->pubpi.phy_rev, 2))
2154
mod_radio_reg(pi, RADIO_2064_REG03A, 0x2, 1 << 1);
2155
else
2156
mod_radio_reg(pi, RADIO_2064_REG03A, 0x4, 1 << 2);
2157
2158
mod_radio_reg(pi, RADIO_2064_REG11A, 0x1, 1 << 0);
2159
2160
mod_radio_reg(pi, RADIO_2064_REG005, 0x8, 1 << 3);
2161
2162
if (!wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
2163
mod_phy_reg(pi, 0x4d7,
2164
(0x1 << 3) | (0x7 << 12), 0 << 3 | 2 << 12);
2165
2166
rfseq = wlc_lcnphy_rfseq_tbl_adc_pwrup(pi);
2167
tab.tbl_id = LCNPHY_TBL_ID_RFSEQ;
2168
tab.tbl_width = 16;
2169
tab.tbl_ptr = &rfseq;
2170
tab.tbl_len = 1;
2171
tab.tbl_offset = 6;
2172
wlc_lcnphy_write_table(pi, &tab);
2173
2174
mod_phy_reg(pi, 0x938, (0x1 << 2), (1) << 2);
2175
2176
mod_phy_reg(pi, 0x939, (0x1 << 2), (1) << 2);
2177
2178
mod_phy_reg(pi, 0x4a4, (0x1 << 12), (1) << 12);
2179
2180
mod_phy_reg(pi, 0x4d7, (0x1 << 2), (1) << 2);
2181
2182
mod_phy_reg(pi, 0x4d7, (0xf << 8), (0) << 8);
2183
2184
mod_radio_reg(pi, RADIO_2064_REG035, 0xff, 0x0);
2185
mod_radio_reg(pi, RADIO_2064_REG036, 0x3, 0x0);
2186
mod_radio_reg(pi, RADIO_2064_REG11A, 0x8, 0x8);
2187
2188
wlc_lcnphy_pwrctrl_rssiparams(pi);
2189
}
2190
2191
void wlc_lcnphy_tx_pwr_update_npt(struct brcms_phy *pi)
2192
{
2193
u16 tx_cnt, tx_total, npt;
2194
struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
2195
2196
tx_total = wlc_lcnphy_total_tx_frames(pi);
2197
tx_cnt = tx_total - pi_lcn->lcnphy_tssi_tx_cnt;
2198
npt = wlc_lcnphy_get_tx_pwr_npt(pi);
2199
2200
if (tx_cnt > (1 << npt)) {
2201
2202
pi_lcn->lcnphy_tssi_tx_cnt = tx_total;
2203
2204
pi_lcn->lcnphy_tssi_idx = wlc_lcnphy_get_current_tx_pwr_idx(pi);
2205
pi_lcn->lcnphy_tssi_npt = npt;
2206
2207
}
2208
}
2209
2210
s32 wlc_lcnphy_tssi2dbm(s32 tssi, s32 a1, s32 b0, s32 b1)
2211
{
2212
s32 a, b, p;
2213
2214
a = 32768 + (a1 * tssi);
2215
b = (1024 * b0) + (64 * b1 * tssi);
2216
p = ((2 * b) + a) / (2 * a);
2217
2218
return p;
2219
}
2220
2221
static void wlc_lcnphy_txpower_reset_npt(struct brcms_phy *pi)
2222
{
2223
struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
2224
if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
2225
return;
2226
2227
pi_lcn->lcnphy_tssi_idx = LCNPHY_TX_PWR_CTRL_START_INDEX_2G_4313;
2228
pi_lcn->lcnphy_tssi_npt = LCNPHY_TX_PWR_CTRL_START_NPT;
2229
}
2230
2231
void wlc_lcnphy_txpower_recalc_target(struct brcms_phy *pi)
2232
{
2233
struct phytbl_info tab;
2234
u32 rate_table[BRCMS_NUM_RATES_CCK + BRCMS_NUM_RATES_OFDM +
2235
BRCMS_NUM_RATES_MCS_1_STREAM];
2236
uint i, j;
2237
if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
2238
return;
2239
2240
for (i = 0, j = 0; i < ARRAY_SIZE(rate_table); i++, j++) {
2241
2242
if (i == BRCMS_NUM_RATES_CCK + BRCMS_NUM_RATES_OFDM)
2243
j = TXP_FIRST_MCS_20_SISO;
2244
2245
rate_table[i] = (u32) ((s32) (-pi->tx_power_offset[j]));
2246
}
2247
2248
tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
2249
tab.tbl_width = 32;
2250
tab.tbl_len = ARRAY_SIZE(rate_table);
2251
tab.tbl_ptr = rate_table;
2252
tab.tbl_offset = LCNPHY_TX_PWR_CTRL_RATE_OFFSET;
2253
wlc_lcnphy_write_table(pi, &tab);
2254
2255
if (wlc_lcnphy_get_target_tx_pwr(pi) != pi->tx_power_min) {
2256
wlc_lcnphy_set_target_tx_pwr(pi, pi->tx_power_min);
2257
2258
wlc_lcnphy_txpower_reset_npt(pi);
2259
}
2260
}
2261
2262
static void wlc_lcnphy_set_tx_pwr_soft_ctrl(struct brcms_phy *pi, s8 index)
2263
{
2264
u32 cck_offset[4] = { 22, 22, 22, 22 };
2265
u32 ofdm_offset, reg_offset_cck;
2266
int i;
2267
u16 index2;
2268
struct phytbl_info tab;
2269
2270
if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi))
2271
return;
2272
2273
mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0x1) << 14);
2274
2275
mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0x0) << 14);
2276
2277
or_phy_reg(pi, 0x6da, 0x0040);
2278
2279
reg_offset_cck = 0;
2280
for (i = 0; i < 4; i++)
2281
cck_offset[i] -= reg_offset_cck;
2282
tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
2283
tab.tbl_width = 32;
2284
tab.tbl_len = 4;
2285
tab.tbl_ptr = cck_offset;
2286
tab.tbl_offset = LCNPHY_TX_PWR_CTRL_RATE_OFFSET;
2287
wlc_lcnphy_write_table(pi, &tab);
2288
ofdm_offset = 0;
2289
tab.tbl_len = 1;
2290
tab.tbl_ptr = &ofdm_offset;
2291
for (i = 836; i < 862; i++) {
2292
tab.tbl_offset = i;
2293
wlc_lcnphy_write_table(pi, &tab);
2294
}
2295
2296
mod_phy_reg(pi, 0x4a4, (0x1 << 15), (0x1) << 15);
2297
2298
mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0x1) << 14);
2299
2300
mod_phy_reg(pi, 0x4a4, (0x1 << 13), (0x1) << 13);
2301
2302
mod_phy_reg(pi, 0x4b0, (0x1 << 7), (0) << 7);
2303
2304
mod_phy_reg(pi, 0x43b, (0x1 << 6), (0) << 6);
2305
2306
mod_phy_reg(pi, 0x4a9, (0x1 << 15), (1) << 15);
2307
2308
index2 = (u16) (index * 2);
2309
mod_phy_reg(pi, 0x4a9, (0x1ff << 0), (index2) << 0);
2310
2311
mod_phy_reg(pi, 0x6a3, (0x1 << 4), (0) << 4);
2312
2313
}
2314
2315
static s8 wlc_lcnphy_tempcompensated_txpwrctrl(struct brcms_phy *pi)
2316
{
2317
s8 index, delta_brd, delta_temp, new_index, tempcorrx;
2318
s16 manp, meas_temp, temp_diff;
2319
bool neg = false;
2320
u16 temp;
2321
struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
2322
2323
if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi))
2324
return pi_lcn->lcnphy_current_index;
2325
2326
index = FIXED_TXPWR;
2327
2328
if (pi_lcn->lcnphy_tempsense_slope == 0)
2329
return index;
2330
2331
temp = (u16) wlc_lcnphy_tempsense(pi, 0);
2332
meas_temp = LCNPHY_TEMPSENSE(temp);
2333
2334
if (pi->tx_power_min != 0)
2335
delta_brd = (pi_lcn->lcnphy_measPower - pi->tx_power_min);
2336
else
2337
delta_brd = 0;
2338
2339
manp = LCNPHY_TEMPSENSE(pi_lcn->lcnphy_rawtempsense);
2340
temp_diff = manp - meas_temp;
2341
if (temp_diff < 0) {
2342
neg = true;
2343
temp_diff = -temp_diff;
2344
}
2345
2346
delta_temp = (s8) wlc_lcnphy_qdiv_roundup((u32) (temp_diff * 192),
2347
(u32) (pi_lcn->
2348
lcnphy_tempsense_slope
2349
* 10), 0);
2350
if (neg)
2351
delta_temp = -delta_temp;
2352
2353
if (pi_lcn->lcnphy_tempsense_option == 3
2354
&& LCNREV_IS(pi->pubpi.phy_rev, 0))
2355
delta_temp = 0;
2356
if (pi_lcn->lcnphy_tempcorrx > 31)
2357
tempcorrx = (s8) (pi_lcn->lcnphy_tempcorrx - 64);
2358
else
2359
tempcorrx = (s8) pi_lcn->lcnphy_tempcorrx;
2360
if (LCNREV_IS(pi->pubpi.phy_rev, 1))
2361
tempcorrx = 4;
2362
new_index =
2363
index + delta_brd + delta_temp - pi_lcn->lcnphy_bandedge_corr;
2364
new_index += tempcorrx;
2365
2366
if (LCNREV_IS(pi->pubpi.phy_rev, 1))
2367
index = 127;
2368
2369
if (new_index < 0 || new_index > 126)
2370
return index;
2371
2372
return new_index;
2373
}
2374
2375
static u16 wlc_lcnphy_set_tx_pwr_ctrl_mode(struct brcms_phy *pi, u16 mode)
2376
{
2377
2378
u16 current_mode = mode;
2379
if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi) &&
2380
mode == LCNPHY_TX_PWR_CTRL_HW)
2381
current_mode = LCNPHY_TX_PWR_CTRL_TEMPBASED;
2382
if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi) &&
2383
mode == LCNPHY_TX_PWR_CTRL_TEMPBASED)
2384
current_mode = LCNPHY_TX_PWR_CTRL_HW;
2385
return current_mode;
2386
}
2387
2388
void wlc_lcnphy_set_tx_pwr_ctrl(struct brcms_phy *pi, u16 mode)
2389
{
2390
u16 old_mode = wlc_lcnphy_get_tx_pwr_ctrl(pi);
2391
s8 index;
2392
struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
2393
2394
mode = wlc_lcnphy_set_tx_pwr_ctrl_mode(pi, mode);
2395
old_mode = wlc_lcnphy_set_tx_pwr_ctrl_mode(pi, old_mode);
2396
2397
mod_phy_reg(pi, 0x6da, (0x1 << 6),
2398
((LCNPHY_TX_PWR_CTRL_HW == mode) ? 1 : 0) << 6);
2399
2400
mod_phy_reg(pi, 0x6a3, (0x1 << 4),
2401
((LCNPHY_TX_PWR_CTRL_HW == mode) ? 0 : 1) << 4);
2402
2403
if (old_mode != mode) {
2404
if (LCNPHY_TX_PWR_CTRL_HW == old_mode) {
2405
2406
wlc_lcnphy_tx_pwr_update_npt(pi);
2407
2408
wlc_lcnphy_clear_tx_power_offsets(pi);
2409
}
2410
if (LCNPHY_TX_PWR_CTRL_HW == mode) {
2411
2412
wlc_lcnphy_txpower_recalc_target(pi);
2413
2414
wlc_lcnphy_set_start_tx_pwr_idx(pi,
2415
pi_lcn->
2416
lcnphy_tssi_idx);
2417
wlc_lcnphy_set_tx_pwr_npt(pi, pi_lcn->lcnphy_tssi_npt);
2418
mod_radio_reg(pi, RADIO_2064_REG11F, 0x4, 0);
2419
2420
pi_lcn->lcnphy_tssi_tx_cnt =
2421
wlc_lcnphy_total_tx_frames(pi);
2422
2423
wlc_lcnphy_disable_tx_gain_override(pi);
2424
pi_lcn->lcnphy_tx_power_idx_override = -1;
2425
} else
2426
wlc_lcnphy_enable_tx_gain_override(pi);
2427
2428
mod_phy_reg(pi, 0x4a4,
2429
((0x1 << 15) | (0x1 << 14) | (0x1 << 13)), mode);
2430
if (mode == LCNPHY_TX_PWR_CTRL_TEMPBASED) {
2431
index = wlc_lcnphy_tempcompensated_txpwrctrl(pi);
2432
wlc_lcnphy_set_tx_pwr_soft_ctrl(pi, index);
2433
pi_lcn->lcnphy_current_index = (s8)
2434
((read_phy_reg(pi,
2435
0x4a9) &
2436
0xFF) / 2);
2437
}
2438
}
2439
}
2440
2441
static void
2442
wlc_lcnphy_tx_iqlo_loopback(struct brcms_phy *pi, u16 *values_to_save)
2443
{
2444
u16 vmid;
2445
int i;
2446
for (i = 0; i < 20; i++)
2447
values_to_save[i] =
2448
read_radio_reg(pi, iqlo_loopback_rf_regs[i]);
2449
2450
mod_phy_reg(pi, 0x44c, (0x1 << 12), 1 << 12);
2451
mod_phy_reg(pi, 0x44d, (0x1 << 14), 1 << 14);
2452
2453
mod_phy_reg(pi, 0x44c, (0x1 << 11), 1 << 11);
2454
mod_phy_reg(pi, 0x44d, (0x1 << 13), 0 << 13);
2455
2456
mod_phy_reg(pi, 0x43b, (0x1 << 1), 1 << 1);
2457
mod_phy_reg(pi, 0x43c, (0x1 << 1), 0 << 1);
2458
2459
mod_phy_reg(pi, 0x43b, (0x1 << 0), 1 << 0);
2460
mod_phy_reg(pi, 0x43c, (0x1 << 0), 0 << 0);
2461
2462
if (LCNREV_IS(pi->pubpi.phy_rev, 2))
2463
and_radio_reg(pi, RADIO_2064_REG03A, 0xFD);
2464
else
2465
and_radio_reg(pi, RADIO_2064_REG03A, 0xF9);
2466
or_radio_reg(pi, RADIO_2064_REG11A, 0x1);
2467
2468
or_radio_reg(pi, RADIO_2064_REG036, 0x01);
2469
or_radio_reg(pi, RADIO_2064_REG11A, 0x18);
2470
udelay(20);
2471
2472
if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
2473
if (CHSPEC_IS5G(pi->radio_chanspec))
2474
mod_radio_reg(pi, RADIO_2064_REG03A, 1, 0);
2475
else
2476
or_radio_reg(pi, RADIO_2064_REG03A, 1);
2477
} else {
2478
if (CHSPEC_IS5G(pi->radio_chanspec))
2479
mod_radio_reg(pi, RADIO_2064_REG03A, 3, 1);
2480
else
2481
or_radio_reg(pi, RADIO_2064_REG03A, 0x3);
2482
}
2483
2484
udelay(20);
2485
2486
write_radio_reg(pi, RADIO_2064_REG025, 0xF);
2487
if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
2488
if (CHSPEC_IS5G(pi->radio_chanspec))
2489
mod_radio_reg(pi, RADIO_2064_REG028, 0xF, 0x4);
2490
else
2491
mod_radio_reg(pi, RADIO_2064_REG028, 0xF, 0x6);
2492
} else {
2493
if (CHSPEC_IS5G(pi->radio_chanspec))
2494
mod_radio_reg(pi, RADIO_2064_REG028, 0x1e, 0x4 << 1);
2495
else
2496
mod_radio_reg(pi, RADIO_2064_REG028, 0x1e, 0x6 << 1);
2497
}
2498
2499
udelay(20);
2500
2501
write_radio_reg(pi, RADIO_2064_REG005, 0x8);
2502
or_radio_reg(pi, RADIO_2064_REG112, 0x80);
2503
udelay(20);
2504
2505
or_radio_reg(pi, RADIO_2064_REG0FF, 0x10);
2506
or_radio_reg(pi, RADIO_2064_REG11F, 0x44);
2507
udelay(20);
2508
2509
or_radio_reg(pi, RADIO_2064_REG00B, 0x7);
2510
or_radio_reg(pi, RADIO_2064_REG113, 0x10);
2511
udelay(20);
2512
2513
write_radio_reg(pi, RADIO_2064_REG007, 0x1);
2514
udelay(20);
2515
2516
vmid = 0x2A6;
2517
mod_radio_reg(pi, RADIO_2064_REG0FC, 0x3 << 0, (vmid >> 8) & 0x3);
2518
write_radio_reg(pi, RADIO_2064_REG0FD, (vmid & 0xff));
2519
or_radio_reg(pi, RADIO_2064_REG11F, 0x44);
2520
udelay(20);
2521
2522
or_radio_reg(pi, RADIO_2064_REG0FF, 0x10);
2523
udelay(20);
2524
write_radio_reg(pi, RADIO_2064_REG012, 0x02);
2525
or_radio_reg(pi, RADIO_2064_REG112, 0x06);
2526
write_radio_reg(pi, RADIO_2064_REG036, 0x11);
2527
write_radio_reg(pi, RADIO_2064_REG059, 0xcc);
2528
write_radio_reg(pi, RADIO_2064_REG05C, 0x2e);
2529
write_radio_reg(pi, RADIO_2064_REG078, 0xd7);
2530
write_radio_reg(pi, RADIO_2064_REG092, 0x15);
2531
}
2532
2533
static bool wlc_lcnphy_iqcal_wait(struct brcms_phy *pi)
2534
{
2535
uint delay_count = 0;
2536
2537
while (wlc_lcnphy_iqcal_active(pi)) {
2538
udelay(100);
2539
delay_count++;
2540
2541
if (delay_count > (10 * 500))
2542
break;
2543
}
2544
2545
return (0 == wlc_lcnphy_iqcal_active(pi));
2546
}
2547
2548
static void
2549
wlc_lcnphy_tx_iqlo_loopback_cleanup(struct brcms_phy *pi, u16 *values_to_save)
2550
{
2551
int i;
2552
2553
and_phy_reg(pi, 0x44c, 0x0 >> 11);
2554
2555
and_phy_reg(pi, 0x43b, 0xC);
2556
2557
for (i = 0; i < 20; i++)
2558
write_radio_reg(pi, iqlo_loopback_rf_regs[i],
2559
values_to_save[i]);
2560
}
2561
2562
static void
2563
wlc_lcnphy_tx_iqlo_cal(struct brcms_phy *pi,
2564
struct lcnphy_txgains *target_gains,
2565
enum lcnphy_cal_mode cal_mode, bool keep_tone)
2566
{
2567
2568
struct lcnphy_txgains cal_gains, temp_gains;
2569
u16 hash;
2570
int j;
2571
u16 ncorr_override[5];
2572
u16 syst_coeffs[] = { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
2573
0x0000, 0x0000, 0x0000, 0x0000, 0x0000};
2574
2575
u16 commands_fullcal[] = {
2576
0x8434, 0x8334, 0x8084, 0x8267, 0x8056, 0x8234
2577
};
2578
2579
u16 commands_recal[] = {
2580
0x8434, 0x8334, 0x8084, 0x8267, 0x8056, 0x8234
2581
};
2582
2583
u16 command_nums_fullcal[] = {
2584
0x7a97, 0x7a97, 0x7a97, 0x7a87, 0x7a87, 0x7b97
2585
};
2586
2587
u16 command_nums_recal[] = {
2588
0x7a97, 0x7a97, 0x7a97, 0x7a87, 0x7a87, 0x7b97
2589
};
2590
u16 *command_nums = command_nums_fullcal;
2591
2592
u16 *start_coeffs = NULL, *cal_cmds = NULL, cal_type, diq_start;
2593
u16 tx_pwr_ctrl_old, save_txpwrctrlrfctrl2;
2594
u16 save_sslpnCalibClkEnCtrl, save_sslpnRxFeClkEnCtrl;
2595
bool tx_gain_override_old;
2596
struct lcnphy_txgains old_gains;
2597
uint i, n_cal_cmds = 0, n_cal_start = 0;
2598
u16 *values_to_save;
2599
struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
2600
2601
if (WARN_ON(CHSPEC_IS5G(pi->radio_chanspec)))
2602
return;
2603
2604
values_to_save = kmalloc_array(20, sizeof(u16), GFP_ATOMIC);
2605
if (NULL == values_to_save)
2606
return;
2607
2608
save_sslpnRxFeClkEnCtrl = read_phy_reg(pi, 0x6db);
2609
save_sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da);
2610
2611
or_phy_reg(pi, 0x6da, 0x40);
2612
or_phy_reg(pi, 0x6db, 0x3);
2613
2614
switch (cal_mode) {
2615
case LCNPHY_CAL_FULL:
2616
start_coeffs = syst_coeffs;
2617
cal_cmds = commands_fullcal;
2618
n_cal_cmds = ARRAY_SIZE(commands_fullcal);
2619
break;
2620
2621
case LCNPHY_CAL_RECAL:
2622
start_coeffs = syst_coeffs;
2623
cal_cmds = commands_recal;
2624
n_cal_cmds = ARRAY_SIZE(commands_recal);
2625
command_nums = command_nums_recal;
2626
break;
2627
2628
default:
2629
break;
2630
}
2631
2632
wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2633
start_coeffs, 11, 16, 64);
2634
2635
write_phy_reg(pi, 0x6da, 0xffff);
2636
mod_phy_reg(pi, 0x503, (0x1 << 3), (1) << 3);
2637
2638
tx_pwr_ctrl_old = wlc_lcnphy_get_tx_pwr_ctrl(pi);
2639
2640
mod_phy_reg(pi, 0x4a4, (0x1 << 12), (1) << 12);
2641
2642
wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
2643
2644
save_txpwrctrlrfctrl2 = read_phy_reg(pi, 0x4db);
2645
2646
mod_phy_reg(pi, 0x4db, (0x3ff << 0), (0x2a6) << 0);
2647
2648
mod_phy_reg(pi, 0x4db, (0x7 << 12), (2) << 12);
2649
2650
wlc_lcnphy_tx_iqlo_loopback(pi, values_to_save);
2651
2652
tx_gain_override_old = wlc_lcnphy_tx_gain_override_enabled(pi);
2653
if (tx_gain_override_old)
2654
wlc_lcnphy_get_tx_gain(pi, &old_gains);
2655
2656
if (!target_gains) {
2657
if (!tx_gain_override_old)
2658
wlc_lcnphy_set_tx_pwr_by_index(pi,
2659
pi_lcn->lcnphy_tssi_idx);
2660
wlc_lcnphy_get_tx_gain(pi, &temp_gains);
2661
target_gains = &temp_gains;
2662
}
2663
2664
hash = (target_gains->gm_gain << 8) |
2665
(target_gains->pga_gain << 4) | (target_gains->pad_gain);
2666
2667
cal_gains = *target_gains;
2668
memset(ncorr_override, 0, sizeof(ncorr_override));
2669
for (j = 0; j < iqcal_gainparams_numgains_lcnphy[0]; j++) {
2670
if (hash == tbl_iqcal_gainparams_lcnphy[0][j][0]) {
2671
cal_gains.gm_gain =
2672
tbl_iqcal_gainparams_lcnphy[0][j][1];
2673
cal_gains.pga_gain =
2674
tbl_iqcal_gainparams_lcnphy[0][j][2];
2675
cal_gains.pad_gain =
2676
tbl_iqcal_gainparams_lcnphy[0][j][3];
2677
memcpy(ncorr_override,
2678
&tbl_iqcal_gainparams_lcnphy[0][j][3],
2679
sizeof(ncorr_override));
2680
break;
2681
}
2682
}
2683
2684
wlc_lcnphy_set_tx_gain(pi, &cal_gains);
2685
2686
write_phy_reg(pi, 0x453, 0xaa9);
2687
write_phy_reg(pi, 0x93d, 0xc0);
2688
2689
wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2690
lcnphy_iqcal_loft_gainladder,
2691
ARRAY_SIZE(lcnphy_iqcal_loft_gainladder),
2692
16, 0);
2693
2694
wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2695
lcnphy_iqcal_ir_gainladder,
2696
ARRAY_SIZE(
2697
lcnphy_iqcal_ir_gainladder), 16,
2698
32);
2699
2700
if (pi->phy_tx_tone_freq) {
2701
2702
wlc_lcnphy_stop_tx_tone(pi);
2703
udelay(5);
2704
wlc_lcnphy_start_tx_tone(pi, 3750, 88, 1);
2705
} else {
2706
wlc_lcnphy_start_tx_tone(pi, 3750, 88, 1);
2707
}
2708
2709
write_phy_reg(pi, 0x6da, 0xffff);
2710
2711
for (i = n_cal_start; i < n_cal_cmds; i++) {
2712
u16 zero_diq = 0;
2713
u16 best_coeffs[11];
2714
u16 command_num;
2715
2716
cal_type = (cal_cmds[i] & 0x0f00) >> 8;
2717
2718
command_num = command_nums[i];
2719
if (ncorr_override[cal_type])
2720
command_num =
2721
ncorr_override[cal_type] << 8 | (command_num &
2722
0xff);
2723
2724
write_phy_reg(pi, 0x452, command_num);
2725
2726
if ((cal_type == 3) || (cal_type == 4)) {
2727
wlc_lcnphy_common_read_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2728
&diq_start, 1, 16, 69);
2729
2730
wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2731
&zero_diq, 1, 16, 69);
2732
}
2733
2734
write_phy_reg(pi, 0x451, cal_cmds[i]);
2735
2736
if (!wlc_lcnphy_iqcal_wait(pi))
2737
goto cleanup;
2738
2739
wlc_lcnphy_common_read_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2740
best_coeffs,
2741
ARRAY_SIZE(best_coeffs), 16, 96);
2742
wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2743
best_coeffs,
2744
ARRAY_SIZE(best_coeffs), 16, 64);
2745
2746
if ((cal_type == 3) || (cal_type == 4))
2747
wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2748
&diq_start, 1, 16, 69);
2749
wlc_lcnphy_common_read_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2750
pi_lcn->lcnphy_cal_results.
2751
txiqlocal_bestcoeffs,
2752
ARRAY_SIZE(pi_lcn->
2753
lcnphy_cal_results.
2754
txiqlocal_bestcoeffs),
2755
16, 96);
2756
}
2757
2758
wlc_lcnphy_common_read_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2759
pi_lcn->lcnphy_cal_results.
2760
txiqlocal_bestcoeffs,
2761
ARRAY_SIZE(pi_lcn->lcnphy_cal_results.
2762
txiqlocal_bestcoeffs), 16, 96);
2763
pi_lcn->lcnphy_cal_results.txiqlocal_bestcoeffs_valid = true;
2764
2765
wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2766
&pi_lcn->lcnphy_cal_results.
2767
txiqlocal_bestcoeffs[0], 4, 16, 80);
2768
2769
wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2770
&pi_lcn->lcnphy_cal_results.
2771
txiqlocal_bestcoeffs[5], 2, 16, 85);
2772
2773
cleanup:
2774
wlc_lcnphy_tx_iqlo_loopback_cleanup(pi, values_to_save);
2775
kfree(values_to_save);
2776
2777
if (!keep_tone)
2778
wlc_lcnphy_stop_tx_tone(pi);
2779
2780
write_phy_reg(pi, 0x4db, save_txpwrctrlrfctrl2);
2781
2782
write_phy_reg(pi, 0x453, 0);
2783
2784
if (tx_gain_override_old)
2785
wlc_lcnphy_set_tx_gain(pi, &old_gains);
2786
wlc_lcnphy_set_tx_pwr_ctrl(pi, tx_pwr_ctrl_old);
2787
2788
write_phy_reg(pi, 0x6da, save_sslpnCalibClkEnCtrl);
2789
write_phy_reg(pi, 0x6db, save_sslpnRxFeClkEnCtrl);
2790
2791
}
2792
2793
static void wlc_lcnphy_idle_tssi_est(struct brcms_phy_pub *ppi)
2794
{
2795
bool suspend, tx_gain_override_old;
2796
struct lcnphy_txgains old_gains;
2797
struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
2798
u16 idleTssi0_2C, idleTssi0_OB, idleTssi0_regvalue_OB,
2799
idleTssi0_regvalue_2C;
2800
u16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
2801
u16 SAVE_lpfgain = read_radio_reg(pi, RADIO_2064_REG112);
2802
u16 SAVE_jtag_bb_afe_switch =
2803
read_radio_reg(pi, RADIO_2064_REG007) & 1;
2804
u16 SAVE_jtag_auxpga = read_radio_reg(pi, RADIO_2064_REG0FF) & 0x10;
2805
u16 SAVE_iqadc_aux_en = read_radio_reg(pi, RADIO_2064_REG11F) & 4;
2806
u8 SAVE_bbmult = wlc_lcnphy_get_bbmult(pi);
2807
2808
read_phy_reg(pi, 0x4ab); /* idleTssi */
2809
suspend = (0 == (bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) &
2810
MCTL_EN_MAC));
2811
if (!suspend)
2812
wlapi_suspend_mac_and_wait(pi->sh->physhim);
2813
wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
2814
2815
tx_gain_override_old = wlc_lcnphy_tx_gain_override_enabled(pi);
2816
wlc_lcnphy_get_tx_gain(pi, &old_gains);
2817
2818
wlc_lcnphy_enable_tx_gain_override(pi);
2819
wlc_lcnphy_set_tx_pwr_by_index(pi, 127);
2820
write_radio_reg(pi, RADIO_2064_REG112, 0x6);
2821
mod_radio_reg(pi, RADIO_2064_REG007, 0x1, 1);
2822
mod_radio_reg(pi, RADIO_2064_REG0FF, 0x10, 1 << 4);
2823
mod_radio_reg(pi, RADIO_2064_REG11F, 0x4, 1 << 2);
2824
wlc_lcnphy_tssi_setup(pi);
2825
2826
mod_phy_reg(pi, 0x4d7, (0x1 << 0), (1 << 0));
2827
mod_phy_reg(pi, 0x4d7, (0x1 << 6), (1 << 6));
2828
2829
wlc_lcnphy_set_bbmult(pi, 0x0);
2830
2831
wlc_phy_do_dummy_tx(pi, true, OFF);
2832
read_phy_reg(pi, 0x4ab); /* idleTssi */
2833
2834
idleTssi0_2C = ((read_phy_reg(pi, 0x63e) & (0x1ff << 0))
2835
>> 0);
2836
2837
if (idleTssi0_2C >= 256)
2838
idleTssi0_OB = idleTssi0_2C - 256;
2839
else
2840
idleTssi0_OB = idleTssi0_2C + 256;
2841
2842
idleTssi0_regvalue_OB = idleTssi0_OB;
2843
if (idleTssi0_regvalue_OB >= 256)
2844
idleTssi0_regvalue_2C = idleTssi0_regvalue_OB - 256;
2845
else
2846
idleTssi0_regvalue_2C = idleTssi0_regvalue_OB + 256;
2847
mod_phy_reg(pi, 0x4a6, (0x1ff << 0), (idleTssi0_regvalue_2C) << 0);
2848
2849
mod_phy_reg(pi, 0x44c, (0x1 << 12), (0) << 12);
2850
2851
wlc_lcnphy_set_bbmult(pi, SAVE_bbmult);
2852
wlc_lcnphy_set_tx_gain_override(pi, tx_gain_override_old);
2853
wlc_lcnphy_set_tx_gain(pi, &old_gains);
2854
wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_txpwrctrl);
2855
2856
write_radio_reg(pi, RADIO_2064_REG112, SAVE_lpfgain);
2857
mod_radio_reg(pi, RADIO_2064_REG007, 0x1, SAVE_jtag_bb_afe_switch);
2858
mod_radio_reg(pi, RADIO_2064_REG0FF, 0x10, SAVE_jtag_auxpga);
2859
mod_radio_reg(pi, RADIO_2064_REG11F, 0x4, SAVE_iqadc_aux_en);
2860
mod_radio_reg(pi, RADIO_2064_REG112, 0x80, 1 << 7);
2861
if (!suspend)
2862
wlapi_enable_mac(pi->sh->physhim);
2863
}
2864
2865
static void wlc_lcnphy_vbat_temp_sense_setup(struct brcms_phy *pi, u8 mode)
2866
{
2867
bool suspend;
2868
u16 save_txpwrCtrlEn;
2869
u8 auxpga_vmidcourse, auxpga_vmidfine, auxpga_gain;
2870
u16 auxpga_vmid;
2871
struct phytbl_info tab;
2872
u32 val;
2873
u8 save_reg007, save_reg0FF, save_reg11F, save_reg005, save_reg025,
2874
save_reg112;
2875
u16 values_to_save[14];
2876
s8 index;
2877
int i;
2878
struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
2879
udelay(999);
2880
2881
save_reg007 = (u8) read_radio_reg(pi, RADIO_2064_REG007);
2882
save_reg0FF = (u8) read_radio_reg(pi, RADIO_2064_REG0FF);
2883
save_reg11F = (u8) read_radio_reg(pi, RADIO_2064_REG11F);
2884
save_reg005 = (u8) read_radio_reg(pi, RADIO_2064_REG005);
2885
save_reg025 = (u8) read_radio_reg(pi, RADIO_2064_REG025);
2886
save_reg112 = (u8) read_radio_reg(pi, RADIO_2064_REG112);
2887
2888
for (i = 0; i < 14; i++)
2889
values_to_save[i] = read_phy_reg(pi, tempsense_phy_regs[i]);
2890
suspend = (0 == (bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) &
2891
MCTL_EN_MAC));
2892
if (!suspend)
2893
wlapi_suspend_mac_and_wait(pi->sh->physhim);
2894
save_txpwrCtrlEn = read_radio_reg(pi, 0x4a4);
2895
2896
wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
2897
index = pi_lcn->lcnphy_current_index;
2898
wlc_lcnphy_set_tx_pwr_by_index(pi, 127);
2899
mod_radio_reg(pi, RADIO_2064_REG007, 0x1, 0x1);
2900
mod_radio_reg(pi, RADIO_2064_REG0FF, 0x10, 0x1 << 4);
2901
mod_radio_reg(pi, RADIO_2064_REG11F, 0x4, 0x1 << 2);
2902
mod_phy_reg(pi, 0x503, (0x1 << 0), (0) << 0);
2903
2904
mod_phy_reg(pi, 0x503, (0x1 << 2), (0) << 2);
2905
2906
mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0) << 14);
2907
2908
mod_phy_reg(pi, 0x4a4, (0x1 << 15), (0) << 15);
2909
2910
mod_phy_reg(pi, 0x4d0, (0x1 << 5), (0) << 5);
2911
2912
mod_phy_reg(pi, 0x4a5, (0xff << 0), (255) << 0);
2913
2914
mod_phy_reg(pi, 0x4a5, (0x7 << 12), (5) << 12);
2915
2916
mod_phy_reg(pi, 0x4a5, (0x7 << 8), (0) << 8);
2917
2918
mod_phy_reg(pi, 0x40d, (0xff << 0), (64) << 0);
2919
2920
mod_phy_reg(pi, 0x40d, (0x7 << 8), (6) << 8);
2921
2922
mod_phy_reg(pi, 0x4a2, (0xff << 0), (64) << 0);
2923
2924
mod_phy_reg(pi, 0x4a2, (0x7 << 8), (6) << 8);
2925
2926
mod_phy_reg(pi, 0x4d9, (0x7 << 4), (2) << 4);
2927
2928
mod_phy_reg(pi, 0x4d9, (0x7 << 8), (3) << 8);
2929
2930
mod_phy_reg(pi, 0x4d9, (0x7 << 12), (1) << 12);
2931
2932
mod_phy_reg(pi, 0x4da, (0x1 << 12), (0) << 12);
2933
2934
mod_phy_reg(pi, 0x4da, (0x1 << 13), (1) << 13);
2935
2936
mod_phy_reg(pi, 0x4a6, (0x1 << 15), (1) << 15);
2937
2938
write_radio_reg(pi, RADIO_2064_REG025, 0xC);
2939
2940
mod_radio_reg(pi, RADIO_2064_REG005, 0x8, 0x1 << 3);
2941
2942
mod_phy_reg(pi, 0x938, (0x1 << 2), (1) << 2);
2943
2944
mod_phy_reg(pi, 0x939, (0x1 << 2), (1) << 2);
2945
2946
mod_phy_reg(pi, 0x4a4, (0x1 << 12), (1) << 12);
2947
2948
val = wlc_lcnphy_rfseq_tbl_adc_pwrup(pi);
2949
tab.tbl_id = LCNPHY_TBL_ID_RFSEQ;
2950
tab.tbl_width = 16;
2951
tab.tbl_len = 1;
2952
tab.tbl_ptr = &val;
2953
tab.tbl_offset = 6;
2954
wlc_lcnphy_write_table(pi, &tab);
2955
if (mode == TEMPSENSE) {
2956
mod_phy_reg(pi, 0x4d7, (0x1 << 3), (1) << 3);
2957
2958
mod_phy_reg(pi, 0x4d7, (0x7 << 12), (1) << 12);
2959
2960
auxpga_vmidcourse = 8;
2961
auxpga_vmidfine = 0x4;
2962
auxpga_gain = 2;
2963
mod_radio_reg(pi, RADIO_2064_REG082, 0x20, 1 << 5);
2964
} else {
2965
mod_phy_reg(pi, 0x4d7, (0x1 << 3), (1) << 3);
2966
2967
mod_phy_reg(pi, 0x4d7, (0x7 << 12), (3) << 12);
2968
2969
auxpga_vmidcourse = 7;
2970
auxpga_vmidfine = 0xa;
2971
auxpga_gain = 2;
2972
}
2973
auxpga_vmid =
2974
(u16) ((2 << 8) | (auxpga_vmidcourse << 4) | auxpga_vmidfine);
2975
mod_phy_reg(pi, 0x4d8, (0x1 << 0), (1) << 0);
2976
2977
mod_phy_reg(pi, 0x4d8, (0x3ff << 2), (auxpga_vmid) << 2);
2978
2979
mod_phy_reg(pi, 0x4d8, (0x1 << 1), (1) << 1);
2980
2981
mod_phy_reg(pi, 0x4d8, (0x7 << 12), (auxpga_gain) << 12);
2982
2983
mod_phy_reg(pi, 0x4d0, (0x1 << 5), (1) << 5);
2984
2985
write_radio_reg(pi, RADIO_2064_REG112, 0x6);
2986
2987
wlc_phy_do_dummy_tx(pi, true, OFF);
2988
if (!tempsense_done(pi))
2989
udelay(10);
2990
2991
write_radio_reg(pi, RADIO_2064_REG007, (u16) save_reg007);
2992
write_radio_reg(pi, RADIO_2064_REG0FF, (u16) save_reg0FF);
2993
write_radio_reg(pi, RADIO_2064_REG11F, (u16) save_reg11F);
2994
write_radio_reg(pi, RADIO_2064_REG005, (u16) save_reg005);
2995
write_radio_reg(pi, RADIO_2064_REG025, (u16) save_reg025);
2996
write_radio_reg(pi, RADIO_2064_REG112, (u16) save_reg112);
2997
for (i = 0; i < 14; i++)
2998
write_phy_reg(pi, tempsense_phy_regs[i], values_to_save[i]);
2999
wlc_lcnphy_set_tx_pwr_by_index(pi, (int)index);
3000
3001
write_radio_reg(pi, 0x4a4, save_txpwrCtrlEn);
3002
if (!suspend)
3003
wlapi_enable_mac(pi->sh->physhim);
3004
udelay(999);
3005
}
3006
3007
static void wlc_lcnphy_tx_pwr_ctrl_init(struct brcms_phy_pub *ppi)
3008
{
3009
struct lcnphy_txgains tx_gains;
3010
u8 bbmult;
3011
struct phytbl_info tab;
3012
s32 a1, b0, b1;
3013
s32 tssi, pwr, mintargetpwr;
3014
bool suspend;
3015
struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
3016
3017
suspend = (0 == (bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) &
3018
MCTL_EN_MAC));
3019
if (!suspend)
3020
wlapi_suspend_mac_and_wait(pi->sh->physhim);
3021
3022
if (!pi->hwpwrctrl_capable) {
3023
if (CHSPEC_IS2G(pi->radio_chanspec)) {
3024
tx_gains.gm_gain = 4;
3025
tx_gains.pga_gain = 12;
3026
tx_gains.pad_gain = 12;
3027
tx_gains.dac_gain = 0;
3028
3029
bbmult = 150;
3030
} else {
3031
tx_gains.gm_gain = 7;
3032
tx_gains.pga_gain = 15;
3033
tx_gains.pad_gain = 14;
3034
tx_gains.dac_gain = 0;
3035
3036
bbmult = 150;
3037
}
3038
wlc_lcnphy_set_tx_gain(pi, &tx_gains);
3039
wlc_lcnphy_set_bbmult(pi, bbmult);
3040
wlc_lcnphy_vbat_temp_sense_setup(pi, TEMPSENSE);
3041
} else {
3042
3043
wlc_lcnphy_idle_tssi_est(ppi);
3044
3045
wlc_lcnphy_clear_tx_power_offsets(pi);
3046
3047
b0 = pi->txpa_2g[0];
3048
b1 = pi->txpa_2g[1];
3049
a1 = pi->txpa_2g[2];
3050
mintargetpwr = wlc_lcnphy_tssi2dbm(125, a1, b0, b1);
3051
3052
tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
3053
tab.tbl_width = 32;
3054
tab.tbl_ptr = &pwr;
3055
tab.tbl_len = 1;
3056
tab.tbl_offset = 0;
3057
for (tssi = 0; tssi < 128; tssi++) {
3058
pwr = wlc_lcnphy_tssi2dbm(tssi, a1, b0, b1);
3059
3060
pwr = (pwr < mintargetpwr) ? mintargetpwr : pwr;
3061
wlc_lcnphy_write_table(pi, &tab);
3062
tab.tbl_offset++;
3063
}
3064
mod_phy_reg(pi, 0x4d0, (0x1 << 0), (0) << 0);
3065
mod_phy_reg(pi, 0x4d3, (0xff << 0), (0) << 0);
3066
mod_phy_reg(pi, 0x4d3, (0xff << 8), (0) << 8);
3067
mod_phy_reg(pi, 0x4d0, (0x1 << 4), (0) << 4);
3068
mod_phy_reg(pi, 0x4d0, (0x1 << 2), (0) << 2);
3069
3070
mod_phy_reg(pi, 0x410, (0x1 << 7), (0) << 7);
3071
3072
write_phy_reg(pi, 0x4a8, 10);
3073
3074
wlc_lcnphy_set_target_tx_pwr(pi, LCN_TARGET_PWR);
3075
3076
wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_HW);
3077
}
3078
if (!suspend)
3079
wlapi_enable_mac(pi->sh->physhim);
3080
}
3081
3082
static void wlc_lcnphy_set_pa_gain(struct brcms_phy *pi, u16 gain)
3083
{
3084
mod_phy_reg(pi, 0x4fb,
3085
LCNPHY_txgainctrlovrval1_pagain_ovr_val1_MASK,
3086
gain << LCNPHY_txgainctrlovrval1_pagain_ovr_val1_SHIFT);
3087
mod_phy_reg(pi, 0x4fd,
3088
LCNPHY_stxtxgainctrlovrval1_pagain_ovr_val1_MASK,
3089
gain << LCNPHY_stxtxgainctrlovrval1_pagain_ovr_val1_SHIFT);
3090
}
3091
3092
void
3093
wlc_lcnphy_get_radio_loft(struct brcms_phy *pi,
3094
u8 *ei0, u8 *eq0, u8 *fi0, u8 *fq0)
3095
{
3096
*ei0 = LCNPHY_IQLOCC_READ(read_radio_reg(pi, RADIO_2064_REG089));
3097
*eq0 = LCNPHY_IQLOCC_READ(read_radio_reg(pi, RADIO_2064_REG08A));
3098
*fi0 = LCNPHY_IQLOCC_READ(read_radio_reg(pi, RADIO_2064_REG08B));
3099
*fq0 = LCNPHY_IQLOCC_READ(read_radio_reg(pi, RADIO_2064_REG08C));
3100
}
3101
3102
void wlc_lcnphy_set_tx_iqcc(struct brcms_phy *pi, u16 a, u16 b)
3103
{
3104
struct phytbl_info tab;
3105
u16 iqcc[2];
3106
3107
iqcc[0] = a;
3108
iqcc[1] = b;
3109
3110
tab.tbl_id = LCNPHY_TBL_ID_IQLOCAL;
3111
tab.tbl_width = 16;
3112
tab.tbl_ptr = iqcc;
3113
tab.tbl_len = 2;
3114
tab.tbl_offset = 80;
3115
wlc_lcnphy_write_table(pi, &tab);
3116
}
3117
3118
void wlc_lcnphy_set_tx_locc(struct brcms_phy *pi, u16 didq)
3119
{
3120
struct phytbl_info tab;
3121
3122
tab.tbl_id = LCNPHY_TBL_ID_IQLOCAL;
3123
tab.tbl_width = 16;
3124
tab.tbl_ptr = &didq;
3125
tab.tbl_len = 1;
3126
tab.tbl_offset = 85;
3127
wlc_lcnphy_write_table(pi, &tab);
3128
}
3129
3130
void wlc_lcnphy_set_tx_pwr_by_index(struct brcms_phy *pi, int index)
3131
{
3132
struct phytbl_info tab;
3133
u16 a, b;
3134
u8 bb_mult;
3135
u32 bbmultiqcomp, txgain, locoeffs, rfpower;
3136
struct lcnphy_txgains gains;
3137
struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
3138
3139
pi_lcn->lcnphy_tx_power_idx_override = (s8) index;
3140
pi_lcn->lcnphy_current_index = (u8) index;
3141
3142
tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
3143
tab.tbl_width = 32;
3144
tab.tbl_len = 1;
3145
3146
wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
3147
3148
tab.tbl_offset = LCNPHY_TX_PWR_CTRL_IQ_OFFSET + index;
3149
tab.tbl_ptr = &bbmultiqcomp;
3150
wlc_lcnphy_read_table(pi, &tab);
3151
3152
tab.tbl_offset = LCNPHY_TX_PWR_CTRL_GAIN_OFFSET + index;
3153
tab.tbl_width = 32;
3154
tab.tbl_ptr = &txgain;
3155
wlc_lcnphy_read_table(pi, &tab);
3156
3157
gains.gm_gain = (u16) (txgain & 0xff);
3158
gains.pga_gain = (u16) (txgain >> 8) & 0xff;
3159
gains.pad_gain = (u16) (txgain >> 16) & 0xff;
3160
gains.dac_gain = (u16) (bbmultiqcomp >> 28) & 0x07;
3161
wlc_lcnphy_set_tx_gain(pi, &gains);
3162
wlc_lcnphy_set_pa_gain(pi, (u16) (txgain >> 24) & 0x7f);
3163
3164
bb_mult = (u8) ((bbmultiqcomp >> 20) & 0xff);
3165
wlc_lcnphy_set_bbmult(pi, bb_mult);
3166
3167
wlc_lcnphy_enable_tx_gain_override(pi);
3168
3169
if (!wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) {
3170
3171
a = (u16) ((bbmultiqcomp >> 10) & 0x3ff);
3172
b = (u16) (bbmultiqcomp & 0x3ff);
3173
wlc_lcnphy_set_tx_iqcc(pi, a, b);
3174
3175
tab.tbl_offset = LCNPHY_TX_PWR_CTRL_LO_OFFSET + index;
3176
tab.tbl_ptr = &locoeffs;
3177
wlc_lcnphy_read_table(pi, &tab);
3178
3179
wlc_lcnphy_set_tx_locc(pi, (u16) locoeffs);
3180
3181
tab.tbl_offset = LCNPHY_TX_PWR_CTRL_PWR_OFFSET + index;
3182
tab.tbl_ptr = &rfpower;
3183
wlc_lcnphy_read_table(pi, &tab);
3184
mod_phy_reg(pi, 0x6a6, (0x1fff << 0), (rfpower * 8) << 0);
3185
3186
}
3187
}
3188
3189
static void wlc_lcnphy_clear_papd_comptable(struct brcms_phy *pi)
3190
{
3191
u32 j;
3192
struct phytbl_info tab;
3193
u32 temp_offset[128];
3194
tab.tbl_ptr = temp_offset;
3195
tab.tbl_len = 128;
3196
tab.tbl_id = LCNPHY_TBL_ID_PAPDCOMPDELTATBL;
3197
tab.tbl_width = 32;
3198
tab.tbl_offset = 0;
3199
3200
memset(temp_offset, 0, sizeof(temp_offset));
3201
for (j = 1; j < 128; j += 2)
3202
temp_offset[j] = 0x80000;
3203
3204
wlc_lcnphy_write_table(pi, &tab);
3205
return;
3206
}
3207
3208
void wlc_lcnphy_tx_pu(struct brcms_phy *pi, bool bEnable)
3209
{
3210
if (!bEnable) {
3211
3212
and_phy_reg(pi, 0x43b, ~(u16) ((0x1 << 1) | (0x1 << 4)));
3213
3214
mod_phy_reg(pi, 0x43c, (0x1 << 1), 1 << 1);
3215
3216
and_phy_reg(pi, 0x44c,
3217
~(u16) ((0x1 << 3) |
3218
(0x1 << 5) |
3219
(0x1 << 12) |
3220
(0x1 << 0) | (0x1 << 1) | (0x1 << 2)));
3221
3222
and_phy_reg(pi, 0x44d,
3223
~(u16) ((0x1 << 3) | (0x1 << 5) | (0x1 << 14)));
3224
mod_phy_reg(pi, 0x44d, (0x1 << 2), 1 << 2);
3225
3226
mod_phy_reg(pi, 0x44d, (0x1 << 1) | (0x1 << 0), (0x1 << 0));
3227
3228
and_phy_reg(pi, 0x4f9,
3229
~(u16) ((0x1 << 0) | (0x1 << 1) | (0x1 << 2)));
3230
3231
and_phy_reg(pi, 0x4fa,
3232
~(u16) ((0x1 << 0) | (0x1 << 1) | (0x1 << 2)));
3233
} else {
3234
3235
mod_phy_reg(pi, 0x43b, (0x1 << 1), 1 << 1);
3236
mod_phy_reg(pi, 0x43c, (0x1 << 1), 0 << 1);
3237
3238
mod_phy_reg(pi, 0x43b, (0x1 << 4), 1 << 4);
3239
mod_phy_reg(pi, 0x43c, (0x1 << 6), 0 << 6);
3240
3241
mod_phy_reg(pi, 0x44c, (0x1 << 12), 1 << 12);
3242
mod_phy_reg(pi, 0x44d, (0x1 << 14), 1 << 14);
3243
3244
wlc_lcnphy_set_trsw_override(pi, true, false);
3245
3246
mod_phy_reg(pi, 0x44d, (0x1 << 2), 0 << 2);
3247
mod_phy_reg(pi, 0x44c, (0x1 << 2), 1 << 2);
3248
3249
if (CHSPEC_IS2G(pi->radio_chanspec)) {
3250
3251
mod_phy_reg(pi, 0x44c, (0x1 << 3), 1 << 3);
3252
mod_phy_reg(pi, 0x44d, (0x1 << 3), 1 << 3);
3253
3254
mod_phy_reg(pi, 0x44c, (0x1 << 5), 1 << 5);
3255
mod_phy_reg(pi, 0x44d, (0x1 << 5), 0 << 5);
3256
3257
mod_phy_reg(pi, 0x4f9, (0x1 << 1), 1 << 1);
3258
mod_phy_reg(pi, 0x4fa, (0x1 << 1), 1 << 1);
3259
3260
mod_phy_reg(pi, 0x4f9, (0x1 << 2), 1 << 2);
3261
mod_phy_reg(pi, 0x4fa, (0x1 << 2), 1 << 2);
3262
3263
mod_phy_reg(pi, 0x4f9, (0x1 << 0), 1 << 0);
3264
mod_phy_reg(pi, 0x4fa, (0x1 << 0), 1 << 0);
3265
} else {
3266
3267
mod_phy_reg(pi, 0x44c, (0x1 << 3), 1 << 3);
3268
mod_phy_reg(pi, 0x44d, (0x1 << 3), 0 << 3);
3269
3270
mod_phy_reg(pi, 0x44c, (0x1 << 5), 1 << 5);
3271
mod_phy_reg(pi, 0x44d, (0x1 << 5), 1 << 5);
3272
3273
mod_phy_reg(pi, 0x4f9, (0x1 << 1), 1 << 1);
3274
mod_phy_reg(pi, 0x4fa, (0x1 << 1), 0 << 1);
3275
3276
mod_phy_reg(pi, 0x4f9, (0x1 << 2), 1 << 2);
3277
mod_phy_reg(pi, 0x4fa, (0x1 << 2), 0 << 2);
3278
3279
mod_phy_reg(pi, 0x4f9, (0x1 << 0), 1 << 0);
3280
mod_phy_reg(pi, 0x4fa, (0x1 << 0), 0 << 0);
3281
}
3282
}
3283
}
3284
3285
static void
3286
wlc_lcnphy_run_samples(struct brcms_phy *pi,
3287
u16 num_samps,
3288
u16 num_loops, u16 wait, bool iqcalmode)
3289
{
3290
3291
or_phy_reg(pi, 0x6da, 0x8080);
3292
3293
mod_phy_reg(pi, 0x642, (0x7f << 0), (num_samps - 1) << 0);
3294
if (num_loops != 0xffff)
3295
num_loops--;
3296
mod_phy_reg(pi, 0x640, (0xffff << 0), num_loops << 0);
3297
3298
mod_phy_reg(pi, 0x641, (0xffff << 0), wait << 0);
3299
3300
if (iqcalmode) {
3301
3302
and_phy_reg(pi, 0x453, 0xffff & ~(0x1 << 15));
3303
or_phy_reg(pi, 0x453, (0x1 << 15));
3304
} else {
3305
write_phy_reg(pi, 0x63f, 1);
3306
wlc_lcnphy_tx_pu(pi, 1);
3307
}
3308
3309
or_radio_reg(pi, RADIO_2064_REG112, 0x6);
3310
}
3311
3312
void wlc_lcnphy_deaf_mode(struct brcms_phy *pi, bool mode)
3313
{
3314
3315
u8 phybw40;
3316
phybw40 = CHSPEC_IS40(pi->radio_chanspec);
3317
3318
mod_phy_reg(pi, 0x4b0, (0x1 << 5), (mode) << 5);
3319
mod_phy_reg(pi, 0x4b1, (0x1 << 9), 0 << 9);
3320
3321
if (phybw40 == 0) {
3322
mod_phy_reg((pi), 0x410,
3323
(0x1 << 6) |
3324
(0x1 << 5),
3325
((CHSPEC_IS2G(
3326
pi->radio_chanspec)) ? (!mode) : 0) <<
3327
6 | (!mode) << 5);
3328
mod_phy_reg(pi, 0x410, (0x1 << 7), (mode) << 7);
3329
}
3330
}
3331
3332
void
3333
wlc_lcnphy_start_tx_tone(struct brcms_phy *pi, s32 f_kHz, u16 max_val,
3334
bool iqcalmode)
3335
{
3336
u8 phy_bw;
3337
u16 num_samps, t, k;
3338
u32 bw;
3339
s32 theta = 0, rot = 0;
3340
struct cordic_iq tone_samp;
3341
u32 data_buf[64];
3342
u16 i_samp, q_samp;
3343
struct phytbl_info tab;
3344
struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
3345
3346
pi->phy_tx_tone_freq = f_kHz;
3347
3348
wlc_lcnphy_deaf_mode(pi, true);
3349
3350
phy_bw = 40;
3351
if (pi_lcn->lcnphy_spurmod) {
3352
write_phy_reg(pi, 0x942, 0x2);
3353
write_phy_reg(pi, 0x93b, 0x0);
3354
write_phy_reg(pi, 0x93c, 0x0);
3355
wlc_lcnphy_txrx_spur_avoidance_mode(pi, false);
3356
}
3357
3358
if (f_kHz) {
3359
k = 1;
3360
do {
3361
bw = phy_bw * 1000 * k;
3362
num_samps = bw / abs(f_kHz);
3363
k++;
3364
} while ((num_samps * (u32) (abs(f_kHz))) != bw);
3365
} else
3366
num_samps = 2;
3367
3368
rot = ((f_kHz * 36) / phy_bw) / 100;
3369
theta = 0;
3370
3371
for (t = 0; t < num_samps; t++) {
3372
3373
tone_samp = cordic_calc_iq(theta);
3374
3375
theta += rot;
3376
3377
i_samp = (u16)(CORDIC_FLOAT(tone_samp.i * max_val) & 0x3ff);
3378
q_samp = (u16)(CORDIC_FLOAT(tone_samp.q * max_val) & 0x3ff);
3379
data_buf[t] = (i_samp << 10) | q_samp;
3380
}
3381
3382
mod_phy_reg(pi, 0x6d6, (0x3 << 0), 0 << 0);
3383
3384
mod_phy_reg(pi, 0x6da, (0x1 << 3), 1 << 3);
3385
3386
tab.tbl_ptr = data_buf;
3387
tab.tbl_len = num_samps;
3388
tab.tbl_id = LCNPHY_TBL_ID_SAMPLEPLAY;
3389
tab.tbl_offset = 0;
3390
tab.tbl_width = 32;
3391
wlc_lcnphy_write_table(pi, &tab);
3392
3393
wlc_lcnphy_run_samples(pi, num_samps, 0xffff, 0, iqcalmode);
3394
}
3395
3396
void wlc_lcnphy_stop_tx_tone(struct brcms_phy *pi)
3397
{
3398
s16 playback_status;
3399
struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
3400
3401
pi->phy_tx_tone_freq = 0;
3402
if (pi_lcn->lcnphy_spurmod) {
3403
write_phy_reg(pi, 0x942, 0x7);
3404
write_phy_reg(pi, 0x93b, 0x2017);
3405
write_phy_reg(pi, 0x93c, 0x27c5);
3406
wlc_lcnphy_txrx_spur_avoidance_mode(pi, true);
3407
}
3408
3409
playback_status = read_phy_reg(pi, 0x644);
3410
if (playback_status & (0x1 << 0)) {
3411
wlc_lcnphy_tx_pu(pi, 0);
3412
mod_phy_reg(pi, 0x63f, (0x1 << 1), 1 << 1);
3413
} else if (playback_status & (0x1 << 1))
3414
mod_phy_reg(pi, 0x453, (0x1 << 15), 0 << 15);
3415
3416
mod_phy_reg(pi, 0x6d6, (0x3 << 0), 1 << 0);
3417
3418
mod_phy_reg(pi, 0x6da, (0x1 << 3), 0 << 3);
3419
3420
mod_phy_reg(pi, 0x6da, (0x1 << 7), 0 << 7);
3421
3422
and_radio_reg(pi, RADIO_2064_REG112, 0xFFF9);
3423
3424
wlc_lcnphy_deaf_mode(pi, false);
3425
}
3426
3427
static void
3428
wlc_lcnphy_set_cc(struct brcms_phy *pi, int cal_type, s16 coeff_x, s16 coeff_y)
3429
{
3430
u16 di0dq0;
3431
u16 x, y, data_rf;
3432
int k;
3433
switch (cal_type) {
3434
case 0:
3435
wlc_lcnphy_set_tx_iqcc(pi, coeff_x, coeff_y);
3436
break;
3437
case 2:
3438
di0dq0 = (coeff_x & 0xff) << 8 | (coeff_y & 0xff);
3439
wlc_lcnphy_set_tx_locc(pi, di0dq0);
3440
break;
3441
case 3:
3442
k = wlc_lcnphy_calc_floor(coeff_x, 0);
3443
y = 8 + k;
3444
k = wlc_lcnphy_calc_floor(coeff_x, 1);
3445
x = 8 - k;
3446
data_rf = (x * 16 + y);
3447
write_radio_reg(pi, RADIO_2064_REG089, data_rf);
3448
k = wlc_lcnphy_calc_floor(coeff_y, 0);
3449
y = 8 + k;
3450
k = wlc_lcnphy_calc_floor(coeff_y, 1);
3451
x = 8 - k;
3452
data_rf = (x * 16 + y);
3453
write_radio_reg(pi, RADIO_2064_REG08A, data_rf);
3454
break;
3455
case 4:
3456
k = wlc_lcnphy_calc_floor(coeff_x, 0);
3457
y = 8 + k;
3458
k = wlc_lcnphy_calc_floor(coeff_x, 1);
3459
x = 8 - k;
3460
data_rf = (x * 16 + y);
3461
write_radio_reg(pi, RADIO_2064_REG08B, data_rf);
3462
k = wlc_lcnphy_calc_floor(coeff_y, 0);
3463
y = 8 + k;
3464
k = wlc_lcnphy_calc_floor(coeff_y, 1);
3465
x = 8 - k;
3466
data_rf = (x * 16 + y);
3467
write_radio_reg(pi, RADIO_2064_REG08C, data_rf);
3468
break;
3469
}
3470
}
3471
3472
static struct lcnphy_unsign16_struct
3473
wlc_lcnphy_get_cc(struct brcms_phy *pi, int cal_type)
3474
{
3475
u16 a, b, didq;
3476
u8 di0, dq0, ei, eq, fi, fq;
3477
struct lcnphy_unsign16_struct cc;
3478
cc.re = 0;
3479
cc.im = 0;
3480
switch (cal_type) {
3481
case 0:
3482
wlc_lcnphy_get_tx_iqcc(pi, &a, &b);
3483
cc.re = a;
3484
cc.im = b;
3485
break;
3486
case 2:
3487
didq = wlc_lcnphy_get_tx_locc(pi);
3488
di0 = (((didq & 0xff00) << 16) >> 24);
3489
dq0 = (((didq & 0x00ff) << 24) >> 24);
3490
cc.re = (u16) di0;
3491
cc.im = (u16) dq0;
3492
break;
3493
case 3:
3494
wlc_lcnphy_get_radio_loft(pi, &ei, &eq, &fi, &fq);
3495
cc.re = (u16) ei;
3496
cc.im = (u16) eq;
3497
break;
3498
case 4:
3499
wlc_lcnphy_get_radio_loft(pi, &ei, &eq, &fi, &fq);
3500
cc.re = (u16) fi;
3501
cc.im = (u16) fq;
3502
break;
3503
}
3504
return cc;
3505
}
3506
3507
static void
3508
wlc_lcnphy_samp_cap(struct brcms_phy *pi, int clip_detect_algo, u16 thresh,
3509
s16 *ptr, int mode)
3510
{
3511
u32 curval1, curval2, stpptr, curptr, strptr, val;
3512
u16 sslpnCalibClkEnCtrl, timer;
3513
u16 old_sslpnCalibClkEnCtrl;
3514
s16 imag, real;
3515
struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
3516
3517
timer = 0;
3518
old_sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da);
3519
3520
curval1 = bcma_read16(pi->d11core, D11REGOFFS(psm_corectlsts));
3521
ptr[130] = 0;
3522
bcma_write16(pi->d11core, D11REGOFFS(psm_corectlsts),
3523
((1 << 6) | curval1));
3524
3525
bcma_write16(pi->d11core, D11REGOFFS(smpl_clct_strptr), 0x7E00);
3526
bcma_write16(pi->d11core, D11REGOFFS(smpl_clct_stpptr), 0x8000);
3527
udelay(20);
3528
curval2 = bcma_read16(pi->d11core, D11REGOFFS(psm_phy_hdr_param));
3529
bcma_write16(pi->d11core, D11REGOFFS(psm_phy_hdr_param),
3530
curval2 | 0x30);
3531
3532
write_phy_reg(pi, 0x555, 0x0);
3533
write_phy_reg(pi, 0x5a6, 0x5);
3534
3535
write_phy_reg(pi, 0x5a2, (u16) (mode | mode << 6));
3536
write_phy_reg(pi, 0x5cf, 3);
3537
write_phy_reg(pi, 0x5a5, 0x3);
3538
write_phy_reg(pi, 0x583, 0x0);
3539
write_phy_reg(pi, 0x584, 0x0);
3540
write_phy_reg(pi, 0x585, 0x0fff);
3541
write_phy_reg(pi, 0x586, 0x0000);
3542
3543
write_phy_reg(pi, 0x580, 0x4501);
3544
3545
sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da);
3546
write_phy_reg(pi, 0x6da, (u32) (sslpnCalibClkEnCtrl | 0x2008));
3547
stpptr = bcma_read16(pi->d11core, D11REGOFFS(smpl_clct_stpptr));
3548
curptr = bcma_read16(pi->d11core, D11REGOFFS(smpl_clct_curptr));
3549
do {
3550
udelay(10);
3551
curptr = bcma_read16(pi->d11core, D11REGOFFS(smpl_clct_curptr));
3552
timer++;
3553
} while ((curptr != stpptr) && (timer < 500));
3554
3555
bcma_write16(pi->d11core, D11REGOFFS(psm_phy_hdr_param), 0x2);
3556
strptr = 0x7E00;
3557
bcma_write32(pi->d11core, D11REGOFFS(tplatewrptr), strptr);
3558
while (strptr < 0x8000) {
3559
val = bcma_read32(pi->d11core, D11REGOFFS(tplatewrdata));
3560
imag = ((val >> 16) & 0x3ff);
3561
real = ((val) & 0x3ff);
3562
if (imag > 511)
3563
imag -= 1024;
3564
3565
if (real > 511)
3566
real -= 1024;
3567
3568
if (pi_lcn->lcnphy_iqcal_swp_dis)
3569
ptr[(strptr - 0x7E00) / 4] = real;
3570
else
3571
ptr[(strptr - 0x7E00) / 4] = imag;
3572
3573
if (clip_detect_algo) {
3574
if (imag > thresh || imag < -thresh) {
3575
strptr = 0x8000;
3576
ptr[130] = 1;
3577
}
3578
}
3579
3580
strptr += 4;
3581
}
3582
3583
write_phy_reg(pi, 0x6da, old_sslpnCalibClkEnCtrl);
3584
bcma_write16(pi->d11core, D11REGOFFS(psm_phy_hdr_param), curval2);
3585
bcma_write16(pi->d11core, D11REGOFFS(psm_corectlsts), curval1);
3586
}
3587
3588
static void
3589
wlc_lcnphy_a1(struct brcms_phy *pi, int cal_type, int num_levels,
3590
int step_size_lg2)
3591
{
3592
const struct lcnphy_spb_tone *phy_c1;
3593
struct lcnphy_spb_tone phy_c2;
3594
struct lcnphy_unsign16_struct phy_c3;
3595
int phy_c4, phy_c5, k, l, j, phy_c6;
3596
u16 phy_c7, phy_c8, phy_c9;
3597
s16 phy_c10, phy_c11, phy_c12, phy_c13, phy_c14, phy_c15, phy_c16;
3598
s16 *ptr, phy_c17;
3599
s32 phy_c18, phy_c19;
3600
u32 phy_c20, phy_c21;
3601
bool phy_c22, phy_c23, phy_c24, phy_c25;
3602
u16 phy_c26, phy_c27;
3603
u16 phy_c28, phy_c29, phy_c30;
3604
u16 phy_c31;
3605
u16 *phy_c32;
3606
phy_c21 = 0;
3607
phy_c10 = phy_c13 = phy_c14 = phy_c8 = 0;
3608
ptr = kmalloc_array(131, sizeof(s16), GFP_ATOMIC);
3609
if (NULL == ptr)
3610
return;
3611
3612
phy_c32 = kmalloc_array(20, sizeof(u16), GFP_ATOMIC);
3613
if (NULL == phy_c32) {
3614
kfree(ptr);
3615
return;
3616
}
3617
phy_c26 = read_phy_reg(pi, 0x6da);
3618
phy_c27 = read_phy_reg(pi, 0x6db);
3619
phy_c31 = read_radio_reg(pi, RADIO_2064_REG026);
3620
write_phy_reg(pi, 0x93d, 0xC0);
3621
3622
wlc_lcnphy_start_tx_tone(pi, 3750, 88, 0);
3623
write_phy_reg(pi, 0x6da, 0xffff);
3624
or_phy_reg(pi, 0x6db, 0x3);
3625
3626
wlc_lcnphy_tx_iqlo_loopback(pi, phy_c32);
3627
udelay(500);
3628
phy_c28 = read_phy_reg(pi, 0x938);
3629
phy_c29 = read_phy_reg(pi, 0x4d7);
3630
phy_c30 = read_phy_reg(pi, 0x4d8);
3631
or_phy_reg(pi, 0x938, 0x1 << 2);
3632
or_phy_reg(pi, 0x4d7, 0x1 << 2);
3633
or_phy_reg(pi, 0x4d7, 0x1 << 3);
3634
mod_phy_reg(pi, 0x4d7, (0x7 << 12), 0x2 << 12);
3635
or_phy_reg(pi, 0x4d8, 1 << 0);
3636
or_phy_reg(pi, 0x4d8, 1 << 1);
3637
mod_phy_reg(pi, 0x4d8, (0x3ff << 2), 0x23A << 2);
3638
mod_phy_reg(pi, 0x4d8, (0x7 << 12), 0x7 << 12);
3639
phy_c1 = &lcnphy_spb_tone_3750[0];
3640
phy_c4 = 32;
3641
3642
if (num_levels == 0) {
3643
if (cal_type != 0)
3644
num_levels = 4;
3645
else
3646
num_levels = 9;
3647
}
3648
if (step_size_lg2 == 0) {
3649
if (cal_type != 0)
3650
step_size_lg2 = 3;
3651
else
3652
step_size_lg2 = 8;
3653
}
3654
3655
phy_c7 = (1 << step_size_lg2);
3656
phy_c3 = wlc_lcnphy_get_cc(pi, cal_type);
3657
phy_c15 = (s16) phy_c3.re;
3658
phy_c16 = (s16) phy_c3.im;
3659
if (cal_type == 2) {
3660
if (phy_c3.re > 127)
3661
phy_c15 = phy_c3.re - 256;
3662
if (phy_c3.im > 127)
3663
phy_c16 = phy_c3.im - 256;
3664
}
3665
wlc_lcnphy_set_cc(pi, cal_type, phy_c15, phy_c16);
3666
udelay(20);
3667
for (phy_c8 = 0; phy_c7 != 0 && phy_c8 < num_levels; phy_c8++) {
3668
phy_c23 = true;
3669
phy_c22 = false;
3670
switch (cal_type) {
3671
case 0:
3672
phy_c10 = 511;
3673
break;
3674
case 2:
3675
phy_c10 = 127;
3676
break;
3677
case 3:
3678
phy_c10 = 15;
3679
break;
3680
case 4:
3681
phy_c10 = 15;
3682
break;
3683
}
3684
3685
phy_c9 = read_phy_reg(pi, 0x93d);
3686
phy_c9 = 2 * phy_c9;
3687
phy_c24 = false;
3688
phy_c5 = 7;
3689
phy_c25 = true;
3690
while (1) {
3691
write_radio_reg(pi, RADIO_2064_REG026,
3692
(phy_c5 & 0x7) | ((phy_c5 & 0x7) << 4));
3693
udelay(50);
3694
phy_c22 = false;
3695
ptr[130] = 0;
3696
wlc_lcnphy_samp_cap(pi, 1, phy_c9, &ptr[0], 2);
3697
if (ptr[130] == 1)
3698
phy_c22 = true;
3699
if (phy_c22)
3700
phy_c5 -= 1;
3701
if ((phy_c22 != phy_c24) && (!phy_c25))
3702
break;
3703
if (!phy_c22)
3704
phy_c5 += 1;
3705
if (phy_c5 <= 0 || phy_c5 >= 7)
3706
break;
3707
phy_c24 = phy_c22;
3708
phy_c25 = false;
3709
}
3710
3711
if (phy_c5 < 0)
3712
phy_c5 = 0;
3713
else if (phy_c5 > 7)
3714
phy_c5 = 7;
3715
3716
for (k = -phy_c7; k <= phy_c7; k += phy_c7) {
3717
for (l = -phy_c7; l <= phy_c7; l += phy_c7) {
3718
phy_c11 = phy_c15 + k;
3719
phy_c12 = phy_c16 + l;
3720
3721
if (phy_c11 < -phy_c10)
3722
phy_c11 = -phy_c10;
3723
else if (phy_c11 > phy_c10)
3724
phy_c11 = phy_c10;
3725
if (phy_c12 < -phy_c10)
3726
phy_c12 = -phy_c10;
3727
else if (phy_c12 > phy_c10)
3728
phy_c12 = phy_c10;
3729
wlc_lcnphy_set_cc(pi, cal_type, phy_c11,
3730
phy_c12);
3731
udelay(20);
3732
wlc_lcnphy_samp_cap(pi, 0, 0, ptr, 2);
3733
3734
phy_c18 = 0;
3735
phy_c19 = 0;
3736
for (j = 0; j < 128; j++) {
3737
if (cal_type != 0)
3738
phy_c6 = j % phy_c4;
3739
else
3740
phy_c6 = (2 * j) % phy_c4;
3741
3742
phy_c2.re = phy_c1[phy_c6].re;
3743
phy_c2.im = phy_c1[phy_c6].im;
3744
phy_c17 = ptr[j];
3745
phy_c18 = phy_c18 + phy_c17 * phy_c2.re;
3746
phy_c19 = phy_c19 + phy_c17 * phy_c2.im;
3747
}
3748
3749
phy_c18 = phy_c18 >> 10;
3750
phy_c19 = phy_c19 >> 10;
3751
phy_c20 = ((phy_c18 * phy_c18) +
3752
(phy_c19 * phy_c19));
3753
3754
if (phy_c23 || phy_c20 < phy_c21) {
3755
phy_c21 = phy_c20;
3756
phy_c13 = phy_c11;
3757
phy_c14 = phy_c12;
3758
}
3759
phy_c23 = false;
3760
}
3761
}
3762
phy_c23 = true;
3763
phy_c15 = phy_c13;
3764
phy_c16 = phy_c14;
3765
phy_c7 = phy_c7 >> 1;
3766
wlc_lcnphy_set_cc(pi, cal_type, phy_c15, phy_c16);
3767
udelay(20);
3768
}
3769
goto cleanup;
3770
cleanup:
3771
wlc_lcnphy_tx_iqlo_loopback_cleanup(pi, phy_c32);
3772
wlc_lcnphy_stop_tx_tone(pi);
3773
write_phy_reg(pi, 0x6da, phy_c26);
3774
write_phy_reg(pi, 0x6db, phy_c27);
3775
write_phy_reg(pi, 0x938, phy_c28);
3776
write_phy_reg(pi, 0x4d7, phy_c29);
3777
write_phy_reg(pi, 0x4d8, phy_c30);
3778
write_radio_reg(pi, RADIO_2064_REG026, phy_c31);
3779
3780
kfree(phy_c32);
3781
kfree(ptr);
3782
}
3783
3784
void wlc_lcnphy_get_tx_iqcc(struct brcms_phy *pi, u16 *a, u16 *b)
3785
{
3786
u16 iqcc[2];
3787
struct phytbl_info tab;
3788
3789
tab.tbl_ptr = iqcc;
3790
tab.tbl_len = 2;
3791
tab.tbl_id = 0;
3792
tab.tbl_offset = 80;
3793
tab.tbl_width = 16;
3794
wlc_lcnphy_read_table(pi, &tab);
3795
3796
*a = iqcc[0];
3797
*b = iqcc[1];
3798
}
3799
3800
static void wlc_lcnphy_tx_iqlo_soft_cal_full(struct brcms_phy *pi)
3801
{
3802
wlc_lcnphy_set_cc(pi, 0, 0, 0);
3803
wlc_lcnphy_set_cc(pi, 2, 0, 0);
3804
wlc_lcnphy_set_cc(pi, 3, 0, 0);
3805
wlc_lcnphy_set_cc(pi, 4, 0, 0);
3806
3807
wlc_lcnphy_a1(pi, 4, 0, 0);
3808
wlc_lcnphy_a1(pi, 3, 0, 0);
3809
wlc_lcnphy_a1(pi, 2, 3, 2);
3810
wlc_lcnphy_a1(pi, 0, 5, 8);
3811
wlc_lcnphy_a1(pi, 2, 2, 1);
3812
wlc_lcnphy_a1(pi, 0, 4, 3);
3813
3814
wlc_lcnphy_get_cc(pi, 0);
3815
wlc_lcnphy_get_cc(pi, 2);
3816
wlc_lcnphy_get_cc(pi, 3);
3817
wlc_lcnphy_get_cc(pi, 4);
3818
}
3819
3820
u16 wlc_lcnphy_get_tx_locc(struct brcms_phy *pi)
3821
{
3822
struct phytbl_info tab;
3823
u16 didq;
3824
3825
tab.tbl_id = 0;
3826
tab.tbl_width = 16;
3827
tab.tbl_ptr = &didq;
3828
tab.tbl_len = 1;
3829
tab.tbl_offset = 85;
3830
wlc_lcnphy_read_table(pi, &tab);
3831
3832
return didq;
3833
}
3834
3835
static void wlc_lcnphy_txpwrtbl_iqlo_cal(struct brcms_phy *pi)
3836
{
3837
3838
struct lcnphy_txgains target_gains, old_gains;
3839
u8 save_bb_mult;
3840
u16 a, b, didq, save_pa_gain = 0;
3841
uint idx, SAVE_txpwrindex = 0xFF;
3842
u32 val;
3843
u16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
3844
struct phytbl_info tab;
3845
u8 ei0, eq0, fi0, fq0;
3846
struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
3847
3848
wlc_lcnphy_get_tx_gain(pi, &old_gains);
3849
save_pa_gain = wlc_lcnphy_get_pa_gain(pi);
3850
3851
save_bb_mult = wlc_lcnphy_get_bbmult(pi);
3852
3853
if (SAVE_txpwrctrl == LCNPHY_TX_PWR_CTRL_OFF)
3854
SAVE_txpwrindex = wlc_lcnphy_get_current_tx_pwr_idx(pi);
3855
3856
wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
3857
3858
target_gains.gm_gain = 7;
3859
target_gains.pga_gain = 0;
3860
target_gains.pad_gain = 21;
3861
target_gains.dac_gain = 0;
3862
wlc_lcnphy_set_tx_gain(pi, &target_gains);
3863
3864
if (LCNREV_IS(pi->pubpi.phy_rev, 1) || pi_lcn->lcnphy_hw_iqcal_en) {
3865
3866
wlc_lcnphy_set_tx_pwr_by_index(pi, 30);
3867
3868
wlc_lcnphy_tx_iqlo_cal(pi, &target_gains,
3869
(pi_lcn->
3870
lcnphy_recal ? LCNPHY_CAL_RECAL :
3871
LCNPHY_CAL_FULL), false);
3872
} else {
3873
wlc_lcnphy_set_tx_pwr_by_index(pi, 16);
3874
wlc_lcnphy_tx_iqlo_soft_cal_full(pi);
3875
}
3876
3877
wlc_lcnphy_get_radio_loft(pi, &ei0, &eq0, &fi0, &fq0);
3878
if ((abs((s8) fi0) == 15) && (abs((s8) fq0) == 15)) {
3879
if (CHSPEC_IS5G(pi->radio_chanspec)) {
3880
target_gains.gm_gain = 255;
3881
target_gains.pga_gain = 255;
3882
target_gains.pad_gain = 0xf0;
3883
target_gains.dac_gain = 0;
3884
} else {
3885
target_gains.gm_gain = 7;
3886
target_gains.pga_gain = 45;
3887
target_gains.pad_gain = 186;
3888
target_gains.dac_gain = 0;
3889
}
3890
3891
if (LCNREV_IS(pi->pubpi.phy_rev, 1)
3892
|| pi_lcn->lcnphy_hw_iqcal_en) {
3893
3894
target_gains.pga_gain = 0;
3895
target_gains.pad_gain = 30;
3896
wlc_lcnphy_set_tx_pwr_by_index(pi, 16);
3897
wlc_lcnphy_tx_iqlo_cal(pi, &target_gains,
3898
LCNPHY_CAL_FULL, false);
3899
} else {
3900
wlc_lcnphy_tx_iqlo_soft_cal_full(pi);
3901
}
3902
}
3903
3904
wlc_lcnphy_get_tx_iqcc(pi, &a, &b);
3905
3906
didq = wlc_lcnphy_get_tx_locc(pi);
3907
3908
tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
3909
tab.tbl_width = 32;
3910
tab.tbl_ptr = &val;
3911
3912
tab.tbl_len = 1;
3913
tab.tbl_offset = LCNPHY_TX_PWR_CTRL_RATE_OFFSET;
3914
3915
for (idx = 0; idx < 128; idx++) {
3916
tab.tbl_offset = LCNPHY_TX_PWR_CTRL_IQ_OFFSET + idx;
3917
3918
wlc_lcnphy_read_table(pi, &tab);
3919
val = (val & 0xfff00000) |
3920
((u32) (a & 0x3FF) << 10) | (b & 0x3ff);
3921
wlc_lcnphy_write_table(pi, &tab);
3922
3923
val = didq;
3924
tab.tbl_offset = LCNPHY_TX_PWR_CTRL_LO_OFFSET + idx;
3925
wlc_lcnphy_write_table(pi, &tab);
3926
}
3927
3928
pi_lcn->lcnphy_cal_results.txiqlocal_a = a;
3929
pi_lcn->lcnphy_cal_results.txiqlocal_b = b;
3930
pi_lcn->lcnphy_cal_results.txiqlocal_didq = didq;
3931
pi_lcn->lcnphy_cal_results.txiqlocal_ei0 = ei0;
3932
pi_lcn->lcnphy_cal_results.txiqlocal_eq0 = eq0;
3933
pi_lcn->lcnphy_cal_results.txiqlocal_fi0 = fi0;
3934
pi_lcn->lcnphy_cal_results.txiqlocal_fq0 = fq0;
3935
3936
wlc_lcnphy_set_bbmult(pi, save_bb_mult);
3937
wlc_lcnphy_set_pa_gain(pi, save_pa_gain);
3938
wlc_lcnphy_set_tx_gain(pi, &old_gains);
3939
3940
if (SAVE_txpwrctrl != LCNPHY_TX_PWR_CTRL_OFF)
3941
wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_txpwrctrl);
3942
else
3943
wlc_lcnphy_set_tx_pwr_by_index(pi, SAVE_txpwrindex);
3944
}
3945
3946
s16 wlc_lcnphy_tempsense_new(struct brcms_phy *pi, bool mode)
3947
{
3948
u16 tempsenseval1, tempsenseval2;
3949
s16 avg = 0;
3950
bool suspend = false;
3951
3952
if (mode == 1) {
3953
suspend = (0 == (bcma_read32(pi->d11core,
3954
D11REGOFFS(maccontrol)) &
3955
MCTL_EN_MAC));
3956
if (!suspend)
3957
wlapi_suspend_mac_and_wait(pi->sh->physhim);
3958
wlc_lcnphy_vbat_temp_sense_setup(pi, TEMPSENSE);
3959
}
3960
tempsenseval1 = read_phy_reg(pi, 0x476) & 0x1FF;
3961
tempsenseval2 = read_phy_reg(pi, 0x477) & 0x1FF;
3962
3963
if (tempsenseval1 > 255)
3964
avg = (s16) (tempsenseval1 - 512);
3965
else
3966
avg = (s16) tempsenseval1;
3967
3968
if (tempsenseval2 > 255)
3969
avg += (s16) (tempsenseval2 - 512);
3970
else
3971
avg += (s16) tempsenseval2;
3972
3973
avg /= 2;
3974
3975
if (mode == 1) {
3976
3977
mod_phy_reg(pi, 0x448, (0x1 << 14), (1) << 14);
3978
3979
udelay(100);
3980
mod_phy_reg(pi, 0x448, (0x1 << 14), (0) << 14);
3981
3982
if (!suspend)
3983
wlapi_enable_mac(pi->sh->physhim);
3984
}
3985
return avg;
3986
}
3987
3988
u16 wlc_lcnphy_tempsense(struct brcms_phy *pi, bool mode)
3989
{
3990
u16 tempsenseval1, tempsenseval2;
3991
s32 avg = 0;
3992
bool suspend = false;
3993
u16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
3994
struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
3995
3996
if (mode == 1) {
3997
suspend = (0 == (bcma_read32(pi->d11core,
3998
D11REGOFFS(maccontrol)) &
3999
MCTL_EN_MAC));
4000
if (!suspend)
4001
wlapi_suspend_mac_and_wait(pi->sh->physhim);
4002
wlc_lcnphy_vbat_temp_sense_setup(pi, TEMPSENSE);
4003
}
4004
tempsenseval1 = read_phy_reg(pi, 0x476) & 0x1FF;
4005
tempsenseval2 = read_phy_reg(pi, 0x477) & 0x1FF;
4006
4007
if (tempsenseval1 > 255)
4008
avg = (int)(tempsenseval1 - 512);
4009
else
4010
avg = (int)tempsenseval1;
4011
4012
if (pi_lcn->lcnphy_tempsense_option == 1 || pi->hwpwrctrl_capable) {
4013
if (tempsenseval2 > 255)
4014
avg = (int)(avg - tempsenseval2 + 512);
4015
else
4016
avg = (int)(avg - tempsenseval2);
4017
} else {
4018
if (tempsenseval2 > 255)
4019
avg = (int)(avg + tempsenseval2 - 512);
4020
else
4021
avg = (int)(avg + tempsenseval2);
4022
avg = avg / 2;
4023
}
4024
if (avg < 0)
4025
avg = avg + 512;
4026
4027
if (pi_lcn->lcnphy_tempsense_option == 2)
4028
avg = tempsenseval1;
4029
4030
if (mode)
4031
wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_txpwrctrl);
4032
4033
if (mode == 1) {
4034
4035
mod_phy_reg(pi, 0x448, (0x1 << 14), (1) << 14);
4036
4037
udelay(100);
4038
mod_phy_reg(pi, 0x448, (0x1 << 14), (0) << 14);
4039
4040
if (!suspend)
4041
wlapi_enable_mac(pi->sh->physhim);
4042
}
4043
return (u16) avg;
4044
}
4045
4046
s8 wlc_lcnphy_tempsense_degree(struct brcms_phy *pi, bool mode)
4047
{
4048
s32 degree = wlc_lcnphy_tempsense_new(pi, mode);
4049
degree =
4050
((degree <<
4051
10) + LCN_TEMPSENSE_OFFSET + (LCN_TEMPSENSE_DEN >> 1))
4052
/ LCN_TEMPSENSE_DEN;
4053
return (s8) degree;
4054
}
4055
4056
s8 wlc_lcnphy_vbatsense(struct brcms_phy *pi, bool mode)
4057
{
4058
u16 vbatsenseval;
4059
s32 avg = 0;
4060
bool suspend = false;
4061
4062
if (mode == 1) {
4063
suspend = (0 == (bcma_read32(pi->d11core,
4064
D11REGOFFS(maccontrol)) &
4065
MCTL_EN_MAC));
4066
if (!suspend)
4067
wlapi_suspend_mac_and_wait(pi->sh->physhim);
4068
wlc_lcnphy_vbat_temp_sense_setup(pi, VBATSENSE);
4069
}
4070
4071
vbatsenseval = read_phy_reg(pi, 0x475) & 0x1FF;
4072
4073
if (vbatsenseval > 255)
4074
avg = (s32) (vbatsenseval - 512);
4075
else
4076
avg = (s32) vbatsenseval;
4077
4078
avg = (avg * LCN_VBAT_SCALE_NOM +
4079
(LCN_VBAT_SCALE_DEN >> 1)) / LCN_VBAT_SCALE_DEN;
4080
4081
if (mode == 1) {
4082
if (!suspend)
4083
wlapi_enable_mac(pi->sh->physhim);
4084
}
4085
return (s8) avg;
4086
}
4087
4088
static void wlc_lcnphy_afe_clk_init(struct brcms_phy *pi, u8 mode)
4089
{
4090
u8 phybw40;
4091
phybw40 = CHSPEC_IS40(pi->radio_chanspec);
4092
4093
mod_phy_reg(pi, 0x6d1, (0x1 << 7), (1) << 7);
4094
4095
if (((mode == AFE_CLK_INIT_MODE_PAPD) && (phybw40 == 0)) ||
4096
(mode == AFE_CLK_INIT_MODE_TXRX2X))
4097
write_phy_reg(pi, 0x6d0, 0x7);
4098
4099
wlc_lcnphy_toggle_afe_pwdn(pi);
4100
}
4101
4102
static void wlc_lcnphy_temp_adj(struct brcms_phy *pi)
4103
{
4104
}
4105
4106
static void wlc_lcnphy_glacial_timer_based_cal(struct brcms_phy *pi)
4107
{
4108
bool suspend;
4109
s8 index;
4110
u16 SAVE_pwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
4111
struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4112
suspend = (0 == (bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) &
4113
MCTL_EN_MAC));
4114
if (!suspend)
4115
wlapi_suspend_mac_and_wait(pi->sh->physhim);
4116
wlc_lcnphy_deaf_mode(pi, true);
4117
pi->phy_lastcal = pi->sh->now;
4118
pi->phy_forcecal = false;
4119
index = pi_lcn->lcnphy_current_index;
4120
4121
wlc_lcnphy_txpwrtbl_iqlo_cal(pi);
4122
4123
wlc_lcnphy_set_tx_pwr_by_index(pi, index);
4124
wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_pwrctrl);
4125
wlc_lcnphy_deaf_mode(pi, false);
4126
if (!suspend)
4127
wlapi_enable_mac(pi->sh->physhim);
4128
4129
}
4130
4131
static void wlc_lcnphy_periodic_cal(struct brcms_phy *pi)
4132
{
4133
bool suspend;
4134
u16 SAVE_pwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
4135
s8 index;
4136
struct phytbl_info tab;
4137
s32 a1, b0, b1;
4138
s32 tssi, pwr, mintargetpwr;
4139
struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4140
4141
pi->phy_lastcal = pi->sh->now;
4142
pi->phy_forcecal = false;
4143
pi_lcn->lcnphy_full_cal_channel = CHSPEC_CHANNEL(pi->radio_chanspec);
4144
index = pi_lcn->lcnphy_current_index;
4145
4146
suspend = (0 == (bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) &
4147
MCTL_EN_MAC));
4148
if (!suspend) {
4149
wlapi_bmac_write_shm(pi->sh->physhim, M_CTS_DURATION, 10000);
4150
wlapi_suspend_mac_and_wait(pi->sh->physhim);
4151
}
4152
4153
wlc_lcnphy_deaf_mode(pi, true);
4154
4155
wlc_lcnphy_txpwrtbl_iqlo_cal(pi);
4156
4157
if (LCNREV_IS(pi->pubpi.phy_rev, 1))
4158
wlc_lcnphy_rx_iq_cal(pi, NULL, 0, true, false, 1, 40);
4159
else
4160
wlc_lcnphy_rx_iq_cal(pi, NULL, 0, true, false, 1, 127);
4161
4162
if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi)) {
4163
4164
wlc_lcnphy_idle_tssi_est((struct brcms_phy_pub *) pi);
4165
4166
b0 = pi->txpa_2g[0];
4167
b1 = pi->txpa_2g[1];
4168
a1 = pi->txpa_2g[2];
4169
mintargetpwr = wlc_lcnphy_tssi2dbm(125, a1, b0, b1);
4170
4171
tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
4172
tab.tbl_width = 32;
4173
tab.tbl_ptr = &pwr;
4174
tab.tbl_len = 1;
4175
tab.tbl_offset = 0;
4176
for (tssi = 0; tssi < 128; tssi++) {
4177
pwr = wlc_lcnphy_tssi2dbm(tssi, a1, b0, b1);
4178
pwr = (pwr < mintargetpwr) ? mintargetpwr : pwr;
4179
wlc_lcnphy_write_table(pi, &tab);
4180
tab.tbl_offset++;
4181
}
4182
}
4183
4184
wlc_lcnphy_set_tx_pwr_by_index(pi, index);
4185
wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_pwrctrl);
4186
wlc_lcnphy_deaf_mode(pi, false);
4187
if (!suspend)
4188
wlapi_enable_mac(pi->sh->physhim);
4189
}
4190
4191
void wlc_lcnphy_calib_modes(struct brcms_phy *pi, uint mode)
4192
{
4193
u16 temp_new;
4194
int temp1, temp2, temp_diff;
4195
struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4196
4197
switch (mode) {
4198
case PHY_PERICAL_CHAN:
4199
break;
4200
case PHY_FULLCAL:
4201
wlc_lcnphy_periodic_cal(pi);
4202
break;
4203
case PHY_PERICAL_PHYINIT:
4204
wlc_lcnphy_periodic_cal(pi);
4205
break;
4206
case PHY_PERICAL_WATCHDOG:
4207
if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) {
4208
temp_new = wlc_lcnphy_tempsense(pi, 0);
4209
temp1 = LCNPHY_TEMPSENSE(temp_new);
4210
temp2 = LCNPHY_TEMPSENSE(pi_lcn->lcnphy_cal_temper);
4211
temp_diff = temp1 - temp2;
4212
if ((pi_lcn->lcnphy_cal_counter > 90) ||
4213
(temp_diff > 60) || (temp_diff < -60)) {
4214
wlc_lcnphy_glacial_timer_based_cal(pi);
4215
wlc_2064_vco_cal(pi);
4216
pi_lcn->lcnphy_cal_temper = temp_new;
4217
pi_lcn->lcnphy_cal_counter = 0;
4218
} else
4219
pi_lcn->lcnphy_cal_counter++;
4220
}
4221
break;
4222
case LCNPHY_PERICAL_TEMPBASED_TXPWRCTRL:
4223
if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
4224
wlc_lcnphy_tx_power_adjustment(
4225
(struct brcms_phy_pub *) pi);
4226
break;
4227
}
4228
}
4229
4230
void wlc_lcnphy_get_tssi(struct brcms_phy *pi, s8 *ofdm_pwr, s8 *cck_pwr)
4231
{
4232
s8 cck_offset;
4233
u16 status;
4234
status = (read_phy_reg(pi, 0x4ab));
4235
if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi) &&
4236
(status & (0x1 << 15))) {
4237
*ofdm_pwr = (s8) (((read_phy_reg(pi, 0x4ab) & (0x1ff << 0))
4238
>> 0) >> 1);
4239
4240
if (wlc_phy_tpc_isenabled_lcnphy(pi))
4241
cck_offset = pi->tx_power_offset[TXP_FIRST_CCK];
4242
else
4243
cck_offset = 0;
4244
4245
*cck_pwr = *ofdm_pwr + cck_offset;
4246
} else {
4247
*cck_pwr = 0;
4248
*ofdm_pwr = 0;
4249
}
4250
}
4251
4252
void wlc_phy_cal_init_lcnphy(struct brcms_phy *pi)
4253
{
4254
return;
4255
4256
}
4257
4258
void wlc_lcnphy_tx_power_adjustment(struct brcms_phy_pub *ppi)
4259
{
4260
s8 index;
4261
u16 index2;
4262
struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
4263
struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4264
u16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
4265
if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi) &&
4266
SAVE_txpwrctrl) {
4267
index = wlc_lcnphy_tempcompensated_txpwrctrl(pi);
4268
index2 = (u16) (index * 2);
4269
mod_phy_reg(pi, 0x4a9, (0x1ff << 0), (index2) << 0);
4270
4271
pi_lcn->lcnphy_current_index =
4272
(s8)((read_phy_reg(pi, 0x4a9) & 0xFF) / 2);
4273
}
4274
}
4275
4276
static void
4277
wlc_lcnphy_load_tx_gain_table(struct brcms_phy *pi,
4278
const struct lcnphy_tx_gain_tbl_entry *gain_table)
4279
{
4280
u32 j;
4281
struct phytbl_info tab;
4282
u32 val;
4283
u16 pa_gain;
4284
u16 gm_gain;
4285
4286
if (pi->sh->boardflags & BFL_FEM)
4287
pa_gain = 0x10;
4288
else
4289
pa_gain = 0x60;
4290
tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
4291
tab.tbl_width = 32;
4292
tab.tbl_len = 1;
4293
tab.tbl_ptr = &val;
4294
4295
/* fixed gm_gain value for iPA */
4296
gm_gain = 15;
4297
for (j = 0; j < 128; j++) {
4298
if (pi->sh->boardflags & BFL_FEM)
4299
gm_gain = gain_table[j].gm;
4300
val = (((u32) pa_gain << 24) |
4301
(gain_table[j].pad << 16) |
4302
(gain_table[j].pga << 8) | gm_gain);
4303
4304
tab.tbl_offset = LCNPHY_TX_PWR_CTRL_GAIN_OFFSET + j;
4305
wlc_lcnphy_write_table(pi, &tab);
4306
4307
val = (gain_table[j].dac << 28) | (gain_table[j].bb_mult << 20);
4308
tab.tbl_offset = LCNPHY_TX_PWR_CTRL_IQ_OFFSET + j;
4309
wlc_lcnphy_write_table(pi, &tab);
4310
}
4311
}
4312
4313
static void wlc_lcnphy_load_rfpower(struct brcms_phy *pi)
4314
{
4315
struct phytbl_info tab;
4316
u32 val, bbmult, rfgain;
4317
u8 index;
4318
u8 scale_factor = 1;
4319
s16 temp, temp1, temp2, qQ, qQ1, qQ2, shift;
4320
4321
tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
4322
tab.tbl_width = 32;
4323
tab.tbl_len = 1;
4324
4325
for (index = 0; index < 128; index++) {
4326
tab.tbl_ptr = &bbmult;
4327
tab.tbl_offset = LCNPHY_TX_PWR_CTRL_IQ_OFFSET + index;
4328
wlc_lcnphy_read_table(pi, &tab);
4329
bbmult = bbmult >> 20;
4330
4331
tab.tbl_ptr = &rfgain;
4332
tab.tbl_offset = LCNPHY_TX_PWR_CTRL_GAIN_OFFSET + index;
4333
wlc_lcnphy_read_table(pi, &tab);
4334
4335
qm_log10((s32) (bbmult), 0, &temp1, &qQ1);
4336
qm_log10((s32) (1 << 6), 0, &temp2, &qQ2);
4337
4338
if (qQ1 < qQ2) {
4339
temp2 = qm_shr16(temp2, qQ2 - qQ1);
4340
qQ = qQ1;
4341
} else {
4342
temp1 = qm_shr16(temp1, qQ1 - qQ2);
4343
qQ = qQ2;
4344
}
4345
temp = qm_sub16(temp1, temp2);
4346
4347
if (qQ >= 4)
4348
shift = qQ - 4;
4349
else
4350
shift = 4 - qQ;
4351
4352
val = (((index << shift) + (5 * temp) +
4353
(1 << (scale_factor + shift - 3))) >> (scale_factor +
4354
shift - 2));
4355
4356
tab.tbl_ptr = &val;
4357
tab.tbl_offset = LCNPHY_TX_PWR_CTRL_PWR_OFFSET + index;
4358
wlc_lcnphy_write_table(pi, &tab);
4359
}
4360
}
4361
4362
static void wlc_lcnphy_bu_tweaks(struct brcms_phy *pi)
4363
{
4364
or_phy_reg(pi, 0x805, 0x1);
4365
4366
mod_phy_reg(pi, 0x42f, (0x7 << 0), (0x3) << 0);
4367
4368
mod_phy_reg(pi, 0x030, (0x7 << 0), (0x3) << 0);
4369
4370
write_phy_reg(pi, 0x414, 0x1e10);
4371
write_phy_reg(pi, 0x415, 0x0640);
4372
4373
mod_phy_reg(pi, 0x4df, (0xff << 8), -9 << 8);
4374
4375
or_phy_reg(pi, 0x44a, 0x44);
4376
write_phy_reg(pi, 0x44a, 0x80);
4377
mod_phy_reg(pi, 0x434, (0xff << 0), (0xFD) << 0);
4378
4379
mod_phy_reg(pi, 0x420, (0xff << 0), (16) << 0);
4380
4381
if (!(pi->sh->boardrev < 0x1204))
4382
mod_radio_reg(pi, RADIO_2064_REG09B, 0xF0, 0xF0);
4383
4384
write_phy_reg(pi, 0x7d6, 0x0902);
4385
mod_phy_reg(pi, 0x429, (0xf << 0), (0x9) << 0);
4386
4387
mod_phy_reg(pi, 0x429, (0x3f << 4), (0xe) << 4);
4388
4389
if (LCNREV_IS(pi->pubpi.phy_rev, 1)) {
4390
mod_phy_reg(pi, 0x423, (0xff << 0), (0x46) << 0);
4391
4392
mod_phy_reg(pi, 0x411, (0xff << 0), (1) << 0);
4393
4394
mod_phy_reg(pi, 0x434, (0xff << 0), (0xFF) << 0);
4395
4396
mod_phy_reg(pi, 0x656, (0xf << 0), (2) << 0);
4397
4398
mod_phy_reg(pi, 0x44d, (0x1 << 2), (1) << 2);
4399
4400
mod_radio_reg(pi, RADIO_2064_REG0F7, 0x4, 0x4);
4401
mod_radio_reg(pi, RADIO_2064_REG0F1, 0x3, 0);
4402
mod_radio_reg(pi, RADIO_2064_REG0F2, 0xF8, 0x90);
4403
mod_radio_reg(pi, RADIO_2064_REG0F3, 0x3, 0x2);
4404
mod_radio_reg(pi, RADIO_2064_REG0F3, 0xf0, 0xa0);
4405
4406
mod_radio_reg(pi, RADIO_2064_REG11F, 0x2, 0x2);
4407
4408
wlc_lcnphy_clear_tx_power_offsets(pi);
4409
mod_phy_reg(pi, 0x4d0, (0x1ff << 6), (10) << 6);
4410
4411
}
4412
}
4413
4414
static void wlc_lcnphy_rcal(struct brcms_phy *pi)
4415
{
4416
u8 rcal_value;
4417
4418
and_radio_reg(pi, RADIO_2064_REG05B, 0xfD);
4419
4420
or_radio_reg(pi, RADIO_2064_REG004, 0x40);
4421
or_radio_reg(pi, RADIO_2064_REG120, 0x10);
4422
4423
or_radio_reg(pi, RADIO_2064_REG078, 0x80);
4424
or_radio_reg(pi, RADIO_2064_REG129, 0x02);
4425
4426
or_radio_reg(pi, RADIO_2064_REG057, 0x01);
4427
4428
or_radio_reg(pi, RADIO_2064_REG05B, 0x02);
4429
mdelay(5);
4430
SPINWAIT(!wlc_radio_2064_rcal_done(pi), 10 * 1000 * 1000);
4431
4432
if (wlc_radio_2064_rcal_done(pi)) {
4433
rcal_value = (u8) read_radio_reg(pi, RADIO_2064_REG05C);
4434
rcal_value = rcal_value & 0x1f;
4435
}
4436
4437
and_radio_reg(pi, RADIO_2064_REG05B, 0xfD);
4438
4439
and_radio_reg(pi, RADIO_2064_REG057, 0xFE);
4440
}
4441
4442
static void wlc_lcnphy_rc_cal(struct brcms_phy *pi)
4443
{
4444
u8 dflt_rc_cal_val;
4445
u16 flt_val;
4446
4447
dflt_rc_cal_val = 7;
4448
if (LCNREV_IS(pi->pubpi.phy_rev, 1))
4449
dflt_rc_cal_val = 11;
4450
flt_val =
4451
(dflt_rc_cal_val << 10) | (dflt_rc_cal_val << 5) |
4452
(dflt_rc_cal_val);
4453
write_phy_reg(pi, 0x933, flt_val);
4454
write_phy_reg(pi, 0x934, flt_val);
4455
write_phy_reg(pi, 0x935, flt_val);
4456
write_phy_reg(pi, 0x936, flt_val);
4457
write_phy_reg(pi, 0x937, (flt_val & 0x1FF));
4458
4459
return;
4460
}
4461
4462
static void wlc_radio_2064_init(struct brcms_phy *pi)
4463
{
4464
u32 i;
4465
const struct lcnphy_radio_regs *lcnphyregs = NULL;
4466
4467
lcnphyregs = lcnphy_radio_regs_2064;
4468
4469
for (i = 0; lcnphyregs[i].address != 0xffff; i++)
4470
if (CHSPEC_IS5G(pi->radio_chanspec) && lcnphyregs[i].do_init_a)
4471
write_radio_reg(pi,
4472
((lcnphyregs[i].address & 0x3fff) |
4473
RADIO_DEFAULT_CORE),
4474
(u16) lcnphyregs[i].init_a);
4475
else if (lcnphyregs[i].do_init_g)
4476
write_radio_reg(pi,
4477
((lcnphyregs[i].address & 0x3fff) |
4478
RADIO_DEFAULT_CORE),
4479
(u16) lcnphyregs[i].init_g);
4480
4481
write_radio_reg(pi, RADIO_2064_REG032, 0x62);
4482
write_radio_reg(pi, RADIO_2064_REG033, 0x19);
4483
4484
write_radio_reg(pi, RADIO_2064_REG090, 0x10);
4485
4486
write_radio_reg(pi, RADIO_2064_REG010, 0x00);
4487
4488
if (LCNREV_IS(pi->pubpi.phy_rev, 1)) {
4489
4490
write_radio_reg(pi, RADIO_2064_REG060, 0x7f);
4491
write_radio_reg(pi, RADIO_2064_REG061, 0x72);
4492
write_radio_reg(pi, RADIO_2064_REG062, 0x7f);
4493
}
4494
4495
write_radio_reg(pi, RADIO_2064_REG01D, 0x02);
4496
write_radio_reg(pi, RADIO_2064_REG01E, 0x06);
4497
4498
mod_phy_reg(pi, 0x4ea, (0x7 << 0), 0 << 0);
4499
4500
mod_phy_reg(pi, 0x4ea, (0x7 << 3), 1 << 3);
4501
4502
mod_phy_reg(pi, 0x4ea, (0x7 << 6), 2 << 6);
4503
4504
mod_phy_reg(pi, 0x4ea, (0x7 << 9), 3 << 9);
4505
4506
mod_phy_reg(pi, 0x4ea, (0x7 << 12), 4 << 12);
4507
4508
write_phy_reg(pi, 0x4ea, 0x4688);
4509
4510
if (pi->sh->boardflags & BFL_FEM)
4511
mod_phy_reg(pi, 0x4eb, (0x7 << 0), 2 << 0);
4512
else
4513
mod_phy_reg(pi, 0x4eb, (0x7 << 0), 3 << 0);
4514
4515
mod_phy_reg(pi, 0x4eb, (0x7 << 6), 0 << 6);
4516
4517
mod_phy_reg(pi, 0x46a, (0xffff << 0), 25 << 0);
4518
4519
wlc_lcnphy_set_tx_locc(pi, 0);
4520
4521
wlc_lcnphy_rcal(pi);
4522
4523
wlc_lcnphy_rc_cal(pi);
4524
4525
if (!(pi->sh->boardflags & BFL_FEM)) {
4526
write_radio_reg(pi, RADIO_2064_REG032, 0x6f);
4527
write_radio_reg(pi, RADIO_2064_REG033, 0x19);
4528
write_radio_reg(pi, RADIO_2064_REG039, 0xe);
4529
}
4530
4531
}
4532
4533
static void wlc_lcnphy_radio_init(struct brcms_phy *pi)
4534
{
4535
wlc_radio_2064_init(pi);
4536
}
4537
4538
static void wlc_lcnphy_tbl_init(struct brcms_phy *pi)
4539
{
4540
uint idx;
4541
struct phytbl_info tab;
4542
const struct phytbl_info *tb;
4543
u32 val;
4544
4545
for (idx = 0; idx < dot11lcnphytbl_info_sz_rev0; idx++)
4546
wlc_lcnphy_write_table(pi, &dot11lcnphytbl_info_rev0[idx]);
4547
4548
if (pi->sh->boardflags & BFL_FEM_BT) {
4549
tab.tbl_id = LCNPHY_TBL_ID_RFSEQ;
4550
tab.tbl_width = 16;
4551
tab.tbl_ptr = &val;
4552
tab.tbl_len = 1;
4553
val = 100;
4554
tab.tbl_offset = 4;
4555
wlc_lcnphy_write_table(pi, &tab);
4556
}
4557
4558
if (!(pi->sh->boardflags & BFL_FEM)) {
4559
tab.tbl_id = LCNPHY_TBL_ID_RFSEQ;
4560
tab.tbl_width = 16;
4561
tab.tbl_ptr = &val;
4562
tab.tbl_len = 1;
4563
4564
val = 150;
4565
tab.tbl_offset = 0;
4566
wlc_lcnphy_write_table(pi, &tab);
4567
4568
val = 220;
4569
tab.tbl_offset = 1;
4570
wlc_lcnphy_write_table(pi, &tab);
4571
}
4572
4573
if (CHSPEC_IS2G(pi->radio_chanspec)) {
4574
if (pi->sh->boardflags & BFL_FEM)
4575
wlc_lcnphy_load_tx_gain_table(
4576
pi,
4577
dot11lcnphy_2GHz_extPA_gaintable_rev0);
4578
else
4579
wlc_lcnphy_load_tx_gain_table(
4580
pi,
4581
dot11lcnphy_2GHz_gaintable_rev0);
4582
}
4583
4584
if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
4585
int l;
4586
4587
if (CHSPEC_IS2G(pi->radio_chanspec)) {
4588
l = dot11lcnphytbl_rx_gain_info_2G_rev2_sz;
4589
if (pi->sh->boardflags & BFL_EXTLNA)
4590
tb = dot11lcnphytbl_rx_gain_info_extlna_2G_rev2;
4591
else
4592
tb = dot11lcnphytbl_rx_gain_info_2G_rev2;
4593
} else {
4594
l = dot11lcnphytbl_rx_gain_info_5G_rev2_sz;
4595
if (pi->sh->boardflags & BFL_EXTLNA_5GHz)
4596
tb = dot11lcnphytbl_rx_gain_info_extlna_5G_rev2;
4597
else
4598
tb = dot11lcnphytbl_rx_gain_info_5G_rev2;
4599
}
4600
4601
for (idx = 0; idx < l; idx++)
4602
wlc_lcnphy_write_table(pi, &tb[idx]);
4603
}
4604
4605
if (pi->sh->boardflags & BFL_FEM) {
4606
if (pi->sh->boardflags & BFL_FEM_BT) {
4607
if (pi->sh->boardrev < 0x1250)
4608
tb = &dot11lcn_sw_ctrl_tbl_info_4313_bt_epa;
4609
else
4610
tb = &dot11lcn_sw_ctrl_tbl_info_4313_bt_epa_p250;
4611
} else {
4612
tb = &dot11lcn_sw_ctrl_tbl_info_4313_epa;
4613
}
4614
} else {
4615
if (pi->sh->boardflags & BFL_FEM_BT)
4616
tb = &dot11lcn_sw_ctrl_tbl_info_4313_bt_ipa;
4617
else
4618
tb = &dot11lcn_sw_ctrl_tbl_info_4313;
4619
}
4620
wlc_lcnphy_write_table(pi, tb);
4621
wlc_lcnphy_load_rfpower(pi);
4622
4623
wlc_lcnphy_clear_papd_comptable(pi);
4624
}
4625
4626
static void wlc_lcnphy_rev0_baseband_init(struct brcms_phy *pi)
4627
{
4628
u16 afectrl1;
4629
struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4630
4631
write_radio_reg(pi, RADIO_2064_REG11C, 0x0);
4632
4633
write_phy_reg(pi, 0x43b, 0x0);
4634
write_phy_reg(pi, 0x43c, 0x0);
4635
write_phy_reg(pi, 0x44c, 0x0);
4636
write_phy_reg(pi, 0x4e6, 0x0);
4637
write_phy_reg(pi, 0x4f9, 0x0);
4638
write_phy_reg(pi, 0x4b0, 0x0);
4639
write_phy_reg(pi, 0x938, 0x0);
4640
write_phy_reg(pi, 0x4b0, 0x0);
4641
write_phy_reg(pi, 0x44e, 0);
4642
4643
or_phy_reg(pi, 0x567, 0x03);
4644
4645
or_phy_reg(pi, 0x44a, 0x44);
4646
write_phy_reg(pi, 0x44a, 0x80);
4647
4648
if (!(pi->sh->boardflags & BFL_FEM))
4649
wlc_lcnphy_set_tx_pwr_by_index(pi, 52);
4650
4651
if (0) {
4652
afectrl1 = 0;
4653
afectrl1 = (u16) ((pi_lcn->lcnphy_rssi_vf) |
4654
(pi_lcn->lcnphy_rssi_vc << 4) |
4655
(pi_lcn->lcnphy_rssi_gs << 10));
4656
write_phy_reg(pi, 0x43e, afectrl1);
4657
}
4658
4659
mod_phy_reg(pi, 0x634, (0xff << 0), 0xC << 0);
4660
if (pi->sh->boardflags & BFL_FEM) {
4661
mod_phy_reg(pi, 0x634, (0xff << 0), 0xA << 0);
4662
4663
write_phy_reg(pi, 0x910, 0x1);
4664
}
4665
4666
mod_phy_reg(pi, 0x448, (0x3 << 8), 1 << 8);
4667
mod_phy_reg(pi, 0x608, (0xff << 0), 0x17 << 0);
4668
mod_phy_reg(pi, 0x604, (0x7ff << 0), 0x3EA << 0);
4669
4670
}
4671
4672
static void wlc_lcnphy_rev2_baseband_init(struct brcms_phy *pi)
4673
{
4674
if (CHSPEC_IS5G(pi->radio_chanspec)) {
4675
mod_phy_reg(pi, 0x416, (0xff << 0), 80 << 0);
4676
mod_phy_reg(pi, 0x416, (0xff << 8), 80 << 8);
4677
}
4678
}
4679
4680
static void wlc_lcnphy_agc_temp_init(struct brcms_phy *pi)
4681
{
4682
s16 temp;
4683
struct phytbl_info tab;
4684
u32 tableBuffer[2];
4685
struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4686
4687
temp = (s16) read_phy_reg(pi, 0x4df);
4688
pi_lcn->lcnphy_ofdmgainidxtableoffset = (temp & (0xff << 0)) >> 0;
4689
4690
if (pi_lcn->lcnphy_ofdmgainidxtableoffset > 127)
4691
pi_lcn->lcnphy_ofdmgainidxtableoffset -= 256;
4692
4693
pi_lcn->lcnphy_dsssgainidxtableoffset = (temp & (0xff << 8)) >> 8;
4694
4695
if (pi_lcn->lcnphy_dsssgainidxtableoffset > 127)
4696
pi_lcn->lcnphy_dsssgainidxtableoffset -= 256;
4697
4698
tab.tbl_ptr = tableBuffer;
4699
tab.tbl_len = 2;
4700
tab.tbl_id = 17;
4701
tab.tbl_offset = 59;
4702
tab.tbl_width = 32;
4703
wlc_lcnphy_read_table(pi, &tab);
4704
4705
if (tableBuffer[0] > 63)
4706
tableBuffer[0] -= 128;
4707
pi_lcn->lcnphy_tr_R_gain_val = tableBuffer[0];
4708
4709
if (tableBuffer[1] > 63)
4710
tableBuffer[1] -= 128;
4711
pi_lcn->lcnphy_tr_T_gain_val = tableBuffer[1];
4712
4713
temp = (s16) (read_phy_reg(pi, 0x434) & (0xff << 0));
4714
if (temp > 127)
4715
temp -= 256;
4716
pi_lcn->lcnphy_input_pwr_offset_db = (s8) temp;
4717
4718
pi_lcn->lcnphy_Med_Low_Gain_db =
4719
(read_phy_reg(pi, 0x424) & (0xff << 8)) >> 8;
4720
pi_lcn->lcnphy_Very_Low_Gain_db =
4721
(read_phy_reg(pi, 0x425) & (0xff << 0)) >> 0;
4722
4723
tab.tbl_ptr = tableBuffer;
4724
tab.tbl_len = 2;
4725
tab.tbl_id = LCNPHY_TBL_ID_GAIN_IDX;
4726
tab.tbl_offset = 28;
4727
tab.tbl_width = 32;
4728
wlc_lcnphy_read_table(pi, &tab);
4729
4730
pi_lcn->lcnphy_gain_idx_14_lowword = tableBuffer[0];
4731
pi_lcn->lcnphy_gain_idx_14_hiword = tableBuffer[1];
4732
4733
}
4734
4735
static void wlc_lcnphy_baseband_init(struct brcms_phy *pi)
4736
{
4737
4738
wlc_lcnphy_tbl_init(pi);
4739
wlc_lcnphy_rev0_baseband_init(pi);
4740
if (LCNREV_IS(pi->pubpi.phy_rev, 2))
4741
wlc_lcnphy_rev2_baseband_init(pi);
4742
wlc_lcnphy_bu_tweaks(pi);
4743
}
4744
4745
void wlc_phy_init_lcnphy(struct brcms_phy *pi)
4746
{
4747
struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4748
4749
pi_lcn->lcnphy_cal_counter = 0;
4750
pi_lcn->lcnphy_cal_temper = pi_lcn->lcnphy_rawtempsense;
4751
4752
or_phy_reg(pi, 0x44a, 0x80);
4753
and_phy_reg(pi, 0x44a, 0x7f);
4754
4755
wlc_lcnphy_afe_clk_init(pi, AFE_CLK_INIT_MODE_TXRX2X);
4756
4757
write_phy_reg(pi, 0x60a, 160);
4758
4759
write_phy_reg(pi, 0x46a, 25);
4760
4761
wlc_lcnphy_baseband_init(pi);
4762
4763
wlc_lcnphy_radio_init(pi);
4764
4765
if (CHSPEC_IS2G(pi->radio_chanspec))
4766
wlc_lcnphy_tx_pwr_ctrl_init((struct brcms_phy_pub *) pi);
4767
4768
wlc_phy_chanspec_set((struct brcms_phy_pub *) pi, pi->radio_chanspec);
4769
4770
bcma_chipco_regctl_maskset(&pi->d11core->bus->drv_cc, 0, ~0xf, 0x9);
4771
4772
bcma_chipco_chipctl_maskset(&pi->d11core->bus->drv_cc, 0, 0x0,
4773
0x03CDDDDD);
4774
4775
if ((pi->sh->boardflags & BFL_FEM)
4776
&& wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
4777
wlc_lcnphy_set_tx_pwr_by_index(pi, FIXED_TXPWR);
4778
4779
wlc_lcnphy_agc_temp_init(pi);
4780
4781
wlc_lcnphy_temp_adj(pi);
4782
4783
mod_phy_reg(pi, 0x448, (0x1 << 14), (1) << 14);
4784
4785
udelay(100);
4786
mod_phy_reg(pi, 0x448, (0x1 << 14), (0) << 14);
4787
4788
wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_HW);
4789
pi_lcn->lcnphy_noise_samples = LCNPHY_NOISE_SAMPLES_DEFAULT;
4790
wlc_lcnphy_calib_modes(pi, PHY_PERICAL_PHYINIT);
4791
}
4792
4793
static bool wlc_phy_txpwr_srom_read_lcnphy(struct brcms_phy *pi)
4794
{
4795
s8 txpwr = 0;
4796
int i;
4797
struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4798
struct ssb_sprom *sprom = &pi->d11core->bus->sprom;
4799
4800
if (CHSPEC_IS2G(pi->radio_chanspec)) {
4801
u16 cckpo = 0;
4802
u32 offset_ofdm, offset_mcs;
4803
4804
pi_lcn->lcnphy_tr_isolation_mid = sprom->fem.ghz2.tr_iso;
4805
4806
pi_lcn->lcnphy_rx_power_offset = sprom->rxpo2g;
4807
4808
pi->txpa_2g[0] = sprom->pa0b0;
4809
pi->txpa_2g[1] = sprom->pa0b1;
4810
pi->txpa_2g[2] = sprom->pa0b2;
4811
4812
pi_lcn->lcnphy_rssi_vf = sprom->rssismf2g;
4813
pi_lcn->lcnphy_rssi_vc = sprom->rssismc2g;
4814
pi_lcn->lcnphy_rssi_gs = sprom->rssisav2g;
4815
4816
pi_lcn->lcnphy_rssi_vf_lowtemp = pi_lcn->lcnphy_rssi_vf;
4817
pi_lcn->lcnphy_rssi_vc_lowtemp = pi_lcn->lcnphy_rssi_vc;
4818
pi_lcn->lcnphy_rssi_gs_lowtemp = pi_lcn->lcnphy_rssi_gs;
4819
4820
pi_lcn->lcnphy_rssi_vf_hightemp = pi_lcn->lcnphy_rssi_vf;
4821
pi_lcn->lcnphy_rssi_vc_hightemp = pi_lcn->lcnphy_rssi_vc;
4822
pi_lcn->lcnphy_rssi_gs_hightemp = pi_lcn->lcnphy_rssi_gs;
4823
4824
txpwr = sprom->core_pwr_info[0].maxpwr_2g;
4825
pi->tx_srom_max_2g = txpwr;
4826
4827
for (i = 0; i < PWRTBL_NUM_COEFF; i++) {
4828
pi->txpa_2g_low_temp[i] = pi->txpa_2g[i];
4829
pi->txpa_2g_high_temp[i] = pi->txpa_2g[i];
4830
}
4831
4832
cckpo = sprom->cck2gpo;
4833
offset_ofdm = sprom->ofdm2gpo;
4834
if (cckpo) {
4835
uint max_pwr_chan = txpwr;
4836
4837
for (i = TXP_FIRST_CCK; i <= TXP_LAST_CCK; i++) {
4838
pi->tx_srom_max_rate_2g[i] =
4839
max_pwr_chan - ((cckpo & 0xf) * 2);
4840
cckpo >>= 4;
4841
}
4842
4843
for (i = TXP_FIRST_OFDM; i <= TXP_LAST_OFDM; i++) {
4844
pi->tx_srom_max_rate_2g[i] =
4845
max_pwr_chan -
4846
((offset_ofdm & 0xf) * 2);
4847
offset_ofdm >>= 4;
4848
}
4849
} else {
4850
for (i = TXP_FIRST_CCK; i <= TXP_LAST_CCK; i++)
4851
pi->tx_srom_max_rate_2g[i] = txpwr;
4852
4853
for (i = TXP_FIRST_OFDM; i <= TXP_LAST_OFDM; i++) {
4854
pi->tx_srom_max_rate_2g[i] = txpwr -
4855
((offset_ofdm & 0xf) * 2);
4856
offset_ofdm >>= 4;
4857
}
4858
offset_mcs = sprom->mcs2gpo[1] << 16;
4859
offset_mcs |= sprom->mcs2gpo[0];
4860
pi_lcn->lcnphy_mcs20_po = offset_mcs;
4861
for (i = TXP_FIRST_SISO_MCS_20;
4862
i <= TXP_LAST_SISO_MCS_20; i++) {
4863
pi->tx_srom_max_rate_2g[i] =
4864
txpwr - ((offset_mcs & 0xf) * 2);
4865
offset_mcs >>= 4;
4866
}
4867
}
4868
4869
pi_lcn->lcnphy_rawtempsense = sprom->rawtempsense;
4870
pi_lcn->lcnphy_measPower = sprom->measpower;
4871
pi_lcn->lcnphy_tempsense_slope = sprom->tempsense_slope;
4872
pi_lcn->lcnphy_hw_iqcal_en = sprom->hw_iqcal_en;
4873
pi_lcn->lcnphy_iqcal_swp_dis = sprom->iqcal_swp_dis;
4874
pi_lcn->lcnphy_tempcorrx = sprom->tempcorrx;
4875
pi_lcn->lcnphy_tempsense_option = sprom->tempsense_option;
4876
pi_lcn->lcnphy_freqoffset_corr = sprom->freqoffset_corr;
4877
if (sprom->ant_available_bg > 1)
4878
wlc_phy_ant_rxdiv_set((struct brcms_phy_pub *) pi,
4879
sprom->ant_available_bg);
4880
}
4881
pi_lcn->lcnphy_cck_dig_filt_type = -1;
4882
4883
return true;
4884
}
4885
4886
void wlc_2064_vco_cal(struct brcms_phy *pi)
4887
{
4888
u8 calnrst;
4889
4890
mod_radio_reg(pi, RADIO_2064_REG057, 1 << 3, 1 << 3);
4891
calnrst = (u8) read_radio_reg(pi, RADIO_2064_REG056) & 0xf8;
4892
write_radio_reg(pi, RADIO_2064_REG056, calnrst);
4893
udelay(1);
4894
write_radio_reg(pi, RADIO_2064_REG056, calnrst | 0x03);
4895
udelay(1);
4896
write_radio_reg(pi, RADIO_2064_REG056, calnrst | 0x07);
4897
udelay(300);
4898
mod_radio_reg(pi, RADIO_2064_REG057, 1 << 3, 0);
4899
}
4900
4901
bool wlc_phy_tpc_isenabled_lcnphy(struct brcms_phy *pi)
4902
{
4903
if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
4904
return false;
4905
else
4906
return (LCNPHY_TX_PWR_CTRL_HW ==
4907
wlc_lcnphy_get_tx_pwr_ctrl((pi)));
4908
}
4909
4910
void wlc_phy_txpower_recalc_target_lcnphy(struct brcms_phy *pi)
4911
{
4912
u16 pwr_ctrl;
4913
if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) {
4914
wlc_lcnphy_calib_modes(pi, LCNPHY_PERICAL_TEMPBASED_TXPWRCTRL);
4915
} else if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi)) {
4916
pwr_ctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
4917
wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
4918
wlc_lcnphy_txpower_recalc_target(pi);
4919
wlc_lcnphy_set_tx_pwr_ctrl(pi, pwr_ctrl);
4920
}
4921
}
4922
4923
void wlc_phy_chanspec_set_lcnphy(struct brcms_phy *pi, u16 chanspec)
4924
{
4925
u8 channel = CHSPEC_CHANNEL(chanspec);
4926
4927
wlc_phy_chanspec_radio_set((struct brcms_phy_pub *)pi, chanspec);
4928
4929
wlc_lcnphy_set_chanspec_tweaks(pi, pi->radio_chanspec);
4930
4931
or_phy_reg(pi, 0x44a, 0x44);
4932
write_phy_reg(pi, 0x44a, 0x80);
4933
4934
wlc_lcnphy_radio_2064_channel_tune_4313(pi, channel);
4935
udelay(1000);
4936
4937
wlc_lcnphy_toggle_afe_pwdn(pi);
4938
4939
write_phy_reg(pi, 0x657, lcnphy_sfo_cfg[channel - 1].ptcentreTs20);
4940
write_phy_reg(pi, 0x658, lcnphy_sfo_cfg[channel - 1].ptcentreFactor);
4941
4942
if (CHSPEC_CHANNEL(pi->radio_chanspec) == 14) {
4943
mod_phy_reg(pi, 0x448, (0x3 << 8), (2) << 8);
4944
4945
wlc_lcnphy_load_tx_iir_filter(pi, false, 3);
4946
} else {
4947
mod_phy_reg(pi, 0x448, (0x3 << 8), (1) << 8);
4948
4949
wlc_lcnphy_load_tx_iir_filter(pi, false, 2);
4950
}
4951
4952
if (pi->sh->boardflags & BFL_FEM)
4953
wlc_lcnphy_load_tx_iir_filter(pi, true, 0);
4954
else
4955
wlc_lcnphy_load_tx_iir_filter(pi, true, 3);
4956
4957
mod_phy_reg(pi, 0x4eb, (0x7 << 3), (1) << 3);
4958
if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi))
4959
wlc_lcnphy_tssi_setup(pi);
4960
}
4961
4962
void wlc_phy_detach_lcnphy(struct brcms_phy *pi)
4963
{
4964
kfree(pi->u.pi_lcnphy);
4965
}
4966
4967
bool wlc_phy_attach_lcnphy(struct brcms_phy *pi)
4968
{
4969
struct brcms_phy_lcnphy *pi_lcn;
4970
4971
pi_lcn = kzalloc(sizeof(*pi_lcn), GFP_ATOMIC);
4972
if (!pi_lcn)
4973
return false;
4974
4975
pi->u.pi_lcnphy = pi_lcn;
4976
4977
if (0 == (pi->sh->boardflags & BFL_NOPA)) {
4978
pi->hwpwrctrl = true;
4979
pi->hwpwrctrl_capable = true;
4980
}
4981
4982
pi->xtalfreq = bcma_chipco_get_alp_clock(&pi->d11core->bus->drv_cc);
4983
pi_lcn->lcnphy_papd_rxGnCtrl_init = 0;
4984
4985
pi->pi_fptr.init = wlc_phy_init_lcnphy;
4986
pi->pi_fptr.calinit = wlc_phy_cal_init_lcnphy;
4987
pi->pi_fptr.chanset = wlc_phy_chanspec_set_lcnphy;
4988
pi->pi_fptr.txpwrrecalc = wlc_phy_txpower_recalc_target_lcnphy;
4989
pi->pi_fptr.txiqccget = wlc_lcnphy_get_tx_iqcc;
4990
pi->pi_fptr.txiqccset = wlc_lcnphy_set_tx_iqcc;
4991
pi->pi_fptr.txloccget = wlc_lcnphy_get_tx_locc;
4992
pi->pi_fptr.radioloftget = wlc_lcnphy_get_radio_loft;
4993
pi->pi_fptr.detach = wlc_phy_detach_lcnphy;
4994
4995
if (!wlc_phy_txpwr_srom_read_lcnphy(pi)) {
4996
kfree(pi->u.pi_lcnphy);
4997
return false;
4998
}
4999
5000
if (LCNREV_IS(pi->pubpi.phy_rev, 1)) {
5001
if (pi_lcn->lcnphy_tempsense_option == 3) {
5002
pi->hwpwrctrl = true;
5003
pi->hwpwrctrl_capable = true;
5004
pi->temppwrctrl_capable = false;
5005
} else {
5006
pi->hwpwrctrl = false;
5007
pi->hwpwrctrl_capable = false;
5008
pi->temppwrctrl_capable = true;
5009
}
5010
}
5011
5012
return true;
5013
}
5014
5015
static void wlc_lcnphy_set_rx_gain(struct brcms_phy *pi, u32 gain)
5016
{
5017
u16 trsw, ext_lna, lna1, lna2, tia, biq0, biq1, gain0_15, gain16_19;
5018
5019
trsw = (gain & ((u32) 1 << 28)) ? 0 : 1;
5020
ext_lna = (u16) (gain >> 29) & 0x01;
5021
lna1 = (u16) (gain >> 0) & 0x0f;
5022
lna2 = (u16) (gain >> 4) & 0x0f;
5023
tia = (u16) (gain >> 8) & 0xf;
5024
biq0 = (u16) (gain >> 12) & 0xf;
5025
biq1 = (u16) (gain >> 16) & 0xf;
5026
5027
gain0_15 = (u16) ((lna1 & 0x3) | ((lna1 & 0x3) << 2) |
5028
((lna2 & 0x3) << 4) | ((lna2 & 0x3) << 6) |
5029
((tia & 0xf) << 8) | ((biq0 & 0xf) << 12));
5030
gain16_19 = biq1;
5031
5032
mod_phy_reg(pi, 0x44d, (0x1 << 0), trsw << 0);
5033
mod_phy_reg(pi, 0x4b1, (0x1 << 9), ext_lna << 9);
5034
mod_phy_reg(pi, 0x4b1, (0x1 << 10), ext_lna << 10);
5035
mod_phy_reg(pi, 0x4b6, (0xffff << 0), gain0_15 << 0);
5036
mod_phy_reg(pi, 0x4b7, (0xf << 0), gain16_19 << 0);
5037
5038
if (CHSPEC_IS2G(pi->radio_chanspec)) {
5039
mod_phy_reg(pi, 0x4b1, (0x3 << 11), lna1 << 11);
5040
mod_phy_reg(pi, 0x4e6, (0x3 << 3), lna1 << 3);
5041
}
5042
wlc_lcnphy_rx_gain_override_enable(pi, true);
5043
}
5044
5045
static u32 wlc_lcnphy_get_receive_power(struct brcms_phy *pi, s32 *gain_index)
5046
{
5047
u32 received_power = 0;
5048
s32 max_index = 0;
5049
u32 gain_code = 0;
5050
struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
5051
5052
max_index = 36;
5053
if (*gain_index >= 0)
5054
gain_code = lcnphy_23bitgaincode_table[*gain_index];
5055
5056
if (-1 == *gain_index) {
5057
*gain_index = 0;
5058
while ((*gain_index <= (s32) max_index)
5059
&& (received_power < 700)) {
5060
wlc_lcnphy_set_rx_gain(pi,
5061
lcnphy_23bitgaincode_table
5062
[*gain_index]);
5063
received_power =
5064
wlc_lcnphy_measure_digital_power(
5065
pi,
5066
pi_lcn->
5067
lcnphy_noise_samples);
5068
(*gain_index)++;
5069
}
5070
(*gain_index)--;
5071
} else {
5072
wlc_lcnphy_set_rx_gain(pi, gain_code);
5073
received_power =
5074
wlc_lcnphy_measure_digital_power(pi,
5075
pi_lcn->
5076
lcnphy_noise_samples);
5077
}
5078
5079
return received_power;
5080
}
5081
5082
s32 wlc_lcnphy_rx_signal_power(struct brcms_phy *pi, s32 gain_index)
5083
{
5084
s32 gain = 0;
5085
s32 nominal_power_db;
5086
s32 log_val, gain_mismatch, desired_gain, input_power_offset_db,
5087
input_power_db;
5088
s32 received_power, temperature;
5089
u32 power;
5090
u32 msb1, msb2, val1, val2, diff1, diff2;
5091
uint freq;
5092
struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
5093
5094
received_power = wlc_lcnphy_get_receive_power(pi, &gain_index);
5095
5096
gain = lcnphy_gain_table[gain_index];
5097
5098
nominal_power_db = read_phy_reg(pi, 0x425) >> 8;
5099
5100
power = (received_power * 16);
5101
msb1 = ffs(power) - 1;
5102
msb2 = msb1 + 1;
5103
val1 = 1 << msb1;
5104
val2 = 1 << msb2;
5105
diff1 = (power - val1);
5106
diff2 = (val2 - power);
5107
if (diff1 < diff2)
5108
log_val = msb1;
5109
else
5110
log_val = msb2;
5111
5112
log_val = log_val * 3;
5113
5114
gain_mismatch = (nominal_power_db / 2) - (log_val);
5115
5116
desired_gain = gain + gain_mismatch;
5117
5118
input_power_offset_db = read_phy_reg(pi, 0x434) & 0xFF;
5119
5120
if (input_power_offset_db > 127)
5121
input_power_offset_db -= 256;
5122
5123
input_power_db = input_power_offset_db - desired_gain;
5124
5125
input_power_db =
5126
input_power_db + lcnphy_gain_index_offset_for_rssi[gain_index];
5127
5128
freq = wlc_phy_channel2freq(CHSPEC_CHANNEL(pi->radio_chanspec));
5129
if ((freq > 2427) && (freq <= 2467))
5130
input_power_db = input_power_db - 1;
5131
5132
temperature = pi_lcn->lcnphy_lastsensed_temperature;
5133
5134
if ((temperature - 15) < -30)
5135
input_power_db =
5136
input_power_db +
5137
(((temperature - 10 - 25) * 286) >> 12) -
5138
7;
5139
else if ((temperature - 15) < 4)
5140
input_power_db =
5141
input_power_db +
5142
(((temperature - 10 - 25) * 286) >> 12) -
5143
3;
5144
else
5145
input_power_db = input_power_db +
5146
(((temperature - 10 - 25) * 286) >> 12);
5147
5148
wlc_lcnphy_rx_gain_override_enable(pi, 0);
5149
5150
return input_power_db;
5151
}
5152
5153