1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Rockchip PCIe Apis For WIFI
4 *
5 * Copyright (c) 2022 Rockchip Electronics Co., Ltd.
6 */
7
8 #include <linux/kernel.h>
9 #include <linux/module.h>
10 #include <linux/pci.h>
11 #include <linux/aspm_ext.h>
12 #include <linux/errno.h>
13
14
rockchip_pcie_pcie_access_cap(struct pci_dev * pdev,int cap,uint offset,bool is_ext,bool is_write,u32 writeval)15 static u32 rockchip_pcie_pcie_access_cap(struct pci_dev *pdev, int cap, uint offset,
16 bool is_ext, bool is_write, u32 writeval)
17 {
18 int cap_ptr = 0;
19 u32 ret = -1;
20 u32 readval;
21
22 if (!(pdev)) {
23 pci_err(pdev, "%s: pdev is NULL\n", __func__);
24 return ret;
25 }
26
27 /* Find Capability offset */
28 if (is_ext) {
29 /* removing max EXT_CAP_ID check as
30 * linux kernel definition's max value is not updated yet as per spec
31 */
32 cap_ptr = pci_find_ext_capability(pdev, cap);
33
34 } else {
35 /* removing max PCI_CAP_ID_MAX check as
36 * previous kernel versions dont have this definition
37 */
38 cap_ptr = pci_find_capability(pdev, cap);
39 }
40
41 /* Return if capability with given ID not found */
42 if (cap_ptr == 0) {
43 pci_err(pdev, "%s: PCI Cap(0x%02x) not supported.\n",
44 __func__, cap);
45 return -EINVAL;
46 }
47
48 if (is_write) {
49 pci_write_config_dword(pdev, (cap_ptr + offset), writeval);
50 ret = 0;
51
52 } else {
53 pci_read_config_dword(pdev, (cap_ptr + offset), &readval);
54 ret = readval;
55 }
56
57 return ret;
58 }
59
rockchip_pcie_bus_aspm_enable_dev(char * device,struct pci_dev * dev,bool enable)60 static bool rockchip_pcie_bus_aspm_enable_dev(char *device, struct pci_dev *dev, bool enable)
61 {
62 u32 linkctrl_before;
63 u32 linkctrl_after = 0;
64 u8 linkctrl_asm;
65
66 linkctrl_before = rockchip_pcie_pcie_access_cap(dev, PCI_CAP_ID_EXP, PCI_EXP_LNKCTL,
67 false, false, 0);
68 linkctrl_asm = (linkctrl_before & PCI_EXP_LNKCTL_ASPMC);
69
70 if (enable) {
71 if (linkctrl_asm == PCI_EXP_LNKCTL_ASPM_L1) {
72 pci_err(dev, "%s: %s already enabled linkctrl: 0x%x\n",
73 __func__, device, linkctrl_before);
74 return false;
75 }
76 /* Enable only L1 ASPM (bit 1) */
77 rockchip_pcie_pcie_access_cap(dev, PCI_CAP_ID_EXP, PCI_EXP_LNKCTL, false,
78 true, (linkctrl_before | PCI_EXP_LNKCTL_ASPM_L1));
79 } else {
80 if (linkctrl_asm == 0) {
81 pci_err(dev, "%s: %s already disabled linkctrl: 0x%x\n",
82 __func__, device, linkctrl_before);
83 return false;
84 }
85 /* Disable complete ASPM (bit 1 and bit 0) */
86 rockchip_pcie_pcie_access_cap(dev, PCI_CAP_ID_EXP, PCI_EXP_LNKCTL, false,
87 true, (linkctrl_before & (~PCI_EXP_LNKCTL_ASPMC)));
88 }
89
90 linkctrl_after = rockchip_pcie_pcie_access_cap(dev, PCI_CAP_ID_EXP, PCI_EXP_LNKCTL,
91 false, false, 0);
92 pci_err(dev, "%s: %s %s, linkctrl_before: 0x%x linkctrl_after: 0x%x\n",
93 __func__, device, (enable ? "ENABLE " : "DISABLE"),
94 linkctrl_before, linkctrl_after);
95
96 return true;
97 }
98
rockchip_pcie_bus_aspm_enable_rc_ep(struct pci_dev * child,struct pci_dev * parent,bool enable)99 static bool rockchip_pcie_bus_aspm_enable_rc_ep(struct pci_dev *child, struct pci_dev *parent, bool enable)
100 {
101 bool ret;
102
103 if (enable) {
104 /* Enable only L1 ASPM first RC then EP */
105 ret = rockchip_pcie_bus_aspm_enable_dev("RC", parent, enable);
106 ret = rockchip_pcie_bus_aspm_enable_dev("EP", child, enable);
107 } else {
108 /* Disable complete ASPM first EP then RC */
109 ret = rockchip_pcie_bus_aspm_enable_dev("EP", child, enable);
110 ret = rockchip_pcie_bus_aspm_enable_dev("RC", parent, enable);
111 }
112
113 return ret;
114 }
115
pci_clear_and_set_dword(struct pci_dev * pdev,int pos,u32 clear,u32 set)116 static void pci_clear_and_set_dword(struct pci_dev *pdev, int pos,
117 u32 clear, u32 set)
118 {
119 u32 val;
120
121 pci_read_config_dword(pdev, pos, &val);
122 val &= ~clear;
123 val |= set;
124 pci_write_config_dword(pdev, pos, val);
125 }
126
127 /* Convert L1SS T_pwr encoding to usec */
calc_l1ss_pwron(struct pci_dev * pdev,u32 scale,u32 val)128 static u32 calc_l1ss_pwron(struct pci_dev *pdev, u32 scale, u32 val)
129 {
130 switch (scale) {
131 case 0:
132 return val * 2;
133 case 1:
134 return val * 10;
135 case 2:
136 return val * 100;
137 }
138
139 return 0;
140 }
141
encode_l12_threshold(u32 threshold_us,u32 * scale,u32 * value)142 static void encode_l12_threshold(u32 threshold_us, u32 *scale, u32 *value)
143 {
144 u32 threshold_ns = threshold_us * 1000;
145
146 /* See PCIe r3.1, sec 7.33.3 and sec 6.18 */
147 if (threshold_ns < 32) {
148 *scale = 0;
149 *value = threshold_ns;
150 } else if (threshold_ns < 1024) {
151 *scale = 1;
152 *value = threshold_ns >> 5;
153 } else if (threshold_ns < 32768) {
154 *scale = 2;
155 *value = threshold_ns >> 10;
156 } else if (threshold_ns < 1048576) {
157 *scale = 3;
158 *value = threshold_ns >> 15;
159 } else if (threshold_ns < 33554432) {
160 *scale = 4;
161 *value = threshold_ns >> 20;
162 } else {
163 *scale = 5;
164 *value = threshold_ns >> 25;
165 }
166 }
167
168 /* Calculate L1.2 PM substate timing parameters */
aspm_calc_l1ss_info(struct pci_dev * child,struct pci_dev * parent)169 static void aspm_calc_l1ss_info(struct pci_dev *child, struct pci_dev *parent)
170 {
171 u32 val1, val2, scale1, scale2;
172 u32 t_common_mode, t_power_on, l1_2_threshold, scale, value;
173 u32 ctl1 = 0, ctl2 = 0;
174 u32 pctl1, pctl2, cctl1, cctl2;
175 u32 pl1_2_enables, cl1_2_enables;
176 u32 parent_l1ss_cap, child_l1ss_cap;
177
178 /* Setup L1 substate */
179 pci_read_config_dword(parent, parent->l1ss + PCI_L1SS_CAP,
180 &parent_l1ss_cap);
181 pci_read_config_dword(child, child->l1ss + PCI_L1SS_CAP,
182 &child_l1ss_cap);
183
184 /* Choose the greater of the two Port Common_Mode_Restore_Times */
185 val1 = (parent_l1ss_cap & PCI_L1SS_CAP_CM_RESTORE_TIME) >> 8;
186 val2 = (child_l1ss_cap & PCI_L1SS_CAP_CM_RESTORE_TIME) >> 8;
187 t_common_mode = max(val1, val2);
188
189 /* Choose the greater of the two Port T_POWER_ON times */
190 val1 = (parent_l1ss_cap & PCI_L1SS_CAP_P_PWR_ON_VALUE) >> 19;
191 scale1 = (parent_l1ss_cap & PCI_L1SS_CAP_P_PWR_ON_SCALE) >> 16;
192 val2 = (child_l1ss_cap & PCI_L1SS_CAP_P_PWR_ON_VALUE) >> 19;
193 scale2 = (child_l1ss_cap & PCI_L1SS_CAP_P_PWR_ON_SCALE) >> 16;
194
195 if (calc_l1ss_pwron(parent, scale1, val1) >
196 calc_l1ss_pwron(child, scale2, val2)) {
197 ctl2 |= scale1 | (val1 << 3);
198 t_power_on = calc_l1ss_pwron(parent, scale1, val1);
199 } else {
200 ctl2 |= scale2 | (val2 << 3);
201 t_power_on = calc_l1ss_pwron(child, scale2, val2);
202 }
203
204 /* Set LTR_L1.2_THRESHOLD to the time required to transition the
205 * Link from L0 to L1.2 and back to L0 so we enter L1.2 only if
206 * downstream devices report (via LTR) that they can tolerate at
207 * least that much latency.
208 *
209 * Based on PCIe r3.1, sec 5.5.3.3.1, Figures 5-16 and 5-17, and
210 * Table 5-11. T(POWER_OFF) is at most 2us and T(L1.2) is at
211 * least 4us.
212 */
213 l1_2_threshold = 2 + 4 + t_common_mode + t_power_on;
214 encode_l12_threshold(l1_2_threshold, &scale, &value);
215 ctl1 |= t_common_mode << 8 | scale << 29 | value << 16;
216
217 pci_read_config_dword(parent, parent->l1ss + PCI_L1SS_CTL1, &pctl1);
218 pci_read_config_dword(parent, parent->l1ss + PCI_L1SS_CTL2, &pctl2);
219 pci_read_config_dword(child, child->l1ss + PCI_L1SS_CTL1, &cctl1);
220 pci_read_config_dword(child, child->l1ss + PCI_L1SS_CTL2, &cctl2);
221
222 if (ctl1 == pctl1 && ctl1 == cctl1 &&
223 ctl2 == pctl2 && ctl2 == cctl2)
224 return;
225
226 /* Disable L1.2 while updating. See PCIe r5.0, sec 5.5.4, 7.8.3.3 */
227 pl1_2_enables = pctl1 & PCI_L1SS_CTL1_L1_2_MASK;
228 cl1_2_enables = cctl1 & PCI_L1SS_CTL1_L1_2_MASK;
229
230 if (pl1_2_enables || cl1_2_enables) {
231 pci_clear_and_set_dword(child, child->l1ss + PCI_L1SS_CTL1,
232 PCI_L1SS_CTL1_L1_2_MASK, 0);
233 pci_clear_and_set_dword(parent, parent->l1ss + PCI_L1SS_CTL1,
234 PCI_L1SS_CTL1_L1_2_MASK, 0);
235 }
236
237 /* Program T_POWER_ON times in both ports */
238 pci_write_config_dword(parent, parent->l1ss + PCI_L1SS_CTL2, ctl2);
239 pci_write_config_dword(child, child->l1ss + PCI_L1SS_CTL2, ctl2);
240
241 /* Program Common_Mode_Restore_Time in upstream device */
242 pci_clear_and_set_dword(parent, parent->l1ss + PCI_L1SS_CTL1,
243 PCI_L1SS_CTL1_CM_RESTORE_TIME, ctl1);
244
245 /* Program LTR_L1.2_THRESHOLD time in both ports */
246 pci_clear_and_set_dword(parent, parent->l1ss + PCI_L1SS_CTL1,
247 PCI_L1SS_CTL1_LTR_L12_TH_VALUE |
248 PCI_L1SS_CTL1_LTR_L12_TH_SCALE, ctl1);
249 pci_clear_and_set_dword(child, child->l1ss + PCI_L1SS_CTL1,
250 PCI_L1SS_CTL1_LTR_L12_TH_VALUE |
251 PCI_L1SS_CTL1_LTR_L12_TH_SCALE, ctl1);
252
253 if (pl1_2_enables || cl1_2_enables) {
254 pci_clear_and_set_dword(parent, parent->l1ss + PCI_L1SS_CTL1, 0,
255 pl1_2_enables);
256 pci_clear_and_set_dword(child, child->l1ss + PCI_L1SS_CTL1, 0,
257 cl1_2_enables);
258 }
259 }
260
rockchip_pcie_bus_l1ss_enable_dev(char * device,struct pci_dev * dev,bool enable)261 static void rockchip_pcie_bus_l1ss_enable_dev(char *device, struct pci_dev *dev, bool enable)
262 {
263 u32 l1ssctrl_before;
264 u32 l1ssctrl_after = 0;
265 u8 l1ss_ep;
266
267 /* Extendend Capacility Reg */
268 l1ssctrl_before = rockchip_pcie_pcie_access_cap(dev, PCI_EXT_CAP_ID_L1SS,
269 PCI_L1SS_CTL1, true, false, 0);
270 l1ss_ep = (l1ssctrl_before & PCI_L1SS_CTL1_L1SS_MASK);
271
272 if (enable) {
273 if (l1ss_ep == PCI_L1SS_CTL1_L1SS_MASK) {
274 pci_err(dev, "%s: %s already enabled, l1ssctrl: 0x%x\n",
275 __func__, device, l1ssctrl_before);
276 return;
277 }
278 rockchip_pcie_pcie_access_cap(dev, PCI_EXT_CAP_ID_L1SS, PCI_L1SS_CTL1,
279 true, true, (l1ssctrl_before | PCI_L1SS_CTL1_L1SS_MASK));
280 } else {
281 if (l1ss_ep == 0) {
282 pci_err(dev, "%s: %s already disabled, l1ssctrl: 0x%x\n",
283 __func__, device, l1ssctrl_before);
284 return;
285 }
286 rockchip_pcie_pcie_access_cap(dev, PCI_EXT_CAP_ID_L1SS, PCI_L1SS_CTL1,
287 true, true, (l1ssctrl_before & (~PCI_L1SS_CTL1_L1SS_MASK)));
288 }
289 l1ssctrl_after = rockchip_pcie_pcie_access_cap(dev, PCI_EXT_CAP_ID_L1SS,
290 PCI_L1SS_CTL1, true, false, 0);
291 pci_err(dev, "%s: %s %s, l1ssctrl_before: 0x%x l1ssctrl_after: 0x%x\n",
292 __func__, device, (enable ? "ENABLE " : "DISABLE"),
293 l1ssctrl_before, l1ssctrl_after);
294 }
295
pcie_aspm_ext_is_rc_ep_l1ss_capable(struct pci_dev * child,struct pci_dev * parent)296 bool pcie_aspm_ext_is_rc_ep_l1ss_capable(struct pci_dev *child, struct pci_dev *parent)
297 {
298 u32 parent_l1ss_cap, child_l1ss_cap;
299
300 /* Setup L1 substate */
301 pci_read_config_dword(parent, parent->l1ss + PCI_L1SS_CAP,
302 &parent_l1ss_cap);
303 pci_read_config_dword(child, child->l1ss + PCI_L1SS_CAP,
304 &child_l1ss_cap);
305
306 if (!(parent_l1ss_cap & PCI_L1SS_CAP_L1_PM_SS))
307 parent_l1ss_cap = 0;
308 if (!(child_l1ss_cap & PCI_L1SS_CAP_L1_PM_SS))
309 child_l1ss_cap = 0;
310
311 if (parent_l1ss_cap && child_l1ss_cap)
312 return true;
313 else
314 return false;
315 }
316 EXPORT_SYMBOL(pcie_aspm_ext_is_rc_ep_l1ss_capable);
317
pcie_aspm_ext_l1ss_enable(struct pci_dev * child,struct pci_dev * parent,bool enable)318 void pcie_aspm_ext_l1ss_enable(struct pci_dev *child, struct pci_dev *parent, bool enable)
319 {
320 bool ret;
321
322 /* Disable ASPM of RC and EP */
323 ret = rockchip_pcie_bus_aspm_enable_rc_ep(child, parent, false);
324
325 if (enable) {
326 /* LRT enable bits loss after wifi off, enable it after power on */
327 if (parent->ltr_path)
328 pcie_capability_set_word(parent, PCI_EXP_DEVCTL2, PCI_EXP_DEVCTL2_LTR_EN);
329
330 /* Enable RC then EP */
331 aspm_calc_l1ss_info(child, parent);
332 rockchip_pcie_bus_l1ss_enable_dev("RC", parent, enable);
333 rockchip_pcie_bus_l1ss_enable_dev("EP", child, enable);
334 } else {
335 /* Disable EP then RC */
336 rockchip_pcie_bus_l1ss_enable_dev("EP", child, enable);
337 rockchip_pcie_bus_l1ss_enable_dev("RC", parent, enable);
338 }
339
340 /* Enable ASPM of RC and EP only if this API disabled */
341 if (ret)
342 rockchip_pcie_bus_aspm_enable_rc_ep(child, parent, true);
343 }
344 EXPORT_SYMBOL(pcie_aspm_ext_l1ss_enable);
345
346 MODULE_LICENSE("GPL");
347