diff options
author | Dmitry Baryshkov <dbaryshkov@gmail.com> | 2007-11-13 10:32:35 +0000 |
---|---|---|
committer | Marcin Juszkiewicz <hrw@openembedded.org> | 2007-11-13 10:32:35 +0000 |
commit | 9110e9170eac0abcb3d9140b8bb0e5785a8ecf4e (patch) | |
tree | da73bec37803a99ba138799559462a5ec91858b8 /packages/linux/linux-rp-2.6.23 | |
parent | 064c08414a56a40968d475a48c22d21930988f9f (diff) |
linux-rp 2.6.23: Update tc6393-ohci driver - close #3290
Diffstat (limited to 'packages/linux/linux-rp-2.6.23')
-rw-r--r-- | packages/linux/linux-rp-2.6.23/arm-dma-coherent.patch | 361 | ||||
-rw-r--r-- | packages/linux/linux-rp-2.6.23/defconfig-tosa | 13 | ||||
-rw-r--r-- | packages/linux/linux-rp-2.6.23/tmio-ohci-r8.patch | 472 | ||||
-rw-r--r-- | packages/linux/linux-rp-2.6.23/usb-ohci-hooks-r3.patch | 47 |
4 files changed, 886 insertions, 7 deletions
diff --git a/packages/linux/linux-rp-2.6.23/arm-dma-coherent.patch b/packages/linux/linux-rp-2.6.23/arm-dma-coherent.patch new file mode 100644 index 0000000000..2454becf66 --- /dev/null +++ b/packages/linux/linux-rp-2.6.23/arm-dma-coherent.patch @@ -0,0 +1,361 @@ +Patch largely based on the work of Ian Molton (spyro@f2s.com). + +Signed-off-by: Dmitry Baryshkov <dbaryshkov@gmail.com> +Index: linux-2.6.23/arch/arm/mm/consistent.c +=================================================================== +--- linux-2.6.23.orig/arch/arm/mm/consistent.c 2007-10-10 00:31:38.000000000 +0400 ++++ linux-2.6.23/arch/arm/mm/consistent.c 2007-11-13 01:20:58.281143408 +0300 +@@ -3,6 +3,8 @@ + * + * Copyright (C) 2000-2004 Russell King + * ++ * Device local coherent memory support added by Ian Molton (spyro@f2s.com) ++ * + * This program 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. +@@ -20,6 +22,7 @@ + + #include <asm/memory.h> + #include <asm/cacheflush.h> ++#include <asm/io.h> + #include <asm/tlbflush.h> + #include <asm/sizes.h> + +@@ -35,6 +38,13 @@ + #define CONSISTENT_PTE_INDEX(x) (((unsigned long)(x) - CONSISTENT_BASE) >> PGDIR_SHIFT) + #define NUM_CONSISTENT_PTES (CONSISTENT_DMA_SIZE >> PGDIR_SHIFT) + ++struct dma_coherent_mem { ++ void *virt_base; ++ u32 device_base; ++ int size; ++ int flags; ++ unsigned long *bitmap; ++}; + + /* + * These are the page tables (2MB each) covering uncached, DMA consistent allocations +@@ -153,6 +163,13 @@ + unsigned long order; + u64 mask = ISA_DMA_THRESHOLD, limit; + ++ /* Following is a work-around (a.k.a. hack) to prevent pages ++ * with __GFP_COMP being passed to split_page() which cannot ++ * handle them. The real problem is that this flag probably ++ * should be 0 on ARM as it is not supported on this ++ * platform--see CONFIG_HUGETLB_PAGE. */ ++ gfp &= ~(__GFP_COMP); ++ + if (!consistent_pte[0]) { + printk(KERN_ERR "%s: not initialised\n", __func__); + dump_stack(); +@@ -160,6 +177,26 @@ + } + + if (dev) { ++ ++ if (dev->dma_mem) { ++ unsigned long flags; ++ int page; ++ void *ret; ++ ++ spin_lock_irqsave(&consistent_lock, flags); ++ page = bitmap_find_free_region(dev->dma_mem->bitmap, ++ dev->dma_mem->size, ++ get_order(size)); ++ spin_unlock_irqrestore(&consistent_lock, flags); ++ ++ if (page >= 0) { ++ *handle = dev->dma_mem->device_base + (page << PAGE_SHIFT); ++ ret = dev->dma_mem->virt_base + (page << PAGE_SHIFT); ++ memset(ret, 0, size); ++ return ret; ++ } ++ } ++ + mask = dev->coherent_dma_mask; + + /* +@@ -177,6 +214,9 @@ + mask, (unsigned long long)ISA_DMA_THRESHOLD); + goto no_page; + } ++ ++ if (dev->dma_mem && dev->dma_mem->flags & DMA_MEMORY_EXCLUSIVE) ++ return NULL; + } + + /* +@@ -360,6 +400,8 @@ + pte_t *ptep; + int idx; + u32 off; ++ struct dma_coherent_mem *mem = dev ? dev->dma_mem : NULL; ++ unsigned long order; + + WARN_ON(irqs_disabled()); + +@@ -369,6 +411,15 @@ + } + + size = PAGE_ALIGN(size); ++ order = get_order(size); ++ ++ /* What if mem is valid and the range is not? */ ++ if (mem && cpu_addr >= mem->virt_base && cpu_addr < (mem->virt_base + (mem->size << PAGE_SHIFT))) { ++ int page = (cpu_addr - mem->virt_base) >> PAGE_SHIFT; ++ ++ bitmap_release_region(mem->bitmap, page, order); ++ return; ++ } + + spin_lock_irqsave(&consistent_lock, flags); + c = vm_region_find(&consistent_head, (unsigned long)cpu_addr); +@@ -438,6 +489,81 @@ + } + EXPORT_SYMBOL(dma_free_coherent); + ++int dma_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr, ++ dma_addr_t device_addr, size_t size, int flags) ++{ ++ void *mem_base; ++ int pages = size >> PAGE_SHIFT; ++ int bitmap_size = (pages + 31)/32; ++ ++ if ((flags & (DMA_MEMORY_MAP | DMA_MEMORY_IO)) == 0) ++ goto out; ++ if (!size) ++ goto out; ++ if (dev->dma_mem) ++ goto out; ++ ++ /* FIXME: this routine just ignores DMA_MEMORY_INCLUDES_CHILDREN */ ++ mem_base = ioremap_nocache(bus_addr, size); ++ if (!mem_base) ++ goto out; ++ ++ dev->dma_mem = kmalloc(GFP_KERNEL, sizeof(struct dma_coherent_mem)); ++ if (!dev->dma_mem) ++ goto out; ++ memset(dev->dma_mem, 0, sizeof(struct dma_coherent_mem)); ++ dev->dma_mem->bitmap = kmalloc(GFP_KERNEL, bitmap_size); ++ if (!dev->dma_mem->bitmap) ++ goto free1_out; ++ memset(dev->dma_mem->bitmap, 0, bitmap_size); ++ ++ dev->dma_mem->virt_base = mem_base; ++ dev->dma_mem->device_base = device_addr; ++ dev->dma_mem->size = pages; ++ dev->dma_mem->flags = flags; ++ ++ if (flags & DMA_MEMORY_MAP) ++ return DMA_MEMORY_MAP; ++ ++ return DMA_MEMORY_IO; ++ ++ free1_out: ++ kfree(dev->dma_mem->bitmap); ++ out: ++ return 0; ++} ++EXPORT_SYMBOL(dma_declare_coherent_memory); ++ ++void dma_release_declared_memory(struct device *dev) ++{ ++ struct dma_coherent_mem *mem = dev->dma_mem; ++ ++ if (!mem) ++ return; ++ dev->dma_mem = NULL; ++ kfree(mem->bitmap); ++ kfree(mem); ++} ++EXPORT_SYMBOL(dma_release_declared_memory); ++ ++void *dma_mark_declared_memory_occupied(struct device *dev, ++ dma_addr_t device_addr, size_t size) ++{ ++ struct dma_coherent_mem *mem = dev->dma_mem; ++ int pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; ++ int pos, err; ++ ++ if (!mem) ++ return ERR_PTR(-EINVAL); ++ ++ pos = (device_addr - mem->device_base) >> PAGE_SHIFT; ++ err = bitmap_allocate_region(mem->bitmap, pos, get_order(pages)); ++ if (err != 0) ++ return ERR_PTR(err); ++ return mem->virt_base + (pos << PAGE_SHIFT); ++} ++EXPORT_SYMBOL(dma_mark_declared_memory_occupied); ++ + /* + * Initialise the consistent memory allocation. + */ +Index: linux-2.6.23/arch/arm/common/dmabounce.c +=================================================================== +--- linux-2.6.23.orig/arch/arm/common/dmabounce.c 2007-10-10 00:31:38.000000000 +0400 ++++ linux-2.6.23/arch/arm/common/dmabounce.c 2007-11-13 01:23:17.452501736 +0300 +@@ -16,6 +16,7 @@ + * + * Copyright (C) 2002 Hewlett Packard Company. + * Copyright (C) 2004 MontaVista Software, Inc. ++ * Copyright (C) 2007 Dmitry Baryshkov <dbaryshkov@gmail.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License +@@ -29,6 +30,7 @@ + #include <linux/dma-mapping.h> + #include <linux/dmapool.h> + #include <linux/list.h> ++#include <linux/rwsem.h> + + #include <asm/cacheflush.h> + +@@ -79,6 +81,75 @@ + rwlock_t lock; + }; + ++struct dmabounce_check_entry { ++ struct list_head list; ++ dmabounce_check checker; ++ void *data; ++}; ++ ++static struct list_head checkers = LIST_HEAD_INIT(checkers); ++static rwlock_t checkers_lock = RW_LOCK_UNLOCKED; ++ ++int ++dmabounce_register_checker(dmabounce_check function, void *data) ++{ ++ unsigned long flags; ++ struct dmabounce_check_entry *entry = ++ kzalloc(sizeof(struct dmabounce_check_entry), GFP_ATOMIC); ++ ++ if (!entry) ++ return ENOMEM; ++ ++ INIT_LIST_HEAD(&entry->list); ++ entry->checker = function; ++ entry->data = data; ++ ++ write_lock_irqsave(checkers_lock, flags); ++ list_add(&entry->list, &checkers); ++ write_unlock_irqrestore(checkers_lock, flags); ++ ++ return 0; ++} ++ ++void ++dmabounce_remove_checker(dmabounce_check function, void *data) ++{ ++ unsigned long flags; ++ struct list_head *pos; ++ ++ write_lock_irqsave(checkers_lock, flags); ++ __list_for_each(pos, &checkers) { ++ struct dmabounce_check_entry *entry = container_of(pos, ++ struct dmabounce_check_entry, list); ++ if (entry->checker == function && entry->data == data) { ++ list_del(pos); ++ write_unlock_irqrestore(checkers_lock, flags); ++ kfree(entry); ++ return; ++ } ++ } ++ ++ printk(KERN_WARNING "dmabounce checker not found: %p\n", function); ++} ++ ++int dma_needs_bounce(struct device *dev, dma_addr_t dma, size_t size) ++{ ++ unsigned long flags; ++ struct list_head *pos; ++ ++ read_lock_irqsave(checkers_lock, flags); ++ __list_for_each(pos, &checkers) { ++ struct dmabounce_check_entry *entry = container_of(pos, ++ struct dmabounce_check_entry, list); ++ if (entry->checker(dev, dma, size, entry->data)) { ++ read_unlock_irqrestore(checkers_lock, flags); ++ return 1; ++ } ++ } ++ ++ read_unlock_irqrestore(checkers_lock, flags); ++ return 0; ++} + #ifdef STATS + static ssize_t dmabounce_show(struct device *dev, struct device_attribute *attr, + char *buf) +@@ -642,7 +713,6 @@ + dev->bus_id, dev->bus->name); + } + +- + EXPORT_SYMBOL(dma_map_single); + EXPORT_SYMBOL(dma_unmap_single); + EXPORT_SYMBOL(dma_map_sg); +@@ -652,6 +722,9 @@ + EXPORT_SYMBOL(dma_sync_sg); + EXPORT_SYMBOL(dmabounce_register_dev); + EXPORT_SYMBOL(dmabounce_unregister_dev); ++EXPORT_SYMBOL(dmabounce_register_checker); ++EXPORT_SYMBOL(dmabounce_remove_checker); ++ + + MODULE_AUTHOR("Christopher Hoover <ch@hpl.hp.com>, Deepak Saxena <dsaxena@plexity.net>"); + MODULE_DESCRIPTION("Special dma_{map/unmap/dma_sync}_* routines for systems with limited DMA windows"); +Index: linux-2.6.23/include/asm-arm/dma-mapping.h +=================================================================== +--- linux-2.6.23.orig/include/asm-arm/dma-mapping.h 2007-10-10 00:31:38.000000000 +0400 ++++ linux-2.6.23/include/asm-arm/dma-mapping.h 2007-11-13 01:24:05.588500474 +0300 +@@ -7,6 +7,18 @@ + + #include <asm/scatterlist.h> + ++#define ARCH_HAS_DMA_DECLARE_COHERENT_MEMORY ++extern int ++dma_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr, ++ dma_addr_t device_addr, size_t size, int flags); ++ ++extern void ++dma_release_declared_memory(struct device *dev); ++ ++extern void * ++dma_mark_declared_memory_occupied(struct device *dev, ++ dma_addr_t device_addr, size_t size); ++ + /* + * DMA-consistent mapping functions. These allocate/free a region of + * uncached, unwrite-buffered mapped memory space for use with DMA +@@ -433,23 +445,10 @@ + */ + extern void dmabounce_unregister_dev(struct device *); + +-/** +- * dma_needs_bounce +- * +- * @dev: valid struct device pointer +- * @dma_handle: dma_handle of unbounced buffer +- * @size: size of region being mapped +- * +- * Platforms that utilize the dmabounce mechanism must implement +- * this function. +- * +- * The dmabounce routines call this function whenever a dma-mapping +- * is requested to determine whether a given buffer needs to be bounced +- * or not. The function must return 0 if the buffer is OK for +- * DMA access and 1 if the buffer needs to be bounced. +- * +- */ +-extern int dma_needs_bounce(struct device*, dma_addr_t, size_t); ++typedef int (*dmabounce_check)(struct device *dev, dma_addr_t dma, size_t size, void *data); ++extern int dmabounce_register_checker(dmabounce_check, void *data); ++extern void dmabounce_remove_checker(dmabounce_check, void *data); ++ + #endif /* CONFIG_DMABOUNCE */ + + #endif /* __KERNEL__ */ diff --git a/packages/linux/linux-rp-2.6.23/defconfig-tosa b/packages/linux/linux-rp-2.6.23/defconfig-tosa index 08c2bbe87a..d3dc74bcc0 100644 --- a/packages/linux/linux-rp-2.6.23/defconfig-tosa +++ b/packages/linux/linux-rp-2.6.23/defconfig-tosa @@ -434,7 +434,7 @@ CONFIG_IEEE80211_CRYPT_TKIP=m # CONFIG_STANDALONE=y CONFIG_PREVENT_FIRMWARE_BUILD=y -CONFIG_FW_LOADER=y +CONFIG_FW_LOADER=m # CONFIG_DEBUG_DRIVER is not set # @@ -1311,8 +1311,7 @@ CONFIG_USB_GADGET=m # CONFIG_USB_GADGET_DEBUG_FILES is not set CONFIG_USB_GADGET_SELECTED=y # CONFIG_USB_GADGET_NET2280 is not set -CONFIG_USB_GADGET_PXA2XX=m -CONFIG_USB_PXA2XX=m +CONFIG_USB_GADGET_PXA2XX=y # CONFIG_USB_PXA2XX_SMALL is not set # CONFIG_USB_GADGET_PXA27X is not set # CONFIG_USB_GADGET_GOKU is not set @@ -1494,9 +1493,9 @@ CONFIG_MSDOS_PARTITION=y # # Native Language Support # -CONFIG_NLS=y +CONFIG_NLS=m CONFIG_NLS_DEFAULT="cp437" -CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_CODEPAGE_437=m CONFIG_NLS_CODEPAGE_737=m CONFIG_NLS_CODEPAGE_775=m CONFIG_NLS_CODEPAGE_850=m @@ -1520,7 +1519,7 @@ CONFIG_NLS_ISO8859_8=m CONFIG_NLS_CODEPAGE_1250=m CONFIG_NLS_CODEPAGE_1251=m CONFIG_NLS_ASCII=m -CONFIG_NLS_ISO8859_1=y +CONFIG_NLS_ISO8859_1=m CONFIG_NLS_ISO8859_2=m CONFIG_NLS_ISO8859_3=m CONFIG_NLS_ISO8859_4=m @@ -1533,7 +1532,7 @@ CONFIG_NLS_ISO8859_14=m CONFIG_NLS_ISO8859_15=m CONFIG_NLS_KOI8_R=m CONFIG_NLS_KOI8_U=m -CONFIG_NLS_UTF8=y +CONFIG_NLS_UTF8=m # # Profiling support diff --git a/packages/linux/linux-rp-2.6.23/tmio-ohci-r8.patch b/packages/linux/linux-rp-2.6.23/tmio-ohci-r8.patch new file mode 100644 index 0000000000..034acc7b8e --- /dev/null +++ b/packages/linux/linux-rp-2.6.23/tmio-ohci-r8.patch @@ -0,0 +1,472 @@ +Signed-off-by: Dmitry Baryshkov <dbaryshkov@gmail.com> + +Index: linux-2.6.23/drivers/usb/host/ohci-tmio.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.23/drivers/usb/host/ohci-tmio.c 2007-11-13 01:35:13.049455112 +0300 +@@ -0,0 +1,417 @@ ++/* ++ * OHCI HCD(Host Controller Driver) for USB. ++ * ++ *(C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at> ++ *(C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net> ++ *(C) Copyright 2002 Hewlett-Packard Company ++ * ++ * Bus glue for Toshiba Mobile IO(TMIO) Controller's OHCI core ++ *(C) Copyright 2005 Chris Humbert <mahadri-usb@drigon.com> ++ * ++ * This is known to work with the following variants: ++ * TC6393XB revision 3 (32kB SRAM) ++ * ++ * The TMIO's OHCI core DMAs through a small internal buffer that ++ * is directly addressable by the CPU. dma_declare_coherent_memory ++ * and DMA bounce buffers allow the higher-level OHCI host driver to ++ * work. However, the dma API doesn't handle dma mapping failures ++ * well(dma_sg_map() is a prime example), so it is unusable. ++ * ++ * This HC pretends be a PIO-ish controller and uses the kernel's ++ * generic allocator for the entire SRAM. Using the USB core's ++ * usb_operations, we provide hcd_buffer_alloc/free. Using the OHCI's ++ * ohci_ops, we provide memory management for OHCI's TDs and EDs. We ++ * internally queue a URB's TDs until enough dma memory is available ++ * to enqueue them with the HC. ++ * ++ * Written from sparse documentation from Toshiba and Sharp's driver ++ * for the 2.4 kernel, ++ * usb-ohci-tc6393.c(C) Copyright 2004 Lineo Solutions, Inc. ++ * ++ * This program 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 <linux/fs.h> ++#include <linux/mount.h> ++#include <linux/pagemap.h> ++#include <linux/init.h> ++#include <linux/namei.h> ++#include <linux/sched.h> ++ ++#include <linux/genalloc.h> ++#include <asm/hardware/tmio.h> ++#include <linux/dma-mapping.h> ++ ++/*-------------------------------------------------------------------------*/ ++ ++/* ++ * USB Host Controller Configuration Register ++ */ ++struct tmio_uhccr { ++ u8 x00[8]; ++ u8 revid; /* 0x08 Revision ID */ ++ u8 x01[7]; ++ u16 basel; /* 0x10 USB Control Register Base Address Low */ ++ u16 baseh; /* 0x12 USB Control Register Base Address High */ ++ u8 x02[0x2c]; ++ u8 ilme; /* 0x40 Internal Local Memory Enable */ ++ u8 x03[0x0b]; ++ u16 pm; /* 0x4c Power Management */ ++ u8 x04[2]; ++ u8 intc; /* 0x50 INT Control */ ++ u8 x05[3]; ++ u16 lmw1l; /* 0x54 Local Memory Window 1 LMADRS Low */ ++ u16 lmw1h; /* 0x56 Local Memory Window 1 LMADRS High */ ++ u16 lmw1bl; /* 0x58 Local Memory Window 1 Base Address Low */ ++ u16 lmw1bh; /* 0x5A Local Memory Window 1 Base Address High */ ++ u16 lmw2l; /* 0x5C Local Memory Window 2 LMADRS Low */ ++ u16 lmw2h; /* 0x5E Local Memory Window 2 LMADRS High */ ++ u16 lmw2bl; /* 0x60 Local Memory Window 2 Base Address Low */ ++ u16 lmw2bh; /* 0x62 Local Memory Window 2 Base Address High */ ++ u8 x06[0x98]; ++ u8 misc; /* 0xFC MISC */ ++ u8 x07[3]; ++} __attribute__((packed)); ++ ++union tmio_uhccr_pm { ++ u16 raw; ++struct { ++ unsigned gcken:1; /* D0 */ ++ unsigned ckrnen:1; /* D1 */ ++ unsigned uspw1:1; /* D2 USB Port 1 Power Disable */ ++ unsigned uspw2:1; /* D3 USB Port 2 Power Disable */ ++ unsigned x00:4; ++ unsigned pmee:1; /* D8 */ ++ unsigned x01:6; ++ unsigned pmes:1; /* D15 */ ++} __attribute__((packed)); ++} __attribute__((packed)); ++ ++/*-------------------------------------------------------------------------*/ ++ ++struct tmio_hcd { ++ struct tmio_uhccr __iomem *ccr; ++}; ++ ++#define hcd_to_tmio(hcd) ((struct tmio_hcd *)(hcd_to_ohci(hcd) + 1)) ++#define ohci_to_tmio(ohci) ((struct tmio_hcd *)(ohci + 1)) ++ ++/*-------------------------------------------------------------------------*/ ++ ++static void tmio_stop_hc(struct device *dev) ++{ ++ struct tmio_device *tdev = dev_to_tdev(dev); ++ struct usb_hcd *hcd = dev_get_drvdata(dev); ++ struct tmio_hcd *tmio = hcd_to_tmio(hcd); ++ struct tmio_uhccr __iomem *ccr = tmio->ccr; ++ union tmio_uhccr_pm pm = {0}; ++ ++ pm.gcken = 1; ++ pm.ckrnen = 1; ++ pm.uspw1 = 1; ++ pm.uspw2 = 1; ++ ++ iowrite8(0, &ccr->intc); ++ iowrite8(0, &ccr->ilme); ++ iowrite16(0, &ccr->basel); ++ iowrite16(0, &ccr->baseh); ++ iowrite16(pm.raw, &ccr->pm); ++ ++ tdev->ops->function(dev, 0); ++ tdev->ops->clock(dev, 0); ++} ++ ++static void tmio_start_hc(struct device *dev) ++{ ++ struct tmio_device *tdev = dev_to_tdev(dev); ++ struct usb_hcd *hcd = dev_get_drvdata(dev); ++ struct tmio_hcd *tmio = hcd_to_tmio(hcd); ++ struct tmio_uhccr __iomem *ccr = tmio->ccr; ++ union tmio_uhccr_pm pm = {0}; ++ unsigned long base = hcd->rsrc_start; ++ ++ pm.pmes = 1; ++ pm.pmee = 1; ++ pm.ckrnen = 1; ++ pm.gcken = 1; ++ ++ tdev->ops->clock(dev, 1); ++ tdev->ops->function(dev, 1); ++ ++ iowrite16(pm.raw, &ccr->pm); ++ iowrite16(base, &ccr->basel); ++ iowrite16(base >> 16, &ccr->baseh); ++ iowrite8(1, &ccr->ilme); ++ iowrite8(2, &ccr->intc); ++ ++ dev_info(dev, "revision %d @ 0x%08llx, irq %d\n", ++ ioread8(&ccr->revid), hcd->rsrc_start, hcd->irq); ++} ++ ++static int usb_hcd_tmio_probe(const struct hc_driver *driver, ++ struct device *dev) ++{ ++ struct tmio_device *tdev = dev_to_tdev(dev); ++ struct resource *config = tmio_resource_config(dev); ++ struct resource *regs = tmio_resource_control(dev); ++ struct resource *sram = tmio_resource_mem(dev); ++ struct resource *irq = tmio_resource_irq(dev); ++ struct tmio_hcd *tmio; ++ struct ohci_hcd *ohci; ++ struct usb_hcd *hcd; ++ int retval; ++ ++ if (usb_disabled()) ++ return -ENODEV; ++ ++ hcd = usb_create_hcd(driver, dev, dev->bus_id); ++ if (!hcd) { ++ retval = -ENOMEM; ++ goto err_usb_create_hcd; ++ } ++ ++ retval = request_resource(tdev->iomem, config); ++ if (retval) ++ goto err_request_config_resource; ++ ++ retval = request_resource(tdev->iomem, regs); ++ if (retval) ++ goto err_request_regs_resource; ++ ++ retval = request_resource(tdev->iomem, sram); ++ if (retval) ++ goto err_request_sram_resource; ++ ++ hcd->rsrc_start = regs->start; ++ hcd->rsrc_len = regs->end - regs->start + 1; ++ ++ tmio = hcd_to_tmio(hcd); ++ ++ tmio->ccr = ioremap(config->start, config->end - config->start + 1); ++ if (!tmio->ccr) { ++ retval = -ENOMEM; ++ goto err_ioremap_ccr; ++ } ++ ++ hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); ++ if (!hcd->regs) { ++ retval = -ENOMEM; ++ goto err_ioremap_regs; ++ } ++ ++ if (dma_declare_coherent_memory(dev, sram->start, ++ sram->start, ++ sram->end - sram->start + 1, ++ DMA_MEMORY_MAP) != DMA_MEMORY_MAP) { ++ retval = -EBUSY; ++ goto err_dma_declare; ++ } ++ ++ retval = dmabounce_register_dev(dev, 512, 4096); ++ if (retval) ++ goto err_dmabounce_register_dev; ++ ++ tmio_start_hc(dev); ++ ohci = hcd_to_ohci(hcd); ++ ohci_hcd_init(ohci); ++ ++ retval = usb_add_hcd(hcd, irq->start, IRQF_DISABLED); ++ ++ if (retval == 0) ++ return retval; ++ ++ tmio_stop_hc(dev); ++ ++ dmabounce_unregister_dev(dev); ++err_dmabounce_register_dev: ++ dma_release_declared_memory(dev); ++err_dma_declare: ++ iounmap(hcd->regs); ++err_ioremap_regs: ++ iounmap(tmio->ccr); ++err_ioremap_ccr: ++ release_resource(sram); ++err_request_sram_resource: ++ release_resource(regs); ++err_request_regs_resource: ++ release_resource(config); ++err_request_config_resource: ++ usb_put_hcd(hcd); ++err_usb_create_hcd: ++ ++ return retval; ++} ++ ++static void usb_hcd_tmio_remove(struct usb_hcd *hcd, struct device *dev) ++{ ++ struct tmio_hcd *tmio = hcd_to_tmio(hcd); ++ ++ usb_remove_hcd(hcd); ++ tmio_stop_hc(dev); ++ dmabounce_unregister_dev(dev); ++ dma_release_declared_memory(dev); ++ iounmap(hcd->regs); ++ iounmap(tmio->ccr); ++ release_resource(tmio_resource_mem(dev)); ++ release_resource(tmio_resource_control(dev)); ++ release_resource(tmio_resource_config(dev)); ++ usb_put_hcd(hcd); ++} ++ ++static int __devinit ++ohci_tmio_start(struct usb_hcd *hcd) ++{ ++ struct ohci_hcd *ohci = hcd_to_ohci(hcd); ++ int retval; ++ ++ if ((retval = ohci_init(ohci)) < 0) ++ return retval; ++ ++ if ((retval = ohci_run(ohci)) < 0) { ++ err("can't start %s", hcd->self.bus_name); ++ ohci_stop(hcd); ++ return retval; ++ } ++ ++ return 0; ++} ++ ++static const struct hc_driver ohci_tmio_hc_driver = { ++ .description = hcd_name, ++ .product_desc = "TMIO OHCI USB Host Controller", ++ .hcd_priv_size = sizeof(struct ohci_hcd) + sizeof (struct tmio_hcd), ++ ++ /* generic hardware linkage */ ++ .irq = ohci_irq, ++ .flags = HCD_USB11 | HCD_MEMORY, ++ ++ /* basic lifecycle operations */ ++ .start = ohci_tmio_start, ++ .stop = ohci_stop, ++ .shutdown = ohci_shutdown, ++ ++ /* 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, ++ .hub_irq_enable = ohci_rhsc_enable, ++#ifdef CONFIG_PM ++ .bus_suspend = ohci_bus_suspend, ++ .bus_resume = ohci_bus_resume, ++#endif ++ .start_port_reset = ohci_start_port_reset, ++}; ++ ++/*-------------------------------------------------------------------------*/ ++static struct device_driver tmio_ohci; ++ ++static int ++tmio_dmabounce_check(struct device *dev, dma_addr_t dma, size_t size, void *data) ++{ ++ struct resource *sram = data; ++#ifdef DEBUG ++ printk(KERN_ERR "tmio_dmabounce_check: %08x %d\n", dma, size); ++#endif ++ ++ if (dev->driver != &tmio_ohci) ++ return 0; ++ ++ if (sram->start <= dma && dma + size <= sram->end) ++ return 0; ++ ++ return 1; ++} ++ ++static u64 dma_mask = DMA_32BIT_MASK; ++ ++static int ohci_hcd_tmio_drv_probe(struct device *dev) ++{ ++ struct resource *sram = tmio_resource_mem(dev); ++ ++ dev->dma_mask = &dma_mask; ++ dev->coherent_dma_mask = DMA_32BIT_MASK; ++ ++ dmabounce_register_checker(tmio_dmabounce_check, sram); ++ ++ return usb_hcd_tmio_probe(&ohci_tmio_hc_driver, dev); ++} ++ ++static int ohci_hcd_tmio_drv_remove(struct device *dev) ++{ ++ struct usb_hcd *hcd = dev_get_drvdata(dev); ++ struct resource *sram = tmio_resource_mem(dev); ++ ++ usb_hcd_tmio_remove(hcd, dev); ++ ++ dev_set_drvdata(dev, NULL); ++ ++ dmabounce_remove_checker(tmio_dmabounce_check, sram); ++ ++ return 0; ++} ++ ++#ifdef CONFIG_PM ++static int ohci_hcd_tmio_drv_suspend(struct device *dev, pm_message_t state) ++{ ++ struct usb_hcd *hcd = dev_get_drvdata(dev); ++ struct ohci_hcd *ohci = hcd_to_ohci(hcd); ++ ++ if (time_before(jiffies, ohci->next_statechange)) ++ msleep(5); ++ ohci->next_statechange = jiffies; ++ ++ tmio_stop_hc(dev); ++ hcd->state = HC_STATE_SUSPENDED; ++ dev->power.power_state = PMSG_SUSPEND; ++ ++ return 0; ++} ++ ++static int ohci_hcd_tmio_drv_resume(struct device *dev) ++{ ++ struct usb_hcd *hcd = dev_get_drvdata(dev); ++ struct ohci_hcd *ohci = hcd_to_ohci(hcd); ++ ++ if (time_before(jiffies, ohci->next_statechange)) ++ msleep(5); ++ ohci->next_statechange = jiffies; ++ ++ tmio_start_hc(dev); ++ ++ dev->power.power_state = PMSG_ON; ++ usb_hcd_resume_root_hub(hcd); ++ ++ return 0; ++} ++#endif ++ ++static void usb_hcd_device_shutdown(struct device *dev) ++{ ++ struct usb_hcd *hcd = dev_get_drvdata(dev); ++ ++ if (hcd->driver->shutdown) ++ hcd->driver->shutdown(hcd); ++} ++ ++static struct device_driver tmio_ohci = { ++ .owner = THIS_MODULE, ++ .name = TMIO_NAME_OHCI, ++ .bus = &tmio_bus_type, ++ .probe = ohci_hcd_tmio_drv_probe, ++ .remove = ohci_hcd_tmio_drv_remove, ++ .shutdown = usb_hcd_device_shutdown, ++#ifdef CONFIG_PM ++ .suspend = ohci_hcd_tmio_drv_suspend, ++ .resume = ohci_hcd_tmio_drv_resume, ++#endif ++}; ++ +Index: linux-2.6.23/drivers/usb/host/Kconfig +=================================================================== +--- linux-2.6.23.orig/drivers/usb/host/Kconfig 2007-10-10 00:31:38.000000000 +0400 ++++ linux-2.6.23/drivers/usb/host/Kconfig 2007-11-12 13:46:53.086559913 +0300 +@@ -101,6 +101,7 @@ + depends on USB && USB_ARCH_HAS_OHCI + select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3 + select I2C if ARCH_PNX4008 ++ select GENERIC_ALLOCATOR if TOSHIBA_TC6393XB + ---help--- + The Open Host Controller Interface (OHCI) is a standard for accessing + USB 1.1 host controller hardware. It does more in hardware than Intel's +Index: linux-2.6.23/drivers/usb/host/ohci-hcd.c +=================================================================== +--- linux-2.6.23.orig/drivers/usb/host/ohci-hcd.c 2007-11-12 13:46:52.894560883 +0300 ++++ linux-2.6.23/drivers/usb/host/ohci-hcd.c 2007-11-13 01:03:53.950798640 +0300 +@@ -915,6 +915,10 @@ + #define PLATFORM_DRIVER usb_hcd_pnx4008_driver + #endif + ++#ifdef CONFIG_TOSHIBA_TC6393XB ++#include "ohci-tmio.c" ++#define DEVICE_DRIVER tmio_ohci ++#endif + + #ifdef CONFIG_USB_OHCI_HCD_PPC_OF + #include "ohci-ppc-of.c" +Index: linux-2.6.23/drivers/usb/Kconfig +=================================================================== +--- linux-2.6.23.orig/drivers/usb/Kconfig 2007-10-10 00:31:38.000000000 +0400 ++++ linux-2.6.23/drivers/usb/Kconfig 2007-11-12 13:46:53.090570777 +0300 +@@ -42,6 +42,7 @@ + # MIPS: + default y if SOC_AU1X00 + # more: ++ default y if TOSHIBA_TC6393XB + default PCI + + # some non-PCI hcds implement EHCI +Index: linux-2.6.23/arch/arm/common/Kconfig +=================================================================== +--- linux-2.6.23.orig/arch/arm/common/Kconfig 2007-11-12 13:46:48.754297930 +0300 ++++ linux-2.6.23/arch/arm/common/Kconfig 2007-11-12 13:46:53.090570777 +0300 +@@ -35,3 +35,4 @@ + + config TOSHIBA_TC6393XB + bool ++ select DMABOUNCE diff --git a/packages/linux/linux-rp-2.6.23/usb-ohci-hooks-r3.patch b/packages/linux/linux-rp-2.6.23/usb-ohci-hooks-r3.patch new file mode 100644 index 0000000000..08f4f15211 --- /dev/null +++ b/packages/linux/linux-rp-2.6.23/usb-ohci-hooks-r3.patch @@ -0,0 +1,47 @@ +Signed-off-by: Dmitry Baryshkov <dbaryshkov@gmail.com> +Index: linux-2.6.23/drivers/usb/host/ohci-hcd.c +=================================================================== +--- linux-2.6.23.orig/drivers/usb/host/ohci-hcd.c 2007-11-12 12:36:12.598560065 +0300 ++++ linux-2.6.23/drivers/usb/host/ohci-hcd.c 2007-11-12 12:36:16.614310504 +0300 +@@ -930,6 +930,7 @@ + !defined(PLATFORM_DRIVER) && \ + !defined(OF_PLATFORM_DRIVER) && \ + !defined(SA1111_DRIVER) && \ ++ !defined(DEVICE_DRIVER) && \ + !defined(PS3_SYSTEM_BUS_DRIVER) + #error "missing bus glue for ohci-hcd" + #endif +@@ -969,6 +970,12 @@ + goto error_sa1111; + #endif + ++#ifdef DEVICE_DRIVER ++ retval = driver_register(&DEVICE_DRIVER); ++ if (retval < 0) ++ goto error_device; ++#endif ++ + #ifdef PCI_DRIVER + retval = pci_register_driver(&PCI_DRIVER); + if (retval < 0) +@@ -981,6 +988,10 @@ + #ifdef PCI_DRIVER + error_pci: + #endif ++#ifdef DEVICE_DRIVER ++ error_device: ++ driver_unregister(&DEVICE_DRIVER); ++#endif + #ifdef SA1111_DRIVER + sa1111_driver_unregister(&SA1111_DRIVER); + error_sa1111: +@@ -1006,6 +1017,9 @@ + #ifdef PCI_DRIVER + pci_unregister_driver(&PCI_DRIVER); + #endif ++#ifdef DEVICE_DRIVER ++ driver_unregister(&DEVICE_DRIVER); ++#endif + #ifdef SA1111_DRIVER + sa1111_driver_unregister(&SA1111_DRIVER); + #endif |