xhci_acpi.c revision 1.4
11.4Sjmcneill/* $NetBSD: xhci_acpi.c,v 1.4 2019/06/19 13:40:23 jmcneill Exp $ */
21.1Sjmcneill
31.1Sjmcneill/*-
41.1Sjmcneill * Copyright (c) 2018 The NetBSD Foundation, Inc.
51.1Sjmcneill * All rights reserved.
61.1Sjmcneill *
71.1Sjmcneill * This code is derived from software contributed to The NetBSD Foundation
81.1Sjmcneill * by Jared McNeill <jmcneill@invisible.ca>.
91.1Sjmcneill *
101.1Sjmcneill * Redistribution and use in source and binary forms, with or without
111.1Sjmcneill * modification, are permitted provided that the following conditions
121.1Sjmcneill * are met:
131.1Sjmcneill * 1. Redistributions of source code must retain the above copyright
141.1Sjmcneill *    notice, this list of conditions and the following disclaimer.
151.1Sjmcneill * 2. Redistributions in binary form must reproduce the above copyright
161.1Sjmcneill *    notice, this list of conditions and the following disclaimer in the
171.1Sjmcneill *    documentation and/or other materials provided with the distribution.
181.1Sjmcneill *
191.1Sjmcneill * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
201.1Sjmcneill * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
211.1Sjmcneill * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
221.1Sjmcneill * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
231.1Sjmcneill * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
241.1Sjmcneill * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
251.1Sjmcneill * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
261.1Sjmcneill * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
271.1Sjmcneill * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
281.1Sjmcneill * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
291.1Sjmcneill * POSSIBILITY OF SUCH DAMAGE.
301.1Sjmcneill */
311.1Sjmcneill
321.1Sjmcneill#include <sys/cdefs.h>
331.4Sjmcneill__KERNEL_RCSID(0, "$NetBSD: xhci_acpi.c,v 1.4 2019/06/19 13:40:23 jmcneill Exp $");
341.1Sjmcneill
351.1Sjmcneill#include <sys/param.h>
361.1Sjmcneill#include <sys/bus.h>
371.1Sjmcneill#include <sys/cpu.h>
381.1Sjmcneill#include <sys/device.h>
391.1Sjmcneill
401.1Sjmcneill#include <dev/usb/usb.h>
411.1Sjmcneill#include <dev/usb/usbdi.h>
421.1Sjmcneill#include <dev/usb/usbdivar.h>
431.1Sjmcneill#include <dev/usb/usb_mem.h>
441.1Sjmcneill#include <dev/usb/xhcireg.h>
451.1Sjmcneill#include <dev/usb/xhcivar.h>
461.1Sjmcneill
471.1Sjmcneill#include <dev/acpi/acpireg.h>
481.1Sjmcneill#include <dev/acpi/acpivar.h>
491.2Sjmcneill#include <dev/acpi/acpi_intr.h>
501.1Sjmcneill#include <dev/acpi/acpi_usb.h>
511.1Sjmcneill
521.1Sjmcneillstatic const char * const compatible[] = {
531.3Stron	"PNP0D10",	/* XHCI-compliant USB controller without standard debug */
541.3Stron	"PNP0D15",	/* XHCI-compliant USB controller with standard debug */
551.1Sjmcneill	NULL
561.1Sjmcneill};
571.1Sjmcneill
581.1Sjmcneillstruct xhci_acpi_softc {
591.1Sjmcneill	struct xhci_softc	sc_xhci;
601.1Sjmcneill	ACPI_HANDLE		sc_handle;
611.1Sjmcneill};
621.1Sjmcneill
631.1Sjmcneillstatic int	xhci_acpi_match(device_t, cfdata_t, void *);
641.1Sjmcneillstatic void	xhci_acpi_attach(device_t, device_t, void *);
651.1Sjmcneill
661.1Sjmcneillstatic void	xhci_acpi_init(struct xhci_softc *);
671.1Sjmcneill
681.1SjmcneillCFATTACH_DECL2_NEW(xhci_acpi, sizeof(struct xhci_acpi_softc),
691.1Sjmcneill	xhci_acpi_match, xhci_acpi_attach, NULL,
701.1Sjmcneill	xhci_activate, NULL, xhci_childdet);
711.1Sjmcneill
721.1Sjmcneillstatic int
731.1Sjmcneillxhci_acpi_match(device_t parent, cfdata_t cf, void *aux)
741.1Sjmcneill{
751.1Sjmcneill	struct acpi_attach_args *aa = aux;
761.1Sjmcneill
771.1Sjmcneill	if (aa->aa_node->ad_type != ACPI_TYPE_DEVICE)
781.1Sjmcneill		return 0;
791.1Sjmcneill
801.1Sjmcneill	return acpi_match_hid(aa->aa_node->ad_devinfo, compatible);
811.1Sjmcneill}
821.1Sjmcneill
831.1Sjmcneillstatic void
841.1Sjmcneillxhci_acpi_attach(device_t parent, device_t self, void *aux)
851.1Sjmcneill{
861.1Sjmcneill	struct xhci_acpi_softc * const asc = device_private(self);
871.1Sjmcneill	struct xhci_softc * const sc = &asc->sc_xhci;
881.1Sjmcneill	struct acpi_attach_args *aa = aux;
891.1Sjmcneill	struct acpi_resources res;
901.1Sjmcneill	struct acpi_mem *mem;
911.1Sjmcneill	struct acpi_irq *irq;
921.4Sjmcneill	uint32_t hccparams;
931.1Sjmcneill	ACPI_STATUS rv;
941.1Sjmcneill	int error;
951.1Sjmcneill	void *ih;
961.1Sjmcneill
971.1Sjmcneill	asc->sc_handle = aa->aa_node->ad_handle;
981.1Sjmcneill
991.1Sjmcneill	sc->sc_dev = self;
1001.1Sjmcneill	sc->sc_bus.ub_hcpriv = sc;
1011.1Sjmcneill	sc->sc_bus.ub_revision = USBREV_3_0;
1021.1Sjmcneill	sc->sc_quirks = 0;
1031.1Sjmcneill	sc->sc_vendor_init = xhci_acpi_init;
1041.1Sjmcneill
1051.1Sjmcneill	rv = acpi_resource_parse(sc->sc_dev, asc->sc_handle, "_CRS",
1061.1Sjmcneill	    &res, &acpi_resource_parse_ops_default);
1071.1Sjmcneill	if (ACPI_FAILURE(rv))
1081.1Sjmcneill		return;
1091.1Sjmcneill
1101.1Sjmcneill	mem = acpi_res_mem(&res, 0);
1111.1Sjmcneill	if (mem == NULL) {
1121.1Sjmcneill		aprint_error_dev(self, "couldn't find mem resource\n");
1131.1Sjmcneill		goto done;
1141.1Sjmcneill	}
1151.1Sjmcneill
1161.1Sjmcneill	irq = acpi_res_irq(&res, 0);
1171.2Sjmcneill	if (irq == NULL) {
1181.1Sjmcneill		aprint_error_dev(self, "couldn't find irq resource\n");
1191.1Sjmcneill		goto done;
1201.1Sjmcneill	}
1211.1Sjmcneill
1221.1Sjmcneill	sc->sc_ios = mem->ar_length;
1231.1Sjmcneill	sc->sc_iot = aa->aa_memt;
1241.1Sjmcneill	error = bus_space_map(sc->sc_iot, mem->ar_base, mem->ar_length, 0, &sc->sc_ioh);
1251.1Sjmcneill	if (error) {
1261.1Sjmcneill		aprint_error_dev(self, "couldn't map registers\n");
1271.1Sjmcneill		return;
1281.1Sjmcneill	}
1291.1Sjmcneill
1301.4Sjmcneill	hccparams = bus_space_read_4(sc->sc_iot, sc->sc_ioh, XHCI_HCCPARAMS);
1311.4Sjmcneill	if (XHCI_HCC_AC64(hccparams)) {
1321.4Sjmcneill		aprint_verbose_dev(self, "using 64-bit DMA\n");
1331.4Sjmcneill		sc->sc_bus.ub_dmatag = aa->aa_dmat64;
1341.4Sjmcneill	} else {
1351.4Sjmcneill		aprint_verbose_dev(self, "using 32-bit DMA\n");
1361.4Sjmcneill		sc->sc_bus.ub_dmatag = aa->aa_dmat;
1371.4Sjmcneill	}
1381.4Sjmcneill
1391.2Sjmcneill        ih = acpi_intr_establish(self, (uint64_t)aa->aa_node->ad_handle,
1401.2Sjmcneill	    IPL_USB, true, xhci_intr, sc, device_xname(self));
1411.1Sjmcneill	if (ih == NULL) {
1421.1Sjmcneill		aprint_error_dev(self, "couldn't establish interrupt\n");
1431.1Sjmcneill		return;
1441.1Sjmcneill	}
1451.1Sjmcneill
1461.1Sjmcneill	error = xhci_init(sc);
1471.1Sjmcneill	if (error) {
1481.1Sjmcneill		aprint_error_dev(self, "init failed, error = %d\n", error);
1491.1Sjmcneill		return;
1501.1Sjmcneill	}
1511.1Sjmcneill
1521.1Sjmcneill	sc->sc_child = config_found(self, &sc->sc_bus, usbctlprint);
1531.1Sjmcneill	sc->sc_child2 = config_found(self, &sc->sc_bus2, usbctlprint);
1541.1Sjmcneill
1551.1Sjmcneilldone:
1561.1Sjmcneill	acpi_resource_cleanup(&res);
1571.1Sjmcneill}
1581.1Sjmcneill
1591.1Sjmcneillstatic void
1601.1Sjmcneillxhci_acpi_init(struct xhci_softc *sc)
1611.1Sjmcneill{
1621.1Sjmcneill	struct xhci_acpi_softc * const asc = (struct xhci_acpi_softc *)sc;
1631.1Sjmcneill
1641.1Sjmcneill	acpi_usb_post_reset(asc->sc_handle);
1651.1Sjmcneill}
166