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