xref: /OK3568_Linux_fs/kernel/drivers/pci/pcie/aspm_ext.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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