This 3-part patch adds support for the big-endian OHCI implementations found on IBM's stb04xxx and Freescale's MPC52xx processors.
Patch 1 Removes byteswapped OHCI constants in preparation for dynamically handling endianness. Patch 2 Adds support for big-endian OHCI controllers. This is done primarily by applying the following transforms when dealing with controller data: ohci_readl(p) --> ohci_read(ohci, p) writel(v, p) --> ohci_writel(ohci, v, p) cpu_to_le16(v) --> cpu_to_ohci16(ohci, v) cpu_to_le16p(v) --> cpu_to_ohci16p(ohci, v) cpu_to_le32(v) --> cpu_to_ohci32(ohci, v) cpu_to_le32p(v) --> cpu_to_ohci32p(ohci, v) le16_to_cpu(v) --> ohci16_to_cpu(ohci, v) le16_to_cpup(v) --> ohci16_to_cpup(ohci, v) le32_to_cpu(v) --> ohci32_to_cpu(ohci, v) le32_to_cpup(v) --> ohci32_to_cpup(ohci, v) A bit in the flags field of struct ohci_hcd, OHCI_BIG_ENDIAN, enables the the transformed functions to support both big-endian and little-endian controllers at runtime, if needed. Patch 3 Adds support for ohci controllers (big-endian) on STB04xxx and MPC52xx Signed-off-by: Dale Farnsworth <[EMAIL PROTECTED]> diff -Nru a/drivers/usb/Kconfig b/drivers/usb/Kconfig --- a/drivers/usb/Kconfig 2004-08-02 13:33:46 -07:00 +++ b/drivers/usb/Kconfig 2004-08-02 13:33:46 -07:00 @@ -7,7 +7,7 @@ # ARM SA1111 chips have a non-PCI based "OHCI-compatible" USB host interface. config USB tristate "Support for Host-side USB" - depends on PCI || SA1111 || ARCH_OMAP1510 || ARCH_OMAP1610 || ARCH_LH7A404 + depends on PCI || SA1111 || ARCH_OMAP1510 || ARCH_OMAP1610 || ARCH_LH7A404 || STB03xxx || PPC_MPC52xx ---help--- Universal Serial Bus (USB) is a specification for a serial bus subsystem which offers higher speeds and more features than the diff -Nru a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c --- a/drivers/usb/host/ohci-hcd.c 2004-08-02 13:33:46 -07:00 +++ b/drivers/usb/host/ohci-hcd.c 2004-08-02 13:33:46 -07:00 @@ -811,10 +811,15 @@ #include "ohci-lh7a404.c" #endif +#ifdef CONFIG_PPC_OCP +#include "ohci-ocp.c" +#endif + #if !(defined(CONFIG_PCI) \ || defined(CONFIG_SA1111) \ || defined(CONFIG_ARCH_OMAP) \ || defined (CONFIG_ARCH_LH7A404) \ + || defined (CONFIG_PPC_OCP) \ ) #error "missing bus glue for ohci-hcd" #endif diff -Nru a/drivers/usb/host/ohci-ocp.c b/drivers/usb/host/ohci-ocp.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/usb/host/ohci-ocp.c 2004-08-02 13:33:46 -07:00 @@ -0,0 +1,340 @@ +/* + * OHCI HCD (Host Controller Driver) for USB. + * + * (C) Copyright 1999 Roman Weissgaerber <[EMAIL PROTECTED]> + * (C) Copyright 2000-2002 David Brownell <[EMAIL PROTECTED]> + * (C) Copyright 2002 Hewlett-Packard Company + * (C) Copyright 2003 MontaVista Software Inc. + * + * Bus Glue for PPC OCP driver + * + * Modified for ocp from ohci-sa1111.c + * by Dale Farnsworth <[EMAIL PROTECTED]> + * + * This file is licenced under the GPL. + */ + +#define DEBUG + +#include <asm/ocp.h> + +#ifdef DEBUG +#undef dbg +#define dbg(format, arg...) printk("%s: " format "\n" , __FILE__ , ## arg) +#endif + +extern int usb_disabled(void); + +/* + * Hardware-specific initialization + */ +static void ocp_start_hc(struct ocp_device *ocp) +{ + int mask; + + printk(KERN_DEBUG __FILE__ + ": starting OCP OHCI USB Controller\n"); + + mask = 1 << (31 - ocp->def->irq); + +#ifdef CONFIG_REDWOOD_5 + /* Setup the UIC because the boot code doesn't seem to do it. */ + /* internal interrupts are positively asserted, level sensative */ + mtdcr(DCRN_UIC_PR(UIC0), mfdcr(DCRN_UIC_PR(UIC0)) | mask); + mtdcr(DCRN_UIC_TR(UIC0), mfdcr(DCRN_UIC_TR(UIC0)) & ~mask); +#endif +} + +/* + * Hardware-specific cleanup + */ +static void ocp_stop_hc(struct ocp_device *ocp) +{ + printk(KERN_DEBUG __FILE__ + ": stopping OCP OHCI USB Controller\n"); +} + +static irqreturn_t usb_hcd_ocp_hcim_irq (int irq, void *__hcd, + struct pt_regs * r) +{ + struct usb_hcd *hcd = __hcd; + + return usb_hcd_irq(irq, hcd, r); +} + +void usb_hcd_ocp_remove (struct usb_hcd *, struct ocp_device *); + +/* configure so an HC device and id are always provided */ +/* always called with process context; sleeping is OK */ + +/** + * usb_hcd_ocp_probe - initialize OCP-based HCDs + * Context: !in_interrupt() + * + * Allocates basic resources for this USB host controller, and + * then invokes the start() method for the HCD associated with it + * through the hotplug entry's driver_data. + * + * Store this function in the HCD's struct pci_driver as probe(). + */ +int usb_hcd_ocp_probe (const struct hc_driver *driver, + struct usb_hcd **hcd_out, + struct ocp_device *ocp) +{ + int retval; + struct usb_hcd *hcd = 0; + struct ohci_hcd *ohci; + phys_addr_t addr = ocp->def->paddr; /* really a vaddr */ + static u64 ocp_dma_mask = 0xffffffffULL; + + if (!request_mem_region (addr, sizeof (struct ohci_regs), + driver->description)) { + dbg("request_mem_region failed"); + return -EBUSY; + } + + ocp_start_hc(ocp); + + hcd = driver->hcd_alloc (); + if (hcd == NULL){ + dbg ("hcd_alloc failed"); + retval = -ENOMEM; + goto err1; + } + + ohci = hcd_to_ohci (hcd); + ohci->flags |= OHCI_BIG_ENDIAN; + + hcd->driver = (struct hc_driver *) driver; + hcd->description = driver->description; + hcd->irq = ocp->def->irq; + hcd->regs = (struct ohci_regs *) addr; + hcd->self.controller = &ocp->dev; + + hcd->self.controller->dma_mask = &ocp_dma_mask; + hcd->self.controller->coherent_dma_mask = 0xffffffffULL; + + retval = hcd_buffer_create (hcd); + if (retval != 0) { + dbg ("pool alloc fail"); + goto err1; + } + + retval = request_irq (hcd->irq, usb_hcd_ocp_hcim_irq, SA_INTERRUPT, + hcd->description, hcd); + if (retval != 0) { + dbg("request_irq failed"); + retval = -EBUSY; + goto err2; + } + + dbg ("%s (OCP OHCI) at 0x%p, irq %d", + hcd->description, hcd->regs, hcd->irq); + + usb_bus_init (&hcd->self); + hcd->self.op = &usb_hcd_operations; + hcd->self.hcpriv = (void *) hcd; + hcd->self.bus_name = "ocp"; + + INIT_LIST_HEAD (&hcd->dev_list); + + usb_register_bus (&hcd->self); + + if ((retval = driver->start (hcd)) < 0) + { + usb_hcd_ocp_remove(hcd, ocp); + return retval; + } + + *hcd_out = hcd; + return 0; + + err2: + hcd_buffer_destroy (hcd); + if (hcd) + driver->hcd_free(hcd); + err1: + ocp_stop_hc(ocp); + release_mem_region(addr, sizeof (struct ohci_regs)); + return retval; +} + + +/* may be called without controller electrically present */ +/* may be called with controller, bus, and devices active */ + +/** + * usb_hcd_ocp_remove - shutdown processing for OCP-based HCDs + * @dev: USB Host Controller being removed + * Context: !in_interrupt() + * + * Reverses the effect of usb_hcd_ocp_probe(), first invoking + * the HCD's stop() method. It is always called from a thread + * context, normally "rmmod", "apmd", or something similar. + * + */ +void usb_hcd_ocp_remove (struct usb_hcd *hcd, struct ocp_device *ocp) +{ + dbg ("remove: %s, state %x", hcd->self.bus_name, hcd->state); + + if (in_interrupt ()) + BUG (); + + hcd->state = USB_STATE_QUIESCING; + + dbg ("%s: roothub graceful disconnect", hcd->self.bus_name); + usb_disconnect (&hcd->self.root_hub); + + hcd->driver->stop (hcd); + hcd->state = USB_STATE_HALT; + + free_irq (hcd->irq, hcd); + hcd_buffer_destroy (hcd); + + usb_deregister_bus (&hcd->self); + + hcd->driver->hcd_free (hcd); + + ocp_stop_hc(ocp); + release_mem_region(ocp->def->paddr, sizeof (struct ohci_regs)); +} + +static int __devinit +ohci_ocp_start (struct usb_hcd *hcd) +{ + struct ohci_hcd *ohci = hcd_to_ohci (hcd); + int ret; + + ohci_dbg (ohci, "ohci_ocp_start, ohci:%p", ohci); + + ohci->hcca = dma_alloc_coherent (hcd->self.controller, + sizeof *ohci->hcca, &ohci->hcca_dma, 0); + if (!ohci->hcca) + return -ENOMEM; + + ohci_dbg (ohci, "ohci_ocp_start, ohci->hcca:%p", ohci->hcca); + + memset (ohci->hcca, 0, sizeof (struct ohci_hcca)); + if ((ret = ohci_mem_init (ohci)) < 0) { + ohci_stop (hcd); + return ret; + } + ohci->regs = hcd->regs; + + if (hc_reset (ohci) < 0) { + ohci_stop (hcd); + return -ENODEV; + } + + if (hc_start (ohci) < 0) { + err ("can't start %s", ohci->hcd.self.bus_name); + ohci_stop (hcd); + return -EBUSY; + } + create_debug_files (ohci); + +#ifdef DEBUG + ohci_dump (ohci, 1); +#endif + return 0; +} + +static const struct hc_driver ohci_ocp_hc_driver = { + .description = "ocp_ohci", + + /* + * generic hardware linkage + */ + .irq = ohci_irq, + .flags = HCD_USB11, + + /* + * basic lifecycle operations + */ + .start = ohci_ocp_start, +#ifdef CONFIG_PM + /* suspend: ohci_ocp_suspend, -- tbd */ + /* resume: ohci_ocp_resume, -- tbd */ +#endif + .stop = ohci_stop, + + /* + * memory lifecycle (except per-request) + */ + .hcd_alloc = ohci_hcd_alloc, + .hcd_free = ohci_hcd_free, + + /* + * managing i/o requests and associated device resources + */ + .urb_enqueue = ohci_urb_enqueue, + .urb_dequeue = ohci_urb_dequeue, + .endpoint_disable = ohci_endpoint_disable, + + /* + * scheduling support + */ + .get_frame_number = ohci_get_frame, + + /* + * root hub support + */ + .hub_status_data = ohci_hub_status_data, + .hub_control = ohci_hub_control, +}; + +static int ohci_hcd_ocp_drv_probe(struct ocp_device *ocp) +{ + struct usb_hcd *hcd = NULL; + int ret; + + if (usb_disabled()) + return -ENODEV; + + ret = usb_hcd_ocp_probe(&ohci_ocp_hc_driver, &hcd, ocp); + + if (ret == 0) + dev_set_drvdata(&ocp->dev, hcd); + + return ret; +} + +static void ohci_hcd_ocp_drv_remove(struct ocp_device *ocp) +{ + struct usb_hcd *hcd = dev_get_drvdata(&ocp->dev); + + usb_hcd_ocp_remove(hcd, ocp); + + dev_set_drvdata(&ocp->dev, NULL); +} + +static struct ocp_device_id ohci_hcd_ocp_ids[] __devinitdata = { + { .vendor = OCP_VENDOR_IBM, .function = OCP_FUNC_USB }, + { .vendor = OCP_VENDOR_INVALID /* Terminating entry */ } +} + +MODULE_DEVICE_TABLE(ocp, ohci_hcd_ocp_ids); + +static struct ocp_driver ohci_hcd_ocp_driver = { + .name = "ocp-ohci", + .id_table = ohci_hcd_ocp_ids, + .probe = ohci_hcd_ocp_drv_probe, + .remove = ohci_hcd_ocp_drv_remove, +}; + +static int __init ohci_hcd_ocp_init (void) +{ + dbg (DRIVER_INFO " (OCP)"); + dbg ("block sizes: ed %d td %d", + sizeof (struct ed), sizeof (struct td)); + + return ocp_register_driver(&ohci_hcd_ocp_driver); +} + +static void __exit ohci_hcd_ocp_cleanup (void) +{ + ocp_unregister_driver(&ohci_hcd_ocp_driver); +} + +module_init (ohci_hcd_ocp_init); +module_exit (ohci_hcd_ocp_cleanup); ------------------------------------------------------- This SF.Net email is sponsored by OSTG. Have you noticed the changes on Linux.com, ITManagersJournal and NewsForge in the past few weeks? Now, one more big change to announce. We are now OSTG- Open Source Technology Group. Come see the changes on the new OSTG site. www.ostg.com _______________________________________________ [EMAIL PROTECTED] To unsubscribe, use the last form field at: https://lists.sourceforge.net/lists/listinfo/linux-usb-devel