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