diff options
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.patch | 1471 |
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 + |