18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org> 48c2ecf20Sopenharmony_ci * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl> 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/of.h> 88c2ecf20Sopenharmony_ci#include <linux/mtd/mtd.h> 98c2ecf20Sopenharmony_ci#include <linux/mtd/partitions.h> 108c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 118c2ecf20Sopenharmony_ci#include <asm/unaligned.h> 128c2ecf20Sopenharmony_ci#include "mt7601u.h" 138c2ecf20Sopenharmony_ci#include "eeprom.h" 148c2ecf20Sopenharmony_ci#include "mac.h" 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_cistatic bool 178c2ecf20Sopenharmony_cifield_valid(u8 val) 188c2ecf20Sopenharmony_ci{ 198c2ecf20Sopenharmony_ci return val != 0xff; 208c2ecf20Sopenharmony_ci} 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_cistatic s8 238c2ecf20Sopenharmony_cifield_validate(u8 val) 248c2ecf20Sopenharmony_ci{ 258c2ecf20Sopenharmony_ci if (!field_valid(val)) 268c2ecf20Sopenharmony_ci return 0; 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci return val; 298c2ecf20Sopenharmony_ci} 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_cistatic int 328c2ecf20Sopenharmony_cimt7601u_efuse_read(struct mt7601u_dev *dev, u16 addr, u8 *data, 338c2ecf20Sopenharmony_ci enum mt7601u_eeprom_access_modes mode) 348c2ecf20Sopenharmony_ci{ 358c2ecf20Sopenharmony_ci u32 val; 368c2ecf20Sopenharmony_ci int i; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci val = mt76_rr(dev, MT_EFUSE_CTRL); 398c2ecf20Sopenharmony_ci val &= ~(MT_EFUSE_CTRL_AIN | 408c2ecf20Sopenharmony_ci MT_EFUSE_CTRL_MODE); 418c2ecf20Sopenharmony_ci val |= FIELD_PREP(MT_EFUSE_CTRL_AIN, addr & ~0xf) | 428c2ecf20Sopenharmony_ci FIELD_PREP(MT_EFUSE_CTRL_MODE, mode) | 438c2ecf20Sopenharmony_ci MT_EFUSE_CTRL_KICK; 448c2ecf20Sopenharmony_ci mt76_wr(dev, MT_EFUSE_CTRL, val); 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci if (!mt76_poll(dev, MT_EFUSE_CTRL, MT_EFUSE_CTRL_KICK, 0, 1000)) 478c2ecf20Sopenharmony_ci return -ETIMEDOUT; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci val = mt76_rr(dev, MT_EFUSE_CTRL); 508c2ecf20Sopenharmony_ci if ((val & MT_EFUSE_CTRL_AOUT) == MT_EFUSE_CTRL_AOUT) { 518c2ecf20Sopenharmony_ci /* Parts of eeprom not in the usage map (0x80-0xc0,0xf0) 528c2ecf20Sopenharmony_ci * will not return valid data but it's ok. 538c2ecf20Sopenharmony_ci */ 548c2ecf20Sopenharmony_ci memset(data, 0xff, 16); 558c2ecf20Sopenharmony_ci return 0; 568c2ecf20Sopenharmony_ci } 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) { 598c2ecf20Sopenharmony_ci val = mt76_rr(dev, MT_EFUSE_DATA(i)); 608c2ecf20Sopenharmony_ci put_unaligned_le32(val, data + 4 * i); 618c2ecf20Sopenharmony_ci } 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci return 0; 648c2ecf20Sopenharmony_ci} 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_cistatic int 678c2ecf20Sopenharmony_cimt7601u_efuse_physical_size_check(struct mt7601u_dev *dev) 688c2ecf20Sopenharmony_ci{ 698c2ecf20Sopenharmony_ci const int map_reads = DIV_ROUND_UP(MT_EFUSE_USAGE_MAP_SIZE, 16); 708c2ecf20Sopenharmony_ci u8 data[round_up(MT_EFUSE_USAGE_MAP_SIZE, 16)]; 718c2ecf20Sopenharmony_ci int ret, i; 728c2ecf20Sopenharmony_ci u32 start = 0, end = 0, cnt_free; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci for (i = 0; i < map_reads; i++) { 758c2ecf20Sopenharmony_ci ret = mt7601u_efuse_read(dev, MT_EE_USAGE_MAP_START + i * 16, 768c2ecf20Sopenharmony_ci data + i * 16, MT_EE_PHYSICAL_READ); 778c2ecf20Sopenharmony_ci if (ret) 788c2ecf20Sopenharmony_ci return ret; 798c2ecf20Sopenharmony_ci } 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci for (i = 0; i < MT_EFUSE_USAGE_MAP_SIZE; i++) 828c2ecf20Sopenharmony_ci if (!data[i]) { 838c2ecf20Sopenharmony_ci if (!start) 848c2ecf20Sopenharmony_ci start = MT_EE_USAGE_MAP_START + i; 858c2ecf20Sopenharmony_ci end = MT_EE_USAGE_MAP_START + i; 868c2ecf20Sopenharmony_ci } 878c2ecf20Sopenharmony_ci cnt_free = end - start + 1; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci if (MT_EFUSE_USAGE_MAP_SIZE - cnt_free < 5) { 908c2ecf20Sopenharmony_ci dev_err(dev->dev, "Error: your device needs default EEPROM file and this driver doesn't support it!\n"); 918c2ecf20Sopenharmony_ci return -EINVAL; 928c2ecf20Sopenharmony_ci } 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci return 0; 958c2ecf20Sopenharmony_ci} 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_cistatic bool 988c2ecf20Sopenharmony_cimt7601u_has_tssi(struct mt7601u_dev *dev, u8 *eeprom) 998c2ecf20Sopenharmony_ci{ 1008c2ecf20Sopenharmony_ci u16 nic_conf1 = get_unaligned_le16(eeprom + MT_EE_NIC_CONF_1); 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci return (u16)~nic_conf1 && (nic_conf1 & MT_EE_NIC_CONF_1_TX_ALC_EN); 1038c2ecf20Sopenharmony_ci} 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_cistatic void 1068c2ecf20Sopenharmony_cimt7601u_set_chip_cap(struct mt7601u_dev *dev, u8 *eeprom) 1078c2ecf20Sopenharmony_ci{ 1088c2ecf20Sopenharmony_ci u16 nic_conf0 = get_unaligned_le16(eeprom + MT_EE_NIC_CONF_0); 1098c2ecf20Sopenharmony_ci u16 nic_conf1 = get_unaligned_le16(eeprom + MT_EE_NIC_CONF_1); 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci if (!field_valid(nic_conf1 & 0xff)) 1128c2ecf20Sopenharmony_ci nic_conf1 &= 0xff00; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci dev->ee->tssi_enabled = mt7601u_has_tssi(dev, eeprom) && 1158c2ecf20Sopenharmony_ci !(nic_conf1 & MT_EE_NIC_CONF_1_TEMP_TX_ALC); 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci if (nic_conf1 & MT_EE_NIC_CONF_1_HW_RF_CTRL) 1188c2ecf20Sopenharmony_ci dev_err(dev->dev, 1198c2ecf20Sopenharmony_ci "Error: this driver does not support HW RF ctrl\n"); 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci if (!field_valid(nic_conf0 >> 8)) 1228c2ecf20Sopenharmony_ci return; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci if (FIELD_GET(MT_EE_NIC_CONF_0_RX_PATH, nic_conf0) > 1 || 1258c2ecf20Sopenharmony_ci FIELD_GET(MT_EE_NIC_CONF_0_TX_PATH, nic_conf0) > 1) 1268c2ecf20Sopenharmony_ci dev_err(dev->dev, 1278c2ecf20Sopenharmony_ci "Error: device has more than 1 RX/TX stream!\n"); 1288c2ecf20Sopenharmony_ci} 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_cistatic void mt7601u_set_channel_target_power(struct mt7601u_dev *dev, 1318c2ecf20Sopenharmony_ci u8 *eeprom, u8 max_pwr) 1328c2ecf20Sopenharmony_ci{ 1338c2ecf20Sopenharmony_ci u8 trgt_pwr = eeprom[MT_EE_TX_TSSI_TARGET_POWER]; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci if (trgt_pwr > max_pwr || !trgt_pwr) { 1368c2ecf20Sopenharmony_ci dev_warn(dev->dev, "Error: EEPROM trgt power invalid %hhx!\n", 1378c2ecf20Sopenharmony_ci trgt_pwr); 1388c2ecf20Sopenharmony_ci trgt_pwr = 0x20; 1398c2ecf20Sopenharmony_ci } 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci memset(dev->ee->chan_pwr, trgt_pwr, sizeof(dev->ee->chan_pwr)); 1428c2ecf20Sopenharmony_ci} 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_cistatic void 1458c2ecf20Sopenharmony_cimt7601u_set_channel_power(struct mt7601u_dev *dev, u8 *eeprom) 1468c2ecf20Sopenharmony_ci{ 1478c2ecf20Sopenharmony_ci u32 i, val; 1488c2ecf20Sopenharmony_ci u8 max_pwr; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci val = mt7601u_rr(dev, MT_TX_ALC_CFG_0); 1518c2ecf20Sopenharmony_ci max_pwr = FIELD_GET(MT_TX_ALC_CFG_0_LIMIT_0, val); 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci if (mt7601u_has_tssi(dev, eeprom)) { 1548c2ecf20Sopenharmony_ci mt7601u_set_channel_target_power(dev, eeprom, max_pwr); 1558c2ecf20Sopenharmony_ci return; 1568c2ecf20Sopenharmony_ci } 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci for (i = 0; i < 14; i++) { 1598c2ecf20Sopenharmony_ci s8 power = field_validate(eeprom[MT_EE_TX_POWER_OFFSET + i]); 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci if (power > max_pwr || power < 0) 1628c2ecf20Sopenharmony_ci power = MT7601U_DEFAULT_TX_POWER; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci dev->ee->chan_pwr[i] = power; 1658c2ecf20Sopenharmony_ci } 1668c2ecf20Sopenharmony_ci} 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_cistatic void 1698c2ecf20Sopenharmony_cimt7601u_set_country_reg(struct mt7601u_dev *dev, u8 *eeprom) 1708c2ecf20Sopenharmony_ci{ 1718c2ecf20Sopenharmony_ci /* Note: - region 31 is not valid for mt7601u (see rtmp_init.c) 1728c2ecf20Sopenharmony_ci * - comments in rtmp_def.h are incorrect (see rt_channel.c) 1738c2ecf20Sopenharmony_ci */ 1748c2ecf20Sopenharmony_ci static const struct reg_channel_bounds chan_bounds[] = { 1758c2ecf20Sopenharmony_ci /* EEPROM country regions 0 - 7 */ 1768c2ecf20Sopenharmony_ci { 1, 11 }, { 1, 13 }, { 10, 2 }, { 10, 4 }, 1778c2ecf20Sopenharmony_ci { 14, 1 }, { 1, 14 }, { 3, 7 }, { 5, 9 }, 1788c2ecf20Sopenharmony_ci /* EEPROM country regions 32 - 33 */ 1798c2ecf20Sopenharmony_ci { 1, 11 }, { 1, 14 } 1808c2ecf20Sopenharmony_ci }; 1818c2ecf20Sopenharmony_ci u8 val = eeprom[MT_EE_COUNTRY_REGION]; 1828c2ecf20Sopenharmony_ci int idx = -1; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci if (val < 8) 1858c2ecf20Sopenharmony_ci idx = val; 1868c2ecf20Sopenharmony_ci if (val > 31 && val < 33) 1878c2ecf20Sopenharmony_ci idx = val - 32 + 8; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci if (idx != -1) 1908c2ecf20Sopenharmony_ci dev_info(dev->dev, 1918c2ecf20Sopenharmony_ci "EEPROM country region %02hhx (channels %hhd-%hhd)\n", 1928c2ecf20Sopenharmony_ci val, chan_bounds[idx].start, 1938c2ecf20Sopenharmony_ci chan_bounds[idx].start + chan_bounds[idx].num - 1); 1948c2ecf20Sopenharmony_ci else 1958c2ecf20Sopenharmony_ci idx = 5; /* channels 1 - 14 */ 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci dev->ee->reg = chan_bounds[idx]; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci /* TODO: country region 33 is special - phy should be set to B-mode 2008c2ecf20Sopenharmony_ci * before entering channel 14 (see sta/connect.c) 2018c2ecf20Sopenharmony_ci */ 2028c2ecf20Sopenharmony_ci} 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_cistatic void 2058c2ecf20Sopenharmony_cimt7601u_set_rf_freq_off(struct mt7601u_dev *dev, u8 *eeprom) 2068c2ecf20Sopenharmony_ci{ 2078c2ecf20Sopenharmony_ci u8 comp; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci dev->ee->rf_freq_off = field_validate(eeprom[MT_EE_FREQ_OFFSET]); 2108c2ecf20Sopenharmony_ci comp = field_validate(eeprom[MT_EE_FREQ_OFFSET_COMPENSATION]); 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci if (comp & BIT(7)) 2138c2ecf20Sopenharmony_ci dev->ee->rf_freq_off -= comp & 0x7f; 2148c2ecf20Sopenharmony_ci else 2158c2ecf20Sopenharmony_ci dev->ee->rf_freq_off += comp; 2168c2ecf20Sopenharmony_ci} 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_cistatic void 2198c2ecf20Sopenharmony_cimt7601u_set_rssi_offset(struct mt7601u_dev *dev, u8 *eeprom) 2208c2ecf20Sopenharmony_ci{ 2218c2ecf20Sopenharmony_ci int i; 2228c2ecf20Sopenharmony_ci s8 *rssi_offset = dev->ee->rssi_offset; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci for (i = 0; i < 2; i++) { 2258c2ecf20Sopenharmony_ci rssi_offset[i] = eeprom[MT_EE_RSSI_OFFSET + i]; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci if (rssi_offset[i] < -10 || rssi_offset[i] > 10) { 2288c2ecf20Sopenharmony_ci dev_warn(dev->dev, 2298c2ecf20Sopenharmony_ci "Warning: EEPROM RSSI is invalid %02hhx\n", 2308c2ecf20Sopenharmony_ci rssi_offset[i]); 2318c2ecf20Sopenharmony_ci rssi_offset[i] = 0; 2328c2ecf20Sopenharmony_ci } 2338c2ecf20Sopenharmony_ci } 2348c2ecf20Sopenharmony_ci} 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_cistatic void 2378c2ecf20Sopenharmony_cimt7601u_extra_power_over_mac(struct mt7601u_dev *dev) 2388c2ecf20Sopenharmony_ci{ 2398c2ecf20Sopenharmony_ci u32 val; 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci val = ((mt7601u_rr(dev, MT_TX_PWR_CFG_1) & 0x0000ff00) >> 8); 2428c2ecf20Sopenharmony_ci val |= ((mt7601u_rr(dev, MT_TX_PWR_CFG_2) & 0x0000ff00) << 8); 2438c2ecf20Sopenharmony_ci mt7601u_wr(dev, MT_TX_PWR_CFG_7, val); 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci val = ((mt7601u_rr(dev, MT_TX_PWR_CFG_4) & 0x0000ff00) >> 8); 2468c2ecf20Sopenharmony_ci mt7601u_wr(dev, MT_TX_PWR_CFG_9, val); 2478c2ecf20Sopenharmony_ci} 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_cistatic void 2508c2ecf20Sopenharmony_cimt7601u_set_power_rate(struct power_per_rate *rate, s8 delta, u8 value) 2518c2ecf20Sopenharmony_ci{ 2528c2ecf20Sopenharmony_ci /* Invalid? Note: vendor driver does not handle this */ 2538c2ecf20Sopenharmony_ci if (value == 0xff) 2548c2ecf20Sopenharmony_ci return; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci rate->raw = s6_validate(value); 2578c2ecf20Sopenharmony_ci rate->bw20 = s6_to_int(value); 2588c2ecf20Sopenharmony_ci /* Note: vendor driver does cap the value to s6 right away */ 2598c2ecf20Sopenharmony_ci rate->bw40 = rate->bw20 + delta; 2608c2ecf20Sopenharmony_ci} 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_cistatic void 2638c2ecf20Sopenharmony_cimt7601u_save_power_rate(struct mt7601u_dev *dev, s8 delta, u32 val, int i) 2648c2ecf20Sopenharmony_ci{ 2658c2ecf20Sopenharmony_ci struct mt7601u_rate_power *t = &dev->ee->power_rate_table; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci switch (i) { 2688c2ecf20Sopenharmony_ci case 0: 2698c2ecf20Sopenharmony_ci mt7601u_set_power_rate(&t->cck[0], delta, (val >> 0) & 0xff); 2708c2ecf20Sopenharmony_ci mt7601u_set_power_rate(&t->cck[1], delta, (val >> 8) & 0xff); 2718c2ecf20Sopenharmony_ci /* Save cck bw20 for fixups of channel 14 */ 2728c2ecf20Sopenharmony_ci dev->ee->real_cck_bw20[0] = t->cck[0].bw20; 2738c2ecf20Sopenharmony_ci dev->ee->real_cck_bw20[1] = t->cck[1].bw20; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci mt7601u_set_power_rate(&t->ofdm[0], delta, (val >> 16) & 0xff); 2768c2ecf20Sopenharmony_ci mt7601u_set_power_rate(&t->ofdm[1], delta, (val >> 24) & 0xff); 2778c2ecf20Sopenharmony_ci break; 2788c2ecf20Sopenharmony_ci case 1: 2798c2ecf20Sopenharmony_ci mt7601u_set_power_rate(&t->ofdm[2], delta, (val >> 0) & 0xff); 2808c2ecf20Sopenharmony_ci mt7601u_set_power_rate(&t->ofdm[3], delta, (val >> 8) & 0xff); 2818c2ecf20Sopenharmony_ci mt7601u_set_power_rate(&t->ht[0], delta, (val >> 16) & 0xff); 2828c2ecf20Sopenharmony_ci mt7601u_set_power_rate(&t->ht[1], delta, (val >> 24) & 0xff); 2838c2ecf20Sopenharmony_ci break; 2848c2ecf20Sopenharmony_ci case 2: 2858c2ecf20Sopenharmony_ci mt7601u_set_power_rate(&t->ht[2], delta, (val >> 0) & 0xff); 2868c2ecf20Sopenharmony_ci mt7601u_set_power_rate(&t->ht[3], delta, (val >> 8) & 0xff); 2878c2ecf20Sopenharmony_ci break; 2888c2ecf20Sopenharmony_ci } 2898c2ecf20Sopenharmony_ci} 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_cistatic s8 2928c2ecf20Sopenharmony_ciget_delta(u8 val) 2938c2ecf20Sopenharmony_ci{ 2948c2ecf20Sopenharmony_ci s8 ret; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci if (!field_valid(val) || !(val & BIT(7))) 2978c2ecf20Sopenharmony_ci return 0; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci ret = val & 0x1f; 3008c2ecf20Sopenharmony_ci if (ret > 8) 3018c2ecf20Sopenharmony_ci ret = 8; 3028c2ecf20Sopenharmony_ci if (val & BIT(6)) 3038c2ecf20Sopenharmony_ci ret = -ret; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci return ret; 3068c2ecf20Sopenharmony_ci} 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_cistatic void 3098c2ecf20Sopenharmony_cimt7601u_config_tx_power_per_rate(struct mt7601u_dev *dev, u8 *eeprom) 3108c2ecf20Sopenharmony_ci{ 3118c2ecf20Sopenharmony_ci u32 val; 3128c2ecf20Sopenharmony_ci s8 bw40_delta; 3138c2ecf20Sopenharmony_ci int i; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci bw40_delta = get_delta(eeprom[MT_EE_TX_POWER_DELTA_BW40]); 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci for (i = 0; i < 5; i++) { 3188c2ecf20Sopenharmony_ci val = get_unaligned_le32(eeprom + MT_EE_TX_POWER_BYRATE(i)); 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci mt7601u_save_power_rate(dev, bw40_delta, val, i); 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci if (~val) 3238c2ecf20Sopenharmony_ci mt7601u_wr(dev, MT_TX_PWR_CFG_0 + i * 4, val); 3248c2ecf20Sopenharmony_ci } 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci mt7601u_extra_power_over_mac(dev); 3278c2ecf20Sopenharmony_ci} 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_cistatic void 3308c2ecf20Sopenharmony_cimt7601u_init_tssi_params(struct mt7601u_dev *dev, u8 *eeprom) 3318c2ecf20Sopenharmony_ci{ 3328c2ecf20Sopenharmony_ci struct tssi_data *d = &dev->ee->tssi_data; 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci if (!dev->ee->tssi_enabled) 3358c2ecf20Sopenharmony_ci return; 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci d->slope = eeprom[MT_EE_TX_TSSI_SLOPE]; 3388c2ecf20Sopenharmony_ci d->tx0_delta_offset = eeprom[MT_EE_TX_TSSI_OFFSET] * 1024; 3398c2ecf20Sopenharmony_ci d->offset[0] = eeprom[MT_EE_TX_TSSI_OFFSET_GROUP]; 3408c2ecf20Sopenharmony_ci d->offset[1] = eeprom[MT_EE_TX_TSSI_OFFSET_GROUP + 1]; 3418c2ecf20Sopenharmony_ci d->offset[2] = eeprom[MT_EE_TX_TSSI_OFFSET_GROUP + 2]; 3428c2ecf20Sopenharmony_ci} 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ciint 3458c2ecf20Sopenharmony_cimt7601u_eeprom_init(struct mt7601u_dev *dev) 3468c2ecf20Sopenharmony_ci{ 3478c2ecf20Sopenharmony_ci u8 *eeprom; 3488c2ecf20Sopenharmony_ci int i, ret; 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci ret = mt7601u_efuse_physical_size_check(dev); 3518c2ecf20Sopenharmony_ci if (ret) 3528c2ecf20Sopenharmony_ci return ret; 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci dev->ee = devm_kzalloc(dev->dev, sizeof(*dev->ee), GFP_KERNEL); 3558c2ecf20Sopenharmony_ci if (!dev->ee) 3568c2ecf20Sopenharmony_ci return -ENOMEM; 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci eeprom = kmalloc(MT7601U_EEPROM_SIZE, GFP_KERNEL); 3598c2ecf20Sopenharmony_ci if (!eeprom) 3608c2ecf20Sopenharmony_ci return -ENOMEM; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci for (i = 0; i + 16 <= MT7601U_EEPROM_SIZE; i += 16) { 3638c2ecf20Sopenharmony_ci ret = mt7601u_efuse_read(dev, i, eeprom + i, MT_EE_READ); 3648c2ecf20Sopenharmony_ci if (ret) 3658c2ecf20Sopenharmony_ci goto out; 3668c2ecf20Sopenharmony_ci } 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci if (eeprom[MT_EE_VERSION_EE] > MT7601U_EE_MAX_VER) 3698c2ecf20Sopenharmony_ci dev_warn(dev->dev, 3708c2ecf20Sopenharmony_ci "Warning: unsupported EEPROM version %02hhx\n", 3718c2ecf20Sopenharmony_ci eeprom[MT_EE_VERSION_EE]); 3728c2ecf20Sopenharmony_ci dev_info(dev->dev, "EEPROM ver:%02hhx fae:%02hhx\n", 3738c2ecf20Sopenharmony_ci eeprom[MT_EE_VERSION_EE], eeprom[MT_EE_VERSION_FAE]); 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci mt7601u_set_macaddr(dev, eeprom + MT_EE_MAC_ADDR); 3768c2ecf20Sopenharmony_ci mt7601u_set_chip_cap(dev, eeprom); 3778c2ecf20Sopenharmony_ci mt7601u_set_channel_power(dev, eeprom); 3788c2ecf20Sopenharmony_ci mt7601u_set_country_reg(dev, eeprom); 3798c2ecf20Sopenharmony_ci mt7601u_set_rf_freq_off(dev, eeprom); 3808c2ecf20Sopenharmony_ci mt7601u_set_rssi_offset(dev, eeprom); 3818c2ecf20Sopenharmony_ci dev->ee->ref_temp = eeprom[MT_EE_REF_TEMP]; 3828c2ecf20Sopenharmony_ci dev->ee->lna_gain = eeprom[MT_EE_LNA_GAIN]; 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci mt7601u_config_tx_power_per_rate(dev, eeprom); 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci mt7601u_init_tssi_params(dev, eeprom); 3878c2ecf20Sopenharmony_ciout: 3888c2ecf20Sopenharmony_ci kfree(eeprom); 3898c2ecf20Sopenharmony_ci return ret; 3908c2ecf20Sopenharmony_ci} 391