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