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-ppc-of.c (5325B)


      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-2002 David Brownell <dbrownell@users.sourceforge.net>
      7 * (C) Copyright 2002 Hewlett-Packard Company
      8 * (C) Copyright 2006 Sylvain Munaut <tnt@246tNt.com>
      9 *
     10 * Bus glue for OHCI HC on the of_platform bus
     11 *
     12 * Modified for of_platform bus from ohci-sa1111.c
     13 *
     14 * This file is licenced under the GPL.
     15 */
     16
     17#include <linux/signal.h>
     18#include <linux/of_address.h>
     19#include <linux/of_irq.h>
     20#include <linux/of_platform.h>
     21
     22static int
     23ohci_ppc_of_start(struct usb_hcd *hcd)
     24{
     25	struct ohci_hcd	*ohci = hcd_to_ohci(hcd);
     26	int		ret;
     27
     28	if ((ret = ohci_init(ohci)) < 0)
     29		return ret;
     30
     31	if ((ret = ohci_run(ohci)) < 0) {
     32		dev_err(hcd->self.controller, "can't start %s\n",
     33			hcd->self.bus_name);
     34		ohci_stop(hcd);
     35		return ret;
     36	}
     37
     38	return 0;
     39}
     40
     41static const struct hc_driver ohci_ppc_of_hc_driver = {
     42	.description =		hcd_name,
     43	.product_desc =		"OF OHCI",
     44	.hcd_priv_size =	sizeof(struct ohci_hcd),
     45
     46	/*
     47	 * generic hardware linkage
     48	 */
     49	.irq =			ohci_irq,
     50	.flags =		HCD_USB11 | HCD_DMA | HCD_MEMORY,
     51
     52	/*
     53	 * basic lifecycle operations
     54	 */
     55	.start =		ohci_ppc_of_start,
     56	.stop =			ohci_stop,
     57	.shutdown = 		ohci_shutdown,
     58
     59	/*
     60	 * managing i/o requests and associated device resources
     61	 */
     62	.urb_enqueue =		ohci_urb_enqueue,
     63	.urb_dequeue =		ohci_urb_dequeue,
     64	.endpoint_disable =	ohci_endpoint_disable,
     65
     66	/*
     67	 * scheduling support
     68	 */
     69	.get_frame_number =	ohci_get_frame,
     70
     71	/*
     72	 * root hub support
     73	 */
     74	.hub_status_data =	ohci_hub_status_data,
     75	.hub_control =		ohci_hub_control,
     76#ifdef	CONFIG_PM
     77	.bus_suspend =		ohci_bus_suspend,
     78	.bus_resume =		ohci_bus_resume,
     79#endif
     80	.start_port_reset =	ohci_start_port_reset,
     81};
     82
     83
     84static int ohci_hcd_ppc_of_probe(struct platform_device *op)
     85{
     86	struct device_node *dn = op->dev.of_node;
     87	struct usb_hcd *hcd;
     88	struct ohci_hcd	*ohci;
     89	struct resource res;
     90	int irq;
     91
     92	int rv;
     93	int is_bigendian;
     94	struct device_node *np;
     95
     96	if (usb_disabled())
     97		return -ENODEV;
     98
     99	is_bigendian =
    100		of_device_is_compatible(dn, "ohci-bigendian") ||
    101		of_device_is_compatible(dn, "ohci-be");
    102
    103	dev_dbg(&op->dev, "initializing PPC-OF USB Controller\n");
    104
    105	rv = of_address_to_resource(dn, 0, &res);
    106	if (rv)
    107		return rv;
    108
    109	hcd = usb_create_hcd(&ohci_ppc_of_hc_driver, &op->dev, "PPC-OF USB");
    110	if (!hcd)
    111		return -ENOMEM;
    112
    113	hcd->rsrc_start = res.start;
    114	hcd->rsrc_len = resource_size(&res);
    115
    116	hcd->regs = devm_ioremap_resource(&op->dev, &res);
    117	if (IS_ERR(hcd->regs)) {
    118		rv = PTR_ERR(hcd->regs);
    119		goto err_rmr;
    120	}
    121
    122	irq = irq_of_parse_and_map(dn, 0);
    123	if (irq == NO_IRQ) {
    124		dev_err(&op->dev, "%s: irq_of_parse_and_map failed\n",
    125			__FILE__);
    126		rv = -EBUSY;
    127		goto err_rmr;
    128	}
    129
    130	ohci = hcd_to_ohci(hcd);
    131	if (is_bigendian) {
    132		ohci->flags |= OHCI_QUIRK_BE_MMIO | OHCI_QUIRK_BE_DESC;
    133		if (of_device_is_compatible(dn, "fsl,mpc5200-ohci"))
    134			ohci->flags |= OHCI_QUIRK_FRAME_NO;
    135		if (of_device_is_compatible(dn, "mpc5200-ohci"))
    136			ohci->flags |= OHCI_QUIRK_FRAME_NO;
    137	}
    138
    139	ohci_hcd_init(ohci);
    140
    141	rv = usb_add_hcd(hcd, irq, 0);
    142	if (rv == 0) {
    143		device_wakeup_enable(hcd->self.controller);
    144		return 0;
    145	}
    146
    147	/* by now, 440epx is known to show usb_23 erratum */
    148	np = of_find_compatible_node(NULL, NULL, "ibm,usb-ehci-440epx");
    149
    150	/* Work around - At this point ohci_run has executed, the
    151	* controller is running, everything, the root ports, etc., is
    152	* set up.  If the ehci driver is loaded, put the ohci core in
    153	* the suspended state.  The ehci driver will bring it out of
    154	* suspended state when / if a non-high speed USB device is
    155	* attached to the USB Host port.  If the ehci driver is not
    156	* loaded, do nothing. request_mem_region is used to test if
    157	* the ehci driver is loaded.
    158	*/
    159	if (np !=  NULL) {
    160		if (!of_address_to_resource(np, 0, &res)) {
    161			if (!request_mem_region(res.start, 0x4, hcd_name)) {
    162				writel_be((readl_be(&ohci->regs->control) |
    163					OHCI_USB_SUSPEND), &ohci->regs->control);
    164					(void) readl_be(&ohci->regs->control);
    165			} else
    166				release_mem_region(res.start, 0x4);
    167		} else
    168			pr_debug("%s: cannot get ehci offset from fdt\n", __FILE__);
    169	}
    170
    171	irq_dispose_mapping(irq);
    172err_rmr:
    173 	usb_put_hcd(hcd);
    174
    175	return rv;
    176}
    177
    178static int ohci_hcd_ppc_of_remove(struct platform_device *op)
    179{
    180	struct usb_hcd *hcd = platform_get_drvdata(op);
    181
    182	dev_dbg(&op->dev, "stopping PPC-OF USB Controller\n");
    183
    184	usb_remove_hcd(hcd);
    185
    186	irq_dispose_mapping(hcd->irq);
    187
    188	usb_put_hcd(hcd);
    189
    190	return 0;
    191}
    192
    193static const struct of_device_id ohci_hcd_ppc_of_match[] = {
    194#ifdef CONFIG_USB_OHCI_HCD_PPC_OF_BE
    195	{
    196		.name = "usb",
    197		.compatible = "ohci-bigendian",
    198	},
    199	{
    200		.name = "usb",
    201		.compatible = "ohci-be",
    202	},
    203#endif
    204#ifdef CONFIG_USB_OHCI_HCD_PPC_OF_LE
    205	{
    206		.name = "usb",
    207		.compatible = "ohci-littledian",
    208	},
    209	{
    210		.name = "usb",
    211		.compatible = "ohci-le",
    212	},
    213#endif
    214	{},
    215};
    216MODULE_DEVICE_TABLE(of, ohci_hcd_ppc_of_match);
    217
    218#if	!defined(CONFIG_USB_OHCI_HCD_PPC_OF_BE) && \
    219	!defined(CONFIG_USB_OHCI_HCD_PPC_OF_LE)
    220#error "No endianness selected for ppc-of-ohci"
    221#endif
    222
    223
    224static struct platform_driver ohci_hcd_ppc_of_driver = {
    225	.probe		= ohci_hcd_ppc_of_probe,
    226	.remove		= ohci_hcd_ppc_of_remove,
    227	.shutdown	= usb_hcd_platform_shutdown,
    228	.driver = {
    229		.name = "ppc-of-ohci",
    230		.of_match_table = ohci_hcd_ppc_of_match,
    231	},
    232};
    233