public inbox for u-boot@lists.denx.de
 help / color / mirror / Atom feed
* [PATCH v2 11/11] mmc: Add support for ADI SC5XX-family processor SDHCI peripherals
  2024-09-25 12:25 [PATCH v2 00/11] drivers: Driver support for ADI SC5xx SoCs Oliver Gaskell via B4 Relay
@ 2024-09-25 12:25 ` Oliver Gaskell via B4 Relay
  0 siblings, 0 replies; 15+ messages in thread
From: Oliver Gaskell via B4 Relay @ 2024-09-25 12:25 UTC (permalink / raw)
  To: Tom Rini, Nathan Barrett-Morrison, Greg Malysa, Ian Roberts,
	Vasileios Bimpikas, Utsav Agarwal, Arturs Artamonovs, Marek Vasut,
	Heiko Schocher, Joe Hershberger, Ramon Fried, Stefan Roese,
	Jagan Teki, Peng Fan, Jaehoon Chung
  Cc: u-boot, adsp-linux, Oliver Gaskell,
	20240828-sc5xx-upstreaming-patches-v1-0-44d9adfdf327

From: Oliver Gaskell <Oliver.Gaskell@analog.com>

Co-developed-by: Greg Malysa <greg.malysa@timesys.com>
Signed-off-by: Greg Malysa <greg.malysa@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: Nathan Barrett-Morrison <nathan.morrison@timesys.com>
Signed-off-by: Oliver Gaskell <Oliver.Gaskell@analog.com>
---
 MAINTAINERS             |   1 +
 drivers/mmc/Kconfig     |   9 +++
 drivers/mmc/Makefile    |   1 +
 drivers/mmc/adi_sdhci.c | 154 ++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 165 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 669b9953c3..7ba20a8e49 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -616,6 +616,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 982e84dc3b..6ac65a8ba8 100644
--- a/drivers/mmc/Kconfig
+++ b/drivers/mmc/Kconfig
@@ -281,6 +281,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 72c3fb66ce..eac8c28ee5 100644
--- a/drivers/mmc/Makefile
+++ b/drivers/mmc/Makefile
@@ -69,6 +69,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_STI)		+= sti_sdhci.o
 obj-$(CONFIG_MMC_SDHCI_TANGIER)		+= tangier_sdhci.o
diff --git a/drivers/mmc/adi_sdhci.c b/drivers/mmc/adi_sdhci.c
new file mode 100644
index 0000000000..311089a5f5
--- /dev/null
+++ b/drivers/mmc/adi_sdhci.c
@@ -0,0 +1,154 @@
+// 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;
+};
+
+struct adi_sdhc {
+	struct sdhci_host host;
+	void *base;
+};
+
+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 adi_sdhc *prv = dev_get_priv(dev);
+	struct sdhci_host *host = &prv->host;
+	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 = &prv->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 adi_sdhc),
+	.plat_auto	= sizeof(struct adi_sdhc_plat),
+};

-- 
2.34.1



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

* [PATCH v2 00/11] drivers: Driver support for ADI SC5xx SoCs
@ 2024-10-21 13:54 Vasileios Bimpikas via B4 Relay
  2024-10-21 13:54 ` [PATCH v2 01/11] pinctrl: Add support for ADI SC5XX-family pinctrl Vasileios Bimpikas via B4 Relay
                   ` (10 more replies)
  0 siblings, 11 replies; 15+ messages in thread
From: Vasileios Bimpikas via B4 Relay @ 2024-10-21 13:54 UTC (permalink / raw)
  To: Tom Rini, Nathan Barrett-Morrison, Greg Malysa, Ian Roberts,
	Vasileios Bimpikas, Utsav Agarwal, Arturs Artamonovs, Marek Vasut,
	Heiko Schocher, Joe Hershberger, Ramon Fried, Stefan Roese,
	Jagan Teki, Peng Fan, Jaehoon Chung
  Cc: u-boot, adsp-linux, Oliver Gaskell, Angelo Dureghello,
	Piotr Wojtaszczyk

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 is based on my earlier patch series:
  "arm: Initial support for Analog Devices SC5xx boards"
  20240828-sc5xx-upstreaming-patches-v1-0-44d9adfdf327@analog.com
since both that series and this series modify MAINTAINERS.

Note that patches 05, 07 had Reviewed-by tags, but have had minor
changes since v1 so these weren't kept.

Signed-off-by: Oliver Gaskell <Oliver.Gaskell@analog.com>
---
Changes in v2:
- Address comments on adi_spi3.c
- Clean up some whitespace errors
- Modify Kconfigs to reflect changes to mach-sc5xx/Kconfig
- Link to v1: https://lore.kernel.org/r/20240515215837.14028-1-greg.malysa@timesys.com

---
Changes in v3:
- Rebased with current master
- Link to v2: https://lore.kernel.org/u-boot/20240925-sc5xx-driver-series-v2-0-ad9287c25c08@analog.com/

---
Greg Malysa (2):
      net: Add support for ADI SC5xx SoCs with DWC QoS ethernet
      dma: Add driver for ADI SC5xx-family SoC MDMA functionality

Nathan Barrett-Morrison (3):
      gpio: Add support for ADI ADP5588 GPIO expander chips
      usb: musb-new: Add support for Analog Devices SC5xx SoCs
      remoteproc: Add in SHARC loading for ADI SC5XX-family processors

Oliver Gaskell (6):
      pinctrl: Add support for ADI SC5XX-family pinctrl
      gpio: Add support for SC5XX-family processor GPIO driver
      i2c: Add support for ADI SC5XX-family I2C peripheral
      watchdog: Add support for ADI SC5XX-family watchdog peripheral
      spi: Add support for ADI SC5XX-family processor SPI peripherals
      mmc: Add support for ADI SC5XX-family processor SDHCI peripherals

 MAINTAINERS                            |  11 +
 drivers/dma/Kconfig                    |   7 +
 drivers/dma/Makefile                   |   1 +
 drivers/dma/adi_dma.c                  | 255 ++++++++++++
 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                   |   3 +-
 drivers/i2c/adi_i2c.c                  | 395 +++++++++++++++++++
 drivers/mmc/Kconfig                    |   9 +
 drivers/mmc/Makefile                   |   1 +
 drivers/mmc/adi_sdhci.c                | 154 ++++++++
 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          | 102 +++++
 drivers/pinctrl/Kconfig                |   8 +
 drivers/pinctrl/Makefile               |   1 +
 drivers/pinctrl/pinctrl-adi-adsp.c     | 156 ++++++++
 drivers/remoteproc/Kconfig             |  11 +
 drivers/remoteproc/Makefile            |   1 +
 drivers/remoteproc/adi_sc5xx_rproc.c   | 276 +++++++++++++
 drivers/spi/Kconfig                    |   7 +
 drivers/spi/Makefile                   |   1 +
 drivers/spi/adi_spi3.c                 | 690 +++++++++++++++++++++++++++++++++
 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             | 145 +++++++
 include/dt-bindings/pinctrl/adi-adsp.h |  21 +
 35 files changed, 2903 insertions(+), 1 deletion(-)
---
base-commit: 041bf69038e2957f38e2de4e5d77bdb3e2ccf8a8
change-id: 20240923-sc5xx-driver-series-a9afb7c598bc
prerequisite-message-id: 20240828-sc5xx-upstreaming-patches-v1-0-44d9adfdf327@analog.com
prerequisite-patch-id: 184667bccb34335a943f5ba405bf2acd75b8c7f3
prerequisite-patch-id: aad9a1786ecfe51a46034fc055c57bff62d2a653
prerequisite-patch-id: 7640097fdc5a25ec2ffdf0eddb22f3c452510390
prerequisite-patch-id: 909e13e6d779858f6d862b703e7cbfe510cb3a16
prerequisite-patch-id: 0564b8079526f2fe1d9f723c8c4a2471e3ec6e1c
prerequisite-patch-id: 469d6193e82a2f702e938004ad6ff7c22dfbab86
prerequisite-patch-id: f6a45739e56120f54170b924a3069b98d355d1c0
prerequisite-patch-id: 24787a90e7adadab2ae3aa2348ac9d5838c26cfe
prerequisite-patch-id: 94e1c6fde429c63a6fa4f7b5aeab0df9a8a00d81
prerequisite-patch-id: 32d268fd6372bda3129cddd26da45d69291efc33
prerequisite-patch-id: f54e027ac323522349f24acbc4a946d8a3cdfaef
prerequisite-patch-id: 0ca62b4ff0cfd3bf5a10ac84f13d0ab261e737d1
prerequisite-patch-id: 8101423151112c3876c88223ac9ab196aebb8912
prerequisite-patch-id: fbc3b9227e2dc550878d4e8d113b1ad81ee00028
prerequisite-patch-id: 63cec707680793ef2feeb5b782b1db19d49766ce
prerequisite-patch-id: 6f85ade3b9119dba85b65da8a49c4a6345c6b3ba
prerequisite-patch-id: 988919879c6440227124dc0bb4b24d22c9041d99
prerequisite-patch-id: 3227e7bdc2614c377b6837a47ad1cde99791d794
prerequisite-patch-id: 10f9f40c697f22a33b83a8538e13bac642795851
prerequisite-patch-id: e57e6a95ef319c12565a6469f230198259f0bf7d

Best regards,
-- 
Vasileios Bimpikas <vasileios.bimpikas@analog.com>



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

* [PATCH v2 01/11] pinctrl: Add support for ADI SC5XX-family pinctrl
  2024-10-21 13:54 [PATCH v2 00/11] drivers: Driver support for ADI SC5xx SoCs Vasileios Bimpikas via B4 Relay
@ 2024-10-21 13:54 ` Vasileios Bimpikas via B4 Relay
  2024-10-21 13:54 ` [PATCH v2 02/11] gpio: Add support for SC5XX-family processor GPIO driver Vasileios Bimpikas via B4 Relay
                   ` (9 subsequent siblings)
  10 siblings, 0 replies; 15+ messages in thread
