1 /*- 2 * Copyright (c) 2009-2010 Weongyo Jeong <weongyo@freebsd.org> 3 * Copyright (c) 2016 Adrian Chadd <adrian@freebsd.org> 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer, 11 * without modification. 12 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 13 * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any 14 * redistribution must be conditioned upon including a substantially 15 * similar Disclaimer requirement for further binary redistribution. 16 * 17 * NO WARRANTY 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY 21 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 22 * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, 23 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 26 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 28 * THE POSSIBILITY OF SUCH DAMAGES. 29 * 30 * $FreeBSD: head/sys/dev/bwn/if_bwn_phy_common.c 299758 2016-05-14 20:11:48Z adrian $ 31 */ 32 33 /* 34 * The Broadcom Wireless LAN controller driver. 35 */ 36 37 #include <sys/param.h> 38 #include <sys/systm.h> 39 #include <sys/kernel.h> 40 #include <sys/malloc.h> 41 #include <sys/module.h> 42 #include <sys/endian.h> 43 #include <sys/errno.h> 44 #include <sys/firmware.h> 45 #include <sys/lock.h> 46 #include <sys/mutex.h> 47 #if !defined(__DragonFly__) 48 #include <machine/bus.h> 49 #include <machine/resource.h> 50 #endif 51 #include <sys/bus.h> 52 #include <sys/rman.h> 53 #include <sys/socket.h> 54 #include <sys/sockio.h> 55 56 #include <net/ethernet.h> 57 #include <net/if.h> 58 #include <net/if_var.h> 59 #include <net/if_arp.h> 60 #include <net/if_dl.h> 61 #include <net/if_llc.h> 62 #include <net/if_media.h> 63 #include <net/if_types.h> 64 65 #if defined(__DragonFly__) 66 #include <bus/pci/pcivar.h> 67 #include <bus/pci/pcireg.h> 68 #include <dev/netif/bwn/siba/siba_ids.h> 69 #include <dev/netif/bwn/siba/sibareg.h> 70 #include <dev/netif/bwn/siba/sibavar.h> 71 #else 72 #include <dev/pci/pcivar.h> 73 #include <dev/pci/pcireg.h> 74 #include <dev/siba/siba_ids.h> 75 #include <dev/siba/sibareg.h> 76 #include <dev/siba/sibavar.h> 77 #endif 78 79 #if defined(__DragonFly__) 80 #include <netproto/802_11/ieee80211_var.h> 81 #include <netproto/802_11/ieee80211_radiotap.h> 82 #include <netproto/802_11/ieee80211_regdomain.h> 83 #include <netproto/802_11/ieee80211_phy.h> 84 #include <netproto/802_11/ieee80211_ratectl.h> 85 #else 86 #include <net80211/ieee80211_var.h> 87 #include <net80211/ieee80211_radiotap.h> 88 #include <net80211/ieee80211_regdomain.h> 89 #include <net80211/ieee80211_phy.h> 90 #include <net80211/ieee80211_ratectl.h> 91 #endif 92 93 #if defined(__DragonFly__) 94 #include "if_bwnreg.h" 95 #include "if_bwnvar.h" 96 #else 97 #include <dev/bwn/if_bwnreg.h> 98 #include <dev/bwn/if_bwnvar.h> 99 #endif 100 101 #if defined(__DragonFly__) 102 #include "if_bwn_chipid.h" 103 #include "if_bwn_debug.h" 104 #include "if_bwn_misc.h" 105 #include "if_bwn_phy_common.h" 106 #else 107 #include <dev/bwn/if_bwn_chipid.h> 108 #include <dev/bwn/if_bwn_debug.h> 109 #include <dev/bwn/if_bwn_misc.h> 110 #include <dev/bwn/if_bwn_phy_common.h> 111 #endif 112 113 void 114 bwn_mac_switch_freq(struct bwn_mac *mac, int spurmode) 115 { 116 struct bwn_softc *sc = mac->mac_sc; 117 uint16_t chip_id = siba_get_chipid(sc->sc_dev); 118 119 if (chip_id == BCMA_CHIP_ID_BCM4331) { 120 switch (spurmode) { 121 case 2: /* 168 Mhz: 2^26/168 = 0x61862 */ 122 BWN_WRITE_2(mac, BWN_TSF_CLK_FRAC_LOW, 0x1862); 123 BWN_WRITE_2(mac, BWN_TSF_CLK_FRAC_HIGH, 0x6); 124 break; 125 case 1: /* 164 Mhz: 2^26/164 = 0x63e70 */ 126 BWN_WRITE_2(mac, BWN_TSF_CLK_FRAC_LOW, 0x3e70); 127 BWN_WRITE_2(mac, BWN_TSF_CLK_FRAC_HIGH, 0x6); 128 break; 129 default: /* 160 Mhz: 2^26/160 = 0x66666 */ 130 BWN_WRITE_2(mac, BWN_TSF_CLK_FRAC_LOW, 0x6666); 131 BWN_WRITE_2(mac, BWN_TSF_CLK_FRAC_HIGH, 0x6); 132 break; 133 } 134 } else if (chip_id == BCMA_CHIP_ID_BCM43131 || 135 chip_id == BCMA_CHIP_ID_BCM43217 || 136 chip_id == BCMA_CHIP_ID_BCM43222 || 137 chip_id == BCMA_CHIP_ID_BCM43224 || 138 chip_id == BCMA_CHIP_ID_BCM43225 || 139 chip_id == BCMA_CHIP_ID_BCM43227 || 140 chip_id == BCMA_CHIP_ID_BCM43228) { 141 switch (spurmode) { 142 case 2: /* 126 Mhz */ 143 BWN_WRITE_2(mac, BWN_TSF_CLK_FRAC_LOW, 0x2082); 144 BWN_WRITE_2(mac, BWN_TSF_CLK_FRAC_HIGH, 0x8); 145 break; 146 case 1: /* 123 Mhz */ 147 BWN_WRITE_2(mac, BWN_TSF_CLK_FRAC_LOW, 0x5341); 148 BWN_WRITE_2(mac, BWN_TSF_CLK_FRAC_HIGH, 0x8); 149 break; 150 default: /* 120 Mhz */ 151 BWN_WRITE_2(mac, BWN_TSF_CLK_FRAC_LOW, 0x8889); 152 BWN_WRITE_2(mac, BWN_TSF_CLK_FRAC_HIGH, 0x8); 153 break; 154 } 155 } else if (mac->mac_phy.type == BWN_PHYTYPE_LCN) { 156 switch (spurmode) { 157 case 1: /* 82 Mhz */ 158 BWN_WRITE_2(mac, BWN_TSF_CLK_FRAC_LOW, 0x7CE0); 159 BWN_WRITE_2(mac, BWN_TSF_CLK_FRAC_HIGH, 0xC); 160 break; 161 default: /* 80 Mhz */ 162 BWN_WRITE_2(mac, BWN_TSF_CLK_FRAC_LOW, 0xCCCD); 163 BWN_WRITE_2(mac, BWN_TSF_CLK_FRAC_HIGH, 0xC); 164 break; 165 } 166 } 167 } 168 169 /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/BmacPhyClkFgc */ 170 void 171 bwn_phy_force_clock(struct bwn_mac *mac, int force) 172 { 173 struct bwn_softc *sc = mac->mac_sc; 174 uint32_t tmp; 175 176 /* XXX Only for N, HT and AC PHYs */ 177 178 /* XXX bhnd bus */ 179 if (bwn_is_bus_siba(mac)) { 180 tmp = siba_read_4(sc->sc_dev, SIBA_TGSLOW); 181 if (force) 182 tmp |= SIBA_TGSLOW_FGC; 183 else 184 tmp &= ~SIBA_TGSLOW_FGC; 185 siba_write_4(sc->sc_dev, SIBA_TGSLOW, tmp); 186 } 187 } 188 189 int 190 bwn_radio_wait_value(struct bwn_mac *mac, uint16_t offset, uint16_t mask, 191 uint16_t value, int delay, int timeout) 192 { 193 uint16_t val; 194 int i; 195 196 for (i = 0; i < timeout; i += delay) { 197 val = BWN_RF_READ(mac, offset); 198 if ((val & mask) == value) 199 return (1); 200 DELAY(delay); 201 } 202 return (0); 203 } 204 205 void 206 bwn_mac_phy_clock_set(struct bwn_mac *mac, int enabled) 207 { 208 struct bwn_softc *sc = mac->mac_sc; 209 uint32_t val; 210 211 /* XXX bhnd bus */ 212 if (bwn_is_bus_siba(mac)) { 213 val = siba_read_4(sc->sc_dev, SIBA_TGSLOW); 214 if (enabled) 215 val |= BWN_TMSLOW_MACPHYCLKEN; 216 else 217 val &= ~BWN_TMSLOW_MACPHYCLKEN; 218 siba_write_4(sc->sc_dev, SIBA_TGSLOW, val); 219 } 220 } 221 222 /* http://bcm-v4.sipsolutions.net/802.11/PHY/BmacCorePllReset */ 223 void 224 bwn_wireless_core_phy_pll_reset(struct bwn_mac *mac) 225 { 226 struct bwn_softc *sc = mac->mac_sc; 227 228 /* XXX bhnd bus */ 229 if (bwn_is_bus_siba(mac)) { 230 siba_cc_write32(sc->sc_dev, SIBA_CC_CHIPCTL_ADDR, 0); 231 siba_cc_mask32(sc->sc_dev, SIBA_CC_CHIPCTL_DATA, ~0x4); 232 siba_cc_set32(sc->sc_dev, SIBA_CC_CHIPCTL_DATA, 0x4); 233 siba_cc_mask32(sc->sc_dev, SIBA_CC_CHIPCTL_DATA, ~0x4); 234 } 235 } 236