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