> -----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. > + 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()? > + } > + > + 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. > MODULE_FIRMWARE("rtlwifi/rtl8192cufw_A.bin"); > MODULE_FIRMWARE("rtlwifi/rtl8192cufw_B.bin"); > MODULE_FIRMWARE("rtlwifi/rtl8192cufw_TMSC.bin"); [...] -- Ping-Ke