112e36acbSWarner Losh /* 212e36acbSWarner Losh * Copyright (c) 2007 The DragonFly Project. All rights reserved. 312e36acbSWarner Losh * 412e36acbSWarner Losh * This code is derived from software contributed to The DragonFly Project 512e36acbSWarner Losh * by Sepherosa Ziehau <sepherosa@gmail.com> 612e36acbSWarner Losh * 712e36acbSWarner Losh * Redistribution and use in source and binary forms, with or without 812e36acbSWarner Losh * modification, are permitted provided that the following conditions 912e36acbSWarner Losh * are met: 1012e36acbSWarner Losh * 1112e36acbSWarner Losh * 1. Redistributions of source code must retain the above copyright 1212e36acbSWarner Losh * notice, this list of conditions and the following disclaimer. 1312e36acbSWarner Losh * 2. Redistributions in binary form must reproduce the above copyright 1412e36acbSWarner Losh * notice, this list of conditions and the following disclaimer in 1512e36acbSWarner Losh * the documentation and/or other materials provided with the 1612e36acbSWarner Losh * distribution. 1712e36acbSWarner Losh * 3. Neither the name of The DragonFly Project nor the names of its 1812e36acbSWarner Losh * contributors may be used to endorse or promote products derived 1912e36acbSWarner Losh * from this software without specific, prior written permission. 2012e36acbSWarner Losh * 2112e36acbSWarner Losh * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 2212e36acbSWarner Losh * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 2312e36acbSWarner Losh * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 2412e36acbSWarner Losh * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 2512e36acbSWarner Losh * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 2612e36acbSWarner Losh * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 2712e36acbSWarner Losh * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 2812e36acbSWarner Losh * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 2912e36acbSWarner Losh * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 3012e36acbSWarner Losh * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 3112e36acbSWarner Losh * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3212e36acbSWarner Losh * SUCH DAMAGE. 3312e36acbSWarner Losh * 3412e36acbSWarner Losh * $DragonFly: src/sys/dev/netif/bwi/bwimac.c,v 1.13 2008/02/15 11:15:38 sephe Exp $ 3512e36acbSWarner Losh */ 3612e36acbSWarner Losh 3712e36acbSWarner Losh #include <sys/cdefs.h> 3812e36acbSWarner Losh __FBSDID("$FreeBSD$"); 3912e36acbSWarner Losh 4012e36acbSWarner Losh #include "opt_inet.h" 4112e36acbSWarner Losh #include "opt_bwi.h" 4260807f5bSAdrian Chadd #include "opt_wlan.h" 4312e36acbSWarner Losh 4412e36acbSWarner Losh #include <sys/param.h> 4512e36acbSWarner Losh #include <sys/endian.h> 4612e36acbSWarner Losh #include <sys/kernel.h> 4712e36acbSWarner Losh #include <sys/bus.h> 4812e36acbSWarner Losh #include <sys/malloc.h> 4912e36acbSWarner Losh #include <sys/proc.h> 5012e36acbSWarner Losh #include <sys/rman.h> 5112e36acbSWarner Losh #include <sys/socket.h> 5212e36acbSWarner Losh #include <sys/sockio.h> 5312e36acbSWarner Losh #include <sys/sysctl.h> 5412e36acbSWarner Losh #include <sys/systm.h> 5512e36acbSWarner Losh 5612e36acbSWarner Losh #include <sys/linker.h> 5712e36acbSWarner Losh #include <sys/firmware.h> 5812e36acbSWarner Losh 5912e36acbSWarner Losh #include <net/if.h> 6076039bc8SGleb Smirnoff #include <net/if_var.h> 6112e36acbSWarner Losh #include <net/if_dl.h> 6212e36acbSWarner Losh #include <net/if_media.h> 6312e36acbSWarner Losh #include <net/if_types.h> 6412e36acbSWarner Losh #include <net/if_arp.h> 6512e36acbSWarner Losh #include <net/ethernet.h> 6612e36acbSWarner Losh #include <net/if_llc.h> 6712e36acbSWarner Losh 6812e36acbSWarner Losh #include <net80211/ieee80211_var.h> 6912e36acbSWarner Losh #include <net80211/ieee80211_radiotap.h> 7012e36acbSWarner Losh #include <net80211/ieee80211_amrr.h> 7112e36acbSWarner Losh #include <net80211/ieee80211_phy.h> 7212e36acbSWarner Losh 7312e36acbSWarner Losh #include <machine/bus.h> 7412e36acbSWarner Losh 7512e36acbSWarner Losh #include <dev/bwi/bitops.h> 7612e36acbSWarner Losh #include <dev/bwi/if_bwireg.h> 7712e36acbSWarner Losh #include <dev/bwi/if_bwivar.h> 7812e36acbSWarner Losh #include <dev/bwi/bwimac.h> 7912e36acbSWarner Losh #include <dev/bwi/bwirf.h> 8012e36acbSWarner Losh #include <dev/bwi/bwiphy.h> 8112e36acbSWarner Losh 8212e36acbSWarner Losh struct bwi_retry_lim { 8312e36acbSWarner Losh uint16_t shretry; 8412e36acbSWarner Losh uint16_t shretry_fb; 8512e36acbSWarner Losh uint16_t lgretry; 8612e36acbSWarner Losh uint16_t lgretry_fb; 8712e36acbSWarner Losh }; 8812e36acbSWarner Losh 8912e36acbSWarner Losh static int bwi_mac_test(struct bwi_mac *); 9012e36acbSWarner Losh static int bwi_mac_get_property(struct bwi_mac *); 9112e36acbSWarner Losh 9212e36acbSWarner Losh static void bwi_mac_set_retry_lim(struct bwi_mac *, 9312e36acbSWarner Losh const struct bwi_retry_lim *); 9412e36acbSWarner Losh static void bwi_mac_set_ackrates(struct bwi_mac *, 9512e36acbSWarner Losh const struct ieee80211_rate_table *rt, 9612e36acbSWarner Losh const struct ieee80211_rateset *); 9712e36acbSWarner Losh 9812e36acbSWarner Losh static int bwi_mac_gpio_init(struct bwi_mac *); 9912e36acbSWarner Losh static int bwi_mac_gpio_fini(struct bwi_mac *); 10012e36acbSWarner Losh static void bwi_mac_opmode_init(struct bwi_mac *); 10112e36acbSWarner Losh static void bwi_mac_hostflags_init(struct bwi_mac *); 10212e36acbSWarner Losh static void bwi_mac_bss_param_init(struct bwi_mac *); 10312e36acbSWarner Losh 10412e36acbSWarner Losh static void bwi_mac_fw_free(struct bwi_mac *); 10512e36acbSWarner Losh static int bwi_mac_fw_load(struct bwi_mac *); 10612e36acbSWarner Losh static int bwi_mac_fw_init(struct bwi_mac *); 10712e36acbSWarner Losh static int bwi_mac_fw_load_iv(struct bwi_mac *, const struct firmware *); 10812e36acbSWarner Losh 10912e36acbSWarner Losh static void bwi_mac_setup_tpctl(struct bwi_mac *); 11012e36acbSWarner Losh static void bwi_mac_adjust_tpctl(struct bwi_mac *, int, int); 11112e36acbSWarner Losh 11212e36acbSWarner Losh static void bwi_mac_lock(struct bwi_mac *); 11312e36acbSWarner Losh static void bwi_mac_unlock(struct bwi_mac *); 11412e36acbSWarner Losh 11512e36acbSWarner Losh static const uint8_t bwi_sup_macrev[] = { 2, 4, 5, 6, 7, 9, 10 }; 11612e36acbSWarner Losh 11712e36acbSWarner Losh void 11812e36acbSWarner Losh bwi_tmplt_write_4(struct bwi_mac *mac, uint32_t ofs, uint32_t val) 11912e36acbSWarner Losh { 12012e36acbSWarner Losh struct bwi_softc *sc = mac->mac_sc; 12112e36acbSWarner Losh 12212e36acbSWarner Losh if (mac->mac_flags & BWI_MAC_F_BSWAP) 12312e36acbSWarner Losh val = bswap32(val); 12412e36acbSWarner Losh 12512e36acbSWarner Losh CSR_WRITE_4(sc, BWI_MAC_TMPLT_CTRL, ofs); 12612e36acbSWarner Losh CSR_WRITE_4(sc, BWI_MAC_TMPLT_DATA, val); 12712e36acbSWarner Losh } 12812e36acbSWarner Losh 12912e36acbSWarner Losh void 13012e36acbSWarner Losh bwi_hostflags_write(struct bwi_mac *mac, uint64_t flags) 13112e36acbSWarner Losh { 13212e36acbSWarner Losh uint64_t val; 13312e36acbSWarner Losh 13412e36acbSWarner Losh val = flags & 0xffff; 13512e36acbSWarner Losh MOBJ_WRITE_2(mac, BWI_COMM_MOBJ, BWI_COMM_MOBJ_HFLAGS_LO, val); 13612e36acbSWarner Losh 13712e36acbSWarner Losh val = (flags >> 16) & 0xffff; 13812e36acbSWarner Losh MOBJ_WRITE_2(mac, BWI_COMM_MOBJ, BWI_COMM_MOBJ_HFLAGS_MI, val); 13912e36acbSWarner Losh 14012e36acbSWarner Losh /* HI has unclear meaning, so leave it as it is */ 14112e36acbSWarner Losh } 14212e36acbSWarner Losh 14312e36acbSWarner Losh uint64_t 14412e36acbSWarner Losh bwi_hostflags_read(struct bwi_mac *mac) 14512e36acbSWarner Losh { 14612e36acbSWarner Losh uint64_t flags, val; 14712e36acbSWarner Losh 14812e36acbSWarner Losh /* HI has unclear meaning, so don't touch it */ 14912e36acbSWarner Losh flags = 0; 15012e36acbSWarner Losh 15112e36acbSWarner Losh val = MOBJ_READ_2(mac, BWI_COMM_MOBJ, BWI_COMM_MOBJ_HFLAGS_MI); 15212e36acbSWarner Losh flags |= val << 16; 15312e36acbSWarner Losh 15412e36acbSWarner Losh val = MOBJ_READ_2(mac, BWI_COMM_MOBJ, BWI_COMM_MOBJ_HFLAGS_LO); 15512e36acbSWarner Losh flags |= val; 15612e36acbSWarner Losh 15712e36acbSWarner Losh return flags; 15812e36acbSWarner Losh } 15912e36acbSWarner Losh 16012e36acbSWarner Losh uint16_t 16112e36acbSWarner Losh bwi_memobj_read_2(struct bwi_mac *mac, uint16_t obj_id, uint16_t ofs0) 16212e36acbSWarner Losh { 16312e36acbSWarner Losh struct bwi_softc *sc = mac->mac_sc; 16412e36acbSWarner Losh uint32_t data_reg; 16512e36acbSWarner Losh int ofs; 16612e36acbSWarner Losh 16712e36acbSWarner Losh data_reg = BWI_MOBJ_DATA; 16812e36acbSWarner Losh ofs = ofs0 / 4; 16912e36acbSWarner Losh 17012e36acbSWarner Losh if (ofs0 % 4 != 0) 17112e36acbSWarner Losh data_reg = BWI_MOBJ_DATA_UNALIGN; 17212e36acbSWarner Losh 17312e36acbSWarner Losh CSR_WRITE_4(sc, BWI_MOBJ_CTRL, BWI_MOBJ_CTRL_VAL(obj_id, ofs)); 17412e36acbSWarner Losh return CSR_READ_2(sc, data_reg); 17512e36acbSWarner Losh } 17612e36acbSWarner Losh 17712e36acbSWarner Losh uint32_t 17812e36acbSWarner Losh bwi_memobj_read_4(struct bwi_mac *mac, uint16_t obj_id, uint16_t ofs0) 17912e36acbSWarner Losh { 18012e36acbSWarner Losh struct bwi_softc *sc = mac->mac_sc; 18112e36acbSWarner Losh int ofs; 18212e36acbSWarner Losh 18312e36acbSWarner Losh ofs = ofs0 / 4; 18412e36acbSWarner Losh if (ofs0 % 4 != 0) { 18512e36acbSWarner Losh uint32_t ret; 18612e36acbSWarner Losh 18712e36acbSWarner Losh CSR_WRITE_4(sc, BWI_MOBJ_CTRL, BWI_MOBJ_CTRL_VAL(obj_id, ofs)); 18812e36acbSWarner Losh ret = CSR_READ_2(sc, BWI_MOBJ_DATA_UNALIGN); 18912e36acbSWarner Losh ret <<= 16; 19012e36acbSWarner Losh 19112e36acbSWarner Losh CSR_WRITE_4(sc, BWI_MOBJ_CTRL, 19212e36acbSWarner Losh BWI_MOBJ_CTRL_VAL(obj_id, ofs + 1)); 19312e36acbSWarner Losh ret |= CSR_READ_2(sc, BWI_MOBJ_DATA); 19412e36acbSWarner Losh 19512e36acbSWarner Losh return ret; 19612e36acbSWarner Losh } else { 19712e36acbSWarner Losh CSR_WRITE_4(sc, BWI_MOBJ_CTRL, BWI_MOBJ_CTRL_VAL(obj_id, ofs)); 19812e36acbSWarner Losh return CSR_READ_4(sc, BWI_MOBJ_DATA); 19912e36acbSWarner Losh } 20012e36acbSWarner Losh } 20112e36acbSWarner Losh 20212e36acbSWarner Losh void 20312e36acbSWarner Losh bwi_memobj_write_2(struct bwi_mac *mac, uint16_t obj_id, uint16_t ofs0, 20412e36acbSWarner Losh uint16_t v) 20512e36acbSWarner Losh { 20612e36acbSWarner Losh struct bwi_softc *sc = mac->mac_sc; 20712e36acbSWarner Losh uint32_t data_reg; 20812e36acbSWarner Losh int ofs; 20912e36acbSWarner Losh 21012e36acbSWarner Losh data_reg = BWI_MOBJ_DATA; 21112e36acbSWarner Losh ofs = ofs0 / 4; 21212e36acbSWarner Losh 21312e36acbSWarner Losh if (ofs0 % 4 != 0) 21412e36acbSWarner Losh data_reg = BWI_MOBJ_DATA_UNALIGN; 21512e36acbSWarner Losh 21612e36acbSWarner Losh CSR_WRITE_4(sc, BWI_MOBJ_CTRL, BWI_MOBJ_CTRL_VAL(obj_id, ofs)); 21712e36acbSWarner Losh CSR_WRITE_2(sc, data_reg, v); 21812e36acbSWarner Losh } 21912e36acbSWarner Losh 22012e36acbSWarner Losh void 22112e36acbSWarner Losh bwi_memobj_write_4(struct bwi_mac *mac, uint16_t obj_id, uint16_t ofs0, 22212e36acbSWarner Losh uint32_t v) 22312e36acbSWarner Losh { 22412e36acbSWarner Losh struct bwi_softc *sc = mac->mac_sc; 22512e36acbSWarner Losh int ofs; 22612e36acbSWarner Losh 22712e36acbSWarner Losh ofs = ofs0 / 4; 22812e36acbSWarner Losh if (ofs0 % 4 != 0) { 22912e36acbSWarner Losh CSR_WRITE_4(sc, BWI_MOBJ_CTRL, BWI_MOBJ_CTRL_VAL(obj_id, ofs)); 23012e36acbSWarner Losh CSR_WRITE_2(sc, BWI_MOBJ_DATA_UNALIGN, v >> 16); 23112e36acbSWarner Losh 23212e36acbSWarner Losh CSR_WRITE_4(sc, BWI_MOBJ_CTRL, 23312e36acbSWarner Losh BWI_MOBJ_CTRL_VAL(obj_id, ofs + 1)); 23412e36acbSWarner Losh CSR_WRITE_2(sc, BWI_MOBJ_DATA, v & 0xffff); 23512e36acbSWarner Losh } else { 23612e36acbSWarner Losh CSR_WRITE_4(sc, BWI_MOBJ_CTRL, BWI_MOBJ_CTRL_VAL(obj_id, ofs)); 23712e36acbSWarner Losh CSR_WRITE_4(sc, BWI_MOBJ_DATA, v); 23812e36acbSWarner Losh } 23912e36acbSWarner Losh } 24012e36acbSWarner Losh 24112e36acbSWarner Losh int 24212e36acbSWarner Losh bwi_mac_lateattach(struct bwi_mac *mac) 24312e36acbSWarner Losh { 24412e36acbSWarner Losh int error; 24512e36acbSWarner Losh 24612e36acbSWarner Losh if (mac->mac_rev >= 5) 24712e36acbSWarner Losh CSR_READ_4(mac->mac_sc, BWI_STATE_HI); /* dummy read */ 24812e36acbSWarner Losh 24912e36acbSWarner Losh bwi_mac_reset(mac, 1); 25012e36acbSWarner Losh 25112e36acbSWarner Losh error = bwi_phy_attach(mac); 25212e36acbSWarner Losh if (error) 25312e36acbSWarner Losh return error; 25412e36acbSWarner Losh 25512e36acbSWarner Losh error = bwi_rf_attach(mac); 25612e36acbSWarner Losh if (error) 25712e36acbSWarner Losh return error; 25812e36acbSWarner Losh 25912e36acbSWarner Losh /* Link 11B/G PHY, unlink 11A PHY */ 26012e36acbSWarner Losh if (mac->mac_phy.phy_mode == IEEE80211_MODE_11A) 26112e36acbSWarner Losh bwi_mac_reset(mac, 0); 26212e36acbSWarner Losh else 26312e36acbSWarner Losh bwi_mac_reset(mac, 1); 26412e36acbSWarner Losh 26512e36acbSWarner Losh error = bwi_mac_test(mac); 26612e36acbSWarner Losh if (error) 26712e36acbSWarner Losh return error; 26812e36acbSWarner Losh 26912e36acbSWarner Losh error = bwi_mac_get_property(mac); 27012e36acbSWarner Losh if (error) 27112e36acbSWarner Losh return error; 27212e36acbSWarner Losh 27312e36acbSWarner Losh error = bwi_rf_map_txpower(mac); 27412e36acbSWarner Losh if (error) 27512e36acbSWarner Losh return error; 27612e36acbSWarner Losh 27712e36acbSWarner Losh bwi_rf_off(mac); 27812e36acbSWarner Losh CSR_WRITE_2(mac->mac_sc, BWI_BBP_ATTEN, BWI_BBP_ATTEN_MAGIC); 27912e36acbSWarner Losh bwi_regwin_disable(mac->mac_sc, &mac->mac_regwin, 0); 28012e36acbSWarner Losh 28112e36acbSWarner Losh return 0; 28212e36acbSWarner Losh } 28312e36acbSWarner Losh 28412e36acbSWarner Losh int 28512e36acbSWarner Losh bwi_mac_init(struct bwi_mac *mac) 28612e36acbSWarner Losh { 28712e36acbSWarner Losh struct bwi_softc *sc = mac->mac_sc; 28812e36acbSWarner Losh int error, i; 28912e36acbSWarner Losh 29012e36acbSWarner Losh /* Clear MAC/PHY/RF states */ 29112e36acbSWarner Losh bwi_mac_setup_tpctl(mac); 29212e36acbSWarner Losh bwi_rf_clear_state(&mac->mac_rf); 29312e36acbSWarner Losh bwi_phy_clear_state(&mac->mac_phy); 29412e36acbSWarner Losh 29512e36acbSWarner Losh /* Enable MAC and linked it to PHY */ 29612e36acbSWarner Losh if (!bwi_regwin_is_enabled(sc, &mac->mac_regwin)) 29712e36acbSWarner Losh bwi_mac_reset(mac, 1); 29812e36acbSWarner Losh 29912e36acbSWarner Losh /* Initialize backplane */ 30012e36acbSWarner Losh error = bwi_bus_init(sc, mac); 30112e36acbSWarner Losh if (error) 30212e36acbSWarner Losh return error; 30312e36acbSWarner Losh 304d83d76dfSWarner Losh /* do timeout fixup */ 30512e36acbSWarner Losh if (sc->sc_bus_regwin.rw_rev <= 5 && 30612e36acbSWarner Losh sc->sc_bus_regwin.rw_type != BWI_REGWIN_T_BUSPCIE) { 30712e36acbSWarner Losh CSR_SETBITS_4(sc, BWI_CONF_LO, 30812e36acbSWarner Losh __SHIFTIN(BWI_CONF_LO_SERVTO, BWI_CONF_LO_SERVTO_MASK) | 30912e36acbSWarner Losh __SHIFTIN(BWI_CONF_LO_REQTO, BWI_CONF_LO_REQTO_MASK)); 31012e36acbSWarner Losh } 31112e36acbSWarner Losh 31212e36acbSWarner Losh /* Calibrate PHY */ 31312e36acbSWarner Losh error = bwi_phy_calibrate(mac); 31412e36acbSWarner Losh if (error) { 31512e36acbSWarner Losh device_printf(sc->sc_dev, "PHY calibrate failed\n"); 31612e36acbSWarner Losh return error; 31712e36acbSWarner Losh } 31812e36acbSWarner Losh 31912e36acbSWarner Losh /* Prepare to initialize firmware */ 32012e36acbSWarner Losh CSR_WRITE_4(sc, BWI_MAC_STATUS, 32112e36acbSWarner Losh BWI_MAC_STATUS_UCODE_JUMP0 | 32212e36acbSWarner Losh BWI_MAC_STATUS_IHREN); 32312e36acbSWarner Losh 32412e36acbSWarner Losh /* 32512e36acbSWarner Losh * Load and initialize firmwares 32612e36acbSWarner Losh */ 32712e36acbSWarner Losh error = bwi_mac_fw_load(mac); 32812e36acbSWarner Losh if (error) 32912e36acbSWarner Losh return error; 33012e36acbSWarner Losh 33112e36acbSWarner Losh error = bwi_mac_gpio_init(mac); 33212e36acbSWarner Losh if (error) 33312e36acbSWarner Losh return error; 33412e36acbSWarner Losh 33512e36acbSWarner Losh error = bwi_mac_fw_init(mac); 33612e36acbSWarner Losh if (error) 33712e36acbSWarner Losh return error; 33812e36acbSWarner Losh 33912e36acbSWarner Losh /* 34012e36acbSWarner Losh * Turn on RF 34112e36acbSWarner Losh */ 34212e36acbSWarner Losh bwi_rf_on(mac); 34312e36acbSWarner Losh 34412e36acbSWarner Losh /* TODO: LED, hardware rf enabled is only related to LED setting */ 34512e36acbSWarner Losh 34612e36acbSWarner Losh /* 34712e36acbSWarner Losh * Initialize PHY 34812e36acbSWarner Losh */ 34912e36acbSWarner Losh CSR_WRITE_2(sc, BWI_BBP_ATTEN, 0); 35012e36acbSWarner Losh bwi_phy_init(mac); 35112e36acbSWarner Losh 35212e36acbSWarner Losh /* TODO: interference mitigation */ 35312e36acbSWarner Losh 35412e36acbSWarner Losh /* 35512e36acbSWarner Losh * Setup antenna mode 35612e36acbSWarner Losh */ 35712e36acbSWarner Losh bwi_rf_set_ant_mode(mac, mac->mac_rf.rf_ant_mode); 35812e36acbSWarner Losh 35912e36acbSWarner Losh /* 36012e36acbSWarner Losh * Initialize operation mode (RX configuration) 36112e36acbSWarner Losh */ 36212e36acbSWarner Losh bwi_mac_opmode_init(mac); 36312e36acbSWarner Losh 364d83d76dfSWarner Losh /* set up Beacon interval */ 36512e36acbSWarner Losh if (mac->mac_rev < 3) { 36612e36acbSWarner Losh CSR_WRITE_2(sc, 0x60e, 0); 36712e36acbSWarner Losh CSR_WRITE_2(sc, 0x610, 0x8000); 36812e36acbSWarner Losh CSR_WRITE_2(sc, 0x604, 0); 36912e36acbSWarner Losh CSR_WRITE_2(sc, 0x606, 0x200); 37012e36acbSWarner Losh } else { 37112e36acbSWarner Losh CSR_WRITE_4(sc, 0x188, 0x80000000); 37212e36acbSWarner Losh CSR_WRITE_4(sc, 0x18c, 0x2000000); 37312e36acbSWarner Losh } 37412e36acbSWarner Losh 37512e36acbSWarner Losh /* 37612e36acbSWarner Losh * Initialize TX/RX interrupts' mask 37712e36acbSWarner Losh */ 37812e36acbSWarner Losh CSR_WRITE_4(sc, BWI_MAC_INTR_STATUS, BWI_INTR_TIMER1); 37912e36acbSWarner Losh for (i = 0; i < BWI_TXRX_NRING; ++i) { 38012e36acbSWarner Losh uint32_t intrs; 38112e36acbSWarner Losh 38212e36acbSWarner Losh if (BWI_TXRX_IS_RX(i)) 38312e36acbSWarner Losh intrs = BWI_TXRX_RX_INTRS; 38412e36acbSWarner Losh else 38512e36acbSWarner Losh intrs = BWI_TXRX_TX_INTRS; 38612e36acbSWarner Losh CSR_WRITE_4(sc, BWI_TXRX_INTR_MASK(i), intrs); 38712e36acbSWarner Losh } 38812e36acbSWarner Losh 389d83d76dfSWarner Losh /* allow the MAC to control the PHY clock (dynamic on/off) */ 39012e36acbSWarner Losh CSR_SETBITS_4(sc, BWI_STATE_LO, 0x100000); 39112e36acbSWarner Losh 39212e36acbSWarner Losh /* Setup MAC power up delay */ 39312e36acbSWarner Losh CSR_WRITE_2(sc, BWI_MAC_POWERUP_DELAY, sc->sc_pwron_delay); 39412e36acbSWarner Losh 39512e36acbSWarner Losh /* Set MAC regwin revision */ 39612e36acbSWarner Losh MOBJ_WRITE_2(mac, BWI_COMM_MOBJ, BWI_COMM_MOBJ_MACREV, mac->mac_rev); 39712e36acbSWarner Losh 39812e36acbSWarner Losh /* 39912e36acbSWarner Losh * Initialize host flags 40012e36acbSWarner Losh */ 40112e36acbSWarner Losh bwi_mac_hostflags_init(mac); 40212e36acbSWarner Losh 40312e36acbSWarner Losh /* 40412e36acbSWarner Losh * Initialize BSS parameters 40512e36acbSWarner Losh */ 40612e36acbSWarner Losh bwi_mac_bss_param_init(mac); 40712e36acbSWarner Losh 40812e36acbSWarner Losh /* 40912e36acbSWarner Losh * Initialize TX rings 41012e36acbSWarner Losh */ 41112e36acbSWarner Losh for (i = 0; i < BWI_TX_NRING; ++i) { 41212e36acbSWarner Losh error = sc->sc_init_tx_ring(sc, i); 41312e36acbSWarner Losh if (error) { 41412e36acbSWarner Losh device_printf(sc->sc_dev, 41512e36acbSWarner Losh "can't initialize %dth TX ring\n", i); 41612e36acbSWarner Losh return error; 41712e36acbSWarner Losh } 41812e36acbSWarner Losh } 41912e36acbSWarner Losh 42012e36acbSWarner Losh /* 42112e36acbSWarner Losh * Initialize RX ring 42212e36acbSWarner Losh */ 42312e36acbSWarner Losh error = sc->sc_init_rx_ring(sc); 42412e36acbSWarner Losh if (error) { 42512e36acbSWarner Losh device_printf(sc->sc_dev, "can't initialize RX ring\n"); 42612e36acbSWarner Losh return error; 42712e36acbSWarner Losh } 42812e36acbSWarner Losh 42912e36acbSWarner Losh /* 43012e36acbSWarner Losh * Initialize TX stats if the current MAC uses that 43112e36acbSWarner Losh */ 43212e36acbSWarner Losh if (mac->mac_flags & BWI_MAC_F_HAS_TXSTATS) { 43312e36acbSWarner Losh error = sc->sc_init_txstats(sc); 43412e36acbSWarner Losh if (error) { 43512e36acbSWarner Losh device_printf(sc->sc_dev, 43612e36acbSWarner Losh "can't initialize TX stats ring\n"); 43712e36acbSWarner Losh return error; 43812e36acbSWarner Losh } 43912e36acbSWarner Losh } 44012e36acbSWarner Losh 441d83d76dfSWarner Losh /* update PRETBTT */ 44212e36acbSWarner Losh CSR_WRITE_2(sc, 0x612, 0x50); /* Force Pre-TBTT to 80? */ 44312e36acbSWarner Losh MOBJ_WRITE_2(mac, BWI_COMM_MOBJ, 0x416, 0x50); 44412e36acbSWarner Losh MOBJ_WRITE_2(mac, BWI_COMM_MOBJ, 0x414, 0x1f4); 44512e36acbSWarner Losh 44612e36acbSWarner Losh mac->mac_flags |= BWI_MAC_F_INITED; 44712e36acbSWarner Losh return 0; 44812e36acbSWarner Losh } 44912e36acbSWarner Losh 45012e36acbSWarner Losh void 45112e36acbSWarner Losh bwi_mac_reset(struct bwi_mac *mac, int link_phy) 45212e36acbSWarner Losh { 45312e36acbSWarner Losh struct bwi_softc *sc = mac->mac_sc; 45412e36acbSWarner Losh uint32_t flags, state_lo, status; 45512e36acbSWarner Losh 45612e36acbSWarner Losh flags = BWI_STATE_LO_FLAG_PHYRST | BWI_STATE_LO_FLAG_PHYCLKEN; 45712e36acbSWarner Losh if (link_phy) 45812e36acbSWarner Losh flags |= BWI_STATE_LO_FLAG_PHYLNK; 45912e36acbSWarner Losh bwi_regwin_enable(sc, &mac->mac_regwin, flags); 46012e36acbSWarner Losh DELAY(2000); 46112e36acbSWarner Losh 46212e36acbSWarner Losh state_lo = CSR_READ_4(sc, BWI_STATE_LO); 46312e36acbSWarner Losh state_lo |= BWI_STATE_LO_GATED_CLOCK; 46412e36acbSWarner Losh state_lo &= ~__SHIFTIN(BWI_STATE_LO_FLAG_PHYRST, 46512e36acbSWarner Losh BWI_STATE_LO_FLAGS_MASK); 46612e36acbSWarner Losh CSR_WRITE_4(sc, BWI_STATE_LO, state_lo); 46712e36acbSWarner Losh /* Flush pending bus write */ 46812e36acbSWarner Losh CSR_READ_4(sc, BWI_STATE_LO); 46912e36acbSWarner Losh DELAY(1000); 47012e36acbSWarner Losh 47112e36acbSWarner Losh state_lo &= ~BWI_STATE_LO_GATED_CLOCK; 47212e36acbSWarner Losh CSR_WRITE_4(sc, BWI_STATE_LO, state_lo); 47312e36acbSWarner Losh /* Flush pending bus write */ 47412e36acbSWarner Losh CSR_READ_4(sc, BWI_STATE_LO); 47512e36acbSWarner Losh DELAY(1000); 47612e36acbSWarner Losh 47712e36acbSWarner Losh CSR_WRITE_2(sc, BWI_BBP_ATTEN, 0); 47812e36acbSWarner Losh 47912e36acbSWarner Losh status = CSR_READ_4(sc, BWI_MAC_STATUS); 48012e36acbSWarner Losh status |= BWI_MAC_STATUS_IHREN; 48112e36acbSWarner Losh if (link_phy) 48212e36acbSWarner Losh status |= BWI_MAC_STATUS_PHYLNK; 48312e36acbSWarner Losh else 48412e36acbSWarner Losh status &= ~BWI_MAC_STATUS_PHYLNK; 48512e36acbSWarner Losh CSR_WRITE_4(sc, BWI_MAC_STATUS, status); 48612e36acbSWarner Losh 48712e36acbSWarner Losh if (link_phy) { 48812e36acbSWarner Losh DPRINTF(sc, BWI_DBG_MAC | BWI_DBG_ATTACH | BWI_DBG_INIT, 48912e36acbSWarner Losh "%s\n", "PHY is linked"); 49012e36acbSWarner Losh mac->mac_phy.phy_flags |= BWI_PHY_F_LINKED; 49112e36acbSWarner Losh } else { 49212e36acbSWarner Losh DPRINTF(sc, BWI_DBG_MAC | BWI_DBG_ATTACH | BWI_DBG_INIT, 49312e36acbSWarner Losh "%s\n", "PHY is unlinked"); 49412e36acbSWarner Losh mac->mac_phy.phy_flags &= ~BWI_PHY_F_LINKED; 49512e36acbSWarner Losh } 49612e36acbSWarner Losh } 49712e36acbSWarner Losh 49812e36acbSWarner Losh void 49912e36acbSWarner Losh bwi_mac_set_tpctl_11bg(struct bwi_mac *mac, const struct bwi_tpctl *new_tpctl) 50012e36acbSWarner Losh { 50112e36acbSWarner Losh struct bwi_rf *rf = &mac->mac_rf; 50212e36acbSWarner Losh struct bwi_tpctl *tpctl = &mac->mac_tpctl; 50312e36acbSWarner Losh 50412e36acbSWarner Losh if (new_tpctl != NULL) { 50512e36acbSWarner Losh KASSERT(new_tpctl->bbp_atten <= BWI_BBP_ATTEN_MAX, 50612e36acbSWarner Losh ("bbp_atten %d", new_tpctl->bbp_atten)); 50712e36acbSWarner Losh KASSERT(new_tpctl->rf_atten <= 50812e36acbSWarner Losh (rf->rf_rev < 6 ? BWI_RF_ATTEN_MAX0 50912e36acbSWarner Losh : BWI_RF_ATTEN_MAX1), 51012e36acbSWarner Losh ("rf_atten %d", new_tpctl->rf_atten)); 51112e36acbSWarner Losh KASSERT(new_tpctl->tp_ctrl1 <= BWI_TPCTL1_MAX, 51212e36acbSWarner Losh ("tp_ctrl1 %d", new_tpctl->tp_ctrl1)); 51312e36acbSWarner Losh 51412e36acbSWarner Losh tpctl->bbp_atten = new_tpctl->bbp_atten; 51512e36acbSWarner Losh tpctl->rf_atten = new_tpctl->rf_atten; 51612e36acbSWarner Losh tpctl->tp_ctrl1 = new_tpctl->tp_ctrl1; 51712e36acbSWarner Losh } 51812e36acbSWarner Losh 51912e36acbSWarner Losh /* Set BBP attenuation */ 52012e36acbSWarner Losh bwi_phy_set_bbp_atten(mac, tpctl->bbp_atten); 52112e36acbSWarner Losh 52212e36acbSWarner Losh /* Set RF attenuation */ 52312e36acbSWarner Losh RF_WRITE(mac, BWI_RFR_ATTEN, tpctl->rf_atten); 52412e36acbSWarner Losh MOBJ_WRITE_2(mac, BWI_COMM_MOBJ, BWI_COMM_MOBJ_RF_ATTEN, 52512e36acbSWarner Losh tpctl->rf_atten); 52612e36acbSWarner Losh 52712e36acbSWarner Losh /* Set TX power */ 52812e36acbSWarner Losh if (rf->rf_type == BWI_RF_T_BCM2050) { 52912e36acbSWarner Losh RF_FILT_SETBITS(mac, BWI_RFR_TXPWR, ~BWI_RFR_TXPWR1_MASK, 53012e36acbSWarner Losh __SHIFTIN(tpctl->tp_ctrl1, BWI_RFR_TXPWR1_MASK)); 53112e36acbSWarner Losh } 53212e36acbSWarner Losh 53312e36acbSWarner Losh /* Adjust RF Local Oscillator */ 53412e36acbSWarner Losh if (mac->mac_phy.phy_mode == IEEE80211_MODE_11G) 53512e36acbSWarner Losh bwi_rf_lo_adjust(mac, tpctl); 53612e36acbSWarner Losh } 53712e36acbSWarner Losh 53812e36acbSWarner Losh static int 53912e36acbSWarner Losh bwi_mac_test(struct bwi_mac *mac) 54012e36acbSWarner Losh { 54112e36acbSWarner Losh struct bwi_softc *sc = mac->mac_sc; 54212e36acbSWarner Losh uint32_t orig_val, val; 54312e36acbSWarner Losh 54412e36acbSWarner Losh #define TEST_VAL1 0xaa5555aa 54512e36acbSWarner Losh #define TEST_VAL2 0x55aaaa55 54612e36acbSWarner Losh 54712e36acbSWarner Losh /* Save it for later restoring */ 54812e36acbSWarner Losh orig_val = MOBJ_READ_4(mac, BWI_COMM_MOBJ, 0); 54912e36acbSWarner Losh 55012e36acbSWarner Losh /* Test 1 */ 55112e36acbSWarner Losh MOBJ_WRITE_4(mac, BWI_COMM_MOBJ, 0, TEST_VAL1); 55212e36acbSWarner Losh val = MOBJ_READ_4(mac, BWI_COMM_MOBJ, 0); 55312e36acbSWarner Losh if (val != TEST_VAL1) { 55412e36acbSWarner Losh device_printf(sc->sc_dev, "TEST1 failed\n"); 55512e36acbSWarner Losh return ENXIO; 55612e36acbSWarner Losh } 55712e36acbSWarner Losh 55812e36acbSWarner Losh /* Test 2 */ 55912e36acbSWarner Losh MOBJ_WRITE_4(mac, BWI_COMM_MOBJ, 0, TEST_VAL2); 56012e36acbSWarner Losh val = MOBJ_READ_4(mac, BWI_COMM_MOBJ, 0); 56112e36acbSWarner Losh if (val != TEST_VAL2) { 56212e36acbSWarner Losh device_printf(sc->sc_dev, "TEST2 failed\n"); 56312e36acbSWarner Losh return ENXIO; 56412e36acbSWarner Losh } 56512e36acbSWarner Losh 56612e36acbSWarner Losh /* Restore to the original value */ 56712e36acbSWarner Losh MOBJ_WRITE_4(mac, BWI_COMM_MOBJ, 0, orig_val); 56812e36acbSWarner Losh 56912e36acbSWarner Losh val = CSR_READ_4(sc, BWI_MAC_STATUS); 57012e36acbSWarner Losh if ((val & ~BWI_MAC_STATUS_PHYLNK) != BWI_MAC_STATUS_IHREN) { 57112e36acbSWarner Losh device_printf(sc->sc_dev, "%s failed, MAC status 0x%08x\n", 57212e36acbSWarner Losh __func__, val); 57312e36acbSWarner Losh return ENXIO; 57412e36acbSWarner Losh } 57512e36acbSWarner Losh 57612e36acbSWarner Losh val = CSR_READ_4(sc, BWI_MAC_INTR_STATUS); 57712e36acbSWarner Losh if (val != 0) { 57812e36acbSWarner Losh device_printf(sc->sc_dev, "%s failed, intr status %08x\n", 57912e36acbSWarner Losh __func__, val); 58012e36acbSWarner Losh return ENXIO; 58112e36acbSWarner Losh } 58212e36acbSWarner Losh 58312e36acbSWarner Losh #undef TEST_VAL2 58412e36acbSWarner Losh #undef TEST_VAL1 58512e36acbSWarner Losh 58612e36acbSWarner Losh return 0; 58712e36acbSWarner Losh } 58812e36acbSWarner Losh 58912e36acbSWarner Losh static void 59012e36acbSWarner Losh bwi_mac_setup_tpctl(struct bwi_mac *mac) 59112e36acbSWarner Losh { 59212e36acbSWarner Losh struct bwi_softc *sc = mac->mac_sc; 59312e36acbSWarner Losh struct bwi_rf *rf = &mac->mac_rf; 59412e36acbSWarner Losh struct bwi_phy *phy = &mac->mac_phy; 59512e36acbSWarner Losh struct bwi_tpctl *tpctl = &mac->mac_tpctl; 59612e36acbSWarner Losh 59712e36acbSWarner Losh /* Calc BBP attenuation */ 59812e36acbSWarner Losh if (rf->rf_type == BWI_RF_T_BCM2050 && rf->rf_rev < 6) 59912e36acbSWarner Losh tpctl->bbp_atten = 0; 60012e36acbSWarner Losh else 60112e36acbSWarner Losh tpctl->bbp_atten = 2; 60212e36acbSWarner Losh 60312e36acbSWarner Losh /* Calc TX power CTRL1?? */ 60412e36acbSWarner Losh tpctl->tp_ctrl1 = 0; 60512e36acbSWarner Losh if (rf->rf_type == BWI_RF_T_BCM2050) { 60612e36acbSWarner Losh if (rf->rf_rev == 1) 60712e36acbSWarner Losh tpctl->tp_ctrl1 = 3; 60812e36acbSWarner Losh else if (rf->rf_rev < 6) 60912e36acbSWarner Losh tpctl->tp_ctrl1 = 2; 61012e36acbSWarner Losh else if (rf->rf_rev == 8) 61112e36acbSWarner Losh tpctl->tp_ctrl1 = 1; 61212e36acbSWarner Losh } 61312e36acbSWarner Losh 61412e36acbSWarner Losh /* Empty TX power CTRL2?? */ 61512e36acbSWarner Losh tpctl->tp_ctrl2 = 0xffff; 61612e36acbSWarner Losh 61712e36acbSWarner Losh /* 61812e36acbSWarner Losh * Calc RF attenuation 61912e36acbSWarner Losh */ 62012e36acbSWarner Losh if (phy->phy_mode == IEEE80211_MODE_11A) { 62112e36acbSWarner Losh tpctl->rf_atten = 0x60; 62212e36acbSWarner Losh goto back; 62312e36acbSWarner Losh } 62412e36acbSWarner Losh 62512e36acbSWarner Losh if (BWI_IS_BRCM_BCM4309G(sc) && sc->sc_pci_revid < 0x51) { 62612e36acbSWarner Losh tpctl->rf_atten = sc->sc_pci_revid < 0x43 ? 2 : 3; 62712e36acbSWarner Losh goto back; 62812e36acbSWarner Losh } 62912e36acbSWarner Losh 63012e36acbSWarner Losh tpctl->rf_atten = 5; 63112e36acbSWarner Losh 63212e36acbSWarner Losh if (rf->rf_type != BWI_RF_T_BCM2050) { 63312e36acbSWarner Losh if (rf->rf_type == BWI_RF_T_BCM2053 && rf->rf_rev == 1) 63412e36acbSWarner Losh tpctl->rf_atten = 6; 63512e36acbSWarner Losh goto back; 63612e36acbSWarner Losh } 63712e36acbSWarner Losh 63812e36acbSWarner Losh /* 63912e36acbSWarner Losh * NB: If we reaches here and the card is BRCM_BCM4309G, 64012e36acbSWarner Losh * then the card's PCI revision must >= 0x51 64112e36acbSWarner Losh */ 64212e36acbSWarner Losh 64312e36acbSWarner Losh /* BCM2050 RF */ 64412e36acbSWarner Losh switch (rf->rf_rev) { 64512e36acbSWarner Losh case 1: 64612e36acbSWarner Losh if (phy->phy_mode == IEEE80211_MODE_11G) { 64712e36acbSWarner Losh if (BWI_IS_BRCM_BCM4309G(sc) || BWI_IS_BRCM_BU4306(sc)) 64812e36acbSWarner Losh tpctl->rf_atten = 3; 64912e36acbSWarner Losh else 65012e36acbSWarner Losh tpctl->rf_atten = 1; 65112e36acbSWarner Losh } else { 65212e36acbSWarner Losh if (BWI_IS_BRCM_BCM4309G(sc)) 65312e36acbSWarner Losh tpctl->rf_atten = 7; 65412e36acbSWarner Losh else 65512e36acbSWarner Losh tpctl->rf_atten = 6; 65612e36acbSWarner Losh } 65712e36acbSWarner Losh break; 65812e36acbSWarner Losh case 2: 65912e36acbSWarner Losh if (phy->phy_mode == IEEE80211_MODE_11G) { 66012e36acbSWarner Losh /* 66112e36acbSWarner Losh * NOTE: Order of following conditions is critical 66212e36acbSWarner Losh */ 66312e36acbSWarner Losh if (BWI_IS_BRCM_BCM4309G(sc)) 66412e36acbSWarner Losh tpctl->rf_atten = 3; 66512e36acbSWarner Losh else if (BWI_IS_BRCM_BU4306(sc)) 66612e36acbSWarner Losh tpctl->rf_atten = 5; 66712e36acbSWarner Losh else if (sc->sc_bbp_id == BWI_BBPID_BCM4320) 66812e36acbSWarner Losh tpctl->rf_atten = 4; 66912e36acbSWarner Losh else 67012e36acbSWarner Losh tpctl->rf_atten = 3; 67112e36acbSWarner Losh } else { 67212e36acbSWarner Losh tpctl->rf_atten = 6; 67312e36acbSWarner Losh } 67412e36acbSWarner Losh break; 67512e36acbSWarner Losh case 4: 67612e36acbSWarner Losh case 5: 67712e36acbSWarner Losh tpctl->rf_atten = 1; 67812e36acbSWarner Losh break; 67912e36acbSWarner Losh case 8: 68012e36acbSWarner Losh tpctl->rf_atten = 0x1a; 68112e36acbSWarner Losh break; 68212e36acbSWarner Losh } 68312e36acbSWarner Losh back: 68412e36acbSWarner Losh DPRINTF(sc, BWI_DBG_MAC | BWI_DBG_INIT | BWI_DBG_TXPOWER, 68512e36acbSWarner Losh "bbp atten: %u, rf atten: %u, ctrl1: %u, ctrl2: %u\n", 68612e36acbSWarner Losh tpctl->bbp_atten, tpctl->rf_atten, 68712e36acbSWarner Losh tpctl->tp_ctrl1, tpctl->tp_ctrl2); 68812e36acbSWarner Losh } 68912e36acbSWarner Losh 69012e36acbSWarner Losh void 69112e36acbSWarner Losh bwi_mac_dummy_xmit(struct bwi_mac *mac) 69212e36acbSWarner Losh { 69312e36acbSWarner Losh #define PACKET_LEN 5 69412e36acbSWarner Losh static const uint32_t packet_11a[PACKET_LEN] = 69512e36acbSWarner Losh { 0x000201cc, 0x00d40000, 0x00000000, 0x01000000, 0x00000000 }; 69612e36acbSWarner Losh static const uint32_t packet_11bg[PACKET_LEN] = 69712e36acbSWarner Losh { 0x000b846e, 0x00d40000, 0x00000000, 0x01000000, 0x00000000 }; 69812e36acbSWarner Losh 69912e36acbSWarner Losh struct bwi_softc *sc = mac->mac_sc; 70012e36acbSWarner Losh struct bwi_rf *rf = &mac->mac_rf; 70112e36acbSWarner Losh const uint32_t *packet; 70212e36acbSWarner Losh uint16_t val_50c; 70312e36acbSWarner Losh int wait_max, i; 70412e36acbSWarner Losh 70512e36acbSWarner Losh if (mac->mac_phy.phy_mode == IEEE80211_MODE_11A) { 70612e36acbSWarner Losh wait_max = 30; 70712e36acbSWarner Losh packet = packet_11a; 70812e36acbSWarner Losh val_50c = 1; 70912e36acbSWarner Losh } else { 71012e36acbSWarner Losh wait_max = 250; 71112e36acbSWarner Losh packet = packet_11bg; 71212e36acbSWarner Losh val_50c = 0; 71312e36acbSWarner Losh } 71412e36acbSWarner Losh 71512e36acbSWarner Losh for (i = 0; i < PACKET_LEN; ++i) 71612e36acbSWarner Losh TMPLT_WRITE_4(mac, i * 4, packet[i]); 71712e36acbSWarner Losh 71812e36acbSWarner Losh CSR_READ_4(sc, BWI_MAC_STATUS); /* dummy read */ 71912e36acbSWarner Losh 72012e36acbSWarner Losh CSR_WRITE_2(sc, 0x568, 0); 72112e36acbSWarner Losh CSR_WRITE_2(sc, 0x7c0, 0); 72212e36acbSWarner Losh CSR_WRITE_2(sc, 0x50c, val_50c); 72312e36acbSWarner Losh CSR_WRITE_2(sc, 0x508, 0); 72412e36acbSWarner Losh CSR_WRITE_2(sc, 0x50a, 0); 72512e36acbSWarner Losh CSR_WRITE_2(sc, 0x54c, 0); 72612e36acbSWarner Losh CSR_WRITE_2(sc, 0x56a, 0x14); 72712e36acbSWarner Losh CSR_WRITE_2(sc, 0x568, 0x826); 72812e36acbSWarner Losh CSR_WRITE_2(sc, 0x500, 0); 72912e36acbSWarner Losh CSR_WRITE_2(sc, 0x502, 0x30); 73012e36acbSWarner Losh 73112e36acbSWarner Losh if (rf->rf_type == BWI_RF_T_BCM2050 && rf->rf_rev <= 5) 73212e36acbSWarner Losh RF_WRITE(mac, 0x51, 0x17); 73312e36acbSWarner Losh 73412e36acbSWarner Losh for (i = 0; i < wait_max; ++i) { 73512e36acbSWarner Losh if (CSR_READ_2(sc, 0x50e) & 0x80) 73612e36acbSWarner Losh break; 73712e36acbSWarner Losh DELAY(10); 73812e36acbSWarner Losh } 73912e36acbSWarner Losh for (i = 0; i < 10; ++i) { 74012e36acbSWarner Losh if (CSR_READ_2(sc, 0x50e) & 0x400) 74112e36acbSWarner Losh break; 74212e36acbSWarner Losh DELAY(10); 74312e36acbSWarner Losh } 74412e36acbSWarner Losh for (i = 0; i < 10; ++i) { 74512e36acbSWarner Losh if ((CSR_READ_2(sc, 0x690) & 0x100) == 0) 74612e36acbSWarner Losh break; 74712e36acbSWarner Losh DELAY(10); 74812e36acbSWarner Losh } 74912e36acbSWarner Losh 75012e36acbSWarner Losh if (rf->rf_type == BWI_RF_T_BCM2050 && rf->rf_rev <= 5) 75112e36acbSWarner Losh RF_WRITE(mac, 0x51, 0x37); 75212e36acbSWarner Losh #undef PACKET_LEN 75312e36acbSWarner Losh } 75412e36acbSWarner Losh 75512e36acbSWarner Losh void 75612e36acbSWarner Losh bwi_mac_init_tpctl_11bg(struct bwi_mac *mac) 75712e36acbSWarner Losh { 75812e36acbSWarner Losh struct bwi_softc *sc = mac->mac_sc; 75912e36acbSWarner Losh struct bwi_phy *phy = &mac->mac_phy; 76012e36acbSWarner Losh struct bwi_rf *rf = &mac->mac_rf; 76112e36acbSWarner Losh struct bwi_tpctl tpctl_orig; 76212e36acbSWarner Losh int restore_tpctl = 0; 76312e36acbSWarner Losh 76412e36acbSWarner Losh KASSERT(phy->phy_mode != IEEE80211_MODE_11A, 76512e36acbSWarner Losh ("phy_mode %d", phy->phy_mode)); 76612e36acbSWarner Losh 76712e36acbSWarner Losh if (BWI_IS_BRCM_BU4306(sc)) 76812e36acbSWarner Losh return; 76912e36acbSWarner Losh 77012e36acbSWarner Losh PHY_WRITE(mac, 0x28, 0x8018); 77112e36acbSWarner Losh CSR_CLRBITS_2(sc, BWI_BBP_ATTEN, 0x20); 77212e36acbSWarner Losh 77312e36acbSWarner Losh if (phy->phy_mode == IEEE80211_MODE_11G) { 77412e36acbSWarner Losh if ((phy->phy_flags & BWI_PHY_F_LINKED) == 0) 77512e36acbSWarner Losh return; 77612e36acbSWarner Losh PHY_WRITE(mac, 0x47a, 0xc111); 77712e36acbSWarner Losh } 77812e36acbSWarner Losh if (mac->mac_flags & BWI_MAC_F_TPCTL_INITED) 77912e36acbSWarner Losh return; 78012e36acbSWarner Losh 78112e36acbSWarner Losh if (phy->phy_mode == IEEE80211_MODE_11B && phy->phy_rev >= 2 && 78212e36acbSWarner Losh rf->rf_type == BWI_RF_T_BCM2050) { 78312e36acbSWarner Losh RF_SETBITS(mac, 0x76, 0x84); 78412e36acbSWarner Losh } else { 78512e36acbSWarner Losh struct bwi_tpctl tpctl; 78612e36acbSWarner Losh 78712e36acbSWarner Losh /* Backup original TX power control variables */ 78812e36acbSWarner Losh bcopy(&mac->mac_tpctl, &tpctl_orig, sizeof(tpctl_orig)); 78912e36acbSWarner Losh restore_tpctl = 1; 79012e36acbSWarner Losh 79112e36acbSWarner Losh bcopy(&mac->mac_tpctl, &tpctl, sizeof(tpctl)); 79212e36acbSWarner Losh tpctl.bbp_atten = 11; 79312e36acbSWarner Losh tpctl.tp_ctrl1 = 0; 79412e36acbSWarner Losh #ifdef notyet 79512e36acbSWarner Losh if (rf->rf_rev >= 6 && rf->rf_rev <= 8) 79612e36acbSWarner Losh tpctl.rf_atten = 31; 79712e36acbSWarner Losh else 79812e36acbSWarner Losh #endif 79912e36acbSWarner Losh tpctl.rf_atten = 9; 80012e36acbSWarner Losh 80112e36acbSWarner Losh bwi_mac_set_tpctl_11bg(mac, &tpctl); 80212e36acbSWarner Losh } 80312e36acbSWarner Losh 80412e36acbSWarner Losh bwi_mac_dummy_xmit(mac); 80512e36acbSWarner Losh 80612e36acbSWarner Losh mac->mac_flags |= BWI_MAC_F_TPCTL_INITED; 80712e36acbSWarner Losh rf->rf_base_tssi = PHY_READ(mac, 0x29); 80812e36acbSWarner Losh DPRINTF(sc, BWI_DBG_MAC | BWI_DBG_INIT | BWI_DBG_TXPOWER, 80912e36acbSWarner Losh "base tssi %d\n", rf->rf_base_tssi); 81012e36acbSWarner Losh 81112e36acbSWarner Losh if (abs(rf->rf_base_tssi - rf->rf_idle_tssi) >= 20) { 81212e36acbSWarner Losh device_printf(sc->sc_dev, "base tssi measure failed\n"); 81312e36acbSWarner Losh mac->mac_flags |= BWI_MAC_F_TPCTL_ERROR; 81412e36acbSWarner Losh } 81512e36acbSWarner Losh 81612e36acbSWarner Losh if (restore_tpctl) 81712e36acbSWarner Losh bwi_mac_set_tpctl_11bg(mac, &tpctl_orig); 81812e36acbSWarner Losh else 81912e36acbSWarner Losh RF_CLRBITS(mac, 0x76, 0x84); 82012e36acbSWarner Losh 82112e36acbSWarner Losh bwi_rf_clear_tssi(mac); 82212e36acbSWarner Losh } 82312e36acbSWarner Losh 82412e36acbSWarner Losh void 82512e36acbSWarner Losh bwi_mac_detach(struct bwi_mac *mac) 82612e36acbSWarner Losh { 82712e36acbSWarner Losh bwi_mac_fw_free(mac); 82812e36acbSWarner Losh } 82912e36acbSWarner Losh 83012e36acbSWarner Losh static __inline int 83112e36acbSWarner Losh bwi_fwimage_is_valid(struct bwi_softc *sc, const struct firmware *fw, 83212e36acbSWarner Losh uint8_t fw_type) 83312e36acbSWarner Losh { 83412e36acbSWarner Losh const struct bwi_fwhdr *hdr; 83512e36acbSWarner Losh 83612e36acbSWarner Losh if (fw->datasize < sizeof(*hdr)) { 8377a79cebfSGleb Smirnoff device_printf(sc->sc_dev, 8387a79cebfSGleb Smirnoff "invalid firmware (%s): invalid size %zu\n", 83912e36acbSWarner Losh fw->name, fw->datasize); 84012e36acbSWarner Losh return 0; 84112e36acbSWarner Losh } 84212e36acbSWarner Losh 84312e36acbSWarner Losh hdr = (const struct bwi_fwhdr *)fw->data; 84412e36acbSWarner Losh 84512e36acbSWarner Losh if (fw_type != BWI_FW_T_IV) { 84612e36acbSWarner Losh /* 84712e36acbSWarner Losh * Don't verify IV's size, it has different meaning 84812e36acbSWarner Losh */ 84912e36acbSWarner Losh if (be32toh(hdr->fw_size) != fw->datasize - sizeof(*hdr)) { 8507a79cebfSGleb Smirnoff device_printf(sc->sc_dev, 8517a79cebfSGleb Smirnoff "invalid firmware (%s): size mismatch, " 85212e36acbSWarner Losh "fw %u, real %zu\n", fw->name, 8537a79cebfSGleb Smirnoff be32toh(hdr->fw_size), fw->datasize - sizeof(*hdr)); 85412e36acbSWarner Losh return 0; 85512e36acbSWarner Losh } 85612e36acbSWarner Losh } 85712e36acbSWarner Losh 85812e36acbSWarner Losh if (hdr->fw_type != fw_type) { 8597a79cebfSGleb Smirnoff device_printf(sc->sc_dev, 8607a79cebfSGleb Smirnoff "invalid firmware (%s): type mismatch, " 86112e36acbSWarner Losh "fw \'%c\', target \'%c\'\n", fw->name, 86212e36acbSWarner Losh hdr->fw_type, fw_type); 86312e36acbSWarner Losh return 0; 86412e36acbSWarner Losh } 86512e36acbSWarner Losh 86612e36acbSWarner Losh if (hdr->fw_gen != BWI_FW_GEN_1) { 8677a79cebfSGleb Smirnoff device_printf(sc->sc_dev, 8687a79cebfSGleb Smirnoff "invalid firmware (%s): wrong generation, " 8697a79cebfSGleb Smirnoff "fw %d, target %d\n", fw->name, hdr->fw_gen, BWI_FW_GEN_1); 87012e36acbSWarner Losh return 0; 87112e36acbSWarner Losh } 87212e36acbSWarner Losh return 1; 87312e36acbSWarner Losh } 87412e36acbSWarner Losh 87512e36acbSWarner Losh /* 87612e36acbSWarner Losh * XXX Error cleanup 87712e36acbSWarner Losh */ 878c803f24bSGleb Smirnoff int 87912e36acbSWarner Losh bwi_mac_fw_alloc(struct bwi_mac *mac) 88012e36acbSWarner Losh { 88112e36acbSWarner Losh struct bwi_softc *sc = mac->mac_sc; 88212e36acbSWarner Losh char fwname[64]; 88312e36acbSWarner Losh int idx; 88412e36acbSWarner Losh 88512e36acbSWarner Losh /* 88612e36acbSWarner Losh * Try getting the firmware stub so firmware 88712e36acbSWarner Losh * module would be loaded automatically 88812e36acbSWarner Losh */ 88912e36acbSWarner Losh if (mac->mac_stub == NULL) { 89012e36acbSWarner Losh snprintf(fwname, sizeof(fwname), BWI_FW_STUB_PATH, 89112e36acbSWarner Losh sc->sc_fw_version); 89212e36acbSWarner Losh mac->mac_stub = firmware_get(fwname); 89315692978SGleb Smirnoff if (mac->mac_stub == NULL) 89415692978SGleb Smirnoff goto no_firmware; 89512e36acbSWarner Losh } 89612e36acbSWarner Losh 89712e36acbSWarner Losh if (mac->mac_ucode == NULL) { 89812e36acbSWarner Losh snprintf(fwname, sizeof(fwname), BWI_FW_UCODE_PATH, 89912e36acbSWarner Losh sc->sc_fw_version, 90012e36acbSWarner Losh mac->mac_rev >= 5 ? 5 : mac->mac_rev); 90112e36acbSWarner Losh 90212e36acbSWarner Losh mac->mac_ucode = firmware_get(fwname); 90315692978SGleb Smirnoff if (mac->mac_ucode == NULL) 90415692978SGleb Smirnoff goto no_firmware; 90512e36acbSWarner Losh if (!bwi_fwimage_is_valid(sc, mac->mac_ucode, BWI_FW_T_UCODE)) 90612e36acbSWarner Losh return EINVAL; 90712e36acbSWarner Losh } 90812e36acbSWarner Losh 90912e36acbSWarner Losh if (mac->mac_pcm == NULL) { 91012e36acbSWarner Losh snprintf(fwname, sizeof(fwname), BWI_FW_PCM_PATH, 91112e36acbSWarner Losh sc->sc_fw_version, 91212e36acbSWarner Losh mac->mac_rev < 5 ? 4 : 5); 91312e36acbSWarner Losh 91412e36acbSWarner Losh mac->mac_pcm = firmware_get(fwname); 91515692978SGleb Smirnoff if (mac->mac_pcm == NULL) 91615692978SGleb Smirnoff goto no_firmware; 91712e36acbSWarner Losh if (!bwi_fwimage_is_valid(sc, mac->mac_pcm, BWI_FW_T_PCM)) 91812e36acbSWarner Losh return EINVAL; 91912e36acbSWarner Losh } 92012e36acbSWarner Losh 92112e36acbSWarner Losh if (mac->mac_iv == NULL) { 92212e36acbSWarner Losh /* TODO: 11A */ 92312e36acbSWarner Losh if (mac->mac_rev == 2 || mac->mac_rev == 4) { 92412e36acbSWarner Losh idx = 2; 92512e36acbSWarner Losh } else if (mac->mac_rev >= 5 && mac->mac_rev <= 10) { 92612e36acbSWarner Losh idx = 5; 92712e36acbSWarner Losh } else { 92815692978SGleb Smirnoff device_printf(sc->sc_dev, 92915692978SGleb Smirnoff "no suitible IV for MAC rev %d\n", mac->mac_rev); 93012e36acbSWarner Losh return ENODEV; 93112e36acbSWarner Losh } 93212e36acbSWarner Losh 93312e36acbSWarner Losh snprintf(fwname, sizeof(fwname), BWI_FW_IV_PATH, 93412e36acbSWarner Losh sc->sc_fw_version, idx); 93512e36acbSWarner Losh 93612e36acbSWarner Losh mac->mac_iv = firmware_get(fwname); 93715692978SGleb Smirnoff if (mac->mac_iv == NULL) 93815692978SGleb Smirnoff goto no_firmware; 93912e36acbSWarner Losh if (!bwi_fwimage_is_valid(sc, mac->mac_iv, BWI_FW_T_IV)) 94012e36acbSWarner Losh return EINVAL; 94112e36acbSWarner Losh } 94212e36acbSWarner Losh 94312e36acbSWarner Losh if (mac->mac_iv_ext == NULL) { 94412e36acbSWarner Losh /* TODO: 11A */ 94512e36acbSWarner Losh if (mac->mac_rev == 2 || mac->mac_rev == 4 || 94612e36acbSWarner Losh mac->mac_rev >= 11) { 94712e36acbSWarner Losh /* No extended IV */ 94815692978SGleb Smirnoff return (0); 94912e36acbSWarner Losh } else if (mac->mac_rev >= 5 && mac->mac_rev <= 10) { 95012e36acbSWarner Losh idx = 5; 95112e36acbSWarner Losh } else { 95215692978SGleb Smirnoff device_printf(sc->sc_dev, 95315692978SGleb Smirnoff "no suitible ExtIV for MAC rev %d\n", mac->mac_rev); 95412e36acbSWarner Losh return ENODEV; 95512e36acbSWarner Losh } 95612e36acbSWarner Losh 95712e36acbSWarner Losh snprintf(fwname, sizeof(fwname), BWI_FW_IV_EXT_PATH, 95812e36acbSWarner Losh sc->sc_fw_version, idx); 95912e36acbSWarner Losh 96012e36acbSWarner Losh mac->mac_iv_ext = firmware_get(fwname); 96115692978SGleb Smirnoff if (mac->mac_iv_ext == NULL) 96215692978SGleb Smirnoff goto no_firmware; 96312e36acbSWarner Losh if (!bwi_fwimage_is_valid(sc, mac->mac_iv_ext, BWI_FW_T_IV)) 96412e36acbSWarner Losh return EINVAL; 96512e36acbSWarner Losh } 96615692978SGleb Smirnoff return (0); 96715692978SGleb Smirnoff 96815692978SGleb Smirnoff no_firmware: 96915692978SGleb Smirnoff device_printf(sc->sc_dev, "request firmware %s failed\n", fwname); 97015692978SGleb Smirnoff return (ENOENT); 97112e36acbSWarner Losh } 97212e36acbSWarner Losh 97312e36acbSWarner Losh static void 97412e36acbSWarner Losh bwi_mac_fw_free(struct bwi_mac *mac) 97512e36acbSWarner Losh { 97612e36acbSWarner Losh if (mac->mac_ucode != NULL) { 97712e36acbSWarner Losh firmware_put(mac->mac_ucode, FIRMWARE_UNLOAD); 97812e36acbSWarner Losh mac->mac_ucode = NULL; 97912e36acbSWarner Losh } 98012e36acbSWarner Losh 98112e36acbSWarner Losh if (mac->mac_pcm != NULL) { 98212e36acbSWarner Losh firmware_put(mac->mac_pcm, FIRMWARE_UNLOAD); 98312e36acbSWarner Losh mac->mac_pcm = NULL; 98412e36acbSWarner Losh } 98512e36acbSWarner Losh 98612e36acbSWarner Losh if (mac->mac_iv != NULL) { 98712e36acbSWarner Losh firmware_put(mac->mac_iv, FIRMWARE_UNLOAD); 98812e36acbSWarner Losh mac->mac_iv = NULL; 98912e36acbSWarner Losh } 99012e36acbSWarner Losh 99112e36acbSWarner Losh if (mac->mac_iv_ext != NULL) { 99212e36acbSWarner Losh firmware_put(mac->mac_iv_ext, FIRMWARE_UNLOAD); 99312e36acbSWarner Losh mac->mac_iv_ext = NULL; 99412e36acbSWarner Losh } 99512e36acbSWarner Losh 99612e36acbSWarner Losh if (mac->mac_stub != NULL) { 99712e36acbSWarner Losh firmware_put(mac->mac_stub, FIRMWARE_UNLOAD); 99812e36acbSWarner Losh mac->mac_stub = NULL; 99912e36acbSWarner Losh } 100012e36acbSWarner Losh } 100112e36acbSWarner Losh 100212e36acbSWarner Losh static int 100312e36acbSWarner Losh bwi_mac_fw_load(struct bwi_mac *mac) 100412e36acbSWarner Losh { 100512e36acbSWarner Losh struct bwi_softc *sc = mac->mac_sc; 100612e36acbSWarner Losh const uint32_t *fw; 100712e36acbSWarner Losh uint16_t fw_rev; 100812e36acbSWarner Losh int fw_len, i; 100912e36acbSWarner Losh 101012e36acbSWarner Losh /* 101112e36acbSWarner Losh * Load ucode image 101212e36acbSWarner Losh */ 101312e36acbSWarner Losh fw = (const uint32_t *) 101412e36acbSWarner Losh ((const uint8_t *)mac->mac_ucode->data + BWI_FWHDR_SZ); 101512e36acbSWarner Losh fw_len = (mac->mac_ucode->datasize - BWI_FWHDR_SZ) / sizeof(uint32_t); 101612e36acbSWarner Losh 101712e36acbSWarner Losh CSR_WRITE_4(sc, BWI_MOBJ_CTRL, 101812e36acbSWarner Losh BWI_MOBJ_CTRL_VAL( 101912e36acbSWarner Losh BWI_FW_UCODE_MOBJ | BWI_WR_MOBJ_AUTOINC, 0)); 102012e36acbSWarner Losh for (i = 0; i < fw_len; ++i) { 102112e36acbSWarner Losh CSR_WRITE_4(sc, BWI_MOBJ_DATA, be32toh(fw[i])); 102212e36acbSWarner Losh DELAY(10); 102312e36acbSWarner Losh } 102412e36acbSWarner Losh 102512e36acbSWarner Losh /* 102612e36acbSWarner Losh * Load PCM image 102712e36acbSWarner Losh */ 102812e36acbSWarner Losh fw = (const uint32_t *) 102912e36acbSWarner Losh ((const uint8_t *)mac->mac_pcm->data + BWI_FWHDR_SZ); 103012e36acbSWarner Losh fw_len = (mac->mac_pcm->datasize - BWI_FWHDR_SZ) / sizeof(uint32_t); 103112e36acbSWarner Losh 103212e36acbSWarner Losh CSR_WRITE_4(sc, BWI_MOBJ_CTRL, 103312e36acbSWarner Losh BWI_MOBJ_CTRL_VAL(BWI_FW_PCM_MOBJ, 0x01ea)); 103412e36acbSWarner Losh CSR_WRITE_4(sc, BWI_MOBJ_DATA, 0x4000); 103512e36acbSWarner Losh 103612e36acbSWarner Losh CSR_WRITE_4(sc, BWI_MOBJ_CTRL, 103712e36acbSWarner Losh BWI_MOBJ_CTRL_VAL(BWI_FW_PCM_MOBJ, 0x01eb)); 103812e36acbSWarner Losh for (i = 0; i < fw_len; ++i) { 103912e36acbSWarner Losh CSR_WRITE_4(sc, BWI_MOBJ_DATA, be32toh(fw[i])); 104012e36acbSWarner Losh DELAY(10); 104112e36acbSWarner Losh } 104212e36acbSWarner Losh 104312e36acbSWarner Losh CSR_WRITE_4(sc, BWI_MAC_INTR_STATUS, BWI_ALL_INTRS); 104412e36acbSWarner Losh CSR_WRITE_4(sc, BWI_MAC_STATUS, 104512e36acbSWarner Losh BWI_MAC_STATUS_UCODE_START | 104612e36acbSWarner Losh BWI_MAC_STATUS_IHREN | 104712e36acbSWarner Losh BWI_MAC_STATUS_INFRA); 104812e36acbSWarner Losh 104912e36acbSWarner Losh #define NRETRY 200 105012e36acbSWarner Losh 105112e36acbSWarner Losh for (i = 0; i < NRETRY; ++i) { 105212e36acbSWarner Losh uint32_t intr_status; 105312e36acbSWarner Losh 105412e36acbSWarner Losh intr_status = CSR_READ_4(sc, BWI_MAC_INTR_STATUS); 105512e36acbSWarner Losh if (intr_status == BWI_INTR_READY) 105612e36acbSWarner Losh break; 105712e36acbSWarner Losh DELAY(10); 105812e36acbSWarner Losh } 105912e36acbSWarner Losh if (i == NRETRY) { 10607a79cebfSGleb Smirnoff device_printf(sc->sc_dev, 10617a79cebfSGleb Smirnoff "firmware (ucode&pcm) loading timed out\n"); 106212e36acbSWarner Losh return ETIMEDOUT; 106312e36acbSWarner Losh } 106412e36acbSWarner Losh 106512e36acbSWarner Losh #undef NRETRY 106612e36acbSWarner Losh 106712e36acbSWarner Losh CSR_READ_4(sc, BWI_MAC_INTR_STATUS); /* dummy read */ 106812e36acbSWarner Losh 106912e36acbSWarner Losh fw_rev = MOBJ_READ_2(mac, BWI_COMM_MOBJ, BWI_COMM_MOBJ_FWREV); 107012e36acbSWarner Losh if (fw_rev > BWI_FW_VERSION3_REVMAX) { 10717a79cebfSGleb Smirnoff device_printf(sc->sc_dev, 10727a79cebfSGleb Smirnoff "firmware version 4 is not supported yet\n"); 107312e36acbSWarner Losh return ENODEV; 107412e36acbSWarner Losh } 107512e36acbSWarner Losh 10767a79cebfSGleb Smirnoff device_printf(sc->sc_dev, 10777a79cebfSGleb Smirnoff "firmware rev 0x%04x, patch level 0x%04x\n", fw_rev, 107812e36acbSWarner Losh MOBJ_READ_2(mac, BWI_COMM_MOBJ, BWI_COMM_MOBJ_FWPATCHLV)); 107912e36acbSWarner Losh return 0; 108012e36acbSWarner Losh } 108112e36acbSWarner Losh 108212e36acbSWarner Losh static int 108312e36acbSWarner Losh bwi_mac_gpio_init(struct bwi_mac *mac) 108412e36acbSWarner Losh { 108512e36acbSWarner Losh struct bwi_softc *sc = mac->mac_sc; 108612e36acbSWarner Losh struct bwi_regwin *old, *gpio_rw; 108712e36acbSWarner Losh uint32_t filt, bits; 108812e36acbSWarner Losh int error; 108912e36acbSWarner Losh 109012e36acbSWarner Losh CSR_CLRBITS_4(sc, BWI_MAC_STATUS, BWI_MAC_STATUS_GPOSEL_MASK); 109112e36acbSWarner Losh /* TODO:LED */ 109212e36acbSWarner Losh 109312e36acbSWarner Losh CSR_SETBITS_2(sc, BWI_MAC_GPIO_MASK, 0xf); 109412e36acbSWarner Losh 109512e36acbSWarner Losh filt = 0x1f; 109612e36acbSWarner Losh bits = 0xf; 109712e36acbSWarner Losh if (sc->sc_bbp_id == BWI_BBPID_BCM4301) { 109812e36acbSWarner Losh filt |= 0x60; 109912e36acbSWarner Losh bits |= 0x60; 110012e36acbSWarner Losh } 110112e36acbSWarner Losh if (sc->sc_card_flags & BWI_CARD_F_PA_GPIO9) { 110212e36acbSWarner Losh CSR_SETBITS_2(sc, BWI_MAC_GPIO_MASK, 0x200); 110312e36acbSWarner Losh filt |= 0x200; 110412e36acbSWarner Losh bits |= 0x200; 110512e36acbSWarner Losh } 110612e36acbSWarner Losh 110712e36acbSWarner Losh gpio_rw = BWI_GPIO_REGWIN(sc); 110812e36acbSWarner Losh error = bwi_regwin_switch(sc, gpio_rw, &old); 110912e36acbSWarner Losh if (error) 111012e36acbSWarner Losh return error; 111112e36acbSWarner Losh 111212e36acbSWarner Losh CSR_FILT_SETBITS_4(sc, BWI_GPIO_CTRL, filt, bits); 111312e36acbSWarner Losh 111412e36acbSWarner Losh return bwi_regwin_switch(sc, old, NULL); 111512e36acbSWarner Losh } 111612e36acbSWarner Losh 111712e36acbSWarner Losh static int 111812e36acbSWarner Losh bwi_mac_gpio_fini(struct bwi_mac *mac) 111912e36acbSWarner Losh { 112012e36acbSWarner Losh struct bwi_softc *sc = mac->mac_sc; 112112e36acbSWarner Losh struct bwi_regwin *old, *gpio_rw; 112212e36acbSWarner Losh int error; 112312e36acbSWarner Losh 112412e36acbSWarner Losh gpio_rw = BWI_GPIO_REGWIN(sc); 112512e36acbSWarner Losh error = bwi_regwin_switch(sc, gpio_rw, &old); 112612e36acbSWarner Losh if (error) 112712e36acbSWarner Losh return error; 112812e36acbSWarner Losh 112912e36acbSWarner Losh CSR_WRITE_4(sc, BWI_GPIO_CTRL, 0); 113012e36acbSWarner Losh 113112e36acbSWarner Losh return bwi_regwin_switch(sc, old, NULL); 113212e36acbSWarner Losh } 113312e36acbSWarner Losh 113412e36acbSWarner Losh static int 113512e36acbSWarner Losh bwi_mac_fw_load_iv(struct bwi_mac *mac, const struct firmware *fw) 113612e36acbSWarner Losh { 113712e36acbSWarner Losh struct bwi_softc *sc = mac->mac_sc; 113812e36acbSWarner Losh const struct bwi_fwhdr *hdr; 113912e36acbSWarner Losh const struct bwi_fw_iv *iv; 114012e36acbSWarner Losh int n, i, iv_img_size; 114112e36acbSWarner Losh 114212e36acbSWarner Losh /* Get the number of IVs in the IV image */ 114312e36acbSWarner Losh hdr = (const struct bwi_fwhdr *)fw->data; 114412e36acbSWarner Losh n = be32toh(hdr->fw_iv_cnt); 114512e36acbSWarner Losh DPRINTF(sc, BWI_DBG_MAC | BWI_DBG_INIT | BWI_DBG_FIRMWARE, 114612e36acbSWarner Losh "IV count %d\n", n); 114712e36acbSWarner Losh 114812e36acbSWarner Losh /* Calculate the IV image size, for later sanity check */ 114912e36acbSWarner Losh iv_img_size = fw->datasize - sizeof(*hdr); 115012e36acbSWarner Losh 115112e36acbSWarner Losh /* Locate the first IV */ 115212e36acbSWarner Losh iv = (const struct bwi_fw_iv *) 115312e36acbSWarner Losh ((const uint8_t *)fw->data + sizeof(*hdr)); 115412e36acbSWarner Losh 115512e36acbSWarner Losh for (i = 0; i < n; ++i) { 115612e36acbSWarner Losh uint16_t iv_ofs, ofs; 115712e36acbSWarner Losh int sz = 0; 115812e36acbSWarner Losh 115912e36acbSWarner Losh if (iv_img_size < sizeof(iv->iv_ofs)) { 11607a79cebfSGleb Smirnoff device_printf(sc->sc_dev, "invalid IV image, ofs\n"); 116112e36acbSWarner Losh return EINVAL; 116212e36acbSWarner Losh } 116312e36acbSWarner Losh iv_img_size -= sizeof(iv->iv_ofs); 116412e36acbSWarner Losh sz += sizeof(iv->iv_ofs); 116512e36acbSWarner Losh 116612e36acbSWarner Losh iv_ofs = be16toh(iv->iv_ofs); 116712e36acbSWarner Losh 116812e36acbSWarner Losh ofs = __SHIFTOUT(iv_ofs, BWI_FW_IV_OFS_MASK); 116912e36acbSWarner Losh if (ofs >= 0x1000) { 11707a79cebfSGleb Smirnoff device_printf(sc->sc_dev, "invalid ofs (0x%04x) " 117112e36acbSWarner Losh "for %dth iv\n", ofs, i); 117212e36acbSWarner Losh return EINVAL; 117312e36acbSWarner Losh } 117412e36acbSWarner Losh 117512e36acbSWarner Losh if (iv_ofs & BWI_FW_IV_IS_32BIT) { 117612e36acbSWarner Losh uint32_t val32; 117712e36acbSWarner Losh 117812e36acbSWarner Losh if (iv_img_size < sizeof(iv->iv_val.val32)) { 11797a79cebfSGleb Smirnoff device_printf(sc->sc_dev, 11807a79cebfSGleb Smirnoff "invalid IV image, val32\n"); 118112e36acbSWarner Losh return EINVAL; 118212e36acbSWarner Losh } 118312e36acbSWarner Losh iv_img_size -= sizeof(iv->iv_val.val32); 118412e36acbSWarner Losh sz += sizeof(iv->iv_val.val32); 118512e36acbSWarner Losh 118612e36acbSWarner Losh val32 = be32toh(iv->iv_val.val32); 118712e36acbSWarner Losh CSR_WRITE_4(sc, ofs, val32); 118812e36acbSWarner Losh } else { 118912e36acbSWarner Losh uint16_t val16; 119012e36acbSWarner Losh 119112e36acbSWarner Losh if (iv_img_size < sizeof(iv->iv_val.val16)) { 11927a79cebfSGleb Smirnoff device_printf(sc->sc_dev, 11937a79cebfSGleb Smirnoff "invalid IV image, val16\n"); 119412e36acbSWarner Losh return EINVAL; 119512e36acbSWarner Losh } 119612e36acbSWarner Losh iv_img_size -= sizeof(iv->iv_val.val16); 119712e36acbSWarner Losh sz += sizeof(iv->iv_val.val16); 119812e36acbSWarner Losh 119912e36acbSWarner Losh val16 = be16toh(iv->iv_val.val16); 120012e36acbSWarner Losh CSR_WRITE_2(sc, ofs, val16); 120112e36acbSWarner Losh } 120212e36acbSWarner Losh 120312e36acbSWarner Losh iv = (const struct bwi_fw_iv *)((const uint8_t *)iv + sz); 120412e36acbSWarner Losh } 120512e36acbSWarner Losh 120612e36acbSWarner Losh if (iv_img_size != 0) { 12077a79cebfSGleb Smirnoff device_printf(sc->sc_dev, "invalid IV image, size left %d\n", 12087a79cebfSGleb Smirnoff iv_img_size); 120912e36acbSWarner Losh return EINVAL; 121012e36acbSWarner Losh } 121112e36acbSWarner Losh return 0; 121212e36acbSWarner Losh } 121312e36acbSWarner Losh 121412e36acbSWarner Losh static int 121512e36acbSWarner Losh bwi_mac_fw_init(struct bwi_mac *mac) 121612e36acbSWarner Losh { 12177a79cebfSGleb Smirnoff device_t dev = mac->mac_sc->sc_dev; 121812e36acbSWarner Losh int error; 121912e36acbSWarner Losh 122012e36acbSWarner Losh error = bwi_mac_fw_load_iv(mac, mac->mac_iv); 122112e36acbSWarner Losh if (error) { 12227a79cebfSGleb Smirnoff device_printf(dev, "load IV failed\n"); 122312e36acbSWarner Losh return error; 122412e36acbSWarner Losh } 122512e36acbSWarner Losh 122612e36acbSWarner Losh if (mac->mac_iv_ext != NULL) { 122712e36acbSWarner Losh error = bwi_mac_fw_load_iv(mac, mac->mac_iv_ext); 122812e36acbSWarner Losh if (error) 12297a79cebfSGleb Smirnoff device_printf(dev, "load ExtIV failed\n"); 123012e36acbSWarner Losh } 123112e36acbSWarner Losh return error; 123212e36acbSWarner Losh } 123312e36acbSWarner Losh 123412e36acbSWarner Losh static void 123512e36acbSWarner Losh bwi_mac_opmode_init(struct bwi_mac *mac) 123612e36acbSWarner Losh { 123712e36acbSWarner Losh struct bwi_softc *sc = mac->mac_sc; 12387a79cebfSGleb Smirnoff struct ieee80211com *ic = &sc->sc_ic; 123912e36acbSWarner Losh uint32_t mac_status; 124012e36acbSWarner Losh uint16_t pre_tbtt; 124112e36acbSWarner Losh 124212e36acbSWarner Losh CSR_CLRBITS_4(sc, BWI_MAC_STATUS, BWI_MAC_STATUS_INFRA); 124312e36acbSWarner Losh CSR_SETBITS_4(sc, BWI_MAC_STATUS, BWI_MAC_STATUS_INFRA); 124412e36acbSWarner Losh 124512e36acbSWarner Losh /* Set probe resp timeout to infinite */ 124612e36acbSWarner Losh MOBJ_WRITE_2(mac, BWI_COMM_MOBJ, BWI_COMM_MOBJ_PROBE_RESP_TO, 0); 124712e36acbSWarner Losh 124812e36acbSWarner Losh /* 124912e36acbSWarner Losh * TODO: factor out following part 125012e36acbSWarner Losh */ 125112e36acbSWarner Losh 125212e36acbSWarner Losh mac_status = CSR_READ_4(sc, BWI_MAC_STATUS); 125312e36acbSWarner Losh mac_status &= ~(BWI_MAC_STATUS_OPMODE_HOSTAP | 125412e36acbSWarner Losh BWI_MAC_STATUS_PASS_CTL | 125512e36acbSWarner Losh BWI_MAC_STATUS_PASS_BCN | 125612e36acbSWarner Losh BWI_MAC_STATUS_PASS_BADPLCP | 125712e36acbSWarner Losh BWI_MAC_STATUS_PASS_BADFCS | 125812e36acbSWarner Losh BWI_MAC_STATUS_PROMISC); 125912e36acbSWarner Losh mac_status |= BWI_MAC_STATUS_INFRA; 126012e36acbSWarner Losh 126112e36acbSWarner Losh /* Always turn on PROMISC on old hardware */ 126212e36acbSWarner Losh if (mac->mac_rev < 5) 126312e36acbSWarner Losh mac_status |= BWI_MAC_STATUS_PROMISC; 126412e36acbSWarner Losh 126512e36acbSWarner Losh switch (ic->ic_opmode) { 126612e36acbSWarner Losh case IEEE80211_M_IBSS: 126712e36acbSWarner Losh mac_status &= ~BWI_MAC_STATUS_INFRA; 126812e36acbSWarner Losh break; 126912e36acbSWarner Losh case IEEE80211_M_HOSTAP: 127012e36acbSWarner Losh mac_status |= BWI_MAC_STATUS_OPMODE_HOSTAP; 127112e36acbSWarner Losh break; 127212e36acbSWarner Losh case IEEE80211_M_MONITOR: 127312e36acbSWarner Losh #if 0 127412e36acbSWarner Losh /* Do you want data from your microwave oven? */ 127512e36acbSWarner Losh mac_status |= BWI_MAC_STATUS_PASS_CTL | 127612e36acbSWarner Losh BWI_MAC_STATUS_PASS_BADPLCP | 127712e36acbSWarner Losh BWI_MAC_STATUS_PASS_BADFCS; 127812e36acbSWarner Losh #else 127912e36acbSWarner Losh mac_status |= BWI_MAC_STATUS_PASS_CTL; 128012e36acbSWarner Losh #endif 128112e36acbSWarner Losh /* Promisc? */ 128212e36acbSWarner Losh break; 128312e36acbSWarner Losh default: 128412e36acbSWarner Losh break; 128512e36acbSWarner Losh } 128612e36acbSWarner Losh 12877a79cebfSGleb Smirnoff if (ic->ic_promisc > 0) 128812e36acbSWarner Losh mac_status |= BWI_MAC_STATUS_PROMISC; 128912e36acbSWarner Losh 129012e36acbSWarner Losh CSR_WRITE_4(sc, BWI_MAC_STATUS, mac_status); 129112e36acbSWarner Losh 129212e36acbSWarner Losh if (ic->ic_opmode != IEEE80211_M_IBSS && 129312e36acbSWarner Losh ic->ic_opmode != IEEE80211_M_HOSTAP) { 129412e36acbSWarner Losh if (sc->sc_bbp_id == BWI_BBPID_BCM4306 && sc->sc_bbp_rev == 3) 129512e36acbSWarner Losh pre_tbtt = 100; 129612e36acbSWarner Losh else 129712e36acbSWarner Losh pre_tbtt = 50; 129812e36acbSWarner Losh } else { 129912e36acbSWarner Losh pre_tbtt = 2; 130012e36acbSWarner Losh } 130112e36acbSWarner Losh CSR_WRITE_2(sc, BWI_MAC_PRE_TBTT, pre_tbtt); 130212e36acbSWarner Losh } 130312e36acbSWarner Losh 130412e36acbSWarner Losh static void 130512e36acbSWarner Losh bwi_mac_hostflags_init(struct bwi_mac *mac) 130612e36acbSWarner Losh { 130712e36acbSWarner Losh struct bwi_softc *sc = mac->mac_sc; 130812e36acbSWarner Losh struct bwi_phy *phy = &mac->mac_phy; 130912e36acbSWarner Losh struct bwi_rf *rf = &mac->mac_rf; 131012e36acbSWarner Losh uint64_t host_flags; 131112e36acbSWarner Losh 131212e36acbSWarner Losh if (phy->phy_mode == IEEE80211_MODE_11A) 131312e36acbSWarner Losh return; 131412e36acbSWarner Losh 131512e36acbSWarner Losh host_flags = HFLAGS_READ(mac); 131612e36acbSWarner Losh host_flags |= BWI_HFLAG_SYM_WA; 131712e36acbSWarner Losh 131812e36acbSWarner Losh if (phy->phy_mode == IEEE80211_MODE_11G) { 131912e36acbSWarner Losh if (phy->phy_rev == 1) 132012e36acbSWarner Losh host_flags |= BWI_HFLAG_GDC_WA; 132112e36acbSWarner Losh if (sc->sc_card_flags & BWI_CARD_F_PA_GPIO9) 132212e36acbSWarner Losh host_flags |= BWI_HFLAG_OFDM_PA; 132312e36acbSWarner Losh } else if (phy->phy_mode == IEEE80211_MODE_11B) { 132412e36acbSWarner Losh if (phy->phy_rev >= 2 && rf->rf_type == BWI_RF_T_BCM2050) 132512e36acbSWarner Losh host_flags &= ~BWI_HFLAG_GDC_WA; 132612e36acbSWarner Losh } else { 132712e36acbSWarner Losh panic("unknown PHY mode %u\n", phy->phy_mode); 132812e36acbSWarner Losh } 132912e36acbSWarner Losh 133012e36acbSWarner Losh HFLAGS_WRITE(mac, host_flags); 133112e36acbSWarner Losh } 133212e36acbSWarner Losh 133312e36acbSWarner Losh static void 133412e36acbSWarner Losh bwi_mac_bss_param_init(struct bwi_mac *mac) 133512e36acbSWarner Losh { 133612e36acbSWarner Losh struct bwi_softc *sc = mac->mac_sc; 133712e36acbSWarner Losh struct bwi_phy *phy = &mac->mac_phy; 13387a79cebfSGleb Smirnoff struct ieee80211com *ic = &sc->sc_ic; 133912e36acbSWarner Losh const struct ieee80211_rate_table *rt; 134012e36acbSWarner Losh struct bwi_retry_lim lim; 134112e36acbSWarner Losh uint16_t cw_min; 134212e36acbSWarner Losh 134312e36acbSWarner Losh /* 134412e36acbSWarner Losh * Set short/long retry limits 134512e36acbSWarner Losh */ 134612e36acbSWarner Losh bzero(&lim, sizeof(lim)); 134712e36acbSWarner Losh lim.shretry = BWI_SHRETRY; 134812e36acbSWarner Losh lim.shretry_fb = BWI_SHRETRY_FB; 134912e36acbSWarner Losh lim.lgretry = BWI_LGRETRY; 135012e36acbSWarner Losh lim.lgretry_fb = BWI_LGRETRY_FB; 135112e36acbSWarner Losh bwi_mac_set_retry_lim(mac, &lim); 135212e36acbSWarner Losh 135312e36acbSWarner Losh /* 135412e36acbSWarner Losh * Implicitly prevent firmware from sending probe response 135512e36acbSWarner Losh * by setting its "probe response timeout" to 1us. 135612e36acbSWarner Losh */ 135712e36acbSWarner Losh MOBJ_WRITE_2(mac, BWI_COMM_MOBJ, BWI_COMM_MOBJ_PROBE_RESP_TO, 1); 135812e36acbSWarner Losh 135912e36acbSWarner Losh /* 136012e36acbSWarner Losh * XXX MAC level acknowledge and CW min/max should depend 136112e36acbSWarner Losh * on the char rateset of the IBSS/BSS to join. 136212e36acbSWarner Losh * XXX this is all wrong; should be done on channel change 136312e36acbSWarner Losh */ 136412e36acbSWarner Losh if (phy->phy_mode == IEEE80211_MODE_11B) { 136512e36acbSWarner Losh rt = ieee80211_get_ratetable( 136612e36acbSWarner Losh ieee80211_find_channel(ic, 2412, IEEE80211_CHAN_B)); 136712e36acbSWarner Losh bwi_mac_set_ackrates(mac, rt, 136812e36acbSWarner Losh &ic->ic_sup_rates[IEEE80211_MODE_11B]); 136912e36acbSWarner Losh } else { 137012e36acbSWarner Losh rt = ieee80211_get_ratetable( 137112e36acbSWarner Losh ieee80211_find_channel(ic, 2412, IEEE80211_CHAN_G)); 137212e36acbSWarner Losh bwi_mac_set_ackrates(mac, rt, 137312e36acbSWarner Losh &ic->ic_sup_rates[IEEE80211_MODE_11G]); 137412e36acbSWarner Losh } 137512e36acbSWarner Losh 137612e36acbSWarner Losh /* 137712e36acbSWarner Losh * Set CW min 137812e36acbSWarner Losh */ 137912e36acbSWarner Losh if (phy->phy_mode == IEEE80211_MODE_11B) 138012e36acbSWarner Losh cw_min = IEEE80211_CW_MIN_0; 138112e36acbSWarner Losh else 138212e36acbSWarner Losh cw_min = IEEE80211_CW_MIN_1; 138312e36acbSWarner Losh MOBJ_WRITE_2(mac, BWI_80211_MOBJ, BWI_80211_MOBJ_CWMIN, cw_min); 138412e36acbSWarner Losh 138512e36acbSWarner Losh /* 138612e36acbSWarner Losh * Set CW max 138712e36acbSWarner Losh */ 138812e36acbSWarner Losh MOBJ_WRITE_2(mac, BWI_80211_MOBJ, BWI_80211_MOBJ_CWMAX, 138912e36acbSWarner Losh IEEE80211_CW_MAX); 139012e36acbSWarner Losh } 139112e36acbSWarner Losh 139212e36acbSWarner Losh static void 139312e36acbSWarner Losh bwi_mac_set_retry_lim(struct bwi_mac *mac, const struct bwi_retry_lim *lim) 139412e36acbSWarner Losh { 139512e36acbSWarner Losh /* Short/Long retry limit */ 139612e36acbSWarner Losh MOBJ_WRITE_2(mac, BWI_80211_MOBJ, BWI_80211_MOBJ_SHRETRY, 139712e36acbSWarner Losh lim->shretry); 139812e36acbSWarner Losh MOBJ_WRITE_2(mac, BWI_80211_MOBJ, BWI_80211_MOBJ_LGRETRY, 139912e36acbSWarner Losh lim->lgretry); 140012e36acbSWarner Losh 140112e36acbSWarner Losh /* Short/Long retry fallback limit */ 140212e36acbSWarner Losh MOBJ_WRITE_2(mac, BWI_COMM_MOBJ, BWI_COMM_MOBJ_SHRETRY_FB, 140312e36acbSWarner Losh lim->shretry_fb); 140412e36acbSWarner Losh MOBJ_WRITE_2(mac, BWI_COMM_MOBJ, BWI_COMM_MOBJ_LGRETEY_FB, 140512e36acbSWarner Losh lim->lgretry_fb); 140612e36acbSWarner Losh } 140712e36acbSWarner Losh 140812e36acbSWarner Losh static void 140912e36acbSWarner Losh bwi_mac_set_ackrates(struct bwi_mac *mac, const struct ieee80211_rate_table *rt, 141012e36acbSWarner Losh const struct ieee80211_rateset *rs) 141112e36acbSWarner Losh { 141212e36acbSWarner Losh int i; 141312e36acbSWarner Losh 141412e36acbSWarner Losh /* XXX not standard conforming */ 141512e36acbSWarner Losh for (i = 0; i < rs->rs_nrates; ++i) { 141612e36acbSWarner Losh enum ieee80211_phytype modtype; 141712e36acbSWarner Losh uint16_t ofs; 141812e36acbSWarner Losh 1419a1df5ac1SAdrian Chadd modtype = ieee80211_rate2phytype(rt, 1420a1df5ac1SAdrian Chadd rs->rs_rates[i] & IEEE80211_RATE_VAL); 142112e36acbSWarner Losh switch (modtype) { 142212e36acbSWarner Losh case IEEE80211_T_DS: 142312e36acbSWarner Losh ofs = 0x4c0; 142412e36acbSWarner Losh break; 142512e36acbSWarner Losh case IEEE80211_T_OFDM: 142612e36acbSWarner Losh ofs = 0x480; 142712e36acbSWarner Losh break; 142812e36acbSWarner Losh default: 142912e36acbSWarner Losh panic("unsupported modtype %u\n", modtype); 143012e36acbSWarner Losh } 1431a1df5ac1SAdrian Chadd ofs += 2*(ieee80211_rate2plcp( 1432a1df5ac1SAdrian Chadd rs->rs_rates[i] & IEEE80211_RATE_VAL, 1433a1df5ac1SAdrian Chadd modtype) & 0xf); 143412e36acbSWarner Losh 143512e36acbSWarner Losh MOBJ_WRITE_2(mac, BWI_COMM_MOBJ, ofs + 0x20, 143612e36acbSWarner Losh MOBJ_READ_2(mac, BWI_COMM_MOBJ, ofs)); 143712e36acbSWarner Losh } 143812e36acbSWarner Losh } 143912e36acbSWarner Losh 144012e36acbSWarner Losh int 144112e36acbSWarner Losh bwi_mac_start(struct bwi_mac *mac) 144212e36acbSWarner Losh { 144312e36acbSWarner Losh struct bwi_softc *sc = mac->mac_sc; 144412e36acbSWarner Losh 144512e36acbSWarner Losh CSR_SETBITS_4(sc, BWI_MAC_STATUS, BWI_MAC_STATUS_ENABLE); 144612e36acbSWarner Losh CSR_WRITE_4(sc, BWI_MAC_INTR_STATUS, BWI_INTR_READY); 144712e36acbSWarner Losh 144812e36acbSWarner Losh /* Flush pending bus writes */ 144912e36acbSWarner Losh CSR_READ_4(sc, BWI_MAC_STATUS); 145012e36acbSWarner Losh CSR_READ_4(sc, BWI_MAC_INTR_STATUS); 145112e36acbSWarner Losh 145212e36acbSWarner Losh return bwi_mac_config_ps(mac); 145312e36acbSWarner Losh } 145412e36acbSWarner Losh 145512e36acbSWarner Losh int 145612e36acbSWarner Losh bwi_mac_stop(struct bwi_mac *mac) 145712e36acbSWarner Losh { 145812e36acbSWarner Losh struct bwi_softc *sc = mac->mac_sc; 145912e36acbSWarner Losh int error, i; 146012e36acbSWarner Losh 146112e36acbSWarner Losh error = bwi_mac_config_ps(mac); 146212e36acbSWarner Losh if (error) 146312e36acbSWarner Losh return error; 146412e36acbSWarner Losh 146512e36acbSWarner Losh CSR_CLRBITS_4(sc, BWI_MAC_STATUS, BWI_MAC_STATUS_ENABLE); 146612e36acbSWarner Losh 146712e36acbSWarner Losh /* Flush pending bus write */ 146812e36acbSWarner Losh CSR_READ_4(sc, BWI_MAC_STATUS); 146912e36acbSWarner Losh 147012e36acbSWarner Losh #define NRETRY 10000 147112e36acbSWarner Losh for (i = 0; i < NRETRY; ++i) { 147212e36acbSWarner Losh if (CSR_READ_4(sc, BWI_MAC_INTR_STATUS) & BWI_INTR_READY) 147312e36acbSWarner Losh break; 147412e36acbSWarner Losh DELAY(1); 147512e36acbSWarner Losh } 147612e36acbSWarner Losh if (i == NRETRY) { 147712e36acbSWarner Losh device_printf(sc->sc_dev, "can't stop MAC\n"); 147812e36acbSWarner Losh return ETIMEDOUT; 147912e36acbSWarner Losh } 148012e36acbSWarner Losh #undef NRETRY 148112e36acbSWarner Losh 148212e36acbSWarner Losh return 0; 148312e36acbSWarner Losh } 148412e36acbSWarner Losh 148512e36acbSWarner Losh int 148612e36acbSWarner Losh bwi_mac_config_ps(struct bwi_mac *mac) 148712e36acbSWarner Losh { 148812e36acbSWarner Losh struct bwi_softc *sc = mac->mac_sc; 148912e36acbSWarner Losh uint32_t status; 149012e36acbSWarner Losh 149112e36acbSWarner Losh status = CSR_READ_4(sc, BWI_MAC_STATUS); 149212e36acbSWarner Losh 149312e36acbSWarner Losh status &= ~BWI_MAC_STATUS_HW_PS; 149412e36acbSWarner Losh status |= BWI_MAC_STATUS_WAKEUP; 149512e36acbSWarner Losh CSR_WRITE_4(sc, BWI_MAC_STATUS, status); 149612e36acbSWarner Losh 149712e36acbSWarner Losh /* Flush pending bus write */ 149812e36acbSWarner Losh CSR_READ_4(sc, BWI_MAC_STATUS); 149912e36acbSWarner Losh 150012e36acbSWarner Losh if (mac->mac_rev >= 5) { 150112e36acbSWarner Losh int i; 150212e36acbSWarner Losh 150312e36acbSWarner Losh #define NRETRY 100 150412e36acbSWarner Losh for (i = 0; i < NRETRY; ++i) { 150512e36acbSWarner Losh if (MOBJ_READ_2(mac, BWI_COMM_MOBJ, 150612e36acbSWarner Losh BWI_COMM_MOBJ_UCODE_STATE) != BWI_UCODE_STATE_PS) 150712e36acbSWarner Losh break; 150812e36acbSWarner Losh DELAY(10); 150912e36acbSWarner Losh } 151012e36acbSWarner Losh if (i == NRETRY) { 151112e36acbSWarner Losh device_printf(sc->sc_dev, "config PS failed\n"); 151212e36acbSWarner Losh return ETIMEDOUT; 151312e36acbSWarner Losh } 151412e36acbSWarner Losh #undef NRETRY 151512e36acbSWarner Losh } 151612e36acbSWarner Losh return 0; 151712e36acbSWarner Losh } 151812e36acbSWarner Losh 151912e36acbSWarner Losh void 152012e36acbSWarner Losh bwi_mac_reset_hwkeys(struct bwi_mac *mac) 152112e36acbSWarner Losh { 152212e36acbSWarner Losh /* TODO: firmware crypto */ 152312e36acbSWarner Losh MOBJ_READ_2(mac, BWI_COMM_MOBJ, BWI_COMM_MOBJ_KEYTABLE_OFS); 152412e36acbSWarner Losh } 152512e36acbSWarner Losh 152612e36acbSWarner Losh void 152712e36acbSWarner Losh bwi_mac_shutdown(struct bwi_mac *mac) 152812e36acbSWarner Losh { 152912e36acbSWarner Losh struct bwi_softc *sc = mac->mac_sc; 153012e36acbSWarner Losh int i; 153112e36acbSWarner Losh 153212e36acbSWarner Losh if (mac->mac_flags & BWI_MAC_F_HAS_TXSTATS) 153312e36acbSWarner Losh sc->sc_free_txstats(sc); 153412e36acbSWarner Losh 153512e36acbSWarner Losh sc->sc_free_rx_ring(sc); 153612e36acbSWarner Losh 153712e36acbSWarner Losh for (i = 0; i < BWI_TX_NRING; ++i) 153812e36acbSWarner Losh sc->sc_free_tx_ring(sc, i); 153912e36acbSWarner Losh 154012e36acbSWarner Losh bwi_rf_off(mac); 154112e36acbSWarner Losh 154212e36acbSWarner Losh /* TODO:LED */ 154312e36acbSWarner Losh 154412e36acbSWarner Losh bwi_mac_gpio_fini(mac); 154512e36acbSWarner Losh 154612e36acbSWarner Losh bwi_rf_off(mac); /* XXX again */ 154712e36acbSWarner Losh CSR_WRITE_2(sc, BWI_BBP_ATTEN, BWI_BBP_ATTEN_MAGIC); 154812e36acbSWarner Losh bwi_regwin_disable(sc, &mac->mac_regwin, 0); 154912e36acbSWarner Losh 155012e36acbSWarner Losh mac->mac_flags &= ~BWI_MAC_F_INITED; 155112e36acbSWarner Losh } 155212e36acbSWarner Losh 155312e36acbSWarner Losh static int 155412e36acbSWarner Losh bwi_mac_get_property(struct bwi_mac *mac) 155512e36acbSWarner Losh { 155612e36acbSWarner Losh struct bwi_softc *sc = mac->mac_sc; 155712e36acbSWarner Losh enum bwi_bus_space old_bus_space; 155812e36acbSWarner Losh uint32_t val; 155912e36acbSWarner Losh 156012e36acbSWarner Losh /* 156112e36acbSWarner Losh * Byte swap 156212e36acbSWarner Losh */ 156312e36acbSWarner Losh val = CSR_READ_4(sc, BWI_MAC_STATUS); 156412e36acbSWarner Losh if (val & BWI_MAC_STATUS_BSWAP) { 156512e36acbSWarner Losh DPRINTF(sc, BWI_DBG_MAC | BWI_DBG_ATTACH, "%s\n", 156612e36acbSWarner Losh "need byte swap"); 156712e36acbSWarner Losh mac->mac_flags |= BWI_MAC_F_BSWAP; 156812e36acbSWarner Losh } 156912e36acbSWarner Losh 157012e36acbSWarner Losh /* 157112e36acbSWarner Losh * DMA address space 157212e36acbSWarner Losh */ 157312e36acbSWarner Losh old_bus_space = sc->sc_bus_space; 157412e36acbSWarner Losh 157512e36acbSWarner Losh val = CSR_READ_4(sc, BWI_STATE_HI); 157612e36acbSWarner Losh if (__SHIFTOUT(val, BWI_STATE_HI_FLAGS_MASK) & 157712e36acbSWarner Losh BWI_STATE_HI_FLAG_64BIT) { 157812e36acbSWarner Losh /* 64bit address */ 157912e36acbSWarner Losh sc->sc_bus_space = BWI_BUS_SPACE_64BIT; 158012e36acbSWarner Losh DPRINTF(sc, BWI_DBG_MAC | BWI_DBG_ATTACH, "%s\n", 158112e36acbSWarner Losh "64bit bus space"); 158212e36acbSWarner Losh } else { 158312e36acbSWarner Losh uint32_t txrx_reg = BWI_TXRX_CTRL_BASE + BWI_TX32_CTRL; 158412e36acbSWarner Losh 158512e36acbSWarner Losh CSR_WRITE_4(sc, txrx_reg, BWI_TXRX32_CTRL_ADDRHI_MASK); 158612e36acbSWarner Losh if (CSR_READ_4(sc, txrx_reg) & BWI_TXRX32_CTRL_ADDRHI_MASK) { 158712e36acbSWarner Losh /* 32bit address */ 158812e36acbSWarner Losh sc->sc_bus_space = BWI_BUS_SPACE_32BIT; 158912e36acbSWarner Losh DPRINTF(sc, BWI_DBG_MAC | BWI_DBG_ATTACH, "%s\n", 159012e36acbSWarner Losh "32bit bus space"); 159112e36acbSWarner Losh } else { 159212e36acbSWarner Losh /* 30bit address */ 159312e36acbSWarner Losh sc->sc_bus_space = BWI_BUS_SPACE_30BIT; 159412e36acbSWarner Losh DPRINTF(sc, BWI_DBG_MAC | BWI_DBG_ATTACH, "%s\n", 159512e36acbSWarner Losh "30bit bus space"); 159612e36acbSWarner Losh } 159712e36acbSWarner Losh } 159812e36acbSWarner Losh 159912e36acbSWarner Losh if (old_bus_space != 0 && old_bus_space != sc->sc_bus_space) { 160012e36acbSWarner Losh device_printf(sc->sc_dev, "MACs bus space mismatch!\n"); 160112e36acbSWarner Losh return ENXIO; 160212e36acbSWarner Losh } 160312e36acbSWarner Losh return 0; 160412e36acbSWarner Losh } 160512e36acbSWarner Losh 160612e36acbSWarner Losh void 160712e36acbSWarner Losh bwi_mac_updateslot(struct bwi_mac *mac, int shslot) 160812e36acbSWarner Losh { 160912e36acbSWarner Losh uint16_t slot_time; 161012e36acbSWarner Losh 161112e36acbSWarner Losh if (mac->mac_phy.phy_mode == IEEE80211_MODE_11B) 161212e36acbSWarner Losh return; 161312e36acbSWarner Losh 161412e36acbSWarner Losh if (shslot) 161512e36acbSWarner Losh slot_time = IEEE80211_DUR_SHSLOT; 161612e36acbSWarner Losh else 161712e36acbSWarner Losh slot_time = IEEE80211_DUR_SLOT; 161812e36acbSWarner Losh 161912e36acbSWarner Losh CSR_WRITE_2(mac->mac_sc, BWI_MAC_SLOTTIME, 162012e36acbSWarner Losh slot_time + BWI_MAC_SLOTTIME_ADJUST); 162112e36acbSWarner Losh MOBJ_WRITE_2(mac, BWI_COMM_MOBJ, BWI_COMM_MOBJ_SLOTTIME, slot_time); 162212e36acbSWarner Losh } 162312e36acbSWarner Losh 162412e36acbSWarner Losh int 162512e36acbSWarner Losh bwi_mac_attach(struct bwi_softc *sc, int id, uint8_t rev) 162612e36acbSWarner Losh { 162712e36acbSWarner Losh struct bwi_mac *mac; 162812e36acbSWarner Losh int i; 162912e36acbSWarner Losh 163012e36acbSWarner Losh KASSERT(sc->sc_nmac <= BWI_MAC_MAX && sc->sc_nmac >= 0, 163112e36acbSWarner Losh ("sc_nmac %d", sc->sc_nmac)); 163212e36acbSWarner Losh 163312e36acbSWarner Losh if (sc->sc_nmac == BWI_MAC_MAX) { 163412e36acbSWarner Losh device_printf(sc->sc_dev, "too many MACs\n"); 163512e36acbSWarner Losh return 0; 163612e36acbSWarner Losh } 163712e36acbSWarner Losh 163812e36acbSWarner Losh /* 163912e36acbSWarner Losh * More than one MAC is only supported by BCM4309 164012e36acbSWarner Losh */ 164112e36acbSWarner Losh if (sc->sc_nmac != 0 && 164212e36acbSWarner Losh sc->sc_pci_did != PCI_PRODUCT_BROADCOM_BCM4309) { 164312e36acbSWarner Losh DPRINTF(sc, BWI_DBG_MAC | BWI_DBG_ATTACH, "%s\n", 164412e36acbSWarner Losh "ignore second MAC"); 164512e36acbSWarner Losh return 0; 164612e36acbSWarner Losh } 164712e36acbSWarner Losh 164812e36acbSWarner Losh mac = &sc->sc_mac[sc->sc_nmac]; 164912e36acbSWarner Losh 165012e36acbSWarner Losh /* XXX will this happen? */ 165112e36acbSWarner Losh if (BWI_REGWIN_EXIST(&mac->mac_regwin)) { 165212e36acbSWarner Losh device_printf(sc->sc_dev, "%dth MAC already attached\n", 165312e36acbSWarner Losh sc->sc_nmac); 165412e36acbSWarner Losh return 0; 165512e36acbSWarner Losh } 165612e36acbSWarner Losh 165712e36acbSWarner Losh /* 165812e36acbSWarner Losh * Test whether the revision of this MAC is supported 165912e36acbSWarner Losh */ 1660*d6166defSAdrian Chadd for (i = 0; i < nitems(bwi_sup_macrev); ++i) { 166112e36acbSWarner Losh if (bwi_sup_macrev[i] == rev) 166212e36acbSWarner Losh break; 166312e36acbSWarner Losh } 1664*d6166defSAdrian Chadd if (i == nitems(bwi_sup_macrev)) { 166512e36acbSWarner Losh device_printf(sc->sc_dev, "MAC rev %u is " 166612e36acbSWarner Losh "not supported\n", rev); 166712e36acbSWarner Losh return ENXIO; 166812e36acbSWarner Losh } 166912e36acbSWarner Losh 167012e36acbSWarner Losh BWI_CREATE_MAC(mac, sc, id, rev); 167112e36acbSWarner Losh sc->sc_nmac++; 167212e36acbSWarner Losh 167312e36acbSWarner Losh if (mac->mac_rev < 5) { 167412e36acbSWarner Losh mac->mac_flags |= BWI_MAC_F_HAS_TXSTATS; 167512e36acbSWarner Losh DPRINTF(sc, BWI_DBG_MAC | BWI_DBG_ATTACH, "%s\n", 167612e36acbSWarner Losh "has TX stats"); 167712e36acbSWarner Losh } else { 167812e36acbSWarner Losh mac->mac_flags |= BWI_MAC_F_PHYE_RESET; 167912e36acbSWarner Losh } 168012e36acbSWarner Losh 168112e36acbSWarner Losh device_printf(sc->sc_dev, "MAC: rev %u\n", rev); 168212e36acbSWarner Losh return 0; 168312e36acbSWarner Losh } 168412e36acbSWarner Losh 168512e36acbSWarner Losh static __inline void 168612e36acbSWarner Losh bwi_mac_balance_atten(int *bbp_atten0, int *rf_atten0) 168712e36acbSWarner Losh { 168812e36acbSWarner Losh int bbp_atten, rf_atten, rf_atten_lim = -1; 168912e36acbSWarner Losh 169012e36acbSWarner Losh bbp_atten = *bbp_atten0; 169112e36acbSWarner Losh rf_atten = *rf_atten0; 169212e36acbSWarner Losh 169312e36acbSWarner Losh /* 169412e36acbSWarner Losh * RF attenuation affects TX power BWI_RF_ATTEN_FACTOR times 169512e36acbSWarner Losh * as much as BBP attenuation, so we try our best to keep RF 169612e36acbSWarner Losh * attenuation within range. BBP attenuation will be clamped 169712e36acbSWarner Losh * later if it is out of range during balancing. 169812e36acbSWarner Losh * 169912e36acbSWarner Losh * BWI_RF_ATTEN_MAX0 is used as RF attenuation upper limit. 170012e36acbSWarner Losh */ 170112e36acbSWarner Losh 170212e36acbSWarner Losh /* 170312e36acbSWarner Losh * Use BBP attenuation to balance RF attenuation 170412e36acbSWarner Losh */ 170512e36acbSWarner Losh if (rf_atten < 0) 170612e36acbSWarner Losh rf_atten_lim = 0; 170712e36acbSWarner Losh else if (rf_atten > BWI_RF_ATTEN_MAX0) 170812e36acbSWarner Losh rf_atten_lim = BWI_RF_ATTEN_MAX0; 170912e36acbSWarner Losh 171012e36acbSWarner Losh if (rf_atten_lim >= 0) { 171112e36acbSWarner Losh bbp_atten += (BWI_RF_ATTEN_FACTOR * (rf_atten - rf_atten_lim)); 171212e36acbSWarner Losh rf_atten = rf_atten_lim; 171312e36acbSWarner Losh } 171412e36acbSWarner Losh 171512e36acbSWarner Losh /* 171612e36acbSWarner Losh * If possible, use RF attenuation to balance BBP attenuation 171712e36acbSWarner Losh * NOTE: RF attenuation is still kept within range. 171812e36acbSWarner Losh */ 171912e36acbSWarner Losh while (rf_atten < BWI_RF_ATTEN_MAX0 && bbp_atten > BWI_BBP_ATTEN_MAX) { 172012e36acbSWarner Losh bbp_atten -= BWI_RF_ATTEN_FACTOR; 172112e36acbSWarner Losh ++rf_atten; 172212e36acbSWarner Losh } 172312e36acbSWarner Losh while (rf_atten > 0 && bbp_atten < 0) { 172412e36acbSWarner Losh bbp_atten += BWI_RF_ATTEN_FACTOR; 172512e36acbSWarner Losh --rf_atten; 172612e36acbSWarner Losh } 172712e36acbSWarner Losh 172812e36acbSWarner Losh /* RF attenuation MUST be within range */ 172912e36acbSWarner Losh KASSERT(rf_atten >= 0 && rf_atten <= BWI_RF_ATTEN_MAX0, 173012e36acbSWarner Losh ("rf_atten %d", rf_atten)); 173112e36acbSWarner Losh 173212e36acbSWarner Losh /* 173312e36acbSWarner Losh * Clamp BBP attenuation 173412e36acbSWarner Losh */ 173512e36acbSWarner Losh if (bbp_atten < 0) 173612e36acbSWarner Losh bbp_atten = 0; 173712e36acbSWarner Losh else if (bbp_atten > BWI_BBP_ATTEN_MAX) 173812e36acbSWarner Losh bbp_atten = BWI_BBP_ATTEN_MAX; 173912e36acbSWarner Losh 174012e36acbSWarner Losh *rf_atten0 = rf_atten; 174112e36acbSWarner Losh *bbp_atten0 = bbp_atten; 174212e36acbSWarner Losh } 174312e36acbSWarner Losh 174412e36acbSWarner Losh static void 174512e36acbSWarner Losh bwi_mac_adjust_tpctl(struct bwi_mac *mac, int rf_atten_adj, int bbp_atten_adj) 174612e36acbSWarner Losh { 174712e36acbSWarner Losh struct bwi_softc *sc = mac->mac_sc; 174812e36acbSWarner Losh struct bwi_rf *rf = &mac->mac_rf; 174912e36acbSWarner Losh struct bwi_tpctl tpctl; 175012e36acbSWarner Losh int bbp_atten, rf_atten, tp_ctrl1; 175112e36acbSWarner Losh 175212e36acbSWarner Losh bcopy(&mac->mac_tpctl, &tpctl, sizeof(tpctl)); 175312e36acbSWarner Losh 175412e36acbSWarner Losh /* NOTE: Use signed value to do calulation */ 175512e36acbSWarner Losh bbp_atten = tpctl.bbp_atten; 175612e36acbSWarner Losh rf_atten = tpctl.rf_atten; 175712e36acbSWarner Losh tp_ctrl1 = tpctl.tp_ctrl1; 175812e36acbSWarner Losh 175912e36acbSWarner Losh bbp_atten += bbp_atten_adj; 176012e36acbSWarner Losh rf_atten += rf_atten_adj; 176112e36acbSWarner Losh 176212e36acbSWarner Losh bwi_mac_balance_atten(&bbp_atten, &rf_atten); 176312e36acbSWarner Losh 176412e36acbSWarner Losh if (rf->rf_type == BWI_RF_T_BCM2050 && rf->rf_rev == 2) { 176512e36acbSWarner Losh if (rf_atten <= 1) { 176612e36acbSWarner Losh if (tp_ctrl1 == 0) { 176712e36acbSWarner Losh tp_ctrl1 = 3; 176812e36acbSWarner Losh bbp_atten += 2; 176912e36acbSWarner Losh rf_atten += 2; 177012e36acbSWarner Losh } else if (sc->sc_card_flags & BWI_CARD_F_PA_GPIO9) { 177112e36acbSWarner Losh bbp_atten += 177212e36acbSWarner Losh (BWI_RF_ATTEN_FACTOR * (rf_atten - 2)); 177312e36acbSWarner Losh rf_atten = 2; 177412e36acbSWarner Losh } 177512e36acbSWarner Losh } else if (rf_atten > 4 && tp_ctrl1 != 0) { 177612e36acbSWarner Losh tp_ctrl1 = 0; 177712e36acbSWarner Losh if (bbp_atten < 3) { 177812e36acbSWarner Losh bbp_atten += 2; 177912e36acbSWarner Losh rf_atten -= 3; 178012e36acbSWarner Losh } else { 178112e36acbSWarner Losh bbp_atten -= 2; 178212e36acbSWarner Losh rf_atten -= 2; 178312e36acbSWarner Losh } 178412e36acbSWarner Losh } 178512e36acbSWarner Losh bwi_mac_balance_atten(&bbp_atten, &rf_atten); 178612e36acbSWarner Losh } 178712e36acbSWarner Losh 178812e36acbSWarner Losh tpctl.bbp_atten = bbp_atten; 178912e36acbSWarner Losh tpctl.rf_atten = rf_atten; 179012e36acbSWarner Losh tpctl.tp_ctrl1 = tp_ctrl1; 179112e36acbSWarner Losh 179212e36acbSWarner Losh bwi_mac_lock(mac); 179312e36acbSWarner Losh bwi_mac_set_tpctl_11bg(mac, &tpctl); 179412e36acbSWarner Losh bwi_mac_unlock(mac); 179512e36acbSWarner Losh } 179612e36acbSWarner Losh 179712e36acbSWarner Losh /* 179812e36acbSWarner Losh * http://bcm-specs.sipsolutions.net/RecalculateTransmissionPower 179912e36acbSWarner Losh */ 180012e36acbSWarner Losh void 180112e36acbSWarner Losh bwi_mac_calibrate_txpower(struct bwi_mac *mac, enum bwi_txpwrcb_type type) 180212e36acbSWarner Losh { 180312e36acbSWarner Losh struct bwi_softc *sc = mac->mac_sc; 180412e36acbSWarner Losh struct bwi_rf *rf = &mac->mac_rf; 180512e36acbSWarner Losh int8_t tssi[4], tssi_avg, cur_txpwr; 180612e36acbSWarner Losh int error, i, ofdm_tssi; 180712e36acbSWarner Losh int txpwr_diff, rf_atten_adj, bbp_atten_adj; 180812e36acbSWarner Losh 180912e36acbSWarner Losh if (!sc->sc_txpwr_calib) 181012e36acbSWarner Losh return; 181112e36acbSWarner Losh 181212e36acbSWarner Losh if (mac->mac_flags & BWI_MAC_F_TPCTL_ERROR) { 181312e36acbSWarner Losh DPRINTF(sc, BWI_DBG_MAC | BWI_DBG_TXPOWER, "%s\n", 181412e36acbSWarner Losh "tpctl error happened, can't set txpower"); 181512e36acbSWarner Losh return; 181612e36acbSWarner Losh } 181712e36acbSWarner Losh 181812e36acbSWarner Losh if (BWI_IS_BRCM_BU4306(sc)) { 181912e36acbSWarner Losh DPRINTF(sc, BWI_DBG_MAC | BWI_DBG_TXPOWER, "%s\n", 182012e36acbSWarner Losh "BU4306, can't set txpower"); 182112e36acbSWarner Losh return; 182212e36acbSWarner Losh } 182312e36acbSWarner Losh 182412e36acbSWarner Losh /* 182512e36acbSWarner Losh * Save latest TSSI and reset the related memory objects 182612e36acbSWarner Losh */ 182712e36acbSWarner Losh ofdm_tssi = 0; 182812e36acbSWarner Losh error = bwi_rf_get_latest_tssi(mac, tssi, BWI_COMM_MOBJ_TSSI_DS); 182912e36acbSWarner Losh if (error) { 183012e36acbSWarner Losh DPRINTF(sc, BWI_DBG_MAC | BWI_DBG_TXPOWER, "%s\n", 183112e36acbSWarner Losh "no DS tssi"); 183212e36acbSWarner Losh 183312e36acbSWarner Losh if (mac->mac_phy.phy_mode == IEEE80211_MODE_11B) { 183412e36acbSWarner Losh if (type == BWI_TXPWR_FORCE) { 183512e36acbSWarner Losh rf_atten_adj = 0; 183612e36acbSWarner Losh bbp_atten_adj = 1; 183712e36acbSWarner Losh goto calib; 183812e36acbSWarner Losh } else { 183912e36acbSWarner Losh return; 184012e36acbSWarner Losh } 184112e36acbSWarner Losh } 184212e36acbSWarner Losh 184312e36acbSWarner Losh error = bwi_rf_get_latest_tssi(mac, tssi, 184412e36acbSWarner Losh BWI_COMM_MOBJ_TSSI_OFDM); 184512e36acbSWarner Losh if (error) { 184612e36acbSWarner Losh DPRINTF(sc, BWI_DBG_MAC | BWI_DBG_TXPOWER, "%s\n", 184712e36acbSWarner Losh "no OFDM tssi"); 184812e36acbSWarner Losh if (type == BWI_TXPWR_FORCE) { 184912e36acbSWarner Losh rf_atten_adj = 0; 185012e36acbSWarner Losh bbp_atten_adj = 1; 185112e36acbSWarner Losh goto calib; 185212e36acbSWarner Losh } else { 185312e36acbSWarner Losh return; 185412e36acbSWarner Losh } 185512e36acbSWarner Losh } 185612e36acbSWarner Losh 185712e36acbSWarner Losh for (i = 0; i < 4; ++i) { 185812e36acbSWarner Losh tssi[i] += 0x20; 185912e36acbSWarner Losh tssi[i] &= 0x3f; 186012e36acbSWarner Losh } 186112e36acbSWarner Losh ofdm_tssi = 1; 186212e36acbSWarner Losh } 186312e36acbSWarner Losh bwi_rf_clear_tssi(mac); 186412e36acbSWarner Losh 186512e36acbSWarner Losh DPRINTF(sc, BWI_DBG_MAC | BWI_DBG_TXPOWER, 186612e36acbSWarner Losh "tssi0 %d, tssi1 %d, tssi2 %d, tssi3 %d\n", 186712e36acbSWarner Losh tssi[0], tssi[1], tssi[2], tssi[3]); 186812e36acbSWarner Losh 186912e36acbSWarner Losh /* 187012e36acbSWarner Losh * Calculate RF/BBP attenuation adjustment based on 187112e36acbSWarner Losh * the difference between desired TX power and sampled 187212e36acbSWarner Losh * TX power. 187312e36acbSWarner Losh */ 187412e36acbSWarner Losh /* +8 == "each incremented by 1/2" */ 187512e36acbSWarner Losh tssi_avg = (tssi[0] + tssi[1] + tssi[2] + tssi[3] + 8) / 4; 187612e36acbSWarner Losh if (ofdm_tssi && (HFLAGS_READ(mac) & BWI_HFLAG_PWR_BOOST_DS)) 187712e36acbSWarner Losh tssi_avg -= 13; 187812e36acbSWarner Losh 187912e36acbSWarner Losh DPRINTF(sc, BWI_DBG_MAC | BWI_DBG_TXPOWER, "tssi avg %d\n", tssi_avg); 188012e36acbSWarner Losh 188112e36acbSWarner Losh error = bwi_rf_tssi2dbm(mac, tssi_avg, &cur_txpwr); 188212e36acbSWarner Losh if (error) 188312e36acbSWarner Losh return; 188412e36acbSWarner Losh DPRINTF(sc, BWI_DBG_MAC | BWI_DBG_TXPOWER, "current txpower %d\n", 188512e36acbSWarner Losh cur_txpwr); 188612e36acbSWarner Losh 188712e36acbSWarner Losh txpwr_diff = rf->rf_txpower_max - cur_txpwr; /* XXX ni_txpower */ 188812e36acbSWarner Losh 188912e36acbSWarner Losh rf_atten_adj = -howmany(txpwr_diff, 8); 189012e36acbSWarner Losh if (type == BWI_TXPWR_INIT) { 189112e36acbSWarner Losh /* 189212e36acbSWarner Losh * Move toward EEPROM max TX power as fast as we can 189312e36acbSWarner Losh */ 189412e36acbSWarner Losh bbp_atten_adj = -txpwr_diff; 189512e36acbSWarner Losh } else { 189612e36acbSWarner Losh bbp_atten_adj = -(txpwr_diff / 2); 189712e36acbSWarner Losh } 189812e36acbSWarner Losh bbp_atten_adj -= (BWI_RF_ATTEN_FACTOR * rf_atten_adj); 189912e36acbSWarner Losh 190012e36acbSWarner Losh if (rf_atten_adj == 0 && bbp_atten_adj == 0) { 190112e36acbSWarner Losh DPRINTF(sc, BWI_DBG_MAC | BWI_DBG_TXPOWER, "%s\n", 190212e36acbSWarner Losh "no need to adjust RF/BBP attenuation"); 190312e36acbSWarner Losh /* TODO: LO */ 190412e36acbSWarner Losh return; 190512e36acbSWarner Losh } 190612e36acbSWarner Losh 190712e36acbSWarner Losh calib: 190812e36acbSWarner Losh DPRINTF(sc, BWI_DBG_MAC | BWI_DBG_TXPOWER, 190912e36acbSWarner Losh "rf atten adjust %d, bbp atten adjust %d\n", 191012e36acbSWarner Losh rf_atten_adj, bbp_atten_adj); 191112e36acbSWarner Losh bwi_mac_adjust_tpctl(mac, rf_atten_adj, bbp_atten_adj); 191212e36acbSWarner Losh /* TODO: LO */ 191312e36acbSWarner Losh } 191412e36acbSWarner Losh 191512e36acbSWarner Losh static void 191612e36acbSWarner Losh bwi_mac_lock(struct bwi_mac *mac) 191712e36acbSWarner Losh { 191812e36acbSWarner Losh struct bwi_softc *sc = mac->mac_sc; 19197a79cebfSGleb Smirnoff struct ieee80211com *ic = &sc->sc_ic; 192012e36acbSWarner Losh 192112e36acbSWarner Losh KASSERT((mac->mac_flags & BWI_MAC_F_LOCKED) == 0, 192212e36acbSWarner Losh ("mac_flags 0x%x", mac->mac_flags)); 192312e36acbSWarner Losh 192412e36acbSWarner Losh if (mac->mac_rev < 3) 192512e36acbSWarner Losh bwi_mac_stop(mac); 192612e36acbSWarner Losh else if (ic->ic_opmode != IEEE80211_M_HOSTAP) 192712e36acbSWarner Losh bwi_mac_config_ps(mac); 192812e36acbSWarner Losh 192912e36acbSWarner Losh CSR_SETBITS_4(sc, BWI_MAC_STATUS, BWI_MAC_STATUS_RFLOCK); 193012e36acbSWarner Losh 193112e36acbSWarner Losh /* Flush pending bus write */ 193212e36acbSWarner Losh CSR_READ_4(sc, BWI_MAC_STATUS); 193312e36acbSWarner Losh DELAY(10); 193412e36acbSWarner Losh 193512e36acbSWarner Losh mac->mac_flags |= BWI_MAC_F_LOCKED; 193612e36acbSWarner Losh } 193712e36acbSWarner Losh 193812e36acbSWarner Losh static void 193912e36acbSWarner Losh bwi_mac_unlock(struct bwi_mac *mac) 194012e36acbSWarner Losh { 194112e36acbSWarner Losh struct bwi_softc *sc = mac->mac_sc; 19427a79cebfSGleb Smirnoff struct ieee80211com *ic = &sc->sc_ic; 194312e36acbSWarner Losh 194412e36acbSWarner Losh KASSERT(mac->mac_flags & BWI_MAC_F_LOCKED, 194512e36acbSWarner Losh ("mac_flags 0x%x", mac->mac_flags)); 194612e36acbSWarner Losh 194712e36acbSWarner Losh CSR_READ_2(sc, BWI_PHYINFO); /* dummy read */ 194812e36acbSWarner Losh 194912e36acbSWarner Losh CSR_CLRBITS_4(sc, BWI_MAC_STATUS, BWI_MAC_STATUS_RFLOCK); 195012e36acbSWarner Losh 195112e36acbSWarner Losh if (mac->mac_rev < 3) 195212e36acbSWarner Losh bwi_mac_start(mac); 195312e36acbSWarner Losh else if (ic->ic_opmode != IEEE80211_M_HOSTAP) 195412e36acbSWarner Losh bwi_mac_config_ps(mac); 195512e36acbSWarner Losh 195612e36acbSWarner Losh mac->mac_flags &= ~BWI_MAC_F_LOCKED; 195712e36acbSWarner Losh } 195812e36acbSWarner Losh 195912e36acbSWarner Losh void 196012e36acbSWarner Losh bwi_mac_set_promisc(struct bwi_mac *mac, int promisc) 196112e36acbSWarner Losh { 196212e36acbSWarner Losh struct bwi_softc *sc = mac->mac_sc; 196312e36acbSWarner Losh 196412e36acbSWarner Losh if (mac->mac_rev < 5) /* Promisc is always on */ 196512e36acbSWarner Losh return; 196612e36acbSWarner Losh 196712e36acbSWarner Losh if (promisc) 196812e36acbSWarner Losh CSR_SETBITS_4(sc, BWI_MAC_STATUS, BWI_MAC_STATUS_PROMISC); 196912e36acbSWarner Losh else 197012e36acbSWarner Losh CSR_CLRBITS_4(sc, BWI_MAC_STATUS, BWI_MAC_STATUS_PROMISC); 197112e36acbSWarner Losh } 1972