]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[dwusb] Add driver for DesignWare USB3 host controller
authorMichael Brown <mcb30@ipxe.org>
Mon, 21 Jul 2025 12:44:38 +0000 (13:44 +0100)
committerMichael Brown <mcb30@ipxe.org>
Mon, 21 Jul 2025 14:55:13 +0000 (15:55 +0100)
Add a basic driver for the DesignWare USB3 host controller as found in
the Lichee Pi 4A.

This driver covers only the DesignWare host controller hardware.  On
the Lichee Pi 4A, this is sufficient to get the single USB root hub
port (exposed internally via the SODIMM connector) up and running.

The driver does not yet handle the various GPIOs that control power
and signal routing for the Lichee Pi 4A's onboard VL817 USB hub and
the four physical USB-A ports.  This therefore leaves the USB hub and
the USB-A ports unpowered, and the USB2 root hub port routed to the
physical USB-C port.  Devices plugged in to the USB-A ports will not
be powered up, and a device plugged in to the USB-C port will
enumerate as a USB2 device.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
src/drivers/usb/dwusb.c [new file with mode: 0644]
src/drivers/usb/dwusb.h [new file with mode: 0644]
src/include/ipxe/errfile.h

diff --git a/src/drivers/usb/dwusb.c b/src/drivers/usb/dwusb.c
new file mode 100644 (file)
index 0000000..1bae2ce
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2025 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <ipxe/timer.h>
+#include <ipxe/devtree.h>
+#include <ipxe/fdt.h>
+#include "dwusb.h"
+
+/** @file
+ *
+ * Synopsys DesignWare USB3 host controller driver
+ *
+ */
+
+/**
+ * Probe devicetree device
+ *
+ * @v dt               Devicetree device
+ * @v offset           Starting node offset
+ * @ret rc             Return status code
+ */
+static int dwusb_probe ( struct dt_device *dt, unsigned int offset ) {
+       struct xhci_device *xhci;
+       uint32_t gctl;
+       int rc;
+
+       /* Allocate and initialise structure */
+       xhci = zalloc ( sizeof ( *xhci ) );
+       if ( ! xhci ) {
+               rc = -ENOMEM;
+               goto err_alloc;
+       }
+       xhci->dev = &dt->dev;
+       xhci->dma = &dt->dma;
+
+       /* Map registers */
+       xhci->regs = dt_ioremap ( dt, offset, 0, 0 );
+       if ( ! xhci->regs ) {
+               rc = -ENODEV;
+               goto err_ioremap;
+       }
+
+       /* Reset via global core control register */
+       gctl = readl ( xhci->regs + DWUSB_GCTL );
+       writel ( ( gctl | DWUSB_GCTL_RESET ), ( xhci->regs + DWUSB_GCTL ) );
+       mdelay ( 100 );
+       writel ( gctl, ( xhci->regs + DWUSB_GCTL ) );
+
+       /* Configure as a host controller */
+       gctl &= ~DWUSB_GCTL_PRTDIR_MASK;
+       gctl |= DWUSB_GCTL_PRTDIR_HOST;
+       writel ( gctl, ( xhci->regs + DWUSB_GCTL ) );
+
+       /* Initialise xHCI device */
+       xhci_init ( xhci );
+
+       /* Register xHCI device */
+       if ( ( rc = xhci_register ( xhci ) ) != 0 ) {
+               DBGC ( xhci, "XHCI %s could not register: %s\n",
+                      xhci->name, strerror ( rc ) );
+               goto err_register;
+       }
+
+       dt_set_drvdata ( dt, xhci );
+       return 0;
+
+       xhci_unregister ( xhci );
+ err_register:
+       iounmap ( xhci->regs );
+ err_ioremap:
+       free ( xhci );
+ err_alloc:
+       return rc;
+}
+
+/**
+ * Remove devicetree device
+ *
+ * @v dt               Devicetree device
+ */
+static void dwusb_remove ( struct dt_device *dt ) {
+       struct xhci_device *xhci = dt_get_drvdata ( dt );
+
+       /* Unregister xHCI device */
+       xhci_unregister ( xhci );
+
+       /* Unmap registers */
+       iounmap ( xhci->regs );
+
+       /* Free device */
+       free ( xhci );
+}
+
+/** DesignWare USB3 compatible model identifiers */
+static const char * dwusb_ids[] = {
+       "snps,dwc3",
+};
+
+/** DesignWare USB3 devicetree driver */
+struct dt_driver dwusb_driver __dt_driver = {
+       .name = "dwusb",
+       .ids = dwusb_ids,
+       .id_count = ( sizeof ( dwusb_ids ) / sizeof ( dwusb_ids[0] ) ),
+       .probe = dwusb_probe,
+       .remove = dwusb_remove,
+};
diff --git a/src/drivers/usb/dwusb.h b/src/drivers/usb/dwusb.h
new file mode 100644 (file)
index 0000000..523f7ba
--- /dev/null
@@ -0,0 +1,23 @@
+#ifndef _DWUSB_H
+#define _DWUSB_H
+
+/** @file
+ *
+ * Synopsys DesignWare USB3 host controller driver
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <ipxe/xhci.h>
+
+/** Global core control register */
+#define DWUSB_GCTL 0xc110
+#define DWUSB_GCTL_PRTDIR( x ) ( (x) << 12 )   /**< Port direction */
+#define DWUSB_GCTL_PRTDIR_HOST \
+       DWUSB_GCTL_PRTDIR ( 1 )                 /**< Operate as a host */
+#define DWUSB_GCTL_PRTDIR_MASK \
+       DWUSB_GCTL_PRTDIR ( 3 )                 /**< Port direction mask */
+#define DWUSB_GCTL_RESET       0x00000800      /**< Core soft reset */
+
+#endif /* _DWUSB_H */
index 0e3634f9e6da22b3a1aa53e8fbd4e722352c0294..7db8d5679073c73ee08ca0c99e009f2305981b24 100644 (file)
@@ -237,6 +237,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 #define ERRFILE_devtree                     ( ERRFILE_DRIVER | 0x00da0000 )
 #define ERRFILE_cgem                ( ERRFILE_DRIVER | 0x00db0000 )
 #define ERRFILE_dwmac               ( ERRFILE_DRIVER | 0x00dc0000 )
+#define ERRFILE_dwusb               ( ERRFILE_DRIVER | 0x00dd0000 )
 
 #define ERRFILE_aoe                    ( ERRFILE_NET | 0x00000000 )
 #define ERRFILE_arp                    ( ERRFILE_NET | 0x00010000 )