linux-mips
[Top] [All Lists]

[PATCH/RFC v1 08/12] [MIPS] BCM63XX: Add USB EHCI support.

To: dbrownell@users.sourceforge.net
Subject: [PATCH/RFC v1 08/12] [MIPS] BCM63XX: Add USB EHCI support.
From: Maxime Bizon <mbizon@freebox.fr>
Date: Sun, 19 Oct 2008 04:07:03 +0200
Cc: linux-mips@linux-mips.org, linux-usb@vger.kernel.org, Maxime Bizon <mbizon@freebox.fr>
Original-recipient: rfc822;linux-mips@linux-mips.org
Sender: linux-mips-bounce@linux-mips.org
Signed-off-by: Maxime Bizon <mbizon@freebox.fr>
---
 arch/mips/bcm63xx/Kconfig                          |    2 +
 arch/mips/bcm63xx/Makefile                         |    1 +
 arch/mips/bcm63xx/dev-usb-ehci.c                   |   50 +++++++
 .../asm/mach-bcm63xx/bcm63xx_dev_usb_ehci.h        |    6 +
 drivers/usb/host/ehci-bcm63xx.c                    |  152 ++++++++++++++++++++
 drivers/usb/host/ehci-hcd.c                        |    5 +
 drivers/usb/host/ehci.h                            |    5 +
 7 files changed, 221 insertions(+), 0 deletions(-)
 create mode 100644 arch/mips/bcm63xx/dev-usb-ehci.c
 create mode 100644 arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_usb_ehci.h
 create mode 100644 drivers/usb/host/ehci-bcm63xx.c

diff --git a/arch/mips/bcm63xx/Kconfig b/arch/mips/bcm63xx/Kconfig
index f2ddb87..be120f7 100644
--- a/arch/mips/bcm63xx/Kconfig
+++ b/arch/mips/bcm63xx/Kconfig
@@ -14,4 +14,6 @@ config BCM63XX_CPU_6358
        select USB_ARCH_HAS_OHCI
        select USB_OHCI_BIG_ENDIAN_DESC
        select USB_OHCI_BIG_ENDIAN_MMIO
+       select USB_ARCH_HAS_EHCI
+       select USB_EHCI_BIG_ENDIAN_MMIO
 endmenu
diff --git a/arch/mips/bcm63xx/Makefile b/arch/mips/bcm63xx/Makefile
index 75f0d54..99e335d 100644
--- a/arch/mips/bcm63xx/Makefile
+++ b/arch/mips/bcm63xx/Makefile
@@ -2,4 +2,5 @@ obj-y           += clk.o cpu.o cs.o gpio.o irq.o prom.o setup.o 
timer.o
 obj-y          += dev-uart.o
 obj-y          += dev-pcmcia.o
 obj-y          += dev-usb-ohci.o
+obj-y          += dev-usb-ehci.o
 obj-$(CONFIG_EARLY_PRINTK)     += early_printk.o