From: Vasileios Bimpikas via B4 Relay @ 2024-10-21 13:54 UTC (permalink / raw)
  To: Tom Rini, Nathan Barrett-Morrison, Greg Malysa, Ian Roberts,
	Vasileios Bimpikas, Utsav Agarwal, Arturs Artamonovs, Marek Vasut,
	Heiko Schocher, Joe Hershberger, Ramon Fried, Stefan Roese,
	Jagan Teki, Peng Fan, Jaehoon Chung
  Cc: u-boot, adsp-linux, Oliver Gaskell

From: Oliver Gaskell <Oliver.Gaskell@analog.com>

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: Greg Malysa <greg.malysa@timesys.com>
Signed-off-by: Oliver Gaskell <Oliver.Gaskell@analog.com>
---
 MAINTAINERS                            |   1 +
 drivers/pinctrl/Kconfig                |   8 ++
 drivers/pinctrl/Makefile               |   1 +
 drivers/pinctrl/pinctrl-adi-adsp.c     | 156 +++++++++++++++++++++++++++++++++
 include/dt-bindings/pinctrl/adi-adsp.h |  21 +++++
 5 files changed, 187 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 573403734b29adc7a091eba93bb5ffab33bdf4d3..47dd18c6563fd3f98643a84cfc48af79e3e39f39 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -612,6 +612,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 a1d53cfbdbed5ef1030fff04715e1436f167554b..a88a4442184b3e62b48b5af7616f2db98789cfeb 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -170,6 +170,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 634047a91f4c78ad7bd301870d9bba803e0bc659..e3a82b12c7838a7ec6d26411ef013cb9aa42452f 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 0000000000000000000000000000000000000000..717ac8e0056bcab6609878b2290508fdfb9f6d07
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-adi-adsp.c
@@ -0,0 +1,156 @@
+// 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->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,
+};
diff --git a/include/dt-bindings/pinctrl/adi-adsp.h b/include/dt-bindings/pinctrl/adi-adsp.h
new file mode 100644
index 0000000000000000000000000000000000000000..7dc8a1ef5c4a34faa76d11cc5bf909531b28fed9
--- /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.34.1



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

* [PATCH v2 02/11] gpio: Add support for SC5XX-family processor GPIO driver
  2024-10-21 13:54 [PATCH v2 00/11] drivers: Driver support for ADI SC5xx SoCs Vasileios Bimpikas via B4 Relay
  2024-10-21 13:54 ` [PATCH v2 01/11] pinctrl: Add support for ADI SC5XX-family pinctrl Vasileios Bimpikas via B4 Relay
@ 2024-10-21 13:54 ` Vasileios Bimpikas via B4 Relay
  2024-10-21 13:54 ` [PATCH v2 03/11] gpio: Add support for ADI ADP5588 GPIO expander chips Vasileios Bimpikas via B4 Relay
                   ` (8 subsequent siblings)
  10 siblings, 0 replies; 15+ messages in thread
From: Vasileios Bimpikas via B4 Relay @ 2024-10-21 13:54 UTC (permalink / raw)
  To: Tom Rini, Nathan Barrett-Morrison, Greg Malysa, Ian Roberts,
	Vasileios Bimpikas, Utsav Agarwal, Arturs Artamonovs, Marek Vasut,
	Heiko Schocher, Joe Hershberger, Ramon Fried, Stefan Roese,
	Jagan Teki, Peng Fan, Jaehoon Chung
  Cc: u-boot, adsp-linux, Oliver Gaskell

From: Oliver Gaskell <Oliver.Gaskell@analog.com>

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: Greg Malysa <greg.malysa@timesys.com>
Signed-off-by: Oliver Gaskell <Oliver.Gaskell@analog.com>
---
 MAINTAINERS                  |   1 +
 drivers/gpio/Kconfig         |   9 +++
 drivers/gpio/Makefile        |   1 +
 drivers/gpio/gpio-adi-adsp.c | 179 +++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 190 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 47dd18c6563fd3f98643a84cfc48af79e3e39f39..c890f2570729606e947ca07d6f12ca202cf91908 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -612,6 +612,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/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 1e5711663eb8adc4109cb9793c49e679025e2ef6..f6f62274fb097f4eb956fa776cbfd76c468caf98 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 fe81b6ba88b1adc815ebf04e6b65a164cda91bb8..882c3f544c7c8d9d84f6511a818ba4d2b83a9aa1 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_AT91_GPIO)	+= at91_gpio.o
diff --git a/drivers/gpio/gpio-adi-adsp.c b/drivers/gpio/gpio-adi-adsp.c
new file mode 100644
index 0000000000000000000000000000000000000000..0ce00572e082003a250ba69a30bde963c654bb2c
--- /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.34.1



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

* [PATCH v2 03/11] gpio: Add support for ADI ADP5588 GPIO expander chips
  2024-10-21 13:54 [PATCH v2 00/11] drivers: Driver support for ADI SC5xx SoCs Vasileios Bimpikas via B4 Relay
  2024-10-21 13:54 ` [PATCH v2 01/11] pinctrl: Add support for ADI SC5XX-family pinctrl Vasileios Bimpikas via B4 Relay
  2024-10-21 13:54 ` [PATCH v2 02/11] gpio: Add support for SC5XX-family processor GPIO driver Vasileios Bimpikas via B4 Relay
