Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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