1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (c) 2015, Google, Inc
4  * Written by Simon Glass <sjg@chromium.org>
5  * All rights reserved.
6  */
7 
8 #include <common.h>
9 #include <dm.h>
10 #include <dm/device_compat.h>
11 #include <init.h>
12 #include <log.h>
13 #include <pci.h>
14 #include <reset.h>
15 #include <usb.h>
16 #include <usb/xhci.h>
17 
18 struct xhci_pci_plat {
19 	struct reset_ctl reset;
20 };
21 
xhci_pci_init(struct udevice * dev,struct xhci_hccr ** ret_hccr,struct xhci_hcor ** ret_hcor)22 static int xhci_pci_init(struct udevice *dev, struct xhci_hccr **ret_hccr,
23 			 struct xhci_hcor **ret_hcor)
24 {
25 	struct xhci_hccr *hccr;
26 	struct xhci_hcor *hcor;
27 	u32 cmd;
28 
29 	hccr = (struct xhci_hccr *)dm_pci_map_bar(dev,
30 			PCI_BASE_ADDRESS_0, PCI_REGION_MEM);
31 	if (!hccr) {
32 		printf("xhci-pci init cannot map PCI mem bar\n");
33 		return -EIO;
34 	}
35 
36 	hcor = (struct xhci_hcor *)((uintptr_t) hccr +
37 			HC_LENGTH(xhci_readl(&hccr->cr_capbase)));
38 
39 	debug("XHCI-PCI init hccr %p and hcor %p hc_length %d\n",
40 	      hccr, hcor, (u32)HC_LENGTH(xhci_readl(&hccr->cr_capbase)));
41 
42 	*ret_hccr = hccr;
43 	*ret_hcor = hcor;
44 
45 	/* enable busmaster */
46 	dm_pci_read_config32(dev, PCI_COMMAND, &cmd);
47 	cmd |= PCI_COMMAND_MASTER;
48 	dm_pci_write_config32(dev, PCI_COMMAND, cmd);
49 	return 0;
50 }
51 
xhci_pci_probe(struct udevice * dev)52 static int xhci_pci_probe(struct udevice *dev)
53 {
54 	struct xhci_pci_plat *plat = dev_get_plat(dev);
55 	struct xhci_hccr *hccr;
56 	struct xhci_hcor *hcor;
57 	int ret;
58 
59 	ret = reset_get_by_index(dev, 0, &plat->reset);
60 	if (ret && ret != -ENOENT && ret != -ENOTSUPP) {
61 		dev_err(dev, "failed to get reset\n");
62 		return ret;
63 	}
64 
65 	if (reset_valid(&plat->reset)) {
66 		ret = reset_assert(&plat->reset);
67 		if (ret)
68 			goto err_reset;
69 
70 		ret = reset_deassert(&plat->reset);
71 		if (ret)
72 			goto err_reset;
73 	}
74 
75 	ret = xhci_pci_init(dev, &hccr, &hcor);
76 	if (ret)
77 		goto err_reset;
78 
79 	ret = xhci_register(dev, hccr, hcor);
80 	if (ret)
81 		goto err_reset;
82 
83 	return 0;
84 
85 err_reset:
86 	if (reset_valid(&plat->reset))
87 		reset_free(&plat->reset);
88 
89 	return ret;
90 }
91 
xhci_pci_remove(struct udevice * dev)92 static int xhci_pci_remove(struct udevice *dev)
93 {
94 	struct xhci_pci_plat *plat = dev_get_plat(dev);
95 
96 	xhci_deregister(dev);
97 	if (reset_valid(&plat->reset))
98 		reset_free(&plat->reset);
99 
100 	return 0;
101 }
102 
103 static const struct udevice_id xhci_pci_ids[] = {
104 	{ .compatible = "xhci-pci" },
105 	{ }
106 };
107 
108 U_BOOT_DRIVER(xhci_pci) = {
109 	.name	= "xhci_pci",
110 	.id	= UCLASS_USB,
111 	.probe = xhci_pci_probe,
112 	.remove	= xhci_pci_remove,
113 	.of_match = xhci_pci_ids,
114 	.ops	= &xhci_usb_ops,
115 	.plat_auto	= sizeof(struct xhci_pci_plat),
116 	.priv_auto	= sizeof(struct xhci_ctrl),
117 	.flags	= DM_FLAG_OS_PREPARE | DM_FLAG_ALLOC_PRIV_DMA,
118 };
119 
120 static struct pci_device_id xhci_pci_supported[] = {
121 	{ PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_USB_XHCI, ~0) },
122 	{},
123 };
124 
125 U_BOOT_PCI_DEVICE(xhci_pci, xhci_pci_supported);
126