xref: /OK3568_Linux_fs/kernel/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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