18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com> 48c2ecf20Sopenharmony_ci <http://rt2x00.serialmonkey.com> 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci/* 98c2ecf20Sopenharmony_ci Module: rt61pci 108c2ecf20Sopenharmony_ci Abstract: rt61pci device specific routines. 118c2ecf20Sopenharmony_ci Supported chipsets: RT2561, RT2561s, RT2661. 128c2ecf20Sopenharmony_ci */ 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include <linux/crc-itu-t.h> 158c2ecf20Sopenharmony_ci#include <linux/delay.h> 168c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 178c2ecf20Sopenharmony_ci#include <linux/kernel.h> 188c2ecf20Sopenharmony_ci#include <linux/module.h> 198c2ecf20Sopenharmony_ci#include <linux/slab.h> 208c2ecf20Sopenharmony_ci#include <linux/pci.h> 218c2ecf20Sopenharmony_ci#include <linux/eeprom_93cx6.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#include "rt2x00.h" 248c2ecf20Sopenharmony_ci#include "rt2x00mmio.h" 258c2ecf20Sopenharmony_ci#include "rt2x00pci.h" 268c2ecf20Sopenharmony_ci#include "rt61pci.h" 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci/* 298c2ecf20Sopenharmony_ci * Allow hardware encryption to be disabled. 308c2ecf20Sopenharmony_ci */ 318c2ecf20Sopenharmony_cistatic bool modparam_nohwcrypt = false; 328c2ecf20Sopenharmony_cimodule_param_named(nohwcrypt, modparam_nohwcrypt, bool, 0444); 338c2ecf20Sopenharmony_ciMODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci/* 368c2ecf20Sopenharmony_ci * Register access. 378c2ecf20Sopenharmony_ci * BBP and RF register require indirect register access, 388c2ecf20Sopenharmony_ci * and use the CSR registers PHY_CSR3 and PHY_CSR4 to achieve this. 398c2ecf20Sopenharmony_ci * These indirect registers work with busy bits, 408c2ecf20Sopenharmony_ci * and we will try maximal REGISTER_BUSY_COUNT times to access 418c2ecf20Sopenharmony_ci * the register while taking a REGISTER_BUSY_DELAY us delay 428c2ecf20Sopenharmony_ci * between each attempt. When the busy bit is still set at that time, 438c2ecf20Sopenharmony_ci * the access attempt is considered to have failed, 448c2ecf20Sopenharmony_ci * and we will print an error. 458c2ecf20Sopenharmony_ci */ 468c2ecf20Sopenharmony_ci#define WAIT_FOR_BBP(__dev, __reg) \ 478c2ecf20Sopenharmony_ci rt2x00mmio_regbusy_read((__dev), PHY_CSR3, PHY_CSR3_BUSY, (__reg)) 488c2ecf20Sopenharmony_ci#define WAIT_FOR_RF(__dev, __reg) \ 498c2ecf20Sopenharmony_ci rt2x00mmio_regbusy_read((__dev), PHY_CSR4, PHY_CSR4_BUSY, (__reg)) 508c2ecf20Sopenharmony_ci#define WAIT_FOR_MCU(__dev, __reg) \ 518c2ecf20Sopenharmony_ci rt2x00mmio_regbusy_read((__dev), H2M_MAILBOX_CSR, \ 528c2ecf20Sopenharmony_ci H2M_MAILBOX_CSR_OWNER, (__reg)) 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_cistatic void rt61pci_bbp_write(struct rt2x00_dev *rt2x00dev, 558c2ecf20Sopenharmony_ci const unsigned int word, const u8 value) 568c2ecf20Sopenharmony_ci{ 578c2ecf20Sopenharmony_ci u32 reg; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci mutex_lock(&rt2x00dev->csr_mutex); 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci /* 628c2ecf20Sopenharmony_ci * Wait until the BBP becomes available, afterwards we 638c2ecf20Sopenharmony_ci * can safely write the new data into the register. 648c2ecf20Sopenharmony_ci */ 658c2ecf20Sopenharmony_ci if (WAIT_FOR_BBP(rt2x00dev, ®)) { 668c2ecf20Sopenharmony_ci reg = 0; 678c2ecf20Sopenharmony_ci rt2x00_set_field32(®, PHY_CSR3_VALUE, value); 688c2ecf20Sopenharmony_ci rt2x00_set_field32(®, PHY_CSR3_REGNUM, word); 698c2ecf20Sopenharmony_ci rt2x00_set_field32(®, PHY_CSR3_BUSY, 1); 708c2ecf20Sopenharmony_ci rt2x00_set_field32(®, PHY_CSR3_READ_CONTROL, 0); 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, PHY_CSR3, reg); 738c2ecf20Sopenharmony_ci } 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci mutex_unlock(&rt2x00dev->csr_mutex); 768c2ecf20Sopenharmony_ci} 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_cistatic u8 rt61pci_bbp_read(struct rt2x00_dev *rt2x00dev, 798c2ecf20Sopenharmony_ci const unsigned int word) 808c2ecf20Sopenharmony_ci{ 818c2ecf20Sopenharmony_ci u32 reg; 828c2ecf20Sopenharmony_ci u8 value; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci mutex_lock(&rt2x00dev->csr_mutex); 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci /* 878c2ecf20Sopenharmony_ci * Wait until the BBP becomes available, afterwards we 888c2ecf20Sopenharmony_ci * can safely write the read request into the register. 898c2ecf20Sopenharmony_ci * After the data has been written, we wait until hardware 908c2ecf20Sopenharmony_ci * returns the correct value, if at any time the register 918c2ecf20Sopenharmony_ci * doesn't become available in time, reg will be 0xffffffff 928c2ecf20Sopenharmony_ci * which means we return 0xff to the caller. 938c2ecf20Sopenharmony_ci */ 948c2ecf20Sopenharmony_ci if (WAIT_FOR_BBP(rt2x00dev, ®)) { 958c2ecf20Sopenharmony_ci reg = 0; 968c2ecf20Sopenharmony_ci rt2x00_set_field32(®, PHY_CSR3_REGNUM, word); 978c2ecf20Sopenharmony_ci rt2x00_set_field32(®, PHY_CSR3_BUSY, 1); 988c2ecf20Sopenharmony_ci rt2x00_set_field32(®, PHY_CSR3_READ_CONTROL, 1); 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, PHY_CSR3, reg); 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci WAIT_FOR_BBP(rt2x00dev, ®); 1038c2ecf20Sopenharmony_ci } 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci value = rt2x00_get_field32(reg, PHY_CSR3_VALUE); 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci mutex_unlock(&rt2x00dev->csr_mutex); 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci return value; 1108c2ecf20Sopenharmony_ci} 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_cistatic void rt61pci_rf_write(struct rt2x00_dev *rt2x00dev, 1138c2ecf20Sopenharmony_ci const unsigned int word, const u32 value) 1148c2ecf20Sopenharmony_ci{ 1158c2ecf20Sopenharmony_ci u32 reg; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci mutex_lock(&rt2x00dev->csr_mutex); 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci /* 1208c2ecf20Sopenharmony_ci * Wait until the RF becomes available, afterwards we 1218c2ecf20Sopenharmony_ci * can safely write the new data into the register. 1228c2ecf20Sopenharmony_ci */ 1238c2ecf20Sopenharmony_ci if (WAIT_FOR_RF(rt2x00dev, ®)) { 1248c2ecf20Sopenharmony_ci reg = 0; 1258c2ecf20Sopenharmony_ci rt2x00_set_field32(®, PHY_CSR4_VALUE, value); 1268c2ecf20Sopenharmony_ci rt2x00_set_field32(®, PHY_CSR4_NUMBER_OF_BITS, 21); 1278c2ecf20Sopenharmony_ci rt2x00_set_field32(®, PHY_CSR4_IF_SELECT, 0); 1288c2ecf20Sopenharmony_ci rt2x00_set_field32(®, PHY_CSR4_BUSY, 1); 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, PHY_CSR4, reg); 1318c2ecf20Sopenharmony_ci rt2x00_rf_write(rt2x00dev, word, value); 1328c2ecf20Sopenharmony_ci } 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci mutex_unlock(&rt2x00dev->csr_mutex); 1358c2ecf20Sopenharmony_ci} 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_cistatic void rt61pci_mcu_request(struct rt2x00_dev *rt2x00dev, 1388c2ecf20Sopenharmony_ci const u8 command, const u8 token, 1398c2ecf20Sopenharmony_ci const u8 arg0, const u8 arg1) 1408c2ecf20Sopenharmony_ci{ 1418c2ecf20Sopenharmony_ci u32 reg; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci mutex_lock(&rt2x00dev->csr_mutex); 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci /* 1468c2ecf20Sopenharmony_ci * Wait until the MCU becomes available, afterwards we 1478c2ecf20Sopenharmony_ci * can safely write the new data into the register. 1488c2ecf20Sopenharmony_ci */ 1498c2ecf20Sopenharmony_ci if (WAIT_FOR_MCU(rt2x00dev, ®)) { 1508c2ecf20Sopenharmony_ci rt2x00_set_field32(®, H2M_MAILBOX_CSR_OWNER, 1); 1518c2ecf20Sopenharmony_ci rt2x00_set_field32(®, H2M_MAILBOX_CSR_CMD_TOKEN, token); 1528c2ecf20Sopenharmony_ci rt2x00_set_field32(®, H2M_MAILBOX_CSR_ARG0, arg0); 1538c2ecf20Sopenharmony_ci rt2x00_set_field32(®, H2M_MAILBOX_CSR_ARG1, arg1); 1548c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, H2M_MAILBOX_CSR, reg); 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, HOST_CMD_CSR); 1578c2ecf20Sopenharmony_ci rt2x00_set_field32(®, HOST_CMD_CSR_HOST_COMMAND, command); 1588c2ecf20Sopenharmony_ci rt2x00_set_field32(®, HOST_CMD_CSR_INTERRUPT_MCU, 1); 1598c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, HOST_CMD_CSR, reg); 1608c2ecf20Sopenharmony_ci } 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci mutex_unlock(&rt2x00dev->csr_mutex); 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci} 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_cistatic void rt61pci_eepromregister_read(struct eeprom_93cx6 *eeprom) 1678c2ecf20Sopenharmony_ci{ 1688c2ecf20Sopenharmony_ci struct rt2x00_dev *rt2x00dev = eeprom->data; 1698c2ecf20Sopenharmony_ci u32 reg; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, E2PROM_CSR); 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci eeprom->reg_data_in = !!rt2x00_get_field32(reg, E2PROM_CSR_DATA_IN); 1748c2ecf20Sopenharmony_ci eeprom->reg_data_out = !!rt2x00_get_field32(reg, E2PROM_CSR_DATA_OUT); 1758c2ecf20Sopenharmony_ci eeprom->reg_data_clock = 1768c2ecf20Sopenharmony_ci !!rt2x00_get_field32(reg, E2PROM_CSR_DATA_CLOCK); 1778c2ecf20Sopenharmony_ci eeprom->reg_chip_select = 1788c2ecf20Sopenharmony_ci !!rt2x00_get_field32(reg, E2PROM_CSR_CHIP_SELECT); 1798c2ecf20Sopenharmony_ci} 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_cistatic void rt61pci_eepromregister_write(struct eeprom_93cx6 *eeprom) 1828c2ecf20Sopenharmony_ci{ 1838c2ecf20Sopenharmony_ci struct rt2x00_dev *rt2x00dev = eeprom->data; 1848c2ecf20Sopenharmony_ci u32 reg = 0; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci rt2x00_set_field32(®, E2PROM_CSR_DATA_IN, !!eeprom->reg_data_in); 1878c2ecf20Sopenharmony_ci rt2x00_set_field32(®, E2PROM_CSR_DATA_OUT, !!eeprom->reg_data_out); 1888c2ecf20Sopenharmony_ci rt2x00_set_field32(®, E2PROM_CSR_DATA_CLOCK, 1898c2ecf20Sopenharmony_ci !!eeprom->reg_data_clock); 1908c2ecf20Sopenharmony_ci rt2x00_set_field32(®, E2PROM_CSR_CHIP_SELECT, 1918c2ecf20Sopenharmony_ci !!eeprom->reg_chip_select); 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, E2PROM_CSR, reg); 1948c2ecf20Sopenharmony_ci} 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci#ifdef CONFIG_RT2X00_LIB_DEBUGFS 1978c2ecf20Sopenharmony_cistatic const struct rt2x00debug rt61pci_rt2x00debug = { 1988c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 1998c2ecf20Sopenharmony_ci .csr = { 2008c2ecf20Sopenharmony_ci .read = rt2x00mmio_register_read, 2018c2ecf20Sopenharmony_ci .write = rt2x00mmio_register_write, 2028c2ecf20Sopenharmony_ci .flags = RT2X00DEBUGFS_OFFSET, 2038c2ecf20Sopenharmony_ci .word_base = CSR_REG_BASE, 2048c2ecf20Sopenharmony_ci .word_size = sizeof(u32), 2058c2ecf20Sopenharmony_ci .word_count = CSR_REG_SIZE / sizeof(u32), 2068c2ecf20Sopenharmony_ci }, 2078c2ecf20Sopenharmony_ci .eeprom = { 2088c2ecf20Sopenharmony_ci .read = rt2x00_eeprom_read, 2098c2ecf20Sopenharmony_ci .write = rt2x00_eeprom_write, 2108c2ecf20Sopenharmony_ci .word_base = EEPROM_BASE, 2118c2ecf20Sopenharmony_ci .word_size = sizeof(u16), 2128c2ecf20Sopenharmony_ci .word_count = EEPROM_SIZE / sizeof(u16), 2138c2ecf20Sopenharmony_ci }, 2148c2ecf20Sopenharmony_ci .bbp = { 2158c2ecf20Sopenharmony_ci .read = rt61pci_bbp_read, 2168c2ecf20Sopenharmony_ci .write = rt61pci_bbp_write, 2178c2ecf20Sopenharmony_ci .word_base = BBP_BASE, 2188c2ecf20Sopenharmony_ci .word_size = sizeof(u8), 2198c2ecf20Sopenharmony_ci .word_count = BBP_SIZE / sizeof(u8), 2208c2ecf20Sopenharmony_ci }, 2218c2ecf20Sopenharmony_ci .rf = { 2228c2ecf20Sopenharmony_ci .read = rt2x00_rf_read, 2238c2ecf20Sopenharmony_ci .write = rt61pci_rf_write, 2248c2ecf20Sopenharmony_ci .word_base = RF_BASE, 2258c2ecf20Sopenharmony_ci .word_size = sizeof(u32), 2268c2ecf20Sopenharmony_ci .word_count = RF_SIZE / sizeof(u32), 2278c2ecf20Sopenharmony_ci }, 2288c2ecf20Sopenharmony_ci}; 2298c2ecf20Sopenharmony_ci#endif /* CONFIG_RT2X00_LIB_DEBUGFS */ 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_cistatic int rt61pci_rfkill_poll(struct rt2x00_dev *rt2x00dev) 2328c2ecf20Sopenharmony_ci{ 2338c2ecf20Sopenharmony_ci u32 reg; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, MAC_CSR13); 2368c2ecf20Sopenharmony_ci return rt2x00_get_field32(reg, MAC_CSR13_VAL5); 2378c2ecf20Sopenharmony_ci} 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci#ifdef CONFIG_RT2X00_LIB_LEDS 2408c2ecf20Sopenharmony_cistatic void rt61pci_brightness_set(struct led_classdev *led_cdev, 2418c2ecf20Sopenharmony_ci enum led_brightness brightness) 2428c2ecf20Sopenharmony_ci{ 2438c2ecf20Sopenharmony_ci struct rt2x00_led *led = 2448c2ecf20Sopenharmony_ci container_of(led_cdev, struct rt2x00_led, led_dev); 2458c2ecf20Sopenharmony_ci unsigned int enabled = brightness != LED_OFF; 2468c2ecf20Sopenharmony_ci unsigned int a_mode = 2478c2ecf20Sopenharmony_ci (enabled && led->rt2x00dev->curr_band == NL80211_BAND_5GHZ); 2488c2ecf20Sopenharmony_ci unsigned int bg_mode = 2498c2ecf20Sopenharmony_ci (enabled && led->rt2x00dev->curr_band == NL80211_BAND_2GHZ); 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci if (led->type == LED_TYPE_RADIO) { 2528c2ecf20Sopenharmony_ci rt2x00_set_field16(&led->rt2x00dev->led_mcu_reg, 2538c2ecf20Sopenharmony_ci MCU_LEDCS_RADIO_STATUS, enabled); 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci rt61pci_mcu_request(led->rt2x00dev, MCU_LED, 0xff, 2568c2ecf20Sopenharmony_ci (led->rt2x00dev->led_mcu_reg & 0xff), 2578c2ecf20Sopenharmony_ci ((led->rt2x00dev->led_mcu_reg >> 8))); 2588c2ecf20Sopenharmony_ci } else if (led->type == LED_TYPE_ASSOC) { 2598c2ecf20Sopenharmony_ci rt2x00_set_field16(&led->rt2x00dev->led_mcu_reg, 2608c2ecf20Sopenharmony_ci MCU_LEDCS_LINK_BG_STATUS, bg_mode); 2618c2ecf20Sopenharmony_ci rt2x00_set_field16(&led->rt2x00dev->led_mcu_reg, 2628c2ecf20Sopenharmony_ci MCU_LEDCS_LINK_A_STATUS, a_mode); 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci rt61pci_mcu_request(led->rt2x00dev, MCU_LED, 0xff, 2658c2ecf20Sopenharmony_ci (led->rt2x00dev->led_mcu_reg & 0xff), 2668c2ecf20Sopenharmony_ci ((led->rt2x00dev->led_mcu_reg >> 8))); 2678c2ecf20Sopenharmony_ci } else if (led->type == LED_TYPE_QUALITY) { 2688c2ecf20Sopenharmony_ci /* 2698c2ecf20Sopenharmony_ci * The brightness is divided into 6 levels (0 - 5), 2708c2ecf20Sopenharmony_ci * this means we need to convert the brightness 2718c2ecf20Sopenharmony_ci * argument into the matching level within that range. 2728c2ecf20Sopenharmony_ci */ 2738c2ecf20Sopenharmony_ci rt61pci_mcu_request(led->rt2x00dev, MCU_LED_STRENGTH, 0xff, 2748c2ecf20Sopenharmony_ci brightness / (LED_FULL / 6), 0); 2758c2ecf20Sopenharmony_ci } 2768c2ecf20Sopenharmony_ci} 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_cistatic int rt61pci_blink_set(struct led_classdev *led_cdev, 2798c2ecf20Sopenharmony_ci unsigned long *delay_on, 2808c2ecf20Sopenharmony_ci unsigned long *delay_off) 2818c2ecf20Sopenharmony_ci{ 2828c2ecf20Sopenharmony_ci struct rt2x00_led *led = 2838c2ecf20Sopenharmony_ci container_of(led_cdev, struct rt2x00_led, led_dev); 2848c2ecf20Sopenharmony_ci u32 reg; 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(led->rt2x00dev, MAC_CSR14); 2878c2ecf20Sopenharmony_ci rt2x00_set_field32(®, MAC_CSR14_ON_PERIOD, *delay_on); 2888c2ecf20Sopenharmony_ci rt2x00_set_field32(®, MAC_CSR14_OFF_PERIOD, *delay_off); 2898c2ecf20Sopenharmony_ci rt2x00mmio_register_write(led->rt2x00dev, MAC_CSR14, reg); 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci return 0; 2928c2ecf20Sopenharmony_ci} 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_cistatic void rt61pci_init_led(struct rt2x00_dev *rt2x00dev, 2958c2ecf20Sopenharmony_ci struct rt2x00_led *led, 2968c2ecf20Sopenharmony_ci enum led_type type) 2978c2ecf20Sopenharmony_ci{ 2988c2ecf20Sopenharmony_ci led->rt2x00dev = rt2x00dev; 2998c2ecf20Sopenharmony_ci led->type = type; 3008c2ecf20Sopenharmony_ci led->led_dev.brightness_set = rt61pci_brightness_set; 3018c2ecf20Sopenharmony_ci led->led_dev.blink_set = rt61pci_blink_set; 3028c2ecf20Sopenharmony_ci led->flags = LED_INITIALIZED; 3038c2ecf20Sopenharmony_ci} 3048c2ecf20Sopenharmony_ci#endif /* CONFIG_RT2X00_LIB_LEDS */ 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci/* 3078c2ecf20Sopenharmony_ci * Configuration handlers. 3088c2ecf20Sopenharmony_ci */ 3098c2ecf20Sopenharmony_cistatic int rt61pci_config_shared_key(struct rt2x00_dev *rt2x00dev, 3108c2ecf20Sopenharmony_ci struct rt2x00lib_crypto *crypto, 3118c2ecf20Sopenharmony_ci struct ieee80211_key_conf *key) 3128c2ecf20Sopenharmony_ci{ 3138c2ecf20Sopenharmony_ci /* 3148c2ecf20Sopenharmony_ci * Let the software handle the shared keys, 3158c2ecf20Sopenharmony_ci * since the hardware decryption does not work reliably, 3168c2ecf20Sopenharmony_ci * because the firmware does not know the key's keyidx. 3178c2ecf20Sopenharmony_ci */ 3188c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 3198c2ecf20Sopenharmony_ci} 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_cistatic int rt61pci_config_pairwise_key(struct rt2x00_dev *rt2x00dev, 3228c2ecf20Sopenharmony_ci struct rt2x00lib_crypto *crypto, 3238c2ecf20Sopenharmony_ci struct ieee80211_key_conf *key) 3248c2ecf20Sopenharmony_ci{ 3258c2ecf20Sopenharmony_ci struct hw_pairwise_ta_entry addr_entry; 3268c2ecf20Sopenharmony_ci struct hw_key_entry key_entry; 3278c2ecf20Sopenharmony_ci u32 mask; 3288c2ecf20Sopenharmony_ci u32 reg; 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci if (crypto->cmd == SET_KEY) { 3318c2ecf20Sopenharmony_ci /* 3328c2ecf20Sopenharmony_ci * rt2x00lib can't determine the correct free 3338c2ecf20Sopenharmony_ci * key_idx for pairwise keys. We have 2 registers 3348c2ecf20Sopenharmony_ci * with key valid bits. The goal is simple: read 3358c2ecf20Sopenharmony_ci * the first register. If that is full, move to 3368c2ecf20Sopenharmony_ci * the next register. 3378c2ecf20Sopenharmony_ci * When both registers are full, we drop the key. 3388c2ecf20Sopenharmony_ci * Otherwise, we use the first invalid entry. 3398c2ecf20Sopenharmony_ci */ 3408c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, SEC_CSR2); 3418c2ecf20Sopenharmony_ci if (reg && reg == ~0) { 3428c2ecf20Sopenharmony_ci key->hw_key_idx = 32; 3438c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, SEC_CSR3); 3448c2ecf20Sopenharmony_ci if (reg && reg == ~0) 3458c2ecf20Sopenharmony_ci return -ENOSPC; 3468c2ecf20Sopenharmony_ci } 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci key->hw_key_idx += reg ? ffz(reg) : 0; 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci /* 3518c2ecf20Sopenharmony_ci * Upload key to hardware 3528c2ecf20Sopenharmony_ci */ 3538c2ecf20Sopenharmony_ci memcpy(key_entry.key, crypto->key, 3548c2ecf20Sopenharmony_ci sizeof(key_entry.key)); 3558c2ecf20Sopenharmony_ci memcpy(key_entry.tx_mic, crypto->tx_mic, 3568c2ecf20Sopenharmony_ci sizeof(key_entry.tx_mic)); 3578c2ecf20Sopenharmony_ci memcpy(key_entry.rx_mic, crypto->rx_mic, 3588c2ecf20Sopenharmony_ci sizeof(key_entry.rx_mic)); 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci memset(&addr_entry, 0, sizeof(addr_entry)); 3618c2ecf20Sopenharmony_ci memcpy(&addr_entry, crypto->address, ETH_ALEN); 3628c2ecf20Sopenharmony_ci addr_entry.cipher = crypto->cipher; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci reg = PAIRWISE_KEY_ENTRY(key->hw_key_idx); 3658c2ecf20Sopenharmony_ci rt2x00mmio_register_multiwrite(rt2x00dev, reg, 3668c2ecf20Sopenharmony_ci &key_entry, sizeof(key_entry)); 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci reg = PAIRWISE_TA_ENTRY(key->hw_key_idx); 3698c2ecf20Sopenharmony_ci rt2x00mmio_register_multiwrite(rt2x00dev, reg, 3708c2ecf20Sopenharmony_ci &addr_entry, sizeof(addr_entry)); 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci /* 3738c2ecf20Sopenharmony_ci * Enable pairwise lookup table for given BSS idx. 3748c2ecf20Sopenharmony_ci * Without this, received frames will not be decrypted 3758c2ecf20Sopenharmony_ci * by the hardware. 3768c2ecf20Sopenharmony_ci */ 3778c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, SEC_CSR4); 3788c2ecf20Sopenharmony_ci reg |= (1 << crypto->bssidx); 3798c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, SEC_CSR4, reg); 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci /* 3828c2ecf20Sopenharmony_ci * The driver does not support the IV/EIV generation 3838c2ecf20Sopenharmony_ci * in hardware. However it doesn't support the IV/EIV 3848c2ecf20Sopenharmony_ci * inside the ieee80211 frame either, but requires it 3858c2ecf20Sopenharmony_ci * to be provided separately for the descriptor. 3868c2ecf20Sopenharmony_ci * rt2x00lib will cut the IV/EIV data out of all frames 3878c2ecf20Sopenharmony_ci * given to us by mac80211, but we must tell mac80211 3888c2ecf20Sopenharmony_ci * to generate the IV/EIV data. 3898c2ecf20Sopenharmony_ci */ 3908c2ecf20Sopenharmony_ci key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; 3918c2ecf20Sopenharmony_ci } 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci /* 3948c2ecf20Sopenharmony_ci * SEC_CSR2 and SEC_CSR3 contain only single-bit fields to indicate 3958c2ecf20Sopenharmony_ci * a particular key is valid. Because using the FIELD32() 3968c2ecf20Sopenharmony_ci * defines directly will cause a lot of overhead, we use 3978c2ecf20Sopenharmony_ci * a calculation to determine the correct bit directly. 3988c2ecf20Sopenharmony_ci */ 3998c2ecf20Sopenharmony_ci if (key->hw_key_idx < 32) { 4008c2ecf20Sopenharmony_ci mask = 1 << key->hw_key_idx; 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, SEC_CSR2); 4038c2ecf20Sopenharmony_ci if (crypto->cmd == SET_KEY) 4048c2ecf20Sopenharmony_ci reg |= mask; 4058c2ecf20Sopenharmony_ci else if (crypto->cmd == DISABLE_KEY) 4068c2ecf20Sopenharmony_ci reg &= ~mask; 4078c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, SEC_CSR2, reg); 4088c2ecf20Sopenharmony_ci } else { 4098c2ecf20Sopenharmony_ci mask = 1 << (key->hw_key_idx - 32); 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, SEC_CSR3); 4128c2ecf20Sopenharmony_ci if (crypto->cmd == SET_KEY) 4138c2ecf20Sopenharmony_ci reg |= mask; 4148c2ecf20Sopenharmony_ci else if (crypto->cmd == DISABLE_KEY) 4158c2ecf20Sopenharmony_ci reg &= ~mask; 4168c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, SEC_CSR3, reg); 4178c2ecf20Sopenharmony_ci } 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci return 0; 4208c2ecf20Sopenharmony_ci} 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_cistatic void rt61pci_config_filter(struct rt2x00_dev *rt2x00dev, 4238c2ecf20Sopenharmony_ci const unsigned int filter_flags) 4248c2ecf20Sopenharmony_ci{ 4258c2ecf20Sopenharmony_ci u32 reg; 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci /* 4288c2ecf20Sopenharmony_ci * Start configuration steps. 4298c2ecf20Sopenharmony_ci * Note that the version error will always be dropped 4308c2ecf20Sopenharmony_ci * and broadcast frames will always be accepted since 4318c2ecf20Sopenharmony_ci * there is no filter for it at this time. 4328c2ecf20Sopenharmony_ci */ 4338c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR0); 4348c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR0_DROP_CRC, 4358c2ecf20Sopenharmony_ci !(filter_flags & FIF_FCSFAIL)); 4368c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR0_DROP_PHYSICAL, 4378c2ecf20Sopenharmony_ci !(filter_flags & FIF_PLCPFAIL)); 4388c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR0_DROP_CONTROL, 4398c2ecf20Sopenharmony_ci !(filter_flags & (FIF_CONTROL | FIF_PSPOLL))); 4408c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR0_DROP_NOT_TO_ME, 4418c2ecf20Sopenharmony_ci !test_bit(CONFIG_MONITORING, &rt2x00dev->flags)); 4428c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR0_DROP_TO_DS, 4438c2ecf20Sopenharmony_ci !test_bit(CONFIG_MONITORING, &rt2x00dev->flags) && 4448c2ecf20Sopenharmony_ci !rt2x00dev->intf_ap_count); 4458c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR0_DROP_VERSION_ERROR, 1); 4468c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR0_DROP_MULTICAST, 4478c2ecf20Sopenharmony_ci !(filter_flags & FIF_ALLMULTI)); 4488c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR0_DROP_BROADCAST, 0); 4498c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR0_DROP_ACK_CTS, 4508c2ecf20Sopenharmony_ci !(filter_flags & FIF_CONTROL)); 4518c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, TXRX_CSR0, reg); 4528c2ecf20Sopenharmony_ci} 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_cistatic void rt61pci_config_intf(struct rt2x00_dev *rt2x00dev, 4558c2ecf20Sopenharmony_ci struct rt2x00_intf *intf, 4568c2ecf20Sopenharmony_ci struct rt2x00intf_conf *conf, 4578c2ecf20Sopenharmony_ci const unsigned int flags) 4588c2ecf20Sopenharmony_ci{ 4598c2ecf20Sopenharmony_ci u32 reg; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci if (flags & CONFIG_UPDATE_TYPE) { 4628c2ecf20Sopenharmony_ci /* 4638c2ecf20Sopenharmony_ci * Enable synchronisation. 4648c2ecf20Sopenharmony_ci */ 4658c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR9); 4668c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, conf->sync); 4678c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, TXRX_CSR9, reg); 4688c2ecf20Sopenharmony_ci } 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci if (flags & CONFIG_UPDATE_MAC) { 4718c2ecf20Sopenharmony_ci reg = le32_to_cpu(conf->mac[1]); 4728c2ecf20Sopenharmony_ci rt2x00_set_field32(®, MAC_CSR3_UNICAST_TO_ME_MASK, 0xff); 4738c2ecf20Sopenharmony_ci conf->mac[1] = cpu_to_le32(reg); 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci rt2x00mmio_register_multiwrite(rt2x00dev, MAC_CSR2, 4768c2ecf20Sopenharmony_ci conf->mac, sizeof(conf->mac)); 4778c2ecf20Sopenharmony_ci } 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci if (flags & CONFIG_UPDATE_BSSID) { 4808c2ecf20Sopenharmony_ci reg = le32_to_cpu(conf->bssid[1]); 4818c2ecf20Sopenharmony_ci rt2x00_set_field32(®, MAC_CSR5_BSS_ID_MASK, 3); 4828c2ecf20Sopenharmony_ci conf->bssid[1] = cpu_to_le32(reg); 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci rt2x00mmio_register_multiwrite(rt2x00dev, MAC_CSR4, 4858c2ecf20Sopenharmony_ci conf->bssid, 4868c2ecf20Sopenharmony_ci sizeof(conf->bssid)); 4878c2ecf20Sopenharmony_ci } 4888c2ecf20Sopenharmony_ci} 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_cistatic void rt61pci_config_erp(struct rt2x00_dev *rt2x00dev, 4918c2ecf20Sopenharmony_ci struct rt2x00lib_erp *erp, 4928c2ecf20Sopenharmony_ci u32 changed) 4938c2ecf20Sopenharmony_ci{ 4948c2ecf20Sopenharmony_ci u32 reg; 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR0); 4978c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR0_RX_ACK_TIMEOUT, 0x32); 4988c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR0_TSF_OFFSET, IEEE80211_HEADER); 4998c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, TXRX_CSR0, reg); 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci if (changed & BSS_CHANGED_ERP_PREAMBLE) { 5028c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR4); 5038c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR4_AUTORESPOND_ENABLE, 1); 5048c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR4_AUTORESPOND_PREAMBLE, 5058c2ecf20Sopenharmony_ci !!erp->short_preamble); 5068c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, TXRX_CSR4, reg); 5078c2ecf20Sopenharmony_ci } 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci if (changed & BSS_CHANGED_BASIC_RATES) 5108c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, TXRX_CSR5, 5118c2ecf20Sopenharmony_ci erp->basic_rates); 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci if (changed & BSS_CHANGED_BEACON_INT) { 5148c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR9); 5158c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR9_BEACON_INTERVAL, 5168c2ecf20Sopenharmony_ci erp->beacon_int * 16); 5178c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, TXRX_CSR9, reg); 5188c2ecf20Sopenharmony_ci } 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci if (changed & BSS_CHANGED_ERP_SLOT) { 5218c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, MAC_CSR9); 5228c2ecf20Sopenharmony_ci rt2x00_set_field32(®, MAC_CSR9_SLOT_TIME, erp->slot_time); 5238c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, MAC_CSR9, reg); 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, MAC_CSR8); 5268c2ecf20Sopenharmony_ci rt2x00_set_field32(®, MAC_CSR8_SIFS, erp->sifs); 5278c2ecf20Sopenharmony_ci rt2x00_set_field32(®, MAC_CSR8_SIFS_AFTER_RX_OFDM, 3); 5288c2ecf20Sopenharmony_ci rt2x00_set_field32(®, MAC_CSR8_EIFS, erp->eifs); 5298c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, MAC_CSR8, reg); 5308c2ecf20Sopenharmony_ci } 5318c2ecf20Sopenharmony_ci} 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_cistatic void rt61pci_config_antenna_5x(struct rt2x00_dev *rt2x00dev, 5348c2ecf20Sopenharmony_ci struct antenna_setup *ant) 5358c2ecf20Sopenharmony_ci{ 5368c2ecf20Sopenharmony_ci u8 r3; 5378c2ecf20Sopenharmony_ci u8 r4; 5388c2ecf20Sopenharmony_ci u8 r77; 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci r3 = rt61pci_bbp_read(rt2x00dev, 3); 5418c2ecf20Sopenharmony_ci r4 = rt61pci_bbp_read(rt2x00dev, 4); 5428c2ecf20Sopenharmony_ci r77 = rt61pci_bbp_read(rt2x00dev, 77); 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, rt2x00_rf(rt2x00dev, RF5325)); 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci /* 5478c2ecf20Sopenharmony_ci * Configure the RX antenna. 5488c2ecf20Sopenharmony_ci */ 5498c2ecf20Sopenharmony_ci switch (ant->rx) { 5508c2ecf20Sopenharmony_ci case ANTENNA_HW_DIVERSITY: 5518c2ecf20Sopenharmony_ci rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 2); 5528c2ecf20Sopenharmony_ci rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, 5538c2ecf20Sopenharmony_ci (rt2x00dev->curr_band != NL80211_BAND_5GHZ)); 5548c2ecf20Sopenharmony_ci break; 5558c2ecf20Sopenharmony_ci case ANTENNA_A: 5568c2ecf20Sopenharmony_ci rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 1); 5578c2ecf20Sopenharmony_ci rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, 0); 5588c2ecf20Sopenharmony_ci if (rt2x00dev->curr_band == NL80211_BAND_5GHZ) 5598c2ecf20Sopenharmony_ci rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 0); 5608c2ecf20Sopenharmony_ci else 5618c2ecf20Sopenharmony_ci rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 3); 5628c2ecf20Sopenharmony_ci break; 5638c2ecf20Sopenharmony_ci case ANTENNA_B: 5648c2ecf20Sopenharmony_ci default: 5658c2ecf20Sopenharmony_ci rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 1); 5668c2ecf20Sopenharmony_ci rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, 0); 5678c2ecf20Sopenharmony_ci if (rt2x00dev->curr_band == NL80211_BAND_5GHZ) 5688c2ecf20Sopenharmony_ci rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 3); 5698c2ecf20Sopenharmony_ci else 5708c2ecf20Sopenharmony_ci rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 0); 5718c2ecf20Sopenharmony_ci break; 5728c2ecf20Sopenharmony_ci } 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci rt61pci_bbp_write(rt2x00dev, 77, r77); 5758c2ecf20Sopenharmony_ci rt61pci_bbp_write(rt2x00dev, 3, r3); 5768c2ecf20Sopenharmony_ci rt61pci_bbp_write(rt2x00dev, 4, r4); 5778c2ecf20Sopenharmony_ci} 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_cistatic void rt61pci_config_antenna_2x(struct rt2x00_dev *rt2x00dev, 5808c2ecf20Sopenharmony_ci struct antenna_setup *ant) 5818c2ecf20Sopenharmony_ci{ 5828c2ecf20Sopenharmony_ci u8 r3; 5838c2ecf20Sopenharmony_ci u8 r4; 5848c2ecf20Sopenharmony_ci u8 r77; 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci r3 = rt61pci_bbp_read(rt2x00dev, 3); 5878c2ecf20Sopenharmony_ci r4 = rt61pci_bbp_read(rt2x00dev, 4); 5888c2ecf20Sopenharmony_ci r77 = rt61pci_bbp_read(rt2x00dev, 77); 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, rt2x00_rf(rt2x00dev, RF2529)); 5918c2ecf20Sopenharmony_ci rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, 5928c2ecf20Sopenharmony_ci !rt2x00_has_cap_frame_type(rt2x00dev)); 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci /* 5958c2ecf20Sopenharmony_ci * Configure the RX antenna. 5968c2ecf20Sopenharmony_ci */ 5978c2ecf20Sopenharmony_ci switch (ant->rx) { 5988c2ecf20Sopenharmony_ci case ANTENNA_HW_DIVERSITY: 5998c2ecf20Sopenharmony_ci rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 2); 6008c2ecf20Sopenharmony_ci break; 6018c2ecf20Sopenharmony_ci case ANTENNA_A: 6028c2ecf20Sopenharmony_ci rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 1); 6038c2ecf20Sopenharmony_ci rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 3); 6048c2ecf20Sopenharmony_ci break; 6058c2ecf20Sopenharmony_ci case ANTENNA_B: 6068c2ecf20Sopenharmony_ci default: 6078c2ecf20Sopenharmony_ci rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 1); 6088c2ecf20Sopenharmony_ci rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 0); 6098c2ecf20Sopenharmony_ci break; 6108c2ecf20Sopenharmony_ci } 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci rt61pci_bbp_write(rt2x00dev, 77, r77); 6138c2ecf20Sopenharmony_ci rt61pci_bbp_write(rt2x00dev, 3, r3); 6148c2ecf20Sopenharmony_ci rt61pci_bbp_write(rt2x00dev, 4, r4); 6158c2ecf20Sopenharmony_ci} 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_cistatic void rt61pci_config_antenna_2529_rx(struct rt2x00_dev *rt2x00dev, 6188c2ecf20Sopenharmony_ci const int p1, const int p2) 6198c2ecf20Sopenharmony_ci{ 6208c2ecf20Sopenharmony_ci u32 reg; 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, MAC_CSR13); 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci rt2x00_set_field32(®, MAC_CSR13_DIR4, 0); 6258c2ecf20Sopenharmony_ci rt2x00_set_field32(®, MAC_CSR13_VAL4, p1); 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci rt2x00_set_field32(®, MAC_CSR13_DIR3, 0); 6288c2ecf20Sopenharmony_ci rt2x00_set_field32(®, MAC_CSR13_VAL3, !p2); 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, MAC_CSR13, reg); 6318c2ecf20Sopenharmony_ci} 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_cistatic void rt61pci_config_antenna_2529(struct rt2x00_dev *rt2x00dev, 6348c2ecf20Sopenharmony_ci struct antenna_setup *ant) 6358c2ecf20Sopenharmony_ci{ 6368c2ecf20Sopenharmony_ci u8 r3; 6378c2ecf20Sopenharmony_ci u8 r4; 6388c2ecf20Sopenharmony_ci u8 r77; 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci r3 = rt61pci_bbp_read(rt2x00dev, 3); 6418c2ecf20Sopenharmony_ci r4 = rt61pci_bbp_read(rt2x00dev, 4); 6428c2ecf20Sopenharmony_ci r77 = rt61pci_bbp_read(rt2x00dev, 77); 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci /* 6458c2ecf20Sopenharmony_ci * Configure the RX antenna. 6468c2ecf20Sopenharmony_ci */ 6478c2ecf20Sopenharmony_ci switch (ant->rx) { 6488c2ecf20Sopenharmony_ci case ANTENNA_A: 6498c2ecf20Sopenharmony_ci rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 1); 6508c2ecf20Sopenharmony_ci rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 0); 6518c2ecf20Sopenharmony_ci rt61pci_config_antenna_2529_rx(rt2x00dev, 0, 0); 6528c2ecf20Sopenharmony_ci break; 6538c2ecf20Sopenharmony_ci case ANTENNA_HW_DIVERSITY: 6548c2ecf20Sopenharmony_ci /* 6558c2ecf20Sopenharmony_ci * FIXME: Antenna selection for the rf 2529 is very confusing 6568c2ecf20Sopenharmony_ci * in the legacy driver. Just default to antenna B until the 6578c2ecf20Sopenharmony_ci * legacy code can be properly translated into rt2x00 code. 6588c2ecf20Sopenharmony_ci */ 6598c2ecf20Sopenharmony_ci case ANTENNA_B: 6608c2ecf20Sopenharmony_ci default: 6618c2ecf20Sopenharmony_ci rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 1); 6628c2ecf20Sopenharmony_ci rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 3); 6638c2ecf20Sopenharmony_ci rt61pci_config_antenna_2529_rx(rt2x00dev, 1, 1); 6648c2ecf20Sopenharmony_ci break; 6658c2ecf20Sopenharmony_ci } 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci rt61pci_bbp_write(rt2x00dev, 77, r77); 6688c2ecf20Sopenharmony_ci rt61pci_bbp_write(rt2x00dev, 3, r3); 6698c2ecf20Sopenharmony_ci rt61pci_bbp_write(rt2x00dev, 4, r4); 6708c2ecf20Sopenharmony_ci} 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_cistruct antenna_sel { 6738c2ecf20Sopenharmony_ci u8 word; 6748c2ecf20Sopenharmony_ci /* 6758c2ecf20Sopenharmony_ci * value[0] -> non-LNA 6768c2ecf20Sopenharmony_ci * value[1] -> LNA 6778c2ecf20Sopenharmony_ci */ 6788c2ecf20Sopenharmony_ci u8 value[2]; 6798c2ecf20Sopenharmony_ci}; 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_cistatic const struct antenna_sel antenna_sel_a[] = { 6828c2ecf20Sopenharmony_ci { 96, { 0x58, 0x78 } }, 6838c2ecf20Sopenharmony_ci { 104, { 0x38, 0x48 } }, 6848c2ecf20Sopenharmony_ci { 75, { 0xfe, 0x80 } }, 6858c2ecf20Sopenharmony_ci { 86, { 0xfe, 0x80 } }, 6868c2ecf20Sopenharmony_ci { 88, { 0xfe, 0x80 } }, 6878c2ecf20Sopenharmony_ci { 35, { 0x60, 0x60 } }, 6888c2ecf20Sopenharmony_ci { 97, { 0x58, 0x58 } }, 6898c2ecf20Sopenharmony_ci { 98, { 0x58, 0x58 } }, 6908c2ecf20Sopenharmony_ci}; 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_cistatic const struct antenna_sel antenna_sel_bg[] = { 6938c2ecf20Sopenharmony_ci { 96, { 0x48, 0x68 } }, 6948c2ecf20Sopenharmony_ci { 104, { 0x2c, 0x3c } }, 6958c2ecf20Sopenharmony_ci { 75, { 0xfe, 0x80 } }, 6968c2ecf20Sopenharmony_ci { 86, { 0xfe, 0x80 } }, 6978c2ecf20Sopenharmony_ci { 88, { 0xfe, 0x80 } }, 6988c2ecf20Sopenharmony_ci { 35, { 0x50, 0x50 } }, 6998c2ecf20Sopenharmony_ci { 97, { 0x48, 0x48 } }, 7008c2ecf20Sopenharmony_ci { 98, { 0x48, 0x48 } }, 7018c2ecf20Sopenharmony_ci}; 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_cistatic void rt61pci_config_ant(struct rt2x00_dev *rt2x00dev, 7048c2ecf20Sopenharmony_ci struct antenna_setup *ant) 7058c2ecf20Sopenharmony_ci{ 7068c2ecf20Sopenharmony_ci const struct antenna_sel *sel; 7078c2ecf20Sopenharmony_ci unsigned int lna; 7088c2ecf20Sopenharmony_ci unsigned int i; 7098c2ecf20Sopenharmony_ci u32 reg; 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci /* 7128c2ecf20Sopenharmony_ci * We should never come here because rt2x00lib is supposed 7138c2ecf20Sopenharmony_ci * to catch this and send us the correct antenna explicitely. 7148c2ecf20Sopenharmony_ci */ 7158c2ecf20Sopenharmony_ci BUG_ON(ant->rx == ANTENNA_SW_DIVERSITY || 7168c2ecf20Sopenharmony_ci ant->tx == ANTENNA_SW_DIVERSITY); 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci if (rt2x00dev->curr_band == NL80211_BAND_5GHZ) { 7198c2ecf20Sopenharmony_ci sel = antenna_sel_a; 7208c2ecf20Sopenharmony_ci lna = rt2x00_has_cap_external_lna_a(rt2x00dev); 7218c2ecf20Sopenharmony_ci } else { 7228c2ecf20Sopenharmony_ci sel = antenna_sel_bg; 7238c2ecf20Sopenharmony_ci lna = rt2x00_has_cap_external_lna_bg(rt2x00dev); 7248c2ecf20Sopenharmony_ci } 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(antenna_sel_a); i++) 7278c2ecf20Sopenharmony_ci rt61pci_bbp_write(rt2x00dev, sel[i].word, sel[i].value[lna]); 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, PHY_CSR0); 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci rt2x00_set_field32(®, PHY_CSR0_PA_PE_BG, 7328c2ecf20Sopenharmony_ci rt2x00dev->curr_band == NL80211_BAND_2GHZ); 7338c2ecf20Sopenharmony_ci rt2x00_set_field32(®, PHY_CSR0_PA_PE_A, 7348c2ecf20Sopenharmony_ci rt2x00dev->curr_band == NL80211_BAND_5GHZ); 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, PHY_CSR0, reg); 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci if (rt2x00_rf(rt2x00dev, RF5225) || rt2x00_rf(rt2x00dev, RF5325)) 7398c2ecf20Sopenharmony_ci rt61pci_config_antenna_5x(rt2x00dev, ant); 7408c2ecf20Sopenharmony_ci else if (rt2x00_rf(rt2x00dev, RF2527)) 7418c2ecf20Sopenharmony_ci rt61pci_config_antenna_2x(rt2x00dev, ant); 7428c2ecf20Sopenharmony_ci else if (rt2x00_rf(rt2x00dev, RF2529)) { 7438c2ecf20Sopenharmony_ci if (rt2x00_has_cap_double_antenna(rt2x00dev)) 7448c2ecf20Sopenharmony_ci rt61pci_config_antenna_2x(rt2x00dev, ant); 7458c2ecf20Sopenharmony_ci else 7468c2ecf20Sopenharmony_ci rt61pci_config_antenna_2529(rt2x00dev, ant); 7478c2ecf20Sopenharmony_ci } 7488c2ecf20Sopenharmony_ci} 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_cistatic void rt61pci_config_lna_gain(struct rt2x00_dev *rt2x00dev, 7518c2ecf20Sopenharmony_ci struct rt2x00lib_conf *libconf) 7528c2ecf20Sopenharmony_ci{ 7538c2ecf20Sopenharmony_ci u16 eeprom; 7548c2ecf20Sopenharmony_ci short lna_gain = 0; 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ci if (libconf->conf->chandef.chan->band == NL80211_BAND_2GHZ) { 7578c2ecf20Sopenharmony_ci if (rt2x00_has_cap_external_lna_bg(rt2x00dev)) 7588c2ecf20Sopenharmony_ci lna_gain += 14; 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_ci eeprom = rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG); 7618c2ecf20Sopenharmony_ci lna_gain -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_BG_1); 7628c2ecf20Sopenharmony_ci } else { 7638c2ecf20Sopenharmony_ci if (rt2x00_has_cap_external_lna_a(rt2x00dev)) 7648c2ecf20Sopenharmony_ci lna_gain += 14; 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci eeprom = rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A); 7678c2ecf20Sopenharmony_ci lna_gain -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_A_1); 7688c2ecf20Sopenharmony_ci } 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ci rt2x00dev->lna_gain = lna_gain; 7718c2ecf20Sopenharmony_ci} 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_cistatic void rt61pci_config_channel(struct rt2x00_dev *rt2x00dev, 7748c2ecf20Sopenharmony_ci struct rf_channel *rf, const int txpower) 7758c2ecf20Sopenharmony_ci{ 7768c2ecf20Sopenharmony_ci u8 r3; 7778c2ecf20Sopenharmony_ci u8 r94; 7788c2ecf20Sopenharmony_ci u8 smart; 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci rt2x00_set_field32(&rf->rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower)); 7818c2ecf20Sopenharmony_ci rt2x00_set_field32(&rf->rf4, RF4_FREQ_OFFSET, rt2x00dev->freq_offset); 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ci smart = !(rt2x00_rf(rt2x00dev, RF5225) || rt2x00_rf(rt2x00dev, RF2527)); 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci r3 = rt61pci_bbp_read(rt2x00dev, 3); 7868c2ecf20Sopenharmony_ci rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, smart); 7878c2ecf20Sopenharmony_ci rt61pci_bbp_write(rt2x00dev, 3, r3); 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ci r94 = 6; 7908c2ecf20Sopenharmony_ci if (txpower > MAX_TXPOWER && txpower <= (MAX_TXPOWER + r94)) 7918c2ecf20Sopenharmony_ci r94 += txpower - MAX_TXPOWER; 7928c2ecf20Sopenharmony_ci else if (txpower < MIN_TXPOWER && txpower >= (MIN_TXPOWER - r94)) 7938c2ecf20Sopenharmony_ci r94 += txpower; 7948c2ecf20Sopenharmony_ci rt61pci_bbp_write(rt2x00dev, 94, r94); 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci rt61pci_rf_write(rt2x00dev, 1, rf->rf1); 7978c2ecf20Sopenharmony_ci rt61pci_rf_write(rt2x00dev, 2, rf->rf2); 7988c2ecf20Sopenharmony_ci rt61pci_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004); 7998c2ecf20Sopenharmony_ci rt61pci_rf_write(rt2x00dev, 4, rf->rf4); 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci udelay(200); 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci rt61pci_rf_write(rt2x00dev, 1, rf->rf1); 8048c2ecf20Sopenharmony_ci rt61pci_rf_write(rt2x00dev, 2, rf->rf2); 8058c2ecf20Sopenharmony_ci rt61pci_rf_write(rt2x00dev, 3, rf->rf3 | 0x00000004); 8068c2ecf20Sopenharmony_ci rt61pci_rf_write(rt2x00dev, 4, rf->rf4); 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci udelay(200); 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_ci rt61pci_rf_write(rt2x00dev, 1, rf->rf1); 8118c2ecf20Sopenharmony_ci rt61pci_rf_write(rt2x00dev, 2, rf->rf2); 8128c2ecf20Sopenharmony_ci rt61pci_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004); 8138c2ecf20Sopenharmony_ci rt61pci_rf_write(rt2x00dev, 4, rf->rf4); 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_ci msleep(1); 8168c2ecf20Sopenharmony_ci} 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_cistatic void rt61pci_config_txpower(struct rt2x00_dev *rt2x00dev, 8198c2ecf20Sopenharmony_ci const int txpower) 8208c2ecf20Sopenharmony_ci{ 8218c2ecf20Sopenharmony_ci struct rf_channel rf; 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ci rf.rf1 = rt2x00_rf_read(rt2x00dev, 1); 8248c2ecf20Sopenharmony_ci rf.rf2 = rt2x00_rf_read(rt2x00dev, 2); 8258c2ecf20Sopenharmony_ci rf.rf3 = rt2x00_rf_read(rt2x00dev, 3); 8268c2ecf20Sopenharmony_ci rf.rf4 = rt2x00_rf_read(rt2x00dev, 4); 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_ci rt61pci_config_channel(rt2x00dev, &rf, txpower); 8298c2ecf20Sopenharmony_ci} 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_cistatic void rt61pci_config_retry_limit(struct rt2x00_dev *rt2x00dev, 8328c2ecf20Sopenharmony_ci struct rt2x00lib_conf *libconf) 8338c2ecf20Sopenharmony_ci{ 8348c2ecf20Sopenharmony_ci u32 reg; 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR4); 8378c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR4_OFDM_TX_RATE_DOWN, 1); 8388c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR4_OFDM_TX_RATE_STEP, 0); 8398c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR4_OFDM_TX_FALLBACK_CCK, 0); 8408c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR4_LONG_RETRY_LIMIT, 8418c2ecf20Sopenharmony_ci libconf->conf->long_frame_max_tx_count); 8428c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR4_SHORT_RETRY_LIMIT, 8438c2ecf20Sopenharmony_ci libconf->conf->short_frame_max_tx_count); 8448c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, TXRX_CSR4, reg); 8458c2ecf20Sopenharmony_ci} 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_cistatic void rt61pci_config_ps(struct rt2x00_dev *rt2x00dev, 8488c2ecf20Sopenharmony_ci struct rt2x00lib_conf *libconf) 8498c2ecf20Sopenharmony_ci{ 8508c2ecf20Sopenharmony_ci enum dev_state state = 8518c2ecf20Sopenharmony_ci (libconf->conf->flags & IEEE80211_CONF_PS) ? 8528c2ecf20Sopenharmony_ci STATE_SLEEP : STATE_AWAKE; 8538c2ecf20Sopenharmony_ci u32 reg; 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_ci if (state == STATE_SLEEP) { 8568c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, MAC_CSR11); 8578c2ecf20Sopenharmony_ci rt2x00_set_field32(®, MAC_CSR11_DELAY_AFTER_TBCN, 8588c2ecf20Sopenharmony_ci rt2x00dev->beacon_int - 10); 8598c2ecf20Sopenharmony_ci rt2x00_set_field32(®, MAC_CSR11_TBCN_BEFORE_WAKEUP, 8608c2ecf20Sopenharmony_ci libconf->conf->listen_interval - 1); 8618c2ecf20Sopenharmony_ci rt2x00_set_field32(®, MAC_CSR11_WAKEUP_LATENCY, 5); 8628c2ecf20Sopenharmony_ci 8638c2ecf20Sopenharmony_ci /* We must first disable autowake before it can be enabled */ 8648c2ecf20Sopenharmony_ci rt2x00_set_field32(®, MAC_CSR11_AUTOWAKE, 0); 8658c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, MAC_CSR11, reg); 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_ci rt2x00_set_field32(®, MAC_CSR11_AUTOWAKE, 1); 8688c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, MAC_CSR11, reg); 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, SOFT_RESET_CSR, 8718c2ecf20Sopenharmony_ci 0x00000005); 8728c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, IO_CNTL_CSR, 0x0000001c); 8738c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, PCI_USEC_CSR, 0x00000060); 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_ci rt61pci_mcu_request(rt2x00dev, MCU_SLEEP, 0xff, 0, 0); 8768c2ecf20Sopenharmony_ci } else { 8778c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, MAC_CSR11); 8788c2ecf20Sopenharmony_ci rt2x00_set_field32(®, MAC_CSR11_DELAY_AFTER_TBCN, 0); 8798c2ecf20Sopenharmony_ci rt2x00_set_field32(®, MAC_CSR11_TBCN_BEFORE_WAKEUP, 0); 8808c2ecf20Sopenharmony_ci rt2x00_set_field32(®, MAC_CSR11_AUTOWAKE, 0); 8818c2ecf20Sopenharmony_ci rt2x00_set_field32(®, MAC_CSR11_WAKEUP_LATENCY, 0); 8828c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, MAC_CSR11, reg); 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, SOFT_RESET_CSR, 8858c2ecf20Sopenharmony_ci 0x00000007); 8868c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, IO_CNTL_CSR, 0x00000018); 8878c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, PCI_USEC_CSR, 0x00000020); 8888c2ecf20Sopenharmony_ci 8898c2ecf20Sopenharmony_ci rt61pci_mcu_request(rt2x00dev, MCU_WAKEUP, 0xff, 0, 0); 8908c2ecf20Sopenharmony_ci } 8918c2ecf20Sopenharmony_ci} 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_cistatic void rt61pci_config(struct rt2x00_dev *rt2x00dev, 8948c2ecf20Sopenharmony_ci struct rt2x00lib_conf *libconf, 8958c2ecf20Sopenharmony_ci const unsigned int flags) 8968c2ecf20Sopenharmony_ci{ 8978c2ecf20Sopenharmony_ci /* Always recalculate LNA gain before changing configuration */ 8988c2ecf20Sopenharmony_ci rt61pci_config_lna_gain(rt2x00dev, libconf); 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci if (flags & IEEE80211_CONF_CHANGE_CHANNEL) 9018c2ecf20Sopenharmony_ci rt61pci_config_channel(rt2x00dev, &libconf->rf, 9028c2ecf20Sopenharmony_ci libconf->conf->power_level); 9038c2ecf20Sopenharmony_ci if ((flags & IEEE80211_CONF_CHANGE_POWER) && 9048c2ecf20Sopenharmony_ci !(flags & IEEE80211_CONF_CHANGE_CHANNEL)) 9058c2ecf20Sopenharmony_ci rt61pci_config_txpower(rt2x00dev, libconf->conf->power_level); 9068c2ecf20Sopenharmony_ci if (flags & IEEE80211_CONF_CHANGE_RETRY_LIMITS) 9078c2ecf20Sopenharmony_ci rt61pci_config_retry_limit(rt2x00dev, libconf); 9088c2ecf20Sopenharmony_ci if (flags & IEEE80211_CONF_CHANGE_PS) 9098c2ecf20Sopenharmony_ci rt61pci_config_ps(rt2x00dev, libconf); 9108c2ecf20Sopenharmony_ci} 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_ci/* 9138c2ecf20Sopenharmony_ci * Link tuning 9148c2ecf20Sopenharmony_ci */ 9158c2ecf20Sopenharmony_cistatic void rt61pci_link_stats(struct rt2x00_dev *rt2x00dev, 9168c2ecf20Sopenharmony_ci struct link_qual *qual) 9178c2ecf20Sopenharmony_ci{ 9188c2ecf20Sopenharmony_ci u32 reg; 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci /* 9218c2ecf20Sopenharmony_ci * Update FCS error count from register. 9228c2ecf20Sopenharmony_ci */ 9238c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, STA_CSR0); 9248c2ecf20Sopenharmony_ci qual->rx_failed = rt2x00_get_field32(reg, STA_CSR0_FCS_ERROR); 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci /* 9278c2ecf20Sopenharmony_ci * Update False CCA count from register. 9288c2ecf20Sopenharmony_ci */ 9298c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, STA_CSR1); 9308c2ecf20Sopenharmony_ci qual->false_cca = rt2x00_get_field32(reg, STA_CSR1_FALSE_CCA_ERROR); 9318c2ecf20Sopenharmony_ci} 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_cistatic inline void rt61pci_set_vgc(struct rt2x00_dev *rt2x00dev, 9348c2ecf20Sopenharmony_ci struct link_qual *qual, u8 vgc_level) 9358c2ecf20Sopenharmony_ci{ 9368c2ecf20Sopenharmony_ci if (qual->vgc_level != vgc_level) { 9378c2ecf20Sopenharmony_ci rt61pci_bbp_write(rt2x00dev, 17, vgc_level); 9388c2ecf20Sopenharmony_ci qual->vgc_level = vgc_level; 9398c2ecf20Sopenharmony_ci qual->vgc_level_reg = vgc_level; 9408c2ecf20Sopenharmony_ci } 9418c2ecf20Sopenharmony_ci} 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_cistatic void rt61pci_reset_tuner(struct rt2x00_dev *rt2x00dev, 9448c2ecf20Sopenharmony_ci struct link_qual *qual) 9458c2ecf20Sopenharmony_ci{ 9468c2ecf20Sopenharmony_ci rt61pci_set_vgc(rt2x00dev, qual, 0x20); 9478c2ecf20Sopenharmony_ci} 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_cistatic void rt61pci_link_tuner(struct rt2x00_dev *rt2x00dev, 9508c2ecf20Sopenharmony_ci struct link_qual *qual, const u32 count) 9518c2ecf20Sopenharmony_ci{ 9528c2ecf20Sopenharmony_ci u8 up_bound; 9538c2ecf20Sopenharmony_ci u8 low_bound; 9548c2ecf20Sopenharmony_ci 9558c2ecf20Sopenharmony_ci /* 9568c2ecf20Sopenharmony_ci * Determine r17 bounds. 9578c2ecf20Sopenharmony_ci */ 9588c2ecf20Sopenharmony_ci if (rt2x00dev->curr_band == NL80211_BAND_5GHZ) { 9598c2ecf20Sopenharmony_ci low_bound = 0x28; 9608c2ecf20Sopenharmony_ci up_bound = 0x48; 9618c2ecf20Sopenharmony_ci if (rt2x00_has_cap_external_lna_a(rt2x00dev)) { 9628c2ecf20Sopenharmony_ci low_bound += 0x10; 9638c2ecf20Sopenharmony_ci up_bound += 0x10; 9648c2ecf20Sopenharmony_ci } 9658c2ecf20Sopenharmony_ci } else { 9668c2ecf20Sopenharmony_ci low_bound = 0x20; 9678c2ecf20Sopenharmony_ci up_bound = 0x40; 9688c2ecf20Sopenharmony_ci if (rt2x00_has_cap_external_lna_bg(rt2x00dev)) { 9698c2ecf20Sopenharmony_ci low_bound += 0x10; 9708c2ecf20Sopenharmony_ci up_bound += 0x10; 9718c2ecf20Sopenharmony_ci } 9728c2ecf20Sopenharmony_ci } 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_ci /* 9758c2ecf20Sopenharmony_ci * If we are not associated, we should go straight to the 9768c2ecf20Sopenharmony_ci * dynamic CCA tuning. 9778c2ecf20Sopenharmony_ci */ 9788c2ecf20Sopenharmony_ci if (!rt2x00dev->intf_associated) 9798c2ecf20Sopenharmony_ci goto dynamic_cca_tune; 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_ci /* 9828c2ecf20Sopenharmony_ci * Special big-R17 for very short distance 9838c2ecf20Sopenharmony_ci */ 9848c2ecf20Sopenharmony_ci if (qual->rssi >= -35) { 9858c2ecf20Sopenharmony_ci rt61pci_set_vgc(rt2x00dev, qual, 0x60); 9868c2ecf20Sopenharmony_ci return; 9878c2ecf20Sopenharmony_ci } 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_ci /* 9908c2ecf20Sopenharmony_ci * Special big-R17 for short distance 9918c2ecf20Sopenharmony_ci */ 9928c2ecf20Sopenharmony_ci if (qual->rssi >= -58) { 9938c2ecf20Sopenharmony_ci rt61pci_set_vgc(rt2x00dev, qual, up_bound); 9948c2ecf20Sopenharmony_ci return; 9958c2ecf20Sopenharmony_ci } 9968c2ecf20Sopenharmony_ci 9978c2ecf20Sopenharmony_ci /* 9988c2ecf20Sopenharmony_ci * Special big-R17 for middle-short distance 9998c2ecf20Sopenharmony_ci */ 10008c2ecf20Sopenharmony_ci if (qual->rssi >= -66) { 10018c2ecf20Sopenharmony_ci rt61pci_set_vgc(rt2x00dev, qual, low_bound + 0x10); 10028c2ecf20Sopenharmony_ci return; 10038c2ecf20Sopenharmony_ci } 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_ci /* 10068c2ecf20Sopenharmony_ci * Special mid-R17 for middle distance 10078c2ecf20Sopenharmony_ci */ 10088c2ecf20Sopenharmony_ci if (qual->rssi >= -74) { 10098c2ecf20Sopenharmony_ci rt61pci_set_vgc(rt2x00dev, qual, low_bound + 0x08); 10108c2ecf20Sopenharmony_ci return; 10118c2ecf20Sopenharmony_ci } 10128c2ecf20Sopenharmony_ci 10138c2ecf20Sopenharmony_ci /* 10148c2ecf20Sopenharmony_ci * Special case: Change up_bound based on the rssi. 10158c2ecf20Sopenharmony_ci * Lower up_bound when rssi is weaker then -74 dBm. 10168c2ecf20Sopenharmony_ci */ 10178c2ecf20Sopenharmony_ci up_bound -= 2 * (-74 - qual->rssi); 10188c2ecf20Sopenharmony_ci if (low_bound > up_bound) 10198c2ecf20Sopenharmony_ci up_bound = low_bound; 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_ci if (qual->vgc_level > up_bound) { 10228c2ecf20Sopenharmony_ci rt61pci_set_vgc(rt2x00dev, qual, up_bound); 10238c2ecf20Sopenharmony_ci return; 10248c2ecf20Sopenharmony_ci } 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_cidynamic_cca_tune: 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_ci /* 10298c2ecf20Sopenharmony_ci * r17 does not yet exceed upper limit, continue and base 10308c2ecf20Sopenharmony_ci * the r17 tuning on the false CCA count. 10318c2ecf20Sopenharmony_ci */ 10328c2ecf20Sopenharmony_ci if ((qual->false_cca > 512) && (qual->vgc_level < up_bound)) 10338c2ecf20Sopenharmony_ci rt61pci_set_vgc(rt2x00dev, qual, ++qual->vgc_level); 10348c2ecf20Sopenharmony_ci else if ((qual->false_cca < 100) && (qual->vgc_level > low_bound)) 10358c2ecf20Sopenharmony_ci rt61pci_set_vgc(rt2x00dev, qual, --qual->vgc_level); 10368c2ecf20Sopenharmony_ci} 10378c2ecf20Sopenharmony_ci 10388c2ecf20Sopenharmony_ci/* 10398c2ecf20Sopenharmony_ci * Queue handlers. 10408c2ecf20Sopenharmony_ci */ 10418c2ecf20Sopenharmony_cistatic void rt61pci_start_queue(struct data_queue *queue) 10428c2ecf20Sopenharmony_ci{ 10438c2ecf20Sopenharmony_ci struct rt2x00_dev *rt2x00dev = queue->rt2x00dev; 10448c2ecf20Sopenharmony_ci u32 reg; 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_ci switch (queue->qid) { 10478c2ecf20Sopenharmony_ci case QID_RX: 10488c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR0); 10498c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR0_DISABLE_RX, 0); 10508c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, TXRX_CSR0, reg); 10518c2ecf20Sopenharmony_ci break; 10528c2ecf20Sopenharmony_ci case QID_BEACON: 10538c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR9); 10548c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 1); 10558c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 1); 10568c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 1); 10578c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, TXRX_CSR9, reg); 10588c2ecf20Sopenharmony_ci break; 10598c2ecf20Sopenharmony_ci default: 10608c2ecf20Sopenharmony_ci break; 10618c2ecf20Sopenharmony_ci } 10628c2ecf20Sopenharmony_ci} 10638c2ecf20Sopenharmony_ci 10648c2ecf20Sopenharmony_cistatic void rt61pci_kick_queue(struct data_queue *queue) 10658c2ecf20Sopenharmony_ci{ 10668c2ecf20Sopenharmony_ci struct rt2x00_dev *rt2x00dev = queue->rt2x00dev; 10678c2ecf20Sopenharmony_ci u32 reg; 10688c2ecf20Sopenharmony_ci 10698c2ecf20Sopenharmony_ci switch (queue->qid) { 10708c2ecf20Sopenharmony_ci case QID_AC_VO: 10718c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, TX_CNTL_CSR); 10728c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_AC0, 1); 10738c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, TX_CNTL_CSR, reg); 10748c2ecf20Sopenharmony_ci break; 10758c2ecf20Sopenharmony_ci case QID_AC_VI: 10768c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, TX_CNTL_CSR); 10778c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_AC1, 1); 10788c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, TX_CNTL_CSR, reg); 10798c2ecf20Sopenharmony_ci break; 10808c2ecf20Sopenharmony_ci case QID_AC_BE: 10818c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, TX_CNTL_CSR); 10828c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_AC2, 1); 10838c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, TX_CNTL_CSR, reg); 10848c2ecf20Sopenharmony_ci break; 10858c2ecf20Sopenharmony_ci case QID_AC_BK: 10868c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, TX_CNTL_CSR); 10878c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_AC3, 1); 10888c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, TX_CNTL_CSR, reg); 10898c2ecf20Sopenharmony_ci break; 10908c2ecf20Sopenharmony_ci default: 10918c2ecf20Sopenharmony_ci break; 10928c2ecf20Sopenharmony_ci } 10938c2ecf20Sopenharmony_ci} 10948c2ecf20Sopenharmony_ci 10958c2ecf20Sopenharmony_cistatic void rt61pci_stop_queue(struct data_queue *queue) 10968c2ecf20Sopenharmony_ci{ 10978c2ecf20Sopenharmony_ci struct rt2x00_dev *rt2x00dev = queue->rt2x00dev; 10988c2ecf20Sopenharmony_ci u32 reg; 10998c2ecf20Sopenharmony_ci 11008c2ecf20Sopenharmony_ci switch (queue->qid) { 11018c2ecf20Sopenharmony_ci case QID_AC_VO: 11028c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, TX_CNTL_CSR); 11038c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TX_CNTL_CSR_ABORT_TX_AC0, 1); 11048c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, TX_CNTL_CSR, reg); 11058c2ecf20Sopenharmony_ci break; 11068c2ecf20Sopenharmony_ci case QID_AC_VI: 11078c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, TX_CNTL_CSR); 11088c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TX_CNTL_CSR_ABORT_TX_AC1, 1); 11098c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, TX_CNTL_CSR, reg); 11108c2ecf20Sopenharmony_ci break; 11118c2ecf20Sopenharmony_ci case QID_AC_BE: 11128c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, TX_CNTL_CSR); 11138c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TX_CNTL_CSR_ABORT_TX_AC2, 1); 11148c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, TX_CNTL_CSR, reg); 11158c2ecf20Sopenharmony_ci break; 11168c2ecf20Sopenharmony_ci case QID_AC_BK: 11178c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, TX_CNTL_CSR); 11188c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TX_CNTL_CSR_ABORT_TX_AC3, 1); 11198c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, TX_CNTL_CSR, reg); 11208c2ecf20Sopenharmony_ci break; 11218c2ecf20Sopenharmony_ci case QID_RX: 11228c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR0); 11238c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR0_DISABLE_RX, 1); 11248c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, TXRX_CSR0, reg); 11258c2ecf20Sopenharmony_ci break; 11268c2ecf20Sopenharmony_ci case QID_BEACON: 11278c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR9); 11288c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 0); 11298c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 0); 11308c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0); 11318c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, TXRX_CSR9, reg); 11328c2ecf20Sopenharmony_ci 11338c2ecf20Sopenharmony_ci /* 11348c2ecf20Sopenharmony_ci * Wait for possibly running tbtt tasklets. 11358c2ecf20Sopenharmony_ci */ 11368c2ecf20Sopenharmony_ci tasklet_kill(&rt2x00dev->tbtt_tasklet); 11378c2ecf20Sopenharmony_ci break; 11388c2ecf20Sopenharmony_ci default: 11398c2ecf20Sopenharmony_ci break; 11408c2ecf20Sopenharmony_ci } 11418c2ecf20Sopenharmony_ci} 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_ci/* 11448c2ecf20Sopenharmony_ci * Firmware functions 11458c2ecf20Sopenharmony_ci */ 11468c2ecf20Sopenharmony_cistatic char *rt61pci_get_firmware_name(struct rt2x00_dev *rt2x00dev) 11478c2ecf20Sopenharmony_ci{ 11488c2ecf20Sopenharmony_ci u16 chip; 11498c2ecf20Sopenharmony_ci char *fw_name; 11508c2ecf20Sopenharmony_ci 11518c2ecf20Sopenharmony_ci pci_read_config_word(to_pci_dev(rt2x00dev->dev), PCI_DEVICE_ID, &chip); 11528c2ecf20Sopenharmony_ci switch (chip) { 11538c2ecf20Sopenharmony_ci case RT2561_PCI_ID: 11548c2ecf20Sopenharmony_ci fw_name = FIRMWARE_RT2561; 11558c2ecf20Sopenharmony_ci break; 11568c2ecf20Sopenharmony_ci case RT2561s_PCI_ID: 11578c2ecf20Sopenharmony_ci fw_name = FIRMWARE_RT2561s; 11588c2ecf20Sopenharmony_ci break; 11598c2ecf20Sopenharmony_ci case RT2661_PCI_ID: 11608c2ecf20Sopenharmony_ci fw_name = FIRMWARE_RT2661; 11618c2ecf20Sopenharmony_ci break; 11628c2ecf20Sopenharmony_ci default: 11638c2ecf20Sopenharmony_ci fw_name = NULL; 11648c2ecf20Sopenharmony_ci break; 11658c2ecf20Sopenharmony_ci } 11668c2ecf20Sopenharmony_ci 11678c2ecf20Sopenharmony_ci return fw_name; 11688c2ecf20Sopenharmony_ci} 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_cistatic int rt61pci_check_firmware(struct rt2x00_dev *rt2x00dev, 11718c2ecf20Sopenharmony_ci const u8 *data, const size_t len) 11728c2ecf20Sopenharmony_ci{ 11738c2ecf20Sopenharmony_ci u16 fw_crc; 11748c2ecf20Sopenharmony_ci u16 crc; 11758c2ecf20Sopenharmony_ci 11768c2ecf20Sopenharmony_ci /* 11778c2ecf20Sopenharmony_ci * Only support 8kb firmware files. 11788c2ecf20Sopenharmony_ci */ 11798c2ecf20Sopenharmony_ci if (len != 8192) 11808c2ecf20Sopenharmony_ci return FW_BAD_LENGTH; 11818c2ecf20Sopenharmony_ci 11828c2ecf20Sopenharmony_ci /* 11838c2ecf20Sopenharmony_ci * The last 2 bytes in the firmware array are the crc checksum itself. 11848c2ecf20Sopenharmony_ci * This means that we should never pass those 2 bytes to the crc 11858c2ecf20Sopenharmony_ci * algorithm. 11868c2ecf20Sopenharmony_ci */ 11878c2ecf20Sopenharmony_ci fw_crc = (data[len - 2] << 8 | data[len - 1]); 11888c2ecf20Sopenharmony_ci 11898c2ecf20Sopenharmony_ci /* 11908c2ecf20Sopenharmony_ci * Use the crc itu-t algorithm. 11918c2ecf20Sopenharmony_ci */ 11928c2ecf20Sopenharmony_ci crc = crc_itu_t(0, data, len - 2); 11938c2ecf20Sopenharmony_ci crc = crc_itu_t_byte(crc, 0); 11948c2ecf20Sopenharmony_ci crc = crc_itu_t_byte(crc, 0); 11958c2ecf20Sopenharmony_ci 11968c2ecf20Sopenharmony_ci return (fw_crc == crc) ? FW_OK : FW_BAD_CRC; 11978c2ecf20Sopenharmony_ci} 11988c2ecf20Sopenharmony_ci 11998c2ecf20Sopenharmony_cistatic int rt61pci_load_firmware(struct rt2x00_dev *rt2x00dev, 12008c2ecf20Sopenharmony_ci const u8 *data, const size_t len) 12018c2ecf20Sopenharmony_ci{ 12028c2ecf20Sopenharmony_ci int i; 12038c2ecf20Sopenharmony_ci u32 reg; 12048c2ecf20Sopenharmony_ci 12058c2ecf20Sopenharmony_ci /* 12068c2ecf20Sopenharmony_ci * Wait for stable hardware. 12078c2ecf20Sopenharmony_ci */ 12088c2ecf20Sopenharmony_ci for (i = 0; i < 100; i++) { 12098c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, MAC_CSR0); 12108c2ecf20Sopenharmony_ci if (reg) 12118c2ecf20Sopenharmony_ci break; 12128c2ecf20Sopenharmony_ci msleep(1); 12138c2ecf20Sopenharmony_ci } 12148c2ecf20Sopenharmony_ci 12158c2ecf20Sopenharmony_ci if (!reg) { 12168c2ecf20Sopenharmony_ci rt2x00_err(rt2x00dev, "Unstable hardware\n"); 12178c2ecf20Sopenharmony_ci return -EBUSY; 12188c2ecf20Sopenharmony_ci } 12198c2ecf20Sopenharmony_ci 12208c2ecf20Sopenharmony_ci /* 12218c2ecf20Sopenharmony_ci * Prepare MCU and mailbox for firmware loading. 12228c2ecf20Sopenharmony_ci */ 12238c2ecf20Sopenharmony_ci reg = 0; 12248c2ecf20Sopenharmony_ci rt2x00_set_field32(®, MCU_CNTL_CSR_RESET, 1); 12258c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, MCU_CNTL_CSR, reg); 12268c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, M2H_CMD_DONE_CSR, 0xffffffff); 12278c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0); 12288c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, HOST_CMD_CSR, 0); 12298c2ecf20Sopenharmony_ci 12308c2ecf20Sopenharmony_ci /* 12318c2ecf20Sopenharmony_ci * Write firmware to device. 12328c2ecf20Sopenharmony_ci */ 12338c2ecf20Sopenharmony_ci reg = 0; 12348c2ecf20Sopenharmony_ci rt2x00_set_field32(®, MCU_CNTL_CSR_RESET, 1); 12358c2ecf20Sopenharmony_ci rt2x00_set_field32(®, MCU_CNTL_CSR_SELECT_BANK, 1); 12368c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, MCU_CNTL_CSR, reg); 12378c2ecf20Sopenharmony_ci 12388c2ecf20Sopenharmony_ci rt2x00mmio_register_multiwrite(rt2x00dev, FIRMWARE_IMAGE_BASE, 12398c2ecf20Sopenharmony_ci data, len); 12408c2ecf20Sopenharmony_ci 12418c2ecf20Sopenharmony_ci rt2x00_set_field32(®, MCU_CNTL_CSR_SELECT_BANK, 0); 12428c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, MCU_CNTL_CSR, reg); 12438c2ecf20Sopenharmony_ci 12448c2ecf20Sopenharmony_ci rt2x00_set_field32(®, MCU_CNTL_CSR_RESET, 0); 12458c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, MCU_CNTL_CSR, reg); 12468c2ecf20Sopenharmony_ci 12478c2ecf20Sopenharmony_ci for (i = 0; i < 100; i++) { 12488c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, MCU_CNTL_CSR); 12498c2ecf20Sopenharmony_ci if (rt2x00_get_field32(reg, MCU_CNTL_CSR_READY)) 12508c2ecf20Sopenharmony_ci break; 12518c2ecf20Sopenharmony_ci msleep(1); 12528c2ecf20Sopenharmony_ci } 12538c2ecf20Sopenharmony_ci 12548c2ecf20Sopenharmony_ci if (i == 100) { 12558c2ecf20Sopenharmony_ci rt2x00_err(rt2x00dev, "MCU Control register not ready\n"); 12568c2ecf20Sopenharmony_ci return -EBUSY; 12578c2ecf20Sopenharmony_ci } 12588c2ecf20Sopenharmony_ci 12598c2ecf20Sopenharmony_ci /* 12608c2ecf20Sopenharmony_ci * Hardware needs another millisecond before it is ready. 12618c2ecf20Sopenharmony_ci */ 12628c2ecf20Sopenharmony_ci msleep(1); 12638c2ecf20Sopenharmony_ci 12648c2ecf20Sopenharmony_ci /* 12658c2ecf20Sopenharmony_ci * Reset MAC and BBP registers. 12668c2ecf20Sopenharmony_ci */ 12678c2ecf20Sopenharmony_ci reg = 0; 12688c2ecf20Sopenharmony_ci rt2x00_set_field32(®, MAC_CSR1_SOFT_RESET, 1); 12698c2ecf20Sopenharmony_ci rt2x00_set_field32(®, MAC_CSR1_BBP_RESET, 1); 12708c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, MAC_CSR1, reg); 12718c2ecf20Sopenharmony_ci 12728c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, MAC_CSR1); 12738c2ecf20Sopenharmony_ci rt2x00_set_field32(®, MAC_CSR1_SOFT_RESET, 0); 12748c2ecf20Sopenharmony_ci rt2x00_set_field32(®, MAC_CSR1_BBP_RESET, 0); 12758c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, MAC_CSR1, reg); 12768c2ecf20Sopenharmony_ci 12778c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, MAC_CSR1); 12788c2ecf20Sopenharmony_ci rt2x00_set_field32(®, MAC_CSR1_HOST_READY, 1); 12798c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, MAC_CSR1, reg); 12808c2ecf20Sopenharmony_ci 12818c2ecf20Sopenharmony_ci return 0; 12828c2ecf20Sopenharmony_ci} 12838c2ecf20Sopenharmony_ci 12848c2ecf20Sopenharmony_ci/* 12858c2ecf20Sopenharmony_ci * Initialization functions. 12868c2ecf20Sopenharmony_ci */ 12878c2ecf20Sopenharmony_cistatic bool rt61pci_get_entry_state(struct queue_entry *entry) 12888c2ecf20Sopenharmony_ci{ 12898c2ecf20Sopenharmony_ci struct queue_entry_priv_mmio *entry_priv = entry->priv_data; 12908c2ecf20Sopenharmony_ci u32 word; 12918c2ecf20Sopenharmony_ci 12928c2ecf20Sopenharmony_ci if (entry->queue->qid == QID_RX) { 12938c2ecf20Sopenharmony_ci word = rt2x00_desc_read(entry_priv->desc, 0); 12948c2ecf20Sopenharmony_ci 12958c2ecf20Sopenharmony_ci return rt2x00_get_field32(word, RXD_W0_OWNER_NIC); 12968c2ecf20Sopenharmony_ci } else { 12978c2ecf20Sopenharmony_ci word = rt2x00_desc_read(entry_priv->desc, 0); 12988c2ecf20Sopenharmony_ci 12998c2ecf20Sopenharmony_ci return (rt2x00_get_field32(word, TXD_W0_OWNER_NIC) || 13008c2ecf20Sopenharmony_ci rt2x00_get_field32(word, TXD_W0_VALID)); 13018c2ecf20Sopenharmony_ci } 13028c2ecf20Sopenharmony_ci} 13038c2ecf20Sopenharmony_ci 13048c2ecf20Sopenharmony_cistatic void rt61pci_clear_entry(struct queue_entry *entry) 13058c2ecf20Sopenharmony_ci{ 13068c2ecf20Sopenharmony_ci struct queue_entry_priv_mmio *entry_priv = entry->priv_data; 13078c2ecf20Sopenharmony_ci struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); 13088c2ecf20Sopenharmony_ci u32 word; 13098c2ecf20Sopenharmony_ci 13108c2ecf20Sopenharmony_ci if (entry->queue->qid == QID_RX) { 13118c2ecf20Sopenharmony_ci word = rt2x00_desc_read(entry_priv->desc, 5); 13128c2ecf20Sopenharmony_ci rt2x00_set_field32(&word, RXD_W5_BUFFER_PHYSICAL_ADDRESS, 13138c2ecf20Sopenharmony_ci skbdesc->skb_dma); 13148c2ecf20Sopenharmony_ci rt2x00_desc_write(entry_priv->desc, 5, word); 13158c2ecf20Sopenharmony_ci 13168c2ecf20Sopenharmony_ci word = rt2x00_desc_read(entry_priv->desc, 0); 13178c2ecf20Sopenharmony_ci rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1); 13188c2ecf20Sopenharmony_ci rt2x00_desc_write(entry_priv->desc, 0, word); 13198c2ecf20Sopenharmony_ci } else { 13208c2ecf20Sopenharmony_ci word = rt2x00_desc_read(entry_priv->desc, 0); 13218c2ecf20Sopenharmony_ci rt2x00_set_field32(&word, TXD_W0_VALID, 0); 13228c2ecf20Sopenharmony_ci rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0); 13238c2ecf20Sopenharmony_ci rt2x00_desc_write(entry_priv->desc, 0, word); 13248c2ecf20Sopenharmony_ci } 13258c2ecf20Sopenharmony_ci} 13268c2ecf20Sopenharmony_ci 13278c2ecf20Sopenharmony_cistatic int rt61pci_init_queues(struct rt2x00_dev *rt2x00dev) 13288c2ecf20Sopenharmony_ci{ 13298c2ecf20Sopenharmony_ci struct queue_entry_priv_mmio *entry_priv; 13308c2ecf20Sopenharmony_ci u32 reg; 13318c2ecf20Sopenharmony_ci 13328c2ecf20Sopenharmony_ci /* 13338c2ecf20Sopenharmony_ci * Initialize registers. 13348c2ecf20Sopenharmony_ci */ 13358c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, TX_RING_CSR0); 13368c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TX_RING_CSR0_AC0_RING_SIZE, 13378c2ecf20Sopenharmony_ci rt2x00dev->tx[0].limit); 13388c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TX_RING_CSR0_AC1_RING_SIZE, 13398c2ecf20Sopenharmony_ci rt2x00dev->tx[1].limit); 13408c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TX_RING_CSR0_AC2_RING_SIZE, 13418c2ecf20Sopenharmony_ci rt2x00dev->tx[2].limit); 13428c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TX_RING_CSR0_AC3_RING_SIZE, 13438c2ecf20Sopenharmony_ci rt2x00dev->tx[3].limit); 13448c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, TX_RING_CSR0, reg); 13458c2ecf20Sopenharmony_ci 13468c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, TX_RING_CSR1); 13478c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TX_RING_CSR1_TXD_SIZE, 13488c2ecf20Sopenharmony_ci rt2x00dev->tx[0].desc_size / 4); 13498c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, TX_RING_CSR1, reg); 13508c2ecf20Sopenharmony_ci 13518c2ecf20Sopenharmony_ci entry_priv = rt2x00dev->tx[0].entries[0].priv_data; 13528c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, AC0_BASE_CSR); 13538c2ecf20Sopenharmony_ci rt2x00_set_field32(®, AC0_BASE_CSR_RING_REGISTER, 13548c2ecf20Sopenharmony_ci entry_priv->desc_dma); 13558c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, AC0_BASE_CSR, reg); 13568c2ecf20Sopenharmony_ci 13578c2ecf20Sopenharmony_ci entry_priv = rt2x00dev->tx[1].entries[0].priv_data; 13588c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, AC1_BASE_CSR); 13598c2ecf20Sopenharmony_ci rt2x00_set_field32(®, AC1_BASE_CSR_RING_REGISTER, 13608c2ecf20Sopenharmony_ci entry_priv->desc_dma); 13618c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, AC1_BASE_CSR, reg); 13628c2ecf20Sopenharmony_ci 13638c2ecf20Sopenharmony_ci entry_priv = rt2x00dev->tx[2].entries[0].priv_data; 13648c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, AC2_BASE_CSR); 13658c2ecf20Sopenharmony_ci rt2x00_set_field32(®, AC2_BASE_CSR_RING_REGISTER, 13668c2ecf20Sopenharmony_ci entry_priv->desc_dma); 13678c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, AC2_BASE_CSR, reg); 13688c2ecf20Sopenharmony_ci 13698c2ecf20Sopenharmony_ci entry_priv = rt2x00dev->tx[3].entries[0].priv_data; 13708c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, AC3_BASE_CSR); 13718c2ecf20Sopenharmony_ci rt2x00_set_field32(®, AC3_BASE_CSR_RING_REGISTER, 13728c2ecf20Sopenharmony_ci entry_priv->desc_dma); 13738c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, AC3_BASE_CSR, reg); 13748c2ecf20Sopenharmony_ci 13758c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, RX_RING_CSR); 13768c2ecf20Sopenharmony_ci rt2x00_set_field32(®, RX_RING_CSR_RING_SIZE, rt2x00dev->rx->limit); 13778c2ecf20Sopenharmony_ci rt2x00_set_field32(®, RX_RING_CSR_RXD_SIZE, 13788c2ecf20Sopenharmony_ci rt2x00dev->rx->desc_size / 4); 13798c2ecf20Sopenharmony_ci rt2x00_set_field32(®, RX_RING_CSR_RXD_WRITEBACK_SIZE, 4); 13808c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, RX_RING_CSR, reg); 13818c2ecf20Sopenharmony_ci 13828c2ecf20Sopenharmony_ci entry_priv = rt2x00dev->rx->entries[0].priv_data; 13838c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, RX_BASE_CSR); 13848c2ecf20Sopenharmony_ci rt2x00_set_field32(®, RX_BASE_CSR_RING_REGISTER, 13858c2ecf20Sopenharmony_ci entry_priv->desc_dma); 13868c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, RX_BASE_CSR, reg); 13878c2ecf20Sopenharmony_ci 13888c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, TX_DMA_DST_CSR); 13898c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TX_DMA_DST_CSR_DEST_AC0, 2); 13908c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TX_DMA_DST_CSR_DEST_AC1, 2); 13918c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TX_DMA_DST_CSR_DEST_AC2, 2); 13928c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TX_DMA_DST_CSR_DEST_AC3, 2); 13938c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, TX_DMA_DST_CSR, reg); 13948c2ecf20Sopenharmony_ci 13958c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, LOAD_TX_RING_CSR); 13968c2ecf20Sopenharmony_ci rt2x00_set_field32(®, LOAD_TX_RING_CSR_LOAD_TXD_AC0, 1); 13978c2ecf20Sopenharmony_ci rt2x00_set_field32(®, LOAD_TX_RING_CSR_LOAD_TXD_AC1, 1); 13988c2ecf20Sopenharmony_ci rt2x00_set_field32(®, LOAD_TX_RING_CSR_LOAD_TXD_AC2, 1); 13998c2ecf20Sopenharmony_ci rt2x00_set_field32(®, LOAD_TX_RING_CSR_LOAD_TXD_AC3, 1); 14008c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, LOAD_TX_RING_CSR, reg); 14018c2ecf20Sopenharmony_ci 14028c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, RX_CNTL_CSR); 14038c2ecf20Sopenharmony_ci rt2x00_set_field32(®, RX_CNTL_CSR_LOAD_RXD, 1); 14048c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, RX_CNTL_CSR, reg); 14058c2ecf20Sopenharmony_ci 14068c2ecf20Sopenharmony_ci return 0; 14078c2ecf20Sopenharmony_ci} 14088c2ecf20Sopenharmony_ci 14098c2ecf20Sopenharmony_cistatic int rt61pci_init_registers(struct rt2x00_dev *rt2x00dev) 14108c2ecf20Sopenharmony_ci{ 14118c2ecf20Sopenharmony_ci u32 reg; 14128c2ecf20Sopenharmony_ci 14138c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR0); 14148c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR0_AUTO_TX_SEQ, 1); 14158c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR0_DISABLE_RX, 0); 14168c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR0_TX_WITHOUT_WAITING, 0); 14178c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, TXRX_CSR0, reg); 14188c2ecf20Sopenharmony_ci 14198c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR1); 14208c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR1_BBP_ID0, 47); /* CCK Signal */ 14218c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR1_BBP_ID0_VALID, 1); 14228c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR1_BBP_ID1, 30); /* Rssi */ 14238c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR1_BBP_ID1_VALID, 1); 14248c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR1_BBP_ID2, 42); /* OFDM Rate */ 14258c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR1_BBP_ID2_VALID, 1); 14268c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR1_BBP_ID3, 30); /* Rssi */ 14278c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR1_BBP_ID3_VALID, 1); 14288c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, TXRX_CSR1, reg); 14298c2ecf20Sopenharmony_ci 14308c2ecf20Sopenharmony_ci /* 14318c2ecf20Sopenharmony_ci * CCK TXD BBP registers 14328c2ecf20Sopenharmony_ci */ 14338c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR2); 14348c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR2_BBP_ID0, 13); 14358c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR2_BBP_ID0_VALID, 1); 14368c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR2_BBP_ID1, 12); 14378c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR2_BBP_ID1_VALID, 1); 14388c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR2_BBP_ID2, 11); 14398c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR2_BBP_ID2_VALID, 1); 14408c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR2_BBP_ID3, 10); 14418c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR2_BBP_ID3_VALID, 1); 14428c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, TXRX_CSR2, reg); 14438c2ecf20Sopenharmony_ci 14448c2ecf20Sopenharmony_ci /* 14458c2ecf20Sopenharmony_ci * OFDM TXD BBP registers 14468c2ecf20Sopenharmony_ci */ 14478c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR3); 14488c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR3_BBP_ID0, 7); 14498c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR3_BBP_ID0_VALID, 1); 14508c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR3_BBP_ID1, 6); 14518c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR3_BBP_ID1_VALID, 1); 14528c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR3_BBP_ID2, 5); 14538c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR3_BBP_ID2_VALID, 1); 14548c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, TXRX_CSR3, reg); 14558c2ecf20Sopenharmony_ci 14568c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR7); 14578c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR7_ACK_CTS_6MBS, 59); 14588c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR7_ACK_CTS_9MBS, 53); 14598c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR7_ACK_CTS_12MBS, 49); 14608c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR7_ACK_CTS_18MBS, 46); 14618c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, TXRX_CSR7, reg); 14628c2ecf20Sopenharmony_ci 14638c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR8); 14648c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR8_ACK_CTS_24MBS, 44); 14658c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR8_ACK_CTS_36MBS, 42); 14668c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR8_ACK_CTS_48MBS, 42); 14678c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR8_ACK_CTS_54MBS, 42); 14688c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, TXRX_CSR8, reg); 14698c2ecf20Sopenharmony_ci 14708c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR9); 14718c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR9_BEACON_INTERVAL, 0); 14728c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 0); 14738c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, 0); 14748c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 0); 14758c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0); 14768c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR9_TIMESTAMP_COMPENSATE, 0); 14778c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, TXRX_CSR9, reg); 14788c2ecf20Sopenharmony_ci 14798c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, TXRX_CSR15, 0x0000000f); 14808c2ecf20Sopenharmony_ci 14818c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, MAC_CSR6, 0x00000fff); 14828c2ecf20Sopenharmony_ci 14838c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, MAC_CSR9); 14848c2ecf20Sopenharmony_ci rt2x00_set_field32(®, MAC_CSR9_CW_SELECT, 0); 14858c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, MAC_CSR9, reg); 14868c2ecf20Sopenharmony_ci 14878c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, MAC_CSR10, 0x0000071c); 14888c2ecf20Sopenharmony_ci 14898c2ecf20Sopenharmony_ci if (rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_AWAKE)) 14908c2ecf20Sopenharmony_ci return -EBUSY; 14918c2ecf20Sopenharmony_ci 14928c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, MAC_CSR13, 0x0000e000); 14938c2ecf20Sopenharmony_ci 14948c2ecf20Sopenharmony_ci /* 14958c2ecf20Sopenharmony_ci * Invalidate all Shared Keys (SEC_CSR0), 14968c2ecf20Sopenharmony_ci * and clear the Shared key Cipher algorithms (SEC_CSR1 & SEC_CSR5) 14978c2ecf20Sopenharmony_ci */ 14988c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, SEC_CSR0, 0x00000000); 14998c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, SEC_CSR1, 0x00000000); 15008c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, SEC_CSR5, 0x00000000); 15018c2ecf20Sopenharmony_ci 15028c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, PHY_CSR1, 0x000023b0); 15038c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, PHY_CSR5, 0x060a100c); 15048c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, PHY_CSR6, 0x00080606); 15058c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, PHY_CSR7, 0x00000a08); 15068c2ecf20Sopenharmony_ci 15078c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, PCI_CFG_CSR, 0x28ca4404); 15088c2ecf20Sopenharmony_ci 15098c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, TEST_MODE_CSR, 0x00000200); 15108c2ecf20Sopenharmony_ci 15118c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, M2H_CMD_DONE_CSR, 0xffffffff); 15128c2ecf20Sopenharmony_ci 15138c2ecf20Sopenharmony_ci /* 15148c2ecf20Sopenharmony_ci * Clear all beacons 15158c2ecf20Sopenharmony_ci * For the Beacon base registers we only need to clear 15168c2ecf20Sopenharmony_ci * the first byte since that byte contains the VALID and OWNER 15178c2ecf20Sopenharmony_ci * bits which (when set to 0) will invalidate the entire beacon. 15188c2ecf20Sopenharmony_ci */ 15198c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, HW_BEACON_BASE0, 0); 15208c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, HW_BEACON_BASE1, 0); 15218c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, HW_BEACON_BASE2, 0); 15228c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, HW_BEACON_BASE3, 0); 15238c2ecf20Sopenharmony_ci 15248c2ecf20Sopenharmony_ci /* 15258c2ecf20Sopenharmony_ci * We must clear the error counters. 15268c2ecf20Sopenharmony_ci * These registers are cleared on read, 15278c2ecf20Sopenharmony_ci * so we may pass a useless variable to store the value. 15288c2ecf20Sopenharmony_ci */ 15298c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, STA_CSR0); 15308c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, STA_CSR1); 15318c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, STA_CSR2); 15328c2ecf20Sopenharmony_ci 15338c2ecf20Sopenharmony_ci /* 15348c2ecf20Sopenharmony_ci * Reset MAC and BBP registers. 15358c2ecf20Sopenharmony_ci */ 15368c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, MAC_CSR1); 15378c2ecf20Sopenharmony_ci rt2x00_set_field32(®, MAC_CSR1_SOFT_RESET, 1); 15388c2ecf20Sopenharmony_ci rt2x00_set_field32(®, MAC_CSR1_BBP_RESET, 1); 15398c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, MAC_CSR1, reg); 15408c2ecf20Sopenharmony_ci 15418c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, MAC_CSR1); 15428c2ecf20Sopenharmony_ci rt2x00_set_field32(®, MAC_CSR1_SOFT_RESET, 0); 15438c2ecf20Sopenharmony_ci rt2x00_set_field32(®, MAC_CSR1_BBP_RESET, 0); 15448c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, MAC_CSR1, reg); 15458c2ecf20Sopenharmony_ci 15468c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, MAC_CSR1); 15478c2ecf20Sopenharmony_ci rt2x00_set_field32(®, MAC_CSR1_HOST_READY, 1); 15488c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, MAC_CSR1, reg); 15498c2ecf20Sopenharmony_ci 15508c2ecf20Sopenharmony_ci return 0; 15518c2ecf20Sopenharmony_ci} 15528c2ecf20Sopenharmony_ci 15538c2ecf20Sopenharmony_cistatic int rt61pci_wait_bbp_ready(struct rt2x00_dev *rt2x00dev) 15548c2ecf20Sopenharmony_ci{ 15558c2ecf20Sopenharmony_ci unsigned int i; 15568c2ecf20Sopenharmony_ci u8 value; 15578c2ecf20Sopenharmony_ci 15588c2ecf20Sopenharmony_ci for (i = 0; i < REGISTER_BUSY_COUNT; i++) { 15598c2ecf20Sopenharmony_ci value = rt61pci_bbp_read(rt2x00dev, 0); 15608c2ecf20Sopenharmony_ci if ((value != 0xff) && (value != 0x00)) 15618c2ecf20Sopenharmony_ci return 0; 15628c2ecf20Sopenharmony_ci udelay(REGISTER_BUSY_DELAY); 15638c2ecf20Sopenharmony_ci } 15648c2ecf20Sopenharmony_ci 15658c2ecf20Sopenharmony_ci rt2x00_err(rt2x00dev, "BBP register access failed, aborting\n"); 15668c2ecf20Sopenharmony_ci return -EACCES; 15678c2ecf20Sopenharmony_ci} 15688c2ecf20Sopenharmony_ci 15698c2ecf20Sopenharmony_cistatic int rt61pci_init_bbp(struct rt2x00_dev *rt2x00dev) 15708c2ecf20Sopenharmony_ci{ 15718c2ecf20Sopenharmony_ci unsigned int i; 15728c2ecf20Sopenharmony_ci u16 eeprom; 15738c2ecf20Sopenharmony_ci u8 reg_id; 15748c2ecf20Sopenharmony_ci u8 value; 15758c2ecf20Sopenharmony_ci 15768c2ecf20Sopenharmony_ci if (unlikely(rt61pci_wait_bbp_ready(rt2x00dev))) 15778c2ecf20Sopenharmony_ci return -EACCES; 15788c2ecf20Sopenharmony_ci 15798c2ecf20Sopenharmony_ci rt61pci_bbp_write(rt2x00dev, 3, 0x00); 15808c2ecf20Sopenharmony_ci rt61pci_bbp_write(rt2x00dev, 15, 0x30); 15818c2ecf20Sopenharmony_ci rt61pci_bbp_write(rt2x00dev, 21, 0xc8); 15828c2ecf20Sopenharmony_ci rt61pci_bbp_write(rt2x00dev, 22, 0x38); 15838c2ecf20Sopenharmony_ci rt61pci_bbp_write(rt2x00dev, 23, 0x06); 15848c2ecf20Sopenharmony_ci rt61pci_bbp_write(rt2x00dev, 24, 0xfe); 15858c2ecf20Sopenharmony_ci rt61pci_bbp_write(rt2x00dev, 25, 0x0a); 15868c2ecf20Sopenharmony_ci rt61pci_bbp_write(rt2x00dev, 26, 0x0d); 15878c2ecf20Sopenharmony_ci rt61pci_bbp_write(rt2x00dev, 34, 0x12); 15888c2ecf20Sopenharmony_ci rt61pci_bbp_write(rt2x00dev, 37, 0x07); 15898c2ecf20Sopenharmony_ci rt61pci_bbp_write(rt2x00dev, 39, 0xf8); 15908c2ecf20Sopenharmony_ci rt61pci_bbp_write(rt2x00dev, 41, 0x60); 15918c2ecf20Sopenharmony_ci rt61pci_bbp_write(rt2x00dev, 53, 0x10); 15928c2ecf20Sopenharmony_ci rt61pci_bbp_write(rt2x00dev, 54, 0x18); 15938c2ecf20Sopenharmony_ci rt61pci_bbp_write(rt2x00dev, 60, 0x10); 15948c2ecf20Sopenharmony_ci rt61pci_bbp_write(rt2x00dev, 61, 0x04); 15958c2ecf20Sopenharmony_ci rt61pci_bbp_write(rt2x00dev, 62, 0x04); 15968c2ecf20Sopenharmony_ci rt61pci_bbp_write(rt2x00dev, 75, 0xfe); 15978c2ecf20Sopenharmony_ci rt61pci_bbp_write(rt2x00dev, 86, 0xfe); 15988c2ecf20Sopenharmony_ci rt61pci_bbp_write(rt2x00dev, 88, 0xfe); 15998c2ecf20Sopenharmony_ci rt61pci_bbp_write(rt2x00dev, 90, 0x0f); 16008c2ecf20Sopenharmony_ci rt61pci_bbp_write(rt2x00dev, 99, 0x00); 16018c2ecf20Sopenharmony_ci rt61pci_bbp_write(rt2x00dev, 102, 0x16); 16028c2ecf20Sopenharmony_ci rt61pci_bbp_write(rt2x00dev, 107, 0x04); 16038c2ecf20Sopenharmony_ci 16048c2ecf20Sopenharmony_ci for (i = 0; i < EEPROM_BBP_SIZE; i++) { 16058c2ecf20Sopenharmony_ci eeprom = rt2x00_eeprom_read(rt2x00dev, EEPROM_BBP_START + i); 16068c2ecf20Sopenharmony_ci 16078c2ecf20Sopenharmony_ci if (eeprom != 0xffff && eeprom != 0x0000) { 16088c2ecf20Sopenharmony_ci reg_id = rt2x00_get_field16(eeprom, EEPROM_BBP_REG_ID); 16098c2ecf20Sopenharmony_ci value = rt2x00_get_field16(eeprom, EEPROM_BBP_VALUE); 16108c2ecf20Sopenharmony_ci rt61pci_bbp_write(rt2x00dev, reg_id, value); 16118c2ecf20Sopenharmony_ci } 16128c2ecf20Sopenharmony_ci } 16138c2ecf20Sopenharmony_ci 16148c2ecf20Sopenharmony_ci return 0; 16158c2ecf20Sopenharmony_ci} 16168c2ecf20Sopenharmony_ci 16178c2ecf20Sopenharmony_ci/* 16188c2ecf20Sopenharmony_ci * Device state switch handlers. 16198c2ecf20Sopenharmony_ci */ 16208c2ecf20Sopenharmony_cistatic void rt61pci_toggle_irq(struct rt2x00_dev *rt2x00dev, 16218c2ecf20Sopenharmony_ci enum dev_state state) 16228c2ecf20Sopenharmony_ci{ 16238c2ecf20Sopenharmony_ci int mask = (state == STATE_RADIO_IRQ_OFF); 16248c2ecf20Sopenharmony_ci u32 reg; 16258c2ecf20Sopenharmony_ci unsigned long flags; 16268c2ecf20Sopenharmony_ci 16278c2ecf20Sopenharmony_ci /* 16288c2ecf20Sopenharmony_ci * When interrupts are being enabled, the interrupt registers 16298c2ecf20Sopenharmony_ci * should clear the register to assure a clean state. 16308c2ecf20Sopenharmony_ci */ 16318c2ecf20Sopenharmony_ci if (state == STATE_RADIO_IRQ_ON) { 16328c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, INT_SOURCE_CSR); 16338c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, INT_SOURCE_CSR, reg); 16348c2ecf20Sopenharmony_ci 16358c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, MCU_INT_SOURCE_CSR); 16368c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, MCU_INT_SOURCE_CSR, reg); 16378c2ecf20Sopenharmony_ci } 16388c2ecf20Sopenharmony_ci 16398c2ecf20Sopenharmony_ci /* 16408c2ecf20Sopenharmony_ci * Only toggle the interrupts bits we are going to use. 16418c2ecf20Sopenharmony_ci * Non-checked interrupt bits are disabled by default. 16428c2ecf20Sopenharmony_ci */ 16438c2ecf20Sopenharmony_ci spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags); 16448c2ecf20Sopenharmony_ci 16458c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, INT_MASK_CSR); 16468c2ecf20Sopenharmony_ci rt2x00_set_field32(®, INT_MASK_CSR_TXDONE, mask); 16478c2ecf20Sopenharmony_ci rt2x00_set_field32(®, INT_MASK_CSR_RXDONE, mask); 16488c2ecf20Sopenharmony_ci rt2x00_set_field32(®, INT_MASK_CSR_BEACON_DONE, mask); 16498c2ecf20Sopenharmony_ci rt2x00_set_field32(®, INT_MASK_CSR_ENABLE_MITIGATION, mask); 16508c2ecf20Sopenharmony_ci rt2x00_set_field32(®, INT_MASK_CSR_MITIGATION_PERIOD, 0xff); 16518c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, INT_MASK_CSR, reg); 16528c2ecf20Sopenharmony_ci 16538c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, MCU_INT_MASK_CSR); 16548c2ecf20Sopenharmony_ci rt2x00_set_field32(®, MCU_INT_MASK_CSR_0, mask); 16558c2ecf20Sopenharmony_ci rt2x00_set_field32(®, MCU_INT_MASK_CSR_1, mask); 16568c2ecf20Sopenharmony_ci rt2x00_set_field32(®, MCU_INT_MASK_CSR_2, mask); 16578c2ecf20Sopenharmony_ci rt2x00_set_field32(®, MCU_INT_MASK_CSR_3, mask); 16588c2ecf20Sopenharmony_ci rt2x00_set_field32(®, MCU_INT_MASK_CSR_4, mask); 16598c2ecf20Sopenharmony_ci rt2x00_set_field32(®, MCU_INT_MASK_CSR_5, mask); 16608c2ecf20Sopenharmony_ci rt2x00_set_field32(®, MCU_INT_MASK_CSR_6, mask); 16618c2ecf20Sopenharmony_ci rt2x00_set_field32(®, MCU_INT_MASK_CSR_7, mask); 16628c2ecf20Sopenharmony_ci rt2x00_set_field32(®, MCU_INT_MASK_CSR_TWAKEUP, mask); 16638c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, MCU_INT_MASK_CSR, reg); 16648c2ecf20Sopenharmony_ci 16658c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags); 16668c2ecf20Sopenharmony_ci 16678c2ecf20Sopenharmony_ci if (state == STATE_RADIO_IRQ_OFF) { 16688c2ecf20Sopenharmony_ci /* 16698c2ecf20Sopenharmony_ci * Ensure that all tasklets are finished. 16708c2ecf20Sopenharmony_ci */ 16718c2ecf20Sopenharmony_ci tasklet_kill(&rt2x00dev->txstatus_tasklet); 16728c2ecf20Sopenharmony_ci tasklet_kill(&rt2x00dev->rxdone_tasklet); 16738c2ecf20Sopenharmony_ci tasklet_kill(&rt2x00dev->autowake_tasklet); 16748c2ecf20Sopenharmony_ci tasklet_kill(&rt2x00dev->tbtt_tasklet); 16758c2ecf20Sopenharmony_ci } 16768c2ecf20Sopenharmony_ci} 16778c2ecf20Sopenharmony_ci 16788c2ecf20Sopenharmony_cistatic int rt61pci_enable_radio(struct rt2x00_dev *rt2x00dev) 16798c2ecf20Sopenharmony_ci{ 16808c2ecf20Sopenharmony_ci u32 reg; 16818c2ecf20Sopenharmony_ci 16828c2ecf20Sopenharmony_ci /* 16838c2ecf20Sopenharmony_ci * Initialize all registers. 16848c2ecf20Sopenharmony_ci */ 16858c2ecf20Sopenharmony_ci if (unlikely(rt61pci_init_queues(rt2x00dev) || 16868c2ecf20Sopenharmony_ci rt61pci_init_registers(rt2x00dev) || 16878c2ecf20Sopenharmony_ci rt61pci_init_bbp(rt2x00dev))) 16888c2ecf20Sopenharmony_ci return -EIO; 16898c2ecf20Sopenharmony_ci 16908c2ecf20Sopenharmony_ci /* 16918c2ecf20Sopenharmony_ci * Enable RX. 16928c2ecf20Sopenharmony_ci */ 16938c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, RX_CNTL_CSR); 16948c2ecf20Sopenharmony_ci rt2x00_set_field32(®, RX_CNTL_CSR_ENABLE_RX_DMA, 1); 16958c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, RX_CNTL_CSR, reg); 16968c2ecf20Sopenharmony_ci 16978c2ecf20Sopenharmony_ci return 0; 16988c2ecf20Sopenharmony_ci} 16998c2ecf20Sopenharmony_ci 17008c2ecf20Sopenharmony_cistatic void rt61pci_disable_radio(struct rt2x00_dev *rt2x00dev) 17018c2ecf20Sopenharmony_ci{ 17028c2ecf20Sopenharmony_ci /* 17038c2ecf20Sopenharmony_ci * Disable power 17048c2ecf20Sopenharmony_ci */ 17058c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, MAC_CSR10, 0x00001818); 17068c2ecf20Sopenharmony_ci} 17078c2ecf20Sopenharmony_ci 17088c2ecf20Sopenharmony_cistatic int rt61pci_set_state(struct rt2x00_dev *rt2x00dev, enum dev_state state) 17098c2ecf20Sopenharmony_ci{ 17108c2ecf20Sopenharmony_ci u32 reg, reg2; 17118c2ecf20Sopenharmony_ci unsigned int i; 17128c2ecf20Sopenharmony_ci char put_to_sleep; 17138c2ecf20Sopenharmony_ci 17148c2ecf20Sopenharmony_ci put_to_sleep = (state != STATE_AWAKE); 17158c2ecf20Sopenharmony_ci 17168c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, MAC_CSR12); 17178c2ecf20Sopenharmony_ci rt2x00_set_field32(®, MAC_CSR12_FORCE_WAKEUP, !put_to_sleep); 17188c2ecf20Sopenharmony_ci rt2x00_set_field32(®, MAC_CSR12_PUT_TO_SLEEP, put_to_sleep); 17198c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, MAC_CSR12, reg); 17208c2ecf20Sopenharmony_ci 17218c2ecf20Sopenharmony_ci /* 17228c2ecf20Sopenharmony_ci * Device is not guaranteed to be in the requested state yet. 17238c2ecf20Sopenharmony_ci * We must wait until the register indicates that the 17248c2ecf20Sopenharmony_ci * device has entered the correct state. 17258c2ecf20Sopenharmony_ci */ 17268c2ecf20Sopenharmony_ci for (i = 0; i < REGISTER_BUSY_COUNT; i++) { 17278c2ecf20Sopenharmony_ci reg2 = rt2x00mmio_register_read(rt2x00dev, MAC_CSR12); 17288c2ecf20Sopenharmony_ci state = rt2x00_get_field32(reg2, MAC_CSR12_BBP_CURRENT_STATE); 17298c2ecf20Sopenharmony_ci if (state == !put_to_sleep) 17308c2ecf20Sopenharmony_ci return 0; 17318c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, MAC_CSR12, reg); 17328c2ecf20Sopenharmony_ci msleep(10); 17338c2ecf20Sopenharmony_ci } 17348c2ecf20Sopenharmony_ci 17358c2ecf20Sopenharmony_ci return -EBUSY; 17368c2ecf20Sopenharmony_ci} 17378c2ecf20Sopenharmony_ci 17388c2ecf20Sopenharmony_cistatic int rt61pci_set_device_state(struct rt2x00_dev *rt2x00dev, 17398c2ecf20Sopenharmony_ci enum dev_state state) 17408c2ecf20Sopenharmony_ci{ 17418c2ecf20Sopenharmony_ci int retval = 0; 17428c2ecf20Sopenharmony_ci 17438c2ecf20Sopenharmony_ci switch (state) { 17448c2ecf20Sopenharmony_ci case STATE_RADIO_ON: 17458c2ecf20Sopenharmony_ci retval = rt61pci_enable_radio(rt2x00dev); 17468c2ecf20Sopenharmony_ci break; 17478c2ecf20Sopenharmony_ci case STATE_RADIO_OFF: 17488c2ecf20Sopenharmony_ci rt61pci_disable_radio(rt2x00dev); 17498c2ecf20Sopenharmony_ci break; 17508c2ecf20Sopenharmony_ci case STATE_RADIO_IRQ_ON: 17518c2ecf20Sopenharmony_ci case STATE_RADIO_IRQ_OFF: 17528c2ecf20Sopenharmony_ci rt61pci_toggle_irq(rt2x00dev, state); 17538c2ecf20Sopenharmony_ci break; 17548c2ecf20Sopenharmony_ci case STATE_DEEP_SLEEP: 17558c2ecf20Sopenharmony_ci case STATE_SLEEP: 17568c2ecf20Sopenharmony_ci case STATE_STANDBY: 17578c2ecf20Sopenharmony_ci case STATE_AWAKE: 17588c2ecf20Sopenharmony_ci retval = rt61pci_set_state(rt2x00dev, state); 17598c2ecf20Sopenharmony_ci break; 17608c2ecf20Sopenharmony_ci default: 17618c2ecf20Sopenharmony_ci retval = -ENOTSUPP; 17628c2ecf20Sopenharmony_ci break; 17638c2ecf20Sopenharmony_ci } 17648c2ecf20Sopenharmony_ci 17658c2ecf20Sopenharmony_ci if (unlikely(retval)) 17668c2ecf20Sopenharmony_ci rt2x00_err(rt2x00dev, "Device failed to enter state %d (%d)\n", 17678c2ecf20Sopenharmony_ci state, retval); 17688c2ecf20Sopenharmony_ci 17698c2ecf20Sopenharmony_ci return retval; 17708c2ecf20Sopenharmony_ci} 17718c2ecf20Sopenharmony_ci 17728c2ecf20Sopenharmony_ci/* 17738c2ecf20Sopenharmony_ci * TX descriptor initialization 17748c2ecf20Sopenharmony_ci */ 17758c2ecf20Sopenharmony_cistatic void rt61pci_write_tx_desc(struct queue_entry *entry, 17768c2ecf20Sopenharmony_ci struct txentry_desc *txdesc) 17778c2ecf20Sopenharmony_ci{ 17788c2ecf20Sopenharmony_ci struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); 17798c2ecf20Sopenharmony_ci struct queue_entry_priv_mmio *entry_priv = entry->priv_data; 17808c2ecf20Sopenharmony_ci __le32 *txd = entry_priv->desc; 17818c2ecf20Sopenharmony_ci u32 word; 17828c2ecf20Sopenharmony_ci 17838c2ecf20Sopenharmony_ci /* 17848c2ecf20Sopenharmony_ci * Start writing the descriptor words. 17858c2ecf20Sopenharmony_ci */ 17868c2ecf20Sopenharmony_ci word = rt2x00_desc_read(txd, 1); 17878c2ecf20Sopenharmony_ci rt2x00_set_field32(&word, TXD_W1_HOST_Q_ID, entry->queue->qid); 17888c2ecf20Sopenharmony_ci rt2x00_set_field32(&word, TXD_W1_AIFSN, entry->queue->aifs); 17898c2ecf20Sopenharmony_ci rt2x00_set_field32(&word, TXD_W1_CWMIN, entry->queue->cw_min); 17908c2ecf20Sopenharmony_ci rt2x00_set_field32(&word, TXD_W1_CWMAX, entry->queue->cw_max); 17918c2ecf20Sopenharmony_ci rt2x00_set_field32(&word, TXD_W1_IV_OFFSET, txdesc->iv_offset); 17928c2ecf20Sopenharmony_ci rt2x00_set_field32(&word, TXD_W1_HW_SEQUENCE, 17938c2ecf20Sopenharmony_ci test_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags)); 17948c2ecf20Sopenharmony_ci rt2x00_set_field32(&word, TXD_W1_BUFFER_COUNT, 1); 17958c2ecf20Sopenharmony_ci rt2x00_desc_write(txd, 1, word); 17968c2ecf20Sopenharmony_ci 17978c2ecf20Sopenharmony_ci word = rt2x00_desc_read(txd, 2); 17988c2ecf20Sopenharmony_ci rt2x00_set_field32(&word, TXD_W2_PLCP_SIGNAL, txdesc->u.plcp.signal); 17998c2ecf20Sopenharmony_ci rt2x00_set_field32(&word, TXD_W2_PLCP_SERVICE, txdesc->u.plcp.service); 18008c2ecf20Sopenharmony_ci rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_LOW, 18018c2ecf20Sopenharmony_ci txdesc->u.plcp.length_low); 18028c2ecf20Sopenharmony_ci rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_HIGH, 18038c2ecf20Sopenharmony_ci txdesc->u.plcp.length_high); 18048c2ecf20Sopenharmony_ci rt2x00_desc_write(txd, 2, word); 18058c2ecf20Sopenharmony_ci 18068c2ecf20Sopenharmony_ci if (test_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags)) { 18078c2ecf20Sopenharmony_ci _rt2x00_desc_write(txd, 3, skbdesc->iv[0]); 18088c2ecf20Sopenharmony_ci _rt2x00_desc_write(txd, 4, skbdesc->iv[1]); 18098c2ecf20Sopenharmony_ci } 18108c2ecf20Sopenharmony_ci 18118c2ecf20Sopenharmony_ci word = rt2x00_desc_read(txd, 5); 18128c2ecf20Sopenharmony_ci rt2x00_set_field32(&word, TXD_W5_PID_TYPE, entry->queue->qid); 18138c2ecf20Sopenharmony_ci rt2x00_set_field32(&word, TXD_W5_PID_SUBTYPE, entry->entry_idx); 18148c2ecf20Sopenharmony_ci rt2x00_set_field32(&word, TXD_W5_TX_POWER, 18158c2ecf20Sopenharmony_ci TXPOWER_TO_DEV(entry->queue->rt2x00dev->tx_power)); 18168c2ecf20Sopenharmony_ci rt2x00_set_field32(&word, TXD_W5_WAITING_DMA_DONE_INT, 1); 18178c2ecf20Sopenharmony_ci rt2x00_desc_write(txd, 5, word); 18188c2ecf20Sopenharmony_ci 18198c2ecf20Sopenharmony_ci if (entry->queue->qid != QID_BEACON) { 18208c2ecf20Sopenharmony_ci word = rt2x00_desc_read(txd, 6); 18218c2ecf20Sopenharmony_ci rt2x00_set_field32(&word, TXD_W6_BUFFER_PHYSICAL_ADDRESS, 18228c2ecf20Sopenharmony_ci skbdesc->skb_dma); 18238c2ecf20Sopenharmony_ci rt2x00_desc_write(txd, 6, word); 18248c2ecf20Sopenharmony_ci 18258c2ecf20Sopenharmony_ci word = rt2x00_desc_read(txd, 11); 18268c2ecf20Sopenharmony_ci rt2x00_set_field32(&word, TXD_W11_BUFFER_LENGTH0, 18278c2ecf20Sopenharmony_ci txdesc->length); 18288c2ecf20Sopenharmony_ci rt2x00_desc_write(txd, 11, word); 18298c2ecf20Sopenharmony_ci } 18308c2ecf20Sopenharmony_ci 18318c2ecf20Sopenharmony_ci /* 18328c2ecf20Sopenharmony_ci * Writing TXD word 0 must the last to prevent a race condition with 18338c2ecf20Sopenharmony_ci * the device, whereby the device may take hold of the TXD before we 18348c2ecf20Sopenharmony_ci * finished updating it. 18358c2ecf20Sopenharmony_ci */ 18368c2ecf20Sopenharmony_ci word = rt2x00_desc_read(txd, 0); 18378c2ecf20Sopenharmony_ci rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 1); 18388c2ecf20Sopenharmony_ci rt2x00_set_field32(&word, TXD_W0_VALID, 1); 18398c2ecf20Sopenharmony_ci rt2x00_set_field32(&word, TXD_W0_MORE_FRAG, 18408c2ecf20Sopenharmony_ci test_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags)); 18418c2ecf20Sopenharmony_ci rt2x00_set_field32(&word, TXD_W0_ACK, 18428c2ecf20Sopenharmony_ci test_bit(ENTRY_TXD_ACK, &txdesc->flags)); 18438c2ecf20Sopenharmony_ci rt2x00_set_field32(&word, TXD_W0_TIMESTAMP, 18448c2ecf20Sopenharmony_ci test_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc->flags)); 18458c2ecf20Sopenharmony_ci rt2x00_set_field32(&word, TXD_W0_OFDM, 18468c2ecf20Sopenharmony_ci (txdesc->rate_mode == RATE_MODE_OFDM)); 18478c2ecf20Sopenharmony_ci rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->u.plcp.ifs); 18488c2ecf20Sopenharmony_ci rt2x00_set_field32(&word, TXD_W0_RETRY_MODE, 18498c2ecf20Sopenharmony_ci test_bit(ENTRY_TXD_RETRY_MODE, &txdesc->flags)); 18508c2ecf20Sopenharmony_ci rt2x00_set_field32(&word, TXD_W0_TKIP_MIC, 18518c2ecf20Sopenharmony_ci test_bit(ENTRY_TXD_ENCRYPT_MMIC, &txdesc->flags)); 18528c2ecf20Sopenharmony_ci rt2x00_set_field32(&word, TXD_W0_KEY_TABLE, 18538c2ecf20Sopenharmony_ci test_bit(ENTRY_TXD_ENCRYPT_PAIRWISE, &txdesc->flags)); 18548c2ecf20Sopenharmony_ci rt2x00_set_field32(&word, TXD_W0_KEY_INDEX, txdesc->key_idx); 18558c2ecf20Sopenharmony_ci rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, txdesc->length); 18568c2ecf20Sopenharmony_ci rt2x00_set_field32(&word, TXD_W0_BURST, 18578c2ecf20Sopenharmony_ci test_bit(ENTRY_TXD_BURST, &txdesc->flags)); 18588c2ecf20Sopenharmony_ci rt2x00_set_field32(&word, TXD_W0_CIPHER_ALG, txdesc->cipher); 18598c2ecf20Sopenharmony_ci rt2x00_desc_write(txd, 0, word); 18608c2ecf20Sopenharmony_ci 18618c2ecf20Sopenharmony_ci /* 18628c2ecf20Sopenharmony_ci * Register descriptor details in skb frame descriptor. 18638c2ecf20Sopenharmony_ci */ 18648c2ecf20Sopenharmony_ci skbdesc->desc = txd; 18658c2ecf20Sopenharmony_ci skbdesc->desc_len = (entry->queue->qid == QID_BEACON) ? TXINFO_SIZE : 18668c2ecf20Sopenharmony_ci TXD_DESC_SIZE; 18678c2ecf20Sopenharmony_ci} 18688c2ecf20Sopenharmony_ci 18698c2ecf20Sopenharmony_ci/* 18708c2ecf20Sopenharmony_ci * TX data initialization 18718c2ecf20Sopenharmony_ci */ 18728c2ecf20Sopenharmony_cistatic void rt61pci_write_beacon(struct queue_entry *entry, 18738c2ecf20Sopenharmony_ci struct txentry_desc *txdesc) 18748c2ecf20Sopenharmony_ci{ 18758c2ecf20Sopenharmony_ci struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; 18768c2ecf20Sopenharmony_ci struct queue_entry_priv_mmio *entry_priv = entry->priv_data; 18778c2ecf20Sopenharmony_ci unsigned int beacon_base; 18788c2ecf20Sopenharmony_ci unsigned int padding_len; 18798c2ecf20Sopenharmony_ci u32 orig_reg, reg; 18808c2ecf20Sopenharmony_ci 18818c2ecf20Sopenharmony_ci /* 18828c2ecf20Sopenharmony_ci * Disable beaconing while we are reloading the beacon data, 18838c2ecf20Sopenharmony_ci * otherwise we might be sending out invalid data. 18848c2ecf20Sopenharmony_ci */ 18858c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR9); 18868c2ecf20Sopenharmony_ci orig_reg = reg; 18878c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0); 18888c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, TXRX_CSR9, reg); 18898c2ecf20Sopenharmony_ci 18908c2ecf20Sopenharmony_ci /* 18918c2ecf20Sopenharmony_ci * Write the TX descriptor for the beacon. 18928c2ecf20Sopenharmony_ci */ 18938c2ecf20Sopenharmony_ci rt61pci_write_tx_desc(entry, txdesc); 18948c2ecf20Sopenharmony_ci 18958c2ecf20Sopenharmony_ci /* 18968c2ecf20Sopenharmony_ci * Dump beacon to userspace through debugfs. 18978c2ecf20Sopenharmony_ci */ 18988c2ecf20Sopenharmony_ci rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_BEACON, entry); 18998c2ecf20Sopenharmony_ci 19008c2ecf20Sopenharmony_ci /* 19018c2ecf20Sopenharmony_ci * Write entire beacon with descriptor and padding to register. 19028c2ecf20Sopenharmony_ci */ 19038c2ecf20Sopenharmony_ci padding_len = roundup(entry->skb->len, 4) - entry->skb->len; 19048c2ecf20Sopenharmony_ci if (padding_len && skb_pad(entry->skb, padding_len)) { 19058c2ecf20Sopenharmony_ci rt2x00_err(rt2x00dev, "Failure padding beacon, aborting\n"); 19068c2ecf20Sopenharmony_ci /* skb freed by skb_pad() on failure */ 19078c2ecf20Sopenharmony_ci entry->skb = NULL; 19088c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, TXRX_CSR9, orig_reg); 19098c2ecf20Sopenharmony_ci return; 19108c2ecf20Sopenharmony_ci } 19118c2ecf20Sopenharmony_ci 19128c2ecf20Sopenharmony_ci beacon_base = HW_BEACON_OFFSET(entry->entry_idx); 19138c2ecf20Sopenharmony_ci rt2x00mmio_register_multiwrite(rt2x00dev, beacon_base, 19148c2ecf20Sopenharmony_ci entry_priv->desc, TXINFO_SIZE); 19158c2ecf20Sopenharmony_ci rt2x00mmio_register_multiwrite(rt2x00dev, beacon_base + TXINFO_SIZE, 19168c2ecf20Sopenharmony_ci entry->skb->data, 19178c2ecf20Sopenharmony_ci entry->skb->len + padding_len); 19188c2ecf20Sopenharmony_ci 19198c2ecf20Sopenharmony_ci /* 19208c2ecf20Sopenharmony_ci * Enable beaconing again. 19218c2ecf20Sopenharmony_ci * 19228c2ecf20Sopenharmony_ci * For Wi-Fi faily generated beacons between participating 19238c2ecf20Sopenharmony_ci * stations. Set TBTT phase adaptive adjustment step to 8us. 19248c2ecf20Sopenharmony_ci */ 19258c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, TXRX_CSR10, 0x00001008); 19268c2ecf20Sopenharmony_ci 19278c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 1); 19288c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, TXRX_CSR9, reg); 19298c2ecf20Sopenharmony_ci 19308c2ecf20Sopenharmony_ci /* 19318c2ecf20Sopenharmony_ci * Clean up beacon skb. 19328c2ecf20Sopenharmony_ci */ 19338c2ecf20Sopenharmony_ci dev_kfree_skb_any(entry->skb); 19348c2ecf20Sopenharmony_ci entry->skb = NULL; 19358c2ecf20Sopenharmony_ci} 19368c2ecf20Sopenharmony_ci 19378c2ecf20Sopenharmony_cistatic void rt61pci_clear_beacon(struct queue_entry *entry) 19388c2ecf20Sopenharmony_ci{ 19398c2ecf20Sopenharmony_ci struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; 19408c2ecf20Sopenharmony_ci u32 orig_reg, reg; 19418c2ecf20Sopenharmony_ci 19428c2ecf20Sopenharmony_ci /* 19438c2ecf20Sopenharmony_ci * Disable beaconing while we are reloading the beacon data, 19448c2ecf20Sopenharmony_ci * otherwise we might be sending out invalid data. 19458c2ecf20Sopenharmony_ci */ 19468c2ecf20Sopenharmony_ci orig_reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR9); 19478c2ecf20Sopenharmony_ci reg = orig_reg; 19488c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0); 19498c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, TXRX_CSR9, reg); 19508c2ecf20Sopenharmony_ci 19518c2ecf20Sopenharmony_ci /* 19528c2ecf20Sopenharmony_ci * Clear beacon. 19538c2ecf20Sopenharmony_ci */ 19548c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, 19558c2ecf20Sopenharmony_ci HW_BEACON_OFFSET(entry->entry_idx), 0); 19568c2ecf20Sopenharmony_ci 19578c2ecf20Sopenharmony_ci /* 19588c2ecf20Sopenharmony_ci * Restore global beaconing state. 19598c2ecf20Sopenharmony_ci */ 19608c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, TXRX_CSR9, orig_reg); 19618c2ecf20Sopenharmony_ci} 19628c2ecf20Sopenharmony_ci 19638c2ecf20Sopenharmony_ci/* 19648c2ecf20Sopenharmony_ci * RX control handlers 19658c2ecf20Sopenharmony_ci */ 19668c2ecf20Sopenharmony_cistatic int rt61pci_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxd_w1) 19678c2ecf20Sopenharmony_ci{ 19688c2ecf20Sopenharmony_ci u8 offset = rt2x00dev->lna_gain; 19698c2ecf20Sopenharmony_ci u8 lna; 19708c2ecf20Sopenharmony_ci 19718c2ecf20Sopenharmony_ci lna = rt2x00_get_field32(rxd_w1, RXD_W1_RSSI_LNA); 19728c2ecf20Sopenharmony_ci switch (lna) { 19738c2ecf20Sopenharmony_ci case 3: 19748c2ecf20Sopenharmony_ci offset += 90; 19758c2ecf20Sopenharmony_ci break; 19768c2ecf20Sopenharmony_ci case 2: 19778c2ecf20Sopenharmony_ci offset += 74; 19788c2ecf20Sopenharmony_ci break; 19798c2ecf20Sopenharmony_ci case 1: 19808c2ecf20Sopenharmony_ci offset += 64; 19818c2ecf20Sopenharmony_ci break; 19828c2ecf20Sopenharmony_ci default: 19838c2ecf20Sopenharmony_ci return 0; 19848c2ecf20Sopenharmony_ci } 19858c2ecf20Sopenharmony_ci 19868c2ecf20Sopenharmony_ci if (rt2x00dev->curr_band == NL80211_BAND_5GHZ) { 19878c2ecf20Sopenharmony_ci if (lna == 3 || lna == 2) 19888c2ecf20Sopenharmony_ci offset += 10; 19898c2ecf20Sopenharmony_ci } 19908c2ecf20Sopenharmony_ci 19918c2ecf20Sopenharmony_ci return rt2x00_get_field32(rxd_w1, RXD_W1_RSSI_AGC) * 2 - offset; 19928c2ecf20Sopenharmony_ci} 19938c2ecf20Sopenharmony_ci 19948c2ecf20Sopenharmony_cistatic void rt61pci_fill_rxdone(struct queue_entry *entry, 19958c2ecf20Sopenharmony_ci struct rxdone_entry_desc *rxdesc) 19968c2ecf20Sopenharmony_ci{ 19978c2ecf20Sopenharmony_ci struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; 19988c2ecf20Sopenharmony_ci struct queue_entry_priv_mmio *entry_priv = entry->priv_data; 19998c2ecf20Sopenharmony_ci u32 word0; 20008c2ecf20Sopenharmony_ci u32 word1; 20018c2ecf20Sopenharmony_ci 20028c2ecf20Sopenharmony_ci word0 = rt2x00_desc_read(entry_priv->desc, 0); 20038c2ecf20Sopenharmony_ci word1 = rt2x00_desc_read(entry_priv->desc, 1); 20048c2ecf20Sopenharmony_ci 20058c2ecf20Sopenharmony_ci if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR)) 20068c2ecf20Sopenharmony_ci rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC; 20078c2ecf20Sopenharmony_ci 20088c2ecf20Sopenharmony_ci rxdesc->cipher = rt2x00_get_field32(word0, RXD_W0_CIPHER_ALG); 20098c2ecf20Sopenharmony_ci rxdesc->cipher_status = rt2x00_get_field32(word0, RXD_W0_CIPHER_ERROR); 20108c2ecf20Sopenharmony_ci 20118c2ecf20Sopenharmony_ci if (rxdesc->cipher != CIPHER_NONE) { 20128c2ecf20Sopenharmony_ci rxdesc->iv[0] = _rt2x00_desc_read(entry_priv->desc, 2); 20138c2ecf20Sopenharmony_ci rxdesc->iv[1] = _rt2x00_desc_read(entry_priv->desc, 3); 20148c2ecf20Sopenharmony_ci rxdesc->dev_flags |= RXDONE_CRYPTO_IV; 20158c2ecf20Sopenharmony_ci 20168c2ecf20Sopenharmony_ci rxdesc->icv = _rt2x00_desc_read(entry_priv->desc, 4); 20178c2ecf20Sopenharmony_ci rxdesc->dev_flags |= RXDONE_CRYPTO_ICV; 20188c2ecf20Sopenharmony_ci 20198c2ecf20Sopenharmony_ci /* 20208c2ecf20Sopenharmony_ci * Hardware has stripped IV/EIV data from 802.11 frame during 20218c2ecf20Sopenharmony_ci * decryption. It has provided the data separately but rt2x00lib 20228c2ecf20Sopenharmony_ci * should decide if it should be reinserted. 20238c2ecf20Sopenharmony_ci */ 20248c2ecf20Sopenharmony_ci rxdesc->flags |= RX_FLAG_IV_STRIPPED; 20258c2ecf20Sopenharmony_ci 20268c2ecf20Sopenharmony_ci /* 20278c2ecf20Sopenharmony_ci * The hardware has already checked the Michael Mic and has 20288c2ecf20Sopenharmony_ci * stripped it from the frame. Signal this to mac80211. 20298c2ecf20Sopenharmony_ci */ 20308c2ecf20Sopenharmony_ci rxdesc->flags |= RX_FLAG_MMIC_STRIPPED; 20318c2ecf20Sopenharmony_ci 20328c2ecf20Sopenharmony_ci if (rxdesc->cipher_status == RX_CRYPTO_SUCCESS) 20338c2ecf20Sopenharmony_ci rxdesc->flags |= RX_FLAG_DECRYPTED; 20348c2ecf20Sopenharmony_ci else if (rxdesc->cipher_status == RX_CRYPTO_FAIL_MIC) 20358c2ecf20Sopenharmony_ci rxdesc->flags |= RX_FLAG_MMIC_ERROR; 20368c2ecf20Sopenharmony_ci } 20378c2ecf20Sopenharmony_ci 20388c2ecf20Sopenharmony_ci /* 20398c2ecf20Sopenharmony_ci * Obtain the status about this packet. 20408c2ecf20Sopenharmony_ci * When frame was received with an OFDM bitrate, 20418c2ecf20Sopenharmony_ci * the signal is the PLCP value. If it was received with 20428c2ecf20Sopenharmony_ci * a CCK bitrate the signal is the rate in 100kbit/s. 20438c2ecf20Sopenharmony_ci */ 20448c2ecf20Sopenharmony_ci rxdesc->signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL); 20458c2ecf20Sopenharmony_ci rxdesc->rssi = rt61pci_agc_to_rssi(rt2x00dev, word1); 20468c2ecf20Sopenharmony_ci rxdesc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); 20478c2ecf20Sopenharmony_ci 20488c2ecf20Sopenharmony_ci if (rt2x00_get_field32(word0, RXD_W0_OFDM)) 20498c2ecf20Sopenharmony_ci rxdesc->dev_flags |= RXDONE_SIGNAL_PLCP; 20508c2ecf20Sopenharmony_ci else 20518c2ecf20Sopenharmony_ci rxdesc->dev_flags |= RXDONE_SIGNAL_BITRATE; 20528c2ecf20Sopenharmony_ci if (rt2x00_get_field32(word0, RXD_W0_MY_BSS)) 20538c2ecf20Sopenharmony_ci rxdesc->dev_flags |= RXDONE_MY_BSS; 20548c2ecf20Sopenharmony_ci} 20558c2ecf20Sopenharmony_ci 20568c2ecf20Sopenharmony_ci/* 20578c2ecf20Sopenharmony_ci * Interrupt functions. 20588c2ecf20Sopenharmony_ci */ 20598c2ecf20Sopenharmony_cistatic void rt61pci_txdone(struct rt2x00_dev *rt2x00dev) 20608c2ecf20Sopenharmony_ci{ 20618c2ecf20Sopenharmony_ci struct data_queue *queue; 20628c2ecf20Sopenharmony_ci struct queue_entry *entry; 20638c2ecf20Sopenharmony_ci struct queue_entry *entry_done; 20648c2ecf20Sopenharmony_ci struct queue_entry_priv_mmio *entry_priv; 20658c2ecf20Sopenharmony_ci struct txdone_entry_desc txdesc; 20668c2ecf20Sopenharmony_ci u32 word; 20678c2ecf20Sopenharmony_ci u32 reg; 20688c2ecf20Sopenharmony_ci int type; 20698c2ecf20Sopenharmony_ci int index; 20708c2ecf20Sopenharmony_ci int i; 20718c2ecf20Sopenharmony_ci 20728c2ecf20Sopenharmony_ci /* 20738c2ecf20Sopenharmony_ci * TX_STA_FIFO is a stack of X entries, hence read TX_STA_FIFO 20748c2ecf20Sopenharmony_ci * at most X times and also stop processing once the TX_STA_FIFO_VALID 20758c2ecf20Sopenharmony_ci * flag is not set anymore. 20768c2ecf20Sopenharmony_ci * 20778c2ecf20Sopenharmony_ci * The legacy drivers use X=TX_RING_SIZE but state in a comment 20788c2ecf20Sopenharmony_ci * that the TX_STA_FIFO stack has a size of 16. We stick to our 20798c2ecf20Sopenharmony_ci * tx ring size for now. 20808c2ecf20Sopenharmony_ci */ 20818c2ecf20Sopenharmony_ci for (i = 0; i < rt2x00dev->tx->limit; i++) { 20828c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, STA_CSR4); 20838c2ecf20Sopenharmony_ci if (!rt2x00_get_field32(reg, STA_CSR4_VALID)) 20848c2ecf20Sopenharmony_ci break; 20858c2ecf20Sopenharmony_ci 20868c2ecf20Sopenharmony_ci /* 20878c2ecf20Sopenharmony_ci * Skip this entry when it contains an invalid 20888c2ecf20Sopenharmony_ci * queue identication number. 20898c2ecf20Sopenharmony_ci */ 20908c2ecf20Sopenharmony_ci type = rt2x00_get_field32(reg, STA_CSR4_PID_TYPE); 20918c2ecf20Sopenharmony_ci queue = rt2x00queue_get_tx_queue(rt2x00dev, type); 20928c2ecf20Sopenharmony_ci if (unlikely(!queue)) 20938c2ecf20Sopenharmony_ci continue; 20948c2ecf20Sopenharmony_ci 20958c2ecf20Sopenharmony_ci /* 20968c2ecf20Sopenharmony_ci * Skip this entry when it contains an invalid 20978c2ecf20Sopenharmony_ci * index number. 20988c2ecf20Sopenharmony_ci */ 20998c2ecf20Sopenharmony_ci index = rt2x00_get_field32(reg, STA_CSR4_PID_SUBTYPE); 21008c2ecf20Sopenharmony_ci if (unlikely(index >= queue->limit)) 21018c2ecf20Sopenharmony_ci continue; 21028c2ecf20Sopenharmony_ci 21038c2ecf20Sopenharmony_ci entry = &queue->entries[index]; 21048c2ecf20Sopenharmony_ci entry_priv = entry->priv_data; 21058c2ecf20Sopenharmony_ci word = rt2x00_desc_read(entry_priv->desc, 0); 21068c2ecf20Sopenharmony_ci 21078c2ecf20Sopenharmony_ci if (rt2x00_get_field32(word, TXD_W0_OWNER_NIC) || 21088c2ecf20Sopenharmony_ci !rt2x00_get_field32(word, TXD_W0_VALID)) 21098c2ecf20Sopenharmony_ci return; 21108c2ecf20Sopenharmony_ci 21118c2ecf20Sopenharmony_ci entry_done = rt2x00queue_get_entry(queue, Q_INDEX_DONE); 21128c2ecf20Sopenharmony_ci while (entry != entry_done) { 21138c2ecf20Sopenharmony_ci /* Catch up. 21148c2ecf20Sopenharmony_ci * Just report any entries we missed as failed. 21158c2ecf20Sopenharmony_ci */ 21168c2ecf20Sopenharmony_ci rt2x00_warn(rt2x00dev, "TX status report missed for entry %d\n", 21178c2ecf20Sopenharmony_ci entry_done->entry_idx); 21188c2ecf20Sopenharmony_ci 21198c2ecf20Sopenharmony_ci rt2x00lib_txdone_noinfo(entry_done, TXDONE_UNKNOWN); 21208c2ecf20Sopenharmony_ci entry_done = rt2x00queue_get_entry(queue, Q_INDEX_DONE); 21218c2ecf20Sopenharmony_ci } 21228c2ecf20Sopenharmony_ci 21238c2ecf20Sopenharmony_ci /* 21248c2ecf20Sopenharmony_ci * Obtain the status about this packet. 21258c2ecf20Sopenharmony_ci */ 21268c2ecf20Sopenharmony_ci txdesc.flags = 0; 21278c2ecf20Sopenharmony_ci switch (rt2x00_get_field32(reg, STA_CSR4_TX_RESULT)) { 21288c2ecf20Sopenharmony_ci case 0: /* Success, maybe with retry */ 21298c2ecf20Sopenharmony_ci __set_bit(TXDONE_SUCCESS, &txdesc.flags); 21308c2ecf20Sopenharmony_ci break; 21318c2ecf20Sopenharmony_ci case 6: /* Failure, excessive retries */ 21328c2ecf20Sopenharmony_ci __set_bit(TXDONE_EXCESSIVE_RETRY, &txdesc.flags); 21338c2ecf20Sopenharmony_ci fallthrough; /* this is a failed frame! */ 21348c2ecf20Sopenharmony_ci default: /* Failure */ 21358c2ecf20Sopenharmony_ci __set_bit(TXDONE_FAILURE, &txdesc.flags); 21368c2ecf20Sopenharmony_ci } 21378c2ecf20Sopenharmony_ci txdesc.retry = rt2x00_get_field32(reg, STA_CSR4_RETRY_COUNT); 21388c2ecf20Sopenharmony_ci 21398c2ecf20Sopenharmony_ci /* 21408c2ecf20Sopenharmony_ci * the frame was retried at least once 21418c2ecf20Sopenharmony_ci * -> hw used fallback rates 21428c2ecf20Sopenharmony_ci */ 21438c2ecf20Sopenharmony_ci if (txdesc.retry) 21448c2ecf20Sopenharmony_ci __set_bit(TXDONE_FALLBACK, &txdesc.flags); 21458c2ecf20Sopenharmony_ci 21468c2ecf20Sopenharmony_ci rt2x00lib_txdone(entry, &txdesc); 21478c2ecf20Sopenharmony_ci } 21488c2ecf20Sopenharmony_ci} 21498c2ecf20Sopenharmony_ci 21508c2ecf20Sopenharmony_cistatic void rt61pci_wakeup(struct rt2x00_dev *rt2x00dev) 21518c2ecf20Sopenharmony_ci{ 21528c2ecf20Sopenharmony_ci struct rt2x00lib_conf libconf = { .conf = &rt2x00dev->hw->conf }; 21538c2ecf20Sopenharmony_ci 21548c2ecf20Sopenharmony_ci rt61pci_config(rt2x00dev, &libconf, IEEE80211_CONF_CHANGE_PS); 21558c2ecf20Sopenharmony_ci} 21568c2ecf20Sopenharmony_ci 21578c2ecf20Sopenharmony_cistatic inline void rt61pci_enable_interrupt(struct rt2x00_dev *rt2x00dev, 21588c2ecf20Sopenharmony_ci struct rt2x00_field32 irq_field) 21598c2ecf20Sopenharmony_ci{ 21608c2ecf20Sopenharmony_ci u32 reg; 21618c2ecf20Sopenharmony_ci 21628c2ecf20Sopenharmony_ci /* 21638c2ecf20Sopenharmony_ci * Enable a single interrupt. The interrupt mask register 21648c2ecf20Sopenharmony_ci * access needs locking. 21658c2ecf20Sopenharmony_ci */ 21668c2ecf20Sopenharmony_ci spin_lock_irq(&rt2x00dev->irqmask_lock); 21678c2ecf20Sopenharmony_ci 21688c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, INT_MASK_CSR); 21698c2ecf20Sopenharmony_ci rt2x00_set_field32(®, irq_field, 0); 21708c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, INT_MASK_CSR, reg); 21718c2ecf20Sopenharmony_ci 21728c2ecf20Sopenharmony_ci spin_unlock_irq(&rt2x00dev->irqmask_lock); 21738c2ecf20Sopenharmony_ci} 21748c2ecf20Sopenharmony_ci 21758c2ecf20Sopenharmony_cistatic void rt61pci_enable_mcu_interrupt(struct rt2x00_dev *rt2x00dev, 21768c2ecf20Sopenharmony_ci struct rt2x00_field32 irq_field) 21778c2ecf20Sopenharmony_ci{ 21788c2ecf20Sopenharmony_ci u32 reg; 21798c2ecf20Sopenharmony_ci 21808c2ecf20Sopenharmony_ci /* 21818c2ecf20Sopenharmony_ci * Enable a single MCU interrupt. The interrupt mask register 21828c2ecf20Sopenharmony_ci * access needs locking. 21838c2ecf20Sopenharmony_ci */ 21848c2ecf20Sopenharmony_ci spin_lock_irq(&rt2x00dev->irqmask_lock); 21858c2ecf20Sopenharmony_ci 21868c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, MCU_INT_MASK_CSR); 21878c2ecf20Sopenharmony_ci rt2x00_set_field32(®, irq_field, 0); 21888c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, MCU_INT_MASK_CSR, reg); 21898c2ecf20Sopenharmony_ci 21908c2ecf20Sopenharmony_ci spin_unlock_irq(&rt2x00dev->irqmask_lock); 21918c2ecf20Sopenharmony_ci} 21928c2ecf20Sopenharmony_ci 21938c2ecf20Sopenharmony_cistatic void rt61pci_txstatus_tasklet(struct tasklet_struct *t) 21948c2ecf20Sopenharmony_ci{ 21958c2ecf20Sopenharmony_ci struct rt2x00_dev *rt2x00dev = from_tasklet(rt2x00dev, t, 21968c2ecf20Sopenharmony_ci txstatus_tasklet); 21978c2ecf20Sopenharmony_ci 21988c2ecf20Sopenharmony_ci rt61pci_txdone(rt2x00dev); 21998c2ecf20Sopenharmony_ci if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) 22008c2ecf20Sopenharmony_ci rt61pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_TXDONE); 22018c2ecf20Sopenharmony_ci} 22028c2ecf20Sopenharmony_ci 22038c2ecf20Sopenharmony_cistatic void rt61pci_tbtt_tasklet(struct tasklet_struct *t) 22048c2ecf20Sopenharmony_ci{ 22058c2ecf20Sopenharmony_ci struct rt2x00_dev *rt2x00dev = from_tasklet(rt2x00dev, t, tbtt_tasklet); 22068c2ecf20Sopenharmony_ci rt2x00lib_beacondone(rt2x00dev); 22078c2ecf20Sopenharmony_ci if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) 22088c2ecf20Sopenharmony_ci rt61pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_BEACON_DONE); 22098c2ecf20Sopenharmony_ci} 22108c2ecf20Sopenharmony_ci 22118c2ecf20Sopenharmony_cistatic void rt61pci_rxdone_tasklet(struct tasklet_struct *t) 22128c2ecf20Sopenharmony_ci{ 22138c2ecf20Sopenharmony_ci struct rt2x00_dev *rt2x00dev = from_tasklet(rt2x00dev, t, 22148c2ecf20Sopenharmony_ci rxdone_tasklet); 22158c2ecf20Sopenharmony_ci if (rt2x00mmio_rxdone(rt2x00dev)) 22168c2ecf20Sopenharmony_ci tasklet_schedule(&rt2x00dev->rxdone_tasklet); 22178c2ecf20Sopenharmony_ci else if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) 22188c2ecf20Sopenharmony_ci rt61pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_RXDONE); 22198c2ecf20Sopenharmony_ci} 22208c2ecf20Sopenharmony_ci 22218c2ecf20Sopenharmony_cistatic void rt61pci_autowake_tasklet(struct tasklet_struct *t) 22228c2ecf20Sopenharmony_ci{ 22238c2ecf20Sopenharmony_ci struct rt2x00_dev *rt2x00dev = from_tasklet(rt2x00dev, t, 22248c2ecf20Sopenharmony_ci autowake_tasklet); 22258c2ecf20Sopenharmony_ci rt61pci_wakeup(rt2x00dev); 22268c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, 22278c2ecf20Sopenharmony_ci M2H_CMD_DONE_CSR, 0xffffffff); 22288c2ecf20Sopenharmony_ci if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) 22298c2ecf20Sopenharmony_ci rt61pci_enable_mcu_interrupt(rt2x00dev, MCU_INT_MASK_CSR_TWAKEUP); 22308c2ecf20Sopenharmony_ci} 22318c2ecf20Sopenharmony_ci 22328c2ecf20Sopenharmony_cistatic irqreturn_t rt61pci_interrupt(int irq, void *dev_instance) 22338c2ecf20Sopenharmony_ci{ 22348c2ecf20Sopenharmony_ci struct rt2x00_dev *rt2x00dev = dev_instance; 22358c2ecf20Sopenharmony_ci u32 reg_mcu, mask_mcu; 22368c2ecf20Sopenharmony_ci u32 reg, mask; 22378c2ecf20Sopenharmony_ci 22388c2ecf20Sopenharmony_ci /* 22398c2ecf20Sopenharmony_ci * Get the interrupt sources & saved to local variable. 22408c2ecf20Sopenharmony_ci * Write register value back to clear pending interrupts. 22418c2ecf20Sopenharmony_ci */ 22428c2ecf20Sopenharmony_ci reg_mcu = rt2x00mmio_register_read(rt2x00dev, MCU_INT_SOURCE_CSR); 22438c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, MCU_INT_SOURCE_CSR, reg_mcu); 22448c2ecf20Sopenharmony_ci 22458c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, INT_SOURCE_CSR); 22468c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, INT_SOURCE_CSR, reg); 22478c2ecf20Sopenharmony_ci 22488c2ecf20Sopenharmony_ci if (!reg && !reg_mcu) 22498c2ecf20Sopenharmony_ci return IRQ_NONE; 22508c2ecf20Sopenharmony_ci 22518c2ecf20Sopenharmony_ci if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) 22528c2ecf20Sopenharmony_ci return IRQ_HANDLED; 22538c2ecf20Sopenharmony_ci 22548c2ecf20Sopenharmony_ci /* 22558c2ecf20Sopenharmony_ci * Schedule tasklets for interrupt handling. 22568c2ecf20Sopenharmony_ci */ 22578c2ecf20Sopenharmony_ci if (rt2x00_get_field32(reg, INT_SOURCE_CSR_RXDONE)) 22588c2ecf20Sopenharmony_ci tasklet_schedule(&rt2x00dev->rxdone_tasklet); 22598c2ecf20Sopenharmony_ci 22608c2ecf20Sopenharmony_ci if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TXDONE)) 22618c2ecf20Sopenharmony_ci tasklet_schedule(&rt2x00dev->txstatus_tasklet); 22628c2ecf20Sopenharmony_ci 22638c2ecf20Sopenharmony_ci if (rt2x00_get_field32(reg, INT_SOURCE_CSR_BEACON_DONE)) 22648c2ecf20Sopenharmony_ci tasklet_hi_schedule(&rt2x00dev->tbtt_tasklet); 22658c2ecf20Sopenharmony_ci 22668c2ecf20Sopenharmony_ci if (rt2x00_get_field32(reg_mcu, MCU_INT_SOURCE_CSR_TWAKEUP)) 22678c2ecf20Sopenharmony_ci tasklet_schedule(&rt2x00dev->autowake_tasklet); 22688c2ecf20Sopenharmony_ci 22698c2ecf20Sopenharmony_ci /* 22708c2ecf20Sopenharmony_ci * Since INT_MASK_CSR and INT_SOURCE_CSR use the same bits 22718c2ecf20Sopenharmony_ci * for interrupts and interrupt masks we can just use the value of 22728c2ecf20Sopenharmony_ci * INT_SOURCE_CSR to create the interrupt mask. 22738c2ecf20Sopenharmony_ci */ 22748c2ecf20Sopenharmony_ci mask = reg; 22758c2ecf20Sopenharmony_ci mask_mcu = reg_mcu; 22768c2ecf20Sopenharmony_ci 22778c2ecf20Sopenharmony_ci /* 22788c2ecf20Sopenharmony_ci * Disable all interrupts for which a tasklet was scheduled right now, 22798c2ecf20Sopenharmony_ci * the tasklet will reenable the appropriate interrupts. 22808c2ecf20Sopenharmony_ci */ 22818c2ecf20Sopenharmony_ci spin_lock(&rt2x00dev->irqmask_lock); 22828c2ecf20Sopenharmony_ci 22838c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, INT_MASK_CSR); 22848c2ecf20Sopenharmony_ci reg |= mask; 22858c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, INT_MASK_CSR, reg); 22868c2ecf20Sopenharmony_ci 22878c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, MCU_INT_MASK_CSR); 22888c2ecf20Sopenharmony_ci reg |= mask_mcu; 22898c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, MCU_INT_MASK_CSR, reg); 22908c2ecf20Sopenharmony_ci 22918c2ecf20Sopenharmony_ci spin_unlock(&rt2x00dev->irqmask_lock); 22928c2ecf20Sopenharmony_ci 22938c2ecf20Sopenharmony_ci return IRQ_HANDLED; 22948c2ecf20Sopenharmony_ci} 22958c2ecf20Sopenharmony_ci 22968c2ecf20Sopenharmony_ci/* 22978c2ecf20Sopenharmony_ci * Device probe functions. 22988c2ecf20Sopenharmony_ci */ 22998c2ecf20Sopenharmony_cistatic int rt61pci_validate_eeprom(struct rt2x00_dev *rt2x00dev) 23008c2ecf20Sopenharmony_ci{ 23018c2ecf20Sopenharmony_ci struct eeprom_93cx6 eeprom; 23028c2ecf20Sopenharmony_ci u32 reg; 23038c2ecf20Sopenharmony_ci u16 word; 23048c2ecf20Sopenharmony_ci u8 *mac; 23058c2ecf20Sopenharmony_ci s8 value; 23068c2ecf20Sopenharmony_ci 23078c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, E2PROM_CSR); 23088c2ecf20Sopenharmony_ci 23098c2ecf20Sopenharmony_ci eeprom.data = rt2x00dev; 23108c2ecf20Sopenharmony_ci eeprom.register_read = rt61pci_eepromregister_read; 23118c2ecf20Sopenharmony_ci eeprom.register_write = rt61pci_eepromregister_write; 23128c2ecf20Sopenharmony_ci eeprom.width = rt2x00_get_field32(reg, E2PROM_CSR_TYPE_93C46) ? 23138c2ecf20Sopenharmony_ci PCI_EEPROM_WIDTH_93C46 : PCI_EEPROM_WIDTH_93C66; 23148c2ecf20Sopenharmony_ci eeprom.reg_data_in = 0; 23158c2ecf20Sopenharmony_ci eeprom.reg_data_out = 0; 23168c2ecf20Sopenharmony_ci eeprom.reg_data_clock = 0; 23178c2ecf20Sopenharmony_ci eeprom.reg_chip_select = 0; 23188c2ecf20Sopenharmony_ci 23198c2ecf20Sopenharmony_ci eeprom_93cx6_multiread(&eeprom, EEPROM_BASE, rt2x00dev->eeprom, 23208c2ecf20Sopenharmony_ci EEPROM_SIZE / sizeof(u16)); 23218c2ecf20Sopenharmony_ci 23228c2ecf20Sopenharmony_ci /* 23238c2ecf20Sopenharmony_ci * Start validation of the data that has been read. 23248c2ecf20Sopenharmony_ci */ 23258c2ecf20Sopenharmony_ci mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0); 23268c2ecf20Sopenharmony_ci rt2x00lib_set_mac_address(rt2x00dev, mac); 23278c2ecf20Sopenharmony_ci 23288c2ecf20Sopenharmony_ci word = rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA); 23298c2ecf20Sopenharmony_ci if (word == 0xffff) { 23308c2ecf20Sopenharmony_ci rt2x00_set_field16(&word, EEPROM_ANTENNA_NUM, 2); 23318c2ecf20Sopenharmony_ci rt2x00_set_field16(&word, EEPROM_ANTENNA_TX_DEFAULT, 23328c2ecf20Sopenharmony_ci ANTENNA_B); 23338c2ecf20Sopenharmony_ci rt2x00_set_field16(&word, EEPROM_ANTENNA_RX_DEFAULT, 23348c2ecf20Sopenharmony_ci ANTENNA_B); 23358c2ecf20Sopenharmony_ci rt2x00_set_field16(&word, EEPROM_ANTENNA_FRAME_TYPE, 0); 23368c2ecf20Sopenharmony_ci rt2x00_set_field16(&word, EEPROM_ANTENNA_DYN_TXAGC, 0); 23378c2ecf20Sopenharmony_ci rt2x00_set_field16(&word, EEPROM_ANTENNA_HARDWARE_RADIO, 0); 23388c2ecf20Sopenharmony_ci rt2x00_set_field16(&word, EEPROM_ANTENNA_RF_TYPE, RF5225); 23398c2ecf20Sopenharmony_ci rt2x00_eeprom_write(rt2x00dev, EEPROM_ANTENNA, word); 23408c2ecf20Sopenharmony_ci rt2x00_eeprom_dbg(rt2x00dev, "Antenna: 0x%04x\n", word); 23418c2ecf20Sopenharmony_ci } 23428c2ecf20Sopenharmony_ci 23438c2ecf20Sopenharmony_ci word = rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC); 23448c2ecf20Sopenharmony_ci if (word == 0xffff) { 23458c2ecf20Sopenharmony_ci rt2x00_set_field16(&word, EEPROM_NIC_ENABLE_DIVERSITY, 0); 23468c2ecf20Sopenharmony_ci rt2x00_set_field16(&word, EEPROM_NIC_TX_DIVERSITY, 0); 23478c2ecf20Sopenharmony_ci rt2x00_set_field16(&word, EEPROM_NIC_RX_FIXED, 0); 23488c2ecf20Sopenharmony_ci rt2x00_set_field16(&word, EEPROM_NIC_TX_FIXED, 0); 23498c2ecf20Sopenharmony_ci rt2x00_set_field16(&word, EEPROM_NIC_EXTERNAL_LNA_BG, 0); 23508c2ecf20Sopenharmony_ci rt2x00_set_field16(&word, EEPROM_NIC_CARDBUS_ACCEL, 0); 23518c2ecf20Sopenharmony_ci rt2x00_set_field16(&word, EEPROM_NIC_EXTERNAL_LNA_A, 0); 23528c2ecf20Sopenharmony_ci rt2x00_eeprom_write(rt2x00dev, EEPROM_NIC, word); 23538c2ecf20Sopenharmony_ci rt2x00_eeprom_dbg(rt2x00dev, "NIC: 0x%04x\n", word); 23548c2ecf20Sopenharmony_ci } 23558c2ecf20Sopenharmony_ci 23568c2ecf20Sopenharmony_ci word = rt2x00_eeprom_read(rt2x00dev, EEPROM_LED); 23578c2ecf20Sopenharmony_ci if (word == 0xffff) { 23588c2ecf20Sopenharmony_ci rt2x00_set_field16(&word, EEPROM_LED_LED_MODE, 23598c2ecf20Sopenharmony_ci LED_MODE_DEFAULT); 23608c2ecf20Sopenharmony_ci rt2x00_eeprom_write(rt2x00dev, EEPROM_LED, word); 23618c2ecf20Sopenharmony_ci rt2x00_eeprom_dbg(rt2x00dev, "Led: 0x%04x\n", word); 23628c2ecf20Sopenharmony_ci } 23638c2ecf20Sopenharmony_ci 23648c2ecf20Sopenharmony_ci word = rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ); 23658c2ecf20Sopenharmony_ci if (word == 0xffff) { 23668c2ecf20Sopenharmony_ci rt2x00_set_field16(&word, EEPROM_FREQ_OFFSET, 0); 23678c2ecf20Sopenharmony_ci rt2x00_set_field16(&word, EEPROM_FREQ_SEQ, 0); 23688c2ecf20Sopenharmony_ci rt2x00_eeprom_write(rt2x00dev, EEPROM_FREQ, word); 23698c2ecf20Sopenharmony_ci rt2x00_eeprom_dbg(rt2x00dev, "Freq: 0x%04x\n", word); 23708c2ecf20Sopenharmony_ci } 23718c2ecf20Sopenharmony_ci 23728c2ecf20Sopenharmony_ci word = rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG); 23738c2ecf20Sopenharmony_ci if (word == 0xffff) { 23748c2ecf20Sopenharmony_ci rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_1, 0); 23758c2ecf20Sopenharmony_ci rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_2, 0); 23768c2ecf20Sopenharmony_ci rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_BG, word); 23778c2ecf20Sopenharmony_ci rt2x00_eeprom_dbg(rt2x00dev, "RSSI OFFSET BG: 0x%04x\n", word); 23788c2ecf20Sopenharmony_ci } else { 23798c2ecf20Sopenharmony_ci value = rt2x00_get_field16(word, EEPROM_RSSI_OFFSET_BG_1); 23808c2ecf20Sopenharmony_ci if (value < -10 || value > 10) 23818c2ecf20Sopenharmony_ci rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_1, 0); 23828c2ecf20Sopenharmony_ci value = rt2x00_get_field16(word, EEPROM_RSSI_OFFSET_BG_2); 23838c2ecf20Sopenharmony_ci if (value < -10 || value > 10) 23848c2ecf20Sopenharmony_ci rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_2, 0); 23858c2ecf20Sopenharmony_ci rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_BG, word); 23868c2ecf20Sopenharmony_ci } 23878c2ecf20Sopenharmony_ci 23888c2ecf20Sopenharmony_ci word = rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A); 23898c2ecf20Sopenharmony_ci if (word == 0xffff) { 23908c2ecf20Sopenharmony_ci rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_1, 0); 23918c2ecf20Sopenharmony_ci rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_2, 0); 23928c2ecf20Sopenharmony_ci rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_A, word); 23938c2ecf20Sopenharmony_ci rt2x00_eeprom_dbg(rt2x00dev, "RSSI OFFSET A: 0x%04x\n", word); 23948c2ecf20Sopenharmony_ci } else { 23958c2ecf20Sopenharmony_ci value = rt2x00_get_field16(word, EEPROM_RSSI_OFFSET_A_1); 23968c2ecf20Sopenharmony_ci if (value < -10 || value > 10) 23978c2ecf20Sopenharmony_ci rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_1, 0); 23988c2ecf20Sopenharmony_ci value = rt2x00_get_field16(word, EEPROM_RSSI_OFFSET_A_2); 23998c2ecf20Sopenharmony_ci if (value < -10 || value > 10) 24008c2ecf20Sopenharmony_ci rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_2, 0); 24018c2ecf20Sopenharmony_ci rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_A, word); 24028c2ecf20Sopenharmony_ci } 24038c2ecf20Sopenharmony_ci 24048c2ecf20Sopenharmony_ci return 0; 24058c2ecf20Sopenharmony_ci} 24068c2ecf20Sopenharmony_ci 24078c2ecf20Sopenharmony_cistatic int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev) 24088c2ecf20Sopenharmony_ci{ 24098c2ecf20Sopenharmony_ci u32 reg; 24108c2ecf20Sopenharmony_ci u16 value; 24118c2ecf20Sopenharmony_ci u16 eeprom; 24128c2ecf20Sopenharmony_ci 24138c2ecf20Sopenharmony_ci /* 24148c2ecf20Sopenharmony_ci * Read EEPROM word for configuration. 24158c2ecf20Sopenharmony_ci */ 24168c2ecf20Sopenharmony_ci eeprom = rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA); 24178c2ecf20Sopenharmony_ci 24188c2ecf20Sopenharmony_ci /* 24198c2ecf20Sopenharmony_ci * Identify RF chipset. 24208c2ecf20Sopenharmony_ci */ 24218c2ecf20Sopenharmony_ci value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE); 24228c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, MAC_CSR0); 24238c2ecf20Sopenharmony_ci rt2x00_set_chip(rt2x00dev, rt2x00_get_field32(reg, MAC_CSR0_CHIPSET), 24248c2ecf20Sopenharmony_ci value, rt2x00_get_field32(reg, MAC_CSR0_REVISION)); 24258c2ecf20Sopenharmony_ci 24268c2ecf20Sopenharmony_ci if (!rt2x00_rf(rt2x00dev, RF5225) && 24278c2ecf20Sopenharmony_ci !rt2x00_rf(rt2x00dev, RF5325) && 24288c2ecf20Sopenharmony_ci !rt2x00_rf(rt2x00dev, RF2527) && 24298c2ecf20Sopenharmony_ci !rt2x00_rf(rt2x00dev, RF2529)) { 24308c2ecf20Sopenharmony_ci rt2x00_err(rt2x00dev, "Invalid RF chipset detected\n"); 24318c2ecf20Sopenharmony_ci return -ENODEV; 24328c2ecf20Sopenharmony_ci } 24338c2ecf20Sopenharmony_ci 24348c2ecf20Sopenharmony_ci /* 24358c2ecf20Sopenharmony_ci * Determine number of antennas. 24368c2ecf20Sopenharmony_ci */ 24378c2ecf20Sopenharmony_ci if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_NUM) == 2) 24388c2ecf20Sopenharmony_ci __set_bit(CAPABILITY_DOUBLE_ANTENNA, &rt2x00dev->cap_flags); 24398c2ecf20Sopenharmony_ci 24408c2ecf20Sopenharmony_ci /* 24418c2ecf20Sopenharmony_ci * Identify default antenna configuration. 24428c2ecf20Sopenharmony_ci */ 24438c2ecf20Sopenharmony_ci rt2x00dev->default_ant.tx = 24448c2ecf20Sopenharmony_ci rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TX_DEFAULT); 24458c2ecf20Sopenharmony_ci rt2x00dev->default_ant.rx = 24468c2ecf20Sopenharmony_ci rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RX_DEFAULT); 24478c2ecf20Sopenharmony_ci 24488c2ecf20Sopenharmony_ci /* 24498c2ecf20Sopenharmony_ci * Read the Frame type. 24508c2ecf20Sopenharmony_ci */ 24518c2ecf20Sopenharmony_ci if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_FRAME_TYPE)) 24528c2ecf20Sopenharmony_ci __set_bit(CAPABILITY_FRAME_TYPE, &rt2x00dev->cap_flags); 24538c2ecf20Sopenharmony_ci 24548c2ecf20Sopenharmony_ci /* 24558c2ecf20Sopenharmony_ci * Detect if this device has a hardware controlled radio. 24568c2ecf20Sopenharmony_ci */ 24578c2ecf20Sopenharmony_ci if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO)) 24588c2ecf20Sopenharmony_ci __set_bit(CAPABILITY_HW_BUTTON, &rt2x00dev->cap_flags); 24598c2ecf20Sopenharmony_ci 24608c2ecf20Sopenharmony_ci /* 24618c2ecf20Sopenharmony_ci * Read frequency offset and RF programming sequence. 24628c2ecf20Sopenharmony_ci */ 24638c2ecf20Sopenharmony_ci eeprom = rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ); 24648c2ecf20Sopenharmony_ci if (rt2x00_get_field16(eeprom, EEPROM_FREQ_SEQ)) 24658c2ecf20Sopenharmony_ci __set_bit(CAPABILITY_RF_SEQUENCE, &rt2x00dev->cap_flags); 24668c2ecf20Sopenharmony_ci 24678c2ecf20Sopenharmony_ci rt2x00dev->freq_offset = rt2x00_get_field16(eeprom, EEPROM_FREQ_OFFSET); 24688c2ecf20Sopenharmony_ci 24698c2ecf20Sopenharmony_ci /* 24708c2ecf20Sopenharmony_ci * Read external LNA informations. 24718c2ecf20Sopenharmony_ci */ 24728c2ecf20Sopenharmony_ci eeprom = rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC); 24738c2ecf20Sopenharmony_ci 24748c2ecf20Sopenharmony_ci if (rt2x00_get_field16(eeprom, EEPROM_NIC_EXTERNAL_LNA_A)) 24758c2ecf20Sopenharmony_ci __set_bit(CAPABILITY_EXTERNAL_LNA_A, &rt2x00dev->cap_flags); 24768c2ecf20Sopenharmony_ci if (rt2x00_get_field16(eeprom, EEPROM_NIC_EXTERNAL_LNA_BG)) 24778c2ecf20Sopenharmony_ci __set_bit(CAPABILITY_EXTERNAL_LNA_BG, &rt2x00dev->cap_flags); 24788c2ecf20Sopenharmony_ci 24798c2ecf20Sopenharmony_ci /* 24808c2ecf20Sopenharmony_ci * When working with a RF2529 chip without double antenna, 24818c2ecf20Sopenharmony_ci * the antenna settings should be gathered from the NIC 24828c2ecf20Sopenharmony_ci * eeprom word. 24838c2ecf20Sopenharmony_ci */ 24848c2ecf20Sopenharmony_ci if (rt2x00_rf(rt2x00dev, RF2529) && 24858c2ecf20Sopenharmony_ci !rt2x00_has_cap_double_antenna(rt2x00dev)) { 24868c2ecf20Sopenharmony_ci rt2x00dev->default_ant.rx = 24878c2ecf20Sopenharmony_ci ANTENNA_A + rt2x00_get_field16(eeprom, EEPROM_NIC_RX_FIXED); 24888c2ecf20Sopenharmony_ci rt2x00dev->default_ant.tx = 24898c2ecf20Sopenharmony_ci ANTENNA_B - rt2x00_get_field16(eeprom, EEPROM_NIC_TX_FIXED); 24908c2ecf20Sopenharmony_ci 24918c2ecf20Sopenharmony_ci if (rt2x00_get_field16(eeprom, EEPROM_NIC_TX_DIVERSITY)) 24928c2ecf20Sopenharmony_ci rt2x00dev->default_ant.tx = ANTENNA_SW_DIVERSITY; 24938c2ecf20Sopenharmony_ci if (rt2x00_get_field16(eeprom, EEPROM_NIC_ENABLE_DIVERSITY)) 24948c2ecf20Sopenharmony_ci rt2x00dev->default_ant.rx = ANTENNA_SW_DIVERSITY; 24958c2ecf20Sopenharmony_ci } 24968c2ecf20Sopenharmony_ci 24978c2ecf20Sopenharmony_ci /* 24988c2ecf20Sopenharmony_ci * Store led settings, for correct led behaviour. 24998c2ecf20Sopenharmony_ci * If the eeprom value is invalid, 25008c2ecf20Sopenharmony_ci * switch to default led mode. 25018c2ecf20Sopenharmony_ci */ 25028c2ecf20Sopenharmony_ci#ifdef CONFIG_RT2X00_LIB_LEDS 25038c2ecf20Sopenharmony_ci eeprom = rt2x00_eeprom_read(rt2x00dev, EEPROM_LED); 25048c2ecf20Sopenharmony_ci value = rt2x00_get_field16(eeprom, EEPROM_LED_LED_MODE); 25058c2ecf20Sopenharmony_ci 25068c2ecf20Sopenharmony_ci rt61pci_init_led(rt2x00dev, &rt2x00dev->led_radio, LED_TYPE_RADIO); 25078c2ecf20Sopenharmony_ci rt61pci_init_led(rt2x00dev, &rt2x00dev->led_assoc, LED_TYPE_ASSOC); 25088c2ecf20Sopenharmony_ci if (value == LED_MODE_SIGNAL_STRENGTH) 25098c2ecf20Sopenharmony_ci rt61pci_init_led(rt2x00dev, &rt2x00dev->led_qual, 25108c2ecf20Sopenharmony_ci LED_TYPE_QUALITY); 25118c2ecf20Sopenharmony_ci 25128c2ecf20Sopenharmony_ci rt2x00_set_field16(&rt2x00dev->led_mcu_reg, MCU_LEDCS_LED_MODE, value); 25138c2ecf20Sopenharmony_ci rt2x00_set_field16(&rt2x00dev->led_mcu_reg, MCU_LEDCS_POLARITY_GPIO_0, 25148c2ecf20Sopenharmony_ci rt2x00_get_field16(eeprom, 25158c2ecf20Sopenharmony_ci EEPROM_LED_POLARITY_GPIO_0)); 25168c2ecf20Sopenharmony_ci rt2x00_set_field16(&rt2x00dev->led_mcu_reg, MCU_LEDCS_POLARITY_GPIO_1, 25178c2ecf20Sopenharmony_ci rt2x00_get_field16(eeprom, 25188c2ecf20Sopenharmony_ci EEPROM_LED_POLARITY_GPIO_1)); 25198c2ecf20Sopenharmony_ci rt2x00_set_field16(&rt2x00dev->led_mcu_reg, MCU_LEDCS_POLARITY_GPIO_2, 25208c2ecf20Sopenharmony_ci rt2x00_get_field16(eeprom, 25218c2ecf20Sopenharmony_ci EEPROM_LED_POLARITY_GPIO_2)); 25228c2ecf20Sopenharmony_ci rt2x00_set_field16(&rt2x00dev->led_mcu_reg, MCU_LEDCS_POLARITY_GPIO_3, 25238c2ecf20Sopenharmony_ci rt2x00_get_field16(eeprom, 25248c2ecf20Sopenharmony_ci EEPROM_LED_POLARITY_GPIO_3)); 25258c2ecf20Sopenharmony_ci rt2x00_set_field16(&rt2x00dev->led_mcu_reg, MCU_LEDCS_POLARITY_GPIO_4, 25268c2ecf20Sopenharmony_ci rt2x00_get_field16(eeprom, 25278c2ecf20Sopenharmony_ci EEPROM_LED_POLARITY_GPIO_4)); 25288c2ecf20Sopenharmony_ci rt2x00_set_field16(&rt2x00dev->led_mcu_reg, MCU_LEDCS_POLARITY_ACT, 25298c2ecf20Sopenharmony_ci rt2x00_get_field16(eeprom, EEPROM_LED_POLARITY_ACT)); 25308c2ecf20Sopenharmony_ci rt2x00_set_field16(&rt2x00dev->led_mcu_reg, MCU_LEDCS_POLARITY_READY_BG, 25318c2ecf20Sopenharmony_ci rt2x00_get_field16(eeprom, 25328c2ecf20Sopenharmony_ci EEPROM_LED_POLARITY_RDY_G)); 25338c2ecf20Sopenharmony_ci rt2x00_set_field16(&rt2x00dev->led_mcu_reg, MCU_LEDCS_POLARITY_READY_A, 25348c2ecf20Sopenharmony_ci rt2x00_get_field16(eeprom, 25358c2ecf20Sopenharmony_ci EEPROM_LED_POLARITY_RDY_A)); 25368c2ecf20Sopenharmony_ci#endif /* CONFIG_RT2X00_LIB_LEDS */ 25378c2ecf20Sopenharmony_ci 25388c2ecf20Sopenharmony_ci return 0; 25398c2ecf20Sopenharmony_ci} 25408c2ecf20Sopenharmony_ci 25418c2ecf20Sopenharmony_ci/* 25428c2ecf20Sopenharmony_ci * RF value list for RF5225 & RF5325 25438c2ecf20Sopenharmony_ci * Supports: 2.4 GHz & 5.2 GHz, rf_sequence disabled 25448c2ecf20Sopenharmony_ci */ 25458c2ecf20Sopenharmony_cistatic const struct rf_channel rf_vals_noseq[] = { 25468c2ecf20Sopenharmony_ci { 1, 0x00002ccc, 0x00004786, 0x00068455, 0x000ffa0b }, 25478c2ecf20Sopenharmony_ci { 2, 0x00002ccc, 0x00004786, 0x00068455, 0x000ffa1f }, 25488c2ecf20Sopenharmony_ci { 3, 0x00002ccc, 0x0000478a, 0x00068455, 0x000ffa0b }, 25498c2ecf20Sopenharmony_ci { 4, 0x00002ccc, 0x0000478a, 0x00068455, 0x000ffa1f }, 25508c2ecf20Sopenharmony_ci { 5, 0x00002ccc, 0x0000478e, 0x00068455, 0x000ffa0b }, 25518c2ecf20Sopenharmony_ci { 6, 0x00002ccc, 0x0000478e, 0x00068455, 0x000ffa1f }, 25528c2ecf20Sopenharmony_ci { 7, 0x00002ccc, 0x00004792, 0x00068455, 0x000ffa0b }, 25538c2ecf20Sopenharmony_ci { 8, 0x00002ccc, 0x00004792, 0x00068455, 0x000ffa1f }, 25548c2ecf20Sopenharmony_ci { 9, 0x00002ccc, 0x00004796, 0x00068455, 0x000ffa0b }, 25558c2ecf20Sopenharmony_ci { 10, 0x00002ccc, 0x00004796, 0x00068455, 0x000ffa1f }, 25568c2ecf20Sopenharmony_ci { 11, 0x00002ccc, 0x0000479a, 0x00068455, 0x000ffa0b }, 25578c2ecf20Sopenharmony_ci { 12, 0x00002ccc, 0x0000479a, 0x00068455, 0x000ffa1f }, 25588c2ecf20Sopenharmony_ci { 13, 0x00002ccc, 0x0000479e, 0x00068455, 0x000ffa0b }, 25598c2ecf20Sopenharmony_ci { 14, 0x00002ccc, 0x000047a2, 0x00068455, 0x000ffa13 }, 25608c2ecf20Sopenharmony_ci 25618c2ecf20Sopenharmony_ci /* 802.11 UNI / HyperLan 2 */ 25628c2ecf20Sopenharmony_ci { 36, 0x00002ccc, 0x0000499a, 0x0009be55, 0x000ffa23 }, 25638c2ecf20Sopenharmony_ci { 40, 0x00002ccc, 0x000049a2, 0x0009be55, 0x000ffa03 }, 25648c2ecf20Sopenharmony_ci { 44, 0x00002ccc, 0x000049a6, 0x0009be55, 0x000ffa0b }, 25658c2ecf20Sopenharmony_ci { 48, 0x00002ccc, 0x000049aa, 0x0009be55, 0x000ffa13 }, 25668c2ecf20Sopenharmony_ci { 52, 0x00002ccc, 0x000049ae, 0x0009ae55, 0x000ffa1b }, 25678c2ecf20Sopenharmony_ci { 56, 0x00002ccc, 0x000049b2, 0x0009ae55, 0x000ffa23 }, 25688c2ecf20Sopenharmony_ci { 60, 0x00002ccc, 0x000049ba, 0x0009ae55, 0x000ffa03 }, 25698c2ecf20Sopenharmony_ci { 64, 0x00002ccc, 0x000049be, 0x0009ae55, 0x000ffa0b }, 25708c2ecf20Sopenharmony_ci 25718c2ecf20Sopenharmony_ci /* 802.11 HyperLan 2 */ 25728c2ecf20Sopenharmony_ci { 100, 0x00002ccc, 0x00004a2a, 0x000bae55, 0x000ffa03 }, 25738c2ecf20Sopenharmony_ci { 104, 0x00002ccc, 0x00004a2e, 0x000bae55, 0x000ffa0b }, 25748c2ecf20Sopenharmony_ci { 108, 0x00002ccc, 0x00004a32, 0x000bae55, 0x000ffa13 }, 25758c2ecf20Sopenharmony_ci { 112, 0x00002ccc, 0x00004a36, 0x000bae55, 0x000ffa1b }, 25768c2ecf20Sopenharmony_ci { 116, 0x00002ccc, 0x00004a3a, 0x000bbe55, 0x000ffa23 }, 25778c2ecf20Sopenharmony_ci { 120, 0x00002ccc, 0x00004a82, 0x000bbe55, 0x000ffa03 }, 25788c2ecf20Sopenharmony_ci { 124, 0x00002ccc, 0x00004a86, 0x000bbe55, 0x000ffa0b }, 25798c2ecf20Sopenharmony_ci { 128, 0x00002ccc, 0x00004a8a, 0x000bbe55, 0x000ffa13 }, 25808c2ecf20Sopenharmony_ci { 132, 0x00002ccc, 0x00004a8e, 0x000bbe55, 0x000ffa1b }, 25818c2ecf20Sopenharmony_ci { 136, 0x00002ccc, 0x00004a92, 0x000bbe55, 0x000ffa23 }, 25828c2ecf20Sopenharmony_ci 25838c2ecf20Sopenharmony_ci /* 802.11 UNII */ 25848c2ecf20Sopenharmony_ci { 140, 0x00002ccc, 0x00004a9a, 0x000bbe55, 0x000ffa03 }, 25858c2ecf20Sopenharmony_ci { 149, 0x00002ccc, 0x00004aa2, 0x000bbe55, 0x000ffa1f }, 25868c2ecf20Sopenharmony_ci { 153, 0x00002ccc, 0x00004aa6, 0x000bbe55, 0x000ffa27 }, 25878c2ecf20Sopenharmony_ci { 157, 0x00002ccc, 0x00004aae, 0x000bbe55, 0x000ffa07 }, 25888c2ecf20Sopenharmony_ci { 161, 0x00002ccc, 0x00004ab2, 0x000bbe55, 0x000ffa0f }, 25898c2ecf20Sopenharmony_ci { 165, 0x00002ccc, 0x00004ab6, 0x000bbe55, 0x000ffa17 }, 25908c2ecf20Sopenharmony_ci 25918c2ecf20Sopenharmony_ci /* MMAC(Japan)J52 ch 34,38,42,46 */ 25928c2ecf20Sopenharmony_ci { 34, 0x00002ccc, 0x0000499a, 0x0009be55, 0x000ffa0b }, 25938c2ecf20Sopenharmony_ci { 38, 0x00002ccc, 0x0000499e, 0x0009be55, 0x000ffa13 }, 25948c2ecf20Sopenharmony_ci { 42, 0x00002ccc, 0x000049a2, 0x0009be55, 0x000ffa1b }, 25958c2ecf20Sopenharmony_ci { 46, 0x00002ccc, 0x000049a6, 0x0009be55, 0x000ffa23 }, 25968c2ecf20Sopenharmony_ci}; 25978c2ecf20Sopenharmony_ci 25988c2ecf20Sopenharmony_ci/* 25998c2ecf20Sopenharmony_ci * RF value list for RF5225 & RF5325 26008c2ecf20Sopenharmony_ci * Supports: 2.4 GHz & 5.2 GHz, rf_sequence enabled 26018c2ecf20Sopenharmony_ci */ 26028c2ecf20Sopenharmony_cistatic const struct rf_channel rf_vals_seq[] = { 26038c2ecf20Sopenharmony_ci { 1, 0x00002ccc, 0x00004786, 0x00068455, 0x000ffa0b }, 26048c2ecf20Sopenharmony_ci { 2, 0x00002ccc, 0x00004786, 0x00068455, 0x000ffa1f }, 26058c2ecf20Sopenharmony_ci { 3, 0x00002ccc, 0x0000478a, 0x00068455, 0x000ffa0b }, 26068c2ecf20Sopenharmony_ci { 4, 0x00002ccc, 0x0000478a, 0x00068455, 0x000ffa1f }, 26078c2ecf20Sopenharmony_ci { 5, 0x00002ccc, 0x0000478e, 0x00068455, 0x000ffa0b }, 26088c2ecf20Sopenharmony_ci { 6, 0x00002ccc, 0x0000478e, 0x00068455, 0x000ffa1f }, 26098c2ecf20Sopenharmony_ci { 7, 0x00002ccc, 0x00004792, 0x00068455, 0x000ffa0b }, 26108c2ecf20Sopenharmony_ci { 8, 0x00002ccc, 0x00004792, 0x00068455, 0x000ffa1f }, 26118c2ecf20Sopenharmony_ci { 9, 0x00002ccc, 0x00004796, 0x00068455, 0x000ffa0b }, 26128c2ecf20Sopenharmony_ci { 10, 0x00002ccc, 0x00004796, 0x00068455, 0x000ffa1f }, 26138c2ecf20Sopenharmony_ci { 11, 0x00002ccc, 0x0000479a, 0x00068455, 0x000ffa0b }, 26148c2ecf20Sopenharmony_ci { 12, 0x00002ccc, 0x0000479a, 0x00068455, 0x000ffa1f }, 26158c2ecf20Sopenharmony_ci { 13, 0x00002ccc, 0x0000479e, 0x00068455, 0x000ffa0b }, 26168c2ecf20Sopenharmony_ci { 14, 0x00002ccc, 0x000047a2, 0x00068455, 0x000ffa13 }, 26178c2ecf20Sopenharmony_ci 26188c2ecf20Sopenharmony_ci /* 802.11 UNI / HyperLan 2 */ 26198c2ecf20Sopenharmony_ci { 36, 0x00002cd4, 0x0004481a, 0x00098455, 0x000c0a03 }, 26208c2ecf20Sopenharmony_ci { 40, 0x00002cd0, 0x00044682, 0x00098455, 0x000c0a03 }, 26218c2ecf20Sopenharmony_ci { 44, 0x00002cd0, 0x00044686, 0x00098455, 0x000c0a1b }, 26228c2ecf20Sopenharmony_ci { 48, 0x00002cd0, 0x0004468e, 0x00098655, 0x000c0a0b }, 26238c2ecf20Sopenharmony_ci { 52, 0x00002cd0, 0x00044692, 0x00098855, 0x000c0a23 }, 26248c2ecf20Sopenharmony_ci { 56, 0x00002cd0, 0x0004469a, 0x00098c55, 0x000c0a13 }, 26258c2ecf20Sopenharmony_ci { 60, 0x00002cd0, 0x000446a2, 0x00098e55, 0x000c0a03 }, 26268c2ecf20Sopenharmony_ci { 64, 0x00002cd0, 0x000446a6, 0x00099255, 0x000c0a1b }, 26278c2ecf20Sopenharmony_ci 26288c2ecf20Sopenharmony_ci /* 802.11 HyperLan 2 */ 26298c2ecf20Sopenharmony_ci { 100, 0x00002cd4, 0x0004489a, 0x000b9855, 0x000c0a03 }, 26308c2ecf20Sopenharmony_ci { 104, 0x00002cd4, 0x000448a2, 0x000b9855, 0x000c0a03 }, 26318c2ecf20Sopenharmony_ci { 108, 0x00002cd4, 0x000448aa, 0x000b9855, 0x000c0a03 }, 26328c2ecf20Sopenharmony_ci { 112, 0x00002cd4, 0x000448b2, 0x000b9a55, 0x000c0a03 }, 26338c2ecf20Sopenharmony_ci { 116, 0x00002cd4, 0x000448ba, 0x000b9a55, 0x000c0a03 }, 26348c2ecf20Sopenharmony_ci { 120, 0x00002cd0, 0x00044702, 0x000b9a55, 0x000c0a03 }, 26358c2ecf20Sopenharmony_ci { 124, 0x00002cd0, 0x00044706, 0x000b9a55, 0x000c0a1b }, 26368c2ecf20Sopenharmony_ci { 128, 0x00002cd0, 0x0004470e, 0x000b9c55, 0x000c0a0b }, 26378c2ecf20Sopenharmony_ci { 132, 0x00002cd0, 0x00044712, 0x000b9c55, 0x000c0a23 }, 26388c2ecf20Sopenharmony_ci { 136, 0x00002cd0, 0x0004471a, 0x000b9e55, 0x000c0a13 }, 26398c2ecf20Sopenharmony_ci 26408c2ecf20Sopenharmony_ci /* 802.11 UNII */ 26418c2ecf20Sopenharmony_ci { 140, 0x00002cd0, 0x00044722, 0x000b9e55, 0x000c0a03 }, 26428c2ecf20Sopenharmony_ci { 149, 0x00002cd0, 0x0004472e, 0x000ba255, 0x000c0a1b }, 26438c2ecf20Sopenharmony_ci { 153, 0x00002cd0, 0x00044736, 0x000ba255, 0x000c0a0b }, 26448c2ecf20Sopenharmony_ci { 157, 0x00002cd4, 0x0004490a, 0x000ba255, 0x000c0a17 }, 26458c2ecf20Sopenharmony_ci { 161, 0x00002cd4, 0x00044912, 0x000ba255, 0x000c0a17 }, 26468c2ecf20Sopenharmony_ci { 165, 0x00002cd4, 0x0004491a, 0x000ba255, 0x000c0a17 }, 26478c2ecf20Sopenharmony_ci 26488c2ecf20Sopenharmony_ci /* MMAC(Japan)J52 ch 34,38,42,46 */ 26498c2ecf20Sopenharmony_ci { 34, 0x00002ccc, 0x0000499a, 0x0009be55, 0x000c0a0b }, 26508c2ecf20Sopenharmony_ci { 38, 0x00002ccc, 0x0000499e, 0x0009be55, 0x000c0a13 }, 26518c2ecf20Sopenharmony_ci { 42, 0x00002ccc, 0x000049a2, 0x0009be55, 0x000c0a1b }, 26528c2ecf20Sopenharmony_ci { 46, 0x00002ccc, 0x000049a6, 0x0009be55, 0x000c0a23 }, 26538c2ecf20Sopenharmony_ci}; 26548c2ecf20Sopenharmony_ci 26558c2ecf20Sopenharmony_cistatic int rt61pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) 26568c2ecf20Sopenharmony_ci{ 26578c2ecf20Sopenharmony_ci struct hw_mode_spec *spec = &rt2x00dev->spec; 26588c2ecf20Sopenharmony_ci struct channel_info *info; 26598c2ecf20Sopenharmony_ci char *tx_power; 26608c2ecf20Sopenharmony_ci unsigned int i; 26618c2ecf20Sopenharmony_ci 26628c2ecf20Sopenharmony_ci /* 26638c2ecf20Sopenharmony_ci * Disable powersaving as default. 26648c2ecf20Sopenharmony_ci */ 26658c2ecf20Sopenharmony_ci rt2x00dev->hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; 26668c2ecf20Sopenharmony_ci 26678c2ecf20Sopenharmony_ci /* 26688c2ecf20Sopenharmony_ci * Initialize all hw fields. 26698c2ecf20Sopenharmony_ci */ 26708c2ecf20Sopenharmony_ci ieee80211_hw_set(rt2x00dev->hw, PS_NULLFUNC_STACK); 26718c2ecf20Sopenharmony_ci ieee80211_hw_set(rt2x00dev->hw, SUPPORTS_PS); 26728c2ecf20Sopenharmony_ci ieee80211_hw_set(rt2x00dev->hw, HOST_BROADCAST_PS_BUFFERING); 26738c2ecf20Sopenharmony_ci ieee80211_hw_set(rt2x00dev->hw, SIGNAL_DBM); 26748c2ecf20Sopenharmony_ci 26758c2ecf20Sopenharmony_ci SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev); 26768c2ecf20Sopenharmony_ci SET_IEEE80211_PERM_ADDR(rt2x00dev->hw, 26778c2ecf20Sopenharmony_ci rt2x00_eeprom_addr(rt2x00dev, 26788c2ecf20Sopenharmony_ci EEPROM_MAC_ADDR_0)); 26798c2ecf20Sopenharmony_ci 26808c2ecf20Sopenharmony_ci /* 26818c2ecf20Sopenharmony_ci * As rt61 has a global fallback table we cannot specify 26828c2ecf20Sopenharmony_ci * more then one tx rate per frame but since the hw will 26838c2ecf20Sopenharmony_ci * try several rates (based on the fallback table) we should 26848c2ecf20Sopenharmony_ci * initialize max_report_rates to the maximum number of rates 26858c2ecf20Sopenharmony_ci * we are going to try. Otherwise mac80211 will truncate our 26868c2ecf20Sopenharmony_ci * reported tx rates and the rc algortihm will end up with 26878c2ecf20Sopenharmony_ci * incorrect data. 26888c2ecf20Sopenharmony_ci */ 26898c2ecf20Sopenharmony_ci rt2x00dev->hw->max_rates = 1; 26908c2ecf20Sopenharmony_ci rt2x00dev->hw->max_report_rates = 7; 26918c2ecf20Sopenharmony_ci rt2x00dev->hw->max_rate_tries = 1; 26928c2ecf20Sopenharmony_ci 26938c2ecf20Sopenharmony_ci /* 26948c2ecf20Sopenharmony_ci * Initialize hw_mode information. 26958c2ecf20Sopenharmony_ci */ 26968c2ecf20Sopenharmony_ci spec->supported_bands = SUPPORT_BAND_2GHZ; 26978c2ecf20Sopenharmony_ci spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM; 26988c2ecf20Sopenharmony_ci 26998c2ecf20Sopenharmony_ci if (!rt2x00_has_cap_rf_sequence(rt2x00dev)) { 27008c2ecf20Sopenharmony_ci spec->num_channels = 14; 27018c2ecf20Sopenharmony_ci spec->channels = rf_vals_noseq; 27028c2ecf20Sopenharmony_ci } else { 27038c2ecf20Sopenharmony_ci spec->num_channels = 14; 27048c2ecf20Sopenharmony_ci spec->channels = rf_vals_seq; 27058c2ecf20Sopenharmony_ci } 27068c2ecf20Sopenharmony_ci 27078c2ecf20Sopenharmony_ci if (rt2x00_rf(rt2x00dev, RF5225) || rt2x00_rf(rt2x00dev, RF5325)) { 27088c2ecf20Sopenharmony_ci spec->supported_bands |= SUPPORT_BAND_5GHZ; 27098c2ecf20Sopenharmony_ci spec->num_channels = ARRAY_SIZE(rf_vals_seq); 27108c2ecf20Sopenharmony_ci } 27118c2ecf20Sopenharmony_ci 27128c2ecf20Sopenharmony_ci /* 27138c2ecf20Sopenharmony_ci * Create channel information array 27148c2ecf20Sopenharmony_ci */ 27158c2ecf20Sopenharmony_ci info = kcalloc(spec->num_channels, sizeof(*info), GFP_KERNEL); 27168c2ecf20Sopenharmony_ci if (!info) 27178c2ecf20Sopenharmony_ci return -ENOMEM; 27188c2ecf20Sopenharmony_ci 27198c2ecf20Sopenharmony_ci spec->channels_info = info; 27208c2ecf20Sopenharmony_ci 27218c2ecf20Sopenharmony_ci tx_power = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_G_START); 27228c2ecf20Sopenharmony_ci for (i = 0; i < 14; i++) { 27238c2ecf20Sopenharmony_ci info[i].max_power = MAX_TXPOWER; 27248c2ecf20Sopenharmony_ci info[i].default_power1 = TXPOWER_FROM_DEV(tx_power[i]); 27258c2ecf20Sopenharmony_ci } 27268c2ecf20Sopenharmony_ci 27278c2ecf20Sopenharmony_ci if (spec->num_channels > 14) { 27288c2ecf20Sopenharmony_ci tx_power = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A_START); 27298c2ecf20Sopenharmony_ci for (i = 14; i < spec->num_channels; i++) { 27308c2ecf20Sopenharmony_ci info[i].max_power = MAX_TXPOWER; 27318c2ecf20Sopenharmony_ci info[i].default_power1 = 27328c2ecf20Sopenharmony_ci TXPOWER_FROM_DEV(tx_power[i - 14]); 27338c2ecf20Sopenharmony_ci } 27348c2ecf20Sopenharmony_ci } 27358c2ecf20Sopenharmony_ci 27368c2ecf20Sopenharmony_ci return 0; 27378c2ecf20Sopenharmony_ci} 27388c2ecf20Sopenharmony_ci 27398c2ecf20Sopenharmony_cistatic int rt61pci_probe_hw(struct rt2x00_dev *rt2x00dev) 27408c2ecf20Sopenharmony_ci{ 27418c2ecf20Sopenharmony_ci int retval; 27428c2ecf20Sopenharmony_ci u32 reg; 27438c2ecf20Sopenharmony_ci 27448c2ecf20Sopenharmony_ci /* 27458c2ecf20Sopenharmony_ci * Disable power saving. 27468c2ecf20Sopenharmony_ci */ 27478c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, SOFT_RESET_CSR, 0x00000007); 27488c2ecf20Sopenharmony_ci 27498c2ecf20Sopenharmony_ci /* 27508c2ecf20Sopenharmony_ci * Allocate eeprom data. 27518c2ecf20Sopenharmony_ci */ 27528c2ecf20Sopenharmony_ci retval = rt61pci_validate_eeprom(rt2x00dev); 27538c2ecf20Sopenharmony_ci if (retval) 27548c2ecf20Sopenharmony_ci return retval; 27558c2ecf20Sopenharmony_ci 27568c2ecf20Sopenharmony_ci retval = rt61pci_init_eeprom(rt2x00dev); 27578c2ecf20Sopenharmony_ci if (retval) 27588c2ecf20Sopenharmony_ci return retval; 27598c2ecf20Sopenharmony_ci 27608c2ecf20Sopenharmony_ci /* 27618c2ecf20Sopenharmony_ci * Enable rfkill polling by setting GPIO direction of the 27628c2ecf20Sopenharmony_ci * rfkill switch GPIO pin correctly. 27638c2ecf20Sopenharmony_ci */ 27648c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, MAC_CSR13); 27658c2ecf20Sopenharmony_ci rt2x00_set_field32(®, MAC_CSR13_DIR5, 1); 27668c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, MAC_CSR13, reg); 27678c2ecf20Sopenharmony_ci 27688c2ecf20Sopenharmony_ci /* 27698c2ecf20Sopenharmony_ci * Initialize hw specifications. 27708c2ecf20Sopenharmony_ci */ 27718c2ecf20Sopenharmony_ci retval = rt61pci_probe_hw_mode(rt2x00dev); 27728c2ecf20Sopenharmony_ci if (retval) 27738c2ecf20Sopenharmony_ci return retval; 27748c2ecf20Sopenharmony_ci 27758c2ecf20Sopenharmony_ci /* 27768c2ecf20Sopenharmony_ci * This device has multiple filters for control frames, 27778c2ecf20Sopenharmony_ci * but has no a separate filter for PS Poll frames. 27788c2ecf20Sopenharmony_ci */ 27798c2ecf20Sopenharmony_ci __set_bit(CAPABILITY_CONTROL_FILTERS, &rt2x00dev->cap_flags); 27808c2ecf20Sopenharmony_ci 27818c2ecf20Sopenharmony_ci /* 27828c2ecf20Sopenharmony_ci * This device requires firmware and DMA mapped skbs. 27838c2ecf20Sopenharmony_ci */ 27848c2ecf20Sopenharmony_ci __set_bit(REQUIRE_FIRMWARE, &rt2x00dev->cap_flags); 27858c2ecf20Sopenharmony_ci __set_bit(REQUIRE_DMA, &rt2x00dev->cap_flags); 27868c2ecf20Sopenharmony_ci if (!modparam_nohwcrypt) 27878c2ecf20Sopenharmony_ci __set_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags); 27888c2ecf20Sopenharmony_ci __set_bit(CAPABILITY_LINK_TUNING, &rt2x00dev->cap_flags); 27898c2ecf20Sopenharmony_ci 27908c2ecf20Sopenharmony_ci /* 27918c2ecf20Sopenharmony_ci * Set the rssi offset. 27928c2ecf20Sopenharmony_ci */ 27938c2ecf20Sopenharmony_ci rt2x00dev->rssi_offset = DEFAULT_RSSI_OFFSET; 27948c2ecf20Sopenharmony_ci 27958c2ecf20Sopenharmony_ci return 0; 27968c2ecf20Sopenharmony_ci} 27978c2ecf20Sopenharmony_ci 27988c2ecf20Sopenharmony_ci/* 27998c2ecf20Sopenharmony_ci * IEEE80211 stack callback functions. 28008c2ecf20Sopenharmony_ci */ 28018c2ecf20Sopenharmony_cistatic int rt61pci_conf_tx(struct ieee80211_hw *hw, 28028c2ecf20Sopenharmony_ci struct ieee80211_vif *vif, u16 queue_idx, 28038c2ecf20Sopenharmony_ci const struct ieee80211_tx_queue_params *params) 28048c2ecf20Sopenharmony_ci{ 28058c2ecf20Sopenharmony_ci struct rt2x00_dev *rt2x00dev = hw->priv; 28068c2ecf20Sopenharmony_ci struct data_queue *queue; 28078c2ecf20Sopenharmony_ci struct rt2x00_field32 field; 28088c2ecf20Sopenharmony_ci int retval; 28098c2ecf20Sopenharmony_ci u32 reg; 28108c2ecf20Sopenharmony_ci u32 offset; 28118c2ecf20Sopenharmony_ci 28128c2ecf20Sopenharmony_ci /* 28138c2ecf20Sopenharmony_ci * First pass the configuration through rt2x00lib, that will 28148c2ecf20Sopenharmony_ci * update the queue settings and validate the input. After that 28158c2ecf20Sopenharmony_ci * we are free to update the registers based on the value 28168c2ecf20Sopenharmony_ci * in the queue parameter. 28178c2ecf20Sopenharmony_ci */ 28188c2ecf20Sopenharmony_ci retval = rt2x00mac_conf_tx(hw, vif, queue_idx, params); 28198c2ecf20Sopenharmony_ci if (retval) 28208c2ecf20Sopenharmony_ci return retval; 28218c2ecf20Sopenharmony_ci 28228c2ecf20Sopenharmony_ci /* 28238c2ecf20Sopenharmony_ci * We only need to perform additional register initialization 28248c2ecf20Sopenharmony_ci * for WMM queues. 28258c2ecf20Sopenharmony_ci */ 28268c2ecf20Sopenharmony_ci if (queue_idx >= 4) 28278c2ecf20Sopenharmony_ci return 0; 28288c2ecf20Sopenharmony_ci 28298c2ecf20Sopenharmony_ci queue = rt2x00queue_get_tx_queue(rt2x00dev, queue_idx); 28308c2ecf20Sopenharmony_ci 28318c2ecf20Sopenharmony_ci /* Update WMM TXOP register */ 28328c2ecf20Sopenharmony_ci offset = AC_TXOP_CSR0 + (sizeof(u32) * (!!(queue_idx & 2))); 28338c2ecf20Sopenharmony_ci field.bit_offset = (queue_idx & 1) * 16; 28348c2ecf20Sopenharmony_ci field.bit_mask = 0xffff << field.bit_offset; 28358c2ecf20Sopenharmony_ci 28368c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, offset); 28378c2ecf20Sopenharmony_ci rt2x00_set_field32(®, field, queue->txop); 28388c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, offset, reg); 28398c2ecf20Sopenharmony_ci 28408c2ecf20Sopenharmony_ci /* Update WMM registers */ 28418c2ecf20Sopenharmony_ci field.bit_offset = queue_idx * 4; 28428c2ecf20Sopenharmony_ci field.bit_mask = 0xf << field.bit_offset; 28438c2ecf20Sopenharmony_ci 28448c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, AIFSN_CSR); 28458c2ecf20Sopenharmony_ci rt2x00_set_field32(®, field, queue->aifs); 28468c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, AIFSN_CSR, reg); 28478c2ecf20Sopenharmony_ci 28488c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, CWMIN_CSR); 28498c2ecf20Sopenharmony_ci rt2x00_set_field32(®, field, queue->cw_min); 28508c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, CWMIN_CSR, reg); 28518c2ecf20Sopenharmony_ci 28528c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, CWMAX_CSR); 28538c2ecf20Sopenharmony_ci rt2x00_set_field32(®, field, queue->cw_max); 28548c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, CWMAX_CSR, reg); 28558c2ecf20Sopenharmony_ci 28568c2ecf20Sopenharmony_ci return 0; 28578c2ecf20Sopenharmony_ci} 28588c2ecf20Sopenharmony_ci 28598c2ecf20Sopenharmony_cistatic u64 rt61pci_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) 28608c2ecf20Sopenharmony_ci{ 28618c2ecf20Sopenharmony_ci struct rt2x00_dev *rt2x00dev = hw->priv; 28628c2ecf20Sopenharmony_ci u64 tsf; 28638c2ecf20Sopenharmony_ci u32 reg; 28648c2ecf20Sopenharmony_ci 28658c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR13); 28668c2ecf20Sopenharmony_ci tsf = (u64) rt2x00_get_field32(reg, TXRX_CSR13_HIGH_TSFTIMER) << 32; 28678c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR12); 28688c2ecf20Sopenharmony_ci tsf |= rt2x00_get_field32(reg, TXRX_CSR12_LOW_TSFTIMER); 28698c2ecf20Sopenharmony_ci 28708c2ecf20Sopenharmony_ci return tsf; 28718c2ecf20Sopenharmony_ci} 28728c2ecf20Sopenharmony_ci 28738c2ecf20Sopenharmony_cistatic const struct ieee80211_ops rt61pci_mac80211_ops = { 28748c2ecf20Sopenharmony_ci .tx = rt2x00mac_tx, 28758c2ecf20Sopenharmony_ci .start = rt2x00mac_start, 28768c2ecf20Sopenharmony_ci .stop = rt2x00mac_stop, 28778c2ecf20Sopenharmony_ci .add_interface = rt2x00mac_add_interface, 28788c2ecf20Sopenharmony_ci .remove_interface = rt2x00mac_remove_interface, 28798c2ecf20Sopenharmony_ci .config = rt2x00mac_config, 28808c2ecf20Sopenharmony_ci .configure_filter = rt2x00mac_configure_filter, 28818c2ecf20Sopenharmony_ci .set_key = rt2x00mac_set_key, 28828c2ecf20Sopenharmony_ci .sw_scan_start = rt2x00mac_sw_scan_start, 28838c2ecf20Sopenharmony_ci .sw_scan_complete = rt2x00mac_sw_scan_complete, 28848c2ecf20Sopenharmony_ci .get_stats = rt2x00mac_get_stats, 28858c2ecf20Sopenharmony_ci .bss_info_changed = rt2x00mac_bss_info_changed, 28868c2ecf20Sopenharmony_ci .conf_tx = rt61pci_conf_tx, 28878c2ecf20Sopenharmony_ci .get_tsf = rt61pci_get_tsf, 28888c2ecf20Sopenharmony_ci .rfkill_poll = rt2x00mac_rfkill_poll, 28898c2ecf20Sopenharmony_ci .flush = rt2x00mac_flush, 28908c2ecf20Sopenharmony_ci .set_antenna = rt2x00mac_set_antenna, 28918c2ecf20Sopenharmony_ci .get_antenna = rt2x00mac_get_antenna, 28928c2ecf20Sopenharmony_ci .get_ringparam = rt2x00mac_get_ringparam, 28938c2ecf20Sopenharmony_ci .tx_frames_pending = rt2x00mac_tx_frames_pending, 28948c2ecf20Sopenharmony_ci}; 28958c2ecf20Sopenharmony_ci 28968c2ecf20Sopenharmony_cistatic const struct rt2x00lib_ops rt61pci_rt2x00_ops = { 28978c2ecf20Sopenharmony_ci .irq_handler = rt61pci_interrupt, 28988c2ecf20Sopenharmony_ci .txstatus_tasklet = rt61pci_txstatus_tasklet, 28998c2ecf20Sopenharmony_ci .tbtt_tasklet = rt61pci_tbtt_tasklet, 29008c2ecf20Sopenharmony_ci .rxdone_tasklet = rt61pci_rxdone_tasklet, 29018c2ecf20Sopenharmony_ci .autowake_tasklet = rt61pci_autowake_tasklet, 29028c2ecf20Sopenharmony_ci .probe_hw = rt61pci_probe_hw, 29038c2ecf20Sopenharmony_ci .get_firmware_name = rt61pci_get_firmware_name, 29048c2ecf20Sopenharmony_ci .check_firmware = rt61pci_check_firmware, 29058c2ecf20Sopenharmony_ci .load_firmware = rt61pci_load_firmware, 29068c2ecf20Sopenharmony_ci .initialize = rt2x00mmio_initialize, 29078c2ecf20Sopenharmony_ci .uninitialize = rt2x00mmio_uninitialize, 29088c2ecf20Sopenharmony_ci .get_entry_state = rt61pci_get_entry_state, 29098c2ecf20Sopenharmony_ci .clear_entry = rt61pci_clear_entry, 29108c2ecf20Sopenharmony_ci .set_device_state = rt61pci_set_device_state, 29118c2ecf20Sopenharmony_ci .rfkill_poll = rt61pci_rfkill_poll, 29128c2ecf20Sopenharmony_ci .link_stats = rt61pci_link_stats, 29138c2ecf20Sopenharmony_ci .reset_tuner = rt61pci_reset_tuner, 29148c2ecf20Sopenharmony_ci .link_tuner = rt61pci_link_tuner, 29158c2ecf20Sopenharmony_ci .start_queue = rt61pci_start_queue, 29168c2ecf20Sopenharmony_ci .kick_queue = rt61pci_kick_queue, 29178c2ecf20Sopenharmony_ci .stop_queue = rt61pci_stop_queue, 29188c2ecf20Sopenharmony_ci .flush_queue = rt2x00mmio_flush_queue, 29198c2ecf20Sopenharmony_ci .write_tx_desc = rt61pci_write_tx_desc, 29208c2ecf20Sopenharmony_ci .write_beacon = rt61pci_write_beacon, 29218c2ecf20Sopenharmony_ci .clear_beacon = rt61pci_clear_beacon, 29228c2ecf20Sopenharmony_ci .fill_rxdone = rt61pci_fill_rxdone, 29238c2ecf20Sopenharmony_ci .config_shared_key = rt61pci_config_shared_key, 29248c2ecf20Sopenharmony_ci .config_pairwise_key = rt61pci_config_pairwise_key, 29258c2ecf20Sopenharmony_ci .config_filter = rt61pci_config_filter, 29268c2ecf20Sopenharmony_ci .config_intf = rt61pci_config_intf, 29278c2ecf20Sopenharmony_ci .config_erp = rt61pci_config_erp, 29288c2ecf20Sopenharmony_ci .config_ant = rt61pci_config_ant, 29298c2ecf20Sopenharmony_ci .config = rt61pci_config, 29308c2ecf20Sopenharmony_ci}; 29318c2ecf20Sopenharmony_ci 29328c2ecf20Sopenharmony_cistatic void rt61pci_queue_init(struct data_queue *queue) 29338c2ecf20Sopenharmony_ci{ 29348c2ecf20Sopenharmony_ci switch (queue->qid) { 29358c2ecf20Sopenharmony_ci case QID_RX: 29368c2ecf20Sopenharmony_ci queue->limit = 32; 29378c2ecf20Sopenharmony_ci queue->data_size = DATA_FRAME_SIZE; 29388c2ecf20Sopenharmony_ci queue->desc_size = RXD_DESC_SIZE; 29398c2ecf20Sopenharmony_ci queue->priv_size = sizeof(struct queue_entry_priv_mmio); 29408c2ecf20Sopenharmony_ci break; 29418c2ecf20Sopenharmony_ci 29428c2ecf20Sopenharmony_ci case QID_AC_VO: 29438c2ecf20Sopenharmony_ci case QID_AC_VI: 29448c2ecf20Sopenharmony_ci case QID_AC_BE: 29458c2ecf20Sopenharmony_ci case QID_AC_BK: 29468c2ecf20Sopenharmony_ci queue->limit = 32; 29478c2ecf20Sopenharmony_ci queue->data_size = DATA_FRAME_SIZE; 29488c2ecf20Sopenharmony_ci queue->desc_size = TXD_DESC_SIZE; 29498c2ecf20Sopenharmony_ci queue->priv_size = sizeof(struct queue_entry_priv_mmio); 29508c2ecf20Sopenharmony_ci break; 29518c2ecf20Sopenharmony_ci 29528c2ecf20Sopenharmony_ci case QID_BEACON: 29538c2ecf20Sopenharmony_ci queue->limit = 4; 29548c2ecf20Sopenharmony_ci queue->data_size = 0; /* No DMA required for beacons */ 29558c2ecf20Sopenharmony_ci queue->desc_size = TXINFO_SIZE; 29568c2ecf20Sopenharmony_ci queue->priv_size = sizeof(struct queue_entry_priv_mmio); 29578c2ecf20Sopenharmony_ci break; 29588c2ecf20Sopenharmony_ci 29598c2ecf20Sopenharmony_ci case QID_ATIM: 29608c2ecf20Sopenharmony_ci default: 29618c2ecf20Sopenharmony_ci BUG(); 29628c2ecf20Sopenharmony_ci break; 29638c2ecf20Sopenharmony_ci } 29648c2ecf20Sopenharmony_ci} 29658c2ecf20Sopenharmony_ci 29668c2ecf20Sopenharmony_cistatic const struct rt2x00_ops rt61pci_ops = { 29678c2ecf20Sopenharmony_ci .name = KBUILD_MODNAME, 29688c2ecf20Sopenharmony_ci .max_ap_intf = 4, 29698c2ecf20Sopenharmony_ci .eeprom_size = EEPROM_SIZE, 29708c2ecf20Sopenharmony_ci .rf_size = RF_SIZE, 29718c2ecf20Sopenharmony_ci .tx_queues = NUM_TX_QUEUES, 29728c2ecf20Sopenharmony_ci .queue_init = rt61pci_queue_init, 29738c2ecf20Sopenharmony_ci .lib = &rt61pci_rt2x00_ops, 29748c2ecf20Sopenharmony_ci .hw = &rt61pci_mac80211_ops, 29758c2ecf20Sopenharmony_ci#ifdef CONFIG_RT2X00_LIB_DEBUGFS 29768c2ecf20Sopenharmony_ci .debugfs = &rt61pci_rt2x00debug, 29778c2ecf20Sopenharmony_ci#endif /* CONFIG_RT2X00_LIB_DEBUGFS */ 29788c2ecf20Sopenharmony_ci}; 29798c2ecf20Sopenharmony_ci 29808c2ecf20Sopenharmony_ci/* 29818c2ecf20Sopenharmony_ci * RT61pci module information. 29828c2ecf20Sopenharmony_ci */ 29838c2ecf20Sopenharmony_cistatic const struct pci_device_id rt61pci_device_table[] = { 29848c2ecf20Sopenharmony_ci /* RT2561s */ 29858c2ecf20Sopenharmony_ci { PCI_DEVICE(0x1814, 0x0301) }, 29868c2ecf20Sopenharmony_ci /* RT2561 v2 */ 29878c2ecf20Sopenharmony_ci { PCI_DEVICE(0x1814, 0x0302) }, 29888c2ecf20Sopenharmony_ci /* RT2661 */ 29898c2ecf20Sopenharmony_ci { PCI_DEVICE(0x1814, 0x0401) }, 29908c2ecf20Sopenharmony_ci { 0, } 29918c2ecf20Sopenharmony_ci}; 29928c2ecf20Sopenharmony_ci 29938c2ecf20Sopenharmony_ciMODULE_AUTHOR(DRV_PROJECT); 29948c2ecf20Sopenharmony_ciMODULE_VERSION(DRV_VERSION); 29958c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Ralink RT61 PCI & PCMCIA Wireless LAN driver."); 29968c2ecf20Sopenharmony_ciMODULE_SUPPORTED_DEVICE("Ralink RT2561, RT2561s & RT2661 " 29978c2ecf20Sopenharmony_ci "PCI & PCMCIA chipset based cards"); 29988c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, rt61pci_device_table); 29998c2ecf20Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_RT2561); 30008c2ecf20Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_RT2561s); 30018c2ecf20Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_RT2661); 30028c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 30038c2ecf20Sopenharmony_ci 30048c2ecf20Sopenharmony_cistatic int rt61pci_probe(struct pci_dev *pci_dev, 30058c2ecf20Sopenharmony_ci const struct pci_device_id *id) 30068c2ecf20Sopenharmony_ci{ 30078c2ecf20Sopenharmony_ci return rt2x00pci_probe(pci_dev, &rt61pci_ops); 30088c2ecf20Sopenharmony_ci} 30098c2ecf20Sopenharmony_ci 30108c2ecf20Sopenharmony_cistatic struct pci_driver rt61pci_driver = { 30118c2ecf20Sopenharmony_ci .name = KBUILD_MODNAME, 30128c2ecf20Sopenharmony_ci .id_table = rt61pci_device_table, 30138c2ecf20Sopenharmony_ci .probe = rt61pci_probe, 30148c2ecf20Sopenharmony_ci .remove = rt2x00pci_remove, 30158c2ecf20Sopenharmony_ci .driver.pm = &rt2x00pci_pm_ops, 30168c2ecf20Sopenharmony_ci}; 30178c2ecf20Sopenharmony_ci 30188c2ecf20Sopenharmony_cimodule_pci_driver(rt61pci_driver); 3019