162306a36Sopenharmony_ci// SPDX-License-Identifier: ISC
262306a36Sopenharmony_ci
362306a36Sopenharmony_ci#include <linux/of.h>
462306a36Sopenharmony_ci#include "mt7603.h"
562306a36Sopenharmony_ci#include "eeprom.h"
662306a36Sopenharmony_ci
762306a36Sopenharmony_cistatic int
862306a36Sopenharmony_cimt7603_efuse_read(struct mt7603_dev *dev, u32 base, u16 addr, u8 *data)
962306a36Sopenharmony_ci{
1062306a36Sopenharmony_ci	u32 val;
1162306a36Sopenharmony_ci	int i;
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci	val = mt76_rr(dev, base + MT_EFUSE_CTRL);
1462306a36Sopenharmony_ci	val &= ~(MT_EFUSE_CTRL_AIN |
1562306a36Sopenharmony_ci		 MT_EFUSE_CTRL_MODE);
1662306a36Sopenharmony_ci	val |= FIELD_PREP(MT_EFUSE_CTRL_AIN, addr & ~0xf);
1762306a36Sopenharmony_ci	val |= MT_EFUSE_CTRL_KICK;
1862306a36Sopenharmony_ci	mt76_wr(dev, base + MT_EFUSE_CTRL, val);
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci	if (!mt76_poll(dev, base + MT_EFUSE_CTRL, MT_EFUSE_CTRL_KICK, 0, 1000))
2162306a36Sopenharmony_ci		return -ETIMEDOUT;
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci	udelay(2);
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci	val = mt76_rr(dev, base + MT_EFUSE_CTRL);
2662306a36Sopenharmony_ci	if ((val & MT_EFUSE_CTRL_AOUT) == MT_EFUSE_CTRL_AOUT ||
2762306a36Sopenharmony_ci	    WARN_ON_ONCE(!(val & MT_EFUSE_CTRL_VALID))) {
2862306a36Sopenharmony_ci		memset(data, 0xff, 16);
2962306a36Sopenharmony_ci		return 0;
3062306a36Sopenharmony_ci	}
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci	for (i = 0; i < 4; i++) {
3362306a36Sopenharmony_ci		val = mt76_rr(dev, base + MT_EFUSE_RDATA(i));
3462306a36Sopenharmony_ci		put_unaligned_le32(val, data + 4 * i);
3562306a36Sopenharmony_ci	}
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci	return 0;
3862306a36Sopenharmony_ci}
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_cistatic int
4162306a36Sopenharmony_cimt7603_efuse_init(struct mt7603_dev *dev)
4262306a36Sopenharmony_ci{
4362306a36Sopenharmony_ci	u32 base = mt7603_reg_map(dev, MT_EFUSE_BASE);
4462306a36Sopenharmony_ci	int len = MT7603_EEPROM_SIZE;
4562306a36Sopenharmony_ci	void *buf;
4662306a36Sopenharmony_ci	int ret, i;
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci	if (mt76_rr(dev, base + MT_EFUSE_BASE_CTRL) & MT_EFUSE_BASE_CTRL_EMPTY)
4962306a36Sopenharmony_ci		return 0;
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci	dev->mt76.otp.data = devm_kzalloc(dev->mt76.dev, len, GFP_KERNEL);
5262306a36Sopenharmony_ci	dev->mt76.otp.size = len;
5362306a36Sopenharmony_ci	if (!dev->mt76.otp.data)
5462306a36Sopenharmony_ci		return -ENOMEM;
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	buf = dev->mt76.otp.data;
5762306a36Sopenharmony_ci	for (i = 0; i + 16 <= len; i += 16) {
5862306a36Sopenharmony_ci		ret = mt7603_efuse_read(dev, base, i, buf + i);
5962306a36Sopenharmony_ci		if (ret)
6062306a36Sopenharmony_ci			return ret;
6162306a36Sopenharmony_ci	}
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	return 0;
6462306a36Sopenharmony_ci}
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_cistatic bool
6762306a36Sopenharmony_cimt7603_has_cal_free_data(struct mt7603_dev *dev, u8 *efuse)
6862306a36Sopenharmony_ci{
6962306a36Sopenharmony_ci	if (!efuse[MT_EE_TEMP_SENSOR_CAL])
7062306a36Sopenharmony_ci		return false;
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	if (get_unaligned_le16(efuse + MT_EE_TX_POWER_0_START_2G) == 0)
7362306a36Sopenharmony_ci		return false;
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	if (get_unaligned_le16(efuse + MT_EE_TX_POWER_1_START_2G) == 0)
7662306a36Sopenharmony_ci		return false;
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	if (!efuse[MT_EE_CP_FT_VERSION])
7962306a36Sopenharmony_ci		return false;
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	if (!efuse[MT_EE_XTAL_FREQ_OFFSET])
8262306a36Sopenharmony_ci		return false;
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	if (!efuse[MT_EE_XTAL_WF_RFCAL])
8562306a36Sopenharmony_ci		return false;
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	return true;
8862306a36Sopenharmony_ci}
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_cistatic void
9162306a36Sopenharmony_cimt7603_apply_cal_free_data(struct mt7603_dev *dev, u8 *efuse)
9262306a36Sopenharmony_ci{
9362306a36Sopenharmony_ci	static const u8 cal_free_bytes[] = {
9462306a36Sopenharmony_ci		MT_EE_TEMP_SENSOR_CAL,
9562306a36Sopenharmony_ci		MT_EE_CP_FT_VERSION,
9662306a36Sopenharmony_ci		MT_EE_XTAL_FREQ_OFFSET,
9762306a36Sopenharmony_ci		MT_EE_XTAL_WF_RFCAL,
9862306a36Sopenharmony_ci		/* Skip for MT7628 */
9962306a36Sopenharmony_ci		MT_EE_TX_POWER_0_START_2G,
10062306a36Sopenharmony_ci		MT_EE_TX_POWER_0_START_2G + 1,
10162306a36Sopenharmony_ci		MT_EE_TX_POWER_1_START_2G,
10262306a36Sopenharmony_ci		MT_EE_TX_POWER_1_START_2G + 1,
10362306a36Sopenharmony_ci	};
10462306a36Sopenharmony_ci	struct device_node *np = dev->mt76.dev->of_node;
10562306a36Sopenharmony_ci	u8 *eeprom = dev->mt76.eeprom.data;
10662306a36Sopenharmony_ci	int n = ARRAY_SIZE(cal_free_bytes);
10762306a36Sopenharmony_ci	int i;
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	if (!np || !of_property_read_bool(np, "mediatek,eeprom-merge-otp"))
11062306a36Sopenharmony_ci		return;
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	if (!mt7603_has_cal_free_data(dev, efuse))
11362306a36Sopenharmony_ci		return;
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	if (is_mt7628(dev))
11662306a36Sopenharmony_ci		n -= 4;
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	for (i = 0; i < n; i++) {
11962306a36Sopenharmony_ci		int offset = cal_free_bytes[i];
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci		eeprom[offset] = efuse[offset];
12262306a36Sopenharmony_ci	}
12362306a36Sopenharmony_ci}
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_cistatic int
12662306a36Sopenharmony_cimt7603_eeprom_load(struct mt7603_dev *dev)
12762306a36Sopenharmony_ci{
12862306a36Sopenharmony_ci	int ret;
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	ret = mt76_eeprom_init(&dev->mt76, MT7603_EEPROM_SIZE);
13162306a36Sopenharmony_ci	if (ret < 0)
13262306a36Sopenharmony_ci		return ret;
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	return mt7603_efuse_init(dev);
13562306a36Sopenharmony_ci}
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_cistatic int mt7603_check_eeprom(struct mt76_dev *dev)
13862306a36Sopenharmony_ci{
13962306a36Sopenharmony_ci	u16 val = get_unaligned_le16(dev->eeprom.data);
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	switch (val) {
14262306a36Sopenharmony_ci	case 0x7628:
14362306a36Sopenharmony_ci	case 0x7603:
14462306a36Sopenharmony_ci	case 0x7600:
14562306a36Sopenharmony_ci		return 0;
14662306a36Sopenharmony_ci	default:
14762306a36Sopenharmony_ci		return -EINVAL;
14862306a36Sopenharmony_ci	}
14962306a36Sopenharmony_ci}
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_cistatic inline bool is_mt7688(struct mt7603_dev *dev)
15262306a36Sopenharmony_ci{
15362306a36Sopenharmony_ci	return mt76_rr(dev, MT_EFUSE_BASE + 0x64) & BIT(4);
15462306a36Sopenharmony_ci}
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ciint mt7603_eeprom_init(struct mt7603_dev *dev)
15762306a36Sopenharmony_ci{
15862306a36Sopenharmony_ci	u8 *eeprom;
15962306a36Sopenharmony_ci	int ret;
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci	ret = mt7603_eeprom_load(dev);
16262306a36Sopenharmony_ci	if (ret < 0)
16362306a36Sopenharmony_ci		return ret;
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	if (dev->mt76.otp.data) {
16662306a36Sopenharmony_ci		if (mt7603_check_eeprom(&dev->mt76) == 0)
16762306a36Sopenharmony_ci			mt7603_apply_cal_free_data(dev, dev->mt76.otp.data);
16862306a36Sopenharmony_ci		else
16962306a36Sopenharmony_ci			memcpy(dev->mt76.eeprom.data, dev->mt76.otp.data,
17062306a36Sopenharmony_ci			       MT7603_EEPROM_SIZE);
17162306a36Sopenharmony_ci	}
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	eeprom = (u8 *)dev->mt76.eeprom.data;
17462306a36Sopenharmony_ci	dev->mphy.cap.has_2ghz = true;
17562306a36Sopenharmony_ci	memcpy(dev->mphy.macaddr, eeprom + MT_EE_MAC_ADDR, ETH_ALEN);
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	/* Check for 1SS devices */
17862306a36Sopenharmony_ci	dev->mphy.antenna_mask = 3;
17962306a36Sopenharmony_ci	if (FIELD_GET(MT_EE_NIC_CONF_0_RX_PATH, eeprom[MT_EE_NIC_CONF_0]) == 1 ||
18062306a36Sopenharmony_ci	    FIELD_GET(MT_EE_NIC_CONF_0_TX_PATH, eeprom[MT_EE_NIC_CONF_0]) == 1 ||
18162306a36Sopenharmony_ci	    is_mt7688(dev))
18262306a36Sopenharmony_ci		dev->mphy.antenna_mask = 1;
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	mt76_eeprom_override(&dev->mphy);
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	return 0;
18762306a36Sopenharmony_ci}
188