From: Mark Kettenis Subject: Re: support MediaTek xHCI USB controller To: James Hastings Cc: moosetek4@gmail.com,tech@openbsd.org Date: Sun, 23 Mar 2025 15:47:43 +0100 > From: James Hastings > Date: Sat, 22 Mar 2025 16:17:49 -0400 (EDT) > > This driver configures the MediaTek xHCI controller and usb(4) bus. > It is able to activate the host ports internally, but the USB T-PHY > is not yet supported and no devices will be found during bus > explore. > > mtxhci0 at mainbus0, xHCI 0.96 > usb0 at mtxhci0: USB revision 3.0 > uhub0 at usb0 configuration 1 interface 0 "MediaTek xHCI root hub" rev 3.00/1.00 addr 1 > > For now, the PHYs can be pre-activated in firmware with a 'usb start' command. > Dmesg and sysctl hw below are obtained via netboot over USB. > > ok? A few small issues below: > Index: sys/dev/fdt/mtxhci.c > =================================================================== > RCS file: sys/dev/fdt/mtxhci.c > diff -N sys/dev/fdt/mtxhci.c > --- /dev/null 1 Jan 1970 00:00:00 -0000 > +++ sys/dev/fdt/mtxhci.c 21 Mar 2025 00:18:05 -0000 > @@ -0,0 +1,253 @@ > +/* $OpenBSD$ */ > +/* > + * Copyright (c) 2025 James Hastings > + * > + * Permission to use, copy, modify, and distribute this software for any > + * purpose with or without fee is hereby granted, provided that the above > + * copyright notice and this permission notice appear in all copies. > + * > + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES > + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF > + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR > + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES > + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN > + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF > + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. > + */ > + > +#include > +#include > +#include > + > +#include > +#include > + > +#include > +#include > +#include > +#include > +#include > + > +#include > +#include > +#include > + > +#include > +#include > + > +#define MTXHCI_MAX_PORTS 4 > + > +/* registers */ > +#define MTXHCI_RESET 0x00 > +#define RESET_ASSERT (1 << 0) > +#define MTXHCI_CFG_HOST 0x04 > +#define MTXHCI_CFG_DEV 0x08 > +#define MTXHCI_CFG_PCIE 0x0c > +#define CFG_PWRDN (1 << 0) > +#define MTXHCI_STA 0x10 > +#define STA_USB3 (1 << 16) > +#define STA_XHCI (1 << 11) > +#define STA_SYS (1 << 10) > +#define STA_REF (1 << 8) > +#define STA_PLL (1 << 0) > +#define MTXHCI_CAPS 0x24 > +#define MTXHCI_USB3_PORT(x) 0x30 + (x) * 8 > +#define MTXHCI_USB2_PORT(x) 0x50 + (x) * 8 > +#define CFG_PORT_HOST (1 << 2) > +#define CFG_PORT_PWRDN (1 << 1) > +#define CFG_PORT_DISABLE (1 << 0) > + > +#define HREAD4(sc, reg) \ > + bus_space_read_4((sc)->sc.iot, (sc)->sc_port_ioh, (reg)) > +#define HWRITE4(sc, reg, val) \ > + bus_space_write_4((sc)->sc.iot, (sc)->sc_port_ioh, (reg), (val)) > + > +struct mtxhci_softc { > + struct xhci_softc sc; > + int sc_node; > + > + bus_space_handle_t sc_port_ioh; > + bus_size_t sc_port_ios; > + int sc_port_node; > + > + int sc_ports_usb2; > + int sc_ports_usb3; > + > + void *sc_ih; > +}; > + > +int mtxhci_match(struct device *, void *, void *); > +void mtxhci_attach(struct device *, struct device *, void *); > + > +const struct cfattach mtxhci_ca = { > + sizeof(struct mtxhci_softc), mtxhci_match, mtxhci_attach > +}; > + > +struct cfdriver mtxhci_cd = { > + NULL, "mtxhci", DV_DULL > +}; > + > +int mtxhci_host_init(struct mtxhci_softc *); > + > +int > +mtxhci_match(struct device *parent, void *match, void *aux) > +{ > + struct fdt_attach_args *faa = aux; > + > + if (OF_is_compatible(faa->fa_node, "mediatek,mtk-xhci")) > + return 1; > + > + return 0; > +} > + > +void > +mtxhci_attach(struct device *parent, struct device *self, void *aux) > +{ > + struct mtxhci_softc *sc = (struct mtxhci_softc *)self; > + struct fdt_attach_args *faa = aux; > + int error = 0, idx; > + > + if (faa->fa_nreg < 2) { > + printf(": no registers\n"); > + return; > + } You don't really need this check (see below). > + > + idx = OF_getindex(faa->fa_node, "ippc", "reg-names"); > + if (idx < 0 || idx > faa->fa_nreg) { Should be: if (idx < 0 || idx >= faa->fa_nreg) { > + printf(": no registers\n"); Probably best to identify the missing register, so: printf(": no ippc registers\n"); > + return; > + } > + > + if (bus_space_map(faa->fa_iot, faa->fa_reg[idx].addr, > + faa->fa_reg[idx].size, 0, &sc->sc_port_ioh)) { > + printf(": can't map registers\n"); > + return; > + } > + > + sc->sc_port_node = faa->fa_node; > + sc->sc_port_ios = faa->fa_reg[idx].size; > + > + idx = OF_getindex(sc->sc_node, "mac", "reg-names"); > + if (idx == -1) > + idx = 0; Still need to check that idx < faa->fa_nregs, so add: if (idx < 0 || idx >= faa->fa_nregs) { printf(": no mac registers\n"); goto unmap_port; } And if you do that the check at the top becomes redundant. > + > + if (bus_space_map(faa->fa_iot, faa->fa_reg[idx].addr, > + faa->fa_reg[idx].size, 0, &sc->sc.ioh)) { > + printf(": can't map registers\n"); > + goto unmap_port; > + } > + > + sc->sc_node = faa->fa_node; > + sc->sc.iot = faa->fa_iot; > + sc->sc.sc_size = faa->fa_reg[idx].size; > + sc->sc.sc_bus.dmatag = faa->fa_dmat; > + > + sc->sc_ih = fdt_intr_establish(sc->sc_node, IPL_USB, > + xhci_intr, sc, sc->sc.sc_bus.bdev.dv_xname); > + if (sc->sc_ih == NULL) { > + printf(": can't establish interrupt\n"); > + goto unmap; > + } > + > + power_domain_enable(sc->sc_node); > + reset_deassert_all(sc->sc_node); > + clock_set_assigned(sc->sc_node); > + clock_enable_all(sc->sc_node); > + > + if ((error = mtxhci_host_init(sc)) != 0) { > + printf(": host init failed, error=%d\n", error); > + goto disestablish_ret; > + } > + > + strlcpy(sc->sc.sc_vendor, "MediaTek", sizeof(sc->sc.sc_vendor)); > + if ((error = xhci_init(&sc->sc)) != 0) { > + printf("%s: init failed, error=%d\n", > + sc->sc.sc_bus.bdev.dv_xname, error); > + goto disestablish_ret; > + } > + > + config_found(self, &sc->sc.sc_bus, usbctlprint); > + > + xhci_config(&sc->sc); > + > + return; > + > +disestablish_ret: > + fdt_intr_disestablish(sc->sc_ih); > +unmap: > + bus_space_unmap(faa->fa_iot, sc->sc.ioh, sc->sc.sc_size); > +unmap_port: > + bus_space_unmap(faa->fa_iot, sc->sc_port_ioh, sc->sc_port_ios); > +} > + > +int > +mtxhci_host_init(struct mtxhci_softc *sc) > +{ > + uint32_t mask, val; > + int i, ntries; > + > + /* port capabilities */ > + val = HREAD4(sc, MTXHCI_CAPS); > + sc->sc_ports_usb3 = MIN(MTXHCI_MAX_PORTS, val & 0x7); > + sc->sc_ports_usb2 = MIN(MTXHCI_MAX_PORTS, (val >> 8) & 0x7); Maybe add some #defines for those magic values and shifts: #define CAPS_USB3_PORTS(x) (((x) >> 0) & 0x7) #define CAPS_USB2_PORTS(x) (((x) >> 8) & 0x7) > + > + if (sc->sc_ports_usb3 == 0 && sc->sc_ports_usb2 == 0) > + return ENXIO; > + > + /* enable phys */ > + phy_enable_idx(sc->sc_port_node, -1); > + > + /* reset */ > + val = HREAD4(sc, MTXHCI_RESET); > + val |= RESET_ASSERT; > + HWRITE4(sc, MTXHCI_RESET, val); > + delay(10); > + val &= ~RESET_ASSERT; > + HWRITE4(sc, MTXHCI_RESET, val); > + delay(10); > + > + /* disable device mode */ > + val = HREAD4(sc, MTXHCI_CFG_DEV); > + val |= CFG_PWRDN; > + HWRITE4(sc, MTXHCI_CFG_DEV, val); > + > + /* enable host mode */ > + val = HREAD4(sc, MTXHCI_CFG_HOST); > + val &= ~CFG_PWRDN; > + HWRITE4(sc, MTXHCI_CFG_HOST, val); > + > + mask = (STA_XHCI | STA_PLL | STA_SYS | STA_REF); > + if (sc->sc_ports_usb3) { > + mask |= STA_USB3; > + > + /* disable PCIe mode */ > + val = HREAD4(sc, MTXHCI_CFG_PCIE); > + val |= CFG_PWRDN; > + HWRITE4(sc, MTXHCI_CFG_PCIE, val); > + } > + > + /* configure host ports */ > + for (i = 0; i < sc->sc_ports_usb3; i++) { > + val = HREAD4(sc, MTXHCI_USB3_PORT(i)); > + val &= ~(CFG_PORT_DISABLE | CFG_PORT_PWRDN); > + val |= CFG_PORT_HOST; > + HWRITE4(sc, MTXHCI_USB3_PORT(i), val); > + } > + for (i = 0; i < sc->sc_ports_usb2; i++) { > + val = HREAD4(sc, MTXHCI_USB2_PORT(i)); > + val &= ~(CFG_PORT_DISABLE | CFG_PORT_PWRDN); > + val |= CFG_PORT_HOST; > + HWRITE4(sc, MTXHCI_USB2_PORT(i), val); > + } > + > + for (ntries = 0; ntries < 100; ntries++) { > + val = HREAD4(sc, MTXHCI_STA); > + if ((val & mask) == mask) > + break; > + delay(50); > + } > + if (ntries == 100) > + return ETIMEDOUT; > + > + return 0; > +} > Index: sys/dev/fdt/files.fdt > =================================================================== > RCS file: /cvs/src/sys/dev/fdt/files.fdt,v > retrieving revision 1.206 > diff -u -p -r1.206 files.fdt > --- sys/dev/fdt/files.fdt 14 Feb 2025 03:11:05 -0000 1.206 > +++ sys/dev/fdt/files.fdt 21 Mar 2025 00:18:05 -0000 > @@ -344,6 +344,10 @@ device mtrng > attach mtrng at fdt > file dev/fdt/mtrng.c mtrng > > +device mtxhci: usbus > +attach mtxhci at fdt > +file dev/fdt/mtxhci.c mtxhci > + > device rkanxdp > attach rkanxdp at fdt > file dev/fdt/rkanxdp.c rkanxdp > Index: share/man/man4/mtxhci.4 > =================================================================== > RCS file: share/man/man4/mtxhci.4 > diff -N share/man/man4/mtxhci.4 > --- /dev/null 1 Jan 1970 00:00:00 -0000 > +++ share/man/man4/mtxhci.4 21 Mar 2025 00:18:05 -0000 > @@ -0,0 +1,49 @@ > +.\" $OpenBSD$ > +.\" > +.\" Copyright (c) 2025 James Hastings > +.\" > +.\" Permission to use, copy, modify, and distribute this software for any > +.\" purpose with or without fee is hereby granted, provided that the above > +.\" copyright notice and this permission notice appear in all copies. > +.\" > +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES > +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF > +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR > +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES > +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN > +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF > +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. > +.\" > +.Dd $Mdocdate$ > +.Dt MTXHCI 4 > +.Os > +.Sh NAME > +.Nm mtxhci > +.Nd MediaTek USB xHCI controller > +.Sh SYNOPSIS > +.Cd "mtxhci* at fdt?" > +.Cd "usb* at mtxhci?" > +.Sh DESCRIPTION > +The > +.Nm > +driver controls the interface logic and supports > +the USB eXtensible Host Controller Interface > +integrated on MediaTek SoCs. > +.Pp > +It provides an interface to > +.Xr usb 4 > +devices and supports all USB 3.0, 2.0 and 1.x device speeds. > +.Sh SEE ALSO > +.Xr intro 4 , > +.Xr usb 4 > +.Sh HISTORY > +The > +.Nm > +device driver first appeared in > +.Ox 7.7 . > +.Sh AUTHORS > +.An -nosplit > +The > +.Nm > +driver was written by > +.An James Hastings Aq Mt hastings@openbsd.org . > Index: share/man/man4/Makefile > =================================================================== > RCS file: /cvs/src/share/man/man4/Makefile,v > retrieving revision 1.859 > diff -u -p -r1.859 Makefile > --- share/man/man4/Makefile 14 Feb 2025 03:15:06 -0000 1.859 > +++ share/man/man4/Makefile 21 Mar 2025 00:18:05 -0000 > @@ -59,7 +59,7 @@ MAN= aac.4 abcrtc.4 abl.4 ac97.4 acphy.4 > mcprtc.4 mcx.4 midi.4 mii.4 mfi.4 mfii.4 mfokrtc.4 \ > mlphy.4 moscom.4 mos.4 mpe.4 mpath.4 mpi.4 mpii.4 \ > mpip.4 mpu.4 msk.4 mpw.4 msts.4 mtd.4 mtdphy.4 \ > - mtintc.4 mtio.4 mtrng.4 mtw.4 mue.4 \ > + mtintc.4 mtio.4 mtrng.4 mtw.4 mtxhci.4 mue.4 \ > multicast.4 mvclock.4 mvdog.4 mvgicp.4 mvgpio.4 mvicu.4 mviic.4 \ > mvkpcie.4 mvneta.4 mvpinctrl.4 mvpp.4 mvrng.4 mvrtc.4 mvspi.4 \ > mvtemp.4 mvsw.4 mvuart.4 myx.4 \ > Index: sys/arch/arm64/conf/GENERIC > =================================================================== > RCS file: /cvs/src/sys/arch/arm64/conf/GENERIC,v > retrieving revision 1.292 > diff -u -p -r1.292 GENERIC > --- sys/arch/arm64/conf/GENERIC 14 Feb 2025 04:56:26 -0000 1.292 > +++ sys/arch/arm64/conf/GENERIC 21 Mar 2025 00:18:05 -0000 > @@ -275,6 +275,8 @@ hitemp* at fdt? > # MediaTek SoCs > mtintc* at fdt? > mtrng* at fdt? > +mtxhci* at fdt? > +usb* at mtxhci? > > # Marvell SoCs > mvclock* at fdt? early 1 > Index: sys/arch/arm64/conf/RAMDISK > =================================================================== > RCS file: /cvs/src/sys/arch/arm64/conf/RAMDISK,v > retrieving revision 1.221 > diff -u -p -r1.221 RAMDISK > --- sys/arch/arm64/conf/RAMDISK 14 Feb 2025 04:56:26 -0000 1.221 > +++ sys/arch/arm64/conf/RAMDISK 21 Mar 2025 00:18:05 -0000 > @@ -207,6 +207,8 @@ hireset* at fdt? early 1 > # MediaTek SoCs > mtintc* at fdt? > mtrng* at fdt? > +mtxhci* at fdt? > +usb* at mtxhci? > > # Marvell SoCs > mvclock* at fdt? early 1 > Index: sys/arch/armv7/conf/GENERIC > =================================================================== > RCS file: /cvs/src/sys/arch/armv7/conf/GENERIC,v > retrieving revision 1.144 > diff -u -p -r1.144 GENERIC > --- sys/arch/armv7/conf/GENERIC 14 Feb 2025 04:56:34 -0000 1.144 > +++ sys/arch/armv7/conf/GENERIC 21 Mar 2025 00:18:05 -0000 > @@ -187,6 +187,8 @@ usb* at dwctwo? > # MediaTek SoCs > mtintc* at fdt? > mtrng* at fdt? > +mtxhci* at fdt? > +usb* at mtxhci? > > # Marvell SoC > mvacc* at fdt? early 1 > Index: sys/arch/armv7/conf/RAMDISK > =================================================================== > RCS file: /cvs/src/sys/arch/armv7/conf/RAMDISK,v > retrieving revision 1.132 > diff -u -p -r1.132 RAMDISK > --- sys/arch/armv7/conf/RAMDISK 14 Feb 2025 04:56:34 -0000 1.132 > +++ sys/arch/armv7/conf/RAMDISK 21 Mar 2025 00:18:05 -0000 > @@ -173,6 +173,8 @@ usb* at dwctwo? > # MediaTek SoCs > mtintc* at fdt? > mtrng* at fdt? > +mtxhci* at fdt? > +usb* at mtxhci? > > # Marvell SoC > mvacc* at fdt? early 1 > > > OpenBSD 7.7-beta (GENERIC.MP) #1: Mon Mar 17 18:00:11 EDT 2025 > hastings@rpi4a.moose-tek.test:/usr/src/sys/arch/arm64/compile/GENERIC.MP > real mem = 1071976448 (1022MB) > avail mem = 998187008 (951MB) > random: good seed from bootblocks > mainbus0 at root: Bananapi BPI-R64 > psci0 at mainbus0: PSCI 1.1, SMCCC 1.4, SYSTEM_SUSPEND > efi0 at mainbus0: UEFI 2.10 > efi0: Das U-Boot rev 0x20241000 > smbios0 at efi0: SMBIOS 3.7.0 > smbios0: vendor U-Boot version "2024.10-OpenWrt-r28427-6df0e3d02a" date 10/01/2024 > smbios0: mediatek mt7622-bpi-r64 > cpu0 at mainbus0 mpidr 0: ARM Cortex-A53 r0p4 > cpu0: 32KB 64b/line 2-way L1 VIPT I-cache, 32KB 64b/line 4-way L1 D-cache > cpu0: 256KB 64b/line 16-way L2 cache > cpu0: CRC32,SHA2,SHA1,AES+PMULL,ASID16 > cpu1 at mainbus0 mpidr 1: ARM Cortex-A53 r0p4 > cpu1: 32KB 64b/line 2-way L1 VIPT I-cache, 32KB 64b/line 4-way L1 D-cache > cpu1: 256KB 64b/line 16-way L2 cache > "ramoops" at mainbus0 not configured > "secmon" at mainbus0 not configured > apm0 at mainbus0 > syscon0 at mainbus0: "infracfg" > syscon1 at mainbus0: "pericfg" > syscon2 at mainbus0: "power-controller" > ampintc0 at mainbus0 nirq 288, ncpu 4 ipi: 0, 1, 2: "interrupt-controller" > syscon3 at mainbus0: "clock-controller" > syscon4 at mainbus0: "pciecfg" > syscon5 at mainbus0: "clock-controller" > syscon6 at mainbus0: "pcie-mirror" > syscon7 at mainbus0: "wed" > syscon8 at mainbus0: "wed" > syscon9 at mainbus0: "sgmiisys" > "opp-table" at mainbus0 not configured > "dummy40m" at mainbus0 not configured > "oscillator" at mainbus0 not configured > "pmu" at mainbus0 not configured > agtimer0 at mainbus0: 12500 kHz > "pwrap" at mainbus0 not configured > "ir-receiver" at mainbus0 not configured > mtintc0 at mainbus0 nirq 256 > "efuse" at mainbus0 not configured > "clock-controller" at mainbus0 not configured > "clock-controller" at mainbus0 not configured > mtrng0 at mainbus0 > "pinctrl" at mainbus0 not configured > "watchdog" at mainbus0 not configured > "rtc" at mainbus0 not configured > "cci" at mainbus0 not configured > "adc" at mainbus0 not configured > com0 at mainbus0: ns16550a, 16 byte fifo > com0: console > "pwm" at mainbus0 not configured > "i2c" at mainbus0 not configured > "i2c" at mainbus0 not configured > "spi" at mainbus0 not configured > "thermal" at mainbus0 not configured > "serial" at mainbus0 not configured > "spi" at mainbus0 not configured > "ecc" at mainbus0 not configured > "mmc" at mainbus0 not configured > "mmc" at mainbus0 not configured > "wmac" at mainbus0 not configured > "clock-controller" at mainbus0 not configured > mtxhci0 at mainbus0, xHCI 0.96 > usb0 at mtxhci0: USB revision 3.0 > uhub0 at usb0 configuration 1 interface 0 "MediaTek xHCI root hub" rev 3.00/1.00 addr 1 > "t-phy" at mainbus0 not configured > "clock-controller" at mainbus0 not configured > "pcie" at mainbus0 not configured > "pcie" at mainbus0 not configured > "clock-controller" at mainbus0 not configured > "dma-controller" at mainbus0 not configured > "ethernet" at mainbus0 not configured > gpiokeys0 at mainbus0: "factory", "wps" > gpioleds0 at mainbus0: "bpi-r64:pio:green", "bpi-r64:pio:red" > "regulator-1p8v" at mainbus0 not configured > "regulator-3p3v" at mainbus0 not configured > "regulator-5v" at mainbus0 not configured > ure0 at uhub0 port 1 configuration 1 interface 0 "Realtek USB 10/100/1000 LAN" rev 3.00/31.00 addr 2 > ure0: RTL8153B (0x6010), address 00:05:1b:db:11:26 > rgephy0 at ure0 phy 0: RTL8251, rev. 0 > vscsi0 at root > scsibus0 at vscsi0: 256 targets > softraid0 at root > scsibus1 at softraid0: 256 targets > root device: ure0 > nfs_boot: using interface ure0, with revarp & bootparams > nfs_boot: client_addr=192.168.3.94 > nfs_boot: server_addr=192.168.3.1 hostname=r64 > root on 192.168.3.1:/_nfs/_root-arm64 > WARNING: CHECK AND RESET THE DATE! > swap on 192.168.3.1:/_nfs/swap > cpu0: clock not implemented > > hw.machine=arm64 > hw.model=ARM Cortex-A53 r0p4 > hw.ncpu=2 > hw.byteorder=1234 > hw.pagesize=4096 > hw.disknames= > hw.diskcount=0 > hw.cpuspeed=0 > hw.vendor=mediatek > hw.product=mt7622-bpi-r64 > hw.physmem=1071976448 > hw.usermem=1071972352 > hw.ncpufound=2 > hw.allowpowerdown=1 > hw.smt=0 > hw.ncpuonline=2 > hw.power=1 > hw.ucomnames= > >