mac80211: add support for rtw88_8822bu
[openwrt/staging/hauke.git] / package / kernel / mac80211 / patches / rt2x00 / 997-wifi-rt2x00-limit-MT7620-TX-power-based-on-eeprom-ca.patch
1 From: Shiji Yang <yangshiji66@outlook.com>
2 Date: Sat, 22 Jul 2023 21:56:30 +0800
3 Subject: [PATCH] wifi: rt2x00: limit MT7620 TX power based on eeprom
4 calibration
5
6 In the vendor driver, the current channel power is queried from
7 EEPROM_TXPOWER_BG1 and EEPROM_TXPOWER_BG2. And then the mixed value
8 will be written into the low half-word of the TX_ALC_CFG_0 register.
9 The high half-word of the TX_ALC_CFG_0 is a fixed value 0x2f2f.
10
11 We can't get the accurate TX power. Based on my tests and the new
12 MediaTek mt76 driver source code, the real TX power is approximately
13 equal to channel_power + (max) rate_power. Usually max rate_power is
14 the gain of the OFDM 6M rate, which can be readed from the offset
15 EEPROM_TXPOWER_BYRATE +1.
16
17 Based on these eeprom values, this patch adds basic TX power control
18 for the MT7620 and limits its maximum TX power. This can avoid the
19 link speed decrease caused by chip overheating. rt2800_config_alc()
20 function has also been renamed to rt2800_config_alc_rt6352() because
21 it's only used by RT6352(MT7620).
22
23 Notice:
24 It's still need some work to sync the max channel power to the user
25 interface. This part is missing from the rt2x00 driver structure. If
26 we set the power exceed the calibration value, it won't take effect.
27
28 Signed-off-by: Shiji Yang <yangshiji66@outlook.com>
29 ---
30 .../net/wireless/ralink/rt2x00/rt2800lib.c | 49 +++++++++++++------
31 1 file changed, 34 insertions(+), 15 deletions(-)
32
33 --- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
34 +++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
35 @@ -3891,28 +3891,47 @@ static void rt2800_config_channel_rf7620
36 }
37 }
38
39 -static void rt2800_config_alc(struct rt2x00_dev *rt2x00dev,
40 +static void rt2800_config_alc_rt6352(struct rt2x00_dev *rt2x00dev,
41 struct ieee80211_channel *chan,
42 int power_level) {
43 - u16 eeprom, target_power, max_power;
44 + u16 eeprom, chan_power, rate_power, target_power;
45 + u16 tx_power[2];
46 + s8 *power_group[2];
47 u32 mac_sys_ctrl;
48 - u32 reg;
49 + u32 cnt, reg;
50 u8 bbp;
51
52 - /* hardware unit is 0.5dBm, limited to 23.5dBm */
53 - power_level *= 2;
54 - if (power_level > 0x2f)
55 - power_level = 0x2f;
56 -
57 - max_power = chan->max_power * 2;
58 - if (max_power > 0x2f)
59 - max_power = 0x2f;
60 + /* get per channel power, 2 channels in total, unit is 0.5dBm */
61 + power_level = (power_level - 3) * 2;
62 + /*
63 + * We can't get the accurate TX power. Based on some tests, the real
64 + * TX power is approximately equal to channel_power + (max)rate_power.
65 + * Usually max rate_power is the gain of the OFDM 6M rate. The antenna
66 + * gain and externel PA gain are not included as we are unable to
67 + * obtain these values.
68 + */
69 + rate_power = rt2800_eeprom_read_from_array(rt2x00dev,
70 + EEPROM_TXPOWER_BYRATE, 1) & 0x3f;
71 + power_level -= rate_power;
72 + if (power_level < 1)
73 + power_level = 1;
74 + if (power_level > chan->max_power * 2)
75 + power_level = chan->max_power * 2;
76 +
77 + power_group[0] = rt2800_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_BG1);
78 + power_group[1] = rt2800_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_BG2);
79 + for (cnt = 0; cnt < 2; cnt++) {
80 + chan_power = power_group[cnt][rt2x00dev->rf_channel - 1];
81 + if (chan_power >= 0x20 || chan_power == 0)
82 + chan_power = 0x10;
83 + tx_power[cnt] = power_level < chan_power ? power_level : chan_power;
84 + }
85
86 reg = rt2800_register_read(rt2x00dev, TX_ALC_CFG_0);
87 - rt2x00_set_field32(&reg, TX_ALC_CFG_0_CH_INIT_0, power_level);
88 - rt2x00_set_field32(&reg, TX_ALC_CFG_0_CH_INIT_1, power_level);
89 - rt2x00_set_field32(&reg, TX_ALC_CFG_0_LIMIT_0, max_power);
90 - rt2x00_set_field32(&reg, TX_ALC_CFG_0_LIMIT_1, max_power);
91 + rt2x00_set_field32(&reg, TX_ALC_CFG_0_CH_INIT_0, tx_power[0]);
92 + rt2x00_set_field32(&reg, TX_ALC_CFG_0_CH_INIT_1, tx_power[1]);
93 + rt2x00_set_field32(&reg, TX_ALC_CFG_0_LIMIT_0, 0x2f);
94 + rt2x00_set_field32(&reg, TX_ALC_CFG_0_LIMIT_1, 0x2f);
95
96 eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1);
97 if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_INTERNAL_TX_ALC)) {
98 @@ -5321,7 +5340,7 @@ static void rt2800_config_txpower_rt6352
99 rt2x00_set_field32(&pwreg, TX_PWR_CFG_9B_STBC_MCS7, t);
100 rt2800_register_write(rt2x00dev, TX_PWR_CFG_9, pwreg);
101
102 - rt2800_config_alc(rt2x00dev, chan, power_level);
103 + rt2800_config_alc_rt6352(rt2x00dev, chan, power_level);
104
105 /* TODO: temperature compensation code! */
106 }