xref: /freebsd/sys/contrib/dev/mediatek/mt76/mt7925/regd.c (revision b1bebaaba9b9c0ddfe503c43ca8e9e3917ee2c57)
1*b1bebaabSBjoern A. Zeeb // SPDX-License-Identifier: BSD-3-Clause-Clear
2*b1bebaabSBjoern A. Zeeb /* Copyright (C) 2025 MediaTek Inc. */
3*b1bebaabSBjoern A. Zeeb 
4*b1bebaabSBjoern A. Zeeb #include "mt7925.h"
5*b1bebaabSBjoern A. Zeeb #include "regd.h"
6*b1bebaabSBjoern A. Zeeb #include "mcu.h"
7*b1bebaabSBjoern A. Zeeb 
8*b1bebaabSBjoern A. Zeeb static bool mt7925_disable_clc;
9*b1bebaabSBjoern A. Zeeb module_param_named(disable_clc, mt7925_disable_clc, bool, 0644);
10*b1bebaabSBjoern A. Zeeb MODULE_PARM_DESC(disable_clc, "disable CLC support");
11*b1bebaabSBjoern A. Zeeb 
mt7925_regd_clc_supported(struct mt792x_dev * dev)12*b1bebaabSBjoern A. Zeeb bool mt7925_regd_clc_supported(struct mt792x_dev *dev)
13*b1bebaabSBjoern A. Zeeb {
14*b1bebaabSBjoern A. Zeeb 	if (mt7925_disable_clc ||
15*b1bebaabSBjoern A. Zeeb 	    mt76_is_usb(&dev->mt76))
16*b1bebaabSBjoern A. Zeeb 		return false;
17*b1bebaabSBjoern A. Zeeb 
18*b1bebaabSBjoern A. Zeeb 	return true;
19*b1bebaabSBjoern A. Zeeb }
20*b1bebaabSBjoern A. Zeeb 
mt7925_regd_be_ctrl(struct mt792x_dev * dev,u8 * alpha2)21*b1bebaabSBjoern A. Zeeb void mt7925_regd_be_ctrl(struct mt792x_dev *dev, u8 *alpha2)
22*b1bebaabSBjoern A. Zeeb {
23*b1bebaabSBjoern A. Zeeb 	struct mt792x_phy *phy = &dev->phy;
24*b1bebaabSBjoern A. Zeeb 	struct mt7925_clc_rule_v2 *rule;
25*b1bebaabSBjoern A. Zeeb 	struct mt7925_clc *clc;
26*b1bebaabSBjoern A. Zeeb 	bool old = dev->has_eht, new = true;
27*b1bebaabSBjoern A. Zeeb 	u32 mtcl_conf = mt792x_acpi_get_mtcl_conf(&dev->phy, alpha2);
28*b1bebaabSBjoern A. Zeeb 	u8 *pos;
29*b1bebaabSBjoern A. Zeeb 
30*b1bebaabSBjoern A. Zeeb 	if (mtcl_conf != MT792X_ACPI_MTCL_INVALID &&
31*b1bebaabSBjoern A. Zeeb 	    (((mtcl_conf >> 4) & 0x3) == 0)) {
32*b1bebaabSBjoern A. Zeeb 		new = false;
33*b1bebaabSBjoern A. Zeeb 		goto out;
34*b1bebaabSBjoern A. Zeeb 	}
35*b1bebaabSBjoern A. Zeeb 
36*b1bebaabSBjoern A. Zeeb 	if (!phy->clc[MT792x_CLC_BE_CTRL])
37*b1bebaabSBjoern A. Zeeb 		goto out;
38*b1bebaabSBjoern A. Zeeb 
39*b1bebaabSBjoern A. Zeeb 	clc = (struct mt7925_clc *)phy->clc[MT792x_CLC_BE_CTRL];
40*b1bebaabSBjoern A. Zeeb 	pos = clc->data;
41*b1bebaabSBjoern A. Zeeb 
42*b1bebaabSBjoern A. Zeeb 	while (1) {
43*b1bebaabSBjoern A. Zeeb 		rule = (struct mt7925_clc_rule_v2 *)pos;
44*b1bebaabSBjoern A. Zeeb 
45*b1bebaabSBjoern A. Zeeb 		if (rule->alpha2[0] == alpha2[0] &&
46*b1bebaabSBjoern A. Zeeb 		    rule->alpha2[1] == alpha2[1]) {
47*b1bebaabSBjoern A. Zeeb 			new = false;
48*b1bebaabSBjoern A. Zeeb 			break;
49*b1bebaabSBjoern A. Zeeb 		}
50*b1bebaabSBjoern A. Zeeb 
51*b1bebaabSBjoern A. Zeeb 		/* Check the last one */
52*b1bebaabSBjoern A. Zeeb 		if (rule->flag & BIT(0))
53*b1bebaabSBjoern A. Zeeb 			break;
54*b1bebaabSBjoern A. Zeeb 
55*b1bebaabSBjoern A. Zeeb 		pos += sizeof(*rule);
56*b1bebaabSBjoern A. Zeeb 	}
57*b1bebaabSBjoern A. Zeeb 
58*b1bebaabSBjoern A. Zeeb out:
59*b1bebaabSBjoern A. Zeeb 	if (old == new)
60*b1bebaabSBjoern A. Zeeb 		return;
61*b1bebaabSBjoern A. Zeeb 
62*b1bebaabSBjoern A. Zeeb 	dev->has_eht = new;
63*b1bebaabSBjoern A. Zeeb 	mt7925_set_stream_he_eht_caps(phy);
64*b1bebaabSBjoern A. Zeeb }
65*b1bebaabSBjoern A. Zeeb 
66*b1bebaabSBjoern A. Zeeb static void
mt7925_regd_channel_update(struct wiphy * wiphy,struct mt792x_dev * dev)67*b1bebaabSBjoern A. Zeeb mt7925_regd_channel_update(struct wiphy *wiphy, struct mt792x_dev *dev)
68*b1bebaabSBjoern A. Zeeb {
69*b1bebaabSBjoern A. Zeeb #define IS_UNII_INVALID(idx, sfreq, efreq, cfreq) \
70*b1bebaabSBjoern A. Zeeb 	(!(dev->phy.clc_chan_conf & BIT(idx)) && (cfreq) >= (sfreq) && (cfreq) <= (efreq))
71*b1bebaabSBjoern A. Zeeb #define MT7925_UNII_59G_IS_VALID	0x1
72*b1bebaabSBjoern A. Zeeb #define MT7925_UNII_6G_IS_VALID	0x1e
73*b1bebaabSBjoern A. Zeeb 	struct ieee80211_supported_band *sband;
74*b1bebaabSBjoern A. Zeeb 	struct mt76_dev *mdev = &dev->mt76;
75*b1bebaabSBjoern A. Zeeb 	struct ieee80211_channel *ch;
76*b1bebaabSBjoern A. Zeeb 	u32 mtcl_conf = mt792x_acpi_get_mtcl_conf(&dev->phy, mdev->alpha2);
77*b1bebaabSBjoern A. Zeeb 	int i;
78*b1bebaabSBjoern A. Zeeb 
79*b1bebaabSBjoern A. Zeeb 	if (mtcl_conf != MT792X_ACPI_MTCL_INVALID) {
80*b1bebaabSBjoern A. Zeeb 		if ((mtcl_conf & 0x3) == 0)
81*b1bebaabSBjoern A. Zeeb 			dev->phy.clc_chan_conf &= ~MT7925_UNII_59G_IS_VALID;
82*b1bebaabSBjoern A. Zeeb 		if (((mtcl_conf >> 2) & 0x3) == 0)
83*b1bebaabSBjoern A. Zeeb 			dev->phy.clc_chan_conf &= ~MT7925_UNII_6G_IS_VALID;
84*b1bebaabSBjoern A. Zeeb 	}
85*b1bebaabSBjoern A. Zeeb 
86*b1bebaabSBjoern A. Zeeb 	sband = wiphy->bands[NL80211_BAND_2GHZ];
87*b1bebaabSBjoern A. Zeeb 	if (!sband)
88*b1bebaabSBjoern A. Zeeb 		return;
89*b1bebaabSBjoern A. Zeeb 
90*b1bebaabSBjoern A. Zeeb 	for (i = 0; i < sband->n_channels; i++) {
91*b1bebaabSBjoern A. Zeeb 		ch = &sband->channels[i];
92*b1bebaabSBjoern A. Zeeb 
93*b1bebaabSBjoern A. Zeeb 		if (!dev->has_eht)
94*b1bebaabSBjoern A. Zeeb 			ch->flags |= IEEE80211_CHAN_NO_EHT;
95*b1bebaabSBjoern A. Zeeb 	}
96*b1bebaabSBjoern A. Zeeb 
97*b1bebaabSBjoern A. Zeeb 	sband = wiphy->bands[NL80211_BAND_5GHZ];
98*b1bebaabSBjoern A. Zeeb 	if (!sband)
99*b1bebaabSBjoern A. Zeeb 		return;
100*b1bebaabSBjoern A. Zeeb 
101*b1bebaabSBjoern A. Zeeb 	for (i = 0; i < sband->n_channels; i++) {
102*b1bebaabSBjoern A. Zeeb 		ch = &sband->channels[i];
103*b1bebaabSBjoern A. Zeeb 
104*b1bebaabSBjoern A. Zeeb 		/* UNII-4 */
105*b1bebaabSBjoern A. Zeeb 		if (IS_UNII_INVALID(0, 5845, 5925, ch->center_freq))
106*b1bebaabSBjoern A. Zeeb 			ch->flags |= IEEE80211_CHAN_DISABLED;
107*b1bebaabSBjoern A. Zeeb 
108*b1bebaabSBjoern A. Zeeb 		if (!dev->has_eht)
109*b1bebaabSBjoern A. Zeeb 			ch->flags |= IEEE80211_CHAN_NO_EHT;
110*b1bebaabSBjoern A. Zeeb 	}
111*b1bebaabSBjoern A. Zeeb 
112*b1bebaabSBjoern A. Zeeb 	sband = wiphy->bands[NL80211_BAND_6GHZ];
113*b1bebaabSBjoern A. Zeeb 	if (!sband)
114*b1bebaabSBjoern A. Zeeb 		return;
115*b1bebaabSBjoern A. Zeeb 
116*b1bebaabSBjoern A. Zeeb 	for (i = 0; i < sband->n_channels; i++) {
117*b1bebaabSBjoern A. Zeeb 		ch = &sband->channels[i];
118*b1bebaabSBjoern A. Zeeb 
119*b1bebaabSBjoern A. Zeeb 		/* UNII-5/6/7/8 */
120*b1bebaabSBjoern A. Zeeb 		if (IS_UNII_INVALID(1, 5925, 6425, ch->center_freq) ||
121*b1bebaabSBjoern A. Zeeb 		    IS_UNII_INVALID(2, 6425, 6525, ch->center_freq) ||
122*b1bebaabSBjoern A. Zeeb 		    IS_UNII_INVALID(3, 6525, 6875, ch->center_freq) ||
123*b1bebaabSBjoern A. Zeeb 		    IS_UNII_INVALID(4, 6875, 7125, ch->center_freq))
124*b1bebaabSBjoern A. Zeeb 			ch->flags |= IEEE80211_CHAN_DISABLED;
125*b1bebaabSBjoern A. Zeeb 
126*b1bebaabSBjoern A. Zeeb 		if (!dev->has_eht)
127*b1bebaabSBjoern A. Zeeb 			ch->flags |= IEEE80211_CHAN_NO_EHT;
128*b1bebaabSBjoern A. Zeeb 	}
129*b1bebaabSBjoern A. Zeeb }
130*b1bebaabSBjoern A. Zeeb 
mt7925_mcu_regd_update(struct mt792x_dev * dev,u8 * alpha2,enum environment_cap country_ie_env)131*b1bebaabSBjoern A. Zeeb int mt7925_mcu_regd_update(struct mt792x_dev *dev, u8 *alpha2,
132*b1bebaabSBjoern A. Zeeb 			   enum environment_cap country_ie_env)
133*b1bebaabSBjoern A. Zeeb {
134*b1bebaabSBjoern A. Zeeb 	struct ieee80211_hw *hw = mt76_hw(dev);
135*b1bebaabSBjoern A. Zeeb 	struct wiphy *wiphy = hw->wiphy;
136*b1bebaabSBjoern A. Zeeb 	int ret = 0;
137*b1bebaabSBjoern A. Zeeb 
138*b1bebaabSBjoern A. Zeeb 	dev->regd_in_progress = true;
139*b1bebaabSBjoern A. Zeeb 
140*b1bebaabSBjoern A. Zeeb 	mt792x_mutex_acquire(dev);
141*b1bebaabSBjoern A. Zeeb 	if (!dev->regd_change)
142*b1bebaabSBjoern A. Zeeb 		goto err;
143*b1bebaabSBjoern A. Zeeb 
144*b1bebaabSBjoern A. Zeeb 	ret = mt7925_mcu_set_clc(dev, alpha2, country_ie_env);
145*b1bebaabSBjoern A. Zeeb 	if (ret < 0)
146*b1bebaabSBjoern A. Zeeb 		goto err;
147*b1bebaabSBjoern A. Zeeb 
148*b1bebaabSBjoern A. Zeeb 	mt7925_regd_be_ctrl(dev, alpha2);
149*b1bebaabSBjoern A. Zeeb 	mt7925_regd_channel_update(wiphy, dev);
150*b1bebaabSBjoern A. Zeeb 
151*b1bebaabSBjoern A. Zeeb 	ret = mt7925_mcu_set_channel_domain(hw->priv);
152*b1bebaabSBjoern A. Zeeb 	if (ret < 0)
153*b1bebaabSBjoern A. Zeeb 		goto err;
154*b1bebaabSBjoern A. Zeeb 
155*b1bebaabSBjoern A. Zeeb 	ret = mt7925_set_tx_sar_pwr(hw, NULL);
156*b1bebaabSBjoern A. Zeeb 	if (ret < 0)
157*b1bebaabSBjoern A. Zeeb 		goto err;
158*b1bebaabSBjoern A. Zeeb 
159*b1bebaabSBjoern A. Zeeb err:
160*b1bebaabSBjoern A. Zeeb 	mt792x_mutex_release(dev);
161*b1bebaabSBjoern A. Zeeb 	dev->regd_change = false;
162*b1bebaabSBjoern A. Zeeb 	dev->regd_in_progress = false;
163*b1bebaabSBjoern A. Zeeb 	wake_up(&dev->wait);
164*b1bebaabSBjoern A. Zeeb 
165*b1bebaabSBjoern A. Zeeb 	return ret;
166*b1bebaabSBjoern A. Zeeb }
167*b1bebaabSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt7925_mcu_regd_update);
168*b1bebaabSBjoern A. Zeeb 
mt7925_regd_notifier(struct wiphy * wiphy,struct regulatory_request * req)169*b1bebaabSBjoern A. Zeeb void mt7925_regd_notifier(struct wiphy *wiphy, struct regulatory_request *req)
170*b1bebaabSBjoern A. Zeeb {
171*b1bebaabSBjoern A. Zeeb 	struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
172*b1bebaabSBjoern A. Zeeb 	struct mt792x_dev *dev = mt792x_hw_dev(hw);
173*b1bebaabSBjoern A. Zeeb 	struct mt76_connac_pm *pm = &dev->pm;
174*b1bebaabSBjoern A. Zeeb 	struct mt76_dev *mdev = &dev->mt76;
175*b1bebaabSBjoern A. Zeeb 
176*b1bebaabSBjoern A. Zeeb 	if (req->initiator == NL80211_REGDOM_SET_BY_USER &&
177*b1bebaabSBjoern A. Zeeb 	    !dev->regd_user)
178*b1bebaabSBjoern A. Zeeb 		dev->regd_user = true;
179*b1bebaabSBjoern A. Zeeb 
180*b1bebaabSBjoern A. Zeeb 	/* allow world regdom at the first boot only */
181*b1bebaabSBjoern A. Zeeb 	if (!memcmp(req->alpha2, "00", 2) &&
182*b1bebaabSBjoern A. Zeeb 	    mdev->alpha2[0] && mdev->alpha2[1])
183*b1bebaabSBjoern A. Zeeb 		return;
184*b1bebaabSBjoern A. Zeeb 
185*b1bebaabSBjoern A. Zeeb 	/* do not need to update the same country twice */
186*b1bebaabSBjoern A. Zeeb 	if (!memcmp(req->alpha2, mdev->alpha2, 2) &&
187*b1bebaabSBjoern A. Zeeb 	    dev->country_ie_env == req->country_ie_env)
188*b1bebaabSBjoern A. Zeeb 		return;
189*b1bebaabSBjoern A. Zeeb 
190*b1bebaabSBjoern A. Zeeb 	memcpy(mdev->alpha2, req->alpha2, 2);
191*b1bebaabSBjoern A. Zeeb 	mdev->region = req->dfs_region;
192*b1bebaabSBjoern A. Zeeb 	dev->country_ie_env = req->country_ie_env;
193*b1bebaabSBjoern A. Zeeb 
194*b1bebaabSBjoern A. Zeeb 	dev->regd_change = true;
195*b1bebaabSBjoern A. Zeeb 
196*b1bebaabSBjoern A. Zeeb 	if (pm->suspended)
197*b1bebaabSBjoern A. Zeeb 		/* postpone the mcu update to resume */
198*b1bebaabSBjoern A. Zeeb 		return;
199*b1bebaabSBjoern A. Zeeb 
200*b1bebaabSBjoern A. Zeeb 	mt7925_mcu_regd_update(dev, req->alpha2,
201*b1bebaabSBjoern A. Zeeb 			       req->country_ie_env);
202*b1bebaabSBjoern A. Zeeb 	return;
203*b1bebaabSBjoern A. Zeeb }
204*b1bebaabSBjoern A. Zeeb 
205*b1bebaabSBjoern A. Zeeb static bool
mt7925_regd_is_valid_alpha2(const char * alpha2)206*b1bebaabSBjoern A. Zeeb mt7925_regd_is_valid_alpha2(const char *alpha2)
207*b1bebaabSBjoern A. Zeeb {
208*b1bebaabSBjoern A. Zeeb 	if (!alpha2)
209*b1bebaabSBjoern A. Zeeb 		return false;
210*b1bebaabSBjoern A. Zeeb 
211*b1bebaabSBjoern A. Zeeb 	if (alpha2[0] == '0' && alpha2[1] == '0')
212*b1bebaabSBjoern A. Zeeb 		return true;
213*b1bebaabSBjoern A. Zeeb 
214*b1bebaabSBjoern A. Zeeb 	if (isalpha(alpha2[0]) && isalpha(alpha2[1]))
215*b1bebaabSBjoern A. Zeeb 		return true;
216*b1bebaabSBjoern A. Zeeb 
217*b1bebaabSBjoern A. Zeeb 	return false;
218*b1bebaabSBjoern A. Zeeb }
219*b1bebaabSBjoern A. Zeeb 
mt7925_regd_change(struct mt792x_phy * phy,char * alpha2)220*b1bebaabSBjoern A. Zeeb int mt7925_regd_change(struct mt792x_phy *phy, char *alpha2)
221*b1bebaabSBjoern A. Zeeb {
222*b1bebaabSBjoern A. Zeeb 	struct wiphy *wiphy = phy->mt76->hw->wiphy;
223*b1bebaabSBjoern A. Zeeb 	struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
224*b1bebaabSBjoern A. Zeeb 	struct mt792x_dev *dev = mt792x_hw_dev(hw);
225*b1bebaabSBjoern A. Zeeb 	struct mt76_dev *mdev = &dev->mt76;
226*b1bebaabSBjoern A. Zeeb 
227*b1bebaabSBjoern A. Zeeb 	if (dev->hw_full_reset)
228*b1bebaabSBjoern A. Zeeb 		return 0;
229*b1bebaabSBjoern A. Zeeb 
230*b1bebaabSBjoern A. Zeeb 	if (!mt7925_regd_is_valid_alpha2(alpha2) ||
231*b1bebaabSBjoern A. Zeeb 	    !mt7925_regd_clc_supported(dev) ||
232*b1bebaabSBjoern A. Zeeb 	    dev->regd_user)
233*b1bebaabSBjoern A. Zeeb 		return -EINVAL;
234*b1bebaabSBjoern A. Zeeb 
235*b1bebaabSBjoern A. Zeeb 	if (mdev->alpha2[0] != '0' && mdev->alpha2[1] != '0')
236*b1bebaabSBjoern A. Zeeb 		return 0;
237*b1bebaabSBjoern A. Zeeb 
238*b1bebaabSBjoern A. Zeeb 	/* do not need to update the same country twice */
239*b1bebaabSBjoern A. Zeeb 	if (!memcmp(alpha2, mdev->alpha2, 2))
240*b1bebaabSBjoern A. Zeeb 		return 0;
241*b1bebaabSBjoern A. Zeeb 
242*b1bebaabSBjoern A. Zeeb 	if (phy->chip_cap & MT792x_CHIP_CAP_11D_EN) {
243*b1bebaabSBjoern A. Zeeb 		return regulatory_hint(wiphy, alpha2);
244*b1bebaabSBjoern A. Zeeb 	} else {
245*b1bebaabSBjoern A. Zeeb 		return mt7925_mcu_set_clc(dev, alpha2, ENVIRON_INDOOR);
246*b1bebaabSBjoern A. Zeeb 	}
247*b1bebaabSBjoern A. Zeeb }
248*b1bebaabSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt7925_regd_change);
249*b1bebaabSBjoern A. Zeeb 
mt7925_regd_init(struct mt792x_phy * phy)250*b1bebaabSBjoern A. Zeeb int mt7925_regd_init(struct mt792x_phy *phy)
251*b1bebaabSBjoern A. Zeeb {
252*b1bebaabSBjoern A. Zeeb 	struct wiphy *wiphy = phy->mt76->hw->wiphy;
253*b1bebaabSBjoern A. Zeeb 	struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
254*b1bebaabSBjoern A. Zeeb 	struct mt792x_dev *dev = mt792x_hw_dev(hw);
255*b1bebaabSBjoern A. Zeeb 	struct mt76_dev *mdev = &dev->mt76;
256*b1bebaabSBjoern A. Zeeb 
257*b1bebaabSBjoern A. Zeeb 	if (phy->chip_cap & MT792x_CHIP_CAP_11D_EN) {
258*b1bebaabSBjoern A. Zeeb 		wiphy->regulatory_flags |= REGULATORY_COUNTRY_IE_IGNORE |
259*b1bebaabSBjoern A. Zeeb 					   REGULATORY_DISABLE_BEACON_HINTS;
260*b1bebaabSBjoern A. Zeeb 	} else {
261*b1bebaabSBjoern A. Zeeb 		memzero_explicit(&mdev->alpha2, sizeof(mdev->alpha2));
262*b1bebaabSBjoern A. Zeeb 	}
263*b1bebaabSBjoern A. Zeeb 
264*b1bebaabSBjoern A. Zeeb 	return 0;
265*b1bebaabSBjoern A. Zeeb }
266