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