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