1 // SPDX-License-Identifier: ISC
2 /* Copyright (C) 2019 MediaTek Inc.
3  *
4  * Author: Ryder Lee <ryder.lee@mediatek.com>
5  *         Felix Fietkau <nbd@nbd.name>
6  */
7 
8 #include "mt7615.h"
9 #include "eeprom.h"
10 
11 static int mt7615_efuse_read(struct mt7615_dev *dev, u32 base,
12 			     u16 addr, u8 *data)
13 {
14 	u32 val;
15 	int i;
16 
17 	val = mt76_rr(dev, base + MT_EFUSE_CTRL);
18 	val &= ~(MT_EFUSE_CTRL_AIN | MT_EFUSE_CTRL_MODE);
19 	val |= FIELD_PREP(MT_EFUSE_CTRL_AIN, addr & ~0xf);
20 	val |= MT_EFUSE_CTRL_KICK;
21 	mt76_wr(dev, base + MT_EFUSE_CTRL, val);
22 
23 	if (!mt76_poll(dev, base + MT_EFUSE_CTRL, MT_EFUSE_CTRL_KICK, 0, 1000))
24 		return -ETIMEDOUT;
25 
26 	udelay(2);
27 
28 	val = mt76_rr(dev, base + MT_EFUSE_CTRL);
29 	if ((val & MT_EFUSE_CTRL_AOUT) == MT_EFUSE_CTRL_AOUT ||
30 	    WARN_ON_ONCE(!(val & MT_EFUSE_CTRL_VALID))) {
31 		memset(data, 0x0, 16);
32 		return 0;
33 	}
34 
35 	for (i = 0; i < 4; i++) {
36 		val = mt76_rr(dev, base + MT_EFUSE_RDATA(i));
37 		put_unaligned_le32(val, data + 4 * i);
38 	}
39 
40 	return 0;
41 }
42 
43 static int mt7615_efuse_init(struct mt7615_dev *dev)
44 {
45 	u32 val, base = mt7615_reg_map(dev, MT_EFUSE_BASE);
46 	int i, len = MT7615_EEPROM_SIZE;
47 	void *buf;
48 
49 	val = mt76_rr(dev, base + MT_EFUSE_BASE_CTRL);
50 	if (val & MT_EFUSE_BASE_CTRL_EMPTY)
51 		return 0;
52 
53 	dev->mt76.otp.data = devm_kzalloc(dev->mt76.dev, len, GFP_KERNEL);
54 	dev->mt76.otp.size = len;
55 	if (!dev->mt76.otp.data)
56 		return -ENOMEM;
57 
58 	buf = dev->mt76.otp.data;
59 	for (i = 0; i + 16 <= len; i += 16) {
60 		int ret;
61 
62 		ret = mt7615_efuse_read(dev, base, i, buf + i);
63 		if (ret)
64 			return ret;
65 	}
66 
67 	return 0;
68 }
69 
70 static int mt7615_eeprom_load(struct mt7615_dev *dev)
71 {
72 	int ret;
73 
74 	ret = mt76_eeprom_init(&dev->mt76, MT7615_EEPROM_SIZE);
75 	if (ret < 0)
76 		return ret;
77 
78 	return mt7615_efuse_init(dev);
79 }
80 
81 static int mt7615_check_eeprom(struct mt76_dev *dev)
82 {
83 	u16 val = get_unaligned_le16(dev->eeprom.data);
84 
85 	switch (val) {
86 	case 0x7615:
87 		return 0;
88 	default:
89 		return -EINVAL;
90 	}
91 }
92 
93 static void mt7615_eeprom_parse_hw_cap(struct mt7615_dev *dev)
94 {
95 	u8 val, *eeprom = dev->mt76.eeprom.data;
96 
97 	val = FIELD_GET(MT_EE_NIC_WIFI_CONF_BAND_SEL,
98 			eeprom[MT_EE_WIFI_CONF]);
99 	switch (val) {
100 	case MT_EE_5GHZ:
101 		dev->mt76.cap.has_5ghz = true;
102 		break;
103 	case MT_EE_2GHZ:
104 		dev->mt76.cap.has_2ghz = true;
105 		break;
106 	default:
107 		dev->mt76.cap.has_2ghz = true;
108 		dev->mt76.cap.has_5ghz = true;
109 		break;
110 	}
111 }
112 
113 int mt7615_eeprom_get_power_index(struct mt7615_dev *dev,
114 				  struct ieee80211_channel *chan,
115 				  u8 chain_idx)
116 {
117 	int index;
118 
119 	if (chain_idx > 3)
120 		return -EINVAL;
121 
122 	/* TSSI disabled */
123 	if (mt7615_ext_pa_enabled(dev, chan->band)) {
124 		if (chan->band == NL80211_BAND_2GHZ)
125 			return MT_EE_EXT_PA_2G_TARGET_POWER;
126 		else
127 			return MT_EE_EXT_PA_5G_TARGET_POWER;
128 	}
129 
130 	/* TSSI enabled */
131 	if (chan->band == NL80211_BAND_2GHZ) {
132 		index = MT_EE_TX0_2G_TARGET_POWER + chain_idx * 6;
133 	} else {
134 		int group = mt7615_get_channel_group(chan->hw_value);
135 
136 		switch (chain_idx) {
137 		case 1:
138 			index = MT_EE_TX1_5G_G0_TARGET_POWER;
139 			break;
140 		case 2:
141 			index = MT_EE_TX2_5G_G0_TARGET_POWER;
142 			break;
143 		case 3:
144 			index = MT_EE_TX3_5G_G0_TARGET_POWER;
145 			break;
146 		case 0:
147 		default:
148 			index = MT_EE_TX0_5G_G0_TARGET_POWER;
149 			break;
150 		}
151 		index += 5 * group;
152 	}
153 
154 	return index;
155 }
156 
157 int mt7615_eeprom_init(struct mt7615_dev *dev)
158 {
159 	int ret;
160 
161 	ret = mt7615_eeprom_load(dev);
162 	if (ret < 0)
163 		return ret;
164 
165 	ret = mt7615_check_eeprom(&dev->mt76);
166 	if (ret && dev->mt76.otp.data)
167 		memcpy(dev->mt76.eeprom.data, dev->mt76.otp.data,
168 		       MT7615_EEPROM_SIZE);
169 
170 	mt7615_eeprom_parse_hw_cap(dev);
171 	memcpy(dev->mt76.macaddr, dev->mt76.eeprom.data + MT_EE_MAC_ADDR,
172 	       ETH_ALEN);
173 
174 	mt76_eeprom_override(&dev->mt76);
175 
176 	return 0;
177 }
178