1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * Copyright (C) 2019 Broadcom.
4 */
5
6 #include <common.h>
7 #include <dm.h>
8 #include <fdtdec.h>
9 #include <usb.h>
10 #include <asm/io.h>
11 #include <usb/xhci.h>
12
13 #define DRD2U3H_XHC_REGS_AXIWRA 0xC08
14 #define DRD2U3H_XHC_REGS_AXIRDA 0xC0C
15
16 #define USBAXI_CACHE 0xF
17 #define USBAXI_PROT 0x8
18 #define USBAXI_SA_MASK 0x1FF
19 #define USBAXI_UA_MASK (0x1FF << 16)
20 #define USBAXI_SA_VAL ((USBAXI_CACHE << 4) | USBAXI_PROT)
21 #define USBAXI_UA_VAL (USBAXI_SA_VAL << 16)
22 #define USBAXI_SA_UA_MASK (USBAXI_UA_MASK | USBAXI_SA_MASK)
23 #define USBAXI_SA_UA_VAL (USBAXI_UA_VAL | USBAXI_SA_VAL)
24
25 struct brcm_xhci_plat {
26 unsigned int arcache;
27 unsigned int awcache;
28 void __iomem *hc_base;
29 };
30
xhci_brcm_probe(struct udevice * dev)31 static int xhci_brcm_probe(struct udevice *dev)
32 {
33 struct brcm_xhci_plat *plat = dev_get_plat(dev);
34 struct xhci_hcor *hcor;
35 struct xhci_hccr *hcd;
36 int len, ret = 0;
37
38 if (!plat) {
39 dev_err(dev, "Can't get xHCI Plat data\n");
40 return -ENOMEM;
41 }
42
43 hcd = dev_read_addr_ptr(dev);
44 if (!hcd) {
45 dev_err(dev, "Can't get the xHCI register base address\n");
46 return -ENXIO;
47 }
48
49 plat->hc_base = hcd;
50 len = HC_LENGTH(xhci_readl(&hcd->cr_capbase));
51 hcor = (struct xhci_hcor *)(plat->hc_base + len);
52
53 /* Save the default values of AXI read and write attributes */
54 plat->awcache = readl(plat->hc_base + DRD2U3H_XHC_REGS_AXIWRA);
55 plat->arcache = readl(plat->hc_base + DRD2U3H_XHC_REGS_AXIRDA);
56
57 /* Enable AXI write attributes */
58 clrsetbits_le32(plat->hc_base + DRD2U3H_XHC_REGS_AXIWRA,
59 USBAXI_SA_UA_MASK, USBAXI_SA_UA_VAL);
60
61 /* Enable AXI read attributes */
62 clrsetbits_le32(plat->hc_base + DRD2U3H_XHC_REGS_AXIRDA,
63 USBAXI_SA_UA_MASK, USBAXI_SA_UA_VAL);
64
65 ret = xhci_register(dev, hcd, hcor);
66 if (ret)
67 dev_err(dev, "Failed to register xHCI\n");
68
69 return ret;
70 }
71
xhci_brcm_deregister(struct udevice * dev)72 static int xhci_brcm_deregister(struct udevice *dev)
73 {
74 struct brcm_xhci_plat *plat = dev_get_plat(dev);
75
76 /* Restore the default values for AXI read and write attributes */
77 writel(plat->awcache, plat->hc_base + DRD2U3H_XHC_REGS_AXIWRA);
78 writel(plat->arcache, plat->hc_base + DRD2U3H_XHC_REGS_AXIRDA);
79
80 return xhci_deregister(dev);
81 }
82
83 static const struct udevice_id xhci_brcm_ids[] = {
84 { .compatible = "brcm,generic-xhci" },
85 { }
86 };
87
88 U_BOOT_DRIVER(usb_xhci) = {
89 .name = "xhci_brcm",
90 .id = UCLASS_USB,
91 .probe = xhci_brcm_probe,
92 .remove = xhci_brcm_deregister,
93 .ops = &xhci_usb_ops,
94 .of_match = xhci_brcm_ids,
95 .plat_auto = sizeof(struct brcm_xhci_plat),
96 .priv_auto = sizeof(struct xhci_ctrl),
97 .flags = DM_FLAG_ALLOC_PRIV_DMA,
98 };
99