@ 2024-10-21 13:54 ` Vasileios Bimpikas via B4 Relay
  2024-10-21 13:54 ` [PATCH v2 04/11] usb: musb-new: Add support for Analog Devices SC5xx SoCs Vasileios Bimpikas via B4 Relay
                   ` (7 subsequent siblings)
  10 siblings, 0 replies; 15+ messages in thread
From: Vasileios Bimpikas via B4 Relay @ 2024-10-21 13:54 UTC (permalink / raw)
  To: Tom Rini, Nathan Barrett-Morrison, Greg Malysa, Ian Roberts,
	Vasileios Bimpikas, Utsav Agarwal, Arturs Artamonovs, Marek Vasut,
	Heiko Schocher, Joe Hershberger, Ramon Fried, Stefan Roese,
	Jagan Teki, Peng Fan, Jaehoon Chung
  Cc: u-boot, adsp-linux, Oliver Gaskell

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 <greg.malysa@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: Nathan Barrett-Morrison <nathan.morrison@timesys.com>
---
 MAINTAINERS                 |   1 +
 drivers/gpio/Kconfig        |   8 ++
 drivers/gpio/Makefile       |   1 +
 drivers/gpio/adp5588_gpio.c | 208 ++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 218 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index c890f2570729606e947ca07d6f12ca202cf91908..981c41cb512684736c933b78a3547657b13e016b 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -612,6 +612,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/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 f6f62274fb097f4eb956fa776cbfd76c468caf98..8c70c96ae7cf3f2c45ab5977215e11b740830c7e 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -547,6 +547,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 882c3f544c7c8d9d84f6511a818ba4d2b83a9aa1..57b12107cfd6ea46f12479fa6f242fb97a711cb3 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -74,6 +74,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 0000000000000000000000000000000000000000..d081e16989713b7dfbd0d4fdadea8dab6e243583
--- /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.34.1



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

* [PATCH v2 04/11] usb: musb-new: Add support for Analog Devices SC5xx SoCs
  2024-10-21 13:54 [PATCH v2 00/11] drivers: Driver support for ADI SC5xx SoCs Vasileios Bimpikas via B4 Relay
                   ` (2 preceding siblings ...)
  2024-10-21 13:54 ` [PATCH v2 03/11] gpio: Add support for ADI ADP5588 GPIO expander chips Vasileios Bimpikas via B4 Relay
@ 2024-10-21 13:54 ` Vasileios Bimpikas via B4 Relay
  2024-10-21 13:54 ` [PATCH v2 05/11] i2c: Add support for ADI SC5XX-family I2C peripheral Vasileios Bimpikas via B4 Relay
                   ` (6 subsequent siblings)
  10 siblings, 0 replies; 15+ messages in thread
