xref: /freebsd/sys/contrib/dev/mediatek/mt76/mt7603/eeprom.c (revision 8ba4d145d351db26e07695b8e90697398c5dfec2)
16c92544dSBjoern A. Zeeb // SPDX-License-Identifier: ISC
26c92544dSBjoern A. Zeeb 
36c92544dSBjoern A. Zeeb #include <linux/of.h>
46c92544dSBjoern A. Zeeb #include "mt7603.h"
56c92544dSBjoern A. Zeeb #include "eeprom.h"
66c92544dSBjoern A. Zeeb 
76c92544dSBjoern A. Zeeb static int
mt7603_efuse_read(struct mt7603_dev * dev,u32 base,u16 addr,u8 * data)86c92544dSBjoern A. Zeeb mt7603_efuse_read(struct mt7603_dev *dev, u32 base, u16 addr, u8 *data)
96c92544dSBjoern A. Zeeb {
106c92544dSBjoern A. Zeeb 	u32 val;
116c92544dSBjoern A. Zeeb 	int i;
126c92544dSBjoern A. Zeeb 
136c92544dSBjoern A. Zeeb 	val = mt76_rr(dev, base + MT_EFUSE_CTRL);
146c92544dSBjoern A. Zeeb 	val &= ~(MT_EFUSE_CTRL_AIN |
156c92544dSBjoern A. Zeeb 		 MT_EFUSE_CTRL_MODE);
166c92544dSBjoern A. Zeeb 	val |= FIELD_PREP(MT_EFUSE_CTRL_AIN, addr & ~0xf);
176c92544dSBjoern A. Zeeb 	val |= MT_EFUSE_CTRL_KICK;
186c92544dSBjoern A. Zeeb 	mt76_wr(dev, base + MT_EFUSE_CTRL, val);
196c92544dSBjoern A. Zeeb 
206c92544dSBjoern A. Zeeb 	if (!mt76_poll(dev, base + MT_EFUSE_CTRL, MT_EFUSE_CTRL_KICK, 0, 1000))
216c92544dSBjoern A. Zeeb 		return -ETIMEDOUT;
226c92544dSBjoern A. Zeeb 
236c92544dSBjoern A. Zeeb 	udelay(2);
246c92544dSBjoern A. Zeeb 
256c92544dSBjoern A. Zeeb 	val = mt76_rr(dev, base + MT_EFUSE_CTRL);
266c92544dSBjoern A. Zeeb 	if ((val & MT_EFUSE_CTRL_AOUT) == MT_EFUSE_CTRL_AOUT ||
276c92544dSBjoern A. Zeeb 	    WARN_ON_ONCE(!(val & MT_EFUSE_CTRL_VALID))) {
286c92544dSBjoern A. Zeeb 		memset(data, 0xff, 16);
296c92544dSBjoern A. Zeeb 		return 0;
306c92544dSBjoern A. Zeeb 	}
316c92544dSBjoern A. Zeeb 
326c92544dSBjoern A. Zeeb 	for (i = 0; i < 4; i++) {
336c92544dSBjoern A. Zeeb 		val = mt76_rr(dev, base + MT_EFUSE_RDATA(i));
346c92544dSBjoern A. Zeeb 		put_unaligned_le32(val, data + 4 * i);
356c92544dSBjoern A. Zeeb 	}
366c92544dSBjoern A. Zeeb 
376c92544dSBjoern A. Zeeb 	return 0;
386c92544dSBjoern A. Zeeb }
396c92544dSBjoern A. Zeeb 
406c92544dSBjoern A. Zeeb static int
mt7603_efuse_init(struct mt7603_dev * dev)416c92544dSBjoern A. Zeeb mt7603_efuse_init(struct mt7603_dev *dev)
426c92544dSBjoern A. Zeeb {
436c92544dSBjoern A. Zeeb 	u32 base = mt7603_reg_map(dev, MT_EFUSE_BASE);
446c92544dSBjoern A. Zeeb 	int len = MT7603_EEPROM_SIZE;
456c92544dSBjoern A. Zeeb 	void *buf;
466c92544dSBjoern A. Zeeb 	int ret, i;
476c92544dSBjoern A. Zeeb 
486c92544dSBjoern A. Zeeb 	if (mt76_rr(dev, base + MT_EFUSE_BASE_CTRL) & MT_EFUSE_BASE_CTRL_EMPTY)
496c92544dSBjoern A. Zeeb 		return 0;
506c92544dSBjoern A. Zeeb 
516c92544dSBjoern A. Zeeb 	dev->mt76.otp.data = devm_kzalloc(dev->mt76.dev, len, GFP_KERNEL);
526c92544dSBjoern A. Zeeb 	dev->mt76.otp.size = len;
536c92544dSBjoern A. Zeeb 	if (!dev->mt76.otp.data)
546c92544dSBjoern A. Zeeb 		return -ENOMEM;
556c92544dSBjoern A. Zeeb 
566c92544dSBjoern A. Zeeb 	buf = dev->mt76.otp.data;
576c92544dSBjoern A. Zeeb 	for (i = 0; i + 16 <= len; i += 16) {
586c92544dSBjoern A. Zeeb 		ret = mt7603_efuse_read(dev, base, i, buf + i);
596c92544dSBjoern A. Zeeb 		if (ret)
606c92544dSBjoern A. Zeeb 			return ret;
616c92544dSBjoern A. Zeeb 	}
626c92544dSBjoern A. Zeeb 
636c92544dSBjoern A. Zeeb 	return 0;
646c92544dSBjoern A. Zeeb }
656c92544dSBjoern A. Zeeb 
666c92544dSBjoern A. Zeeb static bool
mt7603_has_cal_free_data(struct mt7603_dev * dev,u8 * efuse)676c92544dSBjoern A. Zeeb mt7603_has_cal_free_data(struct mt7603_dev *dev, u8 *efuse)
686c92544dSBjoern A. Zeeb {
696c92544dSBjoern A. Zeeb 	if (!efuse[MT_EE_TEMP_SENSOR_CAL])
706c92544dSBjoern A. Zeeb 		return false;
716c92544dSBjoern A. Zeeb 
726c92544dSBjoern A. Zeeb 	if (get_unaligned_le16(efuse + MT_EE_TX_POWER_0_START_2G) == 0)
736c92544dSBjoern A. Zeeb 		return false;
746c92544dSBjoern A. Zeeb 
756c92544dSBjoern A. Zeeb 	if (get_unaligned_le16(efuse + MT_EE_TX_POWER_1_START_2G) == 0)
766c92544dSBjoern A. Zeeb 		return false;
776c92544dSBjoern A. Zeeb 
786c92544dSBjoern A. Zeeb 	if (!efuse[MT_EE_CP_FT_VERSION])
796c92544dSBjoern A. Zeeb 		return false;
806c92544dSBjoern A. Zeeb 
816c92544dSBjoern A. Zeeb 	if (!efuse[MT_EE_XTAL_FREQ_OFFSET])
826c92544dSBjoern A. Zeeb 		return false;
836c92544dSBjoern A. Zeeb 
846c92544dSBjoern A. Zeeb 	if (!efuse[MT_EE_XTAL_WF_RFCAL])
856c92544dSBjoern A. Zeeb 		return false;
866c92544dSBjoern A. Zeeb 
876c92544dSBjoern A. Zeeb 	return true;
886c92544dSBjoern A. Zeeb }
896c92544dSBjoern A. Zeeb 
906c92544dSBjoern A. Zeeb static void
mt7603_apply_cal_free_data(struct mt7603_dev * dev,u8 * efuse)916c92544dSBjoern A. Zeeb mt7603_apply_cal_free_data(struct mt7603_dev *dev, u8 *efuse)
926c92544dSBjoern A. Zeeb {
936c92544dSBjoern A. Zeeb 	static const u8 cal_free_bytes[] = {
946c92544dSBjoern A. Zeeb 		MT_EE_TEMP_SENSOR_CAL,
956c92544dSBjoern A. Zeeb 		MT_EE_CP_FT_VERSION,
966c92544dSBjoern A. Zeeb 		MT_EE_XTAL_FREQ_OFFSET,
976c92544dSBjoern A. Zeeb 		MT_EE_XTAL_WF_RFCAL,
986c92544dSBjoern A. Zeeb 		/* Skip for MT7628 */
996c92544dSBjoern A. Zeeb 		MT_EE_TX_POWER_0_START_2G,
1006c92544dSBjoern A. Zeeb 		MT_EE_TX_POWER_0_START_2G + 1,
1016c92544dSBjoern A. Zeeb 		MT_EE_TX_POWER_1_START_2G,
1026c92544dSBjoern A. Zeeb 		MT_EE_TX_POWER_1_START_2G + 1,
1036c92544dSBjoern A. Zeeb 	};
1046c92544dSBjoern A. Zeeb 	struct device_node *np = dev->mt76.dev->of_node;
1056c92544dSBjoern A. Zeeb 	u8 *eeprom = dev->mt76.eeprom.data;
1066c92544dSBjoern A. Zeeb 	int n = ARRAY_SIZE(cal_free_bytes);
1076c92544dSBjoern A. Zeeb 	int i;
1086c92544dSBjoern A. Zeeb 
1096c92544dSBjoern A. Zeeb 	if (!np || !of_property_read_bool(np, "mediatek,eeprom-merge-otp"))
1106c92544dSBjoern A. Zeeb 		return;
1116c92544dSBjoern A. Zeeb 
1126c92544dSBjoern A. Zeeb 	if (!mt7603_has_cal_free_data(dev, efuse))
1136c92544dSBjoern A. Zeeb 		return;
1146c92544dSBjoern A. Zeeb 
1156c92544dSBjoern A. Zeeb 	if (is_mt7628(dev))
1166c92544dSBjoern A. Zeeb 		n -= 4;
1176c92544dSBjoern A. Zeeb 
1186c92544dSBjoern A. Zeeb 	for (i = 0; i < n; i++) {
1196c92544dSBjoern A. Zeeb 		int offset = cal_free_bytes[i];
1206c92544dSBjoern A. Zeeb 
1216c92544dSBjoern A. Zeeb 		eeprom[offset] = efuse[offset];
1226c92544dSBjoern A. Zeeb 	}
1236c92544dSBjoern A. Zeeb }
1246c92544dSBjoern A. Zeeb 
1256c92544dSBjoern A. Zeeb static int
mt7603_eeprom_load(struct mt7603_dev * dev)1266c92544dSBjoern A. Zeeb mt7603_eeprom_load(struct mt7603_dev *dev)
1276c92544dSBjoern A. Zeeb {
1286c92544dSBjoern A. Zeeb 	int ret;
1296c92544dSBjoern A. Zeeb 
1306c92544dSBjoern A. Zeeb 	ret = mt76_eeprom_init(&dev->mt76, MT7603_EEPROM_SIZE);
1316c92544dSBjoern A. Zeeb 	if (ret < 0)
1326c92544dSBjoern A. Zeeb 		return ret;
1336c92544dSBjoern A. Zeeb 
1346c92544dSBjoern A. Zeeb 	return mt7603_efuse_init(dev);
1356c92544dSBjoern A. Zeeb }
1366c92544dSBjoern A. Zeeb 
mt7603_check_eeprom(struct mt76_dev * dev)1376c92544dSBjoern A. Zeeb static int mt7603_check_eeprom(struct mt76_dev *dev)
1386c92544dSBjoern A. Zeeb {
1396c92544dSBjoern A. Zeeb 	u16 val = get_unaligned_le16(dev->eeprom.data);
1406c92544dSBjoern A. Zeeb 
1416c92544dSBjoern A. Zeeb 	switch (val) {
1426c92544dSBjoern A. Zeeb 	case 0x7628:
1436c92544dSBjoern A. Zeeb 	case 0x7603:
1446c92544dSBjoern A. Zeeb 	case 0x7600:
1456c92544dSBjoern A. Zeeb 		return 0;
1466c92544dSBjoern A. Zeeb 	default:
1476c92544dSBjoern A. Zeeb 		return -EINVAL;
1486c92544dSBjoern A. Zeeb 	}
1496c92544dSBjoern A. Zeeb }
1506c92544dSBjoern A. Zeeb 
is_mt7688(struct mt7603_dev * dev)1516c92544dSBjoern A. Zeeb static inline bool is_mt7688(struct mt7603_dev *dev)
1526c92544dSBjoern A. Zeeb {
1536c92544dSBjoern A. Zeeb 	return mt76_rr(dev, MT_EFUSE_BASE + 0x64) & BIT(4);
1546c92544dSBjoern A. Zeeb }
1556c92544dSBjoern A. Zeeb 
mt7603_eeprom_init(struct mt7603_dev * dev)1566c92544dSBjoern A. Zeeb int mt7603_eeprom_init(struct mt7603_dev *dev)
1576c92544dSBjoern A. Zeeb {
1586c92544dSBjoern A. Zeeb 	u8 *eeprom;
1596c92544dSBjoern A. Zeeb 	int ret;
1606c92544dSBjoern A. Zeeb 
1616c92544dSBjoern A. Zeeb 	ret = mt7603_eeprom_load(dev);
1626c92544dSBjoern A. Zeeb 	if (ret < 0)
1636c92544dSBjoern A. Zeeb 		return ret;
1646c92544dSBjoern A. Zeeb 
1656c92544dSBjoern A. Zeeb 	if (dev->mt76.otp.data) {
1666c92544dSBjoern A. Zeeb 		if (mt7603_check_eeprom(&dev->mt76) == 0)
1676c92544dSBjoern A. Zeeb 			mt7603_apply_cal_free_data(dev, dev->mt76.otp.data);
1686c92544dSBjoern A. Zeeb 		else
1696c92544dSBjoern A. Zeeb 			memcpy(dev->mt76.eeprom.data, dev->mt76.otp.data,
1706c92544dSBjoern A. Zeeb 			       MT7603_EEPROM_SIZE);
1716c92544dSBjoern A. Zeeb 	}
1726c92544dSBjoern A. Zeeb 
1736c92544dSBjoern A. Zeeb 	eeprom = (u8 *)dev->mt76.eeprom.data;
1746c92544dSBjoern A. Zeeb 	dev->mphy.cap.has_2ghz = true;
1756c92544dSBjoern A. Zeeb 	memcpy(dev->mphy.macaddr, eeprom + MT_EE_MAC_ADDR, ETH_ALEN);
1766c92544dSBjoern A. Zeeb 
1776c92544dSBjoern A. Zeeb 	/* Check for 1SS devices */
1786c92544dSBjoern A. Zeeb 	dev->mphy.antenna_mask = 3;
1796c92544dSBjoern A. Zeeb 	if (FIELD_GET(MT_EE_NIC_CONF_0_RX_PATH, eeprom[MT_EE_NIC_CONF_0]) == 1 ||
1806c92544dSBjoern A. Zeeb 	    FIELD_GET(MT_EE_NIC_CONF_0_TX_PATH, eeprom[MT_EE_NIC_CONF_0]) == 1 ||
1816c92544dSBjoern A. Zeeb 	    is_mt7688(dev))
1826c92544dSBjoern A. Zeeb 		dev->mphy.antenna_mask = 1;
1836c92544dSBjoern A. Zeeb 
184*8ba4d145SBjoern A. Zeeb 	dev->mphy.chainmask = dev->mphy.antenna_mask;
1856c92544dSBjoern A. Zeeb 	mt76_eeprom_override(&dev->mphy);
1866c92544dSBjoern A. Zeeb 
1876c92544dSBjoern A. Zeeb 	return 0;
1886c92544dSBjoern A. Zeeb }
189