162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org> 462306a36Sopenharmony_ci * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl> 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/of.h> 862306a36Sopenharmony_ci#include <linux/mtd/mtd.h> 962306a36Sopenharmony_ci#include <linux/mtd/partitions.h> 1062306a36Sopenharmony_ci#include <linux/etherdevice.h> 1162306a36Sopenharmony_ci#include <asm/unaligned.h> 1262306a36Sopenharmony_ci#include "mt7601u.h" 1362306a36Sopenharmony_ci#include "eeprom.h" 1462306a36Sopenharmony_ci#include "mac.h" 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_cistatic bool 1762306a36Sopenharmony_cifield_valid(u8 val) 1862306a36Sopenharmony_ci{ 1962306a36Sopenharmony_ci return val != 0xff; 2062306a36Sopenharmony_ci} 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_cistatic s8 2362306a36Sopenharmony_cifield_validate(u8 val) 2462306a36Sopenharmony_ci{ 2562306a36Sopenharmony_ci if (!field_valid(val)) 2662306a36Sopenharmony_ci return 0; 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci return val; 2962306a36Sopenharmony_ci} 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_cistatic int 3262306a36Sopenharmony_cimt7601u_efuse_read(struct mt7601u_dev *dev, u16 addr, u8 *data, 3362306a36Sopenharmony_ci enum mt7601u_eeprom_access_modes mode) 3462306a36Sopenharmony_ci{ 3562306a36Sopenharmony_ci u32 val; 3662306a36Sopenharmony_ci int i; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci val = mt76_rr(dev, MT_EFUSE_CTRL); 3962306a36Sopenharmony_ci val &= ~(MT_EFUSE_CTRL_AIN | 4062306a36Sopenharmony_ci MT_EFUSE_CTRL_MODE); 4162306a36Sopenharmony_ci val |= FIELD_PREP(MT_EFUSE_CTRL_AIN, addr & ~0xf) | 4262306a36Sopenharmony_ci FIELD_PREP(MT_EFUSE_CTRL_MODE, mode) | 4362306a36Sopenharmony_ci MT_EFUSE_CTRL_KICK; 4462306a36Sopenharmony_ci mt76_wr(dev, MT_EFUSE_CTRL, val); 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci if (!mt76_poll(dev, MT_EFUSE_CTRL, MT_EFUSE_CTRL_KICK, 0, 1000)) 4762306a36Sopenharmony_ci return -ETIMEDOUT; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci val = mt76_rr(dev, MT_EFUSE_CTRL); 5062306a36Sopenharmony_ci if ((val & MT_EFUSE_CTRL_AOUT) == MT_EFUSE_CTRL_AOUT) { 5162306a36Sopenharmony_ci /* Parts of eeprom not in the usage map (0x80-0xc0,0xf0) 5262306a36Sopenharmony_ci * will not return valid data but it's ok. 5362306a36Sopenharmony_ci */ 5462306a36Sopenharmony_ci memset(data, 0xff, 16); 5562306a36Sopenharmony_ci return 0; 5662306a36Sopenharmony_ci } 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci for (i = 0; i < 4; i++) { 5962306a36Sopenharmony_ci val = mt76_rr(dev, MT_EFUSE_DATA(i)); 6062306a36Sopenharmony_ci put_unaligned_le32(val, data + 4 * i); 6162306a36Sopenharmony_ci } 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci return 0; 6462306a36Sopenharmony_ci} 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_cistatic int 6762306a36Sopenharmony_cimt7601u_efuse_physical_size_check(struct mt7601u_dev *dev) 6862306a36Sopenharmony_ci{ 6962306a36Sopenharmony_ci const int map_reads = DIV_ROUND_UP(MT_EFUSE_USAGE_MAP_SIZE, 16); 7062306a36Sopenharmony_ci u8 data[round_up(MT_EFUSE_USAGE_MAP_SIZE, 16)]; 7162306a36Sopenharmony_ci int ret, i; 7262306a36Sopenharmony_ci u32 start = 0, end = 0, cnt_free; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci for (i = 0; i < map_reads; i++) { 7562306a36Sopenharmony_ci ret = mt7601u_efuse_read(dev, MT_EE_USAGE_MAP_START + i * 16, 7662306a36Sopenharmony_ci data + i * 16, MT_EE_PHYSICAL_READ); 7762306a36Sopenharmony_ci if (ret) 7862306a36Sopenharmony_ci return ret; 7962306a36Sopenharmony_ci } 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci for (i = 0; i < MT_EFUSE_USAGE_MAP_SIZE; i++) 8262306a36Sopenharmony_ci if (!data[i]) { 8362306a36Sopenharmony_ci if (!start) 8462306a36Sopenharmony_ci start = MT_EE_USAGE_MAP_START + i; 8562306a36Sopenharmony_ci end = MT_EE_USAGE_MAP_START + i; 8662306a36Sopenharmony_ci } 8762306a36Sopenharmony_ci cnt_free = end - start + 1; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci if (MT_EFUSE_USAGE_MAP_SIZE - cnt_free < 5) { 9062306a36Sopenharmony_ci dev_err(dev->dev, "Error: your device needs default EEPROM file and this driver doesn't support it!\n"); 9162306a36Sopenharmony_ci return -EINVAL; 9262306a36Sopenharmony_ci } 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci return 0; 9562306a36Sopenharmony_ci} 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_cistatic bool 9862306a36Sopenharmony_cimt7601u_has_tssi(struct mt7601u_dev *dev, u8 *eeprom) 9962306a36Sopenharmony_ci{ 10062306a36Sopenharmony_ci u16 nic_conf1 = get_unaligned_le16(eeprom + MT_EE_NIC_CONF_1); 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci return (u16)~nic_conf1 && (nic_conf1 & MT_EE_NIC_CONF_1_TX_ALC_EN); 10362306a36Sopenharmony_ci} 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_cistatic void 10662306a36Sopenharmony_cimt7601u_set_chip_cap(struct mt7601u_dev *dev, u8 *eeprom) 10762306a36Sopenharmony_ci{ 10862306a36Sopenharmony_ci u16 nic_conf0 = get_unaligned_le16(eeprom + MT_EE_NIC_CONF_0); 10962306a36Sopenharmony_ci u16 nic_conf1 = get_unaligned_le16(eeprom + MT_EE_NIC_CONF_1); 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci if (!field_valid(nic_conf1 & 0xff)) 11262306a36Sopenharmony_ci nic_conf1 &= 0xff00; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci dev->ee->tssi_enabled = mt7601u_has_tssi(dev, eeprom) && 11562306a36Sopenharmony_ci !(nic_conf1 & MT_EE_NIC_CONF_1_TEMP_TX_ALC); 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci if (nic_conf1 & MT_EE_NIC_CONF_1_HW_RF_CTRL) 11862306a36Sopenharmony_ci dev_err(dev->dev, 11962306a36Sopenharmony_ci "Error: this driver does not support HW RF ctrl\n"); 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci if (!field_valid(nic_conf0 >> 8)) 12262306a36Sopenharmony_ci return; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci if (FIELD_GET(MT_EE_NIC_CONF_0_RX_PATH, nic_conf0) > 1 || 12562306a36Sopenharmony_ci FIELD_GET(MT_EE_NIC_CONF_0_TX_PATH, nic_conf0) > 1) 12662306a36Sopenharmony_ci dev_err(dev->dev, 12762306a36Sopenharmony_ci "Error: device has more than 1 RX/TX stream!\n"); 12862306a36Sopenharmony_ci} 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_cistatic void mt7601u_set_channel_target_power(struct mt7601u_dev *dev, 13162306a36Sopenharmony_ci u8 *eeprom, u8 max_pwr) 13262306a36Sopenharmony_ci{ 13362306a36Sopenharmony_ci u8 trgt_pwr = eeprom[MT_EE_TX_TSSI_TARGET_POWER]; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci if (trgt_pwr > max_pwr || !trgt_pwr) { 13662306a36Sopenharmony_ci dev_warn(dev->dev, "Error: EEPROM trgt power invalid %hhx!\n", 13762306a36Sopenharmony_ci trgt_pwr); 13862306a36Sopenharmony_ci trgt_pwr = 0x20; 13962306a36Sopenharmony_ci } 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci memset(dev->ee->chan_pwr, trgt_pwr, sizeof(dev->ee->chan_pwr)); 14262306a36Sopenharmony_ci} 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_cistatic void 14562306a36Sopenharmony_cimt7601u_set_channel_power(struct mt7601u_dev *dev, u8 *eeprom) 14662306a36Sopenharmony_ci{ 14762306a36Sopenharmony_ci u32 i, val; 14862306a36Sopenharmony_ci u8 max_pwr; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci val = mt7601u_rr(dev, MT_TX_ALC_CFG_0); 15162306a36Sopenharmony_ci max_pwr = FIELD_GET(MT_TX_ALC_CFG_0_LIMIT_0, val); 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci if (mt7601u_has_tssi(dev, eeprom)) { 15462306a36Sopenharmony_ci mt7601u_set_channel_target_power(dev, eeprom, max_pwr); 15562306a36Sopenharmony_ci return; 15662306a36Sopenharmony_ci } 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci for (i = 0; i < 14; i++) { 15962306a36Sopenharmony_ci s8 power = field_validate(eeprom[MT_EE_TX_POWER_OFFSET + i]); 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci if (power > max_pwr || power < 0) 16262306a36Sopenharmony_ci power = MT7601U_DEFAULT_TX_POWER; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci dev->ee->chan_pwr[i] = power; 16562306a36Sopenharmony_ci } 16662306a36Sopenharmony_ci} 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_cistatic void 16962306a36Sopenharmony_cimt7601u_set_country_reg(struct mt7601u_dev *dev, u8 *eeprom) 17062306a36Sopenharmony_ci{ 17162306a36Sopenharmony_ci /* Note: - region 31 is not valid for mt7601u (see rtmp_init.c) 17262306a36Sopenharmony_ci * - comments in rtmp_def.h are incorrect (see rt_channel.c) 17362306a36Sopenharmony_ci */ 17462306a36Sopenharmony_ci static const struct reg_channel_bounds chan_bounds[] = { 17562306a36Sopenharmony_ci /* EEPROM country regions 0 - 7 */ 17662306a36Sopenharmony_ci { 1, 11 }, { 1, 13 }, { 10, 2 }, { 10, 4 }, 17762306a36Sopenharmony_ci { 14, 1 }, { 1, 14 }, { 3, 7 }, { 5, 9 }, 17862306a36Sopenharmony_ci /* EEPROM country regions 32 - 33 */ 17962306a36Sopenharmony_ci { 1, 11 }, { 1, 14 } 18062306a36Sopenharmony_ci }; 18162306a36Sopenharmony_ci u8 val = eeprom[MT_EE_COUNTRY_REGION]; 18262306a36Sopenharmony_ci int idx = -1; 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci if (val < 8) 18562306a36Sopenharmony_ci idx = val; 18662306a36Sopenharmony_ci if (val > 31 && val < 33) 18762306a36Sopenharmony_ci idx = val - 32 + 8; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci if (idx != -1) 19062306a36Sopenharmony_ci dev_info(dev->dev, 19162306a36Sopenharmony_ci "EEPROM country region %02x (channels %d-%d)\n", 19262306a36Sopenharmony_ci val, chan_bounds[idx].start, 19362306a36Sopenharmony_ci chan_bounds[idx].start + chan_bounds[idx].num - 1); 19462306a36Sopenharmony_ci else 19562306a36Sopenharmony_ci idx = 5; /* channels 1 - 14 */ 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci dev->ee->reg = chan_bounds[idx]; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci /* TODO: country region 33 is special - phy should be set to B-mode 20062306a36Sopenharmony_ci * before entering channel 14 (see sta/connect.c) 20162306a36Sopenharmony_ci */ 20262306a36Sopenharmony_ci} 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_cistatic void 20562306a36Sopenharmony_cimt7601u_set_rf_freq_off(struct mt7601u_dev *dev, u8 *eeprom) 20662306a36Sopenharmony_ci{ 20762306a36Sopenharmony_ci u8 comp; 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci dev->ee->rf_freq_off = field_validate(eeprom[MT_EE_FREQ_OFFSET]); 21062306a36Sopenharmony_ci comp = field_validate(eeprom[MT_EE_FREQ_OFFSET_COMPENSATION]); 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci if (comp & BIT(7)) 21362306a36Sopenharmony_ci dev->ee->rf_freq_off -= comp & 0x7f; 21462306a36Sopenharmony_ci else 21562306a36Sopenharmony_ci dev->ee->rf_freq_off += comp; 21662306a36Sopenharmony_ci} 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_cistatic void 21962306a36Sopenharmony_cimt7601u_set_rssi_offset(struct mt7601u_dev *dev, u8 *eeprom) 22062306a36Sopenharmony_ci{ 22162306a36Sopenharmony_ci int i; 22262306a36Sopenharmony_ci s8 *rssi_offset = dev->ee->rssi_offset; 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci for (i = 0; i < 2; i++) { 22562306a36Sopenharmony_ci rssi_offset[i] = eeprom[MT_EE_RSSI_OFFSET + i]; 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci if (rssi_offset[i] < -10 || rssi_offset[i] > 10) { 22862306a36Sopenharmony_ci dev_warn(dev->dev, 22962306a36Sopenharmony_ci "Warning: EEPROM RSSI is invalid %02hhx\n", 23062306a36Sopenharmony_ci rssi_offset[i]); 23162306a36Sopenharmony_ci rssi_offset[i] = 0; 23262306a36Sopenharmony_ci } 23362306a36Sopenharmony_ci } 23462306a36Sopenharmony_ci} 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_cistatic void 23762306a36Sopenharmony_cimt7601u_extra_power_over_mac(struct mt7601u_dev *dev) 23862306a36Sopenharmony_ci{ 23962306a36Sopenharmony_ci u32 val; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci val = ((mt7601u_rr(dev, MT_TX_PWR_CFG_1) & 0x0000ff00) >> 8); 24262306a36Sopenharmony_ci val |= ((mt7601u_rr(dev, MT_TX_PWR_CFG_2) & 0x0000ff00) << 8); 24362306a36Sopenharmony_ci mt7601u_wr(dev, MT_TX_PWR_CFG_7, val); 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci val = ((mt7601u_rr(dev, MT_TX_PWR_CFG_4) & 0x0000ff00) >> 8); 24662306a36Sopenharmony_ci mt7601u_wr(dev, MT_TX_PWR_CFG_9, val); 24762306a36Sopenharmony_ci} 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_cistatic void 25062306a36Sopenharmony_cimt7601u_set_power_rate(struct power_per_rate *rate, s8 delta, u8 value) 25162306a36Sopenharmony_ci{ 25262306a36Sopenharmony_ci /* Invalid? Note: vendor driver does not handle this */ 25362306a36Sopenharmony_ci if (value == 0xff) 25462306a36Sopenharmony_ci return; 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci rate->raw = s6_validate(value); 25762306a36Sopenharmony_ci rate->bw20 = s6_to_int(value); 25862306a36Sopenharmony_ci /* Note: vendor driver does cap the value to s6 right away */ 25962306a36Sopenharmony_ci rate->bw40 = rate->bw20 + delta; 26062306a36Sopenharmony_ci} 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_cistatic void 26362306a36Sopenharmony_cimt7601u_save_power_rate(struct mt7601u_dev *dev, s8 delta, u32 val, int i) 26462306a36Sopenharmony_ci{ 26562306a36Sopenharmony_ci struct mt7601u_rate_power *t = &dev->ee->power_rate_table; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci switch (i) { 26862306a36Sopenharmony_ci case 0: 26962306a36Sopenharmony_ci mt7601u_set_power_rate(&t->cck[0], delta, (val >> 0) & 0xff); 27062306a36Sopenharmony_ci mt7601u_set_power_rate(&t->cck[1], delta, (val >> 8) & 0xff); 27162306a36Sopenharmony_ci /* Save cck bw20 for fixups of channel 14 */ 27262306a36Sopenharmony_ci dev->ee->real_cck_bw20[0] = t->cck[0].bw20; 27362306a36Sopenharmony_ci dev->ee->real_cck_bw20[1] = t->cck[1].bw20; 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci mt7601u_set_power_rate(&t->ofdm[0], delta, (val >> 16) & 0xff); 27662306a36Sopenharmony_ci mt7601u_set_power_rate(&t->ofdm[1], delta, (val >> 24) & 0xff); 27762306a36Sopenharmony_ci break; 27862306a36Sopenharmony_ci case 1: 27962306a36Sopenharmony_ci mt7601u_set_power_rate(&t->ofdm[2], delta, (val >> 0) & 0xff); 28062306a36Sopenharmony_ci mt7601u_set_power_rate(&t->ofdm[3], delta, (val >> 8) & 0xff); 28162306a36Sopenharmony_ci mt7601u_set_power_rate(&t->ht[0], delta, (val >> 16) & 0xff); 28262306a36Sopenharmony_ci mt7601u_set_power_rate(&t->ht[1], delta, (val >> 24) & 0xff); 28362306a36Sopenharmony_ci break; 28462306a36Sopenharmony_ci case 2: 28562306a36Sopenharmony_ci mt7601u_set_power_rate(&t->ht[2], delta, (val >> 0) & 0xff); 28662306a36Sopenharmony_ci mt7601u_set_power_rate(&t->ht[3], delta, (val >> 8) & 0xff); 28762306a36Sopenharmony_ci break; 28862306a36Sopenharmony_ci } 28962306a36Sopenharmony_ci} 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_cistatic s8 29262306a36Sopenharmony_ciget_delta(u8 val) 29362306a36Sopenharmony_ci{ 29462306a36Sopenharmony_ci s8 ret; 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci if (!field_valid(val) || !(val & BIT(7))) 29762306a36Sopenharmony_ci return 0; 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci ret = val & 0x1f; 30062306a36Sopenharmony_ci if (ret > 8) 30162306a36Sopenharmony_ci ret = 8; 30262306a36Sopenharmony_ci if (val & BIT(6)) 30362306a36Sopenharmony_ci ret = -ret; 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci return ret; 30662306a36Sopenharmony_ci} 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_cistatic void 30962306a36Sopenharmony_cimt7601u_config_tx_power_per_rate(struct mt7601u_dev *dev, u8 *eeprom) 31062306a36Sopenharmony_ci{ 31162306a36Sopenharmony_ci u32 val; 31262306a36Sopenharmony_ci s8 bw40_delta; 31362306a36Sopenharmony_ci int i; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci bw40_delta = get_delta(eeprom[MT_EE_TX_POWER_DELTA_BW40]); 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci for (i = 0; i < 5; i++) { 31862306a36Sopenharmony_ci val = get_unaligned_le32(eeprom + MT_EE_TX_POWER_BYRATE(i)); 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci mt7601u_save_power_rate(dev, bw40_delta, val, i); 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci if (~val) 32362306a36Sopenharmony_ci mt7601u_wr(dev, MT_TX_PWR_CFG_0 + i * 4, val); 32462306a36Sopenharmony_ci } 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci mt7601u_extra_power_over_mac(dev); 32762306a36Sopenharmony_ci} 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_cistatic void 33062306a36Sopenharmony_cimt7601u_init_tssi_params(struct mt7601u_dev *dev, u8 *eeprom) 33162306a36Sopenharmony_ci{ 33262306a36Sopenharmony_ci struct tssi_data *d = &dev->ee->tssi_data; 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci if (!dev->ee->tssi_enabled) 33562306a36Sopenharmony_ci return; 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci d->slope = eeprom[MT_EE_TX_TSSI_SLOPE]; 33862306a36Sopenharmony_ci d->tx0_delta_offset = eeprom[MT_EE_TX_TSSI_OFFSET] * 1024; 33962306a36Sopenharmony_ci d->offset[0] = eeprom[MT_EE_TX_TSSI_OFFSET_GROUP]; 34062306a36Sopenharmony_ci d->offset[1] = eeprom[MT_EE_TX_TSSI_OFFSET_GROUP + 1]; 34162306a36Sopenharmony_ci d->offset[2] = eeprom[MT_EE_TX_TSSI_OFFSET_GROUP + 2]; 34262306a36Sopenharmony_ci} 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ciint 34562306a36Sopenharmony_cimt7601u_eeprom_init(struct mt7601u_dev *dev) 34662306a36Sopenharmony_ci{ 34762306a36Sopenharmony_ci u8 *eeprom; 34862306a36Sopenharmony_ci int i, ret; 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci ret = mt7601u_efuse_physical_size_check(dev); 35162306a36Sopenharmony_ci if (ret) 35262306a36Sopenharmony_ci return ret; 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci dev->ee = devm_kzalloc(dev->dev, sizeof(*dev->ee), GFP_KERNEL); 35562306a36Sopenharmony_ci if (!dev->ee) 35662306a36Sopenharmony_ci return -ENOMEM; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci eeprom = kmalloc(MT7601U_EEPROM_SIZE, GFP_KERNEL); 35962306a36Sopenharmony_ci if (!eeprom) 36062306a36Sopenharmony_ci return -ENOMEM; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci for (i = 0; i + 16 <= MT7601U_EEPROM_SIZE; i += 16) { 36362306a36Sopenharmony_ci ret = mt7601u_efuse_read(dev, i, eeprom + i, MT_EE_READ); 36462306a36Sopenharmony_ci if (ret) 36562306a36Sopenharmony_ci goto out; 36662306a36Sopenharmony_ci } 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci if (eeprom[MT_EE_VERSION_EE] > MT7601U_EE_MAX_VER) 36962306a36Sopenharmony_ci dev_warn(dev->dev, 37062306a36Sopenharmony_ci "Warning: unsupported EEPROM version %02hhx\n", 37162306a36Sopenharmony_ci eeprom[MT_EE_VERSION_EE]); 37262306a36Sopenharmony_ci dev_info(dev->dev, "EEPROM ver:%02hhx fae:%02hhx\n", 37362306a36Sopenharmony_ci eeprom[MT_EE_VERSION_EE], eeprom[MT_EE_VERSION_FAE]); 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci mt7601u_set_macaddr(dev, eeprom + MT_EE_MAC_ADDR); 37662306a36Sopenharmony_ci mt7601u_set_chip_cap(dev, eeprom); 37762306a36Sopenharmony_ci mt7601u_set_channel_power(dev, eeprom); 37862306a36Sopenharmony_ci mt7601u_set_country_reg(dev, eeprom); 37962306a36Sopenharmony_ci mt7601u_set_rf_freq_off(dev, eeprom); 38062306a36Sopenharmony_ci mt7601u_set_rssi_offset(dev, eeprom); 38162306a36Sopenharmony_ci dev->ee->ref_temp = eeprom[MT_EE_REF_TEMP]; 38262306a36Sopenharmony_ci dev->ee->lna_gain = eeprom[MT_EE_LNA_GAIN]; 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci mt7601u_config_tx_power_per_rate(dev, eeprom); 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci mt7601u_init_tssi_params(dev, eeprom); 38762306a36Sopenharmony_ciout: 38862306a36Sopenharmony_ci kfree(eeprom); 38962306a36Sopenharmony_ci return ret; 39062306a36Sopenharmony_ci} 391