aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/layerscape/patches-4.9/817-usb-support-layerscape.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/layerscape/patches-4.9/817-usb-support-layerscape.patch')
-rw-r--r--target/linux/layerscape/patches-4.9/817-usb-support-layerscape.patch1471
1 files changed, 1471 insertions, 0 deletions
diff --git a/target/linux/layerscape/patches-4.9/817-usb-support-layerscape.patch b/target/linux/layerscape/patches-4.9/817-usb-support-layerscape.patch
new file mode 100644
index 0000000000..ce29f5b17a
--- /dev/null
+++ b/target/linux/layerscape/patches-4.9/817-usb-support-layerscape.patch
@@ -0,0 +1,1471 @@
+From f8daa8e984213554008e73cd155530dceec5a109 Mon Sep 17 00:00:00 2001
+From: Yangbo Lu <yangbo.lu@nxp.com>
+Date: Wed, 27 Sep 2017 10:34:07 +0800
+Subject: [PATCH] usb: support layerscape
+
+This is a integrated patch for layerscape usb support.
+
+Signed-off-by: yinbo.zhu <yinbo.zhu@nxp.com>
+Signed-off-by: Ramneek Mehresh <ramneek.mehresh@freescale.com>
+Signed-off-by: Nikhil Badola <nikhil.badola@freescale.com>
+Signed-off-by: Changming Huang <jerry.huang@nxp.com>
+Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
+Signed-off-by: Rajesh Bhagat <rajesh.bhagat@freescale.com>
+Signed-off-by: Suresh Gupta <suresh.gupta@freescale.com>
+Signed-off-by: Zhao Chenhui <chenhui.zhao@freescale.com>
+Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
+---
+ drivers/usb/common/common.c | 50 ++++++
+ drivers/usb/core/hub.c | 8 +
+ drivers/usb/dwc3/core.c | 235 ++++++++++++++++++++++++++-
+ drivers/usb/dwc3/core.h | 46 +++++-
+ drivers/usb/dwc3/host.c | 15 +-
+ drivers/usb/gadget/udc/fsl_udc_core.c | 46 +++---
+ drivers/usb/gadget/udc/fsl_usb2_udc.h | 16 +-
+ drivers/usb/host/Kconfig | 2 +-
+ drivers/usb/host/ehci-fsl.c | 289 +++++++++++++++++++++++++++++++---
+ drivers/usb/host/ehci-fsl.h | 3 +
+ drivers/usb/host/ehci-hub.c | 2 +
+ drivers/usb/host/ehci.h | 5 +
+ drivers/usb/host/fsl-mph-dr-of.c | 12 ++
+ drivers/usb/phy/phy-fsl-usb.c | 59 +++++--
+ drivers/usb/phy/phy-fsl-usb.h | 8 +
+ include/linux/usb.h | 1 +
+ include/linux/usb/of.h | 2 +
+ 17 files changed, 726 insertions(+), 73 deletions(-)
+
+diff --git a/drivers/usb/common/common.c b/drivers/usb/common/common.c
+index 5ef8da6e..176dee01 100644
+--- a/drivers/usb/common/common.c
++++ b/drivers/usb/common/common.c
+@@ -105,6 +105,56 @@ static const char *const usb_dr_modes[] = {
+ [USB_DR_MODE_OTG] = "otg",
+ };
+
++/**
++ * of_usb_get_dr_mode - Get dual role mode for given device_node
++ * @np: Pointer to the given device_node
++ *
++ * The function gets phy interface string from property 'dr_mode',
++ * and returns the correspondig enum usb_dr_mode
++ */
++enum usb_dr_mode of_usb_get_dr_mode(struct device_node *np)
++{
++ const char *dr_mode;
++ int err, i;
++
++ err = of_property_read_string(np, "dr_mode", &dr_mode);
++ if (err < 0)
++ return USB_DR_MODE_UNKNOWN;
++
++ for (i = 0; i < ARRAY_SIZE(usb_dr_modes); i++)
++ if (!strcmp(dr_mode, usb_dr_modes[i]))
++ return i;
++
++ return USB_DR_MODE_UNKNOWN;
++}
++EXPORT_SYMBOL_GPL(of_usb_get_dr_mode);
++
++/**
++ * of_usb_get_maximum_speed - Get maximum requested speed for a given USB
++ * controller.
++ * @np: Pointer to the given device_node
++ *
++ * The function gets the maximum speed string from property "maximum-speed",
++ * and returns the corresponding enum usb_device_speed.
++ */
++enum usb_device_speed of_usb_get_maximum_speed(struct device_node *np)
++{
++ const char *maximum_speed;
++ int err;
++ int i;
++
++ err = of_property_read_string(np, "maximum-speed", &maximum_speed);
++ if (err < 0)
++ return USB_SPEED_UNKNOWN;
++
++ for (i = 0; i < ARRAY_SIZE(speed_names); i++)
++ if (strcmp(maximum_speed, speed_names[i]) == 0)
++ return i;
++
++ return USB_SPEED_UNKNOWN;
++}
++EXPORT_SYMBOL_GPL(of_usb_get_maximum_speed);
++
+ static enum usb_dr_mode usb_get_dr_mode_from_string(const char *str)
+ {
+ int ret;
+diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
+index 80d4ef31..e23acf03 100644
+--- a/drivers/usb/core/hub.c
++++ b/drivers/usb/core/hub.c
+@@ -4412,6 +4412,14 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
+ else
+ speed = usb_speed_string(udev->speed);
+
++#if !defined(CONFIG_FSL_USB2_OTG) && !defined(CONFIG_FSL_USB2_OTG_MODULE)
++if (udev->speed != USB_SPEED_SUPER)
++ dev_info(&udev->dev,
++ "%s %s USB device number %d using %s\n",
++ (udev->config) ? "reset" : "new", speed,
++ devnum, udev->bus->controller->driver->name);
++#endif
++
+ if (udev->speed < USB_SPEED_SUPER)
+ dev_info(&udev->dev,
+ "%s %s USB device number %d using %s\n",
+diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
+index fea44690..e34ef90a 100644
+--- a/drivers/usb/dwc3/core.c
++++ b/drivers/usb/dwc3/core.c
+@@ -58,6 +58,7 @@ static int dwc3_get_dr_mode(struct dwc3 *dwc)
+ enum usb_dr_mode mode;
+ struct device *dev = dwc->dev;
+ unsigned int hw_mode;
++ struct device_node *node = dev->of_node;
+
+ if (dwc->dr_mode == USB_DR_MODE_UNKNOWN)
+ dwc->dr_mode = USB_DR_MODE_OTG;
+@@ -83,6 +84,24 @@ static int dwc3_get_dr_mode(struct dwc3 *dwc)
+ mode = USB_DR_MODE_HOST;
+ break;
+ default:
++ /* Adjust Frame Length */
++ if (dwc->configure_gfladj)
++ dwc3_writel(dwc->regs, DWC3_GFLADJ, GFLADJ_30MHZ_REG_SEL |
++ GFLADJ_30MHZ(GFLADJ_30MHZ_DEFAULT));
++
++ /* Change burst beat and outstanding pipelined transfers requests */
++ dwc3_writel(dwc->regs, DWC3_GSBUSCFG0,
++ (dwc3_readl(dwc->regs, DWC3_GSBUSCFG0) & ~0xff) | 0xf);
++ dwc3_writel(dwc->regs, DWC3_GSBUSCFG1,
++ dwc3_readl(dwc->regs, DWC3_GSBUSCFG1) | 0xf00);
++
++ /* Enable Snooping */
++ if (node && of_dma_is_coherent(node)) {
++ dwc3_writel(dwc->regs, DWC3_GSBUSCFG0,
++ dwc3_readl(dwc->regs, DWC3_GSBUSCFG0) | 0x22220000);
++ dev_dbg(dev, "enabled snooping for usb\n");
++ }
++
+ if (IS_ENABLED(CONFIG_USB_DWC3_HOST))
+ mode = USB_DR_MODE_HOST;
+ else if (IS_ENABLED(CONFIG_USB_DWC3_GADGET))
+@@ -213,8 +232,9 @@ static void dwc3_frame_length_adjustment(struct dwc3 *dwc)
+
+ reg = dwc3_readl(dwc->regs, DWC3_GFLADJ);
+ dft = reg & DWC3_GFLADJ_30MHZ_MASK;
+- if (!dev_WARN_ONCE(dwc->dev, dft == dwc->fladj,
+- "request value same as default, ignoring\n")) {
++ if (dft == dwc->fladj) {
++ dev_warn(dwc->dev, "request value same as default, ignoring\n");
++ } else {
+ reg &= ~DWC3_GFLADJ_30MHZ_MASK;
+ reg |= DWC3_GFLADJ_30MHZ_SDBND_SEL | dwc->fladj;
+ dwc3_writel(dwc->regs, DWC3_GFLADJ, reg);
+@@ -579,6 +599,99 @@ static int dwc3_phy_setup(struct dwc3 *dwc)
+ return 0;
+ }
+
++/* set global soc bus configuration registers */
++static void dwc3_set_soc_bus_cfg(struct dwc3 *dwc)
++{
++ struct device *dev = dwc->dev;
++ u32 *vals;
++ u32 cfg;
++ int ntype;
++ int ret;
++ int i;
++
++ cfg = dwc3_readl(dwc->regs, DWC3_GSBUSCFG0);
++
++ /*
++ * Handle property "snps,incr-burst-type-adjustment".
++ * Get the number of value from this property:
++ * result <= 0, means this property is not supported.
++ * result = 1, means INCRx burst mode supported.
++ * result > 1, means undefined length burst mode supported.
++ */
++ ntype = device_property_read_u32_array(dev,
++ "snps,incr-burst-type-adjustment", NULL, 0);
++ if (ntype > 0) {
++ vals = kcalloc(ntype, sizeof(u32), GFP_KERNEL);
++ if (!vals) {
++ dev_err(dev, "Error to get memory\n");
++ return;
++ }
++ /* Get INCR burst type, and parse it */
++ ret = device_property_read_u32_array(dev,
++ "snps,incr-burst-type-adjustment", vals, ntype);
++ if (ret) {
++ dev_err(dev, "Error to get property\n");
++ return;
++ }
++ *(dwc->incrx_type + 1) = vals[0];
++ if (ntype > 1) {
++ *dwc->incrx_type = 1;
++ for (i = 1; i < ntype; i++) {
++ if (vals[i] > *(dwc->incrx_type + 1))
++ *(dwc->incrx_type + 1) = vals[i];
++ }
++ } else
++ *dwc->incrx_type = 0;
++
++ /* Enable Undefined Length INCR Burst and Enable INCRx Burst */
++ cfg &= ~DWC3_GSBUSCFG0_INCRBRST_MASK;
++ if (*dwc->incrx_type)
++ cfg |= DWC3_GSBUSCFG0_INCRBRSTENA;
++ switch (*(dwc->incrx_type + 1)) {
++ case 256:
++ cfg |= DWC3_GSBUSCFG0_INCR256BRSTENA;
++ break;
++ case 128:
++ cfg |= DWC3_GSBUSCFG0_INCR128BRSTENA;
++ break;
++ case 64:
++ cfg |= DWC3_GSBUSCFG0_INCR64BRSTENA;
++ break;
++ case 32:
++ cfg |= DWC3_GSBUSCFG0_INCR32BRSTENA;
++ break;
++ case 16:
++ cfg |= DWC3_GSBUSCFG0_INCR16BRSTENA;
++ break;
++ case 8:
++ cfg |= DWC3_GSBUSCFG0_INCR8BRSTENA;
++ break;
++ case 4:
++ cfg |= DWC3_GSBUSCFG0_INCR4BRSTENA;
++ break;
++ case 1:
++ break;
++ default:
++ dev_err(dev, "Invalid property\n");
++ break;
++ }
++ }
++
++ /* Handle usb snooping */
++ if (dwc->dma_snooping_quirk) {
++ cfg &= ~DWC3_GSBUSCFG0_SNP_MASK;
++ cfg |= (AXI3_CACHE_TYPE_SNP << DWC3_GSBUSCFG0_DATARD_SHIFT) |
++ (AXI3_CACHE_TYPE_SNP << DWC3_GSBUSCFG0_DESCRD_SHIFT) |
++ (AXI3_CACHE_TYPE_SNP << DWC3_GSBUSCFG0_DATAWR_SHIFT) |
++ (AXI3_CACHE_TYPE_SNP << DWC3_GSBUSCFG0_DESCWR_SHIFT);
++ }
++
++ dwc3_writel(dwc->regs, DWC3_GSBUSCFG0, cfg);
++
++}
++
++
++
+ static void dwc3_core_exit(struct dwc3 *dwc)
+ {
+ dwc3_event_buffers_cleanup(dwc);
+@@ -721,6 +834,8 @@ static int dwc3_core_init(struct dwc3 *dwc)
+ if (ret)
+ goto err1;
+
++ dwc3_set_soc_bus_cfg(dwc);
++
+ /* Adjust Frame Length */
+ dwc3_frame_length_adjustment(dwc);
+
+@@ -919,11 +1034,109 @@ static void dwc3_core_exit_mode(struct dwc3 *dwc)
+ }
+ }
+
++static void dwc3_get_properties(struct dwc3 *dwc)
++{
++ struct device *dev = dwc->dev;
++ struct device_node *node = dev->of_node;
++ u8 lpm_nyet_threshold;
++ u8 tx_de_emphasis;
++ u8 hird_threshold;
++
++ /* default to highest possible threshold */
++ lpm_nyet_threshold = 0xff;
++
++ /* default to -3.5dB de-emphasis */
++ tx_de_emphasis = 1;
++
++ /*
++ * default to assert utmi_sleep_n and use maximum allowed HIRD
++ * threshold value of 0b1100
++ */
++ hird_threshold = 12;
++
++ dwc->maximum_speed = usb_get_maximum_speed(dev);
++ dwc->dr_mode = usb_get_dr_mode(dev);
++ dwc->hsphy_mode = of_usb_get_phy_mode(dev->of_node);
++
++ dwc->sysdev_is_parent = device_property_read_bool(dev,
++ "linux,sysdev_is_parent");
++ if (dwc->sysdev_is_parent)
++ dwc->sysdev = dwc->dev->parent;
++ else
++ dwc->sysdev = dwc->dev;
++
++ dwc->has_lpm_erratum = device_property_read_bool(dev,
++ "snps,has-lpm-erratum");
++ device_property_read_u8(dev, "snps,lpm-nyet-threshold",
++ &lpm_nyet_threshold);
++ dwc->is_utmi_l1_suspend = device_property_read_bool(dev,
++ "snps,is-utmi-l1-suspend");
++ device_property_read_u8(dev, "snps,hird-threshold",
++ &hird_threshold);
++ dwc->usb3_lpm_capable = device_property_read_bool(dev,
++ "snps,usb3_lpm_capable");
++
++ dwc->needs_fifo_resize = of_property_read_bool(node, "tx-fifo-resize");
++
++ dwc->configure_gfladj =
++ of_property_read_bool(node, "configure-gfladj");
++ dwc->dr_mode = usb_get_dr_mode(dev);
++
++ dwc->disable_scramble_quirk = device_property_read_bool(dev,
++ "snps,disable_scramble_quirk");
++ dwc->u2exit_lfps_quirk = device_property_read_bool(dev,
++ "snps,u2exit_lfps_quirk");
++ dwc->u2ss_inp3_quirk = device_property_read_bool(dev,
++ "snps,u2ss_inp3_quirk");
++ dwc->req_p1p2p3_quirk = device_property_read_bool(dev,
++ "snps,req_p1p2p3_quirk");
++ dwc->del_p1p2p3_quirk = device_property_read_bool(dev,
++ "snps,del_p1p2p3_quirk");
++ dwc->del_phy_power_chg_quirk = device_property_read_bool(dev,
++ "snps,del_phy_power_chg_quirk");
++ dwc->lfps_filter_quirk = device_property_read_bool(dev,
++ "snps,lfps_filter_quirk");
++ dwc->rx_detect_poll_quirk = device_property_read_bool(dev,
++ "snps,rx_detect_poll_quirk");
++ dwc->dis_u3_susphy_quirk = device_property_read_bool(dev,
++ "snps,dis_u3_susphy_quirk");
++ dwc->dis_u2_susphy_quirk = device_property_read_bool(dev,
++ "snps,dis_u2_susphy_quirk");
++ dwc->dis_enblslpm_quirk = device_property_read_bool(dev,
++ "snps,dis_enblslpm_quirk");
++ dwc->dis_rxdet_inp3_quirk = device_property_read_bool(dev,
++ "snps,dis_rxdet_inp3_quirk");
++ dwc->dis_u2_freeclk_exists_quirk = device_property_read_bool(dev,
++ "snps,dis-u2-freeclk-exists-quirk");
++ dwc->dis_del_phy_power_chg_quirk = device_property_read_bool(dev,
++ "snps,dis-del-phy-power-chg-quirk");
++ dwc->dma_snooping_quirk = device_property_read_bool(dev,
++ "snps,dma-snooping");
++
++ dwc->tx_de_emphasis_quirk = device_property_read_bool(dev,
++ "snps,tx_de_emphasis_quirk");
++ device_property_read_u8(dev, "snps,tx_de_emphasis",
++ &tx_de_emphasis);
++ device_property_read_string(dev, "snps,hsphy_interface",
++ &dwc->hsphy_interface);
++ device_property_read_u32(dev, "snps,quirk-frame-length-adjustment",
++ &dwc->fladj);
++
++ dwc->lpm_nyet_threshold = lpm_nyet_threshold;
++ dwc->tx_de_emphasis = tx_de_emphasis;
++
++ dwc->hird_threshold = hird_threshold
++ | (dwc->is_utmi_l1_suspend << 4);
++
++ dwc->imod_interval = 0;
++}
++
+ #define DWC3_ALIGN_MASK (16 - 1)
+
+ static int dwc3_probe(struct platform_device *pdev)
+ {
+ struct device *dev = &pdev->dev;
++ struct device_node *node = dev->of_node;
+ struct resource *res;
+ struct dwc3 *dwc;
+ u8 lpm_nyet_threshold;
+@@ -955,6 +1168,11 @@ static int dwc3_probe(struct platform_device *pdev)
+ dwc->xhci_resources[0].flags = res->flags;
+ dwc->xhci_resources[0].name = res->name;
+
++ if (node) {
++ dwc->configure_gfladj =
++ of_property_read_bool(node, "configure-gfladj");
++ }
++
+ res->start += DWC3_GLOBALS_REGS_START;
+
+ /*
+@@ -997,6 +1215,12 @@ static int dwc3_probe(struct platform_device *pdev)
+ dwc->usb3_lpm_capable = device_property_read_bool(dev,
+ "snps,usb3_lpm_capable");
+
++ dwc->needs_fifo_resize = of_property_read_bool(node, "tx-fifo-resize");
++
++ dwc->configure_gfladj =
++ of_property_read_bool(node, "configure-gfladj");
++ dwc->dr_mode = of_usb_get_dr_mode(node);
++
+ dwc->disable_scramble_quirk = device_property_read_bool(dev,
+ "snps,disable_scramble_quirk");
+ dwc->u2exit_lfps_quirk = device_property_read_bool(dev,
+@@ -1041,6 +1265,8 @@ static int dwc3_probe(struct platform_device *pdev)
+ dwc->hird_threshold = hird_threshold
+ | (dwc->is_utmi_l1_suspend << 4);
+
++ dwc3_get_properties(dwc);
++
+ platform_set_drvdata(pdev, dwc);
+ dwc3_cache_hwparams(dwc);
+
+@@ -1064,6 +1290,11 @@ static int dwc3_probe(struct platform_device *pdev)
+ if (ret < 0)
+ goto err1;
+
++ /* Adjust Frame Length */
++ if (dwc->configure_gfladj)
++ dwc3_writel(dwc->regs, DWC3_GFLADJ, GFLADJ_30MHZ_REG_SEL |
++ GFLADJ_30MHZ(GFLADJ_30MHZ_DEFAULT));
++
+ pm_runtime_forbid(dev);
+
+ ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_SIZE);
+diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
+index 884c4371..9151eef4 100644
+--- a/drivers/usb/dwc3/core.h
++++ b/drivers/usb/dwc3/core.h
+@@ -26,6 +26,7 @@
+ #include <linux/dma-mapping.h>
+ #include <linux/mm.h>
+ #include <linux/debugfs.h>
++#include <linux/of_address.h>
+
+ #include <linux/usb/ch9.h>
+ #include <linux/usb/gadget.h>
+@@ -154,6 +155,32 @@
+
+ /* Bit fields */
+
++/* Global SoC Bus Configuration Register 0 */
++#define AXI3_CACHE_TYPE_AW 0x8 /* write allocate */
++#define AXI3_CACHE_TYPE_AR 0x4 /* read allocate */
++#define AXI3_CACHE_TYPE_SNP 0x2 /* cacheable */
++#define AXI3_CACHE_TYPE_BUF 0x1 /* bufferable */
++#define DWC3_GSBUSCFG0_DATARD_SHIFT 28
++#define DWC3_GSBUSCFG0_DESCRD_SHIFT 24
++#define DWC3_GSBUSCFG0_DATAWR_SHIFT 20
++#define DWC3_GSBUSCFG0_DESCWR_SHIFT 16
++#define DWC3_GSBUSCFG0_SNP_MASK 0xffff0000
++#define DWC3_GSBUSCFG0_DATABIGEND (1 << 11)
++#define DWC3_GSBUSCFG0_DESCBIGEND (1 << 10)
++#define DWC3_GSBUSCFG0_INCR256BRSTENA (1 << 7) /* INCR256 burst */
++#define DWC3_GSBUSCFG0_INCR128BRSTENA (1 << 6) /* INCR128 burst */
++#define DWC3_GSBUSCFG0_INCR64BRSTENA (1 << 5) /* INCR64 burst */
++#define DWC3_GSBUSCFG0_INCR32BRSTENA (1 << 4) /* INCR32 burst */
++#define DWC3_GSBUSCFG0_INCR16BRSTENA (1 << 3) /* INCR16 burst */
++#define DWC3_GSBUSCFG0_INCR8BRSTENA (1 << 2) /* INCR8 burst */
++#define DWC3_GSBUSCFG0_INCR4BRSTENA (1 << 1) /* INCR4 burst */
++#define DWC3_GSBUSCFG0_INCRBRSTENA (1 << 0) /* undefined length enable */
++#define DWC3_GSBUSCFG0_INCRBRST_MASK 0xff
++
++/* Global SoC Bus Configuration Register 1 */
++#define DWC3_GSBUSCFG1_1KPAGEENA (1 << 12) /* 1K page boundary enable */
++#define DWC3_GSBUSCFG1_PTRANSLIMIT_MASK 0xf00
++
+ /* Global Debug Queue/FIFO Space Available Register */
+ #define DWC3_GDBGFIFOSPACE_NUM(n) ((n) & 0x1f)
+ #define DWC3_GDBGFIFOSPACE_TYPE(n) (((n) << 5) & 0x1e0)
+@@ -180,7 +207,6 @@
+ #define DWC3_GCTL_CLK_PIPE (1)
+ #define DWC3_GCTL_CLK_PIPEHALF (2)
+ #define DWC3_GCTL_CLK_MASK (3)
+-
+ #define DWC3_GCTL_PRTCAP(n) (((n) & (3 << 12)) >> 12)
+ #define DWC3_GCTL_PRTCAPDIR(n) ((n) << 12)
+ #define DWC3_GCTL_PRTCAP_HOST 1
+@@ -289,6 +315,10 @@
+ /* Global Frame Length Adjustment Register */
+ #define DWC3_GFLADJ_30MHZ_SDBND_SEL (1 << 7)
+ #define DWC3_GFLADJ_30MHZ_MASK 0x3f
++#define GFLADJ_30MHZ_REG_SEL (1 << 7)
++#define GFLADJ_30MHZ(n) ((n) & 0x3f)
++#define GFLADJ_30MHZ_DEFAULT 0x20
++
+
+ /* Global User Control Register 2 */
+ #define DWC3_GUCTL2_RST_ACTBITLATER (1 << 14)
+@@ -753,6 +783,7 @@ struct dwc3_scratchpad_array {
+ * @regs: base address for our registers
+ * @regs_size: address space size
+ * @fladj: frame length adjustment
++ * @incrx_type: INCR burst type adjustment
+ * @irq_gadget: peripheral controller's IRQ number
+ * @nr_scratch: number of scratch buffers
+ * @u1u2: only used on revisions <1.83a for workaround
+@@ -847,6 +878,7 @@ struct dwc3 {
+ spinlock_t lock;
+
+ struct device *dev;
++ struct device *sysdev;
+
+ struct platform_device *xhci;
+ struct resource xhci_resources[DWC3_XHCI_RESOURCES_NUM];
+@@ -872,6 +904,12 @@ struct dwc3 {
+ enum usb_phy_interface hsphy_mode;
+
+ u32 fladj;
++ /*
++ * For INCR burst type.
++ * First field: for undefined length INCR burst type enable.
++ * Second field: for INCRx burst type enable
++ */
++ u32 incrx_type[2];
+ u32 irq_gadget;
+ u32 nr_scratch;
+ u32 u1u2;
+@@ -948,9 +986,12 @@ struct dwc3 {
+ unsigned ep0_bounced:1;
+ unsigned ep0_expect_in:1;
+ unsigned has_hibernation:1;
++ unsigned sysdev_is_parent:1;
+ unsigned has_lpm_erratum:1;
+ unsigned is_utmi_l1_suspend:1;
+ unsigned is_fpga:1;
++ unsigned needs_fifo_resize:1;
++ unsigned configure_gfladj:1;
+ unsigned pending_events:1;
+ unsigned pullups_connected:1;
+ unsigned setup_packet_pending:1;
+@@ -971,9 +1012,12 @@ struct dwc3 {
+ unsigned dis_rxdet_inp3_quirk:1;
+ unsigned dis_u2_freeclk_exists_quirk:1;
+ unsigned dis_del_phy_power_chg_quirk:1;
++ unsigned dma_snooping_quirk:1;
+
+ unsigned tx_de_emphasis_quirk:1;
+ unsigned tx_de_emphasis:2;
++
++ u16 imod_interval;
+ };
+
+ /* -------------------------------------------------------------------------- */
+diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c
+index 626d87d5..f1b98273 100644
+--- a/drivers/usb/dwc3/host.c
++++ b/drivers/usb/dwc3/host.c
+@@ -17,6 +17,8 @@
+
+ #include <linux/platform_device.h>
+
++#include <linux/of_device.h>
++
+ #include "core.h"
+
+ int dwc3_host_init(struct dwc3 *dwc)
+@@ -73,12 +75,21 @@ int dwc3_host_init(struct dwc3 *dwc)
+ return -ENOMEM;
+ }
+
+- dma_set_coherent_mask(&xhci->dev, dwc->dev->coherent_dma_mask);
++ if (IS_ENABLED(CONFIG_OF) && dwc->dev->of_node)
++ of_dma_configure(&xhci->dev, dwc->dev->of_node);
++ else
++ dma_set_coherent_mask(&xhci->dev, dwc->dev->coherent_dma_mask);
+
+- xhci->dev.parent = dwc->dev;
++ xhci->dev.parent = dwc->dev;
+ xhci->dev.dma_mask = dwc->dev->dma_mask;
+ xhci->dev.dma_parms = dwc->dev->dma_parms;
+
++ /* set DMA operations */
++ if (dwc->dev->of_node && of_dma_is_coherent(dwc->dev->of_node)) {
++ xhci->dev.archdata.dma_ops = dwc->dev->archdata.dma_ops;
++ dev_dbg(dwc->dev, "set dma_ops for usb\n");
++ }
++
+ dwc->xhci = xhci;
+
+ ret = platform_device_add_resources(xhci, dwc->xhci_resources,
+diff --git a/drivers/usb/gadget/udc/fsl_udc_core.c b/drivers/usb/gadget/udc/fsl_udc_core.c
+index aac0ce8a..fe49e758 100644
+--- a/drivers/usb/gadget/udc/fsl_udc_core.c
++++ b/drivers/usb/gadget/udc/fsl_udc_core.c
+@@ -198,7 +198,11 @@ __acquires(ep->udc->lock)
+
+ spin_unlock(&ep->udc->lock);
+
+- usb_gadget_giveback_request(&ep->ep, &req->req);
++ /* this complete() should a func implemented by gadget layer,
++ * eg fsg->bulk_in_complete()
++ */
++ if (req->req.complete)
++ usb_gadget_giveback_request(&ep->ep, &req->req);
+
+ spin_lock(&ep->udc->lock);
+ ep->stopped = stopped;
+@@ -245,10 +249,10 @@ static int dr_controller_setup(struct fsl_udc *udc)
+ if (udc->pdata->have_sysif_regs) {
+ if (udc->pdata->controller_ver) {
+ /* controller version 1.6 or above */
+- ctrl = __raw_readl(&usb_sys_regs->control);
++ ctrl = ioread32be(&usb_sys_regs->control);
+ ctrl &= ~USB_CTRL_UTMI_PHY_EN;
+ ctrl |= USB_CTRL_USB_EN;
+- __raw_writel(ctrl, &usb_sys_regs->control);
++ iowrite32be(ctrl, &usb_sys_regs->control);
+ }
+ }
+ portctrl |= PORTSCX_PTS_ULPI;
+@@ -257,13 +261,14 @@ static int dr_controller_setup(struct fsl_udc *udc)
+ portctrl |= PORTSCX_PTW_16BIT;
+ /* fall through */
+ case FSL_USB2_PHY_UTMI:
++ case FSL_USB2_PHY_UTMI_DUAL:
+ if (udc->pdata->have_sysif_regs) {
+ if (udc->pdata->controller_ver) {
+ /* controller version 1.6 or above */
+- ctrl = __raw_readl(&usb_sys_regs->control);
++ ctrl = ioread32be(&usb_sys_regs->control);
+ ctrl |= (USB_CTRL_UTMI_PHY_EN |
+ USB_CTRL_USB_EN);
+- __raw_writel(ctrl, &usb_sys_regs->control);
++ iowrite32be(ctrl, &usb_sys_regs->control);
+ mdelay(FSL_UTMI_PHY_DLY); /* Delay for UTMI
+ PHY CLK to become stable - 10ms*/
+ }
+@@ -329,22 +334,22 @@ static int dr_controller_setup(struct fsl_udc *udc)
+ /* Config control enable i/o output, cpu endian register */
+ #ifndef CONFIG_ARCH_MXC
+ if (udc->pdata->have_sysif_regs) {
+- ctrl = __raw_readl(&usb_sys_regs->control);
++ ctrl = ioread32be(&usb_sys_regs->control);
+ ctrl |= USB_CTRL_IOENB;
+- __raw_writel(ctrl, &usb_sys_regs->control);
++ iowrite32be(ctrl, &usb_sys_regs->control);
+ }
+ #endif
+
+-#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
++#if !defined(CONFIG_NOT_COHERENT_CACHE)
+ /* Turn on cache snooping hardware, since some PowerPC platforms
+ * wholly rely on hardware to deal with cache coherent. */
+
+ if (udc->pdata->have_sysif_regs) {
+ /* Setup Snooping for all the 4GB space */
+ tmp = SNOOP_SIZE_2GB; /* starts from 0x0, size 2G */
+- __raw_writel(tmp, &usb_sys_regs->snoop1);
++ iowrite32be(tmp, &usb_sys_regs->snoop1);
+ tmp |= 0x80000000; /* starts from 0x8000000, size 2G */
+- __raw_writel(tmp, &usb_sys_regs->snoop2);
++ iowrite32be(tmp, &usb_sys_regs->snoop2);
+ }
+ #endif
+
+@@ -1057,7 +1062,7 @@ static int fsl_ep_fifo_status(struct usb_ep *_ep)
+ struct ep_queue_head *qh;
+
+ ep = container_of(_ep, struct fsl_ep, ep);
+- if (!_ep || (!ep->ep.desc && ep_index(ep) != 0))
++ if (!_ep || !ep->ep.desc || (ep_index(ep) == 0))
+ return -ENODEV;
+
+ udc = (struct fsl_udc *)ep->udc;
+@@ -1599,14 +1604,13 @@ static int process_ep_req(struct fsl_udc *udc, int pipe,
+ struct fsl_req *curr_req)
+ {
+ struct ep_td_struct *curr_td;
+- int td_complete, actual, remaining_length, j, tmp;
++ int actual, remaining_length, j, tmp;
+ int status = 0;
+ int errors = 0;
+ struct ep_queue_head *curr_qh = &udc->ep_qh[pipe];
+ int direction = pipe % 2;
+
+ curr_td = curr_req->head;
+- td_complete = 0;
+ actual = curr_req->req.length;
+
+ for (j = 0; j < curr_req->dtd_count; j++) {
+@@ -1651,11 +1655,9 @@ static int process_ep_req(struct fsl_udc *udc, int pipe,
+ status = -EPROTO;
+ break;
+ } else {
+- td_complete++;
+ break;
+ }
+ } else {
+- td_complete++;
+ VDBG("dTD transmitted successful");
+ }
+
+@@ -1698,7 +1700,7 @@ static void dtd_complete_irq(struct fsl_udc *udc)
+ curr_ep = get_ep_by_pipe(udc, i);
+
+ /* If the ep is configured */
+- if (curr_ep->name == NULL) {
++ if (strncmp(curr_ep->name, "ep", 2)) {
+ WARNING("Invalid EP?");
+ continue;
+ }
+@@ -2420,10 +2422,12 @@ static int fsl_udc_probe(struct platform_device *pdev)
+ usb_sys_regs = (void *)dr_regs + USB_DR_SYS_OFFSET;
+ #endif
+
++#ifdef CONFIG_ARCH_MXC
+ /* Initialize USB clocks */
+ ret = fsl_udc_clk_init(pdev);
+ if (ret < 0)
+ goto err_iounmap_noclk;
++#endif
+
+ /* Read Device Controller Capability Parameters register */
+ dccparams = fsl_readl(&dr_regs->dccparams);
+@@ -2463,9 +2467,11 @@ static int fsl_udc_probe(struct platform_device *pdev)
+ dr_controller_setup(udc_controller);
+ }
+
++#ifdef CONFIG_ARCH_MXC
+ ret = fsl_udc_clk_finalize(pdev);
+ if (ret)
+ goto err_free_irq;
++#endif
+
+ /* Setup gadget structure */
+ udc_controller->gadget.ops = &fsl_gadget_ops;
+@@ -2478,6 +2484,7 @@ static int fsl_udc_probe(struct platform_device *pdev)
+ /* Setup gadget.dev and register with kernel */
+ dev_set_name(&udc_controller->gadget.dev, "gadget");
+ udc_controller->gadget.dev.of_node = pdev->dev.of_node;
++ set_dma_ops(&udc_controller->gadget.dev, pdev->dev.archdata.dma_ops);
+
+ if (!IS_ERR_OR_NULL(udc_controller->transceiver))
+ udc_controller->gadget.is_otg = 1;
+@@ -2529,7 +2536,9 @@ static int fsl_udc_probe(struct platform_device *pdev)
+ err_iounmap:
+ if (pdata->exit)
+ pdata->exit(pdev);
++#ifdef CONFIG_ARCH_MXC
+ fsl_udc_clk_release();
++#endif
+ err_iounmap_noclk:
+ iounmap(dr_regs);
+ err_release_mem_region:
+@@ -2557,8 +2566,9 @@ static int fsl_udc_remove(struct platform_device *pdev)
+ udc_controller->done = &done;
+ usb_del_gadget_udc(&udc_controller->gadget);
+
++#ifdef CONFIG_ARCH_MXC
+ fsl_udc_clk_release();
+-
++#endif
+ /* DR has been stopped in usb_gadget_unregister_driver() */
+ remove_proc_file();
+
+@@ -2570,7 +2580,7 @@ static int fsl_udc_remove(struct platform_device *pdev)
+ dma_pool_destroy(udc_controller->td_pool);
+ free_irq(udc_controller->irq, udc_controller);
+ iounmap(dr_regs);
+- if (pdata->operating_mode == FSL_USB2_DR_DEVICE)
++ if (res && (pdata->operating_mode == FSL_USB2_DR_DEVICE))
+ release_mem_region(res->start, resource_size(res));
+
+ /* free udc --wait for the release() finished */
+diff --git a/drivers/usb/gadget/udc/fsl_usb2_udc.h b/drivers/usb/gadget/udc/fsl_usb2_udc.h
+index 84715625..f76c4ddd 100644
+--- a/drivers/usb/gadget/udc/fsl_usb2_udc.h
++++ b/drivers/usb/gadget/udc/fsl_usb2_udc.h
+@@ -20,6 +20,10 @@
+ #define USB_MAX_CTRL_PAYLOAD 64
+ #define USB_DR_SYS_OFFSET 0x400
+
++#ifdef CONFIG_SOC_LS1021A
++#undef CONFIG_ARCH_MXC
++#endif
++
+ /* USB DR device mode registers (Little Endian) */
+ struct usb_dr_device {
+ /* Capability register */
+@@ -597,18 +601,6 @@ struct platform_device;
+ int fsl_udc_clk_init(struct platform_device *pdev);
+ int fsl_udc_clk_finalize(struct platform_device *pdev);
+ void fsl_udc_clk_release(void);
+-#else
+-static inline int fsl_udc_clk_init(struct platform_device *pdev)
+-{
+- return 0;
+-}
+-static inline int fsl_udc_clk_finalize(struct platform_device *pdev)
+-{
+- return 0;
+-}
+-static inline void fsl_udc_clk_release(void)
+-{
+-}
+ #endif
+
+ #endif
+diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
+index 0b80cee3..a57d95c3 100644
+--- a/drivers/usb/host/Kconfig
++++ b/drivers/usb/host/Kconfig
+@@ -165,7 +165,7 @@ config XPS_USB_HCD_XILINX
+
+ config USB_EHCI_FSL
+ tristate "Support for Freescale PPC on-chip EHCI USB controller"
+- depends on FSL_SOC
++ depends on USB_EHCI_HCD
+ select USB_EHCI_ROOT_HUB_TT
+ ---help---
+ Variation of ARC USB block used in some Freescale chips.
+diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c
+index 9f5ffb62..cd16860c 100644
+--- a/drivers/usb/host/ehci-fsl.c
++++ b/drivers/usb/host/ehci-fsl.c
+@@ -37,13 +37,141 @@
+ #include <linux/fsl_devices.h>
+ #include <linux/of_platform.h>
+
++#ifdef CONFIG_PPC
++#include <asm/fsl_pm.h>
++#include <linux/suspend.h>
++#endif
++
+ #include "ehci.h"
+ #include "ehci-fsl.h"
+
++#define FSL_USB_PHY_ADDR 0xffe214000
++
++struct ccsr_usb_port_ctrl {
++ u32 ctrl;
++ u32 drvvbuscfg;
++ u32 pwrfltcfg;
++ u32 sts;
++ u8 res_14[0xc];
++ u32 bistcfg;
++ u32 biststs;
++ u32 abistcfg;
++ u32 abiststs;
++ u8 res_30[0x10];
++ u32 xcvrprg;
++ u32 anaprg;
++ u32 anadrv;
++ u32 anasts;
++};
++
++struct ccsr_usb_phy {
++ u32 id;
++ struct ccsr_usb_port_ctrl port1;
++ u8 res_50[0xc];
++ u32 tvr;
++ u32 pllprg[4];
++ u8 res_70[0x4];
++ u32 anaccfg;
++ u32 dbg;
++ u8 res_7c[0x4];
++ struct ccsr_usb_port_ctrl port2;
++ u8 res_dc[0x334];
++};
++
+ #define DRIVER_DESC "Freescale EHCI Host controller driver"
+ #define DRV_NAME "ehci-fsl"
+
+ static struct hc_driver __read_mostly fsl_ehci_hc_driver;
++struct ehci_fsl {
++ /* store current hcd state for otg;
++ * have_hcd is true when host drv al already part of otg framework,
++ * otherwise false;
++ * hcd_add is true when otg framework wants to add host
++ * drv as part of otg;flase when it wants to remove it
++ */
++unsigned have_hcd:1;
++unsigned hcd_add:1;
++};
++
++static struct ehci_fsl *hcd_to_ehci_fsl(struct usb_hcd *hcd)
++{
++struct ehci_hcd *ehci = hcd_to_ehci(hcd);
++
++return container_of(ehci, struct ehci_fsl, ehci);
++}
++
++#if defined(CONFIG_FSL_USB2_OTG) || defined(CONFIG_FSL_USB2_OTG_MODULE)
++static void do_change_hcd(struct work_struct *work)
++{
++struct ehci_hcd *ehci = container_of(work, struct ehci_hcd,
++ change_hcd_work);
++struct usb_hcd *hcd = ehci_to_hcd(ehci);
++struct ehci_fsl *ehci_fsl = hcd_to_ehci_fsl(hcd);
++void __iomem *non_ehci = hcd->regs;
++int retval;
++
++ if (ehci_fsl->hcd_add && !ehci_fsl->have_hcd) {
++ writel(USBMODE_CM_HOST, non_ehci + FSL_SOC_USB_USBMODE);
++ /* host, gadget and otg share same int line */
++ retval = usb_add_hcd(hcd, hcd->irq, IRQF_SHARED);
++ if (retval == 0)
++ ehci_fsl->have_hcd = 1;
++ } else if (!ehci_fsl->hcd_add && ehci_fsl->have_hcd) {
++ usb_remove_hcd(hcd);
++ ehci_fsl->have_hcd = 0;
++ }
++}
++#endif
++
++struct ehci_fsl {
++ struct ehci_hcd ehci;
++
++#ifdef CONFIG_PM
++struct ehci_regs saved_regs;
++struct ccsr_usb_phy saved_phy_regs;
++/* Saved USB PHY settings, need to restore after deep sleep. */
++u32 usb_ctrl;
++#endif
++ /*
++ * store current hcd state for otg;
++ * have_hcd is true when host drv al already part of otg framework,
++ * otherwise false;
++ * hcd_add is true when otg framework wants to add host
++ * drv as part of otg;flase when it wants to remove it
++ */
++unsigned have_hcd:1;
++unsigned hcd_add:1;
++};
++
++static strut ehci_fsl *hcd_to_ehci_fsl(struct usb_hcd *hcd)
++{
++struct ehci_hcd *ehci = hcd_to_ehci(hcd);
++
++return container_of(ehci, struct ehci_fsl, ehci);
++}
++
++#if defined(CONFIG_FSL_USB2_OTG) || defined(CONFIG_FSL_USB2_OTG_MODULE)
++static void do_change_hcd(struct work_struct *work)
++{
++struct ehci_hcd *ehci = container_of(work, struct ehci_hcd,
++change_hcd_work);
++struct usb_hcd *hcd = ehci_to_hcd(ehci);
++struct ehci_fsl *ehci_fsl = hcd_to_ehci_fsl(hcd);
++void __iomem *non_ehci = hcd->regs;
++int retval;
++
++if (ehci_fsl->hcd_add && !ehci_fsl->have_hcd) {
++writel(USBMODE_CM_HOST, non_ehci + FSL_SOC_USB_USBMODE);
++/* host, gadget and otg share same int line */
++retval = usb_add_hcd(hcd, hcd->irq, IRQF_SHARED);
++if (retval == 0)
++ehci_fsl->have_hcd = 1;
++} else if (!ehci_fsl->hcd_add && ehci_fsl->have_hcd) {
++ usb_remove_hcd(hcd);
++ehci_fsl->have_hcd = 0;
++}
++}
++#endif
+
+ /* configure so an HC device and id are always provided */
+ /* always called with process context; sleeping is OK */
+@@ -131,6 +259,12 @@ static int fsl_ehci_drv_probe(struct platform_device *pdev)
+ clrsetbits_be32(hcd->regs + FSL_SOC_USB_CTRL,
+ CONTROL_REGISTER_W1C_MASK, 0x4);
+
++ /* Set USB_EN bit to select ULPI phy for USB controller version 2.5 */
++ if (pdata->controller_ver == FSL_USB_VER_2_5 &&
++ pdata->phy_mode == FSL_USB2_PHY_ULPI)
++ iowrite32be(USB_CTRL_USB_EN, hcd->regs + FSL_SOC_USB_CTRL);
++
++
+ /*
+ * Enable UTMI phy and program PTS field in UTMI mode before asserting
+ * controller reset for USB Controller version 2.5
+@@ -143,16 +277,20 @@ static int fsl_ehci_drv_probe(struct platform_device *pdev)
+
+ /* Don't need to set host mode here. It will be done by tdi_reset() */
+
+- retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
++ retval = usb_add_hcd(hcd, irq, IRQF_SHARED | IRQF_NO_SUSPEND);
+ if (retval != 0)
+ goto err2;
+ device_wakeup_enable(hcd->self.controller);
+
+-#ifdef CONFIG_USB_OTG
++#if defined(CONFIG_FSL_USB2_OTG) || defined(CONFIG_FSL_USB2_OTG_MODULE)
+ if (pdata->operating_mode == FSL_USB2_DR_OTG) {
+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
++ struct ehci_fsl *ehci_fsl = hcd_to_ehci_fsl(hcd);
+
+ hcd->usb_phy = usb_get_phy(USB_PHY_TYPE_USB2);
++
++ INIT_WORK(&ehci->change_hcd_work, do_change_hcd);
++
+ dev_dbg(&pdev->dev, "hcd=0x%p ehci=0x%p, phy=0x%p\n",
+ hcd, ehci, hcd->usb_phy);
+
+@@ -168,6 +306,11 @@ static int fsl_ehci_drv_probe(struct platform_device *pdev)
+ retval = -ENODEV;
+ goto err2;
+ }
++
++ ehci_fsl->have_hcd = 1;
++ } else {
++ dev_err(&pdev->dev, "wrong operating mode\n");
++ return -ENODEV;
+ }
+ #endif
+ return retval;
+@@ -181,6 +324,18 @@ static int fsl_ehci_drv_probe(struct platform_device *pdev)
+ return retval;
+ }
+
++static bool usb_phy_clk_valid(struct usb_hcd *hcd,
++ enum fsl_usb2_phy_modes phy_mode)
++{
++ void __iomem *non_ehci = hcd->regs;
++ bool ret = true;
++
++ if (!(in_be32(non_ehci + FSL_SOC_USB_CTRL) & PHY_CLK_VALID))
++ ret = false;
++
++ return ret;
++}
++
+ static int ehci_fsl_setup_phy(struct usb_hcd *hcd,
+ enum fsl_usb2_phy_modes phy_mode,
+ unsigned int port_offset)
+@@ -219,6 +374,21 @@ static int ehci_fsl_setup_phy(struct usb_hcd *hcd,
+ /* fall through */
+ case FSL_USB2_PHY_UTMI:
+ case FSL_USB2_PHY_UTMI_DUAL:
++ if (pdata->has_fsl_erratum_a006918) {
++ pr_warn("fsl-ehci: USB PHY clock invalid\n");
++ return -EINVAL;
++ }
++
++ /* PHY_CLK_VALID bit is de-featured from all controller
++ * versions below 2.4 and is to be checked only for
++ * internal UTMI phy
++ */
++ if (pdata->controller_ver > FSL_USB_VER_2_4 &&
++ pdata->have_sysif_regs && !usb_phy_clk_valid(hcd)) {
++ pr_err("fsl-ehci: USB PHY clock invalid\n");
++ return -EINVAL;
++ }
++
+ if (pdata->have_sysif_regs && pdata->controller_ver) {
+ /* controller version 1.6 or above */
+ clrsetbits_be32(non_ehci + FSL_SOC_USB_CTRL,
+@@ -292,14 +462,9 @@ static int ehci_fsl_usb_setup(struct ehci_hcd *ehci)
+ return -EINVAL;
+
+ if (pdata->operating_mode == FSL_USB2_MPH_HOST) {
+- unsigned int chip, rev, svr;
+-
+- svr = mfspr(SPRN_SVR);
+- chip = svr >> 16;
+- rev = (svr >> 4) & 0xf;
+
+ /* Deal with USB Erratum #14 on MPC834x Rev 1.0 & 1.1 chips */
+- if ((rev == 1) && (chip >= 0x8050) && (chip <= 0x8055))
++ if (pdata->has_fsl_erratum_14 == 1)
+ ehci->has_fsl_port_bug = 1;
+
+ if (pdata->port_enables & FSL_USB2_PORT0_ENABLED)
+@@ -379,16 +544,57 @@ static int ehci_fsl_setup(struct usb_hcd *hcd)
+ return retval;
+ }
+
+-struct ehci_fsl {
+- struct ehci_hcd ehci;
+
+ #ifdef CONFIG_PM
+- /* Saved USB PHY settings, need to restore after deep sleep. */
+- u32 usb_ctrl;
+-#endif
+-};
++void __iomem *phy_reg;
+
+-#ifdef CONFIG_PM
++#ifdef CONFIG_PPC
++/* save usb registers */
++static int ehci_fsl_save_context(struct usb_hcd *hcd)
++{
++ struct ehci_fsl *ehci_fsl = hcd_to_ehci_fsl(hcd);
++ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
++ void __iomem *non_ehci = hcd->regs;
++ struct device *dev = hcd->self.controller;
++ struct fsl_usb2_platform_data *pdata = dev_get_platdata(dev);
++
++ if (pdata->phy_mode == FSL_USB2_PHY_UTMI_DUAL) {
++ phy_reg = ioremap(FSL_USB_PHY_ADDR,
++ sizeof(struct ccsr_usb_phy));
++ _memcpy_fromio((void *)&ehci_fsl->saved_phy_regs, phy_reg,
++ sizeof(struct ccsr_usb_phy));
++ }
++
++ _memcpy_fromio((void *)&ehci_fsl->saved_regs, ehci->regs,
++ sizeof(struct ehci_regs));
++ ehci_fsl->usb_ctrl = ioread32be(non_ehci + FSL_SOC_USB_CTRL);
++
++ return 0;
++}
++
++/*Restore usb registers */
++static int ehci_fsl_restore_context(struct usb_hcd *hcd)
++{
++ struct ehci_fsl *ehci_fsl = hcd_to_ehci_fsl(hcd);
++ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
++ void __iomem *non_ehci = hcd->regs;
++ struct device *dev = hcd->self.controller;
++ struct fsl_usb2_platform_data *pdata = dev_get_platdata(dev);
++
++ if (pdata->phy_mode == FSL_USB2_PHY_UTMI_DUAL) {
++ if (phy_reg)
++ _memcpy_toio(phy_reg,
++ (void *)&ehci_fsl->saved_phy_regs,
++ sizeof(struct ccsr_usb_phy));
++ }
++
++ _memcpy_toio(ehci->regs, (void *)&ehci_fsl->saved_regs,
++ sizeof(struct ehci_regs));
++ iowrite32be(ehci_fsl->usb_ctrl, non_ehci + FSL_SOC_USB_CTRL);
++
++ return 0;
++}
++#endif
+
+ #ifdef CONFIG_PPC_MPC512x
+ static int ehci_fsl_mpc512x_drv_suspend(struct device *dev)
+@@ -535,26 +741,43 @@ static inline int ehci_fsl_mpc512x_drv_resume(struct device *dev)
+ }
+ #endif /* CONFIG_PPC_MPC512x */
+
+-static struct ehci_fsl *hcd_to_ehci_fsl(struct usb_hcd *hcd)
+-{
+- struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+-
+- return container_of(ehci, struct ehci_fsl, ehci);
+-}
+-
+ static int ehci_fsl_drv_suspend(struct device *dev)
+ {
+ struct usb_hcd *hcd = dev_get_drvdata(dev);
+ struct ehci_fsl *ehci_fsl = hcd_to_ehci_fsl(hcd);
+ void __iomem *non_ehci = hcd->regs;
++#if defined(CONFIG_FSL_USB2_OTG) || defined(CONFIG_FSL_USB2_OTG_MODULE)
++ struct usb_bus host = hcd->self;
++#endif
++
++#ifdef CONFIG_PPC
++suspend_state_t pm_state;
++pm_state = pm_suspend_state();
++
++if (pm_state == PM_SUSPEND_MEM)
++ ehci_fsl_save_context(hcd);
++#endif
+
+ if (of_device_is_compatible(dev->parent->of_node,
+ "fsl,mpc5121-usb2-dr")) {
+ return ehci_fsl_mpc512x_drv_suspend(dev);
+ }
+
++#if defined(CONFIG_FSL_USB2_OTG) || defined(CONFIG_FSL_USB2_OTG_MODULE)
++ if (host.is_otg) {
++ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
++
++ /* remove hcd */
++ ehci_fsl->hcd_add = 0;
++ schedule_work(&ehci->change_hcd_work);
++ host.is_otg = 0;
++ return 0;
++ }
++#endif
++
+ ehci_prepare_ports_for_controller_suspend(hcd_to_ehci(hcd),
+ device_may_wakeup(dev));
++
+ if (!fsl_deep_sleep())
+ return 0;
+
+@@ -568,12 +791,34 @@ static int ehci_fsl_drv_resume(struct device *dev)
+ struct ehci_fsl *ehci_fsl = hcd_to_ehci_fsl(hcd);
+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+ void __iomem *non_ehci = hcd->regs;
++#if defined(CONFIG_FSL_USB2_OTG) || defined(CONFIG_FSL_USB2_OTG_MODULE)
++ struct usb_bus host = hcd->self;
++#endif
++
++#ifdef CONFIG_PPC
++suspend_state_t pm_state;
++pm_state = pm_suspend_state();
++
++if (pm_state == PM_SUSPEND_MEM)
++ ehci_fsl_restore_context(hcd);
++#endif
+
+ if (of_device_is_compatible(dev->parent->of_node,
+ "fsl,mpc5121-usb2-dr")) {
+ return ehci_fsl_mpc512x_drv_resume(dev);
+ }
+
++#if defined(CONFIG_FSL_USB2_OTG) || defined(CONFIG_FSL_USB2_OTG_MODULE)
++ if (host.is_otg) {
++ /* add hcd */
++ ehci_fsl->hcd_add = 1;
++ schedule_work(&ehci->change_hcd_work);
++ usb_hcd_resume_root_hub(hcd);
++ host.is_otg = 0;
++ return 0;
++ }
++#endif
++
+ ehci_prepare_ports_for_controller_resume(ehci);
+ if (!fsl_deep_sleep())
+ return 0;
+diff --git a/drivers/usb/host/ehci-fsl.h b/drivers/usb/host/ehci-fsl.h
+index 1a8a60a5..42ea2976 100644
+--- a/drivers/usb/host/ehci-fsl.h
++++ b/drivers/usb/host/ehci-fsl.h
+@@ -63,4 +63,7 @@
+ #define UTMI_PHY_EN (1<<9)
+ #define ULPI_PHY_CLK_SEL (1<<10)
+ #define PHY_CLK_VALID (1<<17)
++
++/* Retry count for checking UTMI PHY CLK validity */
++#define UTMI_PHY_CLK_VALID_CHK_RETRY 5
+ #endif /* _EHCI_FSL_H */
+diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
+index 255acca8..c8838c33 100644
+--- a/drivers/usb/host/ehci-hub.c
++++ b/drivers/usb/host/ehci-hub.c
+@@ -305,6 +305,8 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
+ USB_PORT_STAT_HIGH_SPEED)
+ fs_idle_delay = true;
+ ehci_writel(ehci, t2, reg);
++ if (ehci_has_fsl_susp_errata(ehci))
++ usleep_range(10000, 20000);
+ changed = 1;
+ }
+ }
+diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
+index 3b06bb77..f296d1fb 100644
+--- a/drivers/usb/host/ehci.h
++++ b/drivers/usb/host/ehci.h
+@@ -180,6 +180,9 @@ struct ehci_hcd { /* one per controller */
+ unsigned periodic_count; /* periodic activity count */
+ unsigned uframe_periodic_max; /* max periodic time per uframe */
+
++#if defined(CONFIG_FSL_USB2_OTG) || defined(CONFIG_FSL_USB2_OTG_MODULE)
++ struct work_struct change_hcd_work;
++#endif
+
+ /* list of itds & sitds completed while now_frame was still active */
+ struct list_head cached_itd_list;
+@@ -706,8 +709,10 @@ ehci_port_speed(struct ehci_hcd *ehci, unsigned int portsc)
+ * incoming packets get corrupted in HS mode
+ */
+ #define ehci_has_fsl_hs_errata(e) ((e)->has_fsl_hs_errata)
++#define ehci_has_fsl_susp_errata(e) ((e)->has_fsl_susp_errata)
+ #else
+ #define ehci_has_fsl_hs_errata(e) (0)
++#define ehci_has_fsl_susp_errata(e) (0)
+ #endif
+
+ /*
+diff --git a/drivers/usb/host/fsl-mph-dr-of.c b/drivers/usb/host/fsl-mph-dr-of.c
+index f07ccb25..1e59ea9f 100644
+--- a/drivers/usb/host/fsl-mph-dr-of.c
++++ b/drivers/usb/host/fsl-mph-dr-of.c
+@@ -226,6 +226,18 @@ static int fsl_usb2_mph_dr_of_probe(struct platform_device *ofdev)
+ of_property_read_bool(np, "fsl,usb-erratum-a007792");
+ pdata->has_fsl_erratum_a005275 =
+ of_property_read_bool(np, "fsl,usb-erratum-a005275");
++ pdata->has_fsl_erratum_a005697 =
++ of_property_read_bool(np, "fsl,usb_erratum-a005697");
++ if (of_get_property(np, "fsl,erratum_a006918", NULL))
++ pdata->has_fsl_erratum_a006918 = 1;
++ else
++ pdata->has_fsl_erratum_a006918 = 0;
++
++ if (of_get_property(np, "fsl,usb_erratum_14", NULL))
++ pdata->has_fsl_erratum_14 = 1;
++ else
++ pdata->has_fsl_erratum_14 = 0;
++
+
+ /*
+ * Determine whether phy_clk_valid needs to be checked
+diff --git a/drivers/usb/phy/phy-fsl-usb.c b/drivers/usb/phy/phy-fsl-usb.c
+index 94eb2923..836355fa 100644
+--- a/drivers/usb/phy/phy-fsl-usb.c
++++ b/drivers/usb/phy/phy-fsl-usb.c
+@@ -1,5 +1,5 @@
+ /*
+- * Copyright (C) 2007,2008 Freescale semiconductor, Inc.
++ * Copyright 2007,2008 Freescale Semiconductor, Inc.
+ *
+ * Author: Li Yang <LeoLi@freescale.com>
+ * Jerry Huang <Chang-Ming.Huang@freescale.com>
+@@ -463,6 +463,7 @@ void otg_reset_controller(void)
+ int fsl_otg_start_host(struct otg_fsm *fsm, int on)
+ {
+ struct usb_otg *otg = fsm->otg;
++ struct usb_bus *host = otg->host;
+ struct device *dev;
+ struct fsl_otg *otg_dev =
+ container_of(otg->usb_phy, struct fsl_otg, phy);
+@@ -486,6 +487,7 @@ int fsl_otg_start_host(struct otg_fsm *fsm, int on)
+ otg_reset_controller();
+ VDBG("host on......\n");
+ if (dev->driver->pm && dev->driver->pm->resume) {
++ host->is_otg = 1;
+ retval = dev->driver->pm->resume(dev);
+ if (fsm->id) {
+ /* default-b */
+@@ -510,8 +512,11 @@ int fsl_otg_start_host(struct otg_fsm *fsm, int on)
+ else {
+ VDBG("host off......\n");
+ if (dev && dev->driver) {
+- if (dev->driver->pm && dev->driver->pm->suspend)
++ if (dev->driver->pm &&
++ dev->driver->pm->suspend) {
++ host->is_otg = 1;
+ retval = dev->driver->pm->suspend(dev);
++ }
+ if (fsm->id)
+ /* default-b */
+ fsl_otg_drv_vbus(fsm, 0);
+@@ -539,8 +544,17 @@ int fsl_otg_start_gadget(struct otg_fsm *fsm, int on)
+ dev = otg->gadget->dev.parent;
+
+ if (on) {
+- if (dev->driver->resume)
++ /* Delay gadget resume to synchronize between host and gadget
++ * drivers. Upon role-reversal host drv is shutdown by kernel
++ * worker thread. By the time host drv shuts down, controller
++ * gets programmed for gadget role. Shutting host drv after
++ * this results in controller getting reset, and it stops
++ * responding to otg events
++ */
++ if (dev->driver->resume) {
++ msleep(1000);
+ dev->driver->resume(dev);
++ }
+ } else {
+ if (dev->driver->suspend)
+ dev->driver->suspend(dev, otg_suspend_state);
+@@ -672,6 +686,10 @@ static void fsl_otg_event(struct work_struct *work)
+ fsl_otg_start_host(fsm, 0);
+ otg_drv_vbus(fsm, 0);
+ fsl_otg_start_gadget(fsm, 1);
++ } else {
++ fsl_otg_start_gadget(fsm, 0);
++ otg_drv_vbus(fsm, 1);
++ fsl_otg_start_host(fsm, 1);
+ }
+ }
+
+@@ -724,6 +742,7 @@ irqreturn_t fsl_otg_isr(int irq, void *dev_id)
+ {
+ struct otg_fsm *fsm = &((struct fsl_otg *)dev_id)->fsm;
+ struct usb_otg *otg = ((struct fsl_otg *)dev_id)->phy.otg;
++ struct fsl_otg *otg_dev = dev_id;
+ u32 otg_int_src, otg_sc;
+
+ otg_sc = fsl_readl(&usb_dr_regs->otgsc);
+@@ -753,18 +772,8 @@ irqreturn_t fsl_otg_isr(int irq, void *dev_id)
+ otg->gadget->is_a_peripheral = !fsm->id;
+ VDBG("ID int (ID is %d)\n", fsm->id);
+
+- if (fsm->id) { /* switch to gadget */
+- schedule_delayed_work(
+- &((struct fsl_otg *)dev_id)->otg_event,
+- 100);
+- } else { /* switch to host */
+- cancel_delayed_work(&
+- ((struct fsl_otg *)dev_id)->
+- otg_event);
+- fsl_otg_start_gadget(fsm, 0);
+- otg_drv_vbus(fsm, 1);
+- fsl_otg_start_host(fsm, 1);
+- }
++ schedule_delayed_work(&otg_dev->otg_event, 100);
++
+ return IRQ_HANDLED;
+ }
+ }
+@@ -923,12 +932,32 @@ int usb_otg_start(struct platform_device *pdev)
+ temp &= ~(PORTSC_PHY_TYPE_SEL | PORTSC_PTW);
+ switch (pdata->phy_mode) {
+ case FSL_USB2_PHY_ULPI:
++ if (pdata->controller_ver) {
++ /* controller version 1.6 or above */
++ setbits32(&p_otg->dr_mem_map->control,
++ USB_CTRL_ULPI_PHY_CLK_SEL);
++ /*
++ * Due to controller issue of PHY_CLK_VALID in ULPI
++ * mode, we set USB_CTRL_USB_EN before checking
++ * PHY_CLK_VALID, otherwise PHY_CLK_VALID doesn't work.
++ */
++ clrsetbits_be32(&p_otg->dr_mem_map->control,
++ USB_CTRL_UTMI_PHY_EN, USB_CTRL_IOENB);
++ }
+ temp |= PORTSC_PTS_ULPI;
+ break;
+ case FSL_USB2_PHY_UTMI_WIDE:
+ temp |= PORTSC_PTW_16BIT;
+ /* fall through */
+ case FSL_USB2_PHY_UTMI:
++ if (pdata->controller_ver) {
++ /* controller version 1.6 or above */
++ setbits32(&p_otg->dr_mem_map->control,
++ USB_CTRL_UTMI_PHY_EN);
++ /* Delay for UTMI PHY CLK to become stable - 10ms */
++ mdelay(FSL_UTMI_PHY_DLY);
++ }
++ setbits32(&p_otg->dr_mem_map->control, USB_CTRL_UTMI_PHY_EN);
+ temp |= PORTSC_PTS_UTMI;
+ /* fall through */
+ default:
+diff --git a/drivers/usb/phy/phy-fsl-usb.h b/drivers/usb/phy/phy-fsl-usb.h
+index 23149954..c4c08730 100644
+--- a/drivers/usb/phy/phy-fsl-usb.h
++++ b/drivers/usb/phy/phy-fsl-usb.h
+@@ -199,6 +199,14 @@
+ /* control Register Bit Masks */
+ #define USB_CTRL_IOENB (0x1<<2)
+ #define USB_CTRL_ULPI_INT0EN (0x1<<0)
++#define USB_CTRL_WU_INT_EN (0x1<<1)
++#define USB_CTRL_LINE_STATE_FILTER__EN (0x1<<3)
++#define USB_CTRL_KEEP_OTG_ON (0x1<<4)
++#define USB_CTRL_OTG_PORT (0x1<<5)
++#define USB_CTRL_PLL_RESET (0x1<<8)
++#define USB_CTRL_UTMI_PHY_EN (0x1<<9)
++#define USB_CTRL_ULPI_PHY_CLK_SEL (0x1<<10)
++#define USB_CTRL_PHY_CLK_VALID (0x1<<17)
+
+ /* BCSR5 */
+ #define BCSR5_INT_USB (0x02)
+diff --git a/include/linux/usb.h b/include/linux/usb.h
+index eba1f10e..c334e281 100644
+--- a/include/linux/usb.h
++++ b/include/linux/usb.h
+@@ -362,6 +362,7 @@ struct usb_bus {
+ * for control transfers?
+ */
+ u8 otg_port; /* 0, or number of OTG/HNP port */
++ unsigned is_otg:1; /* true when host is also otg */
+ unsigned is_b_host:1; /* true during some HNP roleswitches */
+ unsigned b_hnp_enable:1; /* OTG: did A-Host enable HNP? */
+ unsigned no_stop_on_short:1; /*
+diff --git a/include/linux/usb/of.h b/include/linux/usb/of.h
+index 5ff9032e..2a57e0d2 100644
+--- a/include/linux/usb/of.h
++++ b/include/linux/usb/of.h
+@@ -11,6 +11,8 @@
+ #include <linux/usb/otg.h>
+ #include <linux/usb/phy.h>
+
++enum usb_dr_mode of_usb_get_dr_mode(struct device_node *np);
++
+ #if IS_ENABLED(CONFIG_OF)
+ enum usb_dr_mode of_usb_get_dr_mode_by_phy(struct device_node *np, int arg0);
+ bool of_usb_host_tpl_support(struct device_node *np);
+--
+2.14.1
+