162306a36Sopenharmony_ci// SPDX-License-Identifier: ISC
262306a36Sopenharmony_ci/* Copyright (C) 2020 MediaTek Inc. */
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci#include <linux/etherdevice.h>
562306a36Sopenharmony_ci#include <linux/hwmon.h>
662306a36Sopenharmony_ci#include <linux/hwmon-sysfs.h>
762306a36Sopenharmony_ci#include <linux/of.h>
862306a36Sopenharmony_ci#include <linux/thermal.h>
962306a36Sopenharmony_ci#include "mt7915.h"
1062306a36Sopenharmony_ci#include "mac.h"
1162306a36Sopenharmony_ci#include "mcu.h"
1262306a36Sopenharmony_ci#include "coredump.h"
1362306a36Sopenharmony_ci#include "eeprom.h"
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_cistatic const struct ieee80211_iface_limit if_limits[] = {
1662306a36Sopenharmony_ci	{
1762306a36Sopenharmony_ci		.max = 1,
1862306a36Sopenharmony_ci		.types = BIT(NL80211_IFTYPE_ADHOC)
1962306a36Sopenharmony_ci	}, {
2062306a36Sopenharmony_ci		.max = 16,
2162306a36Sopenharmony_ci		.types = BIT(NL80211_IFTYPE_AP)
2262306a36Sopenharmony_ci#ifdef CONFIG_MAC80211_MESH
2362306a36Sopenharmony_ci			 | BIT(NL80211_IFTYPE_MESH_POINT)
2462306a36Sopenharmony_ci#endif
2562306a36Sopenharmony_ci	}, {
2662306a36Sopenharmony_ci		.max = MT7915_MAX_INTERFACES,
2762306a36Sopenharmony_ci		.types = BIT(NL80211_IFTYPE_STATION)
2862306a36Sopenharmony_ci	}
2962306a36Sopenharmony_ci};
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_cistatic const struct ieee80211_iface_combination if_comb[] = {
3262306a36Sopenharmony_ci	{
3362306a36Sopenharmony_ci		.limits = if_limits,
3462306a36Sopenharmony_ci		.n_limits = ARRAY_SIZE(if_limits),
3562306a36Sopenharmony_ci		.max_interfaces = MT7915_MAX_INTERFACES,
3662306a36Sopenharmony_ci		.num_different_channels = 1,
3762306a36Sopenharmony_ci		.beacon_int_infra_match = true,
3862306a36Sopenharmony_ci		.radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) |
3962306a36Sopenharmony_ci				       BIT(NL80211_CHAN_WIDTH_20) |
4062306a36Sopenharmony_ci				       BIT(NL80211_CHAN_WIDTH_40) |
4162306a36Sopenharmony_ci				       BIT(NL80211_CHAN_WIDTH_80) |
4262306a36Sopenharmony_ci				       BIT(NL80211_CHAN_WIDTH_160),
4362306a36Sopenharmony_ci	}
4462306a36Sopenharmony_ci};
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_cistatic ssize_t mt7915_thermal_temp_show(struct device *dev,
4762306a36Sopenharmony_ci					struct device_attribute *attr,
4862306a36Sopenharmony_ci					char *buf)
4962306a36Sopenharmony_ci{
5062306a36Sopenharmony_ci	struct mt7915_phy *phy = dev_get_drvdata(dev);
5162306a36Sopenharmony_ci	int i = to_sensor_dev_attr(attr)->index;
5262306a36Sopenharmony_ci	int temperature;
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	switch (i) {
5562306a36Sopenharmony_ci	case 0:
5662306a36Sopenharmony_ci		temperature = mt7915_mcu_get_temperature(phy);
5762306a36Sopenharmony_ci		if (temperature < 0)
5862306a36Sopenharmony_ci			return temperature;
5962306a36Sopenharmony_ci		/* display in millidegree celcius */
6062306a36Sopenharmony_ci		return sprintf(buf, "%u\n", temperature * 1000);
6162306a36Sopenharmony_ci	case 1:
6262306a36Sopenharmony_ci	case 2:
6362306a36Sopenharmony_ci		return sprintf(buf, "%u\n",
6462306a36Sopenharmony_ci			       phy->throttle_temp[i - 1] * 1000);
6562306a36Sopenharmony_ci	case 3:
6662306a36Sopenharmony_ci		return sprintf(buf, "%hhu\n", phy->throttle_state);
6762306a36Sopenharmony_ci	default:
6862306a36Sopenharmony_ci		return -EINVAL;
6962306a36Sopenharmony_ci	}
7062306a36Sopenharmony_ci}
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_cistatic ssize_t mt7915_thermal_temp_store(struct device *dev,
7362306a36Sopenharmony_ci					 struct device_attribute *attr,
7462306a36Sopenharmony_ci					 const char *buf, size_t count)
7562306a36Sopenharmony_ci{
7662306a36Sopenharmony_ci	struct mt7915_phy *phy = dev_get_drvdata(dev);
7762306a36Sopenharmony_ci	int ret, i = to_sensor_dev_attr(attr)->index;
7862306a36Sopenharmony_ci	long val;
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	ret = kstrtol(buf, 10, &val);
8162306a36Sopenharmony_ci	if (ret < 0)
8262306a36Sopenharmony_ci		return ret;
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	mutex_lock(&phy->dev->mt76.mutex);
8562306a36Sopenharmony_ci	val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 60, 130);
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	if ((i - 1 == MT7915_CRIT_TEMP_IDX &&
8862306a36Sopenharmony_ci	     val > phy->throttle_temp[MT7915_MAX_TEMP_IDX]) ||
8962306a36Sopenharmony_ci	    (i - 1 == MT7915_MAX_TEMP_IDX &&
9062306a36Sopenharmony_ci	     val < phy->throttle_temp[MT7915_CRIT_TEMP_IDX])) {
9162306a36Sopenharmony_ci		dev_err(phy->dev->mt76.dev,
9262306a36Sopenharmony_ci			"temp1_max shall be greater than temp1_crit.");
9362306a36Sopenharmony_ci		mutex_unlock(&phy->dev->mt76.mutex);
9462306a36Sopenharmony_ci		return -EINVAL;
9562306a36Sopenharmony_ci	}
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	phy->throttle_temp[i - 1] = val;
9862306a36Sopenharmony_ci	mutex_unlock(&phy->dev->mt76.mutex);
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	ret = mt7915_mcu_set_thermal_protect(phy);
10162306a36Sopenharmony_ci	if (ret)
10262306a36Sopenharmony_ci		return ret;
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	return count;
10562306a36Sopenharmony_ci}
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp1_input, mt7915_thermal_temp, 0);
10862306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp1_crit, mt7915_thermal_temp, 1);
10962306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp1_max, mt7915_thermal_temp, 2);
11062306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(throttle1, mt7915_thermal_temp, 3);
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_cistatic struct attribute *mt7915_hwmon_attrs[] = {
11362306a36Sopenharmony_ci	&sensor_dev_attr_temp1_input.dev_attr.attr,
11462306a36Sopenharmony_ci	&sensor_dev_attr_temp1_crit.dev_attr.attr,
11562306a36Sopenharmony_ci	&sensor_dev_attr_temp1_max.dev_attr.attr,
11662306a36Sopenharmony_ci	&sensor_dev_attr_throttle1.dev_attr.attr,
11762306a36Sopenharmony_ci	NULL,
11862306a36Sopenharmony_ci};
11962306a36Sopenharmony_ciATTRIBUTE_GROUPS(mt7915_hwmon);
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_cistatic int
12262306a36Sopenharmony_cimt7915_thermal_get_max_throttle_state(struct thermal_cooling_device *cdev,
12362306a36Sopenharmony_ci				      unsigned long *state)
12462306a36Sopenharmony_ci{
12562306a36Sopenharmony_ci	*state = MT7915_CDEV_THROTTLE_MAX;
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	return 0;
12862306a36Sopenharmony_ci}
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_cistatic int
13162306a36Sopenharmony_cimt7915_thermal_get_cur_throttle_state(struct thermal_cooling_device *cdev,
13262306a36Sopenharmony_ci				      unsigned long *state)
13362306a36Sopenharmony_ci{
13462306a36Sopenharmony_ci	struct mt7915_phy *phy = cdev->devdata;
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	*state = phy->cdev_state;
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	return 0;
13962306a36Sopenharmony_ci}
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_cistatic int
14262306a36Sopenharmony_cimt7915_thermal_set_cur_throttle_state(struct thermal_cooling_device *cdev,
14362306a36Sopenharmony_ci				      unsigned long state)
14462306a36Sopenharmony_ci{
14562306a36Sopenharmony_ci	struct mt7915_phy *phy = cdev->devdata;
14662306a36Sopenharmony_ci	u8 throttling = MT7915_THERMAL_THROTTLE_MAX - state;
14762306a36Sopenharmony_ci	int ret;
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci	if (state > MT7915_CDEV_THROTTLE_MAX) {
15062306a36Sopenharmony_ci		dev_err(phy->dev->mt76.dev,
15162306a36Sopenharmony_ci			"please specify a valid throttling state\n");
15262306a36Sopenharmony_ci		return -EINVAL;
15362306a36Sopenharmony_ci	}
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	if (state == phy->cdev_state)
15662306a36Sopenharmony_ci		return 0;
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	/*
15962306a36Sopenharmony_ci	 * cooling_device convention: 0 = no cooling, more = more cooling
16062306a36Sopenharmony_ci	 * mcu convention: 1 = max cooling, more = less cooling
16162306a36Sopenharmony_ci	 */
16262306a36Sopenharmony_ci	ret = mt7915_mcu_set_thermal_throttling(phy, throttling);
16362306a36Sopenharmony_ci	if (ret)
16462306a36Sopenharmony_ci		return ret;
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	phy->cdev_state = state;
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	return 0;
16962306a36Sopenharmony_ci}
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_cistatic const struct thermal_cooling_device_ops mt7915_thermal_ops = {
17262306a36Sopenharmony_ci	.get_max_state = mt7915_thermal_get_max_throttle_state,
17362306a36Sopenharmony_ci	.get_cur_state = mt7915_thermal_get_cur_throttle_state,
17462306a36Sopenharmony_ci	.set_cur_state = mt7915_thermal_set_cur_throttle_state,
17562306a36Sopenharmony_ci};
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_cistatic void mt7915_unregister_thermal(struct mt7915_phy *phy)
17862306a36Sopenharmony_ci{
17962306a36Sopenharmony_ci	struct wiphy *wiphy = phy->mt76->hw->wiphy;
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	if (!phy->cdev)
18262306a36Sopenharmony_ci		return;
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	sysfs_remove_link(&wiphy->dev.kobj, "cooling_device");
18562306a36Sopenharmony_ci	thermal_cooling_device_unregister(phy->cdev);
18662306a36Sopenharmony_ci}
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_cistatic int mt7915_thermal_init(struct mt7915_phy *phy)
18962306a36Sopenharmony_ci{
19062306a36Sopenharmony_ci	struct wiphy *wiphy = phy->mt76->hw->wiphy;
19162306a36Sopenharmony_ci	struct thermal_cooling_device *cdev;
19262306a36Sopenharmony_ci	struct device *hwmon;
19362306a36Sopenharmony_ci	const char *name;
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	name = devm_kasprintf(&wiphy->dev, GFP_KERNEL, "mt7915_%s",
19662306a36Sopenharmony_ci			      wiphy_name(wiphy));
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	cdev = thermal_cooling_device_register(name, phy, &mt7915_thermal_ops);
19962306a36Sopenharmony_ci	if (!IS_ERR(cdev)) {
20062306a36Sopenharmony_ci		if (sysfs_create_link(&wiphy->dev.kobj, &cdev->device.kobj,
20162306a36Sopenharmony_ci				      "cooling_device") < 0)
20262306a36Sopenharmony_ci			thermal_cooling_device_unregister(cdev);
20362306a36Sopenharmony_ci		else
20462306a36Sopenharmony_ci			phy->cdev = cdev;
20562306a36Sopenharmony_ci	}
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	/* initialize critical/maximum high temperature */
20862306a36Sopenharmony_ci	phy->throttle_temp[MT7915_CRIT_TEMP_IDX] = MT7915_CRIT_TEMP;
20962306a36Sopenharmony_ci	phy->throttle_temp[MT7915_MAX_TEMP_IDX] = MT7915_MAX_TEMP;
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	if (!IS_REACHABLE(CONFIG_HWMON))
21262306a36Sopenharmony_ci		return 0;
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	hwmon = devm_hwmon_device_register_with_groups(&wiphy->dev, name, phy,
21562306a36Sopenharmony_ci						       mt7915_hwmon_groups);
21662306a36Sopenharmony_ci	if (IS_ERR(hwmon))
21762306a36Sopenharmony_ci		return PTR_ERR(hwmon);
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci	return 0;
22062306a36Sopenharmony_ci}
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_cistatic void mt7915_led_set_config(struct led_classdev *led_cdev,
22362306a36Sopenharmony_ci				  u8 delay_on, u8 delay_off)
22462306a36Sopenharmony_ci{
22562306a36Sopenharmony_ci	struct mt7915_dev *dev;
22662306a36Sopenharmony_ci	struct mt76_phy *mphy;
22762306a36Sopenharmony_ci	u32 val;
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	mphy = container_of(led_cdev, struct mt76_phy, leds.cdev);
23062306a36Sopenharmony_ci	dev = container_of(mphy->dev, struct mt7915_dev, mt76);
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	/* set PWM mode */
23362306a36Sopenharmony_ci	val = FIELD_PREP(MT_LED_STATUS_DURATION, 0xffff) |
23462306a36Sopenharmony_ci	      FIELD_PREP(MT_LED_STATUS_OFF, delay_off) |
23562306a36Sopenharmony_ci	      FIELD_PREP(MT_LED_STATUS_ON, delay_on);
23662306a36Sopenharmony_ci	mt76_wr(dev, MT_LED_STATUS_0(mphy->band_idx), val);
23762306a36Sopenharmony_ci	mt76_wr(dev, MT_LED_STATUS_1(mphy->band_idx), val);
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci	/* enable LED */
24062306a36Sopenharmony_ci	mt76_wr(dev, MT_LED_EN(mphy->band_idx), 1);
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci	/* control LED */
24362306a36Sopenharmony_ci	val = MT_LED_CTRL_KICK;
24462306a36Sopenharmony_ci	if (dev->mphy.leds.al)
24562306a36Sopenharmony_ci		val |= MT_LED_CTRL_POLARITY;
24662306a36Sopenharmony_ci	if (mphy->band_idx)
24762306a36Sopenharmony_ci		val |= MT_LED_CTRL_BAND;
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	mt76_wr(dev, MT_LED_CTRL(mphy->band_idx), val);
25062306a36Sopenharmony_ci	mt76_clear(dev, MT_LED_CTRL(mphy->band_idx), MT_LED_CTRL_KICK);
25162306a36Sopenharmony_ci}
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_cistatic int mt7915_led_set_blink(struct led_classdev *led_cdev,
25462306a36Sopenharmony_ci				unsigned long *delay_on,
25562306a36Sopenharmony_ci				unsigned long *delay_off)
25662306a36Sopenharmony_ci{
25762306a36Sopenharmony_ci	u16 delta_on = 0, delta_off = 0;
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci#define HW_TICK		10
26062306a36Sopenharmony_ci#define TO_HW_TICK(_t)	(((_t) > HW_TICK) ? ((_t) / HW_TICK) : HW_TICK)
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	if (*delay_on)
26362306a36Sopenharmony_ci		delta_on = TO_HW_TICK(*delay_on);
26462306a36Sopenharmony_ci	if (*delay_off)
26562306a36Sopenharmony_ci		delta_off = TO_HW_TICK(*delay_off);
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	mt7915_led_set_config(led_cdev, delta_on, delta_off);
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	return 0;
27062306a36Sopenharmony_ci}
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_cistatic void mt7915_led_set_brightness(struct led_classdev *led_cdev,
27362306a36Sopenharmony_ci				      enum led_brightness brightness)
27462306a36Sopenharmony_ci{
27562306a36Sopenharmony_ci	if (!brightness)
27662306a36Sopenharmony_ci		mt7915_led_set_config(led_cdev, 0, 0xff);
27762306a36Sopenharmony_ci	else
27862306a36Sopenharmony_ci		mt7915_led_set_config(led_cdev, 0xff, 0);
27962306a36Sopenharmony_ci}
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_civoid mt7915_init_txpower(struct mt7915_dev *dev,
28262306a36Sopenharmony_ci			 struct ieee80211_supported_band *sband)
28362306a36Sopenharmony_ci{
28462306a36Sopenharmony_ci	int i, n_chains = hweight8(dev->mphy.antenna_mask);
28562306a36Sopenharmony_ci	int nss_delta = mt76_tx_power_nss_delta(n_chains);
28662306a36Sopenharmony_ci	int pwr_delta = mt7915_eeprom_get_power_delta(dev, sband->band);
28762306a36Sopenharmony_ci	struct mt76_power_limits limits;
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	for (i = 0; i < sband->n_channels; i++) {
29062306a36Sopenharmony_ci		struct ieee80211_channel *chan = &sband->channels[i];
29162306a36Sopenharmony_ci		u32 target_power = 0;
29262306a36Sopenharmony_ci		int j;
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci		for (j = 0; j < n_chains; j++) {
29562306a36Sopenharmony_ci			u32 val;
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci			val = mt7915_eeprom_get_target_power(dev, chan, j);
29862306a36Sopenharmony_ci			target_power = max(target_power, val);
29962306a36Sopenharmony_ci		}
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci		target_power += pwr_delta;
30262306a36Sopenharmony_ci		target_power = mt76_get_rate_power_limits(&dev->mphy, chan,
30362306a36Sopenharmony_ci							  &limits,
30462306a36Sopenharmony_ci							  target_power);
30562306a36Sopenharmony_ci		target_power += nss_delta;
30662306a36Sopenharmony_ci		target_power = DIV_ROUND_UP(target_power, 2);
30762306a36Sopenharmony_ci		chan->max_power = min_t(int, chan->max_reg_power,
30862306a36Sopenharmony_ci					target_power);
30962306a36Sopenharmony_ci		chan->orig_mpwr = target_power;
31062306a36Sopenharmony_ci	}
31162306a36Sopenharmony_ci}
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_cistatic void
31462306a36Sopenharmony_cimt7915_regd_notifier(struct wiphy *wiphy,
31562306a36Sopenharmony_ci		     struct regulatory_request *request)
31662306a36Sopenharmony_ci{
31762306a36Sopenharmony_ci	struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
31862306a36Sopenharmony_ci	struct mt7915_dev *dev = mt7915_hw_dev(hw);
31962306a36Sopenharmony_ci	struct mt76_phy *mphy = hw->priv;
32062306a36Sopenharmony_ci	struct mt7915_phy *phy = mphy->priv;
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci	memcpy(dev->mt76.alpha2, request->alpha2, sizeof(dev->mt76.alpha2));
32362306a36Sopenharmony_ci	dev->mt76.region = request->dfs_region;
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	if (dev->mt76.region == NL80211_DFS_UNSET)
32662306a36Sopenharmony_ci		mt7915_mcu_rdd_background_enable(phy, NULL);
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	mt7915_init_txpower(dev, &mphy->sband_2g.sband);
32962306a36Sopenharmony_ci	mt7915_init_txpower(dev, &mphy->sband_5g.sband);
33062306a36Sopenharmony_ci	mt7915_init_txpower(dev, &mphy->sband_6g.sband);
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	mphy->dfs_state = MT_DFS_STATE_UNKNOWN;
33362306a36Sopenharmony_ci	mt7915_dfs_init_radar_detector(phy);
33462306a36Sopenharmony_ci}
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_cistatic void
33762306a36Sopenharmony_cimt7915_init_wiphy(struct mt7915_phy *phy)
33862306a36Sopenharmony_ci{
33962306a36Sopenharmony_ci	struct mt76_phy *mphy = phy->mt76;
34062306a36Sopenharmony_ci	struct ieee80211_hw *hw = mphy->hw;
34162306a36Sopenharmony_ci	struct mt76_dev *mdev = &phy->dev->mt76;
34262306a36Sopenharmony_ci	struct wiphy *wiphy = hw->wiphy;
34362306a36Sopenharmony_ci	struct mt7915_dev *dev = phy->dev;
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	hw->queues = 4;
34662306a36Sopenharmony_ci	hw->max_rx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF_HE;
34762306a36Sopenharmony_ci	hw->max_tx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF_HE;
34862306a36Sopenharmony_ci	hw->netdev_features = NETIF_F_RXCSUM;
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	hw->radiotap_timestamp.units_pos =
35162306a36Sopenharmony_ci		IEEE80211_RADIOTAP_TIMESTAMP_UNIT_US;
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	phy->slottime = 9;
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	hw->sta_data_size = sizeof(struct mt7915_sta);
35662306a36Sopenharmony_ci	hw->vif_data_size = sizeof(struct mt7915_vif);
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci	wiphy->iface_combinations = if_comb;
35962306a36Sopenharmony_ci	wiphy->n_iface_combinations = ARRAY_SIZE(if_comb);
36062306a36Sopenharmony_ci	wiphy->reg_notifier = mt7915_regd_notifier;
36162306a36Sopenharmony_ci	wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH;
36262306a36Sopenharmony_ci	wiphy->mbssid_max_interfaces = 16;
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_BSS_COLOR);
36562306a36Sopenharmony_ci	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_VHT_IBSS);
36662306a36Sopenharmony_ci	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_BEACON_RATE_LEGACY);
36762306a36Sopenharmony_ci	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_BEACON_RATE_HT);
36862306a36Sopenharmony_ci	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_BEACON_RATE_VHT);
36962306a36Sopenharmony_ci	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_BEACON_RATE_HE);
37062306a36Sopenharmony_ci	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_UNSOL_BCAST_PROBE_RESP);
37162306a36Sopenharmony_ci	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_FILS_DISCOVERY);
37262306a36Sopenharmony_ci	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_ACK_SIGNAL_SUPPORT);
37362306a36Sopenharmony_ci	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CAN_REPLACE_PTK0);
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci	if (!is_mt7915(&dev->mt76))
37662306a36Sopenharmony_ci		wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_STA_TX_PWR);
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci	if (!mdev->dev->of_node ||
37962306a36Sopenharmony_ci	    !of_property_read_bool(mdev->dev->of_node,
38062306a36Sopenharmony_ci				   "mediatek,disable-radar-background"))
38162306a36Sopenharmony_ci		wiphy_ext_feature_set(wiphy,
38262306a36Sopenharmony_ci				      NL80211_EXT_FEATURE_RADAR_BACKGROUND);
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci	ieee80211_hw_set(hw, HAS_RATE_CONTROL);
38562306a36Sopenharmony_ci	ieee80211_hw_set(hw, SUPPORTS_TX_ENCAP_OFFLOAD);
38662306a36Sopenharmony_ci	ieee80211_hw_set(hw, SUPPORTS_RX_DECAP_OFFLOAD);
38762306a36Sopenharmony_ci	ieee80211_hw_set(hw, SUPPORTS_MULTI_BSSID);
38862306a36Sopenharmony_ci	ieee80211_hw_set(hw, WANT_MONITOR_VIF);
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci	hw->max_tx_fragments = 4;
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci	if (phy->mt76->cap.has_2ghz) {
39362306a36Sopenharmony_ci		phy->mt76->sband_2g.sband.ht_cap.cap |=
39462306a36Sopenharmony_ci			IEEE80211_HT_CAP_LDPC_CODING |
39562306a36Sopenharmony_ci			IEEE80211_HT_CAP_MAX_AMSDU;
39662306a36Sopenharmony_ci		phy->mt76->sband_2g.sband.ht_cap.ampdu_density =
39762306a36Sopenharmony_ci			IEEE80211_HT_MPDU_DENSITY_4;
39862306a36Sopenharmony_ci	}
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci	if (phy->mt76->cap.has_5ghz) {
40162306a36Sopenharmony_ci		struct ieee80211_sta_vht_cap *vht_cap;
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci		vht_cap = &phy->mt76->sband_5g.sband.vht_cap;
40462306a36Sopenharmony_ci		phy->mt76->sband_5g.sband.ht_cap.cap |=
40562306a36Sopenharmony_ci			IEEE80211_HT_CAP_LDPC_CODING |
40662306a36Sopenharmony_ci			IEEE80211_HT_CAP_MAX_AMSDU;
40762306a36Sopenharmony_ci		phy->mt76->sband_5g.sband.ht_cap.ampdu_density =
40862306a36Sopenharmony_ci			IEEE80211_HT_MPDU_DENSITY_4;
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci		if (is_mt7915(&dev->mt76)) {
41162306a36Sopenharmony_ci			vht_cap->cap |=
41262306a36Sopenharmony_ci				IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991 |
41362306a36Sopenharmony_ci				IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK;
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci			if (!dev->dbdc_support)
41662306a36Sopenharmony_ci				vht_cap->cap |=
41762306a36Sopenharmony_ci					IEEE80211_VHT_CAP_SHORT_GI_160 |
41862306a36Sopenharmony_ci					FIELD_PREP(IEEE80211_VHT_CAP_EXT_NSS_BW_MASK, 1);
41962306a36Sopenharmony_ci		} else {
42062306a36Sopenharmony_ci			vht_cap->cap |=
42162306a36Sopenharmony_ci				IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 |
42262306a36Sopenharmony_ci				IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK;
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci			/* mt7916 dbdc with 2g 2x2 bw40 and 5g 2x2 bw160c */
42562306a36Sopenharmony_ci			vht_cap->cap |=
42662306a36Sopenharmony_ci				IEEE80211_VHT_CAP_SHORT_GI_160 |
42762306a36Sopenharmony_ci				IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
42862306a36Sopenharmony_ci		}
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ci		if (!is_mt7915(&dev->mt76) || !dev->dbdc_support)
43162306a36Sopenharmony_ci			ieee80211_hw_set(hw, SUPPORTS_VHT_EXT_NSS_BW);
43262306a36Sopenharmony_ci	}
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci	mt76_set_stream_caps(phy->mt76, true);
43562306a36Sopenharmony_ci	mt7915_set_stream_vht_txbf_caps(phy);
43662306a36Sopenharmony_ci	mt7915_set_stream_he_caps(phy);
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	wiphy->available_antennas_rx = phy->mt76->antenna_mask;
43962306a36Sopenharmony_ci	wiphy->available_antennas_tx = phy->mt76->antenna_mask;
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci	/* init led callbacks */
44262306a36Sopenharmony_ci	if (IS_ENABLED(CONFIG_MT76_LEDS)) {
44362306a36Sopenharmony_ci		mphy->leds.cdev.brightness_set = mt7915_led_set_brightness;
44462306a36Sopenharmony_ci		mphy->leds.cdev.blink_set = mt7915_led_set_blink;
44562306a36Sopenharmony_ci	}
44662306a36Sopenharmony_ci}
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_cistatic void
44962306a36Sopenharmony_cimt7915_mac_init_band(struct mt7915_dev *dev, u8 band)
45062306a36Sopenharmony_ci{
45162306a36Sopenharmony_ci	u32 mask, set;
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci	mt76_rmw_field(dev, MT_TMAC_CTCR0(band),
45462306a36Sopenharmony_ci		       MT_TMAC_CTCR0_INS_DDLMT_REFTIME, 0x3f);
45562306a36Sopenharmony_ci	mt76_set(dev, MT_TMAC_CTCR0(band),
45662306a36Sopenharmony_ci		 MT_TMAC_CTCR0_INS_DDLMT_VHT_SMPDU_EN |
45762306a36Sopenharmony_ci		 MT_TMAC_CTCR0_INS_DDLMT_EN);
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci	mask = MT_MDP_RCFR0_MCU_RX_MGMT |
46062306a36Sopenharmony_ci	       MT_MDP_RCFR0_MCU_RX_CTL_NON_BAR |
46162306a36Sopenharmony_ci	       MT_MDP_RCFR0_MCU_RX_CTL_BAR;
46262306a36Sopenharmony_ci	set = FIELD_PREP(MT_MDP_RCFR0_MCU_RX_MGMT, MT_MDP_TO_HIF) |
46362306a36Sopenharmony_ci	      FIELD_PREP(MT_MDP_RCFR0_MCU_RX_CTL_NON_BAR, MT_MDP_TO_HIF) |
46462306a36Sopenharmony_ci	      FIELD_PREP(MT_MDP_RCFR0_MCU_RX_CTL_BAR, MT_MDP_TO_HIF);
46562306a36Sopenharmony_ci	mt76_rmw(dev, MT_MDP_BNRCFR0(band), mask, set);
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci	mask = MT_MDP_RCFR1_MCU_RX_BYPASS |
46862306a36Sopenharmony_ci	       MT_MDP_RCFR1_RX_DROPPED_UCAST |
46962306a36Sopenharmony_ci	       MT_MDP_RCFR1_RX_DROPPED_MCAST;
47062306a36Sopenharmony_ci	set = FIELD_PREP(MT_MDP_RCFR1_MCU_RX_BYPASS, MT_MDP_TO_HIF) |
47162306a36Sopenharmony_ci	      FIELD_PREP(MT_MDP_RCFR1_RX_DROPPED_UCAST, MT_MDP_TO_HIF) |
47262306a36Sopenharmony_ci	      FIELD_PREP(MT_MDP_RCFR1_RX_DROPPED_MCAST, MT_MDP_TO_HIF);
47362306a36Sopenharmony_ci	mt76_rmw(dev, MT_MDP_BNRCFR1(band), mask, set);
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci	mt76_rmw_field(dev, MT_DMA_DCR0(band), MT_DMA_DCR0_MAX_RX_LEN, 0x680);
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci	/* mt7915: disable rx rate report by default due to hw issues */
47862306a36Sopenharmony_ci	mt76_clear(dev, MT_DMA_DCR0(band), MT_DMA_DCR0_RXD_G5_EN);
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci	/* clear estimated value of EIFS for Rx duration & OBSS time */
48162306a36Sopenharmony_ci	mt76_wr(dev, MT_WF_RMAC_RSVD0(band), MT_WF_RMAC_RSVD0_EIFS_CLR);
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci	/* clear backoff time for Rx duration  */
48462306a36Sopenharmony_ci	mt76_clear(dev, MT_WF_RMAC_MIB_AIRTIME1(band),
48562306a36Sopenharmony_ci		   MT_WF_RMAC_MIB_NONQOSD_BACKOFF);
48662306a36Sopenharmony_ci	mt76_clear(dev, MT_WF_RMAC_MIB_AIRTIME3(band),
48762306a36Sopenharmony_ci		   MT_WF_RMAC_MIB_QOS01_BACKOFF);
48862306a36Sopenharmony_ci	mt76_clear(dev, MT_WF_RMAC_MIB_AIRTIME4(band),
48962306a36Sopenharmony_ci		   MT_WF_RMAC_MIB_QOS23_BACKOFF);
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ci	/* clear backoff time and set software compensation for OBSS time */
49262306a36Sopenharmony_ci	mask = MT_WF_RMAC_MIB_OBSS_BACKOFF | MT_WF_RMAC_MIB_ED_OFFSET;
49362306a36Sopenharmony_ci	set = FIELD_PREP(MT_WF_RMAC_MIB_OBSS_BACKOFF, 0) |
49462306a36Sopenharmony_ci	      FIELD_PREP(MT_WF_RMAC_MIB_ED_OFFSET, 4);
49562306a36Sopenharmony_ci	mt76_rmw(dev, MT_WF_RMAC_MIB_AIRTIME0(band), mask, set);
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci	/* filter out non-resp frames and get instanstaeous signal reporting */
49862306a36Sopenharmony_ci	mask = MT_WTBLOFF_TOP_RSCR_RCPI_MODE | MT_WTBLOFF_TOP_RSCR_RCPI_PARAM;
49962306a36Sopenharmony_ci	set = FIELD_PREP(MT_WTBLOFF_TOP_RSCR_RCPI_MODE, 0) |
50062306a36Sopenharmony_ci	      FIELD_PREP(MT_WTBLOFF_TOP_RSCR_RCPI_PARAM, 0x3);
50162306a36Sopenharmony_ci	mt76_rmw(dev, MT_WTBLOFF_TOP_RSCR(band), mask, set);
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_ci	/* MT_TXD5_TX_STATUS_HOST (MPDU format) has higher priority than
50462306a36Sopenharmony_ci	 * MT_AGG_ACR_PPDU_TXS2H (PPDU format) even though ACR bit is set.
50562306a36Sopenharmony_ci	 */
50662306a36Sopenharmony_ci	if (mtk_wed_device_active(&dev->mt76.mmio.wed))
50762306a36Sopenharmony_ci		mt76_set(dev, MT_AGG_ACR4(band), MT_AGG_ACR_PPDU_TXS2H);
50862306a36Sopenharmony_ci}
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_cistatic void
51162306a36Sopenharmony_cimt7915_init_led_mux(struct mt7915_dev *dev)
51262306a36Sopenharmony_ci{
51362306a36Sopenharmony_ci	if (!IS_ENABLED(CONFIG_MT76_LEDS))
51462306a36Sopenharmony_ci		return;
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci	if (dev->dbdc_support) {
51762306a36Sopenharmony_ci		switch (mt76_chip(&dev->mt76)) {
51862306a36Sopenharmony_ci		case 0x7915:
51962306a36Sopenharmony_ci			mt76_rmw_field(dev, MT_LED_GPIO_MUX2,
52062306a36Sopenharmony_ci				       GENMASK(11, 8), 4);
52162306a36Sopenharmony_ci			mt76_rmw_field(dev, MT_LED_GPIO_MUX3,
52262306a36Sopenharmony_ci				       GENMASK(11, 8), 4);
52362306a36Sopenharmony_ci			break;
52462306a36Sopenharmony_ci		case 0x7986:
52562306a36Sopenharmony_ci			mt76_rmw_field(dev, MT_LED_GPIO_MUX0,
52662306a36Sopenharmony_ci				       GENMASK(7, 4), 1);
52762306a36Sopenharmony_ci			mt76_rmw_field(dev, MT_LED_GPIO_MUX0,
52862306a36Sopenharmony_ci				       GENMASK(11, 8), 1);
52962306a36Sopenharmony_ci			break;
53062306a36Sopenharmony_ci		case 0x7916:
53162306a36Sopenharmony_ci			mt76_rmw_field(dev, MT_LED_GPIO_MUX1,
53262306a36Sopenharmony_ci				       GENMASK(27, 24), 3);
53362306a36Sopenharmony_ci			mt76_rmw_field(dev, MT_LED_GPIO_MUX1,
53462306a36Sopenharmony_ci				       GENMASK(31, 28), 3);
53562306a36Sopenharmony_ci			break;
53662306a36Sopenharmony_ci		default:
53762306a36Sopenharmony_ci			break;
53862306a36Sopenharmony_ci		}
53962306a36Sopenharmony_ci	} else if (dev->mphy.leds.pin) {
54062306a36Sopenharmony_ci		switch (mt76_chip(&dev->mt76)) {
54162306a36Sopenharmony_ci		case 0x7915:
54262306a36Sopenharmony_ci			mt76_rmw_field(dev, MT_LED_GPIO_MUX3,
54362306a36Sopenharmony_ci				       GENMASK(11, 8), 4);
54462306a36Sopenharmony_ci			break;
54562306a36Sopenharmony_ci		case 0x7986:
54662306a36Sopenharmony_ci			mt76_rmw_field(dev, MT_LED_GPIO_MUX0,
54762306a36Sopenharmony_ci				       GENMASK(11, 8), 1);
54862306a36Sopenharmony_ci			break;
54962306a36Sopenharmony_ci		case 0x7916:
55062306a36Sopenharmony_ci			mt76_rmw_field(dev, MT_LED_GPIO_MUX1,
55162306a36Sopenharmony_ci				       GENMASK(31, 28), 3);
55262306a36Sopenharmony_ci			break;
55362306a36Sopenharmony_ci		default:
55462306a36Sopenharmony_ci			break;
55562306a36Sopenharmony_ci		}
55662306a36Sopenharmony_ci	} else {
55762306a36Sopenharmony_ci		switch (mt76_chip(&dev->mt76)) {
55862306a36Sopenharmony_ci		case 0x7915:
55962306a36Sopenharmony_ci			mt76_rmw_field(dev, MT_LED_GPIO_MUX2,
56062306a36Sopenharmony_ci				       GENMASK(11, 8), 4);
56162306a36Sopenharmony_ci			break;
56262306a36Sopenharmony_ci		case 0x7986:
56362306a36Sopenharmony_ci			mt76_rmw_field(dev, MT_LED_GPIO_MUX0,
56462306a36Sopenharmony_ci				       GENMASK(7, 4), 1);
56562306a36Sopenharmony_ci			break;
56662306a36Sopenharmony_ci		case 0x7916:
56762306a36Sopenharmony_ci			mt76_rmw_field(dev, MT_LED_GPIO_MUX1,
56862306a36Sopenharmony_ci				       GENMASK(27, 24), 3);
56962306a36Sopenharmony_ci			break;
57062306a36Sopenharmony_ci		default:
57162306a36Sopenharmony_ci			break;
57262306a36Sopenharmony_ci		}
57362306a36Sopenharmony_ci	}
57462306a36Sopenharmony_ci}
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_civoid mt7915_mac_init(struct mt7915_dev *dev)
57762306a36Sopenharmony_ci{
57862306a36Sopenharmony_ci	int i;
57962306a36Sopenharmony_ci	u32 rx_len = is_mt7915(&dev->mt76) ? 0x400 : 0x680;
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ci	/* config pse qid6 wfdma port selection */
58262306a36Sopenharmony_ci	if (!is_mt7915(&dev->mt76) && dev->hif2)
58362306a36Sopenharmony_ci		mt76_rmw(dev, MT_WF_PP_TOP_RXQ_WFDMA_CF_5, 0,
58462306a36Sopenharmony_ci			 MT_WF_PP_TOP_RXQ_QID6_WFDMA_HIF_SEL_MASK);
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci	mt76_rmw_field(dev, MT_MDP_DCR1, MT_MDP_DCR1_MAX_RX_LEN, rx_len);
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci	if (!is_mt7915(&dev->mt76))
58962306a36Sopenharmony_ci		mt76_clear(dev, MT_MDP_DCR2, MT_MDP_DCR2_RX_TRANS_SHORT);
59062306a36Sopenharmony_ci	else
59162306a36Sopenharmony_ci		mt76_clear(dev, MT_PLE_HOST_RPT0, MT_PLE_HOST_RPT0_TX_LATENCY);
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci	/* enable hardware de-agg */
59462306a36Sopenharmony_ci	mt76_set(dev, MT_MDP_DCR0, MT_MDP_DCR0_DAMSDU_EN);
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ci	for (i = 0; i < mt7915_wtbl_size(dev); i++)
59762306a36Sopenharmony_ci		mt7915_mac_wtbl_update(dev, i,
59862306a36Sopenharmony_ci				       MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
59962306a36Sopenharmony_ci	for (i = 0; i < 2; i++)
60062306a36Sopenharmony_ci		mt7915_mac_init_band(dev, i);
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci	mt7915_init_led_mux(dev);
60362306a36Sopenharmony_ci}
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ciint mt7915_txbf_init(struct mt7915_dev *dev)
60662306a36Sopenharmony_ci{
60762306a36Sopenharmony_ci	int ret;
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci	if (dev->dbdc_support) {
61062306a36Sopenharmony_ci		ret = mt7915_mcu_set_txbf(dev, MT_BF_MODULE_UPDATE);
61162306a36Sopenharmony_ci		if (ret)
61262306a36Sopenharmony_ci			return ret;
61362306a36Sopenharmony_ci	}
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_ci	/* trigger sounding packets */
61662306a36Sopenharmony_ci	ret = mt7915_mcu_set_txbf(dev, MT_BF_SOUNDING_ON);
61762306a36Sopenharmony_ci	if (ret)
61862306a36Sopenharmony_ci		return ret;
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_ci	/* enable eBF */
62162306a36Sopenharmony_ci	return mt7915_mcu_set_txbf(dev, MT_BF_TYPE_UPDATE);
62262306a36Sopenharmony_ci}
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_cistatic struct mt7915_phy *
62562306a36Sopenharmony_cimt7915_alloc_ext_phy(struct mt7915_dev *dev)
62662306a36Sopenharmony_ci{
62762306a36Sopenharmony_ci	struct mt7915_phy *phy;
62862306a36Sopenharmony_ci	struct mt76_phy *mphy;
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ci	if (!dev->dbdc_support)
63162306a36Sopenharmony_ci		return NULL;
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_ci	mphy = mt76_alloc_phy(&dev->mt76, sizeof(*phy), &mt7915_ops, MT_BAND1);
63462306a36Sopenharmony_ci	if (!mphy)
63562306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_ci	phy = mphy->priv;
63862306a36Sopenharmony_ci	phy->dev = dev;
63962306a36Sopenharmony_ci	phy->mt76 = mphy;
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_ci	/* Bind main phy to band0 and ext_phy to band1 for dbdc case */
64262306a36Sopenharmony_ci	phy->mt76->band_idx = 1;
64362306a36Sopenharmony_ci
64462306a36Sopenharmony_ci	return phy;
64562306a36Sopenharmony_ci}
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_cistatic int
64862306a36Sopenharmony_cimt7915_register_ext_phy(struct mt7915_dev *dev, struct mt7915_phy *phy)
64962306a36Sopenharmony_ci{
65062306a36Sopenharmony_ci	struct mt76_phy *mphy = phy->mt76;
65162306a36Sopenharmony_ci	int ret;
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_ci	INIT_DELAYED_WORK(&mphy->mac_work, mt7915_mac_work);
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_ci	mt7915_eeprom_parse_hw_cap(dev, phy);
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci	memcpy(mphy->macaddr, dev->mt76.eeprom.data + MT_EE_MAC_ADDR2,
65862306a36Sopenharmony_ci	       ETH_ALEN);
65962306a36Sopenharmony_ci	/* Make the secondary PHY MAC address local without overlapping with
66062306a36Sopenharmony_ci	 * the usual MAC address allocation scheme on multiple virtual interfaces
66162306a36Sopenharmony_ci	 */
66262306a36Sopenharmony_ci	if (!is_valid_ether_addr(mphy->macaddr)) {
66362306a36Sopenharmony_ci		memcpy(mphy->macaddr, dev->mt76.eeprom.data + MT_EE_MAC_ADDR,
66462306a36Sopenharmony_ci		       ETH_ALEN);
66562306a36Sopenharmony_ci		mphy->macaddr[0] |= 2;
66662306a36Sopenharmony_ci		mphy->macaddr[0] ^= BIT(7);
66762306a36Sopenharmony_ci	}
66862306a36Sopenharmony_ci	mt76_eeprom_override(mphy);
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_ci	/* init wiphy according to mphy and phy */
67162306a36Sopenharmony_ci	mt7915_init_wiphy(phy);
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_ci	ret = mt76_register_phy(mphy, true, mt76_rates,
67462306a36Sopenharmony_ci				ARRAY_SIZE(mt76_rates));
67562306a36Sopenharmony_ci	if (ret)
67662306a36Sopenharmony_ci		return ret;
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_ci	ret = mt7915_thermal_init(phy);
67962306a36Sopenharmony_ci	if (ret)
68062306a36Sopenharmony_ci		goto unreg;
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_ci	mt7915_init_debugfs(phy);
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci	return 0;
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_ciunreg:
68762306a36Sopenharmony_ci	mt76_unregister_phy(mphy);
68862306a36Sopenharmony_ci	return ret;
68962306a36Sopenharmony_ci}
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_cistatic void mt7915_init_work(struct work_struct *work)
69262306a36Sopenharmony_ci{
69362306a36Sopenharmony_ci	struct mt7915_dev *dev = container_of(work, struct mt7915_dev,
69462306a36Sopenharmony_ci				 init_work);
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_ci	mt7915_mcu_set_eeprom(dev);
69762306a36Sopenharmony_ci	mt7915_mac_init(dev);
69862306a36Sopenharmony_ci	mt7915_init_txpower(dev, &dev->mphy.sband_2g.sband);
69962306a36Sopenharmony_ci	mt7915_init_txpower(dev, &dev->mphy.sband_5g.sband);
70062306a36Sopenharmony_ci	mt7915_init_txpower(dev, &dev->mphy.sband_6g.sband);
70162306a36Sopenharmony_ci	mt7915_txbf_init(dev);
70262306a36Sopenharmony_ci}
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_civoid mt7915_wfsys_reset(struct mt7915_dev *dev)
70562306a36Sopenharmony_ci{
70662306a36Sopenharmony_ci#define MT_MCU_DUMMY_RANDOM	GENMASK(15, 0)
70762306a36Sopenharmony_ci#define MT_MCU_DUMMY_DEFAULT	GENMASK(31, 16)
70862306a36Sopenharmony_ci
70962306a36Sopenharmony_ci	if (is_mt7915(&dev->mt76)) {
71062306a36Sopenharmony_ci		u32 val = MT_TOP_PWR_KEY | MT_TOP_PWR_SW_PWR_ON | MT_TOP_PWR_PWR_ON;
71162306a36Sopenharmony_ci
71262306a36Sopenharmony_ci		mt76_wr(dev, MT_MCU_WFDMA0_DUMMY_CR, MT_MCU_DUMMY_RANDOM);
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_ci		/* change to software control */
71562306a36Sopenharmony_ci		val |= MT_TOP_PWR_SW_RST;
71662306a36Sopenharmony_ci		mt76_wr(dev, MT_TOP_PWR_CTRL, val);
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_ci		/* reset wfsys */
71962306a36Sopenharmony_ci		val &= ~MT_TOP_PWR_SW_RST;
72062306a36Sopenharmony_ci		mt76_wr(dev, MT_TOP_PWR_CTRL, val);
72162306a36Sopenharmony_ci
72262306a36Sopenharmony_ci		/* release wfsys then mcu re-executes romcode */
72362306a36Sopenharmony_ci		val |= MT_TOP_PWR_SW_RST;
72462306a36Sopenharmony_ci		mt76_wr(dev, MT_TOP_PWR_CTRL, val);
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_ci		/* switch to hw control */
72762306a36Sopenharmony_ci		val &= ~MT_TOP_PWR_SW_RST;
72862306a36Sopenharmony_ci		val |= MT_TOP_PWR_HW_CTRL;
72962306a36Sopenharmony_ci		mt76_wr(dev, MT_TOP_PWR_CTRL, val);
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ci		/* check whether mcu resets to default */
73262306a36Sopenharmony_ci		if (!mt76_poll_msec(dev, MT_MCU_WFDMA0_DUMMY_CR,
73362306a36Sopenharmony_ci				    MT_MCU_DUMMY_DEFAULT, MT_MCU_DUMMY_DEFAULT,
73462306a36Sopenharmony_ci				    1000)) {
73562306a36Sopenharmony_ci			dev_err(dev->mt76.dev, "wifi subsystem reset failure\n");
73662306a36Sopenharmony_ci			return;
73762306a36Sopenharmony_ci		}
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_ci		/* wfsys reset won't clear host registers */
74062306a36Sopenharmony_ci		mt76_clear(dev, MT_TOP_MISC, MT_TOP_MISC_FW_STATE);
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_ci		msleep(100);
74362306a36Sopenharmony_ci	} else if (is_mt798x(&dev->mt76)) {
74462306a36Sopenharmony_ci		mt7986_wmac_disable(dev);
74562306a36Sopenharmony_ci		msleep(20);
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_ci		mt7986_wmac_enable(dev);
74862306a36Sopenharmony_ci		msleep(20);
74962306a36Sopenharmony_ci	} else {
75062306a36Sopenharmony_ci		mt76_set(dev, MT_WF_SUBSYS_RST, 0x1);
75162306a36Sopenharmony_ci		msleep(20);
75262306a36Sopenharmony_ci
75362306a36Sopenharmony_ci		mt76_clear(dev, MT_WF_SUBSYS_RST, 0x1);
75462306a36Sopenharmony_ci		msleep(20);
75562306a36Sopenharmony_ci	}
75662306a36Sopenharmony_ci}
75762306a36Sopenharmony_ci
75862306a36Sopenharmony_cistatic bool mt7915_band_config(struct mt7915_dev *dev)
75962306a36Sopenharmony_ci{
76062306a36Sopenharmony_ci	bool ret = true;
76162306a36Sopenharmony_ci
76262306a36Sopenharmony_ci	dev->phy.mt76->band_idx = 0;
76362306a36Sopenharmony_ci
76462306a36Sopenharmony_ci	if (is_mt798x(&dev->mt76)) {
76562306a36Sopenharmony_ci		u32 sku = mt7915_check_adie(dev, true);
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_ci		/*
76862306a36Sopenharmony_ci		 * for mt7986, dbdc support is determined by the number
76962306a36Sopenharmony_ci		 * of adie chips and the main phy is bound to band1 when
77062306a36Sopenharmony_ci		 * dbdc is disabled.
77162306a36Sopenharmony_ci		 */
77262306a36Sopenharmony_ci		if (sku == MT7975_ONE_ADIE || sku == MT7976_ONE_ADIE) {
77362306a36Sopenharmony_ci			dev->phy.mt76->band_idx = 1;
77462306a36Sopenharmony_ci			ret = false;
77562306a36Sopenharmony_ci		}
77662306a36Sopenharmony_ci	} else {
77762306a36Sopenharmony_ci		ret = is_mt7915(&dev->mt76) ?
77862306a36Sopenharmony_ci		      !!(mt76_rr(dev, MT_HW_BOUND) & BIT(5)) : true;
77962306a36Sopenharmony_ci	}
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_ci	return ret;
78262306a36Sopenharmony_ci}
78362306a36Sopenharmony_ci
78462306a36Sopenharmony_cistatic int
78562306a36Sopenharmony_cimt7915_init_hardware(struct mt7915_dev *dev, struct mt7915_phy *phy2)
78662306a36Sopenharmony_ci{
78762306a36Sopenharmony_ci	int ret, idx;
78862306a36Sopenharmony_ci
78962306a36Sopenharmony_ci	mt76_wr(dev, MT_INT_MASK_CSR, 0);
79062306a36Sopenharmony_ci	mt76_wr(dev, MT_INT_SOURCE_CSR, ~0);
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_ci	INIT_WORK(&dev->init_work, mt7915_init_work);
79362306a36Sopenharmony_ci
79462306a36Sopenharmony_ci	ret = mt7915_dma_init(dev, phy2);
79562306a36Sopenharmony_ci	if (ret)
79662306a36Sopenharmony_ci		return ret;
79762306a36Sopenharmony_ci
79862306a36Sopenharmony_ci	set_bit(MT76_STATE_INITIALIZED, &dev->mphy.state);
79962306a36Sopenharmony_ci
80062306a36Sopenharmony_ci	ret = mt7915_mcu_init(dev);
80162306a36Sopenharmony_ci	if (ret)
80262306a36Sopenharmony_ci		return ret;
80362306a36Sopenharmony_ci
80462306a36Sopenharmony_ci	ret = mt7915_eeprom_init(dev);
80562306a36Sopenharmony_ci	if (ret < 0)
80662306a36Sopenharmony_ci		return ret;
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_ci	if (dev->flash_mode) {
80962306a36Sopenharmony_ci		ret = mt7915_mcu_apply_group_cal(dev);
81062306a36Sopenharmony_ci		if (ret)
81162306a36Sopenharmony_ci			return ret;
81262306a36Sopenharmony_ci	}
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_ci	/* Beacon and mgmt frames should occupy wcid 0 */
81562306a36Sopenharmony_ci	idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7915_WTBL_STA);
81662306a36Sopenharmony_ci	if (idx)
81762306a36Sopenharmony_ci		return -ENOSPC;
81862306a36Sopenharmony_ci
81962306a36Sopenharmony_ci	dev->mt76.global_wcid.idx = idx;
82062306a36Sopenharmony_ci	dev->mt76.global_wcid.hw_key_idx = -1;
82162306a36Sopenharmony_ci	dev->mt76.global_wcid.tx_info |= MT_WCID_TX_INFO_SET;
82262306a36Sopenharmony_ci	rcu_assign_pointer(dev->mt76.wcid[idx], &dev->mt76.global_wcid);
82362306a36Sopenharmony_ci
82462306a36Sopenharmony_ci	return 0;
82562306a36Sopenharmony_ci}
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_civoid mt7915_set_stream_vht_txbf_caps(struct mt7915_phy *phy)
82862306a36Sopenharmony_ci{
82962306a36Sopenharmony_ci	int sts;
83062306a36Sopenharmony_ci	u32 *cap;
83162306a36Sopenharmony_ci
83262306a36Sopenharmony_ci	if (!phy->mt76->cap.has_5ghz)
83362306a36Sopenharmony_ci		return;
83462306a36Sopenharmony_ci
83562306a36Sopenharmony_ci	sts = hweight8(phy->mt76->chainmask);
83662306a36Sopenharmony_ci	cap = &phy->mt76->sband_5g.sband.vht_cap.cap;
83762306a36Sopenharmony_ci
83862306a36Sopenharmony_ci	*cap |= IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE |
83962306a36Sopenharmony_ci		IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE |
84062306a36Sopenharmony_ci		FIELD_PREP(IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK,
84162306a36Sopenharmony_ci			   sts - 1);
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_ci	*cap &= ~(IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK |
84462306a36Sopenharmony_ci		  IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE |
84562306a36Sopenharmony_ci		  IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE);
84662306a36Sopenharmony_ci
84762306a36Sopenharmony_ci	if (sts < 2)
84862306a36Sopenharmony_ci		return;
84962306a36Sopenharmony_ci
85062306a36Sopenharmony_ci	*cap |= IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE |
85162306a36Sopenharmony_ci		IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE |
85262306a36Sopenharmony_ci		FIELD_PREP(IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK,
85362306a36Sopenharmony_ci			   sts - 1);
85462306a36Sopenharmony_ci}
85562306a36Sopenharmony_ci
85662306a36Sopenharmony_cistatic void
85762306a36Sopenharmony_cimt7915_set_stream_he_txbf_caps(struct mt7915_phy *phy,
85862306a36Sopenharmony_ci			       struct ieee80211_sta_he_cap *he_cap, int vif)
85962306a36Sopenharmony_ci{
86062306a36Sopenharmony_ci	struct mt7915_dev *dev = phy->dev;
86162306a36Sopenharmony_ci	struct ieee80211_he_cap_elem *elem = &he_cap->he_cap_elem;
86262306a36Sopenharmony_ci	int sts = hweight8(phy->mt76->chainmask);
86362306a36Sopenharmony_ci	u8 c, sts_160 = sts;
86462306a36Sopenharmony_ci
86562306a36Sopenharmony_ci	/* Can do 1/2 of STS in 160Mhz mode for mt7915 */
86662306a36Sopenharmony_ci	if (is_mt7915(&dev->mt76)) {
86762306a36Sopenharmony_ci		if (!dev->dbdc_support)
86862306a36Sopenharmony_ci			sts_160 /= 2;
86962306a36Sopenharmony_ci		else
87062306a36Sopenharmony_ci			sts_160 = 0;
87162306a36Sopenharmony_ci	}
87262306a36Sopenharmony_ci
87362306a36Sopenharmony_ci#ifdef CONFIG_MAC80211_MESH
87462306a36Sopenharmony_ci	if (vif == NL80211_IFTYPE_MESH_POINT)
87562306a36Sopenharmony_ci		return;
87662306a36Sopenharmony_ci#endif
87762306a36Sopenharmony_ci
87862306a36Sopenharmony_ci	elem->phy_cap_info[3] &= ~IEEE80211_HE_PHY_CAP3_SU_BEAMFORMER;
87962306a36Sopenharmony_ci	elem->phy_cap_info[4] &= ~IEEE80211_HE_PHY_CAP4_MU_BEAMFORMER;
88062306a36Sopenharmony_ci
88162306a36Sopenharmony_ci	c = IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_MASK;
88262306a36Sopenharmony_ci	if (sts_160)
88362306a36Sopenharmony_ci		c |= IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_MASK;
88462306a36Sopenharmony_ci	elem->phy_cap_info[5] &= ~c;
88562306a36Sopenharmony_ci
88662306a36Sopenharmony_ci	c = IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMING_FB |
88762306a36Sopenharmony_ci	    IEEE80211_HE_PHY_CAP6_TRIG_MU_BEAMFORMING_PARTIAL_BW_FB;
88862306a36Sopenharmony_ci	elem->phy_cap_info[6] &= ~c;
88962306a36Sopenharmony_ci
89062306a36Sopenharmony_ci	elem->phy_cap_info[7] &= ~IEEE80211_HE_PHY_CAP7_MAX_NC_MASK;
89162306a36Sopenharmony_ci
89262306a36Sopenharmony_ci	c = IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US;
89362306a36Sopenharmony_ci	if (!is_mt7915(&dev->mt76))
89462306a36Sopenharmony_ci		c |= IEEE80211_HE_PHY_CAP2_UL_MU_FULL_MU_MIMO |
89562306a36Sopenharmony_ci		     IEEE80211_HE_PHY_CAP2_UL_MU_PARTIAL_MU_MIMO;
89662306a36Sopenharmony_ci	elem->phy_cap_info[2] |= c;
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_ci	c = IEEE80211_HE_PHY_CAP4_SU_BEAMFORMEE |
89962306a36Sopenharmony_ci	    IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_4;
90062306a36Sopenharmony_ci	if (sts_160)
90162306a36Sopenharmony_ci		c |= IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_4;
90262306a36Sopenharmony_ci	elem->phy_cap_info[4] |= c;
90362306a36Sopenharmony_ci
90462306a36Sopenharmony_ci	/* do not support NG16 due to spec D4.0 changes subcarrier idx */
90562306a36Sopenharmony_ci	c = IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_42_SU |
90662306a36Sopenharmony_ci	    IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_75_MU;
90762306a36Sopenharmony_ci
90862306a36Sopenharmony_ci	if (vif == NL80211_IFTYPE_STATION)
90962306a36Sopenharmony_ci		c |= IEEE80211_HE_PHY_CAP6_PARTIAL_BANDWIDTH_DL_MUMIMO;
91062306a36Sopenharmony_ci
91162306a36Sopenharmony_ci	elem->phy_cap_info[6] |= c;
91262306a36Sopenharmony_ci
91362306a36Sopenharmony_ci	if (sts < 2)
91462306a36Sopenharmony_ci		return;
91562306a36Sopenharmony_ci
91662306a36Sopenharmony_ci	/* the maximum cap is 4 x 3, (Nr, Nc) = (3, 2) */
91762306a36Sopenharmony_ci	elem->phy_cap_info[7] |= min_t(int, sts - 1, 2) << 3;
91862306a36Sopenharmony_ci
91962306a36Sopenharmony_ci	if (vif != NL80211_IFTYPE_AP)
92062306a36Sopenharmony_ci		return;
92162306a36Sopenharmony_ci
92262306a36Sopenharmony_ci	elem->phy_cap_info[3] |= IEEE80211_HE_PHY_CAP3_SU_BEAMFORMER;
92362306a36Sopenharmony_ci	elem->phy_cap_info[4] |= IEEE80211_HE_PHY_CAP4_MU_BEAMFORMER;
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_ci	c = FIELD_PREP(IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_MASK,
92662306a36Sopenharmony_ci		       sts - 1);
92762306a36Sopenharmony_ci	if (sts_160)
92862306a36Sopenharmony_ci		c |= FIELD_PREP(IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_MASK,
92962306a36Sopenharmony_ci				sts_160 - 1);
93062306a36Sopenharmony_ci	elem->phy_cap_info[5] |= c;
93162306a36Sopenharmony_ci
93262306a36Sopenharmony_ci	c = IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMING_FB |
93362306a36Sopenharmony_ci	    IEEE80211_HE_PHY_CAP6_TRIG_MU_BEAMFORMING_PARTIAL_BW_FB;
93462306a36Sopenharmony_ci	elem->phy_cap_info[6] |= c;
93562306a36Sopenharmony_ci
93662306a36Sopenharmony_ci	if (!is_mt7915(&dev->mt76)) {
93762306a36Sopenharmony_ci		c = IEEE80211_HE_PHY_CAP7_STBC_TX_ABOVE_80MHZ |
93862306a36Sopenharmony_ci		    IEEE80211_HE_PHY_CAP7_STBC_RX_ABOVE_80MHZ;
93962306a36Sopenharmony_ci		elem->phy_cap_info[7] |= c;
94062306a36Sopenharmony_ci	}
94162306a36Sopenharmony_ci}
94262306a36Sopenharmony_ci
94362306a36Sopenharmony_cistatic int
94462306a36Sopenharmony_cimt7915_init_he_caps(struct mt7915_phy *phy, enum nl80211_band band,
94562306a36Sopenharmony_ci		    struct ieee80211_sband_iftype_data *data)
94662306a36Sopenharmony_ci{
94762306a36Sopenharmony_ci	struct mt7915_dev *dev = phy->dev;
94862306a36Sopenharmony_ci	int i, idx = 0, nss = hweight8(phy->mt76->antenna_mask);
94962306a36Sopenharmony_ci	u16 mcs_map = 0;
95062306a36Sopenharmony_ci	u16 mcs_map_160 = 0;
95162306a36Sopenharmony_ci	u8 nss_160;
95262306a36Sopenharmony_ci
95362306a36Sopenharmony_ci	if (!is_mt7915(&dev->mt76))
95462306a36Sopenharmony_ci		nss_160 = nss;
95562306a36Sopenharmony_ci	else if (!dev->dbdc_support)
95662306a36Sopenharmony_ci		/* Can do 1/2 of NSS streams in 160Mhz mode for mt7915 */
95762306a36Sopenharmony_ci		nss_160 = nss / 2;
95862306a36Sopenharmony_ci	else
95962306a36Sopenharmony_ci		/* Can't do 160MHz with mt7915 dbdc */
96062306a36Sopenharmony_ci		nss_160 = 0;
96162306a36Sopenharmony_ci
96262306a36Sopenharmony_ci	for (i = 0; i < 8; i++) {
96362306a36Sopenharmony_ci		if (i < nss)
96462306a36Sopenharmony_ci			mcs_map |= (IEEE80211_HE_MCS_SUPPORT_0_11 << (i * 2));
96562306a36Sopenharmony_ci		else
96662306a36Sopenharmony_ci			mcs_map |= (IEEE80211_HE_MCS_NOT_SUPPORTED << (i * 2));
96762306a36Sopenharmony_ci
96862306a36Sopenharmony_ci		if (i < nss_160)
96962306a36Sopenharmony_ci			mcs_map_160 |= (IEEE80211_HE_MCS_SUPPORT_0_11 << (i * 2));
97062306a36Sopenharmony_ci		else
97162306a36Sopenharmony_ci			mcs_map_160 |= (IEEE80211_HE_MCS_NOT_SUPPORTED << (i * 2));
97262306a36Sopenharmony_ci	}
97362306a36Sopenharmony_ci
97462306a36Sopenharmony_ci	for (i = 0; i < NUM_NL80211_IFTYPES; i++) {
97562306a36Sopenharmony_ci		struct ieee80211_sta_he_cap *he_cap = &data[idx].he_cap;
97662306a36Sopenharmony_ci		struct ieee80211_he_cap_elem *he_cap_elem =
97762306a36Sopenharmony_ci				&he_cap->he_cap_elem;
97862306a36Sopenharmony_ci		struct ieee80211_he_mcs_nss_supp *he_mcs =
97962306a36Sopenharmony_ci				&he_cap->he_mcs_nss_supp;
98062306a36Sopenharmony_ci
98162306a36Sopenharmony_ci		switch (i) {
98262306a36Sopenharmony_ci		case NL80211_IFTYPE_STATION:
98362306a36Sopenharmony_ci		case NL80211_IFTYPE_AP:
98462306a36Sopenharmony_ci#ifdef CONFIG_MAC80211_MESH
98562306a36Sopenharmony_ci		case NL80211_IFTYPE_MESH_POINT:
98662306a36Sopenharmony_ci#endif
98762306a36Sopenharmony_ci			break;
98862306a36Sopenharmony_ci		default:
98962306a36Sopenharmony_ci			continue;
99062306a36Sopenharmony_ci		}
99162306a36Sopenharmony_ci
99262306a36Sopenharmony_ci		data[idx].types_mask = BIT(i);
99362306a36Sopenharmony_ci		he_cap->has_he = true;
99462306a36Sopenharmony_ci
99562306a36Sopenharmony_ci		he_cap_elem->mac_cap_info[0] =
99662306a36Sopenharmony_ci			IEEE80211_HE_MAC_CAP0_HTC_HE;
99762306a36Sopenharmony_ci		he_cap_elem->mac_cap_info[3] =
99862306a36Sopenharmony_ci			IEEE80211_HE_MAC_CAP3_OMI_CONTROL |
99962306a36Sopenharmony_ci			IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_3;
100062306a36Sopenharmony_ci		he_cap_elem->mac_cap_info[4] =
100162306a36Sopenharmony_ci			IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU;
100262306a36Sopenharmony_ci
100362306a36Sopenharmony_ci		if (band == NL80211_BAND_2GHZ)
100462306a36Sopenharmony_ci			he_cap_elem->phy_cap_info[0] =
100562306a36Sopenharmony_ci				IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G;
100662306a36Sopenharmony_ci		else if (nss_160)
100762306a36Sopenharmony_ci			he_cap_elem->phy_cap_info[0] =
100862306a36Sopenharmony_ci				IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G |
100962306a36Sopenharmony_ci				IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G;
101062306a36Sopenharmony_ci		else
101162306a36Sopenharmony_ci			he_cap_elem->phy_cap_info[0] =
101262306a36Sopenharmony_ci				IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G;
101362306a36Sopenharmony_ci
101462306a36Sopenharmony_ci		he_cap_elem->phy_cap_info[1] =
101562306a36Sopenharmony_ci			IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD;
101662306a36Sopenharmony_ci		he_cap_elem->phy_cap_info[2] =
101762306a36Sopenharmony_ci			IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ |
101862306a36Sopenharmony_ci			IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ;
101962306a36Sopenharmony_ci
102062306a36Sopenharmony_ci		switch (i) {
102162306a36Sopenharmony_ci		case NL80211_IFTYPE_AP:
102262306a36Sopenharmony_ci			he_cap_elem->mac_cap_info[0] |=
102362306a36Sopenharmony_ci				IEEE80211_HE_MAC_CAP0_TWT_RES;
102462306a36Sopenharmony_ci			he_cap_elem->mac_cap_info[2] |=
102562306a36Sopenharmony_ci				IEEE80211_HE_MAC_CAP2_BSR;
102662306a36Sopenharmony_ci			he_cap_elem->mac_cap_info[4] |=
102762306a36Sopenharmony_ci				IEEE80211_HE_MAC_CAP4_BQR;
102862306a36Sopenharmony_ci			he_cap_elem->mac_cap_info[5] |=
102962306a36Sopenharmony_ci				IEEE80211_HE_MAC_CAP5_OM_CTRL_UL_MU_DATA_DIS_RX;
103062306a36Sopenharmony_ci			he_cap_elem->phy_cap_info[3] |=
103162306a36Sopenharmony_ci				IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_QPSK |
103262306a36Sopenharmony_ci				IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_QPSK;
103362306a36Sopenharmony_ci			he_cap_elem->phy_cap_info[6] |=
103462306a36Sopenharmony_ci				IEEE80211_HE_PHY_CAP6_PARTIAL_BW_EXT_RANGE |
103562306a36Sopenharmony_ci				IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT;
103662306a36Sopenharmony_ci			he_cap_elem->phy_cap_info[9] |=
103762306a36Sopenharmony_ci				IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU |
103862306a36Sopenharmony_ci				IEEE80211_HE_PHY_CAP9_RX_1024_QAM_LESS_THAN_242_TONE_RU;
103962306a36Sopenharmony_ci			break;
104062306a36Sopenharmony_ci		case NL80211_IFTYPE_STATION:
104162306a36Sopenharmony_ci			he_cap_elem->mac_cap_info[1] |=
104262306a36Sopenharmony_ci				IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US;
104362306a36Sopenharmony_ci
104462306a36Sopenharmony_ci			if (band == NL80211_BAND_2GHZ)
104562306a36Sopenharmony_ci				he_cap_elem->phy_cap_info[0] |=
104662306a36Sopenharmony_ci					IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_2G;
104762306a36Sopenharmony_ci			else
104862306a36Sopenharmony_ci				he_cap_elem->phy_cap_info[0] |=
104962306a36Sopenharmony_ci					IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_5G;
105062306a36Sopenharmony_ci
105162306a36Sopenharmony_ci			he_cap_elem->phy_cap_info[1] |=
105262306a36Sopenharmony_ci				IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A |
105362306a36Sopenharmony_ci				IEEE80211_HE_PHY_CAP1_HE_LTF_AND_GI_FOR_HE_PPDUS_0_8US;
105462306a36Sopenharmony_ci			he_cap_elem->phy_cap_info[3] |=
105562306a36Sopenharmony_ci				IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_QPSK |
105662306a36Sopenharmony_ci				IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_QPSK;
105762306a36Sopenharmony_ci			he_cap_elem->phy_cap_info[6] |=
105862306a36Sopenharmony_ci				IEEE80211_HE_PHY_CAP6_TRIG_CQI_FB |
105962306a36Sopenharmony_ci				IEEE80211_HE_PHY_CAP6_PARTIAL_BW_EXT_RANGE |
106062306a36Sopenharmony_ci				IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT;
106162306a36Sopenharmony_ci			he_cap_elem->phy_cap_info[7] |=
106262306a36Sopenharmony_ci				IEEE80211_HE_PHY_CAP7_POWER_BOOST_FACTOR_SUPP |
106362306a36Sopenharmony_ci				IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI;
106462306a36Sopenharmony_ci			he_cap_elem->phy_cap_info[8] |=
106562306a36Sopenharmony_ci				IEEE80211_HE_PHY_CAP8_20MHZ_IN_40MHZ_HE_PPDU_IN_2G |
106662306a36Sopenharmony_ci				IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_484;
106762306a36Sopenharmony_ci			if (nss_160)
106862306a36Sopenharmony_ci				he_cap_elem->phy_cap_info[8] |=
106962306a36Sopenharmony_ci					IEEE80211_HE_PHY_CAP8_20MHZ_IN_160MHZ_HE_PPDU |
107062306a36Sopenharmony_ci					IEEE80211_HE_PHY_CAP8_80MHZ_IN_160MHZ_HE_PPDU;
107162306a36Sopenharmony_ci			he_cap_elem->phy_cap_info[9] |=
107262306a36Sopenharmony_ci				IEEE80211_HE_PHY_CAP9_LONGER_THAN_16_SIGB_OFDM_SYM |
107362306a36Sopenharmony_ci				IEEE80211_HE_PHY_CAP9_NON_TRIGGERED_CQI_FEEDBACK |
107462306a36Sopenharmony_ci				IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU |
107562306a36Sopenharmony_ci				IEEE80211_HE_PHY_CAP9_RX_1024_QAM_LESS_THAN_242_TONE_RU |
107662306a36Sopenharmony_ci				IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_COMP_SIGB |
107762306a36Sopenharmony_ci				IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_NON_COMP_SIGB;
107862306a36Sopenharmony_ci			break;
107962306a36Sopenharmony_ci		}
108062306a36Sopenharmony_ci
108162306a36Sopenharmony_ci		memset(he_mcs, 0, sizeof(*he_mcs));
108262306a36Sopenharmony_ci		he_mcs->rx_mcs_80 = cpu_to_le16(mcs_map);
108362306a36Sopenharmony_ci		he_mcs->tx_mcs_80 = cpu_to_le16(mcs_map);
108462306a36Sopenharmony_ci		he_mcs->rx_mcs_160 = cpu_to_le16(mcs_map_160);
108562306a36Sopenharmony_ci		he_mcs->tx_mcs_160 = cpu_to_le16(mcs_map_160);
108662306a36Sopenharmony_ci
108762306a36Sopenharmony_ci		mt7915_set_stream_he_txbf_caps(phy, he_cap, i);
108862306a36Sopenharmony_ci
108962306a36Sopenharmony_ci		memset(he_cap->ppe_thres, 0, sizeof(he_cap->ppe_thres));
109062306a36Sopenharmony_ci		if (he_cap_elem->phy_cap_info[6] &
109162306a36Sopenharmony_ci		    IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT) {
109262306a36Sopenharmony_ci			mt76_connac_gen_ppe_thresh(he_cap->ppe_thres, nss);
109362306a36Sopenharmony_ci		} else {
109462306a36Sopenharmony_ci			he_cap_elem->phy_cap_info[9] |=
109562306a36Sopenharmony_ci				u8_encode_bits(IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_16US,
109662306a36Sopenharmony_ci					       IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_MASK);
109762306a36Sopenharmony_ci		}
109862306a36Sopenharmony_ci
109962306a36Sopenharmony_ci		if (band == NL80211_BAND_6GHZ) {
110062306a36Sopenharmony_ci			u16 cap = IEEE80211_HE_6GHZ_CAP_TX_ANTPAT_CONS |
110162306a36Sopenharmony_ci				  IEEE80211_HE_6GHZ_CAP_RX_ANTPAT_CONS;
110262306a36Sopenharmony_ci
110362306a36Sopenharmony_ci			cap |= u16_encode_bits(IEEE80211_HT_MPDU_DENSITY_2,
110462306a36Sopenharmony_ci					       IEEE80211_HE_6GHZ_CAP_MIN_MPDU_START) |
110562306a36Sopenharmony_ci			       u16_encode_bits(IEEE80211_VHT_MAX_AMPDU_1024K,
110662306a36Sopenharmony_ci					       IEEE80211_HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP) |
110762306a36Sopenharmony_ci			       u16_encode_bits(IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454,
110862306a36Sopenharmony_ci					       IEEE80211_HE_6GHZ_CAP_MAX_MPDU_LEN);
110962306a36Sopenharmony_ci
111062306a36Sopenharmony_ci			data[idx].he_6ghz_capa.capa = cpu_to_le16(cap);
111162306a36Sopenharmony_ci		}
111262306a36Sopenharmony_ci
111362306a36Sopenharmony_ci		idx++;
111462306a36Sopenharmony_ci	}
111562306a36Sopenharmony_ci
111662306a36Sopenharmony_ci	return idx;
111762306a36Sopenharmony_ci}
111862306a36Sopenharmony_ci
111962306a36Sopenharmony_civoid mt7915_set_stream_he_caps(struct mt7915_phy *phy)
112062306a36Sopenharmony_ci{
112162306a36Sopenharmony_ci	struct ieee80211_sband_iftype_data *data;
112262306a36Sopenharmony_ci	struct ieee80211_supported_band *band;
112362306a36Sopenharmony_ci	int n;
112462306a36Sopenharmony_ci
112562306a36Sopenharmony_ci	if (phy->mt76->cap.has_2ghz) {
112662306a36Sopenharmony_ci		data = phy->iftype[NL80211_BAND_2GHZ];
112762306a36Sopenharmony_ci		n = mt7915_init_he_caps(phy, NL80211_BAND_2GHZ, data);
112862306a36Sopenharmony_ci
112962306a36Sopenharmony_ci		band = &phy->mt76->sband_2g.sband;
113062306a36Sopenharmony_ci		band->iftype_data = data;
113162306a36Sopenharmony_ci		band->n_iftype_data = n;
113262306a36Sopenharmony_ci	}
113362306a36Sopenharmony_ci
113462306a36Sopenharmony_ci	if (phy->mt76->cap.has_5ghz) {
113562306a36Sopenharmony_ci		data = phy->iftype[NL80211_BAND_5GHZ];
113662306a36Sopenharmony_ci		n = mt7915_init_he_caps(phy, NL80211_BAND_5GHZ, data);
113762306a36Sopenharmony_ci
113862306a36Sopenharmony_ci		band = &phy->mt76->sband_5g.sband;
113962306a36Sopenharmony_ci		band->iftype_data = data;
114062306a36Sopenharmony_ci		band->n_iftype_data = n;
114162306a36Sopenharmony_ci	}
114262306a36Sopenharmony_ci
114362306a36Sopenharmony_ci	if (phy->mt76->cap.has_6ghz) {
114462306a36Sopenharmony_ci		data = phy->iftype[NL80211_BAND_6GHZ];
114562306a36Sopenharmony_ci		n = mt7915_init_he_caps(phy, NL80211_BAND_6GHZ, data);
114662306a36Sopenharmony_ci
114762306a36Sopenharmony_ci		band = &phy->mt76->sband_6g.sband;
114862306a36Sopenharmony_ci		band->iftype_data = data;
114962306a36Sopenharmony_ci		band->n_iftype_data = n;
115062306a36Sopenharmony_ci	}
115162306a36Sopenharmony_ci}
115262306a36Sopenharmony_ci
115362306a36Sopenharmony_cistatic void mt7915_unregister_ext_phy(struct mt7915_dev *dev)
115462306a36Sopenharmony_ci{
115562306a36Sopenharmony_ci	struct mt7915_phy *phy = mt7915_ext_phy(dev);
115662306a36Sopenharmony_ci	struct mt76_phy *mphy = dev->mt76.phys[MT_BAND1];
115762306a36Sopenharmony_ci
115862306a36Sopenharmony_ci	if (!phy)
115962306a36Sopenharmony_ci		return;
116062306a36Sopenharmony_ci
116162306a36Sopenharmony_ci	mt7915_unregister_thermal(phy);
116262306a36Sopenharmony_ci	mt76_unregister_phy(mphy);
116362306a36Sopenharmony_ci	ieee80211_free_hw(mphy->hw);
116462306a36Sopenharmony_ci}
116562306a36Sopenharmony_ci
116662306a36Sopenharmony_cistatic void mt7915_stop_hardware(struct mt7915_dev *dev)
116762306a36Sopenharmony_ci{
116862306a36Sopenharmony_ci	mt7915_mcu_exit(dev);
116962306a36Sopenharmony_ci	mt76_connac2_tx_token_put(&dev->mt76);
117062306a36Sopenharmony_ci	mt7915_dma_cleanup(dev);
117162306a36Sopenharmony_ci	tasklet_disable(&dev->mt76.irq_tasklet);
117262306a36Sopenharmony_ci
117362306a36Sopenharmony_ci	if (is_mt798x(&dev->mt76))
117462306a36Sopenharmony_ci		mt7986_wmac_disable(dev);
117562306a36Sopenharmony_ci}
117662306a36Sopenharmony_ci
117762306a36Sopenharmony_ciint mt7915_register_device(struct mt7915_dev *dev)
117862306a36Sopenharmony_ci{
117962306a36Sopenharmony_ci	struct mt7915_phy *phy2;
118062306a36Sopenharmony_ci	int ret;
118162306a36Sopenharmony_ci
118262306a36Sopenharmony_ci	dev->phy.dev = dev;
118362306a36Sopenharmony_ci	dev->phy.mt76 = &dev->mt76.phy;
118462306a36Sopenharmony_ci	dev->mt76.phy.priv = &dev->phy;
118562306a36Sopenharmony_ci	INIT_WORK(&dev->rc_work, mt7915_mac_sta_rc_work);
118662306a36Sopenharmony_ci	INIT_DELAYED_WORK(&dev->mphy.mac_work, mt7915_mac_work);
118762306a36Sopenharmony_ci	INIT_LIST_HEAD(&dev->sta_rc_list);
118862306a36Sopenharmony_ci	INIT_LIST_HEAD(&dev->twt_list);
118962306a36Sopenharmony_ci
119062306a36Sopenharmony_ci	init_waitqueue_head(&dev->reset_wait);
119162306a36Sopenharmony_ci	INIT_WORK(&dev->reset_work, mt7915_mac_reset_work);
119262306a36Sopenharmony_ci	INIT_WORK(&dev->dump_work, mt7915_mac_dump_work);
119362306a36Sopenharmony_ci	mutex_init(&dev->dump_mutex);
119462306a36Sopenharmony_ci
119562306a36Sopenharmony_ci	dev->dbdc_support = mt7915_band_config(dev);
119662306a36Sopenharmony_ci
119762306a36Sopenharmony_ci	phy2 = mt7915_alloc_ext_phy(dev);
119862306a36Sopenharmony_ci	if (IS_ERR(phy2))
119962306a36Sopenharmony_ci		return PTR_ERR(phy2);
120062306a36Sopenharmony_ci
120162306a36Sopenharmony_ci	ret = mt7915_init_hardware(dev, phy2);
120262306a36Sopenharmony_ci	if (ret)
120362306a36Sopenharmony_ci		goto free_phy2;
120462306a36Sopenharmony_ci
120562306a36Sopenharmony_ci	mt7915_init_wiphy(&dev->phy);
120662306a36Sopenharmony_ci
120762306a36Sopenharmony_ci#ifdef CONFIG_NL80211_TESTMODE
120862306a36Sopenharmony_ci	dev->mt76.test_ops = &mt7915_testmode_ops;
120962306a36Sopenharmony_ci#endif
121062306a36Sopenharmony_ci
121162306a36Sopenharmony_ci	ret = mt76_register_device(&dev->mt76, true, mt76_rates,
121262306a36Sopenharmony_ci				   ARRAY_SIZE(mt76_rates));
121362306a36Sopenharmony_ci	if (ret)
121462306a36Sopenharmony_ci		goto stop_hw;
121562306a36Sopenharmony_ci
121662306a36Sopenharmony_ci	ret = mt7915_thermal_init(&dev->phy);
121762306a36Sopenharmony_ci	if (ret)
121862306a36Sopenharmony_ci		goto unreg_dev;
121962306a36Sopenharmony_ci
122062306a36Sopenharmony_ci	ieee80211_queue_work(mt76_hw(dev), &dev->init_work);
122162306a36Sopenharmony_ci
122262306a36Sopenharmony_ci	if (phy2) {
122362306a36Sopenharmony_ci		ret = mt7915_register_ext_phy(dev, phy2);
122462306a36Sopenharmony_ci		if (ret)
122562306a36Sopenharmony_ci			goto unreg_thermal;
122662306a36Sopenharmony_ci	}
122762306a36Sopenharmony_ci
122862306a36Sopenharmony_ci	dev->recovery.hw_init_done = true;
122962306a36Sopenharmony_ci
123062306a36Sopenharmony_ci	ret = mt7915_init_debugfs(&dev->phy);
123162306a36Sopenharmony_ci	if (ret)
123262306a36Sopenharmony_ci		goto unreg_thermal;
123362306a36Sopenharmony_ci
123462306a36Sopenharmony_ci	ret = mt7915_coredump_register(dev);
123562306a36Sopenharmony_ci	if (ret)
123662306a36Sopenharmony_ci		goto unreg_thermal;
123762306a36Sopenharmony_ci
123862306a36Sopenharmony_ci	return 0;
123962306a36Sopenharmony_ci
124062306a36Sopenharmony_ciunreg_thermal:
124162306a36Sopenharmony_ci	mt7915_unregister_thermal(&dev->phy);
124262306a36Sopenharmony_ciunreg_dev:
124362306a36Sopenharmony_ci	mt76_unregister_device(&dev->mt76);
124462306a36Sopenharmony_cistop_hw:
124562306a36Sopenharmony_ci	mt7915_stop_hardware(dev);
124662306a36Sopenharmony_cifree_phy2:
124762306a36Sopenharmony_ci	if (phy2)
124862306a36Sopenharmony_ci		ieee80211_free_hw(phy2->mt76->hw);
124962306a36Sopenharmony_ci	return ret;
125062306a36Sopenharmony_ci}
125162306a36Sopenharmony_ci
125262306a36Sopenharmony_civoid mt7915_unregister_device(struct mt7915_dev *dev)
125362306a36Sopenharmony_ci{
125462306a36Sopenharmony_ci	mt7915_unregister_ext_phy(dev);
125562306a36Sopenharmony_ci	mt7915_coredump_unregister(dev);
125662306a36Sopenharmony_ci	mt7915_unregister_thermal(&dev->phy);
125762306a36Sopenharmony_ci	mt76_unregister_device(&dev->mt76);
125862306a36Sopenharmony_ci	mt7915_stop_hardware(dev);
125962306a36Sopenharmony_ci
126062306a36Sopenharmony_ci	mt76_free_device(&dev->mt76);
126162306a36Sopenharmony_ci}
1262