U-Boot Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 00/12] drivers: Driver support for ADI SC5xx SoCs
@ 2025-02-26 17:30 Greg Malysa
  2025-02-26 17:30 ` [PATCH v3 01/12] pinctrl: Add support for ADI SC5XX-family pinctrl Greg Malysa
                   ` (12 more replies)
  0 siblings, 13 replies; 16+ messages in thread
From: Greg Malysa @ 2025-02-26 17:30 UTC (permalink / raw)
  To: u-boot
  Cc: adsp-linux, Greg Malysa, Angelo Dureghello, Arturs Artamonovs,
	Bastien Curutchet, Billy Tsai, Boon Khai Ng, Caleb Connolly,
	Christophe Leroy, Christophe ROULLIER, David Virag,
	Devarsh Thakkar, Erik Schumacher, Fabio Estevam, Gabor Juhos,
	Greg Malysa, Hanyuan Zhao, Heiko Schocher, Heinrich Schuchardt,
	Ian Roberts, Ilias Apalodimas, Jaehoon Chung, Jagan Teki,
	Jerome Forissier, Jim Liu, Joe Hershberger, John Watts,
	Jonas Karlman, Kongyang Liu, Leo Yu-Chi Liang, Linus Walleij,
	MD Danish Anwar, Maksim Kiselev, Marek Behún, Marek Vasut,
	Markus Gothe, Mattijs Korpershoek, Michal Simek,
	Nathan Barrett-Morrison, Neil Armstrong, Oliver Gaskell,
	Patrice Chotard, Paul Barker, Paul Kocialkowski, Peng Fan,
	Peter Robinson, Philip Oberfichtner, Piotr Wojtaszczyk,
	Quentin Schulz, Ramon Fried, Rasmus Villemoes, Ravi Gunasekaran,
	Robert Marko, Romain Naour, Sam Protsenko, Simon Glass,
	Stefan Roese, Tom Rini, Utsav Agarwal, Vasileios Bimpikas,
	Venkatesh Yadav Abbarapu, Weijie Gao, Ye Li


This series adds all of the supported peripheral drivers for the sc5xx
series of SoCs from Analog Devices and other drivers that are used by
the evaluation kits, such as a GPIO expander used by the EZLITE carrier
boards. This series passes gitlab CI tests.

Changes in v3:
- Add check if PORT peripheral base address was mapped successfully
- replace read*/write* with ioread* and iowrite* and friends across all
  drivers
- update for compatibility with changes to dwc qos driver between 2024.04
  and 2025.01
- (spi) Primarily addressed issues identified in earlier feedback:
  - Removed unused pins and memory_map priv members
  - Added __iomem to device mmio pointers
  - Replaced readl/writel calls with iowrite32/ioread32 and friends
  - Added map_sysmem() call to prepare device mmio pointer
- (sdhci) Removed struct adi_sdhc and replaced with the struct that was its
  only member

Changes in v2:
- Clean up some whitespace errors
- Modify Kconfigs to reflect changes to mach-sc5xx/Kconfig

Greg Malysa (5):
  pinctrl: Add support for ADI SC5XX-family pinctrl
  doc: Add dt-bindings and descriptions for ADI SC5xx-family pinctrl
  gpio: Add support for SC5XX-family processor GPIO driver
  net: Add support for ADI SC5xx SoCs with DWC QoS ethernet
  dma: Add driver for ADI SC5xx-family SoC MDMA functionality

Nathan Barrett-Morrison (7):
  gpio: Add support for ADI ADP5588 GPIO expander chips
  usb: musb-new: Add support for Analog Devices SC5xx SoCs
  i2c: Add support for ADI SC5XX-family I2C peripheral
  watchdog: Add support for ADI SC5XX-family watchdog peripheral
  remoteproc: Add in SHARC loading for ADI SC5XX-family processors
  spi: Add support for ADI SC5XX-family processor SPI peripherals
  mmc: Add support for ADI SC5XX-family processor SDHCI peripherals

 MAINTAINERS                                   |  13 +
 .../pinctrl/adi,adsp-pinctrl.yaml             |  73 ++
 drivers/dma/Kconfig                           |   7 +
 drivers/dma/Makefile                          |   1 +
 drivers/dma/adi_dma.c                         | 253 +++++++
 drivers/gpio/Kconfig                          |  17 +
 drivers/gpio/Makefile                         |   2 +
 drivers/gpio/adp5588_gpio.c                   | 208 ++++++
 drivers/gpio/gpio-adi-adsp.c                  | 179 +++++
 drivers/i2c/Kconfig                           |   7 +
 drivers/i2c/Makefile                          |   1 +
 drivers/i2c/adi_i2c.c                         | 386 ++++++++++
 drivers/mmc/Kconfig                           |   9 +
 drivers/mmc/Makefile                          |   1 +
 drivers/mmc/adi_sdhci.c                       | 148 ++++
 drivers/net/Kconfig                           |   7 +
 drivers/net/Makefile                          |   1 +
 drivers/net/dwc_eth_qos.c                     |   6 +
 drivers/net/dwc_eth_qos.h                     |   2 +
 drivers/net/dwc_eth_qos_adi.c                 | 103 +++
 drivers/pinctrl/Kconfig                       |   8 +
 drivers/pinctrl/Makefile                      |   1 +
 drivers/pinctrl/pinctrl-adi-adsp.c            | 161 +++++
 drivers/remoteproc/Kconfig                    |  11 +
 drivers/remoteproc/Makefile                   |   1 +
 drivers/remoteproc/adi_sc5xx_rproc.c          | 277 +++++++
 drivers/spi/Kconfig                           |   7 +
 drivers/spi/Makefile                          |   1 +
 drivers/spi/adi_spi3.c                        | 679 ++++++++++++++++++
 drivers/usb/musb-new/Kconfig                  |   7 +
 drivers/usb/musb-new/Makefile                 |   1 +
 drivers/usb/musb-new/sc5xx.c                  | 202 ++++++
 drivers/watchdog/Kconfig                      |   9 +
 drivers/watchdog/Makefile                     |   1 +
 drivers/watchdog/adi_wdt.c                    | 143 ++++
 include/dt-bindings/pinctrl/adi-adsp.h        |  21 +
 36 files changed, 2954 insertions(+)
 create mode 100644 doc/device-tree-bindings/pinctrl/adi,adsp-pinctrl.yaml
 create mode 100644 drivers/dma/adi_dma.c
 create mode 100644 drivers/gpio/adp5588_gpio.c
 create mode 100644 drivers/gpio/gpio-adi-adsp.c
 create mode 100644 drivers/i2c/adi_i2c.c
 create mode 100644 drivers/mmc/adi_sdhci.c
 create mode 100644 drivers/net/dwc_eth_qos_adi.c
 create mode 100644 drivers/pinctrl/pinctrl-adi-adsp.c
 create mode 100644 drivers/remoteproc/adi_sc5xx_rproc.c
 create mode 100644 drivers/spi/adi_spi3.c
 create mode 100644 drivers/usb/musb-new/sc5xx.c
 create mode 100644 drivers/watchdog/adi_wdt.c
 create mode 100644 include/dt-bindings/pinctrl/adi-adsp.h

-- 
2.45.2


^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH v3 01/12] pinctrl: Add support for ADI SC5XX-family pinctrl
  2025-02-26 17:30 [PATCH v3 00/12] drivers: Driver support for ADI SC5xx SoCs Greg Malysa
@ 2025-02-26 17:30 ` Greg Malysa
  2025-02-26 17:30 ` [PATCH v3 02/12] doc: Add dt-bindings and descriptions for ADI SC5xx-family pinctrl Greg Malysa
                   ` (11 subsequent siblings)
  12 siblings, 0 replies; 16+ messages in thread
From: Greg Malysa @ 2025-02-26 17:30 UTC (permalink / raw)
  To: u-boot
  Cc: adsp-linux, Greg Malysa, Nathan Barrett-Morrison, Ian Roberts,
	Vasileios Bimpikas, Utsav Agarwal, Arturs Artamonovs,
	Oliver Gaskell, Caleb Connolly, Greg Malysa, Marek Vasut,
	Mattijs Korpershoek, Paul Kocialkowski, Quentin Schulz,
	Robert Marko, Sam Protsenko, Simon Glass, Tom Rini

This adds support for pin configuration on the Analog Devices SC5XX SoC
family. This commit is largely a port of the Linux driver, which has not
yet been submitted upstream.

Co-developed-by: Nathan Barrett-Morrison <nathan.morrison@timesys.com>
Signed-off-by: Nathan Barrett-Morrison <nathan.morrison@timesys.com>
Co-developed-by: Ian Roberts <ian.roberts@timesys.com>
Signed-off-by: Ian Roberts <ian.roberts@timesys.com>
Signed-off-by: Vasileios Bimpikas <vasileios.bimpikas@analog.com>
Signed-off-by: Utsav Agarwal <utsav.agarwal@analog.com>
Signed-off-by: Arturs Artamonovs <arturs.artamonovs@analog.com>
Signed-off-by: Oliver Gaskell <Oliver.Gaskell@analog.com>
Signed-off-by: Greg Malysa <malysagreg@gmail.com>

---

Changes in v3:
- Add check if PORT peripheral base address was mapped successfully

Changes in v2:
- Clean up some whitespace errors
- Modify Kconfigs to reflect changes to mach-sc5xx/Kconfig


---
 MAINTAINERS                        |   1 +
 drivers/pinctrl/Kconfig            |   8 ++
 drivers/pinctrl/Makefile           |   1 +
 drivers/pinctrl/pinctrl-adi-adsp.c | 161 +++++++++++++++++++++++++++++
 4 files changed, 171 insertions(+)
 create mode 100644 drivers/pinctrl/pinctrl-adi-adsp.c

diff --git a/MAINTAINERS b/MAINTAINERS
index c1851280e6e..af8d0b7d5e9 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -631,6 +631,7 @@ F:	doc/device-tree-bindings/arm/adi/adi,sc5xx.yaml
 F:	doc/device-tree-bindings/clock/adi,sc5xx-clocks.yaml
 F:	doc/device-tree-bindings/timer/adi,sc5xx-gptimer.yaml
 F:	drivers/clk/adi/
+F:	drivers/pinctrl/pinctrl-adi-adsp.c
 F:	drivers/serial/serial_adi_uart4.c
 F:	drivers/timer/adi_sc5xx_timer.c
 F:	include/configs/sc5*
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index 6ee7dc1cce8..687fb339ea0 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -178,6 +178,14 @@ config PINCTRL_APPLE
 	  both the GPIO definitions and pin control functions for each
 	  available multiplex function.
 
+config PINCTRL_ADI
+	bool "ADI pinctrl driver"
+	depends on DM && ARCH_SC5XX
+	help
+	  This driver enables pinctrl support on SC5xx processors. This
+	  driver covers only the pin configuration functionality, and
+	  GPIO functionality is contained in the separate GPIO driver.
+
 config PINCTRL_AR933X
 	bool "QCA/Athores ar933x pin control driver"
 	depends on DM && SOC_AR933X
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index 634047a91f4..e3a82b12c78 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -3,6 +3,7 @@
 obj-y					+= pinctrl-uclass.o
 obj-$(CONFIG_$(XPL_)PINCTRL_GENERIC)	+= pinctrl-generic.o
 
+obj-$(CONFIG_PINCTRL_ADI)		+= pinctrl-adi-adsp.o
 obj-$(CONFIG_PINCTRL_APPLE)		+= pinctrl-apple.o
 obj-$(CONFIG_PINCTRL_AT91)		+= pinctrl-at91.o
 obj-$(CONFIG_PINCTRL_AT91PIO4)		+= pinctrl-at91-pio4.o
diff --git a/drivers/pinctrl/pinctrl-adi-adsp.c b/drivers/pinctrl/pinctrl-adi-adsp.c
new file mode 100644
index 00000000000..debf434212d
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-adi-adsp.c
@@ -0,0 +1,161 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * (C) Copyright 2022 - Analog Devices, Inc.
+ *
+ * Written and/or maintained by Timesys Corporation
+ *
+ * Author: Greg Malysa <greg.malysa@timesys.com>
+ * Additional Contact: Nathan Barrett-Morrison <nathan.morrison@timesys.com>
+ *
+ * dm pinctrl implementation for ADI ADSP SoCs
+ *
+ */
+
+#include <dm.h>
+#include <dm/pinctrl.h>
+#include <dm/device_compat.h>
+#include <linux/bitops.h>
+#include <linux/io.h>
+
+#define ADSP_PORT_MMIO_SIZE		0x80
+#define ADSP_PORT_PIN_SIZE		16
+
+#define ADSP_PORT_PORT_MUX_BITS		2
+#define ADSP_PORT_PORT_MUX_MASK		0x03
+#define ADSP_PINCTRL_FUNCTION_COUNT 4
+
+#define ADSP_PORT_REG_FER			0x00
+#define ADSP_PORT_REG_FER_SET		0x04
+#define ADSP_PORT_REG_FER_CLEAR		0x08
+#define ADSP_PORT_REG_DATA			0x0c
+#define ADSP_PORT_REG_DATA_SET		0x10
+#define ADSP_PORT_REG_DATA_CLEAR	0x14
+#define ADSP_PORT_REG_DIR			0x18
+#define ADSP_PORT_REG_DIR_SET		0x1c
+#define ADSP_PORT_REG_DIR_CLEAR		0x20
+#define ADSP_PORT_REG_INEN			0x24
+#define ADSP_PORT_REG_INEN_SET		0x28
+#define ADSP_PORT_REG_INEN_CLEAR	0x2c
+#define ADSP_PORT_REG_PORT_MUX		0x30
+#define ADSP_PORT_REG_DATA_TGL		0x34
+#define ADSP_PORT_REG_POLAR			0x38
+#define ADSP_PORT_REG_POLAR_SET		0x3c
+#define ADSP_PORT_REG_POLAR_CLEAR	0x40
+#define ADSP_PORT_REG_LOCK			0x44
+#define ADSP_PORT_REG_TRIG_TGL		0x48
+
+struct adsp_pinctrl_priv {
+	void __iomem *base;
+	int npins;
+	char pinbuf[16];
+};
+
+static u32 get_port(unsigned int pin)
+{
+	return pin / ADSP_PORT_PIN_SIZE;
+}
+
+static u32 get_offset(unsigned int pin)
+{
+	return pin % ADSP_PORT_PIN_SIZE;
+}
+
+static int adsp_pinctrl_pinmux_set(struct udevice *udev, unsigned int pin, unsigned int func)
+{
+	struct adsp_pinctrl_priv *priv = dev_get_priv(udev);
+	void __iomem *portbase;
+	u32 port, offset;
+	u32 val;
+
+	if (pin >= priv->npins)
+		return -ENODEV;
+
+	if (func >= ADSP_PINCTRL_FUNCTION_COUNT)
+		return -EINVAL;
+
+	port = get_port(pin);
+	offset = get_offset(pin);
+	portbase = priv->base + port * ADSP_PORT_MMIO_SIZE;
+
+	val = ioread32(portbase + ADSP_PORT_REG_PORT_MUX);
+	val &= ~(ADSP_PORT_PORT_MUX_MASK << (ADSP_PORT_PORT_MUX_BITS * offset));
+	val |= func << (ADSP_PORT_PORT_MUX_BITS * offset);
+	iowrite32(val, portbase + ADSP_PORT_REG_PORT_MUX);
+
+	iowrite32(BIT(offset), portbase + ADSP_PORT_REG_FER_SET);
+	return 0;
+}
+
+static int adsp_pinctrl_set_state(struct udevice *udev, struct udevice *config)
+{
+	const struct fdt_property *pinlist;
+	int length = 0;
+	int ret, i;
+	u32 pin, function;
+
+	pinlist = dev_read_prop(config, "adi,pins", &length);
+	if (!pinlist) {
+		dev_err(udev, "missing adi,pins property in pinctrl config node\n");
+		return -EINVAL;
+	}
+
+	if (length % (sizeof(uint32_t) * 2)) {
+		dev_err(udev, "adi,pins property must be a multiple of two uint32_ts\n");
+		return -EINVAL;
+	}
+
+	for (i = 0; i < length / sizeof(uint32_t); i += 2) {
+		ret = dev_read_u32_index(config, "adi,pins", i, &pin);
+		if (ret)
+			return ret;
+
+		ret = dev_read_u32_index(config, "adi,pins", i + 1, &function);
+		if (ret)
+			return ret;
+
+		ret = adsp_pinctrl_pinmux_set(udev, pin, function);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+const struct pinctrl_ops adsp_pinctrl_ops = {
+	.set_state = adsp_pinctrl_set_state,
+};
+
+static int adsp_pinctrl_probe(struct udevice *udev)
+{
+	struct adsp_pinctrl_priv *priv = dev_get_priv(udev);
+
+	priv->base = dev_read_addr_ptr(udev);
+	priv->npins = dev_read_u32_default(udev, "adi,npins", 0);
+
+	if (!priv->base) {
+		dev_err(udev, "Missing or invalid pinctrl base address\n");
+		return -ENOENT;
+	}
+
+	if (!priv->npins) {
+		dev_err(udev, "Missing adi,npins property!\n");
+		return -ENOENT;
+	}
+
+	return 0;
+}
+
+static const struct udevice_id adsp_pinctrl_match[] = {
+	{ .compatible = "adi,adsp-pinctrl" },
+	{ },
+};
+
+U_BOOT_DRIVER(adi_adsp_pinctrl) = {
+	.name = "adi_adsp_pinctrl",
+	.id = UCLASS_PINCTRL,
+	.of_match = adsp_pinctrl_match,
+	.probe = adsp_pinctrl_probe,
+	.priv_auto = sizeof(struct adsp_pinctrl_priv),
+	.ops = &adsp_pinctrl_ops,
+	.flags = DM_FLAG_PRE_RELOC,
+};
-- 
2.45.2


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v3 02/12] doc: Add dt-bindings and descriptions for ADI SC5xx-family pinctrl
  2025-02-26 17:30 [PATCH v3 00/12] drivers: Driver support for ADI SC5xx SoCs Greg Malysa
  2025-02-26 17:30 ` [PATCH v3 01/12] pinctrl: Add support for ADI SC5XX-family pinctrl Greg Malysa
@ 2025-02-26 17:30 ` Greg Malysa
  2025-02-26 17:30 ` [PATCH v3 03/12] gpio: Add support for SC5XX-family processor GPIO driver Greg Malysa
                   ` (10 subsequent siblings)
  12 siblings, 0 replies; 16+ messages in thread
From: Greg Malysa @ 2025-02-26 17:30 UTC (permalink / raw)
  To: u-boot
  Cc: adsp-linux, Greg Malysa, Vasileios Bimpikas, Utsav Agarwal,
	Arturs Artamonovs, Caleb Connolly, Greg Malysa, Ian Roberts,
	Mattijs Korpershoek, Nathan Barrett-Morrison, Oliver Gaskell,
	Robert Marko, Sam Protsenko, Simon Glass, Tom Rini

This adds the necessary dt-bindings and documentation to use the ADI
SC5xx pinctrl driver in a device tree. It is not yet available upstream
in the Linux kernel. Eventually, it will be moved there.

Signed-off-by: Vasileios Bimpikas <vasileios.bimpikas@analog.com>
Signed-off-by: Utsav Agarwal <utsav.agarwal@analog.com>
Signed-off-by: Arturs Artamonovs <arturs.artamonovs@analog.com>
Signed-off-by: Greg Malysa <malysagreg@gmail.com>
---

(no changes since v1)

 MAINTAINERS                                   |  2 +
 .../pinctrl/adi,adsp-pinctrl.yaml             | 73 +++++++++++++++++++
 include/dt-bindings/pinctrl/adi-adsp.h        | 21 ++++++
 3 files changed, 96 insertions(+)
 create mode 100644 doc/device-tree-bindings/pinctrl/adi,adsp-pinctrl.yaml
 create mode 100644 include/dt-bindings/pinctrl/adi-adsp.h

diff --git a/MAINTAINERS b/MAINTAINERS
index af8d0b7d5e9..abdb418b599 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -629,12 +629,14 @@ F:	arch/arm/mach-sc5xx/
 F:	board/adi/
 F:	doc/device-tree-bindings/arm/adi/adi,sc5xx.yaml
 F:	doc/device-tree-bindings/clock/adi,sc5xx-clocks.yaml
+F:	doc/device-tree-bindings/pinctrl/adi,adsp-pinctrl.yaml
 F:	doc/device-tree-bindings/timer/adi,sc5xx-gptimer.yaml
 F:	drivers/clk/adi/
 F:	drivers/pinctrl/pinctrl-adi-adsp.c
 F:	drivers/serial/serial_adi_uart4.c
 F:	drivers/timer/adi_sc5xx_timer.c
 F:	include/configs/sc5*
+F:	include/dt-bindings/pinctrl/adi-adsp.h
 F:	include/env/adi/
 
 ARM SNAPDRAGON
diff --git a/doc/device-tree-bindings/pinctrl/adi,adsp-pinctrl.yaml b/doc/device-tree-bindings/pinctrl/adi,adsp-pinctrl.yaml
new file mode 100644
index 00000000000..418ebd5ce41
--- /dev/null
+++ b/doc/device-tree-bindings/pinctrl/adi,adsp-pinctrl.yaml
@@ -0,0 +1,73 @@
+# SPDX-License-Identifier: (GPL-2.0+ OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pinctrl/adi,adsp-pinctrl.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Pinctrl Driver for Analog Devices SC5xx Processors
+
+maintainers:
+  - Vasileios Bimpikas <vasileios.bimpikas@analog.com>
+  - Utsav Agarwal <utsav.agarwal@analog.com>
+  - Arturs Artamonovs <arturs.artamonovs@analog.com>
+
+description: |
+  This driver provides an interface for performing pin configuration
+  Analog Devices SoCs using the ADSP PORT hardware for pin
+  configuration according to the HRM. Currently this is only the
+  SC5xx series.
+
+properties:
+  compatible:
+    const: adi,adsp-pinctrl
+
+  reg:
+    maxItems: 1
+
+  adi,npins:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description:
+      Total number of pins available to this SoC's pin controller,
+      found in the HRM.
+
+patternProperties:
+  '_pins$':
+    type: object
+
+    properties:
+      adi,pins:
+        $ref: /schemas/types.yaml#/definitions/uint32-array
+        description:
+          For n pins, 2n values must be provided as a sequence of pin
+          name as identified with the ADI_ADSP_PIN() macro and a pin
+          function constant, both defined in
+          include/dt-bindings/pinctrl/adi-adsp.h.
+
+    required:
+     - adi,pins
+
+    additionalProperties: false
+
+required:
+  - compatible
+  - reg
+  - adi,npins
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/pinctrl/adi-adsp.h>
+
+    soc {
+      pinctrl0: pinctrl@0x31004000 {
+        compatible = "adi,adsp-pinctrl";
+        reg = <0x31004000 0x500>;
+        adi,npins = <135>;
+        uart0_default: uart0_pins {
+          adi,pins = <ADI_ADSP_PIN('A', 6) ADI_ADSP_PINFUNC_ALT1>,
+                     <ADI_ADSP_PIN('A', 7) ADI_ADSP_PINFUNC_ALT1>;
+        };
+      };
+
+    };
diff --git a/include/dt-bindings/pinctrl/adi-adsp.h b/include/dt-bindings/pinctrl/adi-adsp.h
new file mode 100644
index 00000000000..7dc8a1ef5c4
--- /dev/null
+++ b/include/dt-bindings/pinctrl/adi-adsp.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * (C) Copyright 2022 - Analog Devices, Inc.
+ *
+ * Written and/or maintained by Timesys Corporation
+ *
+ * Contact: Nathan Barrett-Morrison <nathan.morrison@timesys.com>
+ * Contact: Greg Malysa <greg.malysa@timesys.com>
+ *
+ */
+
+#ifndef DT_BINDINGS_PINCTRL_ADI_ADSP
+#define DT_BINDINGS_PINCTRL_ADI_ADSP
+
+#define ADI_ADSP_PIN(port, pin) (16 * ((port) - 'A') + (pin))
+#define ADI_ADSP_PINFUNC_ALT0 0
+#define ADI_ADSP_PINFUNC_ALT1 1
+#define ADI_ADSP_PINFUNC_ALT2 2
+#define ADI_ADSP_PINFUNC_ALT3 3
+
+#endif
-- 
2.45.2


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v3 03/12] gpio: Add support for SC5XX-family processor GPIO driver
  2025-02-26 17:30 [PATCH v3 00/12] drivers: Driver support for ADI SC5xx SoCs Greg Malysa
  2025-02-26 17:30 ` [PATCH v3 01/12] pinctrl: Add support for ADI SC5XX-family pinctrl Greg Malysa
  2025-02-26 17:30 ` [PATCH v3 02/12] doc: Add dt-bindings and descriptions for ADI SC5xx-family pinctrl Greg Malysa
@ 2025-02-26 17:30 ` Greg Malysa
  2025-02-26 17:30 ` [PATCH v3 04/12] gpio: Add support for ADI ADP5588 GPIO expander chips Greg Malysa
                   ` (9 subsequent siblings)
  12 siblings, 0 replies; 16+ messages in thread
From: Greg Malysa @ 2025-02-26 17:30 UTC (permalink / raw)
  To: u-boot
  Cc: adsp-linux, Greg Malysa, Nathan Barrett-Morrison, Ian Roberts,
	Vasileios Bimpikas, Utsav Agarwal, Arturs Artamonovs,
	Oliver Gaskell, Billy Tsai, Caleb Connolly, Greg Malysa, Jim Liu,
	Marek Behún, Marek Vasut, Mattijs Korpershoek, Michal Simek,
	Piotr Wojtaszczyk, Robert Marko, Sam Protsenko, Simon Glass,
	Tom Rini, Ye Li