From: Vasileios Bimpikas via B4 Relay @ 2024-10-21 13:54 UTC (permalink / raw)
  To: Tom Rini, Nathan Barrett-Morrison, Greg Malysa, Ian Roberts,
	Vasileios Bimpikas, Utsav Agarwal, Arturs Artamonovs, Marek Vasut,
	Heiko Schocher, Joe Hershberger, Ramon Fried, Stefan Roese,
	Jagan Teki, Peng Fan, Jaehoon Chung
  Cc: u-boot, adsp-linux, Oliver Gaskell

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 <greg.malysa@timesys.com>
Signed-off-by: Greg Malysa <greg.malysa@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: Nathan Barrett-Morrison <nathan.morrison@timesys.com>
---
 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(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 981c41cb512684736c933b78a3547657b13e016b..8706bdc1ee5a3e0e9f626f5370c534638bf6d9d0 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -617,6 +617,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/env/adi/
 
diff --git a/drivers/usb/musb-new/Kconfig b/drivers/usb/musb-new/Kconfig
index c52afd41a7532486c57bc2fa9d532757b45d8e83..ad9072a532767b94d4171d1236ffc99f48330206 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 396ff02654b97f318515ea36625444900b9471bf..6638772daca9ef02a0cf40e718c3df4dad02c06c 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 0000000000000000000000000000000000000000..16201480b43b17120109c5575993ff3176f2a70e
--- /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.34.1



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

* [PATCH v2 05/11] i2c: Add support for ADI SC5XX-family I2C peripheral
  2024-10-21 13:54 [PATCH v2 00/11] drivers: Driver support for ADI SC5xx SoCs Vasileios Bimpikas via B4 Relay
                   ` (3 preceding siblings ...)
  2024-10-21 13:54 ` [PATCH v2 04/11] usb: musb-new: Add support for Analog Devices SC5xx SoCs Vasileios Bimpikas via B4 Relay
@ 2024-10-21 13:54 ` Vasileios Bimpikas via B4 Relay
  2024-10-21 13:54 ` [PATCH v2 06/11] net: Add support for ADI SC5xx SoCs with DWC QoS ethernet Vasileios Bimpikas via B4 Relay
                   ` (5 subsequent siblings)
  10 siblings, 0 replies; 15+ messages in thread
From: Vasileios Bimpikas via B4 Relay @ 2024-10-21 13:54 UTC (permalink / raw)
  To: Tom Rini, Nathan Barrett-Morrison, Greg Malysa, Ian Roberts,
	Vasileios Bimpikas, Utsav Agarwal, Arturs Artamonovs, Marek Vasut,
	Heiko Schocher, Joe Hershberger, Ramon Fried, Stefan Roese,
	Jagan Teki, Peng Fan, Jaehoon Chung
  Cc: u-boot, adsp-linux, Oliver Gaskell, Angelo Dureghello

From: Oliver Gaskell <Oliver.Gaskell@analog.com>

Co-developed-by: Greg Malysa <greg.malysa@timesys.com>
Signed-off-by: Greg Malysa <greg.malysa@timesys.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: Utsav Agarwal <utsav.agarwal@analog.com>
Signed-off-by: Arturs Artamonovs <arturs.artamonovs@analog.com>
Signed-off-by: Nathan Barrett-Morrison <nathan.morrison@timesys.com>
Signed-off-by: Oliver Gaskell <Oliver.Gaskell@analog.com>
Reviewed-by: Heiko Schocher <hs@denx.de>
Signed-off-by: Vasileios Bimpikas <vasileios.bimpikas@analog.com>
---
 MAINTAINERS           |   1 +
 drivers/i2c/Kconfig   |   7 +
 drivers/i2c/Makefile  |   3 +-
 drivers/i2c/adi_i2c.c | 395 ++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 405 insertions(+), 1 deletion(-)

diff --git a/MAINTAINERS b/MAINTAINERS
index 8706bdc1ee5a3e0e9f626f5370c534638bf6d9d0..ee41f28914100ac86402af9a10b238edd24916e4 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -614,6 +614,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 52067fa7c1fff5db2b65af24fd10a260254be896..a84731824c7d8351af50eca6637c47fdb71828f0 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 bebd728e7da6efcf914a68559bb174a9fd7cf731..58ce12fc5515a66a0ae00174c735155b52f5ab47 100644
--- a/drivers/i2c/Makefile
+++ b/drivers/i2c/Makefile
@@ -9,8 +9,9 @@ endif
 obj-$(CONFIG_$(XPL_)DM_I2C_GPIO) += i2c-gpio.o
 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_$(SPL_)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 0000000000000000000000000000000000000000..04a63de577c25caed9b05b54f99f811ceab7f9c1
--- /dev/null
+++ b/drivers/i2c/adi_i2c.c
@@ -0,0 +1,395 @@
+// 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 <asm/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, ctl;
+	ulong timebase = get_timer(0);
+
+	do {
+		int_stat = readw(&twi->int_stat);
+
+		if (int_stat & XMTSERV) {
+			writew(XMTSERV, &twi->int_stat);
+			if (msg->olen) {
+				writew(*(msg->obuf++), &twi->xmt_data8);
+				--msg->olen;
+			} else if (!(msg->flags & I2C_M_COMBO) && msg->len) {
+				writew(*(msg->buf++), &twi->xmt_data8);
+				--msg->len;
+			} else {
+				ctl = readw(&twi->master_ctl);
+				if (msg->flags & I2C_M_COMBO)
+					writew(ctl | RSTART | MDIR,
+					       &twi->master_ctl);
+				else
+					writew(ctl | STOP, &twi->master_ctl);
+			}
+		}
+		if (int_stat & RCVSERV) {
+			writew(RCVSERV, &twi->int_stat);
+			if (msg->len) {
+				*(msg->buf++) = readw(&twi->rcv_data8);
+				--msg->len;
+			} else if (msg->flags & I2C_M_STOP) {
+				ctl = readw(&twi->master_ctl);
+				writew(ctl | STOP, &twi->master_ctl);
+			}
+		}
+		if (int_stat & MERR) {
+			pr_err("%s: master transmit terror: %d\n", __func__,
+			       readw(&twi->master_stat));
+			writew(MERR, &twi->int_stat);
+			return -EIO;
+		}
+		if (int_stat & MCOMP) {
+			writew(MCOMP, &twi->int_stat);
+			if (msg->flags & I2C_M_COMBO && msg->len) {
+				ctl = readw(&twi->master_ctl);
+				ctl = (ctl & ~RSTART) |
+					(min((unsigned int)msg->len,
+					     0xffU) << 6) | MEN | MDIR;
+				writew(ctl, &twi->master_ctl);
+			} 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 (readw(&twi->master_stat) & BUSBUSY)
+		if (!IS_ENABLED(CONFIG_SPL_BUILD) && ctrlc())
+			return -EINTR;
+
+	/* Set Transmit device address */
+	writew(chip, &twi->master_addr);
+
+	/* Clear the FIFO before starting things */
+	writew(XMTFLUSH | RCVFLUSH, &twi->fifo_ctl);
+	writew(0, &twi->fifo_ctl);
+
+	/* Prime the pump */
+	if (msg.olen) {
+		len = (msg.flags & I2C_M_COMBO) ? msg.olen : msg.olen + len;
+		writew(*(msg.obuf++), &twi->xmt_data8);
+		--msg.olen;
+	} else if (!(msg.flags & I2C_M_READ) && msg.len) {
+		writew(*(msg.buf++), &twi->xmt_data8);
+		--msg.len;
+	}
+
+	/* clear int stat */
+	writew(-1, &twi->master_stat);
+	writew(-1, &twi->int_stat);
+	writew(0, &twi->int_mask);
+
+	/* Master enable */
+	ctl = readw(&twi->master_ctl);
+	ctl = (ctl & FAST) | (min(len, 0xff) << 6) | MEN |
+		((msg.flags & I2C_M_READ) ? MDIR : 0);
+	writew(ctl, &twi->master_ctl);
+
+	/* Process the rest */
+	ret = wait_for_completion(twi, &msg);
+
+	ctl = readw(&twi->master_ctl) & ~MEN;
+	writew(ctl, &twi->master_ctl);
+	ctl = readw(&twi->control) & ~TWI_ENA;
+	writew(ctl, &twi->control);
+	ctl = readw(&twi->control) | TWI_ENA;
+	writew(ctl, &twi->control);
+	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);
+	writew(clkdiv, &twi->clkdiv);
+
+	/* Don't turn it on */
+	writew(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 */
+	writew(prescale, &twi->control);
+
+	/* Set TWI interface clock as specified */
+	adi_i2c_set_bus_speed(bus, dev->speed);
+
+	/* Enable it */
+	writew(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.34.1



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

* [PATCH v2 06/11] net: Add support for ADI SC5xx SoCs with DWC QoS ethernet
  2024-10-21 13:54 [PATCH v2 00/11] drivers: Driver support for ADI SC5xx SoCs Vasileios Bimpikas via B4 Relay
                   ` (4 preceding siblings ...)
  2024-10-21 13:54 ` [PATCH v2 05/11] i2c: Add support for ADI SC5XX-family I2C peripheral Vasileios Bimpikas via B4 Relay
@ 2024-10-21 13:54 ` Vasileios Bimpikas via B4 Relay
  2024-10-21 13:54 ` [PATCH v2 07/11] watchdog: Add support for ADI SC5XX-family watchdog peripheral Vasileios Bimpikas via B4 Relay
                   ` (4 subsequent siblings)
  10 siblings, 0 replies; 15+ messages in thread
From: Vasileios Bimpikas via B4 Relay @ 2024-10-21 13:54 UTC (permalink / raw)
  To: Tom Rini, Nathan Barrett-Morrison, Greg Malysa, Ian Roberts,
	Vasileios Bimpikas, Utsav Agarwal, Arturs Artamonovs, Marek Vasut,
	Heiko Schocher, Joe Hershberger, Ramon Fried, Stefan Roese,
	Jagan Teki, Peng Fan, Jaehoon Chung
  Cc: u-boot, adsp-linux, Oliver Gaskell

From: Greg Malysa <greg.malysa@timesys.com>

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: Greg Malysa <greg.malysa@timesys.com>
---
 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 | 102 ++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 119 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index ee41f28914100ac86402af9a10b238edd24916e4..b853eec4d961abcd33fe722f3a7f49bf2f24ee29 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -615,6 +615,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 89f7411bdf336d64f8cddadc3f8c077f48481455..6d6060fe48848b6633b2e5c30e87f787559f0692 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 f5ab1f5dedf6b867583b841695dd43bb6fc4db6e..5d2b97db9884ee9ce356719de7ea1ffcd7b55cc7 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 3415c418a93576396f2090849868a66c75b5747f..d163f566255a536a7805617e8824e892335e56be 100644
--- a/drivers/net/dwc_eth_qos.c
+++ b/drivers/net/dwc_eth_qos.c
@@ -1632,6 +1632,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 ce57e22a81f14c46461faa1994a08ed74c940138..0eb9f2f36cacbde7f61260ebc8a421ae6239a7ce 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)
@@ -300,3 +301,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 0000000000000000000000000000000000000000..373e7c25051ccf4af9f5bf0566ca322b796193a7
--- /dev/null
+++ b/drivers/net/dwc_eth_qos_adi.c
@@ -0,0 +1,102 @@
+// 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 <asm/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);
+	u32 val;
+
+	/*
+	 * 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();
+
+	val = readl(&eqos->dma_regs->mode);
+	val |= EQOS_DMA_MODE_SWR;
+	writel(val, &eqos->dma_regs->mode);
+
+	return 0;
+}
+
+static int eqos_probe_resources_adi(struct udevice *dev)
+{
+	struct eqos_priv *eqos = dev_get_priv(dev);
+	phy_interface_t interface;
+
+	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,
+};
+
+// @todo read mdio_wait from device tree
+// @todo read swr_wait from device tree
+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.34.1



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

* [PATCH v2 07/11] watchdog: Add support for ADI SC5XX-family watchdog peripheral
  2024-10-21 13:54 [PATCH v2 00/11] drivers: Driver support for ADI SC5xx SoCs Vasileios Bimpikas via B4 Relay
                   ` (5 preceding siblings ...)
  2024-10-21 13:54 ` [PATCH v2 06/11] net: Add support for ADI SC5xx SoCs with DWC QoS ethernet Vasileios Bimpikas via B4 Relay
@ 2024-10-21 13:54 ` Vasileios Bimpikas via B4 Relay
  2024-10-21 13:54 ` [PATCH v2 08/11] dma: Add driver for ADI SC5xx-family SoC MDMA functionality Vasileios Bimpikas via B4 Relay
                   ` (3 subsequent siblings)
  10 siblings, 0 replies; 15+ messages in thread
From: Vasileios Bimpikas via B4 Relay @ 2024-10-21 13:54 UTC (permalink / raw)
  To: Tom Rini, Nathan Barrett-Morrison, Greg Malysa, Ian Roberts,
	Vasileios Bimpikas, Utsav Agarwal, Arturs Artamonovs, Marek Vasut,
	Heiko Schocher, Joe Hershberger, Ramon Fried, Stefan Roese,
	Jagan Teki, Peng Fan, Jaehoon Chung
  Cc: u-boot, adsp-linux, Oliver Gaskell

From: Oliver Gaskell <Oliver.Gaskell@analog.com>

Co-developed-by: Greg Malysa <greg.malysa@timesys.com>
Signed-off-by: Greg Malysa <greg.malysa@timesys.com>
Co-developed-by: Ian Roberts <ian.roberts@timesys.com>
Signed-off-by: Ian Roberts <ian.roberts@timesys.com>
Signed-off-by: Utsav Agarwal <utsav.agarwal@analog.com>
Signed-off-by: Arturs Artamonovs <arturs.artamonovs@analog.com>
Signed-off-by: Nathan Barrett-Morrison <nathan.morrison@timesys.com>
Signed-off-by: Oliver Gaskell <Oliver.Gaskell@analog.com>
Reviewed-by: Stefan Roese <sr@denx.de>
Signed-off-by: Vasileios Bimpikas <vasileios.bimpikas@analog.com>
---
 MAINTAINERS                |   1 +
 drivers/watchdog/Kconfig   |   9 +++
 drivers/watchdog/Makefile  |   1 +
 drivers/watchdog/adi_wdt.c | 145 +++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 156 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index b853eec4d961abcd33fe722f3a7f49bf2f24ee29..b87a607124f5310f1b75a17fa201d1022d036c6d 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -620,6 +620,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/env/adi/
 
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 90bc5653ee332033db1ee4c7fbc914231f157f88..6e00e9b81c02f5892d4dfd37de9d7f1afc40da4a 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 51be6ab9abe07e410381029fc1dd7ce45787e765..af17dabeeef031ec099b225b3e7c9ae3e3e08b4f 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -51,3 +51,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 0000000000000000000000000000000000000000..67d17dc6928ea9e0c42e0322d6b1c77754f88d69
--- /dev/null
+++ b/drivers/watchdog/adi_wdt.c
@@ -0,0 +1,145 @@
+// 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);
+
+	writel(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);
+	u32 sctl_val;
+
+	/* Disable SYSCD_RESETb input and clear the RCU0 reset status */
+	writel(0xf, priv->rcu_base + RCU_STAT);
+	writel(0x0, priv->rcu_base + RCU_CTL);
+
+	/* reset the SEC controller */
+	writel(0x2, priv->sec_base + SEC_GCTL);
+	writel(0x2, priv->sec_base + SEC_FCTL);
+
+	udelay(50);
+
+	/* enable SEC fault event */
+	writel(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
+	 */
+	writel(0xc0, priv->sec_base + SEC_FCTL);
+	writel(0xc1, priv->sec_base + SEC_FCTL);
+
+	/* enable SEC fault source for watchdog0 */
+	sctl_val = readl((priv->sec_base + SEC_SCTL0) + 3 * 8) | 0x6;
+	writel(sctl_val, (priv->sec_base + SEC_SCTL0) + 3 * 8);
+
+	/* Enable SYSCD_RESETb input */
+	writel(0x100, priv->rcu_base + RCU_CTL);
+
+	/* enable watchdog0 */
+	writel(WDDIS, priv->wdt_base + WDOG_CTL);
+
+	writel(timeout_ms / 1000 *
+	       (clk_get_rate(&priv->clock) / (IS_ENABLED(CONFIG_SC58X) ? 2 : 1)),
+	       priv->wdt_base + WDOG_CNT);
+
+	writel(0, priv->wdt_base + WDOG_STAT);
+	writel(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.34.1



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

* [PATCH v2 08/11] dma: Add driver for ADI SC5xx-family SoC MDMA functionality
  2024-10-21 13:54 [PATCH v2 00/11] drivers: Driver support for ADI SC5xx SoCs Vasileios Bimpikas via B4 Relay
                   ` (6 preceding siblings ...)
  2024-10-21 13:54 ` [PATCH v2 07/11] watchdog: Add support for ADI SC5XX-family watchdog peripheral Vasileios Bimpikas via B4 Relay
@ 2024-10-21 13:54 ` Vasileios Bimpikas via B4 Relay
  2024-10-21 13:54 ` [PATCH v2 09/11] remoteproc: Add in SHARC loading for ADI SC5XX-family processors Vasileios Bimpikas via B4 Relay
                   ` (2 subsequent siblings)
  10 siblings, 0 replies; 15+ messages in thread
From: Vasileios Bimpikas via B4 Relay @ 2024-10-21 13:54 UTC (permalink / raw)
  To: Tom Rini, Nathan Barrett-Morrison, Greg Malysa, Ian Roberts,
	Vasileios Bimpikas, Utsav Agarwal, Arturs Artamonovs, Marek Vasut,
	Heiko Schocher, Joe Hershberger, Ramon Fried, Stefan Roese,
	Jagan Teki, Peng Fan, Jaehoon Chung
  Cc: u-boot, adsp-linux, Oliver Gaskell

From: Greg Malysa <greg.malysa@timesys.com>

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 <greg.malysa@timesys.com>
---
 MAINTAINERS           |   1 +
 drivers/dma/Kconfig   |   7 ++
 drivers/dma/Makefile  |   1 +
 drivers/dma/adi_dma.c | 255 ++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 264 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index b87a607124f5310f1b75a17fa201d1022d036c6d..8dcb1bd5619f79bbcee47b9c8928bc13223fb268 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -612,6 +612,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/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 3c64e8946466cab45d528720369d9467ffd36f9f..4b47be6b016b8e7223842bd07642f542a35093d6 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 48811eaaeb361612c0a8aa2af96c9a04124e3fc7..00d765864cdc04bb5c6e8842ea6865e303a91d81 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 0000000000000000000000000000000000000000..56eceff712f12b6d794dcc1b4cd52dbb821ec814
--- /dev/null
+++ b/drivers/dma/adi_dma.c
@@ -0,0 +1,255 @@
+// 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 <asm/io.h>
+#include <dm/device_compat.h>
+#include <linux/errno.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 = (readl(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 = (readl(chsrc + REG_STAT) & BITM_DMA_STAT_PBWID) >>
+			 BITP_DMA_STAT_PBWID;
+	u8 dstpsizemax = (readl(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 */
+	writel(CLRSTAT, chsrc + REG_STAT);
+	writel(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 */
+	writel(src,			chsrc + REG_ADDRSTART);
+	writel(bytecount >> n_srcmsize,	chsrc + REG_XCNT);
+	writel(1 << n_srcmsize,		chsrc + REG_XMOD);
+	writel(dst,			chdst + REG_ADDRSTART);
+	writel(bytecount >> n_dstmsize,	chdst + REG_XCNT);
+	writel(1 << n_dstmsize,		chdst + REG_XMOD);
+
+	writel(dstconfig, chdst + REG_CFG);
+	writel(srcconfig, chsrc + REG_CFG);
+
+	/* Wait for DMA to complete while checking for a DMA error */
+	do {
+		reg = readl(chsrc + REG_STAT);
+		if ((reg & BITM_DMA_STAT_IRQERR) == BITM_DMA_STAT_IRQERR) {
+			result = adi_dma_get_ch_error(chsrc);
+			break;
+		}
+		reg = readl(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);
+
+	reg = readl(chsrc + REG_CFG);
+	writel(reg & ~1, chsrc + REG_CFG);
+	reg = readl(chdst + REG_CFG);
+	writel(reg & ~1, chdst + REG_CFG);
+
+	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.34.1



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

* [PATCH v2 09/11] remoteproc: Add in SHARC loading for ADI SC5XX-family processors
  2024-10-21 13:54 [PATCH v2 00/11] drivers: Driver support for ADI SC5xx SoCs Vasileios Bimpikas via B4 Relay
                   ` (7 preceding siblings ...)
  2024-10-21 13:54 ` [PATCH v2 08/11] dma: Add driver for ADI SC5xx-family SoC MDMA functionality Vasileios Bimpikas via B4 Relay
@ 2024-10-21 13:54 ` Vasileios Bimpikas via B4 Relay
  2024-10-21 13:54 ` [PATCH v2 10/11] spi: Add support for ADI SC5XX-family processor SPI peripherals Vasileios Bimpikas via B4 Relay
  2024-10-21 13:54 ` [PATCH v2 11/11] mmc: Add support for ADI SC5XX-family processor SDHCI peripherals Vasileios Bimpikas via B4 Relay
  10 siblings, 0 replies; 15+ messages in thread
From: Vasileios Bimpikas via B4 Relay @ 2024-10-21 13:54 UTC (permalink / raw)
  To: Tom Rini, Nathan Barrett-Morrison, Greg Malysa, Ian Roberts,
	Vasileios Bimpikas, Utsav Agarwal, Arturs Artamonovs, Marek Vasut,
	Heiko Schocher, Joe Hershberger, Ramon Fried, Stefan Roese,
	Jagan Teki, Peng Fan, Jaehoon Chung
  Cc: u-boot, adsp-linux, Oliver Gaskell, Piotr Wojtaszczyk

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 <greg.malysa@timesys.com>
Signed-off-by: Greg Malysa <greg.malysa@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: Nathan Barrett-Morrison <nathan.morrison@timesys.com>
---
 MAINTAINERS                          |   1 +
 drivers/remoteproc/Kconfig           |  11 ++
 drivers/remoteproc/Makefile          |   1 +
 drivers/remoteproc/adi_sc5xx_rproc.c | 276 +++++++++++++++++++++++++++++++++++
 4 files changed, 289 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 8dcb1bd5619f79bbcee47b9c8928bc13223fb268..86a7f18f530c0fdabd015d49518841b0160bfdba 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -618,6 +618,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 a49802c132329c6596d5fc69020f748f321a74ac..3f7cebaeb7df82bf21ddf4347a4b2ae5ba54e518 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_SANDBOX
 	bool "Support for Test processor for Sandbox"
 	select REMOTEPROC
diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile
index 801b0965e4f0616ca22266dfd9ff054bee797b03..93923415c00751aef16eb69ec87021513e7e391e 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_SANDBOX) += sandbox_testproc.o
 obj-$(CONFIG_REMOTEPROC_STM32_COPRO) += stm32_copro.o
 obj-$(CONFIG_REMOTEPROC_TI_K3_ARM64) += ti_k3_arm64_rproc.o
diff --git a/drivers/remoteproc/adi_sc5xx_rproc.c b/drivers/remoteproc/adi_sc5xx_rproc.c
new file mode 100644
index 0000000000000000000000000000000000000000..fc9730ef32b0042da65b62be386fda348739f829
--- /dev/null
+++ b/drivers/remoteproc/adi_sc5xx_rproc.c
@@ -0,0 +1,276 @@
+// 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>
+
+/* 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((void *)(phys_addr_t)block_hdr->target_addr,
+				       block_hdr->argument,
+				       block_hdr->byte_count);
+			} else {
+				memcpy((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.34.1



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

* [PATCH v2 10/11] spi: Add support for ADI SC5XX-family processor SPI peripherals
  2024-10-21 13:54 [PATCH v2 00/11] drivers: Driver support for ADI SC5xx SoCs Vasileios Bimpikas via B4 Relay
                   ` (8 preceding siblings ...)
  2024-10-21 13:54 ` [PATCH v2 09/11] remoteproc: Add in SHARC loading for ADI SC5XX-family processors Vasileios Bimpikas via B4 Relay
@ 2024-10-21 13:54 ` Vasileios Bimpikas via B4 Relay
  2024-10-22 16:49   ` Greg Malysa
  2024-10-21 13:54 ` [PATCH v2 11/11] mmc: Add support for ADI SC5XX-family processor SDHCI peripherals Vasileios Bimpikas via B4 Relay
  10 siblings, 1 reply; 15+ messages in thread
From: Vasileios Bimpikas via B4 Relay @ 2024-10-21 13:54 UTC (permalink / raw)
  To: Tom Rini, Nathan Barrett-Morrison, Greg Malysa, Ian Roberts,
	Vasileios Bimpikas, Utsav Agarwal, Arturs Artamonovs, Marek Vasut,
	Heiko Schocher, Joe Hershberger, Ramon Fried, Stefan Roese,
	Jagan Teki, Peng Fan, Jaehoon Chung
  Cc: u-boot, adsp-linux, Oliver Gaskell, Angelo Dureghello,
	Piotr Wojtaszczyk

From: Oliver Gaskell <Oliver.Gaskell@analog.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 <greg.malysa@timesys.com>
Signed-off-by: Greg Malysa <greg.malysa@timesys.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: Nathan Barrett-Morrison <nathan.morrison@timesys.com>
Signed-off-by: Oliver Gaskell <Oliver.Gaskell@analog.com>
---
 MAINTAINERS            |   1 +
 drivers/spi/Kconfig    |   7 +
 drivers/spi/Makefile   |   1 +
 drivers/spi/adi_spi3.c | 690 +++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 699 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 86a7f18f530c0fdabd015d49518841b0160bfdba..a553584fb7390adff2af78fe5d9461e99d0084e7 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -620,6 +620,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 fa817ec4883008481a699a0e673a64c9f923d2d0..1b03bc454f245e12110bfdb15b1f7a1ac85d1a7d 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -58,6 +58,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 7051e2a00c604aaf36995b3921f541f06783b5dd..21895d464294a50b13d49566225e7575058d988c 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 0000000000000000000000000000000000000000..9e75050a89707a883398c9ddb7f16af409f30a21
--- /dev/null
+++ b/drivers/spi/adi_spi3.c
@@ -0,0 +1,690 @@
+// 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 <spi.h>
+#include <spi-mem.h>
+#include <asm/io.h>
+#include <dm/device_compat.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 *regs;
+};
+
+struct adi_spi_priv {
+	u32 control;
+	u32 clock;
+	u32 bus_num;
+	u32 max_cs;
+	struct adi_spi_regs *regs;
+	unsigned short *pins;
+	void *memory_map;
+};
+
+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 = (struct adi_spi_regs *)addr;
+
+	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);
+
+	writel(0x0, &plat->regs->control);
+	writel(0x0, &plat->regs->rx_control);
+	writel(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);
+
+	writel(priv->control, &priv->regs->control);
+	writel(priv->clock, &priv->regs->clock);
+	writel(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);
+
+	writel(0x0, &priv->regs->rx_control);
+	writel(0x0, &priv->regs->tx_control);
+	writel(0x0, &priv->regs->control);
+
+	return 0;
+}
+
+void adi_spi_enable_ssel(struct adi_spi_priv *priv, int cs)
+{
+	u32 ssel = readl(&priv->regs->ssel);
+
+	ssel = readl(&priv->regs->ssel);
+	ssel |= BIT_SSEL_EN(cs);
+	writel(ssel, &priv->regs->ssel);
+}
+
+void adi_spi_set_ssel(struct adi_spi_priv *priv, int cs, int high)
+{
+	u32 ssel = readl(&priv->regs->ssel);
+
+	if (high)
+		ssel |= BIT_SSEL_VAL(cs);
+	else
+		ssel &= ~BIT_SSEL_VAL(cs);
+	writel(ssel, &priv->regs->ssel);
+}
+
+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, high);
+	adi_spi_enable_ssel(priv, slave_plat->cs);
+}
+
+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);
+
+	adi_spi_set_ssel(priv, slave_plat->cs, high);
+}
+
+static void discard_rx_fifo_contents(struct adi_spi_regs *regs)
+{
+	while (!(readl(&regs->status) & SPI_STAT_RFE))
+		readl(&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 */
+	writel((priv->control & ~SPI_CTL_SOSI) | mio_mode,
+	       &priv->regs->control);
+	/*
+	 * Data can only be transferred in one direction in multi-io SPI
+	 * modes, trigger the transfer in respective direction.
+	 */
+	if (rx) {
+		writel(0x0, &priv->regs->tx_control);
+		writel(SPI_RXCTL_REN | SPI_RXCTL_RTI,
+		       &priv->regs->rx_control);
+
+		while (bytes--) {
+			while (readl(&priv->regs->status) &
+				SPI_STAT_RFE)
+				if (ctrlc())
+					return -1;
+			value = readl(&priv->regs->rfifo);
+			*rx++ = value;
+		}
+	} else if (tx) {
+		writel(0x0, &priv->regs->rx_control);
+		writel(SPI_TXCTL_TEN | SPI_TXCTL_TTI,
+		       &priv->regs->tx_control);
+
+		while (bytes--) {
+			value = *tx++;
+			writel(value, &priv->regs->tfifo);
+			while (readl(&priv->regs->status) &
+				SPI_STAT_TFF)
+				if (ctrlc())
+					return -1;
+		}
+
+		/* Wait till the tfifo is empty */
+		while ((readl(&priv->regs->status) & SPI_STAT_TFS) !=
+			0x40000)
+			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;
+	int spi_idle;
+
+	#if defined(CONFIG_SPI_IDLE_VAL)
+		spi_idle = CONFIG_SPI_IDLE_VAL;
+	#else
+		spi_idle = SPI_IDLE_VAL;
+	#endif
+	/*
+	 * Set current SPI transfer in normal mode and trigger
+	 * the bi-direction transfer by tx write operation.
+	 */
+	writel(priv->control, &priv->regs->control);
+	writel(SPI_RXCTL_REN, &priv->regs->rx_control);
+	writel(SPI_TXCTL_TEN | SPI_TXCTL_TTI, &priv->regs->tx_control);
+
+	while (bytes--) {
+		value = (tx ? *tx++ : spi_idle);
+		debug("%s: tx:%x ", __func__, value);
+		writel(value, &priv->regs->tfifo);
+		while (readl(&priv->regs->status) & SPI_STAT_RFE)
+			if (ctrlc())
+				return -1;
+		value = readl(&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 -ENOSYS;
+	}
+}
+
+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, 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.34.1



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

* [PATCH v2 11/11] mmc: Add support for ADI SC5XX-family processor SDHCI peripherals
  2024-10-21 13:54 [PATCH v2 00/11] drivers: Driver support for ADI SC5xx SoCs Vasileios Bimpikas via B4 Relay
                   ` (9 preceding siblings ...)
  2024-10-21 13:54 ` [PATCH v2 10/11] spi: Add support for ADI SC5XX-family processor SPI peripherals Vasileios Bimpikas via B4 Relay
@ 2024-10-21 13:54 ` Vasileios Bimpikas via B4 Relay
  2024-10-22 23:04   ` Jaehoon Chung
  10 siblings, 1 reply; 15+ messages in thread
From: Vasileios Bimpikas via B4 Relay @ 2024-10-21 13:54 UTC (permalink / raw)
  To: Tom Rini, Nathan Barrett-Morrison, Greg Malysa, Ian Roberts,
	Vasileios Bimpikas, Utsav Agarwal, Arturs Artamonovs, Marek Vasut,
	Heiko Schocher, Joe Hershberger, Ramon Fried, Stefan Roese,
	Jagan Teki, Peng Fan, Jaehoon Chung
  Cc: u-boot, adsp-linux, Oliver Gaskell

From: Oliver Gaskell <Oliver.Gaskell@analog.com>

Co-developed-by: Greg Malysa <greg.malysa@timesys.com>
Signed-off-by: Greg Malysa <greg.malysa@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: Nathan Barrett-Morrison <nathan.morrison@timesys.com>
Signed-off-by: Oliver Gaskell <Oliver.Gaskell@analog.com>
---
 MAINTAINERS             |   1 +
 drivers/mmc/Kconfig     |   9 +++
 drivers/mmc/Makefile    |   1 +
 drivers/mmc/adi_sdhci.c | 154 ++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 165 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index a553584fb7390adff2af78fe5d9461e99d0084e7..c59e061671e1bca03236211515bc4016306fdf68 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -616,6 +616,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 38817622fca1784703024c357b5d5ca11703afd6..b922765799bdbda991abb306e61969b4d9646e05 100644
--- a/drivers/mmc/Kconfig
+++ b/drivers/mmc/Kconfig
@@ -293,6 +293,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 868f3090ff24cc50cf9d71ac8f1f779efeb1471f..d4b747784b061996e218a2df6906d8c731732b9f 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_STI)		+= sti_sdhci.o
 obj-$(CONFIG_MMC_SDHCI_TANGIER)		+= tangier_sdhci.o
diff --git a/drivers/mmc/adi_sdhci.c b/drivers/mmc/adi_sdhci.c
new file mode 100644
index 0000000000000000000000000000000000000000..311089a5f5230d827bbf8b5439064c94ada2b209
--- /dev/null
+++ b/drivers/mmc/adi_sdhci.c
@@ -0,0 +1,154 @@
+// 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;
+};
+
+struct adi_sdhc {
+	struct sdhci_host host;
+	void *base;
+};
+
+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 adi_sdhc *prv = dev_get_priv(dev);
+	struct sdhci_host *host = &prv->host;
+	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 = &prv->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 adi_sdhc),
+	.plat_auto	= sizeof(struct adi_sdhc_plat),
+};

