Add STi glue logic to manage the DWC3 HC on STiH407
SoC family. It configures the internal glue logic and
syscfg registers.

Signed-off-by: Patrice Chotard <patrice.chot...@foss.st.com>
Cc: Marek Vasut <ma...@denx.de>

---

Changes in v5:
  - reorder files entry for ARM STI in MAINTAINERS file
  - add #define LOG_CATEGORY UCLASS_NOP
  - use UCLASS_NOP instead of UCLASS_SIMPLE_BUS

Changes in v4:
  - Update Kconfig description

Changes in v3:
  - Replace debug() by dev_err()
  - check return value of syscon_regmap_lookup_by_phandle()

Changes in v2:
  - add dwc3-sti.c DWC3 wrapper as done for dwc3-am62.c

 MAINTAINERS                         |   1 +
 drivers/usb/dwc3/Kconfig            |   8 ++
 drivers/usb/dwc3/Makefile           |   1 +
 drivers/usb/dwc3/dwc3-generic-sti.c | 134 ++++++++++++++++++++++++++++
 4 files changed, 144 insertions(+)
 create mode 100644 drivers/usb/dwc3/dwc3-generic-sti.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 0e93f88c2aa..38501775890 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -657,6 +657,7 @@ F:  drivers/reset/sti-reset.c
 F:     drivers/serial/serial_sti_asc.c
 F:     drivers/sysreset/sysreset_sti.c
 F:     drivers/timer/arm_global_timer.c
+F:     drivers/usb/host/dwc3-sti.c
 F:     include/dt-bindings/clock/stih407-clks.h
 F:     include/dt-bindings/clock/stih410-clks.h
 F:     include/dt-bindings/reset/stih407-resets.h
diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig
index 0100723a68b..682a6910655 100644
--- a/drivers/usb/dwc3/Kconfig
+++ b/drivers/usb/dwc3/Kconfig
@@ -87,6 +87,14 @@ config USB_DWC3_LAYERSCAPE
          Host and Peripheral operation modes are supported. OTG is not
          supported.
 
+config USB_DWC3_STI
+       bool "STi USB wrapper"
+       depends on DM_USB && USB_DWC3_GENERIC && SYSCON
+       help
+         Enables support for the on-chip xHCI controller on STMicroelectronics
+         STiH407 family SoCs. This is a driver for the dwc3 to provide the
+         glue logic to configure the controller.
+
 menu "PHY Subsystem"
 
 config USB_DWC3_PHY_OMAP
diff --git a/drivers/usb/dwc3/Makefile b/drivers/usb/dwc3/Makefile
index a085c9d4628..985206eafe4 100644
--- a/drivers/usb/dwc3/Makefile
+++ b/drivers/usb/dwc3/Makefile
@@ -15,3 +15,4 @@ obj-$(CONFIG_USB_DWC3_UNIPHIER)               += 
dwc3-uniphier.o
 obj-$(CONFIG_USB_DWC3_LAYERSCAPE)      += dwc3-layerscape.o
 obj-$(CONFIG_USB_DWC3_PHY_OMAP)                += ti_usb_phy.o
 obj-$(CONFIG_USB_DWC3_PHY_SAMSUNG)     += samsung_usb_phy.o
+obj-$(CONFIG_USB_DWC3_STI)             += dwc3-generic-sti.o
diff --git a/drivers/usb/dwc3/dwc3-generic-sti.c 
b/drivers/usb/dwc3/dwc3-generic-sti.c
new file mode 100644
index 00000000000..b34f5ceceac
--- /dev/null
+++ b/drivers/usb/dwc3/dwc3-generic-sti.c
@@ -0,0 +1,134 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR BSD-3-Clause
+/*
+ * STi specific glue layer for DWC3
+ *
+ * Copyright (C) 2025, STMicroelectronics - All Rights Reserved
+ */
+
+#define LOG_CATEGORY UCLASS_NOP
+
+#include <reset.h>
+#include <regmap.h>
+#include <syscon.h>
+#include <asm/io.h>
+#include <dm/device.h>
+#include <dm/device_compat.h>
+#include <dm/read.h>
+#include <linux/usb/otg.h>
+#include "dwc3-generic.h"
+
+/* glue registers */
+#define CLKRST_CTRL            0x00
+#define AUX_CLK_EN             BIT(0)
+#define SW_PIPEW_RESET_N       BIT(4)
+#define EXT_CFG_RESET_N                BIT(8)
+
+#define XHCI_REVISION          BIT(12)
+
+#define USB2_VBUS_MNGMNT_SEL1  0x2C
+#define USB2_VBUS_UTMIOTG      0x1
+
+#define SEL_OVERRIDE_VBUSVALID(n)      ((n) << 0)
+#define SEL_OVERRIDE_POWERPRESENT(n)   ((n) << 4)
+#define SEL_OVERRIDE_BVALID(n)         ((n) << 8)
+
+/* Static DRD configuration */
+#define USB3_CONTROL_MASK              0xf77
+
+#define USB3_DEVICE_NOT_HOST           BIT(0)
+#define USB3_FORCE_VBUSVALID           BIT(1)
+#define USB3_DELAY_VBUSVALID           BIT(2)
+#define USB3_SEL_FORCE_OPMODE          BIT(4)
+#define USB3_FORCE_OPMODE(n)           ((n) << 5)
+#define USB3_SEL_FORCE_DPPULLDOWN2     BIT(8)
+#define USB3_FORCE_DPPULLDOWN2         BIT(9)
+#define USB3_SEL_FORCE_DMPULLDOWN2     BIT(10)
+#define USB3_FORCE_DMPULLDOWN2         BIT(11)
+
+static void dwc3_stih407_glue_configure(struct udevice *dev, int index,
+                                       enum usb_dr_mode mode)
+{
+       struct dwc3_glue_data *glue = dev_get_plat(dev);
+       struct regmap *regmap;
+       ulong syscfg_base;
+       ulong syscfg_offset;
+       ulong glue_base;
+       int ret;
+
+       /* deassert both powerdown and softreset */
+       ret = reset_deassert_bulk(&glue->resets);
+       if (ret) {
+               dev_err(dev, "reset_deassert_bulk error: %d\n", ret);
+               return;
+       }
+
+       regmap = syscon_regmap_lookup_by_phandle(dev, "st,syscfg");
+       if (IS_ERR(regmap)) {
+               dev_err(dev, "unable to get st,syscfg, dev %s\n", dev->name);
+               return;
+       }
+
+       syscfg_base = regmap->ranges[0].start;
+       glue_base = dev_read_addr_index(dev, 0);
+       syscfg_offset = dev_read_addr_index(dev, 1);
+
+       clrbits_le32(syscfg_base + syscfg_offset, USB3_CONTROL_MASK);
+
+       /* glue drd init */
+       switch (mode) {
+       case USB_DR_MODE_PERIPHERAL:
+               clrbits_le32(syscfg_base + syscfg_offset,
+                            USB3_DELAY_VBUSVALID | USB3_SEL_FORCE_OPMODE |
+                            USB3_FORCE_OPMODE(0x3) | 
USB3_SEL_FORCE_DPPULLDOWN2 |
+                            USB3_FORCE_DPPULLDOWN2 | 
USB3_SEL_FORCE_DMPULLDOWN2 |
+                            USB3_FORCE_DMPULLDOWN2);
+
+               setbits_le32(syscfg_base + syscfg_offset,
+                            USB3_DEVICE_NOT_HOST | USB3_FORCE_VBUSVALID);
+               break;
+
+       case USB_DR_MODE_HOST:
+               clrbits_le32(syscfg_base + syscfg_offset,
+                            USB3_DEVICE_NOT_HOST | USB3_FORCE_VBUSVALID |
+                            USB3_SEL_FORCE_OPMODE | USB3_FORCE_OPMODE(0x3) |
+                            USB3_SEL_FORCE_DPPULLDOWN2 | 
USB3_FORCE_DPPULLDOWN2 |
+                            USB3_SEL_FORCE_DMPULLDOWN2 | 
USB3_FORCE_DMPULLDOWN2);
+
+               setbits_le32(syscfg_base + syscfg_offset, USB3_DELAY_VBUSVALID);
+               break;
+
+       default:
+               dev_err(dev, "Unsupported mode of operation %d\n", mode);
+               return;
+       }
+
+       /* glue init */
+       setbits_le32(glue_base + CLKRST_CTRL, AUX_CLK_EN | EXT_CFG_RESET_N | 
XHCI_REVISION);
+       clrbits_le32(glue_base + CLKRST_CTRL, SW_PIPEW_RESET_N);
+
+       /* configure mux for vbus, powerpresent and bvalid signals */
+       setbits_le32(glue_base + USB2_VBUS_MNGMNT_SEL1,
+                    SEL_OVERRIDE_VBUSVALID(USB2_VBUS_UTMIOTG) |
+                    SEL_OVERRIDE_POWERPRESENT(USB2_VBUS_UTMIOTG) |
+                    SEL_OVERRIDE_BVALID(USB2_VBUS_UTMIOTG));
+       setbits_le32(glue_base + CLKRST_CTRL, SW_PIPEW_RESET_N);
+};
+
+struct dwc3_glue_ops stih407_ops = {
+       .glue_configure = dwc3_stih407_glue_configure,
+};
+
+static const struct udevice_id dwc3_sti_match[] = {
+       { .compatible = "st,stih407-dwc3", .data = (ulong)&stih407_ops},
+       { /* sentinel */ }
+};
+
+U_BOOT_DRIVER(dwc3_sti_wrapper) = {
+       .name = "dwc3-sti",
+       .id = UCLASS_NOP,
+       .of_match = dwc3_sti_match,
+       .bind = dwc3_glue_bind,
+       .probe = dwc3_glue_probe,
+       .remove = dwc3_glue_remove,
+       .plat_auto = sizeof(struct dwc3_glue_data),
+};
-- 
2.25.1

Reply via email to