blob: 38c5928faed502d66c25babd171c35178b278038 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Marek Vasut24257272017-10-15 15:01:29 +02002/*
3 * Copyright (C) 2017 Marek Vasut <marek.vasut@gmail.com>
4 *
5 * Renesas RCar USB HOST xHCI Controller
Marek Vasut24257272017-10-15 15:01:29 +02006 */
7
Marek Vasut24257272017-10-15 15:01:29 +02008#include <clk.h>
9#include <dm.h>
10#include <fdtdec.h>
Simon Glass0f2af882020-05-10 11:40:05 -060011#include <log.h>
Simon Glass9bc15642020-02-03 07:36:16 -070012#include <malloc.h>
Marek Vasut24257272017-10-15 15:01:29 +020013#include <usb.h>
14#include <wait_bit.h>
Simon Glass9bc15642020-02-03 07:36:16 -070015#include <dm/device_compat.h>
Simon Glass4dcacfc2020-05-10 11:40:13 -060016#include <linux/bitops.h>
Marek Vasut24257272017-10-15 15:01:29 +020017
Jean-Jacques Hiblotad4142b2019-09-11 11:33:46 +020018#include <usb/xhci.h>
Marek Vasut24257272017-10-15 15:01:29 +020019#include "xhci-rcar-r8a779x_usb3_v3.h"
20
21/* Register Offset */
22#define RCAR_USB3_DL_CTRL 0x250 /* FW Download Control & Status */
23#define RCAR_USB3_FW_DATA0 0x258 /* FW Data0 */
24
25/* Register Settings */
26/* FW Download Control & Status */
27#define RCAR_USB3_DL_CTRL_ENABLE BIT(0)
28#define RCAR_USB3_DL_CTRL_FW_SUCCESS BIT(4)
29#define RCAR_USB3_DL_CTRL_FW_SET_DATA0 BIT(8)
30
Simon Glassb75b15b2020-12-03 16:55:23 -070031struct rcar_xhci_plat {
Marek Vasut24257272017-10-15 15:01:29 +020032 fdt_addr_t hcd_base;
33 struct clk clk;
34};
35
36/**
37 * Contains pointers to register base addresses
38 * for the usb controller.
39 */
40struct rcar_xhci {
41 struct xhci_ctrl ctrl; /* Needs to come first in this struct! */
Simon Glassb75b15b2020-12-03 16:55:23 -070042 struct usb_plat usb_plat;
Marek Vasut24257272017-10-15 15:01:29 +020043 struct xhci_hccr *hcd;
44};
45
46static int xhci_rcar_download_fw(struct rcar_xhci *ctx, const u32 *fw_data,
47 const size_t fw_array_size)
48{
49 void __iomem *regs = (void __iomem *)ctx->hcd;
50 int i, ret;
51
52 /* Download R-Car USB3.0 firmware */
53 setbits_le32(regs + RCAR_USB3_DL_CTRL, RCAR_USB3_DL_CTRL_ENABLE);
54
55 for (i = 0; i < fw_array_size; i++) {
56 writel(fw_data[i], regs + RCAR_USB3_FW_DATA0);
57 setbits_le32(regs + RCAR_USB3_DL_CTRL,
58 RCAR_USB3_DL_CTRL_FW_SET_DATA0);
59
Álvaro Fernández Rojas918de032018-01-23 17:14:55 +010060 ret = wait_for_bit_le32(regs + RCAR_USB3_DL_CTRL,
61 RCAR_USB3_DL_CTRL_FW_SET_DATA0, false,
62 10, false);
Marek Vasut24257272017-10-15 15:01:29 +020063 if (ret)
64 break;
65 }
66
67 clrbits_le32(regs + RCAR_USB3_DL_CTRL, RCAR_USB3_DL_CTRL_ENABLE);
68
Álvaro Fernández Rojas918de032018-01-23 17:14:55 +010069 ret = wait_for_bit_le32(regs + RCAR_USB3_DL_CTRL,
70 RCAR_USB3_DL_CTRL_FW_SUCCESS, true,
71 10, false);
Marek Vasut24257272017-10-15 15:01:29 +020072
73 return ret;
74}
75
76static int xhci_rcar_probe(struct udevice *dev)
77{
Simon Glassb75b15b2020-12-03 16:55:23 -070078 struct rcar_xhci_plat *plat = dev_get_plat(dev);
Marek Vasut24257272017-10-15 15:01:29 +020079 struct rcar_xhci *ctx = dev_get_priv(dev);
80 struct xhci_hcor *hcor;
81 int len, ret;
82
83 ret = clk_get_by_index(dev, 0, &plat->clk);
84 if (ret < 0) {
85 dev_err(dev, "Failed to get USB3 clock\n");
86 return ret;
87 }
88
89 ret = clk_enable(&plat->clk);
90 if (ret) {
91 dev_err(dev, "Failed to enable USB3 clock\n");
Sean Andersond318eb32023-12-16 14:38:42 -050092 return ret;
Marek Vasut24257272017-10-15 15:01:29 +020093 }
94
95 ctx->hcd = (struct xhci_hccr *)plat->hcd_base;
96 len = HC_LENGTH(xhci_readl(&ctx->hcd->cr_capbase));
97 hcor = (struct xhci_hcor *)((uintptr_t)ctx->hcd + len);
98
99 ret = xhci_rcar_download_fw(ctx, firmware_r8a779x_usb3_v3,
100 ARRAY_SIZE(firmware_r8a779x_usb3_v3));
101 if (ret) {
102 dev_err(dev, "Failed to download firmware\n");
103 goto err_fw;
104 }
105
106 ret = xhci_register(dev, ctx->hcd, hcor);
107 if (ret) {
108 dev_err(dev, "Failed to register xHCI\n");
109 goto err_fw;
110 }
111
112 return 0;
113
114err_fw:
115 clk_disable(&plat->clk);
Marek Vasut24257272017-10-15 15:01:29 +0200116 return ret;
117}
118
119static int xhci_rcar_deregister(struct udevice *dev)
120{
Matthias Blankertza06ad952018-05-22 15:24:48 +0200121 int ret;
Simon Glassb75b15b2020-12-03 16:55:23 -0700122 struct rcar_xhci_plat *plat = dev_get_plat(dev);
Marek Vasut24257272017-10-15 15:01:29 +0200123
Matthias Blankertza06ad952018-05-22 15:24:48 +0200124 ret = xhci_deregister(dev);
125
Marek Vasut24257272017-10-15 15:01:29 +0200126 clk_disable(&plat->clk);
Marek Vasut24257272017-10-15 15:01:29 +0200127
Matthias Blankertza06ad952018-05-22 15:24:48 +0200128 return ret;
Marek Vasut24257272017-10-15 15:01:29 +0200129}
130
Simon Glassaad29ae2020-12-03 16:55:21 -0700131static int xhci_rcar_of_to_plat(struct udevice *dev)
Marek Vasut24257272017-10-15 15:01:29 +0200132{
Simon Glassb75b15b2020-12-03 16:55:23 -0700133 struct rcar_xhci_plat *plat = dev_get_plat(dev);
Marek Vasut24257272017-10-15 15:01:29 +0200134
Masahiro Yamadaa89b4de2020-07-17 14:36:48 +0900135 plat->hcd_base = dev_read_addr(dev);
Marek Vasut24257272017-10-15 15:01:29 +0200136 if (plat->hcd_base == FDT_ADDR_T_NONE) {
137 debug("Can't get the XHCI register base address\n");
138 return -ENXIO;
139 }
140
141 return 0;
142}
143
144static const struct udevice_id xhci_rcar_ids[] = {
Lad Prabhakar7f2d86d2020-09-21 18:24:09 +0100145 { .compatible = "renesas,rcar-gen3-xhci" },
Marek Vasut24257272017-10-15 15:01:29 +0200146 { .compatible = "renesas,xhci-r8a7795" },
147 { .compatible = "renesas,xhci-r8a7796" },
Marek Vasutf7da2c72018-02-26 10:35:15 +0100148 { .compatible = "renesas,xhci-r8a77965" },
Marek Vasut24257272017-10-15 15:01:29 +0200149 { }
150};
151
152U_BOOT_DRIVER(usb_xhci) = {
153 .name = "xhci_rcar",
154 .id = UCLASS_USB,
155 .probe = xhci_rcar_probe,
156 .remove = xhci_rcar_deregister,
157 .ops = &xhci_usb_ops,
158 .of_match = xhci_rcar_ids,
Simon Glassaad29ae2020-12-03 16:55:21 -0700159 .of_to_plat = xhci_rcar_of_to_plat,
Simon Glassb75b15b2020-12-03 16:55:23 -0700160 .plat_auto = sizeof(struct rcar_xhci_plat),
Simon Glass8a2b47f2020-12-03 16:55:17 -0700161 .priv_auto = sizeof(struct rcar_xhci),
Marek Vasut24257272017-10-15 15:01:29 +0200162 .flags = DM_FLAG_ALLOC_PRIV_DMA,
163};