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