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

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>

authored by

Rafał Miłecki and committed by
John W. Linville
d3fd8bf7 5056635c

+217 -1
+216 -1
drivers/net/wireless/b43/phy_n.c
··· 2420 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 */ 2424 + static 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 */ 2471 + static 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 + 2423 2638 static void b43_nphy_tx_gain_table_upload(struct b43_wldev *dev) 2424 2639 { 2425 2640 struct b43_phy *phy = &dev->phy; ··· 4322 4107 b43_nphy_tx_power_ctrl(dev, false); 4323 4108 b43_nphy_tx_power_fix(dev); 4324 4109 b43_nphy_tx_power_ctl_idle_tssi(dev); 4325 - /* TODO N PHY TX Power Control Setup */ 4110 + b43_nphy_tx_power_ctl_setup(dev); 4326 4111 b43_nphy_tx_gain_table_upload(dev); 4327 4112 4328 4113 if (nphy->phyrxchain != 3)
+1
drivers/net/wireless/b43/phy_n.h
··· 798 798 bool txpwrctrl; 799 799 bool pwg_gain_5ghz; 800 800 u8 tx_pwr_idx[2]; 801 + s8 tx_power_offset[101]; 801 802 u16 adj_pwr_tbl[84]; 802 803 u16 txcal_bbmult; 803 804 u16 txiqlocal_bestc[11];