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