Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754854Ab0K2D6U (ORCPT ); Sun, 28 Nov 2010 22:58:20 -0500 Received: from mail-fx0-f46.google.com ([209.85.161.46]:34007 "EHLO mail-fx0-f46.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754730Ab0K2D6S convert rfc822-to-8bit (ORCPT ); Sun, 28 Nov 2010 22:58:18 -0500 DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=mime-version:in-reply-to:references:date:message-id:subject:from:to :cc:content-type:content-transfer-encoding; b=Dj4dcbe7/GrETDJ/KnE04rCX8fdtHCNLJRuro7Ca45qc4Lcpr/VXqYsffec8OAuTOt OMT94CbPwmLDbd8QMHDXovVldi82C8T0BjGkhocYTVxUQTnKpUM95uihYUFCMlQ0cZLr hBXJsE2O+FOCuESE5fnqXGvgQcDXENJV12y0o= MIME-Version: 1.0 In-Reply-To: References: <20101125171541.GA18152@suse.de> <20101126151131.GA26602@oksana.dev.rtsoft.ru> <20101126170348.GA3331@suse.de> <20101126182328.GA20923@oksana.dev.rtsoft.ru> Date: Mon, 29 Nov 2010 11:58:15 +0800 Message-ID: Subject: Re: [PATCH v3 1/1] USB: cns3xxx: Add EHCI and OHCI bus glue for cns3xxx SOCs From: Lin Mac To: Anton Vorontsov Cc: Greg KH , Alan Stern , linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, dbrownell@users.sourceforge.net, linux-usb@vger.kernel.org Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 8BIT Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 19674 Lines: 565 2010/11/27 Lin Mac : > 2010/11/27 Anton Vorontsov : >> On Fri, Nov 26, 2010 at 09:03:48AM -0800, Greg KH wrote: >> [...] >>> > > As far as the callbacks are concerned, this looks fine. >>> > > >>> > > Acked-by: Alan Stern >>> > >>> > Thanks Alan! >>> > >>> > Greg, should I treat your 'to ack it as well' as 'Acked-by'? :-) >>> >>> Yes please: >>> ? ? ? Acked-by: Greg Kroah-Hartman >> >> Thanks! >> >> >> Lin, >> >> Now that I tried these patches on the real hardware (EV1.3, >> silicon ver. 0xA), USB doesn't seem to work for me. FWIW, >> I use U-Boot from BSP release 1.0. >> >> Here is how it looks: >> >> ehci_hcd: USB 2.0 'Enhanced' Host Controller (EHCI) Driver >> cns3xxx-ehci cns3xxx-ehci.0: CNS3XXX EHCI Host Controller >> cns3xxx-ehci cns3xxx-ehci.0: new USB bus registered, assigned bus number 1 >> cns3xxx-ehci cns3xxx-ehci.0: irq 64, io mem 0x82000000 >> cns3xxx-ehci cns3xxx-ehci.0: USB 0.0 started, EHCI 0.00 >> hub 1-0:1.0: USB hub found >> hub 1-0:1.0: 0 ports detected >> ohci_hcd: USB 1.1 'Open' Host Controller (OHCI) Driver >> cns3xxx-ohci cns3xxx-ohci.0: CNS3XXX OHCI Host controller >> cns3xxx-ohci cns3xxx-ohci.0: new USB bus registered, assigned bus number 2 >> cns3xxx-ohci cns3xxx-ohci.0: irq 91, io mem 0x88000000 >> cns3xxx-ohci cns3xxx-ohci.0: init err (00000000 0000) >> ohci_hcd: can't start cns3xxx-ohci.0 >> cns3xxx-ohci cns3xxx-ohci.0: startup error -75 >> cns3xxx-ohci cns3xxx-ohci.0: USB bus 2 deregistered >> cns3xxx-ohci: probe of cns3xxx-ohci.0 failed with error -75 >> >> I assume this is somehow related to the old hardware I use, >> but please take a look. >> >> I tried this on both 2.6.36 and 2.6.37-rc3. You can find your >> patches in this tree >> >> ?git://git.infradead.org/users/cbou/linux-cns3xxx.git master >> >> I'll try to investigate (found a small issue already, patch >> down below), but if you beat me to it, please send a patch >> agaist the cns3xxx tree. >> Thanks, > I saw this issue on EVB v1.3 chip rev B, with your tree. > I'll do more test and see what I can do there. > Sorry that I didn't notice it more earlier. > >> - - - - >> ARM: cns3xxx: Make cns3xxx_pwr_soft_rst_force() to actually reset blocks >> >> commit 6eb5d146d4535 ("ARM: cns3xxx: Use IO memory accessors everywhere") >> breaks cns3xxx_pwr_soft_rst_force() function, so that it doesn't write >> cleared bit into the register. >> >> This patch fixes the issue by adding the necessary __raw_writel(). >> >> Signed-off-by: Anton Vorontsov >> --- >> ?arch/arm/mach-cns3xxx/pm.c | ? ?1 + >> ?1 files changed, 1 insertions(+), 0 deletions(-) >> >> diff --git a/arch/arm/mach-cns3xxx/pm.c b/arch/arm/mach-cns3xxx/pm.c >> index 78fbaba..5e57955 100644 >> --- a/arch/arm/mach-cns3xxx/pm.c >> +++ b/arch/arm/mach-cns3xxx/pm.c >> @@ -67,6 +67,7 @@ static void cns3xxx_pwr_soft_rst_force(unsigned int block) >> ? ? ? ? ? ? ? ?reg &= ~(block & PM_SOFT_RST_REG_MASK); >> ? ? ? ?} else { >> ? ? ? ? ? ? ? ?reg &= ~(block & PM_SOFT_RST_REG_MASK); >> + ? ? ? ? ? ? ? __raw_writel(reg, PM_SOFT_RST_REG); >> ? ? ? ? ? ? ? ?reg |= (block & PM_SOFT_RST_REG_MASK); >> ? ? ? ?} >> >> -- >> 1.7.0.5 >> >> > 2010/11/25 : > From: Mac Lin > > The CNS3XXX SOC has include USB EHCI and OHCI compatible controllers. This > patch adds the necessary glue logic to allow ehci-hcd and ohci-hcd drivers to > work on CNS3XXX > > The EHCI and OHCI controllers share a common clock control and reset bit, > therefore additional check for the timming of enabling and disabling is > required. The USB bit of PLL Power Down Control is also shared by OTG, 24MHz > UART clock, Crypto clock, PCIe reference clock, and Clock Scale Generator. > Therefore we only ensure it is enabled, while not disabling it. > > Signed-off-by: Mac Lin > --- > drivers/usb/Kconfig | 2 + > drivers/usb/host/Kconfig | 15 ++++ > drivers/usb/host/ehci-cns3xxx.c | 171 +++++++++++++++++++++++++++++++++++++++ > drivers/usb/host/ehci-hcd.c | 5 + > drivers/usb/host/ohci-cns3xxx.c | 165 +++++++++++++++++++++++++++++++++++++ > drivers/usb/host/ohci-hcd.c | 5 + > 6 files changed, 363 insertions(+), 0 deletions(-) > create mode 100644 drivers/usb/host/ehci-cns3xxx.c > create mode 100644 drivers/usb/host/ohci-cns3xxx.c > > diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig > index 67eb377..5a7c8f1 100644 > --- a/drivers/usb/Kconfig > +++ b/drivers/usb/Kconfig > @@ -41,6 +41,7 @@ config USB_ARCH_HAS_OHCI > default y if MFD_TC6393XB > default y if ARCH_W90X900 > default y if ARCH_DAVINCI_DA8XX > + default y if ARCH_CNS3XXX > # PPC: > default y if STB03xxx > default y if PPC_MPC52xx > @@ -66,6 +67,7 @@ config USB_ARCH_HAS_EHCI > default y if ARCH_AT91SAM9G45 > default y if ARCH_MXC > default y if ARCH_OMAP3 > + default y if ARCH_CNS3XXX > default PCI > > # ARM SA1111 chips have a non-PCI based "OHCI-compatible" USB host interface. > diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig > index 6f4f8e6..f8970d1 100644 > --- a/drivers/usb/host/Kconfig > +++ b/drivers/usb/host/Kconfig > @@ -147,6 +147,14 @@ config USB_W90X900_EHCI > ---help--- > Enables support for the W90X900 USB controller > > +config USB_CNS3XXX_EHCI > + bool "Cavium CNS3XXX EHCI Module" > + depends on USB_EHCI_HCD && ARCH_CNS3XXX > + ---help--- > + Enable support for the CNS3XXX SOC's on-chip EHCI controller. > + It is needed for high-speed (480Mbit/sec) USB 2.0 device > + support. > + > config USB_OXU210HP_HCD > tristate "OXU210HP HCD support" > depends on USB > @@ -286,6 +294,13 @@ config USB_OHCI_HCD_SSB > > If unsure, say N. > > +config USB_CNS3XXX_OHCI > + bool "Cavium CNS3XXX OHCI Module" > + depends on USB_OHCI_HCD && ARCH_CNS3XXX > + ---help--- > + Enable support for the CNS3XXX SOC's on-chip OHCI controller. > + It is needed for low-speed USB 1.0 device support. > + > config USB_OHCI_BIG_ENDIAN_DESC > bool > depends on USB_OHCI_HCD > diff --git a/drivers/usb/host/ehci-cns3xxx.c b/drivers/usb/host/ehci-cns3xxx.c > new file mode 100644 > index 0000000..9cf6696 > --- /dev/null > +++ b/drivers/usb/host/ehci-cns3xxx.c > @@ -0,0 +1,171 @@ > +/* > + * Copyright 2008 Cavium Networks > + * > + * This file is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License, Version 2, as > + * published by the Free Software Foundation. > + */ > + > +#include > +#include > +#include > +#include > + > +static int cns3xxx_ehci_init(struct usb_hcd *hcd) > +{ > + struct ehci_hcd *ehci = hcd_to_ehci(hcd); > + int retval; > + > + /* > + * EHCI and OHCI share the same clock and power, > + * resetting twice would cause the 1st controller been reset. > + * Therefore only do power up at the first up device, and > + * power down at the last down device. > + * > + * Set USB AHB INCR length to 16 > + */ > + if (atomic_inc_return(&usb_pwr_ref) == 0) { There's a typo here, the 0 should be 1 instead. > + cns3xxx_pwr_power_up(1 << PM_PLL_HM_PD_CTRL_REG_OFFSET_PLL_USB); > + cns3xxx_pwr_clk_en(1 << PM_CLK_GATE_REG_OFFSET_USB_HOST); > + cns3xxx_pwr_soft_rst(1 << PM_SOFT_RST_REG_OFFST_USB_HOST); > + __raw_writel((__raw_readl(MISC_CHIP_CONFIG_REG) | (0X2 << 24)), > + MISC_CHIP_CONFIG_REG); > + } > + > + ehci->caps = hcd->regs; > + ehci->regs = hcd->regs > + + HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase)); > + ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params); > + > + hcd->has_tt = 0; > + ehci_reset(ehci); > + > + retval = ehci_init(hcd); > + if (retval) > + return retval; > + > + ehci_port_power(ehci, 0); > + > + return retval; > +} > + > +static const struct hc_driver cns3xxx_ehci_hc_driver = { > + .description = hcd_name, > + .product_desc = "CNS3XXX EHCI Host Controller", > + .hcd_priv_size = sizeof(struct ehci_hcd), > + .irq = ehci_irq, > + .flags = HCD_MEMORY | HCD_USB2, > + .reset = cns3xxx_ehci_init, > + .start = ehci_run, > + .stop = ehci_stop, > + .shutdown = ehci_shutdown, > + .urb_enqueue = ehci_urb_enqueue, > + .urb_dequeue = ehci_urb_dequeue, > + .endpoint_disable = ehci_endpoint_disable, > + .endpoint_reset = ehci_endpoint_reset, > + .get_frame_number = ehci_get_frame, > + .hub_status_data = ehci_hub_status_data, > + .hub_control = ehci_hub_control, > +#ifdef CONFIG_PM > + .bus_suspend = ehci_bus_suspend, > + .bus_resume = ehci_bus_resume, > +#endif > + .relinquish_port = ehci_relinquish_port, > + .port_handed_over = ehci_port_handed_over, > + > + .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, > +}; > + > +static int cns3xxx_ehci_probe(struct platform_device *pdev) > +{ > + struct device *dev = &pdev->dev; > + struct usb_hcd *hcd; > + const struct hc_driver *driver = &cns3xxx_ehci_hc_driver; > + struct resource *res; > + int irq; > + int retval; > + > + if (usb_disabled()) > + return -ENODEV; > + > + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); > + if (!res) { > + dev_err(dev, "Found HC with no IRQ.\n"); > + return -ENODEV; > + } > + irq = res->start; > + > + hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev)); > + if (!hcd) > + return -ENOMEM; > + > + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); > + if (!res) { > + dev_err(dev, "Found HC with no register addr.\n"); > + retval = -ENODEV; > + goto err1; > + } > + > + hcd->rsrc_start = res->start; > + hcd->rsrc_len = res->end - res->start + 1; > + > + if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, > + driver->description)) { > + dev_dbg(dev, "controller already in use\n"); > + retval = -EBUSY; > + goto err1; > + } > + > + hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); > + if (hcd->regs == NULL) { > + dev_dbg(dev, "error mapping memory\n"); > + retval = -EFAULT; > + goto err2; > + } > + > + retval = usb_add_hcd(hcd, irq, IRQF_SHARED); > + if (retval == 0) > + return retval; > + > + iounmap(hcd->regs); > +err2: > + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); > +err1: > + usb_put_hcd(hcd); > + > + return retval; > +} > + > +static int cns3xxx_ehci_remove(struct platform_device *pdev) > +{ > + struct usb_hcd *hcd = platform_get_drvdata(pdev); > + > + usb_remove_hcd(hcd); > + iounmap(hcd->regs); > + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); > + > + /* > + * EHCI and OHCI share the same clock and power, > + * resetting twice would cause the 1st controller been reset. > + * Therefore only do power up at the first up device, and > + * power down at the last down device. > + */ > + if (atomic_dec_return(&usb_pwr_ref) == 0) > + cns3xxx_pwr_clk_dis(1 << PM_CLK_GATE_REG_OFFSET_USB_HOST); > + > + usb_put_hcd(hcd); > + > + platform_set_drvdata(pdev, NULL); > + > + return 0; > +} > + > +MODULE_ALIAS("platform:cns3xxx-ehci"); > + > +static struct platform_driver cns3xxx_ehci_driver = { > + .probe = cns3xxx_ehci_probe, > + .remove = cns3xxx_ehci_remove, > + .driver = { > + .name = "cns3xxx-ehci", > + }, > +}; > diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c > index 502a7e6..c5dd1c3 100644 > --- a/drivers/usb/host/ehci-hcd.c > +++ b/drivers/usb/host/ehci-hcd.c > @@ -1216,6 +1216,11 @@ MODULE_LICENSE ("GPL"); > #define PLATFORM_DRIVER ehci_octeon_driver > #endif > > +#ifdef CONFIG_USB_CNS3XXX_EHCI > +#include "ehci-cns3xxx.c" > +#define PLATFORM_DRIVER cns3xxx_ehci_driver > +#endif > + > #if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \ > !defined(PS3_SYSTEM_BUS_DRIVER) && !defined(OF_PLATFORM_DRIVER) && \ > !defined(XILINX_OF_PLATFORM_DRIVER) > diff --git a/drivers/usb/host/ohci-cns3xxx.c b/drivers/usb/host/ohci-cns3xxx.c > new file mode 100644 > index 0000000..f05ef87 > --- /dev/null > +++ b/drivers/usb/host/ohci-cns3xxx.c > @@ -0,0 +1,165 @@ > +/* > + * Copyright 2008 Cavium Networks > + * > + * This file is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License, Version 2, as > + * published by the Free Software Foundation. > + */ > + > +#include > +#include > +#include > +#include > + > +static int __devinit > +cns3xxx_ohci_start(struct usb_hcd *hcd) > +{ > + struct ohci_hcd *ohci = hcd_to_ohci(hcd); > + int ret; > + > + /* > + * EHCI and OHCI share the same clock and power, > + * resetting twice would cause the 1st controller been reset. > + * Therefore only do power up at the first up device, and > + * power down at the last down device. > + * > + * Set USB AHB INCR length to 16 > + */ > + if (atomic_inc_return(&usb_pwr_ref) == 1) { > + cns3xxx_pwr_power_up(1 << PM_PLL_HM_PD_CTRL_REG_OFFSET_PLL_USB); > + cns3xxx_pwr_clk_en(1 << PM_CLK_GATE_REG_OFFSET_USB_HOST); > + cns3xxx_pwr_soft_rst(1 << PM_SOFT_RST_REG_OFFST_USB_HOST); > + __raw_writel((__raw_readl(MISC_CHIP_CONFIG_REG) | (0X2 << 24)), > + MISC_CHIP_CONFIG_REG); > + } > + > + ret = ohci_init(ohci); > + if (ret < 0) > + return ret; > + > + ohci->num_ports = 1; > + > + ret = ohci_run(ohci); > + if (ret < 0) { > + err("can't start %s", hcd->self.bus_name); > + ohci_stop(hcd); > + return ret; > + } > + return 0; > +} > + > +static const struct hc_driver cns3xxx_ohci_hc_driver = { > + .description = hcd_name, > + .product_desc = "CNS3XXX OHCI Host controller", > + .hcd_priv_size = sizeof(struct ohci_hcd), > + .irq = ohci_irq, > + .flags = HCD_USB11 | HCD_MEMORY, > + .start = cns3xxx_ohci_start, > + .stop = ohci_stop, > + .shutdown = ohci_shutdown, > + .urb_enqueue = ohci_urb_enqueue, > + .urb_dequeue = ohci_urb_dequeue, > + .endpoint_disable = ohci_endpoint_disable, > + .get_frame_number = ohci_get_frame, > + .hub_status_data = ohci_hub_status_data, > + .hub_control = ohci_hub_control, > +#ifdef CONFIG_PM > + .bus_suspend = ohci_bus_suspend, > + .bus_resume = ohci_bus_resume, > +#endif > + .start_port_reset = ohci_start_port_reset, > +}; > + > +static int cns3xxx_ohci_probe(struct platform_device *pdev) > +{ > + struct device *dev = &pdev->dev; > + struct usb_hcd *hcd; > + const struct hc_driver *driver = &cns3xxx_ohci_hc_driver; > + struct resource *res; > + int irq; > + int retval; > + > + if (usb_disabled()) > + return -ENODEV; > + > + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); > + if (!res) { > + dev_err(dev, "Found HC with no IRQ.\n"); > + return -ENODEV; > + } > + irq = res->start; > + > + hcd = usb_create_hcd(driver, dev, dev_name(dev)); > + if (!hcd) > + return -ENOMEM; > + > + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); > + if (!res) { > + dev_err(dev, "Found HC with no register addr.\n"); > + retval = -ENODEV; > + goto err1; > + } > + hcd->rsrc_start = res->start; > + hcd->rsrc_len = res->end - res->start + 1; > + > + if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, > + driver->description)) { > + dev_dbg(dev, "controller already in use\n"); > + retval = -EBUSY; > + goto err1; > + } > + > + hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); > + if (!hcd->regs) { > + dev_dbg(dev, "error mapping memory\n"); > + retval = -EFAULT; > + goto err2; > + } > + > + ohci_hcd_init(hcd_to_ohci(hcd)); > + > + retval = usb_add_hcd(hcd, irq, IRQF_SHARED); > + if (retval == 0) > + return retval; > + > + iounmap(hcd->regs); > +err2: > + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); > +err1: > + usb_put_hcd(hcd); > + return retval; > +} > + > +static int cns3xxx_ohci_remove(struct platform_device *pdev) > +{ > + struct usb_hcd *hcd = platform_get_drvdata(pdev); > + > + usb_remove_hcd(hcd); > + iounmap(hcd->regs); > + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); > + > + /* > + * EHCI and OHCI share the same clock and power, > + * resetting twice would cause the 1st controller been reset. > + * Therefore only do power up at the first up device, and > + * power down at the last down device. > + */ > + if (atomic_dec_return(&usb_pwr_ref) == 0) > + cns3xxx_pwr_clk_dis(1 << PM_CLK_GATE_REG_OFFSET_USB_HOST); > + > + usb_put_hcd(hcd); > + > + platform_set_drvdata(pdev, NULL); > + > + return 0; > +} > + > +MODULE_ALIAS("platform:cns3xxx-ohci"); > + > +static struct platform_driver ohci_hcd_cns3xxx_driver = { > + .probe = cns3xxx_ohci_probe, > + .remove = cns3xxx_ohci_remove, > + .driver = { > + .name = "cns3xxx-ohci", > + }, > +}; > diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c > index 5179acb..5cb6731 100644 > --- a/drivers/usb/host/ohci-hcd.c > +++ b/drivers/usb/host/ohci-hcd.c > @@ -1111,6 +1111,11 @@ MODULE_LICENSE ("GPL"); > #define PLATFORM_DRIVER ohci_octeon_driver > #endif > > +#ifdef CONFIG_USB_CNS3XXX_OHCI > +#include "ohci-cns3xxx.c" > +#define PLATFORM_DRIVER ohci_hcd_cns3xxx_driver > +#endif > + > #if !defined(PCI_DRIVER) && \ > !defined(PLATFORM_DRIVER) && \ > !defined(OMAP1_PLATFORM_DRIVER) && \ > -- > 1.7.3 > > Should I resend the patch? Best Regard, Mac Lin -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/