linux/drivers/usb/host/xhci-rcar.c
<<
>>
Prefs
   1/*
   2 * xHCI host controller driver for R-Car SoCs
   3 *
   4 * Copyright (C) 2014 Renesas Electronics Corporation
   5 *
   6 * This program is free software; you can redistribute it and/or
   7 * modify it under the terms of the GNU General Public License
   8 * version 2 as published by the Free Software Foundation.
   9 */
  10
  11#include <linux/firmware.h>
  12#include <linux/module.h>
  13#include <linux/platform_device.h>
  14#include <linux/usb/phy.h>
  15
  16#include "xhci.h"
  17#include "xhci-rcar.h"
  18
  19#define FIRMWARE_NAME           "r8a779x_usb3_v1.dlmem"
  20MODULE_FIRMWARE(FIRMWARE_NAME);
  21
  22/*** Register Offset ***/
  23#define RCAR_USB3_INT_ENA       0x224   /* Interrupt Enable */
  24#define RCAR_USB3_DL_CTRL       0x250   /* FW Download Control & Status */
  25#define RCAR_USB3_FW_DATA0      0x258   /* FW Data0 */
  26
  27#define RCAR_USB3_LCLK          0xa44   /* LCLK Select */
  28#define RCAR_USB3_CONF1         0xa48   /* USB3.0 Configuration1 */
  29#define RCAR_USB3_CONF2         0xa5c   /* USB3.0 Configuration2 */
  30#define RCAR_USB3_CONF3         0xaa8   /* USB3.0 Configuration3 */
  31#define RCAR_USB3_RX_POL        0xab0   /* USB3.0 RX Polarity */
  32#define RCAR_USB3_TX_POL        0xab8   /* USB3.0 TX Polarity */
  33
  34/*** Register Settings ***/
  35/* Interrupt Enable */
  36#define RCAR_USB3_INT_XHC_ENA   0x00000001
  37#define RCAR_USB3_INT_PME_ENA   0x00000002
  38#define RCAR_USB3_INT_HSE_ENA   0x00000004
  39#define RCAR_USB3_INT_ENA_VAL   (RCAR_USB3_INT_XHC_ENA | \
  40                                RCAR_USB3_INT_PME_ENA | RCAR_USB3_INT_HSE_ENA)
  41
  42/* FW Download Control & Status */
  43#define RCAR_USB3_DL_CTRL_ENABLE        0x00000001
  44#define RCAR_USB3_DL_CTRL_FW_SUCCESS    0x00000010
  45#define RCAR_USB3_DL_CTRL_FW_SET_DATA0  0x00000100
  46
  47/* LCLK Select */
  48#define RCAR_USB3_LCLK_ENA_VAL  0x01030001
  49
  50/* USB3.0 Configuration */
  51#define RCAR_USB3_CONF1_VAL     0x00030204
  52#define RCAR_USB3_CONF2_VAL     0x00030300
  53#define RCAR_USB3_CONF3_VAL     0x13802007
  54
  55/* USB3.0 Polarity */
  56#define RCAR_USB3_RX_POL_VAL    BIT(21)
  57#define RCAR_USB3_TX_POL_VAL    BIT(4)
  58
  59void xhci_rcar_start(struct usb_hcd *hcd)
  60{
  61        u32 temp;
  62
  63        if (hcd->regs != NULL) {
  64                /* Interrupt Enable */
  65                temp = readl(hcd->regs + RCAR_USB3_INT_ENA);
  66                temp |= RCAR_USB3_INT_ENA_VAL;
  67                writel(temp, hcd->regs + RCAR_USB3_INT_ENA);
  68                /* LCLK Select */
  69                writel(RCAR_USB3_LCLK_ENA_VAL, hcd->regs + RCAR_USB3_LCLK);
  70                /* USB3.0 Configuration */
  71                writel(RCAR_USB3_CONF1_VAL, hcd->regs + RCAR_USB3_CONF1);
  72                writel(RCAR_USB3_CONF2_VAL, hcd->regs + RCAR_USB3_CONF2);
  73                writel(RCAR_USB3_CONF3_VAL, hcd->regs + RCAR_USB3_CONF3);
  74                /* USB3.0 Polarity */
  75                writel(RCAR_USB3_RX_POL_VAL, hcd->regs + RCAR_USB3_RX_POL);
  76                writel(RCAR_USB3_TX_POL_VAL, hcd->regs + RCAR_USB3_TX_POL);
  77        }
  78}
  79
  80static int xhci_rcar_download_firmware(struct device *dev, void __iomem *regs)
  81{
  82        const struct firmware *fw;
  83        int retval, index, j, time;
  84        int timeout = 10000;
  85        u32 data, val, temp;
  86
  87        /* request R-Car USB3.0 firmware */
  88        retval = request_firmware(&fw, FIRMWARE_NAME, dev);
  89        if (retval)
  90                return retval;
  91
  92        /* download R-Car USB3.0 firmware */
  93        temp = readl(regs + RCAR_USB3_DL_CTRL);
  94        temp |= RCAR_USB3_DL_CTRL_ENABLE;
  95        writel(temp, regs + RCAR_USB3_DL_CTRL);
  96
  97        for (index = 0; index < fw->size; index += 4) {
  98                /* to avoid reading beyond the end of the buffer */
  99                for (data = 0, j = 3; j >= 0; j--) {
 100                        if ((j + index) < fw->size)
 101                                data |= fw->data[index + j] << (8 * j);
 102                }
 103                writel(data, regs + RCAR_USB3_FW_DATA0);
 104                temp = readl(regs + RCAR_USB3_DL_CTRL);
 105                temp |= RCAR_USB3_DL_CTRL_FW_SET_DATA0;
 106                writel(temp, regs + RCAR_USB3_DL_CTRL);
 107
 108                for (time = 0; time < timeout; time++) {
 109                        val = readl(regs + RCAR_USB3_DL_CTRL);
 110                        if ((val & RCAR_USB3_DL_CTRL_FW_SET_DATA0) == 0)
 111                                break;
 112                        udelay(1);
 113                }
 114                if (time == timeout) {
 115                        retval = -ETIMEDOUT;
 116                        break;
 117                }
 118        }
 119
 120        temp = readl(regs + RCAR_USB3_DL_CTRL);
 121        temp &= ~RCAR_USB3_DL_CTRL_ENABLE;
 122        writel(temp, regs + RCAR_USB3_DL_CTRL);
 123
 124        for (time = 0; time < timeout; time++) {
 125                val = readl(regs + RCAR_USB3_DL_CTRL);
 126                if (val & RCAR_USB3_DL_CTRL_FW_SUCCESS) {
 127                        retval = 0;
 128                        break;
 129                }
 130                udelay(1);
 131        }
 132        if (time == timeout)
 133                retval = -ETIMEDOUT;
 134
 135        release_firmware(fw);
 136
 137        return retval;
 138}
 139
 140/* This function needs to initialize a "phy" of usb before */
 141int xhci_rcar_init_quirk(struct usb_hcd *hcd)
 142{
 143        /* If hcd->regs is NULL, we don't just call the following function */
 144        if (!hcd->regs)
 145                return 0;
 146
 147        return xhci_rcar_download_firmware(hcd->self.controller, hcd->regs);
 148}
 149