2faa59d760ee4db4ab3a712c8377c8717b557ec2
[openwrt/openwrt.git] /
1 From 315c23a64e99552502dd4d18d6ddc073fad9a7c3 Mon Sep 17 00:00:00 2001
2 From: Bitterblue Smith <rtl8821cerfe2@gmail.com>
3 Date: Thu, 11 Jul 2024 01:11:33 +0300
4 Subject: [PATCH] wifi: rtw88: usb: Support USB 3 with RTL8822CU/RTL8822BU
5
6 The Realtek wifi 5 devices which support USB 3 are weird: when first
7 plugged in, they pretend to be USB 2. The driver needs to send some
8 commands to the device, which make it disappear and come back as a
9 USB 3 device.
10
11 Implement the required commands in rtw88.
12
13 When a USB 3 device is plugged into a USB 2 port, rtw88 will try to
14 switch it to USB 3 mode only once. The device will disappear and come
15 back still in USB 2 mode, of course.
16
17 Some people experience heavy interference in the 2.4 GHz band in
18 USB 3 mode, so add a module parameter switch_usb_mode with the
19 default value 1 to let people disable the switching.
20
21 Signed-off-by: Bitterblue Smith <rtl8821cerfe2@gmail.com>
22 Acked-by: Ping-Ke Shih <pkshih@realtek.com>
23 Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
24 Link: https://patch.msgid.link/77906c62-5674-426f-bde1-1b2a12a0339d@gmail.com
25 ---
26 drivers/net/wireless/realtek/rtw88/debug.h | 1 +
27 drivers/net/wireless/realtek/rtw88/main.h | 2 +
28 drivers/net/wireless/realtek/rtw88/reg.h | 11 +++
29 drivers/net/wireless/realtek/rtw88/rtw8822b.c | 1 +
30 drivers/net/wireless/realtek/rtw88/rtw8822b.h | 4 +-
31 drivers/net/wireless/realtek/rtw88/rtw8822c.c | 1 +
32 drivers/net/wireless/realtek/rtw88/rtw8822c.h | 24 +++---
33 drivers/net/wireless/realtek/rtw88/usb.c | 84 +++++++++++++++++++
34 8 files changed, 116 insertions(+), 12 deletions(-)
35
36 --- a/drivers/net/wireless/realtek/rtw88/debug.h
37 +++ b/drivers/net/wireless/realtek/rtw88/debug.h
38 @@ -25,6 +25,7 @@ enum rtw_debug_mask {
39 RTW_DBG_HW_SCAN = 0x00010000,
40 RTW_DBG_STATE = 0x00020000,
41 RTW_DBG_SDIO = 0x00040000,
42 + RTW_DBG_USB = 0x00080000,
43
44 RTW_DBG_UNEXP = 0x80000000,
45 RTW_DBG_ALL = 0xffffffff
46 --- a/drivers/net/wireless/realtek/rtw88/main.h
47 +++ b/drivers/net/wireless/realtek/rtw88/main.h
48 @@ -1785,6 +1785,8 @@ struct rtw_efuse {
49 bool share_ant;
50 u8 bt_setting;
51
52 + u8 usb_mode_switch;
53 +
54 struct {
55 u8 hci;
56 u8 bw;
57 --- a/drivers/net/wireless/realtek/rtw88/reg.h
58 +++ b/drivers/net/wireless/realtek/rtw88/reg.h
59 @@ -15,6 +15,7 @@
60 #define BIT_WLOCK_1C_B6 BIT(5)
61 #define REG_SYS_PW_CTRL 0x0004
62 #define BIT_PFM_WOWL BIT(3)
63 +#define BIT_APFM_OFFMAC BIT(9)
64 #define REG_SYS_CLK_CTRL 0x0008
65 #define BIT_CPU_CLK_EN BIT(14)
66
67 @@ -133,6 +134,14 @@
68 #define REG_PMC_DBG_CTRL1 0xa8
69 #define BITS_PMC_BT_IQK_STS GENMASK(22, 21)
70
71 +#define REG_PAD_CTRL2 0x00C4
72 +#define BIT_RSM_EN_V1 BIT(16)
73 +#define BIT_NO_PDN_CHIPOFF_V1 BIT(17)
74 +#define BIT_MASK_USB23_SW_MODE_V1 GENMASK(19, 18)
75 +#define BIT_USB3_USB2_TRANSITION BIT(20)
76 +#define BIT_USB_MODE_U2 1
77 +#define BIT_USB_MODE_U3 2
78 +
79 #define REG_EFUSE_ACCESS 0x00CF
80 #define EFUSE_ACCESS_ON 0x69
81 #define EFUSE_ACCESS_OFF 0x00
82 @@ -568,6 +577,8 @@
83 #define BIT_WL_SECURITY_CLK BIT(15)
84 #define BIT_DDMA_EN BIT(8)
85
86 +#define REG_SW_MDIO 0x10C0
87 +
88 #define REG_H2C_PKT_READADDR 0x10D0
89 #define REG_H2C_PKT_WRITEADDR 0x10D4
90 #define REG_FW_DBG6 0x10F8
91 --- a/drivers/net/wireless/realtek/rtw88/rtw8822b.c
92 +++ b/drivers/net/wireless/realtek/rtw88/rtw8822b.c
93 @@ -46,6 +46,7 @@ static int rtw8822b_read_efuse(struct rt
94
95 map = (struct rtw8822b_efuse *)log_map;
96
97 + efuse->usb_mode_switch = u8_get_bits(map->usb_mode, BIT(7));
98 efuse->rfe_option = map->rfe_option;
99 efuse->rf_board_option = map->rf_board_option;
100 efuse->crystal_cap = map->xtal_k;
101 --- a/drivers/net/wireless/realtek/rtw88/rtw8822b.h
102 +++ b/drivers/net/wireless/realtek/rtw88/rtw8822b.h
103 @@ -72,7 +72,9 @@ struct rtw8822bs_efuse {
104
105 struct rtw8822b_efuse {
106 __le16 rtl_id;
107 - u8 res0[0x0e];
108 + u8 res0[4];
109 + u8 usb_mode;
110 + u8 res1[0x09];
111
112 /* power index for four RF paths */
113 struct rtw_txpwr_idx txpwr_idx_table[4];
114 --- a/drivers/net/wireless/realtek/rtw88/rtw8822c.c
115 +++ b/drivers/net/wireless/realtek/rtw88/rtw8822c.c
116 @@ -49,6 +49,7 @@ static int rtw8822c_read_efuse(struct rt
117
118 map = (struct rtw8822c_efuse *)log_map;
119
120 + efuse->usb_mode_switch = u8_get_bits(map->usb_mode, BIT(7));
121 efuse->rfe_option = map->rfe_option;
122 efuse->rf_board_option = map->rf_board_option;
123 efuse->crystal_cap = map->xtal_k & XCAP_MASK;
124 --- a/drivers/net/wireless/realtek/rtw88/rtw8822c.h
125 +++ b/drivers/net/wireless/realtek/rtw88/rtw8822c.h
126 @@ -59,16 +59,18 @@ struct rtw8822ce_efuse {
127
128 struct rtw8822c_efuse {
129 __le16 rtl_id;
130 - u8 res0[0x0e];
131 + u8 res0[4];
132 + u8 usb_mode;
133 + u8 res1[0x09];
134
135 /* power index for four RF paths */
136 struct rtw_txpwr_idx txpwr_idx_table[4];
137
138 u8 channel_plan; /* 0xb8 */
139 u8 xtal_k;
140 - u8 res1;
141 + u8 res2;
142 u8 iqk_lck;
143 - u8 res2[5]; /* 0xbc */
144 + u8 res3[5]; /* 0xbc */
145 u8 rf_board_option;
146 u8 rf_feature_option;
147 u8 rf_bt_setting;
148 @@ -80,21 +82,21 @@ struct rtw8822c_efuse {
149 u8 rf_antenna_option; /* 0xc9 */
150 u8 rfe_option;
151 u8 country_code[2];
152 - u8 res3[3];
153 + u8 res4[3];
154 u8 path_a_thermal; /* 0xd0 */
155 u8 path_b_thermal;
156 - u8 res4[2];
157 + u8 res5[2];
158 u8 rx_gain_gap_2g_ofdm;
159 - u8 res5;
160 - u8 rx_gain_gap_2g_cck;
161 u8 res6;
162 - u8 rx_gain_gap_5gl;
163 + u8 rx_gain_gap_2g_cck;
164 u8 res7;
165 - u8 rx_gain_gap_5gm;
166 + u8 rx_gain_gap_5gl;
167 u8 res8;
168 - u8 rx_gain_gap_5gh;
169 + u8 rx_gain_gap_5gm;
170 u8 res9;
171 - u8 res10[0x42];
172 + u8 rx_gain_gap_5gh;
173 + u8 res10;
174 + u8 res11[0x42];
175 union {
176 struct rtw8822ce_efuse e;
177 struct rtw8822cu_efuse u;
178 --- a/drivers/net/wireless/realtek/rtw88/usb.c
179 +++ b/drivers/net/wireless/realtek/rtw88/usb.c
180 @@ -14,6 +14,11 @@
181 #include "ps.h"
182 #include "usb.h"
183
184 +static bool rtw_switch_usb_mode = true;
185 +module_param_named(switch_usb_mode, rtw_switch_usb_mode, bool, 0644);
186 +MODULE_PARM_DESC(switch_usb_mode,
187 + "Set to N to disable switching to USB 3 mode to avoid potential interference in the 2.4 GHz band (default: Y)");
188 +
189 #define RTW_USB_MAX_RXQ_LEN 512
190
191 struct rtw_usb_txcb {
192 @@ -841,6 +846,77 @@ static void rtw_usb_intf_deinit(struct r
193 usb_set_intfdata(intf, NULL);
194 }
195
196 +static int rtw_usb_switch_mode_new(struct rtw_dev *rtwdev)
197 +{
198 + enum usb_device_speed cur_speed;
199 + u8 id = rtwdev->chip->id;
200 + bool can_switch;
201 + u32 pad_ctrl2;
202 +
203 + if (rtw_read8(rtwdev, REG_SYS_CFG2 + 3) == 0x20)
204 + cur_speed = USB_SPEED_SUPER;
205 + else
206 + cur_speed = USB_SPEED_HIGH;
207 +
208 + if (cur_speed == USB_SPEED_SUPER)
209 + return 0;
210 +
211 + pad_ctrl2 = rtw_read32(rtwdev, REG_PAD_CTRL2);
212 +
213 + can_switch = !!(pad_ctrl2 & (BIT_MASK_USB23_SW_MODE_V1 |
214 + BIT_USB3_USB2_TRANSITION));
215 +
216 + if (!can_switch) {
217 + rtw_dbg(rtwdev, RTW_DBG_USB,
218 + "Switching to USB 3 mode unsupported by the chip\n");
219 + return 0;
220 + }
221 +
222 + /* At this point cur_speed is USB_SPEED_HIGH. If we already tried
223 + * to switch don't try again - it's a USB 2 port.
224 + */
225 + if (u32_get_bits(pad_ctrl2, BIT_MASK_USB23_SW_MODE_V1) == BIT_USB_MODE_U3)
226 + return 0;
227 +
228 + /* Enable IO wrapper timeout */
229 + if (id == RTW_CHIP_TYPE_8822B || id == RTW_CHIP_TYPE_8821C)
230 + rtw_write8_clr(rtwdev, REG_SW_MDIO + 3, BIT(0));
231 +
232 + u32p_replace_bits(&pad_ctrl2, BIT_USB_MODE_U3, BIT_MASK_USB23_SW_MODE_V1);
233 + pad_ctrl2 |= BIT_RSM_EN_V1;
234 +
235 + rtw_write32(rtwdev, REG_PAD_CTRL2, pad_ctrl2);
236 + rtw_write8(rtwdev, REG_PAD_CTRL2 + 1, 4);
237 +
238 + rtw_write16_set(rtwdev, REG_SYS_PW_CTRL, BIT_APFM_OFFMAC);
239 + usleep_range(1000, 1001);
240 + rtw_write32_set(rtwdev, REG_PAD_CTRL2, BIT_NO_PDN_CHIPOFF_V1);
241 +
242 + return 1;
243 +}
244 +
245 +static int rtw_usb_switch_mode(struct rtw_dev *rtwdev)
246 +{
247 + u8 id = rtwdev->chip->id;
248 +
249 + if (id != RTW_CHIP_TYPE_8822C && id != RTW_CHIP_TYPE_8822B)
250 + return 0;
251 +
252 + if (!rtwdev->efuse.usb_mode_switch) {
253 + rtw_dbg(rtwdev, RTW_DBG_USB,
254 + "Switching to USB 3 mode disabled by chip's efuse\n");
255 + return 0;
256 + }
257 +
258 + if (!rtw_switch_usb_mode) {
259 + rtw_dbg(rtwdev, RTW_DBG_USB,
260 + "Switching to USB 3 mode disabled by module parameter\n");
261 + return 0;
262 + }
263 +
264 + return rtw_usb_switch_mode_new(rtwdev);
265 +}
266 +
267 int rtw_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
268 {
269 struct rtw_dev *rtwdev;
270 @@ -896,6 +972,14 @@ int rtw_usb_probe(struct usb_interface *
271 goto err_destroy_rxwq;
272 }
273
274 + ret = rtw_usb_switch_mode(rtwdev);
275 + if (ret) {
276 + /* Not a fail, but we do need to skip rtw_register_hw. */
277 + rtw_dbg(rtwdev, RTW_DBG_USB, "switching to USB 3 mode\n");
278 + ret = 0;
279 + goto err_destroy_rxwq;
280 + }
281 +
282 ret = rtw_register_hw(rtwdev, rtwdev->hw);
283 if (ret) {
284 rtw_err(rtwdev, "failed to register hw\n");