This adds support for using the GPIO pins on the SC5XX family of SoCs
from Analog Devices.

Co-developed-by: Nathan Barrett-Morrison <nathan.morrison@timesys.com>
Signed-off-by: Nathan Barrett-Morrison <nathan.morrison@timesys.com>
Co-developed-by: Ian Roberts <ian.roberts@timesys.com>
Signed-off-by: Ian Roberts <ian.roberts@timesys.com>
Signed-off-by: Vasileios Bimpikas <vasileios.bimpikas@analog.com>
Signed-off-by: Utsav Agarwal <utsav.agarwal@analog.com>
Signed-off-by: Arturs Artamonovs <arturs.artamonovs@analog.com>
Signed-off-by: Oliver Gaskell <Oliver.Gaskell@analog.com>
Signed-off-by: Greg Malysa <malysagreg@gmail.com>
---

(no changes since v1)

 MAINTAINERS                  |   1 +
 drivers/gpio/Kconfig         |   9 ++
 drivers/gpio/Makefile        |   1 +
 drivers/gpio/gpio-adi-adsp.c | 179 +++++++++++++++++++++++++++++++++++
 4 files changed, 190 insertions(+)
 create mode 100644 drivers/gpio/gpio-adi-adsp.c

diff --git a/MAINTAINERS b/MAINTAINERS
index abdb418b599..5c16c8f6646 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -632,6 +632,7 @@ F:	doc/device-tree-bindings/clock/adi,sc5xx-clocks.yaml
 F:	doc/device-tree-bindings/pinctrl/adi,adsp-pinctrl.yaml
 F:	doc/device-tree-bindings/timer/adi,sc5xx-gptimer.yaml
 F:	drivers/clk/adi/
+F:	drivers/gpio/gpio-adi-adsp.c
 F:	drivers/pinctrl/pinctrl-adi-adsp.c
 F:	drivers/serial/serial_adi_uart4.c
 F:	drivers/timer/adi_sc5xx_timer.c
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index f4a453e1cdd..00b01f5f09e 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -97,6 +97,15 @@ config SPL_DM_GPIO_LOOKUP_LABEL
 	  different gpios on different hardware versions
 	  for the same functionality in board code.
 
+config ADI_GPIO
+	bool "ADI GPIO driver"
+	depends on DM_GPIO && ARCH_SC5XX
+	help
+	  This driver supports GPIO banks on SC5xx processors. It
+	  supports inputs and outputs but does not support pin
+	  interrupt functionality (PINT) or other features in the
+	  Linux version of the driver.
+
 config ALTERA_PIO
 	bool "Altera PIO driver"
 	depends on DM_GPIO
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 3f882c065d8..e25ede1813c 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_$(PHASE_)DM_GPIO) += gpio-uclass.o
 
 obj-$(CONFIG_$(XPL_)DM_PCA953X)	+= pca953x_gpio.o
 
+obj-$(CONFIG_ADI_GPIO)		+= gpio-adi-adsp.o
 obj-$(CONFIG_ASPEED_GPIO)	+= gpio-aspeed.o
 obj-$(CONFIG_ASPEED_G7_GPIO)	+= gpio-aspeed-g7.o
 obj-$(CONFIG_ASPEED_SGPIO)	+= gpio-aspeed-sgpio.o
