On 09/12/2022 09:39, Ping-Ke Shih wrote: > > >> -----Original Message----- >> From: Bitterblue Smith <rtl8821cerfe2@xxxxxxxxx> >> Sent: Wednesday, December 7, 2022 5:44 AM >> To: linux-wireless@xxxxxxxxxxxxxxx >> Cc: Jes Sorensen <Jes.Sorensen@xxxxxxxxx>; Ping-Ke Shih <pkshih@xxxxxxxxxxx>; Andrea Merello >> <andrea.merello@xxxxxxxxx>; Taehee Yoo <ap420073@xxxxxxxxx> >> Subject: [PATCH 1/2] wifi: rtl8xxxu: Support new chip RTL8188EU >> >> From: Jes Sorensen <Jes.Sorensen@xxxxxxxxx> >> >> This chip is found in cheap USB devices from TP-Link, D-Link, etc. >> >> Features: 2.4 GHz, b/g/n mode, 1T1R, 150 Mbps. >> >> Chip versions older than "I cut" need software rate control. That will >> be in the next commit. Until then MCS7 is used for all data frames. >> >> The "I cut" chips are not supported. They require different firmware >> and initialisation tables. Support can be added if someone has the >> hardware to test it. >> >> Co-developed-by: Andrea Merello <andrea.merello@xxxxxxxxx> >> Signed-off-by: Andrea Merello <andrea.merello@xxxxxxxxx> >> Co-developed-by: Taehee Yoo <ap420073@xxxxxxxxx> >> Signed-off-by: Taehee Yoo <ap420073@xxxxxxxxx> >> Signed-off-by: Jes Sorensen <Jes.Sorensen@xxxxxxxxx> >> Co-developed-by: Bitterblue Smith <rtl8821cerfe2@xxxxxxxxx> >> Signed-off-by: Bitterblue Smith <rtl8821cerfe2@xxxxxxxxx> >> --- >> So this patch is 52 of the 57 patches found here, squashed together: >> https://git.kernel.org/pub/scm/linux/kernel/git/jes/linux.git/log/drivers/net/wireless/realtek/rtl8xxx >> u?h=rtl8xxxu-8188eu >> >> Starting from c3f84ded6f76 ("rtl8xxxu: Accept firmware signature 0x88e0") >> up to a9b05c059510 ("rtl8xxxu: Add rpt_sel entry to struct rtl8xxxu_rxdesc16"). >> >> These patches were not needed: >> 3170622ccb61 ("rtl8xxxu: Detect 8188eu parts correctly") >> 8fb5bc92bce0 ("rtl8xxxu: Initialize GPIO settings for 8188eu") >> 6ab646adb585 ("rtl8xxxu: Implement rtl8188e_set_tx_power()") >> 2ccd1f1fc480 ("rtl8xxxu: properly detect RTL8188EU devices") >> 809a2e000cab ("rtl8xxxu: Do not set auto rate fallback on 8188eu") >> >> On top of that, I made various changes required for today's kernel, >> plus changes to match the newer vendor driver more closely, plus some >> bug fixes. >> --- >> .../net/wireless/realtek/rtl8xxxu/Makefile | 3 +- >> .../net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 67 +- >> .../realtek/rtl8xxxu/rtl8xxxu_8188e.c | 1298 +++++++++++++++++ >> .../realtek/rtl8xxxu/rtl8xxxu_8188f.c | 4 +- >> .../wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 201 ++- >> .../wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h | 40 +- >> 6 files changed, 1589 insertions(+), 24 deletions(-) >> create mode 100644 drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188e.c >> >> diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h >> b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h >> index d26df4095da0..27bd07d24889 100644 >> --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h >> +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h >> @@ -36,6 +36,7 @@ >> > > [...] > >> >> +struct rtl8188eu_efuse { >> + __le16 rtl_id; >> + u8 res0[0x0e]; >> + struct rtl8192eu_efuse_tx_power tx_power_index_A; /* 0x10 */ >> + u8 res1[0x7e]; /* 0x3a */ >> + u8 channel_plan; /* 0xb8 */ >> + u8 xtal_k; >> + u8 thermal_meter; >> + u8 iqk_lck; >> + u8 res2[5]; >> + u8 rf_board_option; >> + u8 rf_feature_option; >> + u8 rf_bt_setting; >> + u8 eeprom_version; >> + u8 eeprom_customer_id; >> + u8 res3[3]; >> + u8 rf_antenna_option; /* 0xc9 */ >> + u8 res4[6]; >> + u8 vid; /* 0xd0 */ >> + u8 res5[1]; >> + u8 pid; /* 0xd2 */ >> + u8 res6[1]; >> + u8 usb_optional_function; >> + u8 res7[2]; >> + u8 mac_addr[ETH_ALEN]; /* 0xd7 */ >> + u8 res8[2]; >> + u8 vendor_name[7]; >> + u8 res9[2]; >> + u8 device_name[0x0b]; /* 0xe8 */ >> + u8 res10[2]; >> + u8 serial[0x0b]; /* 0xf5 */ >> + u8 res11[0x30]; >> + u8 unknown[0x0d]; /* 0x130 */ >> + u8 res12[0xc3]; >> +}; >> + > > This is efuse layout, so it needs __packed. > > [...] > >> diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188e.c >> b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188e.c >> new file mode 100644 >> index 000000000000..9eb9ae03ca81 >> --- /dev/null > > [...] > >> +static void rtl8188eu_config_channel(struct ieee80211_hw *hw) >> +{ >> + struct rtl8xxxu_priv *priv = hw->priv; >> + u32 val32, rsr; >> + u8 opmode; >> + bool ht = true; >> + int sec_ch_above, channel; >> + int i; >> + >> + opmode = rtl8xxxu_read8(priv, REG_BW_OPMODE); >> + rsr = rtl8xxxu_read32(priv, REG_RESPONSE_RATE_SET); >> + channel = hw->conf.chandef.chan->hw_value; >> + >> + switch (hw->conf.chandef.width) { >> + case NL80211_CHAN_WIDTH_20_NOHT: >> + ht = false; >> + fallthrough; >> + case NL80211_CHAN_WIDTH_20: >> + opmode |= BW_OPMODE_20MHZ; >> + rtl8xxxu_write8(priv, REG_BW_OPMODE, opmode); >> + >> + val32 = rtl8xxxu_read32(priv, REG_FPGA0_RF_MODE); >> + val32 &= ~FPGA_RF_MODE; >> + rtl8xxxu_write32(priv, REG_FPGA0_RF_MODE, val32); >> + >> + val32 = rtl8xxxu_read32(priv, REG_FPGA1_RF_MODE); >> + val32 &= ~FPGA_RF_MODE; >> + rtl8xxxu_write32(priv, REG_FPGA1_RF_MODE, val32); >> + break; >> + case NL80211_CHAN_WIDTH_40: >> + if (hw->conf.chandef.center_freq1 > >> + hw->conf.chandef.chan->center_freq) { >> + sec_ch_above = 1; >> + channel += 2; >> + } else { >> + sec_ch_above = 0; >> + channel -= 2; >> + } >> + >> + opmode &= ~BW_OPMODE_20MHZ; >> + rtl8xxxu_write8(priv, REG_BW_OPMODE, opmode); >> + rsr &= ~RSR_RSC_BANDWIDTH_40M; >> + if (sec_ch_above) >> + rsr |= RSR_RSC_LOWER_SUB_CHANNEL; >> + else >> + rsr |= RSR_RSC_UPPER_SUB_CHANNEL; >> + rtl8xxxu_write32(priv, REG_RESPONSE_RATE_SET, rsr); >> + >> + val32 = rtl8xxxu_read32(priv, REG_FPGA0_RF_MODE); >> + val32 |= FPGA_RF_MODE; >> + rtl8xxxu_write32(priv, REG_FPGA0_RF_MODE, val32); >> + >> + val32 = rtl8xxxu_read32(priv, REG_FPGA1_RF_MODE); >> + val32 |= FPGA_RF_MODE; >> + rtl8xxxu_write32(priv, REG_FPGA1_RF_MODE, val32); >> + >> + /* >> + * Set Control channel to upper or lower. These settings >> + * are required only for 40MHz >> + */ >> + val32 = rtl8xxxu_read32(priv, REG_CCK0_SYSTEM); >> + val32 &= ~CCK0_SIDEBAND; >> + if (!sec_ch_above) >> + val32 |= CCK0_SIDEBAND; >> + rtl8xxxu_write32(priv, REG_CCK0_SYSTEM, val32); >> + >> + val32 = rtl8xxxu_read32(priv, REG_OFDM1_LSTF); >> + val32 &= ~OFDM_LSTF_PRIME_CH_MASK; /* 0xc00 */ >> + if (sec_ch_above) >> + val32 |= OFDM_LSTF_PRIME_CH_LOW; >> + else >> + val32 |= OFDM_LSTF_PRIME_CH_HIGH; >> + rtl8xxxu_write32(priv, REG_OFDM1_LSTF, val32); >> + >> + val32 = rtl8xxxu_read32(priv, REG_FPGA0_POWER_SAVE); >> + val32 &= ~(FPGA0_PS_LOWER_CHANNEL | FPGA0_PS_UPPER_CHANNEL); >> + if (sec_ch_above) >> + val32 |= FPGA0_PS_UPPER_CHANNEL; >> + else >> + val32 |= FPGA0_PS_LOWER_CHANNEL; >> + rtl8xxxu_write32(priv, REG_FPGA0_POWER_SAVE, val32); >> + break; >> + >> + default: >> + break; >> + } >> + >> + for (i = RF_A; i < priv->rf_paths; i++) { >> + val32 = rtl8xxxu_read_rfreg(priv, i, RF6052_REG_MODE_AG); >> + val32 &= ~MODE_AG_CHANNEL_MASK; >> + val32 |= channel; > > nit: > > val32 = u32_replace_bits(val32, channel, MODE_AG_CHANNEL_MASK); > > or > > u32p_replace_bits(&val32, channel, MODE_AG_CHANNEL_MASK); > > There are some similar changes nearby. If you want this, you can modify them as well. > I changed this one, but the others are not as straightforward so I left them. >> + rtl8xxxu_write_rfreg(priv, i, RF6052_REG_MODE_AG, val32); >> + } >> + >> + for (i = RF_A; i < priv->rf_paths; i++) { >> + val32 = rtl8xxxu_read_rfreg(priv, i, RF6052_REG_MODE_AG); >> + val32 &= ~MODE_AG_BW_MASK; >> + if (hw->conf.chandef.width == NL80211_CHAN_WIDTH_40) >> + val32 |= MODE_AG_BW_40MHZ_8723B; >> + else >> + val32 |= MODE_AG_BW_20MHZ_8723B; >> + rtl8xxxu_write_rfreg(priv, i, RF6052_REG_MODE_AG, val32); >> + } >> +} >> + >> +static void rtl8188eu_init_aggregation(struct rtl8xxxu_priv *priv) >> +{ >> + u8 agg_ctrl, usb_spec; >> + >> + usb_spec = rtl8xxxu_read8(priv, REG_USB_SPECIAL_OPTION); >> + usb_spec &= ~USB_SPEC_USB_AGG_ENABLE; >> + rtl8xxxu_write8(priv, REG_USB_SPECIAL_OPTION, usb_spec); >> + >> + agg_ctrl = rtl8xxxu_read8(priv, REG_TRXDMA_CTRL); >> + agg_ctrl &= ~TRXDMA_CTRL_RXDMA_AGG_EN; >> + rtl8xxxu_write8(priv, REG_TRXDMA_CTRL, agg_ctrl); >> +} >> + >> +static int rtl8188eu_parse_efuse(struct rtl8xxxu_priv *priv) >> +{ >> + struct rtl8188eu_efuse *efuse = &priv->efuse_wifi.efuse8188eu; >> + int i; >> + >> + if (efuse->rtl_id != cpu_to_le16(0x8129)) >> + return -EINVAL; >> + >> + ether_addr_copy(priv->mac_addr, efuse->mac_addr); >> + >> + memcpy(priv->cck_tx_power_index_A, efuse->tx_power_index_A.cck_base, >> + sizeof(efuse->tx_power_index_A.cck_base)); >> + >> + memcpy(priv->ht40_1s_tx_power_index_A, >> + efuse->tx_power_index_A.ht40_base, >> + sizeof(efuse->tx_power_index_A.ht40_base)); >> + >> + priv->default_crystal_cap = efuse->xtal_k & 0x3f; >> + >> + dev_info(&priv->udev->dev, "Vendor: %.7s\n", efuse->vendor_name); >> + dev_info(&priv->udev->dev, "Product: %.11s\n", efuse->device_name); >> + dev_info(&priv->udev->dev, "Serial: %.11s\n", efuse->serial); >> + >> + if (rtl8xxxu_debug & RTL8XXXU_DEBUG_EFUSE) { >> + unsigned char *raw = priv->efuse_wifi.raw; >> + >> + dev_info(&priv->udev->dev, >> + "%s: dumping efuse (0x%02zx bytes):\n", >> + __func__, sizeof(struct rtl8188eu_efuse)); >> + for (i = 0; i < sizeof(struct rtl8188eu_efuse); i += 8) >> + dev_info(&priv->udev->dev, "%02x: %8ph\n", i, &raw[i]); > > print_hex_dump_bytes()? > I have been meaning to get rid of this duplicated code. Every chip has a copy. print_hex_dump_bytes() has the wrong debug level. I will use print_hex_dump(). >> + } >> + >> + return 0; >> +} >> + >> +static void rtl8188eu_reset_8051(struct rtl8xxxu_priv *priv) >> +{ >> + u16 sys_func; >> + >> + sys_func = rtl8xxxu_read16(priv, REG_SYS_FUNC); >> + sys_func &= ~SYS_FUNC_CPU_ENABLE; >> + rtl8xxxu_write16(priv, REG_SYS_FUNC, sys_func); >> + >> + sys_func |= SYS_FUNC_CPU_ENABLE; >> + rtl8xxxu_write16(priv, REG_SYS_FUNC, sys_func); >> +} >> + >> +static int rtl8188eu_load_firmware(struct rtl8xxxu_priv *priv) >> +{ >> + char *fw_name; > > const char *fw_name; > > as well as second parameter of rtl8xxxu_load_firmware() > >> + int ret; >> + >> + fw_name = "rtlwifi/rtl8188eufw.bin"; >> + >> + ret = rtl8xxxu_load_firmware(priv, fw_name); >> + >> + return ret; >> +} >> + > > [...] > >> +static s8 rtl8188e_cck_rssi(struct rtl8xxxu_priv *priv, u8 cck_agc_rpt) >> +{ >> + /* only use lna 0/1/2/3/7 */ >> + static const s8 lna_gain_table_0[8] = {17, -1, -13, -29, -32, -35, -38, -41}; >> + /* only use lna 3/7 */ >> + static const s8 lna_gain_table_1[8] = {29, 20, 12, 3, -6, -15, -24, -33}; >> + >> + s8 rx_pwr_all = 0x00; >> + u8 vga_idx, lna_idx; >> + s8 lna_gain = 0; >> + >> + lna_idx = (cck_agc_rpt & 0xE0) >> 5; >> + vga_idx = cck_agc_rpt & 0x1F; > > #define CCK_AGC_RPT_LNA_IDX_MASK GENMASK(7, 5) > #define CCK_AGC_RPT_VGA_IDX_MASK GENMASK(4, 0) > >> + >> + if (priv->chip_cut >= 8) /* cut I */ >> + lna_gain = lna_gain_table_0[lna_idx]; >> + else >> + lna_gain = lna_gain_table_1[lna_idx]; >> + >> + rx_pwr_all = lna_gain - (2 * vga_idx); >> + >> + return rx_pwr_all; >> +} >> + > > [...] > >> diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188f.c >> b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188f.c >> index 2c4f403ba68f..d6d9ee87e128 100644 >> --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188f.c >> +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188f.c >> @@ -370,7 +370,7 @@ static void rtl8188f_channel_to_group(int channel, int *group, int *cck_group) >> *cck_group = *group; >> } >> >> -static void >> +void >> rtl8188f_set_tx_power(struct rtl8xxxu_priv *priv, int channel, bool ht40) >> { >> u32 val32, ofdm, mcs; >> @@ -1662,7 +1662,7 @@ static void rtl8188f_usb_quirks(struct rtl8xxxu_priv *priv) >> #define XTAL1 GENMASK(22, 17) >> #define XTAL0 GENMASK(16, 11) >> >> -static void rtl8188f_set_crystal_cap(struct rtl8xxxu_priv *priv, u8 crystal_cap) >> +void rtl8188f_set_crystal_cap(struct rtl8xxxu_priv *priv, u8 crystal_cap) >> { >> struct rtl8xxxu_cfo_tracking *cfo = &priv->cfo_tracking; >> u32 val32; >> diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c >> b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c >> index 3ed435401e57..c79f41459559 100644 >> --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c >> +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c >> @@ -46,6 +46,7 @@ MODULE_LICENSE("GPL"); >> MODULE_FIRMWARE("rtlwifi/rtl8723aufw_A.bin"); >> MODULE_FIRMWARE("rtlwifi/rtl8723aufw_B.bin"); >> MODULE_FIRMWARE("rtlwifi/rtl8723aufw_B_NoBT.bin"); >> +MODULE_FIRMWARE("rtlwifi/rtl8188eufw.bin"); > > If you need to send a firmware to linux-firmware, please send a private mail to me. > Then, I can check and send out pull-request. > This time it's not necessary because rtl8188eufw.bin is already there. The module r8188eu from staging uses it. >> MODULE_FIRMWARE("rtlwifi/rtl8192cufw_A.bin"); >> MODULE_FIRMWARE("rtlwifi/rtl8192cufw_B.bin"); >> MODULE_FIRMWARE("rtlwifi/rtl8192cufw_TMSC.bin"); > > [...] > > -- > Ping-Ke > Thank you for reviewing. I will implement your suggestions.