2 * Copyright (c) 2016 Rockchip, Inc.
3 * Authors: Daniel Meng <daniel.meng@rock-chips.com>
5 * SPDX-License-Identifier: GPL-2.0+
12 #include <linux/errno.h>
13 #include <linux/compat.h>
14 #include <linux/usb/dwc3.h>
15 #include <power/regulator.h>
19 DECLARE_GLOBAL_DATA_PTR
;
21 struct rockchip_xhci_platdata
{
24 struct udevice
*vbus_supply
;
28 * Contains pointers to register base addresses
29 * for the usb controller.
31 struct rockchip_xhci
{
32 struct usb_platdata usb_plat
;
33 struct xhci_ctrl ctrl
;
34 struct xhci_hccr
*hcd
;
35 struct dwc3
*dwc3_reg
;
38 static int xhci_usb_ofdata_to_platdata(struct udevice
*dev
)
40 struct rockchip_xhci_platdata
*plat
= dev_get_platdata(dev
);
41 struct udevice
*child
;
45 * Get the base address for XHCI controller from the device node
47 plat
->hcd_base
= dev_read_addr(dev
);
48 if (plat
->hcd_base
== FDT_ADDR_T_NONE
) {
49 pr_err("Can't get the XHCI register base address\n");
53 /* Get the base address for usbphy from the device node */
54 for (device_find_first_child(dev
, &child
); child
;
55 device_find_next_child(&child
)) {
56 if (!device_is_compatible(child
, "rockchip,rk3399-usb3-phy"))
58 plat
->phy_base
= devfdt_get_addr(child
);
62 if (plat
->phy_base
== FDT_ADDR_T_NONE
) {
63 pr_err("Can't get the usbphy register address\n");
68 ret
= device_get_supply_regulator(dev
, "vbus-supply",
71 debug("Can't get VBus regulator!\n");
77 * rockchip_dwc3_phy_setup() - Configure USB PHY Interface of DWC3 Core
78 * @dwc: Pointer to our controller context structure
79 * @dev: Pointer to ulcass device
81 static void rockchip_dwc3_phy_setup(struct dwc3
*dwc3_reg
,
87 /* Set dwc3 usb2 phy config */
88 reg
= readl(&dwc3_reg
->g_usb2phycfg
[0]);
90 if (dev_read_bool(dev
, "snps,dis-enblslpm-quirk"))
91 reg
&= ~DWC3_GUSB2PHYCFG_ENBLSLPM
;
93 utmi_bits
= dev_read_u32_default(dev
, "snps,phyif-utmi-bits", -1);
94 if (utmi_bits
== 16) {
95 reg
|= DWC3_GUSB2PHYCFG_PHYIF
;
96 reg
&= ~DWC3_GUSB2PHYCFG_USBTRDTIM_MASK
;
97 reg
|= DWC3_GUSB2PHYCFG_USBTRDTIM_16BIT
;
98 } else if (utmi_bits
== 8) {
99 reg
&= ~DWC3_GUSB2PHYCFG_PHYIF
;
100 reg
&= ~DWC3_GUSB2PHYCFG_USBTRDTIM_MASK
;
101 reg
|= DWC3_GUSB2PHYCFG_USBTRDTIM_8BIT
;
104 if (dev_read_bool(dev
, "snps,dis-u2-freeclk-exists-quirk"))
105 reg
&= ~DWC3_GUSB2PHYCFG_U2_FREECLK_EXISTS
;
107 if (dev_read_bool(dev
, "snps,dis-u2-susphy-quirk"))
108 reg
&= ~DWC3_GUSB2PHYCFG_SUSPHY
;
110 writel(reg
, &dwc3_reg
->g_usb2phycfg
[0]);
113 static int rockchip_xhci_core_init(struct rockchip_xhci
*rkxhci
,
118 ret
= dwc3_core_init(rkxhci
->dwc3_reg
);
120 pr_err("failed to initialize core\n");
124 rockchip_dwc3_phy_setup(rkxhci
->dwc3_reg
, dev
);
126 /* We are hard-coding DWC3 core to Host Mode */
127 dwc3_set_mode(rkxhci
->dwc3_reg
, DWC3_GCTL_PRTCAP_HOST
);
132 static int rockchip_xhci_core_exit(struct rockchip_xhci
*rkxhci
)
137 static int xhci_usb_probe(struct udevice
*dev
)
139 struct rockchip_xhci_platdata
*plat
= dev_get_platdata(dev
);
140 struct rockchip_xhci
*ctx
= dev_get_priv(dev
);
141 struct xhci_hcor
*hcor
;
144 ctx
->hcd
= (struct xhci_hccr
*)plat
->hcd_base
;
145 ctx
->dwc3_reg
= (struct dwc3
*)((char *)(ctx
->hcd
) + DWC3_REG_OFFSET
);
146 hcor
= (struct xhci_hcor
*)((uint64_t)ctx
->hcd
+
147 HC_LENGTH(xhci_readl(&ctx
->hcd
->cr_capbase
)));
149 if (plat
->vbus_supply
) {
150 ret
= regulator_set_enable(plat
->vbus_supply
, true);
152 pr_err("XHCI: failed to set VBus supply\n");
157 ret
= rockchip_xhci_core_init(ctx
, dev
);
159 pr_err("XHCI: failed to initialize controller\n");
163 return xhci_register(dev
, ctx
->hcd
, hcor
);
166 static int xhci_usb_remove(struct udevice
*dev
)
168 struct rockchip_xhci_platdata
*plat
= dev_get_platdata(dev
);
169 struct rockchip_xhci
*ctx
= dev_get_priv(dev
);
172 ret
= xhci_deregister(dev
);
175 ret
= rockchip_xhci_core_exit(ctx
);
179 if (plat
->vbus_supply
) {
180 ret
= regulator_set_enable(plat
->vbus_supply
, false);
182 pr_err("XHCI: failed to set VBus supply\n");
188 static const struct udevice_id xhci_usb_ids
[] = {
189 { .compatible
= "rockchip,rk3399-xhci" },
190 { .compatible
= "rockchip,rk3328-xhci" },
194 U_BOOT_DRIVER(usb_xhci
) = {
195 .name
= "xhci_rockchip",
197 .of_match
= xhci_usb_ids
,
198 .ofdata_to_platdata
= xhci_usb_ofdata_to_platdata
,
199 .probe
= xhci_usb_probe
,
200 .remove
= xhci_usb_remove
,
201 .ops
= &xhci_usb_ops
,
202 .bind
= dm_scan_fdt_dev
,
203 .platdata_auto_alloc_size
= sizeof(struct rockchip_xhci_platdata
),
204 .priv_auto_alloc_size
= sizeof(struct rockchip_xhci
),
205 .flags
= DM_FLAG_ALLOC_PRIV_DMA
,
208 static const struct udevice_id usb_phy_ids
[] = {
209 { .compatible
= "rockchip,rk3399-usb3-phy" },
210 { .compatible
= "rockchip,rk3328-usb3-phy" },
214 U_BOOT_DRIVER(usb_phy
) = {
215 .name
= "usb_phy_rockchip",
216 .of_match
= usb_phy_ids
,