aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorRafał Miłecki <zajec5@gmail.com>2012-01-02 13:31:22 -0500
committerJohn W. Linville <linville@tuxdriver.com>2012-01-24 14:06:05 -0500
commitd3fd8bf77affcbf80bb8297d177e17ad0b61abc8 (patch)
treea86c6cf34526395bc9ba9a3d34bc55601837f76f /drivers
parent5056635c10151970d87ae256b7f52f056291799e (diff)
b43: N-PHY: implement TX power control setup
Signed-off-by: Rafał Miłecki <zajec5@gmail.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/wireless/b43/phy_n.c217
-rw-r--r--drivers/net/wireless/b43/phy_n.h1
2 files changed, 217 insertions, 1 deletions
diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c
index 9530f12c0282..fbbdbdad1019 100644
--- a/drivers/net/wireless/b43/phy_n.c
+++ b/drivers/net/wireless/b43/phy_n.c
@@ -2420,6 +2420,221 @@ static void b43_nphy_tx_power_ctl_idle_tssi(struct b43_wldev *dev)
2420 nphy->pwr_ctl_info[1].idle_tssi_2g = (tmp >> 8) & 0xFF; 2420 nphy->pwr_ctl_info[1].idle_tssi_2g = (tmp >> 8) & 0xFF;
2421} 2421}
2422 2422
2423/* http://bcm-v4.sipsolutions.net/PHY/N/TxPwrLimitToTbl */
2424static void b43_nphy_tx_prepare_adjusted_power_table(struct b43_wldev *dev)
2425{
2426 struct b43_phy_n *nphy = dev->phy.n;
2427
2428 u8 idx, delta;
2429 u8 i, stf_mode;
2430
2431 for (i = 0; i < 4; i++)
2432 nphy->adj_pwr_tbl[i] = nphy->tx_power_offset[i];
2433
2434 for (stf_mode = 0; stf_mode < 4; stf_mode++) {
2435 delta = 0;
2436 switch (stf_mode) {
2437 case 0:
2438 if (dev->phy.is_40mhz && dev->phy.rev >= 5) {
2439 idx = 68;
2440 } else {
2441 delta = 1;
2442 idx = dev->phy.is_40mhz ? 52 : 4;
2443 }
2444 break;
2445 case 1:
2446 idx = dev->phy.is_40mhz ? 76 : 28;
2447 break;
2448 case 2:
2449 idx = dev->phy.is_40mhz ? 84 : 36;
2450 break;
2451 case 3:
2452 idx = dev->phy.is_40mhz ? 92 : 44;
2453 break;
2454 }
2455
2456 for (i = 0; i < 20; i++) {
2457 nphy->adj_pwr_tbl[4 + 4 * i + stf_mode] =
2458 nphy->tx_power_offset[idx];
2459 if (i == 0)
2460 idx += delta;
2461 if (i == 14)
2462 idx += 1 - delta;
2463 if (i == 3 || i == 4 || i == 7 || i == 8 || i == 11 ||
2464 i == 13)
2465 idx += 1;
2466 }
2467 }
2468}
2469
2470/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxPwrCtrlSetup */
2471static void b43_nphy_tx_power_ctl_setup(struct b43_wldev *dev)
2472{
2473 struct b43_phy_n *nphy = dev->phy.n;
2474 struct ssb_sprom *sprom = dev->dev->bus_sprom;
2475
2476 s16 a1[2], b0[2], b1[2];
2477 u8 idle[2];
2478 s8 target[2];
2479 s32 num, den, pwr;
2480 u32 regval[64];
2481
2482 u16 freq = dev->phy.channel_freq;
2483 u16 tmp;
2484 u16 r; /* routing */
2485 u8 i, c;
2486
2487 if (dev->dev->core_rev == 11 || dev->dev->core_rev == 12) {
2488 b43_maskset32(dev, B43_MMIO_MACCTL, ~0, 0x200000);
2489 b43_read32(dev, B43_MMIO_MACCTL);
2490 udelay(1);
2491 }
2492
2493 if (nphy->hang_avoid)
2494 b43_nphy_stay_in_carrier_search(dev, true);
2495
2496 b43_phy_set(dev, B43_NPHY_TSSIMODE, B43_NPHY_TSSIMODE_EN);
2497 if (dev->phy.rev >= 3)
2498 b43_phy_mask(dev, B43_NPHY_TXPCTL_CMD,
2499 ~B43_NPHY_TXPCTL_CMD_PCTLEN & 0xFFFF);
2500 else
2501 b43_phy_set(dev, B43_NPHY_TXPCTL_CMD,
2502 B43_NPHY_TXPCTL_CMD_PCTLEN);
2503
2504 if (dev->dev->core_rev == 11 || dev->dev->core_rev == 12)
2505 b43_maskset32(dev, B43_MMIO_MACCTL, ~0x200000, 0);
2506
2507 if (sprom->revision < 4) {
2508 idle[0] = nphy->pwr_ctl_info[0].idle_tssi_2g;
2509 idle[1] = nphy->pwr_ctl_info[1].idle_tssi_2g;
2510 target[0] = target[1] = 52;
2511 a1[0] = a1[1] = -424;
2512 b0[0] = b0[1] = 5612;
2513 b1[0] = b1[1] = -1393;
2514 } else {
2515 if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
2516 for (c = 0; c < 2; c++) {
2517 idle[c] = nphy->pwr_ctl_info[c].idle_tssi_2g;
2518 target[c] = sprom->core_pwr_info[c].maxpwr_2g;
2519 a1[c] = sprom->core_pwr_info[c].pa_2g[0];
2520 b0[c] = sprom->core_pwr_info[c].pa_2g[1];
2521 b1[c] = sprom->core_pwr_info[c].pa_2g[2];
2522 }
2523 } else if (freq >= 4900 && freq < 5100) {
2524 for (c = 0; c < 2; c++) {
2525 idle[c] = nphy->pwr_ctl_info[c].idle_tssi_5g;
2526 target[c] = sprom->core_pwr_info[c].maxpwr_5gl;
2527 a1[c] = sprom->core_pwr_info[c].pa_5gl[0];
2528 b0[c] = sprom->core_pwr_info[c].pa_5gl[1];
2529 b1[c] = sprom->core_pwr_info[c].pa_5gl[2];
2530 }
2531 } else if (freq >= 5100 && freq < 5500) {
2532 for (c = 0; c < 2; c++) {
2533 idle[c] = nphy->pwr_ctl_info[c].idle_tssi_5g;
2534 target[c] = sprom->core_pwr_info[c].maxpwr_5g;
2535 a1[c] = sprom->core_pwr_info[c].pa_5g[0];
2536 b0[c] = sprom->core_pwr_info[c].pa_5g[1];
2537 b1[c] = sprom->core_pwr_info[c].pa_5g[2];
2538 }
2539 } else if (freq >= 5500) {
2540 for (c = 0; c < 2; c++) {
2541 idle[c] = nphy->pwr_ctl_info[c].idle_tssi_5g;
2542 target[c] = sprom->core_pwr_info[c].maxpwr_5gh;
2543 a1[c] = sprom->core_pwr_info[c].pa_5gh[0];
2544 b0[c] = sprom->core_pwr_info[c].pa_5gh[1];
2545 b1[c] = sprom->core_pwr_info[c].pa_5gh[2];
2546 }
2547 } else {
2548 idle[0] = nphy->pwr_ctl_info[0].idle_tssi_5g;
2549 idle[1] = nphy->pwr_ctl_info[1].idle_tssi_5g;
2550 target[0] = target[1] = 52;
2551 a1[0] = a1[1] = -424;
2552 b0[0] = b0[1] = 5612;
2553 b1[0] = b1[1] = -1393;
2554 }
2555 }
2556 /* target[0] = target[1] = nphy->tx_power_max; */
2557
2558 if (dev->phy.rev >= 3) {
2559 if (sprom->fem.ghz2.tssipos)
2560 b43_phy_set(dev, B43_NPHY_TXPCTL_ITSSI, 0x4000);
2561 if (dev->phy.rev >= 7) {
2562 for (c = 0; c < 2; c++) {
2563 r = c ? 0x190 : 0x170;
2564 if (b43_nphy_ipa(dev))
2565 b43_radio_write(dev, r + 0x9, (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) ? 0xE : 0xC);
2566 }
2567 } else {
2568 if (b43_nphy_ipa(dev)) {
2569 tmp = (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) ? 0xC : 0xE;
2570 b43_radio_write(dev,
2571 B2056_TX0 | B2056_TX_TX_SSI_MUX, tmp);
2572 b43_radio_write(dev,
2573 B2056_TX1 | B2056_TX_TX_SSI_MUX, tmp);
2574 } else {
2575 b43_radio_write(dev,
2576 B2056_TX0 | B2056_TX_TX_SSI_MUX, 0x11);
2577 b43_radio_write(dev,
2578 B2056_TX1 | B2056_TX_TX_SSI_MUX, 0x11);
2579 }
2580 }
2581 }
2582
2583 if (dev->dev->core_rev == 11 || dev->dev->core_rev == 12) {
2584 b43_maskset32(dev, B43_MMIO_MACCTL, ~0, 0x200000);
2585 b43_read32(dev, B43_MMIO_MACCTL);
2586 udelay(1);
2587 }
2588
2589 if (dev->phy.rev >= 7) {
2590 b43_phy_maskset(dev, B43_NPHY_TXPCTL_CMD,
2591 ~B43_NPHY_TXPCTL_CMD_INIT, 0x19);
2592 b43_phy_maskset(dev, B43_NPHY_TXPCTL_INIT,
2593 ~B43_NPHY_TXPCTL_INIT_PIDXI1, 0x19);
2594 } else {
2595 b43_phy_maskset(dev, B43_NPHY_TXPCTL_CMD,
2596 ~B43_NPHY_TXPCTL_CMD_INIT, 0x40);
2597 if (dev->phy.rev > 1)
2598 b43_phy_maskset(dev, B43_NPHY_TXPCTL_INIT,
2599 ~B43_NPHY_TXPCTL_INIT_PIDXI1, 0x40);
2600 }
2601
2602 if (dev->dev->core_rev == 11 || dev->dev->core_rev == 12)
2603 b43_maskset32(dev, B43_MMIO_MACCTL, ~0x200000, 0);
2604
2605 b43_phy_write(dev, B43_NPHY_TXPCTL_N,
2606 0xF0 << B43_NPHY_TXPCTL_N_TSSID_SHIFT |
2607 3 << B43_NPHY_TXPCTL_N_NPTIL2_SHIFT);
2608 b43_phy_write(dev, B43_NPHY_TXPCTL_ITSSI,
2609 idle[0] << B43_NPHY_TXPCTL_ITSSI_0_SHIFT |
2610 idle[1] << B43_NPHY_TXPCTL_ITSSI_1_SHIFT |
2611 B43_NPHY_TXPCTL_ITSSI_BINF);
2612 b43_phy_write(dev, B43_NPHY_TXPCTL_TPWR,
2613 target[0] << B43_NPHY_TXPCTL_TPWR_0_SHIFT |
2614 target[1] << B43_NPHY_TXPCTL_TPWR_1_SHIFT);
2615
2616 for (c = 0; c < 2; c++) {
2617 for (i = 0; i < 64; i++) {
2618 num = 8 * (16 * b0[c] + b1[c] * i);
2619 den = 32768 + a1[c] * i;
2620 pwr = max((4 * num + den / 2) / den, -8);
2621 if (dev->phy.rev < 3 && (i <= (31 - idle[c] + 1)))
2622 pwr = max(pwr, target[c] + 1);
2623 regval[i] = pwr;
2624 }
2625 b43_ntab_write_bulk(dev, B43_NTAB32(26 + c, 0), 64, regval);
2626 }
2627
2628 b43_nphy_tx_prepare_adjusted_power_table(dev);
2629 /*
2630 b43_ntab_write_bulk(dev, B43_NTAB16(26, 64), 84, nphy->adj_pwr_tbl);
2631 b43_ntab_write_bulk(dev, B43_NTAB16(27, 64), 84, nphy->adj_pwr_tbl);
2632 */
2633
2634 if (nphy->hang_avoid)
2635 b43_nphy_stay_in_carrier_search(dev, false);
2636}
2637
2423static void b43_nphy_tx_gain_table_upload(struct b43_wldev *dev) 2638static void b43_nphy_tx_gain_table_upload(struct b43_wldev *dev)
2424{ 2639{
2425 struct b43_phy *phy = &dev->phy; 2640 struct b43_phy *phy = &dev->phy;
@@ -4107,7 +4322,7 @@ int b43_phy_initn(struct b43_wldev *dev)
4107 b43_nphy_tx_power_ctrl(dev, false); 4322 b43_nphy_tx_power_ctrl(dev, false);
4108 b43_nphy_tx_power_fix(dev); 4323 b43_nphy_tx_power_fix(dev);
4109 b43_nphy_tx_power_ctl_idle_tssi(dev); 4324 b43_nphy_tx_power_ctl_idle_tssi(dev);
4110 /* TODO N PHY TX Power Control Setup */ 4325 b43_nphy_tx_power_ctl_setup(dev);
4111 b43_nphy_tx_gain_table_upload(dev); 4326 b43_nphy_tx_gain_table_upload(dev);
4112 4327
4113 if (nphy->phyrxchain != 3) 4328 if (nphy->phyrxchain != 3)
diff --git a/drivers/net/wireless/b43/phy_n.h b/drivers/net/wireless/b43/phy_n.h
index 5de8f74cc02f..fd12b386fea1 100644
--- a/drivers/net/wireless/b43/phy_n.h
+++ b/drivers/net/wireless/b43/phy_n.h
@@ -798,6 +798,7 @@ struct b43_phy_n {
798 bool txpwrctrl; 798 bool txpwrctrl;
799 bool pwg_gain_5ghz; 799 bool pwg_gain_5ghz;
800 u8 tx_pwr_idx[2]; 800 u8 tx_pwr_idx[2];
801 s8 tx_power_offset[101];
801 u16 adj_pwr_tbl[84]; 802 u16 adj_pwr_tbl[84];
802 u16 txcal_bbmult; 803 u16 txcal_bbmult;
803 u16 txiqlocal_bestc[11]; 804 u16 txiqlocal_bestc[11];