xref: /openbmc/linux/drivers/net/wireless/mediatek/mt76/mt7996/init.c (revision 060f35a317ef09101b128f399dce7ed13d019461)
198686cd2SShayne Chen // SPDX-License-Identifier: ISC
298686cd2SShayne Chen /*
398686cd2SShayne Chen  * Copyright (C) 2022 MediaTek Inc.
498686cd2SShayne Chen  */
598686cd2SShayne Chen 
698686cd2SShayne Chen #include <linux/etherdevice.h>
7e7899a90SRob Herring #include <linux/of.h>
898686cd2SShayne Chen #include <linux/thermal.h>
998686cd2SShayne Chen #include "mt7996.h"
1098686cd2SShayne Chen #include "mac.h"
1198686cd2SShayne Chen #include "mcu.h"
12878161d5SRyder Lee #include "coredump.h"
1398686cd2SShayne Chen #include "eeprom.h"
1498686cd2SShayne Chen 
1598686cd2SShayne Chen static const struct ieee80211_iface_limit if_limits[] = {
1698686cd2SShayne Chen 	{
1798686cd2SShayne Chen 		.max = 1,
1898686cd2SShayne Chen 		.types = BIT(NL80211_IFTYPE_ADHOC)
1998686cd2SShayne Chen 	}, {
2098686cd2SShayne Chen 		.max = 16,
2198686cd2SShayne Chen 		.types = BIT(NL80211_IFTYPE_AP)
2298686cd2SShayne Chen #ifdef CONFIG_MAC80211_MESH
2398686cd2SShayne Chen 			 | BIT(NL80211_IFTYPE_MESH_POINT)
2498686cd2SShayne Chen #endif
2598686cd2SShayne Chen 	}, {
2698686cd2SShayne Chen 		.max = MT7996_MAX_INTERFACES,
2798686cd2SShayne Chen 		.types = BIT(NL80211_IFTYPE_STATION)
2898686cd2SShayne Chen 	}
2998686cd2SShayne Chen };
3098686cd2SShayne Chen 
3198686cd2SShayne Chen static const struct ieee80211_iface_combination if_comb[] = {
3298686cd2SShayne Chen 	{
3398686cd2SShayne Chen 		.limits = if_limits,
3498686cd2SShayne Chen 		.n_limits = ARRAY_SIZE(if_limits),
3598686cd2SShayne Chen 		.max_interfaces = MT7996_MAX_INTERFACES,
3698686cd2SShayne Chen 		.num_different_channels = 1,
3798686cd2SShayne Chen 		.beacon_int_infra_match = true,
3898686cd2SShayne Chen 		.radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) |
3998686cd2SShayne Chen 				       BIT(NL80211_CHAN_WIDTH_20) |
4098686cd2SShayne Chen 				       BIT(NL80211_CHAN_WIDTH_40) |
4198686cd2SShayne Chen 				       BIT(NL80211_CHAN_WIDTH_80) |
42827a6867SShayne Chen 				       BIT(NL80211_CHAN_WIDTH_160),
4398686cd2SShayne Chen 	}
4498686cd2SShayne Chen };
4598686cd2SShayne Chen 
mt7996_led_set_config(struct led_classdev * led_cdev,u8 delay_on,u8 delay_off)4698686cd2SShayne Chen static void mt7996_led_set_config(struct led_classdev *led_cdev,
4798686cd2SShayne Chen 				  u8 delay_on, u8 delay_off)
4898686cd2SShayne Chen {
4998686cd2SShayne Chen 	struct mt7996_dev *dev;
503abd46ddSLorenzo Bianconi 	struct mt76_phy *mphy;
5198686cd2SShayne Chen 	u32 val;
5298686cd2SShayne Chen 
533abd46ddSLorenzo Bianconi 	mphy = container_of(led_cdev, struct mt76_phy, leds.cdev);
543abd46ddSLorenzo Bianconi 	dev = container_of(mphy->dev, struct mt7996_dev, mt76);
5598686cd2SShayne Chen 
5698686cd2SShayne Chen 	/* select TX blink mode, 2: only data frames */
5798686cd2SShayne Chen 	mt76_rmw_field(dev, MT_TMAC_TCR0(0), MT_TMAC_TCR0_TX_BLINK, 2);
5898686cd2SShayne Chen 
5998686cd2SShayne Chen 	/* enable LED */
6098686cd2SShayne Chen 	mt76_wr(dev, MT_LED_EN(0), 1);
6198686cd2SShayne Chen 
6298686cd2SShayne Chen 	/* set LED Tx blink on/off time */
6398686cd2SShayne Chen 	val = FIELD_PREP(MT_LED_TX_BLINK_ON_MASK, delay_on) |
6498686cd2SShayne Chen 	      FIELD_PREP(MT_LED_TX_BLINK_OFF_MASK, delay_off);
6598686cd2SShayne Chen 	mt76_wr(dev, MT_LED_TX_BLINK(0), val);
6698686cd2SShayne Chen 
6798686cd2SShayne Chen 	/* control LED */
6898686cd2SShayne Chen 	val = MT_LED_CTRL_BLINK_MODE | MT_LED_CTRL_KICK;
693abd46ddSLorenzo Bianconi 	if (mphy->leds.al)
7098686cd2SShayne Chen 		val |= MT_LED_CTRL_POLARITY;
7198686cd2SShayne Chen 
7298686cd2SShayne Chen 	mt76_wr(dev, MT_LED_CTRL(0), val);
7398686cd2SShayne Chen 	mt76_clear(dev, MT_LED_CTRL(0), MT_LED_CTRL_KICK);
7498686cd2SShayne Chen }
7598686cd2SShayne Chen 
mt7996_led_set_blink(struct led_classdev * led_cdev,unsigned long * delay_on,unsigned long * delay_off)7698686cd2SShayne Chen static int mt7996_led_set_blink(struct led_classdev *led_cdev,
7798686cd2SShayne Chen 				unsigned long *delay_on,
7898686cd2SShayne Chen 				unsigned long *delay_off)
7998686cd2SShayne Chen {
8098686cd2SShayne Chen 	u16 delta_on = 0, delta_off = 0;
8198686cd2SShayne Chen 
8298686cd2SShayne Chen #define HW_TICK		10
8398686cd2SShayne Chen #define TO_HW_TICK(_t)	(((_t) > HW_TICK) ? ((_t) / HW_TICK) : HW_TICK)
8498686cd2SShayne Chen 
8598686cd2SShayne Chen 	if (*delay_on)
8698686cd2SShayne Chen 		delta_on = TO_HW_TICK(*delay_on);
8798686cd2SShayne Chen 	if (*delay_off)
8898686cd2SShayne Chen 		delta_off = TO_HW_TICK(*delay_off);
8998686cd2SShayne Chen 
9098686cd2SShayne Chen 	mt7996_led_set_config(led_cdev, delta_on, delta_off);
9198686cd2SShayne Chen 
9298686cd2SShayne Chen 	return 0;
9398686cd2SShayne Chen }
9498686cd2SShayne Chen 
mt7996_led_set_brightness(struct led_classdev * led_cdev,enum led_brightness brightness)9598686cd2SShayne Chen static void mt7996_led_set_brightness(struct led_classdev *led_cdev,
9698686cd2SShayne Chen 				      enum led_brightness brightness)
9798686cd2SShayne Chen {
9898686cd2SShayne Chen 	if (!brightness)
9998686cd2SShayne Chen 		mt7996_led_set_config(led_cdev, 0, 0xff);
10098686cd2SShayne Chen 	else
10198686cd2SShayne Chen 		mt7996_led_set_config(led_cdev, 0xff, 0);
10298686cd2SShayne Chen }
10398686cd2SShayne Chen 
mt7996_init_txpower(struct mt7996_dev * dev,struct ieee80211_supported_band * sband)10427015b6fSBo Jiao void mt7996_init_txpower(struct mt7996_dev *dev,
10598686cd2SShayne Chen 			 struct ieee80211_supported_band *sband)
10698686cd2SShayne Chen {
10798686cd2SShayne Chen 	int i, nss = hweight8(dev->mphy.antenna_mask);
10898686cd2SShayne Chen 	int nss_delta = mt76_tx_power_nss_delta(nss);
10998686cd2SShayne Chen 	int pwr_delta = mt7996_eeprom_get_power_delta(dev, sband->band);
11098686cd2SShayne Chen 	struct mt76_power_limits limits;
11198686cd2SShayne Chen 
11298686cd2SShayne Chen 	for (i = 0; i < sband->n_channels; i++) {
11398686cd2SShayne Chen 		struct ieee80211_channel *chan = &sband->channels[i];
11498686cd2SShayne Chen 		int target_power = mt7996_eeprom_get_target_power(dev, chan);
11598686cd2SShayne Chen 
11698686cd2SShayne Chen 		target_power += pwr_delta;
11798686cd2SShayne Chen 		target_power = mt76_get_rate_power_limits(&dev->mphy, chan,
11898686cd2SShayne Chen 							  &limits,
11998686cd2SShayne Chen 							  target_power);
12098686cd2SShayne Chen 		target_power += nss_delta;
12198686cd2SShayne Chen 		target_power = DIV_ROUND_UP(target_power, 2);
12298686cd2SShayne Chen 		chan->max_power = min_t(int, chan->max_reg_power,
12398686cd2SShayne Chen 					target_power);
12498686cd2SShayne Chen 		chan->orig_mpwr = target_power;
12598686cd2SShayne Chen 	}
12698686cd2SShayne Chen }
12798686cd2SShayne Chen 
12898686cd2SShayne Chen static void
mt7996_regd_notifier(struct wiphy * wiphy,struct regulatory_request * request)12998686cd2SShayne Chen mt7996_regd_notifier(struct wiphy *wiphy,
13098686cd2SShayne Chen 		     struct regulatory_request *request)
13198686cd2SShayne Chen {
13298686cd2SShayne Chen 	struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
13398686cd2SShayne Chen 	struct mt7996_dev *dev = mt7996_hw_dev(hw);
13498686cd2SShayne Chen 	struct mt7996_phy *phy = mt7996_hw_phy(hw);
13598686cd2SShayne Chen 
13698686cd2SShayne Chen 	memcpy(dev->mt76.alpha2, request->alpha2, sizeof(dev->mt76.alpha2));
13798686cd2SShayne Chen 	dev->mt76.region = request->dfs_region;
13898686cd2SShayne Chen 
13998686cd2SShayne Chen 	if (dev->mt76.region == NL80211_DFS_UNSET)
14098686cd2SShayne Chen 		mt7996_mcu_rdd_background_enable(phy, NULL);
14198686cd2SShayne Chen 
14298686cd2SShayne Chen 	mt7996_init_txpower(dev, &phy->mt76->sband_2g.sband);
14398686cd2SShayne Chen 	mt7996_init_txpower(dev, &phy->mt76->sband_5g.sband);
14498686cd2SShayne Chen 	mt7996_init_txpower(dev, &phy->mt76->sband_6g.sband);
14598686cd2SShayne Chen 
14698686cd2SShayne Chen 	phy->mt76->dfs_state = MT_DFS_STATE_UNKNOWN;
14798686cd2SShayne Chen 	mt7996_dfs_init_radar_detector(phy);
14898686cd2SShayne Chen }
14998686cd2SShayne Chen 
15098686cd2SShayne Chen static void
mt7996_init_wiphy(struct ieee80211_hw * hw)15198686cd2SShayne Chen mt7996_init_wiphy(struct ieee80211_hw *hw)
15298686cd2SShayne Chen {
15398686cd2SShayne Chen 	struct mt7996_phy *phy = mt7996_hw_phy(hw);
15498686cd2SShayne Chen 	struct mt76_dev *mdev = &phy->dev->mt76;
15598686cd2SShayne Chen 	struct wiphy *wiphy = hw->wiphy;
156348533ebSShayne Chen 	u16 max_subframes = phy->dev->has_eht ? IEEE80211_MAX_AMPDU_BUF_EHT :
157348533ebSShayne Chen 						IEEE80211_MAX_AMPDU_BUF_HE;
15898686cd2SShayne Chen 
15998686cd2SShayne Chen 	hw->queues = 4;
160348533ebSShayne Chen 	hw->max_rx_aggregation_subframes = max_subframes;
161348533ebSShayne Chen 	hw->max_tx_aggregation_subframes = max_subframes;
16298686cd2SShayne Chen 	hw->netdev_features = NETIF_F_RXCSUM;
16398686cd2SShayne Chen 
16498686cd2SShayne Chen 	hw->radiotap_timestamp.units_pos =
16598686cd2SShayne Chen 		IEEE80211_RADIOTAP_TIMESTAMP_UNIT_US;
16698686cd2SShayne Chen 
16798686cd2SShayne Chen 	phy->slottime = 9;
16898686cd2SShayne Chen 
16998686cd2SShayne Chen 	hw->sta_data_size = sizeof(struct mt7996_sta);
17098686cd2SShayne Chen 	hw->vif_data_size = sizeof(struct mt7996_vif);
17198686cd2SShayne Chen 
17298686cd2SShayne Chen 	wiphy->iface_combinations = if_comb;
17398686cd2SShayne Chen 	wiphy->n_iface_combinations = ARRAY_SIZE(if_comb);
17498686cd2SShayne Chen 	wiphy->reg_notifier = mt7996_regd_notifier;
17598686cd2SShayne Chen 	wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH;
17698686cd2SShayne Chen 
17798686cd2SShayne Chen 	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_BSS_COLOR);
17898686cd2SShayne Chen 	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_VHT_IBSS);
17998686cd2SShayne Chen 	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_BEACON_RATE_LEGACY);
18098686cd2SShayne Chen 	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_BEACON_RATE_HT);
18198686cd2SShayne Chen 	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_BEACON_RATE_VHT);
18298686cd2SShayne Chen 	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_BEACON_RATE_HE);
18398686cd2SShayne Chen 	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_UNSOL_BCAST_PROBE_RESP);
18498686cd2SShayne Chen 	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_FILS_DISCOVERY);
185ea5d99d0SRyder Lee 	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_ACK_SIGNAL_SUPPORT);
186230a167eSFelix Fietkau 	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CAN_REPLACE_PTK0);
18768f1c3eaSRyder Lee 	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_MU_MIMO_AIR_SNIFFER);
18898686cd2SShayne Chen 
18998686cd2SShayne Chen 	if (!mdev->dev->of_node ||
19098686cd2SShayne Chen 	    !of_property_read_bool(mdev->dev->of_node,
19198686cd2SShayne Chen 				   "mediatek,disable-radar-background"))
19298686cd2SShayne Chen 		wiphy_ext_feature_set(wiphy,
19398686cd2SShayne Chen 				      NL80211_EXT_FEATURE_RADAR_BACKGROUND);
19498686cd2SShayne Chen 
19598686cd2SShayne Chen 	ieee80211_hw_set(hw, HAS_RATE_CONTROL);
19698686cd2SShayne Chen 	ieee80211_hw_set(hw, SUPPORTS_TX_ENCAP_OFFLOAD);
19798686cd2SShayne Chen 	ieee80211_hw_set(hw, SUPPORTS_RX_DECAP_OFFLOAD);
19898686cd2SShayne Chen 	ieee80211_hw_set(hw, WANT_MONITOR_VIF);
19998686cd2SShayne Chen 
20098686cd2SShayne Chen 	hw->max_tx_fragments = 4;
20198686cd2SShayne Chen 
2024e029000SPeter Chiu 	if (phy->mt76->cap.has_2ghz) {
20398686cd2SShayne Chen 		phy->mt76->sband_2g.sband.ht_cap.cap |=
20498686cd2SShayne Chen 			IEEE80211_HT_CAP_LDPC_CODING |
20598686cd2SShayne Chen 			IEEE80211_HT_CAP_MAX_AMSDU;
2064e029000SPeter Chiu 		phy->mt76->sband_2g.sband.ht_cap.ampdu_density =
2074e029000SPeter Chiu 			IEEE80211_HT_MPDU_DENSITY_2;
2084e029000SPeter Chiu 	}
20998686cd2SShayne Chen 
21098686cd2SShayne Chen 	if (phy->mt76->cap.has_5ghz) {
21198686cd2SShayne Chen 		phy->mt76->sband_5g.sband.ht_cap.cap |=
21298686cd2SShayne Chen 			IEEE80211_HT_CAP_LDPC_CODING |
21398686cd2SShayne Chen 			IEEE80211_HT_CAP_MAX_AMSDU;
21498686cd2SShayne Chen 
21598686cd2SShayne Chen 		phy->mt76->sband_5g.sband.vht_cap.cap |=
21698686cd2SShayne Chen 			IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 |
21798686cd2SShayne Chen 			IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK |
21898686cd2SShayne Chen 			IEEE80211_VHT_CAP_SHORT_GI_160 |
21998686cd2SShayne Chen 			IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
2204e029000SPeter Chiu 		phy->mt76->sband_5g.sband.ht_cap.ampdu_density =
2214e029000SPeter Chiu 			IEEE80211_HT_MPDU_DENSITY_1;
2222b8ca090SPeter Chiu 
2232b8ca090SPeter Chiu 		ieee80211_hw_set(hw, SUPPORTS_VHT_EXT_NSS_BW);
22498686cd2SShayne Chen 	}
22598686cd2SShayne Chen 
22698686cd2SShayne Chen 	mt76_set_stream_caps(phy->mt76, true);
22798686cd2SShayne Chen 	mt7996_set_stream_vht_txbf_caps(phy);
228348533ebSShayne Chen 	mt7996_set_stream_he_eht_caps(phy);
22998686cd2SShayne Chen 
23098686cd2SShayne Chen 	wiphy->available_antennas_rx = phy->mt76->antenna_mask;
23198686cd2SShayne Chen 	wiphy->available_antennas_tx = phy->mt76->antenna_mask;
23298686cd2SShayne Chen }
23398686cd2SShayne Chen 
23498686cd2SShayne Chen static void
mt7996_mac_init_band(struct mt7996_dev * dev,u8 band)23598686cd2SShayne Chen mt7996_mac_init_band(struct mt7996_dev *dev, u8 band)
23698686cd2SShayne Chen {
23798686cd2SShayne Chen 	u32 mask, set;
23898686cd2SShayne Chen 
23998686cd2SShayne Chen 	/* clear estimated value of EIFS for Rx duration & OBSS time */
24098686cd2SShayne Chen 	mt76_wr(dev, MT_WF_RMAC_RSVD0(band), MT_WF_RMAC_RSVD0_EIFS_CLR);
24198686cd2SShayne Chen 
24298686cd2SShayne Chen 	/* clear backoff time for Rx duration  */
24398686cd2SShayne Chen 	mt76_clear(dev, MT_WF_RMAC_MIB_AIRTIME1(band),
24498686cd2SShayne Chen 		   MT_WF_RMAC_MIB_NONQOSD_BACKOFF);
24598686cd2SShayne Chen 	mt76_clear(dev, MT_WF_RMAC_MIB_AIRTIME3(band),
24698686cd2SShayne Chen 		   MT_WF_RMAC_MIB_QOS01_BACKOFF);
24798686cd2SShayne Chen 	mt76_clear(dev, MT_WF_RMAC_MIB_AIRTIME4(band),
24898686cd2SShayne Chen 		   MT_WF_RMAC_MIB_QOS23_BACKOFF);
24998686cd2SShayne Chen 
25098686cd2SShayne Chen 	/* clear backoff time and set software compensation for OBSS time */
25198686cd2SShayne Chen 	mask = MT_WF_RMAC_MIB_OBSS_BACKOFF | MT_WF_RMAC_MIB_ED_OFFSET;
25298686cd2SShayne Chen 	set = FIELD_PREP(MT_WF_RMAC_MIB_OBSS_BACKOFF, 0) |
25398686cd2SShayne Chen 	      FIELD_PREP(MT_WF_RMAC_MIB_ED_OFFSET, 4);
25498686cd2SShayne Chen 	mt76_rmw(dev, MT_WF_RMAC_MIB_AIRTIME0(band), mask, set);
255ea5d99d0SRyder Lee 
256ea5d99d0SRyder Lee 	/* filter out non-resp frames and get instanstaeous signal reporting */
257ea5d99d0SRyder Lee 	mask = MT_WTBLOFF_RSCR_RCPI_MODE | MT_WTBLOFF_RSCR_RCPI_PARAM;
258ea5d99d0SRyder Lee 	set = FIELD_PREP(MT_WTBLOFF_RSCR_RCPI_MODE, 0) |
259ea5d99d0SRyder Lee 	      FIELD_PREP(MT_WTBLOFF_RSCR_RCPI_PARAM, 0x3);
260ea5d99d0SRyder Lee 	mt76_rmw(dev, MT_WTBLOFF_RSCR(band), mask, set);
26198686cd2SShayne Chen }
26298686cd2SShayne Chen 
mt7996_mac_init_basic_rates(struct mt7996_dev * dev)26315ee62e7SRyder Lee static void mt7996_mac_init_basic_rates(struct mt7996_dev *dev)
26415ee62e7SRyder Lee {
26515ee62e7SRyder Lee 	int i;
26615ee62e7SRyder Lee 
26715ee62e7SRyder Lee 	for (i = 0; i < ARRAY_SIZE(mt76_rates); i++) {
26815ee62e7SRyder Lee 		u16 rate = mt76_rates[i].hw_value;
26915ee62e7SRyder Lee 		u16 idx = MT7996_BASIC_RATES_TBL + i;
27015ee62e7SRyder Lee 
27115ee62e7SRyder Lee 		rate = FIELD_PREP(MT_TX_RATE_MODE, rate >> 8) |
27215ee62e7SRyder Lee 		       FIELD_PREP(MT_TX_RATE_IDX, rate & GENMASK(7, 0));
27315ee62e7SRyder Lee 		mt7996_mac_set_fixed_rate_table(dev, idx, rate);
27415ee62e7SRyder Lee 	}
27515ee62e7SRyder Lee }
27615ee62e7SRyder Lee 
mt7996_mac_init(struct mt7996_dev * dev)27727015b6fSBo Jiao void mt7996_mac_init(struct mt7996_dev *dev)
27898686cd2SShayne Chen {
2794bb175d4SBenjamin Lin #define HIF_TXD_V2_1	0x21
28098686cd2SShayne Chen 	int i;
28198686cd2SShayne Chen 
28298686cd2SShayne Chen 	mt76_clear(dev, MT_MDP_DCR2, MT_MDP_DCR2_RX_TRANS_SHORT);
28398686cd2SShayne Chen 
28443482540SShayne Chen 	for (i = 0; i < mt7996_wtbl_size(dev); i++)
28598686cd2SShayne Chen 		mt7996_mac_wtbl_update(dev, i,
28698686cd2SShayne Chen 				       MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
28798686cd2SShayne Chen 
28898686cd2SShayne Chen 	if (IS_ENABLED(CONFIG_MT76_LEDS)) {
2893abd46ddSLorenzo Bianconi 		i = dev->mphy.leds.pin ? MT_LED_GPIO_MUX3 : MT_LED_GPIO_MUX2;
29098686cd2SShayne Chen 		mt76_rmw_field(dev, i, MT_LED_GPIO_SEL_MASK, 4);
29198686cd2SShayne Chen 	}
29298686cd2SShayne Chen 
29398686cd2SShayne Chen 	/* txs report queue */
29498686cd2SShayne Chen 	mt76_rmw_field(dev, MT_DMA_TCRF1(0), MT_DMA_TCRF1_QIDX, 0);
29598686cd2SShayne Chen 	mt76_rmw_field(dev, MT_DMA_TCRF1(1), MT_DMA_TCRF1_QIDX, 6);
29698686cd2SShayne Chen 	mt76_rmw_field(dev, MT_DMA_TCRF1(2), MT_DMA_TCRF1_QIDX, 0);
29798686cd2SShayne Chen 
29898686cd2SShayne Chen 	/* rro module init */
29998686cd2SShayne Chen 	mt7996_mcu_set_rro(dev, UNI_RRO_SET_PLATFORM_TYPE, 2);
30098686cd2SShayne Chen 	mt7996_mcu_set_rro(dev, UNI_RRO_SET_BYPASS_MODE, 3);
30198686cd2SShayne Chen 	mt7996_mcu_set_rro(dev, UNI_RRO_SET_TXFREE_PATH, 1);
30298686cd2SShayne Chen 
30398686cd2SShayne Chen 	mt7996_mcu_wa_cmd(dev, MCU_WA_PARAM_CMD(SET),
30498686cd2SShayne Chen 			  MCU_WA_PARAM_HW_PATH_HIF_VER,
30598686cd2SShayne Chen 			  HIF_TXD_V2_1, 0);
30698686cd2SShayne Chen 
30798686cd2SShayne Chen 	for (i = MT_BAND0; i <= MT_BAND2; i++)
30898686cd2SShayne Chen 		mt7996_mac_init_band(dev, i);
30915ee62e7SRyder Lee 
31015ee62e7SRyder Lee 	mt7996_mac_init_basic_rates(dev);
31198686cd2SShayne Chen }
31298686cd2SShayne Chen 
mt7996_txbf_init(struct mt7996_dev * dev)31327015b6fSBo Jiao int mt7996_txbf_init(struct mt7996_dev *dev)
31498686cd2SShayne Chen {
31598686cd2SShayne Chen 	int ret;
31698686cd2SShayne Chen 
31798686cd2SShayne Chen 	if (dev->dbdc_support) {
31898686cd2SShayne Chen 		ret = mt7996_mcu_set_txbf(dev, BF_MOD_EN_CTRL);
31998686cd2SShayne Chen 		if (ret)
32098686cd2SShayne Chen 			return ret;
32198686cd2SShayne Chen 	}
32298686cd2SShayne Chen 
32398686cd2SShayne Chen 	/* trigger sounding packets */
32498686cd2SShayne Chen 	ret = mt7996_mcu_set_txbf(dev, BF_SOUNDING_ON);
32598686cd2SShayne Chen 	if (ret)
32698686cd2SShayne Chen 		return ret;
32798686cd2SShayne Chen 
32898686cd2SShayne Chen 	/* enable eBF */
32998686cd2SShayne Chen 	return mt7996_mcu_set_txbf(dev, BF_HW_EN_UPDATE);
33098686cd2SShayne Chen }
33198686cd2SShayne Chen 
mt7996_register_phy(struct mt7996_dev * dev,struct mt7996_phy * phy,enum mt76_band_id band)33298686cd2SShayne Chen static int mt7996_register_phy(struct mt7996_dev *dev, struct mt7996_phy *phy,
33398686cd2SShayne Chen 			       enum mt76_band_id band)
33498686cd2SShayne Chen {
33598686cd2SShayne Chen 	struct mt76_phy *mphy;
33698686cd2SShayne Chen 	u32 mac_ofs, hif1_ofs = 0;
33798686cd2SShayne Chen 	int ret;
33898686cd2SShayne Chen 
33998686cd2SShayne Chen 	if (band != MT_BAND1 && band != MT_BAND2)
34098686cd2SShayne Chen 		return 0;
34198686cd2SShayne Chen 
34298686cd2SShayne Chen 	if ((band == MT_BAND1 && !dev->dbdc_support) ||
34398686cd2SShayne Chen 	    (band == MT_BAND2 && !dev->tbtc_support))
34498686cd2SShayne Chen 		return 0;
34598686cd2SShayne Chen 
34698686cd2SShayne Chen 	if (phy)
34798686cd2SShayne Chen 		return 0;
34898686cd2SShayne Chen 
34998686cd2SShayne Chen 	if (band == MT_BAND2 && dev->hif2)
35098686cd2SShayne Chen 		hif1_ofs = MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0);
35198686cd2SShayne Chen 
35298686cd2SShayne Chen 	mphy = mt76_alloc_phy(&dev->mt76, sizeof(*phy), &mt7996_ops, band);
35398686cd2SShayne Chen 	if (!mphy)
35498686cd2SShayne Chen 		return -ENOMEM;
35598686cd2SShayne Chen 
35698686cd2SShayne Chen 	phy = mphy->priv;
35798686cd2SShayne Chen 	phy->dev = dev;
35898686cd2SShayne Chen 	phy->mt76 = mphy;
35998686cd2SShayne Chen 	mphy->dev->phys[band] = mphy;
36098686cd2SShayne Chen 
36198686cd2SShayne Chen 	INIT_DELAYED_WORK(&mphy->mac_work, mt7996_mac_work);
36298686cd2SShayne Chen 
36398686cd2SShayne Chen 	ret = mt7996_eeprom_parse_hw_cap(dev, phy);
36498686cd2SShayne Chen 	if (ret)
36598686cd2SShayne Chen 		goto error;
36698686cd2SShayne Chen 
36798686cd2SShayne Chen 	mac_ofs = band == MT_BAND2 ? MT_EE_MAC_ADDR3 : MT_EE_MAC_ADDR2;
36898686cd2SShayne Chen 	memcpy(mphy->macaddr, dev->mt76.eeprom.data + mac_ofs, ETH_ALEN);
36998686cd2SShayne Chen 	/* Make the extra PHY MAC address local without overlapping with
37098686cd2SShayne Chen 	 * the usual MAC address allocation scheme on multiple virtual interfaces
37198686cd2SShayne Chen 	 */
37298686cd2SShayne Chen 	if (!is_valid_ether_addr(mphy->macaddr)) {
37398686cd2SShayne Chen 		memcpy(mphy->macaddr, dev->mt76.eeprom.data + MT_EE_MAC_ADDR,
37498686cd2SShayne Chen 		       ETH_ALEN);
37598686cd2SShayne Chen 		mphy->macaddr[0] |= 2;
37698686cd2SShayne Chen 		mphy->macaddr[0] ^= BIT(7);
37798686cd2SShayne Chen 		if (band == MT_BAND2)
37898686cd2SShayne Chen 			mphy->macaddr[0] ^= BIT(6);
37998686cd2SShayne Chen 	}
38098686cd2SShayne Chen 	mt76_eeprom_override(mphy);
38198686cd2SShayne Chen 
38298686cd2SShayne Chen 	/* init wiphy according to mphy and phy */
38398686cd2SShayne Chen 	mt7996_init_wiphy(mphy->hw);
38498686cd2SShayne Chen 	ret = mt76_connac_init_tx_queues(phy->mt76,
38598686cd2SShayne Chen 					 MT_TXQ_ID(band),
38698686cd2SShayne Chen 					 MT7996_TX_RING_SIZE,
38798686cd2SShayne Chen 					 MT_TXQ_RING_BASE(band) + hif1_ofs, 0);
38898686cd2SShayne Chen 	if (ret)
38998686cd2SShayne Chen 		goto error;
39098686cd2SShayne Chen 
39198686cd2SShayne Chen 	ret = mt76_register_phy(mphy, true, mt76_rates,
39298686cd2SShayne Chen 				ARRAY_SIZE(mt76_rates));
39398686cd2SShayne Chen 	if (ret)
39498686cd2SShayne Chen 		goto error;
39598686cd2SShayne Chen 
39698686cd2SShayne Chen 	ret = mt7996_init_debugfs(phy);
39798686cd2SShayne Chen 	if (ret)
39898686cd2SShayne Chen 		goto error;
39998686cd2SShayne Chen 
40098686cd2SShayne Chen 	return 0;
40198686cd2SShayne Chen 
40298686cd2SShayne Chen error:
40398686cd2SShayne Chen 	mphy->dev->phys[band] = NULL;
40498686cd2SShayne Chen 	ieee80211_free_hw(mphy->hw);
40598686cd2SShayne Chen 	return ret;
40698686cd2SShayne Chen }
40798686cd2SShayne Chen 
40898686cd2SShayne Chen static void
mt7996_unregister_phy(struct mt7996_phy * phy,enum mt76_band_id band)40998686cd2SShayne Chen mt7996_unregister_phy(struct mt7996_phy *phy, enum mt76_band_id band)
41098686cd2SShayne Chen {
41198686cd2SShayne Chen 	struct mt76_phy *mphy;
41298686cd2SShayne Chen 
41398686cd2SShayne Chen 	if (!phy)
41498686cd2SShayne Chen 		return;
41598686cd2SShayne Chen 
41698686cd2SShayne Chen 	mphy = phy->dev->mt76.phys[band];
41798686cd2SShayne Chen 	mt76_unregister_phy(mphy);
41898686cd2SShayne Chen 	ieee80211_free_hw(mphy->hw);
41998686cd2SShayne Chen 	phy->dev->mt76.phys[band] = NULL;
42098686cd2SShayne Chen }
42198686cd2SShayne Chen 
mt7996_init_work(struct work_struct * work)42298686cd2SShayne Chen static void mt7996_init_work(struct work_struct *work)
42398686cd2SShayne Chen {
42498686cd2SShayne Chen 	struct mt7996_dev *dev = container_of(work, struct mt7996_dev,
42598686cd2SShayne Chen 				 init_work);
42698686cd2SShayne Chen 
42798686cd2SShayne Chen 	mt7996_mcu_set_eeprom(dev);
42898686cd2SShayne Chen 	mt7996_mac_init(dev);
42998686cd2SShayne Chen 	mt7996_init_txpower(dev, &dev->mphy.sband_2g.sband);
43098686cd2SShayne Chen 	mt7996_init_txpower(dev, &dev->mphy.sband_5g.sband);
43198686cd2SShayne Chen 	mt7996_init_txpower(dev, &dev->mphy.sband_6g.sband);
43298686cd2SShayne Chen 	mt7996_txbf_init(dev);
43398686cd2SShayne Chen }
43498686cd2SShayne Chen 
mt7996_wfsys_reset(struct mt7996_dev * dev)43598686cd2SShayne Chen void mt7996_wfsys_reset(struct mt7996_dev *dev)
43698686cd2SShayne Chen {
43798686cd2SShayne Chen 	mt76_set(dev, MT_WF_SUBSYS_RST, 0x1);
43898686cd2SShayne Chen 	msleep(20);
43998686cd2SShayne Chen 
44098686cd2SShayne Chen 	mt76_clear(dev, MT_WF_SUBSYS_RST, 0x1);
44198686cd2SShayne Chen 	msleep(20);
44298686cd2SShayne Chen }
44398686cd2SShayne Chen 
mt7996_init_hardware(struct mt7996_dev * dev)44498686cd2SShayne Chen static int mt7996_init_hardware(struct mt7996_dev *dev)
44598686cd2SShayne Chen {
44698686cd2SShayne Chen 	int ret, idx;
44798686cd2SShayne Chen 
44898686cd2SShayne Chen 	mt76_wr(dev, MT_INT_SOURCE_CSR, ~0);
44998686cd2SShayne Chen 
45098686cd2SShayne Chen 	INIT_WORK(&dev->init_work, mt7996_init_work);
45198686cd2SShayne Chen 
45298686cd2SShayne Chen 	dev->dbdc_support = true;
45398686cd2SShayne Chen 	dev->tbtc_support = true;
45498686cd2SShayne Chen 
45598686cd2SShayne Chen 	ret = mt7996_dma_init(dev);
45698686cd2SShayne Chen 	if (ret)
45798686cd2SShayne Chen 		return ret;
45898686cd2SShayne Chen 
45998686cd2SShayne Chen 	set_bit(MT76_STATE_INITIALIZED, &dev->mphy.state);
46098686cd2SShayne Chen 
46198686cd2SShayne Chen 	ret = mt7996_mcu_init(dev);
46298686cd2SShayne Chen 	if (ret)
46398686cd2SShayne Chen 		return ret;
46498686cd2SShayne Chen 
46598686cd2SShayne Chen 	ret = mt7996_eeprom_init(dev);
46698686cd2SShayne Chen 	if (ret < 0)
46798686cd2SShayne Chen 		return ret;
46898686cd2SShayne Chen 
46998686cd2SShayne Chen 	/* Beacon and mgmt frames should occupy wcid 0 */
47098686cd2SShayne Chen 	idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7996_WTBL_STA);
47198686cd2SShayne Chen 	if (idx)
47298686cd2SShayne Chen 		return -ENOSPC;
47398686cd2SShayne Chen 
47498686cd2SShayne Chen 	dev->mt76.global_wcid.idx = idx;
47598686cd2SShayne Chen 	dev->mt76.global_wcid.hw_key_idx = -1;
47698686cd2SShayne Chen 	dev->mt76.global_wcid.tx_info |= MT_WCID_TX_INFO_SET;
47798686cd2SShayne Chen 	rcu_assign_pointer(dev->mt76.wcid[idx], &dev->mt76.global_wcid);
47898686cd2SShayne Chen 
47998686cd2SShayne Chen 	return 0;
48098686cd2SShayne Chen }
48198686cd2SShayne Chen 
mt7996_set_stream_vht_txbf_caps(struct mt7996_phy * phy)48298686cd2SShayne Chen void mt7996_set_stream_vht_txbf_caps(struct mt7996_phy *phy)
48398686cd2SShayne Chen {
48498686cd2SShayne Chen 	int sts;
48598686cd2SShayne Chen 	u32 *cap;
48698686cd2SShayne Chen 
48798686cd2SShayne Chen 	if (!phy->mt76->cap.has_5ghz)
48898686cd2SShayne Chen 		return;
48998686cd2SShayne Chen 
49098686cd2SShayne Chen 	sts = hweight16(phy->mt76->chainmask);
49198686cd2SShayne Chen 	cap = &phy->mt76->sband_5g.sband.vht_cap.cap;
49298686cd2SShayne Chen 
49398686cd2SShayne Chen 	*cap |= IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE |
49498686cd2SShayne Chen 		IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE |
495c5139fc4SShayne Chen 		FIELD_PREP(IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK, sts - 1);
49698686cd2SShayne Chen 
49798686cd2SShayne Chen 	*cap &= ~(IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK |
49898686cd2SShayne Chen 		  IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE |
49998686cd2SShayne Chen 		  IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE);
50098686cd2SShayne Chen 
50198686cd2SShayne Chen 	if (sts < 2)
50298686cd2SShayne Chen 		return;
50398686cd2SShayne Chen 
50498686cd2SShayne Chen 	*cap |= IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE |
50598686cd2SShayne Chen 		IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE |
50698686cd2SShayne Chen 		FIELD_PREP(IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK, sts - 1);
50798686cd2SShayne Chen }
50898686cd2SShayne Chen 
50998686cd2SShayne Chen static void
mt7996_set_stream_he_txbf_caps(struct mt7996_phy * phy,struct ieee80211_sta_he_cap * he_cap,int vif)51098686cd2SShayne Chen mt7996_set_stream_he_txbf_caps(struct mt7996_phy *phy,
51198686cd2SShayne Chen 			       struct ieee80211_sta_he_cap *he_cap, int vif)
51298686cd2SShayne Chen {
51398686cd2SShayne Chen 	struct ieee80211_he_cap_elem *elem = &he_cap->he_cap_elem;
51498686cd2SShayne Chen 	int sts = hweight16(phy->mt76->chainmask);
51598686cd2SShayne Chen 	u8 c;
51698686cd2SShayne Chen 
51798686cd2SShayne Chen #ifdef CONFIG_MAC80211_MESH
51898686cd2SShayne Chen 	if (vif == NL80211_IFTYPE_MESH_POINT)
51998686cd2SShayne Chen 		return;
52098686cd2SShayne Chen #endif
52198686cd2SShayne Chen 
52298686cd2SShayne Chen 	elem->phy_cap_info[3] &= ~IEEE80211_HE_PHY_CAP3_SU_BEAMFORMER;
52398686cd2SShayne Chen 	elem->phy_cap_info[4] &= ~IEEE80211_HE_PHY_CAP4_MU_BEAMFORMER;
52498686cd2SShayne Chen 
52598686cd2SShayne Chen 	c = IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_MASK |
52698686cd2SShayne Chen 	    IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_MASK;
52798686cd2SShayne Chen 	elem->phy_cap_info[5] &= ~c;
52898686cd2SShayne Chen 
52998686cd2SShayne Chen 	c = IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMING_FB |
53098686cd2SShayne Chen 	    IEEE80211_HE_PHY_CAP6_TRIG_MU_BEAMFORMING_PARTIAL_BW_FB;
53198686cd2SShayne Chen 	elem->phy_cap_info[6] &= ~c;
53298686cd2SShayne Chen 
53398686cd2SShayne Chen 	elem->phy_cap_info[7] &= ~IEEE80211_HE_PHY_CAP7_MAX_NC_MASK;
53498686cd2SShayne Chen 
53598686cd2SShayne Chen 	c = IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US |
53698686cd2SShayne Chen 	    IEEE80211_HE_PHY_CAP2_UL_MU_FULL_MU_MIMO |
53798686cd2SShayne Chen 	    IEEE80211_HE_PHY_CAP2_UL_MU_PARTIAL_MU_MIMO;
53898686cd2SShayne Chen 	elem->phy_cap_info[2] |= c;
53998686cd2SShayne Chen 
54098686cd2SShayne Chen 	c = IEEE80211_HE_PHY_CAP4_SU_BEAMFORMEE |
54198686cd2SShayne Chen 	    IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_4 |
54298686cd2SShayne Chen 	    IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_4;
54398686cd2SShayne Chen 	elem->phy_cap_info[4] |= c;
54498686cd2SShayne Chen 
54598686cd2SShayne Chen 	/* do not support NG16 due to spec D4.0 changes subcarrier idx */
54698686cd2SShayne Chen 	c = IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_42_SU |
54798686cd2SShayne Chen 	    IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_75_MU;
54898686cd2SShayne Chen 
54998686cd2SShayne Chen 	if (vif == NL80211_IFTYPE_STATION)
55098686cd2SShayne Chen 		c |= IEEE80211_HE_PHY_CAP6_PARTIAL_BANDWIDTH_DL_MUMIMO;
55198686cd2SShayne Chen 
55298686cd2SShayne Chen 	elem->phy_cap_info[6] |= c;
55398686cd2SShayne Chen 
55498686cd2SShayne Chen 	if (sts < 2)
55598686cd2SShayne Chen 		return;
55698686cd2SShayne Chen 
55798686cd2SShayne Chen 	/* the maximum cap is 4 x 3, (Nr, Nc) = (3, 2) */
55898686cd2SShayne Chen 	elem->phy_cap_info[7] |= min_t(int, sts - 1, 2) << 3;
55998686cd2SShayne Chen 
5609d87f925SHoward Hsu 	if (!(vif == NL80211_IFTYPE_AP || vif == NL80211_IFTYPE_STATION))
56198686cd2SShayne Chen 		return;
56298686cd2SShayne Chen 
56398686cd2SShayne Chen 	elem->phy_cap_info[3] |= IEEE80211_HE_PHY_CAP3_SU_BEAMFORMER;
56498686cd2SShayne Chen 
56598686cd2SShayne Chen 	c = FIELD_PREP(IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_MASK,
56698686cd2SShayne Chen 		       sts - 1) |
56798686cd2SShayne Chen 	    FIELD_PREP(IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_MASK,
56898686cd2SShayne Chen 		       sts - 1);
56998686cd2SShayne Chen 	elem->phy_cap_info[5] |= c;
57098686cd2SShayne Chen 
571c07082faSHoward Hsu 	if (vif != NL80211_IFTYPE_AP)
572c07082faSHoward Hsu 		return;
573c07082faSHoward Hsu 
574c07082faSHoward Hsu 	elem->phy_cap_info[4] |= IEEE80211_HE_PHY_CAP4_MU_BEAMFORMER;
575c07082faSHoward Hsu 
57698686cd2SShayne Chen 	c = IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMING_FB |
57798686cd2SShayne Chen 	    IEEE80211_HE_PHY_CAP6_TRIG_MU_BEAMFORMING_PARTIAL_BW_FB;
57898686cd2SShayne Chen 	elem->phy_cap_info[6] |= c;
57998686cd2SShayne Chen 
58098686cd2SShayne Chen 	c = IEEE80211_HE_PHY_CAP7_STBC_TX_ABOVE_80MHZ |
58198686cd2SShayne Chen 	    IEEE80211_HE_PHY_CAP7_STBC_RX_ABOVE_80MHZ;
58298686cd2SShayne Chen 	elem->phy_cap_info[7] |= c;
58398686cd2SShayne Chen }
58498686cd2SShayne Chen 
58598686cd2SShayne Chen static void
mt7996_init_he_caps(struct mt7996_phy * phy,enum nl80211_band band,struct ieee80211_sband_iftype_data * data,enum nl80211_iftype iftype)58698686cd2SShayne Chen mt7996_init_he_caps(struct mt7996_phy *phy, enum nl80211_band band,
587827a6867SShayne Chen 		    struct ieee80211_sband_iftype_data *data,
588827a6867SShayne Chen 		    enum nl80211_iftype iftype)
58998686cd2SShayne Chen {
590827a6867SShayne Chen 	struct ieee80211_sta_he_cap *he_cap = &data->he_cap;
591827a6867SShayne Chen 	struct ieee80211_he_cap_elem *he_cap_elem = &he_cap->he_cap_elem;
592827a6867SShayne Chen 	struct ieee80211_he_mcs_nss_supp *he_mcs = &he_cap->he_mcs_nss_supp;
593827a6867SShayne Chen 	int i, nss = hweight8(phy->mt76->antenna_mask);
59498686cd2SShayne Chen 	u16 mcs_map = 0;
59598686cd2SShayne Chen 
59698686cd2SShayne Chen 	for (i = 0; i < 8; i++) {
59798686cd2SShayne Chen 		if (i < nss)
59898686cd2SShayne Chen 			mcs_map |= (IEEE80211_HE_MCS_SUPPORT_0_11 << (i * 2));
59998686cd2SShayne Chen 		else
60098686cd2SShayne Chen 			mcs_map |= (IEEE80211_HE_MCS_NOT_SUPPORTED << (i * 2));
60198686cd2SShayne Chen 	}
60298686cd2SShayne Chen 
60398686cd2SShayne Chen 	he_cap->has_he = true;
60498686cd2SShayne Chen 
605827a6867SShayne Chen 	he_cap_elem->mac_cap_info[0] = IEEE80211_HE_MAC_CAP0_HTC_HE;
606827a6867SShayne Chen 	he_cap_elem->mac_cap_info[3] = IEEE80211_HE_MAC_CAP3_OMI_CONTROL |
60798686cd2SShayne Chen 				       IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_3;
608827a6867SShayne Chen 	he_cap_elem->mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU;
60998686cd2SShayne Chen 
61098686cd2SShayne Chen 	if (band == NL80211_BAND_2GHZ)
61198686cd2SShayne Chen 		he_cap_elem->phy_cap_info[0] =
61298686cd2SShayne Chen 			IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G;
61398686cd2SShayne Chen 	else
61498686cd2SShayne Chen 		he_cap_elem->phy_cap_info[0] =
61598686cd2SShayne Chen 			IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G |
616827a6867SShayne Chen 			IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G;
61798686cd2SShayne Chen 
618827a6867SShayne Chen 	he_cap_elem->phy_cap_info[1] = IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD;
619827a6867SShayne Chen 	he_cap_elem->phy_cap_info[2] = IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ |
62098686cd2SShayne Chen 				       IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ;
62198686cd2SShayne Chen 
622*b9288a13SHoward Hsu 	he_cap_elem->phy_cap_info[7] =
623*b9288a13SHoward Hsu 			IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI;
624*b9288a13SHoward Hsu 
625827a6867SShayne Chen 	switch (iftype) {
62698686cd2SShayne Chen 	case NL80211_IFTYPE_AP:
627827a6867SShayne Chen 		he_cap_elem->mac_cap_info[0] |= IEEE80211_HE_MAC_CAP0_TWT_RES;
628827a6867SShayne Chen 		he_cap_elem->mac_cap_info[2] |= IEEE80211_HE_MAC_CAP2_BSR;
629827a6867SShayne Chen 		he_cap_elem->mac_cap_info[4] |= IEEE80211_HE_MAC_CAP4_BQR;
63098686cd2SShayne Chen 		he_cap_elem->mac_cap_info[5] |=
63198686cd2SShayne Chen 			IEEE80211_HE_MAC_CAP5_OM_CTRL_UL_MU_DATA_DIS_RX;
63298686cd2SShayne Chen 		he_cap_elem->phy_cap_info[3] |=
63398686cd2SShayne Chen 			IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_QPSK |
63498686cd2SShayne Chen 			IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_QPSK;
63598686cd2SShayne Chen 		he_cap_elem->phy_cap_info[6] |=
63698686cd2SShayne Chen 			IEEE80211_HE_PHY_CAP6_PARTIAL_BW_EXT_RANGE |
63798686cd2SShayne Chen 			IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT;
63898686cd2SShayne Chen 		he_cap_elem->phy_cap_info[9] |=
63998686cd2SShayne Chen 			IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU |
64098686cd2SShayne Chen 			IEEE80211_HE_PHY_CAP9_RX_1024_QAM_LESS_THAN_242_TONE_RU;
64198686cd2SShayne Chen 		break;
64298686cd2SShayne Chen 	case NL80211_IFTYPE_STATION:
64398686cd2SShayne Chen 		he_cap_elem->mac_cap_info[1] |=
64498686cd2SShayne Chen 			IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US;
64598686cd2SShayne Chen 
64698686cd2SShayne Chen 		if (band == NL80211_BAND_2GHZ)
64798686cd2SShayne Chen 			he_cap_elem->phy_cap_info[0] |=
64898686cd2SShayne Chen 			IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_2G;
64998686cd2SShayne Chen 		else
65098686cd2SShayne Chen 			he_cap_elem->phy_cap_info[0] |=
65198686cd2SShayne Chen 			IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_5G;
65298686cd2SShayne Chen 
65398686cd2SShayne Chen 		he_cap_elem->phy_cap_info[1] |=
65498686cd2SShayne Chen 			IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A |
65598686cd2SShayne Chen 			IEEE80211_HE_PHY_CAP1_HE_LTF_AND_GI_FOR_HE_PPDUS_0_8US;
65698686cd2SShayne Chen 		he_cap_elem->phy_cap_info[3] |=
65798686cd2SShayne Chen 			IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_QPSK |
65898686cd2SShayne Chen 			IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_QPSK;
65998686cd2SShayne Chen 		he_cap_elem->phy_cap_info[6] |=
66098686cd2SShayne Chen 			IEEE80211_HE_PHY_CAP6_TRIG_CQI_FB |
66198686cd2SShayne Chen 			IEEE80211_HE_PHY_CAP6_PARTIAL_BW_EXT_RANGE |
66298686cd2SShayne Chen 			IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT;
66398686cd2SShayne Chen 		he_cap_elem->phy_cap_info[7] |=
664*b9288a13SHoward Hsu 			IEEE80211_HE_PHY_CAP7_POWER_BOOST_FACTOR_SUPP;
66598686cd2SShayne Chen 		he_cap_elem->phy_cap_info[8] |=
66698686cd2SShayne Chen 			IEEE80211_HE_PHY_CAP8_20MHZ_IN_40MHZ_HE_PPDU_IN_2G |
66798686cd2SShayne Chen 			IEEE80211_HE_PHY_CAP8_20MHZ_IN_160MHZ_HE_PPDU |
66898686cd2SShayne Chen 			IEEE80211_HE_PHY_CAP8_80MHZ_IN_160MHZ_HE_PPDU |
66998686cd2SShayne Chen 			IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_484;
67098686cd2SShayne Chen 		he_cap_elem->phy_cap_info[9] |=
67198686cd2SShayne Chen 			IEEE80211_HE_PHY_CAP9_LONGER_THAN_16_SIGB_OFDM_SYM |
67298686cd2SShayne Chen 			IEEE80211_HE_PHY_CAP9_NON_TRIGGERED_CQI_FEEDBACK |
67398686cd2SShayne Chen 			IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU |
67498686cd2SShayne Chen 			IEEE80211_HE_PHY_CAP9_RX_1024_QAM_LESS_THAN_242_TONE_RU |
67598686cd2SShayne Chen 			IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_COMP_SIGB |
67698686cd2SShayne Chen 			IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_NON_COMP_SIGB;
67798686cd2SShayne Chen 		break;
678827a6867SShayne Chen 	default:
679827a6867SShayne Chen 		break;
68098686cd2SShayne Chen 	}
68198686cd2SShayne Chen 
68298686cd2SShayne Chen 	he_mcs->rx_mcs_80 = cpu_to_le16(mcs_map);
68398686cd2SShayne Chen 	he_mcs->tx_mcs_80 = cpu_to_le16(mcs_map);
68498686cd2SShayne Chen 	he_mcs->rx_mcs_160 = cpu_to_le16(mcs_map);
68598686cd2SShayne Chen 	he_mcs->tx_mcs_160 = cpu_to_le16(mcs_map);
68698686cd2SShayne Chen 
687827a6867SShayne Chen 	mt7996_set_stream_he_txbf_caps(phy, he_cap, iftype);
68898686cd2SShayne Chen 
68998686cd2SShayne Chen 	memset(he_cap->ppe_thres, 0, sizeof(he_cap->ppe_thres));
69098686cd2SShayne Chen 	if (he_cap_elem->phy_cap_info[6] &
69198686cd2SShayne Chen 	    IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT) {
6926a8b899dSLorenzo Bianconi 		mt76_connac_gen_ppe_thresh(he_cap->ppe_thres, nss);
69398686cd2SShayne Chen 	} else {
69498686cd2SShayne Chen 		he_cap_elem->phy_cap_info[9] |=
695827a6867SShayne Chen 			u8_encode_bits(IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_16US,
696827a6867SShayne Chen 				       IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_MASK);
69798686cd2SShayne Chen 	}
69898686cd2SShayne Chen 
69998686cd2SShayne Chen 	if (band == NL80211_BAND_6GHZ) {
70098686cd2SShayne Chen 		u16 cap = IEEE80211_HE_6GHZ_CAP_TX_ANTPAT_CONS |
70198686cd2SShayne Chen 			  IEEE80211_HE_6GHZ_CAP_RX_ANTPAT_CONS;
70298686cd2SShayne Chen 
7034e029000SPeter Chiu 		cap |= u16_encode_bits(IEEE80211_HT_MPDU_DENSITY_0_5,
70498686cd2SShayne Chen 				       IEEE80211_HE_6GHZ_CAP_MIN_MPDU_START) |
70598686cd2SShayne Chen 		       u16_encode_bits(IEEE80211_VHT_MAX_AMPDU_1024K,
70698686cd2SShayne Chen 				       IEEE80211_HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP) |
70798686cd2SShayne Chen 		       u16_encode_bits(IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454,
70898686cd2SShayne Chen 				       IEEE80211_HE_6GHZ_CAP_MAX_MPDU_LEN);
70998686cd2SShayne Chen 
710827a6867SShayne Chen 		data->he_6ghz_capa.capa = cpu_to_le16(cap);
711827a6867SShayne Chen 	}
71298686cd2SShayne Chen }
71398686cd2SShayne Chen 
714827a6867SShayne Chen static void
mt7996_init_eht_caps(struct mt7996_phy * phy,enum nl80211_band band,struct ieee80211_sband_iftype_data * data,enum nl80211_iftype iftype)715348533ebSShayne Chen mt7996_init_eht_caps(struct mt7996_phy *phy, enum nl80211_band band,
716348533ebSShayne Chen 		     struct ieee80211_sband_iftype_data *data,
717348533ebSShayne Chen 		     enum nl80211_iftype iftype)
718348533ebSShayne Chen {
719348533ebSShayne Chen 	struct ieee80211_sta_eht_cap *eht_cap = &data->eht_cap;
720348533ebSShayne Chen 	struct ieee80211_eht_cap_elem_fixed *eht_cap_elem = &eht_cap->eht_cap_elem;
721348533ebSShayne Chen 	struct ieee80211_eht_mcs_nss_supp *eht_nss = &eht_cap->eht_mcs_nss_supp;
722348533ebSShayne Chen 	enum nl80211_chan_width width = phy->mt76->chandef.width;
723348533ebSShayne Chen 	int nss = hweight8(phy->mt76->antenna_mask);
724348533ebSShayne Chen 	int sts = hweight16(phy->mt76->chainmask);
725348533ebSShayne Chen 	u8 val;
726348533ebSShayne Chen 
727348533ebSShayne Chen 	if (!phy->dev->has_eht)
728348533ebSShayne Chen 		return;
729348533ebSShayne Chen 
730348533ebSShayne Chen 	eht_cap->has_eht = true;
731348533ebSShayne Chen 
732348533ebSShayne Chen 	eht_cap_elem->mac_cap_info[0] =
733348533ebSShayne Chen 		IEEE80211_EHT_MAC_CAP0_EPCS_PRIO_ACCESS |
734566b749fSPeter Chiu 		IEEE80211_EHT_MAC_CAP0_OM_CONTROL |
735566b749fSPeter Chiu 		u8_encode_bits(IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN_11454,
736566b749fSPeter Chiu 			       IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN_MASK);
737348533ebSShayne Chen 
738348533ebSShayne Chen 	eht_cap_elem->phy_cap_info[0] =
739348533ebSShayne Chen 		IEEE80211_EHT_PHY_CAP0_NDP_4_EHT_LFT_32_GI |
740348533ebSShayne Chen 		IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMER |
741348533ebSShayne Chen 		IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMEE;
742348533ebSShayne Chen 
7436f866f72SHoward Hsu 	val = max_t(u8, sts - 1, 3);
744348533ebSShayne Chen 	eht_cap_elem->phy_cap_info[0] |=
7456f866f72SHoward Hsu 		u8_encode_bits(u8_get_bits(val, BIT(0)),
746348533ebSShayne Chen 			       IEEE80211_EHT_PHY_CAP0_BEAMFORMEE_SS_80MHZ_MASK);
747348533ebSShayne Chen 
748348533ebSShayne Chen 	eht_cap_elem->phy_cap_info[1] =
7496f866f72SHoward Hsu 		u8_encode_bits(u8_get_bits(val, GENMASK(2, 1)),
750348533ebSShayne Chen 			       IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_80MHZ_MASK) |
7516f866f72SHoward Hsu 		u8_encode_bits(val,
752c07082faSHoward Hsu 			       IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_160MHZ_MASK);
753348533ebSShayne Chen 
754348533ebSShayne Chen 	eht_cap_elem->phy_cap_info[2] =
755348533ebSShayne Chen 		u8_encode_bits(sts - 1, IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_80MHZ_MASK) |
756c07082faSHoward Hsu 		u8_encode_bits(sts - 1, IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_160MHZ_MASK);
757c07082faSHoward Hsu 
758c07082faSHoward Hsu 	if (band == NL80211_BAND_6GHZ) {
759c07082faSHoward Hsu 		eht_cap_elem->phy_cap_info[0] |=
760c07082faSHoward Hsu 			IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ;
761c07082faSHoward Hsu 
762c07082faSHoward Hsu 		eht_cap_elem->phy_cap_info[1] |=
763c07082faSHoward Hsu 			u8_encode_bits(val,
764c07082faSHoward Hsu 				       IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_320MHZ_MASK);
765c07082faSHoward Hsu 
766c07082faSHoward Hsu 		eht_cap_elem->phy_cap_info[2] |=
767c07082faSHoward Hsu 			u8_encode_bits(sts - 1,
768c07082faSHoward Hsu 				       IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_320MHZ_MASK);
769c07082faSHoward Hsu 	}
770348533ebSShayne Chen 
771348533ebSShayne Chen 	eht_cap_elem->phy_cap_info[3] =
772348533ebSShayne Chen 		IEEE80211_EHT_PHY_CAP3_NG_16_SU_FEEDBACK |
773348533ebSShayne Chen 		IEEE80211_EHT_PHY_CAP3_NG_16_MU_FEEDBACK |
774348533ebSShayne Chen 		IEEE80211_EHT_PHY_CAP3_CODEBOOK_4_2_SU_FDBK |
775c07082faSHoward Hsu 		IEEE80211_EHT_PHY_CAP3_CODEBOOK_7_5_MU_FDBK;
776348533ebSShayne Chen 
777348533ebSShayne Chen 	eht_cap_elem->phy_cap_info[4] =
778b20cda1dSHoward Hsu 		IEEE80211_EHT_PHY_CAP4_EHT_MU_PPDU_4_EHT_LTF_08_GI |
779348533ebSShayne Chen 		u8_encode_bits(min_t(int, sts - 1, 2),
780348533ebSShayne Chen 			       IEEE80211_EHT_PHY_CAP4_MAX_NC_MASK);
781348533ebSShayne Chen 
782348533ebSShayne Chen 	eht_cap_elem->phy_cap_info[5] =
783348533ebSShayne Chen 		u8_encode_bits(IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_16US,
784348533ebSShayne Chen 			       IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_MASK) |
785b20cda1dSHoward Hsu 		u8_encode_bits(u8_get_bits(1, GENMASK(1, 0)),
786348533ebSShayne Chen 			       IEEE80211_EHT_PHY_CAP5_MAX_NUM_SUPP_EHT_LTF_MASK);
787348533ebSShayne Chen 
788348533ebSShayne Chen 	val = width == NL80211_CHAN_WIDTH_320 ? 0xf :
789348533ebSShayne Chen 	      width == NL80211_CHAN_WIDTH_160 ? 0x7 :
790348533ebSShayne Chen 	      width == NL80211_CHAN_WIDTH_80 ? 0x3 : 0x1;
791348533ebSShayne Chen 	eht_cap_elem->phy_cap_info[6] =
792348533ebSShayne Chen 		u8_encode_bits(val, IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_MASK);
793348533ebSShayne Chen 
794348533ebSShayne Chen 	val = u8_encode_bits(nss, IEEE80211_EHT_MCS_NSS_RX) |
795348533ebSShayne Chen 	      u8_encode_bits(nss, IEEE80211_EHT_MCS_NSS_TX);
796348533ebSShayne Chen #define SET_EHT_MAX_NSS(_bw, _val) do {				\
797348533ebSShayne Chen 		eht_nss->bw._##_bw.rx_tx_mcs9_max_nss = _val;	\
798348533ebSShayne Chen 		eht_nss->bw._##_bw.rx_tx_mcs11_max_nss = _val;	\
799348533ebSShayne Chen 		eht_nss->bw._##_bw.rx_tx_mcs13_max_nss = _val;	\
800348533ebSShayne Chen 	} while (0)
801348533ebSShayne Chen 
802348533ebSShayne Chen 	SET_EHT_MAX_NSS(80, val);
803348533ebSShayne Chen 	SET_EHT_MAX_NSS(160, val);
804c07082faSHoward Hsu 	if (band == NL80211_BAND_6GHZ)
805348533ebSShayne Chen 		SET_EHT_MAX_NSS(320, val);
806348533ebSShayne Chen #undef SET_EHT_MAX_NSS
807c07082faSHoward Hsu 
808c07082faSHoward Hsu 	if (iftype != NL80211_IFTYPE_AP)
809c07082faSHoward Hsu 		return;
810c07082faSHoward Hsu 
811c07082faSHoward Hsu 	eht_cap_elem->phy_cap_info[3] |=
812c07082faSHoward Hsu 		IEEE80211_EHT_PHY_CAP3_TRIG_SU_BF_FDBK |
813c07082faSHoward Hsu 		IEEE80211_EHT_PHY_CAP3_TRIG_MU_BF_PART_BW_FDBK;
814c07082faSHoward Hsu 
815c07082faSHoward Hsu 	eht_cap_elem->phy_cap_info[7] =
816c07082faSHoward Hsu 		IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_80MHZ |
817c07082faSHoward Hsu 		IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_160MHZ |
818c07082faSHoward Hsu 		IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_80MHZ |
819c07082faSHoward Hsu 		IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_160MHZ;
820c07082faSHoward Hsu 
821c07082faSHoward Hsu 	if (band != NL80211_BAND_6GHZ)
822c07082faSHoward Hsu 		return;
823c07082faSHoward Hsu 
824c07082faSHoward Hsu 	eht_cap_elem->phy_cap_info[7] |=
825c07082faSHoward Hsu 		IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_320MHZ |
826c07082faSHoward Hsu 		IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_320MHZ;
827348533ebSShayne Chen }
828348533ebSShayne Chen 
829348533ebSShayne Chen static void
__mt7996_set_stream_he_eht_caps(struct mt7996_phy * phy,struct ieee80211_supported_band * sband,enum nl80211_band band)830348533ebSShayne Chen __mt7996_set_stream_he_eht_caps(struct mt7996_phy *phy,
831827a6867SShayne Chen 				struct ieee80211_supported_band *sband,
832827a6867SShayne Chen 				enum nl80211_band band)
833827a6867SShayne Chen {
834827a6867SShayne Chen 	struct ieee80211_sband_iftype_data *data = phy->iftype[band];
835827a6867SShayne Chen 	int i, n = 0;
836827a6867SShayne Chen 
837827a6867SShayne Chen 	for (i = 0; i < NUM_NL80211_IFTYPES; i++) {
838827a6867SShayne Chen 		switch (i) {
839827a6867SShayne Chen 		case NL80211_IFTYPE_STATION:
840827a6867SShayne Chen 		case NL80211_IFTYPE_AP:
841827a6867SShayne Chen #ifdef CONFIG_MAC80211_MESH
842827a6867SShayne Chen 		case NL80211_IFTYPE_MESH_POINT:
843827a6867SShayne Chen #endif
844827a6867SShayne Chen 			break;
845827a6867SShayne Chen 		default:
846827a6867SShayne Chen 			continue;
84798686cd2SShayne Chen 		}
84898686cd2SShayne Chen 
849827a6867SShayne Chen 		data[n].types_mask = BIT(i);
850827a6867SShayne Chen 		mt7996_init_he_caps(phy, band, &data[n], i);
851348533ebSShayne Chen 		mt7996_init_eht_caps(phy, band, &data[n], i);
852827a6867SShayne Chen 
853827a6867SShayne Chen 		n++;
854827a6867SShayne Chen 	}
855827a6867SShayne Chen 
856827a6867SShayne Chen 	sband->iftype_data = data;
857827a6867SShayne Chen 	sband->n_iftype_data = n;
85898686cd2SShayne Chen }
85998686cd2SShayne Chen 
mt7996_set_stream_he_eht_caps(struct mt7996_phy * phy)860348533ebSShayne Chen void mt7996_set_stream_he_eht_caps(struct mt7996_phy *phy)
86198686cd2SShayne Chen {
862827a6867SShayne Chen 	if (phy->mt76->cap.has_2ghz)
863348533ebSShayne Chen 		__mt7996_set_stream_he_eht_caps(phy, &phy->mt76->sband_2g.sband,
864827a6867SShayne Chen 						NL80211_BAND_2GHZ);
86598686cd2SShayne Chen 
866827a6867SShayne Chen 	if (phy->mt76->cap.has_5ghz)
867348533ebSShayne Chen 		__mt7996_set_stream_he_eht_caps(phy, &phy->mt76->sband_5g.sband,
868827a6867SShayne Chen 						NL80211_BAND_5GHZ);
86998686cd2SShayne Chen 
870827a6867SShayne Chen 	if (phy->mt76->cap.has_6ghz)
871348533ebSShayne Chen 		__mt7996_set_stream_he_eht_caps(phy, &phy->mt76->sband_6g.sband,
872827a6867SShayne Chen 						NL80211_BAND_6GHZ);
87398686cd2SShayne Chen }
87498686cd2SShayne Chen 
mt7996_register_device(struct mt7996_dev * dev)87598686cd2SShayne Chen int mt7996_register_device(struct mt7996_dev *dev)
87698686cd2SShayne Chen {
87798686cd2SShayne Chen 	struct ieee80211_hw *hw = mt76_hw(dev);
87898686cd2SShayne Chen 	int ret;
87998686cd2SShayne Chen 
88098686cd2SShayne Chen 	dev->phy.dev = dev;
88198686cd2SShayne Chen 	dev->phy.mt76 = &dev->mt76.phy;
88298686cd2SShayne Chen 	dev->mt76.phy.priv = &dev->phy;
88398686cd2SShayne Chen 	INIT_WORK(&dev->rc_work, mt7996_mac_sta_rc_work);
88498686cd2SShayne Chen 	INIT_DELAYED_WORK(&dev->mphy.mac_work, mt7996_mac_work);
88598686cd2SShayne Chen 	INIT_LIST_HEAD(&dev->sta_rc_list);
88698686cd2SShayne Chen 	INIT_LIST_HEAD(&dev->twt_list);
88798686cd2SShayne Chen 
88898686cd2SShayne Chen 	init_waitqueue_head(&dev->reset_wait);
88998686cd2SShayne Chen 	INIT_WORK(&dev->reset_work, mt7996_mac_reset_work);
890878161d5SRyder Lee 	INIT_WORK(&dev->dump_work, mt7996_mac_dump_work);
891878161d5SRyder Lee 	mutex_init(&dev->dump_mutex);
89298686cd2SShayne Chen 
89398686cd2SShayne Chen 	ret = mt7996_init_hardware(dev);
89498686cd2SShayne Chen 	if (ret)
89598686cd2SShayne Chen 		return ret;
89698686cd2SShayne Chen 
89798686cd2SShayne Chen 	mt7996_init_wiphy(hw);
89898686cd2SShayne Chen 
89998686cd2SShayne Chen 	/* init led callbacks */
90098686cd2SShayne Chen 	if (IS_ENABLED(CONFIG_MT76_LEDS)) {
9013abd46ddSLorenzo Bianconi 		dev->mphy.leds.cdev.brightness_set = mt7996_led_set_brightness;
9023abd46ddSLorenzo Bianconi 		dev->mphy.leds.cdev.blink_set = mt7996_led_set_blink;
90398686cd2SShayne Chen 	}
90498686cd2SShayne Chen 
90598686cd2SShayne Chen 	ret = mt76_register_device(&dev->mt76, true, mt76_rates,
90698686cd2SShayne Chen 				   ARRAY_SIZE(mt76_rates));
90798686cd2SShayne Chen 	if (ret)
90898686cd2SShayne Chen 		return ret;
90998686cd2SShayne Chen 
91098686cd2SShayne Chen 	ieee80211_queue_work(mt76_hw(dev), &dev->init_work);
91198686cd2SShayne Chen 
91298686cd2SShayne Chen 	ret = mt7996_register_phy(dev, mt7996_phy2(dev), MT_BAND1);
91398686cd2SShayne Chen 	if (ret)
91498686cd2SShayne Chen 		return ret;
91598686cd2SShayne Chen 
91698686cd2SShayne Chen 	ret = mt7996_register_phy(dev, mt7996_phy3(dev), MT_BAND2);
91798686cd2SShayne Chen 	if (ret)
91898686cd2SShayne Chen 		return ret;
91998686cd2SShayne Chen 
92027015b6fSBo Jiao 	dev->recovery.hw_init_done = true;
92127015b6fSBo Jiao 
922878161d5SRyder Lee 	ret = mt7996_init_debugfs(&dev->phy);
923878161d5SRyder Lee 	if (ret)
924878161d5SRyder Lee 		return ret;
925878161d5SRyder Lee 
926878161d5SRyder Lee 	return mt7996_coredump_register(dev);
92798686cd2SShayne Chen }
92898686cd2SShayne Chen 
mt7996_unregister_device(struct mt7996_dev * dev)92998686cd2SShayne Chen void mt7996_unregister_device(struct mt7996_dev *dev)
93098686cd2SShayne Chen {
93198686cd2SShayne Chen 	mt7996_unregister_phy(mt7996_phy3(dev), MT_BAND2);
93298686cd2SShayne Chen 	mt7996_unregister_phy(mt7996_phy2(dev), MT_BAND1);
933878161d5SRyder Lee 	mt7996_coredump_unregister(dev);
93498686cd2SShayne Chen 	mt76_unregister_device(&dev->mt76);
93598686cd2SShayne Chen 	mt7996_mcu_exit(dev);
93698686cd2SShayne Chen 	mt7996_tx_token_put(dev);
93798686cd2SShayne Chen 	mt7996_dma_cleanup(dev);
938ec193b41SLorenzo Bianconi 	tasklet_disable(&dev->mt76.irq_tasklet);
93998686cd2SShayne Chen 
94098686cd2SShayne Chen 	mt76_free_device(&dev->mt76);
94198686cd2SShayne Chen }
942