mac80211: rt2x00: experimental improvements for MT7620 wifi
[openwrt/openwrt.git] / package / kernel / mac80211 / patches / rt2x00 / 992-rt2x00-more-fixes.patch
diff --git a/package/kernel/mac80211/patches/rt2x00/992-rt2x00-more-fixes.patch b/package/kernel/mac80211/patches/rt2x00/992-rt2x00-more-fixes.patch
new file mode 100644 (file)
index 0000000..2ad6219
--- /dev/null
@@ -0,0 +1,423 @@
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Mon, 12 Sep 2022 21:33:13 +0100
+Subject: [PATCH] rt2x00: various experimental fixes for MT7620
+
+Serge Vasilugin reports:
+
+To improve mt7620 built-in wifi performance some changes:
+1. Correct BW20/BW40 switching (see comments with mark see commets with mark (1))
+2. Correct TX_SW_CFG1 MAC reg from v3 of vendor driver see
+        https://gitlab.com/dm38/padavan-ng/-/blob/master/trunk/proprietary/rt_wifi/rtpci/3.0.X.X/mt76x2/chips/rt6352.c#L531
+3. Set bbp66 for all chains.
+4. US_CYC_CNT init based on Programming guide, default value was 33 (pci),
+   set chipset bus clock with fallback to cpu clock/3.
+5. Don't overwrite default values for mt7620.
+6. Correct some typos.
+7. Add support for external LNA:
+    a) RF and BBP regs never be corrected for this mode
+    b) eLNA is driven the same way as ePA with mt7620's pin PA
+        but vendor driver explicitly pin PA to gpio mode (for forrect calibration?)
+        so I'm not sure that request for pa_pin in dts-file will be enough
+
+First 5 changes (really 2) improve performance for boards w/o eLNA/ePA.
+Changes 7 add support for eLNA
+
+Configuration w/o eLAN/ePA and with eLNA show results
+tx/rx (from router point of view) for each stream:
+ 35-40/30-35 Mbps for HT20
+ 65-70/60-65 Mbps for HT40
+
+Yes. Max results for 2T2R client is 140-145/135-140
+with peaks 160/150, It correspond to mediatek driver results.
+Boards with ePA untested.
+
+Reported-by: Serge Vasilugin <vasilugin@yandex.ru>
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+---
+--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
++++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+@@ -137,6 +137,26 @@ static u8 rt2800_bbp_read(struct rt2x00_
+       return value;
+ }
++//serge: move here for use in test
++static void rt2800_bbp_glrt_write(struct rt2x00_dev *rt2x00dev,
++                                const u8 reg, const u8 value)
++{
++      rt2800_bbp_write(rt2x00dev, 195, reg);
++      rt2800_bbp_write(rt2x00dev, 196, value);
++}
++
++static void rt2800_bbp_dcoc_write(struct rt2x00_dev *rt2x00dev,
++                                const u8 reg, const u8 value)
++{
++      rt2800_bbp_write(rt2x00dev, 158, reg);
++      rt2800_bbp_write(rt2x00dev, 159, value);
++}
++
++static u8 rt2800_bbp_dcoc_read(struct rt2x00_dev *rt2x00dev, const u8 reg)
++{
++      rt2800_bbp_write(rt2x00dev, 158, reg);
++      return rt2800_bbp_read(rt2x00dev, 159);
++}
+ static void rt2800_rfcsr_write(struct rt2x00_dev *rt2x00dev,
+                              const unsigned int word, const u8 value)
+@@ -284,6 +304,28 @@ static void rt2800_rf_write(struct rt2x0
+       mutex_unlock(&rt2x00dev->csr_mutex);
+ }
++void rt6352_enable_pa_pin(struct rt2x00_dev *rt2x00dev, int enable)
++{
++      if (!rt2x00dev->pinctrl)
++              return;
++
++      if (enable) {
++              if (!rt2x00dev->pins_default) {
++                      rt2x00_warn(rt2x00dev, "cannot enable PA pin! no default pinctrl\n");
++                      return;
++              }
++
++              pinctrl_select_state(rt2x00dev->pinctrl, rt2x00dev->pins_default);
++      } else {
++              if (!rt2x00dev->pins_pa_gpio) {
++                      rt2x00_warn(rt2x00dev, "cannot disable PA pin! no pa_gpio pinctrl\n");
++                      return;
++              }
++
++              pinctrl_select_state(rt2x00dev->pinctrl, rt2x00dev->pins_pa_gpio);
++      }
++}
++
+ static const unsigned int rt2800_eeprom_map[EEPROM_WORD_COUNT] = {
+       [EEPROM_CHIP_ID]                = 0x0000,
+       [EEPROM_VERSION]                = 0x0001,
+@@ -3801,6 +3843,20 @@ static void rt2800_config_channel_rf7620
+               rfcsr |= tx_agc_fc;
+               rt2800_rfcsr_write_bank(rt2x00dev, 7, 59, rfcsr);
+       }
++
++      if (conf_is_ht40(conf)) {//serge:skipped this step (1)
++              rt2800_bbp_write(rt2x00dev, 195, 141);
++              rt2800_bbp_write(rt2x00dev, 196, 0x10);
++              rt2800_bbp_write(rt2x00dev, 195, 157);
++              rt2800_bbp_write(rt2x00dev, 196, 0x2f);
++              //rt2800_bbp_write(rt2x00dev, 105, 0x3C);
++      } else {
++              rt2800_bbp_write(rt2x00dev, 195, 141);
++              rt2800_bbp_write(rt2x00dev, 196, 0x1a);
++              rt2800_bbp_write(rt2x00dev, 195, 157);
++              rt2800_bbp_write(rt2x00dev, 196, 0x40);
++              //rt2800_bbp_write(rt2x00dev, 105, 0x1C);
++      }
+ }
+ static void rt2800_config_alc(struct rt2x00_dev *rt2x00dev,
+@@ -4172,6 +4228,11 @@ static void rt2800_config_channel(struct
+                       rt2800_bbp_write(rt2x00dev, 86, 0x46);
+               else
+                       rt2800_bbp_write(rt2x00dev, 86, 0);
++      } else if (rt2x00_rt(rt2x00dev, RT6352)) {//serge: don't overwite bbp r86 (5)
++              rt2800_bbp_write(rt2x00dev, 62, 0x37 - rt2x00dev->lna_gain);
++              rt2800_bbp_write(rt2x00dev, 63, 0x37 - rt2x00dev->lna_gain);
++              rt2800_bbp_write(rt2x00dev, 64, 0x37 - rt2x00dev->lna_gain);
++              rt2800_bbp_write(rt2x00dev, 86, 0x38);
+       } else {
+               rt2800_bbp_write(rt2x00dev, 62, 0x37 - rt2x00dev->lna_gain);
+               rt2800_bbp_write(rt2x00dev, 63, 0x37 - rt2x00dev->lna_gain);
+@@ -4377,7 +4438,8 @@ static void rt2800_config_channel(struct
+               reg = (rf->channel <= 14 ? 0x1c : 0x24) + 2*rt2x00dev->lna_gain;
+               rt2800_bbp_write_with_rx_chain(rt2x00dev, 66, reg);
+-              rt2800_iq_calibrate(rt2x00dev, rf->channel);
++              if (!rt2x00_rt(rt2x00dev, RT6352))//serge: this function for rt5592 only, for rt6352 it switch off compensations (5)
++                  rt2800_iq_calibrate(rt2x00dev, rf->channel);
+       }
+       if (rt2x00_rt(rt2x00dev, RT6352)) {
+@@ -4417,6 +4479,31 @@ static void rt2800_config_channel(struct
+                       rt2800_register_write(rt2x00dev, TX1_RF_GAIN_ATTEN,
+                                             0x6C6C6B6C);
+               }
++
++              if (rt2x00_has_cap_external_lna_bg(rt2x00dev)) {//serge: for support eLNA (7a)
++                      rt2x00_warn(rt2x00dev, "Correct RF/BBP for eLNA!\n");
++                      reg = rt2800_register_read(rt2x00dev, RF_CONTROL3);
++                      reg |= 0x00000101;
++                      rt2800_register_write(rt2x00dev, RF_CONTROL3, reg);
++
++                      reg = rt2800_register_read(rt2x00dev, RF_BYPASS3);
++                      reg |= 0x00000101;
++                      rt2800_register_write(rt2x00dev, RF_BYPASS3, reg);
++
++                      rt2800_rfcsr_write_chanreg(rt2x00dev, 14, 0x66);
++                      rt2800_rfcsr_write_chanreg(rt2x00dev, 17, 0x20);
++                      rt2800_rfcsr_write_chanreg(rt2x00dev, 18, 0x42);
++                      rt2800_bbp_write(rt2x00dev, 75, 0x68);//serge: move bbp eLNA init here?
++                      rt2800_bbp_write(rt2x00dev, 76, 0x4C);
++                      rt2800_bbp_write(rt2x00dev, 79, 0x1C);
++                      rt2800_bbp_write(rt2x00dev, 80, 0x0C);
++                      rt2800_bbp_write(rt2x00dev, 82, 0xB6);
++                      /* bank 0 RF reg 42 and glrt BBP reg 141
++                      will be set in config channel function
++                      in dependence of channel and HT20/HT40
++                      so don't touch it
++                      */
++              }
+       }
+       bbp = rt2800_bbp_read(rt2x00dev, 4);
+@@ -4457,6 +4544,9 @@ static void rt2800_config_channel(struct
+               rt2x00_set_field8(&bbp, BBP49_UPDATE_FLAG, 0);
+               rt2800_bbp_write(rt2x00dev, 49, bbp);
+       }
++//serge:just print results after config channel - don't forget to remove nahren (c) <- this is copyright, not ref to comments :)
++      bbp = rt2800_bbp_dcoc_read(rt2x00dev, 0x03);
++      pr_info("BBP tx/rx compensation control=0x%02x\n", bbp);
+ }
+ static int rt2800_get_gain_calibration_delta(struct rt2x00_dev *rt2x00dev)
+@@ -5527,7 +5617,7 @@ void rt2800_vco_calibration(struct rt2x0
+       }
+       rt2800_register_write(rt2x00dev, TX_PIN_CFG, tx_pin);
+-      if (rt2x00_rt(rt2x00dev, RT6352)) {
++      if (rt2x00_rt(rt2x00dev, RT6352)) {//serge:remark - move all this code to rfcsr_6352 init?
+               if (rt2x00dev->default_ant.rx_chain_num == 1) {
+                       rt2800_bbp_write(rt2x00dev, 91, 0x07);
+                       rt2800_bbp_write(rt2x00dev, 95, 0x1A);
+@@ -5695,7 +5785,8 @@ static inline void rt2800_set_vgc(struct
+       if (qual->vgc_level != vgc_level) {
+               if (rt2x00_rt(rt2x00dev, RT3572) ||
+                   rt2x00_rt(rt2x00dev, RT3593) ||
+-                  rt2x00_rt(rt2x00dev, RT3883)) {
++                  rt2x00_rt(rt2x00dev, RT3883) ||
++                  rt2x00_rt(rt2x00dev, RT6352)) {//serge: rt6352 too (3)
+                       rt2800_bbp_write_with_rx_chain(rt2x00dev, 66,
+                                                      vgc_level);
+               } else if (rt2x00_rt(rt2x00dev, RT5592)) {
+@@ -5930,7 +6021,7 @@ static int rt2800_init_registers(struct
+                                             0x00550055);
+               } else {
+                       rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000401);
+-                      rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x000C0000);
++                      rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x000C0001);//serge:was 0x000C0000 (2)
+                       rt2800_register_write(rt2x00dev, TX_SW_CFG2, 0x00000000);
+                       rt2800_register_write(rt2x00dev, TX_ALC_VGA3, 0x00000000);
+                       rt2800_register_write(rt2x00dev, TX0_BB_GAIN_ATTEN, 0x0);
+@@ -6195,6 +6286,29 @@ static int rt2800_init_registers(struct
+               reg = rt2800_register_read(rt2x00dev, US_CYC_CNT);
+               rt2x00_set_field32(&reg, US_CYC_CNT_CLOCK_CYCLE, 125);
+               rt2800_register_write(rt2x00dev, US_CYC_CNT, reg);
++      } else if (rt2x00_is_soc(rt2x00dev)) {//serge:which value correct? (4)
++              struct clk *clk = clk_get_sys("bus", NULL);
++              int rate;
++
++              if (IS_ERR(clk)) {
++                      rt2x00_warn(rt2x00dev, "system bus clock undefined\n");
++                      clk = clk_get_sys("cpu", NULL);
++
++                      if (IS_ERR(clk))
++                          rate = 125;
++                      else {
++                          rate = clk_get_rate(clk) / 3000000;
++                          clk_put(clk);
++                      }
++              } else {
++                      rate = clk_get_rate(clk) / 1000000;
++                      clk_put(clk);
++              }
++
++              rt2x00_info(rt2x00dev, "set US_CYC=%dMHz\n", rate);
++              reg = rt2800_register_read(rt2x00dev, US_CYC_CNT);
++              rt2x00_set_field32(&reg, US_CYC_CNT_CLOCK_CYCLE, rate);
++              rt2800_register_write(rt2x00dev, US_CYC_CNT, reg);
+       }
+       reg = rt2800_register_read(rt2x00dev, HT_FBK_CFG0);
+@@ -6981,26 +7095,7 @@ static void rt2800_init_bbp_5592(struct
+       if (rt2x00_rt_rev_gte(rt2x00dev, RT5592, REV_RT5592C))
+               rt2800_bbp_write(rt2x00dev, 103, 0xc0);
+ }
+-
+-static void rt2800_bbp_glrt_write(struct rt2x00_dev *rt2x00dev,
+-                                const u8 reg, const u8 value)
+-{
+-      rt2800_bbp_write(rt2x00dev, 195, reg);
+-      rt2800_bbp_write(rt2x00dev, 196, value);
+-}
+-
+-static void rt2800_bbp_dcoc_write(struct rt2x00_dev *rt2x00dev,
+-                                const u8 reg, const u8 value)
+-{
+-      rt2800_bbp_write(rt2x00dev, 158, reg);
+-      rt2800_bbp_write(rt2x00dev, 159, value);
+-}
+-
+-static u8 rt2800_bbp_dcoc_read(struct rt2x00_dev *rt2x00dev, const u8 reg)
+-{
+-      rt2800_bbp_write(rt2x00dev, 158, reg);
+-      return rt2800_bbp_read(rt2x00dev, 159);
+-}
++//serge: move these function upper
+ static void rt2800_init_bbp_6352(struct rt2x00_dev *rt2x00dev)
+ {
+@@ -8635,7 +8730,7 @@ static void rt2800_r_calibration(struct
+               r_cal_code = (u8)rcalcode;
+       rt2800_rfcsr_write_bank(rt2x00dev, 0, 7, r_cal_code);
+-
++      pr_info("RF bank 0 reg 5=0x%02x\n", r_cal_code);//serge: just for info to compare with vendor driver
+       rt2800_bbp_write(rt2x00dev, 22, 0x0);
+       bytevalue = rt2800_bbp_read(rt2x00dev, 21);
+@@ -8693,7 +8788,7 @@ static void rt2800_rxdcoc_calibration(st
+                       break;
+       }
+-      saverfb5r4 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 0);
++      saverfb5r4 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 4);//serge: was 0 - typo? (6)
+       saverfb7r4 = rt2800_rfcsr_read_bank(rt2x00dev, 7, 4);
+       saverfb5r4 = saverfb5r4 & (~0x40);
+       saverfb7r4 = saverfb7r4 & (~0x40);
+@@ -9022,13 +9117,15 @@ static void rt2800_rxiq_calibration(stru
+                               rt2x00_info(rt2x00dev, "RXIQ G_imb=%d, Ph_rx=%d\n", g_imb, ph_rx);
+                               if ((ph_rx > 20) || (ph_rx < -20)) {
++                                      rt2x00_warn(rt2x00dev, "RXIQ calibration FAIL(ph_rx=%d out of [-20..20]", ph_rx);//serge:just to see value
+                                       ph_rx = 0;
+-                                      rt2x00_warn(rt2x00dev, "RXIQ calibration FAIL");
++                                      //rt2x00_warn(rt2x00dev, "RXIQ calibration FAIL");
+                               }
+                               if ((g_imb > 12) || (g_imb < -12)) {
++                                      rt2x00_warn(rt2x00dev, "RXIQ calibration FAIL(g_imb=%d out of (-12..12]", g_imb);//serge:just to see the reason
+                                       g_imb = 0;
+-                                      rt2x00_warn(rt2x00dev, "RXIQ calibration FAIL");
++                                      //rt2x00_warn(rt2x00dev, "RXIQ calibration FAIL");
+                               }
+                       }
+               else {
+@@ -9039,11 +9136,21 @@ static void rt2800_rxiq_calibration(stru
+               }
+               if (ch_idx == 0) {
++                      //serge: just to see values
++                      pr_info("RXIQ RX0 g_imb (0x37, %2x) ph_rx (0x35, %2x)\n",
++                          g_imb & 0x3f,
++                          ph_rx & 0x3f
++                      );
+                       rt2800_bbp_write(rt2x00dev, 158, 0x37);
+                       rt2800_bbp_write(rt2x00dev, 159, g_imb & 0x3f);
+                       rt2800_bbp_write(rt2x00dev, 158, 0x35);
+                       rt2800_bbp_write(rt2x00dev, 159, ph_rx & 0x3f);
+               } else {
++                      //serge: just to see values
++                      pr_info("RXIQ RX1 g_imb (0x55, %2x) ph_rx (0x53, %2x)\n",
++                          g_imb & 0x3f,
++                          ph_rx & 0x3f
++                      );
+                       rt2800_bbp_write(rt2x00dev, 158, 0x55);
+                       rt2800_bbp_write(rt2x00dev, 159, g_imb & 0x3f);
+                       rt2800_bbp_write(rt2x00dev, 158, 0x53);
+@@ -9745,6 +9852,15 @@ void rt2800_loft_iq_calibration(struct r
+       }
+       for (rf_alc_idx = 0; rf_alc_idx < 3; rf_alc_idx++) {
++              //serge: just to see values
++              pr_info("LOFT ALC (0xb0, %2x) I0 (0xb1, %2x) Q0 (0xb2, %2x) I1 (0xb8, %2x) Q1 (0xb9, %2x)\n",
++                  rf_alc_idx,
++                  loft_dc_search_result[CHAIN_0][rf_alc_idx][0x00] & 0x3F,
++                  loft_dc_search_result[CHAIN_0][rf_alc_idx][0x01] & 0x3F,
++                  loft_dc_search_result[CHAIN_1][rf_alc_idx][0x00] & 0x3F,
++                  loft_dc_search_result[CHAIN_1][rf_alc_idx][0x01] & 0x3F
++              );
++
+               for (idx = 0; idx < 4; idx++) {
+                       rt2800_bbp_write(rt2x00dev, 158, 0xB0);
+                       bbp = (idx<<2) + rf_alc_idx;
+@@ -10669,6 +10785,7 @@ static void rt2800_init_rfcsr_6352(struc
+               rt2800_rfcsr_write_dccal(rt2x00dev, 17, 0x7C);
+       }
++      rt6352_enable_pa_pin(rt2x00dev, 0);//serge: vendor driver do it before calibration (7b)
+       rt2800_r_calibration(rt2x00dev);
+       rt2800_rf_self_txdc_cal(rt2x00dev);
+       rt2800_rxdcoc_calibration(rt2x00dev);
+@@ -10676,6 +10793,29 @@ static void rt2800_init_rfcsr_6352(struc
+       rt2800_bw_filter_calibration(rt2x00dev, false);
+       rt2800_loft_iq_calibration(rt2x00dev);
+       rt2800_rxiq_calibration(rt2x00dev);
++      rt6352_enable_pa_pin(rt2x00dev, 1);//serge: vendor driver do it after calibration (7b)
++      /* Vendor driver restore iLNA/iPA before
++      recalibration and set correct values after.
++      Openwrt driver init iLNA and iPA but restore only
++      ePA values after recalibration.
++      So set eLNA values only
++      */
++      if (rt2x00_has_cap_external_lna_bg(rt2x00dev)) {//serge: rf regs never corrected for eLNA (7a)
++              rt2x00_info(rt2x00dev, "Correct RF/BBP for eLNA!\n");
++              rt2800_rfcsr_write_chanreg(rt2x00dev, 14, 0x66);
++              rt2800_rfcsr_write_chanreg(rt2x00dev, 17, 0x20);
++              rt2800_rfcsr_write_chanreg(rt2x00dev, 18, 0x42);
++              rt2800_bbp_write(rt2x00dev, 75, 0x68);//serge: move bbp eLNA init here?
++              rt2800_bbp_write(rt2x00dev, 76, 0x4C);
++              rt2800_bbp_write(rt2x00dev, 79, 0x1C);
++              rt2800_bbp_write(rt2x00dev, 80, 0x0C);
++              rt2800_bbp_write(rt2x00dev, 82, 0xB6);
++              /* bank 0 RF reg 42 and glrt BBP reg 141
++              will be set in config channel function
++              in dependence of channel and HT20/HT40
++              so don't touch it
++              */
++      }
+ }
+ static void rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev)
+--- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h
++++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h
+@@ -28,6 +28,7 @@
+ #include <linux/average.h>
+ #include <linux/usb.h>
+ #include <linux/clk.h>
++#include <linux/pinctrl/consumer.h>
+ #include <linux/rt2x00_platform.h>
+ #include <net/mac80211.h>
+@@ -1029,6 +1030,11 @@ struct rt2x00_dev {
+       /* Clock for System On Chip devices. */
+       struct clk *clk;
++
++      /* pinctrl and states for System On Chip devices with PA/LNA. */
++      struct pinctrl *pinctrl;
++      struct pinctrl_state *pins_default;
++      struct pinctrl_state *pins_pa_gpio;
+ };
+ struct rt2x00_bar_list_entry {
+--- a/drivers/net/wireless/ralink/rt2x00/rt2x00soc.c
++++ b/drivers/net/wireless/ralink/rt2x00/rt2x00soc.c
+@@ -97,6 +97,21 @@ int rt2x00soc_probe(struct platform_devi
+       if (retval)
+               goto exit_free_reg;
++      rt2x00dev->pinctrl = devm_pinctrl_get(&pdev->dev);
++      if (IS_ERR(rt2x00dev->pinctrl)) {
++              rt2x00dev->pinctrl = NULL;
++              rt2x00dev->pins_default = NULL;
++              rt2x00dev->pins_pa_gpio = NULL;
++      } else {
++              rt2x00dev->pins_default = pinctrl_lookup_state(rt2x00dev->pinctrl, "default");
++              if (IS_ERR(rt2x00dev->pins_default))
++                      rt2x00dev->pins_default = NULL;
++
++              rt2x00dev->pins_pa_gpio = pinctrl_lookup_state(rt2x00dev->pinctrl, "pa_gpio");
++              if (IS_ERR(rt2x00dev->pins_pa_gpio))
++                      rt2x00dev->pins_pa_gpio = NULL;
++      }
++
+       return 0;
+ exit_free_reg: