linux/drivers/usb/host/ehci-fsl.c
<<
>>
Prefs
   1/*
   2 * Copyright 2005-2009 MontaVista Software, Inc.
   3 * Copyright 2008      Freescale Semiconductor, Inc.
   4 *
   5 * This program is free software; you can redistribute it and/or modify it
   6 * under the terms of the GNU General Public License as published by the
   7 * Free Software Foundation; either version 2 of the License, or (at your
   8 * option) any later version.
   9 *
  10 * This program is distributed in the hope that it will be useful, but
  11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  12 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  13 * for more details.
  14 *
  15 * You should have received a copy of the GNU General Public License
  16 * along with this program; if not, write to the Free Software Foundation,
  17 * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18 *
  19 * Ported to 834x by Randy Vinson <rvinson@mvista.com> using code provided
  20 * by Hunter Wu.
  21 * Power Management support by Dave Liu <daveliu@freescale.com>,
  22 * Jerry Huang <Chang-Ming.Huang@freescale.com> and
  23 * Anton Vorontsov <avorontsov@ru.mvista.com>.
  24 */
  25
  26#include <linux/kernel.h>
  27#include <linux/types.h>
  28#include <linux/delay.h>
  29#include <linux/pm.h>
  30#include <linux/platform_device.h>
  31#include <linux/fsl_devices.h>
  32
  33#include "ehci-fsl.h"
  34
  35/* configure so an HC device and id are always provided */
  36/* always called with process context; sleeping is OK */
  37
  38/**
  39 * usb_hcd_fsl_probe - initialize FSL-based HCDs
  40 * @drvier: Driver to be used for this HCD
  41 * @pdev: USB Host Controller being probed
  42 * Context: !in_interrupt()
  43 *
  44 * Allocates basic resources for this USB host controller.
  45 *
  46 */
  47static int usb_hcd_fsl_probe(const struct hc_driver *driver,
  48                             struct platform_device *pdev)
  49{
  50        struct fsl_usb2_platform_data *pdata;
  51        struct usb_hcd *hcd;
  52        struct resource *res;
  53        int irq;
  54        int retval;
  55
  56        pr_debug("initializing FSL-SOC USB Controller\n");
  57
  58        /* Need platform data for setup */
  59        pdata = (struct fsl_usb2_platform_data *)pdev->dev.platform_data;
  60        if (!pdata) {
  61                dev_err(&pdev->dev,
  62                        "No platform data for %s.\n", dev_name(&pdev->dev));
  63                return -ENODEV;
  64        }
  65
  66        /*
  67         * This is a host mode driver, verify that we're supposed to be
  68         * in host mode.
  69         */
  70        if (!((pdata->operating_mode == FSL_USB2_DR_HOST) ||
  71              (pdata->operating_mode == FSL_USB2_MPH_HOST) ||
  72              (pdata->operating_mode == FSL_USB2_DR_OTG))) {
  73                dev_err(&pdev->dev,
  74                        "Non Host Mode configured for %s. Wrong driver linked.\n",
  75                        dev_name(&pdev->dev));
  76                return -ENODEV;
  77        }
  78
  79        res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
  80        if (!res) {
  81                dev_err(&pdev->dev,
  82                        "Found HC with no IRQ. Check %s setup!\n",
  83                        dev_name(&pdev->dev));
  84                return -ENODEV;
  85        }
  86        irq = res->start;
  87
  88        hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev));
  89        if (!hcd) {
  90                retval = -ENOMEM;
  91                goto err1;
  92        }
  93
  94        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  95        if (!res) {
  96                dev_err(&pdev->dev,
  97                        "Found HC with no register addr. Check %s setup!\n",
  98                        dev_name(&pdev->dev));
  99                retval = -ENODEV;
 100                goto err2;
 101        }
 102        hcd->rsrc_start = res->start;
 103        hcd->rsrc_len = res->end - res->start + 1;
 104        if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len,
 105                                driver->description)) {
 106                dev_dbg(&pdev->dev, "controller already in use\n");
 107                retval = -EBUSY;
 108                goto err2;
 109        }
 110        hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
 111
 112        if (hcd->regs == NULL) {
 113                dev_dbg(&pdev->dev, "error mapping memory\n");
 114                retval = -EFAULT;
 115                goto err3;
 116        }
 117
 118        pdata->regs = hcd->regs;
 119
 120        /*
 121         * do platform specific init: check the clock, grab/config pins, etc.
 122         */
 123        if (pdata->init && pdata->init(pdev)) {
 124                retval = -ENODEV;
 125                goto err3;
 126        }
 127
 128        /* Enable USB controller, 83xx or 8536 */
 129        if (pdata->have_sysif_regs)
 130                setbits32(hcd->regs + FSL_SOC_USB_CTRL, 0x4);
 131
 132        /* Don't need to set host mode here. It will be done by tdi_reset() */
 133
 134        retval = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
 135        if (retval != 0)
 136                goto err4;
 137        return retval;
 138
 139      err4:
 140        iounmap(hcd->regs);
 141      err3:
 142        release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 143      err2:
 144        usb_put_hcd(hcd);
 145      err1:
 146        dev_err(&pdev->dev, "init %s fail, %d\n", dev_name(&pdev->dev), retval);
 147        if (pdata->exit)
 148                pdata->exit(pdev);
 149        return retval;
 150}
 151
 152/* may be called without controller electrically present */
 153/* may be called with controller, bus, and devices active */
 154
 155/**
 156 * usb_hcd_fsl_remove - shutdown processing for FSL-based HCDs
 157 * @dev: USB Host Controller being removed
 158 * Context: !in_interrupt()
 159 *
 160 * Reverses the effect of usb_hcd_fsl_probe().
 161 *
 162 */
 163static void usb_hcd_fsl_remove(struct usb_hcd *hcd,
 164                               struct platform_device *pdev)
 165{
 166        struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
 167
 168        usb_remove_hcd(hcd);
 169
 170        /*
 171         * do platform specific un-initialization:
 172         * release iomux pins, disable clock, etc.
 173         */
 174        if (pdata->exit)
 175                pdata->exit(pdev);
 176        iounmap(hcd->regs);
 177        release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 178        usb_put_hcd(hcd);
 179}
 180
 181static void ehci_fsl_setup_phy(struct ehci_hcd *ehci,
 182                               enum fsl_usb2_phy_modes phy_mode,
 183                               unsigned int port_offset)
 184{
 185        u32 portsc;
 186
 187        portsc = ehci_readl(ehci, &ehci->regs->port_status[port_offset]);
 188        portsc &= ~(PORT_PTS_MSK | PORT_PTS_PTW);
 189
 190        switch (phy_mode) {
 191        case FSL_USB2_PHY_ULPI:
 192                portsc |= PORT_PTS_ULPI;
 193                break;
 194        case FSL_USB2_PHY_SERIAL:
 195                portsc |= PORT_PTS_SERIAL;
 196                break;
 197        case FSL_USB2_PHY_UTMI_WIDE:
 198                portsc |= PORT_PTS_PTW;
 199                /* fall through */
 200        case FSL_USB2_PHY_UTMI:
 201                portsc |= PORT_PTS_UTMI;
 202                break;
 203        case FSL_USB2_PHY_NONE:
 204                break;
 205        }
 206        ehci_writel(ehci, portsc, &ehci->regs->port_status[port_offset]);
 207}
 208
 209static void ehci_fsl_usb_setup(struct ehci_hcd *ehci)
 210{
 211        struct usb_hcd *hcd = ehci_to_hcd(ehci);
 212        struct fsl_usb2_platform_data *pdata;
 213        void __iomem *non_ehci = hcd->regs;
 214        u32 temp;
 215
 216        pdata = hcd->self.controller->platform_data;
 217
 218        /* Enable PHY interface in the control reg. */
 219        if (pdata->have_sysif_regs) {
 220                temp = in_be32(non_ehci + FSL_SOC_USB_CTRL);
 221                out_be32(non_ehci + FSL_SOC_USB_CTRL, temp | 0x00000004);
 222                out_be32(non_ehci + FSL_SOC_USB_SNOOP1, 0x0000001b);
 223        }
 224
 225#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
 226        /*
 227         * Turn on cache snooping hardware, since some PowerPC platforms
 228         * wholly rely on hardware to deal with cache coherent
 229         */
 230
 231        /* Setup Snooping for all the 4GB space */
 232        /* SNOOP1 starts from 0x0, size 2G */
 233        out_be32(non_ehci + FSL_SOC_USB_SNOOP1, 0x0 | SNOOP_SIZE_2GB);
 234        /* SNOOP2 starts from 0x80000000, size 2G */
 235        out_be32(non_ehci + FSL_SOC_USB_SNOOP2, 0x80000000 | SNOOP_SIZE_2GB);
 236#endif
 237
 238        if ((pdata->operating_mode == FSL_USB2_DR_HOST) ||
 239                        (pdata->operating_mode == FSL_USB2_DR_OTG))
 240                ehci_fsl_setup_phy(ehci, pdata->phy_mode, 0);
 241
 242        if (pdata->operating_mode == FSL_USB2_MPH_HOST) {
 243                unsigned int chip, rev, svr;
 244
 245                svr = mfspr(SPRN_SVR);
 246                chip = svr >> 16;
 247                rev = (svr >> 4) & 0xf;
 248
 249                /* Deal with USB Erratum #14 on MPC834x Rev 1.0 & 1.1 chips */
 250                if ((rev == 1) && (chip >= 0x8050) && (chip <= 0x8055))
 251                        ehci->has_fsl_port_bug = 1;
 252
 253                if (pdata->port_enables & FSL_USB2_PORT0_ENABLED)
 254                        ehci_fsl_setup_phy(ehci, pdata->phy_mode, 0);
 255                if (pdata->port_enables & FSL_USB2_PORT1_ENABLED)
 256                        ehci_fsl_setup_phy(ehci, pdata->phy_mode, 1);
 257        }
 258
 259        if (pdata->have_sysif_regs) {
 260#ifdef CONFIG_PPC_85xx
 261                out_be32(non_ehci + FSL_SOC_USB_PRICTRL, 0x00000008);
 262                out_be32(non_ehci + FSL_SOC_USB_AGECNTTHRSH, 0x00000080);
 263#else
 264                out_be32(non_ehci + FSL_SOC_USB_PRICTRL, 0x0000000c);
 265                out_be32(non_ehci + FSL_SOC_USB_AGECNTTHRSH, 0x00000040);
 266#endif
 267                out_be32(non_ehci + FSL_SOC_USB_SICTRL, 0x00000001);
 268        }
 269}
 270
 271/* called after powerup, by probe or system-pm "wakeup" */
 272static int ehci_fsl_reinit(struct ehci_hcd *ehci)
 273{
 274        ehci_fsl_usb_setup(ehci);
 275        ehci_port_power(ehci, 0);
 276
 277        return 0;
 278}
 279
 280/* called during probe() after chip reset completes */
 281static int ehci_fsl_setup(struct usb_hcd *hcd)
 282{
 283        struct ehci_hcd *ehci = hcd_to_ehci(hcd);
 284        int retval;
 285        struct fsl_usb2_platform_data *pdata;
 286
 287        pdata = hcd->self.controller->platform_data;
 288        ehci->big_endian_desc = pdata->big_endian_desc;
 289        ehci->big_endian_mmio = pdata->big_endian_mmio;
 290
 291        /* EHCI registers start at offset 0x100 */
 292        ehci->caps = hcd->regs + 0x100;
 293        ehci->regs = hcd->regs + 0x100 +
 294            HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
 295        dbg_hcs_params(ehci, "reset");
 296        dbg_hcc_params(ehci, "reset");
 297
 298        /* cache this readonly data; minimize chip reads */
 299        ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
 300
 301        hcd->has_tt = 1;
 302
 303        retval = ehci_halt(ehci);
 304        if (retval)
 305                return retval;
 306
 307        /* data structure init */
 308        retval = ehci_init(hcd);
 309        if (retval)
 310                return retval;
 311
 312        ehci->sbrn = 0x20;
 313
 314        ehci_reset(ehci);
 315
 316        retval = ehci_fsl_reinit(ehci);
 317        return retval;
 318}
 319
 320struct ehci_fsl {
 321        struct ehci_hcd ehci;
 322
 323#ifdef CONFIG_PM
 324        /* Saved USB PHY settings, need to restore after deep sleep. */
 325        u32 usb_ctrl;
 326#endif
 327};
 328
 329#ifdef CONFIG_PM
 330
 331static struct ehci_fsl *hcd_to_ehci_fsl(struct usb_hcd *hcd)
 332{
 333        struct ehci_hcd *ehci = hcd_to_ehci(hcd);
 334
 335        return container_of(ehci, struct ehci_fsl, ehci);
 336}
 337
 338static int ehci_fsl_drv_suspend(struct device *dev)
 339{
 340        struct usb_hcd *hcd = dev_get_drvdata(dev);
 341        struct ehci_fsl *ehci_fsl = hcd_to_ehci_fsl(hcd);
 342        void __iomem *non_ehci = hcd->regs;
 343
 344        ehci_prepare_ports_for_controller_suspend(hcd_to_ehci(hcd),
 345                        device_may_wakeup(dev));
 346        if (!fsl_deep_sleep())
 347                return 0;
 348
 349        ehci_fsl->usb_ctrl = in_be32(non_ehci + FSL_SOC_USB_CTRL);
 350        return 0;
 351}
 352
 353static int ehci_fsl_drv_resume(struct device *dev)
 354{
 355        struct usb_hcd *hcd = dev_get_drvdata(dev);
 356        struct ehci_fsl *ehci_fsl = hcd_to_ehci_fsl(hcd);
 357        struct ehci_hcd *ehci = hcd_to_ehci(hcd);
 358        void __iomem *non_ehci = hcd->regs;
 359
 360        ehci_prepare_ports_for_controller_resume(ehci);
 361        if (!fsl_deep_sleep())
 362                return 0;
 363
 364        usb_root_hub_lost_power(hcd->self.root_hub);
 365
 366        /* Restore USB PHY settings and enable the controller. */
 367        out_be32(non_ehci + FSL_SOC_USB_CTRL, ehci_fsl->usb_ctrl);
 368
 369        ehci_reset(ehci);
 370        ehci_fsl_reinit(ehci);
 371
 372        return 0;
 373}
 374
 375static int ehci_fsl_drv_restore(struct device *dev)
 376{
 377        struct usb_hcd *hcd = dev_get_drvdata(dev);
 378
 379        usb_root_hub_lost_power(hcd->self.root_hub);
 380        return 0;
 381}
 382
 383static struct dev_pm_ops ehci_fsl_pm_ops = {
 384        .suspend = ehci_fsl_drv_suspend,
 385        .resume = ehci_fsl_drv_resume,
 386        .restore = ehci_fsl_drv_restore,
 387};
 388
 389#define EHCI_FSL_PM_OPS         (&ehci_fsl_pm_ops)
 390#else
 391#define EHCI_FSL_PM_OPS         NULL
 392#endif /* CONFIG_PM */
 393
 394static const struct hc_driver ehci_fsl_hc_driver = {
 395        .description = hcd_name,
 396        .product_desc = "Freescale On-Chip EHCI Host Controller",
 397        .hcd_priv_size = sizeof(struct ehci_fsl),
 398
 399        /*
 400         * generic hardware linkage
 401         */
 402        .irq = ehci_irq,
 403        .flags = HCD_USB2 | HCD_MEMORY,
 404
 405        /*
 406         * basic lifecycle operations
 407         */
 408        .reset = ehci_fsl_setup,
 409        .start = ehci_run,
 410        .stop = ehci_stop,
 411        .shutdown = ehci_shutdown,
 412
 413        /*
 414         * managing i/o requests and associated device resources
 415         */
 416        .urb_enqueue = ehci_urb_enqueue,
 417        .urb_dequeue = ehci_urb_dequeue,
 418        .endpoint_disable = ehci_endpoint_disable,
 419        .endpoint_reset = ehci_endpoint_reset,
 420
 421        /*
 422         * scheduling support
 423         */
 424        .get_frame_number = ehci_get_frame,
 425
 426        /*
 427         * root hub support
 428         */
 429        .hub_status_data = ehci_hub_status_data,
 430        .hub_control = ehci_hub_control,
 431        .bus_suspend = ehci_bus_suspend,
 432        .bus_resume = ehci_bus_resume,
 433        .relinquish_port = ehci_relinquish_port,
 434        .port_handed_over = ehci_port_handed_over,
 435
 436        .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
 437};
 438
 439static int ehci_fsl_drv_probe(struct platform_device *pdev)
 440{
 441        if (usb_disabled())
 442                return -ENODEV;
 443
 444        /* FIXME we only want one one probe() not two */
 445        return usb_hcd_fsl_probe(&ehci_fsl_hc_driver, pdev);
 446}
 447
 448static int ehci_fsl_drv_remove(struct platform_device *pdev)
 449{
 450        struct usb_hcd *hcd = platform_get_drvdata(pdev);
 451
 452        /* FIXME we only want one one remove() not two */
 453        usb_hcd_fsl_remove(hcd, pdev);
 454        return 0;
 455}
 456
 457MODULE_ALIAS("platform:fsl-ehci");
 458
 459static struct platform_driver ehci_fsl_driver = {
 460        .probe = ehci_fsl_drv_probe,
 461        .remove = ehci_fsl_drv_remove,
 462        .shutdown = usb_hcd_platform_shutdown,
 463        .driver = {
 464                .name = "fsl-ehci",
 465                .pm = EHCI_FSL_PM_OPS,
 466        },
 467};
 468