16c92544dSBjoern A. Zeeb // SPDX-License-Identifier: ISC 26c92544dSBjoern A. Zeeb /* Copyright (C) 2020 MediaTek Inc. */ 36c92544dSBjoern A. Zeeb 46c92544dSBjoern A. Zeeb #include <linux/etherdevice.h> 56c92544dSBjoern A. Zeeb #include <linux/hwmon.h> 66c92544dSBjoern A. Zeeb #include <linux/hwmon-sysfs.h> 7*cbb3ec25SBjoern A. Zeeb #include <linux/of.h> 86c92544dSBjoern A. Zeeb #include <linux/thermal.h> 96c92544dSBjoern A. Zeeb #if defined(__FreeBSD__) 106c92544dSBjoern A. Zeeb #include <linux/delay.h> 116c92544dSBjoern A. Zeeb #endif 126c92544dSBjoern A. Zeeb #include "mt7915.h" 136c92544dSBjoern A. Zeeb #include "mac.h" 146c92544dSBjoern A. Zeeb #include "mcu.h" 15*cbb3ec25SBjoern A. Zeeb #include "coredump.h" 166c92544dSBjoern A. Zeeb #include "eeprom.h" 176c92544dSBjoern A. Zeeb 186c92544dSBjoern A. Zeeb static const struct ieee80211_iface_limit if_limits[] = { 196c92544dSBjoern A. Zeeb { 206c92544dSBjoern A. Zeeb .max = 1, 216c92544dSBjoern A. Zeeb .types = BIT(NL80211_IFTYPE_ADHOC) 226c92544dSBjoern A. Zeeb }, { 236c92544dSBjoern A. Zeeb .max = 16, 246c92544dSBjoern A. Zeeb .types = BIT(NL80211_IFTYPE_AP) 256c92544dSBjoern A. Zeeb #ifdef CONFIG_MAC80211_MESH 266c92544dSBjoern A. Zeeb | BIT(NL80211_IFTYPE_MESH_POINT) 276c92544dSBjoern A. Zeeb #endif 286c92544dSBjoern A. Zeeb }, { 296c92544dSBjoern A. Zeeb .max = MT7915_MAX_INTERFACES, 306c92544dSBjoern A. Zeeb .types = BIT(NL80211_IFTYPE_STATION) 316c92544dSBjoern A. Zeeb } 326c92544dSBjoern A. Zeeb }; 336c92544dSBjoern A. Zeeb 346c92544dSBjoern A. Zeeb static const struct ieee80211_iface_combination if_comb[] = { 356c92544dSBjoern A. Zeeb { 366c92544dSBjoern A. Zeeb .limits = if_limits, 376c92544dSBjoern A. Zeeb .n_limits = ARRAY_SIZE(if_limits), 386c92544dSBjoern A. Zeeb .max_interfaces = MT7915_MAX_INTERFACES, 396c92544dSBjoern A. Zeeb .num_different_channels = 1, 406c92544dSBjoern A. Zeeb .beacon_int_infra_match = true, 416c92544dSBjoern A. Zeeb .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) | 426c92544dSBjoern A. Zeeb BIT(NL80211_CHAN_WIDTH_20) | 436c92544dSBjoern A. Zeeb BIT(NL80211_CHAN_WIDTH_40) | 446c92544dSBjoern A. Zeeb BIT(NL80211_CHAN_WIDTH_80) | 45*cbb3ec25SBjoern A. Zeeb BIT(NL80211_CHAN_WIDTH_160), 466c92544dSBjoern A. Zeeb } 476c92544dSBjoern A. Zeeb }; 486c92544dSBjoern A. Zeeb 496c92544dSBjoern A. Zeeb #if defined(__linux__) 506c92544dSBjoern A. Zeeb static ssize_t mt7915_thermal_temp_show(struct device *dev, 516c92544dSBjoern A. Zeeb struct device_attribute *attr, 526c92544dSBjoern A. Zeeb char *buf) 536c92544dSBjoern A. Zeeb { 546c92544dSBjoern A. Zeeb struct mt7915_phy *phy = dev_get_drvdata(dev); 556c92544dSBjoern A. Zeeb int i = to_sensor_dev_attr(attr)->index; 566c92544dSBjoern A. Zeeb int temperature; 576c92544dSBjoern A. Zeeb 586c92544dSBjoern A. Zeeb switch (i) { 596c92544dSBjoern A. Zeeb case 0: 606c92544dSBjoern A. Zeeb temperature = mt7915_mcu_get_temperature(phy); 616c92544dSBjoern A. Zeeb if (temperature < 0) 626c92544dSBjoern A. Zeeb return temperature; 636c92544dSBjoern A. Zeeb /* display in millidegree celcius */ 646c92544dSBjoern A. Zeeb return sprintf(buf, "%u\n", temperature * 1000); 656c92544dSBjoern A. Zeeb case 1: 666c92544dSBjoern A. Zeeb case 2: 676c92544dSBjoern A. Zeeb return sprintf(buf, "%u\n", 686c92544dSBjoern A. Zeeb phy->throttle_temp[i - 1] * 1000); 696c92544dSBjoern A. Zeeb case 3: 706c92544dSBjoern A. Zeeb return sprintf(buf, "%hhu\n", phy->throttle_state); 716c92544dSBjoern A. Zeeb default: 726c92544dSBjoern A. Zeeb return -EINVAL; 736c92544dSBjoern A. Zeeb } 746c92544dSBjoern A. Zeeb } 756c92544dSBjoern A. Zeeb 766c92544dSBjoern A. Zeeb static ssize_t mt7915_thermal_temp_store(struct device *dev, 776c92544dSBjoern A. Zeeb struct device_attribute *attr, 786c92544dSBjoern A. Zeeb const char *buf, size_t count) 796c92544dSBjoern A. Zeeb { 806c92544dSBjoern A. Zeeb struct mt7915_phy *phy = dev_get_drvdata(dev); 816c92544dSBjoern A. Zeeb int ret, i = to_sensor_dev_attr(attr)->index; 826c92544dSBjoern A. Zeeb long val; 836c92544dSBjoern A. Zeeb 846c92544dSBjoern A. Zeeb ret = kstrtol(buf, 10, &val); 856c92544dSBjoern A. Zeeb if (ret < 0) 866c92544dSBjoern A. Zeeb return ret; 876c92544dSBjoern A. Zeeb 886c92544dSBjoern A. Zeeb mutex_lock(&phy->dev->mt76.mutex); 896c92544dSBjoern A. Zeeb val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 60, 130); 90*cbb3ec25SBjoern A. Zeeb 91*cbb3ec25SBjoern A. Zeeb if ((i - 1 == MT7915_CRIT_TEMP_IDX && 92*cbb3ec25SBjoern A. Zeeb val > phy->throttle_temp[MT7915_MAX_TEMP_IDX]) || 93*cbb3ec25SBjoern A. Zeeb (i - 1 == MT7915_MAX_TEMP_IDX && 94*cbb3ec25SBjoern A. Zeeb val < phy->throttle_temp[MT7915_CRIT_TEMP_IDX])) { 95*cbb3ec25SBjoern A. Zeeb dev_err(phy->dev->mt76.dev, 96*cbb3ec25SBjoern A. Zeeb "temp1_max shall be greater than temp1_crit."); 97*cbb3ec25SBjoern A. Zeeb mutex_unlock(&phy->dev->mt76.mutex); 98*cbb3ec25SBjoern A. Zeeb return -EINVAL; 99*cbb3ec25SBjoern A. Zeeb } 100*cbb3ec25SBjoern A. Zeeb 1016c92544dSBjoern A. Zeeb phy->throttle_temp[i - 1] = val; 1026c92544dSBjoern A. Zeeb mutex_unlock(&phy->dev->mt76.mutex); 1036c92544dSBjoern A. Zeeb 104*cbb3ec25SBjoern A. Zeeb ret = mt7915_mcu_set_thermal_protect(phy); 105*cbb3ec25SBjoern A. Zeeb if (ret) 106*cbb3ec25SBjoern A. Zeeb return ret; 107*cbb3ec25SBjoern A. Zeeb 1086c92544dSBjoern A. Zeeb return count; 1096c92544dSBjoern A. Zeeb } 1106c92544dSBjoern A. Zeeb 1116c92544dSBjoern A. Zeeb static SENSOR_DEVICE_ATTR_RO(temp1_input, mt7915_thermal_temp, 0); 1126c92544dSBjoern A. Zeeb static SENSOR_DEVICE_ATTR_RW(temp1_crit, mt7915_thermal_temp, 1); 1136c92544dSBjoern A. Zeeb static SENSOR_DEVICE_ATTR_RW(temp1_max, mt7915_thermal_temp, 2); 1146c92544dSBjoern A. Zeeb static SENSOR_DEVICE_ATTR_RO(throttle1, mt7915_thermal_temp, 3); 1156c92544dSBjoern A. Zeeb 1166c92544dSBjoern A. Zeeb static struct attribute *mt7915_hwmon_attrs[] = { 1176c92544dSBjoern A. Zeeb &sensor_dev_attr_temp1_input.dev_attr.attr, 1186c92544dSBjoern A. Zeeb &sensor_dev_attr_temp1_crit.dev_attr.attr, 1196c92544dSBjoern A. Zeeb &sensor_dev_attr_temp1_max.dev_attr.attr, 1206c92544dSBjoern A. Zeeb &sensor_dev_attr_throttle1.dev_attr.attr, 1216c92544dSBjoern A. Zeeb NULL, 1226c92544dSBjoern A. Zeeb }; 1236c92544dSBjoern A. Zeeb ATTRIBUTE_GROUPS(mt7915_hwmon); 1246c92544dSBjoern A. Zeeb 1256c92544dSBjoern A. Zeeb static int 1266c92544dSBjoern A. Zeeb mt7915_thermal_get_max_throttle_state(struct thermal_cooling_device *cdev, 1276c92544dSBjoern A. Zeeb unsigned long *state) 1286c92544dSBjoern A. Zeeb { 1296c92544dSBjoern A. Zeeb *state = MT7915_CDEV_THROTTLE_MAX; 1306c92544dSBjoern A. Zeeb 1316c92544dSBjoern A. Zeeb return 0; 1326c92544dSBjoern A. Zeeb } 1336c92544dSBjoern A. Zeeb 1346c92544dSBjoern A. Zeeb static int 1356c92544dSBjoern A. Zeeb mt7915_thermal_get_cur_throttle_state(struct thermal_cooling_device *cdev, 1366c92544dSBjoern A. Zeeb unsigned long *state) 1376c92544dSBjoern A. Zeeb { 1386c92544dSBjoern A. Zeeb struct mt7915_phy *phy = cdev->devdata; 1396c92544dSBjoern A. Zeeb 1406c92544dSBjoern A. Zeeb *state = phy->cdev_state; 1416c92544dSBjoern A. Zeeb 1426c92544dSBjoern A. Zeeb return 0; 1436c92544dSBjoern A. Zeeb } 1446c92544dSBjoern A. Zeeb 1456c92544dSBjoern A. Zeeb static int 1466c92544dSBjoern A. Zeeb mt7915_thermal_set_cur_throttle_state(struct thermal_cooling_device *cdev, 1476c92544dSBjoern A. Zeeb unsigned long state) 1486c92544dSBjoern A. Zeeb { 1496c92544dSBjoern A. Zeeb struct mt7915_phy *phy = cdev->devdata; 1506c92544dSBjoern A. Zeeb u8 throttling = MT7915_THERMAL_THROTTLE_MAX - state; 1516c92544dSBjoern A. Zeeb int ret; 1526c92544dSBjoern A. Zeeb 153*cbb3ec25SBjoern A. Zeeb if (state > MT7915_CDEV_THROTTLE_MAX) { 154*cbb3ec25SBjoern A. Zeeb dev_err(phy->dev->mt76.dev, 155*cbb3ec25SBjoern A. Zeeb "please specify a valid throttling state\n"); 1566c92544dSBjoern A. Zeeb return -EINVAL; 157*cbb3ec25SBjoern A. Zeeb } 1586c92544dSBjoern A. Zeeb 1596c92544dSBjoern A. Zeeb if (state == phy->cdev_state) 1606c92544dSBjoern A. Zeeb return 0; 1616c92544dSBjoern A. Zeeb 1626c92544dSBjoern A. Zeeb /* 1636c92544dSBjoern A. Zeeb * cooling_device convention: 0 = no cooling, more = more cooling 1646c92544dSBjoern A. Zeeb * mcu convention: 1 = max cooling, more = less cooling 1656c92544dSBjoern A. Zeeb */ 1666c92544dSBjoern A. Zeeb ret = mt7915_mcu_set_thermal_throttling(phy, throttling); 1676c92544dSBjoern A. Zeeb if (ret) 1686c92544dSBjoern A. Zeeb return ret; 1696c92544dSBjoern A. Zeeb 1706c92544dSBjoern A. Zeeb phy->cdev_state = state; 1716c92544dSBjoern A. Zeeb 1726c92544dSBjoern A. Zeeb return 0; 1736c92544dSBjoern A. Zeeb } 1746c92544dSBjoern A. Zeeb 1756c92544dSBjoern A. Zeeb static const struct thermal_cooling_device_ops mt7915_thermal_ops = { 1766c92544dSBjoern A. Zeeb .get_max_state = mt7915_thermal_get_max_throttle_state, 1776c92544dSBjoern A. Zeeb .get_cur_state = mt7915_thermal_get_cur_throttle_state, 1786c92544dSBjoern A. Zeeb .set_cur_state = mt7915_thermal_set_cur_throttle_state, 1796c92544dSBjoern A. Zeeb }; 1806c92544dSBjoern A. Zeeb 1816c92544dSBjoern A. Zeeb static void mt7915_unregister_thermal(struct mt7915_phy *phy) 1826c92544dSBjoern A. Zeeb { 1836c92544dSBjoern A. Zeeb struct wiphy *wiphy = phy->mt76->hw->wiphy; 1846c92544dSBjoern A. Zeeb 1856c92544dSBjoern A. Zeeb if (!phy->cdev) 1866c92544dSBjoern A. Zeeb return; 1876c92544dSBjoern A. Zeeb 1886c92544dSBjoern A. Zeeb sysfs_remove_link(&wiphy->dev.kobj, "cooling_device"); 1896c92544dSBjoern A. Zeeb thermal_cooling_device_unregister(phy->cdev); 1906c92544dSBjoern A. Zeeb } 1916c92544dSBjoern A. Zeeb #endif 1926c92544dSBjoern A. Zeeb 1936c92544dSBjoern A. Zeeb static int mt7915_thermal_init(struct mt7915_phy *phy) 1946c92544dSBjoern A. Zeeb { 1956c92544dSBjoern A. Zeeb #if defined(__linux__) 1966c92544dSBjoern A. Zeeb struct wiphy *wiphy = phy->mt76->hw->wiphy; 1976c92544dSBjoern A. Zeeb struct thermal_cooling_device *cdev; 1986c92544dSBjoern A. Zeeb struct device *hwmon; 1996c92544dSBjoern A. Zeeb const char *name; 2006c92544dSBjoern A. Zeeb 2016c92544dSBjoern A. Zeeb name = devm_kasprintf(&wiphy->dev, GFP_KERNEL, "mt7915_%s", 2026c92544dSBjoern A. Zeeb wiphy_name(wiphy)); 2036c92544dSBjoern A. Zeeb 2046c92544dSBjoern A. Zeeb cdev = thermal_cooling_device_register(name, phy, &mt7915_thermal_ops); 2056c92544dSBjoern A. Zeeb if (!IS_ERR(cdev)) { 2066c92544dSBjoern A. Zeeb if (sysfs_create_link(&wiphy->dev.kobj, &cdev->device.kobj, 2076c92544dSBjoern A. Zeeb "cooling_device") < 0) 2086c92544dSBjoern A. Zeeb thermal_cooling_device_unregister(cdev); 2096c92544dSBjoern A. Zeeb else 2106c92544dSBjoern A. Zeeb phy->cdev = cdev; 2116c92544dSBjoern A. Zeeb } 2126c92544dSBjoern A. Zeeb 213*cbb3ec25SBjoern A. Zeeb /* initialize critical/maximum high temperature */ 214*cbb3ec25SBjoern A. Zeeb phy->throttle_temp[MT7915_CRIT_TEMP_IDX] = MT7915_CRIT_TEMP; 215*cbb3ec25SBjoern A. Zeeb phy->throttle_temp[MT7915_MAX_TEMP_IDX] = MT7915_MAX_TEMP; 216*cbb3ec25SBjoern A. Zeeb 2176c92544dSBjoern A. Zeeb if (!IS_REACHABLE(CONFIG_HWMON)) 2186c92544dSBjoern A. Zeeb return 0; 2196c92544dSBjoern A. Zeeb 2206c92544dSBjoern A. Zeeb hwmon = devm_hwmon_device_register_with_groups(&wiphy->dev, name, phy, 2216c92544dSBjoern A. Zeeb mt7915_hwmon_groups); 2226c92544dSBjoern A. Zeeb if (IS_ERR(hwmon)) 2236c92544dSBjoern A. Zeeb return PTR_ERR(hwmon); 2246c92544dSBjoern A. Zeeb #endif 225*cbb3ec25SBjoern A. Zeeb 226*cbb3ec25SBjoern A. Zeeb return 0; 2276c92544dSBjoern A. Zeeb } 2286c92544dSBjoern A. Zeeb 2296c92544dSBjoern A. Zeeb #if defined(CONFIG_MT76_LEDS) 2306c92544dSBjoern A. Zeeb static void mt7915_led_set_config(struct led_classdev *led_cdev, 2316c92544dSBjoern A. Zeeb u8 delay_on, u8 delay_off) 2326c92544dSBjoern A. Zeeb { 2336c92544dSBjoern A. Zeeb struct mt7915_dev *dev; 234*cbb3ec25SBjoern A. Zeeb struct mt76_phy *mphy; 2356c92544dSBjoern A. Zeeb u32 val; 2366c92544dSBjoern A. Zeeb 237*cbb3ec25SBjoern A. Zeeb mphy = container_of(led_cdev, struct mt76_phy, leds.cdev); 238*cbb3ec25SBjoern A. Zeeb dev = container_of(mphy->dev, struct mt7915_dev, mt76); 2396c92544dSBjoern A. Zeeb 240*cbb3ec25SBjoern A. Zeeb /* set PWM mode */ 241*cbb3ec25SBjoern A. Zeeb val = FIELD_PREP(MT_LED_STATUS_DURATION, 0xffff) | 242*cbb3ec25SBjoern A. Zeeb FIELD_PREP(MT_LED_STATUS_OFF, delay_off) | 243*cbb3ec25SBjoern A. Zeeb FIELD_PREP(MT_LED_STATUS_ON, delay_on); 244*cbb3ec25SBjoern A. Zeeb mt76_wr(dev, MT_LED_STATUS_0(mphy->band_idx), val); 245*cbb3ec25SBjoern A. Zeeb mt76_wr(dev, MT_LED_STATUS_1(mphy->band_idx), val); 2466c92544dSBjoern A. Zeeb 2476c92544dSBjoern A. Zeeb /* enable LED */ 248*cbb3ec25SBjoern A. Zeeb mt76_wr(dev, MT_LED_EN(mphy->band_idx), 1); 2496c92544dSBjoern A. Zeeb 2506c92544dSBjoern A. Zeeb /* control LED */ 251*cbb3ec25SBjoern A. Zeeb val = MT_LED_CTRL_KICK; 252*cbb3ec25SBjoern A. Zeeb if (dev->mphy.leds.al) 2536c92544dSBjoern A. Zeeb val |= MT_LED_CTRL_POLARITY; 254*cbb3ec25SBjoern A. Zeeb if (mphy->band_idx) 255*cbb3ec25SBjoern A. Zeeb val |= MT_LED_CTRL_BAND; 2566c92544dSBjoern A. Zeeb 257*cbb3ec25SBjoern A. Zeeb mt76_wr(dev, MT_LED_CTRL(mphy->band_idx), val); 258*cbb3ec25SBjoern A. Zeeb mt76_clear(dev, MT_LED_CTRL(mphy->band_idx), MT_LED_CTRL_KICK); 2596c92544dSBjoern A. Zeeb } 2606c92544dSBjoern A. Zeeb #endif 2616c92544dSBjoern A. Zeeb 2626c92544dSBjoern A. Zeeb static int mt7915_led_set_blink(struct led_classdev *led_cdev, 2636c92544dSBjoern A. Zeeb unsigned long *delay_on, 2646c92544dSBjoern A. Zeeb unsigned long *delay_off) 2656c92544dSBjoern A. Zeeb { 2666c92544dSBjoern A. Zeeb #if defined(CONFIG_MT76_LEDS) 2676c92544dSBjoern A. Zeeb u16 delta_on = 0, delta_off = 0; 2686c92544dSBjoern A. Zeeb 2696c92544dSBjoern A. Zeeb #define HW_TICK 10 2706c92544dSBjoern A. Zeeb #define TO_HW_TICK(_t) (((_t) > HW_TICK) ? ((_t) / HW_TICK) : HW_TICK) 2716c92544dSBjoern A. Zeeb 2726c92544dSBjoern A. Zeeb if (*delay_on) 2736c92544dSBjoern A. Zeeb delta_on = TO_HW_TICK(*delay_on); 2746c92544dSBjoern A. Zeeb if (*delay_off) 2756c92544dSBjoern A. Zeeb delta_off = TO_HW_TICK(*delay_off); 2766c92544dSBjoern A. Zeeb 2776c92544dSBjoern A. Zeeb mt7915_led_set_config(led_cdev, delta_on, delta_off); 2786c92544dSBjoern A. Zeeb #endif 2796c92544dSBjoern A. Zeeb 2806c92544dSBjoern A. Zeeb return 0; 2816c92544dSBjoern A. Zeeb } 2826c92544dSBjoern A. Zeeb 2836c92544dSBjoern A. Zeeb static void mt7915_led_set_brightness(struct led_classdev *led_cdev, 2846c92544dSBjoern A. Zeeb enum led_brightness brightness) 2856c92544dSBjoern A. Zeeb { 2866c92544dSBjoern A. Zeeb #if defined(CONFIG_MT76_LEDS) 2876c92544dSBjoern A. Zeeb if (!brightness) 2886c92544dSBjoern A. Zeeb mt7915_led_set_config(led_cdev, 0, 0xff); 2896c92544dSBjoern A. Zeeb else 2906c92544dSBjoern A. Zeeb mt7915_led_set_config(led_cdev, 0xff, 0); 2916c92544dSBjoern A. Zeeb #endif 2926c92544dSBjoern A. Zeeb } 2936c92544dSBjoern A. Zeeb 294*cbb3ec25SBjoern A. Zeeb void mt7915_init_txpower(struct mt7915_dev *dev, 2956c92544dSBjoern A. Zeeb struct ieee80211_supported_band *sband) 2966c92544dSBjoern A. Zeeb { 2976c92544dSBjoern A. Zeeb int i, n_chains = hweight8(dev->mphy.antenna_mask); 2986c92544dSBjoern A. Zeeb int nss_delta = mt76_tx_power_nss_delta(n_chains); 2996c92544dSBjoern A. Zeeb int pwr_delta = mt7915_eeprom_get_power_delta(dev, sband->band); 3006c92544dSBjoern A. Zeeb struct mt76_power_limits limits; 3016c92544dSBjoern A. Zeeb 3026c92544dSBjoern A. Zeeb for (i = 0; i < sband->n_channels; i++) { 3036c92544dSBjoern A. Zeeb struct ieee80211_channel *chan = &sband->channels[i]; 3046c92544dSBjoern A. Zeeb u32 target_power = 0; 3056c92544dSBjoern A. Zeeb int j; 3066c92544dSBjoern A. Zeeb 3076c92544dSBjoern A. Zeeb for (j = 0; j < n_chains; j++) { 3086c92544dSBjoern A. Zeeb u32 val; 3096c92544dSBjoern A. Zeeb 3106c92544dSBjoern A. Zeeb val = mt7915_eeprom_get_target_power(dev, chan, j); 3116c92544dSBjoern A. Zeeb target_power = max(target_power, val); 3126c92544dSBjoern A. Zeeb } 3136c92544dSBjoern A. Zeeb 3146c92544dSBjoern A. Zeeb target_power += pwr_delta; 3156c92544dSBjoern A. Zeeb target_power = mt76_get_rate_power_limits(&dev->mphy, chan, 3166c92544dSBjoern A. Zeeb &limits, 3176c92544dSBjoern A. Zeeb target_power); 3186c92544dSBjoern A. Zeeb target_power += nss_delta; 3196c92544dSBjoern A. Zeeb target_power = DIV_ROUND_UP(target_power, 2); 3206c92544dSBjoern A. Zeeb chan->max_power = min_t(int, chan->max_reg_power, 3216c92544dSBjoern A. Zeeb target_power); 3226c92544dSBjoern A. Zeeb chan->orig_mpwr = target_power; 3236c92544dSBjoern A. Zeeb } 3246c92544dSBjoern A. Zeeb } 3256c92544dSBjoern A. Zeeb 3266c92544dSBjoern A. Zeeb static void 3276c92544dSBjoern A. Zeeb mt7915_regd_notifier(struct wiphy *wiphy, 3286c92544dSBjoern A. Zeeb struct regulatory_request *request) 3296c92544dSBjoern A. Zeeb { 3306c92544dSBjoern A. Zeeb struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); 3316c92544dSBjoern A. Zeeb struct mt7915_dev *dev = mt7915_hw_dev(hw); 3326c92544dSBjoern A. Zeeb struct mt76_phy *mphy = hw->priv; 3336c92544dSBjoern A. Zeeb struct mt7915_phy *phy = mphy->priv; 3346c92544dSBjoern A. Zeeb 3356c92544dSBjoern A. Zeeb memcpy(dev->mt76.alpha2, request->alpha2, sizeof(dev->mt76.alpha2)); 3366c92544dSBjoern A. Zeeb dev->mt76.region = request->dfs_region; 3376c92544dSBjoern A. Zeeb 3386c92544dSBjoern A. Zeeb if (dev->mt76.region == NL80211_DFS_UNSET) 3396c92544dSBjoern A. Zeeb mt7915_mcu_rdd_background_enable(phy, NULL); 3406c92544dSBjoern A. Zeeb 3416c92544dSBjoern A. Zeeb mt7915_init_txpower(dev, &mphy->sband_2g.sband); 3426c92544dSBjoern A. Zeeb mt7915_init_txpower(dev, &mphy->sband_5g.sband); 3436c92544dSBjoern A. Zeeb mt7915_init_txpower(dev, &mphy->sband_6g.sband); 3446c92544dSBjoern A. Zeeb 3456c92544dSBjoern A. Zeeb mphy->dfs_state = MT_DFS_STATE_UNKNOWN; 3466c92544dSBjoern A. Zeeb mt7915_dfs_init_radar_detector(phy); 3476c92544dSBjoern A. Zeeb } 3486c92544dSBjoern A. Zeeb 3496c92544dSBjoern A. Zeeb static void 350*cbb3ec25SBjoern A. Zeeb mt7915_init_wiphy(struct mt7915_phy *phy) 3516c92544dSBjoern A. Zeeb { 352*cbb3ec25SBjoern A. Zeeb struct mt76_phy *mphy = phy->mt76; 353*cbb3ec25SBjoern A. Zeeb struct ieee80211_hw *hw = mphy->hw; 3546c92544dSBjoern A. Zeeb #if defined(CONFIG_OF) 3556c92544dSBjoern A. Zeeb struct mt76_dev *mdev = &phy->dev->mt76; 3566c92544dSBjoern A. Zeeb #endif 3576c92544dSBjoern A. Zeeb struct wiphy *wiphy = hw->wiphy; 3586c92544dSBjoern A. Zeeb struct mt7915_dev *dev = phy->dev; 3596c92544dSBjoern A. Zeeb 3606c92544dSBjoern A. Zeeb hw->queues = 4; 3616c92544dSBjoern A. Zeeb hw->max_rx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF_HE; 3626c92544dSBjoern A. Zeeb hw->max_tx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF_HE; 3636c92544dSBjoern A. Zeeb hw->netdev_features = NETIF_F_RXCSUM; 3646c92544dSBjoern A. Zeeb 3656c92544dSBjoern A. Zeeb hw->radiotap_timestamp.units_pos = 3666c92544dSBjoern A. Zeeb IEEE80211_RADIOTAP_TIMESTAMP_UNIT_US; 3676c92544dSBjoern A. Zeeb 3686c92544dSBjoern A. Zeeb phy->slottime = 9; 3696c92544dSBjoern A. Zeeb 3706c92544dSBjoern A. Zeeb hw->sta_data_size = sizeof(struct mt7915_sta); 3716c92544dSBjoern A. Zeeb hw->vif_data_size = sizeof(struct mt7915_vif); 3726c92544dSBjoern A. Zeeb 3736c92544dSBjoern A. Zeeb wiphy->iface_combinations = if_comb; 3746c92544dSBjoern A. Zeeb wiphy->n_iface_combinations = ARRAY_SIZE(if_comb); 3756c92544dSBjoern A. Zeeb wiphy->reg_notifier = mt7915_regd_notifier; 3766c92544dSBjoern A. Zeeb wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH; 3776c92544dSBjoern A. Zeeb wiphy->mbssid_max_interfaces = 16; 3786c92544dSBjoern A. Zeeb 3796c92544dSBjoern A. Zeeb wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_BSS_COLOR); 3806c92544dSBjoern A. Zeeb wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_VHT_IBSS); 3816c92544dSBjoern A. Zeeb wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_BEACON_RATE_LEGACY); 3826c92544dSBjoern A. Zeeb wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_BEACON_RATE_HT); 3836c92544dSBjoern A. Zeeb wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_BEACON_RATE_VHT); 3846c92544dSBjoern A. Zeeb wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_BEACON_RATE_HE); 3856c92544dSBjoern A. Zeeb wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_UNSOL_BCAST_PROBE_RESP); 3866c92544dSBjoern A. Zeeb wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_FILS_DISCOVERY); 387*cbb3ec25SBjoern A. Zeeb wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_ACK_SIGNAL_SUPPORT); 388*cbb3ec25SBjoern A. Zeeb wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CAN_REPLACE_PTK0); 389*cbb3ec25SBjoern A. Zeeb 390*cbb3ec25SBjoern A. Zeeb if (!is_mt7915(&dev->mt76)) 391*cbb3ec25SBjoern A. Zeeb wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_STA_TX_PWR); 3926c92544dSBjoern A. Zeeb 3936c92544dSBjoern A. Zeeb #if defined(CONFIG_OF) 3946c92544dSBjoern A. Zeeb if (!mdev->dev->of_node || 3956c92544dSBjoern A. Zeeb !of_property_read_bool(mdev->dev->of_node, 3966c92544dSBjoern A. Zeeb "mediatek,disable-radar-background")) 3976c92544dSBjoern A. Zeeb #endif 3986c92544dSBjoern A. Zeeb wiphy_ext_feature_set(wiphy, 3996c92544dSBjoern A. Zeeb NL80211_EXT_FEATURE_RADAR_BACKGROUND); 4006c92544dSBjoern A. Zeeb 4016c92544dSBjoern A. Zeeb ieee80211_hw_set(hw, HAS_RATE_CONTROL); 4026c92544dSBjoern A. Zeeb ieee80211_hw_set(hw, SUPPORTS_TX_ENCAP_OFFLOAD); 4036c92544dSBjoern A. Zeeb ieee80211_hw_set(hw, SUPPORTS_RX_DECAP_OFFLOAD); 4046c92544dSBjoern A. Zeeb ieee80211_hw_set(hw, SUPPORTS_MULTI_BSSID); 4056c92544dSBjoern A. Zeeb ieee80211_hw_set(hw, WANT_MONITOR_VIF); 4066c92544dSBjoern A. Zeeb 4076c92544dSBjoern A. Zeeb hw->max_tx_fragments = 4; 4086c92544dSBjoern A. Zeeb 4096c92544dSBjoern A. Zeeb if (phy->mt76->cap.has_2ghz) { 4106c92544dSBjoern A. Zeeb phy->mt76->sband_2g.sband.ht_cap.cap |= 4116c92544dSBjoern A. Zeeb IEEE80211_HT_CAP_LDPC_CODING | 4126c92544dSBjoern A. Zeeb IEEE80211_HT_CAP_MAX_AMSDU; 4136c92544dSBjoern A. Zeeb phy->mt76->sband_2g.sband.ht_cap.ampdu_density = 4146c92544dSBjoern A. Zeeb IEEE80211_HT_MPDU_DENSITY_4; 4156c92544dSBjoern A. Zeeb } 4166c92544dSBjoern A. Zeeb 4176c92544dSBjoern A. Zeeb if (phy->mt76->cap.has_5ghz) { 418*cbb3ec25SBjoern A. Zeeb struct ieee80211_sta_vht_cap *vht_cap; 419*cbb3ec25SBjoern A. Zeeb 420*cbb3ec25SBjoern A. Zeeb vht_cap = &phy->mt76->sband_5g.sband.vht_cap; 4216c92544dSBjoern A. Zeeb phy->mt76->sband_5g.sband.ht_cap.cap |= 4226c92544dSBjoern A. Zeeb IEEE80211_HT_CAP_LDPC_CODING | 4236c92544dSBjoern A. Zeeb IEEE80211_HT_CAP_MAX_AMSDU; 4246c92544dSBjoern A. Zeeb phy->mt76->sband_5g.sband.ht_cap.ampdu_density = 4256c92544dSBjoern A. Zeeb IEEE80211_HT_MPDU_DENSITY_4; 4266c92544dSBjoern A. Zeeb 4276c92544dSBjoern A. Zeeb if (is_mt7915(&dev->mt76)) { 428*cbb3ec25SBjoern A. Zeeb vht_cap->cap |= 4296c92544dSBjoern A. Zeeb IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991 | 4306c92544dSBjoern A. Zeeb IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK; 4316c92544dSBjoern A. Zeeb 4326c92544dSBjoern A. Zeeb if (!dev->dbdc_support) 433*cbb3ec25SBjoern A. Zeeb vht_cap->cap |= 4346c92544dSBjoern A. Zeeb IEEE80211_VHT_CAP_SHORT_GI_160 | 435*cbb3ec25SBjoern A. Zeeb FIELD_PREP(IEEE80211_VHT_CAP_EXT_NSS_BW_MASK, 1); 4366c92544dSBjoern A. Zeeb } else { 437*cbb3ec25SBjoern A. Zeeb vht_cap->cap |= 4386c92544dSBjoern A. Zeeb IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 | 4396c92544dSBjoern A. Zeeb IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK; 4406c92544dSBjoern A. Zeeb 4416c92544dSBjoern A. Zeeb /* mt7916 dbdc with 2g 2x2 bw40 and 5g 2x2 bw160c */ 442*cbb3ec25SBjoern A. Zeeb vht_cap->cap |= 4436c92544dSBjoern A. Zeeb IEEE80211_VHT_CAP_SHORT_GI_160 | 4446c92544dSBjoern A. Zeeb IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ; 4456c92544dSBjoern A. Zeeb } 446*cbb3ec25SBjoern A. Zeeb 447*cbb3ec25SBjoern A. Zeeb if (!is_mt7915(&dev->mt76) || !dev->dbdc_support) 448*cbb3ec25SBjoern A. Zeeb ieee80211_hw_set(hw, SUPPORTS_VHT_EXT_NSS_BW); 4496c92544dSBjoern A. Zeeb } 4506c92544dSBjoern A. Zeeb 4516c92544dSBjoern A. Zeeb mt76_set_stream_caps(phy->mt76, true); 4526c92544dSBjoern A. Zeeb mt7915_set_stream_vht_txbf_caps(phy); 4536c92544dSBjoern A. Zeeb mt7915_set_stream_he_caps(phy); 4546c92544dSBjoern A. Zeeb 4556c92544dSBjoern A. Zeeb wiphy->available_antennas_rx = phy->mt76->antenna_mask; 4566c92544dSBjoern A. Zeeb wiphy->available_antennas_tx = phy->mt76->antenna_mask; 457*cbb3ec25SBjoern A. Zeeb 458*cbb3ec25SBjoern A. Zeeb /* init led callbacks */ 459*cbb3ec25SBjoern A. Zeeb if (IS_ENABLED(CONFIG_MT76_LEDS)) { 460*cbb3ec25SBjoern A. Zeeb mphy->leds.cdev.brightness_set = mt7915_led_set_brightness; 461*cbb3ec25SBjoern A. Zeeb mphy->leds.cdev.blink_set = mt7915_led_set_blink; 462*cbb3ec25SBjoern A. Zeeb } 4636c92544dSBjoern A. Zeeb } 4646c92544dSBjoern A. Zeeb 4656c92544dSBjoern A. Zeeb static void 4666c92544dSBjoern A. Zeeb mt7915_mac_init_band(struct mt7915_dev *dev, u8 band) 4676c92544dSBjoern A. Zeeb { 4686c92544dSBjoern A. Zeeb u32 mask, set; 4696c92544dSBjoern A. Zeeb 4706c92544dSBjoern A. Zeeb mt76_rmw_field(dev, MT_TMAC_CTCR0(band), 4716c92544dSBjoern A. Zeeb MT_TMAC_CTCR0_INS_DDLMT_REFTIME, 0x3f); 4726c92544dSBjoern A. Zeeb mt76_set(dev, MT_TMAC_CTCR0(band), 4736c92544dSBjoern A. Zeeb MT_TMAC_CTCR0_INS_DDLMT_VHT_SMPDU_EN | 4746c92544dSBjoern A. Zeeb MT_TMAC_CTCR0_INS_DDLMT_EN); 4756c92544dSBjoern A. Zeeb 4766c92544dSBjoern A. Zeeb mask = MT_MDP_RCFR0_MCU_RX_MGMT | 4776c92544dSBjoern A. Zeeb MT_MDP_RCFR0_MCU_RX_CTL_NON_BAR | 4786c92544dSBjoern A. Zeeb MT_MDP_RCFR0_MCU_RX_CTL_BAR; 4796c92544dSBjoern A. Zeeb set = FIELD_PREP(MT_MDP_RCFR0_MCU_RX_MGMT, MT_MDP_TO_HIF) | 4806c92544dSBjoern A. Zeeb FIELD_PREP(MT_MDP_RCFR0_MCU_RX_CTL_NON_BAR, MT_MDP_TO_HIF) | 4816c92544dSBjoern A. Zeeb FIELD_PREP(MT_MDP_RCFR0_MCU_RX_CTL_BAR, MT_MDP_TO_HIF); 4826c92544dSBjoern A. Zeeb mt76_rmw(dev, MT_MDP_BNRCFR0(band), mask, set); 4836c92544dSBjoern A. Zeeb 4846c92544dSBjoern A. Zeeb mask = MT_MDP_RCFR1_MCU_RX_BYPASS | 4856c92544dSBjoern A. Zeeb MT_MDP_RCFR1_RX_DROPPED_UCAST | 4866c92544dSBjoern A. Zeeb MT_MDP_RCFR1_RX_DROPPED_MCAST; 4876c92544dSBjoern A. Zeeb set = FIELD_PREP(MT_MDP_RCFR1_MCU_RX_BYPASS, MT_MDP_TO_HIF) | 4886c92544dSBjoern A. Zeeb FIELD_PREP(MT_MDP_RCFR1_RX_DROPPED_UCAST, MT_MDP_TO_HIF) | 4896c92544dSBjoern A. Zeeb FIELD_PREP(MT_MDP_RCFR1_RX_DROPPED_MCAST, MT_MDP_TO_HIF); 4906c92544dSBjoern A. Zeeb mt76_rmw(dev, MT_MDP_BNRCFR1(band), mask, set); 4916c92544dSBjoern A. Zeeb 4926c92544dSBjoern A. Zeeb mt76_rmw_field(dev, MT_DMA_DCR0(band), MT_DMA_DCR0_MAX_RX_LEN, 0x680); 4936c92544dSBjoern A. Zeeb 4946c92544dSBjoern A. Zeeb /* mt7915: disable rx rate report by default due to hw issues */ 4956c92544dSBjoern A. Zeeb mt76_clear(dev, MT_DMA_DCR0(band), MT_DMA_DCR0_RXD_G5_EN); 496*cbb3ec25SBjoern A. Zeeb 497*cbb3ec25SBjoern A. Zeeb /* clear estimated value of EIFS for Rx duration & OBSS time */ 498*cbb3ec25SBjoern A. Zeeb mt76_wr(dev, MT_WF_RMAC_RSVD0(band), MT_WF_RMAC_RSVD0_EIFS_CLR); 499*cbb3ec25SBjoern A. Zeeb 500*cbb3ec25SBjoern A. Zeeb /* clear backoff time for Rx duration */ 501*cbb3ec25SBjoern A. Zeeb mt76_clear(dev, MT_WF_RMAC_MIB_AIRTIME1(band), 502*cbb3ec25SBjoern A. Zeeb MT_WF_RMAC_MIB_NONQOSD_BACKOFF); 503*cbb3ec25SBjoern A. Zeeb mt76_clear(dev, MT_WF_RMAC_MIB_AIRTIME3(band), 504*cbb3ec25SBjoern A. Zeeb MT_WF_RMAC_MIB_QOS01_BACKOFF); 505*cbb3ec25SBjoern A. Zeeb mt76_clear(dev, MT_WF_RMAC_MIB_AIRTIME4(band), 506*cbb3ec25SBjoern A. Zeeb MT_WF_RMAC_MIB_QOS23_BACKOFF); 507*cbb3ec25SBjoern A. Zeeb 508*cbb3ec25SBjoern A. Zeeb /* clear backoff time and set software compensation for OBSS time */ 509*cbb3ec25SBjoern A. Zeeb mask = MT_WF_RMAC_MIB_OBSS_BACKOFF | MT_WF_RMAC_MIB_ED_OFFSET; 510*cbb3ec25SBjoern A. Zeeb set = FIELD_PREP(MT_WF_RMAC_MIB_OBSS_BACKOFF, 0) | 511*cbb3ec25SBjoern A. Zeeb FIELD_PREP(MT_WF_RMAC_MIB_ED_OFFSET, 4); 512*cbb3ec25SBjoern A. Zeeb mt76_rmw(dev, MT_WF_RMAC_MIB_AIRTIME0(band), mask, set); 513*cbb3ec25SBjoern A. Zeeb 514*cbb3ec25SBjoern A. Zeeb /* filter out non-resp frames and get instanstaeous signal reporting */ 515*cbb3ec25SBjoern A. Zeeb mask = MT_WTBLOFF_TOP_RSCR_RCPI_MODE | MT_WTBLOFF_TOP_RSCR_RCPI_PARAM; 516*cbb3ec25SBjoern A. Zeeb set = FIELD_PREP(MT_WTBLOFF_TOP_RSCR_RCPI_MODE, 0) | 517*cbb3ec25SBjoern A. Zeeb FIELD_PREP(MT_WTBLOFF_TOP_RSCR_RCPI_PARAM, 0x3); 518*cbb3ec25SBjoern A. Zeeb mt76_rmw(dev, MT_WTBLOFF_TOP_RSCR(band), mask, set); 519*cbb3ec25SBjoern A. Zeeb 520*cbb3ec25SBjoern A. Zeeb /* MT_TXD5_TX_STATUS_HOST (MPDU format) has higher priority than 521*cbb3ec25SBjoern A. Zeeb * MT_AGG_ACR_PPDU_TXS2H (PPDU format) even though ACR bit is set. 522*cbb3ec25SBjoern A. Zeeb */ 523*cbb3ec25SBjoern A. Zeeb if (mtk_wed_device_active(&dev->mt76.mmio.wed)) 524*cbb3ec25SBjoern A. Zeeb mt76_set(dev, MT_AGG_ACR4(band), MT_AGG_ACR_PPDU_TXS2H); 5256c92544dSBjoern A. Zeeb } 5266c92544dSBjoern A. Zeeb 527*cbb3ec25SBjoern A. Zeeb static void 528*cbb3ec25SBjoern A. Zeeb mt7915_init_led_mux(struct mt7915_dev *dev) 529*cbb3ec25SBjoern A. Zeeb { 530*cbb3ec25SBjoern A. Zeeb if (!IS_ENABLED(CONFIG_MT76_LEDS)) 531*cbb3ec25SBjoern A. Zeeb return; 532*cbb3ec25SBjoern A. Zeeb 533*cbb3ec25SBjoern A. Zeeb if (dev->dbdc_support) { 534*cbb3ec25SBjoern A. Zeeb switch (mt76_chip(&dev->mt76)) { 535*cbb3ec25SBjoern A. Zeeb case 0x7915: 536*cbb3ec25SBjoern A. Zeeb mt76_rmw_field(dev, MT_LED_GPIO_MUX2, 537*cbb3ec25SBjoern A. Zeeb GENMASK(11, 8), 4); 538*cbb3ec25SBjoern A. Zeeb mt76_rmw_field(dev, MT_LED_GPIO_MUX3, 539*cbb3ec25SBjoern A. Zeeb GENMASK(11, 8), 4); 540*cbb3ec25SBjoern A. Zeeb break; 541*cbb3ec25SBjoern A. Zeeb case 0x7986: 542*cbb3ec25SBjoern A. Zeeb mt76_rmw_field(dev, MT_LED_GPIO_MUX0, 543*cbb3ec25SBjoern A. Zeeb GENMASK(7, 4), 1); 544*cbb3ec25SBjoern A. Zeeb mt76_rmw_field(dev, MT_LED_GPIO_MUX0, 545*cbb3ec25SBjoern A. Zeeb GENMASK(11, 8), 1); 546*cbb3ec25SBjoern A. Zeeb break; 547*cbb3ec25SBjoern A. Zeeb case 0x7916: 548*cbb3ec25SBjoern A. Zeeb mt76_rmw_field(dev, MT_LED_GPIO_MUX1, 549*cbb3ec25SBjoern A. Zeeb GENMASK(27, 24), 3); 550*cbb3ec25SBjoern A. Zeeb mt76_rmw_field(dev, MT_LED_GPIO_MUX1, 551*cbb3ec25SBjoern A. Zeeb GENMASK(31, 28), 3); 552*cbb3ec25SBjoern A. Zeeb break; 553*cbb3ec25SBjoern A. Zeeb default: 554*cbb3ec25SBjoern A. Zeeb break; 555*cbb3ec25SBjoern A. Zeeb } 556*cbb3ec25SBjoern A. Zeeb } else if (dev->mphy.leds.pin) { 557*cbb3ec25SBjoern A. Zeeb switch (mt76_chip(&dev->mt76)) { 558*cbb3ec25SBjoern A. Zeeb case 0x7915: 559*cbb3ec25SBjoern A. Zeeb mt76_rmw_field(dev, MT_LED_GPIO_MUX3, 560*cbb3ec25SBjoern A. Zeeb GENMASK(11, 8), 4); 561*cbb3ec25SBjoern A. Zeeb break; 562*cbb3ec25SBjoern A. Zeeb case 0x7986: 563*cbb3ec25SBjoern A. Zeeb mt76_rmw_field(dev, MT_LED_GPIO_MUX0, 564*cbb3ec25SBjoern A. Zeeb GENMASK(11, 8), 1); 565*cbb3ec25SBjoern A. Zeeb break; 566*cbb3ec25SBjoern A. Zeeb case 0x7916: 567*cbb3ec25SBjoern A. Zeeb mt76_rmw_field(dev, MT_LED_GPIO_MUX1, 568*cbb3ec25SBjoern A. Zeeb GENMASK(31, 28), 3); 569*cbb3ec25SBjoern A. Zeeb break; 570*cbb3ec25SBjoern A. Zeeb default: 571*cbb3ec25SBjoern A. Zeeb break; 572*cbb3ec25SBjoern A. Zeeb } 573*cbb3ec25SBjoern A. Zeeb } else { 574*cbb3ec25SBjoern A. Zeeb switch (mt76_chip(&dev->mt76)) { 575*cbb3ec25SBjoern A. Zeeb case 0x7915: 576*cbb3ec25SBjoern A. Zeeb mt76_rmw_field(dev, MT_LED_GPIO_MUX2, 577*cbb3ec25SBjoern A. Zeeb GENMASK(11, 8), 4); 578*cbb3ec25SBjoern A. Zeeb break; 579*cbb3ec25SBjoern A. Zeeb case 0x7986: 580*cbb3ec25SBjoern A. Zeeb mt76_rmw_field(dev, MT_LED_GPIO_MUX0, 581*cbb3ec25SBjoern A. Zeeb GENMASK(7, 4), 1); 582*cbb3ec25SBjoern A. Zeeb break; 583*cbb3ec25SBjoern A. Zeeb case 0x7916: 584*cbb3ec25SBjoern A. Zeeb mt76_rmw_field(dev, MT_LED_GPIO_MUX1, 585*cbb3ec25SBjoern A. Zeeb GENMASK(27, 24), 3); 586*cbb3ec25SBjoern A. Zeeb break; 587*cbb3ec25SBjoern A. Zeeb default: 588*cbb3ec25SBjoern A. Zeeb break; 589*cbb3ec25SBjoern A. Zeeb } 590*cbb3ec25SBjoern A. Zeeb } 591*cbb3ec25SBjoern A. Zeeb } 592*cbb3ec25SBjoern A. Zeeb 593*cbb3ec25SBjoern A. Zeeb void mt7915_mac_init(struct mt7915_dev *dev) 5946c92544dSBjoern A. Zeeb { 5956c92544dSBjoern A. Zeeb int i; 5966c92544dSBjoern A. Zeeb u32 rx_len = is_mt7915(&dev->mt76) ? 0x400 : 0x680; 5976c92544dSBjoern A. Zeeb 5986c92544dSBjoern A. Zeeb /* config pse qid6 wfdma port selection */ 5996c92544dSBjoern A. Zeeb if (!is_mt7915(&dev->mt76) && dev->hif2) 6006c92544dSBjoern A. Zeeb mt76_rmw(dev, MT_WF_PP_TOP_RXQ_WFDMA_CF_5, 0, 6016c92544dSBjoern A. Zeeb MT_WF_PP_TOP_RXQ_QID6_WFDMA_HIF_SEL_MASK); 6026c92544dSBjoern A. Zeeb 6036c92544dSBjoern A. Zeeb mt76_rmw_field(dev, MT_MDP_DCR1, MT_MDP_DCR1_MAX_RX_LEN, rx_len); 6046c92544dSBjoern A. Zeeb 6056c92544dSBjoern A. Zeeb if (!is_mt7915(&dev->mt76)) 6066c92544dSBjoern A. Zeeb mt76_clear(dev, MT_MDP_DCR2, MT_MDP_DCR2_RX_TRANS_SHORT); 607*cbb3ec25SBjoern A. Zeeb else 608*cbb3ec25SBjoern A. Zeeb mt76_clear(dev, MT_PLE_HOST_RPT0, MT_PLE_HOST_RPT0_TX_LATENCY); 6096c92544dSBjoern A. Zeeb 6106c92544dSBjoern A. Zeeb /* enable hardware de-agg */ 6116c92544dSBjoern A. Zeeb mt76_set(dev, MT_MDP_DCR0, MT_MDP_DCR0_DAMSDU_EN); 6126c92544dSBjoern A. Zeeb 6136c92544dSBjoern A. Zeeb for (i = 0; i < mt7915_wtbl_size(dev); i++) 6146c92544dSBjoern A. Zeeb mt7915_mac_wtbl_update(dev, i, 6156c92544dSBjoern A. Zeeb MT_WTBL_UPDATE_ADM_COUNT_CLEAR); 6166c92544dSBjoern A. Zeeb for (i = 0; i < 2; i++) 6176c92544dSBjoern A. Zeeb mt7915_mac_init_band(dev, i); 6186c92544dSBjoern A. Zeeb 619*cbb3ec25SBjoern A. Zeeb mt7915_init_led_mux(dev); 6206c92544dSBjoern A. Zeeb } 6216c92544dSBjoern A. Zeeb 622*cbb3ec25SBjoern A. Zeeb int mt7915_txbf_init(struct mt7915_dev *dev) 6236c92544dSBjoern A. Zeeb { 6246c92544dSBjoern A. Zeeb int ret; 6256c92544dSBjoern A. Zeeb 6266c92544dSBjoern A. Zeeb if (dev->dbdc_support) { 6276c92544dSBjoern A. Zeeb ret = mt7915_mcu_set_txbf(dev, MT_BF_MODULE_UPDATE); 6286c92544dSBjoern A. Zeeb if (ret) 6296c92544dSBjoern A. Zeeb return ret; 6306c92544dSBjoern A. Zeeb } 6316c92544dSBjoern A. Zeeb 6326c92544dSBjoern A. Zeeb /* trigger sounding packets */ 6336c92544dSBjoern A. Zeeb ret = mt7915_mcu_set_txbf(dev, MT_BF_SOUNDING_ON); 6346c92544dSBjoern A. Zeeb if (ret) 6356c92544dSBjoern A. Zeeb return ret; 6366c92544dSBjoern A. Zeeb 6376c92544dSBjoern A. Zeeb /* enable eBF */ 6386c92544dSBjoern A. Zeeb return mt7915_mcu_set_txbf(dev, MT_BF_TYPE_UPDATE); 6396c92544dSBjoern A. Zeeb } 6406c92544dSBjoern A. Zeeb 6416c92544dSBjoern A. Zeeb static struct mt7915_phy * 6426c92544dSBjoern A. Zeeb mt7915_alloc_ext_phy(struct mt7915_dev *dev) 6436c92544dSBjoern A. Zeeb { 6446c92544dSBjoern A. Zeeb struct mt7915_phy *phy; 6456c92544dSBjoern A. Zeeb struct mt76_phy *mphy; 6466c92544dSBjoern A. Zeeb 6476c92544dSBjoern A. Zeeb if (!dev->dbdc_support) 6486c92544dSBjoern A. Zeeb return NULL; 6496c92544dSBjoern A. Zeeb 6506c92544dSBjoern A. Zeeb mphy = mt76_alloc_phy(&dev->mt76, sizeof(*phy), &mt7915_ops, MT_BAND1); 6516c92544dSBjoern A. Zeeb if (!mphy) 6526c92544dSBjoern A. Zeeb return ERR_PTR(-ENOMEM); 6536c92544dSBjoern A. Zeeb 6546c92544dSBjoern A. Zeeb phy = mphy->priv; 6556c92544dSBjoern A. Zeeb phy->dev = dev; 6566c92544dSBjoern A. Zeeb phy->mt76 = mphy; 6576c92544dSBjoern A. Zeeb 6586c92544dSBjoern A. Zeeb /* Bind main phy to band0 and ext_phy to band1 for dbdc case */ 659*cbb3ec25SBjoern A. Zeeb phy->mt76->band_idx = 1; 6606c92544dSBjoern A. Zeeb 6616c92544dSBjoern A. Zeeb return phy; 6626c92544dSBjoern A. Zeeb } 6636c92544dSBjoern A. Zeeb 6646c92544dSBjoern A. Zeeb static int 6656c92544dSBjoern A. Zeeb mt7915_register_ext_phy(struct mt7915_dev *dev, struct mt7915_phy *phy) 6666c92544dSBjoern A. Zeeb { 6676c92544dSBjoern A. Zeeb struct mt76_phy *mphy = phy->mt76; 6686c92544dSBjoern A. Zeeb int ret; 6696c92544dSBjoern A. Zeeb 6706c92544dSBjoern A. Zeeb INIT_DELAYED_WORK(&mphy->mac_work, mt7915_mac_work); 6716c92544dSBjoern A. Zeeb 6726c92544dSBjoern A. Zeeb mt7915_eeprom_parse_hw_cap(dev, phy); 6736c92544dSBjoern A. Zeeb 6746c92544dSBjoern A. Zeeb #if defined(__linux__) 6756c92544dSBjoern A. Zeeb memcpy(mphy->macaddr, dev->mt76.eeprom.data + MT_EE_MAC_ADDR2, 6766c92544dSBjoern A. Zeeb #elif defined(__FreeBSD__) 6776c92544dSBjoern A. Zeeb memcpy(mphy->macaddr, (u8 *)dev->mt76.eeprom.data + MT_EE_MAC_ADDR2, 6786c92544dSBjoern A. Zeeb #endif 6796c92544dSBjoern A. Zeeb ETH_ALEN); 6806c92544dSBjoern A. Zeeb /* Make the secondary PHY MAC address local without overlapping with 6816c92544dSBjoern A. Zeeb * the usual MAC address allocation scheme on multiple virtual interfaces 6826c92544dSBjoern A. Zeeb */ 6836c92544dSBjoern A. Zeeb if (!is_valid_ether_addr(mphy->macaddr)) { 6846c92544dSBjoern A. Zeeb #if defined(__linux__) 6856c92544dSBjoern A. Zeeb memcpy(mphy->macaddr, dev->mt76.eeprom.data + MT_EE_MAC_ADDR, 6866c92544dSBjoern A. Zeeb #elif defined(__FreeBSD__) 6876c92544dSBjoern A. Zeeb memcpy(mphy->macaddr, (u8 *)dev->mt76.eeprom.data + MT_EE_MAC_ADDR, 6886c92544dSBjoern A. Zeeb #endif 6896c92544dSBjoern A. Zeeb ETH_ALEN); 6906c92544dSBjoern A. Zeeb mphy->macaddr[0] |= 2; 6916c92544dSBjoern A. Zeeb mphy->macaddr[0] ^= BIT(7); 6926c92544dSBjoern A. Zeeb } 6936c92544dSBjoern A. Zeeb mt76_eeprom_override(mphy); 6946c92544dSBjoern A. Zeeb 6956c92544dSBjoern A. Zeeb /* init wiphy according to mphy and phy */ 696*cbb3ec25SBjoern A. Zeeb mt7915_init_wiphy(phy); 6976c92544dSBjoern A. Zeeb 6986c92544dSBjoern A. Zeeb ret = mt76_register_phy(mphy, true, mt76_rates, 6996c92544dSBjoern A. Zeeb ARRAY_SIZE(mt76_rates)); 7006c92544dSBjoern A. Zeeb if (ret) 7016c92544dSBjoern A. Zeeb return ret; 7026c92544dSBjoern A. Zeeb 7036c92544dSBjoern A. Zeeb ret = mt7915_thermal_init(phy); 7046c92544dSBjoern A. Zeeb if (ret) 7056c92544dSBjoern A. Zeeb goto unreg; 7066c92544dSBjoern A. Zeeb 7076c92544dSBjoern A. Zeeb #if !defined(__FreeBSD__) || defined(CONFIG_MT7915_DEBUGFS) 7086c92544dSBjoern A. Zeeb mt7915_init_debugfs(phy); 7096c92544dSBjoern A. Zeeb #endif 7106c92544dSBjoern A. Zeeb 7116c92544dSBjoern A. Zeeb return 0; 7126c92544dSBjoern A. Zeeb 7136c92544dSBjoern A. Zeeb unreg: 7146c92544dSBjoern A. Zeeb mt76_unregister_phy(mphy); 7156c92544dSBjoern A. Zeeb return ret; 7166c92544dSBjoern A. Zeeb } 7176c92544dSBjoern A. Zeeb 7186c92544dSBjoern A. Zeeb static void mt7915_init_work(struct work_struct *work) 7196c92544dSBjoern A. Zeeb { 7206c92544dSBjoern A. Zeeb struct mt7915_dev *dev = container_of(work, struct mt7915_dev, 7216c92544dSBjoern A. Zeeb init_work); 7226c92544dSBjoern A. Zeeb 7236c92544dSBjoern A. Zeeb mt7915_mcu_set_eeprom(dev); 7246c92544dSBjoern A. Zeeb mt7915_mac_init(dev); 7256c92544dSBjoern A. Zeeb mt7915_init_txpower(dev, &dev->mphy.sband_2g.sband); 7266c92544dSBjoern A. Zeeb mt7915_init_txpower(dev, &dev->mphy.sband_5g.sband); 7276c92544dSBjoern A. Zeeb mt7915_init_txpower(dev, &dev->mphy.sband_6g.sband); 7286c92544dSBjoern A. Zeeb mt7915_txbf_init(dev); 7296c92544dSBjoern A. Zeeb } 7306c92544dSBjoern A. Zeeb 7316c92544dSBjoern A. Zeeb void mt7915_wfsys_reset(struct mt7915_dev *dev) 7326c92544dSBjoern A. Zeeb { 7336c92544dSBjoern A. Zeeb #define MT_MCU_DUMMY_RANDOM GENMASK(15, 0) 7346c92544dSBjoern A. Zeeb #define MT_MCU_DUMMY_DEFAULT GENMASK(31, 16) 7356c92544dSBjoern A. Zeeb 7366c92544dSBjoern A. Zeeb if (is_mt7915(&dev->mt76)) { 7376c92544dSBjoern A. Zeeb u32 val = MT_TOP_PWR_KEY | MT_TOP_PWR_SW_PWR_ON | MT_TOP_PWR_PWR_ON; 7386c92544dSBjoern A. Zeeb 7396c92544dSBjoern A. Zeeb mt76_wr(dev, MT_MCU_WFDMA0_DUMMY_CR, MT_MCU_DUMMY_RANDOM); 7406c92544dSBjoern A. Zeeb 7416c92544dSBjoern A. Zeeb /* change to software control */ 7426c92544dSBjoern A. Zeeb val |= MT_TOP_PWR_SW_RST; 7436c92544dSBjoern A. Zeeb mt76_wr(dev, MT_TOP_PWR_CTRL, val); 7446c92544dSBjoern A. Zeeb 7456c92544dSBjoern A. Zeeb /* reset wfsys */ 7466c92544dSBjoern A. Zeeb val &= ~MT_TOP_PWR_SW_RST; 7476c92544dSBjoern A. Zeeb mt76_wr(dev, MT_TOP_PWR_CTRL, val); 7486c92544dSBjoern A. Zeeb 7496c92544dSBjoern A. Zeeb /* release wfsys then mcu re-executes romcode */ 7506c92544dSBjoern A. Zeeb val |= MT_TOP_PWR_SW_RST; 7516c92544dSBjoern A. Zeeb mt76_wr(dev, MT_TOP_PWR_CTRL, val); 7526c92544dSBjoern A. Zeeb 7536c92544dSBjoern A. Zeeb /* switch to hw control */ 7546c92544dSBjoern A. Zeeb val &= ~MT_TOP_PWR_SW_RST; 7556c92544dSBjoern A. Zeeb val |= MT_TOP_PWR_HW_CTRL; 7566c92544dSBjoern A. Zeeb mt76_wr(dev, MT_TOP_PWR_CTRL, val); 7576c92544dSBjoern A. Zeeb 7586c92544dSBjoern A. Zeeb /* check whether mcu resets to default */ 7596c92544dSBjoern A. Zeeb if (!mt76_poll_msec(dev, MT_MCU_WFDMA0_DUMMY_CR, 7606c92544dSBjoern A. Zeeb MT_MCU_DUMMY_DEFAULT, MT_MCU_DUMMY_DEFAULT, 7616c92544dSBjoern A. Zeeb 1000)) { 7626c92544dSBjoern A. Zeeb dev_err(dev->mt76.dev, "wifi subsystem reset failure\n"); 7636c92544dSBjoern A. Zeeb return; 7646c92544dSBjoern A. Zeeb } 7656c92544dSBjoern A. Zeeb 7666c92544dSBjoern A. Zeeb /* wfsys reset won't clear host registers */ 7676c92544dSBjoern A. Zeeb mt76_clear(dev, MT_TOP_MISC, MT_TOP_MISC_FW_STATE); 7686c92544dSBjoern A. Zeeb 7696c92544dSBjoern A. Zeeb msleep(100); 770*cbb3ec25SBjoern A. Zeeb } else if (is_mt798x(&dev->mt76)) { 7716c92544dSBjoern A. Zeeb mt7986_wmac_disable(dev); 7726c92544dSBjoern A. Zeeb msleep(20); 7736c92544dSBjoern A. Zeeb 7746c92544dSBjoern A. Zeeb mt7986_wmac_enable(dev); 7756c92544dSBjoern A. Zeeb msleep(20); 7766c92544dSBjoern A. Zeeb } else { 7776c92544dSBjoern A. Zeeb mt76_set(dev, MT_WF_SUBSYS_RST, 0x1); 7786c92544dSBjoern A. Zeeb msleep(20); 7796c92544dSBjoern A. Zeeb 7806c92544dSBjoern A. Zeeb mt76_clear(dev, MT_WF_SUBSYS_RST, 0x1); 7816c92544dSBjoern A. Zeeb msleep(20); 7826c92544dSBjoern A. Zeeb } 7836c92544dSBjoern A. Zeeb } 7846c92544dSBjoern A. Zeeb 7856c92544dSBjoern A. Zeeb static bool mt7915_band_config(struct mt7915_dev *dev) 7866c92544dSBjoern A. Zeeb { 7876c92544dSBjoern A. Zeeb bool ret = true; 7886c92544dSBjoern A. Zeeb 789*cbb3ec25SBjoern A. Zeeb dev->phy.mt76->band_idx = 0; 7906c92544dSBjoern A. Zeeb 791*cbb3ec25SBjoern A. Zeeb if (is_mt798x(&dev->mt76)) { 7926c92544dSBjoern A. Zeeb u32 sku = mt7915_check_adie(dev, true); 7936c92544dSBjoern A. Zeeb 7946c92544dSBjoern A. Zeeb /* 7956c92544dSBjoern A. Zeeb * for mt7986, dbdc support is determined by the number 7966c92544dSBjoern A. Zeeb * of adie chips and the main phy is bound to band1 when 7976c92544dSBjoern A. Zeeb * dbdc is disabled. 7986c92544dSBjoern A. Zeeb */ 7996c92544dSBjoern A. Zeeb if (sku == MT7975_ONE_ADIE || sku == MT7976_ONE_ADIE) { 800*cbb3ec25SBjoern A. Zeeb dev->phy.mt76->band_idx = 1; 8016c92544dSBjoern A. Zeeb ret = false; 8026c92544dSBjoern A. Zeeb } 8036c92544dSBjoern A. Zeeb } else { 8046c92544dSBjoern A. Zeeb ret = is_mt7915(&dev->mt76) ? 8056c92544dSBjoern A. Zeeb !!(mt76_rr(dev, MT_HW_BOUND) & BIT(5)) : true; 8066c92544dSBjoern A. Zeeb } 8076c92544dSBjoern A. Zeeb 8086c92544dSBjoern A. Zeeb return ret; 8096c92544dSBjoern A. Zeeb } 8106c92544dSBjoern A. Zeeb 8116c92544dSBjoern A. Zeeb static int 8126c92544dSBjoern A. Zeeb mt7915_init_hardware(struct mt7915_dev *dev, struct mt7915_phy *phy2) 8136c92544dSBjoern A. Zeeb { 8146c92544dSBjoern A. Zeeb int ret, idx; 8156c92544dSBjoern A. Zeeb 8166c92544dSBjoern A. Zeeb mt76_wr(dev, MT_INT_MASK_CSR, 0); 8176c92544dSBjoern A. Zeeb mt76_wr(dev, MT_INT_SOURCE_CSR, ~0); 8186c92544dSBjoern A. Zeeb 8196c92544dSBjoern A. Zeeb INIT_WORK(&dev->init_work, mt7915_init_work); 8206c92544dSBjoern A. Zeeb 8216c92544dSBjoern A. Zeeb ret = mt7915_dma_init(dev, phy2); 8226c92544dSBjoern A. Zeeb if (ret) 8236c92544dSBjoern A. Zeeb return ret; 8246c92544dSBjoern A. Zeeb 8256c92544dSBjoern A. Zeeb set_bit(MT76_STATE_INITIALIZED, &dev->mphy.state); 8266c92544dSBjoern A. Zeeb 8276c92544dSBjoern A. Zeeb ret = mt7915_mcu_init(dev); 8286c92544dSBjoern A. Zeeb if (ret) 8296c92544dSBjoern A. Zeeb return ret; 8306c92544dSBjoern A. Zeeb 8316c92544dSBjoern A. Zeeb ret = mt7915_eeprom_init(dev); 8326c92544dSBjoern A. Zeeb if (ret < 0) 8336c92544dSBjoern A. Zeeb return ret; 8346c92544dSBjoern A. Zeeb 8356c92544dSBjoern A. Zeeb if (dev->flash_mode) { 8366c92544dSBjoern A. Zeeb ret = mt7915_mcu_apply_group_cal(dev); 8376c92544dSBjoern A. Zeeb if (ret) 8386c92544dSBjoern A. Zeeb return ret; 8396c92544dSBjoern A. Zeeb } 8406c92544dSBjoern A. Zeeb 8416c92544dSBjoern A. Zeeb /* Beacon and mgmt frames should occupy wcid 0 */ 8426c92544dSBjoern A. Zeeb idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7915_WTBL_STA); 8436c92544dSBjoern A. Zeeb if (idx) 8446c92544dSBjoern A. Zeeb return -ENOSPC; 8456c92544dSBjoern A. Zeeb 8466c92544dSBjoern A. Zeeb dev->mt76.global_wcid.idx = idx; 8476c92544dSBjoern A. Zeeb dev->mt76.global_wcid.hw_key_idx = -1; 8486c92544dSBjoern A. Zeeb dev->mt76.global_wcid.tx_info |= MT_WCID_TX_INFO_SET; 8496c92544dSBjoern A. Zeeb rcu_assign_pointer(dev->mt76.wcid[idx], &dev->mt76.global_wcid); 8506c92544dSBjoern A. Zeeb 8516c92544dSBjoern A. Zeeb return 0; 8526c92544dSBjoern A. Zeeb } 8536c92544dSBjoern A. Zeeb 8546c92544dSBjoern A. Zeeb void mt7915_set_stream_vht_txbf_caps(struct mt7915_phy *phy) 8556c92544dSBjoern A. Zeeb { 856*cbb3ec25SBjoern A. Zeeb int sts; 8576c92544dSBjoern A. Zeeb u32 *cap; 8586c92544dSBjoern A. Zeeb 8596c92544dSBjoern A. Zeeb if (!phy->mt76->cap.has_5ghz) 8606c92544dSBjoern A. Zeeb return; 8616c92544dSBjoern A. Zeeb 862*cbb3ec25SBjoern A. Zeeb sts = hweight8(phy->mt76->chainmask); 8636c92544dSBjoern A. Zeeb cap = &phy->mt76->sband_5g.sband.vht_cap.cap; 8646c92544dSBjoern A. Zeeb 8656c92544dSBjoern A. Zeeb *cap |= IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE | 8666c92544dSBjoern A. Zeeb IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE | 867*cbb3ec25SBjoern A. Zeeb FIELD_PREP(IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK, 868*cbb3ec25SBjoern A. Zeeb sts - 1); 8696c92544dSBjoern A. Zeeb 8706c92544dSBjoern A. Zeeb *cap &= ~(IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK | 8716c92544dSBjoern A. Zeeb IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE | 8726c92544dSBjoern A. Zeeb IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE); 8736c92544dSBjoern A. Zeeb 874*cbb3ec25SBjoern A. Zeeb if (sts < 2) 8756c92544dSBjoern A. Zeeb return; 8766c92544dSBjoern A. Zeeb 8776c92544dSBjoern A. Zeeb *cap |= IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE | 8786c92544dSBjoern A. Zeeb IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE | 8796c92544dSBjoern A. Zeeb FIELD_PREP(IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK, 880*cbb3ec25SBjoern A. Zeeb sts - 1); 8816c92544dSBjoern A. Zeeb } 8826c92544dSBjoern A. Zeeb 8836c92544dSBjoern A. Zeeb static void 884*cbb3ec25SBjoern A. Zeeb mt7915_set_stream_he_txbf_caps(struct mt7915_phy *phy, 885*cbb3ec25SBjoern A. Zeeb struct ieee80211_sta_he_cap *he_cap, int vif) 8866c92544dSBjoern A. Zeeb { 887*cbb3ec25SBjoern A. Zeeb struct mt7915_dev *dev = phy->dev; 8886c92544dSBjoern A. Zeeb struct ieee80211_he_cap_elem *elem = &he_cap->he_cap_elem; 889*cbb3ec25SBjoern A. Zeeb int sts = hweight8(phy->mt76->chainmask); 890*cbb3ec25SBjoern A. Zeeb u8 c, sts_160 = sts; 8916c92544dSBjoern A. Zeeb 892*cbb3ec25SBjoern A. Zeeb /* Can do 1/2 of STS in 160Mhz mode for mt7915 */ 893*cbb3ec25SBjoern A. Zeeb if (is_mt7915(&dev->mt76)) { 894*cbb3ec25SBjoern A. Zeeb if (!dev->dbdc_support) 895*cbb3ec25SBjoern A. Zeeb sts_160 /= 2; 8966c92544dSBjoern A. Zeeb else 897*cbb3ec25SBjoern A. Zeeb sts_160 = 0; 898*cbb3ec25SBjoern A. Zeeb } 8996c92544dSBjoern A. Zeeb 9006c92544dSBjoern A. Zeeb #ifdef CONFIG_MAC80211_MESH 9016c92544dSBjoern A. Zeeb if (vif == NL80211_IFTYPE_MESH_POINT) 9026c92544dSBjoern A. Zeeb return; 9036c92544dSBjoern A. Zeeb #endif 9046c92544dSBjoern A. Zeeb 9056c92544dSBjoern A. Zeeb elem->phy_cap_info[3] &= ~IEEE80211_HE_PHY_CAP3_SU_BEAMFORMER; 9066c92544dSBjoern A. Zeeb elem->phy_cap_info[4] &= ~IEEE80211_HE_PHY_CAP4_MU_BEAMFORMER; 9076c92544dSBjoern A. Zeeb 908*cbb3ec25SBjoern A. Zeeb c = IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_MASK; 909*cbb3ec25SBjoern A. Zeeb if (sts_160) 910*cbb3ec25SBjoern A. Zeeb c |= IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_MASK; 9116c92544dSBjoern A. Zeeb elem->phy_cap_info[5] &= ~c; 9126c92544dSBjoern A. Zeeb 9136c92544dSBjoern A. Zeeb c = IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMING_FB | 9146c92544dSBjoern A. Zeeb IEEE80211_HE_PHY_CAP6_TRIG_MU_BEAMFORMING_PARTIAL_BW_FB; 9156c92544dSBjoern A. Zeeb elem->phy_cap_info[6] &= ~c; 9166c92544dSBjoern A. Zeeb 9176c92544dSBjoern A. Zeeb elem->phy_cap_info[7] &= ~IEEE80211_HE_PHY_CAP7_MAX_NC_MASK; 9186c92544dSBjoern A. Zeeb 9196c92544dSBjoern A. Zeeb c = IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US; 9206c92544dSBjoern A. Zeeb if (!is_mt7915(&dev->mt76)) 9216c92544dSBjoern A. Zeeb c |= IEEE80211_HE_PHY_CAP2_UL_MU_FULL_MU_MIMO | 9226c92544dSBjoern A. Zeeb IEEE80211_HE_PHY_CAP2_UL_MU_PARTIAL_MU_MIMO; 9236c92544dSBjoern A. Zeeb elem->phy_cap_info[2] |= c; 9246c92544dSBjoern A. Zeeb 9256c92544dSBjoern A. Zeeb c = IEEE80211_HE_PHY_CAP4_SU_BEAMFORMEE | 926*cbb3ec25SBjoern A. Zeeb IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_4; 927*cbb3ec25SBjoern A. Zeeb if (sts_160) 928*cbb3ec25SBjoern A. Zeeb c |= IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_4; 9296c92544dSBjoern A. Zeeb elem->phy_cap_info[4] |= c; 9306c92544dSBjoern A. Zeeb 9316c92544dSBjoern A. Zeeb /* do not support NG16 due to spec D4.0 changes subcarrier idx */ 9326c92544dSBjoern A. Zeeb c = IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_42_SU | 9336c92544dSBjoern A. Zeeb IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_75_MU; 9346c92544dSBjoern A. Zeeb 9356c92544dSBjoern A. Zeeb if (vif == NL80211_IFTYPE_STATION) 9366c92544dSBjoern A. Zeeb c |= IEEE80211_HE_PHY_CAP6_PARTIAL_BANDWIDTH_DL_MUMIMO; 9376c92544dSBjoern A. Zeeb 9386c92544dSBjoern A. Zeeb elem->phy_cap_info[6] |= c; 9396c92544dSBjoern A. Zeeb 940*cbb3ec25SBjoern A. Zeeb if (sts < 2) 9416c92544dSBjoern A. Zeeb return; 9426c92544dSBjoern A. Zeeb 9436c92544dSBjoern A. Zeeb /* the maximum cap is 4 x 3, (Nr, Nc) = (3, 2) */ 944*cbb3ec25SBjoern A. Zeeb elem->phy_cap_info[7] |= min_t(int, sts - 1, 2) << 3; 9456c92544dSBjoern A. Zeeb 9466c92544dSBjoern A. Zeeb if (vif != NL80211_IFTYPE_AP) 9476c92544dSBjoern A. Zeeb return; 9486c92544dSBjoern A. Zeeb 9496c92544dSBjoern A. Zeeb elem->phy_cap_info[3] |= IEEE80211_HE_PHY_CAP3_SU_BEAMFORMER; 9506c92544dSBjoern A. Zeeb elem->phy_cap_info[4] |= IEEE80211_HE_PHY_CAP4_MU_BEAMFORMER; 9516c92544dSBjoern A. Zeeb 9526c92544dSBjoern A. Zeeb c = FIELD_PREP(IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_MASK, 953*cbb3ec25SBjoern A. Zeeb sts - 1); 954*cbb3ec25SBjoern A. Zeeb if (sts_160) 955*cbb3ec25SBjoern A. Zeeb c |= FIELD_PREP(IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_MASK, 956*cbb3ec25SBjoern A. Zeeb sts_160 - 1); 9576c92544dSBjoern A. Zeeb elem->phy_cap_info[5] |= c; 9586c92544dSBjoern A. Zeeb 9596c92544dSBjoern A. Zeeb c = IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMING_FB | 9606c92544dSBjoern A. Zeeb IEEE80211_HE_PHY_CAP6_TRIG_MU_BEAMFORMING_PARTIAL_BW_FB; 9616c92544dSBjoern A. Zeeb elem->phy_cap_info[6] |= c; 9626c92544dSBjoern A. Zeeb 9636c92544dSBjoern A. Zeeb if (!is_mt7915(&dev->mt76)) { 9646c92544dSBjoern A. Zeeb c = IEEE80211_HE_PHY_CAP7_STBC_TX_ABOVE_80MHZ | 9656c92544dSBjoern A. Zeeb IEEE80211_HE_PHY_CAP7_STBC_RX_ABOVE_80MHZ; 9666c92544dSBjoern A. Zeeb elem->phy_cap_info[7] |= c; 9676c92544dSBjoern A. Zeeb } 9686c92544dSBjoern A. Zeeb } 9696c92544dSBjoern A. Zeeb 9706c92544dSBjoern A. Zeeb static int 9716c92544dSBjoern A. Zeeb mt7915_init_he_caps(struct mt7915_phy *phy, enum nl80211_band band, 9726c92544dSBjoern A. Zeeb struct ieee80211_sband_iftype_data *data) 9736c92544dSBjoern A. Zeeb { 9746c92544dSBjoern A. Zeeb struct mt7915_dev *dev = phy->dev; 975*cbb3ec25SBjoern A. Zeeb int i, idx = 0, nss = hweight8(phy->mt76->antenna_mask); 9766c92544dSBjoern A. Zeeb u16 mcs_map = 0; 9776c92544dSBjoern A. Zeeb u16 mcs_map_160 = 0; 9786c92544dSBjoern A. Zeeb u8 nss_160; 9796c92544dSBjoern A. Zeeb 980*cbb3ec25SBjoern A. Zeeb if (!is_mt7915(&dev->mt76)) 981*cbb3ec25SBjoern A. Zeeb nss_160 = nss; 982*cbb3ec25SBjoern A. Zeeb else if (!dev->dbdc_support) 9836c92544dSBjoern A. Zeeb /* Can do 1/2 of NSS streams in 160Mhz mode for mt7915 */ 9846c92544dSBjoern A. Zeeb nss_160 = nss / 2; 9856c92544dSBjoern A. Zeeb else 986*cbb3ec25SBjoern A. Zeeb /* Can't do 160MHz with mt7915 dbdc */ 987*cbb3ec25SBjoern A. Zeeb nss_160 = 0; 9886c92544dSBjoern A. Zeeb 9896c92544dSBjoern A. Zeeb for (i = 0; i < 8; i++) { 9906c92544dSBjoern A. Zeeb if (i < nss) 9916c92544dSBjoern A. Zeeb mcs_map |= (IEEE80211_HE_MCS_SUPPORT_0_11 << (i * 2)); 9926c92544dSBjoern A. Zeeb else 9936c92544dSBjoern A. Zeeb mcs_map |= (IEEE80211_HE_MCS_NOT_SUPPORTED << (i * 2)); 9946c92544dSBjoern A. Zeeb 9956c92544dSBjoern A. Zeeb if (i < nss_160) 9966c92544dSBjoern A. Zeeb mcs_map_160 |= (IEEE80211_HE_MCS_SUPPORT_0_11 << (i * 2)); 9976c92544dSBjoern A. Zeeb else 9986c92544dSBjoern A. Zeeb mcs_map_160 |= (IEEE80211_HE_MCS_NOT_SUPPORTED << (i * 2)); 9996c92544dSBjoern A. Zeeb } 10006c92544dSBjoern A. Zeeb 10016c92544dSBjoern A. Zeeb for (i = 0; i < NUM_NL80211_IFTYPES; i++) { 10026c92544dSBjoern A. Zeeb struct ieee80211_sta_he_cap *he_cap = &data[idx].he_cap; 10036c92544dSBjoern A. Zeeb struct ieee80211_he_cap_elem *he_cap_elem = 10046c92544dSBjoern A. Zeeb &he_cap->he_cap_elem; 10056c92544dSBjoern A. Zeeb struct ieee80211_he_mcs_nss_supp *he_mcs = 10066c92544dSBjoern A. Zeeb &he_cap->he_mcs_nss_supp; 10076c92544dSBjoern A. Zeeb 10086c92544dSBjoern A. Zeeb switch (i) { 10096c92544dSBjoern A. Zeeb case NL80211_IFTYPE_STATION: 10106c92544dSBjoern A. Zeeb case NL80211_IFTYPE_AP: 10116c92544dSBjoern A. Zeeb #ifdef CONFIG_MAC80211_MESH 10126c92544dSBjoern A. Zeeb case NL80211_IFTYPE_MESH_POINT: 10136c92544dSBjoern A. Zeeb #endif 10146c92544dSBjoern A. Zeeb break; 10156c92544dSBjoern A. Zeeb default: 10166c92544dSBjoern A. Zeeb continue; 10176c92544dSBjoern A. Zeeb } 10186c92544dSBjoern A. Zeeb 10196c92544dSBjoern A. Zeeb data[idx].types_mask = BIT(i); 10206c92544dSBjoern A. Zeeb he_cap->has_he = true; 10216c92544dSBjoern A. Zeeb 10226c92544dSBjoern A. Zeeb he_cap_elem->mac_cap_info[0] = 10236c92544dSBjoern A. Zeeb IEEE80211_HE_MAC_CAP0_HTC_HE; 10246c92544dSBjoern A. Zeeb he_cap_elem->mac_cap_info[3] = 10256c92544dSBjoern A. Zeeb IEEE80211_HE_MAC_CAP3_OMI_CONTROL | 10266c92544dSBjoern A. Zeeb IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_3; 10276c92544dSBjoern A. Zeeb he_cap_elem->mac_cap_info[4] = 10286c92544dSBjoern A. Zeeb IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU; 10296c92544dSBjoern A. Zeeb 10306c92544dSBjoern A. Zeeb if (band == NL80211_BAND_2GHZ) 10316c92544dSBjoern A. Zeeb he_cap_elem->phy_cap_info[0] = 10326c92544dSBjoern A. Zeeb IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G; 1033*cbb3ec25SBjoern A. Zeeb else if (nss_160) 10346c92544dSBjoern A. Zeeb he_cap_elem->phy_cap_info[0] = 10356c92544dSBjoern A. Zeeb IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G | 1036*cbb3ec25SBjoern A. Zeeb IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G; 1037*cbb3ec25SBjoern A. Zeeb else 1038*cbb3ec25SBjoern A. Zeeb he_cap_elem->phy_cap_info[0] = 1039*cbb3ec25SBjoern A. Zeeb IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G; 10406c92544dSBjoern A. Zeeb 10416c92544dSBjoern A. Zeeb he_cap_elem->phy_cap_info[1] = 10426c92544dSBjoern A. Zeeb IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD; 10436c92544dSBjoern A. Zeeb he_cap_elem->phy_cap_info[2] = 10446c92544dSBjoern A. Zeeb IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ | 10456c92544dSBjoern A. Zeeb IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ; 10466c92544dSBjoern A. Zeeb 10476c92544dSBjoern A. Zeeb switch (i) { 10486c92544dSBjoern A. Zeeb case NL80211_IFTYPE_AP: 10496c92544dSBjoern A. Zeeb he_cap_elem->mac_cap_info[0] |= 10506c92544dSBjoern A. Zeeb IEEE80211_HE_MAC_CAP0_TWT_RES; 10516c92544dSBjoern A. Zeeb he_cap_elem->mac_cap_info[2] |= 10526c92544dSBjoern A. Zeeb IEEE80211_HE_MAC_CAP2_BSR; 10536c92544dSBjoern A. Zeeb he_cap_elem->mac_cap_info[4] |= 10546c92544dSBjoern A. Zeeb IEEE80211_HE_MAC_CAP4_BQR; 10556c92544dSBjoern A. Zeeb he_cap_elem->mac_cap_info[5] |= 10566c92544dSBjoern A. Zeeb IEEE80211_HE_MAC_CAP5_OM_CTRL_UL_MU_DATA_DIS_RX; 10576c92544dSBjoern A. Zeeb he_cap_elem->phy_cap_info[3] |= 10586c92544dSBjoern A. Zeeb IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_QPSK | 10596c92544dSBjoern A. Zeeb IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_QPSK; 10606c92544dSBjoern A. Zeeb he_cap_elem->phy_cap_info[6] |= 10616c92544dSBjoern A. Zeeb IEEE80211_HE_PHY_CAP6_PARTIAL_BW_EXT_RANGE | 10626c92544dSBjoern A. Zeeb IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT; 10636c92544dSBjoern A. Zeeb he_cap_elem->phy_cap_info[9] |= 10646c92544dSBjoern A. Zeeb IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU | 10656c92544dSBjoern A. Zeeb IEEE80211_HE_PHY_CAP9_RX_1024_QAM_LESS_THAN_242_TONE_RU; 10666c92544dSBjoern A. Zeeb break; 10676c92544dSBjoern A. Zeeb case NL80211_IFTYPE_STATION: 10686c92544dSBjoern A. Zeeb he_cap_elem->mac_cap_info[1] |= 10696c92544dSBjoern A. Zeeb IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US; 10706c92544dSBjoern A. Zeeb 10716c92544dSBjoern A. Zeeb if (band == NL80211_BAND_2GHZ) 10726c92544dSBjoern A. Zeeb he_cap_elem->phy_cap_info[0] |= 10736c92544dSBjoern A. Zeeb IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_2G; 10746c92544dSBjoern A. Zeeb else 10756c92544dSBjoern A. Zeeb he_cap_elem->phy_cap_info[0] |= 10766c92544dSBjoern A. Zeeb IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_5G; 10776c92544dSBjoern A. Zeeb 10786c92544dSBjoern A. Zeeb he_cap_elem->phy_cap_info[1] |= 10796c92544dSBjoern A. Zeeb IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A | 10806c92544dSBjoern A. Zeeb IEEE80211_HE_PHY_CAP1_HE_LTF_AND_GI_FOR_HE_PPDUS_0_8US; 10816c92544dSBjoern A. Zeeb he_cap_elem->phy_cap_info[3] |= 10826c92544dSBjoern A. Zeeb IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_QPSK | 10836c92544dSBjoern A. Zeeb IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_QPSK; 10846c92544dSBjoern A. Zeeb he_cap_elem->phy_cap_info[6] |= 10856c92544dSBjoern A. Zeeb IEEE80211_HE_PHY_CAP6_TRIG_CQI_FB | 10866c92544dSBjoern A. Zeeb IEEE80211_HE_PHY_CAP6_PARTIAL_BW_EXT_RANGE | 10876c92544dSBjoern A. Zeeb IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT; 10886c92544dSBjoern A. Zeeb he_cap_elem->phy_cap_info[7] |= 10896c92544dSBjoern A. Zeeb IEEE80211_HE_PHY_CAP7_POWER_BOOST_FACTOR_SUPP | 10906c92544dSBjoern A. Zeeb IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI; 10916c92544dSBjoern A. Zeeb he_cap_elem->phy_cap_info[8] |= 10926c92544dSBjoern A. Zeeb IEEE80211_HE_PHY_CAP8_20MHZ_IN_40MHZ_HE_PPDU_IN_2G | 10936c92544dSBjoern A. Zeeb IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_484; 1094*cbb3ec25SBjoern A. Zeeb if (nss_160) 1095*cbb3ec25SBjoern A. Zeeb he_cap_elem->phy_cap_info[8] |= 1096*cbb3ec25SBjoern A. Zeeb IEEE80211_HE_PHY_CAP8_20MHZ_IN_160MHZ_HE_PPDU | 1097*cbb3ec25SBjoern A. Zeeb IEEE80211_HE_PHY_CAP8_80MHZ_IN_160MHZ_HE_PPDU; 10986c92544dSBjoern A. Zeeb he_cap_elem->phy_cap_info[9] |= 10996c92544dSBjoern A. Zeeb IEEE80211_HE_PHY_CAP9_LONGER_THAN_16_SIGB_OFDM_SYM | 11006c92544dSBjoern A. Zeeb IEEE80211_HE_PHY_CAP9_NON_TRIGGERED_CQI_FEEDBACK | 11016c92544dSBjoern A. Zeeb IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU | 11026c92544dSBjoern A. Zeeb IEEE80211_HE_PHY_CAP9_RX_1024_QAM_LESS_THAN_242_TONE_RU | 11036c92544dSBjoern A. Zeeb IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_COMP_SIGB | 11046c92544dSBjoern A. Zeeb IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_NON_COMP_SIGB; 11056c92544dSBjoern A. Zeeb break; 11066c92544dSBjoern A. Zeeb } 11076c92544dSBjoern A. Zeeb 1108*cbb3ec25SBjoern A. Zeeb memset(he_mcs, 0, sizeof(*he_mcs)); 11096c92544dSBjoern A. Zeeb he_mcs->rx_mcs_80 = cpu_to_le16(mcs_map); 11106c92544dSBjoern A. Zeeb he_mcs->tx_mcs_80 = cpu_to_le16(mcs_map); 11116c92544dSBjoern A. Zeeb he_mcs->rx_mcs_160 = cpu_to_le16(mcs_map_160); 11126c92544dSBjoern A. Zeeb he_mcs->tx_mcs_160 = cpu_to_le16(mcs_map_160); 11136c92544dSBjoern A. Zeeb 1114*cbb3ec25SBjoern A. Zeeb mt7915_set_stream_he_txbf_caps(phy, he_cap, i); 11156c92544dSBjoern A. Zeeb 11166c92544dSBjoern A. Zeeb memset(he_cap->ppe_thres, 0, sizeof(he_cap->ppe_thres)); 11176c92544dSBjoern A. Zeeb if (he_cap_elem->phy_cap_info[6] & 11186c92544dSBjoern A. Zeeb IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT) { 1119*cbb3ec25SBjoern A. Zeeb mt76_connac_gen_ppe_thresh(he_cap->ppe_thres, nss); 11206c92544dSBjoern A. Zeeb } else { 11216c92544dSBjoern A. Zeeb he_cap_elem->phy_cap_info[9] |= 11226c92544dSBjoern A. Zeeb u8_encode_bits(IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_16US, 11236c92544dSBjoern A. Zeeb IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_MASK); 11246c92544dSBjoern A. Zeeb } 11256c92544dSBjoern A. Zeeb 11266c92544dSBjoern A. Zeeb if (band == NL80211_BAND_6GHZ) { 11276c92544dSBjoern A. Zeeb u16 cap = IEEE80211_HE_6GHZ_CAP_TX_ANTPAT_CONS | 11286c92544dSBjoern A. Zeeb IEEE80211_HE_6GHZ_CAP_RX_ANTPAT_CONS; 11296c92544dSBjoern A. Zeeb 11306c92544dSBjoern A. Zeeb cap |= u16_encode_bits(IEEE80211_HT_MPDU_DENSITY_2, 11316c92544dSBjoern A. Zeeb IEEE80211_HE_6GHZ_CAP_MIN_MPDU_START) | 11326c92544dSBjoern A. Zeeb u16_encode_bits(IEEE80211_VHT_MAX_AMPDU_1024K, 11336c92544dSBjoern A. Zeeb IEEE80211_HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP) | 11346c92544dSBjoern A. Zeeb u16_encode_bits(IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454, 11356c92544dSBjoern A. Zeeb IEEE80211_HE_6GHZ_CAP_MAX_MPDU_LEN); 11366c92544dSBjoern A. Zeeb 11376c92544dSBjoern A. Zeeb data[idx].he_6ghz_capa.capa = cpu_to_le16(cap); 11386c92544dSBjoern A. Zeeb } 11396c92544dSBjoern A. Zeeb 11406c92544dSBjoern A. Zeeb idx++; 11416c92544dSBjoern A. Zeeb } 11426c92544dSBjoern A. Zeeb 11436c92544dSBjoern A. Zeeb return idx; 11446c92544dSBjoern A. Zeeb } 11456c92544dSBjoern A. Zeeb 11466c92544dSBjoern A. Zeeb void mt7915_set_stream_he_caps(struct mt7915_phy *phy) 11476c92544dSBjoern A. Zeeb { 11486c92544dSBjoern A. Zeeb struct ieee80211_sband_iftype_data *data; 11496c92544dSBjoern A. Zeeb struct ieee80211_supported_band *band; 11506c92544dSBjoern A. Zeeb int n; 11516c92544dSBjoern A. Zeeb 11526c92544dSBjoern A. Zeeb if (phy->mt76->cap.has_2ghz) { 11536c92544dSBjoern A. Zeeb data = phy->iftype[NL80211_BAND_2GHZ]; 11546c92544dSBjoern A. Zeeb n = mt7915_init_he_caps(phy, NL80211_BAND_2GHZ, data); 11556c92544dSBjoern A. Zeeb 11566c92544dSBjoern A. Zeeb band = &phy->mt76->sband_2g.sband; 11576c92544dSBjoern A. Zeeb band->iftype_data = data; 11586c92544dSBjoern A. Zeeb band->n_iftype_data = n; 11596c92544dSBjoern A. Zeeb } 11606c92544dSBjoern A. Zeeb 11616c92544dSBjoern A. Zeeb if (phy->mt76->cap.has_5ghz) { 11626c92544dSBjoern A. Zeeb data = phy->iftype[NL80211_BAND_5GHZ]; 11636c92544dSBjoern A. Zeeb n = mt7915_init_he_caps(phy, NL80211_BAND_5GHZ, data); 11646c92544dSBjoern A. Zeeb 11656c92544dSBjoern A. Zeeb band = &phy->mt76->sband_5g.sband; 11666c92544dSBjoern A. Zeeb band->iftype_data = data; 11676c92544dSBjoern A. Zeeb band->n_iftype_data = n; 11686c92544dSBjoern A. Zeeb } 11696c92544dSBjoern A. Zeeb 11706c92544dSBjoern A. Zeeb if (phy->mt76->cap.has_6ghz) { 11716c92544dSBjoern A. Zeeb data = phy->iftype[NL80211_BAND_6GHZ]; 11726c92544dSBjoern A. Zeeb n = mt7915_init_he_caps(phy, NL80211_BAND_6GHZ, data); 11736c92544dSBjoern A. Zeeb 11746c92544dSBjoern A. Zeeb band = &phy->mt76->sband_6g.sband; 11756c92544dSBjoern A. Zeeb band->iftype_data = data; 11766c92544dSBjoern A. Zeeb band->n_iftype_data = n; 11776c92544dSBjoern A. Zeeb } 11786c92544dSBjoern A. Zeeb } 11796c92544dSBjoern A. Zeeb 11806c92544dSBjoern A. Zeeb static void mt7915_unregister_ext_phy(struct mt7915_dev *dev) 11816c92544dSBjoern A. Zeeb { 11826c92544dSBjoern A. Zeeb struct mt7915_phy *phy = mt7915_ext_phy(dev); 11836c92544dSBjoern A. Zeeb struct mt76_phy *mphy = dev->mt76.phys[MT_BAND1]; 11846c92544dSBjoern A. Zeeb 11856c92544dSBjoern A. Zeeb if (!phy) 11866c92544dSBjoern A. Zeeb return; 11876c92544dSBjoern A. Zeeb 11886c92544dSBjoern A. Zeeb #if defined(__linux__) 11896c92544dSBjoern A. Zeeb mt7915_unregister_thermal(phy); 11906c92544dSBjoern A. Zeeb #endif 11916c92544dSBjoern A. Zeeb mt76_unregister_phy(mphy); 11926c92544dSBjoern A. Zeeb ieee80211_free_hw(mphy->hw); 11936c92544dSBjoern A. Zeeb } 11946c92544dSBjoern A. Zeeb 11956c92544dSBjoern A. Zeeb static void mt7915_stop_hardware(struct mt7915_dev *dev) 11966c92544dSBjoern A. Zeeb { 11976c92544dSBjoern A. Zeeb mt7915_mcu_exit(dev); 1198*cbb3ec25SBjoern A. Zeeb mt76_connac2_tx_token_put(&dev->mt76); 11996c92544dSBjoern A. Zeeb mt7915_dma_cleanup(dev); 1200*cbb3ec25SBjoern A. Zeeb tasklet_disable(&dev->mt76.irq_tasklet); 12016c92544dSBjoern A. Zeeb 1202*cbb3ec25SBjoern A. Zeeb if (is_mt798x(&dev->mt76)) 12036c92544dSBjoern A. Zeeb mt7986_wmac_disable(dev); 12046c92544dSBjoern A. Zeeb } 12056c92544dSBjoern A. Zeeb 12066c92544dSBjoern A. Zeeb int mt7915_register_device(struct mt7915_dev *dev) 12076c92544dSBjoern A. Zeeb { 12086c92544dSBjoern A. Zeeb struct mt7915_phy *phy2; 12096c92544dSBjoern A. Zeeb int ret; 12106c92544dSBjoern A. Zeeb 12116c92544dSBjoern A. Zeeb dev->phy.dev = dev; 12126c92544dSBjoern A. Zeeb dev->phy.mt76 = &dev->mt76.phy; 12136c92544dSBjoern A. Zeeb dev->mt76.phy.priv = &dev->phy; 12146c92544dSBjoern A. Zeeb INIT_WORK(&dev->rc_work, mt7915_mac_sta_rc_work); 12156c92544dSBjoern A. Zeeb INIT_DELAYED_WORK(&dev->mphy.mac_work, mt7915_mac_work); 12166c92544dSBjoern A. Zeeb INIT_LIST_HEAD(&dev->sta_rc_list); 12176c92544dSBjoern A. Zeeb INIT_LIST_HEAD(&dev->twt_list); 12186c92544dSBjoern A. Zeeb 12196c92544dSBjoern A. Zeeb init_waitqueue_head(&dev->reset_wait); 12206c92544dSBjoern A. Zeeb INIT_WORK(&dev->reset_work, mt7915_mac_reset_work); 1221*cbb3ec25SBjoern A. Zeeb INIT_WORK(&dev->dump_work, mt7915_mac_dump_work); 1222*cbb3ec25SBjoern A. Zeeb mutex_init(&dev->dump_mutex); 12236c92544dSBjoern A. Zeeb 12246c92544dSBjoern A. Zeeb dev->dbdc_support = mt7915_band_config(dev); 12256c92544dSBjoern A. Zeeb 12266c92544dSBjoern A. Zeeb phy2 = mt7915_alloc_ext_phy(dev); 12276c92544dSBjoern A. Zeeb if (IS_ERR(phy2)) 12286c92544dSBjoern A. Zeeb return PTR_ERR(phy2); 12296c92544dSBjoern A. Zeeb 12306c92544dSBjoern A. Zeeb ret = mt7915_init_hardware(dev, phy2); 12316c92544dSBjoern A. Zeeb if (ret) 12326c92544dSBjoern A. Zeeb goto free_phy2; 12336c92544dSBjoern A. Zeeb 1234*cbb3ec25SBjoern A. Zeeb mt7915_init_wiphy(&dev->phy); 12356c92544dSBjoern A. Zeeb 12366c92544dSBjoern A. Zeeb #ifdef CONFIG_NL80211_TESTMODE 12376c92544dSBjoern A. Zeeb dev->mt76.test_ops = &mt7915_testmode_ops; 12386c92544dSBjoern A. Zeeb #endif 12396c92544dSBjoern A. Zeeb 12406c92544dSBjoern A. Zeeb ret = mt76_register_device(&dev->mt76, true, mt76_rates, 12416c92544dSBjoern A. Zeeb ARRAY_SIZE(mt76_rates)); 12426c92544dSBjoern A. Zeeb if (ret) 12436c92544dSBjoern A. Zeeb goto stop_hw; 12446c92544dSBjoern A. Zeeb 12456c92544dSBjoern A. Zeeb ret = mt7915_thermal_init(&dev->phy); 12466c92544dSBjoern A. Zeeb if (ret) 12476c92544dSBjoern A. Zeeb goto unreg_dev; 12486c92544dSBjoern A. Zeeb 12496c92544dSBjoern A. Zeeb ieee80211_queue_work(mt76_hw(dev), &dev->init_work); 12506c92544dSBjoern A. Zeeb 12516c92544dSBjoern A. Zeeb if (phy2) { 12526c92544dSBjoern A. Zeeb ret = mt7915_register_ext_phy(dev, phy2); 12536c92544dSBjoern A. Zeeb if (ret) 12546c92544dSBjoern A. Zeeb goto unreg_thermal; 12556c92544dSBjoern A. Zeeb } 12566c92544dSBjoern A. Zeeb 1257*cbb3ec25SBjoern A. Zeeb dev->recovery.hw_init_done = true; 1258*cbb3ec25SBjoern A. Zeeb 12596c92544dSBjoern A. Zeeb #if !defined(__FreeBSD__) || defined(CONFIG_MT7915_DEBUGFS) 1260*cbb3ec25SBjoern A. Zeeb ret = mt7915_init_debugfs(&dev->phy); 1261*cbb3ec25SBjoern A. Zeeb if (ret) 1262*cbb3ec25SBjoern A. Zeeb goto unreg_thermal; 12636c92544dSBjoern A. Zeeb #endif 12646c92544dSBjoern A. Zeeb 1265*cbb3ec25SBjoern A. Zeeb ret = mt7915_coredump_register(dev); 1266*cbb3ec25SBjoern A. Zeeb if (ret) 1267*cbb3ec25SBjoern A. Zeeb goto unreg_thermal; 1268*cbb3ec25SBjoern A. Zeeb 12696c92544dSBjoern A. Zeeb return 0; 12706c92544dSBjoern A. Zeeb 12716c92544dSBjoern A. Zeeb unreg_thermal: 12726c92544dSBjoern A. Zeeb #if defined(__linux__) 12736c92544dSBjoern A. Zeeb mt7915_unregister_thermal(&dev->phy); 12746c92544dSBjoern A. Zeeb #endif 12756c92544dSBjoern A. Zeeb unreg_dev: 12766c92544dSBjoern A. Zeeb mt76_unregister_device(&dev->mt76); 12776c92544dSBjoern A. Zeeb stop_hw: 12786c92544dSBjoern A. Zeeb mt7915_stop_hardware(dev); 12796c92544dSBjoern A. Zeeb free_phy2: 12806c92544dSBjoern A. Zeeb if (phy2) 12816c92544dSBjoern A. Zeeb ieee80211_free_hw(phy2->mt76->hw); 12826c92544dSBjoern A. Zeeb return ret; 12836c92544dSBjoern A. Zeeb } 12846c92544dSBjoern A. Zeeb 12856c92544dSBjoern A. Zeeb void mt7915_unregister_device(struct mt7915_dev *dev) 12866c92544dSBjoern A. Zeeb { 12876c92544dSBjoern A. Zeeb mt7915_unregister_ext_phy(dev); 1288*cbb3ec25SBjoern A. Zeeb mt7915_coredump_unregister(dev); 12896c92544dSBjoern A. Zeeb #if defined(__linux__) 12906c92544dSBjoern A. Zeeb mt7915_unregister_thermal(&dev->phy); 12916c92544dSBjoern A. Zeeb #endif 12926c92544dSBjoern A. Zeeb mt76_unregister_device(&dev->mt76); 12936c92544dSBjoern A. Zeeb mt7915_stop_hardware(dev); 12946c92544dSBjoern A. Zeeb 12956c92544dSBjoern A. Zeeb mt76_free_device(&dev->mt76); 12966c92544dSBjoern A. Zeeb } 1297