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-platform.c (8884B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Generic platform ohci driver
      4 *
      5 * Copyright 2007 Michael Buesch <m@bues.ch>
      6 * Copyright 2011-2012 Hauke Mehrtens <hauke@hauke-m.de>
      7 * Copyright 2014 Hans de Goede <hdegoede@redhat.com>
      8 *
      9 * Derived from the OCHI-SSB driver
     10 * Derived from the OHCI-PCI driver
     11 * Copyright 1999 Roman Weissgaerber
     12 * Copyright 2000-2002 David Brownell
     13 * Copyright 1999 Linus Torvalds
     14 * Copyright 1999 Gregory P. Smith
     15 */
     16
     17#include <linux/clk.h>
     18#include <linux/dma-mapping.h>
     19#include <linux/hrtimer.h>
     20#include <linux/io.h>
     21#include <linux/kernel.h>
     22#include <linux/module.h>
     23#include <linux/err.h>
     24#include <linux/of.h>
     25#include <linux/platform_device.h>
     26#include <linux/pm_runtime.h>
     27#include <linux/reset.h>
     28#include <linux/usb/ohci_pdriver.h>
     29#include <linux/usb.h>
     30#include <linux/usb/hcd.h>
     31
     32#include "ohci.h"
     33
     34#define DRIVER_DESC "OHCI generic platform driver"
     35#define OHCI_MAX_CLKS 3
     36#define hcd_to_ohci_priv(h) ((struct ohci_platform_priv *)hcd_to_ohci(h)->priv)
     37
     38struct ohci_platform_priv {
     39	struct clk *clks[OHCI_MAX_CLKS];
     40	struct reset_control *resets;
     41};
     42
     43static const char hcd_name[] = "ohci-platform";
     44
     45static int ohci_platform_power_on(struct platform_device *dev)
     46{
     47	struct usb_hcd *hcd = platform_get_drvdata(dev);
     48	struct ohci_platform_priv *priv = hcd_to_ohci_priv(hcd);
     49	int clk, ret;
     50
     51	for (clk = 0; clk < OHCI_MAX_CLKS && priv->clks[clk]; clk++) {
     52		ret = clk_prepare_enable(priv->clks[clk]);
     53		if (ret)
     54			goto err_disable_clks;
     55	}
     56
     57	return 0;
     58
     59err_disable_clks:
     60	while (--clk >= 0)
     61		clk_disable_unprepare(priv->clks[clk]);
     62
     63	return ret;
     64}
     65
     66static void ohci_platform_power_off(struct platform_device *dev)
     67{
     68	struct usb_hcd *hcd = platform_get_drvdata(dev);
     69	struct ohci_platform_priv *priv = hcd_to_ohci_priv(hcd);
     70	int clk;
     71
     72	for (clk = OHCI_MAX_CLKS - 1; clk >= 0; clk--)
     73		if (priv->clks[clk])
     74			clk_disable_unprepare(priv->clks[clk]);
     75}
     76
     77static struct hc_driver __read_mostly ohci_platform_hc_driver;
     78
     79static const struct ohci_driver_overrides platform_overrides __initconst = {
     80	.product_desc =		"Generic Platform OHCI controller",
     81	.extra_priv_size =	sizeof(struct ohci_platform_priv),
     82};
     83
     84static struct usb_ohci_pdata ohci_platform_defaults = {
     85	.power_on =		ohci_platform_power_on,
     86	.power_suspend =	ohci_platform_power_off,
     87	.power_off =		ohci_platform_power_off,
     88};
     89
     90static int ohci_platform_probe(struct platform_device *dev)
     91{
     92	struct usb_hcd *hcd;
     93	struct resource *res_mem;
     94	struct usb_ohci_pdata *pdata = dev_get_platdata(&dev->dev);
     95	struct ohci_platform_priv *priv;
     96	struct ohci_hcd *ohci;
     97	int err, irq, clk = 0;
     98
     99	if (usb_disabled())
    100		return -ENODEV;
    101
    102	/*
    103	 * Use reasonable defaults so platforms don't have to provide these
    104	 * with DT probing on ARM.
    105	 */
    106	if (!pdata)
    107		pdata = &ohci_platform_defaults;
    108
    109	err = dma_coerce_mask_and_coherent(&dev->dev, DMA_BIT_MASK(32));
    110	if (err)
    111		return err;
    112
    113	irq = platform_get_irq(dev, 0);
    114	if (irq < 0)
    115		return irq;
    116
    117	hcd = usb_create_hcd(&ohci_platform_hc_driver, &dev->dev,
    118			dev_name(&dev->dev));
    119	if (!hcd)
    120		return -ENOMEM;
    121
    122	platform_set_drvdata(dev, hcd);
    123	dev->dev.platform_data = pdata;
    124	priv = hcd_to_ohci_priv(hcd);
    125	ohci = hcd_to_ohci(hcd);
    126
    127	if (pdata == &ohci_platform_defaults && dev->dev.of_node) {
    128		if (of_property_read_bool(dev->dev.of_node, "big-endian-regs"))
    129			ohci->flags |= OHCI_QUIRK_BE_MMIO;
    130
    131		if (of_property_read_bool(dev->dev.of_node, "big-endian-desc"))
    132			ohci->flags |= OHCI_QUIRK_BE_DESC;
    133
    134		if (of_property_read_bool(dev->dev.of_node, "big-endian"))
    135			ohci->flags |= OHCI_QUIRK_BE_MMIO | OHCI_QUIRK_BE_DESC;
    136
    137		if (of_property_read_bool(dev->dev.of_node, "no-big-frame-no"))
    138			ohci->flags |= OHCI_QUIRK_FRAME_NO;
    139
    140		if (of_property_read_bool(dev->dev.of_node,
    141					  "remote-wakeup-connected"))
    142			ohci->hc_control = OHCI_CTRL_RWC;
    143
    144		of_property_read_u32(dev->dev.of_node, "num-ports",
    145				     &ohci->num_ports);
    146
    147		for (clk = 0; clk < OHCI_MAX_CLKS; clk++) {
    148			priv->clks[clk] = of_clk_get(dev->dev.of_node, clk);
    149			if (IS_ERR(priv->clks[clk])) {
    150				err = PTR_ERR(priv->clks[clk]);
    151				if (err == -EPROBE_DEFER)
    152					goto err_put_clks;
    153				priv->clks[clk] = NULL;
    154				break;
    155			}
    156		}
    157
    158		priv->resets = devm_reset_control_array_get_optional_shared(
    159								&dev->dev);
    160		if (IS_ERR(priv->resets)) {
    161			err = PTR_ERR(priv->resets);
    162			goto err_put_clks;
    163		}
    164
    165		err = reset_control_deassert(priv->resets);
    166		if (err)
    167			goto err_put_clks;
    168	}
    169
    170	if (pdata->big_endian_desc)
    171		ohci->flags |= OHCI_QUIRK_BE_DESC;
    172	if (pdata->big_endian_mmio)
    173		ohci->flags |= OHCI_QUIRK_BE_MMIO;
    174	if (pdata->no_big_frame_no)
    175		ohci->flags |= OHCI_QUIRK_FRAME_NO;
    176	if (pdata->num_ports)
    177		ohci->num_ports = pdata->num_ports;
    178
    179#ifndef CONFIG_USB_OHCI_BIG_ENDIAN_MMIO
    180	if (ohci->flags & OHCI_QUIRK_BE_MMIO) {
    181		dev_err(&dev->dev,
    182			"Error: CONFIG_USB_OHCI_BIG_ENDIAN_MMIO not set\n");
    183		err = -EINVAL;
    184		goto err_reset;
    185	}
    186#endif
    187#ifndef CONFIG_USB_OHCI_BIG_ENDIAN_DESC
    188	if (ohci->flags & OHCI_QUIRK_BE_DESC) {
    189		dev_err(&dev->dev,
    190			"Error: CONFIG_USB_OHCI_BIG_ENDIAN_DESC not set\n");
    191		err = -EINVAL;
    192		goto err_reset;
    193	}
    194#endif
    195
    196	pm_runtime_set_active(&dev->dev);
    197	pm_runtime_enable(&dev->dev);
    198	if (pdata->power_on) {
    199		err = pdata->power_on(dev);
    200		if (err < 0)
    201			goto err_reset;
    202	}
    203
    204	res_mem = platform_get_resource(dev, IORESOURCE_MEM, 0);
    205	hcd->regs = devm_ioremap_resource(&dev->dev, res_mem);
    206	if (IS_ERR(hcd->regs)) {
    207		err = PTR_ERR(hcd->regs);
    208		goto err_power;
    209	}
    210	hcd->rsrc_start = res_mem->start;
    211	hcd->rsrc_len = resource_size(res_mem);
    212
    213	err = usb_add_hcd(hcd, irq, IRQF_SHARED);
    214	if (err)
    215		goto err_power;
    216
    217	device_wakeup_enable(hcd->self.controller);
    218
    219	platform_set_drvdata(dev, hcd);
    220
    221	return err;
    222
    223err_power:
    224	if (pdata->power_off)
    225		pdata->power_off(dev);
    226err_reset:
    227	pm_runtime_disable(&dev->dev);
    228	reset_control_assert(priv->resets);
    229err_put_clks:
    230	while (--clk >= 0)
    231		clk_put(priv->clks[clk]);
    232
    233	if (pdata == &ohci_platform_defaults)
    234		dev->dev.platform_data = NULL;
    235
    236	usb_put_hcd(hcd);
    237
    238	return err;
    239}
    240
    241static int ohci_platform_remove(struct platform_device *dev)
    242{
    243	struct usb_hcd *hcd = platform_get_drvdata(dev);
    244	struct usb_ohci_pdata *pdata = dev_get_platdata(&dev->dev);
    245	struct ohci_platform_priv *priv = hcd_to_ohci_priv(hcd);
    246	int clk;
    247
    248	pm_runtime_get_sync(&dev->dev);
    249	usb_remove_hcd(hcd);
    250
    251	if (pdata->power_off)
    252		pdata->power_off(dev);
    253
    254	reset_control_assert(priv->resets);
    255
    256	for (clk = 0; clk < OHCI_MAX_CLKS && priv->clks[clk]; clk++)
    257		clk_put(priv->clks[clk]);
    258
    259	usb_put_hcd(hcd);
    260
    261	pm_runtime_put_sync(&dev->dev);
    262	pm_runtime_disable(&dev->dev);
    263
    264	if (pdata == &ohci_platform_defaults)
    265		dev->dev.platform_data = NULL;
    266
    267	return 0;
    268}
    269
    270#ifdef CONFIG_PM_SLEEP
    271static int ohci_platform_suspend(struct device *dev)
    272{
    273	struct usb_hcd *hcd = dev_get_drvdata(dev);
    274	struct usb_ohci_pdata *pdata = dev->platform_data;
    275	struct platform_device *pdev = to_platform_device(dev);
    276	bool do_wakeup = device_may_wakeup(dev);
    277	int ret;
    278
    279	ret = ohci_suspend(hcd, do_wakeup);
    280	if (ret)
    281		return ret;
    282
    283	if (pdata->power_suspend)
    284		pdata->power_suspend(pdev);
    285
    286	return ret;
    287}
    288
    289static int ohci_platform_resume(struct device *dev)
    290{
    291	struct usb_hcd *hcd = dev_get_drvdata(dev);
    292	struct usb_ohci_pdata *pdata = dev_get_platdata(dev);
    293	struct platform_device *pdev = to_platform_device(dev);
    294
    295	if (pdata->power_on) {
    296		int err = pdata->power_on(pdev);
    297		if (err < 0)
    298			return err;
    299	}
    300
    301	ohci_resume(hcd, false);
    302
    303	pm_runtime_disable(dev);
    304	pm_runtime_set_active(dev);
    305	pm_runtime_enable(dev);
    306
    307	return 0;
    308}
    309#endif /* CONFIG_PM_SLEEP */
    310
    311static const struct of_device_id ohci_platform_ids[] = {
    312	{ .compatible = "generic-ohci", },
    313	{ .compatible = "cavium,octeon-6335-ohci", },
    314	{ .compatible = "ti,ohci-omap3", },
    315	{ }
    316};
    317MODULE_DEVICE_TABLE(of, ohci_platform_ids);
    318
    319static const struct platform_device_id ohci_platform_table[] = {
    320	{ "ohci-platform", 0 },
    321	{ }
    322};
    323MODULE_DEVICE_TABLE(platform, ohci_platform_table);
    324
    325static SIMPLE_DEV_PM_OPS(ohci_platform_pm_ops, ohci_platform_suspend,
    326	ohci_platform_resume);
    327
    328static struct platform_driver ohci_platform_driver = {
    329	.id_table	= ohci_platform_table,
    330	.probe		= ohci_platform_probe,
    331	.remove		= ohci_platform_remove,
    332	.shutdown	= usb_hcd_platform_shutdown,
    333	.driver		= {
    334		.name	= "ohci-platform",
    335		.pm	= &ohci_platform_pm_ops,
    336		.of_match_table = ohci_platform_ids,
    337		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
    338	}
    339};
    340
    341static int __init ohci_platform_init(void)
    342{
    343	if (usb_disabled())
    344		return -ENODEV;
    345
    346	pr_info("%s: " DRIVER_DESC "\n", hcd_name);
    347
    348	ohci_init_driver(&ohci_platform_hc_driver, &platform_overrides);
    349	return platform_driver_register(&ohci_platform_driver);
    350}
    351module_init(ohci_platform_init);
    352
    353static void __exit ohci_platform_cleanup(void)
    354{
    355	platform_driver_unregister(&ohci_platform_driver);
    356}
    357module_exit(ohci_platform_cleanup);
    358
    359MODULE_DESCRIPTION(DRIVER_DESC);
    360MODULE_AUTHOR("Hauke Mehrtens");
    361MODULE_AUTHOR("Alan Stern");
    362MODULE_LICENSE("GPL");