xref: /rk3399_rockchip-uboot/drivers/usb/host/xhci-rcar.c (revision 1a4f6af8bfd44c8ae6e87a81ff125eed47042cc5)
1b491b498SJon Lin /*
2b491b498SJon Lin  * Copyright (C) 2017 Marek Vasut <marek.vasut@gmail.com>
3b491b498SJon Lin  *
4b491b498SJon Lin  * Renesas RCar USB HOST xHCI Controller
5b491b498SJon Lin  *
6b491b498SJon Lin  * SPDX-License-Identifier:	GPL-2.0+
7b491b498SJon Lin  */
8b491b498SJon Lin 
9b491b498SJon Lin #include <common.h>
10b491b498SJon Lin #include <clk.h>
11b491b498SJon Lin #include <dm.h>
12b491b498SJon Lin #include <fdtdec.h>
13b491b498SJon Lin #include <usb.h>
14b491b498SJon Lin #include <wait_bit.h>
15b491b498SJon Lin 
16*143fc13bSJean-Jacques Hiblot #include <usb/xhci.h>
17b491b498SJon Lin #include "xhci-rcar-r8a779x_usb3_v3.h"
18b491b498SJon Lin 
19b491b498SJon Lin /* Register Offset */
20b491b498SJon Lin #define RCAR_USB3_DL_CTRL	0x250	/* FW Download Control & Status */
21b491b498SJon Lin #define RCAR_USB3_FW_DATA0	0x258	/* FW Data0 */
22b491b498SJon Lin 
23b491b498SJon Lin /* Register Settings */
24b491b498SJon Lin /* FW Download Control & Status */
25b491b498SJon Lin #define RCAR_USB3_DL_CTRL_ENABLE	BIT(0)
26b491b498SJon Lin #define RCAR_USB3_DL_CTRL_FW_SUCCESS	BIT(4)
27b491b498SJon Lin #define RCAR_USB3_DL_CTRL_FW_SET_DATA0	BIT(8)
28b491b498SJon Lin 
29b491b498SJon Lin struct rcar_xhci_platdata {
30b491b498SJon Lin 	fdt_addr_t	hcd_base;
31b491b498SJon Lin 	struct clk	clk;
32b491b498SJon Lin };
33b491b498SJon Lin 
34b491b498SJon Lin /**
35b491b498SJon Lin  * Contains pointers to register base addresses
36b491b498SJon Lin  * for the usb controller.
37b491b498SJon Lin  */
38b491b498SJon Lin struct rcar_xhci {
39b491b498SJon Lin 	struct xhci_ctrl ctrl;	/* Needs to come first in this struct! */
40b491b498SJon Lin 	struct usb_platdata usb_plat;
41b491b498SJon Lin 	struct xhci_hccr *hcd;
42b491b498SJon Lin };
43b491b498SJon Lin 
xhci_rcar_download_fw(struct rcar_xhci * ctx,const u32 * fw_data,const size_t fw_array_size)44b491b498SJon Lin static int xhci_rcar_download_fw(struct rcar_xhci *ctx, const u32 *fw_data,
45b491b498SJon Lin 				 const size_t fw_array_size)
46b491b498SJon Lin {
47b491b498SJon Lin 	void __iomem *regs = (void __iomem *)ctx->hcd;
48b491b498SJon Lin 	int i, ret;
49b491b498SJon Lin 
50b491b498SJon Lin 	/* Download R-Car USB3.0 firmware */
51b491b498SJon Lin 	setbits_le32(regs + RCAR_USB3_DL_CTRL, RCAR_USB3_DL_CTRL_ENABLE);
52b491b498SJon Lin 
53b491b498SJon Lin 	for (i = 0; i < fw_array_size; i++) {
54b491b498SJon Lin 		writel(fw_data[i], regs + RCAR_USB3_FW_DATA0);
55b491b498SJon Lin 		setbits_le32(regs + RCAR_USB3_DL_CTRL,
56b491b498SJon Lin 			     RCAR_USB3_DL_CTRL_FW_SET_DATA0);
57b491b498SJon Lin 
58b27ae02dSMarek Vasut <<<<<<< HEAD
59b491b498SJon Lin 		ret = wait_for_bit_le32(regs + RCAR_USB3_DL_CTRL,
60b491b498SJon Lin 					RCAR_USB3_DL_CTRL_FW_SET_DATA0, false,
61b491b498SJon Lin 					10, false);
62b27ae02dSMarek Vasut =======
63b27ae02dSMarek Vasut 		ret = wait_for_bit("xhci-rcar", regs + RCAR_USB3_DL_CTRL,
64b27ae02dSMarek Vasut 				   RCAR_USB3_DL_CTRL_FW_SET_DATA0, false,
65b27ae02dSMarek Vasut 				   10, false);
66b27ae02dSMarek Vasut >>>>>>> e1cc60c... usb: xhci: Add Renesas R-Car xHCI driver
67b491b498SJon Lin 		if (ret)
68b491b498SJon Lin 			break;
69b491b498SJon Lin 	}
70b491b498SJon Lin 
71b491b498SJon Lin 	clrbits_le32(regs + RCAR_USB3_DL_CTRL, RCAR_USB3_DL_CTRL_ENABLE);
72b491b498SJon Lin 
73b27ae02dSMarek Vasut <<<<<<< HEAD
74b491b498SJon Lin 	ret = wait_for_bit_le32(regs + RCAR_USB3_DL_CTRL,
75b491b498SJon Lin 				RCAR_USB3_DL_CTRL_FW_SUCCESS, true,
76b491b498SJon Lin 				10, false);
77b27ae02dSMarek Vasut =======
78b27ae02dSMarek Vasut 	ret = wait_for_bit("xhci-rcar", regs + RCAR_USB3_DL_CTRL,
79b27ae02dSMarek Vasut 			   RCAR_USB3_DL_CTRL_FW_SUCCESS, true,
80b27ae02dSMarek Vasut 			   10, false);
81b27ae02dSMarek Vasut >>>>>>> e1cc60c... usb: xhci: Add Renesas R-Car xHCI driver
82b491b498SJon Lin 
83b491b498SJon Lin 	return ret;
84b491b498SJon Lin }
85b491b498SJon Lin 
xhci_rcar_probe(struct udevice * dev)86b491b498SJon Lin static int xhci_rcar_probe(struct udevice *dev)
87b491b498SJon Lin {
88b491b498SJon Lin 	struct rcar_xhci_platdata *plat = dev_get_platdata(dev);
89b491b498SJon Lin 	struct rcar_xhci *ctx = dev_get_priv(dev);
90b491b498SJon Lin 	struct xhci_hcor *hcor;
91b491b498SJon Lin 	int len, ret;
92b491b498SJon Lin 
93b491b498SJon Lin 	ret = clk_get_by_index(dev, 0, &plat->clk);
94b491b498SJon Lin 	if (ret < 0) {
95b491b498SJon Lin 		dev_err(dev, "Failed to get USB3 clock\n");
96b491b498SJon Lin 		return ret;
97b491b498SJon Lin 	}
98b491b498SJon Lin 
99b491b498SJon Lin 	ret = clk_enable(&plat->clk);
100b491b498SJon Lin 	if (ret) {
101b491b498SJon Lin 		dev_err(dev, "Failed to enable USB3 clock\n");
102b491b498SJon Lin 		goto err_clk;
103b491b498SJon Lin 	}
104b491b498SJon Lin 
105b491b498SJon Lin 	ctx->hcd = (struct xhci_hccr *)plat->hcd_base;
106b491b498SJon Lin 	len = HC_LENGTH(xhci_readl(&ctx->hcd->cr_capbase));
107b491b498SJon Lin 	hcor = (struct xhci_hcor *)((uintptr_t)ctx->hcd + len);
108b491b498SJon Lin 
109b491b498SJon Lin 	ret = xhci_rcar_download_fw(ctx, firmware_r8a779x_usb3_v3,
110b491b498SJon Lin 				    ARRAY_SIZE(firmware_r8a779x_usb3_v3));
111b491b498SJon Lin 	if (ret) {
112b491b498SJon Lin 		dev_err(dev, "Failed to download firmware\n");
113b491b498SJon Lin 		goto err_fw;
114b491b498SJon Lin 	}
115b491b498SJon Lin 
116b491b498SJon Lin 	ret = xhci_register(dev, ctx->hcd, hcor);
117b491b498SJon Lin 	if (ret) {
118b491b498SJon Lin 		dev_err(dev, "Failed to register xHCI\n");
119b491b498SJon Lin 		goto err_fw;
120b491b498SJon Lin 	}
121b491b498SJon Lin 
122b491b498SJon Lin 	return 0;
123b491b498SJon Lin 
124b491b498SJon Lin err_fw:
125b491b498SJon Lin 	clk_disable(&plat->clk);
126b491b498SJon Lin err_clk:
127b491b498SJon Lin 	clk_free(&plat->clk);
128b491b498SJon Lin 	return ret;
129b491b498SJon Lin }
130b491b498SJon Lin 
xhci_rcar_deregister(struct udevice * dev)131b491b498SJon Lin static int xhci_rcar_deregister(struct udevice *dev)
132b491b498SJon Lin {
1332e8806deSMatthias Blankertz 	int ret;
134b491b498SJon Lin 	struct rcar_xhci_platdata *plat = dev_get_platdata(dev);
135b491b498SJon Lin 
1362e8806deSMatthias Blankertz 	ret = xhci_deregister(dev);
1372e8806deSMatthias Blankertz 
138b491b498SJon Lin 	clk_disable(&plat->clk);
139b491b498SJon Lin 	clk_free(&plat->clk);
140b491b498SJon Lin 
1412e8806deSMatthias Blankertz 	return ret;
142b491b498SJon Lin }
143b491b498SJon Lin 
xhci_rcar_ofdata_to_platdata(struct udevice * dev)144b491b498SJon Lin static int xhci_rcar_ofdata_to_platdata(struct udevice *dev)
145b491b498SJon Lin {
146b491b498SJon Lin 	struct rcar_xhci_platdata *plat = dev_get_platdata(dev);
147b491b498SJon Lin 
148b491b498SJon Lin 	plat->hcd_base = devfdt_get_addr(dev);
149b491b498SJon Lin 	if (plat->hcd_base == FDT_ADDR_T_NONE) {
150b491b498SJon Lin 		debug("Can't get the XHCI register base address\n");
151b491b498SJon Lin 		return -ENXIO;
152b491b498SJon Lin 	}
153b491b498SJon Lin 
154b491b498SJon Lin 	return 0;
155b491b498SJon Lin }
156b491b498SJon Lin 
157b491b498SJon Lin static const struct udevice_id xhci_rcar_ids[] = {
158b491b498SJon Lin 	{ .compatible = "renesas,xhci-r8a7795" },
159b491b498SJon Lin 	{ .compatible = "renesas,xhci-r8a7796" },
160bf6dfe01SMarek Vasut 	{ .compatible = "renesas,xhci-r8a77965" },
161b491b498SJon Lin 	{ }
162b491b498SJon Lin };
163b491b498SJon Lin 
164b491b498SJon Lin U_BOOT_DRIVER(usb_xhci) = {
165b491b498SJon Lin 	.name		= "xhci_rcar",
166b491b498SJon Lin 	.id		= UCLASS_USB,
167b491b498SJon Lin 	.probe		= xhci_rcar_probe,
168b491b498SJon Lin 	.remove		= xhci_rcar_deregister,
169b491b498SJon Lin 	.ops		= &xhci_usb_ops,
170b491b498SJon Lin 	.of_match	= xhci_rcar_ids,
171b491b498SJon Lin 	.ofdata_to_platdata = xhci_rcar_ofdata_to_platdata,
172b491b498SJon Lin 	.platdata_auto_alloc_size = sizeof(struct rcar_xhci_platdata),
173b491b498SJon Lin 	.priv_auto_alloc_size = sizeof(struct rcar_xhci),
174b491b498SJon Lin 	.flags		= DM_FLAG_ALLOC_PRIV_DMA,
175b491b498SJon Lin };
176