| /* |
| Copyright (C) 2010 Willow Garage <http://www.willowgarage.com> |
| Copyright (C) 2010 Ivo van Doorn <IvDoorn@gmail.com> |
| Copyright (C) 2009 Bartlomiej Zolnierkiewicz <bzolnier@gmail.com> |
| Copyright (C) 2009 Gertjan van Wingerde <gwingerde@gmail.com> |
| |
| Based on the original rt2800pci.c and rt2800usb.c. |
| Copyright (C) 2009 Alban Browaeys <prahal@yahoo.com> |
| Copyright (C) 2009 Felix Fietkau <nbd@openwrt.org> |
| Copyright (C) 2009 Luis Correia <luis.f.correia@gmail.com> |
| Copyright (C) 2009 Mattias Nissler <mattias.nissler@gmx.de> |
| Copyright (C) 2009 Mark Asselstine <asselsm@gmail.com> |
| Copyright (C) 2009 Xose Vazquez Perez <xose.vazquez@gmail.com> |
| <http://rt2x00.serialmonkey.com> |
| |
| This program is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 2 of the License, or |
| (at your option) any later version. |
| |
| This program is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with this program; if not, see <http://www.gnu.org/licenses/>. |
| */ |
| |
| /* |
| Module: rt2800lib |
| Abstract: rt2800 generic device routines. |
| */ |
| |
| #include <linux/crc-ccitt.h> |
| #include <linux/kernel.h> |
| #include <linux/module.h> |
| #include <linux/slab.h> |
| |
| #include "rt2x00.h" |
| #include "rt2800lib.h" |
| #include "rt2800.h" |
| |
| /* |
| * Register access. |
| * All access to the CSR registers will go through the methods |
| * rt2800_register_read and rt2800_register_write. |
| * BBP and RF register require indirect register access, |
| * and use the CSR registers BBPCSR and RFCSR to achieve this. |
| * These indirect registers work with busy bits, |
| * and we will try maximal REGISTER_BUSY_COUNT times to access |
| * the register while taking a REGISTER_BUSY_DELAY us delay |
| * between each attampt. When the busy bit is still set at that time, |
| * the access attempt is considered to have failed, |
| * and we will print an error. |
| * The _lock versions must be used if you already hold the csr_mutex |
| */ |
| #define WAIT_FOR_BBP(__dev, __reg) \ |
| rt2800_regbusy_read((__dev), BBP_CSR_CFG, BBP_CSR_CFG_BUSY, (__reg)) |
| #define WAIT_FOR_RFCSR(__dev, __reg) \ |
| rt2800_regbusy_read((__dev), RF_CSR_CFG, RF_CSR_CFG_BUSY, (__reg)) |
| #define WAIT_FOR_RF(__dev, __reg) \ |
| rt2800_regbusy_read((__dev), RF_CSR_CFG0, RF_CSR_CFG0_BUSY, (__reg)) |
| #define WAIT_FOR_MCU(__dev, __reg) \ |
| rt2800_regbusy_read((__dev), H2M_MAILBOX_CSR, \ |
| H2M_MAILBOX_CSR_OWNER, (__reg)) |
| |
| static inline bool rt2800_is_305x_soc(struct rt2x00_dev *rt2x00dev) |
| { |
| /* check for rt2872 on SoC */ |
| if (!rt2x00_is_soc(rt2x00dev) || |
| !rt2x00_rt(rt2x00dev, RT2872)) |
| return false; |
| |
| /* we know for sure that these rf chipsets are used on rt305x boards */ |
| if (rt2x00_rf(rt2x00dev, RF3020) || |
| rt2x00_rf(rt2x00dev, RF3021) || |
| rt2x00_rf(rt2x00dev, RF3022)) |
| return true; |
| |
| rt2x00_warn(rt2x00dev, "Unknown RF chipset on rt305x\n"); |
| return false; |
| } |
| |
| static void rt2800_bbp_write(struct rt2x00_dev *rt2x00dev, |
| const unsigned int word, const u8 value) |
| { |
| u32 reg; |
| |
| mutex_lock(&rt2x00dev->csr_mutex); |
| |
| /* |
| * Wait until the BBP becomes available, afterwards we |
| * can safely write the new data into the register. |
| */ |
| if (WAIT_FOR_BBP(rt2x00dev, ®)) { |
| reg = 0; |
| rt2x00_set_field32(®, BBP_CSR_CFG_VALUE, value); |
| rt2x00_set_field32(®, BBP_CSR_CFG_REGNUM, word); |
| rt2x00_set_field32(®, BBP_CSR_CFG_BUSY, 1); |
| rt2x00_set_field32(®, BBP_CSR_CFG_READ_CONTROL, 0); |
| rt2x00_set_field32(®, BBP_CSR_CFG_BBP_RW_MODE, 1); |
| |
| rt2800_register_write_lock(rt2x00dev, BBP_CSR_CFG, reg); |
| } |
| |
| mutex_unlock(&rt2x00dev->csr_mutex); |
| } |
| |
| static void rt2800_bbp_read(struct rt2x00_dev *rt2x00dev, |
| const unsigned int word, u8 *value) |
| { |
| u32 reg; |
| |
| mutex_lock(&rt2x00dev->csr_mutex); |
| |
| /* |
| * Wait until the BBP becomes available, afterwards we |
| * can safely write the read request into the register. |
| * After the data has been written, we wait until hardware |
| * returns the correct value, if at any time the register |
| * doesn't become available in time, reg will be 0xffffffff |
| * which means we return 0xff to the caller. |
| */ |
| if (WAIT_FOR_BBP(rt2x00dev, ®)) { |
| reg = 0; |
| rt2x00_set_field32(®, BBP_CSR_CFG_REGNUM, word); |
| rt2x00_set_field32(®, BBP_CSR_CFG_BUSY, 1); |
| rt2x00_set_field32(®, BBP_CSR_CFG_READ_CONTROL, 1); |
| rt2x00_set_field32(®, BBP_CSR_CFG_BBP_RW_MODE, 1); |
| |
| rt2800_register_write_lock(rt2x00dev, BBP_CSR_CFG, reg); |
| |
| WAIT_FOR_BBP(rt2x00dev, ®); |
| } |
| |
| *value = rt2x00_get_field32(reg, BBP_CSR_CFG_VALUE); |
| |
| mutex_unlock(&rt2x00dev->csr_mutex); |
| } |
| |
| static void rt2800_rfcsr_write(struct rt2x00_dev *rt2x00dev, |
| const unsigned int word, const u8 value) |
| { |
| u32 reg; |
| |
| mutex_lock(&rt2x00dev->csr_mutex); |
| |
| /* |
| * Wait until the RFCSR becomes available, afterwards we |
| * can safely write the new data into the register. |
| */ |
| if (WAIT_FOR_RFCSR(rt2x00dev, ®)) { |
| reg = 0; |
| rt2x00_set_field32(®, RF_CSR_CFG_DATA, value); |
| rt2x00_set_field32(®, RF_CSR_CFG_REGNUM, word); |
| rt2x00_set_field32(®, RF_CSR_CFG_WRITE, 1); |
| rt2x00_set_field32(®, RF_CSR_CFG_BUSY, 1); |
| |
| rt2800_register_write_lock(rt2x00dev, RF_CSR_CFG, reg); |
| } |
| |
| mutex_unlock(&rt2x00dev->csr_mutex); |
| } |
| |
| static void rt2800_rfcsr_read(struct rt2x00_dev *rt2x00dev, |
| const unsigned int word, u8 *value) |
| { |
| u32 reg; |
| |
| mutex_lock(&rt2x00dev->csr_mutex); |
| |
| /* |
| * Wait until the RFCSR becomes available, afterwards we |
| * can safely write the read request into the register. |
| * After the data has been written, we wait until hardware |
| * returns the correct value, if at any time the register |
| * doesn't become available in time, reg will be 0xffffffff |
| * which means we return 0xff to the caller. |
| */ |
| if (WAIT_FOR_RFCSR(rt2x00dev, ®)) { |
| reg = 0; |
| rt2x00_set_field32(®, RF_CSR_CFG_REGNUM, word); |
| rt2x00_set_field32(®, RF_CSR_CFG_WRITE, 0); |
| rt2x00_set_field32(®, RF_CSR_CFG_BUSY, 1); |
| |
| rt2800_register_write_lock(rt2x00dev, RF_CSR_CFG, reg); |
| |
| WAIT_FOR_RFCSR(rt2x00dev, ®); |
| } |
| |
| *value = rt2x00_get_field32(reg, RF_CSR_CFG_DATA); |
| |
| mutex_unlock(&rt2x00dev->csr_mutex); |
| } |
| |
| static void rt2800_rf_write(struct rt2x00_dev *rt2x00dev, |
| const unsigned int word, const u32 value) |
| { |
| u32 reg; |
| |
| mutex_lock(&rt2x00dev->csr_mutex); |
| |
| /* |
| * Wait until the RF becomes available, afterwards we |
| * can safely write the new data into the register. |
| */ |
| if (WAIT_FOR_RF(rt2x00dev, ®)) { |
| reg = 0; |
| rt2x00_set_field32(®, RF_CSR_CFG0_REG_VALUE_BW, value); |
| rt2x00_set_field32(®, RF_CSR_CFG0_STANDBYMODE, 0); |
| rt2x00_set_field32(®, RF_CSR_CFG0_SEL, 0); |
| rt2x00_set_field32(®, RF_CSR_CFG0_BUSY, 1); |
| |
| rt2800_register_write_lock(rt2x00dev, RF_CSR_CFG0, reg); |
| rt2x00_rf_write(rt2x00dev, word, value); |
| } |
| |
| mutex_unlock(&rt2x00dev->csr_mutex); |
| } |
| |
| static const unsigned int rt2800_eeprom_map[EEPROM_WORD_COUNT] = { |
| [EEPROM_CHIP_ID] = 0x0000, |
| [EEPROM_VERSION] = 0x0001, |
| [EEPROM_MAC_ADDR_0] = 0x0002, |
| [EEPROM_MAC_ADDR_1] = 0x0003, |
| [EEPROM_MAC_ADDR_2] = 0x0004, |
| [EEPROM_NIC_CONF0] = 0x001a, |
| [EEPROM_NIC_CONF1] = 0x001b, |
| [EEPROM_FREQ] = 0x001d, |
| [EEPROM_LED_AG_CONF] = 0x001e, |
| [EEPROM_LED_ACT_CONF] = 0x001f, |
| [EEPROM_LED_POLARITY] = 0x0020, |
| [EEPROM_NIC_CONF2] = 0x0021, |
| [EEPROM_LNA] = 0x0022, |
| [EEPROM_RSSI_BG] = 0x0023, |
| [EEPROM_RSSI_BG2] = 0x0024, |
| [EEPROM_TXMIXER_GAIN_BG] = 0x0024, /* overlaps with RSSI_BG2 */ |
| [EEPROM_RSSI_A] = 0x0025, |
| [EEPROM_RSSI_A2] = 0x0026, |
| [EEPROM_TXMIXER_GAIN_A] = 0x0026, /* overlaps with RSSI_A2 */ |
| [EEPROM_EIRP_MAX_TX_POWER] = 0x0027, |
| [EEPROM_TXPOWER_DELTA] = 0x0028, |
| [EEPROM_TXPOWER_BG1] = 0x0029, |
| [EEPROM_TXPOWER_BG2] = 0x0030, |
| [EEPROM_TSSI_BOUND_BG1] = 0x0037, |
| [EEPROM_TSSI_BOUND_BG2] = 0x0038, |
| [EEPROM_TSSI_BOUND_BG3] = 0x0039, |
| [EEPROM_TSSI_BOUND_BG4] = 0x003a, |
| [EEPROM_TSSI_BOUND_BG5] = 0x003b, |
| [EEPROM_TXPOWER_A1] = 0x003c, |
| [EEPROM_TXPOWER_A2] = 0x0053, |
| [EEPROM_TSSI_BOUND_A1] = 0x006a, |
| [EEPROM_TSSI_BOUND_A2] = 0x006b, |
| [EEPROM_TSSI_BOUND_A3] = 0x006c, |
| [EEPROM_TSSI_BOUND_A4] = 0x006d, |
| [EEPROM_TSSI_BOUND_A5] = 0x006e, |
| [EEPROM_TXPOWER_BYRATE] = 0x006f, |
| [EEPROM_BBP_START] = 0x0078, |
| }; |
| |
| static const unsigned int rt2800_eeprom_map_ext[EEPROM_WORD_COUNT] = { |
| [EEPROM_CHIP_ID] = 0x0000, |
| [EEPROM_VERSION] = 0x0001, |
| [EEPROM_MAC_ADDR_0] = 0x0002, |
| [EEPROM_MAC_ADDR_1] = 0x0003, |
| [EEPROM_MAC_ADDR_2] = 0x0004, |
| [EEPROM_NIC_CONF0] = 0x001a, |
| [EEPROM_NIC_CONF1] = 0x001b, |
| [EEPROM_NIC_CONF2] = 0x001c, |
| [EEPROM_EIRP_MAX_TX_POWER] = 0x0020, |
| [EEPROM_FREQ] = 0x0022, |
| [EEPROM_LED_AG_CONF] = 0x0023, |
| [EEPROM_LED_ACT_CONF] = 0x0024, |
| [EEPROM_LED_POLARITY] = 0x0025, |
| [EEPROM_LNA] = 0x0026, |
| [EEPROM_EXT_LNA2] = 0x0027, |
| [EEPROM_RSSI_BG] = 0x0028, |
| [EEPROM_RSSI_BG2] = 0x0029, |
| [EEPROM_RSSI_A] = 0x002a, |
| [EEPROM_RSSI_A2] = 0x002b, |
| [EEPROM_TXPOWER_BG1] = 0x0030, |
| [EEPROM_TXPOWER_BG2] = 0x0037, |
| [EEPROM_EXT_TXPOWER_BG3] = 0x003e, |
| [EEPROM_TSSI_BOUND_BG1] = 0x0045, |
| [EEPROM_TSSI_BOUND_BG2] = 0x0046, |
| [EEPROM_TSSI_BOUND_BG3] = 0x0047, |
| [EEPROM_TSSI_BOUND_BG4] = 0x0048, |
| [EEPROM_TSSI_BOUND_BG5] = 0x0049, |
| [EEPROM_TXPOWER_A1] = 0x004b, |
| [EEPROM_TXPOWER_A2] = 0x0065, |
| [EEPROM_EXT_TXPOWER_A3] = 0x007f, |
| [EEPROM_TSSI_BOUND_A1] = 0x009a, |
| [EEPROM_TSSI_BOUND_A2] = 0x009b, |
| [EEPROM_TSSI_BOUND_A3] = 0x009c, |
| [EEPROM_TSSI_BOUND_A4] = 0x009d, |
| [EEPROM_TSSI_BOUND_A5] = 0x009e, |
| [EEPROM_TXPOWER_BYRATE] = 0x00a0, |
| }; |
| |
| static unsigned int rt2800_eeprom_word_index(struct rt2x00_dev *rt2x00dev, |
| const enum rt2800_eeprom_word word) |
| { |
| const unsigned int *map; |
| unsigned int index; |
| |
| if (WARN_ONCE(word >= EEPROM_WORD_COUNT, |
| "%s: invalid EEPROM word %d\n", |
| wiphy_name(rt2x00dev->hw->wiphy), word)) |
| return 0; |
| |
| if (rt2x00_rt(rt2x00dev, RT3593)) |
| map = rt2800_eeprom_map_ext; |
| else |
| map = rt2800_eeprom_map; |
| |
| index = map[word]; |
| |
| /* Index 0 is valid only for EEPROM_CHIP_ID. |
| * Otherwise it means that the offset of the |
| * given word is not initialized in the map, |
| * or that the field is not usable on the |
| * actual chipset. |
| */ |
| WARN_ONCE(word != EEPROM_CHIP_ID && index == 0, |
| "%s: invalid access of EEPROM word %d\n", |
| wiphy_name(rt2x00dev->hw->wiphy), word); |
| |
| return index; |
| } |
| |
| static void *rt2800_eeprom_addr(struct rt2x00_dev *rt2x00dev, |
| const enum rt2800_eeprom_word word) |
| { |
| unsigned int index; |
| |
| index = rt2800_eeprom_word_index(rt2x00dev, word); |
| return rt2x00_eeprom_addr(rt2x00dev, index); |
| } |
| |
| static void rt2800_eeprom_read(struct rt2x00_dev *rt2x00dev, |
| const enum rt2800_eeprom_word word, u16 *data) |
| { |
| unsigned int index; |
| |
| index = rt2800_eeprom_word_index(rt2x00dev, word); |
| rt2x00_eeprom_read(rt2x00dev, index, data); |
| } |
| |
| static void rt2800_eeprom_write(struct rt2x00_dev *rt2x00dev, |
| const enum rt2800_eeprom_word word, u16 data) |
| { |
| unsigned int index; |
| |
| index = rt2800_eeprom_word_index(rt2x00dev, word); |
| rt2x00_eeprom_write(rt2x00dev, index, data); |
| } |
| |
| static void rt2800_eeprom_read_from_array(struct rt2x00_dev *rt2x00dev, |
| const enum rt2800_eeprom_word array, |
| unsigned int offset, |
| u16 *data) |
| { |
| unsigned int index; |
| |
| index = rt2800_eeprom_word_index(rt2x00dev, array); |
| rt2x00_eeprom_read(rt2x00dev, index + offset, data); |
| } |
| |
| static int rt2800_enable_wlan_rt3290(struct rt2x00_dev *rt2x00dev) |
| { |
| u32 reg; |
| int i, count; |
| |
| rt2800_register_read(rt2x00dev, WLAN_FUN_CTRL, ®); |
| if (rt2x00_get_field32(reg, WLAN_EN)) |
| return 0; |
| |
| rt2x00_set_field32(®, WLAN_GPIO_OUT_OE_BIT_ALL, 0xff); |
| rt2x00_set_field32(®, FRC_WL_ANT_SET, 1); |
| rt2x00_set_field32(®, WLAN_CLK_EN, 0); |
| rt2x00_set_field32(®, WLAN_EN, 1); |
| rt2800_register_write(rt2x00dev, WLAN_FUN_CTRL, reg); |
| |
| udelay(REGISTER_BUSY_DELAY); |
| |
| count = 0; |
| do { |
| /* |
| * Check PLL_LD & XTAL_RDY. |
| */ |
| for (i = 0; i < REGISTER_BUSY_COUNT; i++) { |
| rt2800_register_read(rt2x00dev, CMB_CTRL, ®); |
| if (rt2x00_get_field32(reg, PLL_LD) && |
| rt2x00_get_field32(reg, XTAL_RDY)) |
| break; |
| udelay(REGISTER_BUSY_DELAY); |
| } |
| |
| if (i >= REGISTER_BUSY_COUNT) { |
| |
| if (count >= 10) |
| return -EIO; |
| |
| rt2800_register_write(rt2x00dev, 0x58, 0x018); |
| udelay(REGISTER_BUSY_DELAY); |
| rt2800_register_write(rt2x00dev, 0x58, 0x418); |
| udelay(REGISTER_BUSY_DELAY); |
| rt2800_register_write(rt2x00dev, 0x58, 0x618); |
| udelay(REGISTER_BUSY_DELAY); |
| count++; |
| } else { |
| count = 0; |
| } |
| |
| rt2800_register_read(rt2x00dev, WLAN_FUN_CTRL, ®); |
| rt2x00_set_field32(®, PCIE_APP0_CLK_REQ, 0); |
| rt2x00_set_field32(®, WLAN_CLK_EN, 1); |
| rt2x00_set_field32(®, WLAN_RESET, 1); |
| rt2800_register_write(rt2x00dev, WLAN_FUN_CTRL, reg); |
| udelay(10); |
| rt2x00_set_field32(®, WLAN_RESET, 0); |
| rt2800_register_write(rt2x00dev, WLAN_FUN_CTRL, reg); |
| udelay(10); |
| rt2800_register_write(rt2x00dev, INT_SOURCE_CSR, 0x7fffffff); |
| } while (count != 0); |
| |
| return 0; |
| } |
| |
| void rt2800_mcu_request(struct rt2x00_dev *rt2x00dev, |
| const u8 command, const u8 token, |
| const u8 arg0, const u8 arg1) |
| { |
| u32 reg; |
| |
| /* |
| * SOC devices don't support MCU requests. |
| */ |
| if (rt2x00_is_soc(rt2x00dev)) |
| return; |
| |
| mutex_lock(&rt2x00dev->csr_mutex); |
| |
| /* |
| * Wait until the MCU becomes available, afterwards we |
| * can safely write the new data into the register. |
| */ |
| if (WAIT_FOR_MCU(rt2x00dev, ®)) { |
| rt2x00_set_field32(®, H2M_MAILBOX_CSR_OWNER, 1); |
| rt2x00_set_field32(®, H2M_MAILBOX_CSR_CMD_TOKEN, token); |
| rt2x00_set_field32(®, H2M_MAILBOX_CSR_ARG0, arg0); |
| rt2x00_set_field32(®, H2M_MAILBOX_CSR_ARG1, arg1); |
| rt2800_register_write_lock(rt2x00dev, H2M_MAILBOX_CSR, reg); |
| |
| reg = 0; |
| rt2x00_set_field32(®, HOST_CMD_CSR_HOST_COMMAND, command); |
| rt2800_register_write_lock(rt2x00dev, HOST_CMD_CSR, reg); |
| } |
| |
| mutex_unlock(&rt2x00dev->csr_mutex); |
| } |
| EXPORT_SYMBOL_GPL(rt2800_mcu_request); |
| |
| int rt2800_wait_csr_ready(struct rt2x00_dev *rt2x00dev) |
| { |
| unsigned int i = 0; |
| u32 reg; |
| |
| for (i = 0; i < REGISTER_BUSY_COUNT; i++) { |
| rt2800_register_read(rt2x00dev, MAC_CSR0, ®); |
| if (reg && reg != ~0) |
| return 0; |
| msleep(1); |
| } |
| |
| rt2x00_err(rt2x00dev, "Unstable hardware\n"); |
| return -EBUSY; |
| } |
| EXPORT_SYMBOL_GPL(rt2800_wait_csr_ready); |
| |
| int rt2800_wait_wpdma_ready(struct rt2x00_dev *rt2x00dev) |
| { |
| unsigned int i; |
| u32 reg; |
| |
| /* |
| * Some devices are really slow to respond here. Wait a whole second |
| * before timing out. |
| */ |
| for (i = 0; i < REGISTER_BUSY_COUNT; i++) { |
| rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, ®); |
| if (!rt2x00_get_field32(reg, WPDMA_GLO_CFG_TX_DMA_BUSY) && |
| !rt2x00_get_field32(reg, WPDMA_GLO_CFG_RX_DMA_BUSY)) |
| return 0; |
| |
| msleep(10); |
| } |
| |
| rt2x00_err(rt2x00dev, "WPDMA TX/RX busy [0x%08x]\n", reg); |
| return -EACCES; |
| } |
| EXPORT_SYMBOL_GPL(rt2800_wait_wpdma_ready); |
| |
| void rt2800_disable_wpdma(struct rt2x00_dev *rt2x00dev) |
| { |
| u32 reg; |
| |
| rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, ®); |
| rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_TX_DMA, 0); |
| rt2x00_set_field32(®, WPDMA_GLO_CFG_TX_DMA_BUSY, 0); |
| rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_RX_DMA, 0); |
| rt2x00_set_field32(®, WPDMA_GLO_CFG_RX_DMA_BUSY, 0); |
| rt2x00_set_field32(®, WPDMA_GLO_CFG_TX_WRITEBACK_DONE, 1); |
| rt2800_register_write(rt2x00dev, WPDMA_GLO_CFG, reg); |
| } |
| EXPORT_SYMBOL_GPL(rt2800_disable_wpdma); |
| |
| void rt2800_get_txwi_rxwi_size(struct rt2x00_dev *rt2x00dev, |
| unsigned short *txwi_size, |
| unsigned short *rxwi_size) |
| { |
| switch (rt2x00dev->chip.rt) { |
| case RT3593: |
| *txwi_size = TXWI_DESC_SIZE_4WORDS; |
| *rxwi_size = RXWI_DESC_SIZE_5WORDS; |
| break; |
| |
| case RT5592: |
| *txwi_size = TXWI_DESC_SIZE_5WORDS; |
| *rxwi_size = RXWI_DESC_SIZE_6WORDS; |
| break; |
| |
| default: |
| *txwi_size = TXWI_DESC_SIZE_4WORDS; |
| *rxwi_size = RXWI_DESC_SIZE_4WORDS; |
| break; |
| } |
| } |
| EXPORT_SYMBOL_GPL(rt2800_get_txwi_rxwi_size); |
| |
| static bool rt2800_check_firmware_crc(const u8 *data, const size_t len) |
| { |
| u16 fw_crc; |
| u16 crc; |
| |
| /* |
| * The last 2 bytes in the firmware array are the crc checksum itself, |
| * this means that we should never pass those 2 bytes to the crc |
| * algorithm. |
| */ |
| fw_crc = (data[len - 2] << 8 | data[len - 1]); |
| |
| /* |
| * Use the crc ccitt algorithm. |
| * This will return the same value as the legacy driver which |
| * used bit ordering reversion on the both the firmware bytes |
| * before input input as well as on the final output. |
| * Obviously using crc ccitt directly is much more efficient. |
| */ |
| crc = crc_ccitt(~0, data, len - 2); |
| |
| /* |
| * There is a small difference between the crc-itu-t + bitrev and |
| * the crc-ccitt crc calculation. In the latter method the 2 bytes |
| * will be swapped, use swab16 to convert the crc to the correct |
| * value. |
| */ |
| crc = swab16(crc); |
| |
| return fw_crc == crc; |
| } |
| |
| int rt2800_check_firmware(struct rt2x00_dev *rt2x00dev, |
| const u8 *data, const size_t len) |
| { |
| size_t offset = 0; |
| size_t fw_len; |
| bool multiple; |
| |
| /* |
| * PCI(e) & SOC devices require firmware with a length |
| * of 8kb. USB devices require firmware files with a length |
| * of 4kb. Certain USB chipsets however require different firmware, |
| * which Ralink only provides attached to the original firmware |
| * file. Thus for USB devices, firmware files have a length |
| * which is a multiple of 4kb. The firmware for rt3290 chip also |
| * have a length which is a multiple of 4kb. |
| */ |
| if (rt2x00_is_usb(rt2x00dev) || rt2x00_rt(rt2x00dev, RT3290)) |
| fw_len = 4096; |
| else |
| fw_len = 8192; |
| |
| multiple = true; |
| /* |
| * Validate the firmware length |
| */ |
| if (len != fw_len && (!multiple || (len % fw_len) != 0)) |
| return FW_BAD_LENGTH; |
| |
| /* |
| * Check if the chipset requires one of the upper parts |
| * of the firmware. |
| */ |
| if (rt2x00_is_usb(rt2x00dev) && |
| !rt2x00_rt(rt2x00dev, RT2860) && |
| !rt2x00_rt(rt2x00dev, RT2872) && |
| !rt2x00_rt(rt2x00dev, RT3070) && |
| ((len / fw_len) == 1)) |
| return FW_BAD_VERSION; |
| |
| /* |
| * 8kb firmware files must be checked as if it were |
| * 2 separate firmware files. |
| */ |
| while (offset < len) { |
| if (!rt2800_check_firmware_crc(data + offset, fw_len)) |
| return FW_BAD_CRC; |
| |
| offset += fw_len; |
| } |
| |
| return FW_OK; |
| } |
| EXPORT_SYMBOL_GPL(rt2800_check_firmware); |
| |
| int rt2800_load_firmware(struct rt2x00_dev *rt2x00dev, |
| const u8 *data, const size_t len) |
| { |
| unsigned int i; |
| u32 reg; |
| int retval; |
| |
| if (rt2x00_rt(rt2x00dev, RT3290)) { |
| retval = rt2800_enable_wlan_rt3290(rt2x00dev); |
| if (retval) |
| return -EBUSY; |
| } |
| |
| /* |
| * If driver doesn't wake up firmware here, |
| * rt2800_load_firmware will hang forever when interface is up again. |
| */ |
| rt2800_register_write(rt2x00dev, AUTOWAKEUP_CFG, 0x00000000); |
| |
| /* |
| * Wait for stable hardware. |
| */ |
| if (rt2800_wait_csr_ready(rt2x00dev)) |
| return -EBUSY; |
| |
| if (rt2x00_is_pci(rt2x00dev)) { |
| if (rt2x00_rt(rt2x00dev, RT3290) || |
| rt2x00_rt(rt2x00dev, RT3572) || |
| rt2x00_rt(rt2x00dev, RT5390) || |
| rt2x00_rt(rt2x00dev, RT5392)) { |
| rt2800_register_read(rt2x00dev, AUX_CTRL, ®); |
| rt2x00_set_field32(®, AUX_CTRL_FORCE_PCIE_CLK, 1); |
| rt2x00_set_field32(®, AUX_CTRL_WAKE_PCIE_EN, 1); |
| rt2800_register_write(rt2x00dev, AUX_CTRL, reg); |
| } |
| rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000002); |
| } |
| |
| rt2800_disable_wpdma(rt2x00dev); |
| |
| /* |
| * Write firmware to the device. |
| */ |
| rt2800_drv_write_firmware(rt2x00dev, data, len); |
| |
| /* |
| * Wait for device to stabilize. |
| */ |
| for (i = 0; i < REGISTER_BUSY_COUNT; i++) { |
| rt2800_register_read(rt2x00dev, PBF_SYS_CTRL, ®); |
| if (rt2x00_get_field32(reg, PBF_SYS_CTRL_READY)) |
| break; |
| msleep(1); |
| } |
| |
| if (i == REGISTER_BUSY_COUNT) { |
| rt2x00_err(rt2x00dev, "PBF system register not ready\n"); |
| return -EBUSY; |
| } |
| |
| /* |
| * Disable DMA, will be reenabled later when enabling |
| * the radio. |
| */ |
| rt2800_disable_wpdma(rt2x00dev); |
| |
| /* |
| * Initialize firmware. |
| */ |
| rt2800_register_write(rt2x00dev, H2M_BBP_AGENT, 0); |
| rt2800_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0); |
| if (rt2x00_is_usb(rt2x00dev)) { |
| rt2800_register_write(rt2x00dev, H2M_INT_SRC, 0); |
| rt2800_mcu_request(rt2x00dev, MCU_BOOT_SIGNAL, 0, 0, 0); |
| } |
| msleep(1); |
| |
| return 0; |
| } |
| EXPORT_SYMBOL_GPL(rt2800_load_firmware); |
| |
| void rt2800_write_tx_data(struct queue_entry *entry, |
| struct txentry_desc *txdesc) |
| { |
| __le32 *txwi = rt2800_drv_get_txwi(entry); |
| u32 word; |
| int i; |
| |
| /* |
| * Initialize TX Info descriptor |
| */ |
| rt2x00_desc_read(txwi, 0, &word); |
| rt2x00_set_field32(&word, TXWI_W0_FRAG, |
| test_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags)); |
| rt2x00_set_field32(&word, TXWI_W0_MIMO_PS, |
| test_bit(ENTRY_TXD_HT_MIMO_PS, &txdesc->flags)); |
| rt2x00_set_field32(&word, TXWI_W0_CF_ACK, 0); |
| rt2x00_set_field32(&word, TXWI_W0_TS, |
| test_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc->flags)); |
| rt2x00_set_field32(&word, TXWI_W0_AMPDU, |
| test_bit(ENTRY_TXD_HT_AMPDU, &txdesc->flags)); |
| rt2x00_set_field32(&word, TXWI_W0_MPDU_DENSITY, |
| txdesc->u.ht.mpdu_density); |
| rt2x00_set_field32(&word, TXWI_W0_TX_OP, txdesc->u.ht.txop); |
| rt2x00_set_field32(&word, TXWI_W0_MCS, txdesc->u.ht.mcs); |
| rt2x00_set_field32(&word, TXWI_W0_BW, |
| test_bit(ENTRY_TXD_HT_BW_40, &txdesc->flags)); |
| rt2x00_set_field32(&word, TXWI_W0_SHORT_GI, |
| test_bit(ENTRY_TXD_HT_SHORT_GI, &txdesc->flags)); |
| rt2x00_set_field32(&word, TXWI_W0_STBC, txdesc->u.ht.stbc); |
| rt2x00_set_field32(&word, TXWI_W0_PHYMODE, txdesc->rate_mode); |
| rt2x00_desc_write(txwi, 0, word); |
| |
| rt2x00_desc_read(txwi, 1, &word); |
| rt2x00_set_field32(&word, TXWI_W1_ACK, |
| test_bit(ENTRY_TXD_ACK, &txdesc->flags)); |
| rt2x00_set_field32(&word, TXWI_W1_NSEQ, |
| test_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags)); |
| rt2x00_set_field32(&word, TXWI_W1_BW_WIN_SIZE, txdesc->u.ht.ba_size); |
| rt2x00_set_field32(&word, TXWI_W1_WIRELESS_CLI_ID, |
| test_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags) ? |
| txdesc->key_idx : txdesc->u.ht.wcid); |
| rt2x00_set_field32(&word, TXWI_W1_MPDU_TOTAL_BYTE_COUNT, |
| txdesc->length); |
| rt2x00_set_field32(&word, TXWI_W1_PACKETID_QUEUE, entry->queue->qid); |
| rt2x00_set_field32(&word, TXWI_W1_PACKETID_ENTRY, (entry->entry_idx % 3) + 1); |
| rt2x00_desc_write(txwi, 1, word); |
| |
| /* |
| * Always write 0 to IV/EIV fields (word 2 and 3), hardware will insert |
| * the IV from the IVEIV register when TXD_W3_WIV is set to 0. |
| * When TXD_W3_WIV is set to 1 it will use the IV data |
| * from the descriptor. The TXWI_W1_WIRELESS_CLI_ID indicates which |
| * crypto entry in the registers should be used to encrypt the frame. |
| * |
| * Nulify all remaining words as well, we don't know how to program them. |
| */ |
| for (i = 2; i < entry->queue->winfo_size / sizeof(__le32); i++) |
| _rt2x00_desc_write(txwi, i, 0); |
| } |
| EXPORT_SYMBOL_GPL(rt2800_write_tx_data); |
| |
| static int rt2800_agc_to_rssi(struct rt2x00_dev *rt2x00dev, u32 rxwi_w2) |
| { |
| s8 rssi0 = rt2x00_get_field32(rxwi_w2, RXWI_W2_RSSI0); |
| s8 rssi1 = rt2x00_get_field32(rxwi_w2, RXWI_W2_RSSI1); |
| s8 rssi2 = rt2x00_get_field32(rxwi_w2, RXWI_W2_RSSI2); |
| u16 eeprom; |
| u8 offset0; |
| u8 offset1; |
| u8 offset2; |
| |
| if (rt2x00dev->curr_band == IEEE80211_BAND_2GHZ) { |
| rt2800_eeprom_read(rt2x00dev, EEPROM_RSSI_BG, &eeprom); |
| offset0 = rt2x00_get_field16(eeprom, EEPROM_RSSI_BG_OFFSET0); |
| offset1 = rt2x00_get_field16(eeprom, EEPROM_RSSI_BG_OFFSET1); |
| rt2800_eeprom_read(rt2x00dev, EEPROM_RSSI_BG2, &eeprom); |
| offset2 = rt2x00_get_field16(eeprom, EEPROM_RSSI_BG2_OFFSET2); |
| } else { |
| rt2800_eeprom_read(rt2x00dev, EEPROM_RSSI_A, &eeprom); |
| offset0 = rt2x00_get_field16(eeprom, EEPROM_RSSI_A_OFFSET0); |
| offset1 = rt2x00_get_field16(eeprom, EEPROM_RSSI_A_OFFSET1); |
| rt2800_eeprom_read(rt2x00dev, EEPROM_RSSI_A2, &eeprom); |
| offset2 = rt2x00_get_field16(eeprom, EEPROM_RSSI_A2_OFFSET2); |
| } |
| |
| /* |
| * Convert the value from the descriptor into the RSSI value |
| * If the value in the descriptor is 0, it is considered invalid |
| * and the default (extremely low) rssi value is assumed |
| */ |
| rssi0 = (rssi0) ? (-12 - offset0 - rt2x00dev->lna_gain - rssi0) : -128; |
| rssi1 = (rssi1) ? (-12 - offset1 - rt2x00dev->lna_gain - rssi1) : -128; |
| rssi2 = (rssi2) ? (-12 - offset2 - rt2x00dev->lna_gain - rssi2) : -128; |
| |
| /* |
| * mac80211 only accepts a single RSSI value. Calculating the |
| * average doesn't deliver a fair answer either since -60:-60 would |
| * be considered equally good as -50:-70 while the second is the one |
| * which gives less energy... |
| */ |
| rssi0 = max(rssi0, rssi1); |
| return (int)max(rssi0, rssi2); |
| } |
| |
| void rt2800_process_rxwi(struct queue_entry *entry, |
| struct rxdone_entry_desc *rxdesc) |
| { |
| __le32 *rxwi = (__le32 *) entry->skb->data; |
| u32 word; |
| |
| rt2x00_desc_read(rxwi, 0, &word); |
| |
| rxdesc->cipher = rt2x00_get_field32(word, RXWI_W0_UDF); |
| rxdesc->size = rt2x00_get_field32(word, RXWI_W0_MPDU_TOTAL_BYTE_COUNT); |
| |
| rt2x00_desc_read(rxwi, 1, &word); |
| |
| if (rt2x00_get_field32(word, RXWI_W1_SHORT_GI)) |
| rxdesc->flags |= RX_FLAG_SHORT_GI; |
| |
| if (rt2x00_get_field32(word, RXWI_W1_BW)) |
| rxdesc->flags |= RX_FLAG_40MHZ; |
| |
| /* |
| * Detect RX rate, always use MCS as signal type. |
| */ |
| rxdesc->dev_flags |= RXDONE_SIGNAL_MCS; |
| rxdesc->signal = rt2x00_get_field32(word, RXWI_W1_MCS); |
| rxdesc->rate_mode = rt2x00_get_field32(word, RXWI_W1_PHYMODE); |
| |
| /* |
| * Mask of 0x8 bit to remove the short preamble flag. |
| */ |
| if (rxdesc->rate_mode == RATE_MODE_CCK) |
| rxdesc->signal &= ~0x8; |
| |
| rt2x00_desc_read(rxwi, 2, &word); |
| |
| /* |
| * Convert descriptor AGC value to RSSI value. |
| */ |
| rxdesc->rssi = rt2800_agc_to_rssi(entry->queue->rt2x00dev, word); |
| /* |
| * Remove RXWI descriptor from start of the buffer. |
| */ |
| skb_pull(entry->skb, entry->queue->winfo_size); |
| } |
| EXPORT_SYMBOL_GPL(rt2800_process_rxwi); |
| |
| void rt2800_txdone_entry(struct queue_entry *entry, u32 status, __le32 *txwi) |
| { |
| struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; |
| struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); |
| struct txdone_entry_desc txdesc; |
| u32 word; |
| u16 mcs, real_mcs; |
| int aggr, ampdu; |
| |
| /* |
| * Obtain the status about this packet. |
| */ |
| txdesc.flags = 0; |
| rt2x00_desc_read(txwi, 0, &word); |
| |
| mcs = rt2x00_get_field32(word, TXWI_W0_MCS); |
| ampdu = rt2x00_get_field32(word, TXWI_W0_AMPDU); |
| |
| real_mcs = rt2x00_get_field32(status, TX_STA_FIFO_MCS); |
| aggr = rt2x00_get_field32(status, TX_STA_FIFO_TX_AGGRE); |
| |
| /* |
| * If a frame was meant to be sent as a single non-aggregated MPDU |
| * but ended up in an aggregate the used tx rate doesn't correlate |
| * with the one specified in the TXWI as the whole aggregate is sent |
| * with the same rate. |
| * |
| * For example: two frames are sent to rt2x00, the first one sets |
| * AMPDU=1 and requests MCS7 whereas the second frame sets AMDPU=0 |
| * and requests MCS15. If the hw aggregates both frames into one |
| * AMDPU the tx status for both frames will contain MCS7 although |
| * the frame was sent successfully. |
| * |
| * Hence, replace the requested rate with the real tx rate to not |
| * confuse the rate control algortihm by providing clearly wrong |
| * data. |
| */ |
| if (unlikely(aggr == 1 && ampdu == 0 && real_mcs != mcs)) { |
| skbdesc->tx_rate_idx = real_mcs; |
| mcs = real_mcs; |
| } |
| |
| if (aggr == 1 || ampdu == 1) |
| __set_bit(TXDONE_AMPDU, &txdesc.flags); |
| |
| /* |
| * Ralink has a retry mechanism using a global fallback |
| * table. We setup this fallback table to try the immediate |
| * lower rate for all rates. In the TX_STA_FIFO, the MCS field |
| * always contains the MCS used for the last transmission, be |
| * it successful or not. |
| */ |
| if (rt2x00_get_field32(status, TX_STA_FIFO_TX_SUCCESS)) { |
| /* |
| * Transmission succeeded. The number of retries is |
| * mcs - real_mcs |
| */ |
| __set_bit(TXDONE_SUCCESS, &txdesc.flags); |
| txdesc.retry = ((mcs > real_mcs) ? mcs - real_mcs : 0); |
| } else { |
| /* |
| * Transmission failed. The number of retries is |
| * always 7 in this case (for a total number of 8 |
| * frames sent). |
| */ |
| __set_bit(TXDONE_FAILURE, &txdesc.flags); |
| txdesc.retry = rt2x00dev->long_retry; |
| } |
| |
| /* |
| * the frame was retried at least once |
| * -> hw used fallback rates |
| */ |
| if (txdesc.retry) |
| __set_bit(TXDONE_FALLBACK, &txdesc.flags); |
| |
| rt2x00lib_txdone(entry, &txdesc); |
| } |
| EXPORT_SYMBOL_GPL(rt2800_txdone_entry); |
| |
| static unsigned int rt2800_hw_beacon_base(struct rt2x00_dev *rt2x00dev, |
| unsigned int index) |
| { |
| return HW_BEACON_BASE(index); |
| } |
| |
| static inline u8 rt2800_get_beacon_offset(struct rt2x00_dev *rt2x00dev, |
| unsigned int index) |
| { |
| return BEACON_BASE_TO_OFFSET(rt2800_hw_beacon_base(rt2x00dev, index)); |
| } |
| |
| static void rt2800_update_beacons_setup(struct rt2x00_dev *rt2x00dev) |
| { |
| struct data_queue *queue = rt2x00dev->bcn; |
| struct queue_entry *entry; |
| int i, bcn_num = 0; |
| u64 off, reg = 0; |
| u32 bssid_dw1; |
| |
| /* |
| * Setup offsets of all active beacons in BCN_OFFSET{0,1} registers. |
| */ |
| for (i = 0; i < queue->limit; i++) { |
| entry = &queue->entries[i]; |
| if (!test_bit(ENTRY_BCN_ENABLED, &entry->flags)) |
| continue; |
| off = rt2800_get_beacon_offset(rt2x00dev, entry->entry_idx); |
| reg |= off << (8 * bcn_num); |
| bcn_num++; |
| } |
| |
| WARN_ON_ONCE(bcn_num != rt2x00dev->intf_beaconing); |
| |
| rt2800_register_write(rt2x00dev, BCN_OFFSET0, (u32) reg); |
| rt2800_register_write(rt2x00dev, BCN_OFFSET1, (u32) (reg >> 32)); |
| |
| /* |
| * H/W sends up to MAC_BSSID_DW1_BSS_BCN_NUM + 1 consecutive beacons. |
| */ |
| rt2800_register_read(rt2x00dev, MAC_BSSID_DW1, &bssid_dw1); |
| rt2x00_set_field32(&bssid_dw1, MAC_BSSID_DW1_BSS_BCN_NUM, |
| bcn_num > 0 ? bcn_num - 1 : 0); |
| rt2800_register_write(rt2x00dev, MAC_BSSID_DW1, bssid_dw1); |
| } |
| |
| void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc) |
| { |
| struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; |
| struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); |
| unsigned int beacon_base; |
| unsigned int padding_len; |
| u32 orig_reg, reg; |
| const int txwi_desc_size = entry->queue->winfo_size; |
| |
| /* |
| * Disable beaconing while we are reloading the beacon data, |
| * otherwise we might be sending out invalid data. |
| */ |
| rt2800_register_read(rt2x00dev, BCN_TIME_CFG, ®); |
| orig_reg = reg; |
| rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_GEN, 0); |
| rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg); |
| |
| /* |
| * Add space for the TXWI in front of the skb. |
| */ |
| memset(skb_push(entry->skb, txwi_desc_size), 0, txwi_desc_size); |
| |
| /* |
| * Register descriptor details in skb frame descriptor. |
| */ |
| skbdesc->flags |= SKBDESC_DESC_IN_SKB; |
| skbdesc->desc = entry->skb->data; |
| skbdesc->desc_len = txwi_desc_size; |
| |
| /* |
| * Add the TXWI for the beacon to the skb. |
| */ |
| rt2800_write_tx_data(entry, txdesc); |
| |
| /* |
| * Dump beacon to userspace through debugfs. |
| */ |
| rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_BEACON, entry->skb); |
| |
| /* |
| * Write entire beacon with TXWI and padding to register. |
| */ |
| padding_len = roundup(entry->skb->len, 4) - entry->skb->len; |
| if (padding_len && skb_pad(entry->skb, padding_len)) { |
| rt2x00_err(rt2x00dev, "Failure padding beacon, aborting\n"); |
| /* skb freed by skb_pad() on failure */ |
| entry->skb = NULL; |
| rt2800_register_write(rt2x00dev, BCN_TIME_CFG, orig_reg); |
| return; |
| } |
| |
| beacon_base = rt2800_hw_beacon_base(rt2x00dev, entry->entry_idx); |
| |
| rt2800_register_multiwrite(rt2x00dev, beacon_base, entry->skb->data, |
| entry->skb->len + padding_len); |
| __set_bit(ENTRY_BCN_ENABLED, &entry->flags); |
| |
| /* |
| * Change global beacons settings. |
| */ |
| rt2800_update_beacons_setup(rt2x00dev); |
| |
| /* |
| * Restore beaconing state. |
| */ |
| rt2800_register_write(rt2x00dev, BCN_TIME_CFG, orig_reg); |
| |
| /* |
| * Clean up beacon skb. |
| */ |
| dev_kfree_skb_any(entry->skb); |
| entry->skb = NULL; |
| } |
| EXPORT_SYMBOL_GPL(rt2800_write_beacon); |
| |
| static inline void rt2800_clear_beacon_register(struct rt2x00_dev *rt2x00dev, |
| unsigned int index) |
| { |
| int i; |
| const int txwi_desc_size = rt2x00dev->bcn->winfo_size; |
| unsigned int beacon_base; |
| |
| beacon_base = rt2800_hw_beacon_base(rt2x00dev, index); |
| |
| /* |
| * For the Beacon base registers we only need to clear |
| * the whole TXWI which (when set to 0) will invalidate |
| * the entire beacon. |
| */ |
| for (i = 0; i < txwi_desc_size; i += sizeof(__le32)) |
| rt2800_register_write(rt2x00dev, beacon_base + i, 0); |
| } |
| |
| void rt2800_clear_beacon(struct queue_entry *entry) |
| { |
| struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; |
| u32 orig_reg, reg; |
| |
| /* |
| * Disable beaconing while we are reloading the beacon data, |
| * otherwise we might be sending out invalid data. |
| */ |
| rt2800_register_read(rt2x00dev, BCN_TIME_CFG, &orig_reg); |
| reg = orig_reg; |
| rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_GEN, 0); |
| rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg); |
| |
| /* |
| * Clear beacon. |
| */ |
| rt2800_clear_beacon_register(rt2x00dev, entry->entry_idx); |
| __clear_bit(ENTRY_BCN_ENABLED, &entry->flags); |
| |
| /* |
| * Change global beacons settings. |
| */ |
| rt2800_update_beacons_setup(rt2x00dev); |
| /* |
| * Restore beaconing state. |
| */ |
| rt2800_register_write(rt2x00dev, BCN_TIME_CFG, orig_reg); |
| } |
| EXPORT_SYMBOL_GPL(rt2800_clear_beacon); |
| |
| #ifdef CONFIG_RT2X00_LIB_DEBUGFS |
| const struct rt2x00debug rt2800_rt2x00debug = { |
| .owner = THIS_MODULE, |
| .csr = { |
| .read = rt2800_register_read, |
| .write = rt2800_register_write, |
| .flags = RT2X00DEBUGFS_OFFSET, |
| .word_base = CSR_REG_BASE, |
| .word_size = sizeof(u32), |
| .word_count = CSR_REG_SIZE / sizeof(u32), |
| }, |
| .eeprom = { |
| /* NOTE: The local EEPROM access functions can't |
| * be used here, use the generic versions instead. |
| */ |
| .read = rt2x00_eeprom_read, |
| .write = rt2x00_eeprom_write, |
| .word_base = EEPROM_BASE, |
| .word_size = sizeof(u16), |
| .word_count = EEPROM_SIZE / sizeof(u16), |
| }, |
| .bbp = { |
| .read = rt2800_bbp_read, |
| .write = rt2800_bbp_write, |
| .word_base = BBP_BASE, |
| .word_size = sizeof(u8), |
| .word_count = BBP_SIZE / sizeof(u8), |
| }, |
| .rf = { |
| .read = rt2x00_rf_read, |
| .write = rt2800_rf_write, |
| .word_base = RF_BASE, |
| .word_size = sizeof(u32), |
| .word_count = RF_SIZE / sizeof(u32), |
| }, |
| .rfcsr = { |
| .read = rt2800_rfcsr_read, |
| .write = rt2800_rfcsr_write, |
| .word_base = RFCSR_BASE, |
| .word_size = sizeof(u8), |
| .word_count = RFCSR_SIZE / sizeof(u8), |
| }, |
| }; |
| EXPORT_SYMBOL_GPL(rt2800_rt2x00debug); |
| #endif /* CONFIG_RT2X00_LIB_DEBUGFS */ |
| |
| int rt2800_rfkill_poll(struct rt2x00_dev *rt2x00dev) |
| { |
| u32 reg; |
| |
| if (rt2x00_rt(rt2x00dev, RT3290)) { |
| rt2800_register_read(rt2x00dev, WLAN_FUN_CTRL, ®); |
| return rt2x00_get_field32(reg, WLAN_GPIO_IN_BIT0); |
| } else { |
| rt2800_register_read(rt2x00dev, GPIO_CTRL, ®); |
| return rt2x00_get_field32(reg, GPIO_CTRL_VAL2); |
| } |
| } |
| EXPORT_SYMBOL_GPL(rt2800_rfkill_poll); |
| |
| #ifdef CONFIG_RT2X00_LIB_LEDS |
| static void rt2800_brightness_set(struct led_classdev *led_cdev, |
| enum led_brightness brightness) |
| { |
| struct rt2x00_led *led = |
| container_of(led_cdev, struct rt2x00_led, led_dev); |
| unsigned int enabled = brightness != LED_OFF; |
| unsigned int bg_mode = |
| (enabled && led->rt2x00dev->curr_band == IEEE80211_BAND_2GHZ); |
| unsigned int polarity = |
| rt2x00_get_field16(led->rt2x00dev->led_mcu_reg, |
| EEPROM_FREQ_LED_POLARITY); |
| unsigned int ledmode = |
| rt2x00_get_field16(led->rt2x00dev->led_mcu_reg, |
| EEPROM_FREQ_LED_MODE); |
| u32 reg; |
| |
| /* Check for SoC (SOC devices don't support MCU requests) */ |
| if (rt2x00_is_soc(led->rt2x00dev)) { |
| rt2800_register_read(led->rt2x00dev, LED_CFG, ®); |
| |
| /* Set LED Polarity */ |
| rt2x00_set_field32(®, LED_CFG_LED_POLAR, polarity); |
| |
| /* Set LED Mode */ |
| if (led->type == LED_TYPE_RADIO) { |
| rt2x00_set_field32(®, LED_CFG_G_LED_MODE, |
| enabled ? 3 : 0); |
| } else if (led->type == LED_TYPE_ASSOC) { |
| rt2x00_set_field32(®, LED_CFG_Y_LED_MODE, |
| enabled ? 3 : 0); |
| } else if (led->type == LED_TYPE_QUALITY) { |
| rt2x00_set_field32(®, LED_CFG_R_LED_MODE, |
| enabled ? 3 : 0); |
| } |
| |
| rt2800_register_write(led->rt2x00dev, LED_CFG, reg); |
| |
| } else { |
| if (led->type == LED_TYPE_RADIO) { |
| rt2800_mcu_request(led->rt2x00dev, MCU_LED, 0xff, ledmode, |
| enabled ? 0x20 : 0); |
| } else if (led->type == LED_TYPE_ASSOC) { |
| rt2800_mcu_request(led->rt2x00dev, MCU_LED, 0xff, ledmode, |
| enabled ? (bg_mode ? 0x60 : 0xa0) : 0x20); |
| } else if (led->type == LED_TYPE_QUALITY) { |
| /* |
| * The brightness is divided into 6 levels (0 - 5), |
| * The specs tell us the following levels: |
| * 0, 1 ,3, 7, 15, 31 |
| * to determine the level in a simple way we can simply |
| * work with bitshifting: |
| * (1 << level) - 1 |
| */ |
| rt2800_mcu_request(led->rt2x00dev, MCU_LED_STRENGTH, 0xff, |
| (1 << brightness / (LED_FULL / 6)) - 1, |
| polarity); |
| } |
| } |
| } |
| |
| static void rt2800_init_led(struct rt2x00_dev *rt2x00dev, |
| struct rt2x00_led *led, enum led_type type) |
| { |
| led->rt2x00dev = rt2x00dev; |
| led->type = type; |
| led->led_dev.brightness_set = rt2800_brightness_set; |
| led->flags = LED_INITIALIZED; |
| } |
| #endif /* CONFIG_RT2X00_LIB_LEDS */ |
| |
| /* |
| * Configuration handlers. |
| */ |
| static void rt2800_config_wcid(struct rt2x00_dev *rt2x00dev, |
| const u8 *address, |
| int wcid) |
| { |
| struct mac_wcid_entry wcid_entry; |
| u32 offset; |
| |
| offset = MAC_WCID_ENTRY(wcid); |
| |
| memset(&wcid_entry, 0xff, sizeof(wcid_entry)); |
| if (address) |
| memcpy(wcid_entry.mac, address, ETH_ALEN); |
| |
| rt2800_register_multiwrite(rt2x00dev, offset, |
| &wcid_entry, sizeof(wcid_entry)); |
| } |
| |
| static void rt2800_delete_wcid_attr(struct rt2x00_dev *rt2x00dev, int wcid) |
| { |
| u32 offset; |
| offset = MAC_WCID_ATTR_ENTRY(wcid); |
| rt2800_register_write(rt2x00dev, offset, 0); |
| } |
| |
| static void rt2800_config_wcid_attr_bssidx(struct rt2x00_dev *rt2x00dev, |
| int wcid, u32 bssidx) |
| { |
| u32 offset = MAC_WCID_ATTR_ENTRY(wcid); |
| u32 reg; |
| |
| /* |
| * The BSS Idx numbers is split in a main value of 3 bits, |
| * and a extended field for adding one additional bit to the value. |
| */ |
| rt2800_register_read(rt2x00dev, offset, ®); |
| rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_BSS_IDX, (bssidx & 0x7)); |
| rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_BSS_IDX_EXT, |
| (bssidx & 0x8) >> 3); |
| rt2800_register_write(rt2x00dev, offset, reg); |
| } |
| |
| static void rt2800_config_wcid_attr_cipher(struct rt2x00_dev *rt2x00dev, |
| struct rt2x00lib_crypto *crypto, |
| struct ieee80211_key_conf *key) |
| { |
| struct mac_iveiv_entry iveiv_entry; |
| u32 offset; |
| u32 reg; |
| |
| offset = MAC_WCID_ATTR_ENTRY(key->hw_key_idx); |
| |
| if (crypto->cmd == SET_KEY) { |
| rt2800_register_read(rt2x00dev, offset, ®); |
| rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_KEYTAB, |
| !!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)); |
| /* |
| * Both the cipher as the BSS Idx numbers are split in a main |
| * value of 3 bits, and a extended field for adding one additional |
| * bit to the value. |
| */ |
| rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_CIPHER, |
| (crypto->cipher & 0x7)); |
| rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_CIPHER_EXT, |
| (crypto->cipher & 0x8) >> 3); |
| rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_RX_WIUDF, crypto->cipher); |
| rt2800_register_write(rt2x00dev, offset, reg); |
| } else { |
| /* Delete the cipher without touching the bssidx */ |
| rt2800_register_read(rt2x00dev, offset, ®); |
| rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_KEYTAB, 0); |
| rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_CIPHER, 0); |
| rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_CIPHER_EXT, 0); |
| rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_RX_WIUDF, 0); |
| rt2800_register_write(rt2x00dev, offset, reg); |
| } |
| |
| offset = MAC_IVEIV_ENTRY(key->hw_key_idx); |
| |
| memset(&iveiv_entry, 0, sizeof(iveiv_entry)); |
| if ((crypto->cipher == CIPHER_TKIP) || |
| (crypto->cipher == CIPHER_TKIP_NO_MIC) || |
| (crypto->cipher == CIPHER_AES)) |
| iveiv_entry.iv[3] |= 0x20; |
| iveiv_entry.iv[3] |= key->keyidx << 6; |
| rt2800_register_multiwrite(rt2x00dev, offset, |
| &iveiv_entry, sizeof(iveiv_entry)); |
| } |
| |
| int rt2800_config_shared_key(struct rt2x00_dev *rt2x00dev, |
| struct rt2x00lib_crypto *crypto, |
| struct ieee80211_key_conf *key) |
| { |
| struct hw_key_entry key_entry; |
| struct rt2x00_field32 field; |
| u32 offset; |
| u32 reg; |
| |
| if (crypto->cmd == SET_KEY) { |
| key->hw_key_idx = (4 * crypto->bssidx) + key->keyidx; |
| |
| memcpy(key_entry.key, crypto->key, |
| sizeof(key_entry.key)); |
| memcpy(key_entry.tx_mic, crypto->tx_mic, |
| sizeof(key_entry.tx_mic)); |
| memcpy(key_entry.rx_mic, crypto->rx_mic, |
| sizeof(key_entry.rx_mic)); |
| |
| offset = SHARED_KEY_ENTRY(key->hw_key_idx); |
| rt2800_register_multiwrite(rt2x00dev, offset, |
| &key_entry, sizeof(key_entry)); |
| } |
| |
| /* |
| * The cipher types are stored over multiple registers |
| * starting with SHARED_KEY_MODE_BASE each word will have |
| * 32 bits and contains the cipher types for 2 bssidx each. |
| * Using the correct defines correctly will cause overhead, |
| * so just calculate the correct offset. |
| */ |
| field.bit_offset = 4 * (key->hw_key_idx % 8); |
| field.bit_mask = 0x7 << field.bit_offset; |
| |
| offset = SHARED_KEY_MODE_ENTRY(key->hw_key_idx / 8); |
| |
| rt2800_register_read(rt2x00dev, offset, ®); |
| rt2x00_set_field32(®, field, |
| (crypto->cmd == SET_KEY) * crypto->cipher); |
| rt2800_register_write(rt2x00dev, offset, reg); |
| |
| /* |
| * Update WCID information |
| */ |
| rt2800_config_wcid(rt2x00dev, crypto->address, key->hw_key_idx); |
| rt2800_config_wcid_attr_bssidx(rt2x00dev, key->hw_key_idx, |
| crypto->bssidx); |
| rt2800_config_wcid_attr_cipher(rt2x00dev, crypto, key); |
| |
| return 0; |
| } |
| EXPORT_SYMBOL_GPL(rt2800_config_shared_key); |
| |
| int rt2800_config_pairwise_key(struct rt2x00_dev *rt2x00dev, |
| struct rt2x00lib_crypto *crypto, |
| struct ieee80211_key_conf *key) |
| { |
| struct hw_key_entry key_entry; |
| u32 offset; |
| |
| if (crypto->cmd == SET_KEY) { |
| /* |
| * Allow key configuration only for STAs that are |
| * known by the hw. |
| */ |
| if (crypto->wcid > WCID_END) |
| return -ENOSPC; |
| key->hw_key_idx = crypto->wcid; |
| |
| memcpy(key_entry.key, crypto->key, |
| sizeof(key_entry.key)); |
| memcpy(key_entry.tx_mic, crypto->tx_mic, |
| sizeof(key_entry.tx_mic)); |
| memcpy(key_entry.rx_mic, crypto->rx_mic, |
| sizeof(key_entry.rx_mic)); |
| |
| offset = PAIRWISE_KEY_ENTRY(key->hw_key_idx); |
| rt2800_register_multiwrite(rt2x00dev, offset, |
| &key_entry, sizeof(key_entry)); |
| } |
| |
| /* |
| * Update WCID information |
| */ |
| rt2800_config_wcid_attr_cipher(rt2x00dev, crypto, key); |
| |
| return 0; |
| } |
| EXPORT_SYMBOL_GPL(rt2800_config_pairwise_key); |
| |
| int rt2800_sta_add(struct rt2x00_dev *rt2x00dev, struct ieee80211_vif *vif, |
| struct ieee80211_sta *sta) |
| { |
| int wcid; |
| struct rt2x00_sta *sta_priv = sta_to_rt2x00_sta(sta); |
| struct rt2800_drv_data *drv_data = rt2x00dev->drv_data; |
| |
| /* |
| * Search for the first free WCID entry and return the corresponding |
| * index. |
| */ |
| wcid = find_first_zero_bit(drv_data->sta_ids, STA_IDS_SIZE) + WCID_START; |
| |
| /* |
| * Store selected wcid even if it is invalid so that we can |
| * later decide if the STA is uploaded into the hw. |
| */ |
| sta_priv->wcid = wcid; |
| |
| /* |
| * No space left in the device, however, we can still communicate |
| * with the STA -> No error. |
| */ |
| if (wcid > WCID_END) |
| return 0; |
| |
| __set_bit(wcid - WCID_START, drv_data->sta_ids); |
| |
| /* |
| * Clean up WCID attributes and write STA address to the device. |
| */ |
| rt2800_delete_wcid_attr(rt2x00dev, wcid); |
| rt2800_config_wcid(rt2x00dev, sta->addr, wcid); |
| rt2800_config_wcid_attr_bssidx(rt2x00dev, wcid, |
| rt2x00lib_get_bssidx(rt2x00dev, vif)); |
| return 0; |
| } |
| EXPORT_SYMBOL_GPL(rt2800_sta_add); |
| |
| int rt2800_sta_remove(struct rt2x00_dev *rt2x00dev, int wcid) |
| { |
| struct rt2800_drv_data *drv_data = rt2x00dev->drv_data; |
| |
| if (wcid > WCID_END) |
| return 0; |
| /* |
| * Remove WCID entry, no need to clean the attributes as they will |
| * get renewed when the WCID is reused. |
| */ |
| rt2800_config_wcid(rt2x00dev, NULL, wcid); |
| __clear_bit(wcid - WCID_START, drv_data->sta_ids); |
| |
| return 0; |
| } |
| EXPORT_SYMBOL_GPL(rt2800_sta_remove); |
| |
| void rt2800_config_filter(struct rt2x00_dev *rt2x00dev, |
| const unsigned int filter_flags) |
| { |
| u32 reg; |
| |
| /* |
| * Start configuration steps. |
| * Note that the version error will always be dropped |
| * and broadcast frames will always be accepted since |
| * there is no filter for it at this time. |
| */ |
| rt2800_register_read(rt2x00dev, RX_FILTER_CFG, ®); |
| rt2x00_set_field32(®, RX_FILTER_CFG_DROP_CRC_ERROR, |
| !(filter_flags & FIF_FCSFAIL)); |
| rt2x00_set_field32(®, RX_FILTER_CFG_DROP_PHY_ERROR, |
| !(filter_flags & FIF_PLCPFAIL)); |
| rt2x00_set_field32(®, RX_FILTER_CFG_DROP_NOT_TO_ME, 1); |
| rt2x00_set_field32(®, RX_FILTER_CFG_DROP_NOT_MY_BSSD, 0); |
| rt2x00_set_field32(®, RX_FILTER_CFG_DROP_VER_ERROR, 1); |
| rt2x00_set_field32(®, RX_FILTER_CFG_DROP_MULTICAST, |
| !(filter_flags & FIF_ALLMULTI)); |
| rt2x00_set_field32(®, RX_FILTER_CFG_DROP_BROADCAST, 0); |
| rt2x00_set_field32(®, RX_FILTER_CFG_DROP_DUPLICATE, 1); |
| rt2x00_set_field32(®, RX_FILTER_CFG_DROP_CF_END_ACK, |
| !(filter_flags & FIF_CONTROL)); |
| rt2x00_set_field32(®, RX_FILTER_CFG_DROP_CF_END, |
| !(filter_flags & FIF_CONTROL)); |
| rt2x00_set_field32(®, RX_FILTER_CFG_DROP_ACK, |
| !(filter_flags & FIF_CONTROL)); |
| rt2x00_set_field32(®, RX_FILTER_CFG_DROP_CTS, |
| !(filter_flags & FIF_CONTROL)); |
| rt2x00_set_field32(®, RX_FILTER_CFG_DROP_RTS, |
| !(filter_flags & FIF_CONTROL)); |
| rt2x00_set_field32(®, RX_FILTER_CFG_DROP_PSPOLL, |
| !(filter_flags & FIF_PSPOLL)); |
| rt2x00_set_field32(®, RX_FILTER_CFG_DROP_BA, 0); |
| rt2x00_set_field32(®, RX_FILTER_CFG_DROP_BAR, |
| !(filter_flags & FIF_CONTROL)); |
| rt2x00_set_field32(®, RX_FILTER_CFG_DROP_CNTL, |
| !(filter_flags & FIF_CONTROL)); |
| rt2800_register_write(rt2x00dev, RX_FILTER_CFG, reg); |
| } |
| EXPORT_SYMBOL_GPL(rt2800_config_filter); |
| |
| void rt2800_config_intf(struct rt2x00_dev *rt2x00dev, struct rt2x00_intf *intf, |
| struct rt2x00intf_conf *conf, const unsigned int flags) |
| { |
| u32 reg; |
| bool update_bssid = false; |
| |
| if (flags & CONFIG_UPDATE_TYPE) { |
| /* |
| * Enable synchronisation. |
| */ |
| rt2800_register_read(rt2x00dev, BCN_TIME_CFG, ®); |
| rt2x00_set_field32(®, BCN_TIME_CFG_TSF_SYNC, conf->sync); |
| rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg); |
| |
| if (conf->sync == TSF_SYNC_AP_NONE) { |
| /* |
| * Tune beacon queue transmit parameters for AP mode |
| */ |
| rt2800_register_read(rt2x00dev, TBTT_SYNC_CFG, ®); |
| rt2x00_set_field32(®, TBTT_SYNC_CFG_BCN_CWMIN, 0); |
| rt2x00_set_field32(®, TBTT_SYNC_CFG_BCN_AIFSN, 1); |
| rt2x00_set_field32(®, TBTT_SYNC_CFG_BCN_EXP_WIN, 32); |
| rt2x00_set_field32(®, TBTT_SYNC_CFG_TBTT_ADJUST, 0); |
| rt2800_register_write(rt2x00dev, TBTT_SYNC_CFG, reg); |
| } else { |
| rt2800_register_read(rt2x00dev, TBTT_SYNC_CFG, ®); |
| rt2x00_set_field32(®, TBTT_SYNC_CFG_BCN_CWMIN, 4); |
| rt2x00_set_field32(®, TBTT_SYNC_CFG_BCN_AIFSN, 2); |
| rt2x00_set_field32(®, TBTT_SYNC_CFG_BCN_EXP_WIN, 32); |
| rt2x00_set_field32(®, TBTT_SYNC_CFG_TBTT_ADJUST, 16); |
| rt2800_register_write(rt2x00dev, TBTT_SYNC_CFG, reg); |
| } |
| } |
| |
| if (flags & CONFIG_UPDATE_MAC) { |
| if (flags & CONFIG_UPDATE_TYPE && |
| conf->sync == TSF_SYNC_AP_NONE) { |
| /* |
| * The BSSID register has to be set to our own mac |
| * address in AP mode. |
| */ |
| memcpy(conf->bssid, conf->mac, sizeof(conf->mac)); |
| update_bssid = true; |
| } |
| |
| if (!is_zero_ether_addr((const u8 *)conf->mac)) { |
| reg = le32_to_cpu(conf->mac[1]); |
| rt2x00_set_field32(®, MAC_ADDR_DW1_UNICAST_TO_ME_MASK, 0xff); |
| conf->mac[1] = cpu_to_le32(reg); |
| } |
| |
| rt2800_register_multiwrite(rt2x00dev, MAC_ADDR_DW0, |
| conf->mac, sizeof(conf->mac)); |
| } |
| |
| if ((flags & CONFIG_UPDATE_BSSID) || update_bssid) { |
| if (!is_zero_ether_addr((const u8 *)conf->bssid)) { |
| reg = le32_to_cpu(conf->bssid[1]); |
| rt2x00_set_field32(®, MAC_BSSID_DW1_BSS_ID_MASK, 3); |
| rt2x00_set_field32(®, MAC_BSSID_DW1_BSS_BCN_NUM, 0); |
| conf->bssid[1] = cpu_to_le32(reg); |
| } |
| |
| rt2800_register_multiwrite(rt2x00dev, MAC_BSSID_DW0, |
| conf->bssid, sizeof(conf->bssid)); |
| } |
| } |
| EXPORT_SYMBOL_GPL(rt2800_config_intf); |
| |
| static void rt2800_config_ht_opmode(struct rt2x00_dev *rt2x00dev, |
| struct rt2x00lib_erp *erp) |
| { |
| bool any_sta_nongf = !!(erp->ht_opmode & |
| IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT); |
| u8 protection = erp->ht_opmode & IEEE80211_HT_OP_MODE_PROTECTION; |
| u8 mm20_mode, mm40_mode, gf20_mode, gf40_mode; |
| u16 mm20_rate, mm40_rate, gf20_rate, gf40_rate; |
| u32 reg; |
| |
| /* default protection rate for HT20: OFDM 24M */ |
| mm20_rate = gf20_rate = 0x4004; |
| |
| /* default protection rate for HT40: duplicate OFDM 24M */ |
| mm40_rate = gf40_rate = 0x4084; |
| |
| switch (protection) { |
| case IEEE80211_HT_OP_MODE_PROTECTION_NONE: |
| /* |
| * All STAs in this BSS are HT20/40 but there might be |
| * STAs not supporting greenfield mode. |
| * => Disable protection for HT transmissions. |
| */ |
| mm20_mode = mm40_mode = gf20_mode = gf40_mode = 0; |
| |
| break; |
| case IEEE80211_HT_OP_MODE_PROTECTION_20MHZ: |
| /* |
| * All STAs in this BSS are HT20 or HT20/40 but there |
| * might be STAs not supporting greenfield mode. |
| * => Protect all HT40 transmissions. |
| */ |
| mm20_mode = gf20_mode = 0; |
| mm40_mode = gf40_mode = 2; |
| |
| break; |
| case IEEE80211_HT_OP_MODE_PROTECTION_NONMEMBER: |
| /* |
| * Nonmember protection: |
| * According to 802.11n we _should_ protect all |
| * HT transmissions (but we don't have to). |
| * |
| * But if cts_protection is enabled we _shall_ protect |
| * all HT transmissions using a CCK rate. |
| * |
| * And if any station is non GF we _shall_ protect |
| * GF transmissions. |
| * |
| * We decide to protect everything |
| * -> fall through to mixed mode. |
| */ |
| case IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED: |
| /* |
| * Legacy STAs are present |
| * => Protect all HT transmissions. |
| */ |
| mm20_mode = mm40_mode = gf20_mode = gf40_mode = 2; |
| |
| /* |
| * If erp protection is needed we have to protect HT |
| * transmissions with CCK 11M long preamble. |
| */ |
| if (erp->cts_protection) { |
| /* don't duplicate RTS/CTS in CCK mode */ |
| mm20_rate = mm40_rate = 0x0003; |
| gf20_rate = gf40_rate = 0x0003; |
| } |
| break; |
| } |
| |
| /* check for STAs not supporting greenfield mode */ |
| if (any_sta_nongf) |
| gf20_mode = gf40_mode = 2; |
| |
| /* Update HT protection config */ |
| rt2800_register_read(rt2x00dev, MM20_PROT_CFG, ®); |
| rt2x00_set_field32(®, MM20_PROT_CFG_PROTECT_RATE, mm20_rate); |
| rt2x00_set_field32(®, MM20_PROT_CFG_PROTECT_CTRL, mm20_mode); |
| rt2800_register_write(rt2x00dev, MM20_PROT_CFG, reg); |
| |
| rt2800_register_read(rt2x00dev, MM40_PROT_CFG, ®); |
| rt2x00_set_field32(®, MM40_PROT_CFG_PROTECT_RATE, mm40_rate); |
| rt2x00_set_field32(®, MM40_PROT_CFG_PROTECT_CTRL, mm40_mode); |
| rt2800_register_write(rt2x00dev, MM40_PROT_CFG, reg); |
| |
| rt2800_register_read(rt2x00dev, GF20_PROT_CFG, ®); |
| rt2x00_set_field32(®, GF20_PROT_CFG_PROTECT_RATE, gf20_rate); |
| rt2x00_set_field32(®, GF20_PROT_CFG_PROTECT_CTRL, gf20_mode); |
| rt2800_register_write(rt2x00dev, GF20_PROT_CFG, reg); |
| |
| rt2800_register_read(rt2x00dev, GF40_PROT_CFG, ®); |
| rt2x00_set_field32(®, GF40_PROT_CFG_PROTECT_RATE, gf40_rate); |
| rt2x00_set_field32(®, GF40_PROT_CFG_PROTECT_CTRL, gf40_mode); |
| rt2800_register_write(rt2x00dev, GF40_PROT_CFG, reg); |
| } |
| |
| void rt2800_config_erp(struct rt2x00_dev *rt2x00dev, struct rt2x00lib_erp *erp, |
| u32 changed) |
| { |
| u32 reg; |
| |
| if (changed & BSS_CHANGED_ERP_PREAMBLE) { |
| rt2800_register_read(rt2x00dev, AUTO_RSP_CFG, ®); |
| rt2x00_set_field32(®, AUTO_RSP_CFG_BAC_ACK_POLICY, |
| !!erp->short_preamble); |
| rt2x00_set_field32(®, AUTO_RSP_CFG_AR_PREAMBLE, |
| !!erp->short_preamble); |
| rt2800_register_write(rt2x00dev, AUTO_RSP_CFG, reg); |
| } |
| |
| if (changed & BSS_CHANGED_ERP_CTS_PROT) { |
| rt2800_register_read(rt2x00dev, OFDM_PROT_CFG, ®); |
| rt2x00_set_field32(®, OFDM_PROT_CFG_PROTECT_CTRL, |
| erp->cts_protection ? 2 : 0); |
| rt2800_register_write(rt2x00dev, OFDM_PROT_CFG, reg); |
| } |
| |
| if (changed & BSS_CHANGED_BASIC_RATES) { |
| rt2800_register_write(rt2x00dev, LEGACY_BASIC_RATE, |
| erp->basic_rates); |
| rt2800_register_write(rt2x00dev, HT_BASIC_RATE, 0x00008003); |
| } |
| |
| if (changed & BSS_CHANGED_ERP_SLOT) { |
| rt2800_register_read(rt2x00dev, BKOFF_SLOT_CFG, ®); |
| rt2x00_set_field32(®, BKOFF_SLOT_CFG_SLOT_TIME, |
| erp->slot_time); |
| rt2800_register_write(rt2x00dev, BKOFF_SLOT_CFG, reg); |
| |
| rt2800_register_read(rt2x00dev, XIFS_TIME_CFG, ®); |
| rt2x00_set_field32(®, XIFS_TIME_CFG_EIFS, erp->eifs); |
| rt2800_register_write(rt2x00dev, XIFS_TIME_CFG, reg); |
| } |
| |
| if (changed & BSS_CHANGED_BEACON_INT) { |
| rt2800_register_read(rt2x00dev, BCN_TIME_CFG, ®); |
| rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_INTERVAL, |
| erp->beacon_int * 16); |
| rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg); |
| } |
| |
| if (changed & BSS_CHANGED_HT) |
| rt2800_config_ht_opmode(rt2x00dev, erp); |
| } |
| EXPORT_SYMBOL_GPL(rt2800_config_erp); |
| |
| static void rt2800_config_3572bt_ant(struct rt2x00_dev *rt2x00dev) |
| { |
| u32 reg; |
| u16 eeprom; |
| u8 led_ctrl, led_g_mode, led_r_mode; |
| |
| rt2800_register_read(rt2x00dev, GPIO_SWITCH, ®); |
| if (rt2x00dev->curr_band == IEEE80211_BAND_5GHZ) { |
| rt2x00_set_field32(®, GPIO_SWITCH_0, 1); |
| rt2x00_set_field32(®, GPIO_SWITCH_1, 1); |
| } else { |
| rt2x00_set_field32(®, GPIO_SWITCH_0, 0); |
| rt2x00_set_field32(®, GPIO_SWITCH_1, 0); |
| } |
| rt2800_register_write(rt2x00dev, GPIO_SWITCH, reg); |
| |
| rt2800_register_read(rt2x00dev, LED_CFG, ®); |
| led_g_mode = rt2x00_get_field32(reg, LED_CFG_LED_POLAR) ? 3 : 0; |
| led_r_mode = rt2x00_get_field32(reg, LED_CFG_LED_POLAR) ? 0 : 3; |
| if (led_g_mode != rt2x00_get_field32(reg, LED_CFG_G_LED_MODE) || |
| led_r_mode != rt2x00_get_field32(reg, LED_CFG_R_LED_MODE)) { |
| rt2800_eeprom_read(rt2x00dev, EEPROM_FREQ, &eeprom); |
| led_ctrl = rt2x00_get_field16(eeprom, EEPROM_FREQ_LED_MODE); |
| if (led_ctrl == 0 || led_ctrl > 0x40) { |
| rt2x00_set_field32(®, LED_CFG_G_LED_MODE, led_g_mode); |
| rt2x00_set_field32(®, LED_CFG_R_LED_MODE, led_r_mode); |
| rt2800_register_write(rt2x00dev, LED_CFG, reg); |
| } else { |
| rt2800_mcu_request(rt2x00dev, MCU_BAND_SELECT, 0xff, |
| (led_g_mode << 2) | led_r_mode, 1); |
| } |
| } |
| } |
| |
| static void rt2800_set_ant_diversity(struct rt2x00_dev *rt2x00dev, |
| enum antenna ant) |
| { |
| u32 reg; |
| u8 eesk_pin = (ant == ANTENNA_A) ? 1 : 0; |
| u8 gpio_bit3 = (ant == ANTENNA_A) ? 0 : 1; |
| |
| if (rt2x00_is_pci(rt2x00dev)) { |
| rt2800_register_read(rt2x00dev, E2PROM_CSR, ®); |
| rt2x00_set_field32(®, E2PROM_CSR_DATA_CLOCK, eesk_pin); |
| rt2800_register_write(rt2x00dev, E2PROM_CSR, reg); |
| } else if (rt2x00_is_usb(rt2x00dev)) |
| rt2800_mcu_request(rt2x00dev, MCU_ANT_SELECT, 0xff, |
| eesk_pin, 0); |
| |
| rt2800_register_read(rt2x00dev, GPIO_CTRL, ®); |
| rt2x00_set_field32(®, GPIO_CTRL_DIR3, 0); |
| rt2x00_set_field32(®, GPIO_CTRL_VAL3, gpio_bit3); |
| rt2800_register_write(rt2x00dev, GPIO_CTRL, reg); |
| } |
| |
| void rt2800_config_ant(struct rt2x00_dev *rt2x00dev, struct antenna_setup *ant) |
| { |
| u8 r1; |
| u8 r3; |
| u16 eeprom; |
| |
| rt2800_bbp_read(rt2x00dev, 1, &r1); |
| rt2800_bbp_read(rt2x00dev, 3, &r3); |
| |
| if (rt2x00_rt(rt2x00dev, RT3572) && |
| rt2x00_has_cap_bt_coexist(rt2x00dev)) |
| rt2800_config_3572bt_ant(rt2x00dev); |
| |
| /* |
| * Configure the TX antenna. |
| */ |
| switch (ant->tx_chain_num) { |
| case 1: |
| rt2x00_set_field8(&r1, BBP1_TX_ANTENNA, 0); |
| break; |
| case 2: |
| if (rt2x00_rt(rt2x00dev, RT3572) && |
| rt2x00_has_cap_bt_coexist(rt2x00dev)) |
| rt2x00_set_field8(&r1, BBP1_TX_ANTENNA, 1); |
| else |
| rt2x00_set_field8(&r1, BBP1_TX_ANTENNA, 2); |
| break; |
| case 3: |
| rt2x00_set_field8(&r1, BBP1_TX_ANTENNA, 2); |
| break; |
| } |
| |
| /* |
| * Configure the RX antenna. |
| */ |
| switch (ant->rx_chain_num) { |
| case 1: |
| if (rt2x00_rt(rt2x00dev, RT3070) || |
| rt2x00_rt(rt2x00dev, RT3090) || |
| rt2x00_rt(rt2x00dev, RT3352) || |
| rt2x00_rt(rt2x00dev, RT3390)) { |
| rt2800_eeprom_read(rt2x00dev, |
| EEPROM_NIC_CONF1, &eeprom); |
| if (rt2x00_get_field16(eeprom, |
| EEPROM_NIC_CONF1_ANT_DIVERSITY)) |
| rt2800_set_ant_diversity(rt2x00dev, |
| rt2x00dev->default_ant.rx); |
| } |
| rt2x00_set_field8(&r3, BBP3_RX_ANTENNA, 0); |
| break; |
| case 2: |
| if (rt2x00_rt(rt2x00dev, RT3572) && |
| rt2x00_has_cap_bt_coexist(rt2x00dev)) { |
| rt2x00_set_field8(&r3, BBP3_RX_ADC, 1); |
| rt2x00_set_field8(&r3, BBP3_RX_ANTENNA, |
| rt2x00dev->curr_band == IEEE80211_BAND_5GHZ); |
| rt2800_set_ant_diversity(rt2x00dev, ANTENNA_B); |
| } else { |
| rt2x00_set_field8(&r3, BBP3_RX_ANTENNA, 1); |
| } |
| break; |
| case 3: |
| rt2x00_set_field8(&r3, BBP3_RX_ANTENNA, 2); |
| break; |
| } |
| |
| rt2800_bbp_write(rt2x00dev, 3, r3); |
| rt2800_bbp_write(rt2x00dev, 1, r1); |
| |
| if (rt2x00_rt(rt2x00dev, RT3593)) { |
| if (ant->rx_chain_num == 1) |
| rt2800_bbp_write(rt2x00dev, 86, 0x00); |
| else |
| rt2800_bbp_write(rt2x00dev, 86, 0x46); |
| } |
| } |
| EXPORT_SYMBOL_GPL(rt2800_config_ant); |
| |
| static void rt2800_config_lna_gain(struct rt2x00_dev *rt2x00dev, |
| struct rt2x00lib_conf *libconf) |
| { |
| u16 eeprom; |
| short lna_gain; |
| |
| if (libconf->rf.channel <= 14) { |
| rt2800_eeprom_read(rt2x00dev, EEPROM_LNA, &eeprom); |
| lna_gain = rt2x00_get_field16(eeprom, EEPROM_LNA_BG); |
| } else if (libconf->rf.channel <= 64) { |
| rt2800_eeprom_read(rt2x00dev, EEPROM_LNA, &eeprom); |
| lna_gain = rt2x00_get_field16(eeprom, EEPROM_LNA_A0); |
| } else if (libconf->rf.channel <= 128) { |
| if (rt2x00_rt(rt2x00dev, RT3593)) { |
| rt2800_eeprom_read(rt2x00dev, EEPROM_EXT_LNA2, &eeprom); |
| lna_gain = rt2x00_get_field16(eeprom, |
| EEPROM_EXT_LNA2_A1); |
| } else { |
| rt2800_eeprom_read(rt2x00dev, EEPROM_RSSI_BG2, &eeprom); |
| lna_gain = rt2x00_get_field16(eeprom, |
| EEPROM_RSSI_BG2_LNA_A1); |
| } |
| } else { |
| if (rt2x00_rt(rt2x00dev, RT3593)) { |
| rt2800_eeprom_read(rt2x00dev, EEPROM_EXT_LNA2, &eeprom); |
| lna_gain = rt2x00_get_field16(eeprom, |
| EEPROM_EXT_LNA2_A2); |
| } else { |
| rt2800_eeprom_read(rt2x00dev, EEPROM_RSSI_A2, &eeprom); |
| lna_gain = rt2x00_get_field16(eeprom, |
| EEPROM_RSSI_A2_LNA_A2); |
| } |
| } |
| |
| rt2x00dev->lna_gain = lna_gain; |
| } |
| |
| #define FREQ_OFFSET_BOUND 0x5f |
| |
| static void rt2800_adjust_freq_offset(struct rt2x00_dev *rt2x00dev) |
| { |
| u8 freq_offset, prev_freq_offset; |
| u8 rfcsr, prev_rfcsr; |
| |
| freq_offset = rt2x00_get_field8(rt2x00dev->freq_offset, RFCSR17_CODE); |
| freq_offset = min_t(u8, freq_offset, FREQ_OFFSET_BOUND); |
| |
| rt2800_rfcsr_read(rt2x00dev, 17, &rfcsr); |
| prev_rfcsr = rfcsr; |
| |
| rt2x00_set_field8(&rfcsr, RFCSR17_CODE, freq_offset); |
| if (rfcsr == prev_rfcsr) |
| return; |
| |
| if (rt2x00_is_usb(rt2x00dev)) { |
| rt2800_mcu_request(rt2x00dev, MCU_FREQ_OFFSET, 0xff, |
| freq_offset, prev_rfcsr); |
| return; |
| } |
| |
| prev_freq_offset = rt2x00_get_field8(prev_rfcsr, RFCSR17_CODE); |
| while (prev_freq_offset != freq_offset) { |
| if (prev_freq_offset < freq_offset) |
| prev_freq_offset++; |
| else |
| prev_freq_offset--; |
| |
| rt2x00_set_field8(&rfcsr, RFCSR17_CODE, prev_freq_offset); |
| rt2800_rfcsr_write(rt2x00dev, 17, rfcsr); |
| |
| usleep_range(1000, 1500); |
| } |
| } |
| |
| static void rt2800_config_channel_rf2xxx(struct rt2x00_dev *rt2x00dev, |
| struct ieee80211_conf *conf, |
| struct rf_channel *rf, |
| struct channel_info *info) |
| { |
| rt2x00_set_field32(&rf->rf4, RF4_FREQ_OFFSET, rt2x00dev->freq_offset); |
| |
| if (rt2x00dev->default_ant.tx_chain_num == 1) |
| rt2x00_set_field32(&rf->rf2, RF2_ANTENNA_TX1, 1); |
| |
| if (rt2x00dev->default_ant.rx_chain_num == 1) { |
| rt2x00_set_field32(&rf->rf2, RF2_ANTENNA_RX1, 1); |
| rt2x00_set_field32(&rf->rf2, RF2_ANTENNA_RX2, 1); |
| } else if (rt2x00dev->default_ant.rx_chain_num == 2) |
| rt2x00_set_field32(&rf->rf2, RF2_ANTENNA_RX2, 1); |
| |
| if (rf->channel > 14) { |
| /* |
| * When TX power is below 0, we should increase it by 7 to |
| * make it a positive value (Minimum value is -7). |
| * However this means that values between 0 and 7 have |
| * double meaning, and we should set a 7DBm boost flag. |
| */ |
| rt2x00_set_field32(&rf->rf3, RF3_TXPOWER_A_7DBM_BOOST, |
| (info->default_power1 >= 0)); |
| |
| if (info->default_power1 < 0) |
| info->default_power1 += 7; |
| |
| rt2x00_set_field32(&rf->rf3, RF3_TXPOWER_A, info->default_power1); |
| |
| rt2x00_set_field32(&rf->rf4, RF4_TXPOWER_A_7DBM_BOOST, |
| (info->default_power2 >= 0)); |
| |
| if (info->default_power2 < 0) |
| info->default_power2 += 7; |
| |
| rt2x00_set_field32(&rf->rf4, RF4_TXPOWER_A, info->default_power2); |
| } else { |
| rt2x00_set_field32(&rf->rf3, RF3_TXPOWER_G, info->default_power1); |
| rt2x00_set_field32(&rf->rf4, RF4_TXPOWER_G, info->default_power2); |
| } |
| |
| rt2x00_set_field32(&rf->rf4, RF4_HT40, conf_is_ht40(conf)); |
| |
| rt2800_rf_write(rt2x00dev, 1, rf->rf1); |
| rt2800_rf_write(rt2x00dev, 2, rf->rf2); |
| rt2800_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004); |
| rt2800_rf_write(rt2x00dev, 4, rf->rf4); |
| |
| udelay(200); |
| |
| rt2800_rf_write(rt2x00dev, 1, rf->rf1); |
| rt2800_rf_write(rt2x00dev, 2, rf->rf2); |
| rt2800_rf_write(rt2x00dev, 3, rf->rf3 | 0x00000004); |
| rt2800_rf_write(rt2x00dev, 4, rf->rf4); |
| |
| udelay(200); |
| |
| rt2800_rf_write(rt2x00dev, 1, rf->rf1); |
| rt2800_rf_write(rt2x00dev, 2, rf->rf2); |
| rt2800_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004); |
| rt2800_rf_write(rt2x00dev, 4, rf->rf4); |
| } |
| |
| static void rt2800_config_channel_rf3xxx(struct rt2x00_dev *rt2x00dev, |
| struct ieee80211_conf *conf, |
| struct rf_channel *rf, |
| struct channel_info *info) |
| { |
| struct rt2800_drv_data *drv_data = rt2x00dev->drv_data; |
| u8 rfcsr, calib_tx, calib_rx; |
| |
| rt2800_rfcsr_write(rt2x00dev, 2, rf->rf1); |
| |
| rt2800_rfcsr_read(rt2x00dev, 3, &rfcsr); |
| rt2x00_set_field8(&rfcsr, RFCSR3_K, rf->rf3); |
| rt2800_rfcsr_write(rt2x00dev, 3, rfcsr); |
| |
| rt2800_rfcsr_read(rt2x00dev, 6, &rfcsr); |
| rt2x00_set_field8(&rfcsr, RFCSR6_R1, rf->rf2); |
| rt2800_rfcsr_write(rt2x00dev, 6, rfcsr); |
| |
| rt2800_rfcsr_read(rt2x00dev, 12, &rfcsr); |
| rt2x00_set_field8(&rfcsr, RFCSR12_TX_POWER, info->default_power1); |
| rt2800_rfcsr_write(rt2x00dev, 12, rfcsr); |
| |
| rt2800_rfcsr_read(rt2x00dev, 13, &rfcsr); |
| rt2x00_set_field8(&rfcsr, RFCSR13_TX_POWER, info->default_power2); |
| rt2800_rfcsr_write(rt2x00dev, 13, rfcsr); |
| |
| rt2800_rfcsr_read(rt2x00dev, 1, &rfcsr); |
| rt2x00_set_field8(&rfcsr, RFCSR1_RX0_PD, 0); |
| rt2x00_set_field8(&rfcsr, RFCSR1_RX1_PD, |
| rt2x00dev->default_ant.rx_chain_num <= 1); |
| rt2x00_set_field8(&rfcsr, RFCSR1_RX2_PD, |
| rt2x00dev->default_ant.rx_chain_num <= 2); |
| rt2x00_set_field8(&rfcsr, RFCSR1_TX0_PD, 0); |
| rt2x00_set_field8(&rfcsr, RFCSR1_TX1_PD, |
| rt2x00dev->default_ant.tx_chain_num <= 1); |
| rt2x00_set_field8(&rfcsr, RFCSR1_TX2_PD, |
| rt2x00dev->default_ant.tx_chain_num <= 2); |
| rt2800_rfcsr_write(rt2x00dev, 1, rfcsr); |
| |
| rt2800_rfcsr_read(rt2x00dev, 23, &rfcsr); |
| rt2x00_set_field8(&rfcsr, RFCSR23_FREQ_OFFSET, rt2x00dev->freq_offset); |
| rt2800_rfcsr_write(rt2x00dev, 23, rfcsr); |
| |
| if (rt2x00_rt(rt2x00dev, RT3390)) { |
| calib_tx = conf_is_ht40(conf) ? 0x68 : 0x4f; |
| calib_rx = conf_is_ht40(conf) ? 0x6f : 0x4f; |
| } else { |
| if (conf_is_ht40(conf)) { |
| calib_tx = drv_data->calibration_bw40; |
| calib_rx = drv_data->calibration_bw40; |
| } else { |
| calib_tx = drv_data->calibration_bw20; |
| calib_rx = drv_data->calibration_bw20; |
| } |
| } |
| |
| rt2800_rfcsr_read(rt2x00dev, 24, &rfcsr); |
| rt2x00_set_field8(&rfcsr, RFCSR24_TX_CALIB, calib_tx); |
| rt2800_rfcsr_write(rt2x00dev, 24, rfcsr); |
| |
| rt2800_rfcsr_read(rt2x00dev, 31, &rfcsr); |
| rt2x00_set_field8(&rfcsr, RFCSR31_RX_CALIB, calib_rx); |
| rt2800_rfcsr_write(rt2x00dev, 31, rfcsr); |
| |
| rt2800_rfcsr_read(rt2x00dev, 7, &rfcsr); |
| rt2x00_set_field8(&rfcsr, RFCSR7_RF_TUNING, 1); |
| rt2800_rfcsr_write(rt2x00dev, 7, rfcsr); |
| |
| rt2800_rfcsr_read(rt2x00dev, 30, &rfcsr); |
| rt2x00_set_field8(&rfcsr, RFCSR30_RF_CALIBRATION, 1); |
| rt2800_rfcsr_write(rt2x00dev, 30, rfcsr); |
| msleep(1); |
| rt2x00_set_field8(&rfcsr, RFCSR30_RF_CALIBRATION, 0); |
| rt2800_rfcsr_write(rt2x00dev, 30, rfcsr); |
| } |
| |
| static void rt2800_config_channel_rf3052(struct rt2x00_dev *rt2x00dev, |
| struct ieee80211_conf *conf, |
| struct rf_channel *rf, |
| struct channel_info *info) |
| { |
| struct rt2800_drv_data *drv_data = rt2x00dev->drv_data; |
| u8 rfcsr; |
| u32 reg; |
| |
| if (rf->channel <= 14) { |
| rt2800_bbp_write(rt2x00dev, 25, drv_data->bbp25); |
| rt2800_bbp_write(rt2x00dev, 26, drv_data->bbp26); |
| } else { |
| rt2800_bbp_write(rt2x00dev, 25, 0x09); |
| rt2800_bbp_write(rt2x00dev, 26, 0xff); |
| } |
| |
| rt2800_rfcsr_write(rt2x00dev, 2, rf->rf1); |
| rt2800_rfcsr_write(rt2x00dev, 3, rf->rf3); |
| |
| rt2800_rfcsr_read(rt2x00dev, 6, &rfcsr); |
| rt2x00_set_field8(&rfcsr, RFCSR6_R1, rf->rf2); |
| if (rf->channel <= 14) |
| rt2x00_set_field8(&rfcsr, RFCSR6_TXDIV, 2); |
| else |
| rt2x00_set_field8(&rfcsr, RFCSR6_TXDIV, 1); |
| rt2800_rfcsr_write(rt2x00dev, 6, rfcsr); |
| |
| rt2800_rfcsr_read(rt2x00dev, 5, &rfcsr); |
| if (rf->channel <= 14) |
| rt2x00_set_field8(&rfcsr, RFCSR5_R1, 1); |
| else |
| rt2x00_set_field8(&rfcsr, RFCSR5_R1, 2); |
| rt2800_rfcsr_write(rt2x00dev, 5, rfcsr); |
| |
| rt2800_rfcsr_read(rt2x00dev, 12, &rfcsr); |
| if (rf->channel <= 14) { |
| rt2x00_set_field8(&rfcsr, RFCSR12_DR0, 3); |
| rt2x00_set_field8(&rfcsr, RFCSR12_TX_POWER, |
| info->default_power1); |
| } else { |
| rt2x00_set_field8(&rfcsr, RFCSR12_DR0, 7); |
| rt2x00_set_field8(&rfcsr, RFCSR12_TX_POWER, |
| (info->default_power1 & 0x3) | |
| ((info->default_power1 & 0xC) << 1)); |
| } |
| rt2800_rfcsr_write(rt2x00dev, 12, rfcsr); |
| |
| rt2800_rfcsr_read(rt2x00dev, 13, &rfcsr); |
| if (rf->channel <= 14) { |
| rt2x00_set_field8(&rfcsr, RFCSR13_DR0, 3); |
| rt2x00_set_field8(&rfcsr, RFCSR13_TX_POWER, |
| info->default_power2); |
| } else { |
| rt2x00_set_field8(&rfcsr, RFCSR13_DR0, 7); |
| rt2x00_set_field8(&rfcsr, RFCSR13_TX_POWER, |
| (info->default_power2 & 0x3) | |
| ((info->default_power2 & 0xC) << 1)); |
| } |
| rt2800_rfcsr_write(rt2x00dev, 13, rfcsr); |
| |
| rt2800_rfcsr_read(rt2x00dev, 1, &rfcsr); |
| rt2x00_set_field8(&rfcsr, RFCSR1_RX0_PD, 0); |
| rt2x00_set_field8(&rfcsr, RFCSR1_TX0_PD, 0); |
| rt2x00_set_field8(&rfcsr, RFCSR1_RX1_PD, 0); |
| rt2x00_set_field8(&rfcsr, RFCSR1_TX1_PD, 0); |
| rt2x00_set_field8(&rfcsr, RFCSR1_RX2_PD, 0); |
| rt2x00_set_field8(&rfcsr, RFCSR1_TX2_PD, 0); |
| if (rt2x00_has_cap_bt_coexist(rt2x00dev)) { |
| if (rf->channel <= 14) { |
| rt2x00_set_field8(&rfcsr, RFCSR1_RX0_PD, 1); |
| rt2x00_set_field8(&rfcsr, RFCSR1_TX0_PD, 1); |
| } |
| rt2x00_set_field8(&rfcsr, RFCSR1_RX2_PD, 1); |
| rt2x00_set_field8(&rfcsr, RFCSR1_TX2_PD, 1); |
| } else { |
| switch (rt2x00dev->default_ant.tx_chain_num) { |
| case 1: |
| rt2x00_set_field8(&rfcsr, RFCSR1_TX1_PD, 1); |
| case 2: |
| rt2x00_set_field8(&rfcsr, RFCSR1_TX2_PD, 1); |
| break; |
| } |
| |
| switch (rt2x00dev->default_ant.rx_chain_num) { |
| case 1: |
| rt2x00_set_field8(&rfcsr, RFCSR1_RX1_PD, 1); |
| case 2: |
| rt2x00_set_field8(&rfcsr, RFCSR1_RX2_PD, 1); |
| break; |
| } |
| } |
| rt2800_rfcsr_write(rt2x00dev, 1, rfcsr); |
| |
| rt2800_rfcsr_read(rt2x00dev, 23, &rfcsr); |
| rt2x00_set_field8(&rfcsr, RFCSR23_FREQ_OFFSET, rt2x00dev->freq_offset); |
| rt2800_rfcsr_write(rt2x00dev, 23, rfcsr); |
| |
| if (conf_is_ht40(conf)) { |
| rt2800_rfcsr_write(rt2x00dev, 24, drv_data->calibration_bw40); |
| rt2800_rfcsr_write(rt2x00dev, 31, drv_data->calibration_bw40); |
| } else { |
| rt2800_rfcsr_write(rt2x00dev, 24, drv_data->calibration_bw20); |
| rt2800_rfcsr_write(rt2x00dev, 31, drv_data->calibration_bw20); |
| } |
| |
| if (rf->channel <= 14) { |
| rt2800_rfcsr_write(rt2x00dev, 7, 0xd8); |
| rt2800_rfcsr_write(rt2x00dev, 9, 0xc3); |
| rt2800_rfcsr_write(rt2x00dev, 10, 0xf1); |
| rt2800_rfcsr_write(rt2x00dev, 11, 0xb9); |
| rt2800_rfcsr_write(rt2x00dev, 15, 0x53); |
| rfcsr = 0x4c; |
| rt2x00_set_field8(&rfcsr, RFCSR16_TXMIXER_GAIN, |
| drv_data->txmixer_gain_24g); |
| rt2800_rfcsr_write(rt2x00dev, 16, rfcsr); |
| rt2800_rfcsr_write(rt2x00dev, 17, 0x23); |
| rt2800_rfcsr_write(rt2x00dev, 19, 0x93); |
| rt2800_rfcsr_write(rt2x00dev, 20, 0xb3); |
| rt2800_rfcsr_write(rt2x00dev, 25, 0x15); |
| rt2800_rfcsr_write(rt2x00dev, 26, 0x85); |
| rt2800_rfcsr_write(rt2x00dev, 27, 0x00); |
| rt2800_rfcsr_write(rt2x00dev, 29, 0x9b); |
| } else { |
| rt2800_rfcsr_read(rt2x00dev, 7, &rfcsr); |
| rt2x00_set_field8(&rfcsr, RFCSR7_BIT2, 1); |
| rt2x00_set_field8(&rfcsr, RFCSR7_BIT3, 0); |
| rt2x00_set_field8(&rfcsr, RFCSR7_BIT4, 1); |
| rt2x00_set_field8(&rfcsr, RFCSR7_BITS67, 0); |
| rt2800_rfcsr_write(rt2x00dev, 7, rfcsr); |
| rt2800_rfcsr_write(rt2x00dev, 9, 0xc0); |
| rt2800_rfcsr_write(rt2x00dev, 10, 0xf1); |
| rt2800_rfcsr_write(rt2x00dev, 11, 0x00); |
| rt2800_rfcsr_write(rt2x00dev, 15, 0x43); |
| rfcsr = 0x7a; |
| rt2x00_set_field8(&rfcsr, RFCSR16_TXMIXER_GAIN, |
| drv_data->txmixer_gain_5g); |
| rt2800_rfcsr_write(rt2x00dev, 16, rfcsr); |
| rt2800_rfcsr_write(rt2x00dev, 17, 0x23); |
| if (rf->channel <= 64) { |
| rt2800_rfcsr_write(rt2x00dev, 19, 0xb7); |
| rt2800_rfcsr_write(rt2x00dev, 20, 0xf6); |
| rt2800_rfcsr_write(rt2x00dev, 25, 0x3d); |
| } else if (rf->channel <= 128) { |
| rt2800_rfcsr_write(rt2x00dev, 19, 0x74); |
| rt2800_rfcsr_write(rt2x00dev, 20, 0xf4); |
| rt2800_rfcsr_write(rt2x00dev, 25, 0x01); |
| } else { |
| rt2800_rfcsr_write(rt2x00dev, 19, 0x72); |
| rt2800_rfcsr_write(rt2x00dev, 20, 0xf3); |
| rt2800_rfcsr_write(rt2x00dev, 25, 0x01); |
| } |
| rt2800_rfcsr_write(rt2x00dev, 26, 0x87); |
| rt2800_rfcsr_write(rt2x00dev, 27, 0x01); |
| rt2800_rfcsr_write(rt2x00dev, 29, 0x9f); |
| } |
| |
| rt2800_register_read(rt2x00dev, GPIO_CTRL, ®); |
| rt2x00_set_field32(®, GPIO_CTRL_DIR7, 0); |
| if (rf->channel <= 14) |
| rt2x00_set_field32(®, GPIO_CTRL_VAL7, 1); |
| else |
| rt2x00_set_field32(®, GPIO_CTRL_VAL7, 0); |
| rt2800_register_write(rt2x00dev, GPIO_CTRL, reg); |
| |
| rt2800_rfcsr_read(rt2x00dev, 7, &rfcsr); |
| rt2x00_set_field8(&rfcsr, RFCSR7_RF_TUNING, 1); |
| rt2800_rfcsr_write(rt2x00dev, 7, rfcsr); |
| } |
| |
| static void rt2800_config_channel_rf3053(struct rt2x00_dev *rt2x00dev, |
| struct ieee80211_conf *conf, |
| struct rf_channel *rf, |
| struct channel_info *info) |
| { |
| struct rt2800_drv_data *drv_data = rt2x00dev->drv_data; |
| u8 txrx_agc_fc; |
| u8 txrx_h20m; |
| u8 rfcsr; |
| u8 bbp; |
| const bool txbf_enabled = false; /* TODO */ |
| |
| /* TODO: use TX{0,1,2}FinePowerControl values from EEPROM */ |
| rt2800_bbp_read(rt2x00dev, 109, &bbp); |
| rt2x00_set_field8(&bbp, BBP109_TX0_POWER, 0); |
| rt2x00_set_field8(&bbp, BBP109_TX1_POWER, 0); |
| rt2800_bbp_write(rt2x00dev, 109, bbp); |
| |
| rt2800_bbp_read(rt2x00dev, 110, &bbp); |
| rt2x00_set_field8(&bbp, BBP110_TX2_POWER, 0); |
| rt2800_bbp_write(rt2x00dev, 110, bbp); |
| |
| if (rf->channel <= 14) { |
| /* Restore BBP 25 & 26 for 2.4 GHz */ |
| rt2800_bbp_write(rt2x00dev, 25, drv_data->bbp25); |
| rt2800_bbp_write(rt2x00dev, 26, drv_data->bbp26); |
| } else { |
| /* Hard code BBP 25 & 26 for 5GHz */ |
| |
| /* Enable IQ Phase correction */ |
| rt2800_bbp_write(rt2x00dev, 25, 0x09); |
| /* Setup IQ Phase correction value */ |
| rt2800_bbp_write(rt2x00dev, 26, 0xff); |
| } |
| |
| rt2800_rfcsr_write(rt2x00dev, 8, rf->rf1); |
| rt2800_rfcsr_write(rt2x00dev, 9, rf->rf3 & 0xf); |
| |
| rt2800_rfcsr_read(rt2x00dev, 11, &rfcsr); |
| rt2x00_set_field8(&rfcsr, RFCSR11_R, (rf->rf2 & 0x3)); |
| rt2800_rfcsr_write(rt2x00dev, 11, rfcsr); |
| |
| rt2800_rfcsr_read(rt2x00dev, 11, &rfcsr); |
| rt2x00_set_field8(&rfcsr, RFCSR11_PLL_IDOH, 1); |
| if (rf->channel <= 14) |
| rt2x00_set_field8(&rfcsr, RFCSR11_PLL_MOD, 1); |
| else |
| rt2x00_set_field8(&rfcsr, RFCSR11_PLL_MOD, 2); |
| rt2800_rfcsr_write(rt2x00dev, 11, rfcsr); |
| |
| rt2800_rfcsr_read(rt2x00dev, 53, &rfcsr); |
| if (rf->channel <= 14) { |
| rfcsr = 0; |
| rt2x00_set_field8(&rfcsr, RFCSR53_TX_POWER, |
| info->default_power1 & 0x1f); |
| } else { |
| if (rt2x00_is_usb(rt2x00dev)) |
| rfcsr = 0x40; |
| |
| rt2x00_set_field8(&rfcsr, RFCSR53_TX_POWER, |
| ((info->default_power1 & 0x18) << 1) | |
| (info->default_power1 & 7)); |
| } |
| rt2800_rfcsr_write(rt2x00dev, 53, rfcsr); |
| |
| rt2800_rfcsr_read(rt2x00dev, 55, &rfcsr); |
| if (rf->channel <= 14) { |
| rfcsr = 0; |
| rt2x00_set_field8(&rfcsr, RFCSR55_TX_POWER, |
| info->default_power2 & 0x1f); |
| } else { |
| if (rt2x00_is_usb(rt2x00dev)) |
| rfcsr = 0x40; |
| |
| rt2x00_set_field8(&rfcsr, RFCSR55_TX_POWER, |
| ((info->default_power2 & 0x18) << 1) | |
| (info->default_power2 & 7)); |
| } |
| rt2800_rfcsr_write(rt2x00dev, 55, rfcsr); |
| |
| rt2800_rfcsr_read(rt2x00dev, 54, &rfcsr); |
| if (rf->channel <= 14) { |
| rfcsr = 0; |
| rt2x00_set_field8(&rfcsr, RFCSR54_TX_POWER, |
| info->default_power3 & 0x1f); |
| } else { |
| if (rt2x00_is_usb(rt2x00dev)) |
| rfcsr = 0x40; |
| |
| rt2x00_set_field8(&rfcsr, RFCSR54_TX_POWER, |
| ((info->default_power3 & 0x18) << 1) | |
| (info->default_power3 & 7)); |
| } |
| rt2800_rfcsr_write(rt2x00dev, 54, rfcsr); |
| |
| rt2800_rfcsr_read(rt2x00dev, 1, &rfcsr); |
| rt2x00_set_field8(&rfcsr, RFCSR1_RX0_PD, 0); |
| rt2x00_set_field8(&rfcsr, RFCSR1_TX0_PD, 0); |
| rt2x00_set_field8(&rfcsr, RFCSR1_RX1_PD, 0); |
| rt2x00_set_field8(&rfcsr, RFCSR1_TX1_PD, 0); |
| rt2x00_set_field8(&rfcsr, RFCSR1_RX2_PD, 0); |
| rt2x00_set_field8(&rfcsr, RFCSR1_TX2_PD, 0); |
| rt2x00_set_field8(&rfcsr, RFCSR1_RF_BLOCK_EN, 1); |
| rt2x00_set_field8(&rfcsr, RFCSR1_PLL_PD, 1); |
| |
| switch (rt2x00dev->default_ant.tx_chain_num) { |
| case 3: |
| rt2x00_set_field8(&rfcsr, RFCSR1_TX2_PD, 1); |
| /* fallthrough */ |
| case 2: |
| rt2x00_set_field8(&rfcsr, RFCSR1_TX1_PD, 1); |
| /* fallthrough */ |
| case 1: |
| rt2x00_set_field8(&rfcsr, RFCSR1_TX0_PD, 1); |
| break; |
| } |
| |
| switch (rt2x00dev->default_ant.rx_chain_num) { |
| case 3: |
| rt2x00_set_field8(&rfcsr, RFCSR1_RX2_PD, 1); |
| /* fallthrough */ |
| case 2: |
| rt2x00_set_field8(&rfcsr, RFCSR1_RX1_PD, 1); |
| /* fallthrough */ |
| case 1: |
| rt2x00_set_field8(&rfcsr, RFCSR1_RX0_PD, 1); |
| break; |
| } |
| rt2800_rfcsr_write(rt2x00dev, 1, rfcsr); |
| |
| rt2800_adjust_freq_offset(rt2x00dev); |
| |
| if (conf_is_ht40(conf)) { |
| txrx_agc_fc = rt2x00_get_field8(drv_data->calibration_bw40, |
| RFCSR24_TX_AGC_FC); |
| txrx_h20m = rt2x00_get_field8(drv_data->calibration_bw40, |
| RFCSR24_TX_H20M); |
| } else { |
| txrx_agc_fc = rt2x00_get_field8(drv_data->calibration_bw20, |
| RFCSR24_TX_AGC_FC); |
| txrx_h20m = rt2x00_get_field8(drv_data->calibration_bw20, |
| RFCSR24_TX_H20M); |
| } |
| |
| /* NOTE: the reference driver does not writes the new value |
| * back to RFCSR 32 |
| */ |
| rt2800_rfcsr_read(rt2x00dev, 32, &rfcsr); |
| rt2x00_set_field8(&rfcsr, RFCSR32_TX_AGC_FC, txrx_agc_fc); |
| |
| if (rf->channel <= 14) |
| rfcsr = 0xa0; |
| else |
| rfcsr = 0x80; |
| rt2800_rfcsr_write(rt2x00dev, 31, rfcsr); |
| |
| rt2800_rfcsr_read(rt2x00dev, 30, &rfcsr); |
| rt2x00_set_field8(&rfcsr, RFCSR30_TX_H20M, txrx_h20m); |
| rt2x00_set_field8(&rfcsr, RFCSR30_RX_H20M, txrx_h20m); |
| rt2800_rfcsr_write(rt2x00dev, 30, rfcsr); |
| |
| /* Band selection */ |
| rt2800_rfcsr_read(rt2x00dev, 36, &rfcsr); |
| if (rf->channel <= 14) |
| rt2x00_set_field8(&rfcsr, RFCSR36_RF_BS, 1); |
| else |
| rt2x00_set_field8(&rfcsr, RFCSR36_RF_BS, 0); |
| rt2800_rfcsr_write(rt2x00dev, 36, rfcsr); |
| |
| rt2800_rfcsr_read(rt2x00dev, 34, &rfcsr); |
| if (rf->channel <= 14) |
| rfcsr = 0x3c; |
| else |
| rfcsr = 0x20; |
| rt2800_rfcsr_write(rt2x00dev, 34, rfcsr); |
| |
| rt2800_rfcsr_read(rt2x00dev, 12, &rfcsr); |
| if (rf->channel <= 14) |
| rfcsr = 0x1a; |
| else |
| rfcsr = 0x12; |
| rt2800_rfcsr_write(rt2x00dev, 12, rfcsr); |
| |
| rt2800_rfcsr_read(rt2x00dev, 6, &rfcsr); |
| if (rf->channel >= 1 && rf->channel <= 14) |
| rt2x00_set_field8(&rfcsr, RFCSR6_VCO_IC, 1); |
| else if (rf->channel >= 36 && rf->channel <= 64) |
| rt2x00_set_field8(&rfcsr, RFCSR6_VCO_IC, 2); |
| else if (rf->channel >= 100 && rf->channel <= 128) |
| rt2x00_set_field8(&rfcsr, RFCSR6_VCO_IC, 2); |
| else |
| rt2x00_set_field8(&rfcsr, RFCSR6_VCO_IC, 1); |
| rt2800_rfcsr_write(rt2x00dev, 6, rfcsr); |
| |
| rt2800_rfcsr_read(rt2x00dev, 30, &rfcsr); |
| rt2x00_set_field8(&rfcsr, RFCSR30_RX_VCM, 2); |
| rt2800_rfcsr_write(rt2x00dev, 30, rfcsr); |
| |
| rt2800_rfcsr_write(rt2x00dev, 46, 0x60); |
| |
| if (rf->channel <= 14) { |
| rt2800_rfcsr_write(rt2x00dev, 10, 0xd3); |
| rt2800_rfcsr_write(rt2x00dev, 13, 0x12); |
| } else { |
| rt2800_rfcsr_write(rt2x00dev, 10, 0xd8); |
| rt2800_rfcsr_write(rt2x00dev, 13, 0x23); |
| } |
| |
| rt2800_rfcsr_read(rt2x00dev, 51, &rfcsr); |
| rt2x00_set_field8(&rfcsr, RFCSR51_BITS01, 1); |
| rt2800_rfcsr_write(rt2x00dev, 51, rfcsr); |
| |
| rt2800_rfcsr_read(rt2x00dev, 51, &rfcsr); |
| if (rf->channel <= 14) { |
| rt2x00_set_field8(&rfcsr, RFCSR51_BITS24, 5); |
| rt2x00_set_field8(&rfcsr, RFCSR51_BITS57, 3); |
| } else { |
| rt2x00_set_field8(&rfcsr, RFCSR51_BITS24, 4); |
| rt2x00_set_field8(&rfcsr, RFCSR51_BITS57, 2); |
| } |
| rt2800_rfcsr_write(rt2x00dev, 51, rfcsr); |
| |
| rt2800_rfcsr_read(rt2x00dev, 49, &rfcsr); |
| if (rf->channel <= 14) |
| rt2x00_set_field8(&rfcsr, RFCSR49_TX_LO1_IC, 3); |
| else |
| rt2x00_set_field8(&rfcsr, RFCSR49_TX_LO1_IC, 2); |
| |
| if (txbf_enabled) |
| rt2x00_set_field8(&rfcsr, RFCSR49_TX_DIV, 1); |
| |
| rt2800_rfcsr_write(rt2x00dev, 49, rfcsr); |
| |
| rt2800_rfcsr_read(rt2x00dev, 50, &rfcsr); |
| rt2x00_set_field8(&rfcsr, RFCSR50_TX_LO1_EN, 0); |
| rt2800_rfcsr_write(rt2x00dev, 50, rfcsr); |
| |
| rt2800_rfcsr_read(rt2x00dev, 57, &rfcsr); |
| if (rf->channel <= 14) |
| rt2x00_set_field8(&rfcsr, RFCSR57_DRV_CC, 0x1b); |
| else |
| rt2x00_set_field8(&rfcsr, RFCSR57_DRV_CC, 0x0f); |
| rt2800_rfcsr_write(rt2x00dev, 57, rfcsr); |
| |
| if (rf->channel <= 14) { |
| rt2800_rfcsr_write(rt2x00dev, 44, 0x93); |
| rt2800_rfcsr_write(rt2x00dev, 52, 0x45); |
| } else { |
| rt2800_rfcsr_write(rt2x00dev, 44, 0x9b); |
| rt2800_rfcsr_write(rt2x00dev, 52, 0x05); |
| } |
| |
| /* Initiate VCO calibration */ |
| rt2800_rfcsr_read(rt2x00dev, 3, &rfcsr); |
| if (rf->channel <= 14) { |
| rt2x00_set_field8(&rfcsr, RFCSR3_VCOCAL_EN, 1); |
| } else { |
| rt2x00_set_field8(&rfcsr, RFCSR3_BIT1, 1); |
| rt2x00_set_field8(&rfcsr, RFCSR3_BIT2, 1); |
| rt2x00_set_field8(&rfcsr, RFCSR3_BIT3, 1); |
| rt2x00_set_field8(&rfcsr, RFCSR3_BIT4, 1); |
| rt2x00_set_field8(&rfcsr, RFCSR3_BIT5, 1); |
| rt2x00_set_field8(&rfcsr, RFCSR3_VCOCAL_EN, 1); |
| } |
| rt2800_rfcsr_write(rt2x00dev, 3, rfcsr); |
| |
| if (rf->channel >= 1 && rf->channel <= 14) { |
| rfcsr = 0x23; |
| if (txbf_enabled) |
| rt2x00_set_field8(&rfcsr, RFCSR39_RX_DIV, 1); |
| rt2800_rfcsr_write(rt2x00dev, 39, rfcsr); |
| |
| rt2800_rfcsr_write(rt2x00dev, 45, 0xbb); |
| } else if (rf->channel >= 36 && rf->channel <= 64) { |
| rfcsr = 0x36; |
| if (txbf_enabled) |
| rt2x00_set_field8(&rfcsr, RFCSR39_RX_DIV, 1); |
| rt2800_rfcsr_write(rt2x00dev, 39, 0x36); |
| |
| rt2800_rfcsr_write(rt2x00dev, 45, 0xeb); |
| } else if (rf->channel >= 100 && rf->channel <= 128) { |
| rfcsr = 0x32; |
| if (txbf_enabled) |
| rt2x00_set_field8(&rfcsr, RFCSR39_RX_DIV, 1); |
| rt2800_rfcsr_write(rt2x00dev, 39, rfcsr); |
| |
| rt2800_rfcsr_write(rt2x00dev, 45, 0xb3); |
| } else { |
| rfcsr = 0x30; |
| if (txbf_enabled) |
| rt2x00_set_field8(&rfcsr, RFCSR39_RX_DIV, 1); |
| rt2800_rfcsr_write(rt2x00dev, 39, rfcsr); |
| |
| rt2800_rfcsr_write(rt2x00dev, 45, 0x9b); |
| } |
| } |
| |
| #define POWER_BOUND 0x27 |
| #define POWER_BOUND_5G 0x2b |
| |
| static void rt2800_config_channel_rf3290(struct rt2x00_dev *rt2x00dev, |
| struct ieee80211_conf *conf, |
| struct rf_channel *rf, |
| struct channel_info *info) |
| { |
| u8 rfcsr; |
| |
| rt2800_rfcsr_write(rt2x00dev, 8, rf->rf1); |
| rt2800_rfcsr_write(rt2x00dev, 9, rf->rf3); |
| rt2800_rfcsr_read(rt2x00dev, 11, &rfcsr); |
| rt2x00_set_field8(&rfcsr, RFCSR11_R, rf->rf2); |
| rt2800_rfcsr_write(rt2x00dev, 11, rfcsr); |
| |
| rt2800_rfcsr_read(rt2x00dev, 49, &rfcsr); |
| if (info->default_power1 > POWER_BOUND) |
| rt2x00_set_field8(&rfcsr, RFCSR49_TX, POWER_BOUND); |
| else |
| rt2x00_set_field8(&rfcsr, RFCSR49_TX, info->default_power1); |
| rt2800_rfcsr_write(rt2x00dev, 49, rfcsr); |
| |
| rt2800_adjust_freq_offset(rt2x00dev); |
| |
| if (rf->channel <= 14) { |
| if (rf->channel == 6) |
| rt2800_bbp_write(rt2x00dev, 68, 0x0c); |
| else |
| rt2800_bbp_write(rt2x00dev, 68, 0x0b); |
| |
| if (rf->channel >= 1 && rf->channel <= 6) |
| rt2800_bbp_write(rt2x00dev, 59, 0x0f); |
| else if (rf->channel >= 7 && rf->channel <= 11) |
| rt2800_bbp_write(rt2x00dev, 59, 0x0e); |
| else if (rf->channel >= 12 && rf->channel <= 14) |
| rt2800_bbp_write(rt2x00dev, 59, 0x0d); |
| } |
| } |
| |
| static void rt2800_config_channel_rf3322(struct rt2x00_dev *rt2x00dev, |
| struct ieee80211_conf *conf, |
| struct rf_channel *rf, |
| struct channel_info *info) |
| { |
| u8 rfcsr; |
| |
| rt2800_rfcsr_write(rt2x00dev, 8, rf->rf1); |
| rt2800_rfcsr_write(rt2x00dev, 9, rf->rf3); |
| |
| rt2800_rfcsr_write(rt2x00dev, 11, 0x42); |
| rt2800_rfcsr_write(rt2x00dev, 12, 0x1c); |
| rt2800_rfcsr_write(rt2x00dev, 13, 0x00); |
| |
| if (info->default_power1 > POWER_BOUND) |
| rt2800_rfcsr_write(rt2x00dev, 47, POWER_BOUND); |
| else |
| rt2800_rfcsr_write(rt2x00dev, 47, info->default_power1); |
| |
| if (info->default_power2 > POWER_BOUND) |
| rt2800_rfcsr_write(rt2x00dev, 48, POWER_BOUND); |
| else |
| rt2800_rfcsr_write(rt2x00dev, 48, info->default_power2); |
| |
| rt2800_adjust_freq_offset(rt2x00dev); |
| |
| rt2800_rfcsr_read(rt2x00dev, 1, &rfcsr); |
| rt2x00_set_field8(&rfcsr, RFCSR1_RX0_PD, 1); |
| rt2x00_set_field8(&rfcsr, RFCSR1_TX0_PD, 1); |
| |
| if ( rt2x00dev->default_ant.tx_chain_num == 2 ) |
| rt2x00_set_field8(&rfcsr, RFCSR1_TX1_PD, 1); |
| else |
| rt2x00_set_field8(&rfcsr, RFCSR1_TX1_PD, 0); |
| |
| if ( rt2x00dev->default_ant.rx_chain_num == 2 ) |
| rt2x00_set_field8(&rfcsr, RFCSR1_RX1_PD, 1); |
| else |
| rt2x00_set_field8(&rfcsr, RFCSR1_RX1_PD, 0); |
| |
| rt2x00_set_field8(&rfcsr, RFCSR1_RX2_PD, 0); |
| rt2x00_set_field8(&rfcsr, RFCSR1_TX2_PD, 0); |
| |
| rt2800_rfcsr_write(rt2x00dev, 1, rfcsr); |
| |
| rt2800_rfcsr_write(rt2x00dev, 31, 80); |
| } |
| |
| static void rt2800_config_channel_rf53xx(struct rt2x00_dev *rt2x00dev, |
| struct ieee80211_conf *conf, |
| struct rf_channel *rf, |
| struct channel_info *info) |
| { |
| u8 rfcsr; |
| |
| rt2800_rfcsr_write(rt2x00dev, 8, rf->rf1); |
| rt2800_rfcsr_write(rt2x00dev, 9, rf->rf3); |
| rt2800_rfcsr_read(rt2x00dev, 11, &rfcsr); |
| rt2x00_set_field8(&rfcsr, RFCSR11_R, rf->rf2); |
| rt2800_rfcsr_write(rt2x00dev, 11, rfcsr); |
| |
| rt2800_rfcsr_read(rt2x00dev, 49, &rfcsr); |
| if (info->default_power1 > POWER_BOUND) |
| rt2x00_set_field8(&rfcsr, RFCSR49_TX, POWER_BOUND); |
| else |
| rt2x00_set_field8(&rfcsr, RFCSR49_TX, info->default_power1); |
| rt2800_rfcsr_write(rt2x00dev, 49, rfcsr); |
| |
| if (rt2x00_rt(rt2x00dev, RT5392)) { |
| rt2800_rfcsr_read(rt2x00dev, 50, &rfcsr); |
| if (info->default_power2 > POWER_BOUND) |
| rt2x00_set_field8(&rfcsr, RFCSR50_TX, POWER_BOUND); |
| else |
| rt2x00_set_field8(&rfcsr, RFCSR50_TX, |
| info->default_power2); |
| rt2800_rfcsr_write(rt2x00dev, 50, rfcsr); |
| } |
| |
| rt2800_rfcsr_read(rt2x00dev, 1, &rfcsr); |
| if (rt2x00_rt(rt2x00dev, RT5392)) { |
| rt2x00_set_field8(&rfcsr, RFCSR1_RX1_PD, 1); |
| rt2x00_set_field8(&rfcsr, RFCSR1_TX1_PD, 1); |
| } |
| rt2x00_set_field8(&rfcsr, RFCSR1_RF_BLOCK_EN, 1); |
| rt2x00_set_field8(&rfcsr, RFCSR1_PLL_PD, 1); |
| rt2x00_set_field8(&rfcsr, RFCSR1_RX0_PD, 1); |
| rt2x00_set_field8(&rfcsr, RFCSR1_TX0_PD, 1); |
| rt2800_rfcsr_write(rt2x00dev, 1, rfcsr); |
| |
| rt2800_adjust_freq_offset(rt2x00dev); |
| |
| if (rf->channel <= 14) { |
| int idx = rf->channel-1; |
| |
| if (rt2x00_has_cap_bt_coexist(rt2x00dev)) { |
| if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F)) { |
| /* r55/r59 value array of channel 1~14 */ |
| static const char r55_bt_rev[] = {0x83, 0x83, |
| 0x83, 0x73, 0x73, 0x63, 0x53, 0x53, |
| 0x53, 0x43, 0x43, 0x43, 0x43, 0x43}; |
| static const char r59_bt_rev[] = {0x0e, 0x0e, |
| 0x0e, 0x0e, 0x0e, 0x0b, 0x0a, 0x09, |
| 0x07, 0x07, 0x07, 0x07, 0x07, 0x07}; |
| |
| rt2800_rfcsr_write(rt2x00dev, 55, |
| r55_bt_rev[idx]); |
| rt2800_rfcsr_write(rt2x00dev, 59, |
| r59_bt_rev[idx]); |
| } else { |
| static const char r59_bt[] = {0x8b, 0x8b, 0x8b, |
| 0x8b, 0x8b, 0x8b, 0x8b, 0x8a, 0x89, |
| 0x88, 0x88, 0x86, 0x85, 0x84}; |
| |
| rt2800_rfcsr_write(rt2x00dev, 59, r59_bt[idx]); |
| } |
| } else { |
| if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F)) { |
| static const char r55_nonbt_rev[] = {0x23, 0x23, |
| 0x23, 0x23, 0x13, 0x13, 0x03, 0x03, |
| 0x03, 0x03, 0x03, 0x03, 0x03, 0x03}; |
| static const char r59_nonbt_rev[] = {0x07, 0x07, |
| 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, |
| 0x07, 0x07, 0x06, 0x05, 0x04, 0x04}; |
| |
| rt2800_rfcsr_write(rt2x00dev, 55, |
| r55_nonbt_rev[idx]); |
| rt2800_rfcsr_write(rt2x00dev, 59, |
| r59_nonbt_rev[idx]); |
| } else if (rt2x00_rt(rt2x00dev, RT5390) || |
| rt2x00_rt(rt2x00dev, RT5392)) { |
| static const char r59_non_bt[] = {0x8f, 0x8f, |
| 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8d, |
| 0x8a, 0x88, 0x88, 0x87, 0x87, 0x86}; |
| |
| rt2800_rfcsr_write(rt2x00dev, 59, |
| r59_non_bt[idx]); |
| } |
| } |
| } |
| } |
| |
| static void rt2800_config_channel_rf55xx(struct rt2x00_dev *rt2x00dev, |
| struct ieee80211_conf *conf, |
| struct rf_channel *rf, |
| struct channel_info *info) |
| { |
| u8 rfcsr, ep_reg; |
| u32 reg; |
| int power_bound; |
| |
| /* TODO */ |
| const bool is_11b = false; |
| const bool is_type_ep = false; |
| |
| rt2800_register_read(rt2x00dev, LDO_CFG0, ®); |
| rt2x00_set_field32(®, LDO_CFG0_LDO_CORE_VLEVEL, |
| (rf->channel > 14 || conf_is_ht40(conf)) ? 5 : 0); |
| rt2800_register_write(rt2x00dev, LDO_CFG0, reg); |
| |
| /* Order of values on rf_channel entry: N, K, mod, R */ |
| rt2800_rfcsr_write(rt2x00dev, 8, rf->rf1 & 0xff); |
| |
| rt2800_rfcsr_read(rt2x00dev, 9, &rfcsr); |
| rt2x00_set_field8(&rfcsr, RFCSR9_K, rf->rf2 & 0xf); |
| rt2x00_set_field8(&rfcsr, RFCSR9_N, (rf->rf1 & 0x100) >> 8); |
| rt2x00_set_field8(&rfcsr, RFCSR9_MOD, ((rf->rf3 - 8) & 0x4) >> 2); |
| rt2800_rfcsr_write(rt2x00dev, 9, rfcsr); |
| |
| rt2800_rfcsr_read(rt2x00dev, 11, &rfcsr); |
| rt2x00_set_field8(&rfcsr, RFCSR11_R, rf->rf4 - 1); |
| rt2x00_set_field8(&rfcsr, RFCSR11_MOD, (rf->rf3 - 8) & 0x3); |
| rt2800_rfcsr_write(rt2x00dev, 11, rfcsr); |
| |
| if (rf->channel <= 14) { |
| rt2800_rfcsr_write(rt2x00dev, 10, 0x90); |
| /* FIXME: RF11 owerwrite ? */ |
| rt2800_rfcsr_write(rt2x00dev, 11, 0x4A); |
| rt2800_rfcsr_write(rt2x00dev, 12, 0x52); |
| rt2800_rfcsr_write(rt2x00dev, 13, 0x42); |
| rt2800_rfcsr_write(rt2x00dev, 22, 0x40); |
| rt2800_rfcsr_write(rt2x00dev, 24, 0x4A); |
| rt2800_rfcsr_write(rt2x00dev, 25, 0x80); |
| rt2800_rfcsr_write(rt2x00dev, 27, 0x42); |
| rt2800_rfcsr_write(rt2x00dev, 36, 0x80); |
| rt2800_rfcsr_write(rt2x00dev, 37, 0x08); |
| rt2800_rfcsr_write(rt2x00dev, 38, 0x89); |
| rt2800_rfcsr_write(rt2x00dev, 39, 0x1B); |
| rt2800_rfcsr_write(rt2x00dev, 40, 0x0D); |
| rt2800_rfcsr_write(rt2x00dev, 41, 0x9B); |
| rt2800_rfcsr_write(rt2x00dev, 42, 0xD5); |
| rt2800_rfcsr_write(rt2x00dev, 43, 0x72); |
| rt2800_rfcsr_write(rt2x00dev, 44, 0x0E); |
| rt2800_rfcsr_write(rt2x00dev, 45, 0xA2); |
| rt2800_rfcsr_write(rt2x00dev, 46, 0x6B); |
| rt2800_rfcsr_write(rt2x00dev, 48, 0x10); |
| rt2800_rfcsr_write(rt2x00dev, 51, 0x3E); |
| rt2800_rfcsr_write(rt2x00dev, 52, 0x48); |
| rt2800_rfcsr_write(rt2x00dev, 54, 0x38); |
| rt2800_rfcsr_write(rt2x00dev, 56, 0xA1); |
| rt2800_rfcsr_write(rt2x00dev, 57, 0x00); |
| rt2800_rfcsr_write(rt2x00dev, 58, 0x39); |
| rt2800_rfcsr_write(rt2x00dev, 60, 0x45); |
| rt2800_rfcsr_write(rt2x00dev, 61, 0x91); |
| rt2800_rfcsr_write(rt2x00dev, 62, 0x39); |
| |
| /* TODO RF27 <- tssi */ |
| |
| rfcsr = rf->channel <= 10 ? 0x07 : 0x06; |
| rt2800_rfcsr_write(rt2x00dev, 23, rfcsr); |
| rt2800_rfcsr_write(rt2x00dev, 59, rfcsr); |
| |
| if (is_11b) { |
| /* CCK */ |
| rt2800_rfcsr_write(rt2x00dev, 31, 0xF8); |
| rt2800_rfcsr_write(rt2x00dev, 32, 0xC0); |
| if (is_type_ep) |
| rt2800_rfcsr_write(rt2x00dev, 55, 0x06); |
| else |
| rt2800_rfcsr_write(rt2x00dev, 55, 0x47); |
| } else { |
| /* OFDM */ |
| if (is_type_ep) |
| rt2800_rfcsr_write(rt2x00dev, 55, 0x03); |
| else |
| rt2800_rfcsr_write(rt2x00dev, 55, 0x43); |
| } |
| |
| power_bound = POWER_BOUND; |
| ep_reg = 0x2; |
| } else { |
| rt2800_rfcsr_write(rt2x00dev, 10, 0x97); |
| /* FIMXE: RF11 overwrite */ |
| rt2800_rfcsr_write(rt2x00dev, 11, 0x40); |
| rt2800_rfcsr_write(rt2x00dev, 25, 0xBF); |
| rt2800_rfcsr_write(rt2x00dev, 27, 0x42); |
| rt2800_rfcsr_write(rt2x00dev, 36, 0x00); |
| rt2800_rfcsr_write(rt2x00dev, 37, 0x04); |
| rt2800_rfcsr_write(rt2x00dev, 38, 0x85); |
| rt2800_rfcsr_write(rt2x00dev, 40, 0x42); |
| rt2800_rfcsr_write(rt2x00dev, 41, 0xBB); |
| rt2800_rfcsr_write(rt2x00dev, 42, 0xD7); |
| rt2800_rfcsr_write(rt2x00dev, 45, 0x41); |
| rt2800_rfcsr_write(rt2x00dev, 48, 0x00); |
| rt2800_rfcsr_write(rt2x00dev, 57, 0x77); |
| rt2800_rfcsr_write(rt2x00dev, 60, 0x05); |
| rt2800_rfcsr_write(rt2x00dev, 61, 0x01); |
| |
| /* TODO RF27 <- tssi */ |
| |
| if (rf->channel >= 36 && rf->channel <= 64) { |
| |
| rt2800_rfcsr_write(rt2x00dev, 12, 0x2E); |
| rt2800_rfcsr_write(rt2x00dev, 13, 0x22); |
| rt2800_rfcsr_write(rt2x00dev, 22, 0x60); |
| rt2800_rfcsr_write(rt2x00dev, 23, 0x7F); |
| if (rf->channel <= 50) |
| rt2800_rfcsr_write(rt2x00dev, 24, 0x09); |
| else if (rf->channel >= 52) |
| rt2800_rfcsr_write(rt2x00dev, 24, 0x07); |
| rt2800_rfcsr_write(rt2x00dev, 39, 0x1C); |
| rt2800_rfcsr_write(rt2x00dev, 43, 0x5B); |
| rt2800_rfcsr_write(rt2x00dev, 44, 0X40); |
| rt2800_rfcsr_write(rt2x00dev, 46, 0X00); |
| rt2800_rfcsr_write(rt2x00dev, 51, 0xFE); |
| rt2800_rfcsr_write(rt2x00dev, 52, 0x0C); |
| rt2800_rfcsr_write(rt2x00dev, 54, 0xF8); |
| if (rf->channel <= 50) { |
| rt2800_rfcsr_write(rt2x00dev, 55, 0x06), |
| rt2800_rfcsr_write(rt2x00dev, 56, 0xD3); |
| } else if (rf->channel >= 52) { |
| rt2800_rfcsr_write(rt2x00dev, 55, 0x04); |
| rt2800_rfcsr_write(rt2x00dev, 56, 0xBB); |
| } |
| |
| rt2800_rfcsr_write(rt2x00dev, 58, 0x15); |
| rt2800_rfcsr_write(rt2x00dev, 59, 0x7F); |
| rt2800_rfcsr_write(rt2x00dev, 62, 0x15); |
| |
| } else if (rf->channel >= 100 && rf->channel <= 165) { |
| |
| rt2800_rfcsr_write(rt2x00dev, 12, 0x0E); |
| rt2800_rfcsr_write(rt2x00dev, 13, 0x42); |
| rt2800_rfcsr_write(rt2x00dev, 22, 0x40); |
| if (rf->channel <= 153) { |
| rt2800_rfcsr_write(rt2x00dev, 23, 0x3C); |
| rt2800_rfcsr_write(rt2x00dev, 24, 0x06); |
| } else if (rf->channel >= 155) |