aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/b43/lo.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/b43/lo.c')
-rw-r--r--drivers/net/wireless/b43/lo.c731
1 files changed, 253 insertions, 478 deletions
diff --git a/drivers/net/wireless/b43/lo.c b/drivers/net/wireless/b43/lo.c
index d890f366a23b..9c854d6aae36 100644
--- a/drivers/net/wireless/b43/lo.c
+++ b/drivers/net/wireless/b43/lo.c
@@ -36,17 +36,28 @@
36#include <linux/sched.h> 36#include <linux/sched.h>
37 37
38 38
39/* Define to 1 to always calibrate all possible LO control pairs. 39static struct b43_lo_calib * b43_find_lo_calib(struct b43_txpower_lo_control *lo,
40 * This is a workaround until we fix the partial LO calibration optimization. */ 40 const struct b43_bbatt *bbatt,
41#define B43_CALIB_ALL_LOCTLS 1 41 const struct b43_rfatt *rfatt)
42{
43 struct b43_lo_calib *c;
44
45 list_for_each_entry(c, &lo->calib_list, list) {
46 if (!b43_compare_bbatt(&c->bbatt, bbatt))
47 continue;
48 if (!b43_compare_rfatt(&c->rfatt, rfatt))
49 continue;
50 return c;
51 }
42 52
53 return NULL;
54}
43 55
44/* Write the LocalOscillator Control (adjust) value-pair. */ 56/* Write the LocalOscillator Control (adjust) value-pair. */
45static void b43_lo_write(struct b43_wldev *dev, struct b43_loctl *control) 57static void b43_lo_write(struct b43_wldev *dev, struct b43_loctl *control)
46{ 58{
47 struct b43_phy *phy = &dev->phy; 59 struct b43_phy *phy = &dev->phy;
48 u16 value; 60 u16 value;
49 u16 reg;
50 61
51 if (B43_DEBUG) { 62 if (B43_DEBUG) {
52 if (unlikely(abs(control->i) > 16 || abs(control->q) > 16)) { 63 if (unlikely(abs(control->i) > 16 || abs(control->q) > 16)) {
@@ -56,189 +67,11 @@ static void b43_lo_write(struct b43_wldev *dev, struct b43_loctl *control)
56 return; 67 return;
57 } 68 }
58 } 69 }
70 B43_WARN_ON(phy->type != B43_PHYTYPE_G);
59 71
60 value = (u8) (control->q); 72 value = (u8) (control->q);
61 value |= ((u8) (control->i)) << 8; 73 value |= ((u8) (control->i)) << 8;
62 74 b43_phy_write(dev, B43_PHY_LO_CTL, value);
63 reg = (phy->type == B43_PHYTYPE_B) ? 0x002F : B43_PHY_LO_CTL;
64 b43_phy_write(dev, reg, value);
65}
66
67static int assert_rfatt_and_bbatt(const struct b43_rfatt *rfatt,
68 const struct b43_bbatt *bbatt,
69 struct b43_wldev *dev)
70{
71 int err = 0;
72
73 /* Check the attenuation values against the LO control array sizes. */
74 if (unlikely(rfatt->att >= B43_NR_RF)) {
75 b43err(dev->wl, "rfatt(%u) >= size of LO array\n", rfatt->att);
76 err = -EINVAL;
77 }
78 if (unlikely(bbatt->att >= B43_NR_BB)) {
79 b43err(dev->wl, "bbatt(%u) >= size of LO array\n", bbatt->att);
80 err = -EINVAL;
81 }
82
83 return err;
84}
85
86#if !B43_CALIB_ALL_LOCTLS
87static
88struct b43_loctl *b43_get_lo_g_ctl_nopadmix(struct b43_wldev *dev,
89 const struct b43_rfatt *rfatt,
90 const struct b43_bbatt *bbatt)
91{
92 struct b43_phy *phy = &dev->phy;
93 struct b43_txpower_lo_control *lo = phy->lo_control;
94
95 if (assert_rfatt_and_bbatt(rfatt, bbatt, dev))
96 return &(lo->no_padmix[0][0]); /* Just prevent a crash */
97 return &(lo->no_padmix[bbatt->att][rfatt->att]);
98}
99#endif /* !B43_CALIB_ALL_LOCTLS */
100
101struct b43_loctl *b43_get_lo_g_ctl(struct b43_wldev *dev,
102 const struct b43_rfatt *rfatt,
103 const struct b43_bbatt *bbatt)
104{
105 struct b43_phy *phy = &dev->phy;
106 struct b43_txpower_lo_control *lo = phy->lo_control;
107
108 if (assert_rfatt_and_bbatt(rfatt, bbatt, dev))
109 return &(lo->no_padmix[0][0]); /* Just prevent a crash */
110 if (rfatt->with_padmix)
111 return &(lo->with_padmix[bbatt->att][rfatt->att]);
112 return &(lo->no_padmix[bbatt->att][rfatt->att]);
113}
114
115/* Call a function for every possible LO control value-pair. */
116static void b43_call_for_each_loctl(struct b43_wldev *dev,
117 void (*func) (struct b43_wldev *,
118 struct b43_loctl *))
119{
120 struct b43_phy *phy = &dev->phy;
121 struct b43_txpower_lo_control *ctl = phy->lo_control;
122 int i, j;
123
124 for (i = 0; i < B43_NR_BB; i++) {
125 for (j = 0; j < B43_NR_RF; j++)
126 func(dev, &(ctl->with_padmix[i][j]));
127 }
128 for (i = 0; i < B43_NR_BB; i++) {
129 for (j = 0; j < B43_NR_RF; j++)
130 func(dev, &(ctl->no_padmix[i][j]));
131 }
132}
133
134static u16 lo_b_r15_loop(struct b43_wldev *dev)
135{
136 int i;
137 u16 ret = 0;
138
139 for (i = 0; i < 10; i++) {
140 b43_phy_write(dev, 0x0015, 0xAFA0);
141 udelay(1);
142 b43_phy_write(dev, 0x0015, 0xEFA0);
143 udelay(10);
144 b43_phy_write(dev, 0x0015, 0xFFA0);
145 udelay(40);
146 ret += b43_phy_read(dev, 0x002C);
147 }
148
149 return ret;
150}
151
152void b43_lo_b_measure(struct b43_wldev *dev)
153{
154 struct b43_phy *phy = &dev->phy;
155 u16 regstack[12] = { 0 };
156 u16 mls;
157 u16 fval;
158 int i, j;
159
160 regstack[0] = b43_phy_read(dev, 0x0015);
161 regstack[1] = b43_radio_read16(dev, 0x0052) & 0xFFF0;
162
163 if (phy->radio_ver == 0x2053) {
164 regstack[2] = b43_phy_read(dev, 0x000A);
165 regstack[3] = b43_phy_read(dev, 0x002A);
166 regstack[4] = b43_phy_read(dev, 0x0035);
167 regstack[5] = b43_phy_read(dev, 0x0003);
168 regstack[6] = b43_phy_read(dev, 0x0001);
169 regstack[7] = b43_phy_read(dev, 0x0030);
170
171 regstack[8] = b43_radio_read16(dev, 0x0043);
172 regstack[9] = b43_radio_read16(dev, 0x007A);
173 regstack[10] = b43_read16(dev, 0x03EC);
174 regstack[11] = b43_radio_read16(dev, 0x0052) & 0x00F0;
175
176 b43_phy_write(dev, 0x0030, 0x00FF);
177 b43_write16(dev, 0x03EC, 0x3F3F);
178 b43_phy_write(dev, 0x0035, regstack[4] & 0xFF7F);
179 b43_radio_write16(dev, 0x007A, regstack[9] & 0xFFF0);
180 }
181 b43_phy_write(dev, 0x0015, 0xB000);
182 b43_phy_write(dev, 0x002B, 0x0004);
183
184 if (phy->radio_ver == 0x2053) {
185 b43_phy_write(dev, 0x002B, 0x0203);
186 b43_phy_write(dev, 0x002A, 0x08A3);
187 }
188
189 phy->minlowsig[0] = 0xFFFF;
190
191 for (i = 0; i < 4; i++) {
192 b43_radio_write16(dev, 0x0052, regstack[1] | i);
193 lo_b_r15_loop(dev);
194 }
195 for (i = 0; i < 10; i++) {
196 b43_radio_write16(dev, 0x0052, regstack[1] | i);
197 mls = lo_b_r15_loop(dev) / 10;
198 if (mls < phy->minlowsig[0]) {
199 phy->minlowsig[0] = mls;
200 phy->minlowsigpos[0] = i;
201 }
202 }
203 b43_radio_write16(dev, 0x0052, regstack[1] | phy->minlowsigpos[0]);
204
205 phy->minlowsig[1] = 0xFFFF;
206
207 for (i = -4; i < 5; i += 2) {
208 for (j = -4; j < 5; j += 2) {
209 if (j < 0)
210 fval = (0x0100 * i) + j + 0x0100;
211 else
212 fval = (0x0100 * i) + j;
213 b43_phy_write(dev, 0x002F, fval);
214 mls = lo_b_r15_loop(dev) / 10;
215 if (mls < phy->minlowsig[1]) {
216 phy->minlowsig[1] = mls;
217 phy->minlowsigpos[1] = fval;
218 }
219 }
220 }
221 phy->minlowsigpos[1] += 0x0101;
222
223 b43_phy_write(dev, 0x002F, phy->minlowsigpos[1]);
224 if (phy->radio_ver == 0x2053) {
225 b43_phy_write(dev, 0x000A, regstack[2]);
226 b43_phy_write(dev, 0x002A, regstack[3]);
227 b43_phy_write(dev, 0x0035, regstack[4]);
228 b43_phy_write(dev, 0x0003, regstack[5]);
229 b43_phy_write(dev, 0x0001, regstack[6]);
230 b43_phy_write(dev, 0x0030, regstack[7]);
231
232 b43_radio_write16(dev, 0x0043, regstack[8]);
233 b43_radio_write16(dev, 0x007A, regstack[9]);
234
235 b43_radio_write16(dev, 0x0052,
236 (b43_radio_read16(dev, 0x0052) & 0x000F)
237 | regstack[11]);
238
239 b43_write16(dev, 0x03EC, regstack[10]);
240 }
241 b43_phy_write(dev, 0x0015, regstack[0]);
242} 75}
243 76
244static u16 lo_measure_feedthrough(struct b43_wldev *dev, 77static u16 lo_measure_feedthrough(struct b43_wldev *dev,
@@ -366,7 +199,7 @@ static void lo_measure_txctl_values(struct b43_wldev *dev)
366 if (lb_gain > 10) { 199 if (lb_gain > 10) {
367 radio_pctl_reg = 0; 200 radio_pctl_reg = 0;
368 pga = abs(10 - lb_gain) / 6; 201 pga = abs(10 - lb_gain) / 6;
369 pga = limit_value(pga, 0, 15); 202 pga = clamp_val(pga, 0, 15);
370 } else { 203 } else {
371 int cmp_val; 204 int cmp_val;
372 int tmp; 205 int tmp;
@@ -438,48 +271,26 @@ static void lo_measure_txctl_values(struct b43_wldev *dev)
438 b43_radio_write16(dev, 0x52, b43_radio_read16(dev, 0x52) 271 b43_radio_write16(dev, 0x52, b43_radio_read16(dev, 0x52)
439 & 0xFFF0); /* TX bias == 0 */ 272 & 0xFFF0); /* TX bias == 0 */
440 } 273 }
274 lo->txctl_measured_time = jiffies;
441} 275}
442 276
443static void lo_read_power_vector(struct b43_wldev *dev) 277static void lo_read_power_vector(struct b43_wldev *dev)
444{ 278{
445 struct b43_phy *phy = &dev->phy; 279 struct b43_phy *phy = &dev->phy;
446 struct b43_txpower_lo_control *lo = phy->lo_control; 280 struct b43_txpower_lo_control *lo = phy->lo_control;
447 u16 i; 281 int i;
448 u64 tmp; 282 u64 tmp;
449 u64 power_vector = 0; 283 u64 power_vector = 0;
450 int rf_offset, bb_offset;
451 struct b43_loctl *loctl;
452 284
453 for (i = 0; i < 8; i += 2) { 285 for (i = 0; i < 8; i += 2) {
454 tmp = b43_shm_read16(dev, B43_SHM_SHARED, 0x310 + i); 286 tmp = b43_shm_read16(dev, B43_SHM_SHARED, 0x310 + i);
455 /* Clear the top byte. We get holes in the bitmap... */
456 tmp &= 0xFF;
457 power_vector |= (tmp << (i * 8)); 287 power_vector |= (tmp << (i * 8));
458 /* Clear the vector on the device. */ 288 /* Clear the vector on the device. */
459 b43_shm_write16(dev, B43_SHM_SHARED, 0x310 + i, 0); 289 b43_shm_write16(dev, B43_SHM_SHARED, 0x310 + i, 0);
460 } 290 }
461
462 if (power_vector) 291 if (power_vector)
463 lo->power_vector = power_vector; 292 lo->power_vector = power_vector;
464 power_vector = lo->power_vector; 293 lo->pwr_vec_read_time = jiffies;
465
466 for (i = 0; i < 64; i++) {
467 if (power_vector & ((u64) 1ULL << i)) {
468 /* Now figure out which b43_loctl corresponds
469 * to this bit.
470 */
471 rf_offset = i / lo->rfatt_list.len;
472 bb_offset = i % lo->rfatt_list.len; //FIXME?
473 loctl =
474 b43_get_lo_g_ctl(dev,
475 &lo->rfatt_list.list[rf_offset],
476 &lo->bbatt_list.list[bb_offset]);
477 /* And mark it as "used", as the device told us
478 * through the bitmap it is using it.
479 */
480 loctl->used = 1;
481 }
482 }
483} 294}
484 295
485/* 802.11/LO/GPHY/MeasuringGains */ 296/* 802.11/LO/GPHY/MeasuringGains */
@@ -510,7 +321,7 @@ static void lo_measure_gain_values(struct b43_wldev *dev,
510 phy->lna_lod_gain = 1; 321 phy->lna_lod_gain = 1;
511 trsw_rx_gain -= 8; 322 trsw_rx_gain -= 8;
512 } 323 }
513 trsw_rx_gain = limit_value(trsw_rx_gain, 0, 0x2D); 324 trsw_rx_gain = clamp_val(trsw_rx_gain, 0, 0x2D);
514 phy->pga_gain = trsw_rx_gain / 3; 325 phy->pga_gain = trsw_rx_gain / 3;
515 if (phy->pga_gain >= 5) { 326 if (phy->pga_gain >= 5) {
516 phy->pga_gain -= 5; 327 phy->pga_gain -= 5;
@@ -609,8 +420,6 @@ static void lo_measure_setup(struct b43_wldev *dev,
609 b43_phy_write(dev, B43_PHY_CCK(0x16), 0x410); 420 b43_phy_write(dev, B43_PHY_CCK(0x16), 0x410);
610 b43_phy_write(dev, B43_PHY_CCK(0x17), 0x820); 421 b43_phy_write(dev, B43_PHY_CCK(0x17), 0x820);
611 } 422 }
612 if (!lo->rebuild && b43_has_hardware_pctl(phy))
613 lo_read_power_vector(dev);
614 if (phy->rev >= 2) { 423 if (phy->rev >= 2) {
615 sav->phy_analogover = b43_phy_read(dev, B43_PHY_ANALOGOVER); 424 sav->phy_analogover = b43_phy_read(dev, B43_PHY_ANALOGOVER);
616 sav->phy_analogoverval = 425 sav->phy_analogoverval =
@@ -691,8 +500,12 @@ static void lo_measure_setup(struct b43_wldev *dev,
691 b43_radio_read16(dev, 0x51); /* dummy read */ 500 b43_radio_read16(dev, 0x51); /* dummy read */
692 if (phy->type == B43_PHYTYPE_G) 501 if (phy->type == B43_PHYTYPE_G)
693 b43_phy_write(dev, B43_PHY_CCK(0x2F), 0); 502 b43_phy_write(dev, B43_PHY_CCK(0x2F), 0);
694 if (lo->rebuild) 503
504 /* Re-measure the txctl values, if needed. */
505 if (time_before(lo->txctl_measured_time,
506 jiffies - B43_LO_TXCTL_EXPIRE))
695 lo_measure_txctl_values(dev); 507 lo_measure_txctl_values(dev);
508
696 if (phy->type == B43_PHYTYPE_G && phy->rev >= 3) { 509 if (phy->type == B43_PHYTYPE_G && phy->rev >= 3) {
697 b43_phy_write(dev, B43_PHY_LO_MASK, 0xC078); 510 b43_phy_write(dev, B43_PHY_LO_MASK, 0xC078);
698 } else { 511 } else {
@@ -707,7 +520,6 @@ static void lo_measure_restore(struct b43_wldev *dev,
707 struct lo_g_saved_values *sav) 520 struct lo_g_saved_values *sav)
708{ 521{
709 struct b43_phy *phy = &dev->phy; 522 struct b43_phy *phy = &dev->phy;
710 struct b43_txpower_lo_control *lo = phy->lo_control;
711 u16 tmp; 523 u16 tmp;
712 524
713 if (phy->rev >= 2) { 525 if (phy->rev >= 2) {
@@ -722,14 +534,6 @@ static void lo_measure_restore(struct b43_wldev *dev,
722 tmp = (phy->pga_gain | 0xEFA0); 534 tmp = (phy->pga_gain | 0xEFA0);
723 b43_phy_write(dev, B43_PHY_PGACTL, tmp); 535 b43_phy_write(dev, B43_PHY_PGACTL, tmp);
724 } 536 }
725 if (b43_has_hardware_pctl(phy)) {
726 b43_gphy_dc_lt_init(dev);
727 } else {
728 if (lo->rebuild)
729 b43_lo_g_adjust_to(dev, 3, 2, 0);
730 else
731 b43_lo_g_adjust(dev);
732 }
733 if (phy->type == B43_PHYTYPE_G) { 537 if (phy->type == B43_PHYTYPE_G) {
734 if (phy->rev >= 3) 538 if (phy->rev >= 3)
735 b43_phy_write(dev, B43_PHY_CCK(0x2E), 0xC078); 539 b43_phy_write(dev, B43_PHY_CCK(0x2E), 0xC078);
@@ -793,7 +597,6 @@ static int lo_probe_possible_loctls(struct b43_wldev *dev,
793 struct b43_lo_g_statemachine *d) 597 struct b43_lo_g_statemachine *d)
794{ 598{
795 struct b43_phy *phy = &dev->phy; 599 struct b43_phy *phy = &dev->phy;
796 struct b43_txpower_lo_control *lo = phy->lo_control;
797 struct b43_loctl test_loctl; 600 struct b43_loctl test_loctl;
798 struct b43_loctl orig_loctl; 601 struct b43_loctl orig_loctl;
799 struct b43_loctl prev_loctl = { 602 struct b43_loctl prev_loctl = {
@@ -852,7 +655,7 @@ static int lo_probe_possible_loctls(struct b43_wldev *dev,
852 found_lower = 1; 655 found_lower = 1;
853 d->lowest_feedth = feedth; 656 d->lowest_feedth = feedth;
854 if ((d->nr_measured < 2) && 657 if ((d->nr_measured < 2) &&
855 (!has_loopback_gain(phy) || lo->rebuild)) 658 !has_loopback_gain(phy))
856 break; 659 break;
857 } 660 }
858 } 661 }
@@ -874,7 +677,6 @@ static void lo_probe_loctls_statemachine(struct b43_wldev *dev,
874 int *max_rx_gain) 677 int *max_rx_gain)
875{ 678{
876 struct b43_phy *phy = &dev->phy; 679 struct b43_phy *phy = &dev->phy;
877 struct b43_txpower_lo_control *lo = phy->lo_control;
878 struct b43_lo_g_statemachine d; 680 struct b43_lo_g_statemachine d;
879 u16 feedth; 681 u16 feedth;
880 int found_lower; 682 int found_lower;
@@ -883,18 +685,18 @@ static void lo_probe_loctls_statemachine(struct b43_wldev *dev,
883 685
884 d.nr_measured = 0; 686 d.nr_measured = 0;
885 d.state_val_multiplier = 1; 687 d.state_val_multiplier = 1;
886 if (has_loopback_gain(phy) && !lo->rebuild) 688 if (has_loopback_gain(phy))
887 d.state_val_multiplier = 3; 689 d.state_val_multiplier = 3;
888 690
889 memcpy(&d.min_loctl, loctl, sizeof(struct b43_loctl)); 691 memcpy(&d.min_loctl, loctl, sizeof(struct b43_loctl));
890 if (has_loopback_gain(phy) && lo->rebuild) 692 if (has_loopback_gain(phy))
891 max_repeat = 4; 693 max_repeat = 4;
892 do { 694 do {
893 b43_lo_write(dev, &d.min_loctl); 695 b43_lo_write(dev, &d.min_loctl);
894 feedth = lo_measure_feedthrough(dev, phy->lna_gain, 696 feedth = lo_measure_feedthrough(dev, phy->lna_gain,
895 phy->pga_gain, 697 phy->pga_gain,
896 phy->trsw_rx_gain); 698 phy->trsw_rx_gain);
897 if (!lo->rebuild && feedth < 0x258) { 699 if (feedth < 0x258) {
898 if (feedth >= 0x12C) 700 if (feedth >= 0x12C)
899 *max_rx_gain += 6; 701 *max_rx_gain += 6;
900 else 702 else
@@ -944,278 +746,188 @@ static void lo_probe_loctls_statemachine(struct b43_wldev *dev,
944 } while (++repeat_cnt < max_repeat); 746 } while (++repeat_cnt < max_repeat);
945} 747}
946 748
947#if B43_CALIB_ALL_LOCTLS 749static
948static const struct b43_rfatt b43_full_rfatt_list_items[] = { 750struct b43_lo_calib * b43_calibrate_lo_setting(struct b43_wldev *dev,
949 { .att = 0, .with_padmix = 0, }, 751 const struct b43_bbatt *bbatt,
950 { .att = 1, .with_padmix = 0, }, 752 const struct b43_rfatt *rfatt)
951 { .att = 2, .with_padmix = 0, },
952 { .att = 3, .with_padmix = 0, },
953 { .att = 4, .with_padmix = 0, },
954 { .att = 5, .with_padmix = 0, },
955 { .att = 6, .with_padmix = 0, },
956 { .att = 7, .with_padmix = 0, },
957 { .att = 8, .with_padmix = 0, },
958 { .att = 9, .with_padmix = 0, },
959 { .att = 10, .with_padmix = 0, },
960 { .att = 11, .with_padmix = 0, },
961 { .att = 12, .with_padmix = 0, },
962 { .att = 13, .with_padmix = 0, },
963 { .att = 14, .with_padmix = 0, },
964 { .att = 15, .with_padmix = 0, },
965 { .att = 0, .with_padmix = 1, },
966 { .att = 1, .with_padmix = 1, },
967 { .att = 2, .with_padmix = 1, },
968 { .att = 3, .with_padmix = 1, },
969 { .att = 4, .with_padmix = 1, },
970 { .att = 5, .with_padmix = 1, },
971 { .att = 6, .with_padmix = 1, },
972 { .att = 7, .with_padmix = 1, },
973 { .att = 8, .with_padmix = 1, },
974 { .att = 9, .with_padmix = 1, },
975 { .att = 10, .with_padmix = 1, },
976 { .att = 11, .with_padmix = 1, },
977 { .att = 12, .with_padmix = 1, },
978 { .att = 13, .with_padmix = 1, },
979 { .att = 14, .with_padmix = 1, },
980 { .att = 15, .with_padmix = 1, },
981};
982static const struct b43_rfatt_list b43_full_rfatt_list = {
983 .list = b43_full_rfatt_list_items,
984 .len = ARRAY_SIZE(b43_full_rfatt_list_items),
985};
986
987static const struct b43_bbatt b43_full_bbatt_list_items[] = {
988 { .att = 0, },
989 { .att = 1, },
990 { .att = 2, },
991 { .att = 3, },
992 { .att = 4, },
993 { .att = 5, },
994 { .att = 6, },
995 { .att = 7, },
996 { .att = 8, },
997 { .att = 9, },
998 { .att = 10, },
999 { .att = 11, },
1000};
1001static const struct b43_bbatt_list b43_full_bbatt_list = {
1002 .list = b43_full_bbatt_list_items,
1003 .len = ARRAY_SIZE(b43_full_bbatt_list_items),
1004};
1005#endif /* B43_CALIB_ALL_LOCTLS */
1006
1007static void lo_measure(struct b43_wldev *dev)
1008{ 753{
1009 struct b43_phy *phy = &dev->phy; 754 struct b43_phy *phy = &dev->phy;
1010 struct b43_txpower_lo_control *lo = phy->lo_control;
1011 struct b43_loctl loctl = { 755 struct b43_loctl loctl = {
1012 .i = 0, 756 .i = 0,
1013 .q = 0, 757 .q = 0,
1014 }; 758 };
1015 struct b43_loctl *ploctl;
1016 int max_rx_gain; 759 int max_rx_gain;
1017 int rfidx, bbidx; 760 struct b43_lo_calib *cal;
1018 const struct b43_bbatt_list *bbatt_list; 761 struct lo_g_saved_values uninitialized_var(saved_regs);
1019 const struct b43_rfatt_list *rfatt_list;
1020
1021 /* Values from the "TXCTL Register and Value Table" */ 762 /* Values from the "TXCTL Register and Value Table" */
1022 u16 txctl_reg; 763 u16 txctl_reg;
1023 u16 txctl_value; 764 u16 txctl_value;
1024 u16 pad_mix_gain; 765 u16 pad_mix_gain;
1025 766
1026 bbatt_list = &lo->bbatt_list; 767 saved_regs.old_channel = phy->channel;
1027 rfatt_list = &lo->rfatt_list; 768 b43_mac_suspend(dev);
1028#if B43_CALIB_ALL_LOCTLS 769 lo_measure_setup(dev, &saved_regs);
1029 bbatt_list = &b43_full_bbatt_list;
1030 rfatt_list = &b43_full_rfatt_list;
1031#endif
1032 770
1033 txctl_reg = lo_txctl_register_table(dev, &txctl_value, &pad_mix_gain); 771 txctl_reg = lo_txctl_register_table(dev, &txctl_value, &pad_mix_gain);
1034 772
1035 for (rfidx = 0; rfidx < rfatt_list->len; rfidx++) { 773 b43_radio_write16(dev, 0x43,
1036 774 (b43_radio_read16(dev, 0x43) & 0xFFF0)
1037 b43_radio_write16(dev, 0x43, (b43_radio_read16(dev, 0x43) 775 | rfatt->att);
1038 & 0xFFF0) | 776 b43_radio_write16(dev, txctl_reg,
1039 rfatt_list->list[rfidx].att); 777 (b43_radio_read16(dev, txctl_reg) & ~txctl_value)
1040 b43_radio_write16(dev, txctl_reg, 778 | (rfatt->with_padmix) ? txctl_value : 0);
1041 (b43_radio_read16(dev, txctl_reg)
1042 & ~txctl_value)
1043 | (rfatt_list->list[rfidx].with_padmix ?
1044 txctl_value : 0));
1045
1046 for (bbidx = 0; bbidx < bbatt_list->len; bbidx++) {
1047 if (lo->rebuild) {
1048#if B43_CALIB_ALL_LOCTLS
1049 ploctl = b43_get_lo_g_ctl(dev,
1050 &rfatt_list->list[rfidx],
1051 &bbatt_list->list[bbidx]);
1052#else
1053 ploctl = b43_get_lo_g_ctl_nopadmix(dev,
1054 &rfatt_list->
1055 list[rfidx],
1056 &bbatt_list->
1057 list[bbidx]);
1058#endif
1059 } else {
1060 ploctl = b43_get_lo_g_ctl(dev,
1061 &rfatt_list->list[rfidx],
1062 &bbatt_list->list[bbidx]);
1063 if (!ploctl->used)
1064 continue;
1065 }
1066 memcpy(&loctl, ploctl, sizeof(loctl));
1067 loctl.i = 0;
1068 loctl.q = 0;
1069
1070 max_rx_gain = rfatt_list->list[rfidx].att * 2;
1071 max_rx_gain += bbatt_list->list[bbidx].att / 2;
1072 if (rfatt_list->list[rfidx].with_padmix)
1073 max_rx_gain -= pad_mix_gain;
1074 if (has_loopback_gain(phy))
1075 max_rx_gain += phy->max_lb_gain;
1076 lo_measure_gain_values(dev, max_rx_gain,
1077 has_loopback_gain(phy));
1078
1079 b43_phy_set_baseband_attenuation(dev,
1080 bbatt_list->list[bbidx].att);
1081 lo_probe_loctls_statemachine(dev, &loctl, &max_rx_gain);
1082 if (phy->type == B43_PHYTYPE_B) {
1083 loctl.i++;
1084 loctl.q++;
1085 }
1086 b43_loctl_set_calibrated(&loctl, 1);
1087 memcpy(ploctl, &loctl, sizeof(loctl));
1088 }
1089 }
1090}
1091
1092#if B43_DEBUG
1093static void do_validate_loctl(struct b43_wldev *dev, struct b43_loctl *control)
1094{
1095 const int is_initializing = (b43_status(dev) == B43_STAT_UNINIT);
1096 int i = control->i;
1097 int q = control->q;
1098 779
1099 if (b43_loctl_is_calibrated(control)) { 780 max_rx_gain = rfatt->att * 2;
1100 if ((abs(i) > 16) || (abs(q) > 16)) 781 max_rx_gain += bbatt->att / 2;
1101 goto error; 782 if (rfatt->with_padmix)
1102 } else { 783 max_rx_gain -= pad_mix_gain;
1103 if (control->used) 784 if (has_loopback_gain(phy))
1104 goto error; 785 max_rx_gain += phy->max_lb_gain;
1105 if (dev->phy.lo_control->rebuild) { 786 lo_measure_gain_values(dev, max_rx_gain,
1106 control->i = 0; 787 has_loopback_gain(phy));
1107 control->q = 0; 788
1108 if ((i != B43_LOCTL_POISON) || 789 b43_phy_set_baseband_attenuation(dev, bbatt->att);
1109 (q != B43_LOCTL_POISON)) 790 lo_probe_loctls_statemachine(dev, &loctl, &max_rx_gain);
1110 goto error; 791
1111 } 792 lo_measure_restore(dev, &saved_regs);
793 b43_mac_enable(dev);
794
795 if (b43_debug(dev, B43_DBG_LO)) {
796 b43dbg(dev->wl, "LO: Calibrated for BB(%u), RF(%u,%u) "
797 "=> I=%d Q=%d\n",
798 bbatt->att, rfatt->att, rfatt->with_padmix,
799 loctl.i, loctl.q);
1112 } 800 }
1113 if (is_initializing && control->used)
1114 goto error;
1115
1116 return;
1117error:
1118 b43err(dev->wl, "LO control pair validation failed "
1119 "(I: %d, Q: %d, used %u, calib: %u, initing: %d)\n",
1120 i, q, control->used,
1121 b43_loctl_is_calibrated(control),
1122 is_initializing);
1123}
1124 801
1125static void validate_all_loctls(struct b43_wldev *dev) 802 cal = kmalloc(sizeof(*cal), GFP_KERNEL);
1126{ 803 if (!cal) {
1127 b43_call_for_each_loctl(dev, do_validate_loctl); 804 b43warn(dev->wl, "LO calib: out of memory\n");
1128} 805 return NULL;
1129
1130static void do_reset_calib(struct b43_wldev *dev, struct b43_loctl *control)
1131{
1132 if (dev->phy.lo_control->rebuild ||
1133 control->used) {
1134 b43_loctl_set_calibrated(control, 0);
1135 control->i = B43_LOCTL_POISON;
1136 control->q = B43_LOCTL_POISON;
1137 } 806 }
807 memcpy(&cal->bbatt, bbatt, sizeof(*bbatt));
808 memcpy(&cal->rfatt, rfatt, sizeof(*rfatt));
809 memcpy(&cal->ctl, &loctl, sizeof(loctl));
810 cal->calib_time = jiffies;
811 INIT_LIST_HEAD(&cal->list);
812
813 return cal;
1138} 814}
1139 815
1140static void reset_all_loctl_calibration_states(struct b43_wldev *dev) 816/* Get a calibrated LO setting for the given attenuation values.
817 * Might return a NULL pointer under OOM! */
818static
819struct b43_lo_calib * b43_get_calib_lo_settings(struct b43_wldev *dev,
820 const struct b43_bbatt *bbatt,
821 const struct b43_rfatt *rfatt)
1141{ 822{
1142 b43_call_for_each_loctl(dev, do_reset_calib); 823 struct b43_txpower_lo_control *lo = dev->phy.lo_control;
824 struct b43_lo_calib *c;
825
826 c = b43_find_lo_calib(lo, bbatt, rfatt);
827 if (c)
828 return c;
829 /* Not in the list of calibrated LO settings.
830 * Calibrate it now. */
831 c = b43_calibrate_lo_setting(dev, bbatt, rfatt);
832 if (!c)
833 return NULL;
834 list_add(&c->list, &lo->calib_list);
835
836 return c;
1143} 837}
1144 838
1145#else /* B43_DEBUG */ 839void b43_gphy_dc_lt_init(struct b43_wldev *dev, bool update_all)
1146static inline void validate_all_loctls(struct b43_wldev *dev) { }
1147static inline void reset_all_loctl_calibration_states(struct b43_wldev *dev) { }
1148#endif /* B43_DEBUG */
1149
1150void b43_lo_g_measure(struct b43_wldev *dev)
1151{ 840{
1152 struct b43_phy *phy = &dev->phy; 841 struct b43_phy *phy = &dev->phy;
1153 struct lo_g_saved_values uninitialized_var(sav); 842 struct b43_txpower_lo_control *lo = phy->lo_control;
1154 843 int i;
1155 B43_WARN_ON((phy->type != B43_PHYTYPE_B) && 844 int rf_offset, bb_offset;
1156 (phy->type != B43_PHYTYPE_G)); 845 const struct b43_rfatt *rfatt;
1157 846 const struct b43_bbatt *bbatt;
1158 sav.old_channel = phy->channel; 847 u64 power_vector;
1159 lo_measure_setup(dev, &sav); 848 bool table_changed = 0;
1160 reset_all_loctl_calibration_states(dev);
1161 lo_measure(dev);
1162 lo_measure_restore(dev, &sav);
1163
1164 validate_all_loctls(dev);
1165 849
1166 phy->lo_control->lo_measured = 1; 850 BUILD_BUG_ON(B43_DC_LT_SIZE != 32);
1167 phy->lo_control->rebuild = 0; 851 B43_WARN_ON(lo->rfatt_list.len * lo->bbatt_list.len > 64);
1168}
1169 852
1170#if B43_DEBUG 853 power_vector = lo->power_vector;
1171static void validate_loctl_calibration(struct b43_wldev *dev, 854 if (!update_all && !power_vector)
1172 struct b43_loctl *loctl, 855 return; /* Nothing to do. */
1173 struct b43_rfatt *rfatt, 856
1174 struct b43_bbatt *bbatt) 857 /* Suspend the MAC now to avoid continuous suspend/enable
1175{ 858 * cycles in the loop. */
1176 if (b43_loctl_is_calibrated(loctl)) 859 b43_mac_suspend(dev);
1177 return; 860
1178 if (!dev->phy.lo_control->lo_measured) { 861 for (i = 0; i < B43_DC_LT_SIZE * 2; i++) {
1179 /* On init we set the attenuation values before we 862 struct b43_lo_calib *cal;
1180 * calibrated the LO. I guess that's OK. */ 863 int idx;
1181 return; 864 u16 val;
865
866 if (!update_all && !(power_vector & (((u64)1ULL) << i)))
867 continue;
868 /* Update the table entry for this power_vector bit.
869 * The table rows are RFatt entries and columns are BBatt. */
870 bb_offset = i / lo->rfatt_list.len;
871 rf_offset = i % lo->rfatt_list.len;
872 bbatt = &(lo->bbatt_list.list[bb_offset]);
873 rfatt = &(lo->rfatt_list.list[rf_offset]);
874
875 cal = b43_calibrate_lo_setting(dev, bbatt, rfatt);
876 if (!cal) {
877 b43warn(dev->wl, "LO: Could not "
878 "calibrate DC table entry\n");
879 continue;
880 }
881 /*FIXME: Is Q really in the low nibble? */
882 val = (u8)(cal->ctl.q);
883 val |= ((u8)(cal->ctl.i)) << 4;
884 kfree(cal);
885
886 /* Get the index into the hardware DC LT. */
887 idx = i / 2;
888 /* Change the table in memory. */
889 if (i % 2) {
890 /* Change the high byte. */
891 lo->dc_lt[idx] = (lo->dc_lt[idx] & 0x00FF)
892 | ((val & 0x00FF) << 8);
893 } else {
894 /* Change the low byte. */
895 lo->dc_lt[idx] = (lo->dc_lt[idx] & 0xFF00)
896 | (val & 0x00FF);
897 }
898 table_changed = 1;
1182 } 899 }
1183 b43err(dev->wl, "Adjusting Local Oscillator to an uncalibrated " 900 if (table_changed) {
1184 "control pair: rfatt=%u,%spadmix bbatt=%u\n", 901 /* The table changed in memory. Update the hardware table. */
1185 rfatt->att, 902 for (i = 0; i < B43_DC_LT_SIZE; i++)
1186 (rfatt->with_padmix) ? "" : "no-", 903 b43_phy_write(dev, 0x3A0 + i, lo->dc_lt[i]);
1187 bbatt->att); 904 }
1188} 905 b43_mac_enable(dev);
1189#else
1190static inline void validate_loctl_calibration(struct b43_wldev *dev,
1191 struct b43_loctl *loctl,
1192 struct b43_rfatt *rfatt,
1193 struct b43_bbatt *bbatt)
1194{
1195} 906}
1196#endif
1197 907
1198static inline void fixup_rfatt_for_txcontrol(struct b43_rfatt *rf, 908/* Fixup the RF attenuation value for the case where we are
1199 u8 tx_control) 909 * using the PAD mixer. */
910static inline void b43_lo_fixup_rfatt(struct b43_rfatt *rf)
1200{ 911{
1201 if (tx_control & B43_TXCTL_TXMIX) { 912 if (!rf->with_padmix)
1202 if (rf->att < 5) 913 return;
1203 rf->att = 4; 914 if ((rf->att != 1) && (rf->att != 2) && (rf->att != 3))
1204 } 915 rf->att = 4;
1205} 916}
1206 917
1207void b43_lo_g_adjust(struct b43_wldev *dev) 918void b43_lo_g_adjust(struct b43_wldev *dev)
1208{ 919{
1209 struct b43_phy *phy = &dev->phy; 920 struct b43_phy *phy = &dev->phy;
921 struct b43_lo_calib *cal;
1210 struct b43_rfatt rf; 922 struct b43_rfatt rf;
1211 struct b43_loctl *loctl;
1212 923
1213 memcpy(&rf, &phy->rfatt, sizeof(rf)); 924 memcpy(&rf, &phy->rfatt, sizeof(rf));
1214 fixup_rfatt_for_txcontrol(&rf, phy->tx_control); 925 b43_lo_fixup_rfatt(&rf);
1215 926
1216 loctl = b43_get_lo_g_ctl(dev, &rf, &phy->bbatt); 927 cal = b43_get_calib_lo_settings(dev, &phy->bbatt, &rf);
1217 validate_loctl_calibration(dev, loctl, &rf, &phy->bbatt); 928 if (!cal)
1218 b43_lo_write(dev, loctl); 929 return;
930 b43_lo_write(dev, &cal->ctl);
1219} 931}
1220 932
1221void b43_lo_g_adjust_to(struct b43_wldev *dev, 933void b43_lo_g_adjust_to(struct b43_wldev *dev,
@@ -1223,39 +935,102 @@ void b43_lo_g_adjust_to(struct b43_wldev *dev,
1223{ 935{
1224 struct b43_rfatt rf; 936 struct b43_rfatt rf;
1225 struct b43_bbatt bb; 937 struct b43_bbatt bb;
1226 struct b43_loctl *loctl; 938 struct b43_lo_calib *cal;
1227 939
1228 memset(&rf, 0, sizeof(rf)); 940 memset(&rf, 0, sizeof(rf));
1229 memset(&bb, 0, sizeof(bb)); 941 memset(&bb, 0, sizeof(bb));
1230 rf.att = rfatt; 942 rf.att = rfatt;
1231 bb.att = bbatt; 943 bb.att = bbatt;
1232 fixup_rfatt_for_txcontrol(&rf, tx_control); 944 b43_lo_fixup_rfatt(&rf);
1233 loctl = b43_get_lo_g_ctl(dev, &rf, &bb); 945 cal = b43_get_calib_lo_settings(dev, &bb, &rf);
1234 validate_loctl_calibration(dev, loctl, &rf, &bb); 946 if (!cal)
1235 b43_lo_write(dev, loctl); 947 return;
948 b43_lo_write(dev, &cal->ctl);
1236} 949}
1237 950
1238static void do_mark_unused(struct b43_wldev *dev, struct b43_loctl *control) 951/* Periodic LO maintanance work */
952void b43_lo_g_maintanance_work(struct b43_wldev *dev)
1239{ 953{
1240 control->used = 0; 954 struct b43_phy *phy = &dev->phy;
955 struct b43_txpower_lo_control *lo = phy->lo_control;
956 unsigned long now;
957 unsigned long expire;
958 struct b43_lo_calib *cal, *tmp;
959 bool current_item_expired = 0;
960 bool hwpctl;
961
962 if (!lo)
963 return;
964 now = jiffies;
965 hwpctl = b43_has_hardware_pctl(phy);
966
967 if (hwpctl) {
968 /* Read the power vector and update it, if needed. */
969 expire = now - B43_LO_PWRVEC_EXPIRE;
970 if (time_before(lo->pwr_vec_read_time, expire)) {
971 lo_read_power_vector(dev);
972 b43_gphy_dc_lt_init(dev, 0);
973 }
974 //FIXME Recalc the whole DC table from time to time?
975 }
976
977 if (hwpctl)
978 return;
979 /* Search for expired LO settings. Remove them.
980 * Recalibrate the current setting, if expired. */
981 expire = now - B43_LO_CALIB_EXPIRE;
982 list_for_each_entry_safe(cal, tmp, &lo->calib_list, list) {
983 if (!time_before(cal->calib_time, expire))
984 continue;
985 /* This item expired. */
986 if (b43_compare_bbatt(&cal->bbatt, &phy->bbatt) &&
987 b43_compare_rfatt(&cal->rfatt, &phy->rfatt)) {
988 B43_WARN_ON(current_item_expired);
989 current_item_expired = 1;
990 }
991 if (b43_debug(dev, B43_DBG_LO)) {
992 b43dbg(dev->wl, "LO: Item BB(%u), RF(%u,%u), "
993 "I=%d, Q=%d expired\n",
994 cal->bbatt.att, cal->rfatt.att,
995 cal->rfatt.with_padmix,
996 cal->ctl.i, cal->ctl.q);
997 }
998 list_del(&cal->list);
999 kfree(cal);
1000 }
1001 if (current_item_expired || unlikely(list_empty(&lo->calib_list))) {
1002 /* Recalibrate currently used LO setting. */
1003 if (b43_debug(dev, B43_DBG_LO))
1004 b43dbg(dev->wl, "LO: Recalibrating current LO setting\n");
1005 cal = b43_calibrate_lo_setting(dev, &phy->bbatt, &phy->rfatt);
1006 if (cal) {
1007 list_add(&cal->list, &lo->calib_list);
1008 b43_lo_write(dev, &cal->ctl);
1009 } else
1010 b43warn(dev->wl, "Failed to recalibrate current LO setting\n");
1011 }
1241} 1012}
1242 1013
1243void b43_lo_g_ctl_mark_all_unused(struct b43_wldev *dev) 1014void b43_lo_g_cleanup(struct b43_wldev *dev)
1244{ 1015{
1245 struct b43_phy *phy = &dev->phy; 1016 struct b43_txpower_lo_control *lo = dev->phy.lo_control;
1246 struct b43_txpower_lo_control *lo = phy->lo_control; 1017 struct b43_lo_calib *cal, *tmp;
1247 1018
1248 b43_call_for_each_loctl(dev, do_mark_unused); 1019 if (!lo)
1249 lo->rebuild = 1; 1020 return;
1021 list_for_each_entry_safe(cal, tmp, &lo->calib_list, list) {
1022 list_del(&cal->list);
1023 kfree(cal);
1024 }
1250} 1025}
1251 1026
1252void b43_lo_g_ctl_mark_cur_used(struct b43_wldev *dev) 1027/* LO Initialization */
1028void b43_lo_g_init(struct b43_wldev *dev)
1253{ 1029{
1254 struct b43_phy *phy = &dev->phy; 1030 struct b43_phy *phy = &dev->phy;
1255 struct b43_rfatt rf;
1256 1031
1257 memcpy(&rf, &phy->rfatt, sizeof(rf)); 1032 if (b43_has_hardware_pctl(phy)) {
1258 fixup_rfatt_for_txcontrol(&rf, phy->tx_control); 1033 lo_read_power_vector(dev);
1259 1034 b43_gphy_dc_lt_init(dev, 1);
1260 b43_get_lo_g_ctl(dev, &rf, &phy->bbatt)->used = 1; 1035 }
1261} 1036}