diff --git a/src/drivers/usb/dwusb.c b/src/drivers/usb/dwusb.c new file mode 100644 index 000000000..1bae2ce74 --- /dev/null +++ b/src/drivers/usb/dwusb.c @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2025 Michael Brown . + * + * 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 +#include +#include +#include +#include +#include +#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 index 000000000..523f7ba81 --- /dev/null +++ b/src/drivers/usb/dwusb.h @@ -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 + +/** 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 */ diff --git a/src/include/ipxe/errfile.h b/src/include/ipxe/errfile.h index 0e3634f9e..7db8d5679 100644 --- a/src/include/ipxe/errfile.h +++ b/src/include/ipxe/errfile.h @@ -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 )