-- 
2.34.1



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

* Re: [PATCH v2 10/11] spi: Add support for ADI SC5XX-family processor SPI peripherals
  2024-10-21 13:54 ` [PATCH v2 10/11] spi: Add support for ADI SC5XX-family processor SPI peripherals Vasileios Bimpikas via B4 Relay
@ 2024-10-22 16:49   ` Greg Malysa
  0 siblings, 0 replies; 15+ messages in thread
From: Greg Malysa @ 2024-10-22 16:49 UTC (permalink / raw)
  To: Tom Rini, Nathan Morrison, Ian Roberts, Vasileios Bimpikas,
	Utsav Agarwal, Arturs Artamonovs, Marek Vasut, Heiko Schocher,
	Joe Hershberger, Ramon Fried, Stefan Roese, Jagan Teki, Peng Fan,
	Jaehoon Chung
  Cc: u-boot@lists.denx.de, adsp-linux@analog.com, Oliver Gaskell,
	Angelo Dureghello, Piotr Wojtaszczyk

Hi Vas,

Last time this series was submitted we received some good feedback from Christophe (https://patchwork.ozlabs.org/project/uboot/patch/20240515215837.14028-11-greg.malysa@timesys.com/), but I don't see the changes applied (or justifications for why they should not be applied). Let's get those issues addressed for v3. I can help with this in the coming weeks; I will reach out to you separately to follow up.

Thanks,
Greg

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

* RE: [PATCH v2 11/11] mmc: Add support for ADI SC5XX-family processor SDHCI peripherals
  2024-10-21 13:54 ` [PATCH v2 11/11] mmc: Add support for ADI SC5XX-family processor SDHCI peripherals Vasileios Bimpikas via B4 Relay
@ 2024-10-22 23:04   ` Jaehoon Chung
  0 siblings, 0 replies; 15+ messages in thread
From: Jaehoon Chung @ 2024-10-22 23:04 UTC (permalink / raw)
  To: vasileios.bimpikas, 'Tom Rini',
	'Nathan Barrett-Morrison', 'Greg Malysa',
	'Ian	Roberts', 'Utsav Agarwal',
	'Arturs Artamonovs', 'Marek Vasut',
	'Heiko Schocher', 'Joe Hershberger',
	'Ramon Fried', 'Stefan Roese',
	'Jagan Teki', 'Peng Fan'
  Cc: u-boot, adsp-linux, 'Oliver Gaskell'



> -----Original Message-----
> From: Vasileios Bimpikas via B4 Relay <devnull+vasileios.bimpikas.analog.com@kernel.org>
> Sent: Monday, October 21, 2024 10:55 PM
> To: Tom Rini <trini@konsulko.com>; Nathan Barrett-Morrison <nathan.morrison@timesys.com>; Greg Malysa
> <greg.malysa@timesys.com>; Ian Roberts <ian.roberts@timesys.com>; Vasileios Bimpikas
> <vasileios.bimpikas@analog.com>; Utsav Agarwal <utsav.agarwal@analog.com>; Arturs Artamonovs
> <arturs.artamonovs@analog.com>; Marek Vasut <marex@denx.de>; Heiko Schocher <hs@denx.de>; Joe
> Hershberger <joe.hershberger@ni.com>; Ramon Fried <rfried.dev@gmail.com>; Stefan Roese <sr@denx.de>;
> Jagan Teki <jagan@amarulasolutions.com>; Peng Fan <peng.fan@nxp.com>; Jaehoon Chung
> <jh80.chung@samsung.com>
> Cc: u-boot@lists.denx.de; adsp-linux@analog.com; Oliver Gaskell <Oliver.Gaskell@analog.com>
> Subject: [PATCH v2 11/11] mmc: Add support for ADI SC5XX-family processor SDHCI peripherals
>
> From: Oliver Gaskell <Oliver.Gaskell@analog.com>
>
> Co-developed-by: Greg Malysa <greg.malysa@timesys.com>
> Signed-off-by: Greg Malysa <greg.malysa@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: Nathan Barrett-Morrison <nathan.morrison@timesys.com>
> Signed-off-by: Oliver Gaskell <Oliver.Gaskell@analog.com>
> ---
>  MAINTAINERS             |   1 +
>  drivers/mmc/Kconfig     |   9 +++
>  drivers/mmc/Makefile    |   1 +
>  drivers/mmc/adi_sdhci.c | 154 ++++++++++++++++++++++++++++++++++++++++++++++++
>  4 files changed, 165 insertions(+)
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index a553584fb7390adff2af78fe5d9461e99d0084e7..c59e061671e1bca03236211515bc4016306fdf68 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -616,6 +616,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 38817622fca1784703024c357b5d5ca11703afd6..b922765799bdbda991abb306e61969b4d9646e05 100644
> --- a/drivers/mmc/Kconfig
> +++ b/drivers/mmc/Kconfig
> @@ -293,6 +293,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 868f3090ff24cc50cf9d71ac8f1f779efeb1471f..d4b747784b061996e218a2df6906d8c731732b9f 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_STI)		+= sti_sdhci.o
>  obj-$(CONFIG_MMC_SDHCI_TANGIER)		+= tangier_sdhci.o
> diff --git a/drivers/mmc/adi_sdhci.c b/drivers/mmc/adi_sdhci.c
> new file mode 100644
> index 0000000000000000000000000000000000000000..311089a5f5230d827bbf8b5439064c94ada2b209
> --- /dev/null
> +++ b/drivers/mmc/adi_sdhci.c
> @@ -0,0 +1,154 @@
> +// 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.
> + */

