1e87b5039SStanislaw Gruszka /* 2e87b5039SStanislaw Gruszka * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org> 3e87b5039SStanislaw Gruszka * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl> 4e87b5039SStanislaw Gruszka * Copyright (C) 2018 Stanislaw Gruszka <stf_xl@wp.pl> 5e87b5039SStanislaw Gruszka * 6e87b5039SStanislaw Gruszka * This program is free software; you can redistribute it and/or modify 7e87b5039SStanislaw Gruszka * it under the terms of the GNU General Public License version 2 8e87b5039SStanislaw Gruszka * as published by the Free Software Foundation 9e87b5039SStanislaw Gruszka * 10e87b5039SStanislaw Gruszka * This program is distributed in the hope that it will be useful, 11e87b5039SStanislaw Gruszka * but WITHOUT ANY WARRANTY; without even the implied warranty of 12e87b5039SStanislaw Gruszka * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13e87b5039SStanislaw Gruszka * GNU General Public License for more details. 14e87b5039SStanislaw Gruszka */ 15e87b5039SStanislaw Gruszka 16e87b5039SStanislaw Gruszka #include <linux/of.h> 17e87b5039SStanislaw Gruszka #include <linux/mtd/mtd.h> 18e87b5039SStanislaw Gruszka #include <linux/mtd/partitions.h> 19e87b5039SStanislaw Gruszka #include <linux/etherdevice.h> 20e87b5039SStanislaw Gruszka #include <asm/unaligned.h> 21e87b5039SStanislaw Gruszka #include "mt76x0.h" 22e87b5039SStanislaw Gruszka #include "eeprom.h" 23e87b5039SStanislaw Gruszka 24e87b5039SStanislaw Gruszka static bool 25e87b5039SStanislaw Gruszka field_valid(u8 val) 26e87b5039SStanislaw Gruszka { 27e87b5039SStanislaw Gruszka return val != 0xff; 28e87b5039SStanislaw Gruszka } 29e87b5039SStanislaw Gruszka 30e87b5039SStanislaw Gruszka static s8 31e87b5039SStanislaw Gruszka field_validate(u8 val) 32e87b5039SStanislaw Gruszka { 33e87b5039SStanislaw Gruszka if (!field_valid(val)) 34e87b5039SStanislaw Gruszka return 0; 35e87b5039SStanislaw Gruszka 36e87b5039SStanislaw Gruszka return val; 37e87b5039SStanislaw Gruszka } 38e87b5039SStanislaw Gruszka 39e87b5039SStanislaw Gruszka static inline int 40e87b5039SStanislaw Gruszka sign_extend(u32 val, unsigned int size) 41e87b5039SStanislaw Gruszka { 42e87b5039SStanislaw Gruszka bool sign = val & BIT(size - 1); 43e87b5039SStanislaw Gruszka 44e87b5039SStanislaw Gruszka val &= BIT(size - 1) - 1; 45e87b5039SStanislaw Gruszka 46e87b5039SStanislaw Gruszka return sign ? val : -val; 47e87b5039SStanislaw Gruszka } 48e87b5039SStanislaw Gruszka 49e87b5039SStanislaw Gruszka static int 50e87b5039SStanislaw Gruszka mt76x0_efuse_read(struct mt76x0_dev *dev, u16 addr, u8 *data, 51e87b5039SStanislaw Gruszka enum mt76x0_eeprom_access_modes mode) 52e87b5039SStanislaw Gruszka { 53e87b5039SStanislaw Gruszka u32 val; 54e87b5039SStanislaw Gruszka int i; 55e87b5039SStanislaw Gruszka 56e87b5039SStanislaw Gruszka val = mt76_rr(dev, MT_EFUSE_CTRL); 57e87b5039SStanislaw Gruszka val &= ~(MT_EFUSE_CTRL_AIN | 58e87b5039SStanislaw Gruszka MT_EFUSE_CTRL_MODE); 59e87b5039SStanislaw Gruszka val |= FIELD_PREP(MT_EFUSE_CTRL_AIN, addr & ~0xf) | 60e87b5039SStanislaw Gruszka FIELD_PREP(MT_EFUSE_CTRL_MODE, mode) | 61e87b5039SStanislaw Gruszka MT_EFUSE_CTRL_KICK; 62e87b5039SStanislaw Gruszka mt76_wr(dev, MT_EFUSE_CTRL, val); 63e87b5039SStanislaw Gruszka 64e87b5039SStanislaw Gruszka if (!mt76_poll(dev, MT_EFUSE_CTRL, MT_EFUSE_CTRL_KICK, 0, 1000)) 65e87b5039SStanislaw Gruszka return -ETIMEDOUT; 66e87b5039SStanislaw Gruszka 67e87b5039SStanislaw Gruszka val = mt76_rr(dev, MT_EFUSE_CTRL); 68e87b5039SStanislaw Gruszka if ((val & MT_EFUSE_CTRL_AOUT) == MT_EFUSE_CTRL_AOUT) { 69e87b5039SStanislaw Gruszka /* Parts of eeprom not in the usage map (0x80-0xc0,0xf0) 70e87b5039SStanislaw Gruszka * will not return valid data but it's ok. 71e87b5039SStanislaw Gruszka */ 72e87b5039SStanislaw Gruszka memset(data, 0xff, 16); 73e87b5039SStanislaw Gruszka return 0; 74e87b5039SStanislaw Gruszka } 75e87b5039SStanislaw Gruszka 76e87b5039SStanislaw Gruszka for (i = 0; i < 4; i++) { 77e87b5039SStanislaw Gruszka val = mt76_rr(dev, MT_EFUSE_DATA(i)); 78e87b5039SStanislaw Gruszka put_unaligned_le32(val, data + 4 * i); 79e87b5039SStanislaw Gruszka } 80e87b5039SStanislaw Gruszka 81e87b5039SStanislaw Gruszka return 0; 82e87b5039SStanislaw Gruszka } 83e87b5039SStanislaw Gruszka 8417ad18fdSKees Cook #define MT_MAP_READS DIV_ROUND_UP(MT_EFUSE_USAGE_MAP_SIZE, 16) 85e87b5039SStanislaw Gruszka static int 86e87b5039SStanislaw Gruszka mt76x0_efuse_physical_size_check(struct mt76x0_dev *dev) 87e87b5039SStanislaw Gruszka { 8817ad18fdSKees Cook u8 data[MT_MAP_READS * 16]; 89e87b5039SStanislaw Gruszka int ret, i; 90e87b5039SStanislaw Gruszka u32 start = 0, end = 0, cnt_free; 91e87b5039SStanislaw Gruszka 9217ad18fdSKees Cook for (i = 0; i < MT_MAP_READS; i++) { 93e87b5039SStanislaw Gruszka ret = mt76x0_efuse_read(dev, MT_EE_USAGE_MAP_START + i * 16, 94e87b5039SStanislaw Gruszka data + i * 16, MT_EE_PHYSICAL_READ); 95e87b5039SStanislaw Gruszka if (ret) 96e87b5039SStanislaw Gruszka return ret; 97e87b5039SStanislaw Gruszka } 98e87b5039SStanislaw Gruszka 99e87b5039SStanislaw Gruszka for (i = 0; i < MT_EFUSE_USAGE_MAP_SIZE; i++) 100e87b5039SStanislaw Gruszka if (!data[i]) { 101e87b5039SStanislaw Gruszka if (!start) 102e87b5039SStanislaw Gruszka start = MT_EE_USAGE_MAP_START + i; 103e87b5039SStanislaw Gruszka end = MT_EE_USAGE_MAP_START + i; 104e87b5039SStanislaw Gruszka } 105e87b5039SStanislaw Gruszka cnt_free = end - start + 1; 106e87b5039SStanislaw Gruszka 107e87b5039SStanislaw Gruszka if (MT_EFUSE_USAGE_MAP_SIZE - cnt_free < 5) { 108e87b5039SStanislaw Gruszka dev_err(dev->mt76.dev, "Error: your device needs default EEPROM file and this driver doesn't support it!\n"); 109e87b5039SStanislaw Gruszka return -EINVAL; 110e87b5039SStanislaw Gruszka } 111e87b5039SStanislaw Gruszka 112e87b5039SStanislaw Gruszka return 0; 113e87b5039SStanislaw Gruszka } 114e87b5039SStanislaw Gruszka 115e87b5039SStanislaw Gruszka static void 116e87b5039SStanislaw Gruszka mt76x0_set_chip_cap(struct mt76x0_dev *dev, u8 *eeprom) 117e87b5039SStanislaw Gruszka { 118e87b5039SStanislaw Gruszka enum mt76x2_board_type { BOARD_TYPE_2GHZ = 1, BOARD_TYPE_5GHZ = 2 }; 119e87b5039SStanislaw Gruszka u16 nic_conf0 = get_unaligned_le16(eeprom + MT_EE_NIC_CONF_0); 120e87b5039SStanislaw Gruszka u16 nic_conf1 = get_unaligned_le16(eeprom + MT_EE_NIC_CONF_1); 121e87b5039SStanislaw Gruszka 122e87b5039SStanislaw Gruszka dev_dbg(dev->mt76.dev, "NIC_CONF0: %04x NIC_CONF1: %04x\n", nic_conf0, nic_conf1); 123e87b5039SStanislaw Gruszka 124e87b5039SStanislaw Gruszka switch (FIELD_GET(MT_EE_NIC_CONF_0_BOARD_TYPE, nic_conf0)) { 125e87b5039SStanislaw Gruszka case BOARD_TYPE_5GHZ: 126540399d5SLorenzo Bianconi dev->mt76.cap.has_5ghz = true; 127e87b5039SStanislaw Gruszka break; 128e87b5039SStanislaw Gruszka case BOARD_TYPE_2GHZ: 129540399d5SLorenzo Bianconi dev->mt76.cap.has_2ghz = true; 130e87b5039SStanislaw Gruszka break; 131e87b5039SStanislaw Gruszka default: 132540399d5SLorenzo Bianconi dev->mt76.cap.has_2ghz = true; 133540399d5SLorenzo Bianconi dev->mt76.cap.has_5ghz = true; 134e87b5039SStanislaw Gruszka break; 135e87b5039SStanislaw Gruszka } 136e87b5039SStanislaw Gruszka 137540399d5SLorenzo Bianconi dev_dbg(dev->mt76.dev, "Has 2GHZ %d 5GHZ %d\n", 138540399d5SLorenzo Bianconi dev->mt76.cap.has_2ghz, dev->mt76.cap.has_5ghz); 139e87b5039SStanislaw Gruszka 140e87b5039SStanislaw Gruszka if (!field_valid(nic_conf1 & 0xff)) 141e87b5039SStanislaw Gruszka nic_conf1 &= 0xff00; 142e87b5039SStanislaw Gruszka 143e87b5039SStanislaw Gruszka if (nic_conf1 & MT_EE_NIC_CONF_1_HW_RF_CTRL) 144e87b5039SStanislaw Gruszka dev_err(dev->mt76.dev, 145e87b5039SStanislaw Gruszka "Error: this driver does not support HW RF ctrl\n"); 146e87b5039SStanislaw Gruszka 147e87b5039SStanislaw Gruszka if (!field_valid(nic_conf0 >> 8)) 148e87b5039SStanislaw Gruszka return; 149e87b5039SStanislaw Gruszka 150e87b5039SStanislaw Gruszka if (FIELD_GET(MT_EE_NIC_CONF_0_RX_PATH, nic_conf0) > 1 || 151e87b5039SStanislaw Gruszka FIELD_GET(MT_EE_NIC_CONF_0_TX_PATH, nic_conf0) > 1) 152e87b5039SStanislaw Gruszka dev_err(dev->mt76.dev, 153e87b5039SStanislaw Gruszka "Error: device has more than 1 RX/TX stream!\n"); 154e87b5039SStanislaw Gruszka 155e87b5039SStanislaw Gruszka dev->ee->pa_type = FIELD_GET(MT_EE_NIC_CONF_0_PA_TYPE, nic_conf0); 156e87b5039SStanislaw Gruszka dev_dbg(dev->mt76.dev, "PA Type %d\n", dev->ee->pa_type); 157e87b5039SStanislaw Gruszka } 158e87b5039SStanislaw Gruszka 159e87b5039SStanislaw Gruszka static int 160e87b5039SStanislaw Gruszka mt76x0_set_macaddr(struct mt76x0_dev *dev, const u8 *eeprom) 161e87b5039SStanislaw Gruszka { 162e87b5039SStanislaw Gruszka const void *src = eeprom + MT_EE_MAC_ADDR; 1631bee323aSLorenzo Bianconi u8 *dst = dev->mt76.macaddr; 164e87b5039SStanislaw Gruszka 1651bee323aSLorenzo Bianconi ether_addr_copy(dev->mt76.macaddr, src); 166e87b5039SStanislaw Gruszka 1671bee323aSLorenzo Bianconi if (!is_valid_ether_addr(dst)) { 1681bee323aSLorenzo Bianconi eth_random_addr(dst); 169e87b5039SStanislaw Gruszka dev_info(dev->mt76.dev, 170e87b5039SStanislaw Gruszka "Invalid MAC address, using random address %pM\n", 1711bee323aSLorenzo Bianconi dst); 172e87b5039SStanislaw Gruszka } 173e87b5039SStanislaw Gruszka 1741bee323aSLorenzo Bianconi mt76_wr(dev, MT_MAC_ADDR_DW0, get_unaligned_le32(dst)); 1751bee323aSLorenzo Bianconi mt76_wr(dev, MT_MAC_ADDR_DW1, get_unaligned_le16(dst + 4) | 176e87b5039SStanislaw Gruszka FIELD_PREP(MT_MAC_ADDR_DW1_U2ME_MASK, 0xff)); 177e87b5039SStanislaw Gruszka 178e87b5039SStanislaw Gruszka return 0; 179e87b5039SStanislaw Gruszka } 180e87b5039SStanislaw Gruszka 181e87b5039SStanislaw Gruszka static void 182e87b5039SStanislaw Gruszka mt76x0_set_temp_offset(struct mt76x0_dev *dev, u8 *eeprom) 183e87b5039SStanislaw Gruszka { 184e87b5039SStanislaw Gruszka u8 temp = eeprom[MT_EE_TEMP_OFFSET]; 185e87b5039SStanislaw Gruszka 186e87b5039SStanislaw Gruszka if (field_valid(temp)) 187e87b5039SStanislaw Gruszka dev->ee->temp_off = sign_extend(temp, 8); 188e87b5039SStanislaw Gruszka else 189e87b5039SStanislaw Gruszka dev->ee->temp_off = -10; 190e87b5039SStanislaw Gruszka } 191e87b5039SStanislaw Gruszka 192e87b5039SStanislaw Gruszka static void 193e87b5039SStanislaw Gruszka mt76x0_set_country_reg(struct mt76x0_dev *dev, u8 *eeprom) 194e87b5039SStanislaw Gruszka { 195e87b5039SStanislaw Gruszka /* Note: - region 31 is not valid for mt76x0 (see rtmp_init.c) 196e87b5039SStanislaw Gruszka * - comments in rtmp_def.h are incorrect (see rt_channel.c) 197e87b5039SStanislaw Gruszka */ 198e87b5039SStanislaw Gruszka static const struct reg_channel_bounds chan_bounds[] = { 199e87b5039SStanislaw Gruszka /* EEPROM country regions 0 - 7 */ 200e87b5039SStanislaw Gruszka { 1, 11 }, { 1, 13 }, { 10, 2 }, { 10, 4 }, 201e87b5039SStanislaw Gruszka { 14, 1 }, { 1, 14 }, { 3, 7 }, { 5, 9 }, 202e87b5039SStanislaw Gruszka /* EEPROM country regions 32 - 33 */ 203e87b5039SStanislaw Gruszka { 1, 11 }, { 1, 14 } 204e87b5039SStanislaw Gruszka }; 205e87b5039SStanislaw Gruszka u8 val = eeprom[MT_EE_COUNTRY_REGION_2GHZ]; 206e87b5039SStanislaw Gruszka int idx = -1; 207e87b5039SStanislaw Gruszka 208e87b5039SStanislaw Gruszka dev_dbg(dev->mt76.dev, "REG 2GHZ %u REG 5GHZ %u\n", val, eeprom[MT_EE_COUNTRY_REGION_5GHZ]); 209e87b5039SStanislaw Gruszka if (val < 8) 210e87b5039SStanislaw Gruszka idx = val; 211e87b5039SStanislaw Gruszka if (val > 31 && val < 33) 212e87b5039SStanislaw Gruszka idx = val - 32 + 8; 213e87b5039SStanislaw Gruszka 214e87b5039SStanislaw Gruszka if (idx != -1) 215e87b5039SStanislaw Gruszka dev_info(dev->mt76.dev, 216e87b5039SStanislaw Gruszka "EEPROM country region %02hhx (channels %hhd-%hhd)\n", 217e87b5039SStanislaw Gruszka val, chan_bounds[idx].start, 218e87b5039SStanislaw Gruszka chan_bounds[idx].start + chan_bounds[idx].num - 1); 219e87b5039SStanislaw Gruszka else 220e87b5039SStanislaw Gruszka idx = 5; /* channels 1 - 14 */ 221e87b5039SStanislaw Gruszka 222e87b5039SStanislaw Gruszka dev->ee->reg = chan_bounds[idx]; 223e87b5039SStanislaw Gruszka 224e87b5039SStanislaw Gruszka /* TODO: country region 33 is special - phy should be set to B-mode 225e87b5039SStanislaw Gruszka * before entering channel 14 (see sta/connect.c) 226e87b5039SStanislaw Gruszka */ 227e87b5039SStanislaw Gruszka } 228e87b5039SStanislaw Gruszka 229e87b5039SStanislaw Gruszka static void 230e87b5039SStanislaw Gruszka mt76x0_set_rf_freq_off(struct mt76x0_dev *dev, u8 *eeprom) 231e87b5039SStanislaw Gruszka { 232e87b5039SStanislaw Gruszka u8 comp; 233e87b5039SStanislaw Gruszka 234e87b5039SStanislaw Gruszka dev->ee->rf_freq_off = field_validate(eeprom[MT_EE_FREQ_OFFSET]); 235e87b5039SStanislaw Gruszka comp = field_validate(eeprom[MT_EE_FREQ_OFFSET_COMPENSATION]); 236e87b5039SStanislaw Gruszka 237e87b5039SStanislaw Gruszka if (comp & BIT(7)) 238e87b5039SStanislaw Gruszka dev->ee->rf_freq_off -= comp & 0x7f; 239e87b5039SStanislaw Gruszka else 240e87b5039SStanislaw Gruszka dev->ee->rf_freq_off += comp; 241e87b5039SStanislaw Gruszka } 242e87b5039SStanislaw Gruszka 243e87b5039SStanislaw Gruszka static void 244e87b5039SStanislaw Gruszka mt76x0_set_lna_gain(struct mt76x0_dev *dev, u8 *eeprom) 245e87b5039SStanislaw Gruszka { 2465dc5bf28SStanislaw Gruszka u8 gain; 247e87b5039SStanislaw Gruszka 248e87b5039SStanislaw Gruszka dev->ee->lna_gain_2ghz = eeprom[MT_EE_LNA_GAIN_2GHZ]; 249e87b5039SStanislaw Gruszka dev->ee->lna_gain_5ghz[0] = eeprom[MT_EE_LNA_GAIN_5GHZ_0]; 250e87b5039SStanislaw Gruszka 251e87b5039SStanislaw Gruszka gain = eeprom[MT_EE_LNA_GAIN_5GHZ_1]; 252e87b5039SStanislaw Gruszka if (gain == 0xff || gain == 0) 253e87b5039SStanislaw Gruszka dev->ee->lna_gain_5ghz[1] = dev->ee->lna_gain_5ghz[0]; 254e87b5039SStanislaw Gruszka else 255e87b5039SStanislaw Gruszka dev->ee->lna_gain_5ghz[1] = gain; 256e87b5039SStanislaw Gruszka 257e87b5039SStanislaw Gruszka gain = eeprom[MT_EE_LNA_GAIN_5GHZ_2]; 258e87b5039SStanislaw Gruszka if (gain == 0xff || gain == 0) 259e87b5039SStanislaw Gruszka dev->ee->lna_gain_5ghz[2] = dev->ee->lna_gain_5ghz[0]; 260e87b5039SStanislaw Gruszka else 261e87b5039SStanislaw Gruszka dev->ee->lna_gain_5ghz[2] = gain; 262e87b5039SStanislaw Gruszka } 263e87b5039SStanislaw Gruszka 264e87b5039SStanislaw Gruszka static void 265e87b5039SStanislaw Gruszka mt76x0_set_rssi_offset(struct mt76x0_dev *dev, u8 *eeprom) 266e87b5039SStanislaw Gruszka { 267e87b5039SStanislaw Gruszka int i; 268e87b5039SStanislaw Gruszka s8 *rssi_offset = dev->ee->rssi_offset_2ghz; 269e87b5039SStanislaw Gruszka 270e87b5039SStanislaw Gruszka for (i = 0; i < 2; i++) { 271e87b5039SStanislaw Gruszka rssi_offset[i] = eeprom[MT_EE_RSSI_OFFSET + i]; 272e87b5039SStanislaw Gruszka 273e87b5039SStanislaw Gruszka if (rssi_offset[i] < -10 || rssi_offset[i] > 10) { 274e87b5039SStanislaw Gruszka dev_warn(dev->mt76.dev, 275e87b5039SStanislaw Gruszka "Warning: EEPROM RSSI is invalid %02hhx\n", 276e87b5039SStanislaw Gruszka rssi_offset[i]); 277e87b5039SStanislaw Gruszka rssi_offset[i] = 0; 278e87b5039SStanislaw Gruszka } 279e87b5039SStanislaw Gruszka } 280e87b5039SStanislaw Gruszka 281e87b5039SStanislaw Gruszka rssi_offset = dev->ee->rssi_offset_5ghz; 282e87b5039SStanislaw Gruszka 283e87b5039SStanislaw Gruszka for (i = 0; i < 3; i++) { 284e87b5039SStanislaw Gruszka rssi_offset[i] = eeprom[MT_EE_RSSI_OFFSET_5GHZ + i]; 285e87b5039SStanislaw Gruszka 286e87b5039SStanislaw Gruszka if (rssi_offset[i] < -10 || rssi_offset[i] > 10) { 287e87b5039SStanislaw Gruszka dev_warn(dev->mt76.dev, 288e87b5039SStanislaw Gruszka "Warning: EEPROM RSSI is invalid %02hhx\n", 289e87b5039SStanislaw Gruszka rssi_offset[i]); 290e87b5039SStanislaw Gruszka rssi_offset[i] = 0; 291e87b5039SStanislaw Gruszka } 292e87b5039SStanislaw Gruszka } 293e87b5039SStanislaw Gruszka } 294e87b5039SStanislaw Gruszka 295e87b5039SStanislaw Gruszka static u32 296e87b5039SStanislaw Gruszka calc_bw40_power_rate(u32 value, int delta) 297e87b5039SStanislaw Gruszka { 298e87b5039SStanislaw Gruszka u32 ret = 0; 299e87b5039SStanislaw Gruszka int i, tmp; 300e87b5039SStanislaw Gruszka 301e87b5039SStanislaw Gruszka for (i = 0; i < 4; i++) { 302e87b5039SStanislaw Gruszka tmp = s6_to_int((value >> i*8) & 0xff) + delta; 303e87b5039SStanislaw Gruszka ret |= (u32)(int_to_s6(tmp)) << i*8; 304e87b5039SStanislaw Gruszka } 305e87b5039SStanislaw Gruszka 306e87b5039SStanislaw Gruszka return ret; 307e87b5039SStanislaw Gruszka } 308e87b5039SStanislaw Gruszka 309e87b5039SStanislaw Gruszka static s8 310e87b5039SStanislaw Gruszka get_delta(u8 val) 311e87b5039SStanislaw Gruszka { 312e87b5039SStanislaw Gruszka s8 ret; 313e87b5039SStanislaw Gruszka 314e87b5039SStanislaw Gruszka if (!field_valid(val) || !(val & BIT(7))) 315e87b5039SStanislaw Gruszka return 0; 316e87b5039SStanislaw Gruszka 317e87b5039SStanislaw Gruszka ret = val & 0x1f; 318e87b5039SStanislaw Gruszka if (ret > 8) 319e87b5039SStanislaw Gruszka ret = 8; 320e87b5039SStanislaw Gruszka if (val & BIT(6)) 321e87b5039SStanislaw Gruszka ret = -ret; 322e87b5039SStanislaw Gruszka 323e87b5039SStanislaw Gruszka return ret; 324e87b5039SStanislaw Gruszka } 325e87b5039SStanislaw Gruszka 326e87b5039SStanislaw Gruszka static void 327e87b5039SStanislaw Gruszka mt76x0_set_tx_power_per_rate(struct mt76x0_dev *dev, u8 *eeprom) 328e87b5039SStanislaw Gruszka { 329e87b5039SStanislaw Gruszka s8 bw40_delta_2g, bw40_delta_5g; 330e87b5039SStanislaw Gruszka u32 val; 331e87b5039SStanislaw Gruszka int i; 332e87b5039SStanislaw Gruszka 333e87b5039SStanislaw Gruszka bw40_delta_2g = get_delta(eeprom[MT_EE_TX_POWER_DELTA_BW40]); 334e87b5039SStanislaw Gruszka bw40_delta_5g = get_delta(eeprom[MT_EE_TX_POWER_DELTA_BW40 + 1]); 335e87b5039SStanislaw Gruszka 336e87b5039SStanislaw Gruszka for (i = 0; i < 5; i++) { 337e87b5039SStanislaw Gruszka val = get_unaligned_le32(eeprom + MT_EE_TX_POWER_BYRATE(i)); 338e87b5039SStanislaw Gruszka 339e87b5039SStanislaw Gruszka /* Skip last 16 bits. */ 340e87b5039SStanislaw Gruszka if (i == 4) 341e87b5039SStanislaw Gruszka val &= 0x0000ffff; 342e87b5039SStanislaw Gruszka 343e87b5039SStanislaw Gruszka dev->ee->tx_pwr_cfg_2g[i][0] = val; 344e87b5039SStanislaw Gruszka dev->ee->tx_pwr_cfg_2g[i][1] = calc_bw40_power_rate(val, bw40_delta_2g); 345e87b5039SStanislaw Gruszka } 346e87b5039SStanislaw Gruszka 347e87b5039SStanislaw Gruszka /* Reading per rate tx power for 5 GHz band is a bit more complex. Note 348e87b5039SStanislaw Gruszka * we mix 16 bit and 32 bit reads and sometimes do shifts. 349e87b5039SStanislaw Gruszka */ 350e87b5039SStanislaw Gruszka val = get_unaligned_le16(eeprom + 0x120); 351e87b5039SStanislaw Gruszka val <<= 16; 352e87b5039SStanislaw Gruszka dev->ee->tx_pwr_cfg_5g[0][0] = val; 353e87b5039SStanislaw Gruszka dev->ee->tx_pwr_cfg_5g[0][1] = calc_bw40_power_rate(val, bw40_delta_5g); 354e87b5039SStanislaw Gruszka 355e87b5039SStanislaw Gruszka val = get_unaligned_le32(eeprom + 0x122); 356e87b5039SStanislaw Gruszka dev->ee->tx_pwr_cfg_5g[1][0] = val; 357e87b5039SStanislaw Gruszka dev->ee->tx_pwr_cfg_5g[1][1] = calc_bw40_power_rate(val, bw40_delta_5g); 358e87b5039SStanislaw Gruszka 359e87b5039SStanislaw Gruszka val = get_unaligned_le16(eeprom + 0x126); 360e87b5039SStanislaw Gruszka dev->ee->tx_pwr_cfg_5g[2][0] = val; 361e87b5039SStanislaw Gruszka dev->ee->tx_pwr_cfg_5g[2][1] = calc_bw40_power_rate(val, bw40_delta_5g); 362e87b5039SStanislaw Gruszka 363e87b5039SStanislaw Gruszka val = get_unaligned_le16(eeprom + 0xec); 364e87b5039SStanislaw Gruszka val <<= 16; 365e87b5039SStanislaw Gruszka dev->ee->tx_pwr_cfg_5g[3][0] = val; 366e87b5039SStanislaw Gruszka dev->ee->tx_pwr_cfg_5g[3][1] = calc_bw40_power_rate(val, bw40_delta_5g); 367e87b5039SStanislaw Gruszka 368e87b5039SStanislaw Gruszka val = get_unaligned_le16(eeprom + 0xee); 369e87b5039SStanislaw Gruszka dev->ee->tx_pwr_cfg_5g[4][0] = val; 370e87b5039SStanislaw Gruszka dev->ee->tx_pwr_cfg_5g[4][1] = calc_bw40_power_rate(val, bw40_delta_5g); 371e87b5039SStanislaw Gruszka } 372e87b5039SStanislaw Gruszka 373e87b5039SStanislaw Gruszka static void 374e87b5039SStanislaw Gruszka mt76x0_set_tx_power_per_chan(struct mt76x0_dev *dev, u8 *eeprom) 375e87b5039SStanislaw Gruszka { 376e87b5039SStanislaw Gruszka int i; 377e87b5039SStanislaw Gruszka u8 tx_pwr; 378e87b5039SStanislaw Gruszka 379e87b5039SStanislaw Gruszka for (i = 0; i < 14; i++) { 380e87b5039SStanislaw Gruszka tx_pwr = eeprom[MT_EE_TX_POWER_OFFSET_2GHZ + i]; 381e87b5039SStanislaw Gruszka if (tx_pwr <= 0x3f && tx_pwr > 0) 382e87b5039SStanislaw Gruszka dev->ee->tx_pwr_per_chan[i] = tx_pwr; 383e87b5039SStanislaw Gruszka else 384e87b5039SStanislaw Gruszka dev->ee->tx_pwr_per_chan[i] = 5; 385e87b5039SStanislaw Gruszka } 386e87b5039SStanislaw Gruszka 387e87b5039SStanislaw Gruszka for (i = 0; i < 40; i++) { 388e87b5039SStanislaw Gruszka tx_pwr = eeprom[MT_EE_TX_POWER_OFFSET_5GHZ + i]; 389e87b5039SStanislaw Gruszka if (tx_pwr <= 0x3f && tx_pwr > 0) 390e87b5039SStanislaw Gruszka dev->ee->tx_pwr_per_chan[14 + i] = tx_pwr; 391e87b5039SStanislaw Gruszka else 392e87b5039SStanislaw Gruszka dev->ee->tx_pwr_per_chan[14 + i] = 5; 393e87b5039SStanislaw Gruszka } 394e87b5039SStanislaw Gruszka 395e87b5039SStanislaw Gruszka dev->ee->tx_pwr_per_chan[54] = dev->ee->tx_pwr_per_chan[22]; 396e87b5039SStanislaw Gruszka dev->ee->tx_pwr_per_chan[55] = dev->ee->tx_pwr_per_chan[28]; 397e87b5039SStanislaw Gruszka dev->ee->tx_pwr_per_chan[56] = dev->ee->tx_pwr_per_chan[34]; 398e87b5039SStanislaw Gruszka dev->ee->tx_pwr_per_chan[57] = dev->ee->tx_pwr_per_chan[44]; 399e87b5039SStanislaw Gruszka } 400e87b5039SStanislaw Gruszka 401e87b5039SStanislaw Gruszka int 402e87b5039SStanislaw Gruszka mt76x0_eeprom_init(struct mt76x0_dev *dev) 403e87b5039SStanislaw Gruszka { 404e87b5039SStanislaw Gruszka u8 *eeprom; 405e87b5039SStanislaw Gruszka int i, ret; 406e87b5039SStanislaw Gruszka 407e87b5039SStanislaw Gruszka ret = mt76x0_efuse_physical_size_check(dev); 408e87b5039SStanislaw Gruszka if (ret) 409e87b5039SStanislaw Gruszka return ret; 410e87b5039SStanislaw Gruszka 411e87b5039SStanislaw Gruszka dev->ee = devm_kzalloc(dev->mt76.dev, sizeof(*dev->ee), GFP_KERNEL); 412e87b5039SStanislaw Gruszka if (!dev->ee) 413e87b5039SStanislaw Gruszka return -ENOMEM; 414e87b5039SStanislaw Gruszka 415e87b5039SStanislaw Gruszka eeprom = kmalloc(MT76X0_EEPROM_SIZE, GFP_KERNEL); 416e87b5039SStanislaw Gruszka if (!eeprom) 417e87b5039SStanislaw Gruszka return -ENOMEM; 418e87b5039SStanislaw Gruszka 419e87b5039SStanislaw Gruszka for (i = 0; i + 16 <= MT76X0_EEPROM_SIZE; i += 16) { 420e87b5039SStanislaw Gruszka ret = mt76x0_efuse_read(dev, i, eeprom + i, MT_EE_READ); 421e87b5039SStanislaw Gruszka if (ret) 422e87b5039SStanislaw Gruszka goto out; 423e87b5039SStanislaw Gruszka } 424e87b5039SStanislaw Gruszka 425e87b5039SStanislaw Gruszka if (eeprom[MT_EE_VERSION_EE] > MT76X0U_EE_MAX_VER) 426e87b5039SStanislaw Gruszka dev_warn(dev->mt76.dev, 427e87b5039SStanislaw Gruszka "Warning: unsupported EEPROM version %02hhx\n", 428e87b5039SStanislaw Gruszka eeprom[MT_EE_VERSION_EE]); 429e87b5039SStanislaw Gruszka dev_info(dev->mt76.dev, "EEPROM ver:%02hhx fae:%02hhx\n", 430e87b5039SStanislaw Gruszka eeprom[MT_EE_VERSION_EE], eeprom[MT_EE_VERSION_FAE]); 431e87b5039SStanislaw Gruszka 432e87b5039SStanislaw Gruszka mt76x0_set_macaddr(dev, eeprom); 433e87b5039SStanislaw Gruszka mt76x0_set_chip_cap(dev, eeprom); 434e87b5039SStanislaw Gruszka mt76x0_set_country_reg(dev, eeprom); 435e87b5039SStanislaw Gruszka mt76x0_set_rf_freq_off(dev, eeprom); 436e87b5039SStanislaw Gruszka mt76x0_set_temp_offset(dev, eeprom); 437e87b5039SStanislaw Gruszka mt76x0_set_lna_gain(dev, eeprom); 438e87b5039SStanislaw Gruszka mt76x0_set_rssi_offset(dev, eeprom); 439e87b5039SStanislaw Gruszka dev->chainmask = 0x0101; 440e87b5039SStanislaw Gruszka 441e87b5039SStanislaw Gruszka mt76x0_set_tx_power_per_rate(dev, eeprom); 442e87b5039SStanislaw Gruszka mt76x0_set_tx_power_per_chan(dev, eeprom); 443e87b5039SStanislaw Gruszka 444e87b5039SStanislaw Gruszka out: 445e87b5039SStanislaw Gruszka kfree(eeprom); 446e87b5039SStanislaw Gruszka return ret; 447e87b5039SStanislaw Gruszka } 448*c2a4d9fbSStanislaw Gruszka 449*c2a4d9fbSStanislaw Gruszka MODULE_LICENSE("Dual BSD/GPL"); 450