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 31 #include <sys/cdefs.h> 32 __FBSDID("$FreeBSD$"); 33 34 #include "opt_bwn.h" 35 #include "opt_wlan.h" 36 37 /* 38 * The Broadcom Wireless LAN controller driver. 39 */ 40 41 #include <sys/param.h> 42 #include <sys/systm.h> 43 #include <sys/kernel.h> 44 #include <sys/malloc.h> 45 #include <sys/module.h> 46 #include <sys/endian.h> 47 #include <sys/errno.h> 48 #include <sys/firmware.h> 49 #include <sys/lock.h> 50 #include <sys/mutex.h> 51 #include <machine/bus.h> 52 #include <machine/resource.h> 53 #include <sys/bus.h> 54 #include <sys/rman.h> 55 #include <sys/socket.h> 56 #include <sys/sockio.h> 57 58 #include <net/ethernet.h> 59 #include <net/if.h> 60 #include <net/if_var.h> 61 #include <net/if_arp.h> 62 #include <net/if_dl.h> 63 #include <net/if_llc.h> 64 #include <net/if_media.h> 65 #include <net/if_types.h> 66 67 #include <dev/pci/pcivar.h> 68 #include <dev/pci/pcireg.h> 69 70 #include <net80211/ieee80211_var.h> 71 #include <net80211/ieee80211_radiotap.h> 72 #include <net80211/ieee80211_regdomain.h> 73 #include <net80211/ieee80211_phy.h> 74 #include <net80211/ieee80211_ratectl.h> 75 76 #include <dev/bhnd/bhnd.h> 77 #include <dev/bhnd/bhnd_ids.h> 78 79 #include <dev/bhnd/cores/chipc/chipc.h> 80 #include <dev/bhnd/cores/pmu/bhnd_pmu.h> 81 82 #include <dev/bwn/if_bwnreg.h> 83 #include <dev/bwn/if_bwnvar.h> 84 85 #include <dev/bwn/if_bwn_debug.h> 86 #include <dev/bwn/if_bwn_misc.h> 87 #include <dev/bwn/if_bwn_phy_common.h> 88 89 void 90 bwn_mac_switch_freq(struct bwn_mac *mac, bhnd_pmu_spuravoid spurmode) 91 { 92 struct bwn_softc *sc = mac->mac_sc; 93 uint16_t chip_id = sc->sc_cid.chip_id; 94 95 if (chip_id == BHND_CHIPID_BCM4331) { 96 switch (spurmode) { 97 case BHND_PMU_SPURAVOID_M2: /* 168 Mhz: 2^26/168 = 0x61862 */ 98 BWN_WRITE_2(mac, BWN_TSF_CLK_FRAC_LOW, 0x1862); 99 BWN_WRITE_2(mac, BWN_TSF_CLK_FRAC_HIGH, 0x6); 100 break; 101 case BHND_PMU_SPURAVOID_M1: /* 164 Mhz: 2^26/164 = 0x63e70 */ 102 BWN_WRITE_2(mac, BWN_TSF_CLK_FRAC_LOW, 0x3e70); 103 BWN_WRITE_2(mac, BWN_TSF_CLK_FRAC_HIGH, 0x6); 104 break; 105 case BHND_PMU_SPURAVOID_NONE: /* 160 Mhz: 2^26/160 = 0x66666 */ 106 BWN_WRITE_2(mac, BWN_TSF_CLK_FRAC_LOW, 0x6666); 107 BWN_WRITE_2(mac, BWN_TSF_CLK_FRAC_HIGH, 0x6); 108 break; 109 } 110 } else if (chip_id == BHND_CHIPID_BCM43131 || 111 chip_id == BHND_CHIPID_BCM43217 || 112 chip_id == BHND_CHIPID_BCM43222 || 113 chip_id == BHND_CHIPID_BCM43224 || 114 chip_id == BHND_CHIPID_BCM43225 || 115 chip_id == BHND_CHIPID_BCM43227 || 116 chip_id == BHND_CHIPID_BCM43228) { 117 switch (spurmode) { 118 case BHND_PMU_SPURAVOID_M2: /* 126 Mhz */ 119 BWN_WRITE_2(mac, BWN_TSF_CLK_FRAC_LOW, 0x2082); 120 BWN_WRITE_2(mac, BWN_TSF_CLK_FRAC_HIGH, 0x8); 121 break; 122 case BHND_PMU_SPURAVOID_M1: /* 123 Mhz */ 123 BWN_WRITE_2(mac, BWN_TSF_CLK_FRAC_LOW, 0x5341); 124 BWN_WRITE_2(mac, BWN_TSF_CLK_FRAC_HIGH, 0x8); 125 break; 126 case BHND_PMU_SPURAVOID_NONE: /* 120 Mhz */ 127 BWN_WRITE_2(mac, BWN_TSF_CLK_FRAC_LOW, 0x8889); 128 BWN_WRITE_2(mac, BWN_TSF_CLK_FRAC_HIGH, 0x8); 129 break; 130 } 131 } else if (mac->mac_phy.type == BWN_PHYTYPE_LCN) { 132 switch (spurmode) { 133 case BHND_PMU_SPURAVOID_M2: 134 device_printf(sc->sc_dev, "invalid spuravoid mode: " 135 "%d\n", spurmode); 136 break; 137 case BHND_PMU_SPURAVOID_M1: /* 82 Mhz */ 138 BWN_WRITE_2(mac, BWN_TSF_CLK_FRAC_LOW, 0x7CE0); 139 BWN_WRITE_2(mac, BWN_TSF_CLK_FRAC_HIGH, 0xC); 140 break; 141 case BHND_PMU_SPURAVOID_NONE: /* 80 Mhz */ 142 BWN_WRITE_2(mac, BWN_TSF_CLK_FRAC_LOW, 0xCCCD); 143 BWN_WRITE_2(mac, BWN_TSF_CLK_FRAC_HIGH, 0xC); 144 break; 145 } 146 } 147 } 148 149 /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/BmacPhyClkFgc */ 150 int 151 bwn_phy_force_clock(struct bwn_mac *mac, int force) 152 { 153 struct bwn_softc *sc; 154 uint32_t val, mask; 155 int error; 156 157 sc = mac->mac_sc; 158 159 /* XXX Only for N, HT and AC PHYs */ 160 mask = BHND_IOCTL_CLK_FORCE; 161 if (force) { 162 val = BHND_IOCTL_CLK_FORCE; 163 } else { 164 val = 0; 165 } 166 167 if ((error = bhnd_write_ioctl(sc->sc_dev, val, mask))) { 168 device_printf(sc->sc_dev, "failed to set CLK_FORCE ioctl flag: " 169 "%d\n", error); 170 return (error); 171 } 172 173 return (0); 174 } 175 176 int 177 bwn_radio_wait_value(struct bwn_mac *mac, uint16_t offset, uint16_t mask, 178 uint16_t value, int delay, int timeout) 179 { 180 uint16_t val; 181 int i; 182 183 for (i = 0; i < timeout; i += delay) { 184 val = BWN_RF_READ(mac, offset); 185 if ((val & mask) == value) 186 return (1); 187 DELAY(delay); 188 } 189 return (0); 190 } 191 192 int 193 bwn_mac_phy_clock_set(struct bwn_mac *mac, int enabled) 194 { 195 struct bwn_softc *sc; 196 uint32_t val, mask; 197 int error; 198 199 sc = mac->mac_sc; 200 201 mask = BWN_IOCTL_MACPHYCLKEN; 202 if (enabled) { 203 val = BWN_IOCTL_MACPHYCLKEN; 204 } else { 205 val = 0; 206 } 207 208 if ((error = bhnd_write_ioctl(sc->sc_dev, val, mask))) { 209 device_printf(sc->sc_dev, "failed to set MACPHYCLKEN ioctl " 210 "flag: %d\n", error); 211 return (error); 212 } 213 214 return (0); 215 } 216 217 /* http://bcm-v4.sipsolutions.net/802.11/PHY/BmacCorePllReset */ 218 int 219 bwn_wireless_core_phy_pll_reset(struct bwn_mac *mac) 220 { 221 struct bwn_softc *sc; 222 uint32_t pll_flag; 223 224 sc = mac->mac_sc; 225 226 if (sc->sc_pmu == NULL) { 227 device_printf(sc->sc_dev, "PMU device not found\n"); 228 return (ENXIO); 229 } 230 231 pll_flag = 0x4; 232 bhnd_pmu_write_chipctrl(sc->sc_pmu, 0x0, 0x0, pll_flag); 233 bhnd_pmu_write_chipctrl(sc->sc_pmu, 0x0, pll_flag, pll_flag); 234 bhnd_pmu_write_chipctrl(sc->sc_pmu, 0x0, 0x0, pll_flag); 235 236 return (0); 237 } 238