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: releng/11.0/sys/dev/bwn/if_bwn_phy_common.c 300549 2016-05-24 01:20:30Z adrian $"); 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#include <dev/siba/siba_ids.h> 70#include <dev/siba/sibareg.h> 71#include <dev/siba/sibavar.h> 72 73#include <net80211/ieee80211_var.h> 74#include <net80211/ieee80211_radiotap.h> 75#include <net80211/ieee80211_regdomain.h> 76#include <net80211/ieee80211_phy.h> 77#include <net80211/ieee80211_ratectl.h> 78 79#include <dev/bwn/if_bwnreg.h> 80#include <dev/bwn/if_bwnvar.h> 81 82#include <dev/bwn/if_bwn_chipid.h> 83#include <dev/bwn/if_bwn_debug.h> 84#include <dev/bwn/if_bwn_misc.h> 85#include <dev/bwn/if_bwn_phy_common.h> 86 87void 88bwn_mac_switch_freq(struct bwn_mac *mac, int spurmode) 89{ 90 struct bwn_softc *sc = mac->mac_sc; 91 uint16_t chip_id = siba_get_chipid(sc->sc_dev); 92 93 if (chip_id == BCMA_CHIP_ID_BCM4331) { 94 switch (spurmode) { 95 case 2: /* 168 Mhz: 2^26/168 = 0x61862 */ 96 BWN_WRITE_2(mac, BWN_TSF_CLK_FRAC_LOW, 0x1862); 97 BWN_WRITE_2(mac, BWN_TSF_CLK_FRAC_HIGH, 0x6); 98 break; 99 case 1: /* 164 Mhz: 2^26/164 = 0x63e70 */ 100 BWN_WRITE_2(mac, BWN_TSF_CLK_FRAC_LOW, 0x3e70); 101 BWN_WRITE_2(mac, BWN_TSF_CLK_FRAC_HIGH, 0x6); 102 break; 103 default: /* 160 Mhz: 2^26/160 = 0x66666 */ 104 BWN_WRITE_2(mac, BWN_TSF_CLK_FRAC_LOW, 0x6666); 105 BWN_WRITE_2(mac, BWN_TSF_CLK_FRAC_HIGH, 0x6); 106 break; 107 } 108 } else if (chip_id == BCMA_CHIP_ID_BCM43131 || 109 chip_id == BCMA_CHIP_ID_BCM43217 || 110 chip_id == BCMA_CHIP_ID_BCM43222 || 111 chip_id == BCMA_CHIP_ID_BCM43224 || 112 chip_id == BCMA_CHIP_ID_BCM43225 || 113 chip_id == BCMA_CHIP_ID_BCM43227 || 114 chip_id == BCMA_CHIP_ID_BCM43228) { 115 switch (spurmode) { 116 case 2: /* 126 Mhz */ 117 BWN_WRITE_2(mac, BWN_TSF_CLK_FRAC_LOW, 0x2082); 118 BWN_WRITE_2(mac, BWN_TSF_CLK_FRAC_HIGH, 0x8); 119 break; 120 case 1: /* 123 Mhz */ 121 BWN_WRITE_2(mac, BWN_TSF_CLK_FRAC_LOW, 0x5341); 122 BWN_WRITE_2(mac, BWN_TSF_CLK_FRAC_HIGH, 0x8); 123 break; 124 default: /* 120 Mhz */ 125 BWN_WRITE_2(mac, BWN_TSF_CLK_FRAC_LOW, 0x8889); 126 BWN_WRITE_2(mac, BWN_TSF_CLK_FRAC_HIGH, 0x8); 127 break; 128 } 129 } else if (mac->mac_phy.type == BWN_PHYTYPE_LCN) { 130 switch (spurmode) { 131 case 1: /* 82 Mhz */ 132 BWN_WRITE_2(mac, BWN_TSF_CLK_FRAC_LOW, 0x7CE0); 133 BWN_WRITE_2(mac, BWN_TSF_CLK_FRAC_HIGH, 0xC); 134 break; 135 default: /* 80 Mhz */ 136 BWN_WRITE_2(mac, BWN_TSF_CLK_FRAC_LOW, 0xCCCD); 137 BWN_WRITE_2(mac, BWN_TSF_CLK_FRAC_HIGH, 0xC); 138 break; 139 } 140 } 141} 142 143/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/BmacPhyClkFgc */ 144void 145bwn_phy_force_clock(struct bwn_mac *mac, int force) 146{ 147 struct bwn_softc *sc = mac->mac_sc; 148 uint32_t tmp; 149 150 /* XXX Only for N, HT and AC PHYs */ 151 152 /* XXX bhnd bus */ 153 if (bwn_is_bus_siba(mac)) { 154 tmp = siba_read_4(sc->sc_dev, SIBA_TGSLOW); 155 if (force) 156 tmp |= SIBA_TGSLOW_FGC; 157 else 158 tmp &= ~SIBA_TGSLOW_FGC; 159 siba_write_4(sc->sc_dev, SIBA_TGSLOW, tmp); 160 } else { 161 BWN_ERRPRINTF(sc, "%s: unknown bus!\n", __func__); 162 } 163} 164 165int 166bwn_radio_wait_value(struct bwn_mac *mac, uint16_t offset, uint16_t mask, 167 uint16_t value, int delay, int timeout) 168{ 169 uint16_t val; 170 int i; 171 172 for (i = 0; i < timeout; i += delay) { 173 val = BWN_RF_READ(mac, offset); 174 if ((val & mask) == value) 175 return (1); 176 DELAY(delay); 177 } 178 return (0); 179} 180 181void 182bwn_mac_phy_clock_set(struct bwn_mac *mac, int enabled) 183{ 184 struct bwn_softc *sc = mac->mac_sc; 185 uint32_t val; 186 187 /* XXX bhnd bus */ 188 if (bwn_is_bus_siba(mac)) { 189 val = siba_read_4(sc->sc_dev, SIBA_TGSLOW); 190 if (enabled) 191 val |= BWN_TGSLOW_MACPHYCLKEN; 192 else 193 val &= ~BWN_TGSLOW_MACPHYCLKEN; 194 siba_write_4(sc->sc_dev, SIBA_TGSLOW, val); 195 } else { 196 BWN_ERRPRINTF(sc, "%s: unknown bus!\n", __func__); 197 } 198} 199 200/* http://bcm-v4.sipsolutions.net/802.11/PHY/BmacCorePllReset */ 201void 202bwn_wireless_core_phy_pll_reset(struct bwn_mac *mac) 203{ 204 struct bwn_softc *sc = mac->mac_sc; 205 206 /* XXX bhnd bus */ 207 if (bwn_is_bus_siba(mac)) { 208 siba_cc_write32(sc->sc_dev, SIBA_CC_CHIPCTL_ADDR, 0); 209 siba_cc_mask32(sc->sc_dev, SIBA_CC_CHIPCTL_DATA, ~0x4); 210 siba_cc_set32(sc->sc_dev, SIBA_CC_CHIPCTL_DATA, 0x4); 211 siba_cc_mask32(sc->sc_dev, SIBA_CC_CHIPCTL_DATA, ~0x4); 212 } else { 213 BWN_ERRPRINTF(sc, "%s: unknown bus!\n", __func__); 214 } 215} 216