xref: /openbmc/linux/drivers/usb/host/ohci-ppc-of.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
15fd54aceSGreg Kroah-Hartman // SPDX-License-Identifier: GPL-1.0+
2495a678fSSylvain Munaut /*
3495a678fSSylvain Munaut  * OHCI HCD (Host Controller Driver) for USB.
4495a678fSSylvain Munaut  *
5495a678fSSylvain Munaut  * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
6495a678fSSylvain Munaut  * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
7495a678fSSylvain Munaut  * (C) Copyright 2002 Hewlett-Packard Company
8495a678fSSylvain Munaut  * (C) Copyright 2006 Sylvain Munaut <tnt@246tNt.com>
9495a678fSSylvain Munaut  *
10495a678fSSylvain Munaut  * Bus glue for OHCI HC on the of_platform bus
11495a678fSSylvain Munaut  *
12495a678fSSylvain Munaut  * Modified for of_platform bus from ohci-sa1111.c
13495a678fSSylvain Munaut  *
14495a678fSSylvain Munaut  * This file is licenced under the GPL.
15495a678fSSylvain Munaut  */
16495a678fSSylvain Munaut 
17495a678fSSylvain Munaut #include <linux/signal.h>
18*484468fbSRob Herring #include <linux/of.h>
195af50730SRob Herring #include <linux/of_address.h>
205af50730SRob Herring #include <linux/of_irq.h>
21*484468fbSRob Herring #include <linux/platform_device.h>
22495a678fSSylvain Munaut 
2341ac7b3aSBill Pemberton static int
ohci_ppc_of_start(struct usb_hcd * hcd)24495a678fSSylvain Munaut ohci_ppc_of_start(struct usb_hcd *hcd)
25495a678fSSylvain Munaut {
26495a678fSSylvain Munaut 	struct ohci_hcd	*ohci = hcd_to_ohci(hcd);
27495a678fSSylvain Munaut 	int		ret;
28495a678fSSylvain Munaut 
29495a678fSSylvain Munaut 	if ((ret = ohci_init(ohci)) < 0)
30495a678fSSylvain Munaut 		return ret;
31495a678fSSylvain Munaut 
32495a678fSSylvain Munaut 	if ((ret = ohci_run(ohci)) < 0) {
331d55b768SGreg Kroah-Hartman 		dev_err(hcd->self.controller, "can't start %s\n",
341d55b768SGreg Kroah-Hartman 			hcd->self.bus_name);
35495a678fSSylvain Munaut 		ohci_stop(hcd);
36495a678fSSylvain Munaut 		return ret;
37495a678fSSylvain Munaut 	}
38495a678fSSylvain Munaut 
39495a678fSSylvain Munaut 	return 0;
40495a678fSSylvain Munaut }
41495a678fSSylvain Munaut 
42495a678fSSylvain Munaut static const struct hc_driver ohci_ppc_of_hc_driver = {
43495a678fSSylvain Munaut 	.description =		hcd_name,
44495a678fSSylvain Munaut 	.product_desc =		"OF OHCI",
45495a678fSSylvain Munaut 	.hcd_priv_size =	sizeof(struct ohci_hcd),
46495a678fSSylvain Munaut 
47495a678fSSylvain Munaut 	/*
48495a678fSSylvain Munaut 	 * generic hardware linkage
49495a678fSSylvain Munaut 	 */
50495a678fSSylvain Munaut 	.irq =			ohci_irq,
517b81cb6bSChristoph Hellwig 	.flags =		HCD_USB11 | HCD_DMA | HCD_MEMORY,
52495a678fSSylvain Munaut 
53495a678fSSylvain Munaut 	/*
54495a678fSSylvain Munaut 	 * basic lifecycle operations
55495a678fSSylvain Munaut 	 */
56495a678fSSylvain Munaut 	.start =		ohci_ppc_of_start,
57495a678fSSylvain Munaut 	.stop =			ohci_stop,
58495a678fSSylvain Munaut 	.shutdown = 		ohci_shutdown,
59495a678fSSylvain Munaut 
60495a678fSSylvain Munaut 	/*
61495a678fSSylvain Munaut 	 * managing i/o requests and associated device resources
62495a678fSSylvain Munaut 	 */
63495a678fSSylvain Munaut 	.urb_enqueue =		ohci_urb_enqueue,
64495a678fSSylvain Munaut 	.urb_dequeue =		ohci_urb_dequeue,
65495a678fSSylvain Munaut 	.endpoint_disable =	ohci_endpoint_disable,
66495a678fSSylvain Munaut 
67495a678fSSylvain Munaut 	/*
68495a678fSSylvain Munaut 	 * scheduling support
69495a678fSSylvain Munaut 	 */
70495a678fSSylvain Munaut 	.get_frame_number =	ohci_get_frame,
71495a678fSSylvain Munaut 
72495a678fSSylvain Munaut 	/*
73495a678fSSylvain Munaut 	 * root hub support
74495a678fSSylvain Munaut 	 */
75495a678fSSylvain Munaut 	.hub_status_data =	ohci_hub_status_data,
76495a678fSSylvain Munaut 	.hub_control =		ohci_hub_control,
77495a678fSSylvain Munaut #ifdef	CONFIG_PM
78495a678fSSylvain Munaut 	.bus_suspend =		ohci_bus_suspend,
79495a678fSSylvain Munaut 	.bus_resume =		ohci_bus_resume,
80495a678fSSylvain Munaut #endif
81495a678fSSylvain Munaut 	.start_port_reset =	ohci_start_port_reset,
82495a678fSSylvain Munaut };
83495a678fSSylvain Munaut 
84495a678fSSylvain Munaut 
ohci_hcd_ppc_of_probe(struct platform_device * op)8541ac7b3aSBill Pemberton static int ohci_hcd_ppc_of_probe(struct platform_device *op)
86495a678fSSylvain Munaut {
8761c7a080SGrant Likely 	struct device_node *dn = op->dev.of_node;
88495a678fSSylvain Munaut 	struct usb_hcd *hcd;
89495a678fSSylvain Munaut 	struct ohci_hcd	*ohci;
90495a678fSSylvain Munaut 	struct resource res;
91495a678fSSylvain Munaut 	int irq;
92495a678fSSylvain Munaut 
93495a678fSSylvain Munaut 	int rv;
94495a678fSSylvain Munaut 	int is_bigendian;
95796bcae7SVitaly Bordug 	struct device_node *np;
96495a678fSSylvain Munaut 
97495a678fSSylvain Munaut 	if (usb_disabled())
98495a678fSSylvain Munaut 		return -ENODEV;
99495a678fSSylvain Munaut 
100495a678fSSylvain Munaut 	is_bigendian =
10155b61fecSStephen Rothwell 		of_device_is_compatible(dn, "ohci-bigendian") ||
10255b61fecSStephen Rothwell 		of_device_is_compatible(dn, "ohci-be");
103495a678fSSylvain Munaut 
104495a678fSSylvain Munaut 	dev_dbg(&op->dev, "initializing PPC-OF USB Controller\n");
105495a678fSSylvain Munaut 
106495a678fSSylvain Munaut 	rv = of_address_to_resource(dn, 0, &res);
107495a678fSSylvain Munaut 	if (rv)
108495a678fSSylvain Munaut 		return rv;
109495a678fSSylvain Munaut 
110495a678fSSylvain Munaut 	hcd = usb_create_hcd(&ohci_ppc_of_hc_driver, &op->dev, "PPC-OF USB");
111495a678fSSylvain Munaut 	if (!hcd)
112495a678fSSylvain Munaut 		return -ENOMEM;
113495a678fSSylvain Munaut 
114495a678fSSylvain Munaut 	hcd->rsrc_start = res.start;
11528f65c11SJoe Perches 	hcd->rsrc_len = resource_size(&res);
116495a678fSSylvain Munaut 
1173e2e714eSJingoo Han 	hcd->regs = devm_ioremap_resource(&op->dev, &res);
1183e2e714eSJingoo Han 	if (IS_ERR(hcd->regs)) {
1193e2e714eSJingoo Han 		rv = PTR_ERR(hcd->regs);
120495a678fSSylvain Munaut 		goto err_rmr;
121495a678fSSylvain Munaut 	}
122495a678fSSylvain Munaut 
123495a678fSSylvain Munaut 	irq = irq_of_parse_and_map(dn, 0);
1248836402dSChristophe Leroy 	if (!irq) {
12563c9b9d3SJingoo Han 		dev_err(&op->dev, "%s: irq_of_parse_and_map failed\n",
12663c9b9d3SJingoo Han 			__FILE__);
127495a678fSSylvain Munaut 		rv = -EBUSY;
1283e2e714eSJingoo Han 		goto err_rmr;
129495a678fSSylvain Munaut 	}
130495a678fSSylvain Munaut 
131495a678fSSylvain Munaut 	ohci = hcd_to_ohci(hcd);
1324f45426cSValentine Barshak 	if (is_bigendian) {
133495a678fSSylvain Munaut 		ohci->flags |= OHCI_QUIRK_BE_MMIO | OHCI_QUIRK_BE_DESC;
13466ffbe49SGrant Likely 		if (of_device_is_compatible(dn, "fsl,mpc5200-ohci"))
13566ffbe49SGrant Likely 			ohci->flags |= OHCI_QUIRK_FRAME_NO;
1364f45426cSValentine Barshak 		if (of_device_is_compatible(dn, "mpc5200-ohci"))
1374f45426cSValentine Barshak 			ohci->flags |= OHCI_QUIRK_FRAME_NO;
1384f45426cSValentine Barshak 	}
139495a678fSSylvain Munaut 
140495a678fSSylvain Munaut 	ohci_hcd_init(ohci);
141495a678fSSylvain Munaut 
142b5dd18d8SYong Zhang 	rv = usb_add_hcd(hcd, irq, 0);
1433c9740a1SPeter Chen 	if (rv == 0) {
1443c9740a1SPeter Chen 		device_wakeup_enable(hcd->self.controller);
145495a678fSSylvain Munaut 		return 0;
1463c9740a1SPeter Chen 	}
147495a678fSSylvain Munaut 
148796bcae7SVitaly Bordug 	/* by now, 440epx is known to show usb_23 erratum */
149796bcae7SVitaly Bordug 	np = of_find_compatible_node(NULL, NULL, "ibm,usb-ehci-440epx");
150796bcae7SVitaly Bordug 
151796bcae7SVitaly Bordug 	/* Work around - At this point ohci_run has executed, the
152796bcae7SVitaly Bordug 	* controller is running, everything, the root ports, etc., is
153796bcae7SVitaly Bordug 	* set up.  If the ehci driver is loaded, put the ohci core in
154796bcae7SVitaly Bordug 	* the suspended state.  The ehci driver will bring it out of
155796bcae7SVitaly Bordug 	* suspended state when / if a non-high speed USB device is
156796bcae7SVitaly Bordug 	* attached to the USB Host port.  If the ehci driver is not
157796bcae7SVitaly Bordug 	* loaded, do nothing. request_mem_region is used to test if
158796bcae7SVitaly Bordug 	* the ehci driver is loaded.
159796bcae7SVitaly Bordug 	*/
160796bcae7SVitaly Bordug 	if (np !=  NULL) {
161796bcae7SVitaly Bordug 		if (!of_address_to_resource(np, 0, &res)) {
162796bcae7SVitaly Bordug 			if (!request_mem_region(res.start, 0x4, hcd_name)) {
163796bcae7SVitaly Bordug 				writel_be((readl_be(&ohci->regs->control) |
164796bcae7SVitaly Bordug 					OHCI_USB_SUSPEND), &ohci->regs->control);
165796bcae7SVitaly Bordug 					(void) readl_be(&ohci->regs->control);
166796bcae7SVitaly Bordug 			} else
167796bcae7SVitaly Bordug 				release_mem_region(res.start, 0x4);
168796bcae7SVitaly Bordug 		} else
169f45ba776SJoe Perches 			pr_debug("%s: cannot get ehci offset from fdt\n", __FILE__);
17040a959d7SLiang He 		of_node_put(np);
171796bcae7SVitaly Bordug 	}
172796bcae7SVitaly Bordug 
173495a678fSSylvain Munaut 	irq_dispose_mapping(irq);
174495a678fSSylvain Munaut err_rmr:
175495a678fSSylvain Munaut  	usb_put_hcd(hcd);
176495a678fSSylvain Munaut 
177495a678fSSylvain Munaut 	return rv;
178495a678fSSylvain Munaut }
179495a678fSSylvain Munaut 
ohci_hcd_ppc_of_remove(struct platform_device * op)1807b0b8100SUwe Kleine-König static void ohci_hcd_ppc_of_remove(struct platform_device *op)
181495a678fSSylvain Munaut {
182477527baSJingoo Han 	struct usb_hcd *hcd = platform_get_drvdata(op);
183495a678fSSylvain Munaut 
184495a678fSSylvain Munaut 	dev_dbg(&op->dev, "stopping PPC-OF USB Controller\n");
185495a678fSSylvain Munaut 
186495a678fSSylvain Munaut 	usb_remove_hcd(hcd);
187495a678fSSylvain Munaut 
188495a678fSSylvain Munaut 	irq_dispose_mapping(hcd->irq);
189495a678fSSylvain Munaut 
190495a678fSSylvain Munaut 	usb_put_hcd(hcd);
191495a678fSSylvain Munaut }
192495a678fSSylvain Munaut 
193c4386ad0SNémeth Márton static const struct of_device_id ohci_hcd_ppc_of_match[] = {
194495a678fSSylvain Munaut #ifdef CONFIG_USB_OHCI_HCD_PPC_OF_BE
195495a678fSSylvain Munaut 	{
196495a678fSSylvain Munaut 		.name = "usb",
197495a678fSSylvain Munaut 		.compatible = "ohci-bigendian",
198495a678fSSylvain Munaut 	},
199495a678fSSylvain Munaut 	{
200495a678fSSylvain Munaut 		.name = "usb",
201495a678fSSylvain Munaut 		.compatible = "ohci-be",
202495a678fSSylvain Munaut 	},
203495a678fSSylvain Munaut #endif
204495a678fSSylvain Munaut #ifdef CONFIG_USB_OHCI_HCD_PPC_OF_LE
205495a678fSSylvain Munaut 	{
206495a678fSSylvain Munaut 		.name = "usb",
207495a678fSSylvain Munaut 		.compatible = "ohci-littledian",
208495a678fSSylvain Munaut 	},
209495a678fSSylvain Munaut 	{
210495a678fSSylvain Munaut 		.name = "usb",
211495a678fSSylvain Munaut 		.compatible = "ohci-le",
212495a678fSSylvain Munaut 	},
213495a678fSSylvain Munaut #endif
214495a678fSSylvain Munaut 	{},
215495a678fSSylvain Munaut };
216495a678fSSylvain Munaut MODULE_DEVICE_TABLE(of, ohci_hcd_ppc_of_match);
217495a678fSSylvain Munaut 
218495a678fSSylvain Munaut #if	!defined(CONFIG_USB_OHCI_HCD_PPC_OF_BE) && \
219495a678fSSylvain Munaut 	!defined(CONFIG_USB_OHCI_HCD_PPC_OF_LE)
2201c1301ddSMasanari Iida #error "No endianness selected for ppc-of-ohci"
221495a678fSSylvain Munaut #endif
222495a678fSSylvain Munaut 
223495a678fSSylvain Munaut 
224d35fb641SGrant Likely static struct platform_driver ohci_hcd_ppc_of_driver = {
225495a678fSSylvain Munaut 	.probe		= ohci_hcd_ppc_of_probe,
2267b0b8100SUwe Kleine-König 	.remove_new	= ohci_hcd_ppc_of_remove,
227aaf6b52dSRoger Quadros 	.shutdown	= usb_hcd_platform_shutdown,
228495a678fSSylvain Munaut 	.driver = {
229495a678fSSylvain Munaut 		.name = "ppc-of-ohci",
2304018294bSGrant Likely 		.of_match_table = ohci_hcd_ppc_of_match,
231495a678fSSylvain Munaut 	},
232495a678fSSylvain Munaut };
233495a678fSSylvain Munaut 
234