blob: 5a7c152c9ee3968acb240b5d4d64caa431d9201d [file] [log] [blame]
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00001// SPDX-License-Identifier: GPL-2.0
2/**
3 * dwc3-pci.c - PCI Specific glue layer
4 *
5 * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
6 *
7 * Authors: Felipe Balbi <balbi@ti.com>,
8 * Sebastian Andrzej Siewior <bigeasy@linutronix.de>
9 */
10
11#include <linux/kernel.h>
12#include <linux/module.h>
13#include <linux/slab.h>
14#include <linux/pci.h>
15#include <linux/workqueue.h>
16#include <linux/pm_runtime.h>
17#include <linux/platform_device.h>
18#include <linux/gpio/consumer.h>
19#include <linux/gpio/machine.h>
20#include <linux/acpi.h>
21#include <linux/delay.h>
22
23#define PCI_DEVICE_ID_INTEL_BYT 0x0f37
24#define PCI_DEVICE_ID_INTEL_MRFLD 0x119e
25#define PCI_DEVICE_ID_INTEL_BSW 0x22b7
26#define PCI_DEVICE_ID_INTEL_SPTLP 0x9d30
27#define PCI_DEVICE_ID_INTEL_SPTH 0xa130
28#define PCI_DEVICE_ID_INTEL_BXT 0x0aaa
29#define PCI_DEVICE_ID_INTEL_BXT_M 0x1aaa
30#define PCI_DEVICE_ID_INTEL_APL 0x5aaa
31#define PCI_DEVICE_ID_INTEL_KBP 0xa2b0
Olivier Deprez0e641232021-09-23 10:07:05 +020032#define PCI_DEVICE_ID_INTEL_CMLLP 0x02ee
33#define PCI_DEVICE_ID_INTEL_CMLH 0x06ee
Andrew Scullb4b6d4a2019-01-02 15:54:55 +000034#define PCI_DEVICE_ID_INTEL_GLK 0x31aa
35#define PCI_DEVICE_ID_INTEL_CNPLP 0x9dee
36#define PCI_DEVICE_ID_INTEL_CNPH 0xa36e
Olivier Deprez0e641232021-09-23 10:07:05 +020037#define PCI_DEVICE_ID_INTEL_CNPV 0xa3b0
Andrew Scullb4b6d4a2019-01-02 15:54:55 +000038#define PCI_DEVICE_ID_INTEL_ICLLP 0x34ee
David Brazdil0f672f62019-12-10 10:32:29 +000039#define PCI_DEVICE_ID_INTEL_EHLLP 0x4b7e
40#define PCI_DEVICE_ID_INTEL_TGPLP 0xa0ee
Olivier Deprez0e641232021-09-23 10:07:05 +020041#define PCI_DEVICE_ID_INTEL_TGPH 0x43ee
42#define PCI_DEVICE_ID_INTEL_JSP 0x4dee
43#define PCI_DEVICE_ID_INTEL_ADLS 0x7ae1
Andrew Scullb4b6d4a2019-01-02 15:54:55 +000044
45#define PCI_INTEL_BXT_DSM_GUID "732b85d5-b7a7-4a1b-9ba0-4bbd00ffd511"
46#define PCI_INTEL_BXT_FUNC_PMU_PWR 4
47#define PCI_INTEL_BXT_STATE_D0 0
48#define PCI_INTEL_BXT_STATE_D3 3
49
50#define GP_RWBAR 1
51#define GP_RWREG1 0xa0
52#define GP_RWREG1_ULPI_REFCLK_DISABLE (1 << 17)
53
54/**
55 * struct dwc3_pci - Driver private structure
56 * @dwc3: child dwc3 platform_device
57 * @pci: our link to PCI bus
58 * @guid: _DSM GUID
59 * @has_dsm_for_pm: true for devices which need to run _DSM on runtime PM
60 * @wakeup_work: work for asynchronous resume
61 */
62struct dwc3_pci {
63 struct platform_device *dwc3;
64 struct pci_dev *pci;
65
66 guid_t guid;
67
68 unsigned int has_dsm_for_pm:1;
69 struct work_struct wakeup_work;
70};
71
72static const struct acpi_gpio_params reset_gpios = { 0, 0, false };
73static const struct acpi_gpio_params cs_gpios = { 1, 0, false };
74
75static const struct acpi_gpio_mapping acpi_dwc3_byt_gpios[] = {
76 { "reset-gpios", &reset_gpios, 1 },
77 { "cs-gpios", &cs_gpios, 1 },
78 { },
79};
80
81static struct gpiod_lookup_table platform_bytcr_gpios = {
82 .dev_id = "0000:00:16.0",
83 .table = {
84 GPIO_LOOKUP("INT33FC:00", 54, "reset", GPIO_ACTIVE_HIGH),
85 GPIO_LOOKUP("INT33FC:02", 14, "cs", GPIO_ACTIVE_HIGH),
86 {}
87 },
88};
89
90static int dwc3_byt_enable_ulpi_refclock(struct pci_dev *pci)
91{
92 void __iomem *reg;
93 u32 value;
94
95 reg = pcim_iomap(pci, GP_RWBAR, 0);
96 if (!reg)
97 return -ENOMEM;
98
99 value = readl(reg + GP_RWREG1);
100 if (!(value & GP_RWREG1_ULPI_REFCLK_DISABLE))
101 goto unmap; /* ULPI refclk already enabled */
102
103 value &= ~GP_RWREG1_ULPI_REFCLK_DISABLE;
104 writel(value, reg + GP_RWREG1);
105 /* This comes from the Intel Android x86 tree w/o any explanation */
106 msleep(100);
107unmap:
108 pcim_iounmap(pci, reg);
109 return 0;
110}
111
112static const struct property_entry dwc3_pci_intel_properties[] = {
113 PROPERTY_ENTRY_STRING("dr_mode", "peripheral"),
114 PROPERTY_ENTRY_BOOL("linux,sysdev_is_parent"),
115 {}
116};
117
118static const struct property_entry dwc3_pci_mrfld_properties[] = {
119 PROPERTY_ENTRY_STRING("dr_mode", "otg"),
Olivier Deprez0e641232021-09-23 10:07:05 +0200120 PROPERTY_ENTRY_STRING("linux,extcon-name", "mrfld_bcove_pwrsrc"),
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000121 PROPERTY_ENTRY_BOOL("linux,sysdev_is_parent"),
122 {}
123};
124
125static const struct property_entry dwc3_pci_amd_properties[] = {
126 PROPERTY_ENTRY_BOOL("snps,has-lpm-erratum"),
127 PROPERTY_ENTRY_U8("snps,lpm-nyet-threshold", 0xf),
128 PROPERTY_ENTRY_BOOL("snps,u2exit_lfps_quirk"),
129 PROPERTY_ENTRY_BOOL("snps,u2ss_inp3_quirk"),
130 PROPERTY_ENTRY_BOOL("snps,req_p1p2p3_quirk"),
131 PROPERTY_ENTRY_BOOL("snps,del_p1p2p3_quirk"),
132 PROPERTY_ENTRY_BOOL("snps,del_phy_power_chg_quirk"),
133 PROPERTY_ENTRY_BOOL("snps,lfps_filter_quirk"),
134 PROPERTY_ENTRY_BOOL("snps,rx_detect_poll_quirk"),
135 PROPERTY_ENTRY_BOOL("snps,tx_de_emphasis_quirk"),
136 PROPERTY_ENTRY_U8("snps,tx_de_emphasis", 1),
137 /* FIXME these quirks should be removed when AMD NL tapes out */
138 PROPERTY_ENTRY_BOOL("snps,disable_scramble_quirk"),
139 PROPERTY_ENTRY_BOOL("snps,dis_u3_susphy_quirk"),
140 PROPERTY_ENTRY_BOOL("snps,dis_u2_susphy_quirk"),
Olivier Deprez0e641232021-09-23 10:07:05 +0200141 PROPERTY_ENTRY_BOOL("snps,usb2-gadget-lpm-disable"),
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000142 PROPERTY_ENTRY_BOOL("linux,sysdev_is_parent"),
143 {}
144};
145
146static int dwc3_pci_quirks(struct dwc3_pci *dwc)
147{
148 struct pci_dev *pdev = dwc->pci;
149
150 if (pdev->vendor == PCI_VENDOR_ID_INTEL) {
151 if (pdev->device == PCI_DEVICE_ID_INTEL_BXT ||
Olivier Deprez0e641232021-09-23 10:07:05 +0200152 pdev->device == PCI_DEVICE_ID_INTEL_BXT_M ||
153 pdev->device == PCI_DEVICE_ID_INTEL_EHLLP) {
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000154 guid_parse(PCI_INTEL_BXT_DSM_GUID, &dwc->guid);
155 dwc->has_dsm_for_pm = true;
156 }
157
158 if (pdev->device == PCI_DEVICE_ID_INTEL_BYT) {
159 struct gpio_desc *gpio;
160 int ret;
161
162 /* On BYT the FW does not always enable the refclock */
163 ret = dwc3_byt_enable_ulpi_refclock(pdev);
164 if (ret)
165 return ret;
166
167 ret = devm_acpi_dev_add_driver_gpios(&pdev->dev,
168 acpi_dwc3_byt_gpios);
169 if (ret)
170 dev_dbg(&pdev->dev, "failed to add mapping table\n");
171
172 /*
173 * A lot of BYT devices lack ACPI resource entries for
174 * the GPIOs, add a fallback mapping to the reference
175 * design GPIOs which all boards seem to use.
176 */
177 gpiod_add_lookup_table(&platform_bytcr_gpios);
178
179 /*
180 * These GPIOs will turn on the USB2 PHY. Note that we have to
181 * put the gpio descriptors again here because the phy driver
182 * might want to grab them, too.
183 */
David Brazdil0f672f62019-12-10 10:32:29 +0000184 gpio = gpiod_get_optional(&pdev->dev, "cs", GPIOD_OUT_LOW);
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000185 if (IS_ERR(gpio))
186 return PTR_ERR(gpio);
187
188 gpiod_set_value_cansleep(gpio, 1);
David Brazdil0f672f62019-12-10 10:32:29 +0000189 gpiod_put(gpio);
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000190
David Brazdil0f672f62019-12-10 10:32:29 +0000191 gpio = gpiod_get_optional(&pdev->dev, "reset", GPIOD_OUT_LOW);
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000192 if (IS_ERR(gpio))
193 return PTR_ERR(gpio);
194
195 if (gpio) {
196 gpiod_set_value_cansleep(gpio, 1);
David Brazdil0f672f62019-12-10 10:32:29 +0000197 gpiod_put(gpio);
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000198 usleep_range(10000, 11000);
199 }
200 }
201 }
202
203 return 0;
204}
205
206#ifdef CONFIG_PM
207static void dwc3_pci_resume_work(struct work_struct *work)
208{
209 struct dwc3_pci *dwc = container_of(work, struct dwc3_pci, wakeup_work);
210 struct platform_device *dwc3 = dwc->dwc3;
211 int ret;
212
213 ret = pm_runtime_get_sync(&dwc3->dev);
Olivier Deprez0e641232021-09-23 10:07:05 +0200214 if (ret) {
215 pm_runtime_put_sync_autosuspend(&dwc3->dev);
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000216 return;
Olivier Deprez0e641232021-09-23 10:07:05 +0200217 }
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000218
219 pm_runtime_mark_last_busy(&dwc3->dev);
220 pm_runtime_put_sync_autosuspend(&dwc3->dev);
221}
222#endif
223
224static int dwc3_pci_probe(struct pci_dev *pci, const struct pci_device_id *id)
225{
226 struct property_entry *p = (struct property_entry *)id->driver_data;
227 struct dwc3_pci *dwc;
228 struct resource res[2];
229 int ret;
230 struct device *dev = &pci->dev;
231
232 ret = pcim_enable_device(pci);
233 if (ret) {
234 dev_err(dev, "failed to enable pci device\n");
235 return -ENODEV;
236 }
237
238 pci_set_master(pci);
239
240 dwc = devm_kzalloc(dev, sizeof(*dwc), GFP_KERNEL);
241 if (!dwc)
242 return -ENOMEM;
243
244 dwc->dwc3 = platform_device_alloc("dwc3", PLATFORM_DEVID_AUTO);
245 if (!dwc->dwc3)
246 return -ENOMEM;
247
248 memset(res, 0x00, sizeof(struct resource) * ARRAY_SIZE(res));
249
250 res[0].start = pci_resource_start(pci, 0);
251 res[0].end = pci_resource_end(pci, 0);
252 res[0].name = "dwc_usb3";
253 res[0].flags = IORESOURCE_MEM;
254
255 res[1].start = pci->irq;
256 res[1].name = "dwc_usb3";
257 res[1].flags = IORESOURCE_IRQ;
258
259 ret = platform_device_add_resources(dwc->dwc3, res, ARRAY_SIZE(res));
260 if (ret) {
261 dev_err(dev, "couldn't add resources to dwc3 device\n");
262 goto err;
263 }
264
265 dwc->pci = pci;
266 dwc->dwc3->dev.parent = dev;
267 ACPI_COMPANION_SET(&dwc->dwc3->dev, ACPI_COMPANION(dev));
268
269 ret = platform_device_add_properties(dwc->dwc3, p);
270 if (ret < 0)
David Brazdil0f672f62019-12-10 10:32:29 +0000271 goto err;
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000272
273 ret = dwc3_pci_quirks(dwc);
274 if (ret)
275 goto err;
276
277 ret = platform_device_add(dwc->dwc3);
278 if (ret) {
279 dev_err(dev, "failed to register dwc3 device\n");
280 goto err;
281 }
282
283 device_init_wakeup(dev, true);
284 pci_set_drvdata(pci, dwc);
285 pm_runtime_put(dev);
286#ifdef CONFIG_PM
287 INIT_WORK(&dwc->wakeup_work, dwc3_pci_resume_work);
288#endif
289
290 return 0;
291err:
292 platform_device_put(dwc->dwc3);
293 return ret;
294}
295
296static void dwc3_pci_remove(struct pci_dev *pci)
297{
298 struct dwc3_pci *dwc = pci_get_drvdata(pci);
299 struct pci_dev *pdev = dwc->pci;
300
301 if (pdev->device == PCI_DEVICE_ID_INTEL_BYT)
302 gpiod_remove_lookup_table(&platform_bytcr_gpios);
303#ifdef CONFIG_PM
304 cancel_work_sync(&dwc->wakeup_work);
305#endif
306 device_init_wakeup(&pci->dev, false);
307 pm_runtime_get(&pci->dev);
308 platform_device_unregister(dwc->dwc3);
309}
310
311static const struct pci_device_id dwc3_pci_id_table[] = {
312 { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_BSW),
313 (kernel_ulong_t) &dwc3_pci_intel_properties },
314
315 { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_BYT),
316 (kernel_ulong_t) &dwc3_pci_intel_properties, },
317
318 { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_MRFLD),
319 (kernel_ulong_t) &dwc3_pci_mrfld_properties, },
320
Olivier Deprez0e641232021-09-23 10:07:05 +0200321 { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_CMLLP),
322 (kernel_ulong_t) &dwc3_pci_intel_properties, },
323
David Brazdil0f672f62019-12-10 10:32:29 +0000324 { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_CMLH),
325 (kernel_ulong_t) &dwc3_pci_intel_properties, },
326
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000327 { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_SPTLP),
328 (kernel_ulong_t) &dwc3_pci_intel_properties, },
329
330 { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_SPTH),
331 (kernel_ulong_t) &dwc3_pci_intel_properties, },
332
333 { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_BXT),
334 (kernel_ulong_t) &dwc3_pci_intel_properties, },
335
336 { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_BXT_M),
337 (kernel_ulong_t) &dwc3_pci_intel_properties, },
338
339 { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_APL),
340 (kernel_ulong_t) &dwc3_pci_intel_properties, },
341
342 { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_KBP),
343 (kernel_ulong_t) &dwc3_pci_intel_properties, },
344
345 { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_GLK),
346 (kernel_ulong_t) &dwc3_pci_intel_properties, },
347
348 { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_CNPLP),
349 (kernel_ulong_t) &dwc3_pci_intel_properties, },
350
351 { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_CNPH),
352 (kernel_ulong_t) &dwc3_pci_intel_properties, },
353
Olivier Deprez0e641232021-09-23 10:07:05 +0200354 { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_CNPV),
355 (kernel_ulong_t) &dwc3_pci_intel_properties, },
356
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000357 { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ICLLP),
358 (kernel_ulong_t) &dwc3_pci_intel_properties, },
359
David Brazdil0f672f62019-12-10 10:32:29 +0000360 { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_EHLLP),
361 (kernel_ulong_t) &dwc3_pci_intel_properties, },
362
363 { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_TGPLP),
364 (kernel_ulong_t) &dwc3_pci_intel_properties, },
365
Olivier Deprez0e641232021-09-23 10:07:05 +0200366 { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_TGPH),
367 (kernel_ulong_t) &dwc3_pci_intel_properties, },
368
369 { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_JSP),
370 (kernel_ulong_t) &dwc3_pci_intel_properties, },
371
372 { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ADLS),
373 (kernel_ulong_t) &dwc3_pci_intel_properties, },
374
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000375 { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_NL_USB),
376 (kernel_ulong_t) &dwc3_pci_amd_properties, },
377 { } /* Terminating Entry */
378};
379MODULE_DEVICE_TABLE(pci, dwc3_pci_id_table);
380
381#if defined(CONFIG_PM) || defined(CONFIG_PM_SLEEP)
382static int dwc3_pci_dsm(struct dwc3_pci *dwc, int param)
383{
384 union acpi_object *obj;
385 union acpi_object tmp;
386 union acpi_object argv4 = ACPI_INIT_DSM_ARGV4(1, &tmp);
387
388 if (!dwc->has_dsm_for_pm)
389 return 0;
390
391 tmp.type = ACPI_TYPE_INTEGER;
392 tmp.integer.value = param;
393
394 obj = acpi_evaluate_dsm(ACPI_HANDLE(&dwc->pci->dev), &dwc->guid,
395 1, PCI_INTEL_BXT_FUNC_PMU_PWR, &argv4);
396 if (!obj) {
397 dev_err(&dwc->pci->dev, "failed to evaluate _DSM\n");
398 return -EIO;
399 }
400
401 ACPI_FREE(obj);
402
403 return 0;
404}
405#endif /* CONFIG_PM || CONFIG_PM_SLEEP */
406
407#ifdef CONFIG_PM
408static int dwc3_pci_runtime_suspend(struct device *dev)
409{
410 struct dwc3_pci *dwc = dev_get_drvdata(dev);
411
412 if (device_can_wakeup(dev))
413 return dwc3_pci_dsm(dwc, PCI_INTEL_BXT_STATE_D3);
414
415 return -EBUSY;
416}
417
418static int dwc3_pci_runtime_resume(struct device *dev)
419{
420 struct dwc3_pci *dwc = dev_get_drvdata(dev);
421 int ret;
422
423 ret = dwc3_pci_dsm(dwc, PCI_INTEL_BXT_STATE_D0);
424 if (ret)
425 return ret;
426
427 queue_work(pm_wq, &dwc->wakeup_work);
428
429 return 0;
430}
431#endif /* CONFIG_PM */
432
433#ifdef CONFIG_PM_SLEEP
434static int dwc3_pci_suspend(struct device *dev)
435{
436 struct dwc3_pci *dwc = dev_get_drvdata(dev);
437
438 return dwc3_pci_dsm(dwc, PCI_INTEL_BXT_STATE_D3);
439}
440
441static int dwc3_pci_resume(struct device *dev)
442{
443 struct dwc3_pci *dwc = dev_get_drvdata(dev);
444
445 return dwc3_pci_dsm(dwc, PCI_INTEL_BXT_STATE_D0);
446}
447#endif /* CONFIG_PM_SLEEP */
448
449static const struct dev_pm_ops dwc3_pci_dev_pm_ops = {
450 SET_SYSTEM_SLEEP_PM_OPS(dwc3_pci_suspend, dwc3_pci_resume)
451 SET_RUNTIME_PM_OPS(dwc3_pci_runtime_suspend, dwc3_pci_runtime_resume,
452 NULL)
453};
454
455static struct pci_driver dwc3_pci_driver = {
456 .name = "dwc3-pci",
457 .id_table = dwc3_pci_id_table,
458 .probe = dwc3_pci_probe,
459 .remove = dwc3_pci_remove,
460 .driver = {
461 .pm = &dwc3_pci_dev_pm_ops,
462 }
463};
464
465MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
466MODULE_LICENSE("GPL v2");
467MODULE_DESCRIPTION("DesignWare USB3 PCI Glue Layer");
468
469module_pci_driver(dwc3_pci_driver);