1*c7fb772bSthorpej /* $NetBSD: ralink_ehci.c,v 1.9 2021/08/07 16:18:59 thorpej Exp $ */
20062f2f2Smatt /*-
30062f2f2Smatt * Copyright (c) 2011 CradlePoint Technology, Inc.
40062f2f2Smatt * All rights reserved.
50062f2f2Smatt *
60062f2f2Smatt *
70062f2f2Smatt * Redistribution and use in source and binary forms, with or without
80062f2f2Smatt * modification, are permitted provided that the following conditions
90062f2f2Smatt * are met:
100062f2f2Smatt * 1. Redistributions of source code must retain the above copyright
110062f2f2Smatt * notice, this list of conditions and the following disclaimer.
120062f2f2Smatt * 2. Redistributions in binary form must reproduce the above copyright
130062f2f2Smatt * notice, this list of conditions and the following disclaimer in the
140062f2f2Smatt * documentation and/or other materials provided with the distribution.
150062f2f2Smatt *
160062f2f2Smatt * THIS SOFTWARE IS PROVIDED BY CRADLEPOINT TECHNOLOGY, INC. AND CONTRIBUTORS
170062f2f2Smatt * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
180062f2f2Smatt * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
190062f2f2Smatt * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
200062f2f2Smatt * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
210062f2f2Smatt * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
220062f2f2Smatt * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
230062f2f2Smatt * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
240062f2f2Smatt * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
250062f2f2Smatt * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
260062f2f2Smatt * POSSIBILITY OF SUCH DAMAGE.
270062f2f2Smatt */
280062f2f2Smatt
290062f2f2Smatt /* ralink_ehci.c -- Ralink EHCI USB Driver */
300062f2f2Smatt
310062f2f2Smatt #include <sys/cdefs.h>
32*c7fb772bSthorpej __KERNEL_RCSID(0, "$NetBSD: ralink_ehci.c,v 1.9 2021/08/07 16:18:59 thorpej Exp $");
330062f2f2Smatt
340062f2f2Smatt #include <sys/param.h>
350062f2f2Smatt #include <sys/bus.h>
360062f2f2Smatt
370062f2f2Smatt #include <dev/usb/usb.h>
380062f2f2Smatt #include <dev/usb/usbdi.h>
390062f2f2Smatt #include <dev/usb/usbdivar.h>
400062f2f2Smatt #include <dev/usb/usb_mem.h>
410062f2f2Smatt
420062f2f2Smatt #include <dev/usb/ehcireg.h>
430062f2f2Smatt #include <dev/usb/ehcivar.h>
440062f2f2Smatt
450062f2f2Smatt #include <mips/ralink/ralink_usbhcvar.h>
460062f2f2Smatt
470062f2f2Smatt #include <mips/ralink/ralink_var.h>
480062f2f2Smatt #include <mips/ralink/ralink_reg.h>
490062f2f2Smatt
500062f2f2Smatt struct ralink_ehci_softc {
510062f2f2Smatt struct ehci_softc sc_ehci;
520062f2f2Smatt void *sc_ih;
530062f2f2Smatt };
540062f2f2Smatt
550062f2f2Smatt static int ralink_ehci_match(device_t, cfdata_t, void *);
560062f2f2Smatt static void ralink_ehci_attach(device_t, device_t, void *);
570062f2f2Smatt static int ralink_ehci_detach(device_t, int);
580062f2f2Smatt
590062f2f2Smatt CFATTACH_DECL2_NEW(ralink_ehci, sizeof(struct ralink_ehci_softc),
600062f2f2Smatt ralink_ehci_match, ralink_ehci_attach, ralink_ehci_detach,
610062f2f2Smatt ehci_activate, NULL, ehci_childdet);
620062f2f2Smatt
630062f2f2Smatt static TAILQ_HEAD(, ralink_usb_hc) ralink_usb_alldevs =
640062f2f2Smatt TAILQ_HEAD_INITIALIZER(ralink_usb_alldevs);
650062f2f2Smatt
660062f2f2Smatt #if 0
670062f2f2Smatt struct usb_hc_alldevs ralink_usb_alldevs = TAILQ_HEAD_INITIALIZER(ralink_usb_alldevs);
680062f2f2Smatt #endif
690062f2f2Smatt
700062f2f2Smatt /*
710062f2f2Smatt * ralink_ehci_match
720062f2f2Smatt */
730062f2f2Smatt static int
ralink_ehci_match(device_t parent,cfdata_t cf,void * aux)740062f2f2Smatt ralink_ehci_match(device_t parent, cfdata_t cf, void *aux)
750062f2f2Smatt {
760062f2f2Smatt
770062f2f2Smatt return 1;
780062f2f2Smatt }
790062f2f2Smatt
800062f2f2Smatt /*
810062f2f2Smatt * ralink_ehci_attach
820062f2f2Smatt */
830062f2f2Smatt static void
ralink_ehci_attach(device_t parent,device_t self,void * aux)840062f2f2Smatt ralink_ehci_attach(device_t parent, device_t self, void *aux)
850062f2f2Smatt {
860062f2f2Smatt struct ralink_ehci_softc * const sc = device_private(self);
870062f2f2Smatt const struct mainbus_attach_args *ma = aux;
880062f2f2Smatt struct ralink_usb_hc *ruh;
890062f2f2Smatt int error;
900062f2f2Smatt
910062f2f2Smatt aprint_naive(": EHCI USB controller\n");
920062f2f2Smatt aprint_normal(": EHCI USB controller\n");
930062f2f2Smatt
940062f2f2Smatt sc->sc_ehci.sc_dev = self;
954e8e6643Sskrll sc->sc_ehci.sc_bus.ub_hcpriv = sc;
960062f2f2Smatt sc->sc_ehci.iot = ma->ma_memt;
974e8e6643Sskrll sc->sc_ehci.sc_bus.ub_dmatag = ma->ma_dmat;
980062f2f2Smatt
990062f2f2Smatt /* Map EHCI registers */
100272c0890Smatt if ((error = bus_space_map(sc->sc_ehci.iot, RA_USB_EHCI_BASE,
101272c0890Smatt RA_USB_BLOCK_SIZE, 0, &sc->sc_ehci.ioh)) != 0) {
1020062f2f2Smatt aprint_error_dev(self, "can't map EHCI registers, "
1030062f2f2Smatt "error=%d\n", error);
1040062f2f2Smatt return;
1050062f2f2Smatt }
1060062f2f2Smatt
107272c0890Smatt sc->sc_ehci.sc_size = RA_USB_BLOCK_SIZE;
1084e8e6643Sskrll sc->sc_ehci.sc_bus.ub_revision = USBREV_2_0;
1090062f2f2Smatt
11086475f59Smatt #if defined(RALINK_EHCI_DEBUG)
11186475f59Smatt aprint_normal_dev(self, "sc %p ma %p\n", sc, ma);
11286475f59Smatt aprint_normal_dev(self, "memt %p dmat %p\n", ma->ma_memt, ma->ma_dmat);
11386475f59Smatt aprint_normal_dev(self, "EHCI HCCAPBASE=%#x\n",
1140062f2f2Smatt EREAD4(&sc->sc_ehci, EHCI_CAPLENGTH));
11586475f59Smatt aprint_normal_dev(self, "EHCI HCSPARAMS=%#x\n",
1160062f2f2Smatt EREAD4(&sc->sc_ehci, EHCI_HCSPARAMS));
11786475f59Smatt aprint_normal_dev(self, "EHCI HCCPARAMS=%#x\n",
1180062f2f2Smatt EREAD4(&sc->sc_ehci, EHCI_HCCPARAMS));
11986475f59Smatt aprint_normal_dev(self, "EHCI HCSP_PORTROUTE=%#x\n",
1200062f2f2Smatt EREAD4(&sc->sc_ehci, EHCI_HCSP_PORTROUTE));
1210062f2f2Smatt #endif
1220062f2f2Smatt
1230062f2f2Smatt /* Disable EHCI interrupts. */
1240062f2f2Smatt sc->sc_ehci.sc_offs = EREAD1(&sc->sc_ehci, EHCI_CAPLENGTH);
12509fca0b7Smatt EOWRITE4(&sc->sc_ehci, EHCI_USBINTR, 0);
1260062f2f2Smatt
12786475f59Smatt #if defined(RALINK_EHCI_DEBUG)
12886475f59Smatt aprint_normal_dev(self, "EHCI USBCMD=%#x USBSTS=%#x USBINTR=%#x\n",
12986475f59Smatt EOREAD4(&sc->sc_ehci, EHCI_USBCMD),
13086475f59Smatt EOREAD4(&sc->sc_ehci, EHCI_USBSTS),
1310062f2f2Smatt EOREAD4(&sc->sc_ehci, EHCI_USBINTR));
1320062f2f2Smatt #endif
1330062f2f2Smatt
1340062f2f2Smatt /* Establish the MIPS level interrupt */
1350062f2f2Smatt sc->sc_ih = ra_intr_establish(RA_IRQ_USB, ehci_intr, sc, 1);
1360062f2f2Smatt if (sc->sc_ih == NULL) {
1370062f2f2Smatt aprint_error_dev(self, "unable to establish irq %d\n",
1380062f2f2Smatt RA_IRQ_USB);
1390062f2f2Smatt goto fail_0;
1400062f2f2Smatt }
1410062f2f2Smatt
1420062f2f2Smatt /*
1430062f2f2Smatt * Find companion controllers. According to the spec they always
1440062f2f2Smatt * have lower function numbers so they should be enumerated already.
1450062f2f2Smatt */
1460062f2f2Smatt int ncomp = 0;
1470062f2f2Smatt TAILQ_FOREACH(ruh, &ralink_usb_alldevs, next) {
1480062f2f2Smatt aprint_normal_dev(self, "companion %s\n",
1490062f2f2Smatt device_xname(ruh->usb));
1500062f2f2Smatt sc->sc_ehci.sc_comps[ncomp++] = ruh->usb;
1510062f2f2Smatt if (ncomp >= EHCI_COMPANION_MAX)
1520062f2f2Smatt break;
1530062f2f2Smatt }
1540062f2f2Smatt sc->sc_ehci.sc_ncomp = ncomp;
1550062f2f2Smatt
1560062f2f2Smatt /* Initialize EHCI */
1574e8e6643Sskrll int err = ehci_init(&sc->sc_ehci);
1584e8e6643Sskrll if (err) {
1594e8e6643Sskrll aprint_error_dev(self, "init failed, error=%d\n", err);
1600062f2f2Smatt goto fail_1;
1610062f2f2Smatt }
1620062f2f2Smatt
1630062f2f2Smatt if (!pmf_device_register1(self, ehci_suspend, ehci_resume,
1640062f2f2Smatt ehci_shutdown))
1650062f2f2Smatt aprint_error_dev(self, "couldn't establish power handler\n");
1660062f2f2Smatt
1670062f2f2Smatt /* Attach usb device. */
1680062f2f2Smatt sc->sc_ehci.sc_child = config_found(self, &sc->sc_ehci.sc_bus,
169*c7fb772bSthorpej usbctlprint, CFARGS_NONE);
1700062f2f2Smatt
1710062f2f2Smatt return;
1720062f2f2Smatt
1730062f2f2Smatt fail_1:
1740062f2f2Smatt ra_intr_disestablish(sc->sc_ih);
1750062f2f2Smatt sc->sc_ih = NULL;
1760062f2f2Smatt fail_0:
1770062f2f2Smatt bus_space_unmap(sc->sc_ehci.iot, sc->sc_ehci.ioh, sc->sc_ehci.sc_size);
1780062f2f2Smatt sc->sc_ehci.sc_size = 0;
1790062f2f2Smatt }
1800062f2f2Smatt
1810062f2f2Smatt static int
ralink_ehci_detach(device_t self,int flags)1820062f2f2Smatt ralink_ehci_detach(device_t self, int flags)
1830062f2f2Smatt {
1840062f2f2Smatt struct ralink_ehci_softc * const sc = device_private(self);
1850062f2f2Smatt int rv;
1860062f2f2Smatt
1870062f2f2Smatt pmf_device_deregister(self);
1880062f2f2Smatt
1890062f2f2Smatt rv = ehci_detach(&sc->sc_ehci, flags);
1900062f2f2Smatt if (rv)
1910062f2f2Smatt return rv;
1920062f2f2Smatt
1930062f2f2Smatt if (sc->sc_ih != NULL) {
1940062f2f2Smatt ra_intr_disestablish(sc->sc_ih);
1950062f2f2Smatt sc->sc_ih = NULL;
1960062f2f2Smatt }
1970062f2f2Smatt
1980062f2f2Smatt if (sc->sc_ehci.sc_size != 0) {
1990062f2f2Smatt bus_space_unmap(sc->sc_ehci.iot, sc->sc_ehci.ioh,
2000062f2f2Smatt sc->sc_ehci.sc_size);
2010062f2f2Smatt sc->sc_ehci.sc_size = 0;
2020062f2f2Smatt }
2030062f2f2Smatt
2040062f2f2Smatt return 0;
2050062f2f2Smatt }
2060062f2f2Smatt
2070062f2f2Smatt void
ralink_usb_hc_add(struct ralink_usb_hc * ruh,device_t usbp)2080062f2f2Smatt ralink_usb_hc_add(struct ralink_usb_hc *ruh, device_t usbp)
2090062f2f2Smatt {
2100062f2f2Smatt TAILQ_INSERT_TAIL(&ralink_usb_alldevs, ruh, next);
2110062f2f2Smatt ruh->usb = usbp;
2120062f2f2Smatt }
2130062f2f2Smatt
2140062f2f2Smatt void
ralink_usb_hc_rem(struct ralink_usb_hc * ruh)2150062f2f2Smatt ralink_usb_hc_rem(struct ralink_usb_hc *ruh)
2160062f2f2Smatt {
2170062f2f2Smatt TAILQ_REMOVE(&ralink_usb_alldevs, ruh, next);
2180062f2f2Smatt }
219