162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci	Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
462306a36Sopenharmony_ci	<http://rt2x00.serialmonkey.com>
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci/*
962306a36Sopenharmony_ci	Module: rt61pci
1062306a36Sopenharmony_ci	Abstract: rt61pci device specific routines.
1162306a36Sopenharmony_ci	Supported chipsets: RT2561, RT2561s, RT2661.
1262306a36Sopenharmony_ci */
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#include <linux/crc-itu-t.h>
1562306a36Sopenharmony_ci#include <linux/delay.h>
1662306a36Sopenharmony_ci#include <linux/etherdevice.h>
1762306a36Sopenharmony_ci#include <linux/kernel.h>
1862306a36Sopenharmony_ci#include <linux/module.h>
1962306a36Sopenharmony_ci#include <linux/slab.h>
2062306a36Sopenharmony_ci#include <linux/pci.h>
2162306a36Sopenharmony_ci#include <linux/eeprom_93cx6.h>
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#include "rt2x00.h"
2462306a36Sopenharmony_ci#include "rt2x00mmio.h"
2562306a36Sopenharmony_ci#include "rt2x00pci.h"
2662306a36Sopenharmony_ci#include "rt61pci.h"
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci/*
2962306a36Sopenharmony_ci * Allow hardware encryption to be disabled.
3062306a36Sopenharmony_ci */
3162306a36Sopenharmony_cistatic bool modparam_nohwcrypt = false;
3262306a36Sopenharmony_cimodule_param_named(nohwcrypt, modparam_nohwcrypt, bool, 0444);
3362306a36Sopenharmony_ciMODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci/*
3662306a36Sopenharmony_ci * Register access.
3762306a36Sopenharmony_ci * BBP and RF register require indirect register access,
3862306a36Sopenharmony_ci * and use the CSR registers PHY_CSR3 and PHY_CSR4 to achieve this.
3962306a36Sopenharmony_ci * These indirect registers work with busy bits,
4062306a36Sopenharmony_ci * and we will try maximal REGISTER_BUSY_COUNT times to access
4162306a36Sopenharmony_ci * the register while taking a REGISTER_BUSY_DELAY us delay
4262306a36Sopenharmony_ci * between each attempt. When the busy bit is still set at that time,
4362306a36Sopenharmony_ci * the access attempt is considered to have failed,
4462306a36Sopenharmony_ci * and we will print an error.
4562306a36Sopenharmony_ci */
4662306a36Sopenharmony_ci#define WAIT_FOR_BBP(__dev, __reg) \
4762306a36Sopenharmony_ci	rt2x00mmio_regbusy_read((__dev), PHY_CSR3, PHY_CSR3_BUSY, (__reg))
4862306a36Sopenharmony_ci#define WAIT_FOR_RF(__dev, __reg) \
4962306a36Sopenharmony_ci	rt2x00mmio_regbusy_read((__dev), PHY_CSR4, PHY_CSR4_BUSY, (__reg))
5062306a36Sopenharmony_ci#define WAIT_FOR_MCU(__dev, __reg) \
5162306a36Sopenharmony_ci	rt2x00mmio_regbusy_read((__dev), H2M_MAILBOX_CSR, \
5262306a36Sopenharmony_ci				H2M_MAILBOX_CSR_OWNER, (__reg))
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_cistatic void rt61pci_bbp_write(struct rt2x00_dev *rt2x00dev,
5562306a36Sopenharmony_ci			      const unsigned int word, const u8 value)
5662306a36Sopenharmony_ci{
5762306a36Sopenharmony_ci	u32 reg;
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	mutex_lock(&rt2x00dev->csr_mutex);
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci	/*
6262306a36Sopenharmony_ci	 * Wait until the BBP becomes available, afterwards we
6362306a36Sopenharmony_ci	 * can safely write the new data into the register.
6462306a36Sopenharmony_ci	 */
6562306a36Sopenharmony_ci	if (WAIT_FOR_BBP(rt2x00dev, &reg)) {
6662306a36Sopenharmony_ci		reg = 0;
6762306a36Sopenharmony_ci		rt2x00_set_field32(&reg, PHY_CSR3_VALUE, value);
6862306a36Sopenharmony_ci		rt2x00_set_field32(&reg, PHY_CSR3_REGNUM, word);
6962306a36Sopenharmony_ci		rt2x00_set_field32(&reg, PHY_CSR3_BUSY, 1);
7062306a36Sopenharmony_ci		rt2x00_set_field32(&reg, PHY_CSR3_READ_CONTROL, 0);
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci		rt2x00mmio_register_write(rt2x00dev, PHY_CSR3, reg);
7362306a36Sopenharmony_ci	}
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	mutex_unlock(&rt2x00dev->csr_mutex);
7662306a36Sopenharmony_ci}
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_cistatic u8 rt61pci_bbp_read(struct rt2x00_dev *rt2x00dev,
7962306a36Sopenharmony_ci			   const unsigned int word)
8062306a36Sopenharmony_ci{
8162306a36Sopenharmony_ci	u32 reg;
8262306a36Sopenharmony_ci	u8 value;
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	mutex_lock(&rt2x00dev->csr_mutex);
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	/*
8762306a36Sopenharmony_ci	 * Wait until the BBP becomes available, afterwards we
8862306a36Sopenharmony_ci	 * can safely write the read request into the register.
8962306a36Sopenharmony_ci	 * After the data has been written, we wait until hardware
9062306a36Sopenharmony_ci	 * returns the correct value, if at any time the register
9162306a36Sopenharmony_ci	 * doesn't become available in time, reg will be 0xffffffff
9262306a36Sopenharmony_ci	 * which means we return 0xff to the caller.
9362306a36Sopenharmony_ci	 */
9462306a36Sopenharmony_ci	if (WAIT_FOR_BBP(rt2x00dev, &reg)) {
9562306a36Sopenharmony_ci		reg = 0;
9662306a36Sopenharmony_ci		rt2x00_set_field32(&reg, PHY_CSR3_REGNUM, word);
9762306a36Sopenharmony_ci		rt2x00_set_field32(&reg, PHY_CSR3_BUSY, 1);
9862306a36Sopenharmony_ci		rt2x00_set_field32(&reg, PHY_CSR3_READ_CONTROL, 1);
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci		rt2x00mmio_register_write(rt2x00dev, PHY_CSR3, reg);
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci		WAIT_FOR_BBP(rt2x00dev, &reg);
10362306a36Sopenharmony_ci	}
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	value = rt2x00_get_field32(reg, PHY_CSR3_VALUE);
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	mutex_unlock(&rt2x00dev->csr_mutex);
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	return value;
11062306a36Sopenharmony_ci}
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_cistatic void rt61pci_rf_write(struct rt2x00_dev *rt2x00dev,
11362306a36Sopenharmony_ci			     const unsigned int word, const u32 value)
11462306a36Sopenharmony_ci{
11562306a36Sopenharmony_ci	u32 reg;
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci	mutex_lock(&rt2x00dev->csr_mutex);
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	/*
12062306a36Sopenharmony_ci	 * Wait until the RF becomes available, afterwards we
12162306a36Sopenharmony_ci	 * can safely write the new data into the register.
12262306a36Sopenharmony_ci	 */
12362306a36Sopenharmony_ci	if (WAIT_FOR_RF(rt2x00dev, &reg)) {
12462306a36Sopenharmony_ci		reg = 0;
12562306a36Sopenharmony_ci		rt2x00_set_field32(&reg, PHY_CSR4_VALUE, value);
12662306a36Sopenharmony_ci		rt2x00_set_field32(&reg, PHY_CSR4_NUMBER_OF_BITS, 21);
12762306a36Sopenharmony_ci		rt2x00_set_field32(&reg, PHY_CSR4_IF_SELECT, 0);
12862306a36Sopenharmony_ci		rt2x00_set_field32(&reg, PHY_CSR4_BUSY, 1);
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci		rt2x00mmio_register_write(rt2x00dev, PHY_CSR4, reg);
13162306a36Sopenharmony_ci		rt2x00_rf_write(rt2x00dev, word, value);
13262306a36Sopenharmony_ci	}
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	mutex_unlock(&rt2x00dev->csr_mutex);
13562306a36Sopenharmony_ci}
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_cistatic void rt61pci_mcu_request(struct rt2x00_dev *rt2x00dev,
13862306a36Sopenharmony_ci				const u8 command, const u8 token,
13962306a36Sopenharmony_ci				const u8 arg0, const u8 arg1)
14062306a36Sopenharmony_ci{
14162306a36Sopenharmony_ci	u32 reg;
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	mutex_lock(&rt2x00dev->csr_mutex);
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	/*
14662306a36Sopenharmony_ci	 * Wait until the MCU becomes available, afterwards we
14762306a36Sopenharmony_ci	 * can safely write the new data into the register.
14862306a36Sopenharmony_ci	 */
14962306a36Sopenharmony_ci	if (WAIT_FOR_MCU(rt2x00dev, &reg)) {
15062306a36Sopenharmony_ci		rt2x00_set_field32(&reg, H2M_MAILBOX_CSR_OWNER, 1);
15162306a36Sopenharmony_ci		rt2x00_set_field32(&reg, H2M_MAILBOX_CSR_CMD_TOKEN, token);
15262306a36Sopenharmony_ci		rt2x00_set_field32(&reg, H2M_MAILBOX_CSR_ARG0, arg0);
15362306a36Sopenharmony_ci		rt2x00_set_field32(&reg, H2M_MAILBOX_CSR_ARG1, arg1);
15462306a36Sopenharmony_ci		rt2x00mmio_register_write(rt2x00dev, H2M_MAILBOX_CSR, reg);
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci		reg = rt2x00mmio_register_read(rt2x00dev, HOST_CMD_CSR);
15762306a36Sopenharmony_ci		rt2x00_set_field32(&reg, HOST_CMD_CSR_HOST_COMMAND, command);
15862306a36Sopenharmony_ci		rt2x00_set_field32(&reg, HOST_CMD_CSR_INTERRUPT_MCU, 1);
15962306a36Sopenharmony_ci		rt2x00mmio_register_write(rt2x00dev, HOST_CMD_CSR, reg);
16062306a36Sopenharmony_ci	}
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	mutex_unlock(&rt2x00dev->csr_mutex);
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci}
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_cistatic void rt61pci_eepromregister_read(struct eeprom_93cx6 *eeprom)
16762306a36Sopenharmony_ci{
16862306a36Sopenharmony_ci	struct rt2x00_dev *rt2x00dev = eeprom->data;
16962306a36Sopenharmony_ci	u32 reg;
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	reg = rt2x00mmio_register_read(rt2x00dev, E2PROM_CSR);
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	eeprom->reg_data_in = !!rt2x00_get_field32(reg, E2PROM_CSR_DATA_IN);
17462306a36Sopenharmony_ci	eeprom->reg_data_out = !!rt2x00_get_field32(reg, E2PROM_CSR_DATA_OUT);
17562306a36Sopenharmony_ci	eeprom->reg_data_clock =
17662306a36Sopenharmony_ci	    !!rt2x00_get_field32(reg, E2PROM_CSR_DATA_CLOCK);
17762306a36Sopenharmony_ci	eeprom->reg_chip_select =
17862306a36Sopenharmony_ci	    !!rt2x00_get_field32(reg, E2PROM_CSR_CHIP_SELECT);
17962306a36Sopenharmony_ci}
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_cistatic void rt61pci_eepromregister_write(struct eeprom_93cx6 *eeprom)
18262306a36Sopenharmony_ci{
18362306a36Sopenharmony_ci	struct rt2x00_dev *rt2x00dev = eeprom->data;
18462306a36Sopenharmony_ci	u32 reg = 0;
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	rt2x00_set_field32(&reg, E2PROM_CSR_DATA_IN, !!eeprom->reg_data_in);
18762306a36Sopenharmony_ci	rt2x00_set_field32(&reg, E2PROM_CSR_DATA_OUT, !!eeprom->reg_data_out);
18862306a36Sopenharmony_ci	rt2x00_set_field32(&reg, E2PROM_CSR_DATA_CLOCK,
18962306a36Sopenharmony_ci			   !!eeprom->reg_data_clock);
19062306a36Sopenharmony_ci	rt2x00_set_field32(&reg, E2PROM_CSR_CHIP_SELECT,
19162306a36Sopenharmony_ci			   !!eeprom->reg_chip_select);
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	rt2x00mmio_register_write(rt2x00dev, E2PROM_CSR, reg);
19462306a36Sopenharmony_ci}
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci#ifdef CONFIG_RT2X00_LIB_DEBUGFS
19762306a36Sopenharmony_cistatic const struct rt2x00debug rt61pci_rt2x00debug = {
19862306a36Sopenharmony_ci	.owner	= THIS_MODULE,
19962306a36Sopenharmony_ci	.csr	= {
20062306a36Sopenharmony_ci		.read		= rt2x00mmio_register_read,
20162306a36Sopenharmony_ci		.write		= rt2x00mmio_register_write,
20262306a36Sopenharmony_ci		.flags		= RT2X00DEBUGFS_OFFSET,
20362306a36Sopenharmony_ci		.word_base	= CSR_REG_BASE,
20462306a36Sopenharmony_ci		.word_size	= sizeof(u32),
20562306a36Sopenharmony_ci		.word_count	= CSR_REG_SIZE / sizeof(u32),
20662306a36Sopenharmony_ci	},
20762306a36Sopenharmony_ci	.eeprom	= {
20862306a36Sopenharmony_ci		.read		= rt2x00_eeprom_read,
20962306a36Sopenharmony_ci		.write		= rt2x00_eeprom_write,
21062306a36Sopenharmony_ci		.word_base	= EEPROM_BASE,
21162306a36Sopenharmony_ci		.word_size	= sizeof(u16),
21262306a36Sopenharmony_ci		.word_count	= EEPROM_SIZE / sizeof(u16),
21362306a36Sopenharmony_ci	},
21462306a36Sopenharmony_ci	.bbp	= {
21562306a36Sopenharmony_ci		.read		= rt61pci_bbp_read,
21662306a36Sopenharmony_ci		.write		= rt61pci_bbp_write,
21762306a36Sopenharmony_ci		.word_base	= BBP_BASE,
21862306a36Sopenharmony_ci		.word_size	= sizeof(u8),
21962306a36Sopenharmony_ci		.word_count	= BBP_SIZE / sizeof(u8),
22062306a36Sopenharmony_ci	},
22162306a36Sopenharmony_ci	.rf	= {
22262306a36Sopenharmony_ci		.read		= rt2x00_rf_read,
22362306a36Sopenharmony_ci		.write		= rt61pci_rf_write,
22462306a36Sopenharmony_ci		.word_base	= RF_BASE,
22562306a36Sopenharmony_ci		.word_size	= sizeof(u32),
22662306a36Sopenharmony_ci		.word_count	= RF_SIZE / sizeof(u32),
22762306a36Sopenharmony_ci	},
22862306a36Sopenharmony_ci};
22962306a36Sopenharmony_ci#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_cistatic int rt61pci_rfkill_poll(struct rt2x00_dev *rt2x00dev)
23262306a36Sopenharmony_ci{
23362306a36Sopenharmony_ci	u32 reg;
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci	reg = rt2x00mmio_register_read(rt2x00dev, MAC_CSR13);
23662306a36Sopenharmony_ci	return rt2x00_get_field32(reg, MAC_CSR13_VAL5);
23762306a36Sopenharmony_ci}
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci#ifdef CONFIG_RT2X00_LIB_LEDS
24062306a36Sopenharmony_cistatic void rt61pci_brightness_set(struct led_classdev *led_cdev,
24162306a36Sopenharmony_ci				   enum led_brightness brightness)
24262306a36Sopenharmony_ci{
24362306a36Sopenharmony_ci	struct rt2x00_led *led =
24462306a36Sopenharmony_ci	    container_of(led_cdev, struct rt2x00_led, led_dev);
24562306a36Sopenharmony_ci	unsigned int enabled = brightness != LED_OFF;
24662306a36Sopenharmony_ci	unsigned int a_mode =
24762306a36Sopenharmony_ci	    (enabled && led->rt2x00dev->curr_band == NL80211_BAND_5GHZ);
24862306a36Sopenharmony_ci	unsigned int bg_mode =
24962306a36Sopenharmony_ci	    (enabled && led->rt2x00dev->curr_band == NL80211_BAND_2GHZ);
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	if (led->type == LED_TYPE_RADIO) {
25262306a36Sopenharmony_ci		rt2x00_set_field16(&led->rt2x00dev->led_mcu_reg,
25362306a36Sopenharmony_ci				   MCU_LEDCS_RADIO_STATUS, enabled);
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci		rt61pci_mcu_request(led->rt2x00dev, MCU_LED, 0xff,
25662306a36Sopenharmony_ci				    (led->rt2x00dev->led_mcu_reg & 0xff),
25762306a36Sopenharmony_ci				    ((led->rt2x00dev->led_mcu_reg >> 8)));
25862306a36Sopenharmony_ci	} else if (led->type == LED_TYPE_ASSOC) {
25962306a36Sopenharmony_ci		rt2x00_set_field16(&led->rt2x00dev->led_mcu_reg,
26062306a36Sopenharmony_ci				   MCU_LEDCS_LINK_BG_STATUS, bg_mode);
26162306a36Sopenharmony_ci		rt2x00_set_field16(&led->rt2x00dev->led_mcu_reg,
26262306a36Sopenharmony_ci				   MCU_LEDCS_LINK_A_STATUS, a_mode);
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci		rt61pci_mcu_request(led->rt2x00dev, MCU_LED, 0xff,
26562306a36Sopenharmony_ci				    (led->rt2x00dev->led_mcu_reg & 0xff),
26662306a36Sopenharmony_ci				    ((led->rt2x00dev->led_mcu_reg >> 8)));
26762306a36Sopenharmony_ci	} else if (led->type == LED_TYPE_QUALITY) {
26862306a36Sopenharmony_ci		/*
26962306a36Sopenharmony_ci		 * The brightness is divided into 6 levels (0 - 5),
27062306a36Sopenharmony_ci		 * this means we need to convert the brightness
27162306a36Sopenharmony_ci		 * argument into the matching level within that range.
27262306a36Sopenharmony_ci		 */
27362306a36Sopenharmony_ci		rt61pci_mcu_request(led->rt2x00dev, MCU_LED_STRENGTH, 0xff,
27462306a36Sopenharmony_ci				    brightness / (LED_FULL / 6), 0);
27562306a36Sopenharmony_ci	}
27662306a36Sopenharmony_ci}
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_cistatic int rt61pci_blink_set(struct led_classdev *led_cdev,
27962306a36Sopenharmony_ci			     unsigned long *delay_on,
28062306a36Sopenharmony_ci			     unsigned long *delay_off)
28162306a36Sopenharmony_ci{
28262306a36Sopenharmony_ci	struct rt2x00_led *led =
28362306a36Sopenharmony_ci	    container_of(led_cdev, struct rt2x00_led, led_dev);
28462306a36Sopenharmony_ci	u32 reg;
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci	reg = rt2x00mmio_register_read(led->rt2x00dev, MAC_CSR14);
28762306a36Sopenharmony_ci	rt2x00_set_field32(&reg, MAC_CSR14_ON_PERIOD, *delay_on);
28862306a36Sopenharmony_ci	rt2x00_set_field32(&reg, MAC_CSR14_OFF_PERIOD, *delay_off);
28962306a36Sopenharmony_ci	rt2x00mmio_register_write(led->rt2x00dev, MAC_CSR14, reg);
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	return 0;
29262306a36Sopenharmony_ci}
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_cistatic void rt61pci_init_led(struct rt2x00_dev *rt2x00dev,
29562306a36Sopenharmony_ci			     struct rt2x00_led *led,
29662306a36Sopenharmony_ci			     enum led_type type)
29762306a36Sopenharmony_ci{
29862306a36Sopenharmony_ci	led->rt2x00dev = rt2x00dev;
29962306a36Sopenharmony_ci	led->type = type;
30062306a36Sopenharmony_ci	led->led_dev.brightness_set = rt61pci_brightness_set;
30162306a36Sopenharmony_ci	led->led_dev.blink_set = rt61pci_blink_set;
30262306a36Sopenharmony_ci	led->flags = LED_INITIALIZED;
30362306a36Sopenharmony_ci}
30462306a36Sopenharmony_ci#endif /* CONFIG_RT2X00_LIB_LEDS */
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci/*
30762306a36Sopenharmony_ci * Configuration handlers.
30862306a36Sopenharmony_ci */
30962306a36Sopenharmony_cistatic int rt61pci_config_shared_key(struct rt2x00_dev *rt2x00dev,
31062306a36Sopenharmony_ci				     struct rt2x00lib_crypto *crypto,
31162306a36Sopenharmony_ci				     struct ieee80211_key_conf *key)
31262306a36Sopenharmony_ci{
31362306a36Sopenharmony_ci	/*
31462306a36Sopenharmony_ci	 * Let the software handle the shared keys,
31562306a36Sopenharmony_ci	 * since the hardware decryption does not work reliably,
31662306a36Sopenharmony_ci	 * because the firmware does not know the key's keyidx.
31762306a36Sopenharmony_ci	 */
31862306a36Sopenharmony_ci	return -EOPNOTSUPP;
31962306a36Sopenharmony_ci}
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_cistatic int rt61pci_config_pairwise_key(struct rt2x00_dev *rt2x00dev,
32262306a36Sopenharmony_ci				       struct rt2x00lib_crypto *crypto,
32362306a36Sopenharmony_ci				       struct ieee80211_key_conf *key)
32462306a36Sopenharmony_ci{
32562306a36Sopenharmony_ci	struct hw_pairwise_ta_entry addr_entry;
32662306a36Sopenharmony_ci	struct hw_key_entry key_entry;
32762306a36Sopenharmony_ci	u32 mask;
32862306a36Sopenharmony_ci	u32 reg;
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	if (crypto->cmd == SET_KEY) {
33162306a36Sopenharmony_ci		/*
33262306a36Sopenharmony_ci		 * rt2x00lib can't determine the correct free
33362306a36Sopenharmony_ci		 * key_idx for pairwise keys. We have 2 registers
33462306a36Sopenharmony_ci		 * with key valid bits. The goal is simple: read
33562306a36Sopenharmony_ci		 * the first register. If that is full, move to
33662306a36Sopenharmony_ci		 * the next register.
33762306a36Sopenharmony_ci		 * When both registers are full, we drop the key.
33862306a36Sopenharmony_ci		 * Otherwise, we use the first invalid entry.
33962306a36Sopenharmony_ci		 */
34062306a36Sopenharmony_ci		reg = rt2x00mmio_register_read(rt2x00dev, SEC_CSR2);
34162306a36Sopenharmony_ci		if (reg && reg == ~0) {
34262306a36Sopenharmony_ci			key->hw_key_idx = 32;
34362306a36Sopenharmony_ci			reg = rt2x00mmio_register_read(rt2x00dev, SEC_CSR3);
34462306a36Sopenharmony_ci			if (reg && reg == ~0)
34562306a36Sopenharmony_ci				return -ENOSPC;
34662306a36Sopenharmony_ci		}
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci		key->hw_key_idx += reg ? ffz(reg) : 0;
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci		/*
35162306a36Sopenharmony_ci		 * Upload key to hardware
35262306a36Sopenharmony_ci		 */
35362306a36Sopenharmony_ci		memcpy(key_entry.key, crypto->key,
35462306a36Sopenharmony_ci		       sizeof(key_entry.key));
35562306a36Sopenharmony_ci		memcpy(key_entry.tx_mic, crypto->tx_mic,
35662306a36Sopenharmony_ci		       sizeof(key_entry.tx_mic));
35762306a36Sopenharmony_ci		memcpy(key_entry.rx_mic, crypto->rx_mic,
35862306a36Sopenharmony_ci		       sizeof(key_entry.rx_mic));
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci		memset(&addr_entry, 0, sizeof(addr_entry));
36162306a36Sopenharmony_ci		memcpy(&addr_entry, crypto->address, ETH_ALEN);
36262306a36Sopenharmony_ci		addr_entry.cipher = crypto->cipher;
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci		reg = PAIRWISE_KEY_ENTRY(key->hw_key_idx);
36562306a36Sopenharmony_ci		rt2x00mmio_register_multiwrite(rt2x00dev, reg,
36662306a36Sopenharmony_ci					       &key_entry, sizeof(key_entry));
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci		reg = PAIRWISE_TA_ENTRY(key->hw_key_idx);
36962306a36Sopenharmony_ci		rt2x00mmio_register_multiwrite(rt2x00dev, reg,
37062306a36Sopenharmony_ci					       &addr_entry, sizeof(addr_entry));
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci		/*
37362306a36Sopenharmony_ci		 * Enable pairwise lookup table for given BSS idx.
37462306a36Sopenharmony_ci		 * Without this, received frames will not be decrypted
37562306a36Sopenharmony_ci		 * by the hardware.
37662306a36Sopenharmony_ci		 */
37762306a36Sopenharmony_ci		reg = rt2x00mmio_register_read(rt2x00dev, SEC_CSR4);
37862306a36Sopenharmony_ci		reg |= (1 << crypto->bssidx);
37962306a36Sopenharmony_ci		rt2x00mmio_register_write(rt2x00dev, SEC_CSR4, reg);
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci		/*
38262306a36Sopenharmony_ci		 * The driver does not support the IV/EIV generation
38362306a36Sopenharmony_ci		 * in hardware. However it doesn't support the IV/EIV
38462306a36Sopenharmony_ci		 * inside the ieee80211 frame either, but requires it
38562306a36Sopenharmony_ci		 * to be provided separately for the descriptor.
38662306a36Sopenharmony_ci		 * rt2x00lib will cut the IV/EIV data out of all frames
38762306a36Sopenharmony_ci		 * given to us by mac80211, but we must tell mac80211
38862306a36Sopenharmony_ci		 * to generate the IV/EIV data.
38962306a36Sopenharmony_ci		 */
39062306a36Sopenharmony_ci		key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
39162306a36Sopenharmony_ci	}
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci	/*
39462306a36Sopenharmony_ci	 * SEC_CSR2 and SEC_CSR3 contain only single-bit fields to indicate
39562306a36Sopenharmony_ci	 * a particular key is valid. Because using the FIELD32()
39662306a36Sopenharmony_ci	 * defines directly will cause a lot of overhead, we use
39762306a36Sopenharmony_ci	 * a calculation to determine the correct bit directly.
39862306a36Sopenharmony_ci	 */
39962306a36Sopenharmony_ci	if (key->hw_key_idx < 32) {
40062306a36Sopenharmony_ci		mask = 1 << key->hw_key_idx;
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci		reg = rt2x00mmio_register_read(rt2x00dev, SEC_CSR2);
40362306a36Sopenharmony_ci		if (crypto->cmd == SET_KEY)
40462306a36Sopenharmony_ci			reg |= mask;
40562306a36Sopenharmony_ci		else if (crypto->cmd == DISABLE_KEY)
40662306a36Sopenharmony_ci			reg &= ~mask;
40762306a36Sopenharmony_ci		rt2x00mmio_register_write(rt2x00dev, SEC_CSR2, reg);
40862306a36Sopenharmony_ci	} else {
40962306a36Sopenharmony_ci		mask = 1 << (key->hw_key_idx - 32);
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci		reg = rt2x00mmio_register_read(rt2x00dev, SEC_CSR3);
41262306a36Sopenharmony_ci		if (crypto->cmd == SET_KEY)
41362306a36Sopenharmony_ci			reg |= mask;
41462306a36Sopenharmony_ci		else if (crypto->cmd == DISABLE_KEY)
41562306a36Sopenharmony_ci			reg &= ~mask;
41662306a36Sopenharmony_ci		rt2x00mmio_register_write(rt2x00dev, SEC_CSR3, reg);
41762306a36Sopenharmony_ci	}
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci	return 0;
42062306a36Sopenharmony_ci}
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_cistatic void rt61pci_config_filter(struct rt2x00_dev *rt2x00dev,
42362306a36Sopenharmony_ci				  const unsigned int filter_flags)
42462306a36Sopenharmony_ci{
42562306a36Sopenharmony_ci	u32 reg;
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	/*
42862306a36Sopenharmony_ci	 * Start configuration steps.
42962306a36Sopenharmony_ci	 * Note that the version error will always be dropped
43062306a36Sopenharmony_ci	 * and broadcast frames will always be accepted since
43162306a36Sopenharmony_ci	 * there is no filter for it at this time.
43262306a36Sopenharmony_ci	 */
43362306a36Sopenharmony_ci	reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR0);
43462306a36Sopenharmony_ci	rt2x00_set_field32(&reg, TXRX_CSR0_DROP_CRC,
43562306a36Sopenharmony_ci			   !(filter_flags & FIF_FCSFAIL));
43662306a36Sopenharmony_ci	rt2x00_set_field32(&reg, TXRX_CSR0_DROP_PHYSICAL,
43762306a36Sopenharmony_ci			   !(filter_flags & FIF_PLCPFAIL));
43862306a36Sopenharmony_ci	rt2x00_set_field32(&reg, TXRX_CSR0_DROP_CONTROL,
43962306a36Sopenharmony_ci			   !(filter_flags & (FIF_CONTROL | FIF_PSPOLL)));
44062306a36Sopenharmony_ci	rt2x00_set_field32(&reg, TXRX_CSR0_DROP_NOT_TO_ME,
44162306a36Sopenharmony_ci			   !test_bit(CONFIG_MONITORING, &rt2x00dev->flags));
44262306a36Sopenharmony_ci	rt2x00_set_field32(&reg, TXRX_CSR0_DROP_TO_DS,
44362306a36Sopenharmony_ci			   !test_bit(CONFIG_MONITORING, &rt2x00dev->flags) &&
44462306a36Sopenharmony_ci			   !rt2x00dev->intf_ap_count);
44562306a36Sopenharmony_ci	rt2x00_set_field32(&reg, TXRX_CSR0_DROP_VERSION_ERROR, 1);
44662306a36Sopenharmony_ci	rt2x00_set_field32(&reg, TXRX_CSR0_DROP_MULTICAST,
44762306a36Sopenharmony_ci			   !(filter_flags & FIF_ALLMULTI));
44862306a36Sopenharmony_ci	rt2x00_set_field32(&reg, TXRX_CSR0_DROP_BROADCAST, 0);
44962306a36Sopenharmony_ci	rt2x00_set_field32(&reg, TXRX_CSR0_DROP_ACK_CTS,
45062306a36Sopenharmony_ci			   !(filter_flags & FIF_CONTROL));
45162306a36Sopenharmony_ci	rt2x00mmio_register_write(rt2x00dev, TXRX_CSR0, reg);
45262306a36Sopenharmony_ci}
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_cistatic void rt61pci_config_intf(struct rt2x00_dev *rt2x00dev,
45562306a36Sopenharmony_ci				struct rt2x00_intf *intf,
45662306a36Sopenharmony_ci				struct rt2x00intf_conf *conf,
45762306a36Sopenharmony_ci				const unsigned int flags)
45862306a36Sopenharmony_ci{
45962306a36Sopenharmony_ci	u32 reg;
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci	if (flags & CONFIG_UPDATE_TYPE) {
46262306a36Sopenharmony_ci		/*
46362306a36Sopenharmony_ci		 * Enable synchronisation.
46462306a36Sopenharmony_ci		 */
46562306a36Sopenharmony_ci		reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR9);
46662306a36Sopenharmony_ci		rt2x00_set_field32(&reg, TXRX_CSR9_TSF_SYNC, conf->sync);
46762306a36Sopenharmony_ci		rt2x00mmio_register_write(rt2x00dev, TXRX_CSR9, reg);
46862306a36Sopenharmony_ci	}
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci	if (flags & CONFIG_UPDATE_MAC) {
47162306a36Sopenharmony_ci		reg = le32_to_cpu(conf->mac[1]);
47262306a36Sopenharmony_ci		rt2x00_set_field32(&reg, MAC_CSR3_UNICAST_TO_ME_MASK, 0xff);
47362306a36Sopenharmony_ci		conf->mac[1] = cpu_to_le32(reg);
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci		rt2x00mmio_register_multiwrite(rt2x00dev, MAC_CSR2,
47662306a36Sopenharmony_ci					       conf->mac, sizeof(conf->mac));
47762306a36Sopenharmony_ci	}
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci	if (flags & CONFIG_UPDATE_BSSID) {
48062306a36Sopenharmony_ci		reg = le32_to_cpu(conf->bssid[1]);
48162306a36Sopenharmony_ci		rt2x00_set_field32(&reg, MAC_CSR5_BSS_ID_MASK, 3);
48262306a36Sopenharmony_ci		conf->bssid[1] = cpu_to_le32(reg);
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci		rt2x00mmio_register_multiwrite(rt2x00dev, MAC_CSR4,
48562306a36Sopenharmony_ci					       conf->bssid,
48662306a36Sopenharmony_ci					       sizeof(conf->bssid));
48762306a36Sopenharmony_ci	}
48862306a36Sopenharmony_ci}
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_cistatic void rt61pci_config_erp(struct rt2x00_dev *rt2x00dev,
49162306a36Sopenharmony_ci			       struct rt2x00lib_erp *erp,
49262306a36Sopenharmony_ci			       u32 changed)
49362306a36Sopenharmony_ci{
49462306a36Sopenharmony_ci	u32 reg;
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci	reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR0);
49762306a36Sopenharmony_ci	rt2x00_set_field32(&reg, TXRX_CSR0_RX_ACK_TIMEOUT, 0x32);
49862306a36Sopenharmony_ci	rt2x00_set_field32(&reg, TXRX_CSR0_TSF_OFFSET, IEEE80211_HEADER);
49962306a36Sopenharmony_ci	rt2x00mmio_register_write(rt2x00dev, TXRX_CSR0, reg);
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci	if (changed & BSS_CHANGED_ERP_PREAMBLE) {
50262306a36Sopenharmony_ci		reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR4);
50362306a36Sopenharmony_ci		rt2x00_set_field32(&reg, TXRX_CSR4_AUTORESPOND_ENABLE, 1);
50462306a36Sopenharmony_ci		rt2x00_set_field32(&reg, TXRX_CSR4_AUTORESPOND_PREAMBLE,
50562306a36Sopenharmony_ci				   !!erp->short_preamble);
50662306a36Sopenharmony_ci		rt2x00mmio_register_write(rt2x00dev, TXRX_CSR4, reg);
50762306a36Sopenharmony_ci	}
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci	if (changed & BSS_CHANGED_BASIC_RATES)
51062306a36Sopenharmony_ci		rt2x00mmio_register_write(rt2x00dev, TXRX_CSR5,
51162306a36Sopenharmony_ci					  erp->basic_rates);
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci	if (changed & BSS_CHANGED_BEACON_INT) {
51462306a36Sopenharmony_ci		reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR9);
51562306a36Sopenharmony_ci		rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_INTERVAL,
51662306a36Sopenharmony_ci				   erp->beacon_int * 16);
51762306a36Sopenharmony_ci		rt2x00mmio_register_write(rt2x00dev, TXRX_CSR9, reg);
51862306a36Sopenharmony_ci	}
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci	if (changed & BSS_CHANGED_ERP_SLOT) {
52162306a36Sopenharmony_ci		reg = rt2x00mmio_register_read(rt2x00dev, MAC_CSR9);
52262306a36Sopenharmony_ci		rt2x00_set_field32(&reg, MAC_CSR9_SLOT_TIME, erp->slot_time);
52362306a36Sopenharmony_ci		rt2x00mmio_register_write(rt2x00dev, MAC_CSR9, reg);
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci		reg = rt2x00mmio_register_read(rt2x00dev, MAC_CSR8);
52662306a36Sopenharmony_ci		rt2x00_set_field32(&reg, MAC_CSR8_SIFS, erp->sifs);
52762306a36Sopenharmony_ci		rt2x00_set_field32(&reg, MAC_CSR8_SIFS_AFTER_RX_OFDM, 3);
52862306a36Sopenharmony_ci		rt2x00_set_field32(&reg, MAC_CSR8_EIFS, erp->eifs);
52962306a36Sopenharmony_ci		rt2x00mmio_register_write(rt2x00dev, MAC_CSR8, reg);
53062306a36Sopenharmony_ci	}
53162306a36Sopenharmony_ci}
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_cistatic void rt61pci_config_antenna_5x(struct rt2x00_dev *rt2x00dev,
53462306a36Sopenharmony_ci				      struct antenna_setup *ant)
53562306a36Sopenharmony_ci{
53662306a36Sopenharmony_ci	u8 r3;
53762306a36Sopenharmony_ci	u8 r4;
53862306a36Sopenharmony_ci	u8 r77;
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci	r3 = rt61pci_bbp_read(rt2x00dev, 3);
54162306a36Sopenharmony_ci	r4 = rt61pci_bbp_read(rt2x00dev, 4);
54262306a36Sopenharmony_ci	r77 = rt61pci_bbp_read(rt2x00dev, 77);
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_ci	rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, rt2x00_rf(rt2x00dev, RF5325));
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci	/*
54762306a36Sopenharmony_ci	 * Configure the RX antenna.
54862306a36Sopenharmony_ci	 */
54962306a36Sopenharmony_ci	switch (ant->rx) {
55062306a36Sopenharmony_ci	case ANTENNA_HW_DIVERSITY:
55162306a36Sopenharmony_ci		rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 2);
55262306a36Sopenharmony_ci		rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END,
55362306a36Sopenharmony_ci				  (rt2x00dev->curr_band != NL80211_BAND_5GHZ));
55462306a36Sopenharmony_ci		break;
55562306a36Sopenharmony_ci	case ANTENNA_A:
55662306a36Sopenharmony_ci		rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 1);
55762306a36Sopenharmony_ci		rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, 0);
55862306a36Sopenharmony_ci		if (rt2x00dev->curr_band == NL80211_BAND_5GHZ)
55962306a36Sopenharmony_ci			rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 0);
56062306a36Sopenharmony_ci		else
56162306a36Sopenharmony_ci			rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 3);
56262306a36Sopenharmony_ci		break;
56362306a36Sopenharmony_ci	case ANTENNA_B:
56462306a36Sopenharmony_ci	default:
56562306a36Sopenharmony_ci		rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 1);
56662306a36Sopenharmony_ci		rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, 0);
56762306a36Sopenharmony_ci		if (rt2x00dev->curr_band == NL80211_BAND_5GHZ)
56862306a36Sopenharmony_ci			rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 3);
56962306a36Sopenharmony_ci		else
57062306a36Sopenharmony_ci			rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 0);
57162306a36Sopenharmony_ci		break;
57262306a36Sopenharmony_ci	}
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_ci	rt61pci_bbp_write(rt2x00dev, 77, r77);
57562306a36Sopenharmony_ci	rt61pci_bbp_write(rt2x00dev, 3, r3);
57662306a36Sopenharmony_ci	rt61pci_bbp_write(rt2x00dev, 4, r4);
57762306a36Sopenharmony_ci}
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_cistatic void rt61pci_config_antenna_2x(struct rt2x00_dev *rt2x00dev,
58062306a36Sopenharmony_ci				      struct antenna_setup *ant)
58162306a36Sopenharmony_ci{
58262306a36Sopenharmony_ci	u8 r3;
58362306a36Sopenharmony_ci	u8 r4;
58462306a36Sopenharmony_ci	u8 r77;
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci	r3 = rt61pci_bbp_read(rt2x00dev, 3);
58762306a36Sopenharmony_ci	r4 = rt61pci_bbp_read(rt2x00dev, 4);
58862306a36Sopenharmony_ci	r77 = rt61pci_bbp_read(rt2x00dev, 77);
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ci	rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, rt2x00_rf(rt2x00dev, RF2529));
59162306a36Sopenharmony_ci	rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END,
59262306a36Sopenharmony_ci			  !rt2x00_has_cap_frame_type(rt2x00dev));
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci	/*
59562306a36Sopenharmony_ci	 * Configure the RX antenna.
59662306a36Sopenharmony_ci	 */
59762306a36Sopenharmony_ci	switch (ant->rx) {
59862306a36Sopenharmony_ci	case ANTENNA_HW_DIVERSITY:
59962306a36Sopenharmony_ci		rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 2);
60062306a36Sopenharmony_ci		break;
60162306a36Sopenharmony_ci	case ANTENNA_A:
60262306a36Sopenharmony_ci		rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 1);
60362306a36Sopenharmony_ci		rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 3);
60462306a36Sopenharmony_ci		break;
60562306a36Sopenharmony_ci	case ANTENNA_B:
60662306a36Sopenharmony_ci	default:
60762306a36Sopenharmony_ci		rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 1);
60862306a36Sopenharmony_ci		rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 0);
60962306a36Sopenharmony_ci		break;
61062306a36Sopenharmony_ci	}
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ci	rt61pci_bbp_write(rt2x00dev, 77, r77);
61362306a36Sopenharmony_ci	rt61pci_bbp_write(rt2x00dev, 3, r3);
61462306a36Sopenharmony_ci	rt61pci_bbp_write(rt2x00dev, 4, r4);
61562306a36Sopenharmony_ci}
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_cistatic void rt61pci_config_antenna_2529_rx(struct rt2x00_dev *rt2x00dev,
61862306a36Sopenharmony_ci					   const int p1, const int p2)
61962306a36Sopenharmony_ci{
62062306a36Sopenharmony_ci	u32 reg;
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci	reg = rt2x00mmio_register_read(rt2x00dev, MAC_CSR13);
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_ci	rt2x00_set_field32(&reg, MAC_CSR13_DIR4, 0);
62562306a36Sopenharmony_ci	rt2x00_set_field32(&reg, MAC_CSR13_VAL4, p1);
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci	rt2x00_set_field32(&reg, MAC_CSR13_DIR3, 0);
62862306a36Sopenharmony_ci	rt2x00_set_field32(&reg, MAC_CSR13_VAL3, !p2);
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ci	rt2x00mmio_register_write(rt2x00dev, MAC_CSR13, reg);
63162306a36Sopenharmony_ci}
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_cistatic void rt61pci_config_antenna_2529(struct rt2x00_dev *rt2x00dev,
63462306a36Sopenharmony_ci					struct antenna_setup *ant)
63562306a36Sopenharmony_ci{
63662306a36Sopenharmony_ci	u8 r3;
63762306a36Sopenharmony_ci	u8 r4;
63862306a36Sopenharmony_ci	u8 r77;
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_ci	r3 = rt61pci_bbp_read(rt2x00dev, 3);
64162306a36Sopenharmony_ci	r4 = rt61pci_bbp_read(rt2x00dev, 4);
64262306a36Sopenharmony_ci	r77 = rt61pci_bbp_read(rt2x00dev, 77);
64362306a36Sopenharmony_ci
64462306a36Sopenharmony_ci	/*
64562306a36Sopenharmony_ci	 * Configure the RX antenna.
64662306a36Sopenharmony_ci	 */
64762306a36Sopenharmony_ci	switch (ant->rx) {
64862306a36Sopenharmony_ci	case ANTENNA_A:
64962306a36Sopenharmony_ci		rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 1);
65062306a36Sopenharmony_ci		rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 0);
65162306a36Sopenharmony_ci		rt61pci_config_antenna_2529_rx(rt2x00dev, 0, 0);
65262306a36Sopenharmony_ci		break;
65362306a36Sopenharmony_ci	case ANTENNA_HW_DIVERSITY:
65462306a36Sopenharmony_ci		/*
65562306a36Sopenharmony_ci		 * FIXME: Antenna selection for the rf 2529 is very confusing
65662306a36Sopenharmony_ci		 * in the legacy driver. Just default to antenna B until the
65762306a36Sopenharmony_ci		 * legacy code can be properly translated into rt2x00 code.
65862306a36Sopenharmony_ci		 */
65962306a36Sopenharmony_ci	case ANTENNA_B:
66062306a36Sopenharmony_ci	default:
66162306a36Sopenharmony_ci		rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 1);
66262306a36Sopenharmony_ci		rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 3);
66362306a36Sopenharmony_ci		rt61pci_config_antenna_2529_rx(rt2x00dev, 1, 1);
66462306a36Sopenharmony_ci		break;
66562306a36Sopenharmony_ci	}
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_ci	rt61pci_bbp_write(rt2x00dev, 77, r77);
66862306a36Sopenharmony_ci	rt61pci_bbp_write(rt2x00dev, 3, r3);
66962306a36Sopenharmony_ci	rt61pci_bbp_write(rt2x00dev, 4, r4);
67062306a36Sopenharmony_ci}
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_cistruct antenna_sel {
67362306a36Sopenharmony_ci	u8 word;
67462306a36Sopenharmony_ci	/*
67562306a36Sopenharmony_ci	 * value[0] -> non-LNA
67662306a36Sopenharmony_ci	 * value[1] -> LNA
67762306a36Sopenharmony_ci	 */
67862306a36Sopenharmony_ci	u8 value[2];
67962306a36Sopenharmony_ci};
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_cistatic const struct antenna_sel antenna_sel_a[] = {
68262306a36Sopenharmony_ci	{ 96,  { 0x58, 0x78 } },
68362306a36Sopenharmony_ci	{ 104, { 0x38, 0x48 } },
68462306a36Sopenharmony_ci	{ 75,  { 0xfe, 0x80 } },
68562306a36Sopenharmony_ci	{ 86,  { 0xfe, 0x80 } },
68662306a36Sopenharmony_ci	{ 88,  { 0xfe, 0x80 } },
68762306a36Sopenharmony_ci	{ 35,  { 0x60, 0x60 } },
68862306a36Sopenharmony_ci	{ 97,  { 0x58, 0x58 } },
68962306a36Sopenharmony_ci	{ 98,  { 0x58, 0x58 } },
69062306a36Sopenharmony_ci};
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_cistatic const struct antenna_sel antenna_sel_bg[] = {
69362306a36Sopenharmony_ci	{ 96,  { 0x48, 0x68 } },
69462306a36Sopenharmony_ci	{ 104, { 0x2c, 0x3c } },
69562306a36Sopenharmony_ci	{ 75,  { 0xfe, 0x80 } },
69662306a36Sopenharmony_ci	{ 86,  { 0xfe, 0x80 } },
69762306a36Sopenharmony_ci	{ 88,  { 0xfe, 0x80 } },
69862306a36Sopenharmony_ci	{ 35,  { 0x50, 0x50 } },
69962306a36Sopenharmony_ci	{ 97,  { 0x48, 0x48 } },
70062306a36Sopenharmony_ci	{ 98,  { 0x48, 0x48 } },
70162306a36Sopenharmony_ci};
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_cistatic void rt61pci_config_ant(struct rt2x00_dev *rt2x00dev,
70462306a36Sopenharmony_ci			       struct antenna_setup *ant)
70562306a36Sopenharmony_ci{
70662306a36Sopenharmony_ci	const struct antenna_sel *sel;
70762306a36Sopenharmony_ci	unsigned int lna;
70862306a36Sopenharmony_ci	unsigned int i;
70962306a36Sopenharmony_ci	u32 reg;
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_ci	/*
71262306a36Sopenharmony_ci	 * We should never come here because rt2x00lib is supposed
71362306a36Sopenharmony_ci	 * to catch this and send us the correct antenna explicitely.
71462306a36Sopenharmony_ci	 */
71562306a36Sopenharmony_ci	BUG_ON(ant->rx == ANTENNA_SW_DIVERSITY ||
71662306a36Sopenharmony_ci	       ant->tx == ANTENNA_SW_DIVERSITY);
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_ci	if (rt2x00dev->curr_band == NL80211_BAND_5GHZ) {
71962306a36Sopenharmony_ci		sel = antenna_sel_a;
72062306a36Sopenharmony_ci		lna = rt2x00_has_cap_external_lna_a(rt2x00dev);
72162306a36Sopenharmony_ci	} else {
72262306a36Sopenharmony_ci		sel = antenna_sel_bg;
72362306a36Sopenharmony_ci		lna = rt2x00_has_cap_external_lna_bg(rt2x00dev);
72462306a36Sopenharmony_ci	}
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(antenna_sel_a); i++)
72762306a36Sopenharmony_ci		rt61pci_bbp_write(rt2x00dev, sel[i].word, sel[i].value[lna]);
72862306a36Sopenharmony_ci
72962306a36Sopenharmony_ci	reg = rt2x00mmio_register_read(rt2x00dev, PHY_CSR0);
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ci	rt2x00_set_field32(&reg, PHY_CSR0_PA_PE_BG,
73262306a36Sopenharmony_ci			   rt2x00dev->curr_band == NL80211_BAND_2GHZ);
73362306a36Sopenharmony_ci	rt2x00_set_field32(&reg, PHY_CSR0_PA_PE_A,
73462306a36Sopenharmony_ci			   rt2x00dev->curr_band == NL80211_BAND_5GHZ);
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ci	rt2x00mmio_register_write(rt2x00dev, PHY_CSR0, reg);
73762306a36Sopenharmony_ci
73862306a36Sopenharmony_ci	if (rt2x00_rf(rt2x00dev, RF5225) || rt2x00_rf(rt2x00dev, RF5325))
73962306a36Sopenharmony_ci		rt61pci_config_antenna_5x(rt2x00dev, ant);
74062306a36Sopenharmony_ci	else if (rt2x00_rf(rt2x00dev, RF2527))
74162306a36Sopenharmony_ci		rt61pci_config_antenna_2x(rt2x00dev, ant);
74262306a36Sopenharmony_ci	else if (rt2x00_rf(rt2x00dev, RF2529)) {
74362306a36Sopenharmony_ci		if (rt2x00_has_cap_double_antenna(rt2x00dev))
74462306a36Sopenharmony_ci			rt61pci_config_antenna_2x(rt2x00dev, ant);
74562306a36Sopenharmony_ci		else
74662306a36Sopenharmony_ci			rt61pci_config_antenna_2529(rt2x00dev, ant);
74762306a36Sopenharmony_ci	}
74862306a36Sopenharmony_ci}
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_cistatic void rt61pci_config_lna_gain(struct rt2x00_dev *rt2x00dev,
75162306a36Sopenharmony_ci				    struct rt2x00lib_conf *libconf)
75262306a36Sopenharmony_ci{
75362306a36Sopenharmony_ci	u16 eeprom;
75462306a36Sopenharmony_ci	short lna_gain = 0;
75562306a36Sopenharmony_ci
75662306a36Sopenharmony_ci	if (libconf->conf->chandef.chan->band == NL80211_BAND_2GHZ) {
75762306a36Sopenharmony_ci		if (rt2x00_has_cap_external_lna_bg(rt2x00dev))
75862306a36Sopenharmony_ci			lna_gain += 14;
75962306a36Sopenharmony_ci
76062306a36Sopenharmony_ci		eeprom = rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG);
76162306a36Sopenharmony_ci		lna_gain -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_BG_1);
76262306a36Sopenharmony_ci	} else {
76362306a36Sopenharmony_ci		if (rt2x00_has_cap_external_lna_a(rt2x00dev))
76462306a36Sopenharmony_ci			lna_gain += 14;
76562306a36Sopenharmony_ci
76662306a36Sopenharmony_ci		eeprom = rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A);
76762306a36Sopenharmony_ci		lna_gain -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_A_1);
76862306a36Sopenharmony_ci	}
76962306a36Sopenharmony_ci
77062306a36Sopenharmony_ci	rt2x00dev->lna_gain = lna_gain;
77162306a36Sopenharmony_ci}
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_cistatic void rt61pci_config_channel(struct rt2x00_dev *rt2x00dev,
77462306a36Sopenharmony_ci				   struct rf_channel *rf, const int txpower)
77562306a36Sopenharmony_ci{
77662306a36Sopenharmony_ci	u8 r3;
77762306a36Sopenharmony_ci	u8 r94;
77862306a36Sopenharmony_ci	u8 smart;
77962306a36Sopenharmony_ci
78062306a36Sopenharmony_ci	rt2x00_set_field32(&rf->rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower));
78162306a36Sopenharmony_ci	rt2x00_set_field32(&rf->rf4, RF4_FREQ_OFFSET, rt2x00dev->freq_offset);
78262306a36Sopenharmony_ci
78362306a36Sopenharmony_ci	smart = !(rt2x00_rf(rt2x00dev, RF5225) || rt2x00_rf(rt2x00dev, RF2527));
78462306a36Sopenharmony_ci
78562306a36Sopenharmony_ci	r3 = rt61pci_bbp_read(rt2x00dev, 3);
78662306a36Sopenharmony_ci	rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, smart);
78762306a36Sopenharmony_ci	rt61pci_bbp_write(rt2x00dev, 3, r3);
78862306a36Sopenharmony_ci
78962306a36Sopenharmony_ci	r94 = 6;
79062306a36Sopenharmony_ci	if (txpower > MAX_TXPOWER && txpower <= (MAX_TXPOWER + r94))
79162306a36Sopenharmony_ci		r94 += txpower - MAX_TXPOWER;
79262306a36Sopenharmony_ci	else if (txpower < MIN_TXPOWER && txpower >= (MIN_TXPOWER - r94))
79362306a36Sopenharmony_ci		r94 += txpower;
79462306a36Sopenharmony_ci	rt61pci_bbp_write(rt2x00dev, 94, r94);
79562306a36Sopenharmony_ci
79662306a36Sopenharmony_ci	rt61pci_rf_write(rt2x00dev, 1, rf->rf1);
79762306a36Sopenharmony_ci	rt61pci_rf_write(rt2x00dev, 2, rf->rf2);
79862306a36Sopenharmony_ci	rt61pci_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004);
79962306a36Sopenharmony_ci	rt61pci_rf_write(rt2x00dev, 4, rf->rf4);
80062306a36Sopenharmony_ci
80162306a36Sopenharmony_ci	udelay(200);
80262306a36Sopenharmony_ci
80362306a36Sopenharmony_ci	rt61pci_rf_write(rt2x00dev, 1, rf->rf1);
80462306a36Sopenharmony_ci	rt61pci_rf_write(rt2x00dev, 2, rf->rf2);
80562306a36Sopenharmony_ci	rt61pci_rf_write(rt2x00dev, 3, rf->rf3 | 0x00000004);
80662306a36Sopenharmony_ci	rt61pci_rf_write(rt2x00dev, 4, rf->rf4);
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_ci	udelay(200);
80962306a36Sopenharmony_ci
81062306a36Sopenharmony_ci	rt61pci_rf_write(rt2x00dev, 1, rf->rf1);
81162306a36Sopenharmony_ci	rt61pci_rf_write(rt2x00dev, 2, rf->rf2);
81262306a36Sopenharmony_ci	rt61pci_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004);
81362306a36Sopenharmony_ci	rt61pci_rf_write(rt2x00dev, 4, rf->rf4);
81462306a36Sopenharmony_ci
81562306a36Sopenharmony_ci	msleep(1);
81662306a36Sopenharmony_ci}
81762306a36Sopenharmony_ci
81862306a36Sopenharmony_cistatic void rt61pci_config_txpower(struct rt2x00_dev *rt2x00dev,
81962306a36Sopenharmony_ci				   const int txpower)
82062306a36Sopenharmony_ci{
82162306a36Sopenharmony_ci	struct rf_channel rf;
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_ci	rf.rf1 = rt2x00_rf_read(rt2x00dev, 1);
82462306a36Sopenharmony_ci	rf.rf2 = rt2x00_rf_read(rt2x00dev, 2);
82562306a36Sopenharmony_ci	rf.rf3 = rt2x00_rf_read(rt2x00dev, 3);
82662306a36Sopenharmony_ci	rf.rf4 = rt2x00_rf_read(rt2x00dev, 4);
82762306a36Sopenharmony_ci
82862306a36Sopenharmony_ci	rt61pci_config_channel(rt2x00dev, &rf, txpower);
82962306a36Sopenharmony_ci}
83062306a36Sopenharmony_ci
83162306a36Sopenharmony_cistatic void rt61pci_config_retry_limit(struct rt2x00_dev *rt2x00dev,
83262306a36Sopenharmony_ci				    struct rt2x00lib_conf *libconf)
83362306a36Sopenharmony_ci{
83462306a36Sopenharmony_ci	u32 reg;
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_ci	reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR4);
83762306a36Sopenharmony_ci	rt2x00_set_field32(&reg, TXRX_CSR4_OFDM_TX_RATE_DOWN, 1);
83862306a36Sopenharmony_ci	rt2x00_set_field32(&reg, TXRX_CSR4_OFDM_TX_RATE_STEP, 0);
83962306a36Sopenharmony_ci	rt2x00_set_field32(&reg, TXRX_CSR4_OFDM_TX_FALLBACK_CCK, 0);
84062306a36Sopenharmony_ci	rt2x00_set_field32(&reg, TXRX_CSR4_LONG_RETRY_LIMIT,
84162306a36Sopenharmony_ci			   libconf->conf->long_frame_max_tx_count);
84262306a36Sopenharmony_ci	rt2x00_set_field32(&reg, TXRX_CSR4_SHORT_RETRY_LIMIT,
84362306a36Sopenharmony_ci			   libconf->conf->short_frame_max_tx_count);
84462306a36Sopenharmony_ci	rt2x00mmio_register_write(rt2x00dev, TXRX_CSR4, reg);
84562306a36Sopenharmony_ci}
84662306a36Sopenharmony_ci
84762306a36Sopenharmony_cistatic void rt61pci_config_ps(struct rt2x00_dev *rt2x00dev,
84862306a36Sopenharmony_ci				struct rt2x00lib_conf *libconf)
84962306a36Sopenharmony_ci{
85062306a36Sopenharmony_ci	enum dev_state state =
85162306a36Sopenharmony_ci	    (libconf->conf->flags & IEEE80211_CONF_PS) ?
85262306a36Sopenharmony_ci		STATE_SLEEP : STATE_AWAKE;
85362306a36Sopenharmony_ci	u32 reg;
85462306a36Sopenharmony_ci
85562306a36Sopenharmony_ci	if (state == STATE_SLEEP) {
85662306a36Sopenharmony_ci		reg = rt2x00mmio_register_read(rt2x00dev, MAC_CSR11);
85762306a36Sopenharmony_ci		rt2x00_set_field32(&reg, MAC_CSR11_DELAY_AFTER_TBCN,
85862306a36Sopenharmony_ci				   rt2x00dev->beacon_int - 10);
85962306a36Sopenharmony_ci		rt2x00_set_field32(&reg, MAC_CSR11_TBCN_BEFORE_WAKEUP,
86062306a36Sopenharmony_ci				   libconf->conf->listen_interval - 1);
86162306a36Sopenharmony_ci		rt2x00_set_field32(&reg, MAC_CSR11_WAKEUP_LATENCY, 5);
86262306a36Sopenharmony_ci
86362306a36Sopenharmony_ci		/* We must first disable autowake before it can be enabled */
86462306a36Sopenharmony_ci		rt2x00_set_field32(&reg, MAC_CSR11_AUTOWAKE, 0);
86562306a36Sopenharmony_ci		rt2x00mmio_register_write(rt2x00dev, MAC_CSR11, reg);
86662306a36Sopenharmony_ci
86762306a36Sopenharmony_ci		rt2x00_set_field32(&reg, MAC_CSR11_AUTOWAKE, 1);
86862306a36Sopenharmony_ci		rt2x00mmio_register_write(rt2x00dev, MAC_CSR11, reg);
86962306a36Sopenharmony_ci
87062306a36Sopenharmony_ci		rt2x00mmio_register_write(rt2x00dev, SOFT_RESET_CSR,
87162306a36Sopenharmony_ci					  0x00000005);
87262306a36Sopenharmony_ci		rt2x00mmio_register_write(rt2x00dev, IO_CNTL_CSR, 0x0000001c);
87362306a36Sopenharmony_ci		rt2x00mmio_register_write(rt2x00dev, PCI_USEC_CSR, 0x00000060);
87462306a36Sopenharmony_ci
87562306a36Sopenharmony_ci		rt61pci_mcu_request(rt2x00dev, MCU_SLEEP, 0xff, 0, 0);
87662306a36Sopenharmony_ci	} else {
87762306a36Sopenharmony_ci		reg = rt2x00mmio_register_read(rt2x00dev, MAC_CSR11);
87862306a36Sopenharmony_ci		rt2x00_set_field32(&reg, MAC_CSR11_DELAY_AFTER_TBCN, 0);
87962306a36Sopenharmony_ci		rt2x00_set_field32(&reg, MAC_CSR11_TBCN_BEFORE_WAKEUP, 0);
88062306a36Sopenharmony_ci		rt2x00_set_field32(&reg, MAC_CSR11_AUTOWAKE, 0);
88162306a36Sopenharmony_ci		rt2x00_set_field32(&reg, MAC_CSR11_WAKEUP_LATENCY, 0);
88262306a36Sopenharmony_ci		rt2x00mmio_register_write(rt2x00dev, MAC_CSR11, reg);
88362306a36Sopenharmony_ci
88462306a36Sopenharmony_ci		rt2x00mmio_register_write(rt2x00dev, SOFT_RESET_CSR,
88562306a36Sopenharmony_ci					  0x00000007);
88662306a36Sopenharmony_ci		rt2x00mmio_register_write(rt2x00dev, IO_CNTL_CSR, 0x00000018);
88762306a36Sopenharmony_ci		rt2x00mmio_register_write(rt2x00dev, PCI_USEC_CSR, 0x00000020);
88862306a36Sopenharmony_ci
88962306a36Sopenharmony_ci		rt61pci_mcu_request(rt2x00dev, MCU_WAKEUP, 0xff, 0, 0);
89062306a36Sopenharmony_ci	}
89162306a36Sopenharmony_ci}
89262306a36Sopenharmony_ci
89362306a36Sopenharmony_cistatic void rt61pci_config(struct rt2x00_dev *rt2x00dev,
89462306a36Sopenharmony_ci			   struct rt2x00lib_conf *libconf,
89562306a36Sopenharmony_ci			   const unsigned int flags)
89662306a36Sopenharmony_ci{
89762306a36Sopenharmony_ci	/* Always recalculate LNA gain before changing configuration */
89862306a36Sopenharmony_ci	rt61pci_config_lna_gain(rt2x00dev, libconf);
89962306a36Sopenharmony_ci
90062306a36Sopenharmony_ci	if (flags & IEEE80211_CONF_CHANGE_CHANNEL)
90162306a36Sopenharmony_ci		rt61pci_config_channel(rt2x00dev, &libconf->rf,
90262306a36Sopenharmony_ci				       libconf->conf->power_level);
90362306a36Sopenharmony_ci	if ((flags & IEEE80211_CONF_CHANGE_POWER) &&
90462306a36Sopenharmony_ci	    !(flags & IEEE80211_CONF_CHANGE_CHANNEL))
90562306a36Sopenharmony_ci		rt61pci_config_txpower(rt2x00dev, libconf->conf->power_level);
90662306a36Sopenharmony_ci	if (flags & IEEE80211_CONF_CHANGE_RETRY_LIMITS)
90762306a36Sopenharmony_ci		rt61pci_config_retry_limit(rt2x00dev, libconf);
90862306a36Sopenharmony_ci	if (flags & IEEE80211_CONF_CHANGE_PS)
90962306a36Sopenharmony_ci		rt61pci_config_ps(rt2x00dev, libconf);
91062306a36Sopenharmony_ci}
91162306a36Sopenharmony_ci
91262306a36Sopenharmony_ci/*
91362306a36Sopenharmony_ci * Link tuning
91462306a36Sopenharmony_ci */
91562306a36Sopenharmony_cistatic void rt61pci_link_stats(struct rt2x00_dev *rt2x00dev,
91662306a36Sopenharmony_ci			       struct link_qual *qual)
91762306a36Sopenharmony_ci{
91862306a36Sopenharmony_ci	u32 reg;
91962306a36Sopenharmony_ci
92062306a36Sopenharmony_ci	/*
92162306a36Sopenharmony_ci	 * Update FCS error count from register.
92262306a36Sopenharmony_ci	 */
92362306a36Sopenharmony_ci	reg = rt2x00mmio_register_read(rt2x00dev, STA_CSR0);
92462306a36Sopenharmony_ci	qual->rx_failed = rt2x00_get_field32(reg, STA_CSR0_FCS_ERROR);
92562306a36Sopenharmony_ci
92662306a36Sopenharmony_ci	/*
92762306a36Sopenharmony_ci	 * Update False CCA count from register.
92862306a36Sopenharmony_ci	 */
92962306a36Sopenharmony_ci	reg = rt2x00mmio_register_read(rt2x00dev, STA_CSR1);
93062306a36Sopenharmony_ci	qual->false_cca = rt2x00_get_field32(reg, STA_CSR1_FALSE_CCA_ERROR);
93162306a36Sopenharmony_ci}
93262306a36Sopenharmony_ci
93362306a36Sopenharmony_cistatic inline void rt61pci_set_vgc(struct rt2x00_dev *rt2x00dev,
93462306a36Sopenharmony_ci				   struct link_qual *qual, u8 vgc_level)
93562306a36Sopenharmony_ci{
93662306a36Sopenharmony_ci	if (qual->vgc_level != vgc_level) {
93762306a36Sopenharmony_ci		rt61pci_bbp_write(rt2x00dev, 17, vgc_level);
93862306a36Sopenharmony_ci		qual->vgc_level = vgc_level;
93962306a36Sopenharmony_ci		qual->vgc_level_reg = vgc_level;
94062306a36Sopenharmony_ci	}
94162306a36Sopenharmony_ci}
94262306a36Sopenharmony_ci
94362306a36Sopenharmony_cistatic void rt61pci_reset_tuner(struct rt2x00_dev *rt2x00dev,
94462306a36Sopenharmony_ci				struct link_qual *qual)
94562306a36Sopenharmony_ci{
94662306a36Sopenharmony_ci	rt61pci_set_vgc(rt2x00dev, qual, 0x20);
94762306a36Sopenharmony_ci}
94862306a36Sopenharmony_ci
94962306a36Sopenharmony_cistatic void rt61pci_link_tuner(struct rt2x00_dev *rt2x00dev,
95062306a36Sopenharmony_ci			       struct link_qual *qual, const u32 count)
95162306a36Sopenharmony_ci{
95262306a36Sopenharmony_ci	u8 up_bound;
95362306a36Sopenharmony_ci	u8 low_bound;
95462306a36Sopenharmony_ci
95562306a36Sopenharmony_ci	/*
95662306a36Sopenharmony_ci	 * Determine r17 bounds.
95762306a36Sopenharmony_ci	 */
95862306a36Sopenharmony_ci	if (rt2x00dev->curr_band == NL80211_BAND_5GHZ) {
95962306a36Sopenharmony_ci		low_bound = 0x28;
96062306a36Sopenharmony_ci		up_bound = 0x48;
96162306a36Sopenharmony_ci		if (rt2x00_has_cap_external_lna_a(rt2x00dev)) {
96262306a36Sopenharmony_ci			low_bound += 0x10;
96362306a36Sopenharmony_ci			up_bound += 0x10;
96462306a36Sopenharmony_ci		}
96562306a36Sopenharmony_ci	} else {
96662306a36Sopenharmony_ci		low_bound = 0x20;
96762306a36Sopenharmony_ci		up_bound = 0x40;
96862306a36Sopenharmony_ci		if (rt2x00_has_cap_external_lna_bg(rt2x00dev)) {
96962306a36Sopenharmony_ci			low_bound += 0x10;
97062306a36Sopenharmony_ci			up_bound += 0x10;
97162306a36Sopenharmony_ci		}
97262306a36Sopenharmony_ci	}
97362306a36Sopenharmony_ci
97462306a36Sopenharmony_ci	/*
97562306a36Sopenharmony_ci	 * If we are not associated, we should go straight to the
97662306a36Sopenharmony_ci	 * dynamic CCA tuning.
97762306a36Sopenharmony_ci	 */
97862306a36Sopenharmony_ci	if (!rt2x00dev->intf_associated)
97962306a36Sopenharmony_ci		goto dynamic_cca_tune;
98062306a36Sopenharmony_ci
98162306a36Sopenharmony_ci	/*
98262306a36Sopenharmony_ci	 * Special big-R17 for very short distance
98362306a36Sopenharmony_ci	 */
98462306a36Sopenharmony_ci	if (qual->rssi >= -35) {
98562306a36Sopenharmony_ci		rt61pci_set_vgc(rt2x00dev, qual, 0x60);
98662306a36Sopenharmony_ci		return;
98762306a36Sopenharmony_ci	}
98862306a36Sopenharmony_ci
98962306a36Sopenharmony_ci	/*
99062306a36Sopenharmony_ci	 * Special big-R17 for short distance
99162306a36Sopenharmony_ci	 */
99262306a36Sopenharmony_ci	if (qual->rssi >= -58) {
99362306a36Sopenharmony_ci		rt61pci_set_vgc(rt2x00dev, qual, up_bound);
99462306a36Sopenharmony_ci		return;
99562306a36Sopenharmony_ci	}
99662306a36Sopenharmony_ci
99762306a36Sopenharmony_ci	/*
99862306a36Sopenharmony_ci	 * Special big-R17 for middle-short distance
99962306a36Sopenharmony_ci	 */
100062306a36Sopenharmony_ci	if (qual->rssi >= -66) {
100162306a36Sopenharmony_ci		rt61pci_set_vgc(rt2x00dev, qual, low_bound + 0x10);
100262306a36Sopenharmony_ci		return;
100362306a36Sopenharmony_ci	}
100462306a36Sopenharmony_ci
100562306a36Sopenharmony_ci	/*
100662306a36Sopenharmony_ci	 * Special mid-R17 for middle distance
100762306a36Sopenharmony_ci	 */
100862306a36Sopenharmony_ci	if (qual->rssi >= -74) {
100962306a36Sopenharmony_ci		rt61pci_set_vgc(rt2x00dev, qual, low_bound + 0x08);
101062306a36Sopenharmony_ci		return;
101162306a36Sopenharmony_ci	}
101262306a36Sopenharmony_ci
101362306a36Sopenharmony_ci	/*
101462306a36Sopenharmony_ci	 * Special case: Change up_bound based on the rssi.
101562306a36Sopenharmony_ci	 * Lower up_bound when rssi is weaker then -74 dBm.
101662306a36Sopenharmony_ci	 */
101762306a36Sopenharmony_ci	up_bound -= 2 * (-74 - qual->rssi);
101862306a36Sopenharmony_ci	if (low_bound > up_bound)
101962306a36Sopenharmony_ci		up_bound = low_bound;
102062306a36Sopenharmony_ci
102162306a36Sopenharmony_ci	if (qual->vgc_level > up_bound) {
102262306a36Sopenharmony_ci		rt61pci_set_vgc(rt2x00dev, qual, up_bound);
102362306a36Sopenharmony_ci		return;
102462306a36Sopenharmony_ci	}
102562306a36Sopenharmony_ci
102662306a36Sopenharmony_cidynamic_cca_tune:
102762306a36Sopenharmony_ci
102862306a36Sopenharmony_ci	/*
102962306a36Sopenharmony_ci	 * r17 does not yet exceed upper limit, continue and base
103062306a36Sopenharmony_ci	 * the r17 tuning on the false CCA count.
103162306a36Sopenharmony_ci	 */
103262306a36Sopenharmony_ci	if ((qual->false_cca > 512) && (qual->vgc_level < up_bound))
103362306a36Sopenharmony_ci		rt61pci_set_vgc(rt2x00dev, qual, ++qual->vgc_level);
103462306a36Sopenharmony_ci	else if ((qual->false_cca < 100) && (qual->vgc_level > low_bound))
103562306a36Sopenharmony_ci		rt61pci_set_vgc(rt2x00dev, qual, --qual->vgc_level);
103662306a36Sopenharmony_ci}
103762306a36Sopenharmony_ci
103862306a36Sopenharmony_ci/*
103962306a36Sopenharmony_ci * Queue handlers.
104062306a36Sopenharmony_ci */
104162306a36Sopenharmony_cistatic void rt61pci_start_queue(struct data_queue *queue)
104262306a36Sopenharmony_ci{
104362306a36Sopenharmony_ci	struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
104462306a36Sopenharmony_ci	u32 reg;
104562306a36Sopenharmony_ci
104662306a36Sopenharmony_ci	switch (queue->qid) {
104762306a36Sopenharmony_ci	case QID_RX:
104862306a36Sopenharmony_ci		reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR0);
104962306a36Sopenharmony_ci		rt2x00_set_field32(&reg, TXRX_CSR0_DISABLE_RX, 0);
105062306a36Sopenharmony_ci		rt2x00mmio_register_write(rt2x00dev, TXRX_CSR0, reg);
105162306a36Sopenharmony_ci		break;
105262306a36Sopenharmony_ci	case QID_BEACON:
105362306a36Sopenharmony_ci		reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR9);
105462306a36Sopenharmony_ci		rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 1);
105562306a36Sopenharmony_ci		rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 1);
105662306a36Sopenharmony_ci		rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 1);
105762306a36Sopenharmony_ci		rt2x00mmio_register_write(rt2x00dev, TXRX_CSR9, reg);
105862306a36Sopenharmony_ci		break;
105962306a36Sopenharmony_ci	default:
106062306a36Sopenharmony_ci		break;
106162306a36Sopenharmony_ci	}
106262306a36Sopenharmony_ci}
106362306a36Sopenharmony_ci
106462306a36Sopenharmony_cistatic void rt61pci_kick_queue(struct data_queue *queue)
106562306a36Sopenharmony_ci{
106662306a36Sopenharmony_ci	struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
106762306a36Sopenharmony_ci	u32 reg;
106862306a36Sopenharmony_ci
106962306a36Sopenharmony_ci	switch (queue->qid) {
107062306a36Sopenharmony_ci	case QID_AC_VO:
107162306a36Sopenharmony_ci		reg = rt2x00mmio_register_read(rt2x00dev, TX_CNTL_CSR);
107262306a36Sopenharmony_ci		rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC0, 1);
107362306a36Sopenharmony_ci		rt2x00mmio_register_write(rt2x00dev, TX_CNTL_CSR, reg);
107462306a36Sopenharmony_ci		break;
107562306a36Sopenharmony_ci	case QID_AC_VI:
107662306a36Sopenharmony_ci		reg = rt2x00mmio_register_read(rt2x00dev, TX_CNTL_CSR);
107762306a36Sopenharmony_ci		rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC1, 1);
107862306a36Sopenharmony_ci		rt2x00mmio_register_write(rt2x00dev, TX_CNTL_CSR, reg);
107962306a36Sopenharmony_ci		break;
108062306a36Sopenharmony_ci	case QID_AC_BE:
108162306a36Sopenharmony_ci		reg = rt2x00mmio_register_read(rt2x00dev, TX_CNTL_CSR);
108262306a36Sopenharmony_ci		rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC2, 1);
108362306a36Sopenharmony_ci		rt2x00mmio_register_write(rt2x00dev, TX_CNTL_CSR, reg);
108462306a36Sopenharmony_ci		break;
108562306a36Sopenharmony_ci	case QID_AC_BK:
108662306a36Sopenharmony_ci		reg = rt2x00mmio_register_read(rt2x00dev, TX_CNTL_CSR);
108762306a36Sopenharmony_ci		rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC3, 1);
108862306a36Sopenharmony_ci		rt2x00mmio_register_write(rt2x00dev, TX_CNTL_CSR, reg);
108962306a36Sopenharmony_ci		break;
109062306a36Sopenharmony_ci	default:
109162306a36Sopenharmony_ci		break;
109262306a36Sopenharmony_ci	}
109362306a36Sopenharmony_ci}
109462306a36Sopenharmony_ci
109562306a36Sopenharmony_cistatic void rt61pci_stop_queue(struct data_queue *queue)
109662306a36Sopenharmony_ci{
109762306a36Sopenharmony_ci	struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
109862306a36Sopenharmony_ci	u32 reg;
109962306a36Sopenharmony_ci
110062306a36Sopenharmony_ci	switch (queue->qid) {
110162306a36Sopenharmony_ci	case QID_AC_VO:
110262306a36Sopenharmony_ci		reg = rt2x00mmio_register_read(rt2x00dev, TX_CNTL_CSR);
110362306a36Sopenharmony_ci		rt2x00_set_field32(&reg, TX_CNTL_CSR_ABORT_TX_AC0, 1);
110462306a36Sopenharmony_ci		rt2x00mmio_register_write(rt2x00dev, TX_CNTL_CSR, reg);
110562306a36Sopenharmony_ci		break;
110662306a36Sopenharmony_ci	case QID_AC_VI:
110762306a36Sopenharmony_ci		reg = rt2x00mmio_register_read(rt2x00dev, TX_CNTL_CSR);
110862306a36Sopenharmony_ci		rt2x00_set_field32(&reg, TX_CNTL_CSR_ABORT_TX_AC1, 1);
110962306a36Sopenharmony_ci		rt2x00mmio_register_write(rt2x00dev, TX_CNTL_CSR, reg);
111062306a36Sopenharmony_ci		break;
111162306a36Sopenharmony_ci	case QID_AC_BE:
111262306a36Sopenharmony_ci		reg = rt2x00mmio_register_read(rt2x00dev, TX_CNTL_CSR);
111362306a36Sopenharmony_ci		rt2x00_set_field32(&reg, TX_CNTL_CSR_ABORT_TX_AC2, 1);
111462306a36Sopenharmony_ci		rt2x00mmio_register_write(rt2x00dev, TX_CNTL_CSR, reg);
111562306a36Sopenharmony_ci		break;
111662306a36Sopenharmony_ci	case QID_AC_BK:
111762306a36Sopenharmony_ci		reg = rt2x00mmio_register_read(rt2x00dev, TX_CNTL_CSR);
111862306a36Sopenharmony_ci		rt2x00_set_field32(&reg, TX_CNTL_CSR_ABORT_TX_AC3, 1);
111962306a36Sopenharmony_ci		rt2x00mmio_register_write(rt2x00dev, TX_CNTL_CSR, reg);
112062306a36Sopenharmony_ci		break;
112162306a36Sopenharmony_ci	case QID_RX:
112262306a36Sopenharmony_ci		reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR0);
112362306a36Sopenharmony_ci		rt2x00_set_field32(&reg, TXRX_CSR0_DISABLE_RX, 1);
112462306a36Sopenharmony_ci		rt2x00mmio_register_write(rt2x00dev, TXRX_CSR0, reg);
112562306a36Sopenharmony_ci		break;
112662306a36Sopenharmony_ci	case QID_BEACON:
112762306a36Sopenharmony_ci		reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR9);
112862306a36Sopenharmony_ci		rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 0);
112962306a36Sopenharmony_ci		rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 0);
113062306a36Sopenharmony_ci		rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 0);
113162306a36Sopenharmony_ci		rt2x00mmio_register_write(rt2x00dev, TXRX_CSR9, reg);
113262306a36Sopenharmony_ci
113362306a36Sopenharmony_ci		/*
113462306a36Sopenharmony_ci		 * Wait for possibly running tbtt tasklets.
113562306a36Sopenharmony_ci		 */
113662306a36Sopenharmony_ci		tasklet_kill(&rt2x00dev->tbtt_tasklet);
113762306a36Sopenharmony_ci		break;
113862306a36Sopenharmony_ci	default:
113962306a36Sopenharmony_ci		break;
114062306a36Sopenharmony_ci	}
114162306a36Sopenharmony_ci}
114262306a36Sopenharmony_ci
114362306a36Sopenharmony_ci/*
114462306a36Sopenharmony_ci * Firmware functions
114562306a36Sopenharmony_ci */
114662306a36Sopenharmony_cistatic char *rt61pci_get_firmware_name(struct rt2x00_dev *rt2x00dev)
114762306a36Sopenharmony_ci{
114862306a36Sopenharmony_ci	u16 chip;
114962306a36Sopenharmony_ci	char *fw_name;
115062306a36Sopenharmony_ci
115162306a36Sopenharmony_ci	pci_read_config_word(to_pci_dev(rt2x00dev->dev), PCI_DEVICE_ID, &chip);
115262306a36Sopenharmony_ci	switch (chip) {
115362306a36Sopenharmony_ci	case RT2561_PCI_ID:
115462306a36Sopenharmony_ci		fw_name = FIRMWARE_RT2561;
115562306a36Sopenharmony_ci		break;
115662306a36Sopenharmony_ci	case RT2561s_PCI_ID:
115762306a36Sopenharmony_ci		fw_name = FIRMWARE_RT2561s;
115862306a36Sopenharmony_ci		break;
115962306a36Sopenharmony_ci	case RT2661_PCI_ID:
116062306a36Sopenharmony_ci		fw_name = FIRMWARE_RT2661;
116162306a36Sopenharmony_ci		break;
116262306a36Sopenharmony_ci	default:
116362306a36Sopenharmony_ci		fw_name = NULL;
116462306a36Sopenharmony_ci		break;
116562306a36Sopenharmony_ci	}
116662306a36Sopenharmony_ci
116762306a36Sopenharmony_ci	return fw_name;
116862306a36Sopenharmony_ci}
116962306a36Sopenharmony_ci
117062306a36Sopenharmony_cistatic int rt61pci_check_firmware(struct rt2x00_dev *rt2x00dev,
117162306a36Sopenharmony_ci				  const u8 *data, const size_t len)
117262306a36Sopenharmony_ci{
117362306a36Sopenharmony_ci	u16 fw_crc;
117462306a36Sopenharmony_ci	u16 crc;
117562306a36Sopenharmony_ci
117662306a36Sopenharmony_ci	/*
117762306a36Sopenharmony_ci	 * Only support 8kb firmware files.
117862306a36Sopenharmony_ci	 */
117962306a36Sopenharmony_ci	if (len != 8192)
118062306a36Sopenharmony_ci		return FW_BAD_LENGTH;
118162306a36Sopenharmony_ci
118262306a36Sopenharmony_ci	/*
118362306a36Sopenharmony_ci	 * The last 2 bytes in the firmware array are the crc checksum itself.
118462306a36Sopenharmony_ci	 * This means that we should never pass those 2 bytes to the crc
118562306a36Sopenharmony_ci	 * algorithm.
118662306a36Sopenharmony_ci	 */
118762306a36Sopenharmony_ci	fw_crc = (data[len - 2] << 8 | data[len - 1]);
118862306a36Sopenharmony_ci
118962306a36Sopenharmony_ci	/*
119062306a36Sopenharmony_ci	 * Use the crc itu-t algorithm.
119162306a36Sopenharmony_ci	 */
119262306a36Sopenharmony_ci	crc = crc_itu_t(0, data, len - 2);
119362306a36Sopenharmony_ci	crc = crc_itu_t_byte(crc, 0);
119462306a36Sopenharmony_ci	crc = crc_itu_t_byte(crc, 0);
119562306a36Sopenharmony_ci
119662306a36Sopenharmony_ci	return (fw_crc == crc) ? FW_OK : FW_BAD_CRC;
119762306a36Sopenharmony_ci}
119862306a36Sopenharmony_ci
119962306a36Sopenharmony_cistatic int rt61pci_load_firmware(struct rt2x00_dev *rt2x00dev,
120062306a36Sopenharmony_ci				 const u8 *data, const size_t len)
120162306a36Sopenharmony_ci{
120262306a36Sopenharmony_ci	int i;
120362306a36Sopenharmony_ci	u32 reg;
120462306a36Sopenharmony_ci
120562306a36Sopenharmony_ci	/*
120662306a36Sopenharmony_ci	 * Wait for stable hardware.
120762306a36Sopenharmony_ci	 */
120862306a36Sopenharmony_ci	for (i = 0; i < 100; i++) {
120962306a36Sopenharmony_ci		reg = rt2x00mmio_register_read(rt2x00dev, MAC_CSR0);
121062306a36Sopenharmony_ci		if (reg)
121162306a36Sopenharmony_ci			break;
121262306a36Sopenharmony_ci		msleep(1);
121362306a36Sopenharmony_ci	}
121462306a36Sopenharmony_ci
121562306a36Sopenharmony_ci	if (!reg) {
121662306a36Sopenharmony_ci		rt2x00_err(rt2x00dev, "Unstable hardware\n");
121762306a36Sopenharmony_ci		return -EBUSY;
121862306a36Sopenharmony_ci	}
121962306a36Sopenharmony_ci
122062306a36Sopenharmony_ci	/*
122162306a36Sopenharmony_ci	 * Prepare MCU and mailbox for firmware loading.
122262306a36Sopenharmony_ci	 */
122362306a36Sopenharmony_ci	reg = 0;
122462306a36Sopenharmony_ci	rt2x00_set_field32(&reg, MCU_CNTL_CSR_RESET, 1);
122562306a36Sopenharmony_ci	rt2x00mmio_register_write(rt2x00dev, MCU_CNTL_CSR, reg);
122662306a36Sopenharmony_ci	rt2x00mmio_register_write(rt2x00dev, M2H_CMD_DONE_CSR, 0xffffffff);
122762306a36Sopenharmony_ci	rt2x00mmio_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0);
122862306a36Sopenharmony_ci	rt2x00mmio_register_write(rt2x00dev, HOST_CMD_CSR, 0);
122962306a36Sopenharmony_ci
123062306a36Sopenharmony_ci	/*
123162306a36Sopenharmony_ci	 * Write firmware to device.
123262306a36Sopenharmony_ci	 */
123362306a36Sopenharmony_ci	reg = 0;
123462306a36Sopenharmony_ci	rt2x00_set_field32(&reg, MCU_CNTL_CSR_RESET, 1);
123562306a36Sopenharmony_ci	rt2x00_set_field32(&reg, MCU_CNTL_CSR_SELECT_BANK, 1);
123662306a36Sopenharmony_ci	rt2x00mmio_register_write(rt2x00dev, MCU_CNTL_CSR, reg);
123762306a36Sopenharmony_ci
123862306a36Sopenharmony_ci	rt2x00mmio_register_multiwrite(rt2x00dev, FIRMWARE_IMAGE_BASE,
123962306a36Sopenharmony_ci				       data, len);
124062306a36Sopenharmony_ci
124162306a36Sopenharmony_ci	rt2x00_set_field32(&reg, MCU_CNTL_CSR_SELECT_BANK, 0);
124262306a36Sopenharmony_ci	rt2x00mmio_register_write(rt2x00dev, MCU_CNTL_CSR, reg);
124362306a36Sopenharmony_ci
124462306a36Sopenharmony_ci	rt2x00_set_field32(&reg, MCU_CNTL_CSR_RESET, 0);
124562306a36Sopenharmony_ci	rt2x00mmio_register_write(rt2x00dev, MCU_CNTL_CSR, reg);
124662306a36Sopenharmony_ci
124762306a36Sopenharmony_ci	for (i = 0; i < 100; i++) {
124862306a36Sopenharmony_ci		reg = rt2x00mmio_register_read(rt2x00dev, MCU_CNTL_CSR);
124962306a36Sopenharmony_ci		if (rt2x00_get_field32(reg, MCU_CNTL_CSR_READY))
125062306a36Sopenharmony_ci			break;
125162306a36Sopenharmony_ci		msleep(1);
125262306a36Sopenharmony_ci	}
125362306a36Sopenharmony_ci
125462306a36Sopenharmony_ci	if (i == 100) {
125562306a36Sopenharmony_ci		rt2x00_err(rt2x00dev, "MCU Control register not ready\n");
125662306a36Sopenharmony_ci		return -EBUSY;
125762306a36Sopenharmony_ci	}
125862306a36Sopenharmony_ci
125962306a36Sopenharmony_ci	/*
126062306a36Sopenharmony_ci	 * Hardware needs another millisecond before it is ready.
126162306a36Sopenharmony_ci	 */
126262306a36Sopenharmony_ci	msleep(1);
126362306a36Sopenharmony_ci
126462306a36Sopenharmony_ci	/*
126562306a36Sopenharmony_ci	 * Reset MAC and BBP registers.
126662306a36Sopenharmony_ci	 */
126762306a36Sopenharmony_ci	reg = 0;
126862306a36Sopenharmony_ci	rt2x00_set_field32(&reg, MAC_CSR1_SOFT_RESET, 1);
126962306a36Sopenharmony_ci	rt2x00_set_field32(&reg, MAC_CSR1_BBP_RESET, 1);
127062306a36Sopenharmony_ci	rt2x00mmio_register_write(rt2x00dev, MAC_CSR1, reg);
127162306a36Sopenharmony_ci
127262306a36Sopenharmony_ci	reg = rt2x00mmio_register_read(rt2x00dev, MAC_CSR1);
127362306a36Sopenharmony_ci	rt2x00_set_field32(&reg, MAC_CSR1_SOFT_RESET, 0);
127462306a36Sopenharmony_ci	rt2x00_set_field32(&reg, MAC_CSR1_BBP_RESET, 0);
127562306a36Sopenharmony_ci	rt2x00mmio_register_write(rt2x00dev, MAC_CSR1, reg);
127662306a36Sopenharmony_ci
127762306a36Sopenharmony_ci	reg = rt2x00mmio_register_read(rt2x00dev, MAC_CSR1);
127862306a36Sopenharmony_ci	rt2x00_set_field32(&reg, MAC_CSR1_HOST_READY, 1);
127962306a36Sopenharmony_ci	rt2x00mmio_register_write(rt2x00dev, MAC_CSR1, reg);
128062306a36Sopenharmony_ci
128162306a36Sopenharmony_ci	return 0;
128262306a36Sopenharmony_ci}
128362306a36Sopenharmony_ci
128462306a36Sopenharmony_ci/*
128562306a36Sopenharmony_ci * Initialization functions.
128662306a36Sopenharmony_ci */
128762306a36Sopenharmony_cistatic bool rt61pci_get_entry_state(struct queue_entry *entry)
128862306a36Sopenharmony_ci{
128962306a36Sopenharmony_ci	struct queue_entry_priv_mmio *entry_priv = entry->priv_data;
129062306a36Sopenharmony_ci	u32 word;
129162306a36Sopenharmony_ci
129262306a36Sopenharmony_ci	if (entry->queue->qid == QID_RX) {
129362306a36Sopenharmony_ci		word = rt2x00_desc_read(entry_priv->desc, 0);
129462306a36Sopenharmony_ci
129562306a36Sopenharmony_ci		return rt2x00_get_field32(word, RXD_W0_OWNER_NIC);
129662306a36Sopenharmony_ci	} else {
129762306a36Sopenharmony_ci		word = rt2x00_desc_read(entry_priv->desc, 0);
129862306a36Sopenharmony_ci
129962306a36Sopenharmony_ci		return (rt2x00_get_field32(word, TXD_W0_OWNER_NIC) ||
130062306a36Sopenharmony_ci		        rt2x00_get_field32(word, TXD_W0_VALID));
130162306a36Sopenharmony_ci	}
130262306a36Sopenharmony_ci}
130362306a36Sopenharmony_ci
130462306a36Sopenharmony_cistatic void rt61pci_clear_entry(struct queue_entry *entry)
130562306a36Sopenharmony_ci{
130662306a36Sopenharmony_ci	struct queue_entry_priv_mmio *entry_priv = entry->priv_data;
130762306a36Sopenharmony_ci	struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
130862306a36Sopenharmony_ci	u32 word;
130962306a36Sopenharmony_ci
131062306a36Sopenharmony_ci	if (entry->queue->qid == QID_RX) {
131162306a36Sopenharmony_ci		word = rt2x00_desc_read(entry_priv->desc, 5);
131262306a36Sopenharmony_ci		rt2x00_set_field32(&word, RXD_W5_BUFFER_PHYSICAL_ADDRESS,
131362306a36Sopenharmony_ci				   skbdesc->skb_dma);
131462306a36Sopenharmony_ci		rt2x00_desc_write(entry_priv->desc, 5, word);
131562306a36Sopenharmony_ci
131662306a36Sopenharmony_ci		word = rt2x00_desc_read(entry_priv->desc, 0);
131762306a36Sopenharmony_ci		rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1);
131862306a36Sopenharmony_ci		rt2x00_desc_write(entry_priv->desc, 0, word);
131962306a36Sopenharmony_ci	} else {
132062306a36Sopenharmony_ci		word = rt2x00_desc_read(entry_priv->desc, 0);
132162306a36Sopenharmony_ci		rt2x00_set_field32(&word, TXD_W0_VALID, 0);
132262306a36Sopenharmony_ci		rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0);
132362306a36Sopenharmony_ci		rt2x00_desc_write(entry_priv->desc, 0, word);
132462306a36Sopenharmony_ci	}
132562306a36Sopenharmony_ci}
132662306a36Sopenharmony_ci
132762306a36Sopenharmony_cistatic int rt61pci_init_queues(struct rt2x00_dev *rt2x00dev)
132862306a36Sopenharmony_ci{
132962306a36Sopenharmony_ci	struct queue_entry_priv_mmio *entry_priv;
133062306a36Sopenharmony_ci	u32 reg;
133162306a36Sopenharmony_ci
133262306a36Sopenharmony_ci	/*
133362306a36Sopenharmony_ci	 * Initialize registers.
133462306a36Sopenharmony_ci	 */
133562306a36Sopenharmony_ci	reg = rt2x00mmio_register_read(rt2x00dev, TX_RING_CSR0);
133662306a36Sopenharmony_ci	rt2x00_set_field32(&reg, TX_RING_CSR0_AC0_RING_SIZE,
133762306a36Sopenharmony_ci			   rt2x00dev->tx[0].limit);
133862306a36Sopenharmony_ci	rt2x00_set_field32(&reg, TX_RING_CSR0_AC1_RING_SIZE,
133962306a36Sopenharmony_ci			   rt2x00dev->tx[1].limit);
134062306a36Sopenharmony_ci	rt2x00_set_field32(&reg, TX_RING_CSR0_AC2_RING_SIZE,
134162306a36Sopenharmony_ci			   rt2x00dev->tx[2].limit);
134262306a36Sopenharmony_ci	rt2x00_set_field32(&reg, TX_RING_CSR0_AC3_RING_SIZE,
134362306a36Sopenharmony_ci			   rt2x00dev->tx[3].limit);
134462306a36Sopenharmony_ci	rt2x00mmio_register_write(rt2x00dev, TX_RING_CSR0, reg);
134562306a36Sopenharmony_ci
134662306a36Sopenharmony_ci	reg = rt2x00mmio_register_read(rt2x00dev, TX_RING_CSR1);
134762306a36Sopenharmony_ci	rt2x00_set_field32(&reg, TX_RING_CSR1_TXD_SIZE,
134862306a36Sopenharmony_ci			   rt2x00dev->tx[0].desc_size / 4);
134962306a36Sopenharmony_ci	rt2x00mmio_register_write(rt2x00dev, TX_RING_CSR1, reg);
135062306a36Sopenharmony_ci
135162306a36Sopenharmony_ci	entry_priv = rt2x00dev->tx[0].entries[0].priv_data;
135262306a36Sopenharmony_ci	reg = rt2x00mmio_register_read(rt2x00dev, AC0_BASE_CSR);
135362306a36Sopenharmony_ci	rt2x00_set_field32(&reg, AC0_BASE_CSR_RING_REGISTER,
135462306a36Sopenharmony_ci			   entry_priv->desc_dma);
135562306a36Sopenharmony_ci	rt2x00mmio_register_write(rt2x00dev, AC0_BASE_CSR, reg);
135662306a36Sopenharmony_ci
135762306a36Sopenharmony_ci	entry_priv = rt2x00dev->tx[1].entries[0].priv_data;
135862306a36Sopenharmony_ci	reg = rt2x00mmio_register_read(rt2x00dev, AC1_BASE_CSR);
135962306a36Sopenharmony_ci	rt2x00_set_field32(&reg, AC1_BASE_CSR_RING_REGISTER,
136062306a36Sopenharmony_ci			   entry_priv->desc_dma);
136162306a36Sopenharmony_ci	rt2x00mmio_register_write(rt2x00dev, AC1_BASE_CSR, reg);
136262306a36Sopenharmony_ci
136362306a36Sopenharmony_ci	entry_priv = rt2x00dev->tx[2].entries[0].priv_data;
136462306a36Sopenharmony_ci	reg = rt2x00mmio_register_read(rt2x00dev, AC2_BASE_CSR);
136562306a36Sopenharmony_ci	rt2x00_set_field32(&reg, AC2_BASE_CSR_RING_REGISTER,
136662306a36Sopenharmony_ci			   entry_priv->desc_dma);
136762306a36Sopenharmony_ci	rt2x00mmio_register_write(rt2x00dev, AC2_BASE_CSR, reg);
136862306a36Sopenharmony_ci
136962306a36Sopenharmony_ci	entry_priv = rt2x00dev->tx[3].entries[0].priv_data;
137062306a36Sopenharmony_ci	reg = rt2x00mmio_register_read(rt2x00dev, AC3_BASE_CSR);
137162306a36Sopenharmony_ci	rt2x00_set_field32(&reg, AC3_BASE_CSR_RING_REGISTER,
137262306a36Sopenharmony_ci			   entry_priv->desc_dma);
137362306a36Sopenharmony_ci	rt2x00mmio_register_write(rt2x00dev, AC3_BASE_CSR, reg);
137462306a36Sopenharmony_ci
137562306a36Sopenharmony_ci	reg = rt2x00mmio_register_read(rt2x00dev, RX_RING_CSR);
137662306a36Sopenharmony_ci	rt2x00_set_field32(&reg, RX_RING_CSR_RING_SIZE, rt2x00dev->rx->limit);
137762306a36Sopenharmony_ci	rt2x00_set_field32(&reg, RX_RING_CSR_RXD_SIZE,
137862306a36Sopenharmony_ci			   rt2x00dev->rx->desc_size / 4);
137962306a36Sopenharmony_ci	rt2x00_set_field32(&reg, RX_RING_CSR_RXD_WRITEBACK_SIZE, 4);
138062306a36Sopenharmony_ci	rt2x00mmio_register_write(rt2x00dev, RX_RING_CSR, reg);
138162306a36Sopenharmony_ci
138262306a36Sopenharmony_ci	entry_priv = rt2x00dev->rx->entries[0].priv_data;
138362306a36Sopenharmony_ci	reg = rt2x00mmio_register_read(rt2x00dev, RX_BASE_CSR);
138462306a36Sopenharmony_ci	rt2x00_set_field32(&reg, RX_BASE_CSR_RING_REGISTER,
138562306a36Sopenharmony_ci			   entry_priv->desc_dma);
138662306a36Sopenharmony_ci	rt2x00mmio_register_write(rt2x00dev, RX_BASE_CSR, reg);
138762306a36Sopenharmony_ci
138862306a36Sopenharmony_ci	reg = rt2x00mmio_register_read(rt2x00dev, TX_DMA_DST_CSR);
138962306a36Sopenharmony_ci	rt2x00_set_field32(&reg, TX_DMA_DST_CSR_DEST_AC0, 2);
139062306a36Sopenharmony_ci	rt2x00_set_field32(&reg, TX_DMA_DST_CSR_DEST_AC1, 2);
139162306a36Sopenharmony_ci	rt2x00_set_field32(&reg, TX_DMA_DST_CSR_DEST_AC2, 2);
139262306a36Sopenharmony_ci	rt2x00_set_field32(&reg, TX_DMA_DST_CSR_DEST_AC3, 2);
139362306a36Sopenharmony_ci	rt2x00mmio_register_write(rt2x00dev, TX_DMA_DST_CSR, reg);
139462306a36Sopenharmony_ci
139562306a36Sopenharmony_ci	reg = rt2x00mmio_register_read(rt2x00dev, LOAD_TX_RING_CSR);
139662306a36Sopenharmony_ci	rt2x00_set_field32(&reg, LOAD_TX_RING_CSR_LOAD_TXD_AC0, 1);
139762306a36Sopenharmony_ci	rt2x00_set_field32(&reg, LOAD_TX_RING_CSR_LOAD_TXD_AC1, 1);
139862306a36Sopenharmony_ci	rt2x00_set_field32(&reg, LOAD_TX_RING_CSR_LOAD_TXD_AC2, 1);
139962306a36Sopenharmony_ci	rt2x00_set_field32(&reg, LOAD_TX_RING_CSR_LOAD_TXD_AC3, 1);
140062306a36Sopenharmony_ci	rt2x00mmio_register_write(rt2x00dev, LOAD_TX_RING_CSR, reg);
140162306a36Sopenharmony_ci
140262306a36Sopenharmony_ci	reg = rt2x00mmio_register_read(rt2x00dev, RX_CNTL_CSR);
140362306a36Sopenharmony_ci	rt2x00_set_field32(&reg, RX_CNTL_CSR_LOAD_RXD, 1);
140462306a36Sopenharmony_ci	rt2x00mmio_register_write(rt2x00dev, RX_CNTL_CSR, reg);
140562306a36Sopenharmony_ci
140662306a36Sopenharmony_ci	return 0;
140762306a36Sopenharmony_ci}
140862306a36Sopenharmony_ci
140962306a36Sopenharmony_cistatic int rt61pci_init_registers(struct rt2x00_dev *rt2x00dev)
141062306a36Sopenharmony_ci{
141162306a36Sopenharmony_ci	u32 reg;
141262306a36Sopenharmony_ci
141362306a36Sopenharmony_ci	reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR0);
141462306a36Sopenharmony_ci	rt2x00_set_field32(&reg, TXRX_CSR0_AUTO_TX_SEQ, 1);
141562306a36Sopenharmony_ci	rt2x00_set_field32(&reg, TXRX_CSR0_DISABLE_RX, 0);
141662306a36Sopenharmony_ci	rt2x00_set_field32(&reg, TXRX_CSR0_TX_WITHOUT_WAITING, 0);
141762306a36Sopenharmony_ci	rt2x00mmio_register_write(rt2x00dev, TXRX_CSR0, reg);
141862306a36Sopenharmony_ci
141962306a36Sopenharmony_ci	reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR1);
142062306a36Sopenharmony_ci	rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID0, 47); /* CCK Signal */
142162306a36Sopenharmony_ci	rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID0_VALID, 1);
142262306a36Sopenharmony_ci	rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID1, 30); /* Rssi */
142362306a36Sopenharmony_ci	rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID1_VALID, 1);
142462306a36Sopenharmony_ci	rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID2, 42); /* OFDM Rate */
142562306a36Sopenharmony_ci	rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID2_VALID, 1);
142662306a36Sopenharmony_ci	rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID3, 30); /* Rssi */
142762306a36Sopenharmony_ci	rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID3_VALID, 1);
142862306a36Sopenharmony_ci	rt2x00mmio_register_write(rt2x00dev, TXRX_CSR1, reg);
142962306a36Sopenharmony_ci
143062306a36Sopenharmony_ci	/*
143162306a36Sopenharmony_ci	 * CCK TXD BBP registers
143262306a36Sopenharmony_ci	 */
143362306a36Sopenharmony_ci	reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR2);
143462306a36Sopenharmony_ci	rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID0, 13);
143562306a36Sopenharmony_ci	rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID0_VALID, 1);
143662306a36Sopenharmony_ci	rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID1, 12);
143762306a36Sopenharmony_ci	rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID1_VALID, 1);
143862306a36Sopenharmony_ci	rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID2, 11);
143962306a36Sopenharmony_ci	rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID2_VALID, 1);
144062306a36Sopenharmony_ci	rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID3, 10);
144162306a36Sopenharmony_ci	rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID3_VALID, 1);
144262306a36Sopenharmony_ci	rt2x00mmio_register_write(rt2x00dev, TXRX_CSR2, reg);
144362306a36Sopenharmony_ci
144462306a36Sopenharmony_ci	/*
144562306a36Sopenharmony_ci	 * OFDM TXD BBP registers
144662306a36Sopenharmony_ci	 */
144762306a36Sopenharmony_ci	reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR3);
144862306a36Sopenharmony_ci	rt2x00_set_field32(&reg, TXRX_CSR3_BBP_ID0, 7);
144962306a36Sopenharmony_ci	rt2x00_set_field32(&reg, TXRX_CSR3_BBP_ID0_VALID, 1);
145062306a36Sopenharmony_ci	rt2x00_set_field32(&reg, TXRX_CSR3_BBP_ID1, 6);
145162306a36Sopenharmony_ci	rt2x00_set_field32(&reg, TXRX_CSR3_BBP_ID1_VALID, 1);
145262306a36Sopenharmony_ci	rt2x00_set_field32(&reg, TXRX_CSR3_BBP_ID2, 5);
145362306a36Sopenharmony_ci	rt2x00_set_field32(&reg, TXRX_CSR3_BBP_ID2_VALID, 1);
145462306a36Sopenharmony_ci	rt2x00mmio_register_write(rt2x00dev, TXRX_CSR3, reg);
145562306a36Sopenharmony_ci
145662306a36Sopenharmony_ci	reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR7);
145762306a36Sopenharmony_ci	rt2x00_set_field32(&reg, TXRX_CSR7_ACK_CTS_6MBS, 59);
145862306a36Sopenharmony_ci	rt2x00_set_field32(&reg, TXRX_CSR7_ACK_CTS_9MBS, 53);
145962306a36Sopenharmony_ci	rt2x00_set_field32(&reg, TXRX_CSR7_ACK_CTS_12MBS, 49);
146062306a36Sopenharmony_ci	rt2x00_set_field32(&reg, TXRX_CSR7_ACK_CTS_18MBS, 46);
146162306a36Sopenharmony_ci	rt2x00mmio_register_write(rt2x00dev, TXRX_CSR7, reg);
146262306a36Sopenharmony_ci
146362306a36Sopenharmony_ci	reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR8);
146462306a36Sopenharmony_ci	rt2x00_set_field32(&reg, TXRX_CSR8_ACK_CTS_24MBS, 44);
146562306a36Sopenharmony_ci	rt2x00_set_field32(&reg, TXRX_CSR8_ACK_CTS_36MBS, 42);
146662306a36Sopenharmony_ci	rt2x00_set_field32(&reg, TXRX_CSR8_ACK_CTS_48MBS, 42);
146762306a36Sopenharmony_ci	rt2x00_set_field32(&reg, TXRX_CSR8_ACK_CTS_54MBS, 42);
146862306a36Sopenharmony_ci	rt2x00mmio_register_write(rt2x00dev, TXRX_CSR8, reg);
146962306a36Sopenharmony_ci
147062306a36Sopenharmony_ci	reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR9);
147162306a36Sopenharmony_ci	rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_INTERVAL, 0);
147262306a36Sopenharmony_ci	rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 0);
147362306a36Sopenharmony_ci	rt2x00_set_field32(&reg, TXRX_CSR9_TSF_SYNC, 0);
147462306a36Sopenharmony_ci	rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 0);
147562306a36Sopenharmony_ci	rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 0);
147662306a36Sopenharmony_ci	rt2x00_set_field32(&reg, TXRX_CSR9_TIMESTAMP_COMPENSATE, 0);
147762306a36Sopenharmony_ci	rt2x00mmio_register_write(rt2x00dev, TXRX_CSR9, reg);
147862306a36Sopenharmony_ci
147962306a36Sopenharmony_ci	rt2x00mmio_register_write(rt2x00dev, TXRX_CSR15, 0x0000000f);
148062306a36Sopenharmony_ci
148162306a36Sopenharmony_ci	rt2x00mmio_register_write(rt2x00dev, MAC_CSR6, 0x00000fff);
148262306a36Sopenharmony_ci
148362306a36Sopenharmony_ci	reg = rt2x00mmio_register_read(rt2x00dev, MAC_CSR9);
148462306a36Sopenharmony_ci	rt2x00_set_field32(&reg, MAC_CSR9_CW_SELECT, 0);
148562306a36Sopenharmony_ci	rt2x00mmio_register_write(rt2x00dev, MAC_CSR9, reg);
148662306a36Sopenharmony_ci
148762306a36Sopenharmony_ci	rt2x00mmio_register_write(rt2x00dev, MAC_CSR10, 0x0000071c);
148862306a36Sopenharmony_ci
148962306a36Sopenharmony_ci	if (rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_AWAKE))
149062306a36Sopenharmony_ci		return -EBUSY;
149162306a36Sopenharmony_ci
149262306a36Sopenharmony_ci	rt2x00mmio_register_write(rt2x00dev, MAC_CSR13, 0x0000e000);
149362306a36Sopenharmony_ci
149462306a36Sopenharmony_ci	/*
149562306a36Sopenharmony_ci	 * Invalidate all Shared Keys (SEC_CSR0),
149662306a36Sopenharmony_ci	 * and clear the Shared key Cipher algorithms (SEC_CSR1 & SEC_CSR5)
149762306a36Sopenharmony_ci	 */
149862306a36Sopenharmony_ci	rt2x00mmio_register_write(rt2x00dev, SEC_CSR0, 0x00000000);
149962306a36Sopenharmony_ci	rt2x00mmio_register_write(rt2x00dev, SEC_CSR1, 0x00000000);
150062306a36Sopenharmony_ci	rt2x00mmio_register_write(rt2x00dev, SEC_CSR5, 0x00000000);
150162306a36Sopenharmony_ci
150262306a36Sopenharmony_ci	rt2x00mmio_register_write(rt2x00dev, PHY_CSR1, 0x000023b0);
150362306a36Sopenharmony_ci	rt2x00mmio_register_write(rt2x00dev, PHY_CSR5, 0x060a100c);
150462306a36Sopenharmony_ci	rt2x00mmio_register_write(rt2x00dev, PHY_CSR6, 0x00080606);
150562306a36Sopenharmony_ci	rt2x00mmio_register_write(rt2x00dev, PHY_CSR7, 0x00000a08);
150662306a36Sopenharmony_ci
150762306a36Sopenharmony_ci	rt2x00mmio_register_write(rt2x00dev, PCI_CFG_CSR, 0x28ca4404);
150862306a36Sopenharmony_ci
150962306a36Sopenharmony_ci	rt2x00mmio_register_write(rt2x00dev, TEST_MODE_CSR, 0x00000200);
151062306a36Sopenharmony_ci
151162306a36Sopenharmony_ci	rt2x00mmio_register_write(rt2x00dev, M2H_CMD_DONE_CSR, 0xffffffff);
151262306a36Sopenharmony_ci
151362306a36Sopenharmony_ci	/*
151462306a36Sopenharmony_ci	 * Clear all beacons
151562306a36Sopenharmony_ci	 * For the Beacon base registers we only need to clear
151662306a36Sopenharmony_ci	 * the first byte since that byte contains the VALID and OWNER
151762306a36Sopenharmony_ci	 * bits which (when set to 0) will invalidate the entire beacon.
151862306a36Sopenharmony_ci	 */
151962306a36Sopenharmony_ci	rt2x00mmio_register_write(rt2x00dev, HW_BEACON_BASE0, 0);
152062306a36Sopenharmony_ci	rt2x00mmio_register_write(rt2x00dev, HW_BEACON_BASE1, 0);
152162306a36Sopenharmony_ci	rt2x00mmio_register_write(rt2x00dev, HW_BEACON_BASE2, 0);
152262306a36Sopenharmony_ci	rt2x00mmio_register_write(rt2x00dev, HW_BEACON_BASE3, 0);
152362306a36Sopenharmony_ci
152462306a36Sopenharmony_ci	/*
152562306a36Sopenharmony_ci	 * We must clear the error counters.
152662306a36Sopenharmony_ci	 * These registers are cleared on read,
152762306a36Sopenharmony_ci	 * so we may pass a useless variable to store the value.
152862306a36Sopenharmony_ci	 */
152962306a36Sopenharmony_ci	reg = rt2x00mmio_register_read(rt2x00dev, STA_CSR0);
153062306a36Sopenharmony_ci	reg = rt2x00mmio_register_read(rt2x00dev, STA_CSR1);
153162306a36Sopenharmony_ci	reg = rt2x00mmio_register_read(rt2x00dev, STA_CSR2);
153262306a36Sopenharmony_ci
153362306a36Sopenharmony_ci	/*
153462306a36Sopenharmony_ci	 * Reset MAC and BBP registers.
153562306a36Sopenharmony_ci	 */
153662306a36Sopenharmony_ci	reg = rt2x00mmio_register_read(rt2x00dev, MAC_CSR1);
153762306a36Sopenharmony_ci	rt2x00_set_field32(&reg, MAC_CSR1_SOFT_RESET, 1);
153862306a36Sopenharmony_ci	rt2x00_set_field32(&reg, MAC_CSR1_BBP_RESET, 1);
153962306a36Sopenharmony_ci	rt2x00mmio_register_write(rt2x00dev, MAC_CSR1, reg);
154062306a36Sopenharmony_ci
154162306a36Sopenharmony_ci	reg = rt2x00mmio_register_read(rt2x00dev, MAC_CSR1);
154262306a36Sopenharmony_ci	rt2x00_set_field32(&reg, MAC_CSR1_SOFT_RESET, 0);
154362306a36Sopenharmony_ci	rt2x00_set_field32(&reg, MAC_CSR1_BBP_RESET, 0);
154462306a36Sopenharmony_ci	rt2x00mmio_register_write(rt2x00dev, MAC_CSR1, reg);
154562306a36Sopenharmony_ci
154662306a36Sopenharmony_ci	reg = rt2x00mmio_register_read(rt2x00dev, MAC_CSR1);
154762306a36Sopenharmony_ci	rt2x00_set_field32(&reg, MAC_CSR1_HOST_READY, 1);
154862306a36Sopenharmony_ci	rt2x00mmio_register_write(rt2x00dev, MAC_CSR1, reg);
154962306a36Sopenharmony_ci
155062306a36Sopenharmony_ci	return 0;
155162306a36Sopenharmony_ci}
155262306a36Sopenharmony_ci
155362306a36Sopenharmony_cistatic int rt61pci_wait_bbp_ready(struct rt2x00_dev *rt2x00dev)
155462306a36Sopenharmony_ci{
155562306a36Sopenharmony_ci	unsigned int i;
155662306a36Sopenharmony_ci	u8 value;
155762306a36Sopenharmony_ci
155862306a36Sopenharmony_ci	for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
155962306a36Sopenharmony_ci		value = rt61pci_bbp_read(rt2x00dev, 0);
156062306a36Sopenharmony_ci		if ((value != 0xff) && (value != 0x00))
156162306a36Sopenharmony_ci			return 0;
156262306a36Sopenharmony_ci		udelay(REGISTER_BUSY_DELAY);
156362306a36Sopenharmony_ci	}
156462306a36Sopenharmony_ci
156562306a36Sopenharmony_ci	rt2x00_err(rt2x00dev, "BBP register access failed, aborting\n");
156662306a36Sopenharmony_ci	return -EACCES;
156762306a36Sopenharmony_ci}
156862306a36Sopenharmony_ci
156962306a36Sopenharmony_cistatic int rt61pci_init_bbp(struct rt2x00_dev *rt2x00dev)
157062306a36Sopenharmony_ci{
157162306a36Sopenharmony_ci	unsigned int i;
157262306a36Sopenharmony_ci	u16 eeprom;
157362306a36Sopenharmony_ci	u8 reg_id;
157462306a36Sopenharmony_ci	u8 value;
157562306a36Sopenharmony_ci
157662306a36Sopenharmony_ci	if (unlikely(rt61pci_wait_bbp_ready(rt2x00dev)))
157762306a36Sopenharmony_ci		return -EACCES;
157862306a36Sopenharmony_ci
157962306a36Sopenharmony_ci	rt61pci_bbp_write(rt2x00dev, 3, 0x00);
158062306a36Sopenharmony_ci	rt61pci_bbp_write(rt2x00dev, 15, 0x30);
158162306a36Sopenharmony_ci	rt61pci_bbp_write(rt2x00dev, 21, 0xc8);
158262306a36Sopenharmony_ci	rt61pci_bbp_write(rt2x00dev, 22, 0x38);
158362306a36Sopenharmony_ci	rt61pci_bbp_write(rt2x00dev, 23, 0x06);
158462306a36Sopenharmony_ci	rt61pci_bbp_write(rt2x00dev, 24, 0xfe);
158562306a36Sopenharmony_ci	rt61pci_bbp_write(rt2x00dev, 25, 0x0a);
158662306a36Sopenharmony_ci	rt61pci_bbp_write(rt2x00dev, 26, 0x0d);
158762306a36Sopenharmony_ci	rt61pci_bbp_write(rt2x00dev, 34, 0x12);
158862306a36Sopenharmony_ci	rt61pci_bbp_write(rt2x00dev, 37, 0x07);
158962306a36Sopenharmony_ci	rt61pci_bbp_write(rt2x00dev, 39, 0xf8);
159062306a36Sopenharmony_ci	rt61pci_bbp_write(rt2x00dev, 41, 0x60);
159162306a36Sopenharmony_ci	rt61pci_bbp_write(rt2x00dev, 53, 0x10);
159262306a36Sopenharmony_ci	rt61pci_bbp_write(rt2x00dev, 54, 0x18);
159362306a36Sopenharmony_ci	rt61pci_bbp_write(rt2x00dev, 60, 0x10);
159462306a36Sopenharmony_ci	rt61pci_bbp_write(rt2x00dev, 61, 0x04);
159562306a36Sopenharmony_ci	rt61pci_bbp_write(rt2x00dev, 62, 0x04);
159662306a36Sopenharmony_ci	rt61pci_bbp_write(rt2x00dev, 75, 0xfe);
159762306a36Sopenharmony_ci	rt61pci_bbp_write(rt2x00dev, 86, 0xfe);
159862306a36Sopenharmony_ci	rt61pci_bbp_write(rt2x00dev, 88, 0xfe);
159962306a36Sopenharmony_ci	rt61pci_bbp_write(rt2x00dev, 90, 0x0f);
160062306a36Sopenharmony_ci	rt61pci_bbp_write(rt2x00dev, 99, 0x00);
160162306a36Sopenharmony_ci	rt61pci_bbp_write(rt2x00dev, 102, 0x16);
160262306a36Sopenharmony_ci	rt61pci_bbp_write(rt2x00dev, 107, 0x04);
160362306a36Sopenharmony_ci
160462306a36Sopenharmony_ci	for (i = 0; i < EEPROM_BBP_SIZE; i++) {
160562306a36Sopenharmony_ci		eeprom = rt2x00_eeprom_read(rt2x00dev, EEPROM_BBP_START + i);
160662306a36Sopenharmony_ci
160762306a36Sopenharmony_ci		if (eeprom != 0xffff && eeprom != 0x0000) {
160862306a36Sopenharmony_ci			reg_id = rt2x00_get_field16(eeprom, EEPROM_BBP_REG_ID);
160962306a36Sopenharmony_ci			value = rt2x00_get_field16(eeprom, EEPROM_BBP_VALUE);
161062306a36Sopenharmony_ci			rt61pci_bbp_write(rt2x00dev, reg_id, value);
161162306a36Sopenharmony_ci		}
161262306a36Sopenharmony_ci	}
161362306a36Sopenharmony_ci
161462306a36Sopenharmony_ci	return 0;
161562306a36Sopenharmony_ci}
161662306a36Sopenharmony_ci
161762306a36Sopenharmony_ci/*
161862306a36Sopenharmony_ci * Device state switch handlers.
161962306a36Sopenharmony_ci */
162062306a36Sopenharmony_cistatic void rt61pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
162162306a36Sopenharmony_ci			       enum dev_state state)
162262306a36Sopenharmony_ci{
162362306a36Sopenharmony_ci	int mask = (state == STATE_RADIO_IRQ_OFF);
162462306a36Sopenharmony_ci	u32 reg;
162562306a36Sopenharmony_ci	unsigned long flags;
162662306a36Sopenharmony_ci
162762306a36Sopenharmony_ci	/*
162862306a36Sopenharmony_ci	 * When interrupts are being enabled, the interrupt registers
162962306a36Sopenharmony_ci	 * should clear the register to assure a clean state.
163062306a36Sopenharmony_ci	 */
163162306a36Sopenharmony_ci	if (state == STATE_RADIO_IRQ_ON) {
163262306a36Sopenharmony_ci		reg = rt2x00mmio_register_read(rt2x00dev, INT_SOURCE_CSR);
163362306a36Sopenharmony_ci		rt2x00mmio_register_write(rt2x00dev, INT_SOURCE_CSR, reg);
163462306a36Sopenharmony_ci
163562306a36Sopenharmony_ci		reg = rt2x00mmio_register_read(rt2x00dev, MCU_INT_SOURCE_CSR);
163662306a36Sopenharmony_ci		rt2x00mmio_register_write(rt2x00dev, MCU_INT_SOURCE_CSR, reg);
163762306a36Sopenharmony_ci	}
163862306a36Sopenharmony_ci
163962306a36Sopenharmony_ci	/*
164062306a36Sopenharmony_ci	 * Only toggle the interrupts bits we are going to use.
164162306a36Sopenharmony_ci	 * Non-checked interrupt bits are disabled by default.
164262306a36Sopenharmony_ci	 */
164362306a36Sopenharmony_ci	spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags);
164462306a36Sopenharmony_ci
164562306a36Sopenharmony_ci	reg = rt2x00mmio_register_read(rt2x00dev, INT_MASK_CSR);
164662306a36Sopenharmony_ci	rt2x00_set_field32(&reg, INT_MASK_CSR_TXDONE, mask);
164762306a36Sopenharmony_ci	rt2x00_set_field32(&reg, INT_MASK_CSR_RXDONE, mask);
164862306a36Sopenharmony_ci	rt2x00_set_field32(&reg, INT_MASK_CSR_BEACON_DONE, mask);
164962306a36Sopenharmony_ci	rt2x00_set_field32(&reg, INT_MASK_CSR_ENABLE_MITIGATION, mask);
165062306a36Sopenharmony_ci	rt2x00_set_field32(&reg, INT_MASK_CSR_MITIGATION_PERIOD, 0xff);
165162306a36Sopenharmony_ci	rt2x00mmio_register_write(rt2x00dev, INT_MASK_CSR, reg);
165262306a36Sopenharmony_ci
165362306a36Sopenharmony_ci	reg = rt2x00mmio_register_read(rt2x00dev, MCU_INT_MASK_CSR);
165462306a36Sopenharmony_ci	rt2x00_set_field32(&reg, MCU_INT_MASK_CSR_0, mask);
165562306a36Sopenharmony_ci	rt2x00_set_field32(&reg, MCU_INT_MASK_CSR_1, mask);
165662306a36Sopenharmony_ci	rt2x00_set_field32(&reg, MCU_INT_MASK_CSR_2, mask);
165762306a36Sopenharmony_ci	rt2x00_set_field32(&reg, MCU_INT_MASK_CSR_3, mask);
165862306a36Sopenharmony_ci	rt2x00_set_field32(&reg, MCU_INT_MASK_CSR_4, mask);
165962306a36Sopenharmony_ci	rt2x00_set_field32(&reg, MCU_INT_MASK_CSR_5, mask);
166062306a36Sopenharmony_ci	rt2x00_set_field32(&reg, MCU_INT_MASK_CSR_6, mask);
166162306a36Sopenharmony_ci	rt2x00_set_field32(&reg, MCU_INT_MASK_CSR_7, mask);
166262306a36Sopenharmony_ci	rt2x00_set_field32(&reg, MCU_INT_MASK_CSR_TWAKEUP, mask);
166362306a36Sopenharmony_ci	rt2x00mmio_register_write(rt2x00dev, MCU_INT_MASK_CSR, reg);
166462306a36Sopenharmony_ci
166562306a36Sopenharmony_ci	spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags);
166662306a36Sopenharmony_ci
166762306a36Sopenharmony_ci	if (state == STATE_RADIO_IRQ_OFF) {
166862306a36Sopenharmony_ci		/*
166962306a36Sopenharmony_ci		 * Ensure that all tasklets are finished.
167062306a36Sopenharmony_ci		 */
167162306a36Sopenharmony_ci		tasklet_kill(&rt2x00dev->txstatus_tasklet);
167262306a36Sopenharmony_ci		tasklet_kill(&rt2x00dev->rxdone_tasklet);
167362306a36Sopenharmony_ci		tasklet_kill(&rt2x00dev->autowake_tasklet);
167462306a36Sopenharmony_ci		tasklet_kill(&rt2x00dev->tbtt_tasklet);
167562306a36Sopenharmony_ci	}
167662306a36Sopenharmony_ci}
167762306a36Sopenharmony_ci
167862306a36Sopenharmony_cistatic int rt61pci_enable_radio(struct rt2x00_dev *rt2x00dev)
167962306a36Sopenharmony_ci{
168062306a36Sopenharmony_ci	u32 reg;
168162306a36Sopenharmony_ci
168262306a36Sopenharmony_ci	/*
168362306a36Sopenharmony_ci	 * Initialize all registers.
168462306a36Sopenharmony_ci	 */
168562306a36Sopenharmony_ci	if (unlikely(rt61pci_init_queues(rt2x00dev) ||
168662306a36Sopenharmony_ci		     rt61pci_init_registers(rt2x00dev) ||
168762306a36Sopenharmony_ci		     rt61pci_init_bbp(rt2x00dev)))
168862306a36Sopenharmony_ci		return -EIO;
168962306a36Sopenharmony_ci
169062306a36Sopenharmony_ci	/*
169162306a36Sopenharmony_ci	 * Enable RX.
169262306a36Sopenharmony_ci	 */
169362306a36Sopenharmony_ci	reg = rt2x00mmio_register_read(rt2x00dev, RX_CNTL_CSR);
169462306a36Sopenharmony_ci	rt2x00_set_field32(&reg, RX_CNTL_CSR_ENABLE_RX_DMA, 1);
169562306a36Sopenharmony_ci	rt2x00mmio_register_write(rt2x00dev, RX_CNTL_CSR, reg);
169662306a36Sopenharmony_ci
169762306a36Sopenharmony_ci	return 0;
169862306a36Sopenharmony_ci}
169962306a36Sopenharmony_ci
170062306a36Sopenharmony_cistatic void rt61pci_disable_radio(struct rt2x00_dev *rt2x00dev)
170162306a36Sopenharmony_ci{
170262306a36Sopenharmony_ci	/*
170362306a36Sopenharmony_ci	 * Disable power
170462306a36Sopenharmony_ci	 */
170562306a36Sopenharmony_ci	rt2x00mmio_register_write(rt2x00dev, MAC_CSR10, 0x00001818);
170662306a36Sopenharmony_ci}
170762306a36Sopenharmony_ci
170862306a36Sopenharmony_cistatic int rt61pci_set_state(struct rt2x00_dev *rt2x00dev, enum dev_state state)
170962306a36Sopenharmony_ci{
171062306a36Sopenharmony_ci	u32 reg, reg2;
171162306a36Sopenharmony_ci	unsigned int i;
171262306a36Sopenharmony_ci	bool put_to_sleep;
171362306a36Sopenharmony_ci
171462306a36Sopenharmony_ci	put_to_sleep = (state != STATE_AWAKE);
171562306a36Sopenharmony_ci
171662306a36Sopenharmony_ci	reg = rt2x00mmio_register_read(rt2x00dev, MAC_CSR12);
171762306a36Sopenharmony_ci	rt2x00_set_field32(&reg, MAC_CSR12_FORCE_WAKEUP, !put_to_sleep);
171862306a36Sopenharmony_ci	rt2x00_set_field32(&reg, MAC_CSR12_PUT_TO_SLEEP, put_to_sleep);
171962306a36Sopenharmony_ci	rt2x00mmio_register_write(rt2x00dev, MAC_CSR12, reg);
172062306a36Sopenharmony_ci
172162306a36Sopenharmony_ci	/*
172262306a36Sopenharmony_ci	 * Device is not guaranteed to be in the requested state yet.
172362306a36Sopenharmony_ci	 * We must wait until the register indicates that the
172462306a36Sopenharmony_ci	 * device has entered the correct state.
172562306a36Sopenharmony_ci	 */
172662306a36Sopenharmony_ci	for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
172762306a36Sopenharmony_ci		reg2 = rt2x00mmio_register_read(rt2x00dev, MAC_CSR12);
172862306a36Sopenharmony_ci		state = rt2x00_get_field32(reg2, MAC_CSR12_BBP_CURRENT_STATE);
172962306a36Sopenharmony_ci		if (state == !put_to_sleep)
173062306a36Sopenharmony_ci			return 0;
173162306a36Sopenharmony_ci		rt2x00mmio_register_write(rt2x00dev, MAC_CSR12, reg);
173262306a36Sopenharmony_ci		msleep(10);
173362306a36Sopenharmony_ci	}
173462306a36Sopenharmony_ci
173562306a36Sopenharmony_ci	return -EBUSY;
173662306a36Sopenharmony_ci}
173762306a36Sopenharmony_ci
173862306a36Sopenharmony_cistatic int rt61pci_set_device_state(struct rt2x00_dev *rt2x00dev,
173962306a36Sopenharmony_ci				    enum dev_state state)
174062306a36Sopenharmony_ci{
174162306a36Sopenharmony_ci	int retval = 0;
174262306a36Sopenharmony_ci
174362306a36Sopenharmony_ci	switch (state) {
174462306a36Sopenharmony_ci	case STATE_RADIO_ON:
174562306a36Sopenharmony_ci		retval = rt61pci_enable_radio(rt2x00dev);
174662306a36Sopenharmony_ci		break;
174762306a36Sopenharmony_ci	case STATE_RADIO_OFF:
174862306a36Sopenharmony_ci		rt61pci_disable_radio(rt2x00dev);
174962306a36Sopenharmony_ci		break;
175062306a36Sopenharmony_ci	case STATE_RADIO_IRQ_ON:
175162306a36Sopenharmony_ci	case STATE_RADIO_IRQ_OFF:
175262306a36Sopenharmony_ci		rt61pci_toggle_irq(rt2x00dev, state);
175362306a36Sopenharmony_ci		break;
175462306a36Sopenharmony_ci	case STATE_DEEP_SLEEP:
175562306a36Sopenharmony_ci	case STATE_SLEEP:
175662306a36Sopenharmony_ci	case STATE_STANDBY:
175762306a36Sopenharmony_ci	case STATE_AWAKE:
175862306a36Sopenharmony_ci		retval = rt61pci_set_state(rt2x00dev, state);
175962306a36Sopenharmony_ci		break;
176062306a36Sopenharmony_ci	default:
176162306a36Sopenharmony_ci		retval = -ENOTSUPP;
176262306a36Sopenharmony_ci		break;
176362306a36Sopenharmony_ci	}
176462306a36Sopenharmony_ci
176562306a36Sopenharmony_ci	if (unlikely(retval))
176662306a36Sopenharmony_ci		rt2x00_err(rt2x00dev, "Device failed to enter state %d (%d)\n",
176762306a36Sopenharmony_ci			   state, retval);
176862306a36Sopenharmony_ci
176962306a36Sopenharmony_ci	return retval;
177062306a36Sopenharmony_ci}
177162306a36Sopenharmony_ci
177262306a36Sopenharmony_ci/*
177362306a36Sopenharmony_ci * TX descriptor initialization
177462306a36Sopenharmony_ci */
177562306a36Sopenharmony_cistatic void rt61pci_write_tx_desc(struct queue_entry *entry,
177662306a36Sopenharmony_ci				  struct txentry_desc *txdesc)
177762306a36Sopenharmony_ci{
177862306a36Sopenharmony_ci	struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
177962306a36Sopenharmony_ci	struct queue_entry_priv_mmio *entry_priv = entry->priv_data;
178062306a36Sopenharmony_ci	__le32 *txd = entry_priv->desc;
178162306a36Sopenharmony_ci	u32 word;
178262306a36Sopenharmony_ci
178362306a36Sopenharmony_ci	/*
178462306a36Sopenharmony_ci	 * Start writing the descriptor words.
178562306a36Sopenharmony_ci	 */
178662306a36Sopenharmony_ci	word = rt2x00_desc_read(txd, 1);
178762306a36Sopenharmony_ci	rt2x00_set_field32(&word, TXD_W1_HOST_Q_ID, entry->queue->qid);
178862306a36Sopenharmony_ci	rt2x00_set_field32(&word, TXD_W1_AIFSN, entry->queue->aifs);
178962306a36Sopenharmony_ci	rt2x00_set_field32(&word, TXD_W1_CWMIN, entry->queue->cw_min);
179062306a36Sopenharmony_ci	rt2x00_set_field32(&word, TXD_W1_CWMAX, entry->queue->cw_max);
179162306a36Sopenharmony_ci	rt2x00_set_field32(&word, TXD_W1_IV_OFFSET, txdesc->iv_offset);
179262306a36Sopenharmony_ci	rt2x00_set_field32(&word, TXD_W1_HW_SEQUENCE,
179362306a36Sopenharmony_ci			   test_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags));
179462306a36Sopenharmony_ci	rt2x00_set_field32(&word, TXD_W1_BUFFER_COUNT, 1);
179562306a36Sopenharmony_ci	rt2x00_desc_write(txd, 1, word);
179662306a36Sopenharmony_ci
179762306a36Sopenharmony_ci	word = rt2x00_desc_read(txd, 2);
179862306a36Sopenharmony_ci	rt2x00_set_field32(&word, TXD_W2_PLCP_SIGNAL, txdesc->u.plcp.signal);
179962306a36Sopenharmony_ci	rt2x00_set_field32(&word, TXD_W2_PLCP_SERVICE, txdesc->u.plcp.service);
180062306a36Sopenharmony_ci	rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_LOW,
180162306a36Sopenharmony_ci			   txdesc->u.plcp.length_low);
180262306a36Sopenharmony_ci	rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_HIGH,
180362306a36Sopenharmony_ci			   txdesc->u.plcp.length_high);
180462306a36Sopenharmony_ci	rt2x00_desc_write(txd, 2, word);
180562306a36Sopenharmony_ci
180662306a36Sopenharmony_ci	if (test_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags)) {
180762306a36Sopenharmony_ci		_rt2x00_desc_write(txd, 3, skbdesc->iv[0]);
180862306a36Sopenharmony_ci		_rt2x00_desc_write(txd, 4, skbdesc->iv[1]);
180962306a36Sopenharmony_ci	}
181062306a36Sopenharmony_ci
181162306a36Sopenharmony_ci	word = rt2x00_desc_read(txd, 5);
181262306a36Sopenharmony_ci	rt2x00_set_field32(&word, TXD_W5_PID_TYPE, entry->queue->qid);
181362306a36Sopenharmony_ci	rt2x00_set_field32(&word, TXD_W5_PID_SUBTYPE, entry->entry_idx);
181462306a36Sopenharmony_ci	rt2x00_set_field32(&word, TXD_W5_TX_POWER,
181562306a36Sopenharmony_ci			   TXPOWER_TO_DEV(entry->queue->rt2x00dev->tx_power));
181662306a36Sopenharmony_ci	rt2x00_set_field32(&word, TXD_W5_WAITING_DMA_DONE_INT, 1);
181762306a36Sopenharmony_ci	rt2x00_desc_write(txd, 5, word);
181862306a36Sopenharmony_ci
181962306a36Sopenharmony_ci	if (entry->queue->qid != QID_BEACON) {
182062306a36Sopenharmony_ci		word = rt2x00_desc_read(txd, 6);
182162306a36Sopenharmony_ci		rt2x00_set_field32(&word, TXD_W6_BUFFER_PHYSICAL_ADDRESS,
182262306a36Sopenharmony_ci				   skbdesc->skb_dma);
182362306a36Sopenharmony_ci		rt2x00_desc_write(txd, 6, word);
182462306a36Sopenharmony_ci
182562306a36Sopenharmony_ci		word = rt2x00_desc_read(txd, 11);
182662306a36Sopenharmony_ci		rt2x00_set_field32(&word, TXD_W11_BUFFER_LENGTH0,
182762306a36Sopenharmony_ci				   txdesc->length);
182862306a36Sopenharmony_ci		rt2x00_desc_write(txd, 11, word);
182962306a36Sopenharmony_ci	}
183062306a36Sopenharmony_ci
183162306a36Sopenharmony_ci	/*
183262306a36Sopenharmony_ci	 * Writing TXD word 0 must the last to prevent a race condition with
183362306a36Sopenharmony_ci	 * the device, whereby the device may take hold of the TXD before we
183462306a36Sopenharmony_ci	 * finished updating it.
183562306a36Sopenharmony_ci	 */
183662306a36Sopenharmony_ci	word = rt2x00_desc_read(txd, 0);
183762306a36Sopenharmony_ci	rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 1);
183862306a36Sopenharmony_ci	rt2x00_set_field32(&word, TXD_W0_VALID, 1);
183962306a36Sopenharmony_ci	rt2x00_set_field32(&word, TXD_W0_MORE_FRAG,
184062306a36Sopenharmony_ci			   test_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags));
184162306a36Sopenharmony_ci	rt2x00_set_field32(&word, TXD_W0_ACK,
184262306a36Sopenharmony_ci			   test_bit(ENTRY_TXD_ACK, &txdesc->flags));
184362306a36Sopenharmony_ci	rt2x00_set_field32(&word, TXD_W0_TIMESTAMP,
184462306a36Sopenharmony_ci			   test_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc->flags));
184562306a36Sopenharmony_ci	rt2x00_set_field32(&word, TXD_W0_OFDM,
184662306a36Sopenharmony_ci			   (txdesc->rate_mode == RATE_MODE_OFDM));
184762306a36Sopenharmony_ci	rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->u.plcp.ifs);
184862306a36Sopenharmony_ci	rt2x00_set_field32(&word, TXD_W0_RETRY_MODE,
184962306a36Sopenharmony_ci			   test_bit(ENTRY_TXD_RETRY_MODE, &txdesc->flags));
185062306a36Sopenharmony_ci	rt2x00_set_field32(&word, TXD_W0_TKIP_MIC,
185162306a36Sopenharmony_ci			   test_bit(ENTRY_TXD_ENCRYPT_MMIC, &txdesc->flags));
185262306a36Sopenharmony_ci	rt2x00_set_field32(&word, TXD_W0_KEY_TABLE,
185362306a36Sopenharmony_ci			   test_bit(ENTRY_TXD_ENCRYPT_PAIRWISE, &txdesc->flags));
185462306a36Sopenharmony_ci	rt2x00_set_field32(&word, TXD_W0_KEY_INDEX, txdesc->key_idx);
185562306a36Sopenharmony_ci	rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, txdesc->length);
185662306a36Sopenharmony_ci	rt2x00_set_field32(&word, TXD_W0_BURST,
185762306a36Sopenharmony_ci			   test_bit(ENTRY_TXD_BURST, &txdesc->flags));
185862306a36Sopenharmony_ci	rt2x00_set_field32(&word, TXD_W0_CIPHER_ALG, txdesc->cipher);
185962306a36Sopenharmony_ci	rt2x00_desc_write(txd, 0, word);
186062306a36Sopenharmony_ci
186162306a36Sopenharmony_ci	/*
186262306a36Sopenharmony_ci	 * Register descriptor details in skb frame descriptor.
186362306a36Sopenharmony_ci	 */
186462306a36Sopenharmony_ci	skbdesc->desc = txd;
186562306a36Sopenharmony_ci	skbdesc->desc_len = (entry->queue->qid == QID_BEACON) ? TXINFO_SIZE :
186662306a36Sopenharmony_ci			    TXD_DESC_SIZE;
186762306a36Sopenharmony_ci}
186862306a36Sopenharmony_ci
186962306a36Sopenharmony_ci/*
187062306a36Sopenharmony_ci * TX data initialization
187162306a36Sopenharmony_ci */
187262306a36Sopenharmony_cistatic void rt61pci_write_beacon(struct queue_entry *entry,
187362306a36Sopenharmony_ci				 struct txentry_desc *txdesc)
187462306a36Sopenharmony_ci{
187562306a36Sopenharmony_ci	struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
187662306a36Sopenharmony_ci	struct queue_entry_priv_mmio *entry_priv = entry->priv_data;
187762306a36Sopenharmony_ci	unsigned int beacon_base;
187862306a36Sopenharmony_ci	unsigned int padding_len;
187962306a36Sopenharmony_ci	u32 orig_reg, reg;
188062306a36Sopenharmony_ci
188162306a36Sopenharmony_ci	/*
188262306a36Sopenharmony_ci	 * Disable beaconing while we are reloading the beacon data,
188362306a36Sopenharmony_ci	 * otherwise we might be sending out invalid data.
188462306a36Sopenharmony_ci	 */
188562306a36Sopenharmony_ci	reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR9);
188662306a36Sopenharmony_ci	orig_reg = reg;
188762306a36Sopenharmony_ci	rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 0);
188862306a36Sopenharmony_ci	rt2x00mmio_register_write(rt2x00dev, TXRX_CSR9, reg);
188962306a36Sopenharmony_ci
189062306a36Sopenharmony_ci	/*
189162306a36Sopenharmony_ci	 * Write the TX descriptor for the beacon.
189262306a36Sopenharmony_ci	 */
189362306a36Sopenharmony_ci	rt61pci_write_tx_desc(entry, txdesc);
189462306a36Sopenharmony_ci
189562306a36Sopenharmony_ci	/*
189662306a36Sopenharmony_ci	 * Dump beacon to userspace through debugfs.
189762306a36Sopenharmony_ci	 */
189862306a36Sopenharmony_ci	rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_BEACON, entry);
189962306a36Sopenharmony_ci
190062306a36Sopenharmony_ci	/*
190162306a36Sopenharmony_ci	 * Write entire beacon with descriptor and padding to register.
190262306a36Sopenharmony_ci	 */
190362306a36Sopenharmony_ci	padding_len = roundup(entry->skb->len, 4) - entry->skb->len;
190462306a36Sopenharmony_ci	if (padding_len && skb_pad(entry->skb, padding_len)) {
190562306a36Sopenharmony_ci		rt2x00_err(rt2x00dev, "Failure padding beacon, aborting\n");
190662306a36Sopenharmony_ci		/* skb freed by skb_pad() on failure */
190762306a36Sopenharmony_ci		entry->skb = NULL;
190862306a36Sopenharmony_ci		rt2x00mmio_register_write(rt2x00dev, TXRX_CSR9, orig_reg);
190962306a36Sopenharmony_ci		return;
191062306a36Sopenharmony_ci	}
191162306a36Sopenharmony_ci
191262306a36Sopenharmony_ci	beacon_base = HW_BEACON_OFFSET(entry->entry_idx);
191362306a36Sopenharmony_ci	rt2x00mmio_register_multiwrite(rt2x00dev, beacon_base,
191462306a36Sopenharmony_ci				       entry_priv->desc, TXINFO_SIZE);
191562306a36Sopenharmony_ci	rt2x00mmio_register_multiwrite(rt2x00dev, beacon_base + TXINFO_SIZE,
191662306a36Sopenharmony_ci				       entry->skb->data,
191762306a36Sopenharmony_ci				       entry->skb->len + padding_len);
191862306a36Sopenharmony_ci
191962306a36Sopenharmony_ci	/*
192062306a36Sopenharmony_ci	 * Enable beaconing again.
192162306a36Sopenharmony_ci	 *
192262306a36Sopenharmony_ci	 * For Wi-Fi faily generated beacons between participating
192362306a36Sopenharmony_ci	 * stations. Set TBTT phase adaptive adjustment step to 8us.
192462306a36Sopenharmony_ci	 */
192562306a36Sopenharmony_ci	rt2x00mmio_register_write(rt2x00dev, TXRX_CSR10, 0x00001008);
192662306a36Sopenharmony_ci
192762306a36Sopenharmony_ci	rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 1);
192862306a36Sopenharmony_ci	rt2x00mmio_register_write(rt2x00dev, TXRX_CSR9, reg);
192962306a36Sopenharmony_ci
193062306a36Sopenharmony_ci	/*
193162306a36Sopenharmony_ci	 * Clean up beacon skb.
193262306a36Sopenharmony_ci	 */
193362306a36Sopenharmony_ci	dev_kfree_skb_any(entry->skb);
193462306a36Sopenharmony_ci	entry->skb = NULL;
193562306a36Sopenharmony_ci}
193662306a36Sopenharmony_ci
193762306a36Sopenharmony_cistatic void rt61pci_clear_beacon(struct queue_entry *entry)
193862306a36Sopenharmony_ci{
193962306a36Sopenharmony_ci	struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
194062306a36Sopenharmony_ci	u32 orig_reg, reg;
194162306a36Sopenharmony_ci
194262306a36Sopenharmony_ci	/*
194362306a36Sopenharmony_ci	 * Disable beaconing while we are reloading the beacon data,
194462306a36Sopenharmony_ci	 * otherwise we might be sending out invalid data.
194562306a36Sopenharmony_ci	 */
194662306a36Sopenharmony_ci	orig_reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR9);
194762306a36Sopenharmony_ci	reg = orig_reg;
194862306a36Sopenharmony_ci	rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 0);
194962306a36Sopenharmony_ci	rt2x00mmio_register_write(rt2x00dev, TXRX_CSR9, reg);
195062306a36Sopenharmony_ci
195162306a36Sopenharmony_ci	/*
195262306a36Sopenharmony_ci	 * Clear beacon.
195362306a36Sopenharmony_ci	 */
195462306a36Sopenharmony_ci	rt2x00mmio_register_write(rt2x00dev,
195562306a36Sopenharmony_ci				  HW_BEACON_OFFSET(entry->entry_idx), 0);
195662306a36Sopenharmony_ci
195762306a36Sopenharmony_ci	/*
195862306a36Sopenharmony_ci	 * Restore global beaconing state.
195962306a36Sopenharmony_ci	 */
196062306a36Sopenharmony_ci	rt2x00mmio_register_write(rt2x00dev, TXRX_CSR9, orig_reg);
196162306a36Sopenharmony_ci}
196262306a36Sopenharmony_ci
196362306a36Sopenharmony_ci/*
196462306a36Sopenharmony_ci * RX control handlers
196562306a36Sopenharmony_ci */
196662306a36Sopenharmony_cistatic int rt61pci_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxd_w1)
196762306a36Sopenharmony_ci{
196862306a36Sopenharmony_ci	u8 offset = rt2x00dev->lna_gain;
196962306a36Sopenharmony_ci	u8 lna;
197062306a36Sopenharmony_ci
197162306a36Sopenharmony_ci	lna = rt2x00_get_field32(rxd_w1, RXD_W1_RSSI_LNA);
197262306a36Sopenharmony_ci	switch (lna) {
197362306a36Sopenharmony_ci	case 3:
197462306a36Sopenharmony_ci		offset += 90;
197562306a36Sopenharmony_ci		break;
197662306a36Sopenharmony_ci	case 2:
197762306a36Sopenharmony_ci		offset += 74;
197862306a36Sopenharmony_ci		break;
197962306a36Sopenharmony_ci	case 1:
198062306a36Sopenharmony_ci		offset += 64;
198162306a36Sopenharmony_ci		break;
198262306a36Sopenharmony_ci	default:
198362306a36Sopenharmony_ci		return 0;
198462306a36Sopenharmony_ci	}
198562306a36Sopenharmony_ci
198662306a36Sopenharmony_ci	if (rt2x00dev->curr_band == NL80211_BAND_5GHZ) {
198762306a36Sopenharmony_ci		if (lna == 3 || lna == 2)
198862306a36Sopenharmony_ci			offset += 10;
198962306a36Sopenharmony_ci	}
199062306a36Sopenharmony_ci
199162306a36Sopenharmony_ci	return rt2x00_get_field32(rxd_w1, RXD_W1_RSSI_AGC) * 2 - offset;
199262306a36Sopenharmony_ci}
199362306a36Sopenharmony_ci
199462306a36Sopenharmony_cistatic void rt61pci_fill_rxdone(struct queue_entry *entry,
199562306a36Sopenharmony_ci				struct rxdone_entry_desc *rxdesc)
199662306a36Sopenharmony_ci{
199762306a36Sopenharmony_ci	struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
199862306a36Sopenharmony_ci	struct queue_entry_priv_mmio *entry_priv = entry->priv_data;
199962306a36Sopenharmony_ci	u32 word0;
200062306a36Sopenharmony_ci	u32 word1;
200162306a36Sopenharmony_ci
200262306a36Sopenharmony_ci	word0 = rt2x00_desc_read(entry_priv->desc, 0);
200362306a36Sopenharmony_ci	word1 = rt2x00_desc_read(entry_priv->desc, 1);
200462306a36Sopenharmony_ci
200562306a36Sopenharmony_ci	if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR))
200662306a36Sopenharmony_ci		rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC;
200762306a36Sopenharmony_ci
200862306a36Sopenharmony_ci	rxdesc->cipher = rt2x00_get_field32(word0, RXD_W0_CIPHER_ALG);
200962306a36Sopenharmony_ci	rxdesc->cipher_status = rt2x00_get_field32(word0, RXD_W0_CIPHER_ERROR);
201062306a36Sopenharmony_ci
201162306a36Sopenharmony_ci	if (rxdesc->cipher != CIPHER_NONE) {
201262306a36Sopenharmony_ci		rxdesc->iv[0] = _rt2x00_desc_read(entry_priv->desc, 2);
201362306a36Sopenharmony_ci		rxdesc->iv[1] = _rt2x00_desc_read(entry_priv->desc, 3);
201462306a36Sopenharmony_ci		rxdesc->dev_flags |= RXDONE_CRYPTO_IV;
201562306a36Sopenharmony_ci
201662306a36Sopenharmony_ci		rxdesc->icv = _rt2x00_desc_read(entry_priv->desc, 4);
201762306a36Sopenharmony_ci		rxdesc->dev_flags |= RXDONE_CRYPTO_ICV;
201862306a36Sopenharmony_ci
201962306a36Sopenharmony_ci		/*
202062306a36Sopenharmony_ci		 * Hardware has stripped IV/EIV data from 802.11 frame during
202162306a36Sopenharmony_ci		 * decryption. It has provided the data separately but rt2x00lib
202262306a36Sopenharmony_ci		 * should decide if it should be reinserted.
202362306a36Sopenharmony_ci		 */
202462306a36Sopenharmony_ci		rxdesc->flags |= RX_FLAG_IV_STRIPPED;
202562306a36Sopenharmony_ci
202662306a36Sopenharmony_ci		/*
202762306a36Sopenharmony_ci		 * The hardware has already checked the Michael Mic and has
202862306a36Sopenharmony_ci		 * stripped it from the frame. Signal this to mac80211.
202962306a36Sopenharmony_ci		 */
203062306a36Sopenharmony_ci		rxdesc->flags |= RX_FLAG_MMIC_STRIPPED;
203162306a36Sopenharmony_ci
203262306a36Sopenharmony_ci		if (rxdesc->cipher_status == RX_CRYPTO_SUCCESS)
203362306a36Sopenharmony_ci			rxdesc->flags |= RX_FLAG_DECRYPTED;
203462306a36Sopenharmony_ci		else if (rxdesc->cipher_status == RX_CRYPTO_FAIL_MIC)
203562306a36Sopenharmony_ci			rxdesc->flags |= RX_FLAG_MMIC_ERROR;
203662306a36Sopenharmony_ci	}
203762306a36Sopenharmony_ci
203862306a36Sopenharmony_ci	/*
203962306a36Sopenharmony_ci	 * Obtain the status about this packet.
204062306a36Sopenharmony_ci	 * When frame was received with an OFDM bitrate,
204162306a36Sopenharmony_ci	 * the signal is the PLCP value. If it was received with
204262306a36Sopenharmony_ci	 * a CCK bitrate the signal is the rate in 100kbit/s.
204362306a36Sopenharmony_ci	 */
204462306a36Sopenharmony_ci	rxdesc->signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL);
204562306a36Sopenharmony_ci	rxdesc->rssi = rt61pci_agc_to_rssi(rt2x00dev, word1);
204662306a36Sopenharmony_ci	rxdesc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
204762306a36Sopenharmony_ci
204862306a36Sopenharmony_ci	if (rt2x00_get_field32(word0, RXD_W0_OFDM))
204962306a36Sopenharmony_ci		rxdesc->dev_flags |= RXDONE_SIGNAL_PLCP;
205062306a36Sopenharmony_ci	else
205162306a36Sopenharmony_ci		rxdesc->dev_flags |= RXDONE_SIGNAL_BITRATE;
205262306a36Sopenharmony_ci	if (rt2x00_get_field32(word0, RXD_W0_MY_BSS))
205362306a36Sopenharmony_ci		rxdesc->dev_flags |= RXDONE_MY_BSS;
205462306a36Sopenharmony_ci}
205562306a36Sopenharmony_ci
205662306a36Sopenharmony_ci/*
205762306a36Sopenharmony_ci * Interrupt functions.
205862306a36Sopenharmony_ci */
205962306a36Sopenharmony_cistatic void rt61pci_txdone(struct rt2x00_dev *rt2x00dev)
206062306a36Sopenharmony_ci{
206162306a36Sopenharmony_ci	struct data_queue *queue;
206262306a36Sopenharmony_ci	struct queue_entry *entry;
206362306a36Sopenharmony_ci	struct queue_entry *entry_done;
206462306a36Sopenharmony_ci	struct queue_entry_priv_mmio *entry_priv;
206562306a36Sopenharmony_ci	struct txdone_entry_desc txdesc;
206662306a36Sopenharmony_ci	u32 word;
206762306a36Sopenharmony_ci	u32 reg;
206862306a36Sopenharmony_ci	int type;
206962306a36Sopenharmony_ci	int index;
207062306a36Sopenharmony_ci	int i;
207162306a36Sopenharmony_ci
207262306a36Sopenharmony_ci	/*
207362306a36Sopenharmony_ci	 * TX_STA_FIFO is a stack of X entries, hence read TX_STA_FIFO
207462306a36Sopenharmony_ci	 * at most X times and also stop processing once the TX_STA_FIFO_VALID
207562306a36Sopenharmony_ci	 * flag is not set anymore.
207662306a36Sopenharmony_ci	 *
207762306a36Sopenharmony_ci	 * The legacy drivers use X=TX_RING_SIZE but state in a comment
207862306a36Sopenharmony_ci	 * that the TX_STA_FIFO stack has a size of 16. We stick to our
207962306a36Sopenharmony_ci	 * tx ring size for now.
208062306a36Sopenharmony_ci	 */
208162306a36Sopenharmony_ci	for (i = 0; i < rt2x00dev->tx->limit; i++) {
208262306a36Sopenharmony_ci		reg = rt2x00mmio_register_read(rt2x00dev, STA_CSR4);
208362306a36Sopenharmony_ci		if (!rt2x00_get_field32(reg, STA_CSR4_VALID))
208462306a36Sopenharmony_ci			break;
208562306a36Sopenharmony_ci
208662306a36Sopenharmony_ci		/*
208762306a36Sopenharmony_ci		 * Skip this entry when it contains an invalid
208862306a36Sopenharmony_ci		 * queue identication number.
208962306a36Sopenharmony_ci		 */
209062306a36Sopenharmony_ci		type = rt2x00_get_field32(reg, STA_CSR4_PID_TYPE);
209162306a36Sopenharmony_ci		queue = rt2x00queue_get_tx_queue(rt2x00dev, type);
209262306a36Sopenharmony_ci		if (unlikely(!queue))
209362306a36Sopenharmony_ci			continue;
209462306a36Sopenharmony_ci
209562306a36Sopenharmony_ci		/*
209662306a36Sopenharmony_ci		 * Skip this entry when it contains an invalid
209762306a36Sopenharmony_ci		 * index number.
209862306a36Sopenharmony_ci		 */
209962306a36Sopenharmony_ci		index = rt2x00_get_field32(reg, STA_CSR4_PID_SUBTYPE);
210062306a36Sopenharmony_ci		if (unlikely(index >= queue->limit))
210162306a36Sopenharmony_ci			continue;
210262306a36Sopenharmony_ci
210362306a36Sopenharmony_ci		entry = &queue->entries[index];
210462306a36Sopenharmony_ci		entry_priv = entry->priv_data;
210562306a36Sopenharmony_ci		word = rt2x00_desc_read(entry_priv->desc, 0);
210662306a36Sopenharmony_ci
210762306a36Sopenharmony_ci		if (rt2x00_get_field32(word, TXD_W0_OWNER_NIC) ||
210862306a36Sopenharmony_ci		    !rt2x00_get_field32(word, TXD_W0_VALID))
210962306a36Sopenharmony_ci			return;
211062306a36Sopenharmony_ci
211162306a36Sopenharmony_ci		entry_done = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
211262306a36Sopenharmony_ci		while (entry != entry_done) {
211362306a36Sopenharmony_ci			/* Catch up.
211462306a36Sopenharmony_ci			 * Just report any entries we missed as failed.
211562306a36Sopenharmony_ci			 */
211662306a36Sopenharmony_ci			rt2x00_warn(rt2x00dev, "TX status report missed for entry %d\n",
211762306a36Sopenharmony_ci				    entry_done->entry_idx);
211862306a36Sopenharmony_ci
211962306a36Sopenharmony_ci			rt2x00lib_txdone_noinfo(entry_done, TXDONE_UNKNOWN);
212062306a36Sopenharmony_ci			entry_done = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
212162306a36Sopenharmony_ci		}
212262306a36Sopenharmony_ci
212362306a36Sopenharmony_ci		/*
212462306a36Sopenharmony_ci		 * Obtain the status about this packet.
212562306a36Sopenharmony_ci		 */
212662306a36Sopenharmony_ci		txdesc.flags = 0;
212762306a36Sopenharmony_ci		switch (rt2x00_get_field32(reg, STA_CSR4_TX_RESULT)) {
212862306a36Sopenharmony_ci		case 0: /* Success, maybe with retry */
212962306a36Sopenharmony_ci			__set_bit(TXDONE_SUCCESS, &txdesc.flags);
213062306a36Sopenharmony_ci			break;
213162306a36Sopenharmony_ci		case 6: /* Failure, excessive retries */
213262306a36Sopenharmony_ci			__set_bit(TXDONE_EXCESSIVE_RETRY, &txdesc.flags);
213362306a36Sopenharmony_ci			fallthrough;	/* this is a failed frame! */
213462306a36Sopenharmony_ci		default: /* Failure */
213562306a36Sopenharmony_ci			__set_bit(TXDONE_FAILURE, &txdesc.flags);
213662306a36Sopenharmony_ci		}
213762306a36Sopenharmony_ci		txdesc.retry = rt2x00_get_field32(reg, STA_CSR4_RETRY_COUNT);
213862306a36Sopenharmony_ci
213962306a36Sopenharmony_ci		/*
214062306a36Sopenharmony_ci		 * the frame was retried at least once
214162306a36Sopenharmony_ci		 * -> hw used fallback rates
214262306a36Sopenharmony_ci		 */
214362306a36Sopenharmony_ci		if (txdesc.retry)
214462306a36Sopenharmony_ci			__set_bit(TXDONE_FALLBACK, &txdesc.flags);
214562306a36Sopenharmony_ci
214662306a36Sopenharmony_ci		rt2x00lib_txdone(entry, &txdesc);
214762306a36Sopenharmony_ci	}
214862306a36Sopenharmony_ci}
214962306a36Sopenharmony_ci
215062306a36Sopenharmony_cistatic void rt61pci_wakeup(struct rt2x00_dev *rt2x00dev)
215162306a36Sopenharmony_ci{
215262306a36Sopenharmony_ci	struct rt2x00lib_conf libconf = { .conf = &rt2x00dev->hw->conf };
215362306a36Sopenharmony_ci
215462306a36Sopenharmony_ci	rt61pci_config(rt2x00dev, &libconf, IEEE80211_CONF_CHANGE_PS);
215562306a36Sopenharmony_ci}
215662306a36Sopenharmony_ci
215762306a36Sopenharmony_cistatic inline void rt61pci_enable_interrupt(struct rt2x00_dev *rt2x00dev,
215862306a36Sopenharmony_ci					    struct rt2x00_field32 irq_field)
215962306a36Sopenharmony_ci{
216062306a36Sopenharmony_ci	u32 reg;
216162306a36Sopenharmony_ci
216262306a36Sopenharmony_ci	/*
216362306a36Sopenharmony_ci	 * Enable a single interrupt. The interrupt mask register
216462306a36Sopenharmony_ci	 * access needs locking.
216562306a36Sopenharmony_ci	 */
216662306a36Sopenharmony_ci	spin_lock_irq(&rt2x00dev->irqmask_lock);
216762306a36Sopenharmony_ci
216862306a36Sopenharmony_ci	reg = rt2x00mmio_register_read(rt2x00dev, INT_MASK_CSR);
216962306a36Sopenharmony_ci	rt2x00_set_field32(&reg, irq_field, 0);
217062306a36Sopenharmony_ci	rt2x00mmio_register_write(rt2x00dev, INT_MASK_CSR, reg);
217162306a36Sopenharmony_ci
217262306a36Sopenharmony_ci	spin_unlock_irq(&rt2x00dev->irqmask_lock);
217362306a36Sopenharmony_ci}
217462306a36Sopenharmony_ci
217562306a36Sopenharmony_cistatic void rt61pci_enable_mcu_interrupt(struct rt2x00_dev *rt2x00dev,
217662306a36Sopenharmony_ci					 struct rt2x00_field32 irq_field)
217762306a36Sopenharmony_ci{
217862306a36Sopenharmony_ci	u32 reg;
217962306a36Sopenharmony_ci
218062306a36Sopenharmony_ci	/*
218162306a36Sopenharmony_ci	 * Enable a single MCU interrupt. The interrupt mask register
218262306a36Sopenharmony_ci	 * access needs locking.
218362306a36Sopenharmony_ci	 */
218462306a36Sopenharmony_ci	spin_lock_irq(&rt2x00dev->irqmask_lock);
218562306a36Sopenharmony_ci
218662306a36Sopenharmony_ci	reg = rt2x00mmio_register_read(rt2x00dev, MCU_INT_MASK_CSR);
218762306a36Sopenharmony_ci	rt2x00_set_field32(&reg, irq_field, 0);
218862306a36Sopenharmony_ci	rt2x00mmio_register_write(rt2x00dev, MCU_INT_MASK_CSR, reg);
218962306a36Sopenharmony_ci
219062306a36Sopenharmony_ci	spin_unlock_irq(&rt2x00dev->irqmask_lock);
219162306a36Sopenharmony_ci}
219262306a36Sopenharmony_ci
219362306a36Sopenharmony_cistatic void rt61pci_txstatus_tasklet(struct tasklet_struct *t)
219462306a36Sopenharmony_ci{
219562306a36Sopenharmony_ci	struct rt2x00_dev *rt2x00dev = from_tasklet(rt2x00dev, t,
219662306a36Sopenharmony_ci						    txstatus_tasklet);
219762306a36Sopenharmony_ci
219862306a36Sopenharmony_ci	rt61pci_txdone(rt2x00dev);
219962306a36Sopenharmony_ci	if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
220062306a36Sopenharmony_ci		rt61pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_TXDONE);
220162306a36Sopenharmony_ci}
220262306a36Sopenharmony_ci
220362306a36Sopenharmony_cistatic void rt61pci_tbtt_tasklet(struct tasklet_struct *t)
220462306a36Sopenharmony_ci{
220562306a36Sopenharmony_ci	struct rt2x00_dev *rt2x00dev = from_tasklet(rt2x00dev, t, tbtt_tasklet);
220662306a36Sopenharmony_ci	rt2x00lib_beacondone(rt2x00dev);
220762306a36Sopenharmony_ci	if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
220862306a36Sopenharmony_ci		rt61pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_BEACON_DONE);
220962306a36Sopenharmony_ci}
221062306a36Sopenharmony_ci
221162306a36Sopenharmony_cistatic void rt61pci_rxdone_tasklet(struct tasklet_struct *t)
221262306a36Sopenharmony_ci{
221362306a36Sopenharmony_ci	struct rt2x00_dev *rt2x00dev = from_tasklet(rt2x00dev, t,
221462306a36Sopenharmony_ci						    rxdone_tasklet);
221562306a36Sopenharmony_ci	if (rt2x00mmio_rxdone(rt2x00dev))
221662306a36Sopenharmony_ci		tasklet_schedule(&rt2x00dev->rxdone_tasklet);
221762306a36Sopenharmony_ci	else if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
221862306a36Sopenharmony_ci		rt61pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_RXDONE);
221962306a36Sopenharmony_ci}
222062306a36Sopenharmony_ci
222162306a36Sopenharmony_cistatic void rt61pci_autowake_tasklet(struct tasklet_struct *t)
222262306a36Sopenharmony_ci{
222362306a36Sopenharmony_ci	struct rt2x00_dev *rt2x00dev = from_tasklet(rt2x00dev, t,
222462306a36Sopenharmony_ci						    autowake_tasklet);
222562306a36Sopenharmony_ci	rt61pci_wakeup(rt2x00dev);
222662306a36Sopenharmony_ci	rt2x00mmio_register_write(rt2x00dev,
222762306a36Sopenharmony_ci				  M2H_CMD_DONE_CSR, 0xffffffff);
222862306a36Sopenharmony_ci	if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
222962306a36Sopenharmony_ci		rt61pci_enable_mcu_interrupt(rt2x00dev, MCU_INT_MASK_CSR_TWAKEUP);
223062306a36Sopenharmony_ci}
223162306a36Sopenharmony_ci
223262306a36Sopenharmony_cistatic irqreturn_t rt61pci_interrupt(int irq, void *dev_instance)
223362306a36Sopenharmony_ci{
223462306a36Sopenharmony_ci	struct rt2x00_dev *rt2x00dev = dev_instance;
223562306a36Sopenharmony_ci	u32 reg_mcu, mask_mcu;
223662306a36Sopenharmony_ci	u32 reg, mask;
223762306a36Sopenharmony_ci
223862306a36Sopenharmony_ci	/*
223962306a36Sopenharmony_ci	 * Get the interrupt sources & saved to local variable.
224062306a36Sopenharmony_ci	 * Write register value back to clear pending interrupts.
224162306a36Sopenharmony_ci	 */
224262306a36Sopenharmony_ci	reg_mcu = rt2x00mmio_register_read(rt2x00dev, MCU_INT_SOURCE_CSR);
224362306a36Sopenharmony_ci	rt2x00mmio_register_write(rt2x00dev, MCU_INT_SOURCE_CSR, reg_mcu);
224462306a36Sopenharmony_ci
224562306a36Sopenharmony_ci	reg = rt2x00mmio_register_read(rt2x00dev, INT_SOURCE_CSR);
224662306a36Sopenharmony_ci	rt2x00mmio_register_write(rt2x00dev, INT_SOURCE_CSR, reg);
224762306a36Sopenharmony_ci
224862306a36Sopenharmony_ci	if (!reg && !reg_mcu)
224962306a36Sopenharmony_ci		return IRQ_NONE;
225062306a36Sopenharmony_ci
225162306a36Sopenharmony_ci	if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
225262306a36Sopenharmony_ci		return IRQ_HANDLED;
225362306a36Sopenharmony_ci
225462306a36Sopenharmony_ci	/*
225562306a36Sopenharmony_ci	 * Schedule tasklets for interrupt handling.
225662306a36Sopenharmony_ci	 */
225762306a36Sopenharmony_ci	if (rt2x00_get_field32(reg, INT_SOURCE_CSR_RXDONE))
225862306a36Sopenharmony_ci		tasklet_schedule(&rt2x00dev->rxdone_tasklet);
225962306a36Sopenharmony_ci
226062306a36Sopenharmony_ci	if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TXDONE))
226162306a36Sopenharmony_ci		tasklet_schedule(&rt2x00dev->txstatus_tasklet);
226262306a36Sopenharmony_ci
226362306a36Sopenharmony_ci	if (rt2x00_get_field32(reg, INT_SOURCE_CSR_BEACON_DONE))
226462306a36Sopenharmony_ci		tasklet_hi_schedule(&rt2x00dev->tbtt_tasklet);
226562306a36Sopenharmony_ci
226662306a36Sopenharmony_ci	if (rt2x00_get_field32(reg_mcu, MCU_INT_SOURCE_CSR_TWAKEUP))
226762306a36Sopenharmony_ci		tasklet_schedule(&rt2x00dev->autowake_tasklet);
226862306a36Sopenharmony_ci
226962306a36Sopenharmony_ci	/*
227062306a36Sopenharmony_ci	 * Since INT_MASK_CSR and INT_SOURCE_CSR use the same bits
227162306a36Sopenharmony_ci	 * for interrupts and interrupt masks we can just use the value of
227262306a36Sopenharmony_ci	 * INT_SOURCE_CSR to create the interrupt mask.
227362306a36Sopenharmony_ci	 */
227462306a36Sopenharmony_ci	mask = reg;
227562306a36Sopenharmony_ci	mask_mcu = reg_mcu;
227662306a36Sopenharmony_ci
227762306a36Sopenharmony_ci	/*
227862306a36Sopenharmony_ci	 * Disable all interrupts for which a tasklet was scheduled right now,
227962306a36Sopenharmony_ci	 * the tasklet will reenable the appropriate interrupts.
228062306a36Sopenharmony_ci	 */
228162306a36Sopenharmony_ci	spin_lock(&rt2x00dev->irqmask_lock);
228262306a36Sopenharmony_ci
228362306a36Sopenharmony_ci	reg = rt2x00mmio_register_read(rt2x00dev, INT_MASK_CSR);
228462306a36Sopenharmony_ci	reg |= mask;
228562306a36Sopenharmony_ci	rt2x00mmio_register_write(rt2x00dev, INT_MASK_CSR, reg);
228662306a36Sopenharmony_ci
228762306a36Sopenharmony_ci	reg = rt2x00mmio_register_read(rt2x00dev, MCU_INT_MASK_CSR);
228862306a36Sopenharmony_ci	reg |= mask_mcu;
228962306a36Sopenharmony_ci	rt2x00mmio_register_write(rt2x00dev, MCU_INT_MASK_CSR, reg);
229062306a36Sopenharmony_ci
229162306a36Sopenharmony_ci	spin_unlock(&rt2x00dev->irqmask_lock);
229262306a36Sopenharmony_ci
229362306a36Sopenharmony_ci	return IRQ_HANDLED;
229462306a36Sopenharmony_ci}
229562306a36Sopenharmony_ci
229662306a36Sopenharmony_ci/*
229762306a36Sopenharmony_ci * Device probe functions.
229862306a36Sopenharmony_ci */
229962306a36Sopenharmony_cistatic int rt61pci_validate_eeprom(struct rt2x00_dev *rt2x00dev)
230062306a36Sopenharmony_ci{
230162306a36Sopenharmony_ci	struct eeprom_93cx6 eeprom;
230262306a36Sopenharmony_ci	u32 reg;
230362306a36Sopenharmony_ci	u16 word;
230462306a36Sopenharmony_ci	u8 *mac;
230562306a36Sopenharmony_ci	s8 value;
230662306a36Sopenharmony_ci
230762306a36Sopenharmony_ci	reg = rt2x00mmio_register_read(rt2x00dev, E2PROM_CSR);
230862306a36Sopenharmony_ci
230962306a36Sopenharmony_ci	eeprom.data = rt2x00dev;
231062306a36Sopenharmony_ci	eeprom.register_read = rt61pci_eepromregister_read;
231162306a36Sopenharmony_ci	eeprom.register_write = rt61pci_eepromregister_write;
231262306a36Sopenharmony_ci	eeprom.width = rt2x00_get_field32(reg, E2PROM_CSR_TYPE_93C46) ?
231362306a36Sopenharmony_ci	    PCI_EEPROM_WIDTH_93C46 : PCI_EEPROM_WIDTH_93C66;
231462306a36Sopenharmony_ci	eeprom.reg_data_in = 0;
231562306a36Sopenharmony_ci	eeprom.reg_data_out = 0;
231662306a36Sopenharmony_ci	eeprom.reg_data_clock = 0;
231762306a36Sopenharmony_ci	eeprom.reg_chip_select = 0;
231862306a36Sopenharmony_ci
231962306a36Sopenharmony_ci	eeprom_93cx6_multiread(&eeprom, EEPROM_BASE, rt2x00dev->eeprom,
232062306a36Sopenharmony_ci			       EEPROM_SIZE / sizeof(u16));
232162306a36Sopenharmony_ci
232262306a36Sopenharmony_ci	/*
232362306a36Sopenharmony_ci	 * Start validation of the data that has been read.
232462306a36Sopenharmony_ci	 */
232562306a36Sopenharmony_ci	mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0);
232662306a36Sopenharmony_ci	rt2x00lib_set_mac_address(rt2x00dev, mac);
232762306a36Sopenharmony_ci
232862306a36Sopenharmony_ci	word = rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA);
232962306a36Sopenharmony_ci	if (word == 0xffff) {
233062306a36Sopenharmony_ci		rt2x00_set_field16(&word, EEPROM_ANTENNA_NUM, 2);
233162306a36Sopenharmony_ci		rt2x00_set_field16(&word, EEPROM_ANTENNA_TX_DEFAULT,
233262306a36Sopenharmony_ci				   ANTENNA_B);
233362306a36Sopenharmony_ci		rt2x00_set_field16(&word, EEPROM_ANTENNA_RX_DEFAULT,
233462306a36Sopenharmony_ci				   ANTENNA_B);
233562306a36Sopenharmony_ci		rt2x00_set_field16(&word, EEPROM_ANTENNA_FRAME_TYPE, 0);
233662306a36Sopenharmony_ci		rt2x00_set_field16(&word, EEPROM_ANTENNA_DYN_TXAGC, 0);
233762306a36Sopenharmony_ci		rt2x00_set_field16(&word, EEPROM_ANTENNA_HARDWARE_RADIO, 0);
233862306a36Sopenharmony_ci		rt2x00_set_field16(&word, EEPROM_ANTENNA_RF_TYPE, RF5225);
233962306a36Sopenharmony_ci		rt2x00_eeprom_write(rt2x00dev, EEPROM_ANTENNA, word);
234062306a36Sopenharmony_ci		rt2x00_eeprom_dbg(rt2x00dev, "Antenna: 0x%04x\n", word);
234162306a36Sopenharmony_ci	}
234262306a36Sopenharmony_ci
234362306a36Sopenharmony_ci	word = rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC);
234462306a36Sopenharmony_ci	if (word == 0xffff) {
234562306a36Sopenharmony_ci		rt2x00_set_field16(&word, EEPROM_NIC_ENABLE_DIVERSITY, 0);
234662306a36Sopenharmony_ci		rt2x00_set_field16(&word, EEPROM_NIC_TX_DIVERSITY, 0);
234762306a36Sopenharmony_ci		rt2x00_set_field16(&word, EEPROM_NIC_RX_FIXED, 0);
234862306a36Sopenharmony_ci		rt2x00_set_field16(&word, EEPROM_NIC_TX_FIXED, 0);
234962306a36Sopenharmony_ci		rt2x00_set_field16(&word, EEPROM_NIC_EXTERNAL_LNA_BG, 0);
235062306a36Sopenharmony_ci		rt2x00_set_field16(&word, EEPROM_NIC_CARDBUS_ACCEL, 0);
235162306a36Sopenharmony_ci		rt2x00_set_field16(&word, EEPROM_NIC_EXTERNAL_LNA_A, 0);
235262306a36Sopenharmony_ci		rt2x00_eeprom_write(rt2x00dev, EEPROM_NIC, word);
235362306a36Sopenharmony_ci		rt2x00_eeprom_dbg(rt2x00dev, "NIC: 0x%04x\n", word);
235462306a36Sopenharmony_ci	}
235562306a36Sopenharmony_ci
235662306a36Sopenharmony_ci	word = rt2x00_eeprom_read(rt2x00dev, EEPROM_LED);
235762306a36Sopenharmony_ci	if (word == 0xffff) {
235862306a36Sopenharmony_ci		rt2x00_set_field16(&word, EEPROM_LED_LED_MODE,
235962306a36Sopenharmony_ci				   LED_MODE_DEFAULT);
236062306a36Sopenharmony_ci		rt2x00_eeprom_write(rt2x00dev, EEPROM_LED, word);
236162306a36Sopenharmony_ci		rt2x00_eeprom_dbg(rt2x00dev, "Led: 0x%04x\n", word);
236262306a36Sopenharmony_ci	}
236362306a36Sopenharmony_ci
236462306a36Sopenharmony_ci	word = rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ);
236562306a36Sopenharmony_ci	if (word == 0xffff) {
236662306a36Sopenharmony_ci		rt2x00_set_field16(&word, EEPROM_FREQ_OFFSET, 0);
236762306a36Sopenharmony_ci		rt2x00_set_field16(&word, EEPROM_FREQ_SEQ, 0);
236862306a36Sopenharmony_ci		rt2x00_eeprom_write(rt2x00dev, EEPROM_FREQ, word);
236962306a36Sopenharmony_ci		rt2x00_eeprom_dbg(rt2x00dev, "Freq: 0x%04x\n", word);
237062306a36Sopenharmony_ci	}
237162306a36Sopenharmony_ci
237262306a36Sopenharmony_ci	word = rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG);
237362306a36Sopenharmony_ci	if (word == 0xffff) {
237462306a36Sopenharmony_ci		rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_1, 0);
237562306a36Sopenharmony_ci		rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_2, 0);
237662306a36Sopenharmony_ci		rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_BG, word);
237762306a36Sopenharmony_ci		rt2x00_eeprom_dbg(rt2x00dev, "RSSI OFFSET BG: 0x%04x\n", word);
237862306a36Sopenharmony_ci	} else {
237962306a36Sopenharmony_ci		value = rt2x00_get_field16(word, EEPROM_RSSI_OFFSET_BG_1);
238062306a36Sopenharmony_ci		if (value < -10 || value > 10)
238162306a36Sopenharmony_ci			rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_1, 0);
238262306a36Sopenharmony_ci		value = rt2x00_get_field16(word, EEPROM_RSSI_OFFSET_BG_2);
238362306a36Sopenharmony_ci		if (value < -10 || value > 10)
238462306a36Sopenharmony_ci			rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_2, 0);
238562306a36Sopenharmony_ci		rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_BG, word);
238662306a36Sopenharmony_ci	}
238762306a36Sopenharmony_ci
238862306a36Sopenharmony_ci	word = rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A);
238962306a36Sopenharmony_ci	if (word == 0xffff) {
239062306a36Sopenharmony_ci		rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_1, 0);
239162306a36Sopenharmony_ci		rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_2, 0);
239262306a36Sopenharmony_ci		rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_A, word);
239362306a36Sopenharmony_ci		rt2x00_eeprom_dbg(rt2x00dev, "RSSI OFFSET A: 0x%04x\n", word);
239462306a36Sopenharmony_ci	} else {
239562306a36Sopenharmony_ci		value = rt2x00_get_field16(word, EEPROM_RSSI_OFFSET_A_1);
239662306a36Sopenharmony_ci		if (value < -10 || value > 10)
239762306a36Sopenharmony_ci			rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_1, 0);
239862306a36Sopenharmony_ci		value = rt2x00_get_field16(word, EEPROM_RSSI_OFFSET_A_2);
239962306a36Sopenharmony_ci		if (value < -10 || value > 10)
240062306a36Sopenharmony_ci			rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_2, 0);
240162306a36Sopenharmony_ci		rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_A, word);
240262306a36Sopenharmony_ci	}
240362306a36Sopenharmony_ci
240462306a36Sopenharmony_ci	return 0;
240562306a36Sopenharmony_ci}
240662306a36Sopenharmony_ci
240762306a36Sopenharmony_cistatic int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
240862306a36Sopenharmony_ci{
240962306a36Sopenharmony_ci	u32 reg;
241062306a36Sopenharmony_ci	u16 value;
241162306a36Sopenharmony_ci	u16 eeprom;
241262306a36Sopenharmony_ci
241362306a36Sopenharmony_ci	/*
241462306a36Sopenharmony_ci	 * Read EEPROM word for configuration.
241562306a36Sopenharmony_ci	 */
241662306a36Sopenharmony_ci	eeprom = rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA);
241762306a36Sopenharmony_ci
241862306a36Sopenharmony_ci	/*
241962306a36Sopenharmony_ci	 * Identify RF chipset.
242062306a36Sopenharmony_ci	 */
242162306a36Sopenharmony_ci	value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE);
242262306a36Sopenharmony_ci	reg = rt2x00mmio_register_read(rt2x00dev, MAC_CSR0);
242362306a36Sopenharmony_ci	rt2x00_set_chip(rt2x00dev, rt2x00_get_field32(reg, MAC_CSR0_CHIPSET),
242462306a36Sopenharmony_ci			value, rt2x00_get_field32(reg, MAC_CSR0_REVISION));
242562306a36Sopenharmony_ci
242662306a36Sopenharmony_ci	if (!rt2x00_rf(rt2x00dev, RF5225) &&
242762306a36Sopenharmony_ci	    !rt2x00_rf(rt2x00dev, RF5325) &&
242862306a36Sopenharmony_ci	    !rt2x00_rf(rt2x00dev, RF2527) &&
242962306a36Sopenharmony_ci	    !rt2x00_rf(rt2x00dev, RF2529)) {
243062306a36Sopenharmony_ci		rt2x00_err(rt2x00dev, "Invalid RF chipset detected\n");
243162306a36Sopenharmony_ci		return -ENODEV;
243262306a36Sopenharmony_ci	}
243362306a36Sopenharmony_ci
243462306a36Sopenharmony_ci	/*
243562306a36Sopenharmony_ci	 * Determine number of antennas.
243662306a36Sopenharmony_ci	 */
243762306a36Sopenharmony_ci	if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_NUM) == 2)
243862306a36Sopenharmony_ci		__set_bit(CAPABILITY_DOUBLE_ANTENNA, &rt2x00dev->cap_flags);
243962306a36Sopenharmony_ci
244062306a36Sopenharmony_ci	/*
244162306a36Sopenharmony_ci	 * Identify default antenna configuration.
244262306a36Sopenharmony_ci	 */
244362306a36Sopenharmony_ci	rt2x00dev->default_ant.tx =
244462306a36Sopenharmony_ci	    rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TX_DEFAULT);
244562306a36Sopenharmony_ci	rt2x00dev->default_ant.rx =
244662306a36Sopenharmony_ci	    rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RX_DEFAULT);
244762306a36Sopenharmony_ci
244862306a36Sopenharmony_ci	/*
244962306a36Sopenharmony_ci	 * Read the Frame type.
245062306a36Sopenharmony_ci	 */
245162306a36Sopenharmony_ci	if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_FRAME_TYPE))
245262306a36Sopenharmony_ci		__set_bit(CAPABILITY_FRAME_TYPE, &rt2x00dev->cap_flags);
245362306a36Sopenharmony_ci
245462306a36Sopenharmony_ci	/*
245562306a36Sopenharmony_ci	 * Detect if this device has a hardware controlled radio.
245662306a36Sopenharmony_ci	 */
245762306a36Sopenharmony_ci	if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO))
245862306a36Sopenharmony_ci		__set_bit(CAPABILITY_HW_BUTTON, &rt2x00dev->cap_flags);
245962306a36Sopenharmony_ci
246062306a36Sopenharmony_ci	/*
246162306a36Sopenharmony_ci	 * Read frequency offset and RF programming sequence.
246262306a36Sopenharmony_ci	 */
246362306a36Sopenharmony_ci	eeprom = rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ);
246462306a36Sopenharmony_ci	if (rt2x00_get_field16(eeprom, EEPROM_FREQ_SEQ))
246562306a36Sopenharmony_ci		__set_bit(CAPABILITY_RF_SEQUENCE, &rt2x00dev->cap_flags);
246662306a36Sopenharmony_ci
246762306a36Sopenharmony_ci	rt2x00dev->freq_offset = rt2x00_get_field16(eeprom, EEPROM_FREQ_OFFSET);
246862306a36Sopenharmony_ci
246962306a36Sopenharmony_ci	/*
247062306a36Sopenharmony_ci	 * Read external LNA informations.
247162306a36Sopenharmony_ci	 */
247262306a36Sopenharmony_ci	eeprom = rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC);
247362306a36Sopenharmony_ci
247462306a36Sopenharmony_ci	if (rt2x00_get_field16(eeprom, EEPROM_NIC_EXTERNAL_LNA_A))
247562306a36Sopenharmony_ci		__set_bit(CAPABILITY_EXTERNAL_LNA_A, &rt2x00dev->cap_flags);
247662306a36Sopenharmony_ci	if (rt2x00_get_field16(eeprom, EEPROM_NIC_EXTERNAL_LNA_BG))
247762306a36Sopenharmony_ci		__set_bit(CAPABILITY_EXTERNAL_LNA_BG, &rt2x00dev->cap_flags);
247862306a36Sopenharmony_ci
247962306a36Sopenharmony_ci	/*
248062306a36Sopenharmony_ci	 * When working with a RF2529 chip without double antenna,
248162306a36Sopenharmony_ci	 * the antenna settings should be gathered from the NIC
248262306a36Sopenharmony_ci	 * eeprom word.
248362306a36Sopenharmony_ci	 */
248462306a36Sopenharmony_ci	if (rt2x00_rf(rt2x00dev, RF2529) &&
248562306a36Sopenharmony_ci	    !rt2x00_has_cap_double_antenna(rt2x00dev)) {
248662306a36Sopenharmony_ci		rt2x00dev->default_ant.rx =
248762306a36Sopenharmony_ci		    ANTENNA_A + rt2x00_get_field16(eeprom, EEPROM_NIC_RX_FIXED);
248862306a36Sopenharmony_ci		rt2x00dev->default_ant.tx =
248962306a36Sopenharmony_ci		    ANTENNA_B - rt2x00_get_field16(eeprom, EEPROM_NIC_TX_FIXED);
249062306a36Sopenharmony_ci
249162306a36Sopenharmony_ci		if (rt2x00_get_field16(eeprom, EEPROM_NIC_TX_DIVERSITY))
249262306a36Sopenharmony_ci			rt2x00dev->default_ant.tx = ANTENNA_SW_DIVERSITY;
249362306a36Sopenharmony_ci		if (rt2x00_get_field16(eeprom, EEPROM_NIC_ENABLE_DIVERSITY))
249462306a36Sopenharmony_ci			rt2x00dev->default_ant.rx = ANTENNA_SW_DIVERSITY;
249562306a36Sopenharmony_ci	}
249662306a36Sopenharmony_ci
249762306a36Sopenharmony_ci	/*
249862306a36Sopenharmony_ci	 * Store led settings, for correct led behaviour.
249962306a36Sopenharmony_ci	 * If the eeprom value is invalid,
250062306a36Sopenharmony_ci	 * switch to default led mode.
250162306a36Sopenharmony_ci	 */
250262306a36Sopenharmony_ci#ifdef CONFIG_RT2X00_LIB_LEDS
250362306a36Sopenharmony_ci	eeprom = rt2x00_eeprom_read(rt2x00dev, EEPROM_LED);
250462306a36Sopenharmony_ci	value = rt2x00_get_field16(eeprom, EEPROM_LED_LED_MODE);
250562306a36Sopenharmony_ci
250662306a36Sopenharmony_ci	rt61pci_init_led(rt2x00dev, &rt2x00dev->led_radio, LED_TYPE_RADIO);
250762306a36Sopenharmony_ci	rt61pci_init_led(rt2x00dev, &rt2x00dev->led_assoc, LED_TYPE_ASSOC);
250862306a36Sopenharmony_ci	if (value == LED_MODE_SIGNAL_STRENGTH)
250962306a36Sopenharmony_ci		rt61pci_init_led(rt2x00dev, &rt2x00dev->led_qual,
251062306a36Sopenharmony_ci				 LED_TYPE_QUALITY);
251162306a36Sopenharmony_ci
251262306a36Sopenharmony_ci	rt2x00_set_field16(&rt2x00dev->led_mcu_reg, MCU_LEDCS_LED_MODE, value);
251362306a36Sopenharmony_ci	rt2x00_set_field16(&rt2x00dev->led_mcu_reg, MCU_LEDCS_POLARITY_GPIO_0,
251462306a36Sopenharmony_ci			   rt2x00_get_field16(eeprom,
251562306a36Sopenharmony_ci					      EEPROM_LED_POLARITY_GPIO_0));
251662306a36Sopenharmony_ci	rt2x00_set_field16(&rt2x00dev->led_mcu_reg, MCU_LEDCS_POLARITY_GPIO_1,
251762306a36Sopenharmony_ci			   rt2x00_get_field16(eeprom,
251862306a36Sopenharmony_ci					      EEPROM_LED_POLARITY_GPIO_1));
251962306a36Sopenharmony_ci	rt2x00_set_field16(&rt2x00dev->led_mcu_reg, MCU_LEDCS_POLARITY_GPIO_2,
252062306a36Sopenharmony_ci			   rt2x00_get_field16(eeprom,
252162306a36Sopenharmony_ci					      EEPROM_LED_POLARITY_GPIO_2));
252262306a36Sopenharmony_ci	rt2x00_set_field16(&rt2x00dev->led_mcu_reg, MCU_LEDCS_POLARITY_GPIO_3,
252362306a36Sopenharmony_ci			   rt2x00_get_field16(eeprom,
252462306a36Sopenharmony_ci					      EEPROM_LED_POLARITY_GPIO_3));
252562306a36Sopenharmony_ci	rt2x00_set_field16(&rt2x00dev->led_mcu_reg, MCU_LEDCS_POLARITY_GPIO_4,
252662306a36Sopenharmony_ci			   rt2x00_get_field16(eeprom,
252762306a36Sopenharmony_ci					      EEPROM_LED_POLARITY_GPIO_4));
252862306a36Sopenharmony_ci	rt2x00_set_field16(&rt2x00dev->led_mcu_reg, MCU_LEDCS_POLARITY_ACT,
252962306a36Sopenharmony_ci			   rt2x00_get_field16(eeprom, EEPROM_LED_POLARITY_ACT));
253062306a36Sopenharmony_ci	rt2x00_set_field16(&rt2x00dev->led_mcu_reg, MCU_LEDCS_POLARITY_READY_BG,
253162306a36Sopenharmony_ci			   rt2x00_get_field16(eeprom,
253262306a36Sopenharmony_ci					      EEPROM_LED_POLARITY_RDY_G));
253362306a36Sopenharmony_ci	rt2x00_set_field16(&rt2x00dev->led_mcu_reg, MCU_LEDCS_POLARITY_READY_A,
253462306a36Sopenharmony_ci			   rt2x00_get_field16(eeprom,
253562306a36Sopenharmony_ci					      EEPROM_LED_POLARITY_RDY_A));
253662306a36Sopenharmony_ci#endif /* CONFIG_RT2X00_LIB_LEDS */
253762306a36Sopenharmony_ci
253862306a36Sopenharmony_ci	return 0;
253962306a36Sopenharmony_ci}
254062306a36Sopenharmony_ci
254162306a36Sopenharmony_ci/*
254262306a36Sopenharmony_ci * RF value list for RF5225 & RF5325
254362306a36Sopenharmony_ci * Supports: 2.4 GHz & 5.2 GHz, rf_sequence disabled
254462306a36Sopenharmony_ci */
254562306a36Sopenharmony_cistatic const struct rf_channel rf_vals_noseq[] = {
254662306a36Sopenharmony_ci	{ 1,  0x00002ccc, 0x00004786, 0x00068455, 0x000ffa0b },
254762306a36Sopenharmony_ci	{ 2,  0x00002ccc, 0x00004786, 0x00068455, 0x000ffa1f },
254862306a36Sopenharmony_ci	{ 3,  0x00002ccc, 0x0000478a, 0x00068455, 0x000ffa0b },
254962306a36Sopenharmony_ci	{ 4,  0x00002ccc, 0x0000478a, 0x00068455, 0x000ffa1f },
255062306a36Sopenharmony_ci	{ 5,  0x00002ccc, 0x0000478e, 0x00068455, 0x000ffa0b },
255162306a36Sopenharmony_ci	{ 6,  0x00002ccc, 0x0000478e, 0x00068455, 0x000ffa1f },
255262306a36Sopenharmony_ci	{ 7,  0x00002ccc, 0x00004792, 0x00068455, 0x000ffa0b },
255362306a36Sopenharmony_ci	{ 8,  0x00002ccc, 0x00004792, 0x00068455, 0x000ffa1f },
255462306a36Sopenharmony_ci	{ 9,  0x00002ccc, 0x00004796, 0x00068455, 0x000ffa0b },
255562306a36Sopenharmony_ci	{ 10, 0x00002ccc, 0x00004796, 0x00068455, 0x000ffa1f },
255662306a36Sopenharmony_ci	{ 11, 0x00002ccc, 0x0000479a, 0x00068455, 0x000ffa0b },
255762306a36Sopenharmony_ci	{ 12, 0x00002ccc, 0x0000479a, 0x00068455, 0x000ffa1f },
255862306a36Sopenharmony_ci	{ 13, 0x00002ccc, 0x0000479e, 0x00068455, 0x000ffa0b },
255962306a36Sopenharmony_ci	{ 14, 0x00002ccc, 0x000047a2, 0x00068455, 0x000ffa13 },
256062306a36Sopenharmony_ci
256162306a36Sopenharmony_ci	/* 802.11 UNI / HyperLan 2 */
256262306a36Sopenharmony_ci	{ 36, 0x00002ccc, 0x0000499a, 0x0009be55, 0x000ffa23 },
256362306a36Sopenharmony_ci	{ 40, 0x00002ccc, 0x000049a2, 0x0009be55, 0x000ffa03 },
256462306a36Sopenharmony_ci	{ 44, 0x00002ccc, 0x000049a6, 0x0009be55, 0x000ffa0b },
256562306a36Sopenharmony_ci	{ 48, 0x00002ccc, 0x000049aa, 0x0009be55, 0x000ffa13 },
256662306a36Sopenharmony_ci	{ 52, 0x00002ccc, 0x000049ae, 0x0009ae55, 0x000ffa1b },
256762306a36Sopenharmony_ci	{ 56, 0x00002ccc, 0x000049b2, 0x0009ae55, 0x000ffa23 },
256862306a36Sopenharmony_ci	{ 60, 0x00002ccc, 0x000049ba, 0x0009ae55, 0x000ffa03 },
256962306a36Sopenharmony_ci	{ 64, 0x00002ccc, 0x000049be, 0x0009ae55, 0x000ffa0b },
257062306a36Sopenharmony_ci
257162306a36Sopenharmony_ci	/* 802.11 HyperLan 2 */
257262306a36Sopenharmony_ci	{ 100, 0x00002ccc, 0x00004a2a, 0x000bae55, 0x000ffa03 },
257362306a36Sopenharmony_ci	{ 104, 0x00002ccc, 0x00004a2e, 0x000bae55, 0x000ffa0b },
257462306a36Sopenharmony_ci	{ 108, 0x00002ccc, 0x00004a32, 0x000bae55, 0x000ffa13 },
257562306a36Sopenharmony_ci	{ 112, 0x00002ccc, 0x00004a36, 0x000bae55, 0x000ffa1b },
257662306a36Sopenharmony_ci	{ 116, 0x00002ccc, 0x00004a3a, 0x000bbe55, 0x000ffa23 },
257762306a36Sopenharmony_ci	{ 120, 0x00002ccc, 0x00004a82, 0x000bbe55, 0x000ffa03 },
257862306a36Sopenharmony_ci	{ 124, 0x00002ccc, 0x00004a86, 0x000bbe55, 0x000ffa0b },
257962306a36Sopenharmony_ci	{ 128, 0x00002ccc, 0x00004a8a, 0x000bbe55, 0x000ffa13 },
258062306a36Sopenharmony_ci	{ 132, 0x00002ccc, 0x00004a8e, 0x000bbe55, 0x000ffa1b },
258162306a36Sopenharmony_ci	{ 136, 0x00002ccc, 0x00004a92, 0x000bbe55, 0x000ffa23 },
258262306a36Sopenharmony_ci
258362306a36Sopenharmony_ci	/* 802.11 UNII */
258462306a36Sopenharmony_ci	{ 140, 0x00002ccc, 0x00004a9a, 0x000bbe55, 0x000ffa03 },
258562306a36Sopenharmony_ci	{ 149, 0x00002ccc, 0x00004aa2, 0x000bbe55, 0x000ffa1f },
258662306a36Sopenharmony_ci	{ 153, 0x00002ccc, 0x00004aa6, 0x000bbe55, 0x000ffa27 },
258762306a36Sopenharmony_ci	{ 157, 0x00002ccc, 0x00004aae, 0x000bbe55, 0x000ffa07 },
258862306a36Sopenharmony_ci	{ 161, 0x00002ccc, 0x00004ab2, 0x000bbe55, 0x000ffa0f },
258962306a36Sopenharmony_ci	{ 165, 0x00002ccc, 0x00004ab6, 0x000bbe55, 0x000ffa17 },
259062306a36Sopenharmony_ci
259162306a36Sopenharmony_ci	/* MMAC(Japan)J52 ch 34,38,42,46 */
259262306a36Sopenharmony_ci	{ 34, 0x00002ccc, 0x0000499a, 0x0009be55, 0x000ffa0b },
259362306a36Sopenharmony_ci	{ 38, 0x00002ccc, 0x0000499e, 0x0009be55, 0x000ffa13 },
259462306a36Sopenharmony_ci	{ 42, 0x00002ccc, 0x000049a2, 0x0009be55, 0x000ffa1b },
259562306a36Sopenharmony_ci	{ 46, 0x00002ccc, 0x000049a6, 0x0009be55, 0x000ffa23 },
259662306a36Sopenharmony_ci};
259762306a36Sopenharmony_ci
259862306a36Sopenharmony_ci/*
259962306a36Sopenharmony_ci * RF value list for RF5225 & RF5325
260062306a36Sopenharmony_ci * Supports: 2.4 GHz & 5.2 GHz, rf_sequence enabled
260162306a36Sopenharmony_ci */
260262306a36Sopenharmony_cistatic const struct rf_channel rf_vals_seq[] = {
260362306a36Sopenharmony_ci	{ 1,  0x00002ccc, 0x00004786, 0x00068455, 0x000ffa0b },
260462306a36Sopenharmony_ci	{ 2,  0x00002ccc, 0x00004786, 0x00068455, 0x000ffa1f },
260562306a36Sopenharmony_ci	{ 3,  0x00002ccc, 0x0000478a, 0x00068455, 0x000ffa0b },
260662306a36Sopenharmony_ci	{ 4,  0x00002ccc, 0x0000478a, 0x00068455, 0x000ffa1f },
260762306a36Sopenharmony_ci	{ 5,  0x00002ccc, 0x0000478e, 0x00068455, 0x000ffa0b },
260862306a36Sopenharmony_ci	{ 6,  0x00002ccc, 0x0000478e, 0x00068455, 0x000ffa1f },
260962306a36Sopenharmony_ci	{ 7,  0x00002ccc, 0x00004792, 0x00068455, 0x000ffa0b },
261062306a36Sopenharmony_ci	{ 8,  0x00002ccc, 0x00004792, 0x00068455, 0x000ffa1f },
261162306a36Sopenharmony_ci	{ 9,  0x00002ccc, 0x00004796, 0x00068455, 0x000ffa0b },
261262306a36Sopenharmony_ci	{ 10, 0x00002ccc, 0x00004796, 0x00068455, 0x000ffa1f },
261362306a36Sopenharmony_ci	{ 11, 0x00002ccc, 0x0000479a, 0x00068455, 0x000ffa0b },
261462306a36Sopenharmony_ci	{ 12, 0x00002ccc, 0x0000479a, 0x00068455, 0x000ffa1f },
261562306a36Sopenharmony_ci	{ 13, 0x00002ccc, 0x0000479e, 0x00068455, 0x000ffa0b },
261662306a36Sopenharmony_ci	{ 14, 0x00002ccc, 0x000047a2, 0x00068455, 0x000ffa13 },
261762306a36Sopenharmony_ci
261862306a36Sopenharmony_ci	/* 802.11 UNI / HyperLan 2 */
261962306a36Sopenharmony_ci	{ 36, 0x00002cd4, 0x0004481a, 0x00098455, 0x000c0a03 },
262062306a36Sopenharmony_ci	{ 40, 0x00002cd0, 0x00044682, 0x00098455, 0x000c0a03 },
262162306a36Sopenharmony_ci	{ 44, 0x00002cd0, 0x00044686, 0x00098455, 0x000c0a1b },
262262306a36Sopenharmony_ci	{ 48, 0x00002cd0, 0x0004468e, 0x00098655, 0x000c0a0b },
262362306a36Sopenharmony_ci	{ 52, 0x00002cd0, 0x00044692, 0x00098855, 0x000c0a23 },
262462306a36Sopenharmony_ci	{ 56, 0x00002cd0, 0x0004469a, 0x00098c55, 0x000c0a13 },
262562306a36Sopenharmony_ci	{ 60, 0x00002cd0, 0x000446a2, 0x00098e55, 0x000c0a03 },
262662306a36Sopenharmony_ci	{ 64, 0x00002cd0, 0x000446a6, 0x00099255, 0x000c0a1b },
262762306a36Sopenharmony_ci
262862306a36Sopenharmony_ci	/* 802.11 HyperLan 2 */
262962306a36Sopenharmony_ci	{ 100, 0x00002cd4, 0x0004489a, 0x000b9855, 0x000c0a03 },
263062306a36Sopenharmony_ci	{ 104, 0x00002cd4, 0x000448a2, 0x000b9855, 0x000c0a03 },
263162306a36Sopenharmony_ci	{ 108, 0x00002cd4, 0x000448aa, 0x000b9855, 0x000c0a03 },
263262306a36Sopenharmony_ci	{ 112, 0x00002cd4, 0x000448b2, 0x000b9a55, 0x000c0a03 },
263362306a36Sopenharmony_ci	{ 116, 0x00002cd4, 0x000448ba, 0x000b9a55, 0x000c0a03 },
263462306a36Sopenharmony_ci	{ 120, 0x00002cd0, 0x00044702, 0x000b9a55, 0x000c0a03 },
263562306a36Sopenharmony_ci	{ 124, 0x00002cd0, 0x00044706, 0x000b9a55, 0x000c0a1b },
263662306a36Sopenharmony_ci	{ 128, 0x00002cd0, 0x0004470e, 0x000b9c55, 0x000c0a0b },
263762306a36Sopenharmony_ci	{ 132, 0x00002cd0, 0x00044712, 0x000b9c55, 0x000c0a23 },
263862306a36Sopenharmony_ci	{ 136, 0x00002cd0, 0x0004471a, 0x000b9e55, 0x000c0a13 },
263962306a36Sopenharmony_ci
264062306a36Sopenharmony_ci	/* 802.11 UNII */
264162306a36Sopenharmony_ci	{ 140, 0x00002cd0, 0x00044722, 0x000b9e55, 0x000c0a03 },
264262306a36Sopenharmony_ci	{ 149, 0x00002cd0, 0x0004472e, 0x000ba255, 0x000c0a1b },
264362306a36Sopenharmony_ci	{ 153, 0x00002cd0, 0x00044736, 0x000ba255, 0x000c0a0b },
264462306a36Sopenharmony_ci	{ 157, 0x00002cd4, 0x0004490a, 0x000ba255, 0x000c0a17 },
264562306a36Sopenharmony_ci	{ 161, 0x00002cd4, 0x00044912, 0x000ba255, 0x000c0a17 },
264662306a36Sopenharmony_ci	{ 165, 0x00002cd4, 0x0004491a, 0x000ba255, 0x000c0a17 },
264762306a36Sopenharmony_ci
264862306a36Sopenharmony_ci	/* MMAC(Japan)J52 ch 34,38,42,46 */
264962306a36Sopenharmony_ci	{ 34, 0x00002ccc, 0x0000499a, 0x0009be55, 0x000c0a0b },
265062306a36Sopenharmony_ci	{ 38, 0x00002ccc, 0x0000499e, 0x0009be55, 0x000c0a13 },
265162306a36Sopenharmony_ci	{ 42, 0x00002ccc, 0x000049a2, 0x0009be55, 0x000c0a1b },
265262306a36Sopenharmony_ci	{ 46, 0x00002ccc, 0x000049a6, 0x0009be55, 0x000c0a23 },
265362306a36Sopenharmony_ci};
265462306a36Sopenharmony_ci
265562306a36Sopenharmony_cistatic int rt61pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
265662306a36Sopenharmony_ci{
265762306a36Sopenharmony_ci	struct hw_mode_spec *spec = &rt2x00dev->spec;
265862306a36Sopenharmony_ci	struct channel_info *info;
265962306a36Sopenharmony_ci	u8 *tx_power;
266062306a36Sopenharmony_ci	unsigned int i;
266162306a36Sopenharmony_ci
266262306a36Sopenharmony_ci	/*
266362306a36Sopenharmony_ci	 * Disable powersaving as default.
266462306a36Sopenharmony_ci	 */
266562306a36Sopenharmony_ci	rt2x00dev->hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
266662306a36Sopenharmony_ci
266762306a36Sopenharmony_ci	/*
266862306a36Sopenharmony_ci	 * Initialize all hw fields.
266962306a36Sopenharmony_ci	 */
267062306a36Sopenharmony_ci	ieee80211_hw_set(rt2x00dev->hw, PS_NULLFUNC_STACK);
267162306a36Sopenharmony_ci	ieee80211_hw_set(rt2x00dev->hw, SUPPORTS_PS);
267262306a36Sopenharmony_ci	ieee80211_hw_set(rt2x00dev->hw, HOST_BROADCAST_PS_BUFFERING);
267362306a36Sopenharmony_ci	ieee80211_hw_set(rt2x00dev->hw, SIGNAL_DBM);
267462306a36Sopenharmony_ci
267562306a36Sopenharmony_ci	SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev);
267662306a36Sopenharmony_ci	SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
267762306a36Sopenharmony_ci				rt2x00_eeprom_addr(rt2x00dev,
267862306a36Sopenharmony_ci						   EEPROM_MAC_ADDR_0));
267962306a36Sopenharmony_ci
268062306a36Sopenharmony_ci	/*
268162306a36Sopenharmony_ci	 * As rt61 has a global fallback table we cannot specify
268262306a36Sopenharmony_ci	 * more then one tx rate per frame but since the hw will
268362306a36Sopenharmony_ci	 * try several rates (based on the fallback table) we should
268462306a36Sopenharmony_ci	 * initialize max_report_rates to the maximum number of rates
268562306a36Sopenharmony_ci	 * we are going to try. Otherwise mac80211 will truncate our
268662306a36Sopenharmony_ci	 * reported tx rates and the rc algortihm will end up with
268762306a36Sopenharmony_ci	 * incorrect data.
268862306a36Sopenharmony_ci	 */
268962306a36Sopenharmony_ci	rt2x00dev->hw->max_rates = 1;
269062306a36Sopenharmony_ci	rt2x00dev->hw->max_report_rates = 7;
269162306a36Sopenharmony_ci	rt2x00dev->hw->max_rate_tries = 1;
269262306a36Sopenharmony_ci
269362306a36Sopenharmony_ci	/*
269462306a36Sopenharmony_ci	 * Initialize hw_mode information.
269562306a36Sopenharmony_ci	 */
269662306a36Sopenharmony_ci	spec->supported_bands = SUPPORT_BAND_2GHZ;
269762306a36Sopenharmony_ci	spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM;
269862306a36Sopenharmony_ci
269962306a36Sopenharmony_ci	if (!rt2x00_has_cap_rf_sequence(rt2x00dev)) {
270062306a36Sopenharmony_ci		spec->num_channels = 14;
270162306a36Sopenharmony_ci		spec->channels = rf_vals_noseq;
270262306a36Sopenharmony_ci	} else {
270362306a36Sopenharmony_ci		spec->num_channels = 14;
270462306a36Sopenharmony_ci		spec->channels = rf_vals_seq;
270562306a36Sopenharmony_ci	}
270662306a36Sopenharmony_ci
270762306a36Sopenharmony_ci	if (rt2x00_rf(rt2x00dev, RF5225) || rt2x00_rf(rt2x00dev, RF5325)) {
270862306a36Sopenharmony_ci		spec->supported_bands |= SUPPORT_BAND_5GHZ;
270962306a36Sopenharmony_ci		spec->num_channels = ARRAY_SIZE(rf_vals_seq);
271062306a36Sopenharmony_ci	}
271162306a36Sopenharmony_ci
271262306a36Sopenharmony_ci	/*
271362306a36Sopenharmony_ci	 * Create channel information array
271462306a36Sopenharmony_ci	 */
271562306a36Sopenharmony_ci	info = kcalloc(spec->num_channels, sizeof(*info), GFP_KERNEL);
271662306a36Sopenharmony_ci	if (!info)
271762306a36Sopenharmony_ci		return -ENOMEM;
271862306a36Sopenharmony_ci
271962306a36Sopenharmony_ci	spec->channels_info = info;
272062306a36Sopenharmony_ci
272162306a36Sopenharmony_ci	tx_power = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_G_START);
272262306a36Sopenharmony_ci	for (i = 0; i < 14; i++) {
272362306a36Sopenharmony_ci		info[i].max_power = MAX_TXPOWER;
272462306a36Sopenharmony_ci		info[i].default_power1 = TXPOWER_FROM_DEV(tx_power[i]);
272562306a36Sopenharmony_ci	}
272662306a36Sopenharmony_ci
272762306a36Sopenharmony_ci	if (spec->num_channels > 14) {
272862306a36Sopenharmony_ci		tx_power = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A_START);
272962306a36Sopenharmony_ci		for (i = 14; i < spec->num_channels; i++) {
273062306a36Sopenharmony_ci			info[i].max_power = MAX_TXPOWER;
273162306a36Sopenharmony_ci			info[i].default_power1 =
273262306a36Sopenharmony_ci					TXPOWER_FROM_DEV(tx_power[i - 14]);
273362306a36Sopenharmony_ci		}
273462306a36Sopenharmony_ci	}
273562306a36Sopenharmony_ci
273662306a36Sopenharmony_ci	return 0;
273762306a36Sopenharmony_ci}
273862306a36Sopenharmony_ci
273962306a36Sopenharmony_cistatic int rt61pci_probe_hw(struct rt2x00_dev *rt2x00dev)
274062306a36Sopenharmony_ci{
274162306a36Sopenharmony_ci	int retval;
274262306a36Sopenharmony_ci	u32 reg;
274362306a36Sopenharmony_ci
274462306a36Sopenharmony_ci	/*
274562306a36Sopenharmony_ci	 * Disable power saving.
274662306a36Sopenharmony_ci	 */
274762306a36Sopenharmony_ci	rt2x00mmio_register_write(rt2x00dev, SOFT_RESET_CSR, 0x00000007);
274862306a36Sopenharmony_ci
274962306a36Sopenharmony_ci	/*
275062306a36Sopenharmony_ci	 * Allocate eeprom data.
275162306a36Sopenharmony_ci	 */
275262306a36Sopenharmony_ci	retval = rt61pci_validate_eeprom(rt2x00dev);
275362306a36Sopenharmony_ci	if (retval)
275462306a36Sopenharmony_ci		return retval;
275562306a36Sopenharmony_ci
275662306a36Sopenharmony_ci	retval = rt61pci_init_eeprom(rt2x00dev);
275762306a36Sopenharmony_ci	if (retval)
275862306a36Sopenharmony_ci		return retval;
275962306a36Sopenharmony_ci
276062306a36Sopenharmony_ci	/*
276162306a36Sopenharmony_ci	 * Enable rfkill polling by setting GPIO direction of the
276262306a36Sopenharmony_ci	 * rfkill switch GPIO pin correctly.
276362306a36Sopenharmony_ci	 */
276462306a36Sopenharmony_ci	reg = rt2x00mmio_register_read(rt2x00dev, MAC_CSR13);
276562306a36Sopenharmony_ci	rt2x00_set_field32(&reg, MAC_CSR13_DIR5, 1);
276662306a36Sopenharmony_ci	rt2x00mmio_register_write(rt2x00dev, MAC_CSR13, reg);
276762306a36Sopenharmony_ci
276862306a36Sopenharmony_ci	/*
276962306a36Sopenharmony_ci	 * Initialize hw specifications.
277062306a36Sopenharmony_ci	 */
277162306a36Sopenharmony_ci	retval = rt61pci_probe_hw_mode(rt2x00dev);
277262306a36Sopenharmony_ci	if (retval)
277362306a36Sopenharmony_ci		return retval;
277462306a36Sopenharmony_ci
277562306a36Sopenharmony_ci	/*
277662306a36Sopenharmony_ci	 * This device has multiple filters for control frames,
277762306a36Sopenharmony_ci	 * but has no a separate filter for PS Poll frames.
277862306a36Sopenharmony_ci	 */
277962306a36Sopenharmony_ci	__set_bit(CAPABILITY_CONTROL_FILTERS, &rt2x00dev->cap_flags);
278062306a36Sopenharmony_ci
278162306a36Sopenharmony_ci	/*
278262306a36Sopenharmony_ci	 * This device requires firmware and DMA mapped skbs.
278362306a36Sopenharmony_ci	 */
278462306a36Sopenharmony_ci	__set_bit(REQUIRE_FIRMWARE, &rt2x00dev->cap_flags);
278562306a36Sopenharmony_ci	__set_bit(REQUIRE_DMA, &rt2x00dev->cap_flags);
278662306a36Sopenharmony_ci	if (!modparam_nohwcrypt)
278762306a36Sopenharmony_ci		__set_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags);
278862306a36Sopenharmony_ci	__set_bit(CAPABILITY_LINK_TUNING, &rt2x00dev->cap_flags);
278962306a36Sopenharmony_ci
279062306a36Sopenharmony_ci	/*
279162306a36Sopenharmony_ci	 * Set the rssi offset.
279262306a36Sopenharmony_ci	 */
279362306a36Sopenharmony_ci	rt2x00dev->rssi_offset = DEFAULT_RSSI_OFFSET;
279462306a36Sopenharmony_ci
279562306a36Sopenharmony_ci	return 0;
279662306a36Sopenharmony_ci}
279762306a36Sopenharmony_ci
279862306a36Sopenharmony_ci/*
279962306a36Sopenharmony_ci * IEEE80211 stack callback functions.
280062306a36Sopenharmony_ci */
280162306a36Sopenharmony_cistatic int rt61pci_conf_tx(struct ieee80211_hw *hw,
280262306a36Sopenharmony_ci			   struct ieee80211_vif *vif,
280362306a36Sopenharmony_ci			   unsigned int link_id, u16 queue_idx,
280462306a36Sopenharmony_ci			   const struct ieee80211_tx_queue_params *params)
280562306a36Sopenharmony_ci{
280662306a36Sopenharmony_ci	struct rt2x00_dev *rt2x00dev = hw->priv;
280762306a36Sopenharmony_ci	struct data_queue *queue;
280862306a36Sopenharmony_ci	struct rt2x00_field32 field;
280962306a36Sopenharmony_ci	int retval;
281062306a36Sopenharmony_ci	u32 reg;
281162306a36Sopenharmony_ci	u32 offset;
281262306a36Sopenharmony_ci
281362306a36Sopenharmony_ci	/*
281462306a36Sopenharmony_ci	 * First pass the configuration through rt2x00lib, that will
281562306a36Sopenharmony_ci	 * update the queue settings and validate the input. After that
281662306a36Sopenharmony_ci	 * we are free to update the registers based on the value
281762306a36Sopenharmony_ci	 * in the queue parameter.
281862306a36Sopenharmony_ci	 */
281962306a36Sopenharmony_ci	retval = rt2x00mac_conf_tx(hw, vif, link_id, queue_idx, params);
282062306a36Sopenharmony_ci	if (retval)
282162306a36Sopenharmony_ci		return retval;
282262306a36Sopenharmony_ci
282362306a36Sopenharmony_ci	/*
282462306a36Sopenharmony_ci	 * We only need to perform additional register initialization
282562306a36Sopenharmony_ci	 * for WMM queues.
282662306a36Sopenharmony_ci	 */
282762306a36Sopenharmony_ci	if (queue_idx >= 4)
282862306a36Sopenharmony_ci		return 0;
282962306a36Sopenharmony_ci
283062306a36Sopenharmony_ci	queue = rt2x00queue_get_tx_queue(rt2x00dev, queue_idx);
283162306a36Sopenharmony_ci
283262306a36Sopenharmony_ci	/* Update WMM TXOP register */
283362306a36Sopenharmony_ci	offset = AC_TXOP_CSR0 + (sizeof(u32) * (!!(queue_idx & 2)));
283462306a36Sopenharmony_ci	field.bit_offset = (queue_idx & 1) * 16;
283562306a36Sopenharmony_ci	field.bit_mask = 0xffff << field.bit_offset;
283662306a36Sopenharmony_ci
283762306a36Sopenharmony_ci	reg = rt2x00mmio_register_read(rt2x00dev, offset);
283862306a36Sopenharmony_ci	rt2x00_set_field32(&reg, field, queue->txop);
283962306a36Sopenharmony_ci	rt2x00mmio_register_write(rt2x00dev, offset, reg);
284062306a36Sopenharmony_ci
284162306a36Sopenharmony_ci	/* Update WMM registers */
284262306a36Sopenharmony_ci	field.bit_offset = queue_idx * 4;
284362306a36Sopenharmony_ci	field.bit_mask = 0xf << field.bit_offset;
284462306a36Sopenharmony_ci
284562306a36Sopenharmony_ci	reg = rt2x00mmio_register_read(rt2x00dev, AIFSN_CSR);
284662306a36Sopenharmony_ci	rt2x00_set_field32(&reg, field, queue->aifs);
284762306a36Sopenharmony_ci	rt2x00mmio_register_write(rt2x00dev, AIFSN_CSR, reg);
284862306a36Sopenharmony_ci
284962306a36Sopenharmony_ci	reg = rt2x00mmio_register_read(rt2x00dev, CWMIN_CSR);
285062306a36Sopenharmony_ci	rt2x00_set_field32(&reg, field, queue->cw_min);
285162306a36Sopenharmony_ci	rt2x00mmio_register_write(rt2x00dev, CWMIN_CSR, reg);
285262306a36Sopenharmony_ci
285362306a36Sopenharmony_ci	reg = rt2x00mmio_register_read(rt2x00dev, CWMAX_CSR);
285462306a36Sopenharmony_ci	rt2x00_set_field32(&reg, field, queue->cw_max);
285562306a36Sopenharmony_ci	rt2x00mmio_register_write(rt2x00dev, CWMAX_CSR, reg);
285662306a36Sopenharmony_ci
285762306a36Sopenharmony_ci	return 0;
285862306a36Sopenharmony_ci}
285962306a36Sopenharmony_ci
286062306a36Sopenharmony_cistatic u64 rt61pci_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
286162306a36Sopenharmony_ci{
286262306a36Sopenharmony_ci	struct rt2x00_dev *rt2x00dev = hw->priv;
286362306a36Sopenharmony_ci	u64 tsf;
286462306a36Sopenharmony_ci	u32 reg;
286562306a36Sopenharmony_ci
286662306a36Sopenharmony_ci	reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR13);
286762306a36Sopenharmony_ci	tsf = (u64) rt2x00_get_field32(reg, TXRX_CSR13_HIGH_TSFTIMER) << 32;
286862306a36Sopenharmony_ci	reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR12);
286962306a36Sopenharmony_ci	tsf |= rt2x00_get_field32(reg, TXRX_CSR12_LOW_TSFTIMER);
287062306a36Sopenharmony_ci
287162306a36Sopenharmony_ci	return tsf;
287262306a36Sopenharmony_ci}
287362306a36Sopenharmony_ci
287462306a36Sopenharmony_cistatic const struct ieee80211_ops rt61pci_mac80211_ops = {
287562306a36Sopenharmony_ci	.tx			= rt2x00mac_tx,
287662306a36Sopenharmony_ci	.wake_tx_queue		= ieee80211_handle_wake_tx_queue,
287762306a36Sopenharmony_ci	.start			= rt2x00mac_start,
287862306a36Sopenharmony_ci	.stop			= rt2x00mac_stop,
287962306a36Sopenharmony_ci	.add_interface		= rt2x00mac_add_interface,
288062306a36Sopenharmony_ci	.remove_interface	= rt2x00mac_remove_interface,
288162306a36Sopenharmony_ci	.config			= rt2x00mac_config,
288262306a36Sopenharmony_ci	.configure_filter	= rt2x00mac_configure_filter,
288362306a36Sopenharmony_ci	.set_key		= rt2x00mac_set_key,
288462306a36Sopenharmony_ci	.sw_scan_start		= rt2x00mac_sw_scan_start,
288562306a36Sopenharmony_ci	.sw_scan_complete	= rt2x00mac_sw_scan_complete,
288662306a36Sopenharmony_ci	.get_stats		= rt2x00mac_get_stats,
288762306a36Sopenharmony_ci	.bss_info_changed	= rt2x00mac_bss_info_changed,
288862306a36Sopenharmony_ci	.conf_tx		= rt61pci_conf_tx,
288962306a36Sopenharmony_ci	.get_tsf		= rt61pci_get_tsf,
289062306a36Sopenharmony_ci	.rfkill_poll		= rt2x00mac_rfkill_poll,
289162306a36Sopenharmony_ci	.flush			= rt2x00mac_flush,
289262306a36Sopenharmony_ci	.set_antenna		= rt2x00mac_set_antenna,
289362306a36Sopenharmony_ci	.get_antenna		= rt2x00mac_get_antenna,
289462306a36Sopenharmony_ci	.get_ringparam		= rt2x00mac_get_ringparam,
289562306a36Sopenharmony_ci	.tx_frames_pending	= rt2x00mac_tx_frames_pending,
289662306a36Sopenharmony_ci};
289762306a36Sopenharmony_ci
289862306a36Sopenharmony_cistatic const struct rt2x00lib_ops rt61pci_rt2x00_ops = {
289962306a36Sopenharmony_ci	.irq_handler		= rt61pci_interrupt,
290062306a36Sopenharmony_ci	.txstatus_tasklet	= rt61pci_txstatus_tasklet,
290162306a36Sopenharmony_ci	.tbtt_tasklet		= rt61pci_tbtt_tasklet,
290262306a36Sopenharmony_ci	.rxdone_tasklet		= rt61pci_rxdone_tasklet,
290362306a36Sopenharmony_ci	.autowake_tasklet	= rt61pci_autowake_tasklet,
290462306a36Sopenharmony_ci	.probe_hw		= rt61pci_probe_hw,
290562306a36Sopenharmony_ci	.get_firmware_name	= rt61pci_get_firmware_name,
290662306a36Sopenharmony_ci	.check_firmware		= rt61pci_check_firmware,
290762306a36Sopenharmony_ci	.load_firmware		= rt61pci_load_firmware,
290862306a36Sopenharmony_ci	.initialize		= rt2x00mmio_initialize,
290962306a36Sopenharmony_ci	.uninitialize		= rt2x00mmio_uninitialize,
291062306a36Sopenharmony_ci	.get_entry_state	= rt61pci_get_entry_state,
291162306a36Sopenharmony_ci	.clear_entry		= rt61pci_clear_entry,
291262306a36Sopenharmony_ci	.set_device_state	= rt61pci_set_device_state,
291362306a36Sopenharmony_ci	.rfkill_poll		= rt61pci_rfkill_poll,
291462306a36Sopenharmony_ci	.link_stats		= rt61pci_link_stats,
291562306a36Sopenharmony_ci	.reset_tuner		= rt61pci_reset_tuner,
291662306a36Sopenharmony_ci	.link_tuner		= rt61pci_link_tuner,
291762306a36Sopenharmony_ci	.start_queue		= rt61pci_start_queue,
291862306a36Sopenharmony_ci	.kick_queue		= rt61pci_kick_queue,
291962306a36Sopenharmony_ci	.stop_queue		= rt61pci_stop_queue,
292062306a36Sopenharmony_ci	.flush_queue		= rt2x00mmio_flush_queue,
292162306a36Sopenharmony_ci	.write_tx_desc		= rt61pci_write_tx_desc,
292262306a36Sopenharmony_ci	.write_beacon		= rt61pci_write_beacon,
292362306a36Sopenharmony_ci	.clear_beacon		= rt61pci_clear_beacon,
292462306a36Sopenharmony_ci	.fill_rxdone		= rt61pci_fill_rxdone,
292562306a36Sopenharmony_ci	.config_shared_key	= rt61pci_config_shared_key,
292662306a36Sopenharmony_ci	.config_pairwise_key	= rt61pci_config_pairwise_key,
292762306a36Sopenharmony_ci	.config_filter		= rt61pci_config_filter,
292862306a36Sopenharmony_ci	.config_intf		= rt61pci_config_intf,
292962306a36Sopenharmony_ci	.config_erp		= rt61pci_config_erp,
293062306a36Sopenharmony_ci	.config_ant		= rt61pci_config_ant,
293162306a36Sopenharmony_ci	.config			= rt61pci_config,
293262306a36Sopenharmony_ci};
293362306a36Sopenharmony_ci
293462306a36Sopenharmony_cistatic void rt61pci_queue_init(struct data_queue *queue)
293562306a36Sopenharmony_ci{
293662306a36Sopenharmony_ci	switch (queue->qid) {
293762306a36Sopenharmony_ci	case QID_RX:
293862306a36Sopenharmony_ci		queue->limit = 32;
293962306a36Sopenharmony_ci		queue->data_size = DATA_FRAME_SIZE;
294062306a36Sopenharmony_ci		queue->desc_size = RXD_DESC_SIZE;
294162306a36Sopenharmony_ci		queue->priv_size = sizeof(struct queue_entry_priv_mmio);
294262306a36Sopenharmony_ci		break;
294362306a36Sopenharmony_ci
294462306a36Sopenharmony_ci	case QID_AC_VO:
294562306a36Sopenharmony_ci	case QID_AC_VI:
294662306a36Sopenharmony_ci	case QID_AC_BE:
294762306a36Sopenharmony_ci	case QID_AC_BK:
294862306a36Sopenharmony_ci		queue->limit = 32;
294962306a36Sopenharmony_ci		queue->data_size = DATA_FRAME_SIZE;
295062306a36Sopenharmony_ci		queue->desc_size = TXD_DESC_SIZE;
295162306a36Sopenharmony_ci		queue->priv_size = sizeof(struct queue_entry_priv_mmio);
295262306a36Sopenharmony_ci		break;
295362306a36Sopenharmony_ci
295462306a36Sopenharmony_ci	case QID_BEACON:
295562306a36Sopenharmony_ci		queue->limit = 4;
295662306a36Sopenharmony_ci		queue->data_size = 0; /* No DMA required for beacons */
295762306a36Sopenharmony_ci		queue->desc_size = TXINFO_SIZE;
295862306a36Sopenharmony_ci		queue->priv_size = sizeof(struct queue_entry_priv_mmio);
295962306a36Sopenharmony_ci		break;
296062306a36Sopenharmony_ci
296162306a36Sopenharmony_ci	case QID_ATIM:
296262306a36Sopenharmony_ci	default:
296362306a36Sopenharmony_ci		BUG();
296462306a36Sopenharmony_ci		break;
296562306a36Sopenharmony_ci	}
296662306a36Sopenharmony_ci}
296762306a36Sopenharmony_ci
296862306a36Sopenharmony_cistatic const struct rt2x00_ops rt61pci_ops = {
296962306a36Sopenharmony_ci	.name			= KBUILD_MODNAME,
297062306a36Sopenharmony_ci	.max_ap_intf		= 4,
297162306a36Sopenharmony_ci	.eeprom_size		= EEPROM_SIZE,
297262306a36Sopenharmony_ci	.rf_size		= RF_SIZE,
297362306a36Sopenharmony_ci	.tx_queues		= NUM_TX_QUEUES,
297462306a36Sopenharmony_ci	.queue_init		= rt61pci_queue_init,
297562306a36Sopenharmony_ci	.lib			= &rt61pci_rt2x00_ops,
297662306a36Sopenharmony_ci	.hw			= &rt61pci_mac80211_ops,
297762306a36Sopenharmony_ci#ifdef CONFIG_RT2X00_LIB_DEBUGFS
297862306a36Sopenharmony_ci	.debugfs		= &rt61pci_rt2x00debug,
297962306a36Sopenharmony_ci#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
298062306a36Sopenharmony_ci};
298162306a36Sopenharmony_ci
298262306a36Sopenharmony_ci/*
298362306a36Sopenharmony_ci * RT61pci module information.
298462306a36Sopenharmony_ci */
298562306a36Sopenharmony_cistatic const struct pci_device_id rt61pci_device_table[] = {
298662306a36Sopenharmony_ci	/* RT2561s */
298762306a36Sopenharmony_ci	{ PCI_DEVICE(0x1814, 0x0301) },
298862306a36Sopenharmony_ci	/* RT2561 v2 */
298962306a36Sopenharmony_ci	{ PCI_DEVICE(0x1814, 0x0302) },
299062306a36Sopenharmony_ci	/* RT2661 */
299162306a36Sopenharmony_ci	{ PCI_DEVICE(0x1814, 0x0401) },
299262306a36Sopenharmony_ci	{ 0, }
299362306a36Sopenharmony_ci};
299462306a36Sopenharmony_ci
299562306a36Sopenharmony_ciMODULE_AUTHOR(DRV_PROJECT);
299662306a36Sopenharmony_ciMODULE_VERSION(DRV_VERSION);
299762306a36Sopenharmony_ciMODULE_DESCRIPTION("Ralink RT61 PCI & PCMCIA Wireless LAN driver.");
299862306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, rt61pci_device_table);
299962306a36Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_RT2561);
300062306a36Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_RT2561s);
300162306a36Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_RT2661);
300262306a36Sopenharmony_ciMODULE_LICENSE("GPL");
300362306a36Sopenharmony_ci
300462306a36Sopenharmony_cistatic int rt61pci_probe(struct pci_dev *pci_dev,
300562306a36Sopenharmony_ci			 const struct pci_device_id *id)
300662306a36Sopenharmony_ci{
300762306a36Sopenharmony_ci	return rt2x00pci_probe(pci_dev, &rt61pci_ops);
300862306a36Sopenharmony_ci}
300962306a36Sopenharmony_ci
301062306a36Sopenharmony_cistatic struct pci_driver rt61pci_driver = {
301162306a36Sopenharmony_ci	.name		= KBUILD_MODNAME,
301262306a36Sopenharmony_ci	.id_table	= rt61pci_device_table,
301362306a36Sopenharmony_ci	.probe		= rt61pci_probe,
301462306a36Sopenharmony_ci	.remove		= rt2x00pci_remove,
301562306a36Sopenharmony_ci	.driver.pm	= &rt2x00pci_pm_ops,
301662306a36Sopenharmony_ci};
301762306a36Sopenharmony_ci
301862306a36Sopenharmony_cimodule_pci_driver(rt61pci_driver);
3019