Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * OHCI HCD(Host Controller Driver) for USB.
0004  *
0005  *(C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
0006  *(C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
0007  *(C) Copyright 2002 Hewlett-Packard Company
0008  *
0009  * Bus glue for Toshiba Mobile IO(TMIO) Controller's OHCI core
0010  * (C) Copyright 2005 Chris Humbert <mahadri-usb@drigon.com>
0011  * (C) Copyright 2007, 2008 Dmitry Baryshkov <dbaryshkov@gmail.com>
0012  *
0013  * This is known to work with the following variants:
0014  *  TC6393XB revision 3 (32kB SRAM)
0015  *
0016  * The TMIO's OHCI core DMAs through a small internal buffer that
0017  * is directly addressable by the CPU.
0018  *
0019  * Written from sparse documentation from Toshiba and Sharp's driver
0020  * for the 2.4 kernel,
0021  *  usb-ohci-tc6393.c(C) Copyright 2004 Lineo Solutions, Inc.
0022  */
0023 
0024 #include <linux/platform_device.h>
0025 #include <linux/mfd/core.h>
0026 #include <linux/mfd/tmio.h>
0027 #include <linux/dma-mapping.h>
0028 
0029 /*-------------------------------------------------------------------------*/
0030 
0031 /*
0032  * USB Host Controller Configuration Register
0033  */
0034 #define CCR_REVID   0x08    /* b Revision ID                */
0035 #define CCR_BASE    0x10    /* l USB Control Register Base Address Low  */
0036 #define CCR_ILME    0x40    /* b Internal Local Memory Enable       */
0037 #define CCR_PM      0x4c    /* w Power Management           */
0038 #define CCR_INTC    0x50    /* b INT Control                */
0039 #define CCR_LMW1L   0x54    /* w Local Memory Window 1 LMADRS Low   */
0040 #define CCR_LMW1H   0x56    /* w Local Memory Window 1 LMADRS High  */
0041 #define CCR_LMW1BL  0x58    /* w Local Memory Window 1 Base Address Low */
0042 #define CCR_LMW1BH  0x5A    /* w Local Memory Window 1 Base Address High    */
0043 #define CCR_LMW2L   0x5C    /* w Local Memory Window 2 LMADRS Low   */
0044 #define CCR_LMW2H   0x5E    /* w Local Memory Window 2 LMADRS High  */
0045 #define CCR_LMW2BL  0x60    /* w Local Memory Window 2 Base Address Low */
0046 #define CCR_LMW2BH  0x62    /* w Local Memory Window 2 Base Address High    */
0047 #define CCR_MISC    0xFC    /* b MISC                   */
0048 
0049 #define CCR_PM_GKEN      0x0001
0050 #define CCR_PM_CKRNEN    0x0002
0051 #define CCR_PM_USBPW1    0x0004
0052 #define CCR_PM_USBPW2    0x0008
0053 #define CCR_PM_USBPW3    0x0010
0054 #define CCR_PM_PMEE      0x0100
0055 #define CCR_PM_PMES      0x8000
0056 
0057 /*-------------------------------------------------------------------------*/
0058 
0059 struct tmio_hcd {
0060     void __iomem        *ccr;
0061     spinlock_t      lock; /* protects RMW cycles */
0062 };
0063 
0064 #define hcd_to_tmio(hcd)    ((struct tmio_hcd *)(hcd_to_ohci(hcd) + 1))
0065 
0066 /*-------------------------------------------------------------------------*/
0067 
0068 static void tmio_write_pm(struct platform_device *dev)
0069 {
0070     struct usb_hcd *hcd = platform_get_drvdata(dev);
0071     struct tmio_hcd *tmio = hcd_to_tmio(hcd);
0072     u16 pm;
0073     unsigned long flags;
0074 
0075     spin_lock_irqsave(&tmio->lock, flags);
0076 
0077     pm = CCR_PM_GKEN | CCR_PM_CKRNEN |
0078          CCR_PM_PMEE | CCR_PM_PMES;
0079 
0080     tmio_iowrite16(pm, tmio->ccr + CCR_PM);
0081     spin_unlock_irqrestore(&tmio->lock, flags);
0082 }
0083 
0084 static void tmio_stop_hc(struct platform_device *dev)
0085 {
0086     struct usb_hcd *hcd = platform_get_drvdata(dev);
0087     struct ohci_hcd *ohci = hcd_to_ohci(hcd);
0088     struct tmio_hcd *tmio = hcd_to_tmio(hcd);
0089     u16 pm;
0090 
0091     pm = CCR_PM_GKEN | CCR_PM_CKRNEN;
0092     switch (ohci->num_ports) {
0093         default:
0094             dev_err(&dev->dev, "Unsupported amount of ports: %d\n", ohci->num_ports);
0095             fallthrough;
0096         case 3:
0097             pm |= CCR_PM_USBPW3;
0098             fallthrough;
0099         case 2:
0100             pm |= CCR_PM_USBPW2;
0101             fallthrough;
0102         case 1:
0103             pm |= CCR_PM_USBPW1;
0104     }
0105     tmio_iowrite8(0, tmio->ccr + CCR_INTC);
0106     tmio_iowrite8(0, tmio->ccr + CCR_ILME);
0107     tmio_iowrite16(0, tmio->ccr + CCR_BASE);
0108     tmio_iowrite16(0, tmio->ccr + CCR_BASE + 2);
0109     tmio_iowrite16(pm, tmio->ccr + CCR_PM);
0110 }
0111 
0112 static void tmio_start_hc(struct platform_device *dev)
0113 {
0114     struct usb_hcd *hcd = platform_get_drvdata(dev);
0115     struct tmio_hcd *tmio = hcd_to_tmio(hcd);
0116     unsigned long base = hcd->rsrc_start;
0117 
0118     tmio_write_pm(dev);
0119     tmio_iowrite16(base, tmio->ccr + CCR_BASE);
0120     tmio_iowrite16(base >> 16, tmio->ccr + CCR_BASE + 2);
0121     tmio_iowrite8(1, tmio->ccr + CCR_ILME);
0122     tmio_iowrite8(2, tmio->ccr + CCR_INTC);
0123 
0124     dev_info(&dev->dev, "revision %d @ 0x%08llx, irq %d\n",
0125             tmio_ioread8(tmio->ccr + CCR_REVID),
0126             (u64) hcd->rsrc_start, hcd->irq);
0127 }
0128 
0129 static int ohci_tmio_start(struct usb_hcd *hcd)
0130 {
0131     struct ohci_hcd *ohci = hcd_to_ohci(hcd);
0132     int ret;
0133 
0134     if ((ret = ohci_init(ohci)) < 0)
0135         return ret;
0136 
0137     if ((ret = ohci_run(ohci)) < 0) {
0138         dev_err(hcd->self.controller, "can't start %s\n",
0139             hcd->self.bus_name);
0140         ohci_stop(hcd);
0141         return ret;
0142     }
0143 
0144     return 0;
0145 }
0146 
0147 static const struct hc_driver ohci_tmio_hc_driver = {
0148     .description =      hcd_name,
0149     .product_desc =     "TMIO OHCI USB Host Controller",
0150     .hcd_priv_size =    sizeof(struct ohci_hcd) + sizeof (struct tmio_hcd),
0151 
0152     /* generic hardware linkage */
0153     .irq =          ohci_irq,
0154     .flags =        HCD_USB11 | HCD_MEMORY,
0155 
0156     /* basic lifecycle operations */
0157     .start =        ohci_tmio_start,
0158     .stop =         ohci_stop,
0159     .shutdown =     ohci_shutdown,
0160 
0161     /* managing i/o requests and associated device resources */
0162     .urb_enqueue =      ohci_urb_enqueue,
0163     .urb_dequeue =      ohci_urb_dequeue,
0164     .endpoint_disable = ohci_endpoint_disable,
0165 
0166     /* scheduling support */
0167     .get_frame_number = ohci_get_frame,
0168 
0169     /* root hub support */
0170     .hub_status_data =  ohci_hub_status_data,
0171     .hub_control =      ohci_hub_control,
0172 #ifdef  CONFIG_PM
0173     .bus_suspend =      ohci_bus_suspend,
0174     .bus_resume =       ohci_bus_resume,
0175 #endif
0176     .start_port_reset = ohci_start_port_reset,
0177 };
0178 
0179 /*-------------------------------------------------------------------------*/
0180 static struct platform_driver ohci_hcd_tmio_driver;
0181 
0182 static int ohci_hcd_tmio_drv_probe(struct platform_device *dev)
0183 {
0184     const struct mfd_cell *cell = mfd_get_cell(dev);
0185     struct resource *regs = platform_get_resource(dev, IORESOURCE_MEM, 0);
0186     struct resource *config = platform_get_resource(dev, IORESOURCE_MEM, 1);
0187     struct resource *sram = platform_get_resource(dev, IORESOURCE_MEM, 2);
0188     int irq = platform_get_irq(dev, 0);
0189     struct tmio_hcd *tmio;
0190     struct ohci_hcd *ohci;
0191     struct usb_hcd *hcd;
0192     int ret;
0193 
0194     if (usb_disabled())
0195         return -ENODEV;
0196 
0197     if (!cell || !regs || !config || !sram)
0198         return -EINVAL;
0199 
0200     if (irq < 0)
0201         return irq;
0202 
0203     hcd = usb_create_hcd(&ohci_tmio_hc_driver, &dev->dev, dev_name(&dev->dev));
0204     if (!hcd) {
0205         ret = -ENOMEM;
0206         goto err_usb_create_hcd;
0207     }
0208 
0209     hcd->rsrc_start = regs->start;
0210     hcd->rsrc_len = resource_size(regs);
0211 
0212     tmio = hcd_to_tmio(hcd);
0213 
0214     spin_lock_init(&tmio->lock);
0215 
0216     tmio->ccr = ioremap(config->start, resource_size(config));
0217     if (!tmio->ccr) {
0218         ret = -ENOMEM;
0219         goto err_ioremap_ccr;
0220     }
0221 
0222     hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
0223     if (!hcd->regs) {
0224         ret = -ENOMEM;
0225         goto err_ioremap_regs;
0226     }
0227 
0228     if (cell->enable) {
0229         ret = cell->enable(dev);
0230         if (ret)
0231             goto err_enable;
0232     }
0233 
0234     tmio_start_hc(dev);
0235     ohci = hcd_to_ohci(hcd);
0236     ohci_hcd_init(ohci);
0237 
0238     ret = usb_hcd_setup_local_mem(hcd, sram->start, sram->start,
0239                       resource_size(sram));
0240     if (ret < 0)
0241         goto err_enable;
0242 
0243     ret = usb_add_hcd(hcd, irq, 0);
0244     if (ret)
0245         goto err_add_hcd;
0246 
0247     device_wakeup_enable(hcd->self.controller);
0248     if (ret == 0)
0249         return ret;
0250 
0251     usb_remove_hcd(hcd);
0252 
0253 err_add_hcd:
0254     tmio_stop_hc(dev);
0255     if (cell->disable)
0256         cell->disable(dev);
0257 err_enable:
0258     iounmap(hcd->regs);
0259 err_ioremap_regs:
0260     iounmap(tmio->ccr);
0261 err_ioremap_ccr:
0262     usb_put_hcd(hcd);
0263 err_usb_create_hcd:
0264 
0265     return ret;
0266 }
0267 
0268 static int ohci_hcd_tmio_drv_remove(struct platform_device *dev)
0269 {
0270     struct usb_hcd *hcd = platform_get_drvdata(dev);
0271     struct tmio_hcd *tmio = hcd_to_tmio(hcd);
0272     const struct mfd_cell *cell = mfd_get_cell(dev);
0273 
0274     usb_remove_hcd(hcd);
0275     tmio_stop_hc(dev);
0276     if (cell->disable)
0277         cell->disable(dev);
0278     iounmap(hcd->regs);
0279     iounmap(tmio->ccr);
0280     usb_put_hcd(hcd);
0281 
0282     return 0;
0283 }
0284 
0285 #ifdef CONFIG_PM
0286 static int ohci_hcd_tmio_drv_suspend(struct platform_device *dev, pm_message_t state)
0287 {
0288     const struct mfd_cell *cell = mfd_get_cell(dev);
0289     struct usb_hcd *hcd = platform_get_drvdata(dev);
0290     struct ohci_hcd *ohci = hcd_to_ohci(hcd);
0291     struct tmio_hcd *tmio = hcd_to_tmio(hcd);
0292     unsigned long flags;
0293     u8 misc;
0294     int ret;
0295 
0296     if (time_before(jiffies, ohci->next_statechange))
0297         msleep(5);
0298     ohci->next_statechange = jiffies;
0299 
0300     spin_lock_irqsave(&tmio->lock, flags);
0301 
0302     misc = tmio_ioread8(tmio->ccr + CCR_MISC);
0303     misc |= 1 << 3; /* USSUSP */
0304     tmio_iowrite8(misc, tmio->ccr + CCR_MISC);
0305 
0306     spin_unlock_irqrestore(&tmio->lock, flags);
0307 
0308     if (cell->suspend) {
0309         ret = cell->suspend(dev);
0310         if (ret)
0311             return ret;
0312     }
0313     return 0;
0314 }
0315 
0316 static int ohci_hcd_tmio_drv_resume(struct platform_device *dev)
0317 {
0318     const struct mfd_cell *cell = mfd_get_cell(dev);
0319     struct usb_hcd *hcd = platform_get_drvdata(dev);
0320     struct ohci_hcd *ohci = hcd_to_ohci(hcd);
0321     struct tmio_hcd *tmio = hcd_to_tmio(hcd);
0322     unsigned long flags;
0323     u8 misc;
0324     int ret;
0325 
0326     if (time_before(jiffies, ohci->next_statechange))
0327         msleep(5);
0328     ohci->next_statechange = jiffies;
0329 
0330     if (cell->resume) {
0331         ret = cell->resume(dev);
0332         if (ret)
0333             return ret;
0334     }
0335 
0336     tmio_start_hc(dev);
0337 
0338     spin_lock_irqsave(&tmio->lock, flags);
0339 
0340     misc = tmio_ioread8(tmio->ccr + CCR_MISC);
0341     misc &= ~(1 << 3); /* USSUSP */
0342     tmio_iowrite8(misc, tmio->ccr + CCR_MISC);
0343 
0344     spin_unlock_irqrestore(&tmio->lock, flags);
0345 
0346     ohci_resume(hcd, false);
0347 
0348     return 0;
0349 }
0350 #else
0351 #define ohci_hcd_tmio_drv_suspend NULL
0352 #define ohci_hcd_tmio_drv_resume NULL
0353 #endif
0354 
0355 static struct platform_driver ohci_hcd_tmio_driver = {
0356     .probe      = ohci_hcd_tmio_drv_probe,
0357     .remove     = ohci_hcd_tmio_drv_remove,
0358     .shutdown   = usb_hcd_platform_shutdown,
0359     .suspend    = ohci_hcd_tmio_drv_suspend,
0360     .resume     = ohci_hcd_tmio_drv_resume,
0361     .driver     = {
0362         .name   = "tmio-ohci",
0363     },
0364 };