diff --git a/arch/mips/bcm63xx/dev-usb-ehci.c b/arch/mips/bcm63xx/dev-usb-ehci.c
new file mode 100644
index 0000000..7885405
--- /dev/null
+++ b/arch/mips/bcm63xx/dev-usb-ehci.c
@@ -0,0 +1,50 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr>
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <bcm63xx_cpu.h>
+#include <bcm63xx_dev_usb_ehci.h>
+
+static struct resource ehci_resources[] = {
+       {
+               .start          = -1, /* filled at runtime */
+               .end            = -1, /* filled at runtime */
+               .flags          = IORESOURCE_MEM,
+       },
+       {
+               .start          = -1, /* filled at runtime */
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+static u64 ehci_dmamask = ~(u32)0;
+
+static struct platform_device bcm63xx_ehci_device = {
+       .name           = "bcm63xx_ehci",
+       .id             = 0,
+       .num_resources  = ARRAY_SIZE(ehci_resources),
+       .resource       = ehci_resources,
+       .dev            = {
+               .dma_mask               = &ehci_dmamask,
+               .coherent_dma_mask      = 0xffffffff,
+       },
+};
+
+int __init bcm63xx_ehci_register(void)
+{
+       if (!BCMCPU_IS_6358())
+               return 0;
+
+       ehci_resources[0].start = bcm63xx_regset_address(RSET_EHCI0);
+       ehci_resources[0].end = ehci_resources[0].start;
+       ehci_resources[0].end += RSET_EHCI_SIZE - 1;
+       ehci_resources[1].start = bcm63xx_get_irq_number(IRQ_EHCI0);
+       return platform_device_register(&bcm63xx_ehci_device);
+}
diff --git a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_usb_ehci.h 
b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_usb_ehci.h
new file mode 100644
index 0000000..17fb519
--- /dev/null
+++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_usb_ehci.h
@@ -0,0 +1,6 @@
+#ifndef BCM63XX_DEV_USB_EHCI_H_
+#define BCM63XX_DEV_USB_EHCI_H_
+
+int bcm63xx_ehci_register(void);
+
+#endif /* BCM63XX_DEV_USB_EHCI_H_ */
diff --git a/drivers/usb/host/ehci-bcm63xx.c b/drivers/usb/host/ehci-bcm63xx.c
new file mode 100644
index 0000000..2fef571
--- /dev/null
+++ b/drivers/usb/host/ehci-bcm63xx.c
@@ -0,0 +1,152 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr>
+ */
+
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <bcm63xx_cpu.h>
+#include <bcm63xx_regs.h>
+#include <bcm63xx_io.h>
+
+static int ehci_bcm63xx_setup(struct usb_hcd *hcd)
+{
+       struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+       int retval;
+
+       retval = ehci_halt(ehci);
+       if (retval)
+               return retval;
+
+       retval = ehci_init(hcd);
+       if (retval)
+               return retval;
+
+       hcd->has_tt = 1;
+       ehci_reset(ehci);
+       ehci_port_power(ehci, 0);
+
+       return retval;
+}
+
+
+static const struct hc_driver ehci_bcm63xx_hc_driver = {
+       .description =          hcd_name,
+       .product_desc =         "BCM63XX integrated EHCI controller",
+       .hcd_priv_size =        sizeof(struct ehci_hcd),
+
+       .irq =                  ehci_irq,
+       .flags =                HCD_MEMORY | HCD_USB2,
+
+       .reset =                ehci_bcm63xx_setup,
+       .start =                ehci_run,
+       .stop =                 ehci_stop,
+       .shutdown =             ehci_shutdown,
+
+       .urb_enqueue =          ehci_urb_enqueue,
+       .urb_dequeue =          ehci_urb_dequeue,
+       .endpoint_disable =     ehci_endpoint_disable,
+
+       .get_frame_number =     ehci_get_frame,
+
+       .hub_status_data =      ehci_hub_status_data,
+       .hub_control =          ehci_hub_control,
+       .bus_suspend =          ehci_bus_suspend,
+       .bus_resume =           ehci_bus_resume,
+       .relinquish_port =      ehci_relinquish_port,
+       .port_handed_over =     ehci_port_handed_over,
+};
+
+static int __devinit ehci_hcd_bcm63xx_drv_probe(struct platform_device *pdev)
+{
+       struct resource *res_mem, *res_irq;
+       struct usb_hcd *hcd;
+       struct ehci_hcd *ehci;
+       u32 reg;
+       int ret;
+
+       res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (!res_mem || !res_irq)
+               return -ENODEV;
+
+       reg = bcm_rset_readl(RSET_USBH_PRIV, USBH_PRIV_SWAP_REG);
+       reg &= ~USBH_PRIV_SWAP_EHCI_DATA_MASK;
+       reg |= USBH_PRIV_SWAP_EHCI_ENDN_MASK;
+       bcm_rset_writel(RSET_USBH_PRIV, reg, USBH_PRIV_SWAP_REG);
+
+       /* don't ask... */
+       bcm_rset_writel(RSET_USBH_PRIV, 0x1c0020, USBH_PRIV_TEST_REG);
+
+       hcd = usb_create_hcd(&ehci_bcm63xx_hc_driver, &pdev->dev, "bcm63xx");
+       if (!hcd)
+               return -ENOMEM;
+       hcd->rsrc_start = res_mem->start;
+       hcd->rsrc_len = res_mem->end - res_mem->start + 1;
+
+       if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
+               pr_debug("request_mem_region failed\n");
+               ret = -EBUSY;
+               goto out;
+       }
+
+       hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+       if (!hcd->regs) {
+               pr_debug("ioremap failed\n");
+               ret = -EIO;
+               goto out1;
+       }
+
+       ehci = hcd_to_ehci(hcd);
+       ehci->big_endian_mmio = 1;
+       ehci->big_endian_desc = 0;
+       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);
+       ehci->sbrn = 0x20;
+
+       ret = usb_add_hcd(hcd, res_irq->start, IRQF_DISABLED);
+       if (ret)
+               goto out2;
+
+       platform_set_drvdata(pdev, hcd);
+       return 0;
+
+out2:
+       iounmap(hcd->regs);
+out1:
+       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+out:
+       usb_put_hcd(hcd);
+       return ret;
+}
+
+static int __devexit ehci_hcd_bcm63xx_drv_remove(struct platform_device *pdev)
+{
+       struct usb_hcd *hcd;
+
+       hcd = platform_get_drvdata(pdev);
+       usb_remove_hcd(hcd);
+       iounmap(hcd->regs);
+       usb_put_hcd(hcd);
+       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+       platform_set_drvdata(pdev, NULL);
+       return 0;
+}
+
+static struct platform_driver ehci_hcd_bcm63xx_driver = {
+       .probe          = ehci_hcd_bcm63xx_drv_probe,
+       .remove         = __devexit_p(ehci_hcd_bcm63xx_drv_remove),
+       .shutdown       = usb_hcd_platform_shutdown,
+       .driver         = {
+               .name   = "bcm63xx_ehci",
+               .owner  = THIS_MODULE,
+               .bus    = &platform_bus_type
+       },
+};
+
+MODULE_ALIAS("platform:bcm63xx_ehci");
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 8409e07..3230ba3 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -1040,6 +1040,11 @@ MODULE_LICENSE ("GPL");
 #define        PLATFORM_DRIVER         ixp4xx_ehci_driver
 #endif
 
+#ifdef CONFIG_BCM63XX
+#include "ehci-bcm63xx.c"
+#define        PLATFORM_DRIVER         ehci_hcd_bcm63xx_driver
+#endif
+
 #if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \
     !defined(PS3_SYSTEM_BUS_DRIVER) && !defined(OF_PLATFORM_DRIVER)
 #error "missing bus glue for ehci-hcd"
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index b697a13..5aae343 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -619,6 +619,11 @@ ehci_port_speed(struct ehci_hcd *ehci, unsigned int portsc)
 #define writel_be(val, addr)   __raw_writel(val, (__force unsigned *)addr)
 #endif
 
+#if defined(CONFIG_MIPS) && defined(CONFIG_BCM63XX)
+#define readl_be(addr)         __raw_readl((__force unsigned *)addr)
+#define writel_be(val, addr)   __raw_writel(val, (__force unsigned *)addr)
+#endif
+
 static inline unsigned int ehci_readl(const struct ehci_hcd *ehci,
                __u32 __iomem * regs)
 {
-- 
1.5.4.3


<Prev in Thread] Current Thread [Next in Thread>
  • [PATCH/RFC v1 08/12] [MIPS] BCM63XX: Add USB EHCI support., Maxime Bizon <=