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