developer | b11a539 | 2022-03-31 00:34:47 +0800 | [diff] [blame] | 1 | // SPDX-License-Identifier: GPL-2.0-only |
| 2 | /* |
| 3 | * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org> |
| 4 | * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl> |
| 5 | * Copyright (C) 2018 Stanislaw Gruszka <stf_xl@wp.pl> |
| 6 | */ |
| 7 | |
| 8 | #include <linux/module.h> |
| 9 | #include <linux/of.h> |
| 10 | #include <linux/mtd/mtd.h> |
| 11 | #include <linux/mtd/partitions.h> |
| 12 | #include <linux/etherdevice.h> |
| 13 | #include <asm/unaligned.h> |
| 14 | #include "mt76x0.h" |
| 15 | #include "eeprom.h" |
| 16 | #include "../mt76x02_phy.h" |
| 17 | |
| 18 | #define MT_MAP_READS DIV_ROUND_UP(MT_EFUSE_USAGE_MAP_SIZE, 16) |
| 19 | static int |
| 20 | mt76x0_efuse_physical_size_check(struct mt76x02_dev *dev) |
| 21 | { |
| 22 | u8 data[MT_MAP_READS * 16]; |
| 23 | int ret, i; |
| 24 | u32 start = 0, end = 0, cnt_free; |
| 25 | |
| 26 | ret = mt76x02_get_efuse_data(dev, MT_EE_USAGE_MAP_START, data, |
| 27 | sizeof(data), MT_EE_PHYSICAL_READ); |
| 28 | if (ret) |
| 29 | return ret; |
| 30 | |
| 31 | for (i = 0; i < MT_EFUSE_USAGE_MAP_SIZE; i++) |
| 32 | if (!data[i]) { |
| 33 | if (!start) |
| 34 | start = MT_EE_USAGE_MAP_START + i; |
| 35 | end = MT_EE_USAGE_MAP_START + i; |
| 36 | } |
| 37 | cnt_free = end - start + 1; |
| 38 | |
| 39 | if (MT_EFUSE_USAGE_MAP_SIZE - cnt_free < 5) { |
| 40 | dev_err(dev->mt76.dev, |
| 41 | "driver does not support default EEPROM\n"); |
| 42 | return -EINVAL; |
| 43 | } |
| 44 | |
| 45 | return 0; |
| 46 | } |
| 47 | |
| 48 | static void mt76x0_set_chip_cap(struct mt76x02_dev *dev) |
| 49 | { |
| 50 | u16 nic_conf0 = mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_0); |
| 51 | u16 nic_conf1 = mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_1); |
| 52 | |
| 53 | mt76x02_eeprom_parse_hw_cap(dev); |
| 54 | dev_dbg(dev->mt76.dev, "2GHz %d 5GHz %d\n", |
| 55 | dev->mphy.cap.has_2ghz, dev->mphy.cap.has_5ghz); |
| 56 | |
| 57 | if (dev->no_2ghz) { |
| 58 | dev->mphy.cap.has_2ghz = false; |
| 59 | dev_dbg(dev->mt76.dev, "mask out 2GHz support\n"); |
| 60 | } |
| 61 | |
| 62 | if (is_mt7630(dev)) { |
| 63 | dev->mphy.cap.has_5ghz = false; |
| 64 | dev_dbg(dev->mt76.dev, "mask out 5GHz support\n"); |
| 65 | } |
| 66 | |
| 67 | if (!mt76x02_field_valid(nic_conf1 & 0xff)) |
| 68 | nic_conf1 &= 0xff00; |
| 69 | |
| 70 | if (nic_conf1 & MT_EE_NIC_CONF_1_HW_RF_CTRL) |
| 71 | dev_dbg(dev->mt76.dev, |
| 72 | "driver does not support HW RF ctrl\n"); |
| 73 | |
| 74 | if (!mt76x02_field_valid(nic_conf0 >> 8)) |
| 75 | return; |
| 76 | |
| 77 | if (FIELD_GET(MT_EE_NIC_CONF_0_RX_PATH, nic_conf0) > 1 || |
| 78 | FIELD_GET(MT_EE_NIC_CONF_0_TX_PATH, nic_conf0) > 1) |
| 79 | dev_err(dev->mt76.dev, "invalid tx-rx stream\n"); |
| 80 | } |
| 81 | |
| 82 | static void mt76x0_set_temp_offset(struct mt76x02_dev *dev) |
| 83 | { |
| 84 | u8 val; |
| 85 | |
| 86 | val = mt76x02_eeprom_get(dev, MT_EE_2G_TARGET_POWER) >> 8; |
| 87 | if (mt76x02_field_valid(val)) |
| 88 | dev->cal.rx.temp_offset = mt76x02_sign_extend(val, 8); |
| 89 | else |
| 90 | dev->cal.rx.temp_offset = -10; |
| 91 | } |
| 92 | |
| 93 | static void mt76x0_set_freq_offset(struct mt76x02_dev *dev) |
| 94 | { |
| 95 | struct mt76x02_rx_freq_cal *caldata = &dev->cal.rx; |
| 96 | u8 val; |
| 97 | |
| 98 | val = mt76x02_eeprom_get(dev, MT_EE_FREQ_OFFSET); |
| 99 | if (!mt76x02_field_valid(val)) |
| 100 | val = 0; |
| 101 | caldata->freq_offset = val; |
| 102 | |
| 103 | val = mt76x02_eeprom_get(dev, MT_EE_TSSI_BOUND4) >> 8; |
| 104 | if (!mt76x02_field_valid(val)) |
| 105 | val = 0; |
| 106 | |
| 107 | caldata->freq_offset -= mt76x02_sign_extend(val, 8); |
| 108 | } |
| 109 | |
| 110 | void mt76x0_read_rx_gain(struct mt76x02_dev *dev) |
| 111 | { |
| 112 | struct ieee80211_channel *chan = dev->mphy.chandef.chan; |
| 113 | struct mt76x02_rx_freq_cal *caldata = &dev->cal.rx; |
| 114 | s8 val, lna_5g[3], lna_2g; |
| 115 | u16 rssi_offset; |
| 116 | int i; |
| 117 | |
| 118 | mt76x02_get_rx_gain(dev, chan->band, &rssi_offset, &lna_2g, lna_5g); |
| 119 | caldata->lna_gain = mt76x02_get_lna_gain(dev, &lna_2g, lna_5g, chan); |
| 120 | |
| 121 | for (i = 0; i < ARRAY_SIZE(caldata->rssi_offset); i++) { |
| 122 | val = rssi_offset >> (8 * i); |
| 123 | if (val < -10 || val > 10) |
| 124 | val = 0; |
| 125 | |
| 126 | caldata->rssi_offset[i] = val; |
| 127 | } |
| 128 | } |
| 129 | |
| 130 | static s8 mt76x0_get_delta(struct mt76x02_dev *dev) |
| 131 | { |
| 132 | struct cfg80211_chan_def *chandef = &dev->mphy.chandef; |
| 133 | u8 val; |
| 134 | |
| 135 | if (chandef->width == NL80211_CHAN_WIDTH_80) { |
| 136 | val = mt76x02_eeprom_get(dev, MT_EE_5G_TARGET_POWER) >> 8; |
| 137 | } else if (chandef->width == NL80211_CHAN_WIDTH_40) { |
| 138 | u16 data; |
| 139 | |
| 140 | data = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_DELTA_BW40); |
| 141 | if (chandef->chan->band == NL80211_BAND_5GHZ) |
| 142 | val = data >> 8; |
| 143 | else |
| 144 | val = data; |
| 145 | } else { |
| 146 | return 0; |
| 147 | } |
| 148 | |
| 149 | return mt76x02_rate_power_val(val); |
| 150 | } |
| 151 | |
| 152 | void mt76x0_get_tx_power_per_rate(struct mt76x02_dev *dev, |
| 153 | struct ieee80211_channel *chan, |
| 154 | struct mt76_rate_power *t) |
| 155 | { |
| 156 | bool is_2ghz = chan->band == NL80211_BAND_2GHZ; |
| 157 | u16 val, addr; |
| 158 | s8 delta; |
| 159 | |
| 160 | memset(t, 0, sizeof(*t)); |
| 161 | |
| 162 | /* cck 1M, 2M, 5.5M, 11M */ |
| 163 | val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_BYRATE_BASE); |
| 164 | t->cck[0] = t->cck[1] = s6_to_s8(val); |
| 165 | t->cck[2] = t->cck[3] = s6_to_s8(val >> 8); |
| 166 | |
| 167 | /* ofdm 6M, 9M, 12M, 18M */ |
| 168 | addr = is_2ghz ? MT_EE_TX_POWER_BYRATE_BASE + 2 : 0x120; |
| 169 | val = mt76x02_eeprom_get(dev, addr); |
| 170 | t->ofdm[0] = t->ofdm[1] = s6_to_s8(val); |
| 171 | t->ofdm[2] = t->ofdm[3] = s6_to_s8(val >> 8); |
| 172 | |
| 173 | /* ofdm 24M, 36M, 48M, 54M */ |
| 174 | addr = is_2ghz ? MT_EE_TX_POWER_BYRATE_BASE + 4 : 0x122; |
| 175 | val = mt76x02_eeprom_get(dev, addr); |
| 176 | t->ofdm[4] = t->ofdm[5] = s6_to_s8(val); |
| 177 | t->ofdm[6] = t->ofdm[7] = s6_to_s8(val >> 8); |
| 178 | |
| 179 | /* ht-vht mcs 1ss 0, 1, 2, 3 */ |
| 180 | addr = is_2ghz ? MT_EE_TX_POWER_BYRATE_BASE + 6 : 0x124; |
| 181 | val = mt76x02_eeprom_get(dev, addr); |
| 182 | t->ht[0] = t->ht[1] = t->vht[0] = t->vht[1] = s6_to_s8(val); |
| 183 | t->ht[2] = t->ht[3] = t->vht[2] = t->vht[3] = s6_to_s8(val >> 8); |
| 184 | |
| 185 | /* ht-vht mcs 1ss 4, 5, 6 */ |
| 186 | addr = is_2ghz ? MT_EE_TX_POWER_BYRATE_BASE + 8 : 0x126; |
| 187 | val = mt76x02_eeprom_get(dev, addr); |
| 188 | t->ht[4] = t->ht[5] = t->vht[4] = t->vht[5] = s6_to_s8(val); |
| 189 | t->ht[6] = t->ht[7] = t->vht[6] = t->vht[7] = s6_to_s8(val >> 8); |
| 190 | |
| 191 | /* ht-vht mcs 1ss 0, 1, 2, 3 stbc */ |
| 192 | addr = is_2ghz ? MT_EE_TX_POWER_BYRATE_BASE + 14 : 0xec; |
| 193 | val = mt76x02_eeprom_get(dev, addr); |
| 194 | t->stbc[0] = t->stbc[1] = s6_to_s8(val); |
| 195 | t->stbc[2] = t->stbc[3] = s6_to_s8(val >> 8); |
| 196 | |
| 197 | /* ht-vht mcs 1ss 4, 5, 6 stbc */ |
| 198 | addr = is_2ghz ? MT_EE_TX_POWER_BYRATE_BASE + 16 : 0xee; |
| 199 | val = mt76x02_eeprom_get(dev, addr); |
| 200 | t->stbc[4] = t->stbc[5] = s6_to_s8(val); |
| 201 | t->stbc[6] = t->stbc[7] = s6_to_s8(val >> 8); |
| 202 | |
| 203 | /* vht mcs 8, 9 5GHz */ |
| 204 | val = mt76x02_eeprom_get(dev, 0x12c); |
| 205 | t->vht[8] = s6_to_s8(val); |
| 206 | t->vht[9] = s6_to_s8(val >> 8); |
| 207 | |
| 208 | delta = mt76x0_tssi_enabled(dev) ? 0 : mt76x0_get_delta(dev); |
| 209 | mt76x02_add_rate_power_offset(t, delta); |
| 210 | } |
| 211 | |
| 212 | void mt76x0_get_power_info(struct mt76x02_dev *dev, |
| 213 | struct ieee80211_channel *chan, s8 *tp) |
| 214 | { |
| 215 | static const struct mt76x0_chan_map { |
| 216 | u8 chan; |
| 217 | u8 offset; |
| 218 | } chan_map[] = { |
| 219 | { 2, 0 }, { 4, 2 }, { 6, 4 }, { 8, 6 }, |
| 220 | { 10, 8 }, { 12, 10 }, { 14, 12 }, { 38, 0 }, |
| 221 | { 44, 2 }, { 48, 4 }, { 54, 6 }, { 60, 8 }, |
| 222 | { 64, 10 }, { 102, 12 }, { 108, 14 }, { 112, 16 }, |
| 223 | { 118, 18 }, { 124, 20 }, { 128, 22 }, { 134, 24 }, |
| 224 | { 140, 26 }, { 151, 28 }, { 157, 30 }, { 161, 32 }, |
| 225 | { 167, 34 }, { 171, 36 }, { 175, 38 }, |
| 226 | }; |
| 227 | u8 offset, addr; |
| 228 | int i, idx = 0; |
| 229 | u16 data; |
| 230 | |
| 231 | if (mt76x0_tssi_enabled(dev)) { |
| 232 | s8 target_power; |
| 233 | |
| 234 | if (chan->band == NL80211_BAND_5GHZ) |
| 235 | data = mt76x02_eeprom_get(dev, MT_EE_5G_TARGET_POWER); |
| 236 | else |
| 237 | data = mt76x02_eeprom_get(dev, MT_EE_2G_TARGET_POWER); |
| 238 | target_power = (data & 0xff) - dev->mt76.rate_power.ofdm[7]; |
| 239 | *tp = target_power + mt76x0_get_delta(dev); |
| 240 | |
| 241 | return; |
| 242 | } |
| 243 | |
| 244 | for (i = 0; i < ARRAY_SIZE(chan_map); i++) { |
| 245 | if (chan->hw_value <= chan_map[i].chan) { |
| 246 | idx = (chan->hw_value == chan_map[i].chan); |
| 247 | offset = chan_map[i].offset; |
| 248 | break; |
| 249 | } |
| 250 | } |
| 251 | if (i == ARRAY_SIZE(chan_map)) |
| 252 | offset = chan_map[0].offset; |
| 253 | |
| 254 | if (chan->band == NL80211_BAND_2GHZ) { |
| 255 | addr = MT_EE_TX_POWER_DELTA_BW80 + offset; |
| 256 | } else { |
| 257 | switch (chan->hw_value) { |
| 258 | case 42: |
| 259 | offset = 2; |
| 260 | break; |
| 261 | case 58: |
| 262 | offset = 8; |
| 263 | break; |
| 264 | case 106: |
| 265 | offset = 14; |
| 266 | break; |
| 267 | case 122: |
| 268 | offset = 20; |
| 269 | break; |
| 270 | case 155: |
| 271 | offset = 30; |
| 272 | break; |
| 273 | default: |
| 274 | break; |
| 275 | } |
| 276 | addr = MT_EE_TX_POWER_0_GRP4_TSSI_SLOPE + 2 + offset; |
| 277 | } |
| 278 | |
| 279 | data = mt76x02_eeprom_get(dev, addr); |
| 280 | *tp = data >> (8 * idx); |
| 281 | if (*tp < 0 || *tp > 0x3f) |
| 282 | *tp = 5; |
| 283 | } |
| 284 | |
| 285 | static int mt76x0_check_eeprom(struct mt76x02_dev *dev) |
| 286 | { |
| 287 | u16 val; |
| 288 | |
| 289 | val = get_unaligned_le16(dev->mt76.eeprom.data); |
| 290 | if (!val) |
| 291 | val = get_unaligned_le16(dev->mt76.eeprom.data + |
| 292 | MT_EE_PCI_ID); |
| 293 | |
| 294 | switch (val) { |
| 295 | case 0x7650: |
| 296 | case 0x7610: |
| 297 | return 0; |
| 298 | default: |
| 299 | dev_err(dev->mt76.dev, "EEPROM data check failed: %04x\n", |
| 300 | val); |
| 301 | return -EINVAL; |
| 302 | } |
| 303 | } |
| 304 | |
| 305 | static int mt76x0_load_eeprom(struct mt76x02_dev *dev) |
| 306 | { |
| 307 | int found; |
| 308 | |
| 309 | found = mt76_eeprom_init(&dev->mt76, MT76X0_EEPROM_SIZE); |
| 310 | if (found < 0) |
| 311 | return found; |
| 312 | |
| 313 | if (found && !mt76x0_check_eeprom(dev)) |
| 314 | return 0; |
| 315 | |
| 316 | found = mt76x0_efuse_physical_size_check(dev); |
| 317 | if (found < 0) |
| 318 | return found; |
| 319 | |
| 320 | return mt76x02_get_efuse_data(dev, 0, dev->mt76.eeprom.data, |
| 321 | MT76X0_EEPROM_SIZE, MT_EE_READ); |
| 322 | } |
| 323 | |
| 324 | int mt76x0_eeprom_init(struct mt76x02_dev *dev) |
| 325 | { |
| 326 | u8 version, fae; |
| 327 | u16 data; |
| 328 | int err; |
| 329 | |
| 330 | err = mt76x0_load_eeprom(dev); |
| 331 | if (err < 0) |
| 332 | return err; |
| 333 | |
| 334 | data = mt76x02_eeprom_get(dev, MT_EE_VERSION); |
| 335 | version = data >> 8; |
| 336 | fae = data; |
| 337 | |
| 338 | if (version > MT76X0U_EE_MAX_VER) |
| 339 | dev_warn(dev->mt76.dev, |
| 340 | "Warning: unsupported EEPROM version %02hhx\n", |
| 341 | version); |
| 342 | dev_info(dev->mt76.dev, "EEPROM ver:%02hhx fae:%02hhx\n", |
| 343 | version, fae); |
| 344 | |
| 345 | memcpy(dev->mphy.macaddr, (u8 *)dev->mt76.eeprom.data + MT_EE_MAC_ADDR, |
| 346 | ETH_ALEN); |
| 347 | mt76_eeprom_override(&dev->mphy); |
| 348 | mt76x02_mac_setaddr(dev, dev->mphy.macaddr); |
| 349 | |
| 350 | mt76x0_set_chip_cap(dev); |
| 351 | mt76x0_set_freq_offset(dev); |
| 352 | mt76x0_set_temp_offset(dev); |
| 353 | |
| 354 | return 0; |
| 355 | } |
| 356 | |
| 357 | MODULE_LICENSE("Dual BSD/GPL"); |