1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 4 Broadcom B43 wireless driver 5 6 G PHY LO (LocalOscillator) Measuring and Control routines 7 8 Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>, 9 Copyright (c) 2005, 2006 Stefano Brivio <stefano.brivio@polimi.it> 10 Copyright (c) 2005-2007 Michael Buesch <m@bues.ch> 11 Copyright (c) 2005, 2006 Danny van Dyk <kugelfang@gentoo.org> 12 Copyright (c) 2005, 2006 Andreas Jaggi <andreas.jaggi@waterwave.ch> 13 14 15 */ 16 17 #include "b43.h" 18 #include "lo.h" 19 #include "phy_g.h" 20 #include "main.h" 21 22 #include <linux/delay.h> 23 #include <linux/sched.h> 24 #include <linux/slab.h> 25 26 27 static struct b43_lo_calib *b43_find_lo_calib(struct b43_txpower_lo_control *lo, 28 const struct b43_bbatt *bbatt, 29 const struct b43_rfatt *rfatt) 30 { 31 struct b43_lo_calib *c; 32 33 list_for_each_entry(c, &lo->calib_list, list) { 34 if (!b43_compare_bbatt(&c->bbatt, bbatt)) 35 continue; 36 if (!b43_compare_rfatt(&c->rfatt, rfatt)) 37 continue; 38 return c; 39 } 40 41 return NULL; 42 } 43 44 /* Write the LocalOscillator Control (adjust) value-pair. */ 45 static void b43_lo_write(struct b43_wldev *dev, struct b43_loctl *control) 46 { 47 struct b43_phy *phy = &dev->phy; 48 u16 value; 49 50 if (B43_DEBUG) { 51 if (unlikely(abs(control->i) > 16 || abs(control->q) > 16)) { 52 b43dbg(dev->wl, "Invalid LO control pair " 53 "(I: %d, Q: %d)\n", control->i, control->q); 54 dump_stack(); 55 return; 56 } 57 } 58 B43_WARN_ON(phy->type != B43_PHYTYPE_G); 59 60 value = (u8) (control->q); 61 value |= ((u8) (control->i)) << 8; 62 b43_phy_write(dev, B43_PHY_LO_CTL, value); 63 } 64 65 static u16 lo_measure_feedthrough(struct b43_wldev *dev, 66 u16 lna, u16 pga, u16 trsw_rx) 67 { 68 struct b43_phy *phy = &dev->phy; 69 u16 rfover; 70 u16 feedthrough; 71 72 if (phy->gmode) { 73 lna <<= B43_PHY_RFOVERVAL_LNA_SHIFT; 74 pga <<= B43_PHY_RFOVERVAL_PGA_SHIFT; 75 76 B43_WARN_ON(lna & ~B43_PHY_RFOVERVAL_LNA); 77 B43_WARN_ON(pga & ~B43_PHY_RFOVERVAL_PGA); 78 /*FIXME This assertion fails B43_WARN_ON(trsw_rx & ~(B43_PHY_RFOVERVAL_TRSWRX | 79 B43_PHY_RFOVERVAL_BW)); 80 */ 81 trsw_rx &= (B43_PHY_RFOVERVAL_TRSWRX | B43_PHY_RFOVERVAL_BW); 82 83 /* Construct the RF Override Value */ 84 rfover = B43_PHY_RFOVERVAL_UNK; 85 rfover |= pga; 86 rfover |= lna; 87 rfover |= trsw_rx; 88 if ((dev->dev->bus_sprom->boardflags_lo & B43_BFL_EXTLNA) 89 && phy->rev > 6) 90 rfover |= B43_PHY_RFOVERVAL_EXTLNA; 91 92 b43_phy_write(dev, B43_PHY_PGACTL, 0xE300); 93 b43_phy_write(dev, B43_PHY_RFOVERVAL, rfover); 94 udelay(10); 95 rfover |= B43_PHY_RFOVERVAL_BW_LBW; 96 b43_phy_write(dev, B43_PHY_RFOVERVAL, rfover); 97 udelay(10); 98 rfover |= B43_PHY_RFOVERVAL_BW_LPF; 99 b43_phy_write(dev, B43_PHY_RFOVERVAL, rfover); 100 udelay(10); 101 b43_phy_write(dev, B43_PHY_PGACTL, 0xF300); 102 } else { 103 pga |= B43_PHY_PGACTL_UNKNOWN; 104 b43_phy_write(dev, B43_PHY_PGACTL, pga); 105 udelay(10); 106 pga |= B43_PHY_PGACTL_LOWBANDW; 107 b43_phy_write(dev, B43_PHY_PGACTL, pga); 108 udelay(10); 109 pga |= B43_PHY_PGACTL_LPF; 110 b43_phy_write(dev, B43_PHY_PGACTL, pga); 111 } 112 udelay(21); 113 feedthrough = b43_phy_read(dev, B43_PHY_LO_LEAKAGE); 114 115 /* This is a good place to check if we need to relax a bit, 116 * as this is the main function called regularly 117 * in the LO calibration. */ 118 cond_resched(); 119 120 return feedthrough; 121 } 122 123 /* TXCTL Register and Value Table. 124 * Returns the "TXCTL Register". 125 * "value" is the "TXCTL Value". 126 * "pad_mix_gain" is the PAD Mixer Gain. 127 */ 128 static u16 lo_txctl_register_table(struct b43_wldev *dev, 129 u16 *value, u16 *pad_mix_gain) 130 { 131 struct b43_phy *phy = &dev->phy; 132 u16 reg, v, padmix; 133 134 if (phy->type == B43_PHYTYPE_B) { 135 v = 0x30; 136 if (phy->radio_rev <= 5) { 137 reg = 0x43; 138 padmix = 0; 139 } else { 140 reg = 0x52; 141 padmix = 5; 142 } 143 } else { 144 if (phy->rev >= 2 && phy->radio_rev == 8) { 145 reg = 0x43; 146 v = 0x10; 147 padmix = 2; 148 } else { 149 reg = 0x52; 150 v = 0x30; 151 padmix = 5; 152 } 153 } 154 if (value) 155 *value = v; 156 if (pad_mix_gain) 157 *pad_mix_gain = padmix; 158 159 return reg; 160 } 161 162 static void lo_measure_txctl_values(struct b43_wldev *dev) 163 { 164 struct b43_phy *phy = &dev->phy; 165 struct b43_phy_g *gphy = phy->g; 166 struct b43_txpower_lo_control *lo = gphy->lo_control; 167 u16 reg, mask; 168 u16 trsw_rx, pga; 169 u16 radio_pctl_reg; 170 171 static const u8 tx_bias_values[] = { 172 0x09, 0x08, 0x0A, 0x01, 0x00, 173 0x02, 0x05, 0x04, 0x06, 174 }; 175 static const u8 tx_magn_values[] = { 176 0x70, 0x40, 177 }; 178 179 if (!has_loopback_gain(phy)) { 180 radio_pctl_reg = 6; 181 trsw_rx = 2; 182 pga = 0; 183 } else { 184 int lb_gain; /* Loopback gain (in dB) */ 185 186 trsw_rx = 0; 187 lb_gain = gphy->max_lb_gain / 2; 188 if (lb_gain > 10) { 189 radio_pctl_reg = 0; 190 pga = abs(10 - lb_gain) / 6; 191 pga = clamp_val(pga, 0, 15); 192 } else { 193 int cmp_val; 194 int tmp; 195 196 pga = 0; 197 cmp_val = 0x24; 198 if ((phy->rev >= 2) && 199 (phy->radio_ver == 0x2050) && (phy->radio_rev == 8)) 200 cmp_val = 0x3C; 201 tmp = lb_gain; 202 if ((10 - lb_gain) < cmp_val) 203 tmp = (10 - lb_gain); 204 if (tmp < 0) 205 tmp += 6; 206 else 207 tmp += 3; 208 cmp_val /= 4; 209 tmp /= 4; 210 if (tmp >= cmp_val) 211 radio_pctl_reg = cmp_val; 212 else 213 radio_pctl_reg = tmp; 214 } 215 } 216 b43_radio_maskset(dev, 0x43, 0xFFF0, radio_pctl_reg); 217 b43_gphy_set_baseband_attenuation(dev, 2); 218 219 reg = lo_txctl_register_table(dev, &mask, NULL); 220 mask = ~mask; 221 b43_radio_mask(dev, reg, mask); 222 223 if (has_tx_magnification(phy)) { 224 int i, j; 225 int feedthrough; 226 int min_feedth = 0xFFFF; 227 u8 tx_magn, tx_bias; 228 229 for (i = 0; i < ARRAY_SIZE(tx_magn_values); i++) { 230 tx_magn = tx_magn_values[i]; 231 b43_radio_maskset(dev, 0x52, 0xFF0F, tx_magn); 232 for (j = 0; j < ARRAY_SIZE(tx_bias_values); j++) { 233 tx_bias = tx_bias_values[j]; 234 b43_radio_maskset(dev, 0x52, 0xFFF0, tx_bias); 235 feedthrough = 236 lo_measure_feedthrough(dev, 0, pga, 237 trsw_rx); 238 if (feedthrough < min_feedth) { 239 lo->tx_bias = tx_bias; 240 lo->tx_magn = tx_magn; 241 min_feedth = feedthrough; 242 } 243 if (lo->tx_bias == 0) 244 break; 245 } 246 b43_radio_write16(dev, 0x52, 247 (b43_radio_read16(dev, 0x52) 248 & 0xFF00) | lo->tx_bias | lo-> 249 tx_magn); 250 } 251 } else { 252 lo->tx_magn = 0; 253 lo->tx_bias = 0; 254 b43_radio_mask(dev, 0x52, 0xFFF0); /* TX bias == 0 */ 255 } 256 lo->txctl_measured_time = jiffies; 257 } 258 259 static void lo_read_power_vector(struct b43_wldev *dev) 260 { 261 struct b43_phy *phy = &dev->phy; 262 struct b43_phy_g *gphy = phy->g; 263 struct b43_txpower_lo_control *lo = gphy->lo_control; 264 int i; 265 u64 tmp; 266 u64 power_vector = 0; 267 268 for (i = 0; i < 8; i += 2) { 269 tmp = b43_shm_read16(dev, B43_SHM_SHARED, 0x310 + i); 270 power_vector |= (tmp << (i * 8)); 271 /* Clear the vector on the device. */ 272 b43_shm_write16(dev, B43_SHM_SHARED, 0x310 + i, 0); 273 } 274 if (power_vector) 275 lo->power_vector = power_vector; 276 lo->pwr_vec_read_time = jiffies; 277 } 278 279 /* 802.11/LO/GPHY/MeasuringGains */ 280 static void lo_measure_gain_values(struct b43_wldev *dev, 281 s16 max_rx_gain, int use_trsw_rx) 282 { 283 struct b43_phy *phy = &dev->phy; 284 struct b43_phy_g *gphy = phy->g; 285 u16 tmp; 286 287 if (max_rx_gain < 0) 288 max_rx_gain = 0; 289 290 if (has_loopback_gain(phy)) { 291 int trsw_rx_gain; 292 293 if (use_trsw_rx) { 294 trsw_rx_gain = gphy->trsw_rx_gain / 2; 295 if (max_rx_gain >= trsw_rx_gain) { 296 trsw_rx_gain = max_rx_gain - trsw_rx_gain; 297 } 298 } else 299 trsw_rx_gain = max_rx_gain; 300 if (trsw_rx_gain < 9) { 301 gphy->lna_lod_gain = 0; 302 } else { 303 gphy->lna_lod_gain = 1; 304 trsw_rx_gain -= 8; 305 } 306 trsw_rx_gain = clamp_val(trsw_rx_gain, 0, 0x2D); 307 gphy->pga_gain = trsw_rx_gain / 3; 308 if (gphy->pga_gain >= 5) { 309 gphy->pga_gain -= 5; 310 gphy->lna_gain = 2; 311 } else 312 gphy->lna_gain = 0; 313 } else { 314 gphy->lna_gain = 0; 315 gphy->trsw_rx_gain = 0x20; 316 if (max_rx_gain >= 0x14) { 317 gphy->lna_lod_gain = 1; 318 gphy->pga_gain = 2; 319 } else if (max_rx_gain >= 0x12) { 320 gphy->lna_lod_gain = 1; 321 gphy->pga_gain = 1; 322 } else if (max_rx_gain >= 0xF) { 323 gphy->lna_lod_gain = 1; 324 gphy->pga_gain = 0; 325 } else { 326 gphy->lna_lod_gain = 0; 327 gphy->pga_gain = 0; 328 } 329 } 330 331 tmp = b43_radio_read16(dev, 0x7A); 332 if (gphy->lna_lod_gain == 0) 333 tmp &= ~0x0008; 334 else 335 tmp |= 0x0008; 336 b43_radio_write16(dev, 0x7A, tmp); 337 } 338 339 struct lo_g_saved_values { 340 u8 old_channel; 341 342 /* Core registers */ 343 u16 reg_3F4; 344 u16 reg_3E2; 345 346 /* PHY registers */ 347 u16 phy_lo_mask; 348 u16 phy_extg_01; 349 u16 phy_dacctl_hwpctl; 350 u16 phy_dacctl; 351 u16 phy_cck_14; 352 u16 phy_hpwr_tssictl; 353 u16 phy_analogover; 354 u16 phy_analogoverval; 355 u16 phy_rfover; 356 u16 phy_rfoverval; 357 u16 phy_classctl; 358 u16 phy_cck_3E; 359 u16 phy_crs0; 360 u16 phy_pgactl; 361 u16 phy_cck_2A; 362 u16 phy_syncctl; 363 u16 phy_cck_30; 364 u16 phy_cck_06; 365 366 /* Radio registers */ 367 u16 radio_43; 368 u16 radio_7A; 369 u16 radio_52; 370 }; 371 372 static void lo_measure_setup(struct b43_wldev *dev, 373 struct lo_g_saved_values *sav) 374 { 375 struct ssb_sprom *sprom = dev->dev->bus_sprom; 376 struct b43_phy *phy = &dev->phy; 377 struct b43_phy_g *gphy = phy->g; 378 struct b43_txpower_lo_control *lo = gphy->lo_control; 379 u16 tmp; 380 381 if (b43_has_hardware_pctl(dev)) { 382 sav->phy_lo_mask = b43_phy_read(dev, B43_PHY_LO_MASK); 383 sav->phy_extg_01 = b43_phy_read(dev, B43_PHY_EXTG(0x01)); 384 sav->phy_dacctl_hwpctl = b43_phy_read(dev, B43_PHY_DACCTL); 385 sav->phy_cck_14 = b43_phy_read(dev, B43_PHY_CCK(0x14)); 386 sav->phy_hpwr_tssictl = b43_phy_read(dev, B43_PHY_HPWR_TSSICTL); 387 388 b43_phy_set(dev, B43_PHY_HPWR_TSSICTL, 0x100); 389 b43_phy_set(dev, B43_PHY_EXTG(0x01), 0x40); 390 b43_phy_set(dev, B43_PHY_DACCTL, 0x40); 391 b43_phy_set(dev, B43_PHY_CCK(0x14), 0x200); 392 } 393 if (phy->type == B43_PHYTYPE_B && 394 phy->radio_ver == 0x2050 && phy->radio_rev < 6) { 395 b43_phy_write(dev, B43_PHY_CCK(0x16), 0x410); 396 b43_phy_write(dev, B43_PHY_CCK(0x17), 0x820); 397 } 398 if (phy->rev >= 2) { 399 sav->phy_analogover = b43_phy_read(dev, B43_PHY_ANALOGOVER); 400 sav->phy_analogoverval = 401 b43_phy_read(dev, B43_PHY_ANALOGOVERVAL); 402 sav->phy_rfover = b43_phy_read(dev, B43_PHY_RFOVER); 403 sav->phy_rfoverval = b43_phy_read(dev, B43_PHY_RFOVERVAL); 404 sav->phy_classctl = b43_phy_read(dev, B43_PHY_CLASSCTL); 405 sav->phy_cck_3E = b43_phy_read(dev, B43_PHY_CCK(0x3E)); 406 sav->phy_crs0 = b43_phy_read(dev, B43_PHY_CRS0); 407 408 b43_phy_mask(dev, B43_PHY_CLASSCTL, 0xFFFC); 409 b43_phy_mask(dev, B43_PHY_CRS0, 0x7FFF); 410 b43_phy_set(dev, B43_PHY_ANALOGOVER, 0x0003); 411 b43_phy_mask(dev, B43_PHY_ANALOGOVERVAL, 0xFFFC); 412 if (phy->type == B43_PHYTYPE_G) { 413 if ((phy->rev >= 7) && 414 (sprom->boardflags_lo & B43_BFL_EXTLNA)) { 415 b43_phy_write(dev, B43_PHY_RFOVER, 0x933); 416 } else { 417 b43_phy_write(dev, B43_PHY_RFOVER, 0x133); 418 } 419 } else { 420 b43_phy_write(dev, B43_PHY_RFOVER, 0); 421 } 422 b43_phy_write(dev, B43_PHY_CCK(0x3E), 0); 423 } 424 sav->reg_3F4 = b43_read16(dev, 0x3F4); 425 sav->reg_3E2 = b43_read16(dev, 0x3E2); 426 sav->radio_43 = b43_radio_read16(dev, 0x43); 427 sav->radio_7A = b43_radio_read16(dev, 0x7A); 428 sav->phy_pgactl = b43_phy_read(dev, B43_PHY_PGACTL); 429 sav->phy_cck_2A = b43_phy_read(dev, B43_PHY_CCK(0x2A)); 430 sav->phy_syncctl = b43_phy_read(dev, B43_PHY_SYNCCTL); 431 sav->phy_dacctl = b43_phy_read(dev, B43_PHY_DACCTL); 432 433 if (!has_tx_magnification(phy)) { 434 sav->radio_52 = b43_radio_read16(dev, 0x52); 435 sav->radio_52 &= 0x00F0; 436 } 437 if (phy->type == B43_PHYTYPE_B) { 438 sav->phy_cck_30 = b43_phy_read(dev, B43_PHY_CCK(0x30)); 439 sav->phy_cck_06 = b43_phy_read(dev, B43_PHY_CCK(0x06)); 440 b43_phy_write(dev, B43_PHY_CCK(0x30), 0x00FF); 441 b43_phy_write(dev, B43_PHY_CCK(0x06), 0x3F3F); 442 } else { 443 b43_write16(dev, 0x3E2, b43_read16(dev, 0x3E2) 444 | 0x8000); 445 } 446 b43_write16(dev, 0x3F4, b43_read16(dev, 0x3F4) 447 & 0xF000); 448 449 tmp = 450 (phy->type == B43_PHYTYPE_G) ? B43_PHY_LO_MASK : B43_PHY_CCK(0x2E); 451 b43_phy_write(dev, tmp, 0x007F); 452 453 tmp = sav->phy_syncctl; 454 b43_phy_write(dev, B43_PHY_SYNCCTL, tmp & 0xFF7F); 455 tmp = sav->radio_7A; 456 b43_radio_write16(dev, 0x007A, tmp & 0xFFF0); 457 458 b43_phy_write(dev, B43_PHY_CCK(0x2A), 0x8A3); 459 if (phy->type == B43_PHYTYPE_G || 460 (phy->type == B43_PHYTYPE_B && 461 phy->radio_ver == 0x2050 && phy->radio_rev >= 6)) { 462 b43_phy_write(dev, B43_PHY_CCK(0x2B), 0x1003); 463 } else 464 b43_phy_write(dev, B43_PHY_CCK(0x2B), 0x0802); 465 if (phy->rev >= 2) 466 b43_dummy_transmission(dev, false, true); 467 b43_gphy_channel_switch(dev, 6, 0); 468 b43_radio_read16(dev, 0x51); /* dummy read */ 469 if (phy->type == B43_PHYTYPE_G) 470 b43_phy_write(dev, B43_PHY_CCK(0x2F), 0); 471 472 /* Re-measure the txctl values, if needed. */ 473 if (time_before(lo->txctl_measured_time, 474 jiffies - B43_LO_TXCTL_EXPIRE)) 475 lo_measure_txctl_values(dev); 476 477 if (phy->type == B43_PHYTYPE_G && phy->rev >= 3) { 478 b43_phy_write(dev, B43_PHY_LO_MASK, 0xC078); 479 } else { 480 if (phy->type == B43_PHYTYPE_B) 481 b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x8078); 482 else 483 b43_phy_write(dev, B43_PHY_LO_MASK, 0x8078); 484 } 485 } 486 487 static void lo_measure_restore(struct b43_wldev *dev, 488 struct lo_g_saved_values *sav) 489 { 490 struct b43_phy *phy = &dev->phy; 491 struct b43_phy_g *gphy = phy->g; 492 u16 tmp; 493 494 if (phy->rev >= 2) { 495 b43_phy_write(dev, B43_PHY_PGACTL, 0xE300); 496 tmp = (gphy->pga_gain << 8); 497 b43_phy_write(dev, B43_PHY_RFOVERVAL, tmp | 0xA0); 498 udelay(5); 499 b43_phy_write(dev, B43_PHY_RFOVERVAL, tmp | 0xA2); 500 udelay(2); 501 b43_phy_write(dev, B43_PHY_RFOVERVAL, tmp | 0xA3); 502 } else { 503 tmp = (gphy->pga_gain | 0xEFA0); 504 b43_phy_write(dev, B43_PHY_PGACTL, tmp); 505 } 506 if (phy->type == B43_PHYTYPE_G) { 507 if (phy->rev >= 3) 508 b43_phy_write(dev, B43_PHY_CCK(0x2E), 0xC078); 509 else 510 b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x8078); 511 if (phy->rev >= 2) 512 b43_phy_write(dev, B43_PHY_CCK(0x2F), 0x0202); 513 else 514 b43_phy_write(dev, B43_PHY_CCK(0x2F), 0x0101); 515 } 516 b43_write16(dev, 0x3F4, sav->reg_3F4); 517 b43_phy_write(dev, B43_PHY_PGACTL, sav->phy_pgactl); 518 b43_phy_write(dev, B43_PHY_CCK(0x2A), sav->phy_cck_2A); 519 b43_phy_write(dev, B43_PHY_SYNCCTL, sav->phy_syncctl); 520 b43_phy_write(dev, B43_PHY_DACCTL, sav->phy_dacctl); 521 b43_radio_write16(dev, 0x43, sav->radio_43); 522 b43_radio_write16(dev, 0x7A, sav->radio_7A); 523 if (!has_tx_magnification(phy)) { 524 tmp = sav->radio_52; 525 b43_radio_maskset(dev, 0x52, 0xFF0F, tmp); 526 } 527 b43_write16(dev, 0x3E2, sav->reg_3E2); 528 if (phy->type == B43_PHYTYPE_B && 529 phy->radio_ver == 0x2050 && phy->radio_rev <= 5) { 530 b43_phy_write(dev, B43_PHY_CCK(0x30), sav->phy_cck_30); 531 b43_phy_write(dev, B43_PHY_CCK(0x06), sav->phy_cck_06); 532 } 533 if (phy->rev >= 2) { 534 b43_phy_write(dev, B43_PHY_ANALOGOVER, sav->phy_analogover); 535 b43_phy_write(dev, B43_PHY_ANALOGOVERVAL, 536 sav->phy_analogoverval); 537 b43_phy_write(dev, B43_PHY_CLASSCTL, sav->phy_classctl); 538 b43_phy_write(dev, B43_PHY_RFOVER, sav->phy_rfover); 539 b43_phy_write(dev, B43_PHY_RFOVERVAL, sav->phy_rfoverval); 540 b43_phy_write(dev, B43_PHY_CCK(0x3E), sav->phy_cck_3E); 541 b43_phy_write(dev, B43_PHY_CRS0, sav->phy_crs0); 542 } 543 if (b43_has_hardware_pctl(dev)) { 544 tmp = (sav->phy_lo_mask & 0xBFFF); 545 b43_phy_write(dev, B43_PHY_LO_MASK, tmp); 546 b43_phy_write(dev, B43_PHY_EXTG(0x01), sav->phy_extg_01); 547 b43_phy_write(dev, B43_PHY_DACCTL, sav->phy_dacctl_hwpctl); 548 b43_phy_write(dev, B43_PHY_CCK(0x14), sav->phy_cck_14); 549 b43_phy_write(dev, B43_PHY_HPWR_TSSICTL, sav->phy_hpwr_tssictl); 550 } 551 b43_gphy_channel_switch(dev, sav->old_channel, 1); 552 } 553 554 struct b43_lo_g_statemachine { 555 int current_state; 556 int nr_measured; 557 int state_val_multiplier; 558 u16 lowest_feedth; 559 struct b43_loctl min_loctl; 560 }; 561 562 /* Loop over each possible value in this state. */ 563 static int lo_probe_possible_loctls(struct b43_wldev *dev, 564 struct b43_loctl *probe_loctl, 565 struct b43_lo_g_statemachine *d) 566 { 567 struct b43_phy *phy = &dev->phy; 568 struct b43_phy_g *gphy = phy->g; 569 struct b43_loctl test_loctl; 570 struct b43_loctl orig_loctl; 571 struct b43_loctl prev_loctl = { 572 .i = -100, 573 .q = -100, 574 }; 575 int i; 576 int begin, end; 577 int found_lower = 0; 578 u16 feedth; 579 580 static const struct b43_loctl modifiers[] = { 581 {.i = 1,.q = 1,}, 582 {.i = 1,.q = 0,}, 583 {.i = 1,.q = -1,}, 584 {.i = 0,.q = -1,}, 585 {.i = -1,.q = -1,}, 586 {.i = -1,.q = 0,}, 587 {.i = -1,.q = 1,}, 588 {.i = 0,.q = 1,}, 589 }; 590 591 if (d->current_state == 0) { 592 begin = 1; 593 end = 8; 594 } else if (d->current_state % 2 == 0) { 595 begin = d->current_state - 1; 596 end = d->current_state + 1; 597 } else { 598 begin = d->current_state - 2; 599 end = d->current_state + 2; 600 } 601 if (begin < 1) 602 begin += 8; 603 if (end > 8) 604 end -= 8; 605 606 memcpy(&orig_loctl, probe_loctl, sizeof(struct b43_loctl)); 607 i = begin; 608 d->current_state = i; 609 while (1) { 610 B43_WARN_ON(!(i >= 1 && i <= 8)); 611 memcpy(&test_loctl, &orig_loctl, sizeof(struct b43_loctl)); 612 test_loctl.i += modifiers[i - 1].i * d->state_val_multiplier; 613 test_loctl.q += modifiers[i - 1].q * d->state_val_multiplier; 614 if ((test_loctl.i != prev_loctl.i || 615 test_loctl.q != prev_loctl.q) && 616 (abs(test_loctl.i) <= 16 && abs(test_loctl.q) <= 16)) { 617 b43_lo_write(dev, &test_loctl); 618 feedth = lo_measure_feedthrough(dev, gphy->lna_gain, 619 gphy->pga_gain, 620 gphy->trsw_rx_gain); 621 if (feedth < d->lowest_feedth) { 622 memcpy(probe_loctl, &test_loctl, 623 sizeof(struct b43_loctl)); 624 found_lower = 1; 625 d->lowest_feedth = feedth; 626 if ((d->nr_measured < 2) && 627 !has_loopback_gain(phy)) 628 break; 629 } 630 } 631 memcpy(&prev_loctl, &test_loctl, sizeof(prev_loctl)); 632 if (i == end) 633 break; 634 if (i == 8) 635 i = 1; 636 else 637 i++; 638 d->current_state = i; 639 } 640 641 return found_lower; 642 } 643 644 static void lo_probe_loctls_statemachine(struct b43_wldev *dev, 645 struct b43_loctl *loctl, 646 int *max_rx_gain) 647 { 648 struct b43_phy *phy = &dev->phy; 649 struct b43_phy_g *gphy = phy->g; 650 struct b43_lo_g_statemachine d; 651 u16 feedth; 652 int found_lower; 653 struct b43_loctl probe_loctl; 654 int max_repeat = 1, repeat_cnt = 0; 655 656 d.nr_measured = 0; 657 d.state_val_multiplier = 1; 658 if (has_loopback_gain(phy)) 659 d.state_val_multiplier = 3; 660 661 memcpy(&d.min_loctl, loctl, sizeof(struct b43_loctl)); 662 if (has_loopback_gain(phy)) 663 max_repeat = 4; 664 do { 665 b43_lo_write(dev, &d.min_loctl); 666 feedth = lo_measure_feedthrough(dev, gphy->lna_gain, 667 gphy->pga_gain, 668 gphy->trsw_rx_gain); 669 if (feedth < 0x258) { 670 if (feedth >= 0x12C) 671 *max_rx_gain += 6; 672 else 673 *max_rx_gain += 3; 674 feedth = lo_measure_feedthrough(dev, gphy->lna_gain, 675 gphy->pga_gain, 676 gphy->trsw_rx_gain); 677 } 678 d.lowest_feedth = feedth; 679 680 d.current_state = 0; 681 do { 682 B43_WARN_ON(! 683 (d.current_state >= 0 684 && d.current_state <= 8)); 685 memcpy(&probe_loctl, &d.min_loctl, 686 sizeof(struct b43_loctl)); 687 found_lower = 688 lo_probe_possible_loctls(dev, &probe_loctl, &d); 689 if (!found_lower) 690 break; 691 if ((probe_loctl.i == d.min_loctl.i) && 692 (probe_loctl.q == d.min_loctl.q)) 693 break; 694 memcpy(&d.min_loctl, &probe_loctl, 695 sizeof(struct b43_loctl)); 696 d.nr_measured++; 697 } while (d.nr_measured < 24); 698 memcpy(loctl, &d.min_loctl, sizeof(struct b43_loctl)); 699 700 if (has_loopback_gain(phy)) { 701 if (d.lowest_feedth > 0x1194) 702 *max_rx_gain -= 6; 703 else if (d.lowest_feedth < 0x5DC) 704 *max_rx_gain += 3; 705 if (repeat_cnt == 0) { 706 if (d.lowest_feedth <= 0x5DC) { 707 d.state_val_multiplier = 1; 708 repeat_cnt++; 709 } else 710 d.state_val_multiplier = 2; 711 } else if (repeat_cnt == 2) 712 d.state_val_multiplier = 1; 713 } 714 lo_measure_gain_values(dev, *max_rx_gain, 715 has_loopback_gain(phy)); 716 } while (++repeat_cnt < max_repeat); 717 } 718 719 static 720 struct b43_lo_calib *b43_calibrate_lo_setting(struct b43_wldev *dev, 721 const struct b43_bbatt *bbatt, 722 const struct b43_rfatt *rfatt) 723 { 724 struct b43_phy *phy = &dev->phy; 725 struct b43_phy_g *gphy = phy->g; 726 struct b43_loctl loctl = { 727 .i = 0, 728 .q = 0, 729 }; 730 int max_rx_gain; 731 struct b43_lo_calib *cal; 732 struct lo_g_saved_values saved_regs; 733 /* Values from the "TXCTL Register and Value Table" */ 734 u16 txctl_reg; 735 u16 txctl_value; 736 u16 pad_mix_gain; 737 738 saved_regs.old_channel = phy->channel; 739 b43_mac_suspend(dev); 740 lo_measure_setup(dev, &saved_regs); 741 742 txctl_reg = lo_txctl_register_table(dev, &txctl_value, &pad_mix_gain); 743 744 b43_radio_maskset(dev, 0x43, 0xFFF0, rfatt->att); 745 b43_radio_maskset(dev, txctl_reg, ~txctl_value, (rfatt->with_padmix ? txctl_value :0)); 746 747 max_rx_gain = rfatt->att * 2; 748 max_rx_gain += bbatt->att / 2; 749 if (rfatt->with_padmix) 750 max_rx_gain -= pad_mix_gain; 751 if (has_loopback_gain(phy)) 752 max_rx_gain += gphy->max_lb_gain; 753 lo_measure_gain_values(dev, max_rx_gain, 754 has_loopback_gain(phy)); 755 756 b43_gphy_set_baseband_attenuation(dev, bbatt->att); 757 lo_probe_loctls_statemachine(dev, &loctl, &max_rx_gain); 758 759 lo_measure_restore(dev, &saved_regs); 760 b43_mac_enable(dev); 761 762 if (b43_debug(dev, B43_DBG_LO)) { 763 b43dbg(dev->wl, "LO: Calibrated for BB(%u), RF(%u,%u) " 764 "=> I=%d Q=%d\n", 765 bbatt->att, rfatt->att, rfatt->with_padmix, 766 loctl.i, loctl.q); 767 } 768 769 cal = kmalloc(sizeof(*cal), GFP_KERNEL); 770 if (!cal) { 771 b43warn(dev->wl, "LO calib: out of memory\n"); 772 return NULL; 773 } 774 memcpy(&cal->bbatt, bbatt, sizeof(*bbatt)); 775 memcpy(&cal->rfatt, rfatt, sizeof(*rfatt)); 776 memcpy(&cal->ctl, &loctl, sizeof(loctl)); 777 cal->calib_time = jiffies; 778 INIT_LIST_HEAD(&cal->list); 779 780 return cal; 781 } 782 783 /* Get a calibrated LO setting for the given attenuation values. 784 * Might return a NULL pointer under OOM! */ 785 static 786 struct b43_lo_calib *b43_get_calib_lo_settings(struct b43_wldev *dev, 787 const struct b43_bbatt *bbatt, 788 const struct b43_rfatt *rfatt) 789 { 790 struct b43_txpower_lo_control *lo = dev->phy.g->lo_control; 791 struct b43_lo_calib *c; 792 793 c = b43_find_lo_calib(lo, bbatt, rfatt); 794 if (c) 795 return c; 796 /* Not in the list of calibrated LO settings. 797 * Calibrate it now. */ 798 c = b43_calibrate_lo_setting(dev, bbatt, rfatt); 799 if (!c) 800 return NULL; 801 list_add(&c->list, &lo->calib_list); 802 803 return c; 804 } 805 806 void b43_gphy_dc_lt_init(struct b43_wldev *dev, bool update_all) 807 { 808 struct b43_phy *phy = &dev->phy; 809 struct b43_phy_g *gphy = phy->g; 810 struct b43_txpower_lo_control *lo = gphy->lo_control; 811 int i; 812 int rf_offset, bb_offset; 813 const struct b43_rfatt *rfatt; 814 const struct b43_bbatt *bbatt; 815 u64 power_vector; 816 bool table_changed = false; 817 818 BUILD_BUG_ON(B43_DC_LT_SIZE != 32); 819 B43_WARN_ON(lo->rfatt_list.len * lo->bbatt_list.len > 64); 820 821 power_vector = lo->power_vector; 822 if (!update_all && !power_vector) 823 return; /* Nothing to do. */ 824 825 /* Suspend the MAC now to avoid continuous suspend/enable 826 * cycles in the loop. */ 827 b43_mac_suspend(dev); 828 829 for (i = 0; i < B43_DC_LT_SIZE * 2; i++) { 830 struct b43_lo_calib *cal; 831 int idx; 832 u16 val; 833 834 if (!update_all && !(power_vector & (((u64)1ULL) << i))) 835 continue; 836 /* Update the table entry for this power_vector bit. 837 * The table rows are RFatt entries and columns are BBatt. */ 838 bb_offset = i / lo->rfatt_list.len; 839 rf_offset = i % lo->rfatt_list.len; 840 bbatt = &(lo->bbatt_list.list[bb_offset]); 841 rfatt = &(lo->rfatt_list.list[rf_offset]); 842 843 cal = b43_calibrate_lo_setting(dev, bbatt, rfatt); 844 if (!cal) { 845 b43warn(dev->wl, "LO: Could not " 846 "calibrate DC table entry\n"); 847 continue; 848 } 849 /*FIXME: Is Q really in the low nibble? */ 850 val = (u8)(cal->ctl.q); 851 val |= ((u8)(cal->ctl.i)) << 4; 852 kfree(cal); 853 854 /* Get the index into the hardware DC LT. */ 855 idx = i / 2; 856 /* Change the table in memory. */ 857 if (i % 2) { 858 /* Change the high byte. */ 859 lo->dc_lt[idx] = (lo->dc_lt[idx] & 0x00FF) 860 | ((val & 0x00FF) << 8); 861 } else { 862 /* Change the low byte. */ 863 lo->dc_lt[idx] = (lo->dc_lt[idx] & 0xFF00) 864 | (val & 0x00FF); 865 } 866 table_changed = true; 867 } 868 if (table_changed) { 869 /* The table changed in memory. Update the hardware table. */ 870 for (i = 0; i < B43_DC_LT_SIZE; i++) 871 b43_phy_write(dev, 0x3A0 + i, lo->dc_lt[i]); 872 } 873 b43_mac_enable(dev); 874 } 875 876 /* Fixup the RF attenuation value for the case where we are 877 * using the PAD mixer. */ 878 static inline void b43_lo_fixup_rfatt(struct b43_rfatt *rf) 879 { 880 if (!rf->with_padmix) 881 return; 882 if ((rf->att != 1) && (rf->att != 2) && (rf->att != 3)) 883 rf->att = 4; 884 } 885 886 void b43_lo_g_adjust(struct b43_wldev *dev) 887 { 888 struct b43_phy_g *gphy = dev->phy.g; 889 struct b43_lo_calib *cal; 890 struct b43_rfatt rf; 891 892 memcpy(&rf, &gphy->rfatt, sizeof(rf)); 893 b43_lo_fixup_rfatt(&rf); 894 895 cal = b43_get_calib_lo_settings(dev, &gphy->bbatt, &rf); 896 if (!cal) 897 return; 898 b43_lo_write(dev, &cal->ctl); 899 } 900 901 void b43_lo_g_adjust_to(struct b43_wldev *dev, 902 u16 rfatt, u16 bbatt, u16 tx_control) 903 { 904 struct b43_rfatt rf; 905 struct b43_bbatt bb; 906 struct b43_lo_calib *cal; 907 908 memset(&rf, 0, sizeof(rf)); 909 memset(&bb, 0, sizeof(bb)); 910 rf.att = rfatt; 911 bb.att = bbatt; 912 b43_lo_fixup_rfatt(&rf); 913 cal = b43_get_calib_lo_settings(dev, &bb, &rf); 914 if (!cal) 915 return; 916 b43_lo_write(dev, &cal->ctl); 917 } 918 919 /* Periodic LO maintenance work */ 920 void b43_lo_g_maintenance_work(struct b43_wldev *dev) 921 { 922 struct b43_phy *phy = &dev->phy; 923 struct b43_phy_g *gphy = phy->g; 924 struct b43_txpower_lo_control *lo = gphy->lo_control; 925 unsigned long now; 926 unsigned long expire; 927 struct b43_lo_calib *cal, *tmp; 928 bool current_item_expired = false; 929 bool hwpctl; 930 931 if (!lo) 932 return; 933 now = jiffies; 934 hwpctl = b43_has_hardware_pctl(dev); 935 936 if (hwpctl) { 937 /* Read the power vector and update it, if needed. */ 938 expire = now - B43_LO_PWRVEC_EXPIRE; 939 if (time_before(lo->pwr_vec_read_time, expire)) { 940 lo_read_power_vector(dev); 941 b43_gphy_dc_lt_init(dev, 0); 942 } 943 //FIXME Recalc the whole DC table from time to time? 944 } 945 946 if (hwpctl) 947 return; 948 /* Search for expired LO settings. Remove them. 949 * Recalibrate the current setting, if expired. */ 950 expire = now - B43_LO_CALIB_EXPIRE; 951 list_for_each_entry_safe(cal, tmp, &lo->calib_list, list) { 952 if (!time_before(cal->calib_time, expire)) 953 continue; 954 /* This item expired. */ 955 if (b43_compare_bbatt(&cal->bbatt, &gphy->bbatt) && 956 b43_compare_rfatt(&cal->rfatt, &gphy->rfatt)) { 957 B43_WARN_ON(current_item_expired); 958 current_item_expired = true; 959 } 960 if (b43_debug(dev, B43_DBG_LO)) { 961 b43dbg(dev->wl, "LO: Item BB(%u), RF(%u,%u), " 962 "I=%d, Q=%d expired\n", 963 cal->bbatt.att, cal->rfatt.att, 964 cal->rfatt.with_padmix, 965 cal->ctl.i, cal->ctl.q); 966 } 967 list_del(&cal->list); 968 kfree(cal); 969 } 970 if (current_item_expired || unlikely(list_empty(&lo->calib_list))) { 971 /* Recalibrate currently used LO setting. */ 972 if (b43_debug(dev, B43_DBG_LO)) 973 b43dbg(dev->wl, "LO: Recalibrating current LO setting\n"); 974 cal = b43_calibrate_lo_setting(dev, &gphy->bbatt, &gphy->rfatt); 975 if (cal) { 976 list_add(&cal->list, &lo->calib_list); 977 b43_lo_write(dev, &cal->ctl); 978 } else 979 b43warn(dev->wl, "Failed to recalibrate current LO setting\n"); 980 } 981 } 982 983 void b43_lo_g_cleanup(struct b43_wldev *dev) 984 { 985 struct b43_txpower_lo_control *lo = dev->phy.g->lo_control; 986 struct b43_lo_calib *cal, *tmp; 987 988 if (!lo) 989 return; 990 list_for_each_entry_safe(cal, tmp, &lo->calib_list, list) { 991 list_del(&cal->list); 992 kfree(cal); 993 } 994 } 995 996 /* LO Initialization */ 997 void b43_lo_g_init(struct b43_wldev *dev) 998 { 999 if (b43_has_hardware_pctl(dev)) { 1000 lo_read_power_vector(dev); 1001 b43_gphy_dc_lt_init(dev, 1); 1002 } 1003 } 1004