1*c7fb772bSthorpej /* $NetBSD: exynos_ohci.c,v 1.7 2021/08/07 16:18:45 thorpej Exp $ */
2ae03e518Smarty
3ae03e518Smarty /*-
41095f2f4Sjmcneill * Copyright (c) 2015-2018 Jared McNeill <jmcneill@invisible.ca>
5ae03e518Smarty * All rights reserved.
6ae03e518Smarty *
7ae03e518Smarty * Redistribution and use in source and binary forms, with or without
8ae03e518Smarty * modification, are permitted provided that the following conditions
9ae03e518Smarty * are met:
10ae03e518Smarty * 1. Redistributions of source code must retain the above copyright
11ae03e518Smarty * notice, this list of conditions and the following disclaimer.
12ae03e518Smarty * 2. Redistributions in binary form must reproduce the above copyright
13ae03e518Smarty * notice, this list of conditions and the following disclaimer in the
14ae03e518Smarty * documentation and/or other materials provided with the distribution.
15ae03e518Smarty *
161095f2f4Sjmcneill * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
171095f2f4Sjmcneill * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
181095f2f4Sjmcneill * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
191095f2f4Sjmcneill * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
201095f2f4Sjmcneill * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
211095f2f4Sjmcneill * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
221095f2f4Sjmcneill * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
231095f2f4Sjmcneill * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
241095f2f4Sjmcneill * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
251095f2f4Sjmcneill * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
261095f2f4Sjmcneill * SUCH DAMAGE.
27ae03e518Smarty */
28ae03e518Smarty
29ae03e518Smarty #include <sys/cdefs.h>
30*c7fb772bSthorpej __KERNEL_RCSID(0, "$NetBSD: exynos_ohci.c,v 1.7 2021/08/07 16:18:45 thorpej Exp $");
31ae03e518Smarty
32ae03e518Smarty #include <sys/param.h>
33ae03e518Smarty #include <sys/bus.h>
34ae03e518Smarty #include <sys/device.h>
351095f2f4Sjmcneill #include <sys/intr.h>
361095f2f4Sjmcneill #include <sys/systm.h>
371095f2f4Sjmcneill #include <sys/kernel.h>
38ae03e518Smarty
39ae03e518Smarty #include <dev/usb/usb.h>
40ae03e518Smarty #include <dev/usb/usbdi.h>
41ae03e518Smarty #include <dev/usb/usbdivar.h>
42ae03e518Smarty #include <dev/usb/usb_mem.h>
43ae03e518Smarty #include <dev/usb/ohcireg.h>
44ae03e518Smarty #include <dev/usb/ohcivar.h>
45ae03e518Smarty
46ae03e518Smarty #include <dev/fdt/fdtvar.h>
47ae03e518Smarty
48ae03e518Smarty static int exynos_ohci_match(device_t, cfdata_t, void *);
49ae03e518Smarty static void exynos_ohci_attach(device_t, device_t, void *);
50ae03e518Smarty
511095f2f4Sjmcneill CFATTACH_DECL2_NEW(exynos_ohci, sizeof(struct ohci_softc),
521095f2f4Sjmcneill exynos_ohci_match, exynos_ohci_attach, NULL,
531095f2f4Sjmcneill ohci_activate, NULL, ohci_childdet);
54ae03e518Smarty
556e54367aSthorpej static const struct device_compatible_entry compat_data[] = {
566e54367aSthorpej { .compat = "samsung,exynos4210-ohci" },
576e54367aSthorpej DEVICE_COMPAT_EOL
586e54367aSthorpej };
596e54367aSthorpej
60ae03e518Smarty static int
exynos_ohci_match(device_t parent,cfdata_t cf,void * aux)61ae03e518Smarty exynos_ohci_match(device_t parent, cfdata_t cf, void *aux)
62ae03e518Smarty {
63ae03e518Smarty struct fdt_attach_args * const faa = aux;
641095f2f4Sjmcneill
656e54367aSthorpej return of_compatible_match(faa->faa_phandle, compat_data);
66ae03e518Smarty }
67ae03e518Smarty
68ae03e518Smarty static void
exynos_ohci_attach(device_t parent,device_t self,void * aux)69ae03e518Smarty exynos_ohci_attach(device_t parent, device_t self, void *aux)
70ae03e518Smarty {
711095f2f4Sjmcneill struct ohci_softc * const sc = device_private(self);
72ae03e518Smarty struct fdt_attach_args * const faa = aux;
731095f2f4Sjmcneill const int phandle = faa->faa_phandle;
741095f2f4Sjmcneill struct fdtbus_phy *phy;
751095f2f4Sjmcneill struct clk *clk;
761095f2f4Sjmcneill char intrstr[128];
77ae03e518Smarty bus_addr_t addr;
78ae03e518Smarty bus_size_t size;
791095f2f4Sjmcneill int error, child;
801095f2f4Sjmcneill void *ih;
81ae03e518Smarty
821095f2f4Sjmcneill if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
83ae03e518Smarty aprint_error(": couldn't get registers\n");
84ae03e518Smarty return;
85ae03e518Smarty }
86ae03e518Smarty
871095f2f4Sjmcneill /* Enable clocks */
881095f2f4Sjmcneill clk = fdtbus_clock_get(phandle, "usbhost");
891095f2f4Sjmcneill if (clk == NULL || clk_enable(clk) != 0) {
901095f2f4Sjmcneill aprint_error(": couldn't enable clock\n");
91ae03e518Smarty return;
92ae03e518Smarty }
93ae03e518Smarty
941095f2f4Sjmcneill /* Enable phys for each port */
951095f2f4Sjmcneill for (child = OF_child(phandle); child; child = OF_peer(child)) {
961095f2f4Sjmcneill phy = fdtbus_phy_get_index(child, 0);
971095f2f4Sjmcneill if (phy && fdtbus_phy_enable(phy, true) != 0)
981095f2f4Sjmcneill aprint_error(": couldn't enable phy for %s\n",
991095f2f4Sjmcneill fdtbus_get_string(child, "name"));
1001095f2f4Sjmcneill }
101ae03e518Smarty
1021095f2f4Sjmcneill sc->sc_dev = self;
1031095f2f4Sjmcneill sc->sc_bus.ub_hcpriv = sc;
1041095f2f4Sjmcneill sc->sc_bus.ub_dmatag = faa->faa_dmat;
1051095f2f4Sjmcneill sc->sc_flags = 0;
1061095f2f4Sjmcneill sc->sc_size = size;
1071095f2f4Sjmcneill sc->iot = faa->faa_bst;
1081095f2f4Sjmcneill if (bus_space_map(sc->iot, addr, size, 0, &sc->ioh) != 0) {
1091095f2f4Sjmcneill aprint_error(": couldn't map registers\n");
1101095f2f4Sjmcneill return;
1111095f2f4Sjmcneill }
1121095f2f4Sjmcneill
1131095f2f4Sjmcneill aprint_naive("\n");
1141095f2f4Sjmcneill aprint_normal(": Exynos OHCI\n");
1151095f2f4Sjmcneill
1161095f2f4Sjmcneill /* Disable interrupts */
1171095f2f4Sjmcneill bus_space_write_4(sc->iot, sc->ioh, OHCI_INTERRUPT_DISABLE,
1181095f2f4Sjmcneill OHCI_ALL_INTRS);
1191095f2f4Sjmcneill
1201095f2f4Sjmcneill if (!fdtbus_intr_str(phandle, 0, intrstr, sizeof(intrstr))) {
1211095f2f4Sjmcneill aprint_error_dev(self, "failed to decode interrupt\n");
1221095f2f4Sjmcneill return;
1231095f2f4Sjmcneill }
1241095f2f4Sjmcneill
12534ee086fSskrll ih = fdtbus_intr_establish_xname(phandle, 0, IPL_USB, FDT_INTR_MPSAFE,
12634ee086fSskrll ohci_intr, sc, device_xname(self));
1271095f2f4Sjmcneill if (ih == NULL) {
1281095f2f4Sjmcneill aprint_error_dev(self, "couldn't establish interrupt on %s\n",
1291095f2f4Sjmcneill intrstr);
1301095f2f4Sjmcneill return;
1311095f2f4Sjmcneill }
1321095f2f4Sjmcneill aprint_normal_dev(self, "interrupting on %s\n", intrstr);
1331095f2f4Sjmcneill
1344e8e6643Sskrll error = ohci_init(sc);
1354e8e6643Sskrll if (error) {
1364e8e6643Sskrll aprint_error_dev(self, "init failed, error = %d\n", error);
137ae03e518Smarty return;
138ae03e518Smarty }
1391095f2f4Sjmcneill
140*c7fb772bSthorpej sc->sc_child = config_found(self, &sc->sc_bus, usbctlprint, CFARGS_NONE);
141ae03e518Smarty }
142