linux/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c
<<
>>
Prefs
   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
  11static 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
  43static 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
  70static 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
  81static 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
  93static void mt7615_eeprom_parse_hw_cap(struct mt7615_dev *dev)
  94{
  95        u8 *eeprom = dev->mt76.eeprom.data;
  96        u8 tx_mask, rx_mask, max_nss;
  97        u32 val;
  98
  99        val = FIELD_GET(MT_EE_NIC_WIFI_CONF_BAND_SEL,
 100                        eeprom[MT_EE_WIFI_CONF]);
 101        switch (val) {
 102        case MT_EE_5GHZ:
 103                dev->mt76.cap.has_5ghz = true;
 104                break;
 105        case MT_EE_2GHZ:
 106                dev->mt76.cap.has_2ghz = true;
 107                break;
 108        default:
 109                dev->mt76.cap.has_2ghz = true;
 110                dev->mt76.cap.has_5ghz = true;
 111                break;
 112        }
 113
 114        /* read tx-rx mask from eeprom */
 115        val = mt76_rr(dev, MT_TOP_STRAP_STA);
 116        max_nss = val & MT_TOP_3NSS ? 3 : 4;
 117
 118        rx_mask =  FIELD_GET(MT_EE_NIC_CONF_RX_MASK,
 119                             eeprom[MT_EE_NIC_CONF_0]);
 120        if (!rx_mask || rx_mask > max_nss)
 121                rx_mask = max_nss;
 122
 123        tx_mask =  FIELD_GET(MT_EE_NIC_CONF_TX_MASK,
 124                             eeprom[MT_EE_NIC_CONF_0]);
 125        if (!tx_mask || tx_mask > max_nss)
 126                tx_mask = max_nss;
 127
 128        dev->mt76.chainmask = tx_mask << 8 | rx_mask;
 129        dev->mt76.antenna_mask = BIT(tx_mask) - 1;
 130}
 131
 132int mt7615_eeprom_get_power_index(struct mt7615_dev *dev,
 133                                  struct ieee80211_channel *chan,
 134                                  u8 chain_idx)
 135{
 136        int index;
 137
 138        if (chain_idx > 3)
 139                return -EINVAL;
 140
 141        /* TSSI disabled */
 142        if (mt7615_ext_pa_enabled(dev, chan->band)) {
 143                if (chan->band == NL80211_BAND_2GHZ)
 144                        return MT_EE_EXT_PA_2G_TARGET_POWER;
 145                else
 146                        return MT_EE_EXT_PA_5G_TARGET_POWER;
 147        }
 148
 149        /* TSSI enabled */
 150        if (chan->band == NL80211_BAND_2GHZ) {
 151                index = MT_EE_TX0_2G_TARGET_POWER + chain_idx * 6;
 152        } else {
 153                int group = mt7615_get_channel_group(chan->hw_value);
 154
 155                switch (chain_idx) {
 156                case 1:
 157                        index = MT_EE_TX1_5G_G0_TARGET_POWER;
 158                        break;
 159                case 2:
 160                        index = MT_EE_TX2_5G_G0_TARGET_POWER;
 161                        break;
 162                case 3:
 163                        index = MT_EE_TX3_5G_G0_TARGET_POWER;
 164                        break;
 165                case 0:
 166                default:
 167                        index = MT_EE_TX0_5G_G0_TARGET_POWER;
 168                        break;
 169                }
 170                index += 5 * group;
 171        }
 172
 173        return index;
 174}
 175
 176static void mt7615_apply_cal_free_data(struct mt7615_dev *dev)
 177{
 178        static const u16 ical[] = {
 179                0x53, 0x54, 0x55, 0x56, 0x57, 0x5c, 0x5d, 0x62, 0x63, 0x68,
 180                0x69, 0x6e, 0x6f, 0x73, 0x74, 0x78, 0x79, 0x82, 0x83, 0x87,
 181                0x88, 0x8c, 0x8d, 0x91, 0x92, 0x96, 0x97, 0x9b, 0x9c, 0xa0,
 182                0xa1, 0xaa, 0xab, 0xaf, 0xb0, 0xb4, 0xb5, 0xb9, 0xba, 0xf4,
 183                0xf7, 0xff,
 184                0x140, 0x141, 0x145, 0x146, 0x14a, 0x14b, 0x154, 0x155, 0x159,
 185                0x15a, 0x15e, 0x15f, 0x163, 0x164, 0x168, 0x169, 0x16d, 0x16e,
 186                0x172, 0x173, 0x17c, 0x17d, 0x181, 0x182, 0x186, 0x187, 0x18b,
 187                0x18c
 188        };
 189        static const u16 ical_nocheck[] = {
 190                0x110, 0x111, 0x112, 0x113, 0x114, 0x115, 0x116, 0x117, 0x118,
 191                0x1b5, 0x1b6, 0x1b7, 0x3ac, 0x3ad, 0x3ae, 0x3af, 0x3b0, 0x3b1,
 192                0x3b2
 193        };
 194        u8 *eeprom = dev->mt76.eeprom.data;
 195        u8 *otp = dev->mt76.otp.data;
 196        int i;
 197
 198        if (!otp)
 199                return;
 200
 201        for (i = 0; i < ARRAY_SIZE(ical); i++)
 202                if (!otp[ical[i]])
 203                        return;
 204
 205        for (i = 0; i < ARRAY_SIZE(ical); i++)
 206                eeprom[ical[i]] = otp[ical[i]];
 207
 208        for (i = 0; i < ARRAY_SIZE(ical_nocheck); i++)
 209                eeprom[ical_nocheck[i]] = otp[ical_nocheck[i]];
 210}
 211
 212int mt7615_eeprom_init(struct mt7615_dev *dev)
 213{
 214        int ret;
 215
 216        ret = mt7615_eeprom_load(dev);
 217        if (ret < 0)
 218                return ret;
 219
 220        ret = mt7615_check_eeprom(&dev->mt76);
 221        if (ret && dev->mt76.otp.data)
 222                memcpy(dev->mt76.eeprom.data, dev->mt76.otp.data,
 223                       MT7615_EEPROM_SIZE);
 224        else
 225                mt7615_apply_cal_free_data(dev);
 226
 227        mt7615_eeprom_parse_hw_cap(dev);
 228        memcpy(dev->mt76.macaddr, dev->mt76.eeprom.data + MT_EE_MAC_ADDR,
 229               ETH_ALEN);
 230
 231        mt76_eeprom_override(&dev->mt76);
 232
 233        return 0;
 234}
 235