18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci 48c2ecf20Sopenharmony_ci Broadcom B43legacy wireless driver 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>, 78c2ecf20Sopenharmony_ci Stefano Brivio <stefano.brivio@polimi.it> 88c2ecf20Sopenharmony_ci Michael Buesch <m@bues.ch> 98c2ecf20Sopenharmony_ci Danny van Dyk <kugelfang@gentoo.org> 108c2ecf20Sopenharmony_ci Andreas Jaggi <andreas.jaggi@waterwave.ch> 118c2ecf20Sopenharmony_ci Copyright (c) 2007 Larry Finger <Larry.Finger@lwfinger.net> 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci Some parts of the code in this file are derived from the ipw2200 148c2ecf20Sopenharmony_ci driver Copyright(c) 2003 - 2004 Intel Corporation. 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci*/ 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include <linux/delay.h> 208c2ecf20Sopenharmony_ci#include <linux/pci.h> 218c2ecf20Sopenharmony_ci#include <linux/sched.h> 228c2ecf20Sopenharmony_ci#include <linux/slab.h> 238c2ecf20Sopenharmony_ci#include <linux/types.h> 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#include "b43legacy.h" 268c2ecf20Sopenharmony_ci#include "phy.h" 278c2ecf20Sopenharmony_ci#include "main.h" 288c2ecf20Sopenharmony_ci#include "radio.h" 298c2ecf20Sopenharmony_ci#include "ilt.h" 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_cistatic const s8 b43legacy_tssi2dbm_b_table[] = { 338c2ecf20Sopenharmony_ci 0x4D, 0x4C, 0x4B, 0x4A, 348c2ecf20Sopenharmony_ci 0x4A, 0x49, 0x48, 0x47, 358c2ecf20Sopenharmony_ci 0x47, 0x46, 0x45, 0x45, 368c2ecf20Sopenharmony_ci 0x44, 0x43, 0x42, 0x42, 378c2ecf20Sopenharmony_ci 0x41, 0x40, 0x3F, 0x3E, 388c2ecf20Sopenharmony_ci 0x3D, 0x3C, 0x3B, 0x3A, 398c2ecf20Sopenharmony_ci 0x39, 0x38, 0x37, 0x36, 408c2ecf20Sopenharmony_ci 0x35, 0x34, 0x32, 0x31, 418c2ecf20Sopenharmony_ci 0x30, 0x2F, 0x2D, 0x2C, 428c2ecf20Sopenharmony_ci 0x2B, 0x29, 0x28, 0x26, 438c2ecf20Sopenharmony_ci 0x25, 0x23, 0x21, 0x1F, 448c2ecf20Sopenharmony_ci 0x1D, 0x1A, 0x17, 0x14, 458c2ecf20Sopenharmony_ci 0x10, 0x0C, 0x06, 0x00, 468c2ecf20Sopenharmony_ci -7, -7, -7, -7, 478c2ecf20Sopenharmony_ci -7, -7, -7, -7, 488c2ecf20Sopenharmony_ci -7, -7, -7, -7, 498c2ecf20Sopenharmony_ci}; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_cistatic const s8 b43legacy_tssi2dbm_g_table[] = { 528c2ecf20Sopenharmony_ci 77, 77, 77, 76, 538c2ecf20Sopenharmony_ci 76, 76, 75, 75, 548c2ecf20Sopenharmony_ci 74, 74, 73, 73, 558c2ecf20Sopenharmony_ci 73, 72, 72, 71, 568c2ecf20Sopenharmony_ci 71, 70, 70, 69, 578c2ecf20Sopenharmony_ci 68, 68, 67, 67, 588c2ecf20Sopenharmony_ci 66, 65, 65, 64, 598c2ecf20Sopenharmony_ci 63, 63, 62, 61, 608c2ecf20Sopenharmony_ci 60, 59, 58, 57, 618c2ecf20Sopenharmony_ci 56, 55, 54, 53, 628c2ecf20Sopenharmony_ci 52, 50, 49, 47, 638c2ecf20Sopenharmony_ci 45, 43, 40, 37, 648c2ecf20Sopenharmony_ci 33, 28, 22, 14, 658c2ecf20Sopenharmony_ci 5, -7, -20, -20, 668c2ecf20Sopenharmony_ci -20, -20, -20, -20, 678c2ecf20Sopenharmony_ci -20, -20, -20, -20, 688c2ecf20Sopenharmony_ci}; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_cistatic void b43legacy_phy_initg(struct b43legacy_wldev *dev); 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci/* Lock the PHY registers against concurrent access from the microcode. 738c2ecf20Sopenharmony_ci * This lock is nonrecursive. */ 748c2ecf20Sopenharmony_civoid b43legacy_phy_lock(struct b43legacy_wldev *dev) 758c2ecf20Sopenharmony_ci{ 768c2ecf20Sopenharmony_ci#if B43legacy_DEBUG 778c2ecf20Sopenharmony_ci B43legacy_WARN_ON(dev->phy.phy_locked); 788c2ecf20Sopenharmony_ci dev->phy.phy_locked = 1; 798c2ecf20Sopenharmony_ci#endif 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci if (dev->dev->id.revision < 3) { 828c2ecf20Sopenharmony_ci b43legacy_mac_suspend(dev); 838c2ecf20Sopenharmony_ci } else { 848c2ecf20Sopenharmony_ci if (!b43legacy_is_mode(dev->wl, NL80211_IFTYPE_AP)) 858c2ecf20Sopenharmony_ci b43legacy_power_saving_ctl_bits(dev, -1, 1); 868c2ecf20Sopenharmony_ci } 878c2ecf20Sopenharmony_ci} 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_civoid b43legacy_phy_unlock(struct b43legacy_wldev *dev) 908c2ecf20Sopenharmony_ci{ 918c2ecf20Sopenharmony_ci#if B43legacy_DEBUG 928c2ecf20Sopenharmony_ci B43legacy_WARN_ON(!dev->phy.phy_locked); 938c2ecf20Sopenharmony_ci dev->phy.phy_locked = 0; 948c2ecf20Sopenharmony_ci#endif 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci if (dev->dev->id.revision < 3) { 978c2ecf20Sopenharmony_ci b43legacy_mac_enable(dev); 988c2ecf20Sopenharmony_ci } else { 998c2ecf20Sopenharmony_ci if (!b43legacy_is_mode(dev->wl, NL80211_IFTYPE_AP)) 1008c2ecf20Sopenharmony_ci b43legacy_power_saving_ctl_bits(dev, -1, -1); 1018c2ecf20Sopenharmony_ci } 1028c2ecf20Sopenharmony_ci} 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ciu16 b43legacy_phy_read(struct b43legacy_wldev *dev, u16 offset) 1058c2ecf20Sopenharmony_ci{ 1068c2ecf20Sopenharmony_ci b43legacy_write16(dev, B43legacy_MMIO_PHY_CONTROL, offset); 1078c2ecf20Sopenharmony_ci return b43legacy_read16(dev, B43legacy_MMIO_PHY_DATA); 1088c2ecf20Sopenharmony_ci} 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_civoid b43legacy_phy_write(struct b43legacy_wldev *dev, u16 offset, u16 val) 1118c2ecf20Sopenharmony_ci{ 1128c2ecf20Sopenharmony_ci b43legacy_write16(dev, B43legacy_MMIO_PHY_CONTROL, offset); 1138c2ecf20Sopenharmony_ci b43legacy_write16(dev, B43legacy_MMIO_PHY_DATA, val); 1148c2ecf20Sopenharmony_ci} 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_civoid b43legacy_phy_calibrate(struct b43legacy_wldev *dev) 1178c2ecf20Sopenharmony_ci{ 1188c2ecf20Sopenharmony_ci struct b43legacy_phy *phy = &dev->phy; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci b43legacy_read32(dev, B43legacy_MMIO_MACCTL); /* Dummy read. */ 1218c2ecf20Sopenharmony_ci if (phy->calibrated) 1228c2ecf20Sopenharmony_ci return; 1238c2ecf20Sopenharmony_ci if (phy->type == B43legacy_PHYTYPE_G && phy->rev == 1) { 1248c2ecf20Sopenharmony_ci b43legacy_wireless_core_reset(dev, 0); 1258c2ecf20Sopenharmony_ci b43legacy_phy_initg(dev); 1268c2ecf20Sopenharmony_ci b43legacy_wireless_core_reset(dev, B43legacy_TMSLOW_GMODE); 1278c2ecf20Sopenharmony_ci } 1288c2ecf20Sopenharmony_ci phy->calibrated = 1; 1298c2ecf20Sopenharmony_ci} 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci/* initialize B PHY power control 1328c2ecf20Sopenharmony_ci * as described in https://bcm-specs.sipsolutions.net/InitPowerControl 1338c2ecf20Sopenharmony_ci */ 1348c2ecf20Sopenharmony_cistatic void b43legacy_phy_init_pctl(struct b43legacy_wldev *dev) 1358c2ecf20Sopenharmony_ci{ 1368c2ecf20Sopenharmony_ci struct b43legacy_phy *phy = &dev->phy; 1378c2ecf20Sopenharmony_ci u16 saved_batt = 0; 1388c2ecf20Sopenharmony_ci u16 saved_ratt = 0; 1398c2ecf20Sopenharmony_ci u16 saved_txctl1 = 0; 1408c2ecf20Sopenharmony_ci int must_reset_txpower = 0; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci B43legacy_BUG_ON(!(phy->type == B43legacy_PHYTYPE_B || 1438c2ecf20Sopenharmony_ci phy->type == B43legacy_PHYTYPE_G)); 1448c2ecf20Sopenharmony_ci if (is_bcm_board_vendor(dev) && 1458c2ecf20Sopenharmony_ci (dev->dev->bus->boardinfo.type == 0x0416)) 1468c2ecf20Sopenharmony_ci return; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0028, 0x8018); 1498c2ecf20Sopenharmony_ci b43legacy_write16(dev, 0x03E6, b43legacy_read16(dev, 0x03E6) & 0xFFDF); 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci if (phy->type == B43legacy_PHYTYPE_G) { 1528c2ecf20Sopenharmony_ci if (!phy->gmode) 1538c2ecf20Sopenharmony_ci return; 1548c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x047A, 0xC111); 1558c2ecf20Sopenharmony_ci } 1568c2ecf20Sopenharmony_ci if (phy->savedpctlreg != 0xFFFF) 1578c2ecf20Sopenharmony_ci return; 1588c2ecf20Sopenharmony_ci#ifdef CONFIG_B43LEGACY_DEBUG 1598c2ecf20Sopenharmony_ci if (phy->manual_txpower_control) 1608c2ecf20Sopenharmony_ci return; 1618c2ecf20Sopenharmony_ci#endif 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci if (phy->type == B43legacy_PHYTYPE_B && 1648c2ecf20Sopenharmony_ci phy->rev >= 2 && 1658c2ecf20Sopenharmony_ci phy->radio_ver == 0x2050) 1668c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x0076, 1678c2ecf20Sopenharmony_ci b43legacy_radio_read16(dev, 0x0076) 1688c2ecf20Sopenharmony_ci | 0x0084); 1698c2ecf20Sopenharmony_ci else { 1708c2ecf20Sopenharmony_ci saved_batt = phy->bbatt; 1718c2ecf20Sopenharmony_ci saved_ratt = phy->rfatt; 1728c2ecf20Sopenharmony_ci saved_txctl1 = phy->txctl1; 1738c2ecf20Sopenharmony_ci if ((phy->radio_rev >= 6) && (phy->radio_rev <= 8) 1748c2ecf20Sopenharmony_ci && /*FIXME: incomplete specs for 5 < revision < 9 */ 0) 1758c2ecf20Sopenharmony_ci b43legacy_radio_set_txpower_bg(dev, 0xB, 0x1F, 0); 1768c2ecf20Sopenharmony_ci else 1778c2ecf20Sopenharmony_ci b43legacy_radio_set_txpower_bg(dev, 0xB, 9, 0); 1788c2ecf20Sopenharmony_ci must_reset_txpower = 1; 1798c2ecf20Sopenharmony_ci } 1808c2ecf20Sopenharmony_ci b43legacy_dummy_transmission(dev); 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci phy->savedpctlreg = b43legacy_phy_read(dev, B43legacy_PHY_G_PCTL); 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci if (must_reset_txpower) 1858c2ecf20Sopenharmony_ci b43legacy_radio_set_txpower_bg(dev, saved_batt, saved_ratt, 1868c2ecf20Sopenharmony_ci saved_txctl1); 1878c2ecf20Sopenharmony_ci else 1888c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x0076, b43legacy_radio_read16(dev, 1898c2ecf20Sopenharmony_ci 0x0076) & 0xFF7B); 1908c2ecf20Sopenharmony_ci b43legacy_radio_clear_tssi(dev); 1918c2ecf20Sopenharmony_ci} 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_cistatic void b43legacy_phy_agcsetup(struct b43legacy_wldev *dev) 1948c2ecf20Sopenharmony_ci{ 1958c2ecf20Sopenharmony_ci struct b43legacy_phy *phy = &dev->phy; 1968c2ecf20Sopenharmony_ci u16 offset = 0x0000; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci if (phy->rev == 1) 1998c2ecf20Sopenharmony_ci offset = 0x4C00; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci b43legacy_ilt_write(dev, offset, 0x00FE); 2028c2ecf20Sopenharmony_ci b43legacy_ilt_write(dev, offset + 1, 0x000D); 2038c2ecf20Sopenharmony_ci b43legacy_ilt_write(dev, offset + 2, 0x0013); 2048c2ecf20Sopenharmony_ci b43legacy_ilt_write(dev, offset + 3, 0x0019); 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci if (phy->rev == 1) { 2078c2ecf20Sopenharmony_ci b43legacy_ilt_write(dev, 0x1800, 0x2710); 2088c2ecf20Sopenharmony_ci b43legacy_ilt_write(dev, 0x1801, 0x9B83); 2098c2ecf20Sopenharmony_ci b43legacy_ilt_write(dev, 0x1802, 0x9B83); 2108c2ecf20Sopenharmony_ci b43legacy_ilt_write(dev, 0x1803, 0x0F8D); 2118c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0455, 0x0004); 2128c2ecf20Sopenharmony_ci } 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x04A5, (b43legacy_phy_read(dev, 0x04A5) 2158c2ecf20Sopenharmony_ci & 0x00FF) | 0x5700); 2168c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x041A, (b43legacy_phy_read(dev, 0x041A) 2178c2ecf20Sopenharmony_ci & 0xFF80) | 0x000F); 2188c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x041A, (b43legacy_phy_read(dev, 0x041A) 2198c2ecf20Sopenharmony_ci & 0xC07F) | 0x2B80); 2208c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x048C, (b43legacy_phy_read(dev, 0x048C) 2218c2ecf20Sopenharmony_ci & 0xF0FF) | 0x0300); 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x007A, 2248c2ecf20Sopenharmony_ci b43legacy_radio_read16(dev, 0x007A) 2258c2ecf20Sopenharmony_ci | 0x0008); 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x04A0, (b43legacy_phy_read(dev, 0x04A0) 2288c2ecf20Sopenharmony_ci & 0xFFF0) | 0x0008); 2298c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x04A1, (b43legacy_phy_read(dev, 0x04A1) 2308c2ecf20Sopenharmony_ci & 0xF0FF) | 0x0600); 2318c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x04A2, (b43legacy_phy_read(dev, 0x04A2) 2328c2ecf20Sopenharmony_ci & 0xF0FF) | 0x0700); 2338c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x04A0, (b43legacy_phy_read(dev, 0x04A0) 2348c2ecf20Sopenharmony_ci & 0xF0FF) | 0x0100); 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci if (phy->rev == 1) 2378c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x04A2, 2388c2ecf20Sopenharmony_ci (b43legacy_phy_read(dev, 0x04A2) 2398c2ecf20Sopenharmony_ci & 0xFFF0) | 0x0007); 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0488, (b43legacy_phy_read(dev, 0x0488) 2428c2ecf20Sopenharmony_ci & 0xFF00) | 0x001C); 2438c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0488, (b43legacy_phy_read(dev, 0x0488) 2448c2ecf20Sopenharmony_ci & 0xC0FF) | 0x0200); 2458c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0496, (b43legacy_phy_read(dev, 0x0496) 2468c2ecf20Sopenharmony_ci & 0xFF00) | 0x001C); 2478c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0489, (b43legacy_phy_read(dev, 0x0489) 2488c2ecf20Sopenharmony_ci & 0xFF00) | 0x0020); 2498c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0489, (b43legacy_phy_read(dev, 0x0489) 2508c2ecf20Sopenharmony_ci & 0xC0FF) | 0x0200); 2518c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0482, (b43legacy_phy_read(dev, 0x0482) 2528c2ecf20Sopenharmony_ci & 0xFF00) | 0x002E); 2538c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0496, (b43legacy_phy_read(dev, 0x0496) 2548c2ecf20Sopenharmony_ci & 0x00FF) | 0x1A00); 2558c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0481, (b43legacy_phy_read(dev, 0x0481) 2568c2ecf20Sopenharmony_ci & 0xFF00) | 0x0028); 2578c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0481, (b43legacy_phy_read(dev, 0x0481) 2588c2ecf20Sopenharmony_ci & 0x00FF) | 0x2C00); 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci if (phy->rev == 1) { 2618c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0430, 0x092B); 2628c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x041B, 2638c2ecf20Sopenharmony_ci (b43legacy_phy_read(dev, 0x041B) 2648c2ecf20Sopenharmony_ci & 0xFFE1) | 0x0002); 2658c2ecf20Sopenharmony_ci } else { 2668c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x041B, 2678c2ecf20Sopenharmony_ci b43legacy_phy_read(dev, 0x041B) & 0xFFE1); 2688c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x041F, 0x287A); 2698c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0420, 2708c2ecf20Sopenharmony_ci (b43legacy_phy_read(dev, 0x0420) 2718c2ecf20Sopenharmony_ci & 0xFFF0) | 0x0004); 2728c2ecf20Sopenharmony_ci } 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci if (phy->rev > 2) { 2758c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0422, 0x287A); 2768c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0420, 2778c2ecf20Sopenharmony_ci (b43legacy_phy_read(dev, 0x0420) 2788c2ecf20Sopenharmony_ci & 0x0FFF) | 0x3000); 2798c2ecf20Sopenharmony_ci } 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x04A8, (b43legacy_phy_read(dev, 0x04A8) 2828c2ecf20Sopenharmony_ci & 0x8080) | 0x7874); 2838c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x048E, 0x1C00); 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci if (phy->rev == 1) { 2868c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x04AB, 2878c2ecf20Sopenharmony_ci (b43legacy_phy_read(dev, 0x04AB) 2888c2ecf20Sopenharmony_ci & 0xF0FF) | 0x0600); 2898c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x048B, 0x005E); 2908c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x048C, 2918c2ecf20Sopenharmony_ci (b43legacy_phy_read(dev, 0x048C) & 0xFF00) 2928c2ecf20Sopenharmony_ci | 0x001E); 2938c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x048D, 0x0002); 2948c2ecf20Sopenharmony_ci } 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci b43legacy_ilt_write(dev, offset + 0x0800, 0); 2978c2ecf20Sopenharmony_ci b43legacy_ilt_write(dev, offset + 0x0801, 7); 2988c2ecf20Sopenharmony_ci b43legacy_ilt_write(dev, offset + 0x0802, 16); 2998c2ecf20Sopenharmony_ci b43legacy_ilt_write(dev, offset + 0x0803, 28); 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci if (phy->rev >= 6) { 3028c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0426, 3038c2ecf20Sopenharmony_ci (b43legacy_phy_read(dev, 0x0426) & 0xFFFC)); 3048c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0426, 3058c2ecf20Sopenharmony_ci (b43legacy_phy_read(dev, 0x0426) & 0xEFFF)); 3068c2ecf20Sopenharmony_ci } 3078c2ecf20Sopenharmony_ci} 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_cistatic void b43legacy_phy_setupg(struct b43legacy_wldev *dev) 3108c2ecf20Sopenharmony_ci{ 3118c2ecf20Sopenharmony_ci struct b43legacy_phy *phy = &dev->phy; 3128c2ecf20Sopenharmony_ci u16 i; 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci B43legacy_BUG_ON(phy->type != B43legacy_PHYTYPE_G); 3158c2ecf20Sopenharmony_ci if (phy->rev == 1) { 3168c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0406, 0x4F19); 3178c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, B43legacy_PHY_G_CRS, 3188c2ecf20Sopenharmony_ci (b43legacy_phy_read(dev, 3198c2ecf20Sopenharmony_ci B43legacy_PHY_G_CRS) & 0xFC3F) | 0x0340); 3208c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x042C, 0x005A); 3218c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0427, 0x001A); 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci for (i = 0; i < B43legacy_ILT_FINEFREQG_SIZE; i++) 3248c2ecf20Sopenharmony_ci b43legacy_ilt_write(dev, 0x5800 + i, 3258c2ecf20Sopenharmony_ci b43legacy_ilt_finefreqg[i]); 3268c2ecf20Sopenharmony_ci for (i = 0; i < B43legacy_ILT_NOISEG1_SIZE; i++) 3278c2ecf20Sopenharmony_ci b43legacy_ilt_write(dev, 0x1800 + i, 3288c2ecf20Sopenharmony_ci b43legacy_ilt_noiseg1[i]); 3298c2ecf20Sopenharmony_ci for (i = 0; i < B43legacy_ILT_ROTOR_SIZE; i++) 3308c2ecf20Sopenharmony_ci b43legacy_ilt_write32(dev, 0x2000 + i, 3318c2ecf20Sopenharmony_ci b43legacy_ilt_rotor[i]); 3328c2ecf20Sopenharmony_ci } else { 3338c2ecf20Sopenharmony_ci /* nrssi values are signed 6-bit values. Why 0x7654 here? */ 3348c2ecf20Sopenharmony_ci b43legacy_nrssi_hw_write(dev, 0xBA98, (s16)0x7654); 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci if (phy->rev == 2) { 3378c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x04C0, 0x1861); 3388c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x04C1, 0x0271); 3398c2ecf20Sopenharmony_ci } else if (phy->rev > 2) { 3408c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x04C0, 0x0098); 3418c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x04C1, 0x0070); 3428c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x04C9, 0x0080); 3438c2ecf20Sopenharmony_ci } 3448c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x042B, b43legacy_phy_read(dev, 3458c2ecf20Sopenharmony_ci 0x042B) | 0x800); 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci for (i = 0; i < 64; i++) 3488c2ecf20Sopenharmony_ci b43legacy_ilt_write(dev, 0x4000 + i, i); 3498c2ecf20Sopenharmony_ci for (i = 0; i < B43legacy_ILT_NOISEG2_SIZE; i++) 3508c2ecf20Sopenharmony_ci b43legacy_ilt_write(dev, 0x1800 + i, 3518c2ecf20Sopenharmony_ci b43legacy_ilt_noiseg2[i]); 3528c2ecf20Sopenharmony_ci } 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci if (phy->rev <= 2) 3558c2ecf20Sopenharmony_ci for (i = 0; i < B43legacy_ILT_NOISESCALEG_SIZE; i++) 3568c2ecf20Sopenharmony_ci b43legacy_ilt_write(dev, 0x1400 + i, 3578c2ecf20Sopenharmony_ci b43legacy_ilt_noisescaleg1[i]); 3588c2ecf20Sopenharmony_ci else if ((phy->rev >= 7) && (b43legacy_phy_read(dev, 0x0449) & 0x0200)) 3598c2ecf20Sopenharmony_ci for (i = 0; i < B43legacy_ILT_NOISESCALEG_SIZE; i++) 3608c2ecf20Sopenharmony_ci b43legacy_ilt_write(dev, 0x1400 + i, 3618c2ecf20Sopenharmony_ci b43legacy_ilt_noisescaleg3[i]); 3628c2ecf20Sopenharmony_ci else 3638c2ecf20Sopenharmony_ci for (i = 0; i < B43legacy_ILT_NOISESCALEG_SIZE; i++) 3648c2ecf20Sopenharmony_ci b43legacy_ilt_write(dev, 0x1400 + i, 3658c2ecf20Sopenharmony_ci b43legacy_ilt_noisescaleg2[i]); 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci if (phy->rev == 2) 3688c2ecf20Sopenharmony_ci for (i = 0; i < B43legacy_ILT_SIGMASQR_SIZE; i++) 3698c2ecf20Sopenharmony_ci b43legacy_ilt_write(dev, 0x5000 + i, 3708c2ecf20Sopenharmony_ci b43legacy_ilt_sigmasqr1[i]); 3718c2ecf20Sopenharmony_ci else if ((phy->rev > 2) && (phy->rev <= 8)) 3728c2ecf20Sopenharmony_ci for (i = 0; i < B43legacy_ILT_SIGMASQR_SIZE; i++) 3738c2ecf20Sopenharmony_ci b43legacy_ilt_write(dev, 0x5000 + i, 3748c2ecf20Sopenharmony_ci b43legacy_ilt_sigmasqr2[i]); 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci if (phy->rev == 1) { 3778c2ecf20Sopenharmony_ci for (i = 0; i < B43legacy_ILT_RETARD_SIZE; i++) 3788c2ecf20Sopenharmony_ci b43legacy_ilt_write32(dev, 0x2400 + i, 3798c2ecf20Sopenharmony_ci b43legacy_ilt_retard[i]); 3808c2ecf20Sopenharmony_ci for (i = 4; i < 20; i++) 3818c2ecf20Sopenharmony_ci b43legacy_ilt_write(dev, 0x5400 + i, 0x0020); 3828c2ecf20Sopenharmony_ci b43legacy_phy_agcsetup(dev); 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci if (is_bcm_board_vendor(dev) && 3858c2ecf20Sopenharmony_ci (dev->dev->bus->boardinfo.type == 0x0416) && 3868c2ecf20Sopenharmony_ci (dev->dev->bus->sprom.board_rev == 0x0017)) 3878c2ecf20Sopenharmony_ci return; 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci b43legacy_ilt_write(dev, 0x5001, 0x0002); 3908c2ecf20Sopenharmony_ci b43legacy_ilt_write(dev, 0x5002, 0x0001); 3918c2ecf20Sopenharmony_ci } else { 3928c2ecf20Sopenharmony_ci for (i = 0; i <= 0x20; i++) 3938c2ecf20Sopenharmony_ci b43legacy_ilt_write(dev, 0x1000 + i, 0x0820); 3948c2ecf20Sopenharmony_ci b43legacy_phy_agcsetup(dev); 3958c2ecf20Sopenharmony_ci b43legacy_phy_read(dev, 0x0400); /* dummy read */ 3968c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0403, 0x1000); 3978c2ecf20Sopenharmony_ci b43legacy_ilt_write(dev, 0x3C02, 0x000F); 3988c2ecf20Sopenharmony_ci b43legacy_ilt_write(dev, 0x3C03, 0x0014); 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci if (is_bcm_board_vendor(dev) && 4018c2ecf20Sopenharmony_ci (dev->dev->bus->boardinfo.type == 0x0416) && 4028c2ecf20Sopenharmony_ci (dev->dev->bus->sprom.board_rev == 0x0017)) 4038c2ecf20Sopenharmony_ci return; 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci b43legacy_ilt_write(dev, 0x0401, 0x0002); 4068c2ecf20Sopenharmony_ci b43legacy_ilt_write(dev, 0x0402, 0x0001); 4078c2ecf20Sopenharmony_ci } 4088c2ecf20Sopenharmony_ci} 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci/* Initialize the APHY portion of a GPHY. */ 4118c2ecf20Sopenharmony_cistatic void b43legacy_phy_inita(struct b43legacy_wldev *dev) 4128c2ecf20Sopenharmony_ci{ 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci might_sleep(); 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci b43legacy_phy_setupg(dev); 4178c2ecf20Sopenharmony_ci if (dev->dev->bus->sprom.boardflags_lo & B43legacy_BFL_PACTRL) 4188c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x046E, 0x03CF); 4198c2ecf20Sopenharmony_ci} 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_cistatic void b43legacy_phy_initb2(struct b43legacy_wldev *dev) 4228c2ecf20Sopenharmony_ci{ 4238c2ecf20Sopenharmony_ci struct b43legacy_phy *phy = &dev->phy; 4248c2ecf20Sopenharmony_ci u16 offset; 4258c2ecf20Sopenharmony_ci int val; 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci b43legacy_write16(dev, 0x03EC, 0x3F22); 4288c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0020, 0x301C); 4298c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0026, 0x0000); 4308c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0030, 0x00C6); 4318c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0088, 0x3E00); 4328c2ecf20Sopenharmony_ci val = 0x3C3D; 4338c2ecf20Sopenharmony_ci for (offset = 0x0089; offset < 0x00A7; offset++) { 4348c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, offset, val); 4358c2ecf20Sopenharmony_ci val -= 0x0202; 4368c2ecf20Sopenharmony_ci } 4378c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x03E4, 0x3000); 4388c2ecf20Sopenharmony_ci b43legacy_radio_selectchannel(dev, phy->channel, 0); 4398c2ecf20Sopenharmony_ci if (phy->radio_ver != 0x2050) { 4408c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x0075, 0x0080); 4418c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x0079, 0x0081); 4428c2ecf20Sopenharmony_ci } 4438c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x0050, 0x0020); 4448c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x0050, 0x0023); 4458c2ecf20Sopenharmony_ci if (phy->radio_ver == 0x2050) { 4468c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x0050, 0x0020); 4478c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x005A, 0x0070); 4488c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x005B, 0x007B); 4498c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x005C, 0x00B0); 4508c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x007A, 0x000F); 4518c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0038, 0x0677); 4528c2ecf20Sopenharmony_ci b43legacy_radio_init2050(dev); 4538c2ecf20Sopenharmony_ci } 4548c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0014, 0x0080); 4558c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0032, 0x00CA); 4568c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0032, 0x00CC); 4578c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0035, 0x07C2); 4588c2ecf20Sopenharmony_ci b43legacy_phy_lo_b_measure(dev); 4598c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0026, 0xCC00); 4608c2ecf20Sopenharmony_ci if (phy->radio_ver != 0x2050) 4618c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0026, 0xCE00); 4628c2ecf20Sopenharmony_ci b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT, 0x1000); 4638c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x002A, 0x88A3); 4648c2ecf20Sopenharmony_ci if (phy->radio_ver != 0x2050) 4658c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x002A, 0x88C2); 4668c2ecf20Sopenharmony_ci b43legacy_radio_set_txpower_bg(dev, 0xFFFF, 0xFFFF, 0xFFFF); 4678c2ecf20Sopenharmony_ci b43legacy_phy_init_pctl(dev); 4688c2ecf20Sopenharmony_ci} 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_cistatic void b43legacy_phy_initb4(struct b43legacy_wldev *dev) 4718c2ecf20Sopenharmony_ci{ 4728c2ecf20Sopenharmony_ci struct b43legacy_phy *phy = &dev->phy; 4738c2ecf20Sopenharmony_ci u16 offset; 4748c2ecf20Sopenharmony_ci u16 val; 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci b43legacy_write16(dev, 0x03EC, 0x3F22); 4778c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0020, 0x301C); 4788c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0026, 0x0000); 4798c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0030, 0x00C6); 4808c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0088, 0x3E00); 4818c2ecf20Sopenharmony_ci val = 0x3C3D; 4828c2ecf20Sopenharmony_ci for (offset = 0x0089; offset < 0x00A7; offset++) { 4838c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, offset, val); 4848c2ecf20Sopenharmony_ci val -= 0x0202; 4858c2ecf20Sopenharmony_ci } 4868c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x03E4, 0x3000); 4878c2ecf20Sopenharmony_ci b43legacy_radio_selectchannel(dev, phy->channel, 0); 4888c2ecf20Sopenharmony_ci if (phy->radio_ver != 0x2050) { 4898c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x0075, 0x0080); 4908c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x0079, 0x0081); 4918c2ecf20Sopenharmony_ci } 4928c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x0050, 0x0020); 4938c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x0050, 0x0023); 4948c2ecf20Sopenharmony_ci if (phy->radio_ver == 0x2050) { 4958c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x0050, 0x0020); 4968c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x005A, 0x0070); 4978c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x005B, 0x007B); 4988c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x005C, 0x00B0); 4998c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x007A, 0x000F); 5008c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0038, 0x0677); 5018c2ecf20Sopenharmony_ci b43legacy_radio_init2050(dev); 5028c2ecf20Sopenharmony_ci } 5038c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0014, 0x0080); 5048c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0032, 0x00CA); 5058c2ecf20Sopenharmony_ci if (phy->radio_ver == 0x2050) 5068c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0032, 0x00E0); 5078c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0035, 0x07C2); 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci b43legacy_phy_lo_b_measure(dev); 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0026, 0xCC00); 5128c2ecf20Sopenharmony_ci if (phy->radio_ver == 0x2050) 5138c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0026, 0xCE00); 5148c2ecf20Sopenharmony_ci b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT, 0x1100); 5158c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x002A, 0x88A3); 5168c2ecf20Sopenharmony_ci if (phy->radio_ver == 0x2050) 5178c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x002A, 0x88C2); 5188c2ecf20Sopenharmony_ci b43legacy_radio_set_txpower_bg(dev, 0xFFFF, 0xFFFF, 0xFFFF); 5198c2ecf20Sopenharmony_ci if (dev->dev->bus->sprom.boardflags_lo & B43legacy_BFL_RSSI) { 5208c2ecf20Sopenharmony_ci b43legacy_calc_nrssi_slope(dev); 5218c2ecf20Sopenharmony_ci b43legacy_calc_nrssi_threshold(dev); 5228c2ecf20Sopenharmony_ci } 5238c2ecf20Sopenharmony_ci b43legacy_phy_init_pctl(dev); 5248c2ecf20Sopenharmony_ci} 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_cistatic void b43legacy_phy_initb5(struct b43legacy_wldev *dev) 5278c2ecf20Sopenharmony_ci{ 5288c2ecf20Sopenharmony_ci struct b43legacy_phy *phy = &dev->phy; 5298c2ecf20Sopenharmony_ci u16 offset; 5308c2ecf20Sopenharmony_ci u16 value; 5318c2ecf20Sopenharmony_ci u8 old_channel; 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci if (phy->analog == 1) 5348c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x007A, 5358c2ecf20Sopenharmony_ci b43legacy_radio_read16(dev, 0x007A) 5368c2ecf20Sopenharmony_ci | 0x0050); 5378c2ecf20Sopenharmony_ci if (!is_bcm_board_vendor(dev) && 5388c2ecf20Sopenharmony_ci (dev->dev->bus->boardinfo.type != 0x0416)) { 5398c2ecf20Sopenharmony_ci value = 0x2120; 5408c2ecf20Sopenharmony_ci for (offset = 0x00A8 ; offset < 0x00C7; offset++) { 5418c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, offset, value); 5428c2ecf20Sopenharmony_ci value += 0x0202; 5438c2ecf20Sopenharmony_ci } 5448c2ecf20Sopenharmony_ci } 5458c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0035, 5468c2ecf20Sopenharmony_ci (b43legacy_phy_read(dev, 0x0035) & 0xF0FF) 5478c2ecf20Sopenharmony_ci | 0x0700); 5488c2ecf20Sopenharmony_ci if (phy->radio_ver == 0x2050) 5498c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0038, 0x0667); 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci if (phy->gmode) { 5528c2ecf20Sopenharmony_ci if (phy->radio_ver == 0x2050) { 5538c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x007A, 5548c2ecf20Sopenharmony_ci b43legacy_radio_read16(dev, 0x007A) 5558c2ecf20Sopenharmony_ci | 0x0020); 5568c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x0051, 5578c2ecf20Sopenharmony_ci b43legacy_radio_read16(dev, 0x0051) 5588c2ecf20Sopenharmony_ci | 0x0004); 5598c2ecf20Sopenharmony_ci } 5608c2ecf20Sopenharmony_ci b43legacy_write16(dev, B43legacy_MMIO_PHY_RADIO, 0x0000); 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0802, b43legacy_phy_read(dev, 0x0802) 5638c2ecf20Sopenharmony_ci | 0x0100); 5648c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x042B, b43legacy_phy_read(dev, 0x042B) 5658c2ecf20Sopenharmony_ci | 0x2000); 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x001C, 0x186A); 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0013, (b43legacy_phy_read(dev, 5708c2ecf20Sopenharmony_ci 0x0013) & 0x00FF) | 0x1900); 5718c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0035, (b43legacy_phy_read(dev, 5728c2ecf20Sopenharmony_ci 0x0035) & 0xFFC0) | 0x0064); 5738c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x005D, (b43legacy_phy_read(dev, 5748c2ecf20Sopenharmony_ci 0x005D) & 0xFF80) | 0x000A); 5758c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x5B, 0x0000); 5768c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x5C, 0x0000); 5778c2ecf20Sopenharmony_ci } 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci if (dev->bad_frames_preempt) 5808c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, B43legacy_PHY_RADIO_BITFIELD, 5818c2ecf20Sopenharmony_ci b43legacy_phy_read(dev, 5828c2ecf20Sopenharmony_ci B43legacy_PHY_RADIO_BITFIELD) | (1 << 12)); 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci if (phy->analog == 1) { 5858c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0026, 0xCE00); 5868c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0021, 0x3763); 5878c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0022, 0x1BC3); 5888c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0023, 0x06F9); 5898c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0024, 0x037E); 5908c2ecf20Sopenharmony_ci } else 5918c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0026, 0xCC00); 5928c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0030, 0x00C6); 5938c2ecf20Sopenharmony_ci b43legacy_write16(dev, 0x03EC, 0x3F22); 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci if (phy->analog == 1) 5968c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0020, 0x3E1C); 5978c2ecf20Sopenharmony_ci else 5988c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0020, 0x301C); 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci if (phy->analog == 0) 6018c2ecf20Sopenharmony_ci b43legacy_write16(dev, 0x03E4, 0x3000); 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci old_channel = (phy->channel == 0xFF) ? 1 : phy->channel; 6048c2ecf20Sopenharmony_ci /* Force to channel 7, even if not supported. */ 6058c2ecf20Sopenharmony_ci b43legacy_radio_selectchannel(dev, 7, 0); 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci if (phy->radio_ver != 0x2050) { 6088c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x0075, 0x0080); 6098c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x0079, 0x0081); 6108c2ecf20Sopenharmony_ci } 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x0050, 0x0020); 6138c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x0050, 0x0023); 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci if (phy->radio_ver == 0x2050) { 6168c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x0050, 0x0020); 6178c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x005A, 0x0070); 6188c2ecf20Sopenharmony_ci } 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x005B, 0x007B); 6218c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x005C, 0x00B0); 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x007A, b43legacy_radio_read16(dev, 6248c2ecf20Sopenharmony_ci 0x007A) | 0x0007); 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci b43legacy_radio_selectchannel(dev, old_channel, 0); 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0014, 0x0080); 6298c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0032, 0x00CA); 6308c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x002A, 0x88A3); 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci b43legacy_radio_set_txpower_bg(dev, 0xFFFF, 0xFFFF, 0xFFFF); 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci if (phy->radio_ver == 0x2050) 6358c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x005D, 0x000D); 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci b43legacy_write16(dev, 0x03E4, (b43legacy_read16(dev, 0x03E4) & 6388c2ecf20Sopenharmony_ci 0xFFC0) | 0x0004); 6398c2ecf20Sopenharmony_ci} 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_cistatic void b43legacy_phy_initb6(struct b43legacy_wldev *dev) 6428c2ecf20Sopenharmony_ci{ 6438c2ecf20Sopenharmony_ci struct b43legacy_phy *phy = &dev->phy; 6448c2ecf20Sopenharmony_ci u16 offset; 6458c2ecf20Sopenharmony_ci u16 val; 6468c2ecf20Sopenharmony_ci u8 old_channel; 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x003E, 0x817A); 6498c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x007A, 6508c2ecf20Sopenharmony_ci (b43legacy_radio_read16(dev, 0x007A) | 0x0058)); 6518c2ecf20Sopenharmony_ci if (phy->radio_rev == 4 || 6528c2ecf20Sopenharmony_ci phy->radio_rev == 5) { 6538c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x0051, 0x0037); 6548c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x0052, 0x0070); 6558c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x0053, 0x00B3); 6568c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x0054, 0x009B); 6578c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x005A, 0x0088); 6588c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x005B, 0x0088); 6598c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x005D, 0x0088); 6608c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x005E, 0x0088); 6618c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x007D, 0x0088); 6628c2ecf20Sopenharmony_ci b43legacy_shm_write32(dev, B43legacy_SHM_SHARED, 6638c2ecf20Sopenharmony_ci B43legacy_UCODEFLAGS_OFFSET, 6648c2ecf20Sopenharmony_ci (b43legacy_shm_read32(dev, 6658c2ecf20Sopenharmony_ci B43legacy_SHM_SHARED, 6668c2ecf20Sopenharmony_ci B43legacy_UCODEFLAGS_OFFSET) 6678c2ecf20Sopenharmony_ci | 0x00000200)); 6688c2ecf20Sopenharmony_ci } 6698c2ecf20Sopenharmony_ci if (phy->radio_rev == 8) { 6708c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x0051, 0x0000); 6718c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x0052, 0x0040); 6728c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x0053, 0x00B7); 6738c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x0054, 0x0098); 6748c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x005A, 0x0088); 6758c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x005B, 0x006B); 6768c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x005C, 0x000F); 6778c2ecf20Sopenharmony_ci if (dev->dev->bus->sprom.boardflags_lo & 0x8000) { 6788c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x005D, 0x00FA); 6798c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x005E, 0x00D8); 6808c2ecf20Sopenharmony_ci } else { 6818c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x005D, 0x00F5); 6828c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x005E, 0x00B8); 6838c2ecf20Sopenharmony_ci } 6848c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x0073, 0x0003); 6858c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x007D, 0x00A8); 6868c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x007C, 0x0001); 6878c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x007E, 0x0008); 6888c2ecf20Sopenharmony_ci } 6898c2ecf20Sopenharmony_ci val = 0x1E1F; 6908c2ecf20Sopenharmony_ci for (offset = 0x0088; offset < 0x0098; offset++) { 6918c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, offset, val); 6928c2ecf20Sopenharmony_ci val -= 0x0202; 6938c2ecf20Sopenharmony_ci } 6948c2ecf20Sopenharmony_ci val = 0x3E3F; 6958c2ecf20Sopenharmony_ci for (offset = 0x0098; offset < 0x00A8; offset++) { 6968c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, offset, val); 6978c2ecf20Sopenharmony_ci val -= 0x0202; 6988c2ecf20Sopenharmony_ci } 6998c2ecf20Sopenharmony_ci val = 0x2120; 7008c2ecf20Sopenharmony_ci for (offset = 0x00A8; offset < 0x00C8; offset++) { 7018c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, offset, (val & 0x3F3F)); 7028c2ecf20Sopenharmony_ci val += 0x0202; 7038c2ecf20Sopenharmony_ci } 7048c2ecf20Sopenharmony_ci if (phy->type == B43legacy_PHYTYPE_G) { 7058c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x007A, 7068c2ecf20Sopenharmony_ci b43legacy_radio_read16(dev, 0x007A) | 7078c2ecf20Sopenharmony_ci 0x0020); 7088c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x0051, 7098c2ecf20Sopenharmony_ci b43legacy_radio_read16(dev, 0x0051) | 7108c2ecf20Sopenharmony_ci 0x0004); 7118c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0802, 7128c2ecf20Sopenharmony_ci b43legacy_phy_read(dev, 0x0802) | 0x0100); 7138c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x042B, 7148c2ecf20Sopenharmony_ci b43legacy_phy_read(dev, 0x042B) | 0x2000); 7158c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x5B, 0x0000); 7168c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x5C, 0x0000); 7178c2ecf20Sopenharmony_ci } 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci old_channel = phy->channel; 7208c2ecf20Sopenharmony_ci if (old_channel >= 8) 7218c2ecf20Sopenharmony_ci b43legacy_radio_selectchannel(dev, 1, 0); 7228c2ecf20Sopenharmony_ci else 7238c2ecf20Sopenharmony_ci b43legacy_radio_selectchannel(dev, 13, 0); 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x0050, 0x0020); 7268c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x0050, 0x0023); 7278c2ecf20Sopenharmony_ci udelay(40); 7288c2ecf20Sopenharmony_ci if (phy->radio_rev < 6 || phy->radio_rev == 8) { 7298c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x007C, 7308c2ecf20Sopenharmony_ci (b43legacy_radio_read16(dev, 0x007C) 7318c2ecf20Sopenharmony_ci | 0x0002)); 7328c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x0050, 0x0020); 7338c2ecf20Sopenharmony_ci } 7348c2ecf20Sopenharmony_ci if (phy->radio_rev <= 2) { 7358c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x0050, 0x0020); 7368c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x005A, 0x0070); 7378c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x005B, 0x007B); 7388c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x005C, 0x00B0); 7398c2ecf20Sopenharmony_ci } 7408c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x007A, 7418c2ecf20Sopenharmony_ci (b43legacy_radio_read16(dev, 7428c2ecf20Sopenharmony_ci 0x007A) & 0x00F8) | 0x0007); 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci b43legacy_radio_selectchannel(dev, old_channel, 0); 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0014, 0x0200); 7478c2ecf20Sopenharmony_ci if (phy->radio_rev >= 6) 7488c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x002A, 0x88C2); 7498c2ecf20Sopenharmony_ci else 7508c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x002A, 0x8AC0); 7518c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0038, 0x0668); 7528c2ecf20Sopenharmony_ci b43legacy_radio_set_txpower_bg(dev, 0xFFFF, 0xFFFF, 0xFFFF); 7538c2ecf20Sopenharmony_ci if (phy->radio_rev == 4 || phy->radio_rev == 5) 7548c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x005D, (b43legacy_phy_read(dev, 7558c2ecf20Sopenharmony_ci 0x005D) & 0xFF80) | 0x0003); 7568c2ecf20Sopenharmony_ci if (phy->radio_rev <= 2) 7578c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x005D, 0x000D); 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci if (phy->analog == 4) { 7608c2ecf20Sopenharmony_ci b43legacy_write16(dev, 0x03E4, 0x0009); 7618c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x61, b43legacy_phy_read(dev, 0x61) 7628c2ecf20Sopenharmony_ci & 0xFFF); 7638c2ecf20Sopenharmony_ci } else 7648c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0002, (b43legacy_phy_read(dev, 7658c2ecf20Sopenharmony_ci 0x0002) & 0xFFC0) | 0x0004); 7668c2ecf20Sopenharmony_ci if (phy->type == B43legacy_PHYTYPE_G) 7678c2ecf20Sopenharmony_ci b43legacy_write16(dev, 0x03E6, 0x0); 7688c2ecf20Sopenharmony_ci if (phy->type == B43legacy_PHYTYPE_B) { 7698c2ecf20Sopenharmony_ci b43legacy_write16(dev, 0x03E6, 0x8140); 7708c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0016, 0x0410); 7718c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0017, 0x0820); 7728c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0062, 0x0007); 7738c2ecf20Sopenharmony_ci b43legacy_radio_init2050(dev); 7748c2ecf20Sopenharmony_ci b43legacy_phy_lo_g_measure(dev); 7758c2ecf20Sopenharmony_ci if (dev->dev->bus->sprom.boardflags_lo & 7768c2ecf20Sopenharmony_ci B43legacy_BFL_RSSI) { 7778c2ecf20Sopenharmony_ci b43legacy_calc_nrssi_slope(dev); 7788c2ecf20Sopenharmony_ci b43legacy_calc_nrssi_threshold(dev); 7798c2ecf20Sopenharmony_ci } 7808c2ecf20Sopenharmony_ci b43legacy_phy_init_pctl(dev); 7818c2ecf20Sopenharmony_ci } 7828c2ecf20Sopenharmony_ci} 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_cistatic void b43legacy_calc_loopback_gain(struct b43legacy_wldev *dev) 7858c2ecf20Sopenharmony_ci{ 7868c2ecf20Sopenharmony_ci struct b43legacy_phy *phy = &dev->phy; 7878c2ecf20Sopenharmony_ci u16 backup_phy[15] = {0}; 7888c2ecf20Sopenharmony_ci u16 backup_radio[3]; 7898c2ecf20Sopenharmony_ci u16 backup_bband; 7908c2ecf20Sopenharmony_ci u16 i; 7918c2ecf20Sopenharmony_ci u16 loop1_cnt; 7928c2ecf20Sopenharmony_ci u16 loop1_done; 7938c2ecf20Sopenharmony_ci u16 loop1_omitted; 7948c2ecf20Sopenharmony_ci u16 loop2_done; 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci backup_phy[0] = b43legacy_phy_read(dev, 0x0429); 7978c2ecf20Sopenharmony_ci backup_phy[1] = b43legacy_phy_read(dev, 0x0001); 7988c2ecf20Sopenharmony_ci backup_phy[2] = b43legacy_phy_read(dev, 0x0811); 7998c2ecf20Sopenharmony_ci backup_phy[3] = b43legacy_phy_read(dev, 0x0812); 8008c2ecf20Sopenharmony_ci if (phy->rev != 1) { 8018c2ecf20Sopenharmony_ci backup_phy[4] = b43legacy_phy_read(dev, 0x0814); 8028c2ecf20Sopenharmony_ci backup_phy[5] = b43legacy_phy_read(dev, 0x0815); 8038c2ecf20Sopenharmony_ci } 8048c2ecf20Sopenharmony_ci backup_phy[6] = b43legacy_phy_read(dev, 0x005A); 8058c2ecf20Sopenharmony_ci backup_phy[7] = b43legacy_phy_read(dev, 0x0059); 8068c2ecf20Sopenharmony_ci backup_phy[8] = b43legacy_phy_read(dev, 0x0058); 8078c2ecf20Sopenharmony_ci backup_phy[9] = b43legacy_phy_read(dev, 0x000A); 8088c2ecf20Sopenharmony_ci backup_phy[10] = b43legacy_phy_read(dev, 0x0003); 8098c2ecf20Sopenharmony_ci backup_phy[11] = b43legacy_phy_read(dev, 0x080F); 8108c2ecf20Sopenharmony_ci backup_phy[12] = b43legacy_phy_read(dev, 0x0810); 8118c2ecf20Sopenharmony_ci backup_phy[13] = b43legacy_phy_read(dev, 0x002B); 8128c2ecf20Sopenharmony_ci backup_phy[14] = b43legacy_phy_read(dev, 0x0015); 8138c2ecf20Sopenharmony_ci b43legacy_phy_read(dev, 0x002D); /* dummy read */ 8148c2ecf20Sopenharmony_ci backup_bband = phy->bbatt; 8158c2ecf20Sopenharmony_ci backup_radio[0] = b43legacy_radio_read16(dev, 0x0052); 8168c2ecf20Sopenharmony_ci backup_radio[1] = b43legacy_radio_read16(dev, 0x0043); 8178c2ecf20Sopenharmony_ci backup_radio[2] = b43legacy_radio_read16(dev, 0x007A); 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0429, 8208c2ecf20Sopenharmony_ci b43legacy_phy_read(dev, 0x0429) & 0x3FFF); 8218c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0001, 8228c2ecf20Sopenharmony_ci b43legacy_phy_read(dev, 0x0001) & 0x8000); 8238c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0811, 8248c2ecf20Sopenharmony_ci b43legacy_phy_read(dev, 0x0811) | 0x0002); 8258c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0812, 8268c2ecf20Sopenharmony_ci b43legacy_phy_read(dev, 0x0812) & 0xFFFD); 8278c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0811, 8288c2ecf20Sopenharmony_ci b43legacy_phy_read(dev, 0x0811) | 0x0001); 8298c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0812, 8308c2ecf20Sopenharmony_ci b43legacy_phy_read(dev, 0x0812) & 0xFFFE); 8318c2ecf20Sopenharmony_ci if (phy->rev != 1) { 8328c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0814, 8338c2ecf20Sopenharmony_ci b43legacy_phy_read(dev, 0x0814) | 0x0001); 8348c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0815, 8358c2ecf20Sopenharmony_ci b43legacy_phy_read(dev, 0x0815) & 0xFFFE); 8368c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0814, 8378c2ecf20Sopenharmony_ci b43legacy_phy_read(dev, 0x0814) | 0x0002); 8388c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0815, 8398c2ecf20Sopenharmony_ci b43legacy_phy_read(dev, 0x0815) & 0xFFFD); 8408c2ecf20Sopenharmony_ci } 8418c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0811, b43legacy_phy_read(dev, 0x0811) | 8428c2ecf20Sopenharmony_ci 0x000C); 8438c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0812, b43legacy_phy_read(dev, 0x0812) | 8448c2ecf20Sopenharmony_ci 0x000C); 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0811, (b43legacy_phy_read(dev, 0x0811) 8478c2ecf20Sopenharmony_ci & 0xFFCF) | 0x0030); 8488c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0812, (b43legacy_phy_read(dev, 0x0812) 8498c2ecf20Sopenharmony_ci & 0xFFCF) | 0x0010); 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x005A, 0x0780); 8528c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0059, 0xC810); 8538c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0058, 0x000D); 8548c2ecf20Sopenharmony_ci if (phy->analog == 0) 8558c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0003, 0x0122); 8568c2ecf20Sopenharmony_ci else 8578c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x000A, 8588c2ecf20Sopenharmony_ci b43legacy_phy_read(dev, 0x000A) 8598c2ecf20Sopenharmony_ci | 0x2000); 8608c2ecf20Sopenharmony_ci if (phy->rev != 1) { 8618c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0814, 8628c2ecf20Sopenharmony_ci b43legacy_phy_read(dev, 0x0814) | 0x0004); 8638c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0815, 8648c2ecf20Sopenharmony_ci b43legacy_phy_read(dev, 0x0815) & 0xFFFB); 8658c2ecf20Sopenharmony_ci } 8668c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0003, 8678c2ecf20Sopenharmony_ci (b43legacy_phy_read(dev, 0x0003) 8688c2ecf20Sopenharmony_ci & 0xFF9F) | 0x0040); 8698c2ecf20Sopenharmony_ci if (phy->radio_ver == 0x2050 && phy->radio_rev == 2) { 8708c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x0052, 0x0000); 8718c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x0043, 8728c2ecf20Sopenharmony_ci (b43legacy_radio_read16(dev, 0x0043) 8738c2ecf20Sopenharmony_ci & 0xFFF0) | 0x0009); 8748c2ecf20Sopenharmony_ci loop1_cnt = 9; 8758c2ecf20Sopenharmony_ci } else if (phy->radio_rev == 8) { 8768c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x0043, 0x000F); 8778c2ecf20Sopenharmony_ci loop1_cnt = 15; 8788c2ecf20Sopenharmony_ci } else 8798c2ecf20Sopenharmony_ci loop1_cnt = 0; 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_ci b43legacy_phy_set_baseband_attenuation(dev, 11); 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci if (phy->rev >= 3) 8848c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x080F, 0xC020); 8858c2ecf20Sopenharmony_ci else 8868c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x080F, 0x8020); 8878c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0810, 0x0000); 8888c2ecf20Sopenharmony_ci 8898c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x002B, 8908c2ecf20Sopenharmony_ci (b43legacy_phy_read(dev, 0x002B) 8918c2ecf20Sopenharmony_ci & 0xFFC0) | 0x0001); 8928c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x002B, 8938c2ecf20Sopenharmony_ci (b43legacy_phy_read(dev, 0x002B) 8948c2ecf20Sopenharmony_ci & 0xC0FF) | 0x0800); 8958c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0811, 8968c2ecf20Sopenharmony_ci b43legacy_phy_read(dev, 0x0811) | 0x0100); 8978c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0812, 8988c2ecf20Sopenharmony_ci b43legacy_phy_read(dev, 0x0812) & 0xCFFF); 8998c2ecf20Sopenharmony_ci if (dev->dev->bus->sprom.boardflags_lo & B43legacy_BFL_EXTLNA) { 9008c2ecf20Sopenharmony_ci if (phy->rev >= 7) { 9018c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0811, 9028c2ecf20Sopenharmony_ci b43legacy_phy_read(dev, 0x0811) 9038c2ecf20Sopenharmony_ci | 0x0800); 9048c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0812, 9058c2ecf20Sopenharmony_ci b43legacy_phy_read(dev, 0x0812) 9068c2ecf20Sopenharmony_ci | 0x8000); 9078c2ecf20Sopenharmony_ci } 9088c2ecf20Sopenharmony_ci } 9098c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x007A, 9108c2ecf20Sopenharmony_ci b43legacy_radio_read16(dev, 0x007A) 9118c2ecf20Sopenharmony_ci & 0x00F7); 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci for (i = 0; i < loop1_cnt; i++) { 9148c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x0043, loop1_cnt); 9158c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0812, 9168c2ecf20Sopenharmony_ci (b43legacy_phy_read(dev, 0x0812) 9178c2ecf20Sopenharmony_ci & 0xF0FF) | (i << 8)); 9188c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0015, 9198c2ecf20Sopenharmony_ci (b43legacy_phy_read(dev, 0x0015) 9208c2ecf20Sopenharmony_ci & 0x0FFF) | 0xA000); 9218c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0015, 9228c2ecf20Sopenharmony_ci (b43legacy_phy_read(dev, 0x0015) 9238c2ecf20Sopenharmony_ci & 0x0FFF) | 0xF000); 9248c2ecf20Sopenharmony_ci udelay(20); 9258c2ecf20Sopenharmony_ci if (b43legacy_phy_read(dev, 0x002D) >= 0x0DFC) 9268c2ecf20Sopenharmony_ci break; 9278c2ecf20Sopenharmony_ci } 9288c2ecf20Sopenharmony_ci loop1_done = i; 9298c2ecf20Sopenharmony_ci loop1_omitted = loop1_cnt - loop1_done; 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_ci loop2_done = 0; 9328c2ecf20Sopenharmony_ci if (loop1_done >= 8) { 9338c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0812, 9348c2ecf20Sopenharmony_ci b43legacy_phy_read(dev, 0x0812) 9358c2ecf20Sopenharmony_ci | 0x0030); 9368c2ecf20Sopenharmony_ci for (i = loop1_done - 8; i < 16; i++) { 9378c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0812, 9388c2ecf20Sopenharmony_ci (b43legacy_phy_read(dev, 0x0812) 9398c2ecf20Sopenharmony_ci & 0xF0FF) | (i << 8)); 9408c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0015, 9418c2ecf20Sopenharmony_ci (b43legacy_phy_read(dev, 0x0015) 9428c2ecf20Sopenharmony_ci & 0x0FFF) | 0xA000); 9438c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0015, 9448c2ecf20Sopenharmony_ci (b43legacy_phy_read(dev, 0x0015) 9458c2ecf20Sopenharmony_ci & 0x0FFF) | 0xF000); 9468c2ecf20Sopenharmony_ci udelay(20); 9478c2ecf20Sopenharmony_ci if (b43legacy_phy_read(dev, 0x002D) >= 0x0DFC) 9488c2ecf20Sopenharmony_ci break; 9498c2ecf20Sopenharmony_ci } 9508c2ecf20Sopenharmony_ci } 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_ci if (phy->rev != 1) { 9538c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0814, backup_phy[4]); 9548c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0815, backup_phy[5]); 9558c2ecf20Sopenharmony_ci } 9568c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x005A, backup_phy[6]); 9578c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0059, backup_phy[7]); 9588c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0058, backup_phy[8]); 9598c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x000A, backup_phy[9]); 9608c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0003, backup_phy[10]); 9618c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x080F, backup_phy[11]); 9628c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0810, backup_phy[12]); 9638c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x002B, backup_phy[13]); 9648c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0015, backup_phy[14]); 9658c2ecf20Sopenharmony_ci 9668c2ecf20Sopenharmony_ci b43legacy_phy_set_baseband_attenuation(dev, backup_bband); 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x0052, backup_radio[0]); 9698c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x0043, backup_radio[1]); 9708c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x007A, backup_radio[2]); 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0811, backup_phy[2] | 0x0003); 9738c2ecf20Sopenharmony_ci udelay(10); 9748c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0811, backup_phy[2]); 9758c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0812, backup_phy[3]); 9768c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0429, backup_phy[0]); 9778c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0001, backup_phy[1]); 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_ci phy->loopback_gain[0] = ((loop1_done * 6) - (loop1_omitted * 4)) - 11; 9808c2ecf20Sopenharmony_ci phy->loopback_gain[1] = (24 - (3 * loop2_done)) * 2; 9818c2ecf20Sopenharmony_ci} 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_cistatic void b43legacy_phy_initg(struct b43legacy_wldev *dev) 9848c2ecf20Sopenharmony_ci{ 9858c2ecf20Sopenharmony_ci struct b43legacy_phy *phy = &dev->phy; 9868c2ecf20Sopenharmony_ci u16 tmp; 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_ci if (phy->rev == 1) 9898c2ecf20Sopenharmony_ci b43legacy_phy_initb5(dev); 9908c2ecf20Sopenharmony_ci else 9918c2ecf20Sopenharmony_ci b43legacy_phy_initb6(dev); 9928c2ecf20Sopenharmony_ci if (phy->rev >= 2 && phy->gmode) 9938c2ecf20Sopenharmony_ci b43legacy_phy_inita(dev); 9948c2ecf20Sopenharmony_ci 9958c2ecf20Sopenharmony_ci if (phy->rev >= 2) { 9968c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0814, 0x0000); 9978c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0815, 0x0000); 9988c2ecf20Sopenharmony_ci } 9998c2ecf20Sopenharmony_ci if (phy->rev == 2) { 10008c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0811, 0x0000); 10018c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0015, 0x00C0); 10028c2ecf20Sopenharmony_ci } 10038c2ecf20Sopenharmony_ci if (phy->rev > 5) { 10048c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0811, 0x0400); 10058c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0015, 0x00C0); 10068c2ecf20Sopenharmony_ci } 10078c2ecf20Sopenharmony_ci if (phy->gmode) { 10088c2ecf20Sopenharmony_ci tmp = b43legacy_phy_read(dev, 0x0400) & 0xFF; 10098c2ecf20Sopenharmony_ci if (tmp == 3) { 10108c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x04C2, 0x1816); 10118c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x04C3, 0x8606); 10128c2ecf20Sopenharmony_ci } 10138c2ecf20Sopenharmony_ci if (tmp == 4 || tmp == 5) { 10148c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x04C2, 0x1816); 10158c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x04C3, 0x8006); 10168c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x04CC, 10178c2ecf20Sopenharmony_ci (b43legacy_phy_read(dev, 10188c2ecf20Sopenharmony_ci 0x04CC) & 0x00FF) | 10198c2ecf20Sopenharmony_ci 0x1F00); 10208c2ecf20Sopenharmony_ci } 10218c2ecf20Sopenharmony_ci if (phy->rev >= 2) 10228c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x047E, 0x0078); 10238c2ecf20Sopenharmony_ci } 10248c2ecf20Sopenharmony_ci if (phy->radio_rev == 8) { 10258c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0801, b43legacy_phy_read(dev, 0x0801) 10268c2ecf20Sopenharmony_ci | 0x0080); 10278c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x043E, b43legacy_phy_read(dev, 0x043E) 10288c2ecf20Sopenharmony_ci | 0x0004); 10298c2ecf20Sopenharmony_ci } 10308c2ecf20Sopenharmony_ci if (phy->rev >= 2 && phy->gmode) 10318c2ecf20Sopenharmony_ci b43legacy_calc_loopback_gain(dev); 10328c2ecf20Sopenharmony_ci if (phy->radio_rev != 8) { 10338c2ecf20Sopenharmony_ci if (phy->initval == 0xFFFF) 10348c2ecf20Sopenharmony_ci phy->initval = b43legacy_radio_init2050(dev); 10358c2ecf20Sopenharmony_ci else 10368c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x0078, phy->initval); 10378c2ecf20Sopenharmony_ci } 10388c2ecf20Sopenharmony_ci if (phy->txctl2 == 0xFFFF) 10398c2ecf20Sopenharmony_ci b43legacy_phy_lo_g_measure(dev); 10408c2ecf20Sopenharmony_ci else { 10418c2ecf20Sopenharmony_ci if (phy->radio_ver == 0x2050 && phy->radio_rev == 8) 10428c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x0052, 10438c2ecf20Sopenharmony_ci (phy->txctl1 << 4) | 10448c2ecf20Sopenharmony_ci phy->txctl2); 10458c2ecf20Sopenharmony_ci else 10468c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x0052, 10478c2ecf20Sopenharmony_ci (b43legacy_radio_read16(dev, 10488c2ecf20Sopenharmony_ci 0x0052) & 0xFFF0) | 10498c2ecf20Sopenharmony_ci phy->txctl1); 10508c2ecf20Sopenharmony_ci if (phy->rev >= 6) 10518c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0036, 10528c2ecf20Sopenharmony_ci (b43legacy_phy_read(dev, 0x0036) 10538c2ecf20Sopenharmony_ci & 0x0FFF) | (phy->txctl2 << 12)); 10548c2ecf20Sopenharmony_ci if (dev->dev->bus->sprom.boardflags_lo & 10558c2ecf20Sopenharmony_ci B43legacy_BFL_PACTRL) 10568c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x002E, 0x8075); 10578c2ecf20Sopenharmony_ci else 10588c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x002E, 0x807F); 10598c2ecf20Sopenharmony_ci if (phy->rev < 2) 10608c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x002F, 0x0101); 10618c2ecf20Sopenharmony_ci else 10628c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x002F, 0x0202); 10638c2ecf20Sopenharmony_ci } 10648c2ecf20Sopenharmony_ci if (phy->gmode) { 10658c2ecf20Sopenharmony_ci b43legacy_phy_lo_adjust(dev, 0); 10668c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x080F, 0x8078); 10678c2ecf20Sopenharmony_ci } 10688c2ecf20Sopenharmony_ci 10698c2ecf20Sopenharmony_ci if (!(dev->dev->bus->sprom.boardflags_lo & B43legacy_BFL_RSSI)) { 10708c2ecf20Sopenharmony_ci /* The specs state to update the NRSSI LT with 10718c2ecf20Sopenharmony_ci * the value 0x7FFFFFFF here. I think that is some weird 10728c2ecf20Sopenharmony_ci * compiler optimization in the original driver. 10738c2ecf20Sopenharmony_ci * Essentially, what we do here is resetting all NRSSI LT 10748c2ecf20Sopenharmony_ci * entries to -32 (see the clamp_val() in nrssi_hw_update()) 10758c2ecf20Sopenharmony_ci */ 10768c2ecf20Sopenharmony_ci b43legacy_nrssi_hw_update(dev, 0xFFFF); 10778c2ecf20Sopenharmony_ci b43legacy_calc_nrssi_threshold(dev); 10788c2ecf20Sopenharmony_ci } else if (phy->gmode || phy->rev >= 2) { 10798c2ecf20Sopenharmony_ci if (phy->nrssi[0] == -1000) { 10808c2ecf20Sopenharmony_ci B43legacy_WARN_ON(phy->nrssi[1] != -1000); 10818c2ecf20Sopenharmony_ci b43legacy_calc_nrssi_slope(dev); 10828c2ecf20Sopenharmony_ci } else { 10838c2ecf20Sopenharmony_ci B43legacy_WARN_ON(phy->nrssi[1] == -1000); 10848c2ecf20Sopenharmony_ci b43legacy_calc_nrssi_threshold(dev); 10858c2ecf20Sopenharmony_ci } 10868c2ecf20Sopenharmony_ci } 10878c2ecf20Sopenharmony_ci if (phy->radio_rev == 8) 10888c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0805, 0x3230); 10898c2ecf20Sopenharmony_ci b43legacy_phy_init_pctl(dev); 10908c2ecf20Sopenharmony_ci if (dev->dev->bus->chip_id == 0x4306 10918c2ecf20Sopenharmony_ci && dev->dev->bus->chip_package == 2) { 10928c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0429, 10938c2ecf20Sopenharmony_ci b43legacy_phy_read(dev, 0x0429) & 0xBFFF); 10948c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x04C3, 10958c2ecf20Sopenharmony_ci b43legacy_phy_read(dev, 0x04C3) & 0x7FFF); 10968c2ecf20Sopenharmony_ci } 10978c2ecf20Sopenharmony_ci} 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_cistatic u16 b43legacy_phy_lo_b_r15_loop(struct b43legacy_wldev *dev) 11008c2ecf20Sopenharmony_ci{ 11018c2ecf20Sopenharmony_ci int i; 11028c2ecf20Sopenharmony_ci u16 ret = 0; 11038c2ecf20Sopenharmony_ci unsigned long flags; 11048c2ecf20Sopenharmony_ci 11058c2ecf20Sopenharmony_ci local_irq_save(flags); 11068c2ecf20Sopenharmony_ci for (i = 0; i < 10; i++) { 11078c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0015, 0xAFA0); 11088c2ecf20Sopenharmony_ci udelay(1); 11098c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0015, 0xEFA0); 11108c2ecf20Sopenharmony_ci udelay(10); 11118c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0015, 0xFFA0); 11128c2ecf20Sopenharmony_ci udelay(40); 11138c2ecf20Sopenharmony_ci ret += b43legacy_phy_read(dev, 0x002C); 11148c2ecf20Sopenharmony_ci } 11158c2ecf20Sopenharmony_ci local_irq_restore(flags); 11168c2ecf20Sopenharmony_ci cond_resched(); 11178c2ecf20Sopenharmony_ci 11188c2ecf20Sopenharmony_ci return ret; 11198c2ecf20Sopenharmony_ci} 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_civoid b43legacy_phy_lo_b_measure(struct b43legacy_wldev *dev) 11228c2ecf20Sopenharmony_ci{ 11238c2ecf20Sopenharmony_ci struct b43legacy_phy *phy = &dev->phy; 11248c2ecf20Sopenharmony_ci u16 regstack[12] = { 0 }; 11258c2ecf20Sopenharmony_ci u16 mls; 11268c2ecf20Sopenharmony_ci s16 fval; 11278c2ecf20Sopenharmony_ci int i; 11288c2ecf20Sopenharmony_ci int j; 11298c2ecf20Sopenharmony_ci 11308c2ecf20Sopenharmony_ci regstack[0] = b43legacy_phy_read(dev, 0x0015); 11318c2ecf20Sopenharmony_ci regstack[1] = b43legacy_radio_read16(dev, 0x0052) & 0xFFF0; 11328c2ecf20Sopenharmony_ci 11338c2ecf20Sopenharmony_ci if (phy->radio_ver == 0x2053) { 11348c2ecf20Sopenharmony_ci regstack[2] = b43legacy_phy_read(dev, 0x000A); 11358c2ecf20Sopenharmony_ci regstack[3] = b43legacy_phy_read(dev, 0x002A); 11368c2ecf20Sopenharmony_ci regstack[4] = b43legacy_phy_read(dev, 0x0035); 11378c2ecf20Sopenharmony_ci regstack[5] = b43legacy_phy_read(dev, 0x0003); 11388c2ecf20Sopenharmony_ci regstack[6] = b43legacy_phy_read(dev, 0x0001); 11398c2ecf20Sopenharmony_ci regstack[7] = b43legacy_phy_read(dev, 0x0030); 11408c2ecf20Sopenharmony_ci 11418c2ecf20Sopenharmony_ci regstack[8] = b43legacy_radio_read16(dev, 0x0043); 11428c2ecf20Sopenharmony_ci regstack[9] = b43legacy_radio_read16(dev, 0x007A); 11438c2ecf20Sopenharmony_ci regstack[10] = b43legacy_read16(dev, 0x03EC); 11448c2ecf20Sopenharmony_ci regstack[11] = b43legacy_radio_read16(dev, 0x0052) & 0x00F0; 11458c2ecf20Sopenharmony_ci 11468c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0030, 0x00FF); 11478c2ecf20Sopenharmony_ci b43legacy_write16(dev, 0x03EC, 0x3F3F); 11488c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0035, regstack[4] & 0xFF7F); 11498c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x007A, regstack[9] & 0xFFF0); 11508c2ecf20Sopenharmony_ci } 11518c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0015, 0xB000); 11528c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x002B, 0x0004); 11538c2ecf20Sopenharmony_ci 11548c2ecf20Sopenharmony_ci if (phy->radio_ver == 0x2053) { 11558c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x002B, 0x0203); 11568c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x002A, 0x08A3); 11578c2ecf20Sopenharmony_ci } 11588c2ecf20Sopenharmony_ci 11598c2ecf20Sopenharmony_ci phy->minlowsig[0] = 0xFFFF; 11608c2ecf20Sopenharmony_ci 11618c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) { 11628c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x0052, regstack[1] | i); 11638c2ecf20Sopenharmony_ci b43legacy_phy_lo_b_r15_loop(dev); 11648c2ecf20Sopenharmony_ci } 11658c2ecf20Sopenharmony_ci for (i = 0; i < 10; i++) { 11668c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x0052, regstack[1] | i); 11678c2ecf20Sopenharmony_ci mls = b43legacy_phy_lo_b_r15_loop(dev) / 10; 11688c2ecf20Sopenharmony_ci if (mls < phy->minlowsig[0]) { 11698c2ecf20Sopenharmony_ci phy->minlowsig[0] = mls; 11708c2ecf20Sopenharmony_ci phy->minlowsigpos[0] = i; 11718c2ecf20Sopenharmony_ci } 11728c2ecf20Sopenharmony_ci } 11738c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x0052, regstack[1] 11748c2ecf20Sopenharmony_ci | phy->minlowsigpos[0]); 11758c2ecf20Sopenharmony_ci 11768c2ecf20Sopenharmony_ci phy->minlowsig[1] = 0xFFFF; 11778c2ecf20Sopenharmony_ci 11788c2ecf20Sopenharmony_ci for (i = -4; i < 5; i += 2) { 11798c2ecf20Sopenharmony_ci for (j = -4; j < 5; j += 2) { 11808c2ecf20Sopenharmony_ci if (j < 0) 11818c2ecf20Sopenharmony_ci fval = (0x0100 * i) + j + 0x0100; 11828c2ecf20Sopenharmony_ci else 11838c2ecf20Sopenharmony_ci fval = (0x0100 * i) + j; 11848c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x002F, fval); 11858c2ecf20Sopenharmony_ci mls = b43legacy_phy_lo_b_r15_loop(dev) / 10; 11868c2ecf20Sopenharmony_ci if (mls < phy->minlowsig[1]) { 11878c2ecf20Sopenharmony_ci phy->minlowsig[1] = mls; 11888c2ecf20Sopenharmony_ci phy->minlowsigpos[1] = fval; 11898c2ecf20Sopenharmony_ci } 11908c2ecf20Sopenharmony_ci } 11918c2ecf20Sopenharmony_ci } 11928c2ecf20Sopenharmony_ci phy->minlowsigpos[1] += 0x0101; 11938c2ecf20Sopenharmony_ci 11948c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x002F, phy->minlowsigpos[1]); 11958c2ecf20Sopenharmony_ci if (phy->radio_ver == 0x2053) { 11968c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x000A, regstack[2]); 11978c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x002A, regstack[3]); 11988c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0035, regstack[4]); 11998c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0003, regstack[5]); 12008c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0001, regstack[6]); 12018c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0030, regstack[7]); 12028c2ecf20Sopenharmony_ci 12038c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x0043, regstack[8]); 12048c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x007A, regstack[9]); 12058c2ecf20Sopenharmony_ci 12068c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x0052, 12078c2ecf20Sopenharmony_ci (b43legacy_radio_read16(dev, 0x0052) 12088c2ecf20Sopenharmony_ci & 0x000F) | regstack[11]); 12098c2ecf20Sopenharmony_ci 12108c2ecf20Sopenharmony_ci b43legacy_write16(dev, 0x03EC, regstack[10]); 12118c2ecf20Sopenharmony_ci } 12128c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0015, regstack[0]); 12138c2ecf20Sopenharmony_ci} 12148c2ecf20Sopenharmony_ci 12158c2ecf20Sopenharmony_cistatic inline 12168c2ecf20Sopenharmony_ciu16 b43legacy_phy_lo_g_deviation_subval(struct b43legacy_wldev *dev, 12178c2ecf20Sopenharmony_ci u16 control) 12188c2ecf20Sopenharmony_ci{ 12198c2ecf20Sopenharmony_ci struct b43legacy_phy *phy = &dev->phy; 12208c2ecf20Sopenharmony_ci u16 ret; 12218c2ecf20Sopenharmony_ci unsigned long flags; 12228c2ecf20Sopenharmony_ci 12238c2ecf20Sopenharmony_ci local_irq_save(flags); 12248c2ecf20Sopenharmony_ci if (phy->gmode) { 12258c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x15, 0xE300); 12268c2ecf20Sopenharmony_ci control <<= 8; 12278c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0812, control | 0x00B0); 12288c2ecf20Sopenharmony_ci udelay(5); 12298c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0812, control | 0x00B2); 12308c2ecf20Sopenharmony_ci udelay(2); 12318c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0812, control | 0x00B3); 12328c2ecf20Sopenharmony_ci udelay(4); 12338c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0015, 0xF300); 12348c2ecf20Sopenharmony_ci udelay(8); 12358c2ecf20Sopenharmony_ci } else { 12368c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0015, control | 0xEFA0); 12378c2ecf20Sopenharmony_ci udelay(2); 12388c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0015, control | 0xEFE0); 12398c2ecf20Sopenharmony_ci udelay(4); 12408c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0015, control | 0xFFE0); 12418c2ecf20Sopenharmony_ci udelay(8); 12428c2ecf20Sopenharmony_ci } 12438c2ecf20Sopenharmony_ci ret = b43legacy_phy_read(dev, 0x002D); 12448c2ecf20Sopenharmony_ci local_irq_restore(flags); 12458c2ecf20Sopenharmony_ci cond_resched(); 12468c2ecf20Sopenharmony_ci 12478c2ecf20Sopenharmony_ci return ret; 12488c2ecf20Sopenharmony_ci} 12498c2ecf20Sopenharmony_ci 12508c2ecf20Sopenharmony_cistatic u32 b43legacy_phy_lo_g_singledeviation(struct b43legacy_wldev *dev, 12518c2ecf20Sopenharmony_ci u16 control) 12528c2ecf20Sopenharmony_ci{ 12538c2ecf20Sopenharmony_ci int i; 12548c2ecf20Sopenharmony_ci u32 ret = 0; 12558c2ecf20Sopenharmony_ci 12568c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++) 12578c2ecf20Sopenharmony_ci ret += b43legacy_phy_lo_g_deviation_subval(dev, control); 12588c2ecf20Sopenharmony_ci 12598c2ecf20Sopenharmony_ci return ret; 12608c2ecf20Sopenharmony_ci} 12618c2ecf20Sopenharmony_ci 12628c2ecf20Sopenharmony_ci/* Write the LocalOscillator CONTROL */ 12638c2ecf20Sopenharmony_cistatic inline 12648c2ecf20Sopenharmony_civoid b43legacy_lo_write(struct b43legacy_wldev *dev, 12658c2ecf20Sopenharmony_ci struct b43legacy_lopair *pair) 12668c2ecf20Sopenharmony_ci{ 12678c2ecf20Sopenharmony_ci u16 value; 12688c2ecf20Sopenharmony_ci 12698c2ecf20Sopenharmony_ci value = (u8)(pair->low); 12708c2ecf20Sopenharmony_ci value |= ((u8)(pair->high)) << 8; 12718c2ecf20Sopenharmony_ci 12728c2ecf20Sopenharmony_ci#ifdef CONFIG_B43LEGACY_DEBUG 12738c2ecf20Sopenharmony_ci /* Sanity check. */ 12748c2ecf20Sopenharmony_ci if (pair->low < -8 || pair->low > 8 || 12758c2ecf20Sopenharmony_ci pair->high < -8 || pair->high > 8) { 12768c2ecf20Sopenharmony_ci b43legacydbg(dev->wl, 12778c2ecf20Sopenharmony_ci "WARNING: Writing invalid LOpair " 12788c2ecf20Sopenharmony_ci "(low: %d, high: %d)\n", 12798c2ecf20Sopenharmony_ci pair->low, pair->high); 12808c2ecf20Sopenharmony_ci dump_stack(); 12818c2ecf20Sopenharmony_ci } 12828c2ecf20Sopenharmony_ci#endif 12838c2ecf20Sopenharmony_ci 12848c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, B43legacy_PHY_G_LO_CONTROL, value); 12858c2ecf20Sopenharmony_ci} 12868c2ecf20Sopenharmony_ci 12878c2ecf20Sopenharmony_cistatic inline 12888c2ecf20Sopenharmony_cistruct b43legacy_lopair *b43legacy_find_lopair(struct b43legacy_wldev *dev, 12898c2ecf20Sopenharmony_ci u16 bbatt, 12908c2ecf20Sopenharmony_ci u16 rfatt, 12918c2ecf20Sopenharmony_ci u16 tx) 12928c2ecf20Sopenharmony_ci{ 12938c2ecf20Sopenharmony_ci static const u8 dict[10] = { 11, 10, 11, 12, 13, 12, 13, 12, 13, 12 }; 12948c2ecf20Sopenharmony_ci struct b43legacy_phy *phy = &dev->phy; 12958c2ecf20Sopenharmony_ci 12968c2ecf20Sopenharmony_ci if (bbatt > 6) 12978c2ecf20Sopenharmony_ci bbatt = 6; 12988c2ecf20Sopenharmony_ci B43legacy_WARN_ON(rfatt >= 10); 12998c2ecf20Sopenharmony_ci 13008c2ecf20Sopenharmony_ci if (tx == 3) 13018c2ecf20Sopenharmony_ci return b43legacy_get_lopair(phy, rfatt, bbatt); 13028c2ecf20Sopenharmony_ci return b43legacy_get_lopair(phy, dict[rfatt], bbatt); 13038c2ecf20Sopenharmony_ci} 13048c2ecf20Sopenharmony_ci 13058c2ecf20Sopenharmony_cistatic inline 13068c2ecf20Sopenharmony_cistruct b43legacy_lopair *b43legacy_current_lopair(struct b43legacy_wldev *dev) 13078c2ecf20Sopenharmony_ci{ 13088c2ecf20Sopenharmony_ci struct b43legacy_phy *phy = &dev->phy; 13098c2ecf20Sopenharmony_ci 13108c2ecf20Sopenharmony_ci return b43legacy_find_lopair(dev, phy->bbatt, 13118c2ecf20Sopenharmony_ci phy->rfatt, phy->txctl1); 13128c2ecf20Sopenharmony_ci} 13138c2ecf20Sopenharmony_ci 13148c2ecf20Sopenharmony_ci/* Adjust B/G LO */ 13158c2ecf20Sopenharmony_civoid b43legacy_phy_lo_adjust(struct b43legacy_wldev *dev, int fixed) 13168c2ecf20Sopenharmony_ci{ 13178c2ecf20Sopenharmony_ci struct b43legacy_lopair *pair; 13188c2ecf20Sopenharmony_ci 13198c2ecf20Sopenharmony_ci if (fixed) { 13208c2ecf20Sopenharmony_ci /* Use fixed values. Only for initialization. */ 13218c2ecf20Sopenharmony_ci pair = b43legacy_find_lopair(dev, 2, 3, 0); 13228c2ecf20Sopenharmony_ci } else 13238c2ecf20Sopenharmony_ci pair = b43legacy_current_lopair(dev); 13248c2ecf20Sopenharmony_ci b43legacy_lo_write(dev, pair); 13258c2ecf20Sopenharmony_ci} 13268c2ecf20Sopenharmony_ci 13278c2ecf20Sopenharmony_cistatic void b43legacy_phy_lo_g_measure_txctl2(struct b43legacy_wldev *dev) 13288c2ecf20Sopenharmony_ci{ 13298c2ecf20Sopenharmony_ci struct b43legacy_phy *phy = &dev->phy; 13308c2ecf20Sopenharmony_ci u16 txctl2 = 0; 13318c2ecf20Sopenharmony_ci u16 i; 13328c2ecf20Sopenharmony_ci u32 smallest; 13338c2ecf20Sopenharmony_ci u32 tmp; 13348c2ecf20Sopenharmony_ci 13358c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x0052, 0x0000); 13368c2ecf20Sopenharmony_ci udelay(10); 13378c2ecf20Sopenharmony_ci smallest = b43legacy_phy_lo_g_singledeviation(dev, 0); 13388c2ecf20Sopenharmony_ci for (i = 0; i < 16; i++) { 13398c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x0052, i); 13408c2ecf20Sopenharmony_ci udelay(10); 13418c2ecf20Sopenharmony_ci tmp = b43legacy_phy_lo_g_singledeviation(dev, 0); 13428c2ecf20Sopenharmony_ci if (tmp < smallest) { 13438c2ecf20Sopenharmony_ci smallest = tmp; 13448c2ecf20Sopenharmony_ci txctl2 = i; 13458c2ecf20Sopenharmony_ci } 13468c2ecf20Sopenharmony_ci } 13478c2ecf20Sopenharmony_ci phy->txctl2 = txctl2; 13488c2ecf20Sopenharmony_ci} 13498c2ecf20Sopenharmony_ci 13508c2ecf20Sopenharmony_cistatic 13518c2ecf20Sopenharmony_civoid b43legacy_phy_lo_g_state(struct b43legacy_wldev *dev, 13528c2ecf20Sopenharmony_ci const struct b43legacy_lopair *in_pair, 13538c2ecf20Sopenharmony_ci struct b43legacy_lopair *out_pair, 13548c2ecf20Sopenharmony_ci u16 r27) 13558c2ecf20Sopenharmony_ci{ 13568c2ecf20Sopenharmony_ci static const struct b43legacy_lopair transitions[8] = { 13578c2ecf20Sopenharmony_ci { .high = 1, .low = 1, }, 13588c2ecf20Sopenharmony_ci { .high = 1, .low = 0, }, 13598c2ecf20Sopenharmony_ci { .high = 1, .low = -1, }, 13608c2ecf20Sopenharmony_ci { .high = 0, .low = -1, }, 13618c2ecf20Sopenharmony_ci { .high = -1, .low = -1, }, 13628c2ecf20Sopenharmony_ci { .high = -1, .low = 0, }, 13638c2ecf20Sopenharmony_ci { .high = -1, .low = 1, }, 13648c2ecf20Sopenharmony_ci { .high = 0, .low = 1, }, 13658c2ecf20Sopenharmony_ci }; 13668c2ecf20Sopenharmony_ci struct b43legacy_lopair lowest_transition = { 13678c2ecf20Sopenharmony_ci .high = in_pair->high, 13688c2ecf20Sopenharmony_ci .low = in_pair->low, 13698c2ecf20Sopenharmony_ci }; 13708c2ecf20Sopenharmony_ci struct b43legacy_lopair tmp_pair; 13718c2ecf20Sopenharmony_ci struct b43legacy_lopair transition; 13728c2ecf20Sopenharmony_ci int i = 12; 13738c2ecf20Sopenharmony_ci int state = 0; 13748c2ecf20Sopenharmony_ci int found_lower; 13758c2ecf20Sopenharmony_ci int j; 13768c2ecf20Sopenharmony_ci int begin; 13778c2ecf20Sopenharmony_ci int end; 13788c2ecf20Sopenharmony_ci u32 lowest_deviation; 13798c2ecf20Sopenharmony_ci u32 tmp; 13808c2ecf20Sopenharmony_ci 13818c2ecf20Sopenharmony_ci /* Note that in_pair and out_pair can point to the same pair. 13828c2ecf20Sopenharmony_ci * Be careful. */ 13838c2ecf20Sopenharmony_ci 13848c2ecf20Sopenharmony_ci b43legacy_lo_write(dev, &lowest_transition); 13858c2ecf20Sopenharmony_ci lowest_deviation = b43legacy_phy_lo_g_singledeviation(dev, r27); 13868c2ecf20Sopenharmony_ci do { 13878c2ecf20Sopenharmony_ci found_lower = 0; 13888c2ecf20Sopenharmony_ci B43legacy_WARN_ON(!(state >= 0 && state <= 8)); 13898c2ecf20Sopenharmony_ci if (state == 0) { 13908c2ecf20Sopenharmony_ci begin = 1; 13918c2ecf20Sopenharmony_ci end = 8; 13928c2ecf20Sopenharmony_ci } else if (state % 2 == 0) { 13938c2ecf20Sopenharmony_ci begin = state - 1; 13948c2ecf20Sopenharmony_ci end = state + 1; 13958c2ecf20Sopenharmony_ci } else { 13968c2ecf20Sopenharmony_ci begin = state - 2; 13978c2ecf20Sopenharmony_ci end = state + 2; 13988c2ecf20Sopenharmony_ci } 13998c2ecf20Sopenharmony_ci if (begin < 1) 14008c2ecf20Sopenharmony_ci begin += 8; 14018c2ecf20Sopenharmony_ci if (end > 8) 14028c2ecf20Sopenharmony_ci end -= 8; 14038c2ecf20Sopenharmony_ci 14048c2ecf20Sopenharmony_ci j = begin; 14058c2ecf20Sopenharmony_ci tmp_pair.high = lowest_transition.high; 14068c2ecf20Sopenharmony_ci tmp_pair.low = lowest_transition.low; 14078c2ecf20Sopenharmony_ci while (1) { 14088c2ecf20Sopenharmony_ci B43legacy_WARN_ON(!(j >= 1 && j <= 8)); 14098c2ecf20Sopenharmony_ci transition.high = tmp_pair.high + 14108c2ecf20Sopenharmony_ci transitions[j - 1].high; 14118c2ecf20Sopenharmony_ci transition.low = tmp_pair.low + transitions[j - 1].low; 14128c2ecf20Sopenharmony_ci if ((abs(transition.low) < 9) 14138c2ecf20Sopenharmony_ci && (abs(transition.high) < 9)) { 14148c2ecf20Sopenharmony_ci b43legacy_lo_write(dev, &transition); 14158c2ecf20Sopenharmony_ci tmp = b43legacy_phy_lo_g_singledeviation(dev, 14168c2ecf20Sopenharmony_ci r27); 14178c2ecf20Sopenharmony_ci if (tmp < lowest_deviation) { 14188c2ecf20Sopenharmony_ci lowest_deviation = tmp; 14198c2ecf20Sopenharmony_ci state = j; 14208c2ecf20Sopenharmony_ci found_lower = 1; 14218c2ecf20Sopenharmony_ci 14228c2ecf20Sopenharmony_ci lowest_transition.high = 14238c2ecf20Sopenharmony_ci transition.high; 14248c2ecf20Sopenharmony_ci lowest_transition.low = transition.low; 14258c2ecf20Sopenharmony_ci } 14268c2ecf20Sopenharmony_ci } 14278c2ecf20Sopenharmony_ci if (j == end) 14288c2ecf20Sopenharmony_ci break; 14298c2ecf20Sopenharmony_ci if (j == 8) 14308c2ecf20Sopenharmony_ci j = 1; 14318c2ecf20Sopenharmony_ci else 14328c2ecf20Sopenharmony_ci j++; 14338c2ecf20Sopenharmony_ci } 14348c2ecf20Sopenharmony_ci } while (i-- && found_lower); 14358c2ecf20Sopenharmony_ci 14368c2ecf20Sopenharmony_ci out_pair->high = lowest_transition.high; 14378c2ecf20Sopenharmony_ci out_pair->low = lowest_transition.low; 14388c2ecf20Sopenharmony_ci} 14398c2ecf20Sopenharmony_ci 14408c2ecf20Sopenharmony_ci/* Set the baseband attenuation value on chip. */ 14418c2ecf20Sopenharmony_civoid b43legacy_phy_set_baseband_attenuation(struct b43legacy_wldev *dev, 14428c2ecf20Sopenharmony_ci u16 bbatt) 14438c2ecf20Sopenharmony_ci{ 14448c2ecf20Sopenharmony_ci struct b43legacy_phy *phy = &dev->phy; 14458c2ecf20Sopenharmony_ci u16 value; 14468c2ecf20Sopenharmony_ci 14478c2ecf20Sopenharmony_ci if (phy->analog == 0) { 14488c2ecf20Sopenharmony_ci value = (b43legacy_read16(dev, 0x03E6) & 0xFFF0); 14498c2ecf20Sopenharmony_ci value |= (bbatt & 0x000F); 14508c2ecf20Sopenharmony_ci b43legacy_write16(dev, 0x03E6, value); 14518c2ecf20Sopenharmony_ci return; 14528c2ecf20Sopenharmony_ci } 14538c2ecf20Sopenharmony_ci 14548c2ecf20Sopenharmony_ci if (phy->analog > 1) { 14558c2ecf20Sopenharmony_ci value = b43legacy_phy_read(dev, 0x0060) & 0xFFC3; 14568c2ecf20Sopenharmony_ci value |= (bbatt << 2) & 0x003C; 14578c2ecf20Sopenharmony_ci } else { 14588c2ecf20Sopenharmony_ci value = b43legacy_phy_read(dev, 0x0060) & 0xFF87; 14598c2ecf20Sopenharmony_ci value |= (bbatt << 3) & 0x0078; 14608c2ecf20Sopenharmony_ci } 14618c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0060, value); 14628c2ecf20Sopenharmony_ci} 14638c2ecf20Sopenharmony_ci 14648c2ecf20Sopenharmony_ci/* https://bcm-specs.sipsolutions.net/LocalOscillator/Measure */ 14658c2ecf20Sopenharmony_civoid b43legacy_phy_lo_g_measure(struct b43legacy_wldev *dev) 14668c2ecf20Sopenharmony_ci{ 14678c2ecf20Sopenharmony_ci static const u8 pairorder[10] = { 3, 1, 5, 7, 9, 2, 0, 4, 6, 8 }; 14688c2ecf20Sopenharmony_ci const int is_initializing = (b43legacy_status(dev) 14698c2ecf20Sopenharmony_ci < B43legacy_STAT_STARTED); 14708c2ecf20Sopenharmony_ci struct b43legacy_phy *phy = &dev->phy; 14718c2ecf20Sopenharmony_ci u16 h; 14728c2ecf20Sopenharmony_ci u16 i; 14738c2ecf20Sopenharmony_ci u16 oldi = 0; 14748c2ecf20Sopenharmony_ci u16 j; 14758c2ecf20Sopenharmony_ci struct b43legacy_lopair control; 14768c2ecf20Sopenharmony_ci struct b43legacy_lopair *tmp_control; 14778c2ecf20Sopenharmony_ci u16 tmp; 14788c2ecf20Sopenharmony_ci u16 regstack[16] = { 0 }; 14798c2ecf20Sopenharmony_ci u8 oldchannel; 14808c2ecf20Sopenharmony_ci 14818c2ecf20Sopenharmony_ci /* XXX: What are these? */ 14828c2ecf20Sopenharmony_ci u8 r27 = 0; 14838c2ecf20Sopenharmony_ci u16 r31; 14848c2ecf20Sopenharmony_ci 14858c2ecf20Sopenharmony_ci oldchannel = phy->channel; 14868c2ecf20Sopenharmony_ci /* Setup */ 14878c2ecf20Sopenharmony_ci if (phy->gmode) { 14888c2ecf20Sopenharmony_ci regstack[0] = b43legacy_phy_read(dev, B43legacy_PHY_G_CRS); 14898c2ecf20Sopenharmony_ci regstack[1] = b43legacy_phy_read(dev, 0x0802); 14908c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, B43legacy_PHY_G_CRS, regstack[0] 14918c2ecf20Sopenharmony_ci & 0x7FFF); 14928c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0802, regstack[1] & 0xFFFC); 14938c2ecf20Sopenharmony_ci } 14948c2ecf20Sopenharmony_ci regstack[3] = b43legacy_read16(dev, 0x03E2); 14958c2ecf20Sopenharmony_ci b43legacy_write16(dev, 0x03E2, regstack[3] | 0x8000); 14968c2ecf20Sopenharmony_ci regstack[4] = b43legacy_read16(dev, B43legacy_MMIO_CHANNEL_EXT); 14978c2ecf20Sopenharmony_ci regstack[5] = b43legacy_phy_read(dev, 0x15); 14988c2ecf20Sopenharmony_ci regstack[6] = b43legacy_phy_read(dev, 0x2A); 14998c2ecf20Sopenharmony_ci regstack[7] = b43legacy_phy_read(dev, 0x35); 15008c2ecf20Sopenharmony_ci regstack[8] = b43legacy_phy_read(dev, 0x60); 15018c2ecf20Sopenharmony_ci regstack[9] = b43legacy_radio_read16(dev, 0x43); 15028c2ecf20Sopenharmony_ci regstack[10] = b43legacy_radio_read16(dev, 0x7A); 15038c2ecf20Sopenharmony_ci regstack[11] = b43legacy_radio_read16(dev, 0x52); 15048c2ecf20Sopenharmony_ci if (phy->gmode) { 15058c2ecf20Sopenharmony_ci regstack[12] = b43legacy_phy_read(dev, 0x0811); 15068c2ecf20Sopenharmony_ci regstack[13] = b43legacy_phy_read(dev, 0x0812); 15078c2ecf20Sopenharmony_ci regstack[14] = b43legacy_phy_read(dev, 0x0814); 15088c2ecf20Sopenharmony_ci regstack[15] = b43legacy_phy_read(dev, 0x0815); 15098c2ecf20Sopenharmony_ci } 15108c2ecf20Sopenharmony_ci b43legacy_radio_selectchannel(dev, 6, 0); 15118c2ecf20Sopenharmony_ci if (phy->gmode) { 15128c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, B43legacy_PHY_G_CRS, regstack[0] 15138c2ecf20Sopenharmony_ci & 0x7FFF); 15148c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0802, regstack[1] & 0xFFFC); 15158c2ecf20Sopenharmony_ci b43legacy_dummy_transmission(dev); 15168c2ecf20Sopenharmony_ci } 15178c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x0043, 0x0006); 15188c2ecf20Sopenharmony_ci 15198c2ecf20Sopenharmony_ci b43legacy_phy_set_baseband_attenuation(dev, 2); 15208c2ecf20Sopenharmony_ci 15218c2ecf20Sopenharmony_ci b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT, 0x0000); 15228c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x002E, 0x007F); 15238c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x080F, 0x0078); 15248c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0035, regstack[7] & ~(1 << 7)); 15258c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x007A, regstack[10] & 0xFFF0); 15268c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x002B, 0x0203); 15278c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x002A, 0x08A3); 15288c2ecf20Sopenharmony_ci if (phy->gmode) { 15298c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0814, regstack[14] | 0x0003); 15308c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0815, regstack[15] & 0xFFFC); 15318c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0811, 0x01B3); 15328c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0812, 0x00B2); 15338c2ecf20Sopenharmony_ci } 15348c2ecf20Sopenharmony_ci if (is_initializing) 15358c2ecf20Sopenharmony_ci b43legacy_phy_lo_g_measure_txctl2(dev); 15368c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x080F, 0x8078); 15378c2ecf20Sopenharmony_ci 15388c2ecf20Sopenharmony_ci /* Measure */ 15398c2ecf20Sopenharmony_ci control.low = 0; 15408c2ecf20Sopenharmony_ci control.high = 0; 15418c2ecf20Sopenharmony_ci for (h = 0; h < 10; h++) { 15428c2ecf20Sopenharmony_ci /* Loop over each possible RadioAttenuation (0-9) */ 15438c2ecf20Sopenharmony_ci i = pairorder[h]; 15448c2ecf20Sopenharmony_ci if (is_initializing) { 15458c2ecf20Sopenharmony_ci if (i == 3) { 15468c2ecf20Sopenharmony_ci control.low = 0; 15478c2ecf20Sopenharmony_ci control.high = 0; 15488c2ecf20Sopenharmony_ci } else if (((i % 2 == 1) && (oldi % 2 == 1)) || 15498c2ecf20Sopenharmony_ci ((i % 2 == 0) && (oldi % 2 == 0))) { 15508c2ecf20Sopenharmony_ci tmp_control = b43legacy_get_lopair(phy, oldi, 15518c2ecf20Sopenharmony_ci 0); 15528c2ecf20Sopenharmony_ci memcpy(&control, tmp_control, sizeof(control)); 15538c2ecf20Sopenharmony_ci } else { 15548c2ecf20Sopenharmony_ci tmp_control = b43legacy_get_lopair(phy, 3, 0); 15558c2ecf20Sopenharmony_ci memcpy(&control, tmp_control, sizeof(control)); 15568c2ecf20Sopenharmony_ci } 15578c2ecf20Sopenharmony_ci } 15588c2ecf20Sopenharmony_ci /* Loop over each possible BasebandAttenuation/2 */ 15598c2ecf20Sopenharmony_ci for (j = 0; j < 4; j++) { 15608c2ecf20Sopenharmony_ci if (is_initializing) { 15618c2ecf20Sopenharmony_ci tmp = i * 2 + j; 15628c2ecf20Sopenharmony_ci r27 = 0; 15638c2ecf20Sopenharmony_ci r31 = 0; 15648c2ecf20Sopenharmony_ci if (tmp > 14) { 15658c2ecf20Sopenharmony_ci r31 = 1; 15668c2ecf20Sopenharmony_ci if (tmp > 17) 15678c2ecf20Sopenharmony_ci r27 = 1; 15688c2ecf20Sopenharmony_ci if (tmp > 19) 15698c2ecf20Sopenharmony_ci r27 = 2; 15708c2ecf20Sopenharmony_ci } 15718c2ecf20Sopenharmony_ci } else { 15728c2ecf20Sopenharmony_ci tmp_control = b43legacy_get_lopair(phy, i, 15738c2ecf20Sopenharmony_ci j * 2); 15748c2ecf20Sopenharmony_ci if (!tmp_control->used) 15758c2ecf20Sopenharmony_ci continue; 15768c2ecf20Sopenharmony_ci memcpy(&control, tmp_control, sizeof(control)); 15778c2ecf20Sopenharmony_ci r27 = 3; 15788c2ecf20Sopenharmony_ci r31 = 0; 15798c2ecf20Sopenharmony_ci } 15808c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x43, i); 15818c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x52, phy->txctl2); 15828c2ecf20Sopenharmony_ci udelay(10); 15838c2ecf20Sopenharmony_ci cond_resched(); 15848c2ecf20Sopenharmony_ci 15858c2ecf20Sopenharmony_ci b43legacy_phy_set_baseband_attenuation(dev, j * 2); 15868c2ecf20Sopenharmony_ci 15878c2ecf20Sopenharmony_ci tmp = (regstack[10] & 0xFFF0); 15888c2ecf20Sopenharmony_ci if (r31) 15898c2ecf20Sopenharmony_ci tmp |= 0x0008; 15908c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x007A, tmp); 15918c2ecf20Sopenharmony_ci 15928c2ecf20Sopenharmony_ci tmp_control = b43legacy_get_lopair(phy, i, j * 2); 15938c2ecf20Sopenharmony_ci b43legacy_phy_lo_g_state(dev, &control, tmp_control, 15948c2ecf20Sopenharmony_ci r27); 15958c2ecf20Sopenharmony_ci } 15968c2ecf20Sopenharmony_ci oldi = i; 15978c2ecf20Sopenharmony_ci } 15988c2ecf20Sopenharmony_ci /* Loop over each possible RadioAttenuation (10-13) */ 15998c2ecf20Sopenharmony_ci for (i = 10; i < 14; i++) { 16008c2ecf20Sopenharmony_ci /* Loop over each possible BasebandAttenuation/2 */ 16018c2ecf20Sopenharmony_ci for (j = 0; j < 4; j++) { 16028c2ecf20Sopenharmony_ci if (is_initializing) { 16038c2ecf20Sopenharmony_ci tmp_control = b43legacy_get_lopair(phy, i - 9, 16048c2ecf20Sopenharmony_ci j * 2); 16058c2ecf20Sopenharmony_ci memcpy(&control, tmp_control, sizeof(control)); 16068c2ecf20Sopenharmony_ci /* FIXME: The next line is wrong, as the 16078c2ecf20Sopenharmony_ci * following if statement can never trigger. */ 16088c2ecf20Sopenharmony_ci tmp = (i - 9) * 2 + j - 5; 16098c2ecf20Sopenharmony_ci r27 = 0; 16108c2ecf20Sopenharmony_ci r31 = 0; 16118c2ecf20Sopenharmony_ci if (tmp > 14) { 16128c2ecf20Sopenharmony_ci r31 = 1; 16138c2ecf20Sopenharmony_ci if (tmp > 17) 16148c2ecf20Sopenharmony_ci r27 = 1; 16158c2ecf20Sopenharmony_ci if (tmp > 19) 16168c2ecf20Sopenharmony_ci r27 = 2; 16178c2ecf20Sopenharmony_ci } 16188c2ecf20Sopenharmony_ci } else { 16198c2ecf20Sopenharmony_ci tmp_control = b43legacy_get_lopair(phy, i - 9, 16208c2ecf20Sopenharmony_ci j * 2); 16218c2ecf20Sopenharmony_ci if (!tmp_control->used) 16228c2ecf20Sopenharmony_ci continue; 16238c2ecf20Sopenharmony_ci memcpy(&control, tmp_control, sizeof(control)); 16248c2ecf20Sopenharmony_ci r27 = 3; 16258c2ecf20Sopenharmony_ci r31 = 0; 16268c2ecf20Sopenharmony_ci } 16278c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x43, i - 9); 16288c2ecf20Sopenharmony_ci /* FIXME: shouldn't txctl1 be zero in the next line 16298c2ecf20Sopenharmony_ci * and 3 in the loop above? */ 16308c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x52, 16318c2ecf20Sopenharmony_ci phy->txctl2 16328c2ecf20Sopenharmony_ci | (3/*txctl1*/ << 4)); 16338c2ecf20Sopenharmony_ci udelay(10); 16348c2ecf20Sopenharmony_ci cond_resched(); 16358c2ecf20Sopenharmony_ci 16368c2ecf20Sopenharmony_ci b43legacy_phy_set_baseband_attenuation(dev, j * 2); 16378c2ecf20Sopenharmony_ci 16388c2ecf20Sopenharmony_ci tmp = (regstack[10] & 0xFFF0); 16398c2ecf20Sopenharmony_ci if (r31) 16408c2ecf20Sopenharmony_ci tmp |= 0x0008; 16418c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x7A, tmp); 16428c2ecf20Sopenharmony_ci 16438c2ecf20Sopenharmony_ci tmp_control = b43legacy_get_lopair(phy, i, j * 2); 16448c2ecf20Sopenharmony_ci b43legacy_phy_lo_g_state(dev, &control, tmp_control, 16458c2ecf20Sopenharmony_ci r27); 16468c2ecf20Sopenharmony_ci } 16478c2ecf20Sopenharmony_ci } 16488c2ecf20Sopenharmony_ci 16498c2ecf20Sopenharmony_ci /* Restoration */ 16508c2ecf20Sopenharmony_ci if (phy->gmode) { 16518c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0015, 0xE300); 16528c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0812, (r27 << 8) | 0xA0); 16538c2ecf20Sopenharmony_ci udelay(5); 16548c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0812, (r27 << 8) | 0xA2); 16558c2ecf20Sopenharmony_ci udelay(2); 16568c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0812, (r27 << 8) | 0xA3); 16578c2ecf20Sopenharmony_ci cond_resched(); 16588c2ecf20Sopenharmony_ci } else 16598c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0015, r27 | 0xEFA0); 16608c2ecf20Sopenharmony_ci b43legacy_phy_lo_adjust(dev, is_initializing); 16618c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x002E, 0x807F); 16628c2ecf20Sopenharmony_ci if (phy->gmode) 16638c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x002F, 0x0202); 16648c2ecf20Sopenharmony_ci else 16658c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x002F, 0x0101); 16668c2ecf20Sopenharmony_ci b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT, regstack[4]); 16678c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0015, regstack[5]); 16688c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x002A, regstack[6]); 16698c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0035, regstack[7]); 16708c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0060, regstack[8]); 16718c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x0043, regstack[9]); 16728c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x007A, regstack[10]); 16738c2ecf20Sopenharmony_ci regstack[11] &= 0x00F0; 16748c2ecf20Sopenharmony_ci regstack[11] |= (b43legacy_radio_read16(dev, 0x52) & 0x000F); 16758c2ecf20Sopenharmony_ci b43legacy_radio_write16(dev, 0x52, regstack[11]); 16768c2ecf20Sopenharmony_ci b43legacy_write16(dev, 0x03E2, regstack[3]); 16778c2ecf20Sopenharmony_ci if (phy->gmode) { 16788c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0811, regstack[12]); 16798c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0812, regstack[13]); 16808c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0814, regstack[14]); 16818c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0815, regstack[15]); 16828c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, B43legacy_PHY_G_CRS, regstack[0]); 16838c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0802, regstack[1]); 16848c2ecf20Sopenharmony_ci } 16858c2ecf20Sopenharmony_ci b43legacy_radio_selectchannel(dev, oldchannel, 1); 16868c2ecf20Sopenharmony_ci 16878c2ecf20Sopenharmony_ci#ifdef CONFIG_B43LEGACY_DEBUG 16888c2ecf20Sopenharmony_ci { 16898c2ecf20Sopenharmony_ci /* Sanity check for all lopairs. */ 16908c2ecf20Sopenharmony_ci for (i = 0; i < B43legacy_LO_COUNT; i++) { 16918c2ecf20Sopenharmony_ci tmp_control = phy->_lo_pairs + i; 16928c2ecf20Sopenharmony_ci if (tmp_control->low < -8 || tmp_control->low > 8 || 16938c2ecf20Sopenharmony_ci tmp_control->high < -8 || tmp_control->high > 8) 16948c2ecf20Sopenharmony_ci b43legacywarn(dev->wl, 16958c2ecf20Sopenharmony_ci "WARNING: Invalid LOpair (low: %d, high:" 16968c2ecf20Sopenharmony_ci " %d, index: %d)\n", 16978c2ecf20Sopenharmony_ci tmp_control->low, tmp_control->high, i); 16988c2ecf20Sopenharmony_ci } 16998c2ecf20Sopenharmony_ci } 17008c2ecf20Sopenharmony_ci#endif /* CONFIG_B43LEGACY_DEBUG */ 17018c2ecf20Sopenharmony_ci} 17028c2ecf20Sopenharmony_ci 17038c2ecf20Sopenharmony_cistatic 17048c2ecf20Sopenharmony_civoid b43legacy_phy_lo_mark_current_used(struct b43legacy_wldev *dev) 17058c2ecf20Sopenharmony_ci{ 17068c2ecf20Sopenharmony_ci struct b43legacy_lopair *pair; 17078c2ecf20Sopenharmony_ci 17088c2ecf20Sopenharmony_ci pair = b43legacy_current_lopair(dev); 17098c2ecf20Sopenharmony_ci pair->used = 1; 17108c2ecf20Sopenharmony_ci} 17118c2ecf20Sopenharmony_ci 17128c2ecf20Sopenharmony_civoid b43legacy_phy_lo_mark_all_unused(struct b43legacy_wldev *dev) 17138c2ecf20Sopenharmony_ci{ 17148c2ecf20Sopenharmony_ci struct b43legacy_phy *phy = &dev->phy; 17158c2ecf20Sopenharmony_ci struct b43legacy_lopair *pair; 17168c2ecf20Sopenharmony_ci int i; 17178c2ecf20Sopenharmony_ci 17188c2ecf20Sopenharmony_ci for (i = 0; i < B43legacy_LO_COUNT; i++) { 17198c2ecf20Sopenharmony_ci pair = phy->_lo_pairs + i; 17208c2ecf20Sopenharmony_ci pair->used = 0; 17218c2ecf20Sopenharmony_ci } 17228c2ecf20Sopenharmony_ci} 17238c2ecf20Sopenharmony_ci 17248c2ecf20Sopenharmony_ci/* https://bcm-specs.sipsolutions.net/EstimatePowerOut 17258c2ecf20Sopenharmony_ci * This function converts a TSSI value to dBm in Q5.2 17268c2ecf20Sopenharmony_ci */ 17278c2ecf20Sopenharmony_cistatic s8 b43legacy_phy_estimate_power_out(struct b43legacy_wldev *dev, s8 tssi) 17288c2ecf20Sopenharmony_ci{ 17298c2ecf20Sopenharmony_ci struct b43legacy_phy *phy = &dev->phy; 17308c2ecf20Sopenharmony_ci s8 dbm = 0; 17318c2ecf20Sopenharmony_ci s32 tmp; 17328c2ecf20Sopenharmony_ci 17338c2ecf20Sopenharmony_ci tmp = phy->idle_tssi; 17348c2ecf20Sopenharmony_ci tmp += tssi; 17358c2ecf20Sopenharmony_ci tmp -= phy->savedpctlreg; 17368c2ecf20Sopenharmony_ci 17378c2ecf20Sopenharmony_ci switch (phy->type) { 17388c2ecf20Sopenharmony_ci case B43legacy_PHYTYPE_B: 17398c2ecf20Sopenharmony_ci case B43legacy_PHYTYPE_G: 17408c2ecf20Sopenharmony_ci tmp = clamp_val(tmp, 0x00, 0x3F); 17418c2ecf20Sopenharmony_ci dbm = phy->tssi2dbm[tmp]; 17428c2ecf20Sopenharmony_ci break; 17438c2ecf20Sopenharmony_ci default: 17448c2ecf20Sopenharmony_ci B43legacy_BUG_ON(1); 17458c2ecf20Sopenharmony_ci } 17468c2ecf20Sopenharmony_ci 17478c2ecf20Sopenharmony_ci return dbm; 17488c2ecf20Sopenharmony_ci} 17498c2ecf20Sopenharmony_ci 17508c2ecf20Sopenharmony_ci/* https://bcm-specs.sipsolutions.net/RecalculateTransmissionPower */ 17518c2ecf20Sopenharmony_civoid b43legacy_phy_xmitpower(struct b43legacy_wldev *dev) 17528c2ecf20Sopenharmony_ci{ 17538c2ecf20Sopenharmony_ci struct b43legacy_phy *phy = &dev->phy; 17548c2ecf20Sopenharmony_ci u16 tmp; 17558c2ecf20Sopenharmony_ci u16 txpower; 17568c2ecf20Sopenharmony_ci s8 v0; 17578c2ecf20Sopenharmony_ci s8 v1; 17588c2ecf20Sopenharmony_ci s8 v2; 17598c2ecf20Sopenharmony_ci s8 v3; 17608c2ecf20Sopenharmony_ci s8 average; 17618c2ecf20Sopenharmony_ci int max_pwr; 17628c2ecf20Sopenharmony_ci s16 desired_pwr; 17638c2ecf20Sopenharmony_ci s16 estimated_pwr; 17648c2ecf20Sopenharmony_ci s16 pwr_adjust; 17658c2ecf20Sopenharmony_ci s16 radio_att_delta; 17668c2ecf20Sopenharmony_ci s16 baseband_att_delta; 17678c2ecf20Sopenharmony_ci s16 radio_attenuation; 17688c2ecf20Sopenharmony_ci s16 baseband_attenuation; 17698c2ecf20Sopenharmony_ci 17708c2ecf20Sopenharmony_ci if (phy->savedpctlreg == 0xFFFF) 17718c2ecf20Sopenharmony_ci return; 17728c2ecf20Sopenharmony_ci if ((dev->dev->bus->boardinfo.type == 0x0416) && 17738c2ecf20Sopenharmony_ci is_bcm_board_vendor(dev)) 17748c2ecf20Sopenharmony_ci return; 17758c2ecf20Sopenharmony_ci#ifdef CONFIG_B43LEGACY_DEBUG 17768c2ecf20Sopenharmony_ci if (phy->manual_txpower_control) 17778c2ecf20Sopenharmony_ci return; 17788c2ecf20Sopenharmony_ci#endif 17798c2ecf20Sopenharmony_ci 17808c2ecf20Sopenharmony_ci B43legacy_BUG_ON(!(phy->type == B43legacy_PHYTYPE_B || 17818c2ecf20Sopenharmony_ci phy->type == B43legacy_PHYTYPE_G)); 17828c2ecf20Sopenharmony_ci tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x0058); 17838c2ecf20Sopenharmony_ci v0 = (s8)(tmp & 0x00FF); 17848c2ecf20Sopenharmony_ci v1 = (s8)((tmp & 0xFF00) >> 8); 17858c2ecf20Sopenharmony_ci tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x005A); 17868c2ecf20Sopenharmony_ci v2 = (s8)(tmp & 0x00FF); 17878c2ecf20Sopenharmony_ci v3 = (s8)((tmp & 0xFF00) >> 8); 17888c2ecf20Sopenharmony_ci tmp = 0; 17898c2ecf20Sopenharmony_ci 17908c2ecf20Sopenharmony_ci if (v0 == 0x7F || v1 == 0x7F || v2 == 0x7F || v3 == 0x7F) { 17918c2ecf20Sopenharmony_ci tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 17928c2ecf20Sopenharmony_ci 0x0070); 17938c2ecf20Sopenharmony_ci v0 = (s8)(tmp & 0x00FF); 17948c2ecf20Sopenharmony_ci v1 = (s8)((tmp & 0xFF00) >> 8); 17958c2ecf20Sopenharmony_ci tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 17968c2ecf20Sopenharmony_ci 0x0072); 17978c2ecf20Sopenharmony_ci v2 = (s8)(tmp & 0x00FF); 17988c2ecf20Sopenharmony_ci v3 = (s8)((tmp & 0xFF00) >> 8); 17998c2ecf20Sopenharmony_ci if (v0 == 0x7F || v1 == 0x7F || v2 == 0x7F || v3 == 0x7F) 18008c2ecf20Sopenharmony_ci return; 18018c2ecf20Sopenharmony_ci v0 = (v0 + 0x20) & 0x3F; 18028c2ecf20Sopenharmony_ci v1 = (v1 + 0x20) & 0x3F; 18038c2ecf20Sopenharmony_ci v2 = (v2 + 0x20) & 0x3F; 18048c2ecf20Sopenharmony_ci v3 = (v3 + 0x20) & 0x3F; 18058c2ecf20Sopenharmony_ci tmp = 1; 18068c2ecf20Sopenharmony_ci } 18078c2ecf20Sopenharmony_ci b43legacy_radio_clear_tssi(dev); 18088c2ecf20Sopenharmony_ci 18098c2ecf20Sopenharmony_ci average = (v0 + v1 + v2 + v3 + 2) / 4; 18108c2ecf20Sopenharmony_ci 18118c2ecf20Sopenharmony_ci if (tmp && (b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x005E) 18128c2ecf20Sopenharmony_ci & 0x8)) 18138c2ecf20Sopenharmony_ci average -= 13; 18148c2ecf20Sopenharmony_ci 18158c2ecf20Sopenharmony_ci estimated_pwr = b43legacy_phy_estimate_power_out(dev, average); 18168c2ecf20Sopenharmony_ci 18178c2ecf20Sopenharmony_ci max_pwr = dev->dev->bus->sprom.maxpwr_bg; 18188c2ecf20Sopenharmony_ci 18198c2ecf20Sopenharmony_ci if ((dev->dev->bus->sprom.boardflags_lo 18208c2ecf20Sopenharmony_ci & B43legacy_BFL_PACTRL) && 18218c2ecf20Sopenharmony_ci (phy->type == B43legacy_PHYTYPE_G)) 18228c2ecf20Sopenharmony_ci max_pwr -= 0x3; 18238c2ecf20Sopenharmony_ci if (unlikely(max_pwr <= 0)) { 18248c2ecf20Sopenharmony_ci b43legacywarn(dev->wl, "Invalid max-TX-power value in SPROM." 18258c2ecf20Sopenharmony_ci "\n"); 18268c2ecf20Sopenharmony_ci max_pwr = 74; /* fake it */ 18278c2ecf20Sopenharmony_ci dev->dev->bus->sprom.maxpwr_bg = max_pwr; 18288c2ecf20Sopenharmony_ci } 18298c2ecf20Sopenharmony_ci 18308c2ecf20Sopenharmony_ci /* Use regulatory information to get the maximum power. 18318c2ecf20Sopenharmony_ci * In the absence of such data from mac80211, we will use 20 dBm, which 18328c2ecf20Sopenharmony_ci * is the value for the EU, US, Canada, and most of the world. 18338c2ecf20Sopenharmony_ci * The regulatory maximum is reduced by the antenna gain (from sprom) 18348c2ecf20Sopenharmony_ci * and 1.5 dBm (a safety factor??). The result is in Q5.2 format 18358c2ecf20Sopenharmony_ci * which accounts for the factor of 4 */ 18368c2ecf20Sopenharmony_ci#define REG_MAX_PWR 20 18378c2ecf20Sopenharmony_ci max_pwr = min(REG_MAX_PWR * 4 18388c2ecf20Sopenharmony_ci - dev->dev->bus->sprom.antenna_gain.a0 18398c2ecf20Sopenharmony_ci - 0x6, max_pwr); 18408c2ecf20Sopenharmony_ci 18418c2ecf20Sopenharmony_ci /* find the desired power in Q5.2 - power_level is in dBm 18428c2ecf20Sopenharmony_ci * and limit it - max_pwr is already in Q5.2 */ 18438c2ecf20Sopenharmony_ci desired_pwr = clamp_val(phy->power_level << 2, 0, max_pwr); 18448c2ecf20Sopenharmony_ci if (b43legacy_debug(dev, B43legacy_DBG_XMITPOWER)) 18458c2ecf20Sopenharmony_ci b43legacydbg(dev->wl, "Current TX power output: " Q52_FMT 18468c2ecf20Sopenharmony_ci " dBm, Desired TX power output: " Q52_FMT 18478c2ecf20Sopenharmony_ci " dBm\n", Q52_ARG(estimated_pwr), 18488c2ecf20Sopenharmony_ci Q52_ARG(desired_pwr)); 18498c2ecf20Sopenharmony_ci /* Check if we need to adjust the current power. The factor of 2 is 18508c2ecf20Sopenharmony_ci * for damping */ 18518c2ecf20Sopenharmony_ci pwr_adjust = (desired_pwr - estimated_pwr) / 2; 18528c2ecf20Sopenharmony_ci /* RF attenuation delta 18538c2ecf20Sopenharmony_ci * The minus sign is because lower attenuation => more power */ 18548c2ecf20Sopenharmony_ci radio_att_delta = -(pwr_adjust + 7) >> 3; 18558c2ecf20Sopenharmony_ci /* Baseband attenuation delta */ 18568c2ecf20Sopenharmony_ci baseband_att_delta = -(pwr_adjust >> 1) - (4 * radio_att_delta); 18578c2ecf20Sopenharmony_ci /* Do we need to adjust anything? */ 18588c2ecf20Sopenharmony_ci if ((radio_att_delta == 0) && (baseband_att_delta == 0)) { 18598c2ecf20Sopenharmony_ci b43legacy_phy_lo_mark_current_used(dev); 18608c2ecf20Sopenharmony_ci return; 18618c2ecf20Sopenharmony_ci } 18628c2ecf20Sopenharmony_ci 18638c2ecf20Sopenharmony_ci /* Calculate the new attenuation values. */ 18648c2ecf20Sopenharmony_ci baseband_attenuation = phy->bbatt; 18658c2ecf20Sopenharmony_ci baseband_attenuation += baseband_att_delta; 18668c2ecf20Sopenharmony_ci radio_attenuation = phy->rfatt; 18678c2ecf20Sopenharmony_ci radio_attenuation += radio_att_delta; 18688c2ecf20Sopenharmony_ci 18698c2ecf20Sopenharmony_ci /* Get baseband and radio attenuation values into permitted ranges. 18708c2ecf20Sopenharmony_ci * baseband 0-11, radio 0-9. 18718c2ecf20Sopenharmony_ci * Radio attenuation affects power level 4 times as much as baseband. 18728c2ecf20Sopenharmony_ci */ 18738c2ecf20Sopenharmony_ci if (radio_attenuation < 0) { 18748c2ecf20Sopenharmony_ci baseband_attenuation -= (4 * -radio_attenuation); 18758c2ecf20Sopenharmony_ci radio_attenuation = 0; 18768c2ecf20Sopenharmony_ci } else if (radio_attenuation > 9) { 18778c2ecf20Sopenharmony_ci baseband_attenuation += (4 * (radio_attenuation - 9)); 18788c2ecf20Sopenharmony_ci radio_attenuation = 9; 18798c2ecf20Sopenharmony_ci } else { 18808c2ecf20Sopenharmony_ci while (baseband_attenuation < 0 && radio_attenuation > 0) { 18818c2ecf20Sopenharmony_ci baseband_attenuation += 4; 18828c2ecf20Sopenharmony_ci radio_attenuation--; 18838c2ecf20Sopenharmony_ci } 18848c2ecf20Sopenharmony_ci while (baseband_attenuation > 11 && radio_attenuation < 9) { 18858c2ecf20Sopenharmony_ci baseband_attenuation -= 4; 18868c2ecf20Sopenharmony_ci radio_attenuation++; 18878c2ecf20Sopenharmony_ci } 18888c2ecf20Sopenharmony_ci } 18898c2ecf20Sopenharmony_ci baseband_attenuation = clamp_val(baseband_attenuation, 0, 11); 18908c2ecf20Sopenharmony_ci 18918c2ecf20Sopenharmony_ci txpower = phy->txctl1; 18928c2ecf20Sopenharmony_ci if ((phy->radio_ver == 0x2050) && (phy->radio_rev == 2)) { 18938c2ecf20Sopenharmony_ci if (radio_attenuation <= 1) { 18948c2ecf20Sopenharmony_ci if (txpower == 0) { 18958c2ecf20Sopenharmony_ci txpower = 3; 18968c2ecf20Sopenharmony_ci radio_attenuation += 2; 18978c2ecf20Sopenharmony_ci baseband_attenuation += 2; 18988c2ecf20Sopenharmony_ci } else if (dev->dev->bus->sprom.boardflags_lo 18998c2ecf20Sopenharmony_ci & B43legacy_BFL_PACTRL) { 19008c2ecf20Sopenharmony_ci baseband_attenuation += 4 * 19018c2ecf20Sopenharmony_ci (radio_attenuation - 2); 19028c2ecf20Sopenharmony_ci radio_attenuation = 2; 19038c2ecf20Sopenharmony_ci } 19048c2ecf20Sopenharmony_ci } else if (radio_attenuation > 4 && txpower != 0) { 19058c2ecf20Sopenharmony_ci txpower = 0; 19068c2ecf20Sopenharmony_ci if (baseband_attenuation < 3) { 19078c2ecf20Sopenharmony_ci radio_attenuation -= 3; 19088c2ecf20Sopenharmony_ci baseband_attenuation += 2; 19098c2ecf20Sopenharmony_ci } else { 19108c2ecf20Sopenharmony_ci radio_attenuation -= 2; 19118c2ecf20Sopenharmony_ci baseband_attenuation -= 2; 19128c2ecf20Sopenharmony_ci } 19138c2ecf20Sopenharmony_ci } 19148c2ecf20Sopenharmony_ci } 19158c2ecf20Sopenharmony_ci /* Save the control values */ 19168c2ecf20Sopenharmony_ci phy->txctl1 = txpower; 19178c2ecf20Sopenharmony_ci baseband_attenuation = clamp_val(baseband_attenuation, 0, 11); 19188c2ecf20Sopenharmony_ci radio_attenuation = clamp_val(radio_attenuation, 0, 9); 19198c2ecf20Sopenharmony_ci phy->rfatt = radio_attenuation; 19208c2ecf20Sopenharmony_ci phy->bbatt = baseband_attenuation; 19218c2ecf20Sopenharmony_ci 19228c2ecf20Sopenharmony_ci /* Adjust the hardware */ 19238c2ecf20Sopenharmony_ci b43legacy_phy_lock(dev); 19248c2ecf20Sopenharmony_ci b43legacy_radio_lock(dev); 19258c2ecf20Sopenharmony_ci b43legacy_radio_set_txpower_bg(dev, baseband_attenuation, 19268c2ecf20Sopenharmony_ci radio_attenuation, txpower); 19278c2ecf20Sopenharmony_ci b43legacy_phy_lo_mark_current_used(dev); 19288c2ecf20Sopenharmony_ci b43legacy_radio_unlock(dev); 19298c2ecf20Sopenharmony_ci b43legacy_phy_unlock(dev); 19308c2ecf20Sopenharmony_ci} 19318c2ecf20Sopenharmony_ci 19328c2ecf20Sopenharmony_cistatic inline 19338c2ecf20Sopenharmony_cis32 b43legacy_tssi2dbm_ad(s32 num, s32 den) 19348c2ecf20Sopenharmony_ci{ 19358c2ecf20Sopenharmony_ci if (num < 0) 19368c2ecf20Sopenharmony_ci return num/den; 19378c2ecf20Sopenharmony_ci else 19388c2ecf20Sopenharmony_ci return (num+den/2)/den; 19398c2ecf20Sopenharmony_ci} 19408c2ecf20Sopenharmony_ci 19418c2ecf20Sopenharmony_cistatic inline 19428c2ecf20Sopenharmony_cis8 b43legacy_tssi2dbm_entry(s8 entry [], u8 index, s16 pab0, s16 pab1, s16 pab2) 19438c2ecf20Sopenharmony_ci{ 19448c2ecf20Sopenharmony_ci s32 m1; 19458c2ecf20Sopenharmony_ci s32 m2; 19468c2ecf20Sopenharmony_ci s32 f = 256; 19478c2ecf20Sopenharmony_ci s32 q; 19488c2ecf20Sopenharmony_ci s32 delta; 19498c2ecf20Sopenharmony_ci s8 i = 0; 19508c2ecf20Sopenharmony_ci 19518c2ecf20Sopenharmony_ci m1 = b43legacy_tssi2dbm_ad(16 * pab0 + index * pab1, 32); 19528c2ecf20Sopenharmony_ci m2 = max(b43legacy_tssi2dbm_ad(32768 + index * pab2, 256), 1); 19538c2ecf20Sopenharmony_ci do { 19548c2ecf20Sopenharmony_ci if (i > 15) 19558c2ecf20Sopenharmony_ci return -EINVAL; 19568c2ecf20Sopenharmony_ci q = b43legacy_tssi2dbm_ad(f * 4096 - 19578c2ecf20Sopenharmony_ci b43legacy_tssi2dbm_ad(m2 * f, 16) * 19588c2ecf20Sopenharmony_ci f, 2048); 19598c2ecf20Sopenharmony_ci delta = abs(q - f); 19608c2ecf20Sopenharmony_ci f = q; 19618c2ecf20Sopenharmony_ci i++; 19628c2ecf20Sopenharmony_ci } while (delta >= 2); 19638c2ecf20Sopenharmony_ci entry[index] = clamp_val(b43legacy_tssi2dbm_ad(m1 * f, 8192), 19648c2ecf20Sopenharmony_ci -127, 128); 19658c2ecf20Sopenharmony_ci return 0; 19668c2ecf20Sopenharmony_ci} 19678c2ecf20Sopenharmony_ci 19688c2ecf20Sopenharmony_ci/* http://bcm-specs.sipsolutions.net/TSSI_to_DBM_Table */ 19698c2ecf20Sopenharmony_ciint b43legacy_phy_init_tssi2dbm_table(struct b43legacy_wldev *dev) 19708c2ecf20Sopenharmony_ci{ 19718c2ecf20Sopenharmony_ci struct b43legacy_phy *phy = &dev->phy; 19728c2ecf20Sopenharmony_ci s16 pab0; 19738c2ecf20Sopenharmony_ci s16 pab1; 19748c2ecf20Sopenharmony_ci s16 pab2; 19758c2ecf20Sopenharmony_ci u8 idx; 19768c2ecf20Sopenharmony_ci s8 *dyn_tssi2dbm; 19778c2ecf20Sopenharmony_ci 19788c2ecf20Sopenharmony_ci B43legacy_WARN_ON(!(phy->type == B43legacy_PHYTYPE_B || 19798c2ecf20Sopenharmony_ci phy->type == B43legacy_PHYTYPE_G)); 19808c2ecf20Sopenharmony_ci pab0 = (s16)(dev->dev->bus->sprom.pa0b0); 19818c2ecf20Sopenharmony_ci pab1 = (s16)(dev->dev->bus->sprom.pa0b1); 19828c2ecf20Sopenharmony_ci pab2 = (s16)(dev->dev->bus->sprom.pa0b2); 19838c2ecf20Sopenharmony_ci 19848c2ecf20Sopenharmony_ci if ((dev->dev->bus->chip_id == 0x4301) && (phy->radio_ver != 0x2050)) { 19858c2ecf20Sopenharmony_ci phy->idle_tssi = 0x34; 19868c2ecf20Sopenharmony_ci phy->tssi2dbm = b43legacy_tssi2dbm_b_table; 19878c2ecf20Sopenharmony_ci return 0; 19888c2ecf20Sopenharmony_ci } 19898c2ecf20Sopenharmony_ci 19908c2ecf20Sopenharmony_ci if (pab0 != 0 && pab1 != 0 && pab2 != 0 && 19918c2ecf20Sopenharmony_ci pab0 != -1 && pab1 != -1 && pab2 != -1) { 19928c2ecf20Sopenharmony_ci /* The pabX values are set in SPROM. Use them. */ 19938c2ecf20Sopenharmony_ci if ((s8)dev->dev->bus->sprom.itssi_bg != 0 && 19948c2ecf20Sopenharmony_ci (s8)dev->dev->bus->sprom.itssi_bg != -1) 19958c2ecf20Sopenharmony_ci phy->idle_tssi = (s8)(dev->dev->bus->sprom. 19968c2ecf20Sopenharmony_ci itssi_bg); 19978c2ecf20Sopenharmony_ci else 19988c2ecf20Sopenharmony_ci phy->idle_tssi = 62; 19998c2ecf20Sopenharmony_ci dyn_tssi2dbm = kmalloc(64, GFP_KERNEL); 20008c2ecf20Sopenharmony_ci if (dyn_tssi2dbm == NULL) { 20018c2ecf20Sopenharmony_ci b43legacyerr(dev->wl, "Could not allocate memory " 20028c2ecf20Sopenharmony_ci "for tssi2dbm table\n"); 20038c2ecf20Sopenharmony_ci return -ENOMEM; 20048c2ecf20Sopenharmony_ci } 20058c2ecf20Sopenharmony_ci for (idx = 0; idx < 64; idx++) 20068c2ecf20Sopenharmony_ci if (b43legacy_tssi2dbm_entry(dyn_tssi2dbm, idx, pab0, 20078c2ecf20Sopenharmony_ci pab1, pab2)) { 20088c2ecf20Sopenharmony_ci phy->tssi2dbm = NULL; 20098c2ecf20Sopenharmony_ci b43legacyerr(dev->wl, "Could not generate " 20108c2ecf20Sopenharmony_ci "tssi2dBm table\n"); 20118c2ecf20Sopenharmony_ci kfree(dyn_tssi2dbm); 20128c2ecf20Sopenharmony_ci return -ENODEV; 20138c2ecf20Sopenharmony_ci } 20148c2ecf20Sopenharmony_ci phy->tssi2dbm = dyn_tssi2dbm; 20158c2ecf20Sopenharmony_ci phy->dyn_tssi_tbl = 1; 20168c2ecf20Sopenharmony_ci } else { 20178c2ecf20Sopenharmony_ci /* pabX values not set in SPROM. */ 20188c2ecf20Sopenharmony_ci switch (phy->type) { 20198c2ecf20Sopenharmony_ci case B43legacy_PHYTYPE_B: 20208c2ecf20Sopenharmony_ci phy->idle_tssi = 0x34; 20218c2ecf20Sopenharmony_ci phy->tssi2dbm = b43legacy_tssi2dbm_b_table; 20228c2ecf20Sopenharmony_ci break; 20238c2ecf20Sopenharmony_ci case B43legacy_PHYTYPE_G: 20248c2ecf20Sopenharmony_ci phy->idle_tssi = 0x34; 20258c2ecf20Sopenharmony_ci phy->tssi2dbm = b43legacy_tssi2dbm_g_table; 20268c2ecf20Sopenharmony_ci break; 20278c2ecf20Sopenharmony_ci } 20288c2ecf20Sopenharmony_ci } 20298c2ecf20Sopenharmony_ci 20308c2ecf20Sopenharmony_ci return 0; 20318c2ecf20Sopenharmony_ci} 20328c2ecf20Sopenharmony_ci 20338c2ecf20Sopenharmony_ciint b43legacy_phy_init(struct b43legacy_wldev *dev) 20348c2ecf20Sopenharmony_ci{ 20358c2ecf20Sopenharmony_ci struct b43legacy_phy *phy = &dev->phy; 20368c2ecf20Sopenharmony_ci int err = -ENODEV; 20378c2ecf20Sopenharmony_ci 20388c2ecf20Sopenharmony_ci switch (phy->type) { 20398c2ecf20Sopenharmony_ci case B43legacy_PHYTYPE_B: 20408c2ecf20Sopenharmony_ci switch (phy->rev) { 20418c2ecf20Sopenharmony_ci case 2: 20428c2ecf20Sopenharmony_ci b43legacy_phy_initb2(dev); 20438c2ecf20Sopenharmony_ci err = 0; 20448c2ecf20Sopenharmony_ci break; 20458c2ecf20Sopenharmony_ci case 4: 20468c2ecf20Sopenharmony_ci b43legacy_phy_initb4(dev); 20478c2ecf20Sopenharmony_ci err = 0; 20488c2ecf20Sopenharmony_ci break; 20498c2ecf20Sopenharmony_ci case 5: 20508c2ecf20Sopenharmony_ci b43legacy_phy_initb5(dev); 20518c2ecf20Sopenharmony_ci err = 0; 20528c2ecf20Sopenharmony_ci break; 20538c2ecf20Sopenharmony_ci case 6: 20548c2ecf20Sopenharmony_ci b43legacy_phy_initb6(dev); 20558c2ecf20Sopenharmony_ci err = 0; 20568c2ecf20Sopenharmony_ci break; 20578c2ecf20Sopenharmony_ci } 20588c2ecf20Sopenharmony_ci break; 20598c2ecf20Sopenharmony_ci case B43legacy_PHYTYPE_G: 20608c2ecf20Sopenharmony_ci b43legacy_phy_initg(dev); 20618c2ecf20Sopenharmony_ci err = 0; 20628c2ecf20Sopenharmony_ci break; 20638c2ecf20Sopenharmony_ci } 20648c2ecf20Sopenharmony_ci if (err) 20658c2ecf20Sopenharmony_ci b43legacyerr(dev->wl, "Unknown PHYTYPE found\n"); 20668c2ecf20Sopenharmony_ci 20678c2ecf20Sopenharmony_ci return err; 20688c2ecf20Sopenharmony_ci} 20698c2ecf20Sopenharmony_ci 20708c2ecf20Sopenharmony_civoid b43legacy_phy_set_antenna_diversity(struct b43legacy_wldev *dev) 20718c2ecf20Sopenharmony_ci{ 20728c2ecf20Sopenharmony_ci struct b43legacy_phy *phy = &dev->phy; 20738c2ecf20Sopenharmony_ci u16 antennadiv; 20748c2ecf20Sopenharmony_ci u16 offset; 20758c2ecf20Sopenharmony_ci u16 value; 20768c2ecf20Sopenharmony_ci u32 ucodeflags; 20778c2ecf20Sopenharmony_ci 20788c2ecf20Sopenharmony_ci antennadiv = phy->antenna_diversity; 20798c2ecf20Sopenharmony_ci 20808c2ecf20Sopenharmony_ci if (antennadiv == 0xFFFF) 20818c2ecf20Sopenharmony_ci antennadiv = 3; 20828c2ecf20Sopenharmony_ci B43legacy_WARN_ON(antennadiv > 3); 20838c2ecf20Sopenharmony_ci 20848c2ecf20Sopenharmony_ci ucodeflags = b43legacy_shm_read32(dev, B43legacy_SHM_SHARED, 20858c2ecf20Sopenharmony_ci B43legacy_UCODEFLAGS_OFFSET); 20868c2ecf20Sopenharmony_ci b43legacy_shm_write32(dev, B43legacy_SHM_SHARED, 20878c2ecf20Sopenharmony_ci B43legacy_UCODEFLAGS_OFFSET, 20888c2ecf20Sopenharmony_ci ucodeflags & ~B43legacy_UCODEFLAG_AUTODIV); 20898c2ecf20Sopenharmony_ci 20908c2ecf20Sopenharmony_ci switch (phy->type) { 20918c2ecf20Sopenharmony_ci case B43legacy_PHYTYPE_G: 20928c2ecf20Sopenharmony_ci offset = 0x0400; 20938c2ecf20Sopenharmony_ci 20948c2ecf20Sopenharmony_ci if (antennadiv == 2) 20958c2ecf20Sopenharmony_ci value = (3/*automatic*/ << 7); 20968c2ecf20Sopenharmony_ci else 20978c2ecf20Sopenharmony_ci value = (antennadiv << 7); 20988c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, offset + 1, 20998c2ecf20Sopenharmony_ci (b43legacy_phy_read(dev, offset + 1) 21008c2ecf20Sopenharmony_ci & 0x7E7F) | value); 21018c2ecf20Sopenharmony_ci 21028c2ecf20Sopenharmony_ci if (antennadiv >= 2) { 21038c2ecf20Sopenharmony_ci if (antennadiv == 2) 21048c2ecf20Sopenharmony_ci value = (antennadiv << 7); 21058c2ecf20Sopenharmony_ci else 21068c2ecf20Sopenharmony_ci value = (0/*force0*/ << 7); 21078c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, offset + 0x2B, 21088c2ecf20Sopenharmony_ci (b43legacy_phy_read(dev, 21098c2ecf20Sopenharmony_ci offset + 0x2B) 21108c2ecf20Sopenharmony_ci & 0xFEFF) | value); 21118c2ecf20Sopenharmony_ci } 21128c2ecf20Sopenharmony_ci 21138c2ecf20Sopenharmony_ci if (phy->type == B43legacy_PHYTYPE_G) { 21148c2ecf20Sopenharmony_ci if (antennadiv >= 2) 21158c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x048C, 21168c2ecf20Sopenharmony_ci b43legacy_phy_read(dev, 21178c2ecf20Sopenharmony_ci 0x048C) | 0x2000); 21188c2ecf20Sopenharmony_ci else 21198c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x048C, 21208c2ecf20Sopenharmony_ci b43legacy_phy_read(dev, 21218c2ecf20Sopenharmony_ci 0x048C) & ~0x2000); 21228c2ecf20Sopenharmony_ci if (phy->rev >= 2) { 21238c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0461, 21248c2ecf20Sopenharmony_ci b43legacy_phy_read(dev, 21258c2ecf20Sopenharmony_ci 0x0461) | 0x0010); 21268c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x04AD, 21278c2ecf20Sopenharmony_ci (b43legacy_phy_read(dev, 21288c2ecf20Sopenharmony_ci 0x04AD) 21298c2ecf20Sopenharmony_ci & 0x00FF) | 0x0015); 21308c2ecf20Sopenharmony_ci if (phy->rev == 2) 21318c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0427, 21328c2ecf20Sopenharmony_ci 0x0008); 21338c2ecf20Sopenharmony_ci else 21348c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0427, 21358c2ecf20Sopenharmony_ci (b43legacy_phy_read(dev, 0x0427) 21368c2ecf20Sopenharmony_ci & 0x00FF) | 0x0008); 21378c2ecf20Sopenharmony_ci } else if (phy->rev >= 6) 21388c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x049B, 0x00DC); 21398c2ecf20Sopenharmony_ci } else { 21408c2ecf20Sopenharmony_ci if (phy->rev < 3) 21418c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x002B, 21428c2ecf20Sopenharmony_ci (b43legacy_phy_read(dev, 21438c2ecf20Sopenharmony_ci 0x002B) & 0x00FF) 21448c2ecf20Sopenharmony_ci | 0x0024); 21458c2ecf20Sopenharmony_ci else { 21468c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0061, 21478c2ecf20Sopenharmony_ci b43legacy_phy_read(dev, 21488c2ecf20Sopenharmony_ci 0x0061) | 0x0010); 21498c2ecf20Sopenharmony_ci if (phy->rev == 3) { 21508c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0093, 21518c2ecf20Sopenharmony_ci 0x001D); 21528c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0027, 21538c2ecf20Sopenharmony_ci 0x0008); 21548c2ecf20Sopenharmony_ci } else { 21558c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0093, 21568c2ecf20Sopenharmony_ci 0x003A); 21578c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x0027, 21588c2ecf20Sopenharmony_ci (b43legacy_phy_read(dev, 0x0027) 21598c2ecf20Sopenharmony_ci & 0x00FF) | 0x0008); 21608c2ecf20Sopenharmony_ci } 21618c2ecf20Sopenharmony_ci } 21628c2ecf20Sopenharmony_ci } 21638c2ecf20Sopenharmony_ci break; 21648c2ecf20Sopenharmony_ci case B43legacy_PHYTYPE_B: 21658c2ecf20Sopenharmony_ci if (dev->dev->id.revision == 2) 21668c2ecf20Sopenharmony_ci value = (3/*automatic*/ << 7); 21678c2ecf20Sopenharmony_ci else 21688c2ecf20Sopenharmony_ci value = (antennadiv << 7); 21698c2ecf20Sopenharmony_ci b43legacy_phy_write(dev, 0x03E2, 21708c2ecf20Sopenharmony_ci (b43legacy_phy_read(dev, 0x03E2) 21718c2ecf20Sopenharmony_ci & 0xFE7F) | value); 21728c2ecf20Sopenharmony_ci break; 21738c2ecf20Sopenharmony_ci default: 21748c2ecf20Sopenharmony_ci B43legacy_WARN_ON(1); 21758c2ecf20Sopenharmony_ci } 21768c2ecf20Sopenharmony_ci 21778c2ecf20Sopenharmony_ci if (antennadiv >= 2) { 21788c2ecf20Sopenharmony_ci ucodeflags = b43legacy_shm_read32(dev, B43legacy_SHM_SHARED, 21798c2ecf20Sopenharmony_ci B43legacy_UCODEFLAGS_OFFSET); 21808c2ecf20Sopenharmony_ci b43legacy_shm_write32(dev, B43legacy_SHM_SHARED, 21818c2ecf20Sopenharmony_ci B43legacy_UCODEFLAGS_OFFSET, 21828c2ecf20Sopenharmony_ci ucodeflags | B43legacy_UCODEFLAG_AUTODIV); 21838c2ecf20Sopenharmony_ci } 21848c2ecf20Sopenharmony_ci 21858c2ecf20Sopenharmony_ci phy->antenna_diversity = antennadiv; 21868c2ecf20Sopenharmony_ci} 21878c2ecf20Sopenharmony_ci 21888c2ecf20Sopenharmony_ci/* Set the PowerSavingControlBits. 21898c2ecf20Sopenharmony_ci * Bitvalues: 21908c2ecf20Sopenharmony_ci * 0 => unset the bit 21918c2ecf20Sopenharmony_ci * 1 => set the bit 21928c2ecf20Sopenharmony_ci * -1 => calculate the bit 21938c2ecf20Sopenharmony_ci */ 21948c2ecf20Sopenharmony_civoid b43legacy_power_saving_ctl_bits(struct b43legacy_wldev *dev, 21958c2ecf20Sopenharmony_ci int bit25, int bit26) 21968c2ecf20Sopenharmony_ci{ 21978c2ecf20Sopenharmony_ci int i; 21988c2ecf20Sopenharmony_ci u32 status; 21998c2ecf20Sopenharmony_ci 22008c2ecf20Sopenharmony_ci/* FIXME: Force 25 to off and 26 to on for now: */ 22018c2ecf20Sopenharmony_cibit25 = 0; 22028c2ecf20Sopenharmony_cibit26 = 1; 22038c2ecf20Sopenharmony_ci 22048c2ecf20Sopenharmony_ci if (bit25 == -1) { 22058c2ecf20Sopenharmony_ci /* TODO: If powersave is not off and FIXME is not set and we 22068c2ecf20Sopenharmony_ci * are not in adhoc and thus is not an AP and we arei 22078c2ecf20Sopenharmony_ci * associated, set bit 25 */ 22088c2ecf20Sopenharmony_ci } 22098c2ecf20Sopenharmony_ci if (bit26 == -1) { 22108c2ecf20Sopenharmony_ci /* TODO: If the device is awake or this is an AP, or we are 22118c2ecf20Sopenharmony_ci * scanning, or FIXME, or we are associated, or FIXME, 22128c2ecf20Sopenharmony_ci * or the latest PS-Poll packet sent was successful, 22138c2ecf20Sopenharmony_ci * set bit26 */ 22148c2ecf20Sopenharmony_ci } 22158c2ecf20Sopenharmony_ci status = b43legacy_read32(dev, B43legacy_MMIO_MACCTL); 22168c2ecf20Sopenharmony_ci if (bit25) 22178c2ecf20Sopenharmony_ci status |= B43legacy_MACCTL_HWPS; 22188c2ecf20Sopenharmony_ci else 22198c2ecf20Sopenharmony_ci status &= ~B43legacy_MACCTL_HWPS; 22208c2ecf20Sopenharmony_ci if (bit26) 22218c2ecf20Sopenharmony_ci status |= B43legacy_MACCTL_AWAKE; 22228c2ecf20Sopenharmony_ci else 22238c2ecf20Sopenharmony_ci status &= ~B43legacy_MACCTL_AWAKE; 22248c2ecf20Sopenharmony_ci b43legacy_write32(dev, B43legacy_MMIO_MACCTL, status); 22258c2ecf20Sopenharmony_ci if (bit26 && dev->dev->id.revision >= 5) { 22268c2ecf20Sopenharmony_ci for (i = 0; i < 100; i++) { 22278c2ecf20Sopenharmony_ci if (b43legacy_shm_read32(dev, B43legacy_SHM_SHARED, 22288c2ecf20Sopenharmony_ci 0x0040) != 4) 22298c2ecf20Sopenharmony_ci break; 22308c2ecf20Sopenharmony_ci udelay(10); 22318c2ecf20Sopenharmony_ci } 22328c2ecf20Sopenharmony_ci } 22338c2ecf20Sopenharmony_ci} 2234