1*4882a593Smuzhiyun // SPDX-License-Identifier: ISC
2*4882a593Smuzhiyun /* Copyright (C) 2020 MediaTek Inc. */
3*4882a593Smuzhiyun
4*4882a593Smuzhiyun #include "mt7915.h"
5*4882a593Smuzhiyun #include "eeprom.h"
6*4882a593Smuzhiyun
mt7915_efuse_valid(u8 val)7*4882a593Smuzhiyun static inline bool mt7915_efuse_valid(u8 val)
8*4882a593Smuzhiyun {
9*4882a593Smuzhiyun return !(val == 0xff);
10*4882a593Smuzhiyun }
11*4882a593Smuzhiyun
mt7915_eeprom_read(struct mt7915_dev * dev,u32 offset)12*4882a593Smuzhiyun u32 mt7915_eeprom_read(struct mt7915_dev *dev, u32 offset)
13*4882a593Smuzhiyun {
14*4882a593Smuzhiyun u8 *data = dev->mt76.eeprom.data;
15*4882a593Smuzhiyun
16*4882a593Smuzhiyun if (!mt7915_efuse_valid(data[offset]))
17*4882a593Smuzhiyun mt7915_mcu_get_eeprom(dev, offset);
18*4882a593Smuzhiyun
19*4882a593Smuzhiyun return data[offset];
20*4882a593Smuzhiyun }
21*4882a593Smuzhiyun
mt7915_eeprom_load(struct mt7915_dev * dev)22*4882a593Smuzhiyun static int mt7915_eeprom_load(struct mt7915_dev *dev)
23*4882a593Smuzhiyun {
24*4882a593Smuzhiyun int ret;
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun ret = mt76_eeprom_init(&dev->mt76, MT7915_EEPROM_SIZE);
27*4882a593Smuzhiyun if (ret < 0)
28*4882a593Smuzhiyun return ret;
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun memset(dev->mt76.eeprom.data, -1, MT7915_EEPROM_SIZE);
31*4882a593Smuzhiyun
32*4882a593Smuzhiyun return 0;
33*4882a593Smuzhiyun }
34*4882a593Smuzhiyun
mt7915_check_eeprom(struct mt7915_dev * dev)35*4882a593Smuzhiyun static int mt7915_check_eeprom(struct mt7915_dev *dev)
36*4882a593Smuzhiyun {
37*4882a593Smuzhiyun u16 val;
38*4882a593Smuzhiyun u8 *eeprom = dev->mt76.eeprom.data;
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun mt7915_eeprom_read(dev, 0);
41*4882a593Smuzhiyun val = get_unaligned_le16(eeprom);
42*4882a593Smuzhiyun
43*4882a593Smuzhiyun switch (val) {
44*4882a593Smuzhiyun case 0x7915:
45*4882a593Smuzhiyun return 0;
46*4882a593Smuzhiyun default:
47*4882a593Smuzhiyun return -EINVAL;
48*4882a593Smuzhiyun }
49*4882a593Smuzhiyun }
50*4882a593Smuzhiyun
mt7915_eeprom_parse_hw_cap(struct mt7915_dev * dev)51*4882a593Smuzhiyun static void mt7915_eeprom_parse_hw_cap(struct mt7915_dev *dev)
52*4882a593Smuzhiyun {
53*4882a593Smuzhiyun u8 *eeprom = dev->mt76.eeprom.data;
54*4882a593Smuzhiyun u8 tx_mask, max_nss = 4;
55*4882a593Smuzhiyun u32 val = mt7915_eeprom_read(dev, MT_EE_WIFI_CONF);
56*4882a593Smuzhiyun
57*4882a593Smuzhiyun val = FIELD_GET(MT_EE_WIFI_CONF_BAND_SEL, val);
58*4882a593Smuzhiyun switch (val) {
59*4882a593Smuzhiyun case MT_EE_5GHZ:
60*4882a593Smuzhiyun dev->mt76.cap.has_5ghz = true;
61*4882a593Smuzhiyun break;
62*4882a593Smuzhiyun case MT_EE_2GHZ:
63*4882a593Smuzhiyun dev->mt76.cap.has_2ghz = true;
64*4882a593Smuzhiyun break;
65*4882a593Smuzhiyun default:
66*4882a593Smuzhiyun dev->mt76.cap.has_2ghz = true;
67*4882a593Smuzhiyun dev->mt76.cap.has_5ghz = true;
68*4882a593Smuzhiyun break;
69*4882a593Smuzhiyun }
70*4882a593Smuzhiyun
71*4882a593Smuzhiyun /* read tx mask from eeprom */
72*4882a593Smuzhiyun tx_mask = FIELD_GET(MT_EE_WIFI_CONF_TX_MASK,
73*4882a593Smuzhiyun eeprom[MT_EE_WIFI_CONF]);
74*4882a593Smuzhiyun if (!tx_mask || tx_mask > max_nss)
75*4882a593Smuzhiyun tx_mask = max_nss;
76*4882a593Smuzhiyun
77*4882a593Smuzhiyun dev->chainmask = BIT(tx_mask) - 1;
78*4882a593Smuzhiyun dev->mphy.antenna_mask = dev->chainmask;
79*4882a593Smuzhiyun dev->phy.chainmask = dev->chainmask;
80*4882a593Smuzhiyun }
81*4882a593Smuzhiyun
mt7915_eeprom_init(struct mt7915_dev * dev)82*4882a593Smuzhiyun int mt7915_eeprom_init(struct mt7915_dev *dev)
83*4882a593Smuzhiyun {
84*4882a593Smuzhiyun int ret;
85*4882a593Smuzhiyun
86*4882a593Smuzhiyun ret = mt7915_eeprom_load(dev);
87*4882a593Smuzhiyun if (ret < 0)
88*4882a593Smuzhiyun return ret;
89*4882a593Smuzhiyun
90*4882a593Smuzhiyun ret = mt7915_check_eeprom(dev);
91*4882a593Smuzhiyun if (ret)
92*4882a593Smuzhiyun return ret;
93*4882a593Smuzhiyun
94*4882a593Smuzhiyun mt7915_eeprom_parse_hw_cap(dev);
95*4882a593Smuzhiyun memcpy(dev->mt76.macaddr, dev->mt76.eeprom.data + MT_EE_MAC_ADDR,
96*4882a593Smuzhiyun ETH_ALEN);
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun mt76_eeprom_override(&dev->mt76);
99*4882a593Smuzhiyun
100*4882a593Smuzhiyun return 0;
101*4882a593Smuzhiyun }
102*4882a593Smuzhiyun
mt7915_eeprom_get_target_power(struct mt7915_dev * dev,struct ieee80211_channel * chan,u8 chain_idx)103*4882a593Smuzhiyun int mt7915_eeprom_get_target_power(struct mt7915_dev *dev,
104*4882a593Smuzhiyun struct ieee80211_channel *chan,
105*4882a593Smuzhiyun u8 chain_idx)
106*4882a593Smuzhiyun {
107*4882a593Smuzhiyun int index, target_power;
108*4882a593Smuzhiyun bool tssi_on;
109*4882a593Smuzhiyun
110*4882a593Smuzhiyun if (chain_idx > 3)
111*4882a593Smuzhiyun return -EINVAL;
112*4882a593Smuzhiyun
113*4882a593Smuzhiyun tssi_on = mt7915_tssi_enabled(dev, chan->band);
114*4882a593Smuzhiyun
115*4882a593Smuzhiyun if (chan->band == NL80211_BAND_2GHZ) {
116*4882a593Smuzhiyun index = MT_EE_TX0_POWER_2G + chain_idx * 3;
117*4882a593Smuzhiyun target_power = mt7915_eeprom_read(dev, index);
118*4882a593Smuzhiyun
119*4882a593Smuzhiyun if (!tssi_on)
120*4882a593Smuzhiyun target_power += mt7915_eeprom_read(dev, index + 1);
121*4882a593Smuzhiyun } else {
122*4882a593Smuzhiyun int group = mt7915_get_channel_group(chan->hw_value);
123*4882a593Smuzhiyun
124*4882a593Smuzhiyun index = MT_EE_TX0_POWER_5G + chain_idx * 12;
125*4882a593Smuzhiyun target_power = mt7915_eeprom_read(dev, index + group);
126*4882a593Smuzhiyun
127*4882a593Smuzhiyun if (!tssi_on)
128*4882a593Smuzhiyun target_power += mt7915_eeprom_read(dev, index + 8);
129*4882a593Smuzhiyun }
130*4882a593Smuzhiyun
131*4882a593Smuzhiyun return target_power;
132*4882a593Smuzhiyun }
133*4882a593Smuzhiyun
134*4882a593Smuzhiyun static const u8 sku_cck_delta_map[] = {
135*4882a593Smuzhiyun SKU_CCK_GROUP0,
136*4882a593Smuzhiyun SKU_CCK_GROUP0,
137*4882a593Smuzhiyun SKU_CCK_GROUP1,
138*4882a593Smuzhiyun SKU_CCK_GROUP1,
139*4882a593Smuzhiyun };
140*4882a593Smuzhiyun
141*4882a593Smuzhiyun static const u8 sku_ofdm_delta_map[] = {
142*4882a593Smuzhiyun SKU_OFDM_GROUP0,
143*4882a593Smuzhiyun SKU_OFDM_GROUP0,
144*4882a593Smuzhiyun SKU_OFDM_GROUP1,
145*4882a593Smuzhiyun SKU_OFDM_GROUP1,
146*4882a593Smuzhiyun SKU_OFDM_GROUP2,
147*4882a593Smuzhiyun SKU_OFDM_GROUP2,
148*4882a593Smuzhiyun SKU_OFDM_GROUP3,
149*4882a593Smuzhiyun SKU_OFDM_GROUP4,
150*4882a593Smuzhiyun };
151*4882a593Smuzhiyun
152*4882a593Smuzhiyun static const u8 sku_mcs_delta_map[] = {
153*4882a593Smuzhiyun SKU_MCS_GROUP0,
154*4882a593Smuzhiyun SKU_MCS_GROUP1,
155*4882a593Smuzhiyun SKU_MCS_GROUP1,
156*4882a593Smuzhiyun SKU_MCS_GROUP2,
157*4882a593Smuzhiyun SKU_MCS_GROUP2,
158*4882a593Smuzhiyun SKU_MCS_GROUP3,
159*4882a593Smuzhiyun SKU_MCS_GROUP4,
160*4882a593Smuzhiyun SKU_MCS_GROUP5,
161*4882a593Smuzhiyun SKU_MCS_GROUP6,
162*4882a593Smuzhiyun SKU_MCS_GROUP7,
163*4882a593Smuzhiyun SKU_MCS_GROUP8,
164*4882a593Smuzhiyun SKU_MCS_GROUP9,
165*4882a593Smuzhiyun };
166*4882a593Smuzhiyun
167*4882a593Smuzhiyun #define SKU_GROUP(_mode, _len, _ofs_2g, _ofs_5g, _map) \
168*4882a593Smuzhiyun [_mode] = { \
169*4882a593Smuzhiyun .len = _len, \
170*4882a593Smuzhiyun .offset = { \
171*4882a593Smuzhiyun _ofs_2g, \
172*4882a593Smuzhiyun _ofs_5g, \
173*4882a593Smuzhiyun }, \
174*4882a593Smuzhiyun .delta_map = _map \
175*4882a593Smuzhiyun }
176*4882a593Smuzhiyun
177*4882a593Smuzhiyun const struct sku_group mt7915_sku_groups[] = {
178*4882a593Smuzhiyun SKU_GROUP(SKU_CCK, 4, 0x252, 0, sku_cck_delta_map),
179*4882a593Smuzhiyun SKU_GROUP(SKU_OFDM, 8, 0x254, 0x29d, sku_ofdm_delta_map),
180*4882a593Smuzhiyun
181*4882a593Smuzhiyun SKU_GROUP(SKU_HT_BW20, 8, 0x259, 0x2a2, sku_mcs_delta_map),
182*4882a593Smuzhiyun SKU_GROUP(SKU_HT_BW40, 9, 0x262, 0x2ab, sku_mcs_delta_map),
183*4882a593Smuzhiyun SKU_GROUP(SKU_VHT_BW20, 12, 0x259, 0x2a2, sku_mcs_delta_map),
184*4882a593Smuzhiyun SKU_GROUP(SKU_VHT_BW40, 12, 0x262, 0x2ab, sku_mcs_delta_map),
185*4882a593Smuzhiyun SKU_GROUP(SKU_VHT_BW80, 12, 0, 0x2b4, sku_mcs_delta_map),
186*4882a593Smuzhiyun SKU_GROUP(SKU_VHT_BW160, 12, 0, 0, sku_mcs_delta_map),
187*4882a593Smuzhiyun
188*4882a593Smuzhiyun SKU_GROUP(SKU_HE_RU26, 12, 0x27f, 0x2dd, sku_mcs_delta_map),
189*4882a593Smuzhiyun SKU_GROUP(SKU_HE_RU52, 12, 0x289, 0x2e7, sku_mcs_delta_map),
190*4882a593Smuzhiyun SKU_GROUP(SKU_HE_RU106, 12, 0x293, 0x2f1, sku_mcs_delta_map),
191*4882a593Smuzhiyun SKU_GROUP(SKU_HE_RU242, 12, 0x26b, 0x2bf, sku_mcs_delta_map),
192*4882a593Smuzhiyun SKU_GROUP(SKU_HE_RU484, 12, 0x275, 0x2c9, sku_mcs_delta_map),
193*4882a593Smuzhiyun SKU_GROUP(SKU_HE_RU996, 12, 0, 0x2d3, sku_mcs_delta_map),
194*4882a593Smuzhiyun SKU_GROUP(SKU_HE_RU2x996, 12, 0, 0, sku_mcs_delta_map),
195*4882a593Smuzhiyun };
196*4882a593Smuzhiyun
197*4882a593Smuzhiyun static s8
mt7915_get_sku_delta(struct mt7915_dev * dev,u32 addr)198*4882a593Smuzhiyun mt7915_get_sku_delta(struct mt7915_dev *dev, u32 addr)
199*4882a593Smuzhiyun {
200*4882a593Smuzhiyun u32 val = mt7915_eeprom_read(dev, addr);
201*4882a593Smuzhiyun s8 delta = FIELD_GET(SKU_DELTA_VAL, val);
202*4882a593Smuzhiyun
203*4882a593Smuzhiyun if (!(val & SKU_DELTA_EN))
204*4882a593Smuzhiyun return 0;
205*4882a593Smuzhiyun
206*4882a593Smuzhiyun return val & SKU_DELTA_ADD ? delta : -delta;
207*4882a593Smuzhiyun }
208*4882a593Smuzhiyun
209*4882a593Smuzhiyun static void
mt7915_eeprom_init_sku_band(struct mt7915_dev * dev,struct ieee80211_supported_band * sband)210*4882a593Smuzhiyun mt7915_eeprom_init_sku_band(struct mt7915_dev *dev,
211*4882a593Smuzhiyun struct ieee80211_supported_band *sband)
212*4882a593Smuzhiyun {
213*4882a593Smuzhiyun int i, band = sband->band;
214*4882a593Smuzhiyun s8 *rate_power = dev->rate_power[band], max_delta = 0;
215*4882a593Smuzhiyun u8 idx = 0;
216*4882a593Smuzhiyun
217*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(mt7915_sku_groups); i++) {
218*4882a593Smuzhiyun const struct sku_group *sku = &mt7915_sku_groups[i];
219*4882a593Smuzhiyun u32 offset = sku->offset[band];
220*4882a593Smuzhiyun int j;
221*4882a593Smuzhiyun
222*4882a593Smuzhiyun if (!offset) {
223*4882a593Smuzhiyun idx += sku->len;
224*4882a593Smuzhiyun continue;
225*4882a593Smuzhiyun }
226*4882a593Smuzhiyun
227*4882a593Smuzhiyun rate_power[idx++] = mt7915_get_sku_delta(dev, offset);
228*4882a593Smuzhiyun if (rate_power[idx - 1] > max_delta)
229*4882a593Smuzhiyun max_delta = rate_power[idx - 1];
230*4882a593Smuzhiyun
231*4882a593Smuzhiyun if (i == SKU_HT_BW20 || i == SKU_VHT_BW20)
232*4882a593Smuzhiyun offset += 1;
233*4882a593Smuzhiyun
234*4882a593Smuzhiyun for (j = 1; j < sku->len; j++) {
235*4882a593Smuzhiyun u32 addr = offset + sku->delta_map[j];
236*4882a593Smuzhiyun
237*4882a593Smuzhiyun rate_power[idx++] = mt7915_get_sku_delta(dev, addr);
238*4882a593Smuzhiyun if (rate_power[idx - 1] > max_delta)
239*4882a593Smuzhiyun max_delta = rate_power[idx - 1];
240*4882a593Smuzhiyun }
241*4882a593Smuzhiyun }
242*4882a593Smuzhiyun
243*4882a593Smuzhiyun rate_power[idx] = max_delta;
244*4882a593Smuzhiyun }
245*4882a593Smuzhiyun
mt7915_eeprom_init_sku(struct mt7915_dev * dev)246*4882a593Smuzhiyun void mt7915_eeprom_init_sku(struct mt7915_dev *dev)
247*4882a593Smuzhiyun {
248*4882a593Smuzhiyun mt7915_eeprom_init_sku_band(dev, &dev->mphy.sband_2g.sband);
249*4882a593Smuzhiyun mt7915_eeprom_init_sku_band(dev, &dev->mphy.sband_5g.sband);
250*4882a593Smuzhiyun }
251