2 * Copyright 2015 Freescale Semiconductor, Inc.
4 * DWC3 controller driver
6 * Author: Ramneek Mehresh<ramneek.mehresh@freescale.com>
8 * SPDX-License-Identifier: GPL-2.0+
14 #include <generic-phy.h>
19 #include <linux/usb/dwc3.h>
20 #include <linux/usb/otg.h>
22 DECLARE_GLOBAL_DATA_PTR
;
24 struct xhci_dwc3_platdata
{
28 void dwc3_set_mode(struct dwc3
*dwc3_reg
, u32 mode
)
30 clrsetbits_le32(&dwc3_reg
->g_ctl
,
31 DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG
),
32 DWC3_GCTL_PRTCAPDIR(mode
));
35 static void dwc3_phy_reset(struct dwc3
*dwc3_reg
)
37 /* Assert USB3 PHY reset */
38 setbits_le32(&dwc3_reg
->g_usb3pipectl
[0], DWC3_GUSB3PIPECTL_PHYSOFTRST
);
40 /* Assert USB2 PHY reset */
41 setbits_le32(&dwc3_reg
->g_usb2phycfg
, DWC3_GUSB2PHYCFG_PHYSOFTRST
);
45 /* Clear USB3 PHY reset */
46 clrbits_le32(&dwc3_reg
->g_usb3pipectl
[0], DWC3_GUSB3PIPECTL_PHYSOFTRST
);
48 /* Clear USB2 PHY reset */
49 clrbits_le32(&dwc3_reg
->g_usb2phycfg
, DWC3_GUSB2PHYCFG_PHYSOFTRST
);
52 void dwc3_core_soft_reset(struct dwc3
*dwc3_reg
)
54 /* Before Resetting PHY, put Core in Reset */
55 setbits_le32(&dwc3_reg
->g_ctl
, DWC3_GCTL_CORESOFTRESET
);
57 /* reset USB3 phy - if required */
58 dwc3_phy_reset(dwc3_reg
);
62 /* After PHYs are stable we can take Core out of reset state */
63 clrbits_le32(&dwc3_reg
->g_ctl
, DWC3_GCTL_CORESOFTRESET
);
66 int dwc3_core_init(struct dwc3
*dwc3_reg
)
70 unsigned int dwc3_hwparams1
;
72 revision
= readl(&dwc3_reg
->g_snpsid
);
73 /* This should read as U3 followed by revision number */
74 if ((revision
& DWC3_GSNPSID_MASK
) != 0x55330000) {
75 puts("this is not a DesignWare USB3 DRD Core\n");
79 dwc3_core_soft_reset(dwc3_reg
);
81 dwc3_hwparams1
= readl(&dwc3_reg
->g_hwparams1
);
83 reg
= readl(&dwc3_reg
->g_ctl
);
84 reg
&= ~DWC3_GCTL_SCALEDOWN_MASK
;
85 reg
&= ~DWC3_GCTL_DISSCRAMBLE
;
86 switch (DWC3_GHWPARAMS1_EN_PWROPT(dwc3_hwparams1
)) {
87 case DWC3_GHWPARAMS1_EN_PWROPT_CLK
:
88 reg
&= ~DWC3_GCTL_DSBLCLKGTNG
;
91 debug("No power optimization available\n");
95 * WORKAROUND: DWC3 revisions <1.90a have a bug
96 * where the device can fail to connect at SuperSpeed
97 * and falls back to high-speed mode which causes
98 * the device to enter a Connect/Disconnect loop
100 if ((revision
& DWC3_REVISION_MASK
) < 0x190a)
101 reg
|= DWC3_GCTL_U2RSTECN
;
103 writel(reg
, &dwc3_reg
->g_ctl
);
108 void dwc3_set_fladj(struct dwc3
*dwc3_reg
, u32 val
)
110 setbits_le32(&dwc3_reg
->g_fladj
, GFLADJ_30MHZ_REG_SEL
|
115 static int xhci_dwc3_probe(struct udevice
*dev
)
117 struct xhci_dwc3_platdata
*plat
= dev_get_platdata(dev
);
118 struct xhci_hcor
*hcor
;
119 struct xhci_hccr
*hccr
;
120 struct dwc3
*dwc3_reg
;
121 enum usb_dr_mode dr_mode
;
124 hccr
= (struct xhci_hccr
*)((uintptr_t)dev_read_addr(dev
));
125 hcor
= (struct xhci_hcor
*)((uintptr_t)hccr
+
126 HC_LENGTH(xhci_readl(&(hccr
)->cr_capbase
)));
128 ret
= generic_phy_get_by_index(dev
, 0, &plat
->usb_phy
);
130 if (ret
!= -ENOENT
) {
131 pr_err("Failed to get USB PHY for %s\n", dev
->name
);
135 ret
= generic_phy_init(&plat
->usb_phy
);
137 pr_err("Can't init USB PHY for %s\n", dev
->name
);
142 dwc3_reg
= (struct dwc3
*)((char *)(hccr
) + DWC3_REG_OFFSET
);
144 dwc3_core_init(dwc3_reg
);
146 dr_mode
= usb_get_dr_mode(dev_of_offset(dev
));
147 if (dr_mode
== USB_DR_MODE_UNKNOWN
)
148 /* by default set dual role mode to HOST */
149 dr_mode
= USB_DR_MODE_HOST
;
151 dwc3_set_mode(dwc3_reg
, dr_mode
);
153 return xhci_register(dev
, hccr
, hcor
);
156 static int xhci_dwc3_remove(struct udevice
*dev
)
158 struct xhci_dwc3_platdata
*plat
= dev_get_platdata(dev
);
161 if (generic_phy_valid(&plat
->usb_phy
)) {
162 ret
= generic_phy_exit(&plat
->usb_phy
);
164 pr_err("Can't deinit USB PHY for %s\n", dev
->name
);
169 return xhci_deregister(dev
);
172 static const struct udevice_id xhci_dwc3_ids
[] = {
173 { .compatible
= "snps,dwc3" },
177 U_BOOT_DRIVER(xhci_dwc3
) = {
180 .of_match
= xhci_dwc3_ids
,
181 .probe
= xhci_dwc3_probe
,
182 .remove
= xhci_dwc3_remove
,
183 .ops
= &xhci_usb_ops
,
184 .priv_auto_alloc_size
= sizeof(struct xhci_ctrl
),
185 .platdata_auto_alloc_size
= sizeof(struct xhci_dwc3_platdata
),
186 .flags
= DM_FLAG_ALLOC_PRIV_DMA
,