diff options
Diffstat (limited to 'packages/linux/linux-rp-2.6.24/tosa/0045-Update-tmio_ohci.patch')
-rw-r--r-- | packages/linux/linux-rp-2.6.24/tosa/0045-Update-tmio_ohci.patch | 416 |
1 files changed, 416 insertions, 0 deletions
diff --git a/packages/linux/linux-rp-2.6.24/tosa/0045-Update-tmio_ohci.patch b/packages/linux/linux-rp-2.6.24/tosa/0045-Update-tmio_ohci.patch new file mode 100644 index 0000000000..10f483b89d --- /dev/null +++ b/packages/linux/linux-rp-2.6.24/tosa/0045-Update-tmio_ohci.patch @@ -0,0 +1,416 @@ +From fe3c05491370965eb821aedc95f771b86ebab3ab Mon Sep 17 00:00:00 2001 +From: Dmitry Baryshkov <dbaryshkov@gmail.com> +Date: Wed, 9 Jan 2008 02:01:44 +0300 +Subject: [PATCH 45/64] Update tmio_ohci: + Ports management. + Basic support for ohci suspend/resume. + +Signed-off-by: Dmitry Baryshkov <dbaryshkov@gmail.com> +--- + drivers/mfd/tc6393xb.c | 40 ++++++++ + drivers/usb/host/ohci-tmio.c | 206 +++++++++++++++++++++++++++++++++++++++--- + 2 files changed, 235 insertions(+), 11 deletions(-) + +diff --git a/drivers/mfd/tc6393xb.c b/drivers/mfd/tc6393xb.c +index 9439f39..5d17687 100644 +--- a/drivers/mfd/tc6393xb.c ++++ b/drivers/mfd/tc6393xb.c +@@ -224,6 +224,44 @@ static int tc6393xb_ohci_enable(struct platform_device *ohci) + return 0; + } + ++static int tc6393xb_ohci_suspend(struct platform_device *ohci) ++{ ++ struct platform_device *dev = to_platform_device(ohci->dev.parent); ++ struct tc6393xb *tc6393xb = platform_get_drvdata(dev); ++ struct tc6393xb_scr __iomem *scr = tc6393xb->scr; ++ union tc6393xb_scr_ccr ccr; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&tc6393xb->lock, flags); ++ ++ ccr.raw = ioread16(&scr->ccr); ++ ccr.bits.usbcken = 0; ++ iowrite16(ccr.raw, &scr->ccr); ++ ++ spin_unlock_irqrestore(&tc6393xb->lock, flags); ++ ++ return 0; ++} ++ ++static int tc6393xb_ohci_resume(struct platform_device *ohci) ++{ ++ struct platform_device *dev = to_platform_device(ohci->dev.parent); ++ struct tc6393xb *tc6393xb = platform_get_drvdata(dev); ++ struct tc6393xb_scr __iomem *scr = tc6393xb->scr; ++ union tc6393xb_scr_ccr ccr; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&tc6393xb->lock, flags); ++ ++ ccr.raw = ioread16(&scr->ccr); ++ ccr.bits.usbcken = 1; ++ iowrite16(ccr.raw, &scr->ccr); ++ ++ spin_unlock_irqrestore(&tc6393xb->lock, flags); ++ ++ return 0; ++} ++ + static int tc6393xb_fb_disable(struct platform_device *fb) + { + struct platform_device *dev = to_platform_device(fb->dev.parent); +@@ -423,6 +461,8 @@ static struct mfd_cell tc6393xb_cells[] = { + .name = "tmio-ohci", + .enable = tc6393xb_ohci_enable, + .disable = tc6393xb_ohci_disable, ++ .suspend = tc6393xb_ohci_suspend, ++ .resume = tc6393xb_ohci_resume, + .num_resources = ARRAY_SIZE(tc6393xb_ohci_resources), + .resources = tc6393xb_ohci_resources, + }, +diff --git a/drivers/usb/host/ohci-tmio.c b/drivers/usb/host/ohci-tmio.c +index be609f3..65e3cd3 100644 +--- a/drivers/usb/host/ohci-tmio.c ++++ b/drivers/usb/host/ohci-tmio.c +@@ -75,10 +75,13 @@ struct tmio_uhccr { + u8 x07[3]; + } __attribute__((packed)); + ++#define MAX_TMIO_OHCI_PORTS 3 ++ + #define UHCCR_PM_GKEN 0x0001 + #define UHCCR_PM_CKRNEN 0x0002 + #define UHCCR_PM_USBPW1 0x0004 + #define UHCCR_PM_USBPW2 0x0008 ++#define UHCCR_PM_USBPW3 0x0008 + #define UHCCR_PM_PMEE 0x0100 + #define UHCCR_PM_PMES 0x8000 + +@@ -86,44 +89,96 @@ struct tmio_uhccr { + + struct tmio_hcd { + struct tmio_uhccr __iomem *ccr; ++ spinlock_t lock; /* protects RMW cycles and disabled_ports data */ ++ bool disabled_ports[MAX_TMIO_OHCI_PORTS]; + }; + + #define hcd_to_tmio(hcd) ((struct tmio_hcd *)(hcd_to_ohci(hcd) + 1)) + #define ohci_to_tmio(ohci) ((struct tmio_hcd *)(ohci + 1)) + ++struct indexed_device_attribute{ ++ struct device_attribute dev_attr; ++ int index; ++}; ++#define to_indexed_dev_attr(_dev_attr) \ ++ container_of(_dev_attr, struct indexed_device_attribute, dev_attr) ++ ++#define INDEXED_ATTR(_name, _mode, _show, _store, _index) \ ++ { .dev_attr = __ATTR(_name ## _index, _mode, _show, _store), \ ++ .index = _index } ++ ++#define INDEXED_DEVICE_ATTR(_name, _mode, _show, _store, _index) \ ++struct indexed_device_attribute dev_attr_##_name ## _index \ ++ = INDEXED_ATTR(_name, _mode, _show, _store, _index) ++ ++static bool disabled_tmio_ports[MAX_TMIO_OHCI_PORTS]; ++module_param_array(disabled_tmio_ports, bool, NULL, 0644); ++MODULE_PARM_DESC(disabled_tmio_ports, ++ "disable specified TC6393 usb ports (default: all enabled)"); ++ + /*-------------------------------------------------------------------------*/ + ++static void tmio_write_pm(struct platform_device *dev) ++{ ++ struct usb_hcd *hcd = platform_get_drvdata(dev); ++ struct tmio_hcd *tmio = hcd_to_tmio(hcd); ++ struct tmio_uhccr __iomem *ccr = tmio->ccr; ++ u16 pm; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&tmio->lock, flags); ++ ++ pm = UHCCR_PM_GKEN | UHCCR_PM_CKRNEN | ++ UHCCR_PM_PMEE | UHCCR_PM_PMES; ++ ++ if (tmio->disabled_ports[0]) ++ pm |= UHCCR_PM_USBPW1; ++ if (tmio->disabled_ports[1]) ++ pm |= UHCCR_PM_USBPW2; ++ if (tmio->disabled_ports[2]) ++ pm |= UHCCR_PM_USBPW3; ++ ++ iowrite16(pm, &ccr->pm); ++ spin_unlock_irqrestore(&tmio->lock, flags); ++} ++ + static void tmio_stop_hc(struct platform_device *dev) + { + struct mfd_cell *cell = mfd_get_cell(dev); + struct usb_hcd *hcd = platform_get_drvdata(dev); ++ struct ohci_hcd *ohci = hcd_to_ohci(hcd); + struct tmio_hcd *tmio = hcd_to_tmio(hcd); + struct tmio_uhccr __iomem *ccr = tmio->ccr; + u16 pm; + +- pm = UHCCR_PM_GKEN | UHCCR_PM_CKRNEN | UHCCR_PM_USBPW1 | UHCCR_PM_USBPW2; ++ pm = UHCCR_PM_GKEN | UHCCR_PM_CKRNEN; ++ switch (ohci->num_ports) { ++ default: ++ dev_err(&dev->dev, "Unsupported amount of ports: %d\n", ohci->num_ports); ++ case 3: ++ pm |= UHCCR_PM_USBPW3; ++ case 2: ++ pm |= UHCCR_PM_USBPW2; ++ case 1: ++ pm |= UHCCR_PM_USBPW1; ++ } + iowrite8(0, &ccr->intc); + iowrite8(0, &ccr->ilme); + iowrite16(0, &ccr->basel); + iowrite16(0, &ccr->baseh); +- iowrite16(pm, &ccr->pm); ++ iowrite16(pm, &ccr->pm); + + cell->disable(dev); + } + + static void tmio_start_hc(struct platform_device *dev) + { +- struct mfd_cell *cell = mfd_get_cell(dev); + struct usb_hcd *hcd = platform_get_drvdata(dev); + struct tmio_hcd *tmio = hcd_to_tmio(hcd); + struct tmio_uhccr __iomem *ccr = tmio->ccr; +- u16 pm; + unsigned long base = hcd->rsrc_start; + +- pm = UHCCR_PM_CKRNEN | UHCCR_PM_GKEN | UHCCR_PM_PMEE | UHCCR_PM_PMES; +- cell->enable(dev); +- +- iowrite16(pm, &ccr->pm); ++ tmio_write_pm(dev); + iowrite16(base, &ccr->basel); + iowrite16(base >> 16, &ccr->baseh); + iowrite8(1, &ccr->ilme); +@@ -133,9 +188,56 @@ static void tmio_start_hc(struct platform_device *dev) + ioread8(&ccr->revid), hcd->rsrc_start, hcd->irq); + } + ++static ssize_t tmio_disabled_port_show(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ struct usb_hcd *hcd = dev_get_drvdata(dev); ++ struct tmio_hcd *tmio = hcd_to_tmio(hcd); ++ int index = to_indexed_dev_attr(attr)->index; ++ return snprintf(buf, PAGE_SIZE, "%c", ++ tmio->disabled_ports[index-1]? 'Y': 'N'); ++} ++ ++static ssize_t tmio_disabled_port_store(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct usb_hcd *hcd = dev_get_drvdata(dev); ++ struct tmio_hcd *tmio = hcd_to_tmio(hcd); ++ int index = to_indexed_dev_attr(attr)->index; ++ ++ if (!count) ++ return -EINVAL; ++ ++ switch (buf[0]) { ++ case 'y': case 'Y': case '1': ++ tmio->disabled_ports[index-1] = true; ++ break; ++ case 'n': case 'N': case '0': ++ tmio->disabled_ports[index-1] = false; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ tmio_write_pm(to_platform_device(dev)); ++ ++ return 1; ++} ++ ++ ++static INDEXED_DEVICE_ATTR(disabled_usb_port, S_IRUGO | S_IWUSR, ++ tmio_disabled_port_show, tmio_disabled_port_store, 1); ++static INDEXED_DEVICE_ATTR(disabled_usb_port, S_IRUGO | S_IWUSR, ++ tmio_disabled_port_show, tmio_disabled_port_store, 2); ++static INDEXED_DEVICE_ATTR(disabled_usb_port, S_IRUGO | S_IWUSR, ++ tmio_disabled_port_show, tmio_disabled_port_store, 3); ++ + static int usb_hcd_tmio_probe(const struct hc_driver *driver, + struct platform_device *dev) + { ++ struct mfd_cell *cell = mfd_get_cell(dev); + struct resource *config = platform_get_resource_byname(dev, IORESOURCE_MEM, TMIO_OHCI_CONFIG); + struct resource *regs = platform_get_resource_byname(dev, IORESOURCE_MEM, TMIO_OHCI_CONTROL); + struct resource *sram = platform_get_resource_byname(dev, IORESOURCE_MEM, TMIO_OHCI_SRAM); +@@ -159,6 +261,12 @@ static int usb_hcd_tmio_probe(const struct hc_driver *driver, + + tmio = hcd_to_tmio(hcd); + ++ spin_lock_init(&tmio->lock); ++ ++ memcpy(tmio->disabled_ports, ++ disabled_tmio_ports, ++ sizeof(disabled_tmio_ports)); ++ + tmio->ccr = ioremap(config->start, config->end - config->start + 1); + if (!tmio->ccr) { + retval = -ENOMEM; +@@ -183,17 +291,46 @@ static int usb_hcd_tmio_probe(const struct hc_driver *driver, + if (retval) + goto err_dmabounce_register_dev; + ++ retval = cell->enable(dev); ++ if (retval) ++ goto err_enable; ++ + tmio_start_hc(dev); + ohci = hcd_to_ohci(hcd); + ohci_hcd_init(ohci); + + retval = usb_add_hcd(hcd, irq, IRQF_DISABLED); ++ if (retval) ++ goto err_add_hcd; ++ ++ switch (ohci->num_ports) { ++ default: ++ dev_err(&dev->dev, "Unsupported amount of ports: %d\n", ++ ohci->num_ports); ++ case 3: ++ retval |= device_create_file(&dev->dev, ++ &dev_attr_disabled_usb_port3.dev_attr); ++ case 2: ++ retval |= device_create_file(&dev->dev, ++ &dev_attr_disabled_usb_port2.dev_attr); ++ case 1: ++ retval |= device_create_file(&dev->dev, ++ &dev_attr_disabled_usb_port1.dev_attr); ++ } + + if (retval == 0) + return retval; + +- tmio_stop_hc(dev); ++ device_remove_file(&dev->dev, &dev_attr_disabled_usb_port3.dev_attr); ++ device_remove_file(&dev->dev, &dev_attr_disabled_usb_port2.dev_attr); ++ device_remove_file(&dev->dev, &dev_attr_disabled_usb_port1.dev_attr); ++ ++ usb_remove_hcd(hcd); + ++err_add_hcd: ++ tmio_stop_hc(dev); ++ cell->disable(dev); ++err_enable: + dmabounce_unregister_dev(&dev->dev); + err_dmabounce_register_dev: + dma_release_declared_memory(&dev->dev); +@@ -212,6 +349,9 @@ static void usb_hcd_tmio_remove(struct usb_hcd *hcd, struct platform_device *dev + { + struct tmio_hcd *tmio = hcd_to_tmio(hcd); + ++ device_remove_file(&dev->dev, &dev_attr_disabled_usb_port3.dev_attr); ++ device_remove_file(&dev->dev, &dev_attr_disabled_usb_port2.dev_attr); ++ device_remove_file(&dev->dev, &dev_attr_disabled_usb_port1.dev_attr); + usb_remove_hcd(hcd); + tmio_stop_hc(dev); + dmabounce_unregister_dev(&dev->dev); +@@ -297,13 +437,22 @@ static u64 dma_mask = DMA_32BIT_MASK; + static int ohci_hcd_tmio_drv_probe(struct platform_device *dev) + { + struct resource *sram = platform_get_resource_byname(dev, IORESOURCE_MEM, TMIO_OHCI_SRAM); ++ int retval; + + dev->dev.dma_mask = &dma_mask; + dev->dev.coherent_dma_mask = DMA_32BIT_MASK; + ++ /* FIXME: move dmabounce checkers to tc6393xb core? */ + dmabounce_register_checker(tmio_dmabounce_check, sram); + +- return usb_hcd_tmio_probe(&ohci_tmio_hc_driver, dev); ++ retval = usb_hcd_tmio_probe(&ohci_tmio_hc_driver, dev); ++ ++ if (retval == 0) ++ return retval; ++ ++ dmabounce_remove_checker(tmio_dmabounce_check, sram); ++ ++ return retval; + } + + static int ohci_hcd_tmio_drv_remove(struct platform_device *dev) +@@ -323,14 +472,31 @@ static int ohci_hcd_tmio_drv_remove(struct platform_device *dev) + #ifdef CONFIG_PM + static int ohci_hcd_tmio_drv_suspend(struct platform_device *dev, pm_message_t state) + { ++ struct mfd_cell *cell = mfd_get_cell(dev); + struct usb_hcd *hcd = platform_get_drvdata(dev); + struct ohci_hcd *ohci = hcd_to_ohci(hcd); ++ struct tmio_hcd *tmio = hcd_to_tmio(hcd); ++ struct tmio_uhccr __iomem *ccr = tmio->ccr; ++ unsigned long flags; ++ u8 misc; ++ int ret; + + if (time_before(jiffies, ohci->next_statechange)) + msleep(5); + ohci->next_statechange = jiffies; + +- tmio_stop_hc(dev); ++ spin_lock_irqsave(&tmio->lock, flags); ++ ++ misc = ioread8(&ccr->misc); ++ misc |= 1 << 3; /* USSUSP */ ++ iowrite8(misc, &ccr->misc); ++ ++ spin_unlock_irqrestore(&tmio->lock, flags); ++ ++ ret = cell->suspend(dev); ++ if (ret) ++ return ret; ++ + hcd->state = HC_STATE_SUSPENDED; + dev->dev.power.power_state = PMSG_SUSPEND; + +@@ -339,15 +505,33 @@ static int ohci_hcd_tmio_drv_suspend(struct platform_device *dev, pm_message_t s + + static int ohci_hcd_tmio_drv_resume(struct platform_device *dev) + { ++ struct mfd_cell *cell = mfd_get_cell(dev); + struct usb_hcd *hcd = platform_get_drvdata(dev); + struct ohci_hcd *ohci = hcd_to_ohci(hcd); ++ struct tmio_hcd *tmio = hcd_to_tmio(hcd); ++ struct tmio_uhccr __iomem *ccr = tmio->ccr; ++ unsigned long flags; ++ u8 misc; ++ int ret; + + if (time_before(jiffies, ohci->next_statechange)) + msleep(5); + ohci->next_statechange = jiffies; + ++ ret = cell->resume(dev); ++ if (ret) ++ return ret; ++ + tmio_start_hc(dev); + ++ spin_lock_irqsave(&tmio->lock, flags); ++ ++ misc = ioread8(&ccr->misc); ++ misc &= ~(1 << 3); /* USSUSP */ ++ iowrite8(misc, &ccr->misc); ++ ++ spin_unlock_irqrestore(&tmio->lock, flags); ++ + dev->dev.power.power_state = PMSG_ON; + usb_hcd_resume_root_hub(hcd); + +-- +1.5.3.8 + |