cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

ohci-omap.c (11352B)


      1// SPDX-License-Identifier: GPL-1.0+
      2/*
      3 * OHCI HCD (Host Controller Driver) for USB.
      4 *
      5 * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
      6 * (C) Copyright 2000-2005 David Brownell
      7 * (C) Copyright 2002 Hewlett-Packard Company
      8 *
      9 * OMAP Bus Glue
     10 *
     11 * Modified for OMAP by Tony Lindgren <tony@atomide.com>
     12 * Based on the 2.4 OMAP OHCI driver originally done by MontaVista Software Inc.
     13 * and on ohci-sa1111.c by Christopher Hoover <ch@hpl.hp.com>
     14 *
     15 * This file is licenced under the GPL.
     16 */
     17
     18#include <linux/clk.h>
     19#include <linux/dma-mapping.h>
     20#include <linux/err.h>
     21#include <linux/gpio/consumer.h>
     22#include <linux/io.h>
     23#include <linux/jiffies.h>
     24#include <linux/kernel.h>
     25#include <linux/module.h>
     26#include <linux/usb/otg.h>
     27#include <linux/platform_device.h>
     28#include <linux/platform_data/usb-omap1.h>
     29#include <linux/soc/ti/omap1-usb.h>
     30#include <linux/soc/ti/omap1-mux.h>
     31#include <linux/soc/ti/omap1-soc.h>
     32#include <linux/soc/ti/omap1-io.h>
     33#include <linux/signal.h>
     34#include <linux/usb.h>
     35#include <linux/usb/hcd.h>
     36
     37#include "ohci.h"
     38
     39#include <asm/io.h>
     40#include <asm/mach-types.h>
     41
     42#define DRIVER_DESC "OHCI OMAP driver"
     43
     44struct ohci_omap_priv {
     45	struct clk *usb_host_ck;
     46	struct clk *usb_dc_ck;
     47	struct gpio_desc *power;
     48	struct gpio_desc *overcurrent;
     49};
     50
     51static const char hcd_name[] = "ohci-omap";
     52static struct hc_driver __read_mostly ohci_omap_hc_driver;
     53
     54#define hcd_to_ohci_omap_priv(h) \
     55	((struct ohci_omap_priv *)hcd_to_ohci(h)->priv)
     56
     57static void omap_ohci_clock_power(struct ohci_omap_priv *priv, int on)
     58{
     59	if (on) {
     60		clk_enable(priv->usb_dc_ck);
     61		clk_enable(priv->usb_host_ck);
     62		/* guesstimate for T5 == 1x 32K clock + APLL lock time */
     63		udelay(100);
     64	} else {
     65		clk_disable(priv->usb_host_ck);
     66		clk_disable(priv->usb_dc_ck);
     67	}
     68}
     69
     70#ifdef	CONFIG_USB_OTG
     71
     72static void start_hnp(struct ohci_hcd *ohci)
     73{
     74	struct usb_hcd *hcd = ohci_to_hcd(ohci);
     75	const unsigned	port = hcd->self.otg_port - 1;
     76	unsigned long	flags;
     77	u32 l;
     78
     79	otg_start_hnp(hcd->usb_phy->otg);
     80
     81	local_irq_save(flags);
     82	hcd->usb_phy->otg->state = OTG_STATE_A_SUSPEND;
     83	writel (RH_PS_PSS, &ohci->regs->roothub.portstatus [port]);
     84	l = omap_readl(OTG_CTRL);
     85	l &= ~OTG_A_BUSREQ;
     86	omap_writel(l, OTG_CTRL);
     87	local_irq_restore(flags);
     88}
     89
     90#endif
     91
     92/*-------------------------------------------------------------------------*/
     93
     94static int ohci_omap_reset(struct usb_hcd *hcd)
     95{
     96	struct ohci_hcd		*ohci = hcd_to_ohci(hcd);
     97	struct omap_usb_config	*config = dev_get_platdata(hcd->self.controller);
     98	struct ohci_omap_priv	*priv = hcd_to_ohci_omap_priv(hcd);
     99	int			need_transceiver = (config->otg != 0);
    100	int			ret;
    101
    102	dev_dbg(hcd->self.controller, "starting USB Controller\n");
    103
    104	if (config->otg) {
    105		hcd->self.otg_port = config->otg;
    106		/* default/minimum OTG power budget:  8 mA */
    107		hcd->power_budget = 8;
    108	}
    109
    110	/* boards can use OTG transceivers in non-OTG modes */
    111	need_transceiver = need_transceiver
    112			|| machine_is_omap_h2() || machine_is_omap_h3();
    113
    114	/* XXX OMAP16xx only */
    115	if (config->ocpi_enable)
    116		config->ocpi_enable();
    117
    118#ifdef	CONFIG_USB_OTG
    119	if (need_transceiver) {
    120		hcd->usb_phy = usb_get_phy(USB_PHY_TYPE_USB2);
    121		if (!IS_ERR_OR_NULL(hcd->usb_phy)) {
    122			int	status = otg_set_host(hcd->usb_phy->otg,
    123						&ohci_to_hcd(ohci)->self);
    124			dev_dbg(hcd->self.controller, "init %s phy, status %d\n",
    125					hcd->usb_phy->label, status);
    126			if (status) {
    127				usb_put_phy(hcd->usb_phy);
    128				return status;
    129			}
    130		} else {
    131			return -EPROBE_DEFER;
    132		}
    133		hcd->skip_phy_initialization = 1;
    134		ohci->start_hnp = start_hnp;
    135	}
    136#endif
    137
    138	omap_ohci_clock_power(priv, 1);
    139
    140	if (config->lb_reset)
    141		config->lb_reset();
    142
    143	ret = ohci_setup(hcd);
    144	if (ret < 0)
    145		return ret;
    146
    147	if (config->otg || config->rwc) {
    148		ohci->hc_control = OHCI_CTRL_RWC;
    149		writel(OHCI_CTRL_RWC, &ohci->regs->control);
    150	}
    151
    152	/* board-specific power switching and overcurrent support */
    153	if (machine_is_omap_osk() || machine_is_omap_innovator()) {
    154		u32	rh = roothub_a (ohci);
    155
    156		/* power switching (ganged by default) */
    157		rh &= ~RH_A_NPS;
    158
    159		/* TPS2045 switch for internal transceiver (port 1) */
    160		if (machine_is_omap_osk()) {
    161			ohci_to_hcd(ohci)->power_budget = 250;
    162
    163			rh &= ~RH_A_NOCP;
    164
    165			/* gpio9 for overcurrent detction */
    166			omap_cfg_reg(W8_1610_GPIO9);
    167
    168			/* for paranoia's sake:  disable USB.PUEN */
    169			omap_cfg_reg(W4_USB_HIGHZ);
    170		}
    171		ohci_writel(ohci, rh, &ohci->regs->roothub.a);
    172		ohci->flags &= ~OHCI_QUIRK_HUB_POWER;
    173	} else if (machine_is_nokia770()) {
    174		/* We require a self-powered hub, which should have
    175		 * plenty of power. */
    176		ohci_to_hcd(ohci)->power_budget = 0;
    177	}
    178
    179	/* FIXME hub_wq hub requests should manage power switching */
    180	if (config->transceiver_power)
    181		return config->transceiver_power(1);
    182
    183	if (priv->power)
    184		gpiod_set_value_cansleep(priv->power, 0);
    185
    186	/* board init will have already handled HMC and mux setup.
    187	 * any external transceiver should already be initialized
    188	 * too, so all configured ports use the right signaling now.
    189	 */
    190
    191	return 0;
    192}
    193
    194/*-------------------------------------------------------------------------*/
    195
    196/**
    197 * ohci_hcd_omap_probe - initialize OMAP-based HCDs
    198 * @pdev:	USB controller to probe
    199 *
    200 * Context: task context, might sleep
    201 *
    202 * Allocates basic resources for this USB host controller, and
    203 * then invokes the start() method for the HCD associated with it
    204 * through the hotplug entry's driver_data.
    205 */
    206static int ohci_hcd_omap_probe(struct platform_device *pdev)
    207{
    208	int retval, irq;
    209	struct usb_hcd *hcd = 0;
    210	struct ohci_omap_priv *priv;
    211
    212	if (pdev->num_resources != 2) {
    213		dev_err(&pdev->dev, "invalid num_resources: %i\n",
    214		       pdev->num_resources);
    215		return -ENODEV;
    216	}
    217
    218	if (pdev->resource[0].flags != IORESOURCE_MEM
    219			|| pdev->resource[1].flags != IORESOURCE_IRQ) {
    220		dev_err(&pdev->dev, "invalid resource type\n");
    221		return -ENODEV;
    222	}
    223
    224	hcd = usb_create_hcd(&ohci_omap_hc_driver, &pdev->dev,
    225			dev_name(&pdev->dev));
    226	if (!hcd)
    227		return -ENOMEM;
    228
    229	hcd->rsrc_start = pdev->resource[0].start;
    230	hcd->rsrc_len = pdev->resource[0].end - pdev->resource[0].start + 1;
    231	priv = hcd_to_ohci_omap_priv(hcd);
    232
    233	/* Obtain two optional GPIO lines */
    234	priv->power = devm_gpiod_get_optional(&pdev->dev, "power", GPIOD_ASIS);
    235	if (IS_ERR(priv->power)) {
    236		retval = PTR_ERR(priv->power);
    237		goto err_put_hcd;
    238	}
    239	if (priv->power)
    240		gpiod_set_consumer_name(priv->power, "OHCI power");
    241
    242	/*
    243	 * This "overcurrent" GPIO line isn't really used in the code,
    244	 * but has a designated hardware function.
    245	 * TODO: implement proper overcurrent handling.
    246	 */
    247	priv->overcurrent = devm_gpiod_get_optional(&pdev->dev, "overcurrent",
    248						    GPIOD_IN);
    249	if (IS_ERR(priv->overcurrent)) {
    250		retval = PTR_ERR(priv->overcurrent);
    251		goto err_put_hcd;
    252	}
    253	if (priv->overcurrent)
    254		gpiod_set_consumer_name(priv->overcurrent, "OHCI overcurrent");
    255
    256	priv->usb_host_ck = clk_get(&pdev->dev, "usb_hhc_ck");
    257	if (IS_ERR(priv->usb_host_ck)) {
    258		retval = PTR_ERR(priv->usb_host_ck);
    259		goto err_put_hcd;
    260	}
    261
    262	retval = clk_prepare(priv->usb_host_ck);
    263	if (retval)
    264		goto err_put_host_ck;
    265
    266	if (!cpu_is_omap15xx())
    267		priv->usb_dc_ck = clk_get(&pdev->dev, "usb_dc_ck");
    268	else
    269		priv->usb_dc_ck = clk_get(&pdev->dev, "lb_ck");
    270
    271	if (IS_ERR(priv->usb_dc_ck)) {
    272		retval = PTR_ERR(priv->usb_dc_ck);
    273		goto err_unprepare_host_ck;
    274	}
    275
    276	retval = clk_prepare(priv->usb_dc_ck);
    277	if (retval)
    278		goto err_put_dc_ck;
    279
    280	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
    281		dev_dbg(&pdev->dev, "request_mem_region failed\n");
    282		retval = -EBUSY;
    283		goto err_unprepare_dc_ck;
    284	}
    285
    286	hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
    287	if (!hcd->regs) {
    288		dev_err(&pdev->dev, "can't ioremap OHCI HCD\n");
    289		retval = -ENOMEM;
    290		goto err2;
    291	}
    292
    293	irq = platform_get_irq(pdev, 0);
    294	if (irq < 0) {
    295		retval = irq;
    296		goto err3;
    297	}
    298	retval = usb_add_hcd(hcd, irq, 0);
    299	if (retval)
    300		goto err3;
    301
    302	device_wakeup_enable(hcd->self.controller);
    303	return 0;
    304err3:
    305	iounmap(hcd->regs);
    306err2:
    307	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
    308err_unprepare_dc_ck:
    309	clk_unprepare(priv->usb_dc_ck);
    310err_put_dc_ck:
    311	clk_put(priv->usb_dc_ck);
    312err_unprepare_host_ck:
    313	clk_unprepare(priv->usb_host_ck);
    314err_put_host_ck:
    315	clk_put(priv->usb_host_ck);
    316err_put_hcd:
    317	usb_put_hcd(hcd);
    318	return retval;
    319}
    320
    321
    322/* may be called with controller, bus, and devices active */
    323
    324/**
    325 * ohci_hcd_omap_remove - shutdown processing for OMAP-based HCDs
    326 * @pdev: USB Host Controller being removed
    327 *
    328 * Context: task context, might sleep
    329 *
    330 * Reverses the effect of ohci_hcd_omap_probe(), first invoking
    331 * the HCD's stop() method.  It is always called from a thread
    332 * context, normally "rmmod", "apmd", or something similar.
    333 */
    334static int ohci_hcd_omap_remove(struct platform_device *pdev)
    335{
    336	struct usb_hcd	*hcd = platform_get_drvdata(pdev);
    337	struct ohci_omap_priv *priv = hcd_to_ohci_omap_priv(hcd);
    338
    339	dev_dbg(hcd->self.controller, "stopping USB Controller\n");
    340	usb_remove_hcd(hcd);
    341	omap_ohci_clock_power(priv, 0);
    342	if (!IS_ERR_OR_NULL(hcd->usb_phy)) {
    343		(void) otg_set_host(hcd->usb_phy->otg, 0);
    344		usb_put_phy(hcd->usb_phy);
    345	}
    346	iounmap(hcd->regs);
    347	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
    348	clk_unprepare(priv->usb_dc_ck);
    349	clk_put(priv->usb_dc_ck);
    350	clk_unprepare(priv->usb_host_ck);
    351	clk_put(priv->usb_host_ck);
    352	usb_put_hcd(hcd);
    353	return 0;
    354}
    355
    356/*-------------------------------------------------------------------------*/
    357
    358#ifdef	CONFIG_PM
    359
    360static int ohci_omap_suspend(struct platform_device *pdev, pm_message_t message)
    361{
    362	struct usb_hcd *hcd = platform_get_drvdata(pdev);
    363	struct ohci_hcd *ohci = hcd_to_ohci(hcd);
    364	struct ohci_omap_priv *priv = hcd_to_ohci_omap_priv(hcd);
    365	bool do_wakeup = device_may_wakeup(&pdev->dev);
    366	int ret;
    367
    368	if (time_before(jiffies, ohci->next_statechange))
    369		msleep(5);
    370	ohci->next_statechange = jiffies;
    371
    372	ret = ohci_suspend(hcd, do_wakeup);
    373	if (ret)
    374		return ret;
    375
    376	omap_ohci_clock_power(priv, 0);
    377	return ret;
    378}
    379
    380static int ohci_omap_resume(struct platform_device *dev)
    381{
    382	struct usb_hcd	*hcd = platform_get_drvdata(dev);
    383	struct ohci_hcd	*ohci = hcd_to_ohci(hcd);
    384	struct ohci_omap_priv *priv = hcd_to_ohci_omap_priv(hcd);
    385
    386	if (time_before(jiffies, ohci->next_statechange))
    387		msleep(5);
    388	ohci->next_statechange = jiffies;
    389
    390	omap_ohci_clock_power(priv, 1);
    391	ohci_resume(hcd, false);
    392	return 0;
    393}
    394
    395#endif
    396
    397/*-------------------------------------------------------------------------*/
    398
    399/*
    400 * Driver definition to register with the OMAP bus
    401 */
    402static struct platform_driver ohci_hcd_omap_driver = {
    403	.probe		= ohci_hcd_omap_probe,
    404	.remove		= ohci_hcd_omap_remove,
    405	.shutdown	= usb_hcd_platform_shutdown,
    406#ifdef	CONFIG_PM
    407	.suspend	= ohci_omap_suspend,
    408	.resume		= ohci_omap_resume,
    409#endif
    410	.driver		= {
    411		.name	= "ohci",
    412	},
    413};
    414
    415static const struct ohci_driver_overrides omap_overrides __initconst = {
    416	.product_desc	= "OMAP OHCI",
    417	.reset		= ohci_omap_reset,
    418	.extra_priv_size = sizeof(struct ohci_omap_priv),
    419};
    420
    421static int __init ohci_omap_init(void)
    422{
    423	if (usb_disabled())
    424		return -ENODEV;
    425
    426	pr_info("%s: " DRIVER_DESC "\n", hcd_name);
    427
    428	ohci_init_driver(&ohci_omap_hc_driver, &omap_overrides);
    429	return platform_driver_register(&ohci_hcd_omap_driver);
    430}
    431module_init(ohci_omap_init);
    432
    433static void __exit ohci_omap_cleanup(void)
    434{
    435	platform_driver_unregister(&ohci_hcd_omap_driver);
    436}
    437module_exit(ohci_omap_cleanup);
    438
    439MODULE_DESCRIPTION(DRIVER_DESC);
    440MODULE_ALIAS("platform:ohci");
    441MODULE_LICENSE("GPL");