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 84e87b5039SStanislaw Gruszka static int 85e87b5039SStanislaw Gruszka mt76x0_efuse_physical_size_check(struct mt76x0_dev *dev) 86e87b5039SStanislaw Gruszka { 87e87b5039SStanislaw Gruszka const int map_reads = DIV_ROUND_UP(MT_EFUSE_USAGE_MAP_SIZE, 16); 88e87b5039SStanislaw Gruszka u8 data[map_reads * 16]; 89e87b5039SStanislaw Gruszka int ret, i; 90e87b5039SStanislaw Gruszka u32 start = 0, end = 0, cnt_free; 91e87b5039SStanislaw Gruszka 92e87b5039SStanislaw Gruszka for (i = 0; i < 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: 126e87b5039SStanislaw Gruszka dev->ee->has_5ghz = true; 127e87b5039SStanislaw Gruszka break; 128e87b5039SStanislaw Gruszka case BOARD_TYPE_2GHZ: 129e87b5039SStanislaw Gruszka dev->ee->has_2ghz = true; 130e87b5039SStanislaw Gruszka break; 131e87b5039SStanislaw Gruszka default: 132e87b5039SStanislaw Gruszka dev->ee->has_2ghz = true; 133e87b5039SStanislaw Gruszka dev->ee->has_5ghz = true; 134e87b5039SStanislaw Gruszka break; 135e87b5039SStanislaw Gruszka } 136e87b5039SStanislaw Gruszka 137e87b5039SStanislaw Gruszka dev_dbg(dev->mt76.dev, "Has 2GHZ %d 5GHZ %d\n", dev->ee->has_2ghz, dev->ee->has_5ghz); 138e87b5039SStanislaw Gruszka 139e87b5039SStanislaw Gruszka if (!field_valid(nic_conf1 & 0xff)) 140e87b5039SStanislaw Gruszka nic_conf1 &= 0xff00; 141e87b5039SStanislaw Gruszka 142e87b5039SStanislaw Gruszka if (nic_conf1 & MT_EE_NIC_CONF_1_HW_RF_CTRL) 143e87b5039SStanislaw Gruszka dev_err(dev->mt76.dev, 144e87b5039SStanislaw Gruszka "Error: this driver does not support HW RF ctrl\n"); 145e87b5039SStanislaw Gruszka 146e87b5039SStanislaw Gruszka if (!field_valid(nic_conf0 >> 8)) 147e87b5039SStanislaw Gruszka return; 148e87b5039SStanislaw Gruszka 149e87b5039SStanislaw Gruszka if (FIELD_GET(MT_EE_NIC_CONF_0_RX_PATH, nic_conf0) > 1 || 150e87b5039SStanislaw Gruszka FIELD_GET(MT_EE_NIC_CONF_0_TX_PATH, nic_conf0) > 1) 151e87b5039SStanislaw Gruszka dev_err(dev->mt76.dev, 152e87b5039SStanislaw Gruszka "Error: device has more than 1 RX/TX stream!\n"); 153e87b5039SStanislaw Gruszka 154e87b5039SStanislaw Gruszka dev->ee->pa_type = FIELD_GET(MT_EE_NIC_CONF_0_PA_TYPE, nic_conf0); 155e87b5039SStanislaw Gruszka dev_dbg(dev->mt76.dev, "PA Type %d\n", dev->ee->pa_type); 156e87b5039SStanislaw Gruszka } 157e87b5039SStanislaw Gruszka 158e87b5039SStanislaw Gruszka static int 159e87b5039SStanislaw Gruszka mt76x0_set_macaddr(struct mt76x0_dev *dev, const u8 *eeprom) 160e87b5039SStanislaw Gruszka { 161e87b5039SStanislaw Gruszka const void *src = eeprom + MT_EE_MAC_ADDR; 162e87b5039SStanislaw Gruszka 163e87b5039SStanislaw Gruszka ether_addr_copy(dev->macaddr, src); 164e87b5039SStanislaw Gruszka 165e87b5039SStanislaw Gruszka if (!is_valid_ether_addr(dev->macaddr)) { 166e87b5039SStanislaw Gruszka eth_random_addr(dev->macaddr); 167e87b5039SStanislaw Gruszka dev_info(dev->mt76.dev, 168e87b5039SStanislaw Gruszka "Invalid MAC address, using random address %pM\n", 169e87b5039SStanislaw Gruszka dev->macaddr); 170e87b5039SStanislaw Gruszka } 171e87b5039SStanislaw Gruszka 172e87b5039SStanislaw Gruszka mt76_wr(dev, MT_MAC_ADDR_DW0, get_unaligned_le32(dev->macaddr)); 173e87b5039SStanislaw Gruszka mt76_wr(dev, MT_MAC_ADDR_DW1, get_unaligned_le16(dev->macaddr + 4) | 174e87b5039SStanislaw Gruszka FIELD_PREP(MT_MAC_ADDR_DW1_U2ME_MASK, 0xff)); 175e87b5039SStanislaw Gruszka 176e87b5039SStanislaw Gruszka return 0; 177e87b5039SStanislaw Gruszka } 178e87b5039SStanislaw Gruszka 179e87b5039SStanislaw Gruszka static void 180e87b5039SStanislaw Gruszka mt76x0_set_temp_offset(struct mt76x0_dev *dev, u8 *eeprom) 181e87b5039SStanislaw Gruszka { 182e87b5039SStanislaw Gruszka u8 temp = eeprom[MT_EE_TEMP_OFFSET]; 183e87b5039SStanislaw Gruszka 184e87b5039SStanislaw Gruszka if (field_valid(temp)) 185e87b5039SStanislaw Gruszka dev->ee->temp_off = sign_extend(temp, 8); 186e87b5039SStanislaw Gruszka else 187e87b5039SStanislaw Gruszka dev->ee->temp_off = -10; 188e87b5039SStanislaw Gruszka } 189e87b5039SStanislaw Gruszka 190e87b5039SStanislaw Gruszka static void 191e87b5039SStanislaw Gruszka mt76x0_set_country_reg(struct mt76x0_dev *dev, u8 *eeprom) 192e87b5039SStanislaw Gruszka { 193e87b5039SStanislaw Gruszka /* Note: - region 31 is not valid for mt76x0 (see rtmp_init.c) 194e87b5039SStanislaw Gruszka * - comments in rtmp_def.h are incorrect (see rt_channel.c) 195e87b5039SStanislaw Gruszka */ 196e87b5039SStanislaw Gruszka static const struct reg_channel_bounds chan_bounds[] = { 197e87b5039SStanislaw Gruszka /* EEPROM country regions 0 - 7 */ 198e87b5039SStanislaw Gruszka { 1, 11 }, { 1, 13 }, { 10, 2 }, { 10, 4 }, 199e87b5039SStanislaw Gruszka { 14, 1 }, { 1, 14 }, { 3, 7 }, { 5, 9 }, 200e87b5039SStanislaw Gruszka /* EEPROM country regions 32 - 33 */ 201e87b5039SStanislaw Gruszka { 1, 11 }, { 1, 14 } 202e87b5039SStanislaw Gruszka }; 203e87b5039SStanislaw Gruszka u8 val = eeprom[MT_EE_COUNTRY_REGION_2GHZ]; 204e87b5039SStanislaw Gruszka int idx = -1; 205e87b5039SStanislaw Gruszka 206e87b5039SStanislaw Gruszka dev_dbg(dev->mt76.dev, "REG 2GHZ %u REG 5GHZ %u\n", val, eeprom[MT_EE_COUNTRY_REGION_5GHZ]); 207e87b5039SStanislaw Gruszka if (val < 8) 208e87b5039SStanislaw Gruszka idx = val; 209e87b5039SStanislaw Gruszka if (val > 31 && val < 33) 210e87b5039SStanislaw Gruszka idx = val - 32 + 8; 211e87b5039SStanislaw Gruszka 212e87b5039SStanislaw Gruszka if (idx != -1) 213e87b5039SStanislaw Gruszka dev_info(dev->mt76.dev, 214e87b5039SStanislaw Gruszka "EEPROM country region %02hhx (channels %hhd-%hhd)\n", 215e87b5039SStanislaw Gruszka val, chan_bounds[idx].start, 216e87b5039SStanislaw Gruszka chan_bounds[idx].start + chan_bounds[idx].num - 1); 217e87b5039SStanislaw Gruszka else 218e87b5039SStanislaw Gruszka idx = 5; /* channels 1 - 14 */ 219e87b5039SStanislaw Gruszka 220e87b5039SStanislaw Gruszka dev->ee->reg = chan_bounds[idx]; 221e87b5039SStanislaw Gruszka 222e87b5039SStanislaw Gruszka /* TODO: country region 33 is special - phy should be set to B-mode 223e87b5039SStanislaw Gruszka * before entering channel 14 (see sta/connect.c) 224e87b5039SStanislaw Gruszka */ 225e87b5039SStanislaw Gruszka } 226e87b5039SStanislaw Gruszka 227e87b5039SStanislaw Gruszka static void 228e87b5039SStanislaw Gruszka mt76x0_set_rf_freq_off(struct mt76x0_dev *dev, u8 *eeprom) 229e87b5039SStanislaw Gruszka { 230e87b5039SStanislaw Gruszka u8 comp; 231e87b5039SStanislaw Gruszka 232e87b5039SStanislaw Gruszka dev->ee->rf_freq_off = field_validate(eeprom[MT_EE_FREQ_OFFSET]); 233e87b5039SStanislaw Gruszka comp = field_validate(eeprom[MT_EE_FREQ_OFFSET_COMPENSATION]); 234e87b5039SStanislaw Gruszka 235e87b5039SStanislaw Gruszka if (comp & BIT(7)) 236e87b5039SStanislaw Gruszka dev->ee->rf_freq_off -= comp & 0x7f; 237e87b5039SStanislaw Gruszka else 238e87b5039SStanislaw Gruszka dev->ee->rf_freq_off += comp; 239e87b5039SStanislaw Gruszka } 240e87b5039SStanislaw Gruszka 241e87b5039SStanislaw Gruszka static void 242e87b5039SStanislaw Gruszka mt76x0_set_lna_gain(struct mt76x0_dev *dev, u8 *eeprom) 243e87b5039SStanislaw Gruszka { 244*5dc5bf28SStanislaw Gruszka u8 gain; 245e87b5039SStanislaw Gruszka 246e87b5039SStanislaw Gruszka dev->ee->lna_gain_2ghz = eeprom[MT_EE_LNA_GAIN_2GHZ]; 247e87b5039SStanislaw Gruszka dev->ee->lna_gain_5ghz[0] = eeprom[MT_EE_LNA_GAIN_5GHZ_0]; 248e87b5039SStanislaw Gruszka 249e87b5039SStanislaw Gruszka gain = eeprom[MT_EE_LNA_GAIN_5GHZ_1]; 250e87b5039SStanislaw Gruszka if (gain == 0xff || gain == 0) 251e87b5039SStanislaw Gruszka dev->ee->lna_gain_5ghz[1] = dev->ee->lna_gain_5ghz[0]; 252e87b5039SStanislaw Gruszka else 253e87b5039SStanislaw Gruszka dev->ee->lna_gain_5ghz[1] = gain; 254e87b5039SStanislaw Gruszka 255e87b5039SStanislaw Gruszka gain = eeprom[MT_EE_LNA_GAIN_5GHZ_2]; 256e87b5039SStanislaw Gruszka if (gain == 0xff || gain == 0) 257e87b5039SStanislaw Gruszka dev->ee->lna_gain_5ghz[2] = dev->ee->lna_gain_5ghz[0]; 258e87b5039SStanislaw Gruszka else 259e87b5039SStanislaw Gruszka dev->ee->lna_gain_5ghz[2] = gain; 260e87b5039SStanislaw Gruszka } 261e87b5039SStanislaw Gruszka 262e87b5039SStanislaw Gruszka static void 263e87b5039SStanislaw Gruszka mt76x0_set_rssi_offset(struct mt76x0_dev *dev, u8 *eeprom) 264e87b5039SStanislaw Gruszka { 265e87b5039SStanislaw Gruszka int i; 266e87b5039SStanislaw Gruszka s8 *rssi_offset = dev->ee->rssi_offset_2ghz; 267e87b5039SStanislaw Gruszka 268e87b5039SStanislaw Gruszka for (i = 0; i < 2; i++) { 269e87b5039SStanislaw Gruszka rssi_offset[i] = eeprom[MT_EE_RSSI_OFFSET + i]; 270e87b5039SStanislaw Gruszka 271e87b5039SStanislaw Gruszka if (rssi_offset[i] < -10 || rssi_offset[i] > 10) { 272e87b5039SStanislaw Gruszka dev_warn(dev->mt76.dev, 273e87b5039SStanislaw Gruszka "Warning: EEPROM RSSI is invalid %02hhx\n", 274e87b5039SStanislaw Gruszka rssi_offset[i]); 275e87b5039SStanislaw Gruszka rssi_offset[i] = 0; 276e87b5039SStanislaw Gruszka } 277e87b5039SStanislaw Gruszka } 278e87b5039SStanislaw Gruszka 279e87b5039SStanislaw Gruszka rssi_offset = dev->ee->rssi_offset_5ghz; 280e87b5039SStanislaw Gruszka 281e87b5039SStanislaw Gruszka for (i = 0; i < 3; i++) { 282e87b5039SStanislaw Gruszka rssi_offset[i] = eeprom[MT_EE_RSSI_OFFSET_5GHZ + i]; 283e87b5039SStanislaw Gruszka 284e87b5039SStanislaw Gruszka if (rssi_offset[i] < -10 || rssi_offset[i] > 10) { 285e87b5039SStanislaw Gruszka dev_warn(dev->mt76.dev, 286e87b5039SStanislaw Gruszka "Warning: EEPROM RSSI is invalid %02hhx\n", 287e87b5039SStanislaw Gruszka rssi_offset[i]); 288e87b5039SStanislaw Gruszka rssi_offset[i] = 0; 289e87b5039SStanislaw Gruszka } 290e87b5039SStanislaw Gruszka } 291e87b5039SStanislaw Gruszka } 292e87b5039SStanislaw Gruszka 293e87b5039SStanislaw Gruszka static u32 294e87b5039SStanislaw Gruszka calc_bw40_power_rate(u32 value, int delta) 295e87b5039SStanislaw Gruszka { 296e87b5039SStanislaw Gruszka u32 ret = 0; 297e87b5039SStanislaw Gruszka int i, tmp; 298e87b5039SStanislaw Gruszka 299e87b5039SStanislaw Gruszka for (i = 0; i < 4; i++) { 300e87b5039SStanislaw Gruszka tmp = s6_to_int((value >> i*8) & 0xff) + delta; 301e87b5039SStanislaw Gruszka ret |= (u32)(int_to_s6(tmp)) << i*8; 302e87b5039SStanislaw Gruszka } 303e87b5039SStanislaw Gruszka 304e87b5039SStanislaw Gruszka return ret; 305e87b5039SStanislaw Gruszka } 306e87b5039SStanislaw Gruszka 307e87b5039SStanislaw Gruszka static s8 308e87b5039SStanislaw Gruszka get_delta(u8 val) 309e87b5039SStanislaw Gruszka { 310e87b5039SStanislaw Gruszka s8 ret; 311e87b5039SStanislaw Gruszka 312e87b5039SStanislaw Gruszka if (!field_valid(val) || !(val & BIT(7))) 313e87b5039SStanislaw Gruszka return 0; 314e87b5039SStanislaw Gruszka 315e87b5039SStanislaw Gruszka ret = val & 0x1f; 316e87b5039SStanislaw Gruszka if (ret > 8) 317e87b5039SStanislaw Gruszka ret = 8; 318e87b5039SStanislaw Gruszka if (val & BIT(6)) 319e87b5039SStanislaw Gruszka ret = -ret; 320e87b5039SStanislaw Gruszka 321e87b5039SStanislaw Gruszka return ret; 322e87b5039SStanislaw Gruszka } 323e87b5039SStanislaw Gruszka 324e87b5039SStanislaw Gruszka static void 325e87b5039SStanislaw Gruszka mt76x0_set_tx_power_per_rate(struct mt76x0_dev *dev, u8 *eeprom) 326e87b5039SStanislaw Gruszka { 327e87b5039SStanislaw Gruszka s8 bw40_delta_2g, bw40_delta_5g; 328e87b5039SStanislaw Gruszka u32 val; 329e87b5039SStanislaw Gruszka int i; 330e87b5039SStanislaw Gruszka 331e87b5039SStanislaw Gruszka bw40_delta_2g = get_delta(eeprom[MT_EE_TX_POWER_DELTA_BW40]); 332e87b5039SStanislaw Gruszka bw40_delta_5g = get_delta(eeprom[MT_EE_TX_POWER_DELTA_BW40 + 1]); 333e87b5039SStanislaw Gruszka 334e87b5039SStanislaw Gruszka for (i = 0; i < 5; i++) { 335e87b5039SStanislaw Gruszka val = get_unaligned_le32(eeprom + MT_EE_TX_POWER_BYRATE(i)); 336e87b5039SStanislaw Gruszka 337e87b5039SStanislaw Gruszka /* Skip last 16 bits. */ 338e87b5039SStanislaw Gruszka if (i == 4) 339e87b5039SStanislaw Gruszka val &= 0x0000ffff; 340e87b5039SStanislaw Gruszka 341e87b5039SStanislaw Gruszka dev->ee->tx_pwr_cfg_2g[i][0] = val; 342e87b5039SStanislaw Gruszka dev->ee->tx_pwr_cfg_2g[i][1] = calc_bw40_power_rate(val, bw40_delta_2g); 343e87b5039SStanislaw Gruszka } 344e87b5039SStanislaw Gruszka 345e87b5039SStanislaw Gruszka /* Reading per rate tx power for 5 GHz band is a bit more complex. Note 346e87b5039SStanislaw Gruszka * we mix 16 bit and 32 bit reads and sometimes do shifts. 347e87b5039SStanislaw Gruszka */ 348e87b5039SStanislaw Gruszka val = get_unaligned_le16(eeprom + 0x120); 349e87b5039SStanislaw Gruszka val <<= 16; 350e87b5039SStanislaw Gruszka dev->ee->tx_pwr_cfg_5g[0][0] = val; 351e87b5039SStanislaw Gruszka dev->ee->tx_pwr_cfg_5g[0][1] = calc_bw40_power_rate(val, bw40_delta_5g); 352e87b5039SStanislaw Gruszka 353e87b5039SStanislaw Gruszka val = get_unaligned_le32(eeprom + 0x122); 354e87b5039SStanislaw Gruszka dev->ee->tx_pwr_cfg_5g[1][0] = val; 355e87b5039SStanislaw Gruszka dev->ee->tx_pwr_cfg_5g[1][1] = calc_bw40_power_rate(val, bw40_delta_5g); 356e87b5039SStanislaw Gruszka 357e87b5039SStanislaw Gruszka val = get_unaligned_le16(eeprom + 0x126); 358e87b5039SStanislaw Gruszka dev->ee->tx_pwr_cfg_5g[2][0] = val; 359e87b5039SStanislaw Gruszka dev->ee->tx_pwr_cfg_5g[2][1] = calc_bw40_power_rate(val, bw40_delta_5g); 360e87b5039SStanislaw Gruszka 361e87b5039SStanislaw Gruszka val = get_unaligned_le16(eeprom + 0xec); 362e87b5039SStanislaw Gruszka val <<= 16; 363e87b5039SStanislaw Gruszka dev->ee->tx_pwr_cfg_5g[3][0] = val; 364e87b5039SStanislaw Gruszka dev->ee->tx_pwr_cfg_5g[3][1] = calc_bw40_power_rate(val, bw40_delta_5g); 365e87b5039SStanislaw Gruszka 366e87b5039SStanislaw Gruszka val = get_unaligned_le16(eeprom + 0xee); 367e87b5039SStanislaw Gruszka dev->ee->tx_pwr_cfg_5g[4][0] = val; 368e87b5039SStanislaw Gruszka dev->ee->tx_pwr_cfg_5g[4][1] = calc_bw40_power_rate(val, bw40_delta_5g); 369e87b5039SStanislaw Gruszka } 370e87b5039SStanislaw Gruszka 371e87b5039SStanislaw Gruszka static void 372e87b5039SStanislaw Gruszka mt76x0_set_tx_power_per_chan(struct mt76x0_dev *dev, u8 *eeprom) 373e87b5039SStanislaw Gruszka { 374e87b5039SStanislaw Gruszka int i; 375e87b5039SStanislaw Gruszka u8 tx_pwr; 376e87b5039SStanislaw Gruszka 377e87b5039SStanislaw Gruszka for (i = 0; i < 14; i++) { 378e87b5039SStanislaw Gruszka tx_pwr = eeprom[MT_EE_TX_POWER_OFFSET_2GHZ + i]; 379e87b5039SStanislaw Gruszka if (tx_pwr <= 0x3f && tx_pwr > 0) 380e87b5039SStanislaw Gruszka dev->ee->tx_pwr_per_chan[i] = tx_pwr; 381e87b5039SStanislaw Gruszka else 382e87b5039SStanislaw Gruszka dev->ee->tx_pwr_per_chan[i] = 5; 383e87b5039SStanislaw Gruszka } 384e87b5039SStanislaw Gruszka 385e87b5039SStanislaw Gruszka for (i = 0; i < 40; i++) { 386e87b5039SStanislaw Gruszka tx_pwr = eeprom[MT_EE_TX_POWER_OFFSET_5GHZ + i]; 387e87b5039SStanislaw Gruszka if (tx_pwr <= 0x3f && tx_pwr > 0) 388e87b5039SStanislaw Gruszka dev->ee->tx_pwr_per_chan[14 + i] = tx_pwr; 389e87b5039SStanislaw Gruszka else 390e87b5039SStanislaw Gruszka dev->ee->tx_pwr_per_chan[14 + i] = 5; 391e87b5039SStanislaw Gruszka } 392e87b5039SStanislaw Gruszka 393e87b5039SStanislaw Gruszka dev->ee->tx_pwr_per_chan[54] = dev->ee->tx_pwr_per_chan[22]; 394e87b5039SStanislaw Gruszka dev->ee->tx_pwr_per_chan[55] = dev->ee->tx_pwr_per_chan[28]; 395e87b5039SStanislaw Gruszka dev->ee->tx_pwr_per_chan[56] = dev->ee->tx_pwr_per_chan[34]; 396e87b5039SStanislaw Gruszka dev->ee->tx_pwr_per_chan[57] = dev->ee->tx_pwr_per_chan[44]; 397e87b5039SStanislaw Gruszka } 398e87b5039SStanislaw Gruszka 399e87b5039SStanislaw Gruszka int 400e87b5039SStanislaw Gruszka mt76x0_eeprom_init(struct mt76x0_dev *dev) 401e87b5039SStanislaw Gruszka { 402e87b5039SStanislaw Gruszka u8 *eeprom; 403e87b5039SStanislaw Gruszka int i, ret; 404e87b5039SStanislaw Gruszka 405e87b5039SStanislaw Gruszka ret = mt76x0_efuse_physical_size_check(dev); 406e87b5039SStanislaw Gruszka if (ret) 407e87b5039SStanislaw Gruszka return ret; 408e87b5039SStanislaw Gruszka 409e87b5039SStanislaw Gruszka dev->ee = devm_kzalloc(dev->mt76.dev, sizeof(*dev->ee), GFP_KERNEL); 410e87b5039SStanislaw Gruszka if (!dev->ee) 411e87b5039SStanislaw Gruszka return -ENOMEM; 412e87b5039SStanislaw Gruszka 413e87b5039SStanislaw Gruszka eeprom = kmalloc(MT76X0_EEPROM_SIZE, GFP_KERNEL); 414e87b5039SStanislaw Gruszka if (!eeprom) 415e87b5039SStanislaw Gruszka return -ENOMEM; 416e87b5039SStanislaw Gruszka 417e87b5039SStanislaw Gruszka for (i = 0; i + 16 <= MT76X0_EEPROM_SIZE; i += 16) { 418e87b5039SStanislaw Gruszka ret = mt76x0_efuse_read(dev, i, eeprom + i, MT_EE_READ); 419e87b5039SStanislaw Gruszka if (ret) 420e87b5039SStanislaw Gruszka goto out; 421e87b5039SStanislaw Gruszka } 422e87b5039SStanislaw Gruszka 423e87b5039SStanislaw Gruszka if (eeprom[MT_EE_VERSION_EE] > MT76X0U_EE_MAX_VER) 424e87b5039SStanislaw Gruszka dev_warn(dev->mt76.dev, 425e87b5039SStanislaw Gruszka "Warning: unsupported EEPROM version %02hhx\n", 426e87b5039SStanislaw Gruszka eeprom[MT_EE_VERSION_EE]); 427e87b5039SStanislaw Gruszka dev_info(dev->mt76.dev, "EEPROM ver:%02hhx fae:%02hhx\n", 428e87b5039SStanislaw Gruszka eeprom[MT_EE_VERSION_EE], eeprom[MT_EE_VERSION_FAE]); 429e87b5039SStanislaw Gruszka 430e87b5039SStanislaw Gruszka mt76x0_set_macaddr(dev, eeprom); 431e87b5039SStanislaw Gruszka mt76x0_set_chip_cap(dev, eeprom); 432e87b5039SStanislaw Gruszka mt76x0_set_country_reg(dev, eeprom); 433e87b5039SStanislaw Gruszka mt76x0_set_rf_freq_off(dev, eeprom); 434e87b5039SStanislaw Gruszka mt76x0_set_temp_offset(dev, eeprom); 435e87b5039SStanislaw Gruszka mt76x0_set_lna_gain(dev, eeprom); 436e87b5039SStanislaw Gruszka mt76x0_set_rssi_offset(dev, eeprom); 437e87b5039SStanislaw Gruszka dev->chainmask = 0x0101; 438e87b5039SStanislaw Gruszka 439e87b5039SStanislaw Gruszka mt76x0_set_tx_power_per_rate(dev, eeprom); 440e87b5039SStanislaw Gruszka mt76x0_set_tx_power_per_chan(dev, eeprom); 441e87b5039SStanislaw Gruszka 442e87b5039SStanislaw Gruszka out: 443e87b5039SStanislaw Gruszka kfree(eeprom); 444e87b5039SStanislaw Gruszka return ret; 445e87b5039SStanislaw Gruszka } 446