blob: 526edc7eda76a43815e7e58af28687337195265c [file] [log] [blame]
developerde9ecce2023-05-22 11:17:16 +08001From 7d85212987815786ceff28379015a6bb23012dc3 Mon Sep 17 00:00:00 2001
developer483388c2023-03-08 13:52:15 +08002From: Howard Hsu <howard-yh.hsu@mediatek.com>
3Date: Thu, 2 Feb 2023 21:20:31 +0800
developerde9ecce2023-05-22 11:17:16 +08004Subject: [PATCH 07/22] wifi: mt76: mt7996: add thermal protection support
developer483388c2023-03-08 13:52:15 +08005
6This commit includes the following changes:
71. implement MTK thermal protection driver API
82. support Linux cooling device control
9
10Change-Id: I8fecc28f5b17ee50ae4644d1dd17d188dd694731
11---
12 mt76_connac_mcu.h | 1 +
developerde9ecce2023-05-22 11:17:16 +080013 mt7996/init.c | 103 ++++++++++++++++++++++++++++++++++++++++++++
developer483388c2023-03-08 13:52:15 +080014 mt7996/main.c | 8 ++++
15 mt7996/mcu.c | 106 ++++++++++++++++++++++++++++++++++++++++++++++
16 mt7996/mcu.h | 44 +++++++++++++++++++
17 mt7996/mt7996.h | 15 +++++++
developerde9ecce2023-05-22 11:17:16 +080018 6 files changed, 277 insertions(+)
developer483388c2023-03-08 13:52:15 +080019
20diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h
developerde9ecce2023-05-22 11:17:16 +080021index 8580ca59..c5c48349 100644
developer483388c2023-03-08 13:52:15 +080022--- a/mt76_connac_mcu.h
23+++ b/mt76_connac_mcu.h
24@@ -1009,6 +1009,7 @@ enum {
25 MCU_UNI_EVENT_FW_LOG_2_HOST = 0x04,
26 MCU_UNI_EVENT_IE_COUNTDOWN = 0x09,
27 MCU_UNI_EVENT_RDD_REPORT = 0x11,
28+ MCU_UNI_EVENT_THERMAL = 0x35,
29 };
30
31 #define MCU_UNI_CMD_EVENT BIT(1)
32diff --git a/mt7996/init.c b/mt7996/init.c
developerde9ecce2023-05-22 11:17:16 +080033index f1b48cdd..53852ffc 100644
developer483388c2023-03-08 13:52:15 +080034--- a/mt7996/init.c
35+++ b/mt7996/init.c
developerde9ecce2023-05-22 11:17:16 +080036@@ -42,6 +42,98 @@ static const struct ieee80211_iface_combination if_comb[] = {
developer483388c2023-03-08 13:52:15 +080037 }
38 };
39
40+static int
41+mt7996_thermal_get_max_throttle_state(struct thermal_cooling_device *cdev,
42+ unsigned long *state)
43+{
44+ *state = MT7996_CDEV_THROTTLE_MAX;
45+
46+ return 0;
47+}
48+
49+static int
50+mt7996_thermal_get_cur_throttle_state(struct thermal_cooling_device *cdev,
51+ unsigned long *state)
52+{
53+ struct mt7996_phy *phy = cdev->devdata;
54+
55+ *state = phy->cdev_state;
56+
57+ return 0;
58+}
59+
60+static int
61+mt7996_thermal_set_cur_throttle_state(struct thermal_cooling_device *cdev,
62+ unsigned long state)
63+{
64+ struct mt7996_phy *phy = cdev->devdata;
65+ u8 throttling = MT7996_THERMAL_THROTTLE_MAX - state;
66+ int ret;
67+
68+ if (state > MT7996_CDEV_THROTTLE_MAX) {
69+ dev_err(phy->dev->mt76.dev,
70+ "please specify a valid throttling state\n");
71+ return -EINVAL;
72+ }
73+
74+ if (state == phy->cdev_state)
75+ return 0;
76+
77+ /*
78+ * cooling_device convention: 0 = no cooling, more = more cooling
79+ * mcu convention: 1 = max cooling, more = less cooling
80+ */
81+ ret = mt7996_mcu_set_thermal_throttling(phy, throttling);
82+ if (ret)
83+ return ret;
84+
85+ phy->cdev_state = state;
86+
87+ return 0;
88+}
89+
90+static const struct thermal_cooling_device_ops mt7996_thermal_ops = {
91+ .get_max_state = mt7996_thermal_get_max_throttle_state,
92+ .get_cur_state = mt7996_thermal_get_cur_throttle_state,
93+ .set_cur_state = mt7996_thermal_set_cur_throttle_state,
94+};
95+
96+static void mt7996_unregister_thermal(struct mt7996_phy *phy)
97+{
98+ struct wiphy *wiphy = phy->mt76->hw->wiphy;
99+
100+ if (!phy->cdev)
101+ return;
102+
103+ sysfs_remove_link(&wiphy->dev.kobj, "cooling_device");
104+ thermal_cooling_device_unregister(phy->cdev);
105+}
106+
107+static int mt7996_thermal_init(struct mt7996_phy *phy)
108+{
109+ struct wiphy *wiphy = phy->mt76->hw->wiphy;
110+ struct thermal_cooling_device *cdev;
111+ const char *name;
112+
113+ name = devm_kasprintf(&wiphy->dev, GFP_KERNEL, "mt7996_%s",
114+ wiphy_name(wiphy));
115+
116+ cdev = thermal_cooling_device_register(name, phy, &mt7996_thermal_ops);
117+ if (!IS_ERR(cdev)) {
118+ if (sysfs_create_link(&wiphy->dev.kobj, &cdev->device.kobj,
119+ "cooling_device") < 0)
120+ thermal_cooling_device_unregister(cdev);
121+ else
122+ phy->cdev = cdev;
123+ }
124+
125+ /* initialize critical/maximum high temperature */
126+ phy->throttle_temp[MT7996_CRIT_TEMP_IDX] = MT7996_CRIT_TEMP;
127+ phy->throttle_temp[MT7996_MAX_TEMP_IDX] = MT7996_MAX_TEMP;
128+
129+ return 0;
130+}
131+
132 static void mt7996_led_set_config(struct led_classdev *led_cdev,
133 u8 delay_on, u8 delay_off)
134 {
developerde9ecce2023-05-22 11:17:16 +0800135@@ -389,6 +481,10 @@ static int mt7996_register_phy(struct mt7996_dev *dev, struct mt7996_phy *phy,
developer483388c2023-03-08 13:52:15 +0800136 if (ret)
137 goto error;
138
139+ ret = mt7996_thermal_init(phy);
140+ if (ret)
141+ goto error;
142+
143 ret = mt7996_init_debugfs(phy);
144 if (ret)
145 goto error;
developerde9ecce2023-05-22 11:17:16 +0800146@@ -409,6 +505,8 @@ mt7996_unregister_phy(struct mt7996_phy *phy, enum mt76_band_id band)
developer483388c2023-03-08 13:52:15 +0800147 if (!phy)
148 return;
149
150+ mt7996_unregister_thermal(phy);
151+
152 mphy = phy->dev->mt76.phys[band];
153 mt76_unregister_phy(mphy);
154 ieee80211_free_hw(mphy->hw);
developerde9ecce2023-05-22 11:17:16 +0800155@@ -879,6 +977,10 @@ int mt7996_register_device(struct mt7996_dev *dev)
developer483388c2023-03-08 13:52:15 +0800156 if (ret)
157 return ret;
158
159+ ret = mt7996_thermal_init(&dev->phy);
160+ if (ret)
161+ return ret;
162+
163 ieee80211_queue_work(mt76_hw(dev), &dev->init_work);
164
165 ret = mt7996_register_phy(dev, mt7996_phy2(dev), MT_BAND1);
developerde9ecce2023-05-22 11:17:16 +0800166@@ -902,6 +1004,7 @@ void mt7996_unregister_device(struct mt7996_dev *dev)
developer483388c2023-03-08 13:52:15 +0800167 {
168 mt7996_unregister_phy(mt7996_phy3(dev), MT_BAND2);
169 mt7996_unregister_phy(mt7996_phy2(dev), MT_BAND1);
developer483388c2023-03-08 13:52:15 +0800170+ mt7996_unregister_thermal(&dev->phy);
developerde9ecce2023-05-22 11:17:16 +0800171 mt7996_coredump_unregister(dev);
developer483388c2023-03-08 13:52:15 +0800172 mt76_unregister_device(&dev->mt76);
173 mt7996_mcu_exit(dev);
developer483388c2023-03-08 13:52:15 +0800174diff --git a/mt7996/main.c b/mt7996/main.c
developerde9ecce2023-05-22 11:17:16 +0800175index 28b63d44..fbb7270d 100644
developer483388c2023-03-08 13:52:15 +0800176--- a/mt7996/main.c
177+++ b/mt7996/main.c
developerde9ecce2023-05-22 11:17:16 +0800178@@ -51,6 +51,14 @@ int mt7996_run(struct ieee80211_hw *hw)
developer483388c2023-03-08 13:52:15 +0800179 if (ret)
180 goto out;
181
182+ ret = mt7996_mcu_set_thermal_throttling(phy, MT7996_THERMAL_THROTTLE_MAX);
183+ if (ret)
184+ goto out;
185+
186+ ret = mt7996_mcu_set_thermal_protect(phy);
187+ if (ret)
188+ goto out;
189+
190 set_bit(MT76_STATE_RUNNING, &phy->mt76->state);
191
192 ieee80211_queue_delayed_work(hw, &phy->mt76->mac_work,
193diff --git a/mt7996/mcu.c b/mt7996/mcu.c
developerde9ecce2023-05-22 11:17:16 +0800194index 6812a47b..325051bd 100644
developer483388c2023-03-08 13:52:15 +0800195--- a/mt7996/mcu.c
196+++ b/mt7996/mcu.c
197@@ -443,6 +443,34 @@ mt7996_mcu_ie_countdown(struct mt7996_dev *dev, struct sk_buff *skb)
198 }
199 }
200
201+static void
202+mt7996_mcu_rx_thermal_notify(struct mt7996_dev *dev, struct sk_buff *skb)
203+{
204+#define THERMAL_NOTIFY_TAG 0x4
205+#define THERMAL_NOTIFY 0x2
206+ struct mt76_phy *mphy = &dev->mt76.phy;
207+ struct mt7996_mcu_thermal_notify *n;
208+ struct mt7996_phy *phy;
209+
210+ n = (struct mt7996_mcu_thermal_notify *)skb->data;
211+
212+ if (n->tag != THERMAL_NOTIFY_TAG)
213+ return;
214+
215+ if (n->event_id != THERMAL_NOTIFY)
216+ return;
217+
218+ if (n->band_idx > MT_BAND2)
219+ return;
220+
221+ mphy = dev->mt76.phys[n->band_idx];
222+ if (!mphy)
223+ return;
224+
225+ phy = (struct mt7996_phy *)mphy->priv;
226+ phy->throttle_state = n->duty_percent;
227+}
228+
229 static void
230 mt7996_mcu_rx_ext_event(struct mt7996_dev *dev, struct sk_buff *skb)
231 {
232@@ -487,6 +515,9 @@ mt7996_mcu_uni_rx_unsolicited_event(struct mt7996_dev *dev, struct sk_buff *skb)
233 case MCU_UNI_EVENT_RDD_REPORT:
234 mt7996_mcu_rx_radar_detected(dev, skb);
235 break;
236+ case MCU_UNI_EVENT_THERMAL:
237+ mt7996_mcu_rx_thermal_notify(dev, skb);
238+ break;
239 default:
240 break;
241 }
developerde9ecce2023-05-22 11:17:16 +0800242@@ -3178,6 +3209,81 @@ out:
developer483388c2023-03-08 13:52:15 +0800243 return 0;
244 }
245
246+
247+int mt7996_mcu_set_thermal_throttling(struct mt7996_phy *phy, u8 state)
248+{
249+ struct {
250+ u8 _rsv[4];
251+
252+ __le16 tag;
253+ __le16 len;
254+
255+ struct mt7996_mcu_thermal_ctrl ctrl;
256+ } __packed req = {
257+ .tag = cpu_to_le16(UNI_CMD_THERMAL_PROTECT_DUTY_CONFIG),
258+ .len = cpu_to_le16(sizeof(req) - 4),
259+ .ctrl = {
260+ .band_idx = phy->mt76->band_idx,
261+ },
262+ };
263+ int level, ret;
264+
265+ /* set duty cycle and level */
266+ for (level = 0; level < 4; level++) {
267+ req.ctrl.duty.duty_level = level;
268+ req.ctrl.duty.duty_cycle = state;
269+ state /= 2;
270+
271+ ret = mt76_mcu_send_msg(&phy->dev->mt76, MCU_WM_UNI_CMD(THERMAL),
272+ &req, sizeof(req), false);
273+ if (ret)
274+ return ret;
275+ }
276+
277+ return 0;
278+}
279+
280+int mt7996_mcu_set_thermal_protect(struct mt7996_phy *phy)
281+{
282+#define SUSTAIN_PERIOD 10
283+ struct {
284+ u8 _rsv[4];
285+
286+ __le16 tag;
287+ __le16 len;
288+
289+ struct mt7996_mcu_thermal_ctrl ctrl;
290+ struct mt7996_mcu_thermal_enable enable;
291+ } __packed req = {
292+ .len = cpu_to_le16(sizeof(req) - 4 - sizeof(req.enable)),
293+ .ctrl = {
294+ .band_idx = phy->mt76->band_idx,
295+ .type.protect_type = 1,
296+ .type.trigger_type = 1,
297+ },
298+ };
299+ int ret;
300+
301+ req.tag = cpu_to_le16(UNI_CMD_THERMAL_PROTECT_DISABLE);
302+
303+ ret = mt76_mcu_send_msg(&phy->dev->mt76, MCU_WM_UNI_CMD(THERMAL),
304+ &req, sizeof(req) - sizeof(req.enable), false);
305+ if (ret)
306+ return ret;
307+
308+ /* set high-temperature trigger threshold */
309+ req.tag = cpu_to_le16(UNI_CMD_THERMAL_PROTECT_ENABLE);
310+ /* add a safety margin ~10 */
311+ req.enable.restore_temp = cpu_to_le32(phy->throttle_temp[0] - 10);
312+ req.enable.trigger_temp = cpu_to_le32(phy->throttle_temp[1]);
313+ req.enable.sustain_time = cpu_to_le16(SUSTAIN_PERIOD);
314+
315+ req.len = cpu_to_le16(sizeof(req) - 4);
316+
317+ return mt76_mcu_send_msg(&phy->dev->mt76, MCU_WM_UNI_CMD(THERMAL),
318+ &req, sizeof(req), false);
319+}
320+
321 int mt7996_mcu_set_ser(struct mt7996_dev *dev, u8 action, u8 val, u8 band)
322 {
323 struct {
324diff --git a/mt7996/mcu.h b/mt7996/mcu.h
developerde9ecce2023-05-22 11:17:16 +0800325index d7075a4d..778deedf 100644
developer483388c2023-03-08 13:52:15 +0800326--- a/mt7996/mcu.h
327+++ b/mt7996/mcu.h
328@@ -30,6 +30,28 @@ struct mt7996_mcu_uni_event {
329 __le32 status; /* 0: success, others: fail */
330 } __packed;
331
332+struct mt7996_mcu_thermal_ctrl {
333+ u8 ctrl_id;
334+ u8 band_idx;
335+ union {
336+ struct {
337+ u8 protect_type; /* 1: duty admit, 2: radio off */
338+ u8 trigger_type; /* 0: low, 1: high */
339+ } __packed type;
340+ struct {
341+ u8 duty_level; /* level 0~3 */
342+ u8 duty_cycle;
343+ } __packed duty;
344+ };
345+} __packed;
346+
347+struct mt7996_mcu_thermal_enable {
348+ __le32 trigger_temp;
349+ __le32 restore_temp;
350+ __le16 sustain_time;
351+ u8 rsv[2];
352+} __packed;
353+
354 struct mt7996_mcu_csa_notify {
355 struct mt7996_mcu_rxd rxd;
356
357@@ -153,6 +175,22 @@ struct mt7996_mcu_mib {
358 __le64 data;
359 } __packed;
360
361+struct mt7996_mcu_thermal_notify {
362+ struct mt7996_mcu_rxd rxd;
363+
364+ u8 __rsv1[4];
365+
366+ __le16 tag;
367+ __le16 len;
368+
369+ u8 event_id;
370+ u8 band_idx;
371+ u8 level_idx;
372+ u8 duty_percent;
373+ __le32 restore_temp;
374+ u8 __rsv2[4];
375+} __packed;
376+
377 enum mt7996_chan_mib_offs {
378 UNI_MIB_OBSS_AIRTIME = 26,
379 UNI_MIB_NON_WIFI_TIME = 27,
380@@ -642,6 +680,12 @@ enum{
381 UNI_CMD_SR_SET_SIGA = 0xd0,
382 };
383
384+enum {
385+ UNI_CMD_THERMAL_PROTECT_ENABLE = 0x6,
386+ UNI_CMD_THERMAL_PROTECT_DISABLE,
387+ UNI_CMD_THERMAL_PROTECT_DUTY_CONFIG,
388+};
389+
390 enum {
391 UNI_CMD_ACCESS_REG_BASIC = 0x0,
392 UNI_CMD_ACCESS_RF_REG_BASIC,
393diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
developerde9ecce2023-05-22 11:17:16 +0800394index 4d7dcb95..36337808 100644
developer483388c2023-03-08 13:52:15 +0800395--- a/mt7996/mt7996.h
396+++ b/mt7996/mt7996.h
developerde9ecce2023-05-22 11:17:16 +0800397@@ -47,6 +47,13 @@
398 #define MT7996_BASIC_RATES_TBL 11
399 #define MT7996_BEACON_RATES_TBL 25
developer483388c2023-03-08 13:52:15 +0800400
401+#define MT7996_THERMAL_THROTTLE_MAX 100
402+#define MT7996_CDEV_THROTTLE_MAX 99
403+#define MT7996_CRIT_TEMP_IDX 0
404+#define MT7996_MAX_TEMP_IDX 1
405+#define MT7996_CRIT_TEMP 110
406+#define MT7996_MAX_TEMP 120
407+
408 struct mt7996_vif;
409 struct mt7996_sta;
410 struct mt7996_dfs_pulse;
developerde9ecce2023-05-22 11:17:16 +0800411@@ -209,6 +216,11 @@ struct mt7996_phy {
developer483388c2023-03-08 13:52:15 +0800412
413 struct ieee80211_vif *monitor_vif;
414
415+ struct thermal_cooling_device *cdev;
416+ u8 cdev_state;
417+ u8 throttle_state;
418+ u32 throttle_temp[2]; /* 0: critical high, 1: maximum */
419+
420 u32 rxfilter;
421 u64 omac_mask;
422
developerde9ecce2023-05-22 11:17:16 +0800423@@ -457,6 +469,9 @@ int mt7996_mcu_set_radar_th(struct mt7996_dev *dev, int index,
developer483388c2023-03-08 13:52:15 +0800424 int mt7996_mcu_set_radio_en(struct mt7996_phy *phy, bool enable);
425 int mt7996_mcu_set_rts_thresh(struct mt7996_phy *phy, u32 val);
426 int mt7996_mcu_get_chan_mib_info(struct mt7996_phy *phy, bool chan_switch);
427+int mt7996_mcu_get_temperature(struct mt7996_phy *phy);
428+int mt7996_mcu_set_thermal_throttling(struct mt7996_phy *phy, u8 state);
429+int mt7996_mcu_set_thermal_protect(struct mt7996_phy *phy);
430 int mt7996_mcu_rdd_cmd(struct mt7996_dev *dev, int cmd, u8 index,
431 u8 rx_sel, u8 val);
432 int mt7996_mcu_rdd_background_enable(struct mt7996_phy *phy,
433--
developerde9ecce2023-05-22 11:17:16 +08004342.39.2
developer483388c2023-03-08 13:52:15 +0800435