1518da7acSAndrew Turner /*-
24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
3518da7acSAndrew Turner *
4518da7acSAndrew Turner * Copyright (c) 2012 Hans Petter Selasky.
5518da7acSAndrew Turner *
6518da7acSAndrew Turner * Redistribution and use in source and binary forms, with or without
7518da7acSAndrew Turner * modification, are permitted provided that the following conditions
8518da7acSAndrew Turner * are met:
9518da7acSAndrew Turner * 1. Redistributions of source code must retain the above copyright
10518da7acSAndrew Turner * notice, this list of conditions and the following disclaimer.
11518da7acSAndrew Turner * 2. Redistributions in binary form must reproduce the above copyright
12518da7acSAndrew Turner * notice, this list of conditions and the following disclaimer in the
13518da7acSAndrew Turner * documentation and/or other materials provided with the distribution.
14518da7acSAndrew Turner *
15518da7acSAndrew Turner * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16518da7acSAndrew Turner * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17518da7acSAndrew Turner * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18518da7acSAndrew Turner * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19518da7acSAndrew Turner * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20518da7acSAndrew Turner * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21518da7acSAndrew Turner * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22518da7acSAndrew Turner * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23518da7acSAndrew Turner * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24518da7acSAndrew Turner * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25518da7acSAndrew Turner * SUCH DAMAGE.
26518da7acSAndrew Turner */
27518da7acSAndrew Turner
28518da7acSAndrew Turner #include "opt_acpi.h"
29518da7acSAndrew Turner
30518da7acSAndrew Turner #include <sys/param.h>
31518da7acSAndrew Turner #include <sys/systm.h>
32518da7acSAndrew Turner #include <sys/bus.h>
33518da7acSAndrew Turner #include <sys/condvar.h>
34518da7acSAndrew Turner #include <sys/kernel.h>
35518da7acSAndrew Turner #include <sys/lock.h>
36518da7acSAndrew Turner #include <sys/malloc.h>
37518da7acSAndrew Turner #include <sys/module.h>
38518da7acSAndrew Turner #include <sys/mutex.h>
39518da7acSAndrew Turner #include <sys/rman.h>
40518da7acSAndrew Turner
41518da7acSAndrew Turner #include <contrib/dev/acpica/include/acpi.h>
42518da7acSAndrew Turner #include <contrib/dev/acpica/include/accommon.h>
43518da7acSAndrew Turner
44518da7acSAndrew Turner #include <dev/acpica/acpivar.h>
45518da7acSAndrew Turner
46518da7acSAndrew Turner #include <dev/usb/usb.h>
47518da7acSAndrew Turner #include <dev/usb/usbdi.h>
48518da7acSAndrew Turner
49518da7acSAndrew Turner #include <dev/usb/usb_core.h>
50518da7acSAndrew Turner #include <dev/usb/usb_busdma.h>
51518da7acSAndrew Turner #include <dev/usb/usb_process.h>
52518da7acSAndrew Turner #include <dev/usb/usb_util.h>
53518da7acSAndrew Turner
54518da7acSAndrew Turner #include <dev/usb/usb_controller.h>
55518da7acSAndrew Turner #include <dev/usb/usb_bus.h>
56518da7acSAndrew Turner
57518da7acSAndrew Turner #include <dev/usb/controller/dwc_otg.h>
58518da7acSAndrew Turner
59518da7acSAndrew Turner static device_probe_t dwc_otg_probe;
60518da7acSAndrew Turner static device_attach_t dwc_otg_attach;
61518da7acSAndrew Turner static device_attach_t dwc_otg_detach;
62518da7acSAndrew Turner
63518da7acSAndrew Turner static char *dwc_otg_ids[] = {
64518da7acSAndrew Turner "BCM2848",
65518da7acSAndrew Turner NULL
66518da7acSAndrew Turner };
67518da7acSAndrew Turner
68518da7acSAndrew Turner static int
dwc_otg_probe(device_t dev)69518da7acSAndrew Turner dwc_otg_probe(device_t dev)
70518da7acSAndrew Turner {
71518da7acSAndrew Turner int rv;
72518da7acSAndrew Turner
73518da7acSAndrew Turner if (acpi_disabled("dwc_otg"))
74518da7acSAndrew Turner return (ENXIO);
75518da7acSAndrew Turner
76518da7acSAndrew Turner rv = ACPI_ID_PROBE(device_get_parent(dev), dev, dwc_otg_ids, NULL);
77518da7acSAndrew Turner if (rv > 0)
78518da7acSAndrew Turner return (rv);
79518da7acSAndrew Turner
80518da7acSAndrew Turner device_set_desc(dev, "DWC OTG 2.0 integrated USB controller");
81518da7acSAndrew Turner
82518da7acSAndrew Turner return (BUS_PROBE_DEFAULT);
83518da7acSAndrew Turner }
84518da7acSAndrew Turner
85518da7acSAndrew Turner static int
dwc_otg_attach(device_t dev)86518da7acSAndrew Turner dwc_otg_attach(device_t dev)
87518da7acSAndrew Turner {
88518da7acSAndrew Turner struct dwc_otg_softc *sc = device_get_softc(dev);
89518da7acSAndrew Turner int err;
90518da7acSAndrew Turner int rid;
91518da7acSAndrew Turner
92518da7acSAndrew Turner sc->sc_bus.parent = dev;
93518da7acSAndrew Turner
94518da7acSAndrew Turner /* assume device mode (this is only used for the Raspberry Pi 4's
95518da7acSAndrew Turner * USB-C port, which only works in device mode) */
96518da7acSAndrew Turner sc->sc_mode = DWC_MODE_DEVICE;
97518da7acSAndrew Turner
98518da7acSAndrew Turner rid = 0;
99518da7acSAndrew Turner sc->sc_io_res =
100518da7acSAndrew Turner bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
101518da7acSAndrew Turner
102518da7acSAndrew Turner if (sc->sc_io_res == NULL)
103518da7acSAndrew Turner goto error;
104518da7acSAndrew Turner
105518da7acSAndrew Turner rid = 0;
106518da7acSAndrew Turner sc->sc_irq_res =
107518da7acSAndrew Turner bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE);
108518da7acSAndrew Turner if (sc->sc_irq_res == NULL)
109518da7acSAndrew Turner goto error;
110518da7acSAndrew Turner
111518da7acSAndrew Turner err = dwc_otg_init(sc);
112518da7acSAndrew Turner if (err == 0) {
113518da7acSAndrew Turner err = device_probe_and_attach(sc->sc_bus.bdev);
114518da7acSAndrew Turner }
115518da7acSAndrew Turner if (err)
116518da7acSAndrew Turner goto error;
117518da7acSAndrew Turner
118518da7acSAndrew Turner return (0);
119518da7acSAndrew Turner
120518da7acSAndrew Turner error:
121518da7acSAndrew Turner dwc_otg_detach(dev);
122518da7acSAndrew Turner return (ENXIO);
123518da7acSAndrew Turner }
124518da7acSAndrew Turner
125518da7acSAndrew Turner static int
dwc_otg_detach(device_t dev)126518da7acSAndrew Turner dwc_otg_detach(device_t dev)
127518da7acSAndrew Turner {
128518da7acSAndrew Turner struct dwc_otg_softc *sc = device_get_softc(dev);
129*3ddaf820SJohn Baldwin int error;
130518da7acSAndrew Turner
131518da7acSAndrew Turner /* during module unload there are lots of children leftover */
132*3ddaf820SJohn Baldwin error = bus_generic_detach(dev);
133*3ddaf820SJohn Baldwin if (error != 0)
134*3ddaf820SJohn Baldwin return (error);
135518da7acSAndrew Turner
136518da7acSAndrew Turner if (sc->sc_irq_res && sc->sc_intr_hdl) {
137518da7acSAndrew Turner /*
138518da7acSAndrew Turner * only call dwc_otg_uninit() after dwc_otg_init()
139518da7acSAndrew Turner */
140518da7acSAndrew Turner dwc_otg_uninit(sc);
141518da7acSAndrew Turner
142518da7acSAndrew Turner bus_teardown_intr(dev, sc->sc_irq_res,
143518da7acSAndrew Turner sc->sc_intr_hdl);
144518da7acSAndrew Turner sc->sc_intr_hdl = NULL;
145518da7acSAndrew Turner }
146518da7acSAndrew Turner /* free IRQ channel, if any */
147518da7acSAndrew Turner if (sc->sc_irq_res) {
148518da7acSAndrew Turner bus_release_resource(dev, SYS_RES_IRQ, 0,
149518da7acSAndrew Turner sc->sc_irq_res);
150518da7acSAndrew Turner sc->sc_irq_res = NULL;
151518da7acSAndrew Turner }
152518da7acSAndrew Turner /* free memory resource, if any */
153518da7acSAndrew Turner if (sc->sc_io_res) {
154518da7acSAndrew Turner bus_release_resource(dev, SYS_RES_MEMORY, 0,
155518da7acSAndrew Turner sc->sc_io_res);
156518da7acSAndrew Turner sc->sc_io_res = NULL;
157518da7acSAndrew Turner }
158518da7acSAndrew Turner usb_bus_mem_free_all(&sc->sc_bus, NULL);
159518da7acSAndrew Turner
160518da7acSAndrew Turner return (0);
161518da7acSAndrew Turner }
162518da7acSAndrew Turner
163518da7acSAndrew Turner static device_method_t dwc_otg_methods[] = {
164518da7acSAndrew Turner /* Device interface */
165518da7acSAndrew Turner DEVMETHOD(device_probe, dwc_otg_probe),
166518da7acSAndrew Turner DEVMETHOD(device_attach, dwc_otg_attach),
167518da7acSAndrew Turner DEVMETHOD(device_detach, dwc_otg_detach),
168518da7acSAndrew Turner DEVMETHOD(device_suspend, bus_generic_suspend),
169518da7acSAndrew Turner DEVMETHOD(device_resume, bus_generic_resume),
170518da7acSAndrew Turner DEVMETHOD(device_shutdown, bus_generic_shutdown),
171518da7acSAndrew Turner
172518da7acSAndrew Turner DEVMETHOD_END
173518da7acSAndrew Turner };
174518da7acSAndrew Turner
175518da7acSAndrew Turner static driver_t dwc_otg_driver = {
176518da7acSAndrew Turner .name = "dwcotg",
177518da7acSAndrew Turner .methods = dwc_otg_methods,
178518da7acSAndrew Turner .size = sizeof(struct dwc_otg_softc),
179518da7acSAndrew Turner };
180518da7acSAndrew Turner
181bc9372d7SJohn Baldwin DRIVER_MODULE(dwcotg, acpi, dwc_otg_driver, 0, 0);
182518da7acSAndrew Turner MODULE_DEPEND(dwcotg, usb, 1, 1, 1);
183