Could you change the above comment? I can't know where is relevant to this comment.

> +#define ADMA_TABLE_EXTRA_SZ (ADMA_POTENTIAL_CROSSINGS * ADMA_DESC_LEN)
> +
> +struct adi_sdhc_plat {
> +	struct mmc_config cfg;
> +	struct mmc mmc;
> +};
> +
> +struct adi_sdhc {
> +	struct sdhci_host host;
> +	void *base;
> +};
> +
> +void adi_dwcmshc_adma_write_desc(struct sdhci_host *host, void **desc,
> +				 dma_addr_t addr, int len, bool end)

Can it be static?

> +{
> +	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 adi_sdhc *prv = dev_get_priv(dev);
> +	struct sdhci_host *host = &prv->host;
> +	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 = &prv->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 adi_sdhc),
> +	.plat_auto	= sizeof(struct adi_sdhc_plat),
> +};
>
> --
> 2.34.1
>




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

end of thread, other threads:[~2024-10-22 23:04 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-10-21 13:54 [PATCH v2 00/11] drivers: Driver support for ADI SC5xx SoCs Vasileios Bimpikas via B4 Relay
2024-10-21 13:54 ` [PATCH v2 01/11] pinctrl: Add support for ADI SC5XX-family pinctrl Vasileios Bimpikas via B4 Relay
2024-10-21 13:54 ` [PATCH v2 02/11] gpio: Add support for SC5XX-family processor GPIO driver Vasileios Bimpikas via B4 Relay
2024-10-21 13:54 ` [PATCH v2 03/11] gpio: Add support for ADI ADP5588 GPIO expander chips Vasileios Bimpikas via B4 Relay
2024-10-21 13:54 ` [PATCH v2 04/11] usb: musb-new: Add support for Analog Devices SC5xx SoCs Vasileios Bimpikas via B4 Relay
2024-10-21 13:54 ` [PATCH v2 05/11] i2c: Add support for ADI SC5XX-family I2C peripheral Vasileios Bimpikas via B4 Relay
2024-10-21 13:54 ` [PATCH v2 06/11] net: Add support for ADI SC5xx SoCs with DWC QoS ethernet Vasileios Bimpikas via B4 Relay
2024-10-21 13:54 ` [PATCH v2 07/11] watchdog: Add support for ADI SC5XX-family watchdog peripheral Vasileios Bimpikas via B4 Relay
2024-10-21 13:54 ` [PATCH v2 08/11] dma: Add driver for ADI SC5xx-family SoC MDMA functionality Vasileios Bimpikas via B4 Relay
2024-10-21 13:54 ` [PATCH v2 09/11] remoteproc: Add in SHARC loading for ADI SC5XX-family processors Vasileios Bimpikas via B4 Relay
2024-10-21 13:54 ` [PATCH v2 10/11] spi: Add support for ADI SC5XX-family processor SPI peripherals Vasileios Bimpikas via B4 Relay
2024-10-22 16:49   ` Greg Malysa
2024-10-21 13:54 ` [PATCH v2 11/11] mmc: Add support for ADI SC5XX-family processor SDHCI peripherals Vasileios Bimpikas via B4 Relay
2024-10-22 23:04   ` Jaehoon Chung
  -- strict thread matches above, loose matches on Subject: below --
2024-09-25 12:25 [PATCH v2 00/11] drivers: Driver support for ADI SC5xx SoCs Oliver Gaskell via B4 Relay
2024-09-25 12:25 ` [PATCH v2 11/11] mmc: Add support for ADI SC5XX-family processor SDHCI peripherals Oliver Gaskell via B4 Relay

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