--- zzzz-none-000/linux-3.10.107/drivers/usb/host/ehci-fsl.c 2017-06-27 09:49:32.000000000 +0000 +++ scorpion-7490-727/linux-3.10.107/drivers/usb/host/ehci-fsl.c 2021-02-04 17:41:59.000000000 +0000 @@ -1,6 +1,6 @@ /* * Copyright 2005-2009 MontaVista Software, Inc. - * Copyright 2008,2012 Freescale Semiconductor, Inc. + * Copyright 2008,2012,2015 Freescale Semiconductor, Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -24,29 +24,38 @@ */ #include +#include #include #include #include #include +#include +#include +#include +#include #include #include +#include "ehci.h" #include "ehci-fsl.h" +#define DRIVER_DESC "Freescale EHCI Host controller driver" +#define DRV_NAME "ehci-fsl" + +static struct hc_driver __read_mostly fsl_ehci_hc_driver; + /* configure so an HC device and id are always provided */ /* always called with process context; sleeping is OK */ -/** - * usb_hcd_fsl_probe - initialize FSL-based HCDs - * @drvier: Driver to be used for this HCD +/* + * fsl_ehci_drv_probe - initialize FSL-based HCDs * @pdev: USB Host Controller being probed * Context: !in_interrupt() * * Allocates basic resources for this USB host controller. * */ -static int usb_hcd_fsl_probe(const struct hc_driver *driver, - struct platform_device *pdev) +static int fsl_ehci_drv_probe(struct platform_device *pdev) { struct fsl_usb2_platform_data *pdata; struct usb_hcd *hcd; @@ -57,7 +66,7 @@ pr_debug("initializing FSL-SOC USB Controller\n"); /* Need platform data for setup */ - pdata = (struct fsl_usb2_platform_data *)pdev->dev.platform_data; + pdata = dev_get_platdata(&pdev->dev); if (!pdata) { dev_err(&pdev->dev, "No platform data for %s.\n", dev_name(&pdev->dev)); @@ -86,35 +95,22 @@ } irq = res->start; - hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev)); + hcd = usb_create_hcd(&fsl_ehci_hc_driver, &pdev->dev, + dev_name(&pdev->dev)); if (!hcd) { retval = -ENOMEM; goto err1; } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, - "Found HC with no register addr. Check %s setup!\n", - dev_name(&pdev->dev)); - retval = -ENODEV; + hcd->regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(hcd->regs)) { + retval = PTR_ERR(hcd->regs); goto err2; } + hcd->rsrc_start = res->start; hcd->rsrc_len = resource_size(res); - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, - driver->description)) { - dev_dbg(&pdev->dev, "controller already in use\n"); - retval = -EBUSY; - goto err2; - } - hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); - - if (hcd->regs == NULL) { - dev_dbg(&pdev->dev, "error mapping memory\n"); - retval = -EFAULT; - goto err3; - } pdata->regs = hcd->regs; @@ -126,47 +122,55 @@ */ if (pdata->init && pdata->init(pdev)) { retval = -ENODEV; - goto err4; + goto err2; } /* Enable USB controller, 83xx or 8536 */ if (pdata->have_sysif_regs && pdata->controller_ver < FSL_USB_VER_1_6) - setbits32(hcd->regs + FSL_SOC_USB_CTRL, 0x4); + clrsetbits_be32(hcd->regs + FSL_SOC_USB_CTRL, + CONTROL_REGISTER_W1C_MASK, 0x4); + + /* + * Enable UTMI phy and program PTS field in UTMI mode before asserting + * controller reset for USB Controller version 2.5 + */ + if (pdata->has_fsl_erratum_a007792) { + clrsetbits_be32(hcd->regs + FSL_SOC_USB_CTRL, + CONTROL_REGISTER_W1C_MASK, CTRL_UTMI_PHY_EN); + writel(PORT_PTS_UTMI, hcd->regs + FSL_SOC_USB_PORTSC1); + } /* Don't need to set host mode here. It will be done by tdi_reset() */ retval = usb_add_hcd(hcd, irq, IRQF_SHARED); if (retval != 0) - goto err4; + goto err2; + device_wakeup_enable(hcd->self.controller); #ifdef CONFIG_USB_OTG if (pdata->operating_mode == FSL_USB2_DR_OTG) { struct ehci_hcd *ehci = hcd_to_ehci(hcd); - hcd->phy = usb_get_phy(USB_PHY_TYPE_USB2); + hcd->usb_phy = usb_get_phy(USB_PHY_TYPE_USB2); dev_dbg(&pdev->dev, "hcd=0x%p ehci=0x%p, phy=0x%p\n", - hcd, ehci, hcd->phy); + hcd, ehci, hcd->usb_phy); - if (!IS_ERR_OR_NULL(hcd->phy)) { - retval = otg_set_host(hcd->phy->otg, + if (!IS_ERR_OR_NULL(hcd->usb_phy)) { + retval = otg_set_host(hcd->usb_phy->otg, &ehci_to_hcd(ehci)->self); if (retval) { - usb_put_phy(hcd->phy); - goto err4; + usb_put_phy(hcd->usb_phy); + goto err2; } } else { dev_err(&pdev->dev, "can't find phy\n"); retval = -ENODEV; - goto err4; + goto err2; } } #endif return retval; - err4: - iounmap(hcd->regs); - err3: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); err2: usb_put_hcd(hcd); err1: @@ -176,40 +180,6 @@ return retval; } -/* may be called without controller electrically present */ -/* may be called with controller, bus, and devices active */ - -/** - * usb_hcd_fsl_remove - shutdown processing for FSL-based HCDs - * @dev: USB Host Controller being removed - * Context: !in_interrupt() - * - * Reverses the effect of usb_hcd_fsl_probe(). - * - */ -static void usb_hcd_fsl_remove(struct usb_hcd *hcd, - struct platform_device *pdev) -{ - struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data; - - if (!IS_ERR_OR_NULL(hcd->phy)) { - otg_set_host(hcd->phy->otg, NULL); - usb_put_phy(hcd->phy); - } - - usb_remove_hcd(hcd); - - /* - * do platform specific un-initialization: - * release iomux pins, disable clock, etc. - */ - if (pdata->exit) - pdata->exit(pdev); - iounmap(hcd->regs); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - usb_put_hcd(hcd); -} - static int ehci_fsl_setup_phy(struct usb_hcd *hcd, enum fsl_usb2_phy_modes phy_mode, unsigned int port_offset) @@ -218,7 +188,7 @@ 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->platform_data; + struct fsl_usb2_platform_data *pdata = dev_get_platdata(dev); if (pdata->controller_ver < 0) { dev_warn(hcd->self.controller, "Could not get controller version\n"); @@ -232,9 +202,11 @@ case FSL_USB2_PHY_ULPI: if (pdata->have_sysif_regs && pdata->controller_ver) { /* controller version 1.6 or above */ - clrbits32(non_ehci + FSL_SOC_USB_CTRL, UTMI_PHY_EN); - setbits32(non_ehci + FSL_SOC_USB_CTRL, - ULPI_PHY_CLK_SEL | USB_CTRL_USB_EN); + clrbits32(non_ehci + FSL_SOC_USB_CTRL, + CONTROL_REGISTER_W1C_MASK | UTMI_PHY_EN); + clrsetbits_be32(non_ehci + FSL_SOC_USB_CTRL, + CONTROL_REGISTER_W1C_MASK, + ULPI_PHY_CLK_SEL | USB_CTRL_USB_EN); } portsc |= PORT_PTS_ULPI; break; @@ -245,29 +217,33 @@ portsc |= PORT_PTS_PTW; /* fall through */ case FSL_USB2_PHY_UTMI: + case FSL_USB2_PHY_UTMI_DUAL: if (pdata->have_sysif_regs && pdata->controller_ver) { /* controller version 1.6 or above */ - setbits32(non_ehci + FSL_SOC_USB_CTRL, UTMI_PHY_EN); + clrsetbits_be32(non_ehci + FSL_SOC_USB_CTRL, + CONTROL_REGISTER_W1C_MASK, UTMI_PHY_EN); mdelay(FSL_UTMI_PHY_DLY); /* Delay for UTMI PHY CLK to become stable - 10ms*/ } /* enable UTMI PHY */ if (pdata->have_sysif_regs) - setbits32(non_ehci + FSL_SOC_USB_CTRL, - CTRL_UTMI_PHY_EN); + clrsetbits_be32(non_ehci + FSL_SOC_USB_CTRL, + CONTROL_REGISTER_W1C_MASK, + CTRL_UTMI_PHY_EN); portsc |= PORT_PTS_UTMI; break; case FSL_USB2_PHY_NONE: break; } - if (pdata->have_sysif_regs && - pdata->controller_ver > FSL_USB_VER_1_6 && - (phy_mode == FSL_USB2_PHY_ULPI)) { - /* check PHY_CLK_VALID to get phy clk valid */ - if (!spin_event_timeout(in_be32(non_ehci + FSL_SOC_USB_CTRL) & - PHY_CLK_VALID, FSL_USB_PHY_CLK_TIMEOUT, 0)) { - printk(KERN_WARNING "fsl-ehci: USB PHY clock invalid\n"); + /* + * check PHY_CLK_VALID to determine phy clock presence before writing + * to portsc + */ + if (pdata->check_phy_clk_valid) { + if (!(in_be32(non_ehci + FSL_SOC_USB_CTRL) & PHY_CLK_VALID)) { + dev_warn(hcd->self.controller, + "USB PHY clock invalid\n"); return -EINVAL; } } @@ -275,7 +251,8 @@ ehci_writel(ehci, portsc, &ehci->regs->port_status[port_offset]); if (phy_mode != FSL_USB2_PHY_ULPI && pdata->have_sysif_regs) - setbits32(non_ehci + FSL_SOC_USB_CTRL, USB_CTRL_USB_EN); + clrsetbits_be32(non_ehci + FSL_SOC_USB_CTRL, + CONTROL_REGISTER_W1C_MASK, USB_CTRL_USB_EN); return 0; } @@ -286,7 +263,7 @@ struct fsl_usb2_platform_data *pdata; void __iomem *non_ehci = hcd->regs; - pdata = hcd->self.controller->platform_data; + pdata = dev_get_platdata(hcd->self.controller); if (pdata->have_sysif_regs) { /* @@ -301,6 +278,10 @@ out_be32(non_ehci + FSL_SOC_USB_SNOOP2, 0x80000000 | SNOOP_SIZE_2GB); } + /* Deal with USB erratum A-005275 */ + if (pdata->has_fsl_erratum_a005275 == 1) + ehci->has_fsl_hs_errata = 1; + if ((pdata->operating_mode == FSL_USB2_DR_HOST) || (pdata->operating_mode == FSL_USB2_DR_OTG)) if (ehci_fsl_setup_phy(hcd, pdata->phy_mode, 0)) @@ -358,7 +339,7 @@ struct device *dev; dev = hcd->self.controller; - pdata = hcd->self.controller->platform_data; + pdata = dev_get_platdata(hcd->self.controller); ehci->big_endian_desc = pdata->big_endian_desc; ehci->big_endian_mmio = pdata->big_endian_mmio; @@ -410,10 +391,10 @@ { struct usb_hcd *hcd = dev_get_drvdata(dev); struct ehci_hcd *ehci = hcd_to_ehci(hcd); - struct fsl_usb2_platform_data *pdata = dev->platform_data; + struct fsl_usb2_platform_data *pdata = dev_get_platdata(dev); u32 tmp; -#ifdef DEBUG +#ifdef CONFIG_DYNAMIC_DEBUG u32 mode = ehci_readl(ehci, hcd->regs + FSL_SOC_USB_USBMODE); mode &= USBMODE_CM_MASK; tmp = ehci_readl(ehci, hcd->regs + 0x140); /* usbcmd */ @@ -479,7 +460,7 @@ { struct usb_hcd *hcd = dev_get_drvdata(dev); struct ehci_hcd *ehci = hcd_to_ehci(hcd); - struct fsl_usb2_platform_data *pdata = dev->platform_data; + struct fsl_usb2_platform_data *pdata = dev_get_platdata(dev); u32 tmp; dev_dbg(dev, "suspend=%d already_suspended=%d\n", @@ -639,7 +620,7 @@ if (!(status & PORT_CONNECT)) return -ENODEV; - /* khubd will finish the reset later */ + /* hub_wq will finish the reset later */ if (ehci_is_TDI(ehci)) { writel(PORT_RESET | (status & ~(PORT_CSC | PORT_PEC | PORT_OCC)), @@ -654,79 +635,77 @@ #define ehci_start_port_reset NULL #endif /* CONFIG_USB_OTG */ +static struct ehci_driver_overrides ehci_fsl_overrides __initdata = { + .extra_priv_size = sizeof(struct ehci_fsl), + .reset = ehci_fsl_setup, +}; -static const struct hc_driver ehci_fsl_hc_driver = { - .description = hcd_name, - .product_desc = "Freescale On-Chip EHCI Host Controller", - .hcd_priv_size = sizeof(struct ehci_fsl), +/** + * fsl_ehci_drv_remove - shutdown processing for FSL-based HCDs + * @dev: USB Host Controller being removed + * Context: !in_interrupt() + * + * Reverses the effect of usb_hcd_fsl_probe(). + * + */ - /* - * generic hardware linkage - */ - .irq = ehci_irq, - .flags = HCD_USB2 | HCD_MEMORY, +static int fsl_ehci_drv_remove(struct platform_device *pdev) +{ + struct fsl_usb2_platform_data *pdata = dev_get_platdata(&pdev->dev); + struct usb_hcd *hcd = platform_get_drvdata(pdev); - /* - * basic lifecycle operations - */ - .reset = ehci_fsl_setup, - .start = ehci_run, - .stop = ehci_stop, - .shutdown = ehci_shutdown, + if (!IS_ERR_OR_NULL(hcd->usb_phy)) { + otg_set_host(hcd->usb_phy->otg, NULL); + usb_put_phy(hcd->usb_phy); + } - /* - * managing i/o requests and associated device resources - */ - .urb_enqueue = ehci_urb_enqueue, - .urb_dequeue = ehci_urb_dequeue, - .endpoint_disable = ehci_endpoint_disable, - .endpoint_reset = ehci_endpoint_reset, + usb_remove_hcd(hcd); /* - * scheduling support + * do platform specific un-initialization: + * release iomux pins, disable clock, etc. */ - .get_frame_number = ehci_get_frame, + if (pdata->exit) + pdata->exit(pdev); + usb_put_hcd(hcd); - /* - * root hub support - */ - .hub_status_data = ehci_hub_status_data, - .hub_control = ehci_hub_control, - .bus_suspend = ehci_bus_suspend, - .bus_resume = ehci_bus_resume, - .start_port_reset = ehci_start_port_reset, - .relinquish_port = ehci_relinquish_port, - .port_handed_over = ehci_port_handed_over, + return 0; +} - .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, +static struct platform_driver ehci_fsl_driver = { + .probe = fsl_ehci_drv_probe, + .remove = fsl_ehci_drv_remove, + .shutdown = usb_hcd_platform_shutdown, + .driver = { + .name = "fsl-ehci", + .pm = EHCI_FSL_PM_OPS, + }, }; -static int ehci_fsl_drv_probe(struct platform_device *pdev) +static int __init ehci_fsl_init(void) { if (usb_disabled()) return -ENODEV; - /* FIXME we only want one one probe() not two */ - return usb_hcd_fsl_probe(&ehci_fsl_hc_driver, pdev); -} + pr_info(DRV_NAME ": " DRIVER_DESC "\n"); -static int ehci_fsl_drv_remove(struct platform_device *pdev) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); + ehci_init_driver(&fsl_ehci_hc_driver, &ehci_fsl_overrides); - /* FIXME we only want one one remove() not two */ - usb_hcd_fsl_remove(hcd, pdev); - return 0; + fsl_ehci_hc_driver.product_desc = + "Freescale On-Chip EHCI Host Controller"; + fsl_ehci_hc_driver.start_port_reset = ehci_start_port_reset; + + + return platform_driver_register(&ehci_fsl_driver); } +module_init(ehci_fsl_init); -MODULE_ALIAS("platform:fsl-ehci"); +static void __exit ehci_fsl_cleanup(void) +{ + platform_driver_unregister(&ehci_fsl_driver); +} +module_exit(ehci_fsl_cleanup); -static struct platform_driver ehci_fsl_driver = { - .probe = ehci_fsl_drv_probe, - .remove = ehci_fsl_drv_remove, - .shutdown = usb_hcd_platform_shutdown, - .driver = { - .name = "fsl-ehci", - .pm = EHCI_FSL_PM_OPS, - }, -}; +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:" DRV_NAME);