diff --git a/drivers/gpio/gpio-adi-adsp.c b/drivers/gpio/gpio-adi-adsp.c
new file mode 100644
index 00000000000..0ce00572e08
--- /dev/null
+++ b/drivers/gpio/gpio-adi-adsp.c
@@ -0,0 +1,179 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * (C) Copyright 2022 - Analog Devices, Inc.
+ *
+ * Written and/or maintained by Timesys Corporation
+ *
+ * Author: Greg Malysa <greg.malysa@timesys.com>
+ * Additional Contact: Nathan Barrett-Morrison <nathan.morrison@timesys.com>
+ */
+
+#include <dm.h>
+#include <asm-generic/gpio.h>
+#include <dm/device_compat.h>
+#include <linux/bitops.h>
+#include <linux/io.h>
+
+#define ADSP_PORT_MMIO_SIZE		0x80
+#define ADSP_PORT_PIN_SIZE		16
+
+#define ADSP_PORT_REG_FER			0x00
+#define ADSP_PORT_REG_FER_SET		0x04
+#define ADSP_PORT_REG_FER_CLEAR		0x08
+#define ADSP_PORT_REG_DATA			0x0c
+#define ADSP_PORT_REG_DATA_SET		0x10
+#define ADSP_PORT_REG_DATA_CLEAR	0x14
+#define ADSP_PORT_REG_DIR			0x18
+#define ADSP_PORT_REG_DIR_SET		0x1c
+#define ADSP_PORT_REG_DIR_CLEAR		0x20
+#define ADSP_PORT_REG_INEN			0x24
+#define ADSP_PORT_REG_INEN_SET		0x28
+#define ADSP_PORT_REG_INEN_CLEAR	0x2c
+#define ADSP_PORT_REG_PORT_MUX		0x30
+#define ADSP_PORT_REG_DATA_TGL		0x34
+#define ADSP_PORT_REG_POLAR			0x38
+#define ADSP_PORT_REG_POLAR_SET		0x3c
+#define ADSP_PORT_REG_POLAR_CLEAR	0x40
+#define ADSP_PORT_REG_LOCK			0x44
+#define ADSP_PORT_REG_TRIG_TGL		0x48
+
+struct adsp_gpio_priv {
+	void __iomem *base;
+	int ngpio;
+};
+
+static u32 get_port(unsigned int pin)
+{
+	return pin / ADSP_PORT_PIN_SIZE;
+}
+
+static u32 get_offset(unsigned int pin)
+{
+	return pin % ADSP_PORT_PIN_SIZE;
+}
+
+static int adsp_gpio_input(struct udevice *udev, unsigned int pin)
+{
+	struct adsp_gpio_priv *priv = dev_get_priv(udev);
+	u32 port, offset;
+	void __iomem *portbase;
+
+	if (pin < priv->ngpio) {
+		port = get_port(pin);
+		offset = get_offset(pin);
+		portbase = priv->base + port * ADSP_PORT_MMIO_SIZE;
+
+		iowrite16(BIT(offset), portbase + ADSP_PORT_REG_FER_CLEAR);
+		iowrite16(BIT(offset), portbase + ADSP_PORT_REG_DIR_CLEAR);
+		iowrite16(BIT(offset), portbase + ADSP_PORT_REG_INEN_SET);
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+static int adsp_gpio_output(struct udevice *udev, unsigned int pin, int value)
+{
+	struct adsp_gpio_priv *priv = dev_get_priv(udev);
+	u32 port, offset;
+	void __iomem *portbase;
+
+	if (pin < priv->ngpio) {
+		port = get_port(pin);
+		offset = get_offset(pin);
+		portbase = priv->base + port * ADSP_PORT_MMIO_SIZE;
+
+		iowrite16(BIT(offset), portbase + ADSP_PORT_REG_FER_CLEAR);
+
+		if (value)
+			iowrite16(BIT(offset), portbase + ADSP_PORT_REG_DATA_SET);
+		else
+			iowrite16(BIT(offset), portbase + ADSP_PORT_REG_DATA_CLEAR);
+
+		iowrite16(BIT(offset), portbase + ADSP_PORT_REG_DIR_SET);
+		iowrite16(BIT(offset), portbase + ADSP_PORT_REG_INEN_CLEAR);
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+static int adsp_gpio_get_value(struct udevice *udev, unsigned int pin)
+{
+	struct adsp_gpio_priv *priv = dev_get_priv(udev);
+	u32 port, offset;
+	u16 val;
+	void __iomem *portbase;
+
+	if (pin < priv->ngpio) {
+		port = get_port(pin);
+		offset = get_offset(pin);
+		portbase = priv->base + port * ADSP_PORT_MMIO_SIZE;
+
+		val = ioread16(portbase + ADSP_PORT_REG_DATA);
+		return !!(val & BIT(offset));
+	}
+
+	return 0;
+}
+
+static int adsp_gpio_set_value(struct udevice *udev, unsigned int pin, int value)
+{
+	struct adsp_gpio_priv *priv = dev_get_priv(udev);
+	u32 port, offset;
+	void __iomem *portbase;
+
+	if (pin < priv->ngpio) {
+		port = get_port(pin);
+		offset = get_offset(pin);
+		portbase = priv->base + port * ADSP_PORT_MMIO_SIZE;
+
+		if (value)
+			iowrite16(BIT(offset), portbase + ADSP_PORT_REG_DATA_SET);
+		else
+			iowrite16(BIT(offset), portbase + ADSP_PORT_REG_DATA_CLEAR);
+	}
+
+	return 0;
+}
+
+static const struct dm_gpio_ops adsp_gpio_ops = {
+	.direction_input = adsp_gpio_input,
+	.direction_output = adsp_gpio_output,
+	.get_value = adsp_gpio_get_value,
+	.set_value = adsp_gpio_set_value,
+};
+
+static int adsp_gpio_probe(struct udevice *udev)
+{
+	struct adsp_gpio_priv *priv = dev_get_priv(udev);
+	struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(udev);
+
+	uc_priv->bank_name = "adsp gpio";
+	uc_priv->gpio_count = dev_read_u32_default(udev, "adi,ngpios", 0);
+
+	if (!uc_priv->gpio_count) {
+		dev_err(udev, "Missing adi,ngpios property!\n");
+		return -ENOENT;
+	}
+
+	priv->base = dev_read_addr_ptr(udev);
+	priv->ngpio = uc_priv->gpio_count;
+
+	return 0;
+}
+
+static const struct udevice_id adsp_gpio_match[] = {
+	{ .compatible = "adi,adsp-gpio" },
+	{ },
+};
+
+U_BOOT_DRIVER(adi_adsp_gpio) = {
+	.name	= "adi_adsp_gpio",
+	.id	= UCLASS_GPIO,
+	.ops	= &adsp_gpio_ops,
+	.probe	= adsp_gpio_probe,
+	.priv_auto = sizeof(struct adsp_gpio_priv),
+	.of_match = adsp_gpio_match,
+	.flags = DM_FLAG_PRE_RELOC,
+};
-- 
2.45.2


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v3 04/12] gpio: Add support for ADI ADP5588 GPIO expander chips
  2025-02-26 17:30 [PATCH v3 00/12] drivers: Driver support for ADI SC5xx SoCs Greg Malysa
                   ` (2 preceding siblings ...)
  2025-02-26 17:30 ` [PATCH v3 03/12] gpio: Add support for SC5XX-family processor GPIO driver Greg Malysa
@ 2025-02-26 17:30 ` Greg Malysa
  2025-02-26 17:30 ` [PATCH v3 05/12] usb: musb-new: Add support for Analog Devices SC5xx SoCs Greg Malysa
                   ` (8 subsequent siblings)
  12 siblings, 0 replies; 16+ messages in thread
From: Greg Malysa @ 2025-02-26 17:30 UTC (permalink / raw)
  To: u-boot
  Cc: adsp-linux, Nathan Barrett-Morrison, Ian Roberts, Greg Malysa,
	Vasileios Bimpikas, Utsav Agarwal, Arturs Artamonovs,
	Oliver Gaskell, Billy Tsai, Caleb Connolly, Greg Malysa, Jim Liu,
	Marek Behún, Marek Vasut, Mattijs Korpershoek, Michal Simek,
	Piotr Wojtaszczyk, Robert Marko, Sam Protsenko, Simon Glass,
	Tom Rini, Ye Li

From: Nathan Barrett-Morrison <nathan.morrison@timesys.com>

This adds support for the ADP588 GPIO expander from Analog Devices. It
is accessed over I2C and provides up to 18 pins. It is largely a port of
the Linux driver developed by Michael Hennerich
<michael.hennerich@analog.com>

Signed-off-by: Ian Roberts <ian.roberts@timesys.com>
Signed-off-by: Greg Malysa <malysagreg@gmail.com>
Signed-off-by: Vasileios Bimpikas <vasileios.bimpikas@analog.com>
Signed-off-by: Utsav Agarwal <utsav.agarwal@analog.com>
Signed-off-by: Arturs Artamonovs <arturs.artamonovs@analog.com>
Signed-off-by: Oliver Gaskell <Oliver.Gaskell@analog.com>
Signed-off-by: Nathan Barrett-Morrison <nathan.morrison@timesys.com>
---

(no changes since v1)

 MAINTAINERS                 |   1 +
 drivers/gpio/Kconfig        |   8 ++
 drivers/gpio/Makefile       |   1 +
 drivers/gpio/adp5588_gpio.c | 208 ++++++++++++++++++++++++++++++++++++
 4 files changed, 218 insertions(+)
 create mode 100644 drivers/gpio/adp5588_gpio.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 5c16c8f6646..bfb81bb9891 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -632,6 +632,7 @@ F:	doc/device-tree-bindings/clock/adi,sc5xx-clocks.yaml
 F:	doc/device-tree-bindings/pinctrl/adi,adsp-pinctrl.yaml
 F:	doc/device-tree-bindings/timer/adi,sc5xx-gptimer.yaml
 F:	drivers/clk/adi/
+F:	drivers/gpio/adp5588_gpio.c
 F:	drivers/gpio/gpio-adi-adsp.c
 F:	drivers/pinctrl/pinctrl-adi-adsp.c
 F:	drivers/serial/serial_adi_uart4.c
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 00b01f5f09e..8d7a990b04f 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -554,6 +554,14 @@ config DM_PCA953X
 	  Now, max 24 bits chips and PCA953X compatible chips are
 	  supported
 
+config ADP5588_GPIO
+	bool "ADP5588 GPIO expander driver"
+	depends on DM_GPIO && DM_I2C
+	help
+	  Say yes here to support GPIO functionality of ADI ADP5588 chips.
+
+	  The ADP5588 is an 18-port I2C GPIO expander and keypad controller.
+
 config SPL_DM_PCA953X
 	bool "PCA95[357]x, PCA9698, TCA64xx, and MAX7310 I/O ports in SPL"
 	depends on SPL_DM_GPIO
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index e25ede1813c..d426d3a2d7b 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -75,6 +75,7 @@ obj-$(CONFIG_NOMADIK_GPIO)	+= nmk_gpio.o
 obj-$(CONFIG_MAX7320_GPIO)	+= max7320_gpio.o
 obj-$(CONFIG_$(XPL_)MAX77663_GPIO)	+= max77663_gpio.o
 obj-$(CONFIG_SL28CPLD_GPIO)	+= sl28cpld-gpio.o
+obj-$(CONFIG_ADP5588_GPIO)	+= adp5588_gpio.o
 obj-$(CONFIG_ZYNQMP_GPIO_MODEPIN)	+= zynqmp_gpio_modepin.o
 obj-$(CONFIG_SLG7XL45106_I2C_GPO)	+= gpio_slg7xl45106.o
 obj-$(CONFIG_FTGPIO010)		+= ftgpio010.o
diff --git a/drivers/gpio/adp5588_gpio.c b/drivers/gpio/adp5588_gpio.c
new file mode 100644
index 00000000000..d081e169897
--- /dev/null
+++ b/drivers/gpio/adp5588_gpio.c
@@ -0,0 +1,208 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * GPIO Chip driver for Analog Devices
+ * ADP5588/ADP5587 I/O Expander and QWERTY Keypad Controller
+ *
+ * (C) Copyright 2022 - Analog Devices, Inc.
+ *
+ * Written and/or maintained by Timesys Corporation
+ *
+ * Contact: Nathan Barrett-Morrison <nathan.morrison@timesys.com>
+ * Contact: Greg Malysa <greg.malysa@timesys.com>
+ *
+ * Based on Michael Hennerich's Linux driver:
+ * Michael Hennerich <michael.hennerich@analog.com>
+ *
+ */
+
+#include <dm.h>
+#include <i2c.h>
+#include <asm-generic/gpio.h>
+
+#define ADP5588_MAXGPIO     18
+#define ADP5588_BANK(offs)  ((offs) >> 3)
+#define ADP5588_BIT(offs)   (1u << ((offs) & 0x7))
+
+#define DEV_ID          0x00    /* Device ID */
+#define GPIO_DAT_STAT1  0x14    /* GPIO Data Status, Read twice to clear */
+#define GPIO_DAT_STAT2  0x15    /* GPIO Data Status, Read twice to clear */
+#define GPIO_DAT_STAT3  0x16    /* GPIO Data Status, Read twice to clear */
+#define GPIO_DAT_OUT1   0x17    /* GPIO DATA OUT */
+#define GPIO_DAT_OUT2   0x18    /* GPIO DATA OUT */
+#define GPIO_DAT_OUT3   0x19    /* GPIO DATA OUT */
+#define GPIO_INT_EN1    0x1A    /* GPIO Interrupt Enable */
+#define GPIO_INT_EN2    0x1B    /* GPIO Interrupt Enable */
+#define GPIO_INT_EN3    0x1C    /* GPIO Interrupt Enable */
+#define KP_GPIO1        0x1D    /* Keypad or GPIO Selection */
+#define KP_GPIO2        0x1E    /* Keypad or GPIO Selection */
+#define KP_GPIO3        0x1F    /* Keypad or GPIO Selection */
+#define GPIO_DIR1       0x23    /* GPIO Data Direction */
+#define GPIO_DIR2       0x24    /* GPIO Data Direction */
+#define GPIO_DIR3       0x25	/* GPIO Data Direction */
+#define GPIO_PULL1      0x2C    /* GPIO Pull Disable */
+#define GPIO_PULL2      0x2D    /* GPIO Pull Disable */
+#define GPIO_PULL3      0x2E    /* GPIO Pull Disable */
+#define ID_MASK	        0x0F
+
+struct adp5588_gpio {
+	u8 dat_out[3];
+	u8 dir[3];
+};
+
+static int adp5588_gpio_read(struct udevice *dev, u8 reg)
+{
+	int ret;
+	u8 val;
+
+	ret = dm_i2c_read(dev, reg, &val, 1);
+
+	if (ret < 0) {
+		pr_err("%s: read error\n", __func__);
+		return ret;
+	}
+
+	return val;
+}
+
+static int adp5588_gpio_write(struct udevice *dev, u8 reg, u8 val)
+{
+	int ret;
+
+	ret = dm_i2c_write(dev, reg, &val, 1);
+	if (ret < 0) {
+		pr_err("%s: write error\n", __func__);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int adp5588_get_value(struct udevice *dev, u32 offset)
+{
+	struct adp5588_gpio *plat = dev_get_plat(dev);
+	unsigned int bank = ADP5588_BANK(offset);
+	unsigned int bit = ADP5588_BIT(offset);
+	int val;
+
+	if (plat->dir[bank] & bit)
+		val = plat->dat_out[bank];
+	else
+		val = adp5588_gpio_read(dev, GPIO_DAT_STAT1 + bank);
+
+	return !!(val & bit);
+}
+
+static int adp5588_set_value(struct udevice *dev, u32 offset,
+			     int32_t value)
+{
+	unsigned int bank, bit;
+	int ret;
+	struct adp5588_gpio *plat = dev_get_plat(dev);
+
+	bank = ADP5588_BANK(offset);
+	bit = ADP5588_BIT(offset);
+
+	if (value)
+		plat->dat_out[bank] |= bit;
+	else
+		plat->dat_out[bank] &= ~bit;
+
+	ret = adp5588_gpio_write(dev, GPIO_DAT_OUT1 + bank,
+				 plat->dat_out[bank]);
+
+	return ret;
+}
+
+static int adp5588_direction_input(struct udevice *dev, u32 offset)
+{
+	int ret;
+	unsigned int bank;
+	struct adp5588_gpio *plat = dev_get_plat(dev);
+
+	bank = ADP5588_BANK(offset);
+
+	plat->dir[bank] &= ~ADP5588_BIT(offset);
+	ret = adp5588_gpio_write(dev, GPIO_DIR1 + bank, plat->dir[bank]);
+
+	return ret;
+}
+
+static int adp5588_direction_output(struct udevice *dev,
+				    u32 offset, int value)
+{
+	int ret;
+	unsigned int bank, bit;
+	struct adp5588_gpio *plat = dev_get_plat(dev);
+
+	bank = ADP5588_BANK(offset);
+	bit = ADP5588_BIT(offset);
+
+	plat->dir[bank] |= bit;
+
+	if (value)
+		plat->dat_out[bank] |= bit;
+	else
+		plat->dat_out[bank] &= ~bit;
+
+	ret = adp5588_gpio_write(dev, GPIO_DAT_OUT1 + bank,
+				 plat->dat_out[bank]);
+	ret |= adp5588_gpio_write(dev, GPIO_DIR1 + bank,
+				 plat->dir[bank]);
+
+	return ret;
+}
+
+static int adp5588_ofdata_platdata(struct udevice *dev)
+{
+	struct adp5588_gpio *plat = dev_get_plat(dev);
+	struct gpio_dev_priv *priv = dev_get_uclass_priv(dev);
+	int node = dev_of_offset(dev);
+	int ret, i, revid;
+
+	priv->gpio_count = ADP5588_MAXGPIO;
+	priv->bank_name = fdt_get_name(gd->fdt_blob, node, NULL);
+
+	ret = adp5588_gpio_read(dev, DEV_ID);
+	if (ret < 0)
+		return ret;
+
+	revid = ret & ID_MASK;
+
+	printf("ADP5588 Detected: Rev %x, Rev ID %x\n", ret, revid);
+
+	for (i = 0, ret = 0; i <= ADP5588_BANK(ADP5588_MAXGPIO); i++) {
+		plat->dat_out[i] = adp5588_gpio_read(dev, GPIO_DAT_OUT1 + i);
+		plat->dir[i] = adp5588_gpio_read(dev, GPIO_DIR1 + i);
+		ret |= adp5588_gpio_write(dev, KP_GPIO1 + i, 0);
+		ret |= adp5588_gpio_write(dev, GPIO_PULL1 + i, 0);
+		ret |= adp5588_gpio_write(dev, GPIO_INT_EN1 + i, 0);
+		if (ret) {
+			pr_err("%s: Initialization error\n", __func__);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static const struct dm_gpio_ops adp5588_ops = {
+	.direction_input  = adp5588_direction_input,
+	.direction_output = adp5588_direction_output,
+	.get_value		  = adp5588_get_value,
+	.set_value		  = adp5588_set_value,
+};
+
+static const struct udevice_id adp5588_of_match_list[] = {
+	{ .compatible = "adi,adp5588"},
+	{ /* sentinel */ }
+};
+
+U_BOOT_DRIVER(gpio_adp5588) = {
+	.name					  = "gpio_adp5588",
+	.id						  = UCLASS_GPIO,
+	.ops					  = &adp5588_ops,
+	.of_match				  = adp5588_of_match_list,
+	.of_to_plat		  = adp5588_ofdata_platdata,
+	.plat_auto = sizeof(struct adp5588_gpio),
+	.flags					  = DM_FLAG_PRE_RELOC,
+};
-- 
2.45.2


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v3 05/12] usb: musb-new: Add support for Analog Devices SC5xx SoCs
  2025-02-26 17:30 [PATCH v3 00/12] drivers: Driver support for ADI SC5xx SoCs Greg Malysa
                   ` (3 preceding siblings ...)
  2025-02-26 17:30 ` [PATCH v3 04/12] gpio: Add support for ADI ADP5588 GPIO expander chips Greg Malysa
@ 2025-02-26 17:30 ` Greg Malysa
  2025-02-26 17:30 ` [PATCH v3 06/12] i2c: Add support for ADI SC5XX-family I2C peripheral Greg Malysa
                   ` (7 subsequent siblings)
  12 siblings, 0 replies; 16+ messages in thread
From: Greg Malysa @ 2025-02-26 17:30 UTC (permalink / raw)
  To: u-boot
  Cc: adsp-linux, Nathan Barrett-Morrison, Greg Malysa, Ian Roberts,
	Vasileios Bimpikas, Utsav Agarwal, Arturs Artamonovs,
	Oliver Gaskell, Caleb Connolly, Greg Malysa, Marek Vasut,
	Mattijs Korpershoek, Robert Marko, Sam Protsenko, Simon Glass,
	Tom Rini

From: Nathan Barrett-Morrison <nathan.morrison@timesys.com>

This adds support for the MUSB-based USB controller found in the
Analog Devices SC57x and SC58x SoCs.

Co-developed-by: Greg Malysa <malysagreg@gmail.com>
Signed-off-by: Greg Malysa <malysagreg@gmail.com>
Co-developed-by: Ian Roberts <ian.roberts@timesys.com>
Signed-off-by: Ian Roberts <ian.roberts@timesys.com>
Signed-off-by: Vasileios Bimpikas <vasileios.bimpikas@analog.com>
Signed-off-by: Utsav Agarwal <utsav.agarwal@analog.com>
Signed-off-by: Arturs Artamonovs <arturs.artamonovs@analog.com>
Signed-off-by: Oliver Gaskell <Oliver.Gaskell@analog.com>
Signed-off-by: Nathan Barrett-Morrison <nathan.morrison@timesys.com>
---

(no changes since v1)

 MAINTAINERS                   |   1 +
 drivers/usb/musb-new/Kconfig  |   7 ++
 drivers/usb/musb-new/Makefile |   1 +
 drivers/usb/musb-new/sc5xx.c  | 202 ++++++++++++++++++++++++++++++++++
 4 files changed, 211 insertions(+)
 create mode 100644 drivers/usb/musb-new/sc5xx.c

diff --git a/MAINTAINERS b/MAINTAINERS
index bfb81bb9891..b57e2119679 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -637,6 +637,7 @@ F:	drivers/gpio/gpio-adi-adsp.c
 F:	drivers/pinctrl/pinctrl-adi-adsp.c
 F:	drivers/serial/serial_adi_uart4.c
 F:	drivers/timer/adi_sc5xx_timer.c
+F:	drivers/usb/musb-new/sc5xx.c
 F:	include/configs/sc5*
 F:	include/dt-bindings/pinctrl/adi-adsp.h
 F:	include/env/adi/
diff --git a/drivers/usb/musb-new/Kconfig b/drivers/usb/musb-new/Kconfig
index c52afd41a75..ad9072a5327 100644
--- a/drivers/usb/musb-new/Kconfig
+++ b/drivers/usb/musb-new/Kconfig
@@ -22,6 +22,13 @@ config USB_MUSB_GADGET
 	  Enables the MUSB USB dual-role controller in gadget mode.
 
 if USB_MUSB_HOST || USB_MUSB_GADGET
+config USB_MUSB_SC5XX
+        bool "Analog Devices MUSB support"
+        depends on (SC57X || SC58X)
+	help
+	 Say y here to enable support for the USB controller on
+	 ADI SC57X/SC58X processors.
+
 config USB_MUSB_DA8XX
 	bool "Enable DA8xx MUSB Controller"
 	depends on ARCH_DAVINCI
diff --git a/drivers/usb/musb-new/Makefile b/drivers/usb/musb-new/Makefile
index 396ff02654b..6638772daca 100644
--- a/drivers/usb/musb-new/Makefile
+++ b/drivers/usb/musb-new/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_USB_MUSB_PIC32) += pic32.o
 obj-$(CONFIG_USB_MUSB_SUNXI) += sunxi.o
 obj-$(CONFIG_USB_MUSB_TI) += ti-musb.o
 obj-$(CONFIG_USB_MUSB_UX500) += ux500.o
+obj-$(CONFIG_USB_MUSB_SC5XX) += sc5xx.o
 
 ccflags-y := $(call cc-option,-Wno-unused-variable) \
 		$(call cc-option,-Wno-unused-but-set-variable) \
diff --git a/drivers/usb/musb-new/sc5xx.c b/drivers/usb/musb-new/sc5xx.c
new file mode 100644
index 00000000000..16201480b43
--- /dev/null
+++ b/drivers/usb/musb-new/sc5xx.c
@@ -0,0 +1,202 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * (C) Copyright 2022 - Analog Devices, Inc.
+ *
+ * ADI SC5XX MUSB "glue layer"
+ *
+ * Written and/or maintained by Timesys Corporation
+ *
+ * Loosely ported from Linux driver:
+ * Author: Nathan Barrett-Morrison <nathan.morrison@timesys.com>
+ *
+ */
+
+#include <dm.h>
+#include <dm/device_compat.h>
+#include <linux/bitops.h>
+#include <linux/io.h>
+#include <linux/usb/musb.h>
+#include "linux-compat.h"
+#include "musb_core.h"
+#include "musb_uboot.h"
+
+#define MUSB_SOFTRST		0x7f
+#define  MUSB_SOFTRST_NRST	BIT(0)
+#define  MUSB_SOFTRST_NRSTX	BIT(1)
+
+#define REG_USB_VBUS_CTL	0x380
+#define REG_USB_ID_CTL		0x382
+#define REG_USB_PHY_CTL		0x394
+#define REG_USB_PLL_OSC		0x398
+#define REG_USB_UTMI_CTL	0x39c
+
+/* controller data */
+struct sc5xx_musb_data {
+	struct musb_host_data mdata;
+	struct device dev;
+};
+
+#define to_sc5xx_musb_data(d)	\
+	container_of(d, struct sc5xx_musb_data, dev)
+
+static void sc5xx_musb_disable(struct musb *musb)
+{
+	/* no way to shut the controller */
+}
+
+static int sc5xx_musb_enable(struct musb *musb)
+{
+	/* soft reset by NRSTx */
+	musb_writeb(musb->mregs, MUSB_SOFTRST, MUSB_SOFTRST_NRSTX);
+	/* set mode */
+	musb_platform_set_mode(musb, musb->board_mode);
+
+	return 0;
+}
+
+static irqreturn_t sc5xx_interrupt(int irq, void *hci)
+{
+	struct musb  *musb = hci;
+	irqreturn_t ret = IRQ_NONE;
+	u8 devctl;
+
+	musb->int_usb = musb_readb(musb->mregs, MUSB_INTRUSB);
+	musb->int_tx = musb_readw(musb->mregs, MUSB_INTRTX);
+	musb->int_rx = musb_readw(musb->mregs, MUSB_INTRRX);
+
+	if (musb->int_usb & MUSB_INTR_VBUSERROR) {
+		musb->int_usb &= ~MUSB_INTR_VBUSERROR;
+		devctl = musb_readw(musb->mregs, MUSB_DEVCTL);
+		devctl |= MUSB_DEVCTL_SESSION;
+		musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
+	}
+	if (musb->int_usb || musb->int_tx || musb->int_rx) {
+		musb_writeb(musb->mregs, MUSB_INTRUSB, musb->int_usb);
+		musb_writew(musb->mregs, MUSB_INTRTX, musb->int_tx);
+		musb_writew(musb->mregs, MUSB_INTRRX, musb->int_rx);
+		ret = musb_interrupt(musb);
+	}
+
+	if (musb->int_usb & MUSB_INTR_DISCONNECT && is_host_active(musb))
+		musb_writeb(musb->mregs, REG_USB_VBUS_CTL, 0x0);
+
+	return ret;
+}
+
+static int sc5xx_musb_set_mode(struct musb *musb, u8 mode)
+{
+	struct device *dev = musb->controller;
+	struct sc5xx_musb_data *pdata = to_sc5xx_musb_data(dev);
+
+	switch (mode) {
+	case MUSB_HOST:
+		musb_writeb(musb->mregs, REG_USB_ID_CTL, 0x1);
+		break;
+	case MUSB_PERIPHERAL:
+		musb_writeb(musb->mregs, REG_USB_ID_CTL, 0x3);
+		break;
+	case MUSB_OTG:
+		musb_writeb(musb->mregs, REG_USB_ID_CTL, 0x0);
+		break;
+	default:
+		dev_err(dev, "unsupported mode %d\n", mode);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int sc5xx_musb_init(struct musb *musb)
+{
+	struct sc5xx_musb_data *pdata = to_sc5xx_musb_data(musb->controller);
+
+	musb->isr = sc5xx_interrupt;
+
+	musb_writel(musb->mregs, REG_USB_PLL_OSC, 20 << 1);
+	musb_writeb(musb->mregs, REG_USB_VBUS_CTL, 0x0);
+	musb_writeb(musb->mregs, REG_USB_PHY_CTL, 0x80);
+	musb_writel(musb->mregs, REG_USB_UTMI_CTL,
+		    0x40 | musb_readl(musb->mregs, REG_USB_UTMI_CTL));
+
+	return 0;
+}
+
+const struct musb_platform_ops sc5xx_musb_ops = {
+	.init		= sc5xx_musb_init,
+	.set_mode	= sc5xx_musb_set_mode,
+	.disable	= sc5xx_musb_disable,
+	.enable		= sc5xx_musb_enable,
+};
+
+static struct musb_hdrc_config sc5xx_musb_config = {
+	.multipoint     = 1,
+	.dyn_fifo       = 1,
+	.num_eps        = 16,
+	.ram_bits       = 12,
+};
+
+/* has one MUSB controller which can be host or gadget */
+static struct musb_hdrc_platform_data sc5xx_musb_plat = {
+	.mode           = MUSB_HOST,
+	.config         = &sc5xx_musb_config,
+	.power          = 100,
+	.platform_ops	= &sc5xx_musb_ops,
+};
+
+static int musb_usb_probe(struct udevice *dev)
+{
+	struct usb_bus_priv *priv = dev_get_uclass_priv(dev);
+	struct sc5xx_musb_data *pdata = dev_get_priv(dev);
+	struct musb_host_data *mdata = &pdata->mdata;
+	void __iomem *mregs;
+	int ret;
+
+	priv->desc_before_addr = true;
+
+	mregs = dev_remap_addr(dev);
+	if (!mregs)
+		return -EINVAL;
+
+	/* init controller */
+	if (IS_ENABLED(CONFIG_USB_MUSB_HOST)) {
+		mdata->host = musb_init_controller(&sc5xx_musb_plat,
+						   &pdata->dev, mregs);
+		if (!mdata->host)
+			return -EIO;
+
+		ret = musb_lowlevel_init(mdata);
+	} else {
+		sc5xx_musb_plat.mode = MUSB_PERIPHERAL;
+		mdata->host = musb_register(&sc5xx_musb_plat, &pdata->dev, mregs);
+		if (!mdata->host)
+			return -EIO;
+	}
+	return ret;
+}
+
+static int musb_usb_remove(struct udevice *dev)
+{
+	struct sc5xx_musb_data *pdata = dev_get_priv(dev);
+
+	musb_stop(pdata->mdata.host);
+
+	return 0;
+}
+
+static const struct udevice_id sc5xx_musb_ids[] = {
+	{ .compatible = "adi,sc5xx-musb" },
+	{ }
+};
+
+U_BOOT_DRIVER(usb_musb) = {
+	.name		= "sc5xx-musb",
+	.id		= UCLASS_USB,
+	.of_match	= sc5xx_musb_ids,
+	.probe		= musb_usb_probe,
+	.remove		= musb_usb_remove,
+#ifdef CONFIG_USB_MUSB_HOST
+	.ops		= &musb_usb_ops,
+#endif
+	.plat_auto	= sizeof(struct usb_plat),
+	.priv_auto	= sizeof(struct sc5xx_musb_data),
+};
-- 
2.45.2


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v3 06/12] i2c: Add support for ADI SC5XX-family I2C peripheral
  2025-02-26 17:30 [PATCH v3 00/12] drivers: Driver support for ADI SC5xx SoCs Greg Malysa
                   ` (4 preceding siblings ...)
  2025-02-26 17:30 ` [PATCH v3 05/12] usb: musb-new: Add support for Analog Devices SC5xx SoCs Greg Malysa
@ 2025-02-26 17:30 ` Greg Malysa
  2025-03-06  5:56   ` Heiko Schocher
  2025-02-26 17:30 ` [PATCH v3 07/12] net: Add support for ADI SC5xx SoCs with DWC QoS ethernet Greg Malysa
                   ` (6 subsequent siblings)
  12 siblings, 1 reply; 16+ messages in thread
From: Greg Malysa @ 2025-02-26 17:30 UTC (permalink / raw)
  To: u-boot
  Cc: adsp-linux, Nathan Barrett-Morrison, Greg Malysa, Ian Roberts,
	Angelo Dureghello, Vasileios Bimpikas, Utsav Agarwal,
	Arturs Artamonovs, Oliver Gaskell, Caleb Connolly, David Virag,
	Greg Malysa, Heiko Schocher, Marek Vasut, Mattijs Korpershoek,
	Neil Armstrong, Paul Barker, Robert Marko, Sam Protsenko,
	Simon Glass, Tom Rini

From: Nathan Barrett-Morrison <nathan.morrison@timesys.com>

Co-developed-by: Greg Malysa <malysagreg@gmail.com>
Signed-off-by: Greg Malysa <malysagreg@gmail.com>
Co-developed-by: Ian Roberts <ian.roberts@timesys.com>
Signed-off-by: Ian Roberts <ian.roberts@timesys.com>
Co-developed-by: Angelo Dureghello <angelo.dureghello@timesys.com>
Signed-off-by: Angelo Dureghello <angelo.dureghello@timesys.com>
Signed-off-by: Vasileios Bimpikas <vasileios.bimpikas@analog.com>
Signed-off-by: Utsav Agarwal <utsav.agarwal@analog.com>
Signed-off-by: Arturs Artamonovs <arturs.artamonovs@analog.com>
Signed-off-by: Oliver Gaskell <Oliver.Gaskell@analog.com>
Signed-off-by: Nathan Barrett-Morrison <nathan.morrison@timesys.com>

---

Changes in v3:
- replace readw/writew with ioread16 and iowrite16 and friends

 MAINTAINERS           |   1 +
 drivers/i2c/Kconfig   |   7 +
 drivers/i2c/Makefile  |   1 +
 drivers/i2c/adi_i2c.c | 386 ++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 395 insertions(+)
 create mode 100644 drivers/i2c/adi_i2c.c

diff --git a/MAINTAINERS b/MAINTAINERS
index b57e2119679..f2638becc32 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -634,6 +634,7 @@ F:	doc/device-tree-bindings/timer/adi,sc5xx-gptimer.yaml
 F:	drivers/clk/adi/
 F:	drivers/gpio/adp5588_gpio.c
 F:	drivers/gpio/gpio-adi-adsp.c
+F:	drivers/i2c/adi_i2c.c
 F:	drivers/pinctrl/pinctrl-adi-adsp.c
 F:	drivers/serial/serial_adi_uart4.c
 F:	drivers/timer/adi_sc5xx_timer.c
diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig
index cdae6825736..46e76385961 100644
--- a/drivers/i2c/Kconfig
+++ b/drivers/i2c/Kconfig
@@ -154,6 +154,13 @@ config SPL_DM_I2C_GPIO
 	  bindings are supported.
 	  Binding info: doc/device-tree-bindings/i2c/i2c-gpio.txt
 
+config SYS_I2C_ADI
+	bool "ADI I2C driver"
+	depends on DM_I2C && ARCH_SC5XX
+	help
+	  Add support for the ADI (Analog Devices) I2C driver as used
+	  in SC57X, SC58X, SC59X, SC59X_64.
+
 config SYS_I2C_AT91
 	bool "Atmel I2C driver"
 	depends on DM_I2C && ARCH_AT91
diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile
index bebd728e7da..2713289f7db 100644
--- a/drivers/i2c/Makefile
+++ b/drivers/i2c/Makefile
@@ -11,6 +11,7 @@ obj-$(CONFIG_$(XPL_)I2C_CROS_EC_TUNNEL) += cros_ec_tunnel.o
 obj-$(CONFIG_$(XPL_)I2C_CROS_EC_LDO) += cros_ec_ldo.o
 
 obj-$(CONFIG_$(XPL_)SYS_I2C_LEGACY) += i2c_core.o
+obj-$(CONFIG_SYS_I2C_ADI) += adi_i2c.o
 obj-$(CONFIG_SYS_I2C_ASPEED) += ast_i2c.o
 obj-$(CONFIG_SYS_I2C_AST2600) += ast2600_i2c.o
 obj-$(CONFIG_SYS_I2C_AT91) += at91_i2c.o
diff --git a/drivers/i2c/adi_i2c.c b/drivers/i2c/adi_i2c.c
new file mode 100644
index 00000000000..4cddcfa6b7f
--- /dev/null
+++ b/drivers/i2c/adi_i2c.c
@@ -0,0 +1,386 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * (C) Copyright 2022 - Analog Devices, Inc.
+ *
+ * Written and/or maintained by Timesys Corporation
+ *
+ * Converted to driver model by Nathan Barrett-Morrison
+ *
+ * Contact: Nathan Barrett-Morrison <nathan.morrison@timesys.com>
+ * Contact: Greg Malysa <greg.malysa@timesys.com>
+ */
+
+#include <clk.h>
+#include <dm.h>
+#include <i2c.h>
+#include <mapmem.h>
+#include <linux/io.h>
+
+#define CLKLOW(x) ((x) & 0xFF)     // Periods Clock Is Held Low
+#define CLKHI(y) (((y) & 0xFF) << 0x8) // Periods Clock Is High
+
+#define PRESCALE        0x007F     // SCLKs Per Internal Time Reference (10MHz)
+#define TWI_ENA         0x0080     // TWI Enable
+#define SCCB            0x0200     // SCCB Compatibility Enable
+
+#define SEN             0x0001     // Slave Enable
+#define SADD_LEN        0x0002     // Slave Address Length
+#define STDVAL          0x0004     // Slave Transmit Data Valid
+#define TSC_NAK         0x0008     // NAK Generated At Conclusion Of Transfer
+#define GEN             0x0010     // General Call Adrress Matching Enabled
+
+#define SDIR            0x0001     // Slave Transfer Direction
+#define GCALL           0x0002     // General Call Indicator
+
+#define MEN             0x0001     // Master Mode Enable
+#define MADD_LEN        0x0002     // Master Address Length
+#define MDIR            0x0004     // Master Transmit Direction (RX/TX*)
+#define FAST            0x0008     // Use Fast Mode Timing Specs
+#define STOP            0x0010     // Issue Stop Condition
+#define RSTART          0x0020     // Repeat Start or Stop* At End Of Transfer
+#define DCNT            0x3FC0     // Data Bytes To Transfer
+#define SDAOVR          0x4000     // Serial Data Override
+#define SCLOVR          0x8000     // Serial Clock Override
+
+#define MPROG           0x0001     // Master Transfer In Progress
+#define LOSTARB         0x0002     // Lost Arbitration Indicator (Xfer Aborted)
+#define ANAK            0x0004     // Address Not Acknowledged
+#define DNAK            0x0008     // Data Not Acknowledged
+#define BUFRDERR        0x0010     // Buffer Read Error
+#define BUFWRERR        0x0020     // Buffer Write Error
+#define SDASEN          0x0040     // Serial Data Sense
+#define SCLSEN          0x0080     // Serial Clock Sense
+#define BUSBUSY         0x0100     // Bus Busy Indicator
+
+#define SINIT           0x0001     // Slave Transfer Initiated
+#define SCOMP           0x0002     // Slave Transfer Complete
+#define SERR            0x0004     // Slave Transfer Error
+#define SOVF            0x0008     // Slave Overflow
+#define MCOMP           0x0010     // Master Transfer Complete
+#define MERR            0x0020     // Master Transfer Error
+#define XMTSERV         0x0040     // Transmit FIFO Service
+#define RCVSERV         0x0080     // Receive FIFO Service
+
+#define XMTFLUSH        0x0001     // Transmit Buffer Flush
+#define RCVFLUSH        0x0002     // Receive Buffer Flush
+#define XMTINTLEN       0x0004     // Transmit Buffer Interrupt Length
+#define RCVINTLEN       0x0008     // Receive Buffer Interrupt Length
+
+#define XMTSTAT         0x0003     // Transmit FIFO Status
+#define XMT_EMPTY       0x0000     // Transmit FIFO Empty
+#define XMT_HALF        0x0001     // Transmit FIFO Has 1 Byte To Write
+#define XMT_FULL        0x0003     // Transmit FIFO Full (2 Bytes To Write)
+
+#define RCVSTAT         0x000C     // Receive FIFO Status
+#define RCV_EMPTY       0x0000     // Receive FIFO Empty
+#define RCV_HALF        0x0004     // Receive FIFO Has 1 Byte To Read
+#define RCV_FULL        0x000C     // Receive FIFO Full (2 Bytes To Read)
+
+/* Every register is 32bit aligned, but only 16bits in size */
+#define ureg(name) u16 name; u16 __pad_##name
+
+struct twi_regs {
+	ureg(clkdiv);
+	ureg(control);
+	ureg(slave_ctl);
+	ureg(slave_stat);
+	ureg(slave_addr);
+	ureg(master_ctl);
+	ureg(master_stat);
+	ureg(master_addr);
+	ureg(int_stat);
+	ureg(int_mask);
+	ureg(fifo_ctl);
+	ureg(fifo_stat);
+	u8 __pad[0x50];
+
+	ureg(xmt_data8);
+	ureg(xmt_data16);
+	ureg(rcv_data8);
+	ureg(rcv_data16);
+};
+
+#undef ureg
+
+/*
+ * The way speed is changed into duty often results in integer truncation
+ * with 50% duty, so we'll force rounding up to the next duty by adding 1
+ * to the max. In practice this will get us a speed of something like
+ * 385 KHz. The other limit is easy to handle as it is only 8 bits.
+ */
+#define I2C_SPEED_MAX             400000
+#define I2C_SPEED_TO_DUTY(speed)  (5000000 / (speed))
+#define I2C_DUTY_MAX              (I2C_SPEED_TO_DUTY(I2C_SPEED_MAX) + 1)
+#define I2C_DUTY_MIN              0xff	/* 8 bit limited */
+
+#define I2C_M_COMBO		0x4
+#define I2C_M_STOP		0x2
+#define I2C_M_READ		0x1
+
+/*
+ * All transfers are described by this data structure
+ */
+struct adi_i2c_msg {
+	u8 flags;
+	u32 len;		/* msg length */
+	u8 *buf;		/* pointer to msg data */
+	u32 olen;		/* addr length */
+	u8 *obuf;		/* addr buffer */
+};
+
+struct adi_i2c_dev {
+	struct twi_regs  __iomem *base;
+	u32 i2c_clk;
+	uint speed;
+};
+
+/* Allow msec timeout per ~byte transfer */
+#define I2C_TIMEOUT 10
+
+/**
+ * wait_for_completion - manage the actual i2c transfer
+ *	@msg: the i2c msg
+ */
+static int wait_for_completion(struct twi_regs *twi, struct adi_i2c_msg *msg)
+{
+	u16 int_stat;
+	ulong timebase = get_timer(0);
+
+	do {
+		int_stat = ioread16(&twi->int_stat);
+
+		if (int_stat & XMTSERV) {
+			iowrite16(XMTSERV, &twi->int_stat);
+			if (msg->olen) {
+				iowrite16(*(msg->obuf++), &twi->xmt_data8);
+				--msg->olen;
+			} else if (!(msg->flags & I2C_M_COMBO) && msg->len) {
+				iowrite16(*(msg->buf++), &twi->xmt_data8);
+				--msg->len;
+			} else {
+				if (msg->flags & I2C_M_COMBO)
+					setbits_16(&twi->master_ctl, RSTART | MDIR);
+				else
+					setbits_16(&twi->master_ctl, STOP);
+			}
+		}
+		if (int_stat & RCVSERV) {
+			iowrite16(RCVSERV, &twi->int_stat);
+			if (msg->len) {
+				*(msg->buf++) = ioread16(&twi->rcv_data8);
+				--msg->len;
+			} else if (msg->flags & I2C_M_STOP) {
+				setbits_16(&twi->master_ctl, STOP);
+			}
+		}
+		if (int_stat & MERR) {
+			pr_err("%s: master transmit terror: %d\n", __func__,
+			       ioread16(&twi->master_stat));
+			iowrite16(MERR, &twi->int_stat);
+			return -EIO;
+		}
+		if (int_stat & MCOMP) {
+			iowrite16(MCOMP, &twi->int_stat);
+			if (msg->flags & I2C_M_COMBO && msg->len) {
+				u16 mlen = min(msg->len, 0xffu) << 6;
+				clrsetbits_16(&twi->master_ctl, RSTART, mlen | MEN | MDIR);
+			} else {
+				break;
+			}
+		}
+
+		/* If we were able to do something, reset timeout */
+		if (int_stat)
+			timebase = get_timer(0);
+
+	} while (get_timer(timebase) < I2C_TIMEOUT);
+
+	return 0;
+}
+
+static int i2c_transfer(struct twi_regs *twi, u8 chip, u8 *offset,
+			int olen, u8 *buffer, int len, u8 flags)
+{
+	int ret;
+	u16 ctl;
+
+	struct adi_i2c_msg msg = {
+		.flags = flags | (len >= 0xff ? I2C_M_STOP : 0),
+		.buf   = buffer,
+		.len   = len,
+		.obuf  = offset,
+		.olen  = olen,
+	};
+
+	/* wait for things to settle */
+	while (ioread16(&twi->master_stat) & BUSBUSY)
+		if (!IS_ENABLED(CONFIG_SPL_BUILD) && ctrlc())
+			return -EINTR;
+
+	/* Set Transmit device address */
+	iowrite16(chip, &twi->master_addr);
+
+	/* Clear the FIFO before starting things */
+	iowrite16(XMTFLUSH | RCVFLUSH, &twi->fifo_ctl);
+	iowrite16(0, &twi->fifo_ctl);
+
+	/* Prime the pump */
+	if (msg.olen) {
+		len = (msg.flags & I2C_M_COMBO) ? msg.olen : msg.olen + len;
+		iowrite16(*(msg.obuf++), &twi->xmt_data8);
+		--msg.olen;
+	} else if (!(msg.flags & I2C_M_READ) && msg.len) {
+		iowrite16(*(msg.buf++), &twi->xmt_data8);
+		--msg.len;
+	}
+
+	/* clear int stat */
+	iowrite16(-1, &twi->master_stat);
+	iowrite16(-1, &twi->int_stat);
+	iowrite16(0, &twi->int_mask);
+
+	/* Master enable */
+	ctl = ioread16(&twi->master_ctl);
+	ctl = (ctl & FAST) | (min(len, 0xff) << 6) | MEN |
+		((msg.flags & I2C_M_READ) ? MDIR : 0);
+	iowrite16(ctl, &twi->master_ctl);
+
+	/* Process the rest */
+	ret = wait_for_completion(twi, &msg);
+
+	clrbits_16(&twi->master_ctl, MEN);
+	clrbits_16(&twi->control, TWI_ENA);
+	setbits_16(&twi->control, TWI_ENA);
+	return ret;
+}
+
+static int adi_i2c_read(struct twi_regs *twi, u8 chip,
+			u8 *offset, int olen, u8 *buffer, int len)
+{
+	return i2c_transfer(twi, chip, offset, olen, buffer,
+			len, olen ? I2C_M_COMBO : I2C_M_READ);
+}
+
+static int adi_i2c_write(struct twi_regs *twi, u8 chip,
+			 u8 *offset, int olen, u8 *buffer, int len)
+{
+	return i2c_transfer(twi, chip, offset, olen, buffer, len, 0);
+}
+
+static int adi_i2c_set_bus_speed(struct udevice *bus, uint speed)
+{
+	struct adi_i2c_dev *dev = dev_get_priv(bus);
+	struct twi_regs *twi = dev->base;
+	u16 clkdiv = I2C_SPEED_TO_DUTY(speed);
+
+	/* Set TWI interface clock */
+	if (clkdiv < I2C_DUTY_MAX || clkdiv > I2C_DUTY_MIN)
+		return -1;
+	clkdiv = (clkdiv << 8) | (clkdiv & 0xff);
+	iowrite16(clkdiv, &twi->clkdiv);
+
+	/* Don't turn it on */
+	iowrite16(speed > 100000 ? FAST : 0, &twi->master_ctl);
+
+	return 0;
+}
+
+static int adi_i2c_of_to_plat(struct udevice *bus)
+{
+	struct adi_i2c_dev *dev = dev_get_priv(bus);
+	struct clk clock;
+	u32 ret;
+
+	dev->base = map_sysmem(dev_read_addr(bus), sizeof(struct twi_regs));
+
+	if (!dev->base)
+		return -ENOMEM;
+
+	dev->speed = dev_read_u32_default(bus, "clock-frequency",
+					  I2C_SPEED_FAST_RATE);
+
+	ret = clk_get_by_name(bus, "i2c", &clock);
+	if (ret < 0)
+		printf("%s: Can't get I2C clk: %d\n", __func__, ret);
+	else
+		dev->i2c_clk = clk_get_rate(&clock);
+
+	return 0;
+}
+
+static int adi_i2c_probe_chip(struct udevice *bus, u32 chip_addr,
+			      u32 chip_flags)
+{
+	struct adi_i2c_dev *dev = dev_get_priv(bus);
+	u8 byte;
+
+	return adi_i2c_read(dev->base, chip_addr, NULL, 0, &byte, 1);
+}
+
+static int adi_i2c_xfer(struct udevice *bus, struct i2c_msg *msg, int nmsgs)
+{
+	struct adi_i2c_dev *dev = dev_get_priv(bus);
+	struct i2c_msg *dmsg, *omsg, dummy;
+
+	memset(&dummy, 0, sizeof(struct i2c_msg));
+
+	/*
+	 * We expect either two messages (one with an offset and one with the
+	 * actual data) or one message (just data)
+	 */
+	if (nmsgs > 2 || nmsgs == 0) {
+		debug("%s: Only one or two messages are supported.", __func__);
+		return -EINVAL;
+	}
+
+	omsg = nmsgs == 1 ? &dummy : msg;
+	dmsg = nmsgs == 1 ? msg : msg + 1;
+
+	if (dmsg->flags & I2C_M_RD)
+		return adi_i2c_read(dev->base, dmsg->addr, omsg->buf, omsg->len,
+				  dmsg->buf, dmsg->len);
+	else
+		return adi_i2c_write(dev->base, dmsg->addr, omsg->buf, omsg->len,
+				   dmsg->buf, dmsg->len);
+}
+
+int adi_i2c_probe(struct udevice *bus)
+{
+	struct adi_i2c_dev *dev = dev_get_priv(bus);
+	struct twi_regs *twi = dev->base;
+
+	u16 prescale = ((dev->i2c_clk / 1000 / 1000 + 5) / 10) & 0x7F;
+
+	/* Set TWI internal clock as 10MHz */
+	iowrite16(prescale, &twi->control);
+
+	/* Set TWI interface clock as specified */
+	adi_i2c_set_bus_speed(bus, dev->speed);
+
+	/* Enable it */
+	iowrite16(TWI_ENA | prescale, &twi->control);
+
+	return 0;
+}
+
+static const struct dm_i2c_ops adi_i2c_ops = {
+	.xfer           = adi_i2c_xfer,
+	.probe_chip     = adi_i2c_probe_chip,
+	.set_bus_speed  = adi_i2c_set_bus_speed,
+};
+
+static const struct udevice_id adi_i2c_ids[] = {
+	{ .compatible = "adi-i2c", },
+	{ /* sentinel */ }
+};
+
+U_BOOT_DRIVER(i2c_adi) = {
+	.name = "i2c_adi",
+	.id = UCLASS_I2C,
+	.of_match = adi_i2c_ids,
+	.probe = adi_i2c_probe,
+	.of_to_plat = adi_i2c_of_to_plat,
+	.priv_auto = sizeof(struct adi_i2c_dev),
+	.ops = &adi_i2c_ops,
+	.flags = DM_FLAG_PRE_RELOC,
+};
-- 
2.45.2


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v3 07/12] net: Add support for ADI SC5xx SoCs with DWC QoS ethernet
  2025-02-26 17:30 [PATCH v3 00/12] drivers: Driver support for ADI SC5xx SoCs Greg Malysa
                   ` (5 preceding siblings ...)
  2025-02-26 17:30 ` [PATCH v3 06/12] i2c: Add support for ADI SC5XX-family I2C peripheral Greg Malysa
@ 2025-02-26 17:30 ` Greg Malysa
  2025-02-26 17:30 ` [PATCH v3 08/12] watchdog: Add support for ADI SC5XX-family watchdog peripheral Greg Malysa
                   ` (5 subsequent siblings)
  12 siblings, 0 replies; 16+ messages in thread
From: Greg Malysa @ 2025-02-26 17:30 UTC (permalink / raw)
  To: u-boot
  Cc: adsp-linux, Greg Malysa, Ian Roberts, Nathan Barrett-Morrison,
	Vasileios Bimpikas, Utsav Agarwal, Arturs Artamonovs,
	Oliver Gaskell, Boon Khai Ng, Caleb Connolly, Christophe ROULLIER,
	Erik Schumacher, Gabor Juhos, Greg Malysa, Hanyuan Zhao,
	Heinrich Schuchardt, Ilias Apalodimas, Jerome Forissier,
	Joe Hershberger, Marek Vasut, Markus Gothe, Mattijs Korpershoek,
	Patrice Chotard, Philip Oberfichtner, Ramon Fried, Robert Marko,
	Romain Naour, Sam Protsenko, Simon Glass, Tom Rini, Weijie Gao

The ADI SC598 includes a Designware QoS 5.20a IP block. This
commit adds support for using the existing ethernet QoS driver
with the SC598 SoC.

Co-developed-by: Ian Roberts <ian.roberts@timesys.com>
Signed-off-by: Ian Roberts <ian.roberts@timesys.com>
Co-developed-by: Nathan Barrett-Morrison <nathan.morrison@timesys.com>
Signed-off-by: Nathan Barrett-Morrison <nathan.morrison@timesys.com>
Signed-off-by: Vasileios Bimpikas <vasileios.bimpikas@analog.com>
Signed-off-by: Utsav Agarwal <utsav.agarwal@analog.com>
Signed-off-by: Arturs Artamonovs <arturs.artamonovs@analog.com>
Signed-off-by: Oliver Gaskell <Oliver.Gaskell@analog.com>
Signed-off-by: Greg Malysa <malysagreg@gmail.com>

---

Changes in v3:
- replace readl/writel with ioread32 and iowrite32 and friends
- update for compatibility with changes to dwc qos driver between 2024.04 and 2025.01

 MAINTAINERS                   |   1 +
 drivers/net/Kconfig           |   7 +++
 drivers/net/Makefile          |   1 +
 drivers/net/dwc_eth_qos.c     |   6 ++
 drivers/net/dwc_eth_qos.h     |   2 +
 drivers/net/dwc_eth_qos_adi.c | 103 ++++++++++++++++++++++++++++++++++
 6 files changed, 120 insertions(+)
 create mode 100644 drivers/net/dwc_eth_qos_adi.c

diff --git a/MAINTAINERS b/MAINTAINERS
index f2638becc32..2c4dc8b14c1 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -635,6 +635,7 @@ F:	drivers/clk/adi/
 F:	drivers/gpio/adp5588_gpio.c
 F:	drivers/gpio/gpio-adi-adsp.c
 F:	drivers/i2c/adi_i2c.c
+F:	drivers/net/dwc_eth_qos_adi.c
 F:	drivers/pinctrl/pinctrl-adi-adsp.c
 F:	drivers/serial/serial_adi_uart4.c
 F:	drivers/timer/adi_sc5xx_timer.c
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 1563404ca17..8dc5f4810e9 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -237,6 +237,13 @@ config DWC_ETH_QOS
 	  Of Service) IP block. The IP supports many options for bus type,
 	  clocking/reset structure, and feature list.
 
+config DWC_ETH_QOS_ADI
+	bool "Synopsys DWC Ethernet QOS device support for ADI SC59x-64 parts"
+	depends on DWC_ETH_QOS
+	help
+		The Synopsis Designware Ethernet QoS IP block with the specific
+		configuration used in the ADI ADSP-SC59X 64 bit SoCs
+
 config DWC_ETH_QOS_IMX
 	bool "Synopsys DWC Ethernet QOS device support for IMX"
 	depends on DWC_ETH_QOS
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 80d70212971..d919d437c08 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -19,6 +19,7 @@ obj-$(CONFIG_DM_ETH_PHY) += eth-phy-uclass.o
 obj-$(CONFIG_DRIVER_DM9000) += dm9000x.o
 obj-$(CONFIG_DSA_SANDBOX) += dsa_sandbox.o
 obj-$(CONFIG_DWC_ETH_QOS) += dwc_eth_qos.o
+obj-$(CONFIG_DWC_ETH_QOS_ADI) += dwc_eth_qos_adi.o
 obj-$(CONFIG_DWC_ETH_QOS_IMX) += dwc_eth_qos_imx.o
 obj-$(CONFIG_DWC_ETH_QOS_INTEL) += dwc_eth_qos_intel.o
 obj-$(CONFIG_DWC_ETH_QOS_ROCKCHIP) += dwc_eth_qos_rockchip.o
diff --git a/drivers/net/dwc_eth_qos.c b/drivers/net/dwc_eth_qos.c
index 2279481d935..b4ec3614696 100644
--- a/drivers/net/dwc_eth_qos.c
+++ b/drivers/net/dwc_eth_qos.c
@@ -1631,6 +1631,12 @@ static const struct udevice_id eqos_ids[] = {
 		.compatible = "starfive,jh7110-dwmac",
 		.data = (ulong)&eqos_jh7110_config
 	},
+#endif
+#if IS_ENABLED(CONFIG_DWC_ETH_QOS_ADI)
+	{
+		.compatible = "adi,sc59x-dwmac-eqos",
+		.data = (ulong)&eqos_adi_config
+	},
 #endif
 	{ }
 };
diff --git a/drivers/net/dwc_eth_qos.h b/drivers/net/dwc_eth_qos.h
index 123f98d5d53..403e8203974 100644
--- a/drivers/net/dwc_eth_qos.h
+++ b/drivers/net/dwc_eth_qos.h
@@ -87,6 +87,7 @@ struct eqos_mac_regs {
 #define EQOS_MAC_MDIO_ADDRESS_CR_MASK			GENMASK(11, 8)
 #define EQOS_MAC_MDIO_ADDRESS_CR_100_150		1
 #define EQOS_MAC_MDIO_ADDRESS_CR_20_35			2
+#define EQOS_MAC_MDIO_ADDRESS_CR_150_250		4
 #define EQOS_MAC_MDIO_ADDRESS_CR_250_300		5
 #define EQOS_MAC_MDIO_ADDRESS_SKAP			BIT(4)
 #define EQOS_MAC_MDIO_ADDRESS_GOC_MASK			GENMASK(3, 2)
@@ -301,3 +302,4 @@ extern struct eqos_config eqos_qcom_config;
 extern struct eqos_config eqos_stm32mp13_config;
 extern struct eqos_config eqos_stm32mp15_config;
 extern struct eqos_config eqos_jh7110_config;
+extern struct eqos_config eqos_adi_config;
diff --git a/drivers/net/dwc_eth_qos_adi.c b/drivers/net/dwc_eth_qos_adi.c
new file mode 100644
index 00000000000..0e6a901e303
--- /dev/null
+++ b/drivers/net/dwc_eth_qos_adi.c
@@ -0,0 +1,103 @@
+// SPDX-License-Identifier: GPL-2.0
+/**
+ * (C) Copyright 2024 - Analog Devices, Inc.
+ *
+ * Written and/or maintained by Timesys Corporation
+ *
+ * Author: Greg Malysa <greg.malysa@timesys.com>
+ * Additional Contact: Nathan Barrett-Morrison <nathan.morrison@timesys.com>
+ */
+
+#include <clk.h>
+#include <dm.h>
+#include <net.h>
+#include <phy.h>
+#include <reset.h>
+#include <linux/io.h>
+
+#include <asm/arch-adi/sc5xx/sc5xx.h>
+
+#include "dwc_eth_qos.h"
+
+static int eqos_start_resets_adi(struct udevice *dev)
+{
+	struct eqos_priv *eqos = dev_get_priv(dev);
+
+	/*
+	 * Settings need to latch with the DMA reset below. Currently only
+	 * rgmii is supported but other phy interfaces may be supported in
+	 * the future
+	 */
+	sc5xx_enable_rgmii();
+	setbits_32(&eqos->dma_regs->mode, EQOS_DMA_MODE_SWR);
+
+	return 0;
+}
+
+static int eqos_probe_resources_adi(struct udevice *dev)
+{
+	struct eqos_priv *eqos = dev_get_priv(dev);
+	phy_interface_t interface;
+	int ret;
+
+	ret = eqos_get_base_addr_dt(dev);
+	if (ret) {
+		pr_err("eqos_get_base_addr_dt failed: %d\n", ret);
+		return ret;
+	}
+
+	interface = eqos->config->interface(dev);
+	if (interface == PHY_INTERFACE_MODE_NA) {
+		pr_err("Invalid PHY interface\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/**
+ * rgmii tx clock rate is set to 125 MHz regardless of phy mode, and
+ * by default the internal clock is always connected to 125 MHz. According
+ * to the HRM it is invalid for this clock to have any other speed, so
+ * the hardware won't work anyway if this is wrong.
+ */
+static ulong eqos_get_tick_clk_rate_adi(struct udevice *dev)
+{
+	return 125 * 1000000;
+}
+
+static int eqos_get_enetaddr_adi(struct udevice *dev)
+{
+	struct eth_pdata *pdata = dev_get_plat(dev);
+
+	return eth_env_get_enetaddr("ethaddr", pdata->enetaddr);
+}
+
+static struct eqos_ops eqos_adi_ops = {
+	.eqos_inval_desc = eqos_inval_desc_generic,
+	.eqos_flush_desc = eqos_flush_desc_generic,
+	.eqos_inval_buffer = eqos_inval_buffer_generic,
+	.eqos_flush_buffer = eqos_flush_buffer_generic,
+	.eqos_probe_resources = eqos_probe_resources_adi,
+	.eqos_remove_resources = eqos_null_ops,
+	.eqos_start_resets = eqos_start_resets_adi,
+	.eqos_stop_resets = eqos_null_ops,
+	.eqos_start_clks = eqos_null_ops,
+	.eqos_stop_clks = eqos_null_ops,
+	.eqos_calibrate_pads = eqos_null_ops,
+	.eqos_disable_calibration = eqos_null_ops,
+	.eqos_set_tx_clk_speed = eqos_null_ops,
+	.eqos_get_enetaddr = eqos_get_enetaddr_adi,
+	.eqos_get_tick_clk_rate = eqos_get_tick_clk_rate_adi,
+};
+
+struct eqos_config __maybe_unused eqos_adi_config = {
+	.reg_access_always_ok = true,
+	.mdio_wait =  20,
+	.swr_wait = 50,
+	.config_mac = EQOS_MAC_RXQ_CTRL0_RXQ0EN_ENABLED_DCB,
+	.config_mac_mdio = EQOS_MAC_MDIO_ADDRESS_CR_150_250,
+	.axi_bus_width = EQOS_AXI_WIDTH_32,
+	.interface = dev_read_phy_mode,
+	.ops = &eqos_adi_ops,
+};
-- 
2.45.2


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v3 08/12] watchdog: Add support for ADI SC5XX-family watchdog peripheral
  2025-02-26 17:30 [PATCH v3 00/12] drivers: Driver support for ADI SC5xx SoCs Greg Malysa
                   ` (6 preceding siblings ...)
  2025-02-26 17:30 ` [PATCH v3 07/12] net: Add support for ADI SC5xx SoCs with DWC QoS ethernet Greg Malysa
@ 2025-02-26 17:30 ` Greg Malysa
  2025-02-27  8:44   ` Stefan Roese
  2025-02-26 17:30 ` [PATCH v3 09/12] dma: Add driver for ADI SC5xx-family SoC MDMA functionality Greg Malysa
                   ` (4 subsequent siblings)
  12 siblings, 1 reply; 16+ messages in thread
From: Greg Malysa @ 2025-02-26 17:30 UTC (permalink / raw)
  To: u-boot
  Cc: adsp-linux, Nathan Barrett-Morrison, Greg Malysa, Ian Roberts,
	Vasileios Bimpikas, Utsav Agarwal, Arturs Artamonovs,
	Oliver Gaskell, Bastien Curutchet, Caleb Connolly,
	Devarsh Thakkar, Fabio Estevam, Greg Malysa, Heiko Schocher,
	Mattijs Korpershoek, Rasmus Villemoes, Robert Marko,
	Sam Protsenko, Simon Glass, Stefan Roese, Tom Rini

From: Nathan Barrett-Morrison <nathan.morrison@timesys.com>

Co-developed-by: Greg Malysa <malysagreg@gmail.com>
Signed-off-by: Greg Malysa <malysagreg@gmail.com>
Co-developed-by: Ian Roberts <ian.roberts@timesys.com>
Signed-off-by: Ian Roberts <ian.roberts@timesys.com>
Signed-off-by: Vasileios Bimpikas <vasileios.bimpikas@analog.com>
Signed-off-by: Utsav Agarwal <utsav.agarwal@analog.com>
Signed-off-by: Arturs Artamonovs <arturs.artamonovs@analog.com>
Signed-off-by: Oliver Gaskell <Oliver.Gaskell@analog.com>
Signed-off-by: Nathan Barrett-Morrison <nathan.morrison@timesys.com>

---

Changes in v3:
- replace readl/writel with ioread32 and iowrite32 and friends

 MAINTAINERS                |   1 +
 drivers/watchdog/Kconfig   |   9 +++
 drivers/watchdog/Makefile  |   1 +
 drivers/watchdog/adi_wdt.c | 143 +++++++++++++++++++++++++++++++++++++
 4 files changed, 154 insertions(+)
 create mode 100644 drivers/watchdog/adi_wdt.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 2c4dc8b14c1..0cefd888885 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -640,6 +640,7 @@ F:	drivers/pinctrl/pinctrl-adi-adsp.c
 F:	drivers/serial/serial_adi_uart4.c
 F:	drivers/timer/adi_sc5xx_timer.c
 F:	drivers/usb/musb-new/sc5xx.c
+F:	drivers/watchdog/adi_wdt.c
 F:	include/configs/sc5*
 F:	include/dt-bindings/pinctrl/adi-adsp.h
 F:	include/env/adi/
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index b39b2546e5c..1bb67f50352 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -95,6 +95,15 @@ config WDT_APPLE
 	  The watchdog will perform a full SoC reset resulting in a
 	  reboot of the entire system.
 
+config WDT_ADI
+	bool "Analog Devices watchdog timer support"
+	select WDT
+	select SPL_WDT if SPL
+	depends on ARCH_SC5XX
+	help
+	  Enable this to support Watchdog Timer on ADI SC57X, SC58X, SC59X,
+	  and SC59X_64 processors
+
 config WDT_ARMADA_37XX
 	bool "Marvell Armada 37xx watchdog timer support"
 	depends on WDT && ARMADA_3700
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index 9b6b1a8e8ad..e6bd4c587af 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -53,3 +53,4 @@ obj-$(CONFIG_WDT_STM32MP) += stm32mp_wdt.o
 obj-$(CONFIG_WDT_SUNXI) += sunxi_wdt.o
 obj-$(CONFIG_WDT_TANGIER) += tangier_wdt.o
 obj-$(CONFIG_WDT_XILINX) += xilinx_wwdt.o
+obj-$(CONFIG_WDT_ADI) += adi_wdt.o
diff --git a/drivers/watchdog/adi_wdt.c b/drivers/watchdog/adi_wdt.c
new file mode 100644
index 00000000000..6f5b3d5d042
--- /dev/null
+++ b/drivers/watchdog/adi_wdt.c
@@ -0,0 +1,143 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * (C) Copyright 2022 - Analog Devices, Inc.
+ *
+ * Written and/or maintained by Timesys Corporation
+ *
+ * Converted to driver model by Nathan Barrett-Morrison
+ *
+ * Contact: Nathan Barrett-Morrison <nathan.morrison@timesys.com>
+ * Contact: Greg Malysa <greg.malysa@timesys.com>
+ *
+ * adi_wtd.c - driver for ADI on-chip watchdog
+ *
+ */
+
+#include <clk.h>
+#include <dm.h>
+#include <wdt.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/io.h>
+
+#define WDOG_CTL  0x0
+#define WDOG_CNT  0x4
+#define WDOG_STAT 0x8
+
+#define RCU_CTL   0x0
+#define RCU_STAT  0x4
+
+#define SEC_GCTL  0x0
+#define SEC_FCTL  0x10
+#define SEC_SCTL0 0x800
+
+#define WDEN      0x0010
+#define WDDIS     0x0AD0
+
+struct adi_wdt_priv {
+	void __iomem *rcu_base;
+	void __iomem *sec_base;
+	void __iomem *wdt_base;
+	struct clk clock;
+};
+
+static int adi_wdt_reset(struct udevice *dev)
+{
+	struct adi_wdt_priv *priv = dev_get_priv(dev);
+
+	iowrite32(0, priv->wdt_base + WDOG_STAT);
+
+	return 0;
+}
+
+static int adi_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags)
+{
+	struct adi_wdt_priv *priv = dev_get_priv(dev);
+
+	/* Disable SYSCD_RESETb input and clear the RCU0 reset status */
+	iowrite32(0xf, priv->rcu_base + RCU_STAT);
+	iowrite32(0x0, priv->rcu_base + RCU_CTL);
+
+	/* reset the SEC controller */
+	iowrite32(0x2, priv->sec_base + SEC_GCTL);
+	iowrite32(0x2, priv->sec_base + SEC_FCTL);
+
+	udelay(50);
+
+	/* enable SEC fault event */
+	iowrite32(0x1, priv->sec_base + SEC_GCTL);
+
+	/* ANOMALY 36100004 Spurious External Fault event occurs when FCTL
+	 * is re-programmed when currently active fault is not cleared
+	 */
+	iowrite32(0xc0, priv->sec_base + SEC_FCTL);
+	iowrite32(0xc1, priv->sec_base + SEC_FCTL);
+
+	/* enable SEC fault source for watchdog0 */
+	setbits_32(priv->sec_base + SEC_SCTL0 + (3*8), 0x6);
+
+	/* Enable SYSCD_RESETb input */
+	iowrite32(0x100, priv->rcu_base + RCU_CTL);
+
+	/* enable watchdog0 */
+	iowrite32(WDDIS, priv->wdt_base + WDOG_CTL);
+
+	iowrite32(timeout_ms / 1000 *
+	       (clk_get_rate(&priv->clock) / (IS_ENABLED(CONFIG_SC58X) ? 2 : 1)),
+	       priv->wdt_base + WDOG_CNT);
+
+	iowrite32(0, priv->wdt_base + WDOG_STAT);
+	iowrite32(WDEN, priv->wdt_base + WDOG_CTL);
+
+	return 0;
+}
+
+static int adi_wdt_probe(struct udevice *dev)
+{
+	struct adi_wdt_priv *priv = dev_get_priv(dev);
+	int ret;
+	struct resource res;
+
+	ret = dev_read_resource_byname(dev, "rcu", &res);
+	if (ret)
+		return ret;
+	priv->rcu_base = devm_ioremap(dev, res.start, resource_size(&res));
+
+	ret = dev_read_resource_byname(dev, "sec", &res);
+	if (ret)
+		return ret;
+	priv->sec_base = devm_ioremap(dev, res.start, resource_size(&res));
+
+	ret = dev_read_resource_byname(dev, "wdt", &res);
+	if (ret)
+		return ret;
+	priv->wdt_base = devm_ioremap(dev, res.start, resource_size(&res));
+
+	ret = clk_get_by_name(dev, "sclk0", &priv->clock);
+	if (ret < 0) {
+		printf("Can't get WDT clk: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static const struct wdt_ops adi_wdt_ops = {
+	.start		= adi_wdt_start,
+	.reset		= adi_wdt_reset,
+};
+
+static const struct udevice_id adi_wdt_ids[] = {
+	{ .compatible = "adi,wdt" },
+	{}
+};
+
+U_BOOT_DRIVER(adi_wdt) = {
+	.name		= "adi_wdt",
+	.id		= UCLASS_WDT,
+	.of_match	= adi_wdt_ids,
+	.probe		= adi_wdt_probe,
+	.ops		= &adi_wdt_ops,
+	.priv_auto = sizeof(struct adi_wdt_priv),
+	.flags		= DM_FLAG_PRE_RELOC,
+};
-- 
2.45.2


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v3 09/12] dma: Add driver for ADI SC5xx-family SoC MDMA functionality
  2025-02-26 17:30 [PATCH v3 00/12] drivers: Driver support for ADI SC5xx SoCs Greg Malysa
                   ` (7 preceding siblings ...)
  2025-02-26 17:30 ` [PATCH v3 08/12] watchdog: Add support for ADI SC5XX-family watchdog peripheral Greg Malysa
@ 2025-02-26 17:30 ` Greg Malysa
  2025-02-26 17:30 ` [PATCH v3 10/12] remoteproc: Add in SHARC loading for ADI SC5XX-family processors Greg Malysa
                   ` (3 subsequent siblings)
  12 siblings, 0 replies; 16+ messages in thread
From: Greg Malysa @ 2025-02-26 17:30 UTC (permalink / raw)
  To: u-boot
  Cc: adsp-linux, Greg Malysa, Ian Roberts, Nathan Barrett-Morrison,
	Vasileios Bimpikas, Utsav Agarwal, Arturs Artamonovs,
	Oliver Gaskell, Caleb Connolly, Greg Malysa, Mattijs Korpershoek,
	Robert Marko, Sam Protsenko, Simon Glass, Tom Rini

Add a rudimentary MDMA driver for the Analog Devices SC5xx SoCs,
primarily intended for use with and tested against the QSPI/OSPI
IP included in the SoC.

Co-developed-by: Ian Roberts <ian.roberts@timesys.com>
Signed-off-by: Ian Roberts <ian.roberts@timesys.com>
Co-developed-by: Nathan Barrett-Morrison <nathan.morrison@timesys.com>
Signed-off-by: Nathan Barrett-Morrison <nathan.morrison@timesys.com>
Signed-off-by: Vasileios Bimpikas <vasileios.bimpikas@analog.com>
Signed-off-by: Utsav Agarwal <utsav.agarwal@analog.com>
Signed-off-by: Arturs Artamonovs <arturs.artamonovs@analog.com>
Signed-off-by: Greg Malysa <malysagreg@gmail.com>
Signed-off-by: Oliver Gaskell <Oliver.Gaskell@analog.com>

---

Changes in v3:
- replace readl/writel with ioread32 and iowrite32 and friends

 MAINTAINERS           |   1 +
 drivers/dma/Kconfig   |   7 ++
 drivers/dma/Makefile  |   1 +
 drivers/dma/adi_dma.c | 253 ++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 262 insertions(+)
 create mode 100644 drivers/dma/adi_dma.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 0cefd888885..a9d05356763 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -632,6 +632,7 @@ F:	doc/device-tree-bindings/clock/adi,sc5xx-clocks.yaml
 F:	doc/device-tree-bindings/pinctrl/adi,adsp-pinctrl.yaml
 F:	doc/device-tree-bindings/timer/adi,sc5xx-gptimer.yaml
 F:	drivers/clk/adi/
+F:	drivers/dma/adi_dma.c
 F:	drivers/gpio/adp5588_gpio.c
 F:	drivers/gpio/gpio-adi-adsp.c
 F:	drivers/i2c/adi_i2c.c
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index 3c64e894646..4b47be6b016 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -76,6 +76,13 @@ config XILINX_DPDMA
 	  this file is used as placeholder for driver. The main reason is
 	  to record compatible string and calling power domain driver.
 
+config ADI_DMA
+	bool "ADI DMA driver"
+	depends on DMA && DMA_CHANNELS
+	help
+	  Enable DMA support for Analog Devices SOCs, such as the SC5xx.
+	  Currently this is a minimalistic driver tested against OSPI use only.
+
 if APBH_DMA
 config APBH_DMA_BURST
 	bool "Enable DMA BURST"
diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
index 48811eaaeb3..00d765864cd 100644
--- a/drivers/dma/Makefile
+++ b/drivers/dma/Makefile
@@ -13,5 +13,6 @@ obj-$(CONFIG_TI_KSNAV) += keystone_nav.o keystone_nav_cfg.o
 obj-$(CONFIG_TI_EDMA3) += ti-edma3.o
 obj-$(CONFIG_DMA_LPC32XX) += lpc32xx_dma.o
 obj-$(CONFIG_XILINX_DPDMA) += xilinx_dpdma.o
+obj-$(CONFIG_ADI_DMA) += adi_dma.o
 
 obj-y += ti/
diff --git a/drivers/dma/adi_dma.c b/drivers/dma/adi_dma.c
new file mode 100644
index 00000000000..28afe488db0
--- /dev/null
+++ b/drivers/dma/adi_dma.c
@@ -0,0 +1,253 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Analog Devices DMA controller driver
+ *
+ * (C) Copyright 2024 - Analog Devices, Inc.
+ *
+ * Written and/or maintained by Timesys Corporation
+ *
+ * Contact: Nathan Barrett-Morrison <nathan.morrison@timesys.com>
+ * Contact: Greg Malysa <greg.malysa@timesys.com>
+ * Contact: Ian Roberts <ian.roberts@timesys.com>
+ *
+ */
+#include <dm.h>
+#include <dma.h>
+#include <dma-uclass.h>
+#include <dm/device_compat.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+
+#define HAS_MDMA	BIT(0)
+
+#define REG_ADDRSTART	0x04
+#define REG_CFG		0x08
+#define REG_XCNT	0x0C
+#define REG_XMOD	0x10
+#define REG_STAT	0x30
+
+#define BITP_DMA_CFG_MSIZE                        8
+#define BITP_DMA_CFG_PSIZE                        4
+#define BITM_DMA_CFG_WNR                 0x00000002
+#define BITM_DMA_CFG_EN                  0x00000001
+#define ENUM_DMA_CFG_XCNT_INT            0x00100000
+
+#define BITP_DMA_STAT_PBWID                      12
+#define BITP_DMA_STAT_ERRC                        4
+#define BITM_DMA_STAT_PBWID              0x00003000
+#define BITM_DMA_STAT_ERRC               0x00000070
+#define BITM_DMA_STAT_PIRQ               0x00000004
+#define BITM_DMA_STAT_IRQERR             0x00000002
+#define BITM_DMA_STAT_IRQDONE            0x00000001
+
+#define DMA_MDMA_SRC_DEFAULT_CONFIG(psize, msize) \
+	(BITM_DMA_CFG_EN | ((psize) << BITP_DMA_CFG_PSIZE) | ((msize) << BITP_DMA_CFG_MSIZE))
+#define DMA_MDMA_DST_DEFAULT_CONFIG(psize, msize) \
+	(BITM_DMA_CFG_EN | BITM_DMA_CFG_WNR | ENUM_DMA_CFG_XCNT_INT | \
+	((psize) << BITP_DMA_CFG_PSIZE) | ((msize) << BITP_DMA_CFG_MSIZE))
+
+struct adi_dma_channel {
+	int id;
+	struct adi_dma *dma;
+	void __iomem *iosrc;
+	void __iomem *iodest;
+};
+
+struct adi_dma {
+	struct udevice *dev;
+	struct adi_dma_channel channels[1];
+	void __iomem *ioaddr;
+	unsigned long hw_cfg;
+};
+
+static const struct udevice_id dma_dt_ids[] = {
+	{ .compatible = "adi,mdma-controller", .data = HAS_MDMA },
+	{ }
+};
+
+static u8 adi_dma_get_msize(u32 n_bytecount, u32 n_address)
+{
+	/* Calculate MSIZE, PSIZE, XCNT and XMOD */
+	u8 n_msize = 0;
+	u32 n_value = n_bytecount | n_address;
+	u32 n_mask = 0x1;
+
+	for (n_msize = 0; n_msize < 5; n_msize++, n_mask <<= 1) {
+		if ((n_value & n_mask) == n_mask)
+			break;
+	}
+
+	return n_msize;
+}
+
+static int adi_dma_get_ch_error(void __iomem *ch)
+{
+	u32 cause = (ioread32(ch + REG_STAT) &  BITM_DMA_STAT_ERRC) >>
+		    BITP_DMA_STAT_ERRC;
+	switch (cause) {
+	case 0:
+		return -EINVAL;
+	case 1:
+		return -EBUSY;
+	case 2:
+		return -EFAULT;
+	case 3:
+		fallthrough;
+	case 5:
+		fallthrough;
+	case 6:
+		fallthrough;
+	default:
+		return -EIO;
+	}
+}
+
+static int adi_mdma_transfer(struct udevice *dev, int direction,
+			     dma_addr_t dst, dma_addr_t src, size_t len)
+{
+	struct adi_dma *priv = dev_get_priv(dev);
+	void __iomem *chsrc = priv->channels[0].iosrc;
+	void __iomem *chdst = priv->channels[0].iodest;
+
+	int result = 0;
+	u32 reg;
+	u32 bytecount = len;
+
+	u8 n_srcmsize;
+	u8 n_dstmsize;
+	u8 n_srcpsize;
+	u8 n_dstpsize;
+	u8 n_psize;
+	u32 srcconfig;
+	u32 dstconfig;
+	u8 srcpsizemax = (ioread32(chsrc + REG_STAT) & BITM_DMA_STAT_PBWID) >>
+			 BITP_DMA_STAT_PBWID;
+	u8 dstpsizemax = (ioread32(chdst + REG_STAT) & BITM_DMA_STAT_PBWID) >>
+			 BITP_DMA_STAT_PBWID;
+
+	const u32 CLRSTAT = (BITM_DMA_STAT_IRQDONE | BITM_DMA_STAT_IRQERR |
+			     BITM_DMA_STAT_PIRQ);
+
+	if (len == 0)
+		return -EINVAL;
+
+	/* Clear DMA status */
+	iowrite32(CLRSTAT, chsrc + REG_STAT);
+	iowrite32(CLRSTAT, chdst + REG_STAT);
+
+	/* Calculate MSIZE, PSIZE, XCNT and XMOD */
+	n_srcmsize = adi_dma_get_msize(bytecount, src);
+	n_dstmsize = adi_dma_get_msize(bytecount, dst);
+	n_srcpsize = min(n_srcmsize, srcpsizemax);
+	n_dstpsize = min(n_dstmsize, dstpsizemax);
+	n_psize = min(n_srcpsize, n_dstpsize);
+
+	srcconfig = DMA_MDMA_SRC_DEFAULT_CONFIG(n_psize, n_srcmsize);
+	dstconfig = DMA_MDMA_DST_DEFAULT_CONFIG(n_psize, n_dstmsize);
+
+	/* Load the DMA descriptors */
+	iowrite32(src,			chsrc + REG_ADDRSTART);
+	iowrite32(bytecount >> n_srcmsize,	chsrc + REG_XCNT);
+	iowrite32(1 << n_srcmsize,		chsrc + REG_XMOD);
+	iowrite32(dst,			chdst + REG_ADDRSTART);
+	iowrite32(bytecount >> n_dstmsize,	chdst + REG_XCNT);
+	iowrite32(1 << n_dstmsize,		chdst + REG_XMOD);
+
+	iowrite32(dstconfig, chdst + REG_CFG);
+	iowrite32(srcconfig, chsrc + REG_CFG);
+
+	/* Wait for DMA to complete while checking for a DMA error */
+	do {
+		reg = ioread32(chsrc + REG_STAT);
+		if ((reg & BITM_DMA_STAT_IRQERR) == BITM_DMA_STAT_IRQERR) {
+			result = adi_dma_get_ch_error(chsrc);
+			break;
+		}
+		reg = ioread32(chdst + REG_STAT);
+		if ((reg & BITM_DMA_STAT_IRQERR) == BITM_DMA_STAT_IRQERR) {
+			result = adi_dma_get_ch_error(chdst);
+			break;
+		}
+	} while ((reg & BITM_DMA_STAT_IRQDONE) == 0);
+
+	clrbits_32(chsrc + REG_CFG, 1);
+	clrbits_32(chdst + REG_CFG, 1);
+
+	return result;
+}
+
+static int adi_dma_init_channel(struct adi_dma *dma,
+				struct adi_dma_channel *channel, ofnode node)
+{
+	u32 offset;
+
+	if (ofnode_read_u32(node, "adi,id", &channel->id)) {
+		dev_err(dma->dev, "Missing adi,id for channel %s\n",
+			ofnode_get_name(node));
+		return -ENOENT;
+	}
+
+	if (ofnode_read_u32(node, "adi,src-offset", &offset)) {
+		dev_err(dma->dev, "Missing adi,src-offset for channel %s\n",
+			ofnode_get_name(node));
+		return -ENOENT;
+	}
+
+	channel->iosrc = dma->ioaddr + offset;
+	channel->dma = dma;
+
+	if (dma->hw_cfg & HAS_MDMA) {
+		if (ofnode_read_u32(node, "adi,dest-offset", &offset)) {
+			dev_err(dma->dev,
+				"Missing adi,dest-offset for channel %s\n",
+				ofnode_get_name(node));
+			return -ENOENT;
+		}
+		channel->iodest = dma->ioaddr + offset;
+	}
+
+	return 0;
+}
+
+static int adi_dma_probe(struct udevice *dev)
+{
+	struct dma_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+	struct adi_dma *priv = dev_get_priv(dev);
+	ofnode node, child;
+
+	priv->hw_cfg = dev_get_driver_data(dev);
+	if (priv->hw_cfg & HAS_MDMA)
+		uc_priv->supported = DMA_SUPPORTS_MEM_TO_MEM;
+
+	priv->ioaddr = dev_remap_addr(dev);
+	if (!priv->ioaddr)
+		return -EINVAL;
+
+	node = dev_read_first_subnode(dev);
+	if (!ofnode_valid(node)) {
+		dev_err(dev,
+			"Error: device tree DMA channel config missing!\n");
+		return -ENODEV;
+	}
+
+	node = dev_ofnode(dev);
+	ofnode_for_each_subnode(child, node) {
+		adi_dma_init_channel(priv, priv->channels, child);
+		break; //Only 1 channel supported for now
+	}
+
+	return 0;
+}
+
+static const struct dma_ops adi_dma_ops = {
+	.transfer = adi_mdma_transfer,
+};
+
+U_BOOT_DRIVER(adi_dma) = {
+	.name = "adi_dma",
+	.id = UCLASS_DMA,
+	.of_match = dma_dt_ids,
+	.ops = &adi_dma_ops,
+	.probe = adi_dma_probe,
+	.priv_auto = sizeof(struct adi_dma),
+};
-- 
2.45.2


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v3 10/12] remoteproc: Add in SHARC loading for ADI SC5XX-family processors
  2025-02-26 17:30 [PATCH v3 00/12] drivers: Driver support for ADI SC5xx SoCs Greg Malysa
                   ` (8 preceding siblings ...)
  2025-02-26 17:30 ` [PATCH v3 09/12] dma: Add driver for ADI SC5xx-family SoC MDMA functionality Greg Malysa
@ 2025-02-26 17:30 ` Greg Malysa
  2025-02-26 17:30 ` [PATCH v3 11/12] spi: Add support for ADI SC5XX-family processor SPI peripherals Greg Malysa
                   ` (2 subsequent siblings)
  12 siblings, 0 replies; 16+ messages in thread
From: Greg Malysa @ 2025-02-26 17:30 UTC (permalink / raw)
  To: u-boot
  Cc: adsp-linux, Nathan Barrett-Morrison, Greg Malysa, Ian Roberts,
	Piotr Wojtaszczyk, Vasileios Bimpikas, Utsav Agarwal,
	Arturs Artamonovs, Oliver Gaskell, Caleb Connolly, Greg Malysa,
	MD Danish Anwar, Marek Vasut, Mattijs Korpershoek,
	Ravi Gunasekaran, Robert Marko, Sam Protsenko, Simon Glass,
	Tom Rini

From: Nathan Barrett-Morrison <nathan.morrison@timesys.com>

This adds the ability to load ldr-formatted files to the SHARC
coprocessors using the rproc interface. Only a minimal subset
of rproc functionality is supported: loading and starting
the remote core.

Secure boot and signed ldr verification are not available
at this time through the U-Boot interface.

Co-developed-by: Greg Malysa <malysagreg@gmail.com>
Signed-off-by: Greg Malysa <malysagreg@gmail.com>
Co-developed-by: Ian Roberts <ian.roberts@timesys.com>
Signed-off-by: Ian Roberts <ian.roberts@timesys.com>
Co-developed-by: Piotr Wojtaszczyk <piotr.wojtaszczyk@timesys.com>
Signed-off-by: Piotr Wojtaszczyk <piotr.wojtaszczyk@timesys.com>
Signed-off-by: Vasileios Bimpikas <vasileios.bimpikas@analog.com>
Signed-off-by: Utsav Agarwal <utsav.agarwal@analog.com>
Signed-off-by: Arturs Artamonovs <arturs.artamonovs@analog.com>
Signed-off-by: Oliver Gaskell <Oliver.Gaskell@analog.com>
Signed-off-by: Nathan Barrett-Morrison <nathan.morrison@timesys.com>

---

Changes in v3:
- replace readl/writel with ioread32 and iowrite32 and friends

 MAINTAINERS                          |   1 +
 drivers/remoteproc/Kconfig           |  11 ++
 drivers/remoteproc/Makefile          |   1 +
 drivers/remoteproc/adi_sc5xx_rproc.c | 277 +++++++++++++++++++++++++++
 4 files changed, 290 insertions(+)
 create mode 100644 drivers/remoteproc/adi_sc5xx_rproc.c

diff --git a/MAINTAINERS b/MAINTAINERS
index a9d05356763..42ee02bf391 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -638,6 +638,7 @@ F:	drivers/gpio/gpio-adi-adsp.c
 F:	drivers/i2c/adi_i2c.c
 F:	drivers/net/dwc_eth_qos_adi.c
 F:	drivers/pinctrl/pinctrl-adi-adsp.c
+F:	drivers/remoteproc/adi_sc5xx_rproc.c
 F:	drivers/serial/serial_adi_uart4.c
 F:	drivers/timer/adi_sc5xx_timer.c
 F:	drivers/usb/musb-new/sc5xx.c
diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
index 2790b168b19..8cb2fd006f5 100644
--- a/drivers/remoteproc/Kconfig
+++ b/drivers/remoteproc/Kconfig
@@ -13,6 +13,7 @@ config REMOTEPROC
 	depends on DM
 
 # Please keep the configuration alphabetically sorted.
+
 config K3_SYSTEM_CONTROLLER
 	bool "Support for TI' K3 System Controller"
 	select REMOTEPROC
@@ -22,6 +23,16 @@ config K3_SYSTEM_CONTROLLER
 	help
 	  Say 'y' here to add support for TI' K3 System Controller.
 
+config REMOTEPROC_ADI_SC5XX
+	bool "Support for ADI SC5xx SHARC cores"
+	select REMOTEPROC
+	depends on DM
+	depends on ARCH_SC5XX
+	depends on SYSCON
+	help
+	  Say 'y' here to add support for loading code onto SHARC cores in
+	  an ADSP-SC5xx SoC from Analog Devices
+
 config REMOTEPROC_RENESAS_APMU
 	bool "Support for Renesas R-Car Gen4 APMU start of CR52 processor"
 	select REMOTEPROC
diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile
index 3a092b7660e..65ba3ebfe4e 100644
--- a/drivers/remoteproc/Makefile
+++ b/drivers/remoteproc/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_$(XPL_)REMOTEPROC) += rproc-uclass.o rproc-elf-loader.o
 
 # Remote proc drivers - Please keep this list alphabetically sorted.
 obj-$(CONFIG_K3_SYSTEM_CONTROLLER) += k3_system_controller.o
+obj-$(CONFIG_REMOTEPROC_ADI_SC5XX) += adi_sc5xx_rproc.o
 obj-$(CONFIG_REMOTEPROC_RENESAS_APMU) += renesas_apmu.o
 obj-$(CONFIG_REMOTEPROC_SANDBOX) += sandbox_testproc.o
 obj-$(CONFIG_REMOTEPROC_STM32_COPRO) += stm32_copro.o
diff --git a/drivers/remoteproc/adi_sc5xx_rproc.c b/drivers/remoteproc/adi_sc5xx_rproc.c
new file mode 100644
index 00000000000..86acd1b98c7
--- /dev/null
+++ b/drivers/remoteproc/adi_sc5xx_rproc.c
@@ -0,0 +1,277 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * (C) Copyright 2022 - Analog Devices, Inc.
+ *
+ * Written and/or maintained by Timesys Corporation
+ *
+ * Contact: Nathan Barrett-Morrison <nathan.morrison@timesys.com>
+ * Contact: Greg Malysa <greg.malysa@timesys.com>
+ *
+ * Analog Devices SC5xx remoteproc driver for loading code onto SHARC cores
+ */
+
+#include <dm.h>
+#include <regmap.h>
+#include <remoteproc.h>
+#include <syscon.h>
+#include <dm/device_compat.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+
+/* Register offsets */
+#ifdef CONFIG_SC58X
+#define ADI_RCU_REG_CTL		0x00
+#define ADI_RCU_REG_STAT	0x04
+#define ADI_RCU_REG_CRCTL	0x08
+#define ADI_RCU_REG_CRSTAT	0x0c
+#define ADI_RCU_REG_SIDIS	0x10
+#define ADI_RCU_REG_SISTAT	0x14
+#define ADI_RCU_REG_BCODE	0x1c
+#define ADI_RCU_REG_SVECT0	0x20
+#define ADI_RCU_REG_SVECT1	0x24
+#define ADI_RCU_REG_SVECT2	0x28
+#define ADI_RCU_REG_MSG		0x60
+#define ADI_RCU_REG_MSG_SET	0x64
+#define ADI_RCU_REG_MSG_CLR	0x68
+#else
+#define ADI_RCU_REG_CTL		0x00
+#define ADI_RCU_REG_STAT	0x04
+#define ADI_RCU_REG_CRCTL	0x08
+#define ADI_RCU_REG_CRSTAT	0x0c
+#define ADI_RCU_REG_SRRQSTAT	0x18
+#define ADI_RCU_REG_SIDIS	0x1c
+#define ADI_RCU_REG_SISTAT	0x20
+#define ADI_RCU_REG_SVECT_LCK	0x24
+#define ADI_RCU_REG_BCODE	0x28
+#define ADI_RCU_REG_SVECT0	0x2c
+#define ADI_RCU_REG_SVECT1	0x30
+#define ADI_RCU_REG_SVECT2	0x34
+#define ADI_RCU_REG_MSG		0x6c
+#define ADI_RCU_REG_MSG_SET	0x70
+#define ADI_RCU_REG_MSG_CLR	0x74
+#endif /* CONFIG_SC58X */
+
+/* Register bit definitions */
+#define ADI_RCU_CTL_SYSRST		BIT(0)
+
+/* Bit values for the RCU0_MSG register */
+#define RCU0_MSG_C0IDLE			0x00000100		/* Core 0 Idle */
+#define RCU0_MSG_C1IDLE			0x00000200		/* Core 1 Idle */
+#define RCU0_MSG_C2IDLE			0x00000400		/* Core 2 Idle */
+#define RCU0_MSG_CRR0			0x00001000		/* Core 0 reset request */
+#define RCU0_MSG_CRR1			0x00002000		/* Core 1 reset request */
+#define RCU0_MSG_CRR2			0x00004000		/* Core 2 reset request */
+#define RCU0_MSG_C1ACTIVATE		0x00080000		/* Core 1 Activated */
+#define RCU0_MSG_C2ACTIVATE		0x00100000		/* Core 2 Activated */
+
+struct sc5xx_rproc_data {
+	/* Address to load to svect when rebooting core */
+	u32 load_addr;
+
+	/* RCU parameters */
+	struct regmap *rcu;
+	u32 svect_offset;
+	u32 coreid;
+};
+
+struct block_code_flag {
+	u32 bcode:4,		/* 0-3 */
+	    bflag_save:1,	/* 4 */
+	    bflag_aux:1,	/* 5 */
+	    breserved:1,	/* 6 */
+	    bflag_forward:1,	/* 7 */
+	    bflag_fill:1,	/* 8 */
+	    bflag_quickboot:1,	/* 9 */
+	    bflag_callback:1,	/* 10 */
+	    bflag_init:1,	/* 11 */
+	    bflag_ignore:1,	/* 12 */
+	    bflag_indirect:1,	/* 13 */
+	    bflag_first:1,	/* 14 */
+	    bflag_final:1,	/* 15 */
+	    bhdrchk:8,		/* 16-23 */
+	    bhdrsign:8;		/* 0xAD, 0xAC or 0xAB */
+};
+
+struct ldr_hdr {
+	struct block_code_flag bcode_flag;
+	u32 target_addr;
+	u32 byte_count;
+	u32 argument;
+};
+
+static int is_final(struct ldr_hdr *hdr)
+{
+	return hdr->bcode_flag.bflag_final;
+}
+
+static int is_empty(struct ldr_hdr *hdr)
+{
+	return hdr->bcode_flag.bflag_ignore || (hdr->byte_count == 0);
+}
+
+static int adi_valid_firmware(struct ldr_hdr *adi_ldr_hdr)
+{
+	if (!adi_ldr_hdr->byte_count &&
+	    (adi_ldr_hdr->bcode_flag.bhdrsign == 0xAD ||
+	     adi_ldr_hdr->bcode_flag.bhdrsign == 0xAC ||
+	     adi_ldr_hdr->bcode_flag.bhdrsign == 0xAB))
+		return 1;
+
+	return 0;
+}
+
+static int sharc_load(struct udevice *dev, ulong addr, ulong size)
+{
+	struct sc5xx_rproc_data *priv = dev_get_priv(dev);
+	size_t offset;
+	u8 *buf = (u8 *)addr;
+	struct ldr_hdr *ldr = (struct ldr_hdr *)addr;
+	struct ldr_hdr *block_hdr;
+	struct ldr_hdr *next_hdr;
+
+	if (!adi_valid_firmware(ldr)) {
+		dev_err(dev, "Firmware at 0x%lx does not appear to be an LDR image\n", addr);
+		dev_err(dev, "Note: Signed firmware is not currently supported\n");
+		return -EINVAL;
+	}
+
+	do {
+		block_hdr = (struct ldr_hdr *)buf;
+		offset = sizeof(struct ldr_hdr) + (block_hdr->bcode_flag.bflag_fill ?
+							0 : block_hdr->byte_count);
+		next_hdr = (struct ldr_hdr *)(buf + offset);
+
+		if (block_hdr->bcode_flag.bflag_first)
+			priv->load_addr = (unsigned long)block_hdr->target_addr;
+
+		if (!is_empty(block_hdr)) {
+			if (block_hdr->bcode_flag.bflag_fill) {
+				memset_io((void *)(phys_addr_t)block_hdr->target_addr,
+					  block_hdr->argument,
+					  block_hdr->byte_count);
+			} else {
+				memcpy_toio((void *)(phys_addr_t)block_hdr->target_addr,
+					  buf + sizeof(struct ldr_hdr),
+					  block_hdr->byte_count);
+			}
+		}
+
+		if (is_final(block_hdr))
+			break;
+
+		buf += offset;
+	} while (1);
+
+	return 0;
+}
+
+static void sharc_reset(struct sc5xx_rproc_data *priv)
+{
+	u32 coreid = priv->coreid;
+	u32 val;
+
+	/* First put core in reset.
+	 * Clear CRSTAT bit for given coreid.
+	 */
+	regmap_write(priv->rcu, ADI_RCU_REG_CRSTAT, 1 << coreid);
+
+	/* Set SIDIS to disable the system interface */
+	regmap_read(priv->rcu, ADI_RCU_REG_SIDIS, &val);
+	regmap_write(priv->rcu, ADI_RCU_REG_SIDIS, val | (1 << (coreid - 1)));
+
+	/*
+	 * Wait for access to coreX have been disabled and all the pending
+	 * transactions have completed
+	 */
+	udelay(50);
+
+	/* Set CRCTL bit to put core in reset */
+	regmap_read(priv->rcu, ADI_RCU_REG_CRCTL, &val);
+	regmap_write(priv->rcu, ADI_RCU_REG_CRCTL, val | (1 << coreid));
+
+	/* Poll until Core is in reset */
+	while (!(regmap_read(priv->rcu, ADI_RCU_REG_CRSTAT, &val), val & (1 << coreid)))
+		;
+
+	/* Clear SIDIS to reenable the system interface */
+	regmap_read(priv->rcu, ADI_RCU_REG_SIDIS, &val);
+	regmap_write(priv->rcu, ADI_RCU_REG_SIDIS, val & ~(1 << (coreid - 1)));
+
+	udelay(50);
+
+	/* Take Core out of reset */
+	regmap_read(priv->rcu, ADI_RCU_REG_CRCTL, &val);
+	regmap_write(priv->rcu, ADI_RCU_REG_CRCTL, val & ~(1 << coreid));
+
+	/* Wait for done */
+	udelay(50);
+}
+
+static int sharc_start(struct udevice *dev)
+{
+	struct sc5xx_rproc_data *priv = dev_get_priv(dev);
+
+	/* Write load address to appropriate SVECT for core */
+	regmap_write(priv->rcu, priv->svect_offset, priv->load_addr);
+
+	sharc_reset(priv);
+
+	/* Clear the IDLE bit when start the SHARC core */
+	regmap_write(priv->rcu, ADI_RCU_REG_MSG_CLR, RCU0_MSG_C0IDLE << priv->coreid);
+
+	/* Notify CCES */
+	regmap_write(priv->rcu, ADI_RCU_REG_MSG_SET, RCU0_MSG_C1ACTIVATE << (priv->coreid - 1));
+	return 0;
+}
+
+static const struct dm_rproc_ops sc5xx_ops = {
+	.load = sharc_load,
+	.start = sharc_start,
+};
+
+static int sc5xx_probe(struct udevice *dev)
+{
+	struct sc5xx_rproc_data *priv = dev_get_priv(dev);
+	u32 coreid;
+
+	if (dev_read_u32(dev, "coreid", &coreid)) {
+		dev_err(dev, "Missing property coreid\n");
+		return -ENOENT;
+	}
+
+	priv->coreid = coreid;
+	switch (coreid) {
+	case 1:
+		priv->svect_offset = ADI_RCU_REG_SVECT1;
+		break;
+	case 2:
+		priv->svect_offset = ADI_RCU_REG_SVECT2;
+		break;
+	default:
+		dev_err(dev, "Invalid value %d for coreid, must be 1 or 2\n", coreid);
+		return -EINVAL;
+	}
+
+	priv->rcu = syscon_regmap_lookup_by_phandle(dev, "adi,rcu");
+	if (IS_ERR(priv->rcu))
+		return PTR_ERR(priv->rcu);
+
+	dev_err(dev, "sc5xx remoteproc core %d available\n", priv->coreid);
+
+	return 0;
+}
+
+static const struct udevice_id sc5xx_ids[] = {
+	{ .compatible = "adi,sc5xx-rproc" },
+	{ }
+};
+
+U_BOOT_DRIVER(adi_sc5xx_rproc) = {
+	.name = "adi_sc5xx_rproc",
+	.of_match = sc5xx_ids,
+	.id = UCLASS_REMOTEPROC,
+	.ops = &sc5xx_ops,
+	.probe = sc5xx_probe,
+	.priv_auto = sizeof(struct sc5xx_rproc_data),
+	.flags = 0,
+};
-- 
2.45.2


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v3 11/12] spi: Add support for ADI SC5XX-family processor SPI peripherals
  2025-02-26 17:30 [PATCH v3 00/12] drivers: Driver support for ADI SC5xx SoCs Greg Malysa
                   ` (9 preceding siblings ...)
  2025-02-26 17:30 ` [PATCH v3 10/12] remoteproc: Add in SHARC loading for ADI SC5XX-family processors Greg Malysa
@ 2025-02-26 17:30 ` Greg Malysa
  2025-02-26 17:30 ` [PATCH v3 12/12] mmc: Add support for ADI SC5XX-family processor SDHCI peripherals Greg Malysa
  2025-03-12 19:43 ` [PATCH v3 00/12] drivers: Driver support for ADI SC5xx SoCs Tom Rini
  12 siblings, 0 replies; 16+ messages in thread
From: Greg Malysa @ 2025-02-26 17:30 UTC (permalink / raw)
  To: u-boot
  Cc: adsp-linux, Nathan Barrett-Morrison, Greg Malysa,
	Angelo Dureghello, Ian Roberts, Piotr Wojtaszczyk,
	Vasileios Bimpikas, Utsav Agarwal, Arturs Artamonovs,
	Oliver Gaskell, Caleb Connolly, Christophe Leroy, Greg Malysa,
	Jagan Teki, John Watts, Kongyang Liu, Leo Yu-Chi Liang,
	Marek Vasut, Mattijs Korpershoek, Michal Simek, Robert Marko,
	Sam Protsenko, Simon Glass, Tom Rini, Venkatesh Yadav Abbarapu

From: Nathan Barrett-Morrison <nathan.morrison@timesys.com>

This adds support for the ADI-specific SPI driver present in the ADI
SC5xx line of SoCs. This IP block is distinct from the QSPI/OSPI block
that uses the Cadence driver. Both may be used at once with appropriate
pin muxing configuration.

Co-developed-by: Greg Malysa <malysagreg@gmail.com>
Signed-off-by: Greg Malysa <malysagreg@gmail.com>
Co-developed-by: Angelo Dureghello <angelo.dureghello@timesys.com>
Signed-off-by: Angelo Dureghello <angelo.dureghello@timesys.com>
Co-developed-by: Ian Roberts <ian.roberts@timesys.com>
Signed-off-by: Ian Roberts <ian.roberts@timesys.com>
Co-developed-by: Piotr Wojtaszczyk <piotr.wojtaszczyk@timesys.com>
Signed-off-by: Piotr Wojtaszczyk <piotr.wojtaszczyk@timesys.com>
Signed-off-by: Vasileios Bimpikas <vasileios.bimpikas@analog.com>
Signed-off-by: Utsav Agarwal <utsav.agarwal@analog.com>
Signed-off-by: Arturs Artamonovs <arturs.artamonovs@analog.com>
Signed-off-by: Oliver Gaskell <Oliver.Gaskell@analog.com>
Signed-off-by: Nathan Barrett-Morrison <nathan.morrison@timesys.com>

---

Changes in v3:
- Primarily addressed issues identified in earlier feedback:
- Removed unused pins and memory_map priv members
- Added __iomem to device mmio pointers
- Replaced readl/writel calls with iowrite32/ioread32 and friends
- Added map_sysmem() call to prepare device mmio pointer

 MAINTAINERS            |   1 +
 drivers/spi/Kconfig    |   7 +
 drivers/spi/Makefile   |   1 +
 drivers/spi/adi_spi3.c | 679 +++++++++++++++++++++++++++++++++++++++++
 4 files changed, 688 insertions(+)
 create mode 100644 drivers/spi/adi_spi3.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 42ee02bf391..889695c1edd 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -640,6 +640,7 @@ F:	drivers/net/dwc_eth_qos_adi.c
 F:	drivers/pinctrl/pinctrl-adi-adsp.c
 F:	drivers/remoteproc/adi_sc5xx_rproc.c
 F:	drivers/serial/serial_adi_uart4.c
+F:	drivers/spi/adi_spi3.c
 F:	drivers/timer/adi_sc5xx_timer.c
 F:	drivers/usb/musb-new/sc5xx.c
 F:	drivers/watchdog/adi_wdt.c
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 96ea033082b..846a93a4e57 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -52,6 +52,13 @@ config SPI_DIRMAP
 
 if DM_SPI
 
+config ADI_SPI3
+	bool "Enable ADI SPI Driver"
+	depends on ARCH_SC5XX
+	help
+	  Enable the ADI (Analog Devices) SPI controller driver. This
+	  driver enables the support for SC5XX spi controller.
+
 config ALTERA_SPI
 	bool "Altera SPI driver"
 	help
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 7051e2a00c6..21895d46429 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -19,6 +19,7 @@ obj-y += spi.o
 obj-$(CONFIG_SPI_MEM) += spi-mem-nodm.o
 endif
 
+obj-$(CONFIG_ADI_SPI3) += adi_spi3.o
 obj-$(CONFIG_ALTERA_SPI) += altera_spi.o
 obj-$(CONFIG_APPLE_SPI) += apple_spi.o
 obj-$(CONFIG_ATH79_SPI) += ath79_spi.o
diff --git a/drivers/spi/adi_spi3.c b/drivers/spi/adi_spi3.c
new file mode 100644
index 00000000000..2125d25561a
--- /dev/null
+++ b/drivers/spi/adi_spi3.c
@@ -0,0 +1,679 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * (C) Copyright 2022 - Analog Devices, Inc.
+ *
+ * Written and/or maintained by Timesys Corporation
+ *
+ * Converted to driver model by Nathan Barrett-Morrison
+ *
+ * Contact: Nathan Barrett-Morrison <nathan.morrison@timesys.com>
+ * Contact: Greg Malysa <greg.malysa@timesys.com>
+ * Contact: Ian Roberts <ian.roberts@timesys.com>
+ * Contact: Piotr Wojtaszczyk <piotr.wojtaszczyk@timesys.com>
+ *
+ */
+
+#include <clk.h>
+#include <dm.h>
+#include <mapmem.h>
+#include <spi.h>
+#include <spi-mem.h>
+#include <dm/device_compat.h>
+#include <linux/io.h>
+
+#define SPI_IDLE_VAL	0xff
+
+#define MAX_CTRL_CS 7
+
+/* SPI_CONTROL */
+#define SPI_CTL_EN          0x00000001 /* Enable */
+#define SPI_CTL_MSTR        0x00000002 /* Master/Slave */
+#define SPI_CTL_PSSE        0x00000004 /* controls modf error in master mode */
+#define SPI_CTL_ODM         0x00000008 /* Open Drain Mode */
+#define SPI_CTL_CPHA        0x00000010 /* Clock Phase */
+#define SPI_CTL_CPOL        0x00000020 /* Clock Polarity */
+#define SPI_CTL_ASSEL       0x00000040 /* Slave Select Pin Control */
+#define SPI_CTL_SELST       0x00000080 /* Slave Select Polarity in transfers */
+#define SPI_CTL_EMISO       0x00000100 /*Enable MISO */
+#define SPI_CTL_SIZE        0x00000600 /*Word Transfer Size */
+#define SPI_CTL_SIZE08      0x00000000 /*SIZE: 8 bits */
+#define SPI_CTL_SIZE16      0x00000200 /*SIZE: 16 bits */
+#define SPI_CTL_SIZE32      0x00000400 /*SIZE: 32 bits */
+#define SPI_CTL_LSBF        0x00001000 /*LSB First */
+#define SPI_CTL_FCEN        0x00002000 /*Flow-Control Enable */
+#define SPI_CTL_FCCH        0x00004000 /*Flow-Control Channel Selection */
+#define SPI_CTL_FCPL        0x00008000 /*Flow-Control Polarity */
+#define SPI_CTL_FCWM        0x00030000 /*Flow-Control Water-Mark */
+#define SPI_CTL_FIFO0       0x00000000 /*FCWM: Tx empty or Rx Full */
+#define SPI_CTL_FIFO1       0x00010000 /*FCWM: Tx empty or Rx full (>=75%) */
+#define SPI_CTL_FIFO2       0x00020000 /*FCWM: Tx empty or Rx full (>=50%) */
+#define SPI_CTL_FMODE       0x00040000 /*Fast-mode Enable */
+#define SPI_CTL_MIOM        0x00300000 /*Multiple I/O Mode */
+#define SPI_CTL_MIO_DIS     0x00000000 /*MIOM: Disable */
+#define SPI_CTL_MIO_DUAL    0x00100000 /*MIOM: Enable DIOM (Dual I/O Mode) */
+#define SPI_CTL_MIO_QUAD    0x00200000 /*MIOM: Enable QUAD (Quad SPI Mode) */
+#define SPI_CTL_SOSI        0x00400000 /*Start on MOSI */
+#define SPI_CTL_MMWEM       0x40000000 /*Start on MMWEM */
+#define SPI_CTL_MMSE        0x80000000 /*Start on MMSE */
+/* SPI_RX_CONTROL */
+#define SPI_RXCTL_REN       0x00000001 /*Receive Channel Enable */
+#define SPI_RXCTL_RTI       0x00000004 /*Receive Transfer Initiate */
+#define SPI_RXCTL_RWCEN     0x00000008 /*Receive Word Counter Enable */
+#define SPI_RXCTL_RDR       0x00000070 /*Receive Data Request */
+#define SPI_RXCTL_RDR_DIS   0x00000000 /*RDR: Disabled */
+#define SPI_RXCTL_RDR_NE    0x00000010 /*RDR: RFIFO not empty */
+#define SPI_RXCTL_RDR_25    0x00000020 /*RDR: RFIFO 25% full */
+#define SPI_RXCTL_RDR_50    0x00000030 /*RDR: RFIFO 50% full */
+#define SPI_RXCTL_RDR_75    0x00000040 /*RDR: RFIFO 75% full */
+#define SPI_RXCTL_RDR_FULL  0x00000050 /*RDR: RFIFO full */
+#define SPI_RXCTL_RDO       0x00000100 /*Receive Data Over-Run */
+#define SPI_RXCTL_RRWM      0x00003000 /*FIFO Regular Water-Mark */
+#define SPI_RXCTL_RWM_0     0x00000000 /*RRWM: RFIFO Empty */
+#define SPI_RXCTL_RWM_25    0x00001000 /*RRWM: RFIFO 25% full */
+#define SPI_RXCTL_RWM_50    0x00002000 /*RRWM: RFIFO 50% full */
+#define SPI_RXCTL_RWM_75    0x00003000 /*RRWM: RFIFO 75% full */
+#define SPI_RXCTL_RUWM      0x00070000 /*FIFO Urgent Water-Mark */
+#define SPI_RXCTL_UWM_DIS   0x00000000 /*RUWM: Disabled */
+#define SPI_RXCTL_UWM_25    0x00010000 /*RUWM: RFIFO 25% full */
+#define SPI_RXCTL_UWM_50    0x00020000 /*RUWM: RFIFO 50% full */
+#define SPI_RXCTL_UWM_75    0x00030000 /*RUWM: RFIFO 75% full */
+#define SPI_RXCTL_UWM_FULL  0x00040000 /*RUWM: RFIFO full */
+/* SPI_TX_CONTROL */
+#define SPI_TXCTL_TEN       0x00000001 /*Transmit Channel Enable */
+#define SPI_TXCTL_TTI       0x00000004 /*Transmit Transfer Initiate */
+#define SPI_TXCTL_TWCEN     0x00000008 /*Transmit Word Counter Enable */
+#define SPI_TXCTL_TDR       0x00000070 /*Transmit Data Request */
+#define SPI_TXCTL_TDR_DIS   0x00000000 /*TDR: Disabled */
+#define SPI_TXCTL_TDR_NF    0x00000010 /*TDR: TFIFO not full */
+#define SPI_TXCTL_TDR_25    0x00000020 /*TDR: TFIFO 25% empty */
+#define SPI_TXCTL_TDR_50    0x00000030 /*TDR: TFIFO 50% empty */
+#define SPI_TXCTL_TDR_75    0x00000040 /*TDR: TFIFO 75% empty */
+#define SPI_TXCTL_TDR_EMPTY 0x00000050 /*TDR: TFIFO empty */
+#define SPI_TXCTL_TDU       0x00000100 /*Transmit Data Under-Run */
+#define SPI_TXCTL_TRWM      0x00003000 /*FIFO Regular Water-Mark */
+#define SPI_TXCTL_RWM_FULL  0x00000000 /*TRWM: TFIFO full */
+#define SPI_TXCTL_RWM_25    0x00001000 /*TRWM: TFIFO 25% empty */
+#define SPI_TXCTL_RWM_50    0x00002000 /*TRWM: TFIFO 50% empty */
+#define SPI_TXCTL_RWM_75    0x00003000 /*TRWM: TFIFO 75% empty */
+#define SPI_TXCTL_TUWM      0x00070000 /*FIFO Urgent Water-Mark */
+#define SPI_TXCTL_UWM_DIS   0x00000000 /*TUWM: Disabled */
+#define SPI_TXCTL_UWM_25    0x00010000 /*TUWM: TFIFO 25% empty */
+#define SPI_TXCTL_UWM_50    0x00020000 /*TUWM: TFIFO 50% empty */
+#define SPI_TXCTL_UWM_75    0x00030000 /*TUWM: TFIFO 75% empty */
+#define SPI_TXCTL_UWM_EMPTY 0x00040000 /*TUWM: TFIFO empty */
+/* SPI_CLOCK */
+#define SPI_CLK_BAUD        0x0000FFFF /*Baud Rate */
+/* SPI_DELAY */
+#define SPI_DLY_STOP        0x000000FF /*Transfer delay time */
+#define SPI_DLY_LEADX       0x00000100 /*Extended (1 SCK) LEAD Control */
+#define SPI_DLY_LAGX        0x00000200 /*Extended (1 SCK) LAG control */
+/* SPI_SSEL */
+#define SPI_SLVSEL_SSE1     0x00000002 /*SPISSEL1 Enable */
+#define SPI_SLVSEL_SSE2     0x00000004 /*SPISSEL2 Enable */
+#define SPI_SLVSEL_SSE3     0x00000008 /*SPISSEL3 Enable */
+#define SPI_SLVSEL_SSE4     0x00000010 /*SPISSEL4 Enable */
+#define SPI_SLVSEL_SSE5     0x00000020 /*SPISSEL5 Enable */
+#define SPI_SLVSEL_SSE6     0x00000040 /*SPISSEL6 Enable */
+#define SPI_SLVSEL_SSE7     0x00000080 /*SPISSEL7 Enable */
+#define SPI_SLVSEL_SSEL1    0x00000200 /*SPISSEL1 Value */
+#define SPI_SLVSEL_SSEL2    0x00000400 /*SPISSEL2 Value */
+#define SPI_SLVSEL_SSEL3    0x00000800 /*SPISSEL3 Value */
+#define SPI_SLVSEL_SSEL4    0x00001000 /*SPISSEL4 Value */
+#define SPI_SLVSEL_SSEL5    0x00002000 /*SPISSEL5 Value */
+#define SPI_SLVSEL_SSEL6    0x00004000 /*SPISSEL6 Value */
+#define SPI_SLVSEL_SSEL7    0x00008000 /*SPISSEL7 Value */
+/* SPI_RWC */
+#define SPI_RWC_VALUE       0x0000FFFF /*Received Word-Count */
+/* SPI_RWCR */
+#define SPI_RWCR_VALUE      0x0000FFFF /*Received Word-Count Reload */
+/* SPI_TWC */
+#define SPI_TWC_VALUE       0x0000FFFF /*Transmitted Word-Count */
+/* SPI_TWCR */
+#define SPI_TWCR_VALUE      0x0000FFFF /*Transmitted Word-Count Reload */
+/* SPI_IMASK */
+#define SPI_IMSK_RUWM       0x00000002 /*Receive Water-Mark Interrupt Mask */
+#define SPI_IMSK_TUWM       0x00000004 /*Transmit Water-Mark Interrupt Mask */
+#define SPI_IMSK_ROM        0x00000010 /*Receive Over-Run Interrupt Mask */
+#define SPI_IMSK_TUM        0x00000020 /*Transmit Under-Run Interrupt Mask */
+#define SPI_IMSK_TCM        0x00000040 /*Transmit Collision Interrupt Mask */
+#define SPI_IMSK_MFM        0x00000080 /*Mode Fault Interrupt Mask */
+#define SPI_IMSK_RSM        0x00000100 /*Receive Start Interrupt Mask */
+#define SPI_IMSK_TSM        0x00000200 /*Transmit Start Interrupt Mask */
+#define SPI_IMSK_RFM        0x00000400 /*Receive Finish Interrupt Mask */
+#define SPI_IMSK_TFM        0x00000800 /*Transmit Finish Interrupt Mask */
+/* SPI_IMASKCL */
+#define SPI_IMSK_CLR_RUW    0x00000002 /*Receive Water-Mark Interrupt Mask */
+#define SPI_IMSK_CLR_TUWM   0x00000004 /*Transmit Water-Mark Interrupt Mask */
+#define SPI_IMSK_CLR_ROM    0x00000010 /*Receive Over-Run Interrupt Mask */
+#define SPI_IMSK_CLR_TUM    0x00000020 /*Transmit Under-Run Interrupt Mask */
+#define SPI_IMSK_CLR_TCM    0x00000040 /*Transmit Collision Interrupt Mask */
+#define SPI_IMSK_CLR_MFM    0x00000080 /*Mode Fault Interrupt Mask */
+#define SPI_IMSK_CLR_RSM    0x00000100 /*Receive Start Interrupt Mask */
+#define SPI_IMSK_CLR_TSM    0x00000200 /*Transmit Start Interrupt Mask */
+#define SPI_IMSK_CLR_RFM    0x00000400 /*Receive Finish Interrupt Mask */
+#define SPI_IMSK_CLR_TFM    0x00000800 /*Transmit Finish Interrupt Mask */
+/* SPI_IMASKST */
+#define SPI_IMSK_SET_RUWM   0x00000002 /*Receive Water-Mark Interrupt Mask */
+#define SPI_IMSK_SET_TUWM   0x00000004 /*Transmit Water-Mark Interrupt Mask */
+#define SPI_IMSK_SET_ROM    0x00000010 /*Receive Over-Run Interrupt Mask */
+#define SPI_IMSK_SET_TUM    0x00000020 /*Transmit Under-Run Interrupt Mask */
+#define SPI_IMSK_SET_TCM    0x00000040 /*Transmit Collision Interrupt Mask */
+#define SPI_IMSK_SET_MFM    0x00000080 /*Mode Fault Interrupt Mask */
+#define SPI_IMSK_SET_RSM    0x00000100 /*Receive Start Interrupt Mask */
+#define SPI_IMSK_SET_TSM    0x00000200 /*Transmit Start Interrupt Mask */
+#define SPI_IMSK_SET_RFM    0x00000400 /*Receive Finish Interrupt Mask */
+#define SPI_IMSK_SET_TFM    0x00000800 /*Transmit Finish Interrupt Mask */
+/* SPI_STATUS */
+#define SPI_STAT_SPIF       0x00000001 /*SPI Finished */
+#define SPI_STAT_RUWM       0x00000002 /*Receive Water-Mark Breached */
+#define SPI_STAT_TUWM       0x00000004 /*Transmit Water-Mark Breached */
+#define SPI_STAT_ROE        0x00000010 /*Receive Over-Run Indication */
+#define SPI_STAT_TUE        0x00000020 /*Transmit Under-Run Indication */
+#define SPI_STAT_TCE        0x00000040 /*Transmit Collision Indication */
+#define SPI_STAT_MODF       0x00000080 /*Mode Fault Indication */
+#define SPI_STAT_RS         0x00000100 /*Receive Start Indication */
+#define SPI_STAT_TS         0x00000200 /*Transmit Start Indication */
+#define SPI_STAT_RF         0x00000400 /*Receive Finish Indication */
+#define SPI_STAT_TF         0x00000800 /*Transmit Finish Indication */
+#define SPI_STAT_RFS        0x00007000 /*SPI_RFIFO status */
+#define SPI_STAT_RFIFO_EMPTY 0x00000000 /*RFS: RFIFO Empty */
+#define SPI_STAT_RFIFO_25   0x00001000 /*RFS: RFIFO 25% Full */
+#define SPI_STAT_RFIFO_50   0x00002000 /*RFS: RFIFO 50% Full */
+#define SPI_STAT_RFIFO_75   0x00003000 /*RFS: RFIFO 75% Full */
+#define SPI_STAT_RFIFO_FULL 0x00004000 /*RFS: RFIFO Full */
+#define SPI_STAT_TFS        0x00070000 /*SPI_TFIFO status */
+#define SPI_STAT_TFIFO_FULL 0x00000000 /*TFS: TFIFO full */
+#define SPI_STAT_TFIFO_25   0x00010000 /*TFS: TFIFO 25% empty */
+#define SPI_STAT_TFIFO_50   0x00020000 /*TFS: TFIFO 50% empty */
+#define SPI_STAT_TFIFO_75   0x00030000 /*TFS: TFIFO 75% empty */
+#define SPI_STAT_TFIFO_EMPTY 0x00040000 /*TFS: TFIFO empty */
+#define SPI_STAT_FCS        0x00100000 /*Flow-Control Stall Indication */
+#define SPI_STAT_RFE        0x00400000 /*SPI_RFIFO Empty */
+#define SPI_STAT_TFF        0x00800000 /*SPI_TFIFO Full */
+/* SPI_ILAT */
+#define SPI_ILAT_RUWMI      0x00000002 /*Receive Water Mark Interrupt */
+#define SPI_ILAT_TUWMI      0x00000004 /*Transmit Water Mark Interrupt */
+#define SPI_ILAT_ROI        0x00000010 /*Receive Over-Run Indication */
+#define SPI_ILAT_TUI        0x00000020 /*Transmit Under-Run Indication */
+#define SPI_ILAT_TCI        0x00000040 /*Transmit Collision Indication */
+#define SPI_ILAT_MFI        0x00000080 /*Mode Fault Indication */
+#define SPI_ILAT_RSI        0x00000100 /*Receive Start Indication */
+#define SPI_ILAT_TSI        0x00000200 /*Transmit Start Indication */
+#define SPI_ILAT_RFI        0x00000400 /*Receive Finish Indication */
+#define SPI_ILAT_TFI        0x00000800 /*Transmit Finish Indication */
+/* SPI_ILATCL */
+#define SPI_ILAT_CLR_RUWMI  0x00000002 /*Receive Water Mark Interrupt */
+#define SPI_ILAT_CLR_TUWMI  0x00000004 /*Transmit Water Mark Interrupt */
+#define SPI_ILAT_CLR_ROI    0x00000010 /*Receive Over-Run Indication */
+#define SPI_ILAT_CLR_TUI    0x00000020 /*Transmit Under-Run Indication */
+#define SPI_ILAT_CLR_TCI    0x00000040 /*Transmit Collision Indication */
+#define SPI_ILAT_CLR_MFI    0x00000080 /*Mode Fault Indication */
+#define SPI_ILAT_CLR_RSI    0x00000100 /*Receive Start Indication */
+#define SPI_ILAT_CLR_TSI    0x00000200 /*Transmit Start Indication */
+#define SPI_ILAT_CLR_RFI    0x00000400 /*Receive Finish Indication */
+#define SPI_ILAT_CLR_TFI    0x00000800 /*Transmit Finish Indication */
+/* SPI_MMRDH */
+#define SPI_MMRDH_MERGE     0x04000000 /*Merge Enable */
+#define SPI_MMRDH_DMY_SZ    0x00007000 /*Bytes of Dummy */
+#define SPI_MMRDH_ADDR_PINS 0x00000800 /*Pins used for Address */
+#define SPI_MMRDH_ADDR_SZ   0x00000700 /*Bytes of Read Address */
+#define SPI_MMRDH_OPCODE    0x000000FF /*Read Opcode */
+
+#define SPI_MMRDH_TRIDMY_OFF	24 /*Bytes of Dummy offset */
+#define SPI_MMRDH_DMY_SZ_OFF	12 /*Bytes of Dummy offset */
+#define SPI_MMRDH_ADDR_SZ_OFF	8  /*Bytes of Read Address offset */
+
+#define BIT_SSEL_VAL(x) ((1 << 8) << (x)) /* Slave Select input value bit */
+#define BIT_SSEL_EN(x) (1 << (x))         /* Slave Select enable bit*/
+
+struct adi_spi_regs {
+	u32 revid;
+	u32 control;
+	u32 rx_control;
+	u32 tx_control;
+	u32 clock;
+	u32 delay;
+	u32 ssel;
+	u32 rwc;
+	u32 rwcr;
+	u32 twc;
+	u32 twcr;
+	u32 reserved0;
+	u32 emask;
+	u32 emaskcl;
+	u32 emaskst;
+	u32 reserved1;
+	u32 status;
+	u32 elat;
+	u32 elatcl;
+	u32 reserved2;
+	u32 rfifo;
+	u32 reserved3;
+	u32 tfifo;
+	u32 reserved4;
+	u32 mmrdh;
+	u32 mmtop;
+};
+
+struct adi_spi_platdata {
+	u32 max_hz;
+	u32 bus_num;
+	struct adi_spi_regs __iomem *regs;
+};
+
+struct adi_spi_priv {
+	u32 control;
+	u32 clock;
+	u32 bus_num;
+	u32 max_cs;
+	struct adi_spi_regs __iomem *regs;
+};
+
+/**
+ * By convention, this driver uses the same CS numbering that is used with the SSEL bit
+ * definitions (both here and in the TRM on which this is based), which are 1-indexed not
+ * 0-indexed. The valid CS range is therefore [1,max_cs], in contrast with other drivers
+ * where it is [0,max_cs-1].
+ */
+static int adi_spi_cs_info(struct udevice *bus, uint cs,
+			   struct spi_cs_info *info)
+{
+	struct adi_spi_priv *priv = dev_get_priv(bus);
+
+	if (cs == 0 || cs > priv->max_cs) {
+		dev_err(bus, "invalid chipselect %u\n", cs);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int adi_spi_of_to_plat(struct udevice *bus)
+{
+	struct adi_spi_platdata *plat = dev_get_plat(bus);
+	fdt_addr_t addr;
+
+	plat->max_hz = dev_read_u32_default(bus, "spi-max-frequency", 500000);
+	plat->bus_num = dev_read_u32_default(bus, "bus-num", 0);
+	addr = dev_read_addr(bus);
+
+	if (addr == FDT_ADDR_T_NONE)
+		return -EINVAL;
+
+	plat->regs = map_sysmem(addr, sizeof(*plat->regs));
+
+	return 0;
+}
+
+static int adi_spi_probe(struct udevice *bus)
+{
+	struct adi_spi_platdata *plat = dev_get_plat(bus);
+	struct adi_spi_priv *priv = dev_get_priv(bus);
+
+	priv->bus_num = plat->bus_num;
+	priv->regs = plat->regs;
+	priv->max_cs = dev_read_u32_default(bus, "num-cs", MAX_CTRL_CS);
+
+	iowrite32(0x0, &plat->regs->control);
+	iowrite32(0x0, &plat->regs->rx_control);
+	iowrite32(0x0, &plat->regs->tx_control);
+
+	return 0;
+}
+
+static int adi_spi_remove(struct udevice *dev)
+{
+	return -ENODEV;
+}
+
+static int adi_spi_claim_bus(struct udevice *dev)
+{
+	struct adi_spi_priv *priv;
+	struct udevice *bus = dev->parent;
+
+	priv = dev_get_priv(bus);
+
+	debug("%s: control:%i clock:%i\n",
+	      __func__, priv->control, priv->clock);
+
+	iowrite32(priv->control, &priv->regs->control);
+	iowrite32(priv->clock, &priv->regs->clock);
+	iowrite32(0x0, &priv->regs->delay);
+
+	return 0;
+}
+
+static int adi_spi_release_bus(struct udevice *dev)
+{
+	struct adi_spi_priv *priv;
+	struct udevice *bus = dev->parent;
+
+	priv = dev_get_priv(bus);
+
+	debug("%s: control:%i clock:%i\n",
+	      __func__, priv->control, priv->clock);
+
+	iowrite32(0x0, &priv->regs->rx_control);
+	iowrite32(0x0, &priv->regs->tx_control);
+	iowrite32(0x0, &priv->regs->control);
+
+	return 0;
+}
+
+void adi_spi_enable_ssel(struct adi_spi_priv *priv, int cs)
+{
+	setbits_32(&priv->regs->ssel, BIT_SSEL_EN(cs));
+}
+
+void adi_spi_set_ssel(struct adi_spi_priv *priv, int cs, int high)
+{
+	if (high)
+		setbits_32(&priv->regs->ssel, BIT_SSEL_VAL(cs));
+	else
+		clrbits_32(&priv->regs->ssel, BIT_SSEL_VAL(cs));
+}
+
+void adi_spi_cs_activate(struct adi_spi_priv *priv, struct dm_spi_slave_plat *slave_plat)
+{
+	bool high = slave_plat->mode & SPI_CS_HIGH;
+
+	adi_spi_set_ssel(priv, slave_plat->cs[0], high);
+	adi_spi_enable_ssel(priv, slave_plat->cs[0]);
+}
+
+void adi_spi_cs_deactivate(struct adi_spi_priv *priv, struct dm_spi_slave_plat *slave_plat)
+{
+	bool high = slave_plat->mode & SPI_CS_HIGH;
+
+	/* invert CS for matching SSEL to deactivate */
+	adi_spi_set_ssel(priv, slave_plat->cs[0], !high);
+}
+
+static void discard_rx_fifo_contents(struct adi_spi_regs *regs)
+{
+	while (!(ioread32(&regs->status) & SPI_STAT_RFE))
+		ioread32(&regs->rfifo);
+}
+
+static int adi_spi_fifo_mio_xfer(struct adi_spi_priv *priv, const u8 *tx, u8 *rx,
+				 uint bytes, uint32_t mio_mode)
+{
+	u8 value;
+
+	/* switch current SPI transfer to mio SPI mode */
+	clrsetbits_32(&priv->regs->control, SPI_CTL_SOSI, mio_mode);
+	/*
+	 * Data can only be transferred in one direction in multi-io SPI
+	 * modes, trigger the transfer in respective direction.
+	 */
+	if (rx) {
+		iowrite32(0x0, &priv->regs->tx_control);
+		iowrite32(SPI_RXCTL_REN | SPI_RXCTL_RTI, &priv->regs->rx_control);
+
+		while (bytes--) {
+			while (ioread32(&priv->regs->status) &
+				SPI_STAT_RFE)
+				if (ctrlc())
+					return -1;
+			value = ioread32(&priv->regs->rfifo);
+			*rx++ = value;
+		}
+	} else if (tx) {
+		iowrite32(0x0, &priv->regs->rx_control);
+		iowrite32(SPI_TXCTL_TEN | SPI_TXCTL_TTI, &priv->regs->tx_control);
+
+		while (bytes--) {
+			value = *tx++;
+			iowrite32(value, &priv->regs->tfifo);
+			while (ioread32(&priv->regs->status) &
+				SPI_STAT_TFF)
+				if (ctrlc())
+					return -1;
+		}
+
+		/* Wait till the tfifo is empty */
+		while ((ioread32(&priv->regs->status) & SPI_STAT_TFS) != SPI_STAT_TFIFO_EMPTY)
+			if (ctrlc())
+				return -1;
+	} else {
+		return -1;
+	}
+	return 0;
+}
+
+static int adi_spi_fifo_1x_xfer(struct adi_spi_priv *priv, const u8 *tx, u8 *rx,
+				uint bytes)
+{
+	u8 value;
+
+	/*
+	 * Set current SPI transfer in normal mode and trigger
+	 * the bi-direction transfer by tx write operation.
+	 */
+	iowrite32(priv->control, &priv->regs->control);
+	iowrite32(SPI_RXCTL_REN, &priv->regs->rx_control);
+	iowrite32(SPI_TXCTL_TEN | SPI_TXCTL_TTI, &priv->regs->tx_control);
+
+	while (bytes--) {
+		value = (tx ? *tx++ : SPI_IDLE_VAL);
+		debug("%s: tx:%x ", __func__, value);
+		iowrite32(value, &priv->regs->tfifo);
+		while (ioread32(&priv->regs->status) & SPI_STAT_RFE)
+			if (ctrlc())
+				return -1;
+		value = ioread32(&priv->regs->rfifo);
+		if (rx)
+			*rx++ = value;
+		debug("rx:%x\n", value);
+	}
+	return 0;
+}
+
+static int adi_spi_fifo_xfer(struct adi_spi_priv *priv, int buswidth,
+			     const u8 *tx, u8 *rx, uint bytes)
+{
+	switch (buswidth) {
+	case 1:
+		return adi_spi_fifo_1x_xfer(priv, tx, rx, bytes);
+	case 2:
+		return adi_spi_fifo_mio_xfer(priv, tx, rx, bytes, SPI_CTL_MIO_DUAL);
+	case 4:
+		return adi_spi_fifo_mio_xfer(priv, tx, rx, bytes, SPI_CTL_MIO_QUAD);
+	default:
+		return -ENOTSUPP;
+	}
+}
+
+static int adi_spi_xfer(struct udevice *dev, unsigned int bitlen,
+			const void *dout, void *din, unsigned long flags)
+{
+	struct udevice *bus = dev->parent;
+	struct adi_spi_priv *priv = dev_get_priv(bus);
+	struct dm_spi_slave_plat *slave_plat = dev_get_parent_plat(dev);
+
+	const u8 *tx = dout;
+	u8 *rx = din;
+	uint bytes = bitlen / 8;
+	int ret = 0;
+
+	debug("%s: bus_num:%i cs:%i bitlen:%i bytes:%i flags:%lx\n", __func__,
+	      priv->bus_num, slave_plat->cs[0], bitlen, bytes, flags);
+
+	if (flags & SPI_XFER_BEGIN)
+		adi_spi_cs_activate(priv, slave_plat);
+
+	if (bitlen == 0)
+		goto done;
+
+	/* we can only do 8 bit transfers */
+	if (bitlen % 8) {
+		flags |= SPI_XFER_END;
+		goto done;
+	}
+
+	/* Discard invalid rx data and empty rfifo */
+	discard_rx_fifo_contents(priv->regs);
+
+	ret = adi_spi_fifo_1x_xfer(priv, tx, rx, bytes);
+
+ done:
+	if (flags & SPI_XFER_END)
+		adi_spi_cs_deactivate(priv, slave_plat);
+
+	return ret;
+}
+
+static int adi_spi_set_speed(struct udevice *bus, uint speed)
+{
+	struct adi_spi_platdata *plat = dev_get_plat(bus);
+	struct adi_spi_priv *priv = dev_get_priv(bus);
+	int ret;
+	u32 clock, spi_base_clk;
+	struct clk spi_clk;
+
+	ret = clk_get_by_name(bus, "spi", &spi_clk);
+	if (ret < 0) {
+		dev_err(bus, "Can't get SPI clk: %d\n", ret);
+		return ret;
+	}
+	spi_base_clk = clk_get_rate(&spi_clk);
+
+	if (speed > plat->max_hz)
+		speed = plat->max_hz;
+
+	if (speed > spi_base_clk)
+		return -ENODEV;
+
+	clock = spi_base_clk / speed;
+	if (clock)
+		clock--;
+
+	priv->clock = clock;
+
+	debug("%s: priv->clock: %x, speed: %x, get_spi_clk(): %x\n",
+	      __func__, clock, speed, spi_base_clk);
+
+	return 0;
+}
+
+static int adi_spi_set_mode(struct udevice *bus, uint mode)
+{
+	struct adi_spi_priv *priv = dev_get_priv(bus);
+	u32 reg;
+
+	reg = SPI_CTL_EN | SPI_CTL_MSTR;
+	if (mode & SPI_CPHA)
+		reg |= SPI_CTL_CPHA;
+	if (mode & SPI_CPOL)
+		reg |= SPI_CTL_CPOL;
+	if (mode & SPI_LSB_FIRST)
+		reg |= SPI_CTL_LSBF;
+	reg &= ~SPI_CTL_ASSEL;
+
+	priv->control = reg;
+
+	debug("%s: control=%d, cs_pol=%d\n", __func__, reg, mode & SPI_CS_HIGH ? 1 : 0);
+
+	return 0;
+}
+
+/**
+ * U-boot's version of spi-mem does not support mixed bus-width
+ * commands nor anything more than 1x mode.
+ * Using a custom exec_op implementation, we can support it.
+ */
+static int adi_spi_mem_exec_op(struct spi_slave *slave,
+			       const struct spi_mem_op *op)
+{
+	int rv = 0;
+	struct udevice *bus = slave->dev->parent;
+	struct adi_spi_priv *priv = dev_get_priv(bus);
+	struct dm_spi_slave_plat *slave_plat = dev_get_parent_plat(slave->dev);
+	u8 tmpbuf[64];
+	int i;
+
+	if ((op->cmd.nbytes + op->addr.nbytes + op->dummy.nbytes) >
+	    sizeof(tmpbuf))
+		return -ENOMEM;
+
+	for (i = 0; i < op->cmd.nbytes; i++)
+		tmpbuf[i] = op->cmd.opcode >>
+				(8 * (op->cmd.nbytes - i - 1));
+	for (i = 0; i < op->addr.nbytes; i++)
+		tmpbuf[i + op->cmd.nbytes] = op->addr.val >>
+				(8 * (op->addr.nbytes - i - 1));
+	memset(tmpbuf + op->addr.nbytes + op->cmd.nbytes, 0xff,
+	       op->dummy.nbytes);
+
+	adi_spi_cs_activate(priv, slave_plat);
+	discard_rx_fifo_contents(priv->regs);
+
+	if (op->cmd.nbytes) {
+		rv = adi_spi_fifo_xfer(priv, op->cmd.buswidth,
+				       tmpbuf, NULL, op->cmd.nbytes);
+		if (rv != 0)
+			goto cleanup;
+	}
+
+	if (op->addr.nbytes) {
+		rv = adi_spi_fifo_xfer(priv, op->addr.buswidth,
+				       tmpbuf + op->cmd.nbytes, NULL,
+				       op->addr.nbytes);
+		if (rv != 0)
+			goto cleanup;
+	}
+
+	if (op->dummy.nbytes) {
+		rv = adi_spi_fifo_xfer(priv, op->dummy.buswidth,
+				       tmpbuf + op->cmd.nbytes +
+				       op->addr.nbytes,
+				       NULL, op->dummy.nbytes);
+		if (rv != 0)
+			goto cleanup;
+	}
+
+	if (op->data.dir == SPI_MEM_DATA_IN)
+		rv = adi_spi_fifo_xfer(priv, op->data.buswidth,
+				       NULL, op->data.buf.in,
+				       op->data.nbytes);
+	else if (op->data.dir == SPI_MEM_DATA_OUT)
+		rv = adi_spi_fifo_xfer(priv, op->data.buswidth,
+				       op->data.buf.out, NULL,
+				       op->data.nbytes);
+
+cleanup:
+	adi_spi_cs_deactivate(priv, slave_plat);
+	return rv;
+}
+
+static const struct spi_controller_mem_ops adi_spi_mem_ops = {
+	.exec_op = adi_spi_mem_exec_op,
+};
+
+static const struct dm_spi_ops adi_spi_ops = {
+	.claim_bus = adi_spi_claim_bus,
+	.release_bus = adi_spi_release_bus,
+	.xfer = adi_spi_xfer,
+	.set_speed = adi_spi_set_speed,
+	.set_mode = adi_spi_set_mode,
+	.cs_info = adi_spi_cs_info,
+	.mem_ops = &adi_spi_mem_ops,
+};
+
+static const struct udevice_id adi_spi_ids[] = {
+	{ .compatible = "adi,spi3" },
+	{ }
+};
+
+U_BOOT_DRIVER(adi_spi3) = {
+	.name = "adi_spi3",
+	.id = UCLASS_SPI,
+	.of_match = adi_spi_ids,
+	.ops = &adi_spi_ops,
+	.of_to_plat = adi_spi_of_to_plat,
+	.probe = adi_spi_probe,
+	.remove = adi_spi_remove,
+	.plat_auto = sizeof(struct adi_spi_platdata),
+	.priv_auto = sizeof(struct adi_spi_priv),
+	.per_child_auto = sizeof(struct spi_slave),
+};
-- 
2.45.2


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v3 12/12] mmc: Add support for ADI SC5XX-family processor SDHCI peripherals
  2025-02-26 17:30 [PATCH v3 00/12] drivers: Driver support for ADI SC5xx SoCs Greg Malysa
                   ` (10 preceding siblings ...)
  2025-02-26 17:30 ` [PATCH v3 11/12] spi: Add support for ADI SC5XX-family processor SPI peripherals Greg Malysa
@ 2025-02-26 17:30 ` Greg Malysa
  2025-03-12 19:43 ` [PATCH v3 00/12] drivers: Driver support for ADI SC5xx SoCs Tom Rini
  12 siblings, 0 replies; 16+ messages in thread
From: Greg Malysa @ 2025-02-26 17:30 UTC (permalink / raw)
  To: u-boot
  Cc: adsp-linux, Nathan Barrett-Morrison, Greg Malysa, Ian Roberts,
	Vasileios Bimpikas, Utsav Agarwal, Arturs Artamonovs,
	Oliver Gaskell, Caleb Connolly, Greg Malysa, Heinrich Schuchardt,
	Jaehoon Chung, Jonas Karlman, Kongyang Liu, Linus Walleij,
	Maksim Kiselev, Mattijs Korpershoek, Peng Fan, Peter Robinson,
	Robert Marko, Sam Protsenko, Simon Glass, Tom Rini

From: Nathan Barrett-Morrison <nathan.morrison@timesys.com>

Co-developed-by: Greg Malysa <malysagreg@gmail.com>
Signed-off-by: Greg Malysa <malysagreg@gmail.com>
Co-developed-by: Ian Roberts <ian.roberts@timesys.com>
Signed-off-by: Ian Roberts <ian.roberts@timesys.com>
Signed-off-by: Vasileios Bimpikas <vasileios.bimpikas@analog.com>
Signed-off-by: Utsav Agarwal <utsav.agarwal@analog.com>
Signed-off-by: Arturs Artamonovs <arturs.artamonovs@analog.com>
Signed-off-by: Oliver Gaskell <Oliver.Gaskell@analog.com>
Signed-off-by: Nathan Barrett-Morrison <nathan.morrison@timesys.com>

---

Changes in v3:
- Removed struct adi_sdhc and replaced with the struct that was its only
  member

 MAINTAINERS             |   1 +
 drivers/mmc/Kconfig     |   9 +++
 drivers/mmc/Makefile    |   1 +
 drivers/mmc/adi_sdhci.c | 148 ++++++++++++++++++++++++++++++++++++++++
 4 files changed, 159 insertions(+)
 create mode 100644 drivers/mmc/adi_sdhci.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 889695c1edd..31adefd9f9c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -636,6 +636,7 @@ F:	drivers/dma/adi_dma.c
 F:	drivers/gpio/adp5588_gpio.c
 F:	drivers/gpio/gpio-adi-adsp.c
 F:	drivers/i2c/adi_i2c.c
+F:	drivers/mmc/adi_sdhci.c
 F:	drivers/net/dwc_eth_qos_adi.c
 F:	drivers/pinctrl/pinctrl-adi-adsp.c
 F:	drivers/remoteproc/adi_sc5xx_rproc.c
diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig
index 4827834b4aa..ab56bd3939f 100644
--- a/drivers/mmc/Kconfig
+++ b/drivers/mmc/Kconfig
@@ -292,6 +292,15 @@ config MMC_DW_ROCKCHIP
 	  SD 3.0, SDIO 3.0 and MMC 4.5 and supports common eMMC chips as well
 	  as removeable SD and micro-SD cards.
 
+config MMC_SDHCI_ADI
+	bool "ADI SD/MMC controller support"
+	depends on ARCH_SC5XX
+	depends on DM_MMC && OF_CONTROL
+	depends on MMC_SDHCI && MMC_SDHCI_ADMA
+	help
+	  This enables support for the SD/MMC controller included in some Analog
+	  Devices SC5XX Socs.
+
 config MMC_DW_SOCFPGA
 	bool "SOCFPGA specific extensions for Synopsys DW Memory Card Interface"
 	depends on ARCH_SOCFPGA
diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile
index 90e76f90769..94ed28ead71 100644
--- a/drivers/mmc/Makefile
+++ b/drivers/mmc/Makefile
@@ -70,6 +70,7 @@ obj-$(CONFIG_MMC_SDHCI_MV)		+= mv_sdhci.o
 obj-$(CONFIG_MMC_SDHCI_NPCM)            += npcm_sdhci.o
 obj-$(CONFIG_MMC_SDHCI_PIC32)		+= pic32_sdhci.o
 obj-$(CONFIG_MMC_SDHCI_ROCKCHIP)	+= rockchip_sdhci.o
+obj-$(CONFIG_MMC_SDHCI_ADI)		+= adi_sdhci.o
 obj-$(CONFIG_MMC_SDHCI_S5P)		+= s5p_sdhci.o
 obj-$(CONFIG_MMC_SDHCI_SNPS)		+= snps_sdhci.o
 obj-$(CONFIG_MMC_SDHCI_STI)		+= sti_sdhci.o
diff --git a/drivers/mmc/adi_sdhci.c b/drivers/mmc/adi_sdhci.c
new file mode 100644
index 00000000000..65a22cefb71
--- /dev/null
+++ b/drivers/mmc/adi_sdhci.c
@@ -0,0 +1,148 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * (C) Copyright 2022 - Analog Devices, Inc.
+ *
+ * Written and/or maintained by Timesys Corporation
+ *
+ * Contact: Nathan Barrett-Morrison <nathan.morrison@timesys.com>
+ * Contact: Greg Malysa <greg.malysa@timesys.com>
+ *
+ * Based on Rockchip's sdhci.c file
+ */
+
+#include <clk.h>
+#include <dm.h>
+#include <malloc.h>
+#include <sdhci.h>
+#include <asm/cache.h>
+
+/* 400KHz is max freq for card ID etc. Use that as min */
+#define EMMC_MIN_FREQ	400000
+
+/* Check if an operation crossed a boundary of size ADMA_BOUNDARY_ALIGN */
+#define ADMA_BOUNDARY_ALGN SZ_128M
+#define BOUNDARY_OK(addr, len) \
+	(((addr) | (ADMA_BOUNDARY_ALGN - 1)) == (((addr) + (len) - 1) | \
+	(ADMA_BOUNDARY_ALGN - 1)))
+
+/* We split a descriptor for every crossing of the ADMA alignment boundary,
+ * so we need an additional descriptor for every expected crossing.
+ * As I understand it, the max expected transaction size is:
+ *  CONFIG_SYS_MMC_MAX_BLK_COUNT * MMC_MAX_BLOCK_LEN
+ *
+ * With the way the SDHCI-ADMA driver is implemented, if ADMA_MAX_LEN was a
+ * clean power of two, we'd only ever need +1 descriptor as the first
+ * descriptor that got split would then bring the remaining DMA
+ * destination addresses into alignment. Unfortunately, it's currently
+ * hardcoded to a non-power-of-two value.
+ *
+ * If that ever becomes parameterized, ADMA max length can be set to
+ * 0x10000, and set this to 1.
+ */
+#define ADMA_POTENTIAL_CROSSINGS \
+	DIV_ROUND_UP((CONFIG_SYS_MMC_MAX_BLK_COUNT * MMC_MAX_BLOCK_LEN), \
+		 ADMA_BOUNDARY_ALGN)
+/* +1 descriptor for each crossing.
+ */
+#define ADMA_TABLE_EXTRA_SZ (ADMA_POTENTIAL_CROSSINGS * ADMA_DESC_LEN)
+
+struct adi_sdhc_plat {
+	struct mmc_config cfg;
+	struct mmc mmc;
+};
+
+void adi_dwcmshc_adma_write_desc(struct sdhci_host *host, void **desc,
+				 dma_addr_t addr, int len, bool end)
+{
+	int tmplen, offset;
+
+	if (likely(!len || BOUNDARY_OK(addr, len))) {
+		sdhci_adma_write_desc(host, desc, addr, len, end);
+		return;
+	}
+
+	offset = addr & (ADMA_BOUNDARY_ALGN - 1);
+	tmplen = ADMA_BOUNDARY_ALGN - offset;
+	sdhci_adma_write_desc(host, desc, addr, tmplen, false);
+
+	addr += tmplen;
+	len -= tmplen;
+	sdhci_adma_write_desc(host, desc, addr, len, end);
+}
+
+struct sdhci_ops adi_dwcmshc_sdhci_ops = {
+	.adma_write_desc = adi_dwcmshc_adma_write_desc,
+};
+
+static int adi_dwcmshc_sdhci_probe(struct udevice *dev)
+{
+	struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
+	struct adi_sdhc_plat *plat = dev_get_plat(dev);
+	struct sdhci_host *host = dev_get_priv(dev);
+	int max_frequency, ret;
+	struct clk clk;
+
+	max_frequency = dev_read_u32_default(dev, "max-frequency", 0);
+	ret = clk_get_by_index(dev, 0, &clk);
+
+	host->quirks = 0;
+	host->max_clk = max_frequency;
+	/*
+	 * The sdhci-driver only supports 4bit and 8bit, as sdhci_setup_cfg
+	 * doesn't allow us to clear MMC_MODE_4BIT.  Consequently, we don't
+	 * check for other bus-width values.
+	 */
+	if (host->bus_width == 8)
+		host->host_caps |= MMC_MODE_8BIT;
+
+	host->mmc = &plat->mmc;
+	host->mmc->priv = host;
+	host->mmc->dev = dev;
+	upriv->mmc = host->mmc;
+
+	host->ops = &adi_dwcmshc_sdhci_ops;
+	host->adma_desc_table = memalign(ARCH_DMA_MINALIGN,
+					 ADMA_TABLE_SZ + ADMA_TABLE_EXTRA_SZ);
+	host->adma_addr = virt_to_phys(host->adma_desc_table);
+
+	ret = sdhci_setup_cfg(&plat->cfg, host, 0, EMMC_MIN_FREQ);
+	if (ret)
+		return ret;
+
+	return sdhci_probe(dev);
+}
+
+static int adi_dwcmshc_sdhci_of_to_plat(struct udevice *dev)
+{
+	struct sdhci_host *host = dev_get_priv(dev);
+
+	host->name = dev->name;
+	host->ioaddr = dev_read_addr_ptr(dev);
+	host->bus_width = dev_read_u32_default(dev, "bus-width", 4);
+
+	return 0;
+}
+
+static int adi_sdhci_bind(struct udevice *dev)
+{
+	struct adi_sdhc_plat *plat = dev_get_plat(dev);
+
+	return sdhci_bind(dev, &plat->mmc, &plat->cfg);
+}
+
+static const struct udevice_id adi_dwcmshc_sdhci_ids[] = {
+	{ .compatible = "adi,dwc-sdhci" },
+	{ }
+};
+
+U_BOOT_DRIVER(adi_dwcmshc_sdhci_drv) = {
+	.name		= "adi_sdhci",
+	.id		= UCLASS_MMC,
+	.of_match	= adi_dwcmshc_sdhci_ids,
+	.of_to_plat	= adi_dwcmshc_sdhci_of_to_plat,
+	.ops		= &sdhci_ops,
+	.bind		= adi_sdhci_bind,
+	.probe		= adi_dwcmshc_sdhci_probe,
+	.priv_auto	= sizeof(struct sdhci_host),
+	.plat_auto	= sizeof(struct adi_sdhc_plat),
+};
-- 
2.45.2


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* Re: [PATCH v3 08/12] watchdog: Add support for ADI SC5XX-family watchdog peripheral
  2025-02-26 17:30 ` [PATCH v3 08/12] watchdog: Add support for ADI SC5XX-family watchdog peripheral Greg Malysa
@ 2025-02-27  8:44   ` Stefan Roese
  0 siblings, 0 replies; 16+ messages in thread
From: Stefan Roese @ 2025-02-27  8:44 UTC (permalink / raw)
  To: Greg Malysa, u-boot
  Cc: adsp-linux, Nathan Barrett-Morrison, Ian Roberts,
	Vasileios Bimpikas, Utsav Agarwal, Arturs Artamonovs,
	Oliver Gaskell, Bastien Curutchet, Caleb Connolly,
	Devarsh Thakkar, Fabio Estevam, Greg Malysa, Heiko Schocher,
	Mattijs Korpershoek, Rasmus Villemoes, Robert Marko,
	Sam Protsenko, Simon Glass, Tom Rini

On 26.02.25 18:30, Greg Malysa wrote:
> From: Nathan Barrett-Morrison <nathan.morrison@timesys.com>
> 
> Co-developed-by: Greg Malysa <malysagreg@gmail.com>
> Signed-off-by: Greg Malysa <malysagreg@gmail.com>
> Co-developed-by: Ian Roberts <ian.roberts@timesys.com>
> Signed-off-by: Ian Roberts <ian.roberts@timesys.com>
> Signed-off-by: Vasileios Bimpikas <vasileios.bimpikas@analog.com>
> Signed-off-by: Utsav Agarwal <utsav.agarwal@analog.com>
> Signed-off-by: Arturs Artamonovs <arturs.artamonovs@analog.com>
> Signed-off-by: Oliver Gaskell <Oliver.Gaskell@analog.com>
> Signed-off-by: Nathan Barrett-Morrison <nathan.morrison@timesys.com>
> 
> ---
> 
> Changes in v3:
> - replace readl/writel with ioread32 and iowrite32 and friends

Reviewed-by: Stefan Roese <sr@denx.de>

BTW: I already added my RB tag on v1, please include it in later
versions, if not bigger changes occur.

Thanks,
Stefan

>   MAINTAINERS                |   1 +
>   drivers/watchdog/Kconfig   |   9 +++
>   drivers/watchdog/Makefile  |   1 +
>   drivers/watchdog/adi_wdt.c | 143 +++++++++++++++++++++++++++++++++++++
>   4 files changed, 154 insertions(+)
>   create mode 100644 drivers/watchdog/adi_wdt.c
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 2c4dc8b14c1..0cefd888885 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -640,6 +640,7 @@ F:	drivers/pinctrl/pinctrl-adi-adsp.c
>   F:	drivers/serial/serial_adi_uart4.c
>   F:	drivers/timer/adi_sc5xx_timer.c
>   F:	drivers/usb/musb-new/sc5xx.c
> +F:	drivers/watchdog/adi_wdt.c
>   F:	include/configs/sc5*
>   F:	include/dt-bindings/pinctrl/adi-adsp.h
>   F:	include/env/adi/
> diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
> index b39b2546e5c..1bb67f50352 100644
> --- a/drivers/watchdog/Kconfig
> +++ b/drivers/watchdog/Kconfig
> @@ -95,6 +95,15 @@ config WDT_APPLE
>   	  The watchdog will perform a full SoC reset resulting in a
>   	  reboot of the entire system.
>   
> +config WDT_ADI
> +	bool "Analog Devices watchdog timer support"
> +	select WDT
> +	select SPL_WDT if SPL
> +	depends on ARCH_SC5XX
> +	help
> +	  Enable this to support Watchdog Timer on ADI SC57X, SC58X, SC59X,
> +	  and SC59X_64 processors
> +
>   config WDT_ARMADA_37XX
>   	bool "Marvell Armada 37xx watchdog timer support"
>   	depends on WDT && ARMADA_3700
> diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
> index 9b6b1a8e8ad..e6bd4c587af 100644
> --- a/drivers/watchdog/Makefile
> +++ b/drivers/watchdog/Makefile
> @@ -53,3 +53,4 @@ obj-$(CONFIG_WDT_STM32MP) += stm32mp_wdt.o
>   obj-$(CONFIG_WDT_SUNXI) += sunxi_wdt.o
>   obj-$(CONFIG_WDT_TANGIER) += tangier_wdt.o
>   obj-$(CONFIG_WDT_XILINX) += xilinx_wwdt.o
> +obj-$(CONFIG_WDT_ADI) += adi_wdt.o
> diff --git a/drivers/watchdog/adi_wdt.c b/drivers/watchdog/adi_wdt.c
> new file mode 100644
> index 00000000000..6f5b3d5d042
> --- /dev/null
> +++ b/drivers/watchdog/adi_wdt.c
> @@ -0,0 +1,143 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * (C) Copyright 2022 - Analog Devices, Inc.
> + *
> + * Written and/or maintained by Timesys Corporation
> + *
> + * Converted to driver model by Nathan Barrett-Morrison
> + *
> + * Contact: Nathan Barrett-Morrison <nathan.morrison@timesys.com>
> + * Contact: Greg Malysa <greg.malysa@timesys.com>
> + *
> + * adi_wtd.c - driver for ADI on-chip watchdog
> + *
> + */
> +
> +#include <clk.h>
> +#include <dm.h>
> +#include <wdt.h>
> +#include <linux/delay.h>
> +#include <linux/ioport.h>
> +#include <linux/io.h>
> +
> +#define WDOG_CTL  0x0
> +#define WDOG_CNT  0x4
> +#define WDOG_STAT 0x8
> +
> +#define RCU_CTL   0x0
> +#define RCU_STAT  0x4
> +
> +#define SEC_GCTL  0x0
> +#define SEC_FCTL  0x10
> +#define SEC_SCTL0 0x800
> +
> +#define WDEN      0x0010
> +#define WDDIS     0x0AD0
> +
> +struct adi_wdt_priv {
> +	void __iomem *rcu_base;
> +	void __iomem *sec_base;
> +	void __iomem *wdt_base;
> +	struct clk clock;
> +};
> +
> +static int adi_wdt_reset(struct udevice *dev)
> +{
> +	struct adi_wdt_priv *priv = dev_get_priv(dev);
> +
> +	iowrite32(0, priv->wdt_base + WDOG_STAT);
> +
> +	return 0;
> +}
> +
> +static int adi_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags)
> +{
> +	struct adi_wdt_priv *priv = dev_get_priv(dev);
> +
> +	/* Disable SYSCD_RESETb input and clear the RCU0 reset status */
> +	iowrite32(0xf, priv->rcu_base + RCU_STAT);
> +	iowrite32(0x0, priv->rcu_base + RCU_CTL);
> +
> +	/* reset the SEC controller */
> +	iowrite32(0x2, priv->sec_base + SEC_GCTL);
> +	iowrite32(0x2, priv->sec_base + SEC_FCTL);
> +
> +	udelay(50);
> +
> +	/* enable SEC fault event */
> +	iowrite32(0x1, priv->sec_base + SEC_GCTL);
> +
> +	/* ANOMALY 36100004 Spurious External Fault event occurs when FCTL
> +	 * is re-programmed when currently active fault is not cleared
> +	 */
> +	iowrite32(0xc0, priv->sec_base + SEC_FCTL);
> +	iowrite32(0xc1, priv->sec_base + SEC_FCTL);
> +
> +	/* enable SEC fault source for watchdog0 */
> +	setbits_32(priv->sec_base + SEC_SCTL0 + (3*8), 0x6);
> +
> +	/* Enable SYSCD_RESETb input */
> +	iowrite32(0x100, priv->rcu_base + RCU_CTL);
> +
> +	/* enable watchdog0 */
> +	iowrite32(WDDIS, priv->wdt_base + WDOG_CTL);
> +
> +	iowrite32(timeout_ms / 1000 *
> +	       (clk_get_rate(&priv->clock) / (IS_ENABLED(CONFIG_SC58X) ? 2 : 1)),
> +	       priv->wdt_base + WDOG_CNT);
> +
> +	iowrite32(0, priv->wdt_base + WDOG_STAT);
> +	iowrite32(WDEN, priv->wdt_base + WDOG_CTL);
> +
> +	return 0;
> +}
> +
> +static int adi_wdt_probe(struct udevice *dev)
> +{
> +	struct adi_wdt_priv *priv = dev_get_priv(dev);
> +	int ret;
> +	struct resource res;
> +
> +	ret = dev_read_resource_byname(dev, "rcu", &res);
> +	if (ret)
> +		return ret;
> +	priv->rcu_base = devm_ioremap(dev, res.start, resource_size(&res));
> +
> +	ret = dev_read_resource_byname(dev, "sec", &res);
> +	if (ret)
> +		return ret;
> +	priv->sec_base = devm_ioremap(dev, res.start, resource_size(&res));
> +
> +	ret = dev_read_resource_byname(dev, "wdt", &res);
> +	if (ret)
> +		return ret;
> +	priv->wdt_base = devm_ioremap(dev, res.start, resource_size(&res));
> +
> +	ret = clk_get_by_name(dev, "sclk0", &priv->clock);
> +	if (ret < 0) {
> +		printf("Can't get WDT clk: %d\n", ret);
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static const struct wdt_ops adi_wdt_ops = {
> +	.start		= adi_wdt_start,
> +	.reset		= adi_wdt_reset,
> +};
> +
> +static const struct udevice_id adi_wdt_ids[] = {
> +	{ .compatible = "adi,wdt" },
> +	{}
> +};
> +
> +U_BOOT_DRIVER(adi_wdt) = {
> +	.name		= "adi_wdt",
> +	.id		= UCLASS_WDT,
> +	.of_match	= adi_wdt_ids,
> +	.probe		= adi_wdt_probe,
> +	.ops		= &adi_wdt_ops,
> +	.priv_auto = sizeof(struct adi_wdt_priv),
> +	.flags		= DM_FLAG_PRE_RELOC,
> +};

Viele Grüße,
Stefan Roese

-- 
DENX Software Engineering GmbH,      Managing Director: Erika Unter
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-51 Fax: (+49)-8142-66989-80 Email: sr@denx.de


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v3 06/12] i2c: Add support for ADI SC5XX-family I2C peripheral
  2025-02-26 17:30 ` [PATCH v3 06/12] i2c: Add support for ADI SC5XX-family I2C peripheral Greg Malysa
@ 2025-03-06  5:56   ` Heiko Schocher
  0 siblings, 0 replies; 16+ messages in thread
From: Heiko Schocher @ 2025-03-06  5:56 UTC (permalink / raw)
  To: Greg Malysa, u-boot
  Cc: adsp-linux, Nathan Barrett-Morrison, Ian Roberts,
	Angelo Dureghello, Vasileios Bimpikas, Utsav Agarwal,
	Arturs Artamonovs, Oliver Gaskell, Caleb Connolly, David Virag,
	Greg Malysa, Marek Vasut, Mattijs Korpershoek, Neil Armstrong,
	Paul Barker, Robert Marko, Sam Protsenko, Simon Glass, Tom Rini

Hello Greg,

On 26.02.25 18:30, Greg Malysa wrote:
> From: Nathan Barrett-Morrison <nathan.morrison@timesys.com>
> 
> Co-developed-by: Greg Malysa <malysagreg@gmail.com>
> Signed-off-by: Greg Malysa <malysagreg@gmail.com>
> Co-developed-by: Ian Roberts <ian.roberts@timesys.com>
> Signed-off-by: Ian Roberts <ian.roberts@timesys.com>
> Co-developed-by: Angelo Dureghello <angelo.dureghello@timesys.com>
> Signed-off-by: Angelo Dureghello <angelo.dureghello@timesys.com>
> Signed-off-by: Vasileios Bimpikas <vasileios.bimpikas@analog.com>
> Signed-off-by: Utsav Agarwal <utsav.agarwal@analog.com>
> Signed-off-by: Arturs Artamonovs <arturs.artamonovs@analog.com>
> Signed-off-by: Oliver Gaskell <Oliver.Gaskell@analog.com>
> Signed-off-by: Nathan Barrett-Morrison <nathan.morrison@timesys.com>
> 
> ---
> 
> Changes in v3:
> - replace readw/writew with ioread16 and iowrite16 and friends
> 
>   MAINTAINERS           |   1 +
>   drivers/i2c/Kconfig   |   7 +
>   drivers/i2c/Makefile  |   1 +
>   drivers/i2c/adi_i2c.c | 386 ++++++++++++++++++++++++++++++++++++++++++
>   4 files changed, 395 insertions(+)
>   create mode 100644 drivers/i2c/adi_i2c.c

I am unsure if I not already sended a Reviewed by in an earlier version, so:

Reviewed-by: Heiko Schocher <hs@denx.de>

Thanks!

bye,
HEiko
-- 
DENX Software Engineering GmbH,      Managing Director: Erika Unter
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: +49-8142-66989-52   Fax: +49-8142-66989-80   Email: hs@denx.de

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v3 00/12] drivers: Driver support for ADI SC5xx SoCs
  2025-02-26 17:30 [PATCH v3 00/12] drivers: Driver support for ADI SC5xx SoCs Greg Malysa
                   ` (11 preceding siblings ...)
  2025-02-26 17:30 ` [PATCH v3 12/12] mmc: Add support for ADI SC5XX-family processor SDHCI peripherals Greg Malysa
@ 2025-03-12 19:43 ` Tom Rini
  12 siblings, 0 replies; 16+ messages in thread
From: Tom Rini @ 2025-03-12 19:43 UTC (permalink / raw)
  To: u-boot, Greg Malysa
  Cc: adsp-linux, Angelo Dureghello, Arturs Artamonovs,
	Bastien Curutchet, Billy Tsai, Boon Khai Ng, Caleb Connolly,
	Christophe Leroy, Christophe ROULLIER, David Virag,
	Devarsh Thakkar, Erik Schumacher, Fabio Estevam, Gabor Juhos,
	Hanyuan Zhao, Heiko Schocher, Heinrich Schuchardt, Ian Roberts,
	Ilias Apalodimas, Jaehoon Chung, Jagan Teki, Jerome Forissier,
	Jim Liu, Joe Hershberger, John Watts, Jonas Karlman, Kongyang Liu,
	Leo Yu-Chi Liang, Linus Walleij, MD Danish Anwar, Maksim Kiselev,
	Marek Behún, Marek Vasut, Markus Gothe, Mattijs Korpershoek,
	Michal Simek, Nathan Barrett-Morrison, Neil Armstrong,
	Oliver Gaskell, Patrice Chotard, Paul Barker, Paul Kocialkowski,
	Peng Fan, Peter Robinson, Philip Oberfichtner, Piotr Wojtaszczyk,
	Quentin Schulz, Ramon Fried, Rasmus Villemoes, Ravi Gunasekaran,
	Robert Marko, Romain Naour, Sam Protsenko, Simon Glass,
	Stefan Roese, Utsav Agarwal, Vasileios Bimpikas,
	Venkatesh Yadav Abbarapu, Weijie Gao, Ye Li, Greg Malysa

On Wed, 26 Feb 2025 12:30:22 -0500, Greg Malysa wrote:

> This series adds all of the supported peripheral drivers for the sc5xx
> series of SoCs from Analog Devices and other drivers that are used by
> the evaluation kits, such as a GPIO expander used by the EZLITE carrier
> boards. This series passes gitlab CI tests.
> 
> Changes in v3:
> - Add check if PORT peripheral base address was mapped successfully
> - replace read*/write* with ioread* and iowrite* and friends across all
>   drivers
> - update for compatibility with changes to dwc qos driver between 2024.04
>   and 2025.01
> - (spi) Primarily addressed issues identified in earlier feedback:
>   - Removed unused pins and memory_map priv members
>   - Added __iomem to device mmio pointers
>   - Replaced readl/writel calls with iowrite32/ioread32 and friends
>   - Added map_sysmem() call to prepare device mmio pointer
> - (sdhci) Removed struct adi_sdhc and replaced with the struct that was its
>   only member
> 
> [...]

Applied to u-boot/next, thanks!

[01/12] pinctrl: Add support for ADI SC5XX-family pinctrl
        commit: 79ccd6c7dc7055d5bbe375fddef925d7986c204d
[02/12] doc: Add dt-bindings and descriptions for ADI SC5xx-family pinctrl
        commit: a0ffd8d7cd8efb8b348c07fa18a610a4534f9bea
[03/12] gpio: Add support for SC5XX-family processor GPIO driver
        commit: 1e87f0ed79100d915540658eda76e4e125713323
[04/12] gpio: Add support for ADI ADP5588 GPIO expander chips
        commit: 446179627fcac2e99aaa329a1d6cf49805482c6b
[05/12] usb: musb-new: Add support for Analog Devices SC5xx SoCs
        commit: 2f6a86a6125645ef818dd0d4c0bfc1f77c73e31f
[06/12] i2c: Add support for ADI SC5XX-family I2C peripheral
        commit: 7f99650bb8f592827fc687022f4238ffdd4fde3e
[07/12] net: Add support for ADI SC5xx SoCs with DWC QoS ethernet
        commit: df831ebf6114c5f534f774c8b5b6998d328d0101
[08/12] watchdog: Add support for ADI SC5XX-family watchdog peripheral
        commit: cbc0dfd424caabaa9f2a1fee911940c7f65666e2
[09/12] dma: Add driver for ADI SC5xx-family SoC MDMA functionality
        commit: 072320d9215641dd30c5697a6b479ad46f05f2f9
[10/12] remoteproc: Add in SHARC loading for ADI SC5XX-family processors
        commit: d3bfe577880d20a19f155cf2bd33c5545c72cf6f
[11/12] spi: Add support for ADI SC5XX-family processor SPI peripherals
        commit: 7535a9280be1fc81b280517c7c44b5f1c2efc0ba
[12/12] mmc: Add support for ADI SC5XX-family processor SDHCI peripherals
        commit: 036118ebd81e6b2c593d5ea6dc0056b34931c870
-- 
Tom



^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2025-03-13  3:19 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-02-26 17:30 [PATCH v3 00/12] drivers: Driver support for ADI SC5xx SoCs Greg Malysa
2025-02-26 17:30 ` [PATCH v3 01/12] pinctrl: Add support for ADI SC5XX-family pinctrl Greg Malysa
2025-02-26 17:30 ` [PATCH v3 02/12] doc: Add dt-bindings and descriptions for ADI SC5xx-family pinctrl Greg Malysa
2025-02-26 17:30 ` [PATCH v3 03/12] gpio: Add support for SC5XX-family processor GPIO driver Greg Malysa
2025-02-26 17:30 ` [PATCH v3 04/12] gpio: Add support for ADI ADP5588 GPIO expander chips Greg Malysa
2025-02-26 17:30 ` [PATCH v3 05/12] usb: musb-new: Add support for Analog Devices SC5xx SoCs Greg Malysa
2025-02-26 17:30 ` [PATCH v3 06/12] i2c: Add support for ADI SC5XX-family I2C peripheral Greg Malysa
2025-03-06  5:56   ` Heiko Schocher
2025-02-26 17:30 ` [PATCH v3 07/12] net: Add support for ADI SC5xx SoCs with DWC QoS ethernet Greg Malysa
2025-02-26 17:30 ` [PATCH v3 08/12] watchdog: Add support for ADI SC5XX-family watchdog peripheral Greg Malysa
2025-02-27  8:44   ` Stefan Roese
2025-02-26 17:30 ` [PATCH v3 09/12] dma: Add driver for ADI SC5xx-family SoC MDMA functionality Greg Malysa
2025-02-26 17:30 ` [PATCH v3 10/12] remoteproc: Add in SHARC loading for ADI SC5XX-family processors Greg Malysa
2025-02-26 17:30 ` [PATCH v3 11/12] spi: Add support for ADI SC5XX-family processor SPI peripherals Greg Malysa
2025-02-26 17:30 ` [PATCH v3 12/12] mmc: Add support for ADI SC5XX-family processor SDHCI peripherals Greg Malysa
2025-03-12 19:43 ` [PATCH v3 00/12] drivers: Driver support for ADI SC5xx SoCs Tom Rini

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox