Merge branch 'master' of git://git.denx.de/u-boot-spi
[platform/kernel/u-boot.git] / drivers / usb / host / dwc2.c
index 138646e..a62a2f8 100644 (file)
@@ -1,8 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  * Copyright (C) 2012 Oleksandr Tymoshenko <gonzo@freebsd.org>
  * Copyright (C) 2014 Marek Vasut <marex@denx.de>
- *
- * SPDX-License-Identifier:     GPL-2.0+
  */
 
 #include <common.h>
 #include <wait_bit.h>
 #include <asm/io.h>
 #include <power/regulator.h>
+#include <reset.h>
 
 #include "dwc2.h"
 
-DECLARE_GLOBAL_DATA_PTR;
-
 /* Use only HC channel 0. */
 #define DWC2_HC_CHANNEL                        0
 
@@ -31,7 +29,7 @@ DECLARE_GLOBAL_DATA_PTR;
 #define MAX_ENDPOINT                   16
 
 struct dwc2_priv {
-#ifdef CONFIG_DM_USB
+#if CONFIG_IS_ENABLED(DM_USB)
        uint8_t aligned_buffer[DWC2_DATA_BUF_SIZE] __aligned(ARCH_DMA_MINALIGN);
        uint8_t status_buffer[DWC2_STATUS_BUF_SIZE] __aligned(ARCH_DMA_MINALIGN);
 #ifdef CONFIG_DM_REGULATOR
@@ -52,9 +50,11 @@ struct dwc2_priv {
         */
        bool hnp_srp_disable;
        bool oc_disable;
+
+       struct reset_ctl_bulk   resets;
 };
 
-#ifndef CONFIG_DM_USB
+#if !CONFIG_IS_ENABLED(DM_USB)
 /* We need cacheline-aligned buffers for DMA transfers and dcache support */
 DEFINE_ALIGN_BUFFER(uint8_t, aligned_buffer_addr, DWC2_DATA_BUF_SIZE,
                ARCH_DMA_MINALIGN);
@@ -114,7 +114,7 @@ static void dwc_otg_flush_tx_fifo(struct dwc2_core_regs *regs, const int num)
        ret = wait_for_bit_le32(&regs->grstctl, DWC2_GRSTCTL_TXFFLSH,
                                false, 1000, false);
        if (ret)
-               printf("%s: Timeout!\n", __func__);
+               dev_info(dev, "%s: Timeout!\n", __func__);
 
        /* Wait for 3 PHY Clocks */
        udelay(1);
@@ -133,7 +133,7 @@ static void dwc_otg_flush_rx_fifo(struct dwc2_core_regs *regs)
        ret = wait_for_bit_le32(&regs->grstctl, DWC2_GRSTCTL_RXFFLSH,
                                false, 1000, false);
        if (ret)
-               printf("%s: Timeout!\n", __func__);
+               dev_info(dev, "%s: Timeout!\n", __func__);
 
        /* Wait for 3 PHY Clocks */
        udelay(1);
@@ -151,14 +151,14 @@ static void dwc_otg_core_reset(struct dwc2_core_regs *regs)
        ret = wait_for_bit_le32(&regs->grstctl, DWC2_GRSTCTL_AHBIDLE,
                                true, 1000, false);
        if (ret)
-               printf("%s: Timeout!\n", __func__);
+               dev_info(dev, "%s: Timeout!\n", __func__);
 
        /* Core Soft Reset */
        writel(DWC2_GRSTCTL_CSFTRST, &regs->grstctl);
        ret = wait_for_bit_le32(&regs->grstctl, DWC2_GRSTCTL_CSFTRST,
                                false, 1000, false);
        if (ret)
-               printf("%s: Timeout!\n", __func__);
+               dev_info(dev, "%s: Timeout!\n", __func__);
 
        /*
         * Wait for core to come out of reset.
@@ -168,7 +168,7 @@ static void dwc_otg_core_reset(struct dwc2_core_regs *regs)
        mdelay(100);
 }
 
-#if defined(CONFIG_DM_USB) && defined(CONFIG_DM_REGULATOR)
+#if CONFIG_IS_ENABLED(DM_USB) && defined(CONFIG_DM_REGULATOR)
 static int dwc_vbus_supply_init(struct udevice *dev)
 {
        struct dwc2_priv *priv = dev_get_priv(dev);
@@ -183,7 +183,7 @@ static int dwc_vbus_supply_init(struct udevice *dev)
 
        ret = regulator_set_enable(priv->vbus_supply, true);
        if (ret) {
-               pr_err("Error enabling vbus supply\n");
+               dev_err(dev, "Error enabling vbus supply\n");
                return ret;
        }
 
@@ -211,7 +211,7 @@ static int dwc_vbus_supply_init(struct udevice *dev)
        return 0;
 }
 
-#if defined(CONFIG_DM_USB)
+#if CONFIG_IS_ENABLED(DM_USB)
 static int dwc_vbus_supply_exit(struct udevice *dev)
 {
        return 0;
@@ -297,7 +297,7 @@ static void dwc_otg_core_host_init(struct udevice *dev,
                ret = wait_for_bit_le32(&regs->hc_regs[i].hcchar,
                                        DWC2_HCCHAR_CHEN, false, 1000, false);
                if (ret)
-                       printf("%s: Timeout!\n", __func__);
+                       dev_info("%s: Timeout!\n", __func__);
        }
 
        /* Turn on the vbus power. */
@@ -811,7 +811,7 @@ int wait_for_chhltd(struct dwc2_hc_regs *hc_regs, uint32_t *sub, u8 *toggle)
        uint32_t hcint, hctsiz;
 
        ret = wait_for_bit_le32(&hc_regs->hcint, DWC2_HCINT_CHHLTD, true,
-                               1000, false);
+                               2000, false);
        if (ret)
                return ret;
 
@@ -1118,7 +1118,7 @@ int _submit_int_msg(struct dwc2_priv *priv, struct usb_device *dev,
        timeout = get_timer(0) + USB_TIMEOUT_MS(pipe);
        for (;;) {
                if (get_timer(0) > timeout) {
-                       printf("Timeout poll on interrupt endpoint\n");
+                       dev_err(dev, "Timeout poll on interrupt endpoint\n");
                        return -ETIMEDOUT;
                }
                ret = _submit_bulk_msg(priv, dev, pipe, buffer, len);
@@ -1127,18 +1127,52 @@ int _submit_int_msg(struct dwc2_priv *priv, struct usb_device *dev,
        }
 }
 
+static int dwc2_reset(struct udevice *dev)
+{
+       int ret;
+       struct dwc2_priv *priv = dev_get_priv(dev);
+
+       ret = reset_get_bulk(dev, &priv->resets);
+       if (ret) {
+               dev_warn(dev, "Can't get reset: %d\n", ret);
+               /* Return 0 if error due to !CONFIG_DM_RESET and reset
+                * DT property is not present.
+                */
+               if (ret == -ENOENT || ret == -ENOTSUPP)
+                       return 0;
+               else
+                       return ret;
+       }
+
+       ret = reset_deassert_bulk(&priv->resets);
+       if (ret) {
+               reset_release_bulk(&priv->resets);
+               dev_err(dev, "Failed to reset: %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
 static int dwc2_init_common(struct udevice *dev, struct dwc2_priv *priv)
 {
        struct dwc2_core_regs *regs = priv->regs;
        uint32_t snpsid;
        int i, j;
+       int ret;
+
+       ret = dwc2_reset(dev);
+       if (ret)
+               return ret;
 
        snpsid = readl(&regs->gsnpsid);
-       printf("Core Release: %x.%03x\n", snpsid >> 12 & 0xf, snpsid & 0xfff);
+       dev_info(dev, "Core Release: %x.%03x\n",
+                snpsid >> 12 & 0xf, snpsid & 0xfff);
 
        if ((snpsid & DWC2_SNPSID_DEVID_MASK) != DWC2_SNPSID_DEVID_VER_2xx &&
            (snpsid & DWC2_SNPSID_DEVID_MASK) != DWC2_SNPSID_DEVID_VER_3xx) {
-               printf("SNPSID invalid (not DWC2 OTG device): %08x\n", snpsid);
+               dev_info(dev, "SNPSID invalid (not DWC2 OTG device): %08x\n",
+                        snpsid);
                return -ENODEV;
        }
 
@@ -1188,7 +1222,7 @@ static void dwc2_uninit_common(struct dwc2_core_regs *regs)
                        DWC2_HPRT0_PRTRST);
 }
 
-#ifndef CONFIG_DM_USB
+#if !CONFIG_IS_ENABLED(DM_USB)
 int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
                       int len, struct devrequest *setup)
 {
@@ -1233,7 +1267,7 @@ int usb_lowlevel_stop(int index)
 }
 #endif
 
-#ifdef CONFIG_DM_USB
+#if CONFIG_IS_ENABLED(DM_USB)
 static int dwc2_submit_control_msg(struct udevice *dev, struct usb_device *udev,
                                   unsigned long pipe, void *buffer, int length,
                                   struct devrequest *setup)
@@ -1304,6 +1338,8 @@ static int dwc2_usb_remove(struct udevice *dev)
 
        dwc2_uninit_common(priv->regs);
 
+       reset_release_bulk(&priv->resets);
+
        return 0;
 }
 
@@ -1315,6 +1351,7 @@ struct dm_usb_ops dwc2_usb_ops = {
 
 static const struct udevice_id dwc2_usb_ids[] = {
        { .compatible = "brcm,bcm2835-usb" },
+       { .compatible = "brcm,bcm2708-usb" },
        { .compatible = "snps,dwc2" },
        { }
 };