Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 12 Oct 2020 10:51:34 +0000 (UTC)
From:      Andriy Gapon <avg@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-12@freebsd.org
Subject:   svn commit: r366637 - in stable/12/sys: arm/allwinner arm64/conf conf dev/usb/controller
Message-ID:  <202010121051.09CApZQG075023@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: avg
Date: Mon Oct 12 10:51:34 2020
New Revision: 366637
URL: https://svnweb.freebsd.org/changeset/base/366637

Log:
  MFC r365398,r365399: Allwinner USB DRD support (musb_otg)
  
  Allwinner USB DRD is based on the Mentor USB OTG controller, with a
  different register layout and a few missing registers.
  
  The code is by Andrew Turner (andrew).

Added:
  stable/12/sys/dev/usb/controller/musb_otg_allwinner.c
     - copied unchanged from r365399, head/sys/dev/usb/controller/musb_otg_allwinner.c
Modified:
  stable/12/sys/arm/allwinner/aw_usbphy.c
  stable/12/sys/arm/allwinner/files.allwinner
  stable/12/sys/arm64/conf/GENERIC
  stable/12/sys/conf/files.arm64
Directory Properties:
  stable/12/   (props changed)

Modified: stable/12/sys/arm/allwinner/aw_usbphy.c
==============================================================================
--- stable/12/sys/arm/allwinner/aw_usbphy.c	Mon Oct 12 10:42:33 2020	(r366636)
+++ stable/12/sys/arm/allwinner/aw_usbphy.c	Mon Oct 12 10:51:34 2020	(r366637)
@@ -161,6 +161,18 @@ DEFINE_CLASS_1(awusbphy_phynode, awusbphy_phynode_clas
 #define	CLR4(res, o, m)	WR4(res, o, RD4(res, o) & ~(m))
 #define	SET4(res, o, m)	WR4(res, o, RD4(res, o) | (m))
 
+#define	PHY_CSR		0x00
+#define	 ID_PULLUP_EN		(1 << 17)
+#define	 DPDM_PULLUP_EN		(1 << 16)
+#define	 FORCE_ID		(0x3 << 14)
+#define	 FORCE_ID_SHIFT		14
+#define	 FORCE_ID_LOW		2
+#define	 FORCE_VBUS_VALID	(0x3 << 12)
+#define	 FORCE_VBUS_VALID_SHIFT	12
+#define	 FORCE_VBUS_VALID_HIGH	3
+#define	 VBUS_CHANGE_DET	(1 << 6)
+#define	 ID_CHANGE_DET		(1 << 5)
+#define	 DPDM_CHANGE_DET	(1 << 4)
 #define	OTG_PHY_CFG	0x20
 #define	 OTG_PHY_ROUTE_OTG	(1 << 0)
 #define	PMU_IRQ_ENABLE	0x00
@@ -206,6 +218,7 @@ awusbphy_init(device_t dev)
 	struct awusbphy_softc *sc;
 	phandle_t node;
 	char pname[20];
+	uint32_t val;
 	int error, off, rid;
 	regulator_t reg;
 	hwreset_t rst;
@@ -280,6 +293,16 @@ awusbphy_init(device_t dev)
 			return (ENXIO);
 		}
 	}
+
+	/* Enable OTG PHY for host mode */
+	val = bus_read_4(sc->phy_ctrl, PHY_CSR);
+	val &= ~(VBUS_CHANGE_DET | ID_CHANGE_DET | DPDM_CHANGE_DET);
+	val |= (ID_PULLUP_EN | DPDM_PULLUP_EN);
+	val &= ~FORCE_ID;
+	val |= (FORCE_ID_LOW << FORCE_ID_SHIFT);
+	val &= ~FORCE_VBUS_VALID;
+	val |= (FORCE_VBUS_VALID_HIGH << FORCE_VBUS_VALID_SHIFT);
+	bus_write_4(sc->phy_ctrl, PHY_CSR, val);
 
 	return (0);
 }

Modified: stable/12/sys/arm/allwinner/files.allwinner
==============================================================================
--- stable/12/sys/arm/allwinner/files.allwinner	Mon Oct 12 10:42:33 2020	(r366636)
+++ stable/12/sys/arm/allwinner/files.allwinner	Mon Oct 12 10:51:34 2020	(r366637)
@@ -27,6 +27,7 @@ dev/usb/controller/generic_ohci.c	optional	ohci
 dev/usb/controller/generic_usb_if.m	optional	ohci
 dev/usb/controller/generic_ehci.c	optional	ehci
 dev/usb/controller/generic_ehci_fdt.c	optional	ehci
+dev/usb/controller/musb_otg_allwinner.c	optional	musb
 arm/allwinner/aw_sid.c			optional	aw_sid
 arm/allwinner/aw_thermal.c		optional	aw_thermal
 arm/allwinner/aw_cir.c			optional	aw_cir evdev

Modified: stable/12/sys/arm64/conf/GENERIC
==============================================================================
--- stable/12/sys/arm64/conf/GENERIC	Mon Oct 12 10:42:33 2020	(r366636)
+++ stable/12/sys/arm64/conf/GENERIC	Mon Oct 12 10:51:34 2020	(r366637)
@@ -185,6 +185,7 @@ device		aw_usbphy		# Allwinner USB PHY
 device		rk_usb2phy		# Rockchip USB2PHY
 device		rk_typec_phy		# Rockchip TypeC PHY
 device		dwcotg			# DWC OTG controller
+device		musb			# Mentor Graphics USB OTG controller
 device		ohci			# OHCI USB interface
 device		ehci			# EHCI USB interface (USB 2.0)
 device		ehci_mv			# Marvell EHCI USB interface

Modified: stable/12/sys/conf/files.arm64
==============================================================================
--- stable/12/sys/conf/files.arm64	Mon Oct 12 10:42:33 2020	(r366636)
+++ stable/12/sys/conf/files.arm64	Mon Oct 12 10:51:34 2020	(r366637)
@@ -300,6 +300,7 @@ dev/usb/controller/generic_ehci_acpi.c optional	ehci a
 dev/usb/controller/generic_ehci_fdt.c optional	ehci fdt
 dev/usb/controller/generic_ohci.c optional	ohci fdt
 dev/usb/controller/generic_usb_if.m optional	ohci fdt
+dev/usb/controller/musb_otg_allwinner.c	optional musb fdt soc_allwinner_a64
 dev/usb/controller/usb_nop_xceiv.c	optional fdt ext_resources
 dev/usb/controller/generic_xhci.c	optional	xhci fdt
 dev/vnic/mrml_bridge.c		optional	vnic fdt

Copied: stable/12/sys/dev/usb/controller/musb_otg_allwinner.c (from r365399, head/sys/dev/usb/controller/musb_otg_allwinner.c)
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ stable/12/sys/dev/usb/controller/musb_otg_allwinner.c	Mon Oct 12 10:51:34 2020	(r366637, copy of r365399, head/sys/dev/usb/controller/musb_otg_allwinner.c)
@@ -0,0 +1,543 @@
+/*-
+ * Copyright (c) 2016 Jared McNeill <jmcneill@invisible.ca>
+ * Copyright (c) 2018 Andrew Turner <andrew@FreeBSD.org>
+ * All rights reserved.
+ *
+ * This software was developed by SRI International and the University of
+ * Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-10-C-0237
+ * ("CTSRD"), as part of the DARPA CRASH research programme.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Allwinner USB Dual-Role Device (DRD) controller
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+#include <sys/kernel.h>
+#include <sys/condvar.h>
+#include <sys/module.h>
+#include <machine/bus.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <dev/usb/usb.h>
+#include <dev/usb/usbdi.h>
+
+#include <dev/usb/usb_core.h>
+#include <dev/usb/usb_busdma.h>
+#include <dev/usb/usb_process.h>
+#include <dev/usb/usb_util.h>
+
+#include <dev/usb/usb_controller.h>
+#include <dev/usb/usb_bus.h>
+#include <dev/usb/controller/musb_otg.h>
+
+#include <dev/extres/clk/clk.h>
+#include <dev/extres/hwreset/hwreset.h>
+
+#ifdef __arm__
+#include <arm/allwinner/aw_machdep.h>
+#include <arm/allwinner/a10_sramc.h>
+#endif
+
+#define	DRD_EP_MAX		5
+
+#define	MUSB2_REG_AWIN_VEND0	0x0043
+#define	VEND0_PIO_MODE		0
+
+#if defined(__arm__)
+#define	bs_parent_space(bs)	((bs)->bs_parent)
+typedef bus_space_tag_t	awusb_bs_tag;
+#elif defined(__aarch64__)
+#define	bs_parent_space(bs)	(bs)
+typedef void *		awusb_bs_tag;
+#endif
+
+#define	AWUSB_OKAY		0x01
+#define	AWUSB_NO_CONFDATA	0x02
+static struct ofw_compat_data compat_data[] = {
+	{ "allwinner,sun4i-a10-musb",	AWUSB_OKAY },
+	{ "allwinner,sun6i-a31-musb",	AWUSB_OKAY },
+	{ "allwinner,sun8i-a33-musb",	AWUSB_OKAY | AWUSB_NO_CONFDATA },
+	{ NULL,				0 }
+};
+
+static const struct musb_otg_ep_cfg musbotg_ep_allwinner[] = {
+	{
+		.ep_end = 5,
+		.ep_fifosz_shift = 9,
+		.ep_fifosz_reg = MUSB2_VAL_FIFOSZ_512,
+	},
+	{
+		.ep_end = -1,
+	},
+};
+
+struct awusbdrd_softc {
+	struct musbotg_softc	sc;
+	struct resource		*res[2];
+	clk_t			clk;
+	hwreset_t		reset;
+	struct bus_space	bs;
+	int			flags;
+};
+
+static struct resource_spec awusbdrd_spec[] = {
+	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },
+	{ SYS_RES_IRQ,		0,	RF_ACTIVE },
+	{ -1, 0 }
+};
+
+#define	REMAPFLAG	0x8000
+#define	REGDECL(a, b)	[(a)] = ((b) | REMAPFLAG)
+
+/* Allwinner USB DRD register mappings */
+static const uint16_t awusbdrd_regmap[] = {
+	REGDECL(MUSB2_REG_EPFIFO(0),	0x0000),
+	REGDECL(MUSB2_REG_EPFIFO(1),	0x0004),
+	REGDECL(MUSB2_REG_EPFIFO(2),	0x0008),
+	REGDECL(MUSB2_REG_EPFIFO(3),	0x000c),
+	REGDECL(MUSB2_REG_EPFIFO(4),	0x0010),
+	REGDECL(MUSB2_REG_EPFIFO(5),	0x0014),
+	REGDECL(MUSB2_REG_POWER,	0x0040),
+	REGDECL(MUSB2_REG_DEVCTL,	0x0041),
+	REGDECL(MUSB2_REG_EPINDEX,	0x0042),
+	REGDECL(MUSB2_REG_INTTX,	0x0044),
+	REGDECL(MUSB2_REG_INTRX,	0x0046),
+	REGDECL(MUSB2_REG_INTTXE,	0x0048),
+	REGDECL(MUSB2_REG_INTRXE,	0x004a),
+	REGDECL(MUSB2_REG_INTUSB,	0x004c),
+	REGDECL(MUSB2_REG_INTUSBE,	0x0050),
+	REGDECL(MUSB2_REG_FRAME,	0x0054),
+	REGDECL(MUSB2_REG_TESTMODE,	0x007c),
+	REGDECL(MUSB2_REG_TXMAXP,	0x0080),
+	REGDECL(MUSB2_REG_TXCSRL,	0x0082),
+	REGDECL(MUSB2_REG_TXCSRH,	0x0083),
+	REGDECL(MUSB2_REG_RXMAXP,	0x0084),
+	REGDECL(MUSB2_REG_RXCSRL,	0x0086),
+	REGDECL(MUSB2_REG_RXCSRH,	0x0087),
+	REGDECL(MUSB2_REG_RXCOUNT,	0x0088),
+	REGDECL(MUSB2_REG_TXTI,		0x008c),
+	REGDECL(MUSB2_REG_TXNAKLIMIT,	0x008d),
+	REGDECL(MUSB2_REG_RXNAKLIMIT,	0x008f),
+	REGDECL(MUSB2_REG_RXTI,		0x008e),
+	REGDECL(MUSB2_REG_TXFIFOSZ,	0x0090),
+	REGDECL(MUSB2_REG_TXFIFOADD,	0x0092),
+	REGDECL(MUSB2_REG_RXFIFOSZ,	0x0094),
+	REGDECL(MUSB2_REG_RXFIFOADD,	0x0096),
+	REGDECL(MUSB2_REG_FADDR,	0x0098),
+	REGDECL(MUSB2_REG_TXFADDR(0),	0x0098),
+	REGDECL(MUSB2_REG_TXHADDR(0),	0x009a),
+	REGDECL(MUSB2_REG_TXHUBPORT(0),	0x009b),
+	REGDECL(MUSB2_REG_RXFADDR(0),	0x009c),
+	REGDECL(MUSB2_REG_RXHADDR(0),	0x009e),
+	REGDECL(MUSB2_REG_RXHUBPORT(0),	0x009f),
+	REGDECL(MUSB2_REG_TXFADDR(1),	0x0098),
+	REGDECL(MUSB2_REG_TXHADDR(1),	0x009a),
+	REGDECL(MUSB2_REG_TXHUBPORT(1),	0x009b),
+	REGDECL(MUSB2_REG_RXFADDR(1),	0x009c),
+	REGDECL(MUSB2_REG_RXHADDR(1),	0x009e),
+	REGDECL(MUSB2_REG_RXHUBPORT(1),	0x009f),
+	REGDECL(MUSB2_REG_TXFADDR(2),	0x0098),
+	REGDECL(MUSB2_REG_TXHADDR(2),	0x009a),
+	REGDECL(MUSB2_REG_TXHUBPORT(2),	0x009b),
+	REGDECL(MUSB2_REG_RXFADDR(2),	0x009c),
+	REGDECL(MUSB2_REG_RXHADDR(2),	0x009e),
+	REGDECL(MUSB2_REG_RXHUBPORT(2),	0x009f),
+	REGDECL(MUSB2_REG_TXFADDR(3),	0x0098),
+	REGDECL(MUSB2_REG_TXHADDR(3),	0x009a),
+	REGDECL(MUSB2_REG_TXHUBPORT(3),	0x009b),
+	REGDECL(MUSB2_REG_RXFADDR(3),	0x009c),
+	REGDECL(MUSB2_REG_RXHADDR(3),	0x009e),
+	REGDECL(MUSB2_REG_RXHUBPORT(3),	0x009f),
+	REGDECL(MUSB2_REG_TXFADDR(4),	0x0098),
+	REGDECL(MUSB2_REG_TXHADDR(4),	0x009a),
+	REGDECL(MUSB2_REG_TXHUBPORT(4),	0x009b),
+	REGDECL(MUSB2_REG_RXFADDR(4),	0x009c),
+	REGDECL(MUSB2_REG_RXHADDR(4),	0x009e),
+	REGDECL(MUSB2_REG_RXHUBPORT(4),	0x009f),
+	REGDECL(MUSB2_REG_TXFADDR(5),	0x0098),
+	REGDECL(MUSB2_REG_TXHADDR(5),	0x009a),
+	REGDECL(MUSB2_REG_TXHUBPORT(5),	0x009b),
+	REGDECL(MUSB2_REG_RXFADDR(5),	0x009c),
+	REGDECL(MUSB2_REG_RXHADDR(5),	0x009e),
+	REGDECL(MUSB2_REG_RXHUBPORT(5),	0x009f),
+	REGDECL(MUSB2_REG_CONFDATA,	0x00c0),
+};
+
+static bus_size_t
+awusbdrd_reg(bus_size_t o)
+{
+	bus_size_t v;
+
+	KASSERT(o < nitems(awusbdrd_regmap),
+	    ("%s: Invalid register %#lx", __func__, o));
+	if (o >= nitems(awusbdrd_regmap))
+		return (o);
+
+	v = awusbdrd_regmap[o];
+
+	KASSERT((v & REMAPFLAG) != 0, ("%s: reg %#lx not in regmap",
+	    __func__, o));
+
+	return (v & ~REMAPFLAG);
+}
+
+static int
+awusbdrd_filt(bus_size_t o)
+{
+	switch (o) {
+	case MUSB2_REG_MISC:
+	case MUSB2_REG_RXDBDIS:
+	case MUSB2_REG_TXDBDIS:
+		return (1);
+	default:
+		return (0);
+	}
+}
+
+static uint8_t
+awusbdrd_bs_r_1(awusb_bs_tag t, bus_space_handle_t h, bus_size_t o)
+{
+	const struct bus_space *bs = t;
+
+	switch (o) {
+	case MUSB2_REG_HWVERS:
+		return (0);	/* no known equivalent */
+	}
+
+	return (bus_space_read_1(bs_parent_space(bs), h, awusbdrd_reg(o)));
+}
+
+static uint8_t
+awusbdrd_bs_r_1_noconf(awusb_bs_tag t, bus_space_handle_t h, bus_size_t o)
+{
+
+	/*
+	 * There is no confdata register on some SoCs, return the same
+	 * magic value as Linux.
+	 */
+	if (o == MUSB2_REG_CONFDATA)
+		return (0xde);
+
+	return (awusbdrd_bs_r_1(t, h, o));
+}
+
+
+static uint16_t
+awusbdrd_bs_r_2(awusb_bs_tag t, bus_space_handle_t h, bus_size_t o)
+{
+	const struct bus_space *bs = t;
+
+	return bus_space_read_2(bs_parent_space(bs), h, awusbdrd_reg(o));
+}
+
+static void
+awusbdrd_bs_w_1(awusb_bs_tag t, bus_space_handle_t h, bus_size_t o,
+    uint8_t v)
+{
+	const struct bus_space *bs = t;
+
+	if (awusbdrd_filt(o) != 0)
+		return;
+
+	bus_space_write_1(bs_parent_space(bs), h, awusbdrd_reg(o), v);
+}
+
+static void
+awusbdrd_bs_w_2(awusb_bs_tag t, bus_space_handle_t h, bus_size_t o,
+    uint16_t v)
+{
+	const struct bus_space *bs = t;
+
+	if (awusbdrd_filt(o) != 0)
+		return;
+
+	bus_space_write_2(bs_parent_space(bs), h, awusbdrd_reg(o), v);
+}
+
+static void
+awusbdrd_bs_rm_1(awusb_bs_tag t, bus_space_handle_t h, bus_size_t o,
+    uint8_t *d, bus_size_t c)
+{
+	const struct bus_space *bs = t;
+
+	bus_space_read_multi_1(bs_parent_space(bs), h, awusbdrd_reg(o), d, c);
+}
+
+static void
+awusbdrd_bs_rm_4(awusb_bs_tag t, bus_space_handle_t h, bus_size_t o,
+    uint32_t *d, bus_size_t c)
+{
+	const struct bus_space *bs = t;
+
+	bus_space_read_multi_4(bs_parent_space(bs), h, awusbdrd_reg(o), d, c);
+}
+
+static void
+awusbdrd_bs_wm_1(awusb_bs_tag t, bus_space_handle_t h, bus_size_t o,
+    const uint8_t *d, bus_size_t c)
+{
+	const struct bus_space *bs = t;
+
+	if (awusbdrd_filt(o) != 0)
+		return;
+
+	bus_space_write_multi_1(bs_parent_space(bs), h, awusbdrd_reg(o), d, c);
+}
+
+static void
+awusbdrd_bs_wm_4(awusb_bs_tag t, bus_space_handle_t h, bus_size_t o,
+    const uint32_t *d, bus_size_t c)
+{
+	const struct bus_space *bs = t;
+
+	if (awusbdrd_filt(o) != 0)
+		return;
+
+	bus_space_write_multi_4(bs_parent_space(bs), h, awusbdrd_reg(o), d, c);
+}
+
+static void
+awusbdrd_intr(void *arg)
+{
+	struct awusbdrd_softc *sc = arg;
+	uint8_t intusb;
+	uint16_t inttx, intrx;
+
+	intusb = MUSB2_READ_1(&sc->sc, MUSB2_REG_INTUSB);
+	inttx = MUSB2_READ_2(&sc->sc, MUSB2_REG_INTTX);
+	intrx = MUSB2_READ_2(&sc->sc, MUSB2_REG_INTRX);
+	if (intusb == 0 && inttx == 0 && intrx == 0)
+		return;
+
+	if (intusb)
+		MUSB2_WRITE_1(&sc->sc, MUSB2_REG_INTUSB, intusb);
+	if (inttx)
+		MUSB2_WRITE_2(&sc->sc, MUSB2_REG_INTTX, inttx);
+	if (intrx)
+		MUSB2_WRITE_2(&sc->sc, MUSB2_REG_INTRX, intrx);
+
+	musbotg_interrupt(arg, intrx, inttx, intusb);
+}
+
+static int
+awusbdrd_probe(device_t dev)
+{
+	if (!ofw_bus_status_okay(dev))
+		return (ENXIO);
+
+	if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
+		return (ENXIO);
+
+	device_set_desc(dev, "Allwinner USB DRD");
+	return (BUS_PROBE_DEFAULT);
+}
+
+static int
+awusbdrd_attach(device_t dev)
+{
+	struct awusbdrd_softc *sc;
+	int error;
+
+	sc = device_get_softc(dev);
+	sc->flags = ofw_bus_search_compatible(dev, compat_data)->ocd_data;
+
+	error = bus_alloc_resources(dev, awusbdrd_spec, sc->res);
+	if (error != 0)
+		return (error);
+
+	/* AHB gate clock is required */
+	error = clk_get_by_ofw_index(dev, 0, 0, &sc->clk);
+	if (error != 0)
+		goto fail;
+
+	/* AHB reset is only present on some SoCs */
+	(void)hwreset_get_by_ofw_idx(dev, 0, 0, &sc->reset);
+
+	/* Enable clocks */
+	error = clk_enable(sc->clk);
+	if (error != 0) {
+		device_printf(dev, "failed to enable clock: %d\n", error);
+		goto fail;
+	}
+	if (sc->reset != NULL) {
+		error = hwreset_deassert(sc->reset);
+		if (error != 0) {
+			device_printf(dev, "failed to de-assert reset: %d\n",
+			    error);
+			goto fail;
+		}
+	}
+
+	sc->sc.sc_bus.parent = dev;
+	sc->sc.sc_bus.devices = sc->sc.sc_devices;
+	sc->sc.sc_bus.devices_max = MUSB2_MAX_DEVICES;
+	sc->sc.sc_bus.dma_bits = 32;
+
+	error = usb_bus_mem_alloc_all(&sc->sc.sc_bus, USB_GET_DMA_TAG(dev),
+	    NULL);
+	if (error != 0) {
+		error = ENOMEM;
+		goto fail;
+	}
+
+#if defined(__arm__)
+	sc->bs.bs_parent = rman_get_bustag(sc->res[0]);
+#elif defined(__aarch64__)
+	sc->bs.bs_cookie = rman_get_bustag(sc->res[0]);
+#endif
+
+	if ((sc->flags & AWUSB_NO_CONFDATA) == AWUSB_NO_CONFDATA)
+		sc->bs.bs_r_1 = awusbdrd_bs_r_1_noconf;
+	else
+		sc->bs.bs_r_1 = awusbdrd_bs_r_1;
+	sc->bs.bs_r_2 = awusbdrd_bs_r_2;
+	sc->bs.bs_w_1 = awusbdrd_bs_w_1;
+	sc->bs.bs_w_2 = awusbdrd_bs_w_2;
+	sc->bs.bs_rm_1 = awusbdrd_bs_rm_1;
+	sc->bs.bs_rm_4 = awusbdrd_bs_rm_4;
+	sc->bs.bs_wm_1 = awusbdrd_bs_wm_1;
+	sc->bs.bs_wm_4 = awusbdrd_bs_wm_4;
+
+	sc->sc.sc_io_tag = &sc->bs;
+	sc->sc.sc_io_hdl = rman_get_bushandle(sc->res[0]);
+	sc->sc.sc_io_size = rman_get_size(sc->res[0]);
+
+	sc->sc.sc_bus.bdev = device_add_child(dev, "usbus", -1);
+	if (sc->sc.sc_bus.bdev == NULL) {
+		error = ENXIO;
+		goto fail;
+	}
+	device_set_ivars(sc->sc.sc_bus.bdev, &sc->sc.sc_bus);
+	sc->sc.sc_id = 0;
+	sc->sc.sc_platform_data = sc;
+	sc->sc.sc_mode = MUSB2_HOST_MODE;	/* XXX HOST vs DEVICE mode */
+	sc->sc.sc_ep_max = DRD_EP_MAX;
+	sc->sc.sc_ep_cfg = musbotg_ep_allwinner;
+
+	error = bus_setup_intr(dev, sc->res[1], INTR_MPSAFE | INTR_TYPE_BIO,
+	    NULL, awusbdrd_intr, sc, &sc->sc.sc_intr_hdl);
+	if (error != 0)
+		goto fail;
+
+	/* Enable PIO mode */
+	bus_write_1(sc->res[0], MUSB2_REG_AWIN_VEND0, VEND0_PIO_MODE);
+
+#ifdef __arm__
+	/* Map SRAMD area to USB0 (sun4i/sun7i only) */
+	switch (allwinner_soc_family()) {
+	case ALLWINNERSOC_SUN4I:
+	case ALLWINNERSOC_SUN7I:
+		a10_map_to_otg();
+		break;
+	}
+#endif
+
+	error = musbotg_init(&sc->sc);
+	if (error != 0)
+		goto fail;
+
+	error = device_probe_and_attach(sc->sc.sc_bus.bdev);
+	if (error != 0)
+		goto fail;
+
+	musbotg_vbus_interrupt(&sc->sc, 1);	/* XXX VBUS */
+
+	return (0);
+
+fail:
+	if (sc->reset != NULL)
+		hwreset_release(sc->reset);
+	if (sc->clk != NULL)
+		clk_release(sc->clk);
+	bus_release_resources(dev, awusbdrd_spec, sc->res);
+	return (error);
+}
+
+static int
+awusbdrd_detach(device_t dev)
+{
+	struct awusbdrd_softc *sc;
+	device_t bdev;
+	int error;
+
+	sc = device_get_softc(dev);
+
+	if (sc->sc.sc_bus.bdev != NULL) {
+		bdev = sc->sc.sc_bus.bdev;
+		device_detach(bdev);
+		device_delete_child(dev, bdev);
+	}
+
+	musbotg_uninit(&sc->sc);
+	error = bus_teardown_intr(dev, sc->res[1], sc->sc.sc_intr_hdl);
+	if (error != 0)
+		return (error);
+
+	usb_bus_mem_free_all(&sc->sc.sc_bus, NULL);
+
+	if (sc->reset != NULL)
+		hwreset_release(sc->reset);
+	if (sc->clk != NULL)
+		clk_release(sc->clk);
+
+	bus_release_resources(dev, awusbdrd_spec, sc->res);
+
+	device_delete_children(dev);
+
+	return (0);
+}
+
+static device_method_t awusbdrd_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,		awusbdrd_probe),
+	DEVMETHOD(device_attach,	awusbdrd_attach),
+	DEVMETHOD(device_detach,	awusbdrd_detach),
+	DEVMETHOD(device_suspend,	bus_generic_suspend),
+	DEVMETHOD(device_resume,	bus_generic_resume),
+	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
+
+	DEVMETHOD_END
+};
+
+static driver_t awusbdrd_driver = {
+	.name = "musbotg",
+	.methods = awusbdrd_methods,
+	.size = sizeof(struct awusbdrd_softc),
+};
+
+static devclass_t awusbdrd_devclass;
+
+DRIVER_MODULE(musbotg, simplebus, awusbdrd_driver, awusbdrd_devclass, 0, 0);
+MODULE_DEPEND(musbotg, usb, 1, 1, 1);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202010121051.09CApZQG075023>