linux/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.c
<<
>>
Prefs
   1// SPDX-License-Identifier: ISC
   2/*
   3 * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
   4 * Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
   5 */
   6
   7#include <asm/unaligned.h>
   8
   9#include "mt76x02_eeprom.h"
  10
  11static int
  12mt76x02_efuse_read(struct mt76x02_dev *dev, u16 addr, u8 *data,
  13                   enum mt76x02_eeprom_modes mode)
  14{
  15        u32 val;
  16        int i;
  17
  18        val = mt76_rr(dev, MT_EFUSE_CTRL);
  19        val &= ~(MT_EFUSE_CTRL_AIN |
  20                 MT_EFUSE_CTRL_MODE);
  21        val |= FIELD_PREP(MT_EFUSE_CTRL_AIN, addr & ~0xf);
  22        val |= FIELD_PREP(MT_EFUSE_CTRL_MODE, mode);
  23        val |= MT_EFUSE_CTRL_KICK;
  24        mt76_wr(dev, MT_EFUSE_CTRL, val);
  25
  26        if (!mt76_poll_msec(dev, MT_EFUSE_CTRL, MT_EFUSE_CTRL_KICK, 0, 1000))
  27                return -ETIMEDOUT;
  28
  29        udelay(2);
  30
  31        val = mt76_rr(dev, MT_EFUSE_CTRL);
  32        if ((val & MT_EFUSE_CTRL_AOUT) == MT_EFUSE_CTRL_AOUT) {
  33                memset(data, 0xff, 16);
  34                return 0;
  35        }
  36
  37        for (i = 0; i < 4; i++) {
  38                val = mt76_rr(dev, MT_EFUSE_DATA(i));
  39                put_unaligned_le32(val, data + 4 * i);
  40        }
  41
  42        return 0;
  43}
  44
  45int mt76x02_eeprom_copy(struct mt76x02_dev *dev,
  46                        enum mt76x02_eeprom_field field,
  47                        void *dest, int len)
  48{
  49        if (field + len > dev->mt76.eeprom.size)
  50                return -1;
  51
  52        memcpy(dest, dev->mt76.eeprom.data + field, len);
  53        return 0;
  54}
  55EXPORT_SYMBOL_GPL(mt76x02_eeprom_copy);
  56
  57int mt76x02_get_efuse_data(struct mt76x02_dev *dev, u16 base, void *buf,
  58                           int len, enum mt76x02_eeprom_modes mode)
  59{
  60        int ret, i;
  61
  62        for (i = 0; i + 16 <= len; i += 16) {
  63                ret = mt76x02_efuse_read(dev, base + i, buf + i, mode);
  64                if (ret)
  65                        return ret;
  66        }
  67
  68        return 0;
  69}
  70EXPORT_SYMBOL_GPL(mt76x02_get_efuse_data);
  71
  72void mt76x02_eeprom_parse_hw_cap(struct mt76x02_dev *dev)
  73{
  74        u16 val = mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_0);
  75
  76        switch (FIELD_GET(MT_EE_NIC_CONF_0_BOARD_TYPE, val)) {
  77        case BOARD_TYPE_5GHZ:
  78                dev->mt76.cap.has_5ghz = true;
  79                break;
  80        case BOARD_TYPE_2GHZ:
  81                dev->mt76.cap.has_2ghz = true;
  82                break;
  83        default:
  84                dev->mt76.cap.has_2ghz = true;
  85                dev->mt76.cap.has_5ghz = true;
  86                break;
  87        }
  88}
  89EXPORT_SYMBOL_GPL(mt76x02_eeprom_parse_hw_cap);
  90
  91bool mt76x02_ext_pa_enabled(struct mt76x02_dev *dev, enum nl80211_band band)
  92{
  93        u16 conf0 = mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_0);
  94
  95        if (band == NL80211_BAND_5GHZ)
  96                return !(conf0 & MT_EE_NIC_CONF_0_PA_INT_5G);
  97        else
  98                return !(conf0 & MT_EE_NIC_CONF_0_PA_INT_2G);
  99}
 100EXPORT_SYMBOL_GPL(mt76x02_ext_pa_enabled);
 101
 102void mt76x02_get_rx_gain(struct mt76x02_dev *dev, enum nl80211_band band,
 103                         u16 *rssi_offset, s8 *lna_2g, s8 *lna_5g)
 104{
 105        u16 val;
 106
 107        val = mt76x02_eeprom_get(dev, MT_EE_LNA_GAIN);
 108        *lna_2g = val & 0xff;
 109        lna_5g[0] = val >> 8;
 110
 111        val = mt76x02_eeprom_get(dev, MT_EE_RSSI_OFFSET_2G_1);
 112        lna_5g[1] = val >> 8;
 113
 114        val = mt76x02_eeprom_get(dev, MT_EE_RSSI_OFFSET_5G_1);
 115        lna_5g[2] = val >> 8;
 116
 117        if (!mt76x02_field_valid(lna_5g[1]))
 118                lna_5g[1] = lna_5g[0];
 119
 120        if (!mt76x02_field_valid(lna_5g[2]))
 121                lna_5g[2] = lna_5g[0];
 122
 123        if (band == NL80211_BAND_2GHZ)
 124                *rssi_offset = mt76x02_eeprom_get(dev, MT_EE_RSSI_OFFSET_2G_0);
 125        else
 126                *rssi_offset = mt76x02_eeprom_get(dev, MT_EE_RSSI_OFFSET_5G_0);
 127}
 128EXPORT_SYMBOL_GPL(mt76x02_get_rx_gain);
 129
 130u8 mt76x02_get_lna_gain(struct mt76x02_dev *dev,
 131                        s8 *lna_2g, s8 *lna_5g,
 132                        struct ieee80211_channel *chan)
 133{
 134        u16 val;
 135        u8 lna;
 136
 137        val = mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_1);
 138        if (val & MT_EE_NIC_CONF_1_LNA_EXT_2G)
 139                *lna_2g = 0;
 140        if (val & MT_EE_NIC_CONF_1_LNA_EXT_5G)
 141                memset(lna_5g, 0, sizeof(s8) * 3);
 142
 143        if (chan->band == NL80211_BAND_2GHZ)
 144                lna = *lna_2g;
 145        else if (chan->hw_value <= 64)
 146                lna = lna_5g[0];
 147        else if (chan->hw_value <= 128)
 148                lna = lna_5g[1];
 149        else
 150                lna = lna_5g[2];
 151
 152        return lna != 0xff ? lna : 0;
 153}
 154EXPORT_SYMBOL_GPL(mt76x02_get_lna_gain);
 155