[][MAC80211][mt76][update mt76 patches]

[Description]
Add and sync mt76 patches for bug fixes and new features.

[Release-log]
N/A

Change-Id: Iea7dbbed1c51ad1320607415fc7574640315bb9a
Reviewed-on: https://gerrit.mediatek.inc/c/openwrt/feeds/mtk_openwrt_feeds/+/7295789
diff --git a/autobuild_mac80211_release/mt7988_mt7996_mac80211/package/kernel/mt76/patches/0012-wifi-mt76-mt7996-add-thermal-protection-support.patch b/autobuild_mac80211_release/mt7988_mt7996_mac80211/package/kernel/mt76/patches/0012-wifi-mt76-mt7996-add-thermal-protection-support.patch
new file mode 100644
index 0000000..9ab919e
--- /dev/null
+++ b/autobuild_mac80211_release/mt7988_mt7996_mac80211/package/kernel/mt76/patches/0012-wifi-mt76-mt7996-add-thermal-protection-support.patch
@@ -0,0 +1,437 @@
+From 43cb74cdfc3651a15f6dd2b22bff3a83a2464950 Mon Sep 17 00:00:00 2001
+From: Howard Hsu <howard-yh.hsu@mediatek.com>
+Date: Thu, 2 Feb 2023 21:20:31 +0800
+Subject: [PATCH 12/29] wifi: mt76: mt7996: add thermal protection support
+
+This commit includes the following changes:
+1. implement MTK thermal protection driver API
+2. support Linux cooling device control
+
+Change-Id: I8fecc28f5b17ee50ae4644d1dd17d188dd694731
+---
+ mt76_connac_mcu.h |   1 +
+ mt7996/init.c     | 105 +++++++++++++++++++++++++++++++++++++++++++++
+ mt7996/main.c     |   8 ++++
+ mt7996/mcu.c      | 106 ++++++++++++++++++++++++++++++++++++++++++++++
+ mt7996/mcu.h      |  44 +++++++++++++++++++
+ mt7996/mt7996.h   |  15 +++++++
+ 6 files changed, 279 insertions(+)
+
+diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h
+index 6f30a0fb..fa10d823 100644
+--- a/mt76_connac_mcu.h
++++ b/mt76_connac_mcu.h
+@@ -1009,6 +1009,7 @@ enum {
+ 	MCU_UNI_EVENT_FW_LOG_2_HOST = 0x04,
+ 	MCU_UNI_EVENT_IE_COUNTDOWN = 0x09,
+ 	MCU_UNI_EVENT_RDD_REPORT = 0x11,
++	MCU_UNI_EVENT_THERMAL = 0x35,
+ };
+ 
+ #define MCU_UNI_CMD_EVENT			BIT(1)
+diff --git a/mt7996/init.c b/mt7996/init.c
+index de94e151..44165a35 100644
+--- a/mt7996/init.c
++++ b/mt7996/init.c
+@@ -41,6 +41,98 @@ static const struct ieee80211_iface_combination if_comb[] = {
+ 	}
+ };
+ 
++static int
++mt7996_thermal_get_max_throttle_state(struct thermal_cooling_device *cdev,
++				      unsigned long *state)
++{
++	*state = MT7996_CDEV_THROTTLE_MAX;
++
++	return 0;
++}
++
++static int
++mt7996_thermal_get_cur_throttle_state(struct thermal_cooling_device *cdev,
++				      unsigned long *state)
++{
++	struct mt7996_phy *phy = cdev->devdata;
++
++	*state = phy->cdev_state;
++
++	return 0;
++}
++
++static int
++mt7996_thermal_set_cur_throttle_state(struct thermal_cooling_device *cdev,
++				      unsigned long state)
++{
++	struct mt7996_phy *phy = cdev->devdata;
++	u8 throttling = MT7996_THERMAL_THROTTLE_MAX - state;
++	int ret;
++
++	if (state > MT7996_CDEV_THROTTLE_MAX) {
++		dev_err(phy->dev->mt76.dev,
++			"please specify a valid throttling state\n");
++		return -EINVAL;
++	}
++
++	if (state == phy->cdev_state)
++		return 0;
++
++	/*
++	 * cooling_device convention: 0 = no cooling, more = more cooling
++	 * mcu convention: 1 = max cooling, more = less cooling
++	 */
++	ret = mt7996_mcu_set_thermal_throttling(phy, throttling);
++	if (ret)
++		return ret;
++
++	phy->cdev_state = state;
++
++	return 0;
++}
++
++static const struct thermal_cooling_device_ops mt7996_thermal_ops = {
++	.get_max_state = mt7996_thermal_get_max_throttle_state,
++	.get_cur_state = mt7996_thermal_get_cur_throttle_state,
++	.set_cur_state = mt7996_thermal_set_cur_throttle_state,
++};
++
++static void mt7996_unregister_thermal(struct mt7996_phy *phy)
++{
++	struct wiphy *wiphy = phy->mt76->hw->wiphy;
++
++	if (!phy->cdev)
++	    return;
++
++	sysfs_remove_link(&wiphy->dev.kobj, "cooling_device");
++	thermal_cooling_device_unregister(phy->cdev);
++}
++
++static int mt7996_thermal_init(struct mt7996_phy *phy)
++{
++	struct wiphy *wiphy = phy->mt76->hw->wiphy;
++	struct thermal_cooling_device *cdev;
++	const char *name;
++
++	name = devm_kasprintf(&wiphy->dev, GFP_KERNEL, "mt7996_%s",
++			      wiphy_name(wiphy));
++
++	cdev = thermal_cooling_device_register(name, phy, &mt7996_thermal_ops);
++	if (!IS_ERR(cdev)) {
++		if (sysfs_create_link(&wiphy->dev.kobj, &cdev->device.kobj,
++				      "cooling_device") < 0)
++			thermal_cooling_device_unregister(cdev);
++		else
++			phy->cdev = cdev;
++	}
++
++	/* initialize critical/maximum high temperature */
++	phy->throttle_temp[MT7996_CRIT_TEMP_IDX] = MT7996_CRIT_TEMP;
++	phy->throttle_temp[MT7996_MAX_TEMP_IDX] = MT7996_MAX_TEMP;
++
++	return 0;
++}
++
+ static void mt7996_led_set_config(struct led_classdev *led_cdev,
+ 				  u8 delay_on, u8 delay_off)
+ {
+@@ -372,6 +464,10 @@ static int mt7996_register_phy(struct mt7996_dev *dev, struct mt7996_phy *phy,
+ 	if (ret)
+ 		goto error;
+ 
++	ret = mt7996_thermal_init(phy);
++	if (ret)
++		goto error;
++
+ 	ret = mt7996_init_debugfs(phy);
+ 	if (ret)
+ 		goto error;
+@@ -392,6 +488,8 @@ mt7996_unregister_phy(struct mt7996_phy *phy, enum mt76_band_id band)
+ 	if (!phy)
+ 		return;
+ 
++	mt7996_unregister_thermal(phy);
++
+ 	mphy = phy->dev->mt76.phys[band];
+ 	mt76_unregister_phy(mphy);
+ 	ieee80211_free_hw(mphy->hw);
+@@ -881,6 +979,10 @@ int mt7996_register_device(struct mt7996_dev *dev)
+ 	if (ret)
+ 		return ret;
+ 
++	ret = mt7996_thermal_init(&dev->phy);
++	if (ret)
++		return ret;
++
+ 	ieee80211_queue_work(mt76_hw(dev), &dev->init_work);
+ 
+ 	ret = mt7996_register_phy(dev, mt7996_phy2(dev), MT_BAND1);
+@@ -898,6 +1000,9 @@ void mt7996_unregister_device(struct mt7996_dev *dev)
+ {
+ 	mt7996_unregister_phy(mt7996_phy3(dev), MT_BAND2);
+ 	mt7996_unregister_phy(mt7996_phy2(dev), MT_BAND1);
++
++	mt7996_unregister_thermal(&dev->phy);
++
+ 	mt76_unregister_device(&dev->mt76);
+ 	mt7996_mcu_exit(dev);
+ 	mt7996_tx_token_put(dev);
+diff --git a/mt7996/main.c b/mt7996/main.c
+index 44d23e1d..d8d578c0 100644
+--- a/mt7996/main.c
++++ b/mt7996/main.c
+@@ -54,6 +54,14 @@ static int mt7996_start(struct ieee80211_hw *hw)
+ 	if (ret)
+ 		goto out;
+ 
++	ret = mt7996_mcu_set_thermal_throttling(phy, MT7996_THERMAL_THROTTLE_MAX);
++	if (ret)
++		goto out;
++
++	ret = mt7996_mcu_set_thermal_protect(phy);
++	if (ret)
++		goto out;
++
+ 	set_bit(MT76_STATE_RUNNING, &phy->mt76->state);
+ 
+ 	ieee80211_queue_delayed_work(hw, &phy->mt76->mac_work,
+diff --git a/mt7996/mcu.c b/mt7996/mcu.c
+index b6bd36c2..3820a63e 100644
+--- a/mt7996/mcu.c
++++ b/mt7996/mcu.c
+@@ -443,6 +443,34 @@ mt7996_mcu_ie_countdown(struct mt7996_dev *dev, struct sk_buff *skb)
+ 	}
+ }
+ 
++static void
++mt7996_mcu_rx_thermal_notify(struct mt7996_dev *dev, struct sk_buff *skb)
++{
++#define THERMAL_NOTIFY_TAG 0x4
++#define THERMAL_NOTIFY 0x2
++	struct mt76_phy *mphy = &dev->mt76.phy;
++	struct mt7996_mcu_thermal_notify *n;
++	struct mt7996_phy *phy;
++
++	n = (struct mt7996_mcu_thermal_notify *)skb->data;
++
++	if (n->tag != THERMAL_NOTIFY_TAG)
++		return;
++
++	if (n->event_id != THERMAL_NOTIFY)
++		return;
++
++	if (n->band_idx > MT_BAND2)
++		return;
++
++	mphy = dev->mt76.phys[n->band_idx];
++	if (!mphy)
++		return;
++
++	phy = (struct mt7996_phy *)mphy->priv;
++	phy->throttle_state = n->duty_percent;
++}
++
+ static void
+ mt7996_mcu_rx_ext_event(struct mt7996_dev *dev, struct sk_buff *skb)
+ {
+@@ -487,6 +515,9 @@ mt7996_mcu_uni_rx_unsolicited_event(struct mt7996_dev *dev, struct sk_buff *skb)
+ 	case MCU_UNI_EVENT_RDD_REPORT:
+ 		mt7996_mcu_rx_radar_detected(dev, skb);
+ 		break;
++	case MCU_UNI_EVENT_THERMAL:
++		mt7996_mcu_rx_thermal_notify(dev, skb);
++		break;
+ 	default:
+ 		break;
+ 	}
+@@ -3277,6 +3308,81 @@ out:
+ 	return 0;
+ }
+ 
++
++int mt7996_mcu_set_thermal_throttling(struct mt7996_phy *phy, u8 state)
++{
++	struct {
++		u8 _rsv[4];
++
++		__le16 tag;
++		__le16 len;
++
++		struct mt7996_mcu_thermal_ctrl ctrl;
++	} __packed req = {
++		.tag = cpu_to_le16(UNI_CMD_THERMAL_PROTECT_DUTY_CONFIG),
++		.len = cpu_to_le16(sizeof(req) - 4),
++		.ctrl = {
++			.band_idx = phy->mt76->band_idx,
++		},
++	};
++	int level, ret;
++
++	/* set duty cycle and level */
++	for (level = 0; level < 4; level++) {
++		req.ctrl.duty.duty_level = level;
++		req.ctrl.duty.duty_cycle = state;
++		state /= 2;
++
++		ret = mt76_mcu_send_msg(&phy->dev->mt76, MCU_WM_UNI_CMD(THERMAL),
++					&req, sizeof(req), false);
++		if (ret)
++			return ret;
++	}
++
++	return 0;
++}
++
++int mt7996_mcu_set_thermal_protect(struct mt7996_phy *phy)
++{
++#define SUSTAIN_PERIOD		10
++	struct {
++		u8 _rsv[4];
++
++		__le16 tag;
++		__le16 len;
++
++		struct mt7996_mcu_thermal_ctrl ctrl;
++		struct mt7996_mcu_thermal_enable enable;
++	} __packed req = {
++		.len = cpu_to_le16(sizeof(req) - 4 - sizeof(req.enable)),
++		.ctrl = {
++			.band_idx = phy->mt76->band_idx,
++			.type.protect_type = 1,
++			.type.trigger_type = 1,
++		},
++	};
++	int ret;
++
++	req.tag = cpu_to_le16(UNI_CMD_THERMAL_PROTECT_DISABLE);
++
++	ret = mt76_mcu_send_msg(&phy->dev->mt76, MCU_WM_UNI_CMD(THERMAL),
++				&req, sizeof(req) - sizeof(req.enable), false);
++	if (ret)
++		return ret;
++
++	/* set high-temperature trigger threshold */
++	req.tag = cpu_to_le16(UNI_CMD_THERMAL_PROTECT_ENABLE);
++	/* add a safety margin ~10 */
++	req.enable.restore_temp = cpu_to_le32(phy->throttle_temp[0] - 10);
++	req.enable.trigger_temp = cpu_to_le32(phy->throttle_temp[1]);
++	req.enable.sustain_time = cpu_to_le16(SUSTAIN_PERIOD);
++
++	req.len = cpu_to_le16(sizeof(req) - 4);
++
++	return mt76_mcu_send_msg(&phy->dev->mt76, MCU_WM_UNI_CMD(THERMAL),
++				 &req, sizeof(req), false);
++}
++
+ int mt7996_mcu_set_ser(struct mt7996_dev *dev, u8 action, u8 val, u8 band)
+ {
+ 	struct {
+diff --git a/mt7996/mcu.h b/mt7996/mcu.h
+index dd0c5ac5..7fefc28f 100644
+--- a/mt7996/mcu.h
++++ b/mt7996/mcu.h
+@@ -30,6 +30,28 @@ struct mt7996_mcu_uni_event {
+ 	__le32 status; /* 0: success, others: fail */
+ } __packed;
+ 
++struct mt7996_mcu_thermal_ctrl {
++	u8 ctrl_id;
++	u8 band_idx;
++	union {
++		struct {
++			u8 protect_type; /* 1: duty admit, 2: radio off */
++			u8 trigger_type; /* 0: low, 1: high */
++		} __packed type;
++		struct {
++			u8 duty_level;	/* level 0~3 */
++			u8 duty_cycle;
++		} __packed duty;
++	};
++} __packed;
++
++struct mt7996_mcu_thermal_enable {
++	__le32 trigger_temp;
++	__le32 restore_temp;
++	__le16 sustain_time;
++	u8 rsv[2];
++} __packed;
++
+ struct mt7996_mcu_csa_notify {
+ 	struct mt7996_mcu_rxd rxd;
+ 
+@@ -153,6 +175,22 @@ struct mt7996_mcu_mib {
+ 	__le64 data;
+ } __packed;
+ 
++struct mt7996_mcu_thermal_notify {
++	struct mt7996_mcu_rxd rxd;
++
++	u8 __rsv1[4];
++
++	__le16 tag;
++	__le16 len;
++
++	u8 event_id;
++	u8 band_idx;
++	u8 level_idx;
++	u8 duty_percent;
++	__le32 restore_temp;
++	u8 __rsv2[4];
++} __packed;
++
+ enum mt7996_chan_mib_offs {
+ 	UNI_MIB_OBSS_AIRTIME = 26,
+ 	UNI_MIB_NON_WIFI_TIME = 27,
+@@ -642,6 +680,12 @@ enum{
+ 	UNI_CMD_SR_SET_SIGA = 0xd0,
+ };
+ 
++enum {
++	UNI_CMD_THERMAL_PROTECT_ENABLE = 0x6,
++	UNI_CMD_THERMAL_PROTECT_DISABLE,
++	UNI_CMD_THERMAL_PROTECT_DUTY_CONFIG,
++};
++
+ enum {
+ 	UNI_CMD_ACCESS_REG_BASIC = 0x0,
+ 	UNI_CMD_ACCESS_RF_REG_BASIC,
+diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
+index 997a0bf0..25b20fa6 100644
+--- a/mt7996/mt7996.h
++++ b/mt7996/mt7996.h
+@@ -43,6 +43,13 @@
+ #define MT7996_MAX_STA_TWT_AGRT		8
+ #define MT7996_MAX_QUEUE		(__MT_RXQ_MAX +	__MT_MCUQ_MAX + 3)
+ 
++#define MT7996_THERMAL_THROTTLE_MAX	100
++#define MT7996_CDEV_THROTTLE_MAX	99
++#define MT7996_CRIT_TEMP_IDX		0
++#define MT7996_MAX_TEMP_IDX		1
++#define MT7996_CRIT_TEMP		110
++#define MT7996_MAX_TEMP			120
++
+ struct mt7996_vif;
+ struct mt7996_sta;
+ struct mt7996_dfs_pulse;
+@@ -211,6 +218,11 @@ struct mt7996_phy {
+ 
+ 	struct ieee80211_vif *monitor_vif;
+ 
++	struct thermal_cooling_device *cdev;
++	u8 cdev_state;
++	u8 throttle_state;
++	u32 throttle_temp[2]; /* 0: critical high, 1: maximum */
++
+ 	u32 rxfilter;
+ 	u64 omac_mask;
+ 
+@@ -437,6 +449,9 @@ int mt7996_mcu_set_radar_th(struct mt7996_dev *dev, int index,
+ int mt7996_mcu_set_radio_en(struct mt7996_phy *phy, bool enable);
+ int mt7996_mcu_set_rts_thresh(struct mt7996_phy *phy, u32 val);
+ int mt7996_mcu_get_chan_mib_info(struct mt7996_phy *phy, bool chan_switch);
++int mt7996_mcu_get_temperature(struct mt7996_phy *phy);
++int mt7996_mcu_set_thermal_throttling(struct mt7996_phy *phy, u8 state);
++int mt7996_mcu_set_thermal_protect(struct mt7996_phy *phy);
+ int mt7996_mcu_rdd_cmd(struct mt7996_dev *dev, int cmd, u8 index,
+ 		       u8 rx_sel, u8 val);
+ int mt7996_mcu_rdd_background_enable(struct mt7996_phy *phy,
+-- 
+2.39.2
+