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

Add support for the SC5xx machine type from Analog Devices. This
includes support for the SC57x, SC58x, SC59x, and SC59x-64 SoCs, which
have many common features such as common ADI IP blocks, and SHARC DSP
cores. This commit introduces core functionality required for all boards
using an SC5xx SoC, such as:

- SPL configuration
- Required CPU hooks such as reset
- Boot ROM interaction to load the stage 2 bootloader in the reference
  configuration. Other options are possible but not officially supported
  at this time
- SoC-common configuration expected to be reused by all boards
- Early initialization for system clocks and DDR controller

Co-developed-by: Greg Malysa <greg.mal...@timesys.com>
Signed-off-by: Greg Malysa <greg.mal...@timesys.com>
Co-developed-by: Ian Roberts <ian.robe...@timesys.com>
Signed-off-by: Ian Roberts <ian.robe...@timesys.com>
Signed-off-by: Vasileios Bimpikas <vasileios.bimpi...@analog.com>
Signed-off-by: Utsav Agarwal <utsav.agar...@analog.com>
Signed-off-by: Arturs Artamonovs <arturs.artamon...@analog.com>
Signed-off-by: Nathan Barrett-Morrison <nathan.morri...@timesys.com>

---


---
 MAINTAINERS                                  |  13 +
 arch/arm/Kconfig                             |   6 +
 arch/arm/Makefile                            |   1 +
 arch/arm/include/asm/arch-adi/sc5xx/sc5xx.h  | 115 +++
 arch/arm/include/asm/arch-adi/sc5xx/soc.h    |  18 +
 arch/arm/include/asm/arch-adi/sc5xx/spl.h    |  41 +
 arch/arm/include/asm/mach-types.h            |   4 +
 arch/arm/mach-sc5xx/Kconfig                  | 464 +++++++++
 arch/arm/mach-sc5xx/Makefile                 |  19 +
 arch/arm/mach-sc5xx/config.mk                |  21 +
 arch/arm/mach-sc5xx/init/Makefile            |  11 +
 arch/arm/mach-sc5xx/init/clkinit.c           | 543 +++++++++++
 arch/arm/mach-sc5xx/init/clkinit.h           |  18 +
 arch/arm/mach-sc5xx/init/dmcinit.c           | 973 +++++++++++++++++++
 arch/arm/mach-sc5xx/init/dmcinit.h           |  29 +
 arch/arm/mach-sc5xx/init/init.c              |  68 ++
 arch/arm/mach-sc5xx/init/init.h              |  37 +
 arch/arm/mach-sc5xx/init/mem/is43tr16512bl.h |  63 ++
 arch/arm/mach-sc5xx/init/mem/mt41k128m16jt.h |  51 +
 arch/arm/mach-sc5xx/init/mem/mt41k512m16ha.h |  51 +
 arch/arm/mach-sc5xx/init/mem/mt47h128m16rt.h |  50 +
 arch/arm/mach-sc5xx/rcu.c                    |  22 +
 arch/arm/mach-sc5xx/sc57x.c                  |  21 +
 arch/arm/mach-sc5xx/sc58x.c                  |  21 +
 arch/arm/mach-sc5xx/sc59x.c                  |  32 +
 arch/arm/mach-sc5xx/sc59x_64.c               |  36 +
 arch/arm/mach-sc5xx/soc.c                    | 142 +++
 arch/arm/mach-sc5xx/spl.c                    | 140 +++
 include/configs/sc_adi_common.h              | 226 +++++
 29 files changed, 3236 insertions(+)
 create mode 100644 arch/arm/include/asm/arch-adi/sc5xx/sc5xx.h
 create mode 100644 arch/arm/include/asm/arch-adi/sc5xx/soc.h
 create mode 100644 arch/arm/include/asm/arch-adi/sc5xx/spl.h
 create mode 100644 arch/arm/mach-sc5xx/Kconfig
 create mode 100644 arch/arm/mach-sc5xx/Makefile
 create mode 100644 arch/arm/mach-sc5xx/config.mk
 create mode 100644 arch/arm/mach-sc5xx/init/Makefile
 create mode 100644 arch/arm/mach-sc5xx/init/clkinit.c
 create mode 100644 arch/arm/mach-sc5xx/init/clkinit.h
 create mode 100644 arch/arm/mach-sc5xx/init/dmcinit.c
 create mode 100644 arch/arm/mach-sc5xx/init/dmcinit.h
 create mode 100644 arch/arm/mach-sc5xx/init/init.c
 create mode 100644 arch/arm/mach-sc5xx/init/init.h
 create mode 100644 arch/arm/mach-sc5xx/init/mem/is43tr16512bl.h
 create mode 100644 arch/arm/mach-sc5xx/init/mem/mt41k128m16jt.h
 create mode 100644 arch/arm/mach-sc5xx/init/mem/mt41k512m16ha.h
 create mode 100644 arch/arm/mach-sc5xx/init/mem/mt47h128m16rt.h
 create mode 100644 arch/arm/mach-sc5xx/rcu.c
 create mode 100644 arch/arm/mach-sc5xx/sc57x.c
 create mode 100644 arch/arm/mach-sc5xx/sc58x.c
 create mode 100644 arch/arm/mach-sc5xx/sc59x.c
 create mode 100644 arch/arm/mach-sc5xx/sc59x_64.c
 create mode 100644 arch/arm/mach-sc5xx/soc.c
 create mode 100644 arch/arm/mach-sc5xx/spl.c
 create mode 100644 include/configs/sc_adi_common.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 83fd68e3f3..9693b86ddd 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -598,6 +598,19 @@ R: Marc Murphy <marc.mur...@sancloud.com>
 S:     Supported
 F:     arch/arm/dts/am335x-sancloud*
 
+ARM SC5XX
+M:     Nathan Barrett-Morrison <nathan.morri...@timesys.com>
+M:     Greg Malysa <greg.mal...@timesys.com>
+M:     Ian Roberts <ian.robe...@timesys.com>
+M:     Vasileios Bimpikas <vasileios.bimpi...@analog.com>
+M:     Utsav Agarwal <utsav.agar...@analog.com>
+M:     Arturs Artamonovs <arturs.artamon...@analog.com>
+S:     Supported
+T:     git https://github.com/analogdevicesinc/lnxdsp-u-boot
+F:     arch/arm/include/asm/arch-adi/
+F:     arch/arm/mach-sc5xx/
+F:     include/configs/sc_adi_common.h
+
 ARM SNAPDRAGON
 M:     Caleb Connolly <caleb.conno...@linaro.org>
 M:     Neil Armstrong <neil.armstr...@linaro.org>
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index a0842e1933..fdaf4e23d0 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1843,6 +1843,10 @@ config TARGET_LS1046AFRWY
          development platform that supports the QorIQ LS1046A
          Layerscape Architecture processor.
 
+config ARCH_SC5XX
+       bool "Analog Devices SC5XX-processor family"
+       select STATIC_MACH_TYPE
+
 config TARGET_SL28
        bool "Support sl28"
        select ARCH_LS1028A
@@ -2276,6 +2280,8 @@ source "arch/arm/mach-rockchip/Kconfig"
 
 source "arch/arm/mach-s5pc1xx/Kconfig"
 
+source "arch/arm/mach-sc5xx/Kconfig"
+
 source "arch/arm/mach-snapdragon/Kconfig"
 
 source "arch/arm/mach-socfpga/Kconfig"
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index a4266a3e36..734c6d6992 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -78,6 +78,7 @@ machine-$(CONFIG_ARCH_OWL)            += owl
 machine-$(CONFIG_ARCH_RENESAS)         += renesas
 machine-$(CONFIG_ARCH_ROCKCHIP)                += rockchip
 machine-$(CONFIG_ARCH_S5PC1XX)         += s5pc1xx
+machine-$(CONFIG_ARCH_SC5XX)           += sc5xx
 machine-$(CONFIG_ARCH_SNAPDRAGON)      += snapdragon
 machine-$(CONFIG_ARCH_SOCFPGA)         += socfpga
 machine-$(CONFIG_ARCH_STM32)           += stm32
diff --git a/arch/arm/include/asm/arch-adi/sc5xx/sc5xx.h 
b/arch/arm/include/asm/arch-adi/sc5xx/sc5xx.h
new file mode 100644
index 0000000000..bcac3ad8e3
--- /dev/null
+++ b/arch/arm/include/asm/arch-adi/sc5xx/sc5xx.h
@@ -0,0 +1,115 @@
+/* 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.morri...@timesys.com>
+ * Contact: Greg Malysa <greg.mal...@timesys.com>
+ */
+#ifndef ARCH_ADI_SC5XX_SC5XX_H
+#define ARCH_ADI_SC5XX_SC5XX_H
+
+#include <inttypes.h>
+
+#ifdef CONFIG_SC57X
+#define L2_SRAM_BASE                0x20000000
+#else
+#define L2_SRAM_BASE                0x20080000
+#endif
+
+#define TWI0_CLKDIV                 0x31001400    // TWI0 SCL Clock Divider 
Register
+#define TWI1_CLKDIV                 0x31001500    // TWI1 SCL Clock Divider 
Register
+#define TWI2_CLKDIV                 0x31001600    // TWI2 SCL Clock Divider 
Register
+
+#ifdef CONFIG_SC58X
+#define RCU0_CTL                    0x3108B000    // RCU0 Control Register
+#define RCU0_STAT                   0x3108B004    // RCU0 Status Register
+#define RCU0_CRCTL                  0x3108B008    // RCU0 Core Reset Control 
Register
+#define RCU0_CRSTAT                 0x3108B00C    // RCU0 Core Reset Status 
Register
+#define RCU0_SIDIS                  0x3108B010    // RCU0 System Interface 
Disable Register
+#define RCU0_MSG_SET                0x3108B064    // RCU0 Message Set Bits 
Register
+#else
+#define RCU0_CTL                    0x3108C000    // RCU0 Control Register
+#define RCU0_STAT                   0x3108C004    // RCU0 Status Register
+#define RCU0_CRCTL                  0x3108C008    // RCU0 Core Reset Control 
Register
+#define RCU0_CRSTAT                 0x3108C00C    // RCU0 Core Reset Status 
Register
+#define RCU0_SIDIS                  0x3108C01C    // RCU0 System Interface 
Disable Register
+#define RCU0_MSG_SET                0x3108C070    // RCU0 Message Set Bits 
Register
+#endif
+
+#define BITP_RCU_STAT_BMODE                  8    // Boot Mode
+#define BITM_RCU_STAT_BMODE         0x00000F00    // Boot Mode
+
+#ifdef CONFIG_SC58X
+#define REG_SPU0_CTL                0x3108C000    // SPU0 Control Register
+#else
+#define REG_SPU0_CTL                0x3108B000    // SPU0 Control Register
+#define REG_SPU0_SECUREC0           0x3108B980    // SPU0 Secure Core Registers
+#define REG_SPU0_SECUREC1           0x3108B984    // SPU0 Secure Core Registers
+#define REG_SPU0_SECUREC2           0x3108B988    // SPU0 Secure Core Registers
+#define REG_SPU0_SECURECn(i)        (REG_SPU0_SECUREC0 + ((i) * 4))
+#define REG_SPU0_SECURECn_COUNT              3
+#endif
+
+#define CGU0_CTL                    0x3108D000    // CGU0 Control Register
+#define CGU0_PLLCTL                 0x3108D004    // CGU0 PLL Control Register
+#define CGU0_STAT                   0x3108D008    // CGU0 Status Register
+#define CGU0_DIV                    0x3108D00C    // CGU0 Clocks Divisor 
Register
+#define CGU0_CLKOUTSEL              0x3108D010    // CGU0 CLKOUT Select 
Register
+#define CGU0_DIVEX                  0x3108D040    // CGU0 DIV Register 
Extension
+
+#define CGU1_CTL                    0x3108E000    // CGU1 Control Register
+#define CGU1_PLLCTL                 0x3108E004    // CGU1 PLL Control Register
+#define CGU1_STAT                   0x3108E008    // CGU1 Status Register
+
+#define BITP_CGU_DIV_OSEL                   22    // OUTCLK Divisor
+#define BITP_CGU_DIV_DSEL                   16    // DCLK Divisor
+#define BITP_CGU_DIV_S1SEL                  13    // SCLK 1 Divisor
+#define BITP_CGU_DIV_SYSSEL                  8    // SYSCLK Divisor
+#define BITP_CGU_DIV_S0SEL                   5    // SCLK 0 Divisor
+#define BITP_CGU_DIV_CSEL                    0    // CCLK Divisor
+
+#define BITP_CGU_CTL_MSEL                    8    // Multiplier Select
+#define BITP_CGU_CTL_DF                      0    // Divide Frequency
+
+#define BITM_CGU_STAT_CLKSALGN      0x00000008
+#define BITM_CGU_STAT_PLOCK         0x00000004
+#define BITM_CGU_STAT_PLLBP         0x00000002
+#define BITM_CGU_STAT_PLLEN         0x00000001
+
+#define REG_MISC_REG10_tst_addr     0x310A902C
+
+#define REG_USB0_FADDR              0x310C1000    // USB0 Function Address 
Register
+#define REG_USB0_DMA_IRQ            0x310C1200    // USB0 DMA Interrupt 
Register
+#define REG_USB0_VBUS_CTL           0x310C1380    // USB0 VBUS Control Register
+#define REG_USB0_PHY_CTL            0x310C1394    // USB0 PHY Control Register
+#define REG_USB0_PLL_OSC            0x310C1398    // USB0 PLL and Oscillator 
Control Register
+#define REG_USB0_UTMI_CTL           0x310C139C
+
+#define BITP_USB_DMA_CTL_IE                  3    // DMA Interrupt Enable
+#define BITP_USB_DMA_CTL_DIR                 1    // DMA Transfer Direction
+#define BITP_USB_DMA_CTL_EN                  0    // DMA Enable
+
+#if defined(CONFIG_SC59X)
+       #define pRCU_MSG                ((void __iomem *)0x3108C06C)
+#elif defined(CONFIG_SC59X_64)
+       #define pRCU_MSG                ((void __iomem *)0x3108C06C)
+       #define pREG_EMSI0_SWRST        ((void __iomem *)0x310C702F)
+#elif defined(CONFIG_SC57X)
+       #define pRCU_MSG                ((void __iomem *)0x3108C06C)
+#elif defined(CONFIG_SC58X)
+       #define pRCU_MSG                ((void __iomem *)0x3108B06C)
+#endif
+
+const char *sc5xx_get_boot_mode(u32 *bmode);
+void sc5xx_enable_rgmii(void);
+
+/*
+ * Reconfigure SPI memory map region for OSPI use. The adi-spi3 driver
+ * does not use the memory map, while the OSPI driver requires it. Only
+ * available on sc59x and sc59x-64
+ */
+void sc59x_remap_ospi(void);
+
+#endif
diff --git a/arch/arm/include/asm/arch-adi/sc5xx/soc.h 
b/arch/arm/include/asm/arch-adi/sc5xx/soc.h
new file mode 100644
index 0000000000..430dbe2dae
--- /dev/null
+++ b/arch/arm/include/asm/arch-adi/sc5xx/soc.h
@@ -0,0 +1,18 @@
+/* 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.morri...@timesys.com>
+ * Contact: Greg Malysa <greg.mal...@timesys.com>
+ */
+
+#ifndef BOARD_ADI_COMMON_SOC_H
+#define BOARD_ADI_COMMON_SOC_H
+
+#include <phy.h>
+
+void fixup_dp83867_phy(struct phy_device *phydev);
+
+#endif
diff --git a/arch/arm/include/asm/arch-adi/sc5xx/spl.h 
b/arch/arm/include/asm/arch-adi/sc5xx/spl.h
new file mode 100644
index 0000000000..946d599b56
--- /dev/null
+++ b/arch/arm/include/asm/arch-adi/sc5xx/spl.h
@@ -0,0 +1,41 @@
+/* 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.morri...@timesys.com>
+ * Contact: Greg Malysa <greg.mal...@timesys.com>
+ */
+#ifndef ARCH_ADI_SC5XX_SPL_H
+#define ARCH_ADI_SC5XX_SPL_H
+
+#include <netdev.h>
+#include <phy.h>
+#include <asm/io.h>
+#include <asm/mach-types.h>
+#include <asm/arch-adi/sc5xx/sc5xx.h>
+#include <linux/delay.h>
+#include <linux/stringify.h>
+#include <watchdog.h>
+#include <asm/spl.h>
+
+struct adi_boot_args {
+       phys_addr_t addr;
+       u32 flags;
+       u32 cmd;
+};
+
+extern u32 bmode;
+
+extern const struct adi_boot_args adi_rom_boot_args[8];
+
+// Struct layout is processor specific
+struct ADI_ROM_BOOT_CONFIG;
+
+int32_t adi_rom_boot_hook(struct ADI_ROM_BOOT_CONFIG *cfg, int32_t cause);
+
+extern void (*adi_rom_boot)(void *address, uint32_t flags, int32_t count,
+                           void *hook, uint32_t command);
+
+#endif
diff --git a/arch/arm/include/asm/mach-types.h 
b/arch/arm/include/asm/mach-types.h
index 2713b1d2c5..3e577fc0f1 100644
--- a/arch/arm/include/asm/mach-types.h
+++ b/arch/arm/include/asm/mach-types.h
@@ -5050,4 +5050,8 @@
 #define MACH_TYPE_NASM25               5112
 #define MACH_TYPE_TOMATO               5113
 #define MACH_TYPE_OMAP3_MRC3D          5114
+#define MACH_TYPE_SC57X                5115
+#define MACH_TYPE_SC58X                5116
+#define MACH_TYPE_SC59X                5117
+#define MACH_TYPE_SC59X_64             5118
 #endif
diff --git a/arch/arm/mach-sc5xx/Kconfig b/arch/arm/mach-sc5xx/Kconfig
new file mode 100644
index 0000000000..b1253290f2
--- /dev/null
+++ b/arch/arm/mach-sc5xx/Kconfig
@@ -0,0 +1,464 @@
+# 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.morri...@timesys.com>
+# Contact: Greg Malysa <greg.mal...@timesys.com>
+#
+
+# All 32-bit platforms require SYS_ARM_CACHE_WRITETHROUGH
+# But it is ignored if selected here, so it must be in the defconfig
+
+if ARCH_SC5XX
+
+config TARGET_SC573_EZKIT
+       bool "Analog Devices SC573 EZ Kit"
+       select SC57X
+
+config SC57X
+       bool
+       select SUPPORT_SPL
+       select CPU_V7A
+       select PANIC_HANG
+       select COMMON_CLK_ADI_SC57X
+       select TIMER
+       select ADI_SC5XX_TIMER
+
+config SC58X
+       bool
+       select SUPPORT_SPL
+       select CPU_V7A
+       select PANIC_HANG
+       select COMMON_CLK_ADI_SC58X
+       select TIMER
+       select ADI_SC5XX_TIMER
+
+config SC59X
+       bool
+       select SUPPORT_SPL
+       select CPU_V7A
+       select PANIC_HANG
+       select COMMON_CLK_ADI_SC594
+       select TIMER
+       select ADI_SC5XX_TIMER
+       select NOP_PHY
+
+config SC59X_64
+       bool
+       select SUPPORT_SPL
+       select PANIC_HANG
+       select MMC_SDHCI_ADMA_FORCE_32BIT
+       select ARM64
+       select DM
+       select DM_SERIAL
+       select COMMON_CLK_ADI_SC598
+       select GICV3
+       select GIC_600_CLEAR_RDPD
+       select NOP_PHY
+
+# These need to match the constants in arch/arm/include/asm/mach-types.h
+config MACH_TYPE
+       default 5115 if SC57X
+       default 5116 if SC58X
+       default 5117 if SC59X
+       default 5118 if SC59X_64
+
+config SC_BOOT_MODE
+       int "SC5XX boot mode select"
+       default 1
+       range 0 7
+       help
+         Mode 0: do nothing, just idle
+         Mode 1: boot ldr out of serial flash
+         Mode 7: boot ldr over uart
+
+config SC_BOOT_SPI_BUS
+       int "sc5xx spi boot bus"
+       default 2
+       range 0 4
+       help
+               This is the SPI peripheral number to use for booting, X in the
+               expression `sf probe X:Y`
+
+config SC_BOOT_SPI_SSEL
+       int "sc5xx spi boot chipselect"
+       default 1
+       range 0 6
+       help
+               This is the SPI chip select number to use for booting, Y in the
+               expression `sf probe X:Y`
+
+config SC_BOOT_OSPI_BUS
+       int "sc5xx ospi boot bus"
+       default 0
+       help
+               This is the OSPI peripheral number to use for booting, X in the
+               expression `sf probe X:Y`
+
+config SC_BOOT_OSPI_SSEL
+       int "sc5xx ospi boot chipselect"
+       default 0
+       help
+               This is the OSPI chip select number to use for booting, Y in the
+               expression `sf probe X:Y`
+
+config SYS_FLASH_BASE
+       hex
+       default 0x60000000
+
+config UART_CONSOLE
+       int
+       default 0
+
+config UART4_SERIAL
+       bool
+       depends on DM_SERIAL
+       default y
+
+config WDT_ADI
+       bool
+       default y
+
+config WATCHDOG_TIMEOUT_MSECS
+       int
+       default 30000
+
+config DW_PORTS
+       int
+       default 1
+
+config ADI_BUG_EZKHW21
+       bool "SC584 EZKIT phy bug workaround"
+       depends on SC58X
+       default n
+       help
+         This workaround affects the SC584 EZKIT and addresses bug EZKHW21.
+         It disables gigabit ethernet mode and limits the board to 100 Mbps
+
+config ADI_CARRIER_SOMCRR_EZKIT
+       bool "Support the EV-SOMCRR-EZKIT"
+       depends on (SC59X || SC59X_64)
+       default n
+       help
+         Say y to include support for the EV-SOMCRR-EZKIT carrier board,
+         which is compatible with the SC594 and SC598 SOMs. The EZKIT is
+         mutually incompatible with the EZLITE.
+
+config ADI_CARRIER_SOMCRR_EZLITE
+       bool "Support the EV-SOMCRR-EZLITE"
+       depends on (SC59X || SC59X_64)
+       default n
+       help
+         Say y to include support for the EV-SOMCRR-EZLITE carrier board,
+         which is compatible with the SC594 and SC598 SOMs. The EZLITE is
+         mutually incompatible with the EZKIT.
+
+config ADI_SPL_FORCE_BMODE
+       int "Force the SPL to use this BMODE device during next boot stage"
+       default 0
+       range 0 9
+       depends on SPL
+       help
+         Force the SPL to use this BMODE device during next boot stage.
+         For example, if booting via QSPI, we can force the second stage
+         Of the boot process to use other peripherals via:
+         1 = QSPI -> QSPI
+         5 = QSPI -> OSPI
+         6 = QSPI -> eMMC
+
+menu "Clock configuration"
+
+config CGU0_DF_DIV
+       int "CGU0_DF_DIV"
+       range 0 1
+       help
+               Select 0 to pass CLKIN to PLL
+               Select 1 to pass CLKIN/2 to PLL
+
+config CGU0_VCO_MULT
+       int "CGU0_VCO_MULT"
+       range 0 127
+       help
+               VCO_MULT controls the MSEL (multiplier) bits in PLL_CTL
+               A value of 0 means 128
+
+config CGU0_CCLK_DIV
+       int "CGU0_CCLK_DIV"
+       range 0 31
+       help
+               CCLK_DIV controls the core clock divider
+               A value of 0 means 32
+               CCLK = ((CLKIN / (1 + DF)) * VCO_MULT) / CCLK_DIV
+
+config CGU0_SCLK_DIV
+       int "CGU0_SCLK_DIV"
+       range 0 31
+       help
+               SCLK_DIV controls the system clock divider
+               A value of 0 means 32
+               SCLK = ((CLKIN / (1 + DF)) * VCO_MULT) / SYSCLK_DIV
+
+config CGU0_SCLK0_DIV
+       int "CGU0_SCLK0_DIV"
+       range 0 7
+       help
+               A value of 0 means 8
+               SCLK0 = SCLK / SCLK0_DIV
+
+config CGU0_SCLK1_DIV
+       int "CGU0_SCLK1_DIV"
+       depends on (SC57X || SC58X)
+       range 0 7
+       help
+               A value of 0 means 8
+               SCLK1 = SCLK / SCLK1_DIV
+
+config CGU0_DCLK_DIV
+       int "CGU0_DCLK_DIV"
+       range 0 31
+       help
+               DCLK_DIV controls the DDR clock divider
+               A value of 0 means 32
+               DCLK = ((CLKIN / (1 + DF)) * VCO_MULT) / DCLK_DIV
+
+config CGU0_OCLK_DIV
+       int "CGU0_OCLK_DIV"
+       range 0 127
+       help
+               OCLK_DIV controls the output clock divider
+               A value of 0 means 128
+               OCLK = ((CLKIN / (1 + DF)) * VCO_MULT) / OCLK_DIV
+
+config CGU0_DIV_S1SELEX
+       int "CGU0_DIV_S1SELEX"
+       depends on !SC57X && !SC58X
+       range 0 255
+       help
+               CGU0 SCLK1 Extended divisor register.
+               A value of 0 means 256.
+               SCLK1 = ((CLKIN / (1 + DF)) * VCO_MULT) / DIV_S1SELEX
+
+config CGU0_CLKOUTSEL
+       int "CGU0_CLKOUTSEL"
+       default 0
+       range 0 31
+       help
+               Select signal driven through CLKOUT pin multiplexer.
+               This value varies on each SOC. Refer to
+               CGU_CLKOUTSEL.CLKOUTSEL in the Hardware Reference Manual
+               for values applicable to each SOC.
+               Commonly, values 0 and 1 select CLKIN0 or CLKIN1 respectively.
+
+config CGU1_PLL3_DDRCLK
+       bool "DDRCLK From 3rd PLL"
+       depends on SC59X_64
+       help
+               3rd PLL output is connected to DMC block when set.
+               When cleared, DDR clock is CLKO3 output of CDU.
+
+config CGU1_PLL3_VCO_MSEL
+       int "CGU0_PLL3_VCO_MSEL"
+       depends on CGU1_PLL3_DDRCLK
+       range 1 128
+       help
+               PLL multiplier value for the 3rd PLL.
+               DCLK = (CLKIN * PLL3_VCO_MSEL) / PLL3_DCLK_DIV
+
+config CGU1_PLL3_DCLK_DIV
+       int "CGU0_PLL3_DCLK_DIV"
+       depends on CGU1_PLL3_DDRCLK
+       range 1 32
+       help
+               PLL divider value for the 3rd PLL.
+               DCLK = (CLKIN * PLL3_VCO_MSEL) / PLL3_DCLK_DIV
+
+config CGU1_DF_DIV
+       int "CGU1_DF_DIV"
+       range 0 1
+       help
+               Select 0 to pass CLKIN to PLL
+               Select 1 to pass CLKIN/2 to PLL
+
+config CGU1_VCO_MULT
+       int "CGU1_VCO_MULT"
+       range 0 127
+       help
+               VCO_MULT controls the MSEL (multiplier) bits in PLL_CTL
+               A value of 0 means 128
+
+config CGU1_CCLK_DIV
+       int "CGU1_CCLK_DIV"
+       range 0 31
+       help
+               CCLK_DIV controls the core clock divider
+               A value of 0 means 32
+               CCLK = ((CLKIN / (1 + DF)) * VCO_MULT) / CCLK_DIV
+
+config CGU1_SCLK_DIV
+       int "CGU1_SCLK_DIV"
+       range 0 31
+       help
+               SCLK_DIV controls the system clock divider
+               A value of 0 means 32
+               SCLK = ((CLKIN / (1 + DF)) * VCO_MULT) / SYSCLK_DIV
+
+config CGU1_SCLK0_DIV
+       int "CGU1_SCLK0_DIV"
+       depends on (SC57X || SC58X || SC59X)
+       range 0 7
+       help
+               A value of 0 means 8
+               SCLK0 = SCLK / SCLK0_DIV
+
+config CGU1_SCLK1_DIV
+       int "CGU1_SCLK1_DIV"
+       depends on (SC57X || SC58X)
+       range 0 7
+       help
+               A value of 0 means 8
+               SCLK1 = SCLK / SCLK1_DIV
+
+config CGU1_DCLK_DIV
+       int "CGU1_DCLK_DIV"
+       range 0 31
+       help
+               DCLK_DIV controls the DDR clock divider
+               A value of 0 means 32
+               DCLK = ((CLKIN / (1 + DF)) * VCO_MULT) / DCLK_DIV
+
+config CGU1_OCLK_DIV
+       int "CGU1_OCLK_DIV"
+       range 0 127
+       help
+               OCLK_DIV controls the output clock divider
+               A value of 0 means 128
+               OCLK = ((CLKIN / (1 + DF)) * VCO_MULT) / OCLK_DIV
+
+config CGU1_DIV_S0SELEX
+       int "CGU1_DIV_S0SELEX"
+       depends on !SC57X && !SC58X && !SC59X
+       range 0 255
+       help
+               CGU1 SCLK0 Extended divisor register.
+               A value of 0 means 256.
+               SCLK0 = ((CLKIN / (1 + DF)) * VCO_MULT) / DIV_S0SELEX
+
+config CGU1_DIV_S1SELEX
+       int "CGU1_DIV_S1SELEX"
+       depends on !SC57X && !SC58X
+       range 0 255
+       help
+               CGU1 SCLK1 Extended divisor register.
+               A value of 0 means 256.
+               SCLK1 = ((CLKIN / (1 + DF)) * VCO_MULT) / DIV_S1SELEX
+
+config CDU0_CGU1_CLKIN
+       int "CDU0 CGU1 CLKINn Select"
+       default 0
+       range 0 1
+       help
+               Selects source clock for CGU1.
+               0 for CLKIN0
+               1 for CLKIN1
+
+config CDU0_CLKO0
+       int "CDU0_CLKO0"
+       range 1 7
+       help
+               Clock source select. Refer to SOC Hardware Reference Manual
+
+config CDU0_CLKO1
+       int "CDU0_CLKO1"
+       range 1 7
+       help
+               Clock source select. Refer to SOC Hardware Reference Manual
+
+config CDU0_CLKO2
+       int "CDU0_CLKO2"
+       range 1 7
+       help
+               Clock source select. Refer to SOC Hardware Reference Manual
+
+config CDU0_CLKO3
+       int "CDU0_CLKO3"
+       range 1 7
+       help
+               Clock source select. Refer to SOC Hardware Reference Manual
+
+config CDU0_CLKO4
+       int "CDU0_CLKO4"
+       range 1 7
+       help
+               Clock source select. Refer to SOC Hardware Reference Manual
+
+config CDU0_CLKO5
+       int "CDU0_CLKO5"
+       range 1 7
+       help
+               Clock source select. Refer to SOC Hardware Reference Manual
+
+config CDU0_CLKO6
+       int "CDU0_CLKO6"
+       range 1 7
+       help
+               Clock source select. Refer to SOC Hardware Reference Manual
+
+config CDU0_CLKO7
+       int "CDU0_CLKO7"
+       range 1 7
+       help
+               Clock source select. Refer to SOC Hardware Reference Manual
+
+config CDU0_CLKO8
+       int "CDU0_CLKO8"
+       range 1 7
+       help
+               Clock source select. Refer to SOC Hardware Reference Manual
+
+config CDU0_CLKO9
+       int "CDU0_CLKO9"
+       range 1 7
+       help
+               Clock source select. Refer to SOC Hardware Reference Manual
+
+config CDU0_CLKO10
+       int "CDU0_CLKO10"
+       range 1 7
+       depends on (SC59X || SC59X_64)
+       help
+               Clock source select. Refer to SOC Hardware Reference Manual
+
+config CDU0_CLKO12
+       int "CDU0_CLKO12"
+       range 1 7
+       depends on (SC59X || SC59X_64)
+       help
+               Clock source select. Refer to SOC Hardware Reference Manual
+
+config CDU0_CLKO13
+       int "CDU0_CLKO13"
+       range 1 7
+       depends on SC59X_64
+       help
+               Clock source select. Refer to SOC Hardware Reference Manual
+
+config CDU0_CLKO14
+       int "CDU0_CLKO14"
+       range 1 7
+       depends on SC59X_64
+       help
+               Clock source select. Refer to SOC Hardware Reference Manual
+
+endmenu
+
+config ADI_GPIO
+       default y
+
+config PINCTRL_ADI
+       default y
+
+source "board/adi/sc573-ezkit/Kconfig"
+
+endif
diff --git a/arch/arm/mach-sc5xx/Makefile b/arch/arm/mach-sc5xx/Makefile
new file mode 100644
index 0000000000..eeb56c078b
--- /dev/null
+++ b/arch/arm/mach-sc5xx/Makefile
@@ -0,0 +1,19 @@
+# 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.morri...@timesys.com>
+# Contact: Greg Malysa <greg.mal...@timesys.com>
+#
+
+obj-y += soc.o init/
+
+obj-$(CONFIG_SC57X) += sc57x.o
+obj-$(CONFIG_SC58X) += sc58x.o
+obj-$(CONFIG_SC59X) += sc59x.o
+obj-$(CONFIG_SC59X_64) += sc59x_64.o
+
+obj-$(CONFIG_SPL_BUILD) += spl.o
+obj-$(CONFIG_SYSCON) += rcu.o
diff --git a/arch/arm/mach-sc5xx/config.mk b/arch/arm/mach-sc5xx/config.mk
new file mode 100644
index 0000000000..b80644d6dc
--- /dev/null
+++ b/arch/arm/mach-sc5xx/config.mk
@@ -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.morri...@timesys.com>
+# Contact: Greg Malysa <greg.mal...@timesys.com>
+#
+
+ifdef CONFIG_SPL_BUILD
+INPUTS-y += $(obj)/u-boot-spl.ldr
+endif
+
+LDR_FLAGS += --bcode=$(CONFIG_SC_BOOT_MODE)
+LDR_FLAGS += --use-vmas
+
+ifndef CONFIG_SC59X_64
+       # Select the Analog Devices processor.
+       PLATFORM_RELFLAGS += -fno-stack-protector -std=gnu89
+endif
diff --git a/arch/arm/mach-sc5xx/init/Makefile 
b/arch/arm/mach-sc5xx/init/Makefile
new file mode 100644
index 0000000000..c2835318a6
--- /dev/null
+++ b/arch/arm/mach-sc5xx/init/Makefile
@@ -0,0 +1,11 @@
+# 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.morri...@timesys.com>
+# Contact: Greg Malysa <greg.mal...@timesys.com>
+#
+
+obj-y += init.o dmcinit.o clkinit.o
diff --git a/arch/arm/mach-sc5xx/init/clkinit.c 
b/arch/arm/mach-sc5xx/init/clkinit.c
new file mode 100644
index 0000000000..44d3d16d74
--- /dev/null
+++ b/arch/arm/mach-sc5xx/init/clkinit.c
@@ -0,0 +1,543 @@
+// 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.morri...@timesys.com>
+ * Contact: Greg Malysa <greg.mal...@timesys.com>
+ */
+
+#include <asm/arch-adi/sc5xx/sc5xx.h>
+#include <asm/io.h>
+#include <config.h>
+#include <linux/types.h>
+#include <asm/io.h>
+#include "clkinit.h"
+#include "dmcinit.h"
+
+#ifdef CONFIG_CGU0_SCLK0_DIV
+       #define VAL_CGU0_SCLK0_DIV CONFIG_CGU0_SCLK0_DIV
+#else
+       #define VAL_CGU0_SCLK0_DIV 1
+#endif
+#ifdef CONFIG_CGU0_SCLK1_DIV
+       #define VAL_CGU0_SCLK1_DIV CONFIG_CGU0_SCLK1_DIV
+#else
+       #define VAL_CGU0_SCLK1_DIV 1
+#endif
+#ifdef CONFIG_CGU0_DIV_S0SELEX
+       #define VAL_CGU0_DIV_S0SELEX CONFIG_CGU0_DIV_S0SELEX
+#else
+       #define VAL_CGU0_DIV_S0SELEX -1
+#endif
+#ifdef CONFIG_CGU0_DIV_S1SELEX
+       #define VAL_CGU0_DIV_S1SELEX CONFIG_CGU0_DIV_S1SELEX
+#else
+       #define VAL_CGU0_DIV_S1SELEX -1
+#endif
+#ifdef CONFIG_CGU0_CLKOUTSEL
+       #define VAL_CGU0_CLKOUTSEL CONFIG_CGU0_CLKOUTSEL
+#else
+       #define VAL_CGU0_CLKOUTSEL -1
+#endif
+#ifdef CONFIG_CGU1_SCLK0_DIV
+       #define VAL_CGU1_SCLK0_DIV CONFIG_CGU1_SCLK0_DIV
+#else
+       #define VAL_CGU1_SCLK0_DIV 1
+#endif
+#ifdef CONFIG_CGU1_SCLK1_DIV
+       #define VAL_CGU1_SCLK1_DIV CONFIG_CGU1_SCLK1_DIV
+#else
+       #define VAL_CGU1_SCLK1_DIV 1
+#endif
+#ifdef CONFIG_CGU1_DIV_S0SELEX
+       #define VAL_CGU1_DIV_S0SELEX CONFIG_CGU1_DIV_S0SELEX
+#else
+       #define VAL_CGU1_DIV_S0SELEX -1
+#endif
+#ifdef CONFIG_CGU1_DIV_S1SELEX
+       #define VAL_CGU1_DIV_S1SELEX CONFIG_CGU1_DIV_S1SELEX
+#else
+       #define VAL_CGU1_DIV_S1SELEX -1
+#endif
+#ifdef CONFIG_CGU1_CLKOUTSEL
+       #define VAL_CGU1_CLKOUTSEL CONFIG_CGU1_CLKOUTSEL
+#else
+       #define VAL_CGU1_CLKOUTSEL -1
+#endif
+
+#define CGU0_REGBASE   0x3108D000
+#define CGU1_REGBASE   0x3108E000
+
+#define CGU_CTL                0x00 // CGU0 Control Register
+#define CGU_PLLCTL     0x04 // CGU0 PLL Control Register
+#define CGU_STAT       0x08 // CGU0 Status Register
+#define CGU_DIV                0x0C // CGU0 Clocks Divisor Register
+#define CGU_CLKOUTSEL  0x10 // CGU0 CLKOUT Select Register
+#define CGU_DIVEX      0x40 // CGU0 DIV Register Extension
+
+/*  PLL Multiplier and Divisor Selections (Required Value, Bit Position) */
+/* PLL Multiplier Select */
+#define MSEL(X)                (((X) << BITP_CGU_CTL_MSEL) & \
+                                BITM_CGU_CTL_MSEL)
+/* Divide frequency[true or false] */
+#define DF(X)          (((X) << BITP_CGU_CTL_DF) & \
+                                BITM_CGU_CTL_DF)
+/* Core Clock Divisor Select */
+#define CSEL(X)                (((X) << BITP_CGU_DIV_CSEL) & \
+                                BITM_CGU_DIV_CSEL)
+/* System Clock Divisor Select */
+#define SYSSEL(X)      (((X) << BITP_CGU_DIV_SYSSEL) & \
+                                BITM_CGU_DIV_SYSSEL)
+/* SCLK0 Divisor Select  */
+#define S0SEL(X)       (((X) << BITP_CGU_DIV_S0SEL) & \
+                                BITM_CGU_DIV_S0SEL)
+/* SCLK1 Divisor Select  */
+#define S1SEL(X)       (((X) << BITP_CGU_DIV_S1SEL) & \
+                                BITM_CGU_DIV_S1SEL)
+/* DDR Clock Divisor Select */
+#define DSEL(X)                (((X) << BITP_CGU_DIV_DSEL) & \
+                                BITM_CGU_DIV_DSEL)
+/* OUTCLK Divisor Select */
+#define OSEL(X)                (((X) << BITP_CGU_DIV_OSEL) & \
+                                BITM_CGU_DIV_OSEL)
+/* CLKOUT select       */
+#define CLKOUTSEL(X)   (((X) << BITP_CGU_CLKOUTSEL_CLKOUTSEL) & \
+                                BITM_CGU_CLKOUTSEL_CLKOUTSEL)
+#define S0SELEX(X)     (((X) << BITP_CGU_DIVEX_S0SELEX) & \
+                                BITM_CGU_DIVEX_S0SELEX)
+#define S1SELEX(X)     (((X) << BITP_CGU_DIVEX_S1SELEX) & \
+                                BITM_CGU_DIVEX_S1SELEX)
+
+struct CGU_Settings {
+       phys_addr_t rbase;
+       u32 ctl_MSEL:7;
+       u32 ctl_DF:1;
+       u32 div_CSEL:5;
+       u32 div_SYSSEL:5;
+       u32 div_S0SEL:3;
+       u32 div_S1SEL:3;
+       u32 div_DSEL:5;
+       u32 div_OSEL:7;
+       s16 divex_S0SELEX;
+       s16 divex_S1SELEX;
+       s8  clkoutsel;
+};
+
+/* CGU Registers */
+#define BITM_CGU_CTL_LOCK      0x80000000 /* Lock */
+
+#define BITM_CGU_CTL_MSEL      0x00007F00 /* Multiplier Select */
+#define BITM_CGU_CTL_DF                0x00000001 /* Divide Frequency */
+#define BITM_CGU_CTL_S1SELEXEN 0x00020000 /* SCLK1 Extension Divider Enable */
+#define BITM_CGU_CTL_S0SELEXEN 0x00010000 /* SCLK0 Extension Divider Enable */
+
+#define BITM_CGU_DIV_LOCK      0x80000000 /* Lock */
+#define BITM_CGU_DIV_UPDT      0x40000000 /* Update Clock Divisors */
+#define BITM_CGU_DIV_ALGN      0x20000000 /* Align */
+#define BITM_CGU_DIV_OSEL      0x1FC00000 /* OUTCLK Divisor */
+#define BITM_CGU_DIV_DSEL      0x001F0000 /* DCLK Divisor */
+#define BITM_CGU_DIV_S1SEL     0x0000E000 /* SCLK 1 Divisor */
+#define BITM_CGU_DIV_SYSSEL    0x00001F00 /* SYSCLK Divisor */
+#define BITM_CGU_DIV_S0SEL     0x000000E0 /* SCLK 0 Divisor */
+#define BITM_CGU_DIV_CSEL      0x0000001F /* CCLK Divisor */
+
+#define BITP_CGU_DIVEX_S0SELEX 0
+#define BITM_CGU_DIVEX_S0SELEX 0x000000FF /*  SCLK 0 Extension Divisor */
+
+#define BITP_CGU_DIVEX_S1SELEX 16
+#define BITM_CGU_DIVEX_S1SELEX 0x00FF0000 /*  SCLK 1 Extension Divisor */
+
+#define BITM_CGU_PLLCTL_PLLEN          0x00000008      /* PLL Enable */
+#define BITM_CGU_PLLCTL_PLLBPCL                0x00000002      /* PLL Bypass 
Clear */
+#define BITM_CGU_PLLCTL_PLLBPST                0x00000001      /* PLL Bypass 
Set */
+
+#define BITP_CGU_CLKOUTSEL_CLKOUTSEL   0               /* CLKOUT Select */
+#define BITM_CGU_CLKOUTSEL_CLKOUTSEL   0x0000001F      /* CLKOUT Select */
+
+#define CGU_STAT_MASK (BITM_CGU_STAT_PLLEN | BITM_CGU_STAT_PLOCK | \
+           BITM_CGU_STAT_CLKSALGN)
+#define CGU_STAT_ALGN_LOCK (BITM_CGU_STAT_PLLEN | BITM_CGU_STAT_PLOCK)
+
+/* Clock Distribution Unit Registers */
+#define REG_CDU0_CFG0                  0x3108F000
+#define REG_CDU0_CFG1                  0x3108F004
+#define REG_CDU0_CFG2                  0x3108F008
+#define REG_CDU0_CFG3                  0x3108F00C
+#define REG_CDU0_CFG4                  0x3108F010
+#define REG_CDU0_CFG5                  0x3108F014
+#define REG_CDU0_CFG6                  0x3108F018
+#define REG_CDU0_CFG7                  0x3108F01C
+#define REG_CDU0_CFG8                  0x3108F020
+#define REG_CDU0_CFG9                  0x3108F024
+#define REG_CDU0_CFG10                 0x3108F028
+#define REG_CDU0_CFG11                 0x3108F02C
+#define REG_CDU0_CFG12                 0x3108F030
+#define REG_CDU0_CFG13                 0x3108F034
+#define REG_CDU0_CFG14                 0x3108F038
+#define REG_CDU0_STAT                  0x3108F040
+#define REG_CDU0_CLKINSEL              0x3108F044
+#define REG_CDU0_REVID                 0x3108F048
+
+#define BITM_REG10_MSEL3               0x000007F0
+#define BITP_REG10_MSEL3               4
+
+#define BITM_REG10_DSEL3               0x0001F000
+#define BITP_REG10_DSEL3               12
+
+/* Selected clock macros */
+#define CGUn_MULT(cgu)         ((CONFIG_CGU##cgu##_VCO_MULT == 0) ? \
+                                128 : CONFIG_CGU##cgu##_VCO_MULT)
+#define CGUn_DIV(clkname, cgu) ((CONFIG_CGU##cgu##_##clkname##_DIV == 0) ? \
+                                32 : CONFIG_CGU##cgu##_##clkname##_DIV)
+#define CCLK1_n_RATIO(cgu)     (((CGUn_MULT(cgu)) / \
+                                 (1 + CONFIG_CGU##cgu##_DF_DIV)) / \
+                                  CGUn_DIV(CCLK, cgu))
+#define CCLK2_n_RATIO(cgu)     (((CGUn_MULT(cgu) * 2) / 3) / \
+                                 (1 + CONFIG_CGU##cgu##_DF_DIV))
+#define DCLK_n_RATIO(cgu)      (((CGUn_MULT(cgu)) / \
+                                (1 + CONFIG_CGU##cgu##_DF_DIV)) / \
+                                 CGUn_DIV(DCLK, cgu))
+#define SYSCLK_n_RATIO(cgu)    (((CGUn_MULT(cgu)) / \
+                                (1 + CONFIG_CGU##cgu##_DF_DIV)) / \
+                                 CGUn_DIV(SCLK, cgu))
+#define PLL3_RATIO             ((CONFIG_CGU1_PLL3_VCO_MSEL) / \
+                                (CONFIG_CGU1_PLL3_DCLK_DIV))
+
+#if (1 == CONFIG_CDU0_CLKO2)
+       #define ARMCLK_IN       0
+       #define ARMCLK_RATIO    CCLK1_n_RATIO(0)
+#elif (3 == CONFIG_CDU0_CLKO2) && \
+       (defined(CONFIG_SC57X) || defined(CONFIG_SC58X))
+       #define ARMCLK_IN       0
+       #define ARMCLK_RATIO    SYSCLK_n_RATIO(0)
+#elif (5 == CONFIG_CDU0_CLKO2) && defined(CONFIG_SC59X_64)
+       #define ARMCLK_IN       0
+       #define ARMCLK_RATIO    CCLK2_n_RATIO(0)
+#elif (7 == CONFIG_CDU0_CLKO2) && defined(CONFIG_SC59X_64)
+       #define ARMCLK_IN       CDU0_CGU1_CLKIN
+       #define ARMCLK_RATIO    CCLK2_n_RATIO(1)
+#endif
+
+#ifdef CONFIG_CGU1_PLL3_DDRCLK
+       #define DDRCLK_IN       CDU0_CGU1_CLKIN
+       #define DDRCLK_RATIO    PLL3_RATIO
+#elif (1 == CONFIG_CDU0_CLKO3)
+       #define DDRCLK_IN       0
+       #define DDRCLK_RATIO    DCLK_n_RATIO(0)
+#elif (3 == CONFIG_CDU0_CLKO3)
+       #define DDRCLK_IN       CDU0_CGU1_CLKIN
+       #define DDRCLK_RATIO    DCLK_n_RATIO(1)
+#endif
+
+#ifndef ARMCLK_RATIO
+       #error Invalid/unknown ARMCLK selection!
+#endif
+#ifndef DDRCLK_RATIO
+       #error Invalid/unknown DDRCLK selection!
+#endif
+
+#define ARMDDR_CLK_RATIO_FPERCISION 1000
+
+#if ARMCLK_IN != DDRCLK_IN
+       #ifndef CUSTOM_ARMDDR_CLK_RATIO
+               /**
+                * SYS_CLKINx are defined within the device tree, not configs.
+                * Thus, we can only determine cross-CGU clock ratios if they
+                * use the same SYS_CLKINx.
+                */
+               #error Define CUSTOM_ARMDDR_CLK_RATIO for different SYS_CLKINs
+       #else
+               #define ARMDDR_CLK_RATIO CUSTOM_ARMDDR_CLK_RATIO
+       #endif
+#else
+       #define ARMDDR_CLK_RATIO (ARMDDR_CLK_RATIO_FPERCISION *\
+                                  ARMCLK_RATIO / DDRCLK_RATIO)
+#endif
+
+void dmcdelay(uint32_t delay)
+{
+       /* There is no zero-overhead loop on ARM, so assume each iteration
+        * takes 4 processor cycles (based on examination of -O3 and -Ofast
+        * output).
+        */
+       u32 i, remainder;
+
+       /* Convert DDR cycles to core clock cycles */
+       u32 f = delay * ARMDDR_CLK_RATIO;
+
+       delay = f + 500;
+       delay /= ARMDDR_CLK_RATIO_FPERCISION;
+
+       /* Round up to multiple of 4 */
+       remainder = delay % 4;
+       if (remainder != 0u)
+               delay += (4u - remainder);
+
+       for (i = 0; i < delay; i += 4)
+               asm("nop");
+}
+
+static void program_cgu(const struct CGU_Settings *cgu)
+{
+       const uintptr_t b = cgu->rbase;
+       const bool use_extension0 = cgu->divex_S0SELEX >= 0;
+       const bool use_extension1 = cgu->divex_S1SELEX >= 0;
+       u32 temp;
+
+       temp =  OSEL(cgu->div_OSEL);
+       temp |= SYSSEL(cgu->div_SYSSEL);
+       temp |= CSEL(cgu->div_CSEL);
+       temp |= DSEL(cgu->div_DSEL);
+       temp |= (S0SEL(cgu->div_S0SEL));
+       temp |= (S1SEL(cgu->div_S1SEL));
+       temp &= ~BITM_CGU_DIV_LOCK;
+
+       //Put PLL in to Bypass Mode
+       writel(BITM_CGU_PLLCTL_PLLEN | BITM_CGU_PLLCTL_PLLBPST,
+              b + CGU_PLLCTL);
+       while (!(readl(b + CGU_STAT) & BITM_CGU_STAT_PLLBP))
+               ;
+
+       while (!((readl(b + CGU_STAT) & CGU_STAT_MASK) == CGU_STAT_ALGN_LOCK))
+               ;
+
+       dmcdelay(1000);
+
+       writel(temp & (~BITM_CGU_DIV_ALGN) & (~BITM_CGU_DIV_UPDT),
+              b + CGU_DIV);
+
+       dmcdelay(1000);
+
+       temp = MSEL(cgu->ctl_MSEL) | DF(cgu->ctl_DF);
+       if (use_extension0)
+               temp |= BITM_CGU_CTL_S0SELEXEN;
+       if (use_extension1)
+               temp |= BITM_CGU_CTL_S1SELEXEN;
+
+       writel(temp & (~BITM_CGU_CTL_LOCK), b + CGU_CTL);
+
+       if (use_extension0 || use_extension1) {
+               u32 mask = BITM_CGU_CTL_S1SELEXEN | BITM_CGU_CTL_S0SELEXEN;
+
+               while (!(readl(b + CGU_CTL) & mask))
+                       ;
+
+               temp = readl(b + CGU_DIVEX);
+
+               if (use_extension0) {
+                       temp &= ~BITM_CGU_DIVEX_S0SELEX;
+                       temp |= S0SELEX(cgu->divex_S0SELEX);
+               }
+
+               if (use_extension1) {
+                       temp &= ~BITM_CGU_DIVEX_S1SELEX;
+                       temp |= S1SELEX(cgu->divex_S1SELEX);
+               }
+
+               writel(temp, b + CGU_DIVEX);
+       }
+
+       dmcdelay(1000);
+
+       //Take PLL out of Bypass Mode
+       writel(BITM_CGU_PLLCTL_PLLEN | BITM_CGU_PLLCTL_PLLBPCL,
+              b + CGU_PLLCTL);
+       while ((readl(b + CGU_STAT) &
+              (BITM_CGU_STAT_PLLBP | BITM_CGU_STAT_CLKSALGN)))
+               ;
+
+       dmcdelay(1000);
+
+       if (cgu->clkoutsel >= 0) {
+               temp = readl(b + CGU_CLKOUTSEL);
+               temp &= ~BITM_CGU_CLKOUTSEL_CLKOUTSEL;
+               temp |= CLKOUTSEL(cgu->clkoutsel);
+               writel(temp, b + CGU_CLKOUTSEL);
+       }
+}
+
+void adi_config_third_pll(void)
+{
+#if defined(CONFIG_CGU1_PLL3_VCO_MSEL) && defined(CONFIG_CGU1_PLL3_DCLK_DIV)
+       u32 temp;
+
+       u32 msel = CONFIG_CGU1_PLL3_VCO_MSEL - 1;
+       u32 dsel = CONFIG_CGU1_PLL3_DCLK_DIV - 1;
+
+       temp = readl(REG_MISC_REG10_tst_addr);
+       temp &= 0xFFFE0000;
+       writel(temp, REG_MISC_REG10_tst_addr);
+
+       dmcdelay(4000u);
+
+       //update MSEL [10:4]
+       temp = readl(REG_MISC_REG10_tst_addr);
+       temp |= ((msel << BITP_REG10_MSEL3) & BITM_REG10_MSEL3);
+       writel(temp, REG_MISC_REG10_tst_addr);
+
+       temp = readl(REG_MISC_REG10_tst_addr);
+       temp |= 0x2;
+       writel(temp, REG_MISC_REG10_tst_addr);
+
+       dmcdelay(100000u);
+
+       temp = readl(REG_MISC_REG10_tst_addr);
+       temp |= 0x1;
+       writel(temp, REG_MISC_REG10_tst_addr);
+
+       temp = readl(REG_MISC_REG10_tst_addr);
+       temp |= 0x800;
+       writel(temp, REG_MISC_REG10_tst_addr);
+
+       temp = readl(REG_MISC_REG10_tst_addr);
+       temp &= 0xFFFFF7F8;
+       writel(temp, REG_MISC_REG10_tst_addr);
+
+       dmcdelay(4000u);
+
+       temp = readl(REG_MISC_REG10_tst_addr);
+       temp |= ((dsel << BITP_REG10_DSEL3) & BITM_REG10_DSEL3);
+       writel(temp, REG_MISC_REG10_tst_addr);
+
+       temp = readl(REG_MISC_REG10_tst_addr);
+       temp |= 0x4;
+       writel(temp, REG_MISC_REG10_tst_addr);
+
+       dmcdelay(100000u);
+
+       temp = readl(REG_MISC_REG10_tst_addr);
+       temp |= 0x1;
+       writel(temp, REG_MISC_REG10_tst_addr);
+
+       temp = readl(REG_MISC_REG10_tst_addr);
+       temp |= 0x800;
+       writel(temp, REG_MISC_REG10_tst_addr);
+#endif
+}
+
+static void Active_To_Fullon(const struct CGU_Settings *pCGU)
+{
+       u32 tmp;
+
+       while (1) {
+               tmp = readl(pCGU->rbase + CGU_STAT);
+               if ((tmp & BITM_CGU_STAT_PLLEN) &&
+                   (tmp & BITM_CGU_STAT_PLLBP))
+                       break;
+       }
+
+       writel(BITM_CGU_PLLCTL_PLLBPCL, pCGU->rbase + CGU_PLLCTL);
+
+       while (1) {
+               tmp = readl(pCGU->rbase + CGU_STAT);
+               if ((tmp & BITM_CGU_STAT_PLLEN) &&
+                   ~(tmp & BITM_CGU_STAT_PLLBP) &&
+                   ~(tmp & BITM_CGU_STAT_CLKSALGN))
+                       break;
+       }
+}
+
+static void CGU_Init(const struct CGU_Settings *pCGU)
+{
+       const uintptr_t b = pCGU->rbase;
+
+#if defined(CONFIG_SC59X) || defined(CONFIG_SC59X_64)
+       if (readl(b + CGU_STAT) & BITM_CGU_STAT_PLLEN)
+               writel(BITM_CGU_PLLCTL_PLLEN, b + CGU_PLLCTL);
+
+       dmcdelay(1000);
+#endif
+
+       /* Check if processor is in Active mode */
+       if (readl(b + CGU_STAT) & BITM_CGU_STAT_PLLBP)
+               Active_To_Fullon(pCGU);
+
+#if defined(CONFIG_SC59X) || defined(CONFIG_SC59X_64)
+       dmcdelay(1000);
+#endif
+
+       program_cgu(pCGU);
+}
+
+void cgu_init(void)
+{
+       const struct CGU_Settings dividers0 = {
+               .rbase =                CGU0_REGBASE,
+               .ctl_MSEL =             CONFIG_CGU0_VCO_MULT,
+               .ctl_DF =               CONFIG_CGU0_DF_DIV,
+               .div_CSEL =             CONFIG_CGU0_CCLK_DIV,
+               .div_SYSSEL =           CONFIG_CGU0_SCLK_DIV,
+               .div_S0SEL =            VAL_CGU0_SCLK0_DIV,
+               .div_S1SEL =            VAL_CGU0_SCLK1_DIV,
+               .div_DSEL =             CONFIG_CGU0_DCLK_DIV,
+               .div_OSEL =             CONFIG_CGU0_OCLK_DIV,
+               .divex_S0SELEX =        VAL_CGU0_DIV_S0SELEX,
+               .divex_S1SELEX =        VAL_CGU0_DIV_S1SELEX,
+               .clkoutsel =            VAL_CGU0_CLKOUTSEL,
+       };
+       const struct CGU_Settings dividers1 = {
+               .rbase =                CGU1_REGBASE,
+               .ctl_MSEL =             CONFIG_CGU1_VCO_MULT,
+               .ctl_DF =               CONFIG_CGU1_DF_DIV,
+               .div_CSEL =             CONFIG_CGU1_CCLK_DIV,
+               .div_SYSSEL =           CONFIG_CGU1_SCLK_DIV,
+               .div_S0SEL =            VAL_CGU1_SCLK0_DIV,
+               .div_S1SEL =            VAL_CGU1_SCLK1_DIV,
+               .div_DSEL =             CONFIG_CGU1_DCLK_DIV,
+               .div_OSEL =             CONFIG_CGU1_OCLK_DIV,
+               .divex_S0SELEX =        VAL_CGU1_DIV_S0SELEX,
+               .divex_S1SELEX =        VAL_CGU1_DIV_S1SELEX,
+               .clkoutsel =            VAL_CGU1_CLKOUTSEL,
+       };
+
+       CGU_Init(&dividers0);
+       CGU_Init(&dividers1);
+}
+
+#define CONFIGURE_CDU0(a, b, c) \
+       writel(a, b); \
+       while (readl(REG_CDU0_STAT) & (1 << (c)))
+
+void cdu_init(void)
+{
+       while (readl(REG_CDU0_STAT) & 0xffff)
+               ;
+       writel((CONFIG_CDU0_CGU1_CLKIN & 0x1), REG_CDU0_CLKINSEL);
+
+       CONFIGURE_CDU0(CONFIG_CDU0_CLKO0, REG_CDU0_CFG0, 0);
+       CONFIGURE_CDU0(CONFIG_CDU0_CLKO1, REG_CDU0_CFG1, 1);
+       CONFIGURE_CDU0(CONFIG_CDU0_CLKO2, REG_CDU0_CFG2, 2);
+       CONFIGURE_CDU0(CONFIG_CDU0_CLKO3, REG_CDU0_CFG3, 3);
+       CONFIGURE_CDU0(CONFIG_CDU0_CLKO4, REG_CDU0_CFG4, 4);
+       CONFIGURE_CDU0(CONFIG_CDU0_CLKO5, REG_CDU0_CFG5, 5);
+       CONFIGURE_CDU0(CONFIG_CDU0_CLKO6, REG_CDU0_CFG6, 6);
+       CONFIGURE_CDU0(CONFIG_CDU0_CLKO7, REG_CDU0_CFG7, 7);
+       CONFIGURE_CDU0(CONFIG_CDU0_CLKO8, REG_CDU0_CFG8, 8);
+       CONFIGURE_CDU0(CONFIG_CDU0_CLKO9, REG_CDU0_CFG9, 9);
+#ifdef CONFIG_CDU0_CLKO10
+       CONFIGURE_CDU0(CONFIG_CDU0_CLKO10, REG_CDU0_CFG10, 10);
+#endif
+#ifdef CONFIG_CDU0_CLKO12
+       CONFIGURE_CDU0(CONFIG_CDU0_CLKO12, REG_CDU0_CFG12, 12);
+#endif
+#ifdef CONFIG_CDU0_CLKO13
+       CONFIGURE_CDU0(CONFIG_CDU0_CLKO13, REG_CDU0_CFG13, 13);
+#endif
+#ifdef CONFIG_CDU0_CLKO14
+       CONFIGURE_CDU0(CONFIG_CDU0_CLKO14, REG_CDU0_CFG14, 14);
+#endif
+}
+
+void clks_init(void)
+{
+       adi_dmc_reset_lanes(true);
+
+       cdu_init();
+       cgu_init();
+
+       adi_config_third_pll();
+
+       adi_dmc_reset_lanes(false);
+}
diff --git a/arch/arm/mach-sc5xx/init/clkinit.h 
b/arch/arm/mach-sc5xx/init/clkinit.h
new file mode 100644
index 0000000000..b05f4325bf
--- /dev/null
+++ b/arch/arm/mach-sc5xx/init/clkinit.h
@@ -0,0 +1,18 @@
+/* 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.morri...@timesys.com>
+ * Contact: Greg Malysa <greg.mal...@timesys.com>
+ */
+
+#ifndef CLKINIT_H_
+#define CLKINIT_H_
+
+void clks_init(void);
+
+void dmcdelay(uint32_t delay);
+
+#endif
diff --git a/arch/arm/mach-sc5xx/init/dmcinit.c 
b/arch/arm/mach-sc5xx/init/dmcinit.c
new file mode 100644
index 0000000000..3b9d2f7039
--- /dev/null
+++ b/arch/arm/mach-sc5xx/init/dmcinit.c
@@ -0,0 +1,973 @@
+// 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.morri...@timesys.com>
+ * Contact: Greg Malysa <greg.mal...@timesys.com>
+ */
+
+#include <config.h>
+#include <asm/arch-adi/sc5xx/sc5xx.h>
+#include <linux/types.h>
+#include <asm/io.h>
+#include "clkinit.h"
+#include "dmcinit.h"
+#include <stdbool.h>
+
+#define REG_DMC0_BASE          0x31070000
+#define REG_DMC1_BASE          0x31073000
+
+#define REG_DMC_CTL            0x0004 // Control Register
+#define REG_DMC_STAT           0x0008 // Status Register
+#define REG_DMC_CFG            0x0040 // Configuration Register
+#define REG_DMC_TR0            0x0044 // Timing 0 Register
+#define REG_DMC_TR1            0x0048 // Timing 1 Register
+#define REG_DMC_TR2            0x004C // Timing 2 Register
+#define REG_DMC_MR             0x0060 // Shadow MR Register (DDR3)
+#define REG_DMC_EMR1           0x0064 // Shadow EMR1 Register
+#define REG_DMC_EMR2           0x0068 // Shadow EMR2 Register
+#define REG_DMC_EMR3           0x006C
+#define REG_DMC_DLLCTL         0x0080 // DLL Control Register
+#define REG_DMC_DT_CALIB_ADDR  0x0090 // Data Calibration Address Register
+#define REG_DMC_CPHY_CTL       0x01C0 // Controller to PHY Interface Register
+
+/* SC57x && SC58x DMC REGs */
+#define REG_DMC_PHY_CTL0       0x1000 // PHY Control 0 Register
+#define REG_DMC_PHY_CTL1       0x1004 // PHY Control 1 Register
+#define REG_DMC_PHY_CTL2       0x1008 // PHY Control 2 Register
+#define REG_DMC_PHY_CTL3       0x100c // PHY Control 3 Register
+#define REG_DMC_PHY_CTL4       0x1010 // PHY Control 4 Register
+#define REG_DMC_CAL_PADCTL0    0x1034 // CALIBRATION PAD CTL 0 Register
+#define REG_DMC_CAL_PADCTL2    0x103C // CALIBRATION PAD CTL2 Register
+/* END */
+
+/* SC59x DMC REGs */
+#define REG_DMC_DDR_LANE0_CTL0 0x1000 // Data Lane 0 Control Register 0
+#define REG_DMC_DDR_LANE0_CTL1 0x1004 // Data Lane 0 Control Register 1
+#define REG_DMC_DDR_LANE1_CTL0 0x100C // Data Lane 1 Control Register 0
+#define REG_DMC_DDR_LANE1_CTL1 0x1010 // Data Lane 1 Control Register 1
+#define REG_DMC_DDR_ROOT_CTL   0x1018 // DDR ROOT Module Control Register
+#define REG_DMC_DDR_ZQ_CTL0    0x1034 // DDR Calibration Control Register 0
+#define REG_DMC_DDR_ZQ_CTL1    0x1038 // DDR Calibration Control Register 1
+#define REG_DMC_DDR_ZQ_CTL2    0x103C // DDR Calibration Control Register 2
+#define REG_DMC_DDR_CA_CTL     0x1068 // DDR CA Lane Control Register
+/* END */
+
+#define REG_DMC_DDR_SCRATCH_2  0x1074
+#define REG_DMC_DDR_SCRATCH_3  0x1078
+#define REG_DMC_DDR_SCRATCH_6  0x1084
+#define REG_DMC_DDR_SCRATCH_7  0x1088
+
+#define REG_DMC_DDR_SCRATCH_STAT0      0x107C
+#define REG_DMC_DDR_SCRATCH_STAT1      0x1080
+
+#define DMC0_DATA_CALIB_ADD    0x80000000
+#define DMC1_DATA_CALIB_ADD    0xC0000000
+
+#define BITM_DMC_CFG_EXTBANK   0x0000F000  /* External Banks */
+#define ENUM_DMC_CFG_EXTBANK1  0x00000000  /* EXTBANK: 1 External Bank */
+#define BITM_DMC_CFG_SDRSIZE   0x00000F00  /* SDRAM Size */
+#define ENUM_DMC_CFG_SDRSIZE64 0x00000000  /* SDRSIZE: 64M Bit SDRAM (LPDDR 
Only) */
+#define ENUM_DMC_CFG_SDRSIZE128        0x00000100  /* SDRSIZE: 128M Bit SDRAM 
(LPDDR Only) */
+#define ENUM_DMC_CFG_SDRSIZE256        0x00000200  /* SDRSIZE: 256M Bit SDRAM 
*/
+#define ENUM_DMC_CFG_SDRSIZE512        0x00000300  /* SDRSIZE: 512M Bit SDRAM 
*/
+#define ENUM_DMC_CFG_SDRSIZE1G 0x00000400  /* SDRSIZE: 1G Bit SDRAM */
+#define ENUM_DMC_CFG_SDRSIZE2G 0x00000500  /* SDRSIZE: 2G Bit SDRAM */
+#define ENUM_DMC_CFG_SDRSIZE4G 0x00000600  /* SDRSIZE: 4G Bit SDRAM */
+#define ENUM_DMC_CFG_SDRSIZE8G 0x00000700  /* SDRSIZE: 8G Bit SDRAM */
+#define BITM_DMC_CFG_SDRWID    0x000000F0  /* SDRAM Width */
+#define ENUM_DMC_CFG_SDRWID16  0x00000020  /* SDRWID: 16-Bit Wide SDRAM */
+#define BITM_DMC_CFG_IFWID     0x0000000F  /* Interface Width */
+#define ENUM_DMC_CFG_IFWID16   0x00000002  /* IFWID: 16-Bit Wide Interface */
+
+#define BITM_DMC_CTL_DDR3EN    0x00000001
+#define BITM_DMC_CTL_INIT      0x00000004
+#define BITP_DMC_STAT_INITDONE 2            /* Initialization Done */
+#define BITM_DMC_STAT_INITDONE 0x00000004
+
+#define BITP_DMC_CTL_AL_EN     27
+#define BITP_DMC_CTL_ZQCL      25           /* ZQ Calibration Long */
+#define BITP_DMC_CTL_ZQCS      24           /* ZQ Calibration Short */
+#define BITP_DMC_CTL_DLLCAL    13           /* DLL Calibration Start */
+#define BITP_DMC_CTL_PPREF     12           /* Postpone Refresh */
+#define BITP_DMC_CTL_RDTOWR     9           /* Read-to-Write Cycle */
+#define BITP_DMC_CTL_ADDRMODE   8           /* Addressing (Page/Bank) Mode */
+#define BITP_DMC_CTL_RESET      7           /* Reset SDRAM */
+#define BITP_DMC_CTL_PREC       6           /* Precharge */
+#define BITP_DMC_CTL_DPDREQ     5           /* Deep Power Down Request */
+#define BITP_DMC_CTL_PDREQ      4           /* Power Down Request */
+#define BITP_DMC_CTL_SRREQ      3           /* Self Refresh Request */
+#define BITP_DMC_CTL_INIT       2           /* Initialize DRAM Start */
+#define BITP_DMC_CTL_LPDDR      1           /* Low Power DDR Mode */
+#define BITP_DMC_CTL_DDR3EN     0           /* DDR3 Mode */
+
+#ifdef CONFIG_TARGET_SC584_EZKIT
+       #define DMC_PADCTL2_VALUE       0x0078283C
+#elif CONFIG_TARGET_SC573_EZKIT
+       #define DMC_PADCTL2_VALUE       0x00782828
+#elif CONFIG_TARGET_SC589_MINI || CONFIG_TARGET_SC589_EZKIT
+       #define DMC_PADCTL2_VALUE       0x00783C3C
+#elif defined(CONFIG_SC57X) || defined(CONFIG_SC58X)
+       #error "PADCTL2 not specified for custom board!"
+#else
+       //Newer DMC. Legacy calibration obsolete
+       #define DMC_PADCTL2_VALUE       0x0
+#endif
+
+#define DMC_CPHYCTL_VALUE      0x0000001A
+
+#define BITP_DMC_MR1_QOFF      12 /*  Output Buffer Enable */
+#define BITP_DMC_MR1_TDQS      11 /*  Termination Data Strobe */
+#define BITP_DMC_MR1_RTT2       9 /*  Rtt_nom */
+#define BITP_DMC_MR1_WL                 7 /*  Write Leveling Enable. */
+#define BITP_DMC_MR1_RTT1       6 /*  Rtt_nom */
+#define BITP_DMC_MR1_DIC1       5 /*  Output Driver Impedance Control */
+#define BITP_DMC_MR1_AL                 3 /*  Additive Latency */
+#define BITP_DMC_MR1_RTT0       2 /*  Rtt_nom */
+#define BITP_DMC_MR1_DIC0       1 /*  Output Driver Impedance control */
+#define BITP_DMC_MR1_DLLEN      0 /*  DLL Enable */
+
+#define BITP_DMC_MR2_CWL        3 /* CAS write Latency */
+
+#define BITP_DMC_TR0_TMRD      28 /* Timing Mode Register Delay */
+#define BITP_DMC_TR0_TRC       20 /* Timing Row Cycle */
+#define BITP_DMC_TR0_TRAS      12 /* Timing Row Active Time */
+#define BITP_DMC_TR0_TRP        8 /* Timing RAS Precharge. */
+#define BITP_DMC_TR0_TWTR       4 /* Timing Write to Read */
+#define BITP_DMC_TR0_TRCD       0 /* Timing RAS to CAS Delay */
+
+#define BITP_DMC_TR1_TRRD      28 /* Timing Read-Read Delay */
+#define BITP_DMC_TR1_TRFC      16 /* Timing Refresh-to-Command */
+#define BITP_DMC_TR1_TREF       0 /* Timing Refresh Interval */
+
+#define BITP_DMC_TR2_TCKE      20 /* Timing Clock Enable */
+#define BITP_DMC_TR2_TXP       16 /* Timing Exit Powerdown */
+#define BITP_DMC_TR2_TWR       12 /* Timing Write Recovery */
+#define BITP_DMC_TR2_TRTP       8 /* Timing Read-to-Precharge */
+#define BITP_DMC_TR2_TFAW       0 /* Timing Four-Activated-Window */
+
+#define BITP_DMC_MR_PD         12 /* Active Powerdown Mode */
+#define BITP_DMC_MR_WRRECOV     9 /* Write Recovery */
+#define BITP_DMC_MR_DLLRST      8 /* DLL Reset */
+#define BITP_DMC_MR_CL          4 /* CAS Latency */
+#define BITP_DMC_MR_CL0                 2 /* CAS Latency */
+#define BITP_DMC_MR_BLEN        0 /* Burst Length */
+
+#define BITP_DMC_DLLCTL_DATACYC                8 /* Data Cycles */
+#define BITP_DMC_DLLCTL_DLLCALRDCNT    0 /* DLL Calibration RD Count */
+
+#define BITM_DMC_DLLCTL_DATACYC                0x00000F00 /* Data Cycles */
+#define BITM_DMC_DLLCTL_DLLCALRDCNT    0x000000FF /* DLL Calib RD Count */
+
+#define BITP_DMC_STAT_PHYRDPHASE       20 /* PHY Read Phase */
+
+#define BITM_DMC_DDR_LANE0_CTL0_CB_RSTDAT      0x08000000 /* Rst Data Pads */
+#define BITM_DMC_DDR_LANE1_CTL0_CB_RSTDAT      0x08000000 /* Rst Data Pads */
+#define BITM_DMC_DDR_LANE0_CTL1_COMP_DCYCLE    0x00000002 /* Compute Dcycle */
+#define BITM_DMC_DDR_LANE1_CTL1_COMP_DCYCLE    0x00000002 /* Compute Dcycle */
+#define BITM_DMC_DDR_LANE1_CTL0_CB_RSTDLL      0x00000100 /* Rst Lane DLL */
+#define BITM_DMC_DDR_LANE0_CTL0_CB_RSTDLL      0x00000100 /* Rst Lane DLL */
+#define BITP_DMC_DDR_ROOT_CTL_PIPE_OFSTDCYCLE  10         /* Pipeline offset 
for PHYC_DATACYCLE */
+#define BITM_DMC_DDR_ROOT_CTL_SW_REFRESH       0x00002000 /* Refresh Lane DLL 
Code */
+#define BITM_DMC_DDR_CA_CTL_SW_REFRESH         0x00004000 /* Refresh Lane DLL 
Code */
+
+#define BITP_DMC_CTL_RL_DQS            26         /* RL_DQS */
+#define BITM_DMC_CTL_RL_DQS            0x04000000 /* RL_DQS */
+#define BITP_DMC_EMR3_MPR               2         /* Multi Purpose Read Enable 
(Read Leveling)*/
+#define BITM_DMC_EMR3_MPR              0x00000004 /* Multi Purpose Read Enable 
(Read Leveling)*/
+#define BITM_DMC_MR1_WL                        0x00000080 /* Write Leveling 
Enable.*/
+#define BITM_DMC_STAT_PHYRDPHASE       0x00F00000 /* PHY Read Phase */
+
+#define BITP_DMC_DDR_LANE0_CTL1_BYPCODE                10
+#define BITM_DMC_DDR_LANE0_CTL1_BYPCODE                0x00007C00
+#define BITP_DMC_DDR_LANE0_CTL1_BYPDELCHAINEN  15
+#define BITM_DMC_DDR_LANE0_CTL1_BYPDELCHAINEN  0x00008000
+
+#define DMC_ZQCTL0_VALUE                       0x00785A64
+#define DMC_ZQCTL1_VALUE                       0
+#define DMC_ZQCTL2_VALUE                       0x70000000
+
+#define DMC_TRIG_CALIB                         0
+#define DMC_OFSTDCYCLE                         2
+
+#define BITP_DMC_CAL_PADCTL0_RTTCALEN  31         /* RTT Calibration Enable */
+#define BITP_DMC_CAL_PADCTL0_PDCALEN   30         /* PULLDOWN Calib Enable */
+#define BITP_DMC_CAL_PADCTL0_PUCALEN   29         /* PULLUP Calib Enable */
+#define BITP_DMC_CAL_PADCTL0_CALSTRT   28         /* Start New Calib ( 
Hardware Cleared) */
+#define BITM_DMC_CAL_PADCTL0_RTTCALEN  0x80000000 /* RTT Calibration Enable */
+#define BITM_DMC_CAL_PADCTL0_PDCALEN   0x40000000 /* PULLDOWN Calib Enable */
+#define BITM_DMC_CAL_PADCTL0_PUCALEN   0x20000000 /* PULLUP Calib Enable */
+#define BITM_DMC_CAL_PADCTL0_CALSTRT   0x10000000 /* Start New Calib ( 
Hardware Cleared) */
+#define ENUM_DMC_PHY_CTL4_DDR3         0x00000000 /* DDRMODE: DDR3 Mode */
+#define ENUM_DMC_PHY_CTL4_DDR2         0x00000001 /* DDRMODE: DDR2 Mode */
+#define ENUM_DMC_PHY_CTL4_LPDDR                0x00000003 /* DDRMODE: LPDDR 
Mode */
+
+#define BITP_DMC_DDR_ZQ_CTL0_IMPRTT    16         /*  Data/DQS ODT */
+#define BITP_DMC_DDR_ZQ_CTL0_IMPWRDQ    8         /*  Data/DQS/DM/CLK Drive 
Strength */
+#define BITP_DMC_DDR_ZQ_CTL0_IMPWRADD   0         /*  Address/Command Drive 
Strength */
+#define BITM_DMC_DDR_ZQ_CTL0_IMPRTT    0x00FF0000 /* Data/DQS ODT */
+#define BITM_DMC_DDR_ZQ_CTL0_IMPWRDQ   0x0000FF00 /* Data/DQS/DM/CLK Drive 
Strength */
+#define BITM_DMC_DDR_ZQ_CTL0_IMPWRADD  0x000000FF /* Address/Command Drive 
Strength */
+
+#define BITM_DMC_DDR_ROOT_CTL_TRIG_RD_XFER_ALL 0x00200000 /* All Lane Read 
Status */
+
+#ifdef MEM_DDR2
+       #define DMC_MR0_VALUE \
+               ((DMC_BL / 4 + 1) << BITP_DMC_MR_BLEN) | \
+               (DMC_CL << BITP_DMC_MR_CL) | \
+               (DMC_WRRECOV << BITP_DMC_MR_WRRECOV)
+
+       #define DMC_MR1_VALUE \
+               (DMC_MR1_AL << BITP_DMC_MR1_AL | 0x04) \
+
+       #define DMC_MR2_VALUE 0
+       #define DMC_MR3_VALUE 0
+
+       #define DMC_CTL_VALUE \
+               (DMC_RDTOWR << BITP_DMC_CTL_RDTOWR) | \
+               (1 << BITP_DMC_CTL_DLLCAL) | \
+               (BITM_DMC_CTL_INIT)
+#endif
+
+#ifdef MEM_DDR3
+       #define DMC_MR0_VALUE \
+               (0 << BITP_DMC_MR_BLEN) | \
+               (DMC_CL0 << BITP_DMC_MR_CL0) | \
+               (DMC_CL123 << BITP_DMC_MR_CL) | \
+               (DMC_WRRECOV << BITP_DMC_MR_WRRECOV) | \
+               (1 << BITP_DMC_MR_DLLRST)
+
+       #define DMC_MR1_VALUE \
+               (DMC_MR1_DLLEN << BITP_DMC_MR1_DLLEN) | \
+               (DMC_MR1_DIC0 << BITP_DMC_MR1_DIC0) | \
+               (DMC_MR1_RTT0 << BITP_DMC_MR1_RTT0) | \
+               (DMC_MR1_AL << BITP_DMC_MR1_AL) | \
+               (DMC_MR1_DIC1 << BITP_DMC_MR1_DIC1) | \
+               (DMC_MR1_RTT1 << BITP_DMC_MR1_RTT1) | \
+               (DMC_MR1_RTT2 << BITP_DMC_MR1_RTT2) | \
+               (DMC_MR1_WL << BITP_DMC_MR1_WL) | \
+               (DMC_MR1_TDQS << BITP_DMC_MR1_TDQS) | \
+               (DMC_MR1_QOFF << BITP_DMC_MR1_QOFF)
+
+       #define DMC_MR2_VALUE \
+               ((DMC_WL) << BITP_DMC_MR2_CWL)
+
+       #define DMC_MR3_VALUE \
+               ((DMC_WL) << BITP_DMC_MR2_CWL)
+
+       #define DMC_CTL_VALUE \
+               (DMC_RDTOWR << BITP_DMC_CTL_RDTOWR) | \
+               (BITM_DMC_CTL_INIT) | \
+               (BITM_DMC_CTL_DDR3EN) | \
+               (DMC_CTL_AL_EN << BITP_DMC_CTL_AL_EN)
+#endif
+
+#define DMC_DLLCTL_VALUE \
+       (DMC_DATACYC << BITP_DMC_DLLCTL_DATACYC) | \
+       (DMC_DLLCALRDCNT << BITP_DMC_DLLCTL_DLLCALRDCNT)
+
+#define DMC_CFG_VALUE \
+       ENUM_DMC_CFG_IFWID16 | \
+       ENUM_DMC_CFG_SDRWID16 | \
+       SDR_CHIP_SIZE | \
+       ENUM_DMC_CFG_EXTBANK1
+
+#define DMC_TR0_VALUE \
+       (DMC_TRCD << BITP_DMC_TR0_TRCD) | \
+       (DMC_TWTR << BITP_DMC_TR0_TWTR) | \
+       (DMC_TRP << BITP_DMC_TR0_TRP) | \
+       (DMC_TRAS << BITP_DMC_TR0_TRAS) | \
+       (DMC_TRC << BITP_DMC_TR0_TRC) | \
+       (DMC_TMRD << BITP_DMC_TR0_TMRD)
+
+#define DMC_TR1_VALUE \
+       (DMC_TREF << BITP_DMC_TR1_TREF) | \
+       (DMC_TRFC << BITP_DMC_TR1_TRFC) | \
+       (DMC_TRRD << BITP_DMC_TR1_TRRD)
+
+#define DMC_TR2_VALUE \
+       (DMC_TFAW << BITP_DMC_TR2_TFAW) | \
+       (DMC_TRTP << BITP_DMC_TR2_TRTP) | \
+       (DMC_TWR << BITP_DMC_TR2_TWR) | \
+       (DMC_TXP << BITP_DMC_TR2_TXP) | \
+       (DMC_TCKE << BITP_DMC_TR2_TCKE)
+
+enum DDR_MODE {
+       DDR3_MODE,
+       DDR2_MODE,
+       LPDDR_MODE,
+};
+
+enum CALIBRATION_MODE {
+       CALIBRATION_LEGACY,
+       CALIBRATION_METHOD1,
+       CALIBRATION_METHOD2,
+};
+
+static struct dmc_param {
+       phys_addr_t reg;
+       u32 ddr_mode;
+       u32 padctl2_value;
+       u32 dmc_cphyctl_value;
+       u32 dmc_cfg_value;
+       u32 dmc_dllctl_value;
+       u32 dmc_ctl_value;
+       u32 dmc_tr0_value;
+       u32 dmc_tr1_value;
+       u32 dmc_tr2_value;
+       u32 dmc_mr0_value;
+       u32 dmc_mr1_value;
+       u32 dmc_mr2_value;
+       u32 dmc_mr3_value;
+       u32 dmc_zqctl0_value;
+       u32 dmc_zqctl1_value;
+       u32 dmc_zqctl2_value;
+       u32 dmc_data_calib_add_value;
+       bool phy_init_required;
+       bool anomaly_20000037_applicable;
+       enum CALIBRATION_MODE calib_mode;
+} dmc;
+
+#ifdef CONFIG_SC59X_64
+#define DQS_DEFAULT_DELAY      3ul
+
+#define DELAYTRIM      1
+#define LANE0_DQS_DELAY        1
+#define LANE1_DQS_DELAY        1
+
+#define CLKDIR         0ul
+
+#define DQSTRIM                0
+#define DQSCODE                0ul
+
+#define CLKTRIM                0
+#define CLKCODE                0ul
+#endif
+
+static inline void calibration_legacy(void)
+{
+       u32 temp;
+
+       /* 1. Set DDR mode to DDR3/DDR2/LPDDR in DMCx_PHY_CTL4 register */
+       if (dmc.ddr_mode == DDR3_MODE)
+               writel(ENUM_DMC_PHY_CTL4_DDR3, dmc.reg + REG_DMC_PHY_CTL4);
+       else if (dmc.ddr_mode == DDR2_MODE)
+               writel(ENUM_DMC_PHY_CTL4_DDR2, dmc.reg + REG_DMC_PHY_CTL4);
+       else if (dmc.ddr_mode == LPDDR_MODE)
+               writel(ENUM_DMC_PHY_CTL4_LPDDR, dmc.reg + REG_DMC_PHY_CTL4);
+
+       /*
+        * 2. Make sure that the bits 6, 7, 25, and 27 of the DMC_PHY_
+        * CTL3 register are set
+        */
+       writel(0x0A0000C0, dmc.reg + REG_DMC_PHY_CTL3);
+
+       /*
+        * 3. For DDR2/DDR3 mode, make sure that the bits 0, 1, 2, 3 of
+        * the DMC_PHY_CTL0 register and the bits 26, 27, 28, 29, 30, 31
+        * of the DMC_PHY_CTL2 are set.
+        */
+       if (dmc.ddr_mode == DDR3_MODE ||
+           dmc.ddr_mode == DDR2_MODE) {
+               writel(0XFC000000, dmc.reg + REG_DMC_PHY_CTL2);
+               writel(0x0000000f, dmc.reg + REG_DMC_PHY_CTL0);
+       }
+
+       writel(0x00000000, dmc.reg + REG_DMC_PHY_CTL1);
+
+       /* 4. For DDR3 mode, set bit 1 and configure bits [5:2] of the
+        * DMC_CPHY_CTL register with WL=CWL+AL in DCLK cycles.
+        */
+       if (dmc.ddr_mode == DDR3_MODE)
+               writel(dmc.dmc_cphyctl_value, dmc.reg + REG_DMC_CPHY_CTL);
+       /* 5. Perform On Die Termination(ODT) & Driver Impedance Calibration */
+       if (dmc.ddr_mode == LPDDR_MODE) {
+               /* Bypass processor ODT */
+               writel(0x80000, dmc.reg + REG_DMC_PHY_CTL1);
+       } else {
+               /* Set bits RTTCALEN, PDCALEN, PUCALEN of register */
+               temp = BITM_DMC_CAL_PADCTL0_RTTCALEN |
+                      BITM_DMC_CAL_PADCTL0_PDCALEN |
+                      BITM_DMC_CAL_PADCTL0_PUCALEN;
+               writel(temp, dmc.reg + REG_DMC_CAL_PADCTL0);
+               /* Configure ODT and drive impedance values in the
+                * DMCx_CAL_PADCTL2 register
+                */
+               writel(dmc.padctl2_value, dmc.reg + REG_DMC_CAL_PADCTL2);
+               /* start calibration */
+               temp |= BITM_DMC_CAL_PADCTL0_CALSTRT;
+               writel(temp, dmc.reg + REG_DMC_CAL_PADCTL0);
+               /* Wait for PAD calibration to complete - 300 DCLK cycle.
+                * Worst case: CCLK=450 MHz, DCLK=125 MHz
+                */
+               dmcdelay(300);
+       }
+}
+
+static inline void calibration_method1(void)
+{
+#if defined(CONFIG_SC59X) || defined(CONFIG_SC59X_64)
+       writel(dmc.dmc_zqctl0_value, dmc.reg + REG_DMC_DDR_ZQ_CTL0);
+       writel(dmc.dmc_zqctl1_value, dmc.reg + REG_DMC_DDR_ZQ_CTL1);
+       writel(dmc.dmc_zqctl2_value, dmc.reg + REG_DMC_DDR_ZQ_CTL2);
+
+       /* Generate the trigger */
+       writel(0x0ul, dmc.reg + REG_DMC_DDR_CA_CTL);
+       writel(0x0ul, dmc.reg + REG_DMC_DDR_ROOT_CTL);
+       writel(0x00010000ul, dmc.reg + REG_DMC_DDR_ROOT_CTL);
+       dmcdelay(8000u);
+
+       /* The [31:26] bits may change if pad ring changes */
+       writel(0x0C000001ul | DMC_TRIG_CALIB,  dmc.reg + REG_DMC_DDR_CA_CTL);
+       dmcdelay(8000u);
+       writel(0x0ul, dmc.reg + REG_DMC_DDR_CA_CTL);
+       writel(0x0ul, dmc.reg + REG_DMC_DDR_ROOT_CTL);
+#endif
+}
+
+static inline void calibration_method2(void)
+{
+#if defined(CONFIG_SC59X) || defined(CONFIG_SC59X_64)
+       u32 stat_value = 0x0u;
+       u32 drv_pu, drv_pd, odt_pu, odt_pd;
+       u32 ro_dt, clk_dqs_drv_impedance;
+       u32 temp;
+
+       /* Reset trigger */
+       writel(0x0ul, dmc.reg + REG_DMC_DDR_CA_CTL);
+       writel(0x0ul, dmc.reg + REG_DMC_DDR_ROOT_CTL);
+       writel(0x0ul, dmc.reg + REG_DMC_DDR_SCRATCH_3);
+       writel(0x0ul, dmc.reg + REG_DMC_DDR_SCRATCH_2);
+
+       /* Writing internal registers in calib pad to zero. Calib mode set
+        * to 1 [26], trig M1 S1 write [16], this enables usage of scratch
+        * registers instead of ZQCTL registers
+        */
+       writel(0x04010000ul, dmc.reg + REG_DMC_DDR_ROOT_CTL);
+       dmcdelay(2500u);
+
+       /* TRIGGER FOR M2-S2 WRITE     -> slave id 31:26  trig m2,s2 write
+        * bit 1->1 slave1 address is 4
+        */
+       writel(0x10000002ul, dmc.reg + REG_DMC_DDR_CA_CTL);
+       dmcdelay(2500u);
+
+       /* reset Trigger */
+       writel(0x0u, dmc.reg + REG_DMC_DDR_CA_CTL);
+       writel(0x0u, dmc.reg + REG_DMC_DDR_ROOT_CTL);
+
+       /* write to slave 1, make the power down bit high */
+       writel(0x1ul << 12, dmc.reg + REG_DMC_DDR_SCRATCH_3);
+       writel(0x0ul, dmc.reg + REG_DMC_DDR_SCRATCH_2);
+       dmcdelay(2500u);
+
+       /* Calib mode set to 1 [26], trig M1 S1 write [16] */
+       writel(0x04010000ul, dmc.reg + REG_DMC_DDR_ROOT_CTL);
+       dmcdelay(2500u);
+
+       writel(0x10000002ul, dmc.reg + REG_DMC_DDR_CA_CTL);
+       dmcdelay(2500u);
+
+       writel(0x0ul, dmc.reg + REG_DMC_DDR_CA_CTL);
+       writel(0x0ul, dmc.reg + REG_DMC_DDR_ROOT_CTL);
+       writel(0x0, dmc.reg + REG_DMC_DDR_SCRATCH_3);
+
+       /* for slave 0 */
+       writel(dmc.dmc_zqctl0_value, dmc.reg + REG_DMC_DDR_SCRATCH_2);
+
+       /* Calib mode set to 1 [26], trig M1 S1 write [16] */
+       writel(0x04010000ul, dmc.reg + REG_DMC_DDR_ROOT_CTL);
+       dmcdelay(2500u);
+
+       writel(0x0C000002ul, dmc.reg + REG_DMC_DDR_CA_CTL);
+       dmcdelay(2500u);
+
+       writel(0x0ul, dmc.reg + REG_DMC_DDR_CA_CTL);
+       writel(0x0ul, dmc.reg + REG_DMC_DDR_ROOT_CTL);
+
+       /* writing to slave 1
+        * calstrt is 0, but other programming is done
+        *
+        * make power down LOW again, to kickstart BIAS circuit
+        */
+       writel(0x0ul, dmc.reg + REG_DMC_DDR_SCRATCH_3);
+       writel(0x30000000ul, dmc.reg + REG_DMC_DDR_SCRATCH_2);
+
+       /* write to ca_ctl lane, calib mode set to 1 [26],
+        * trig M1 S1 write [16]
+        */
+       writel(0x04010000ul, dmc.reg + REG_DMC_DDR_ROOT_CTL);
+       dmcdelay(2500u);
+
+       /*  copies data to lane controller slave
+        *  TRIGGER FOR M2-S2 WRITE     -> slave id 31:26
+        *  trig m2,s2 write bit 1->1
+        *  slave1 address is 4
+        */
+       writel(0x10000002ul, dmc.reg + REG_DMC_DDR_CA_CTL);
+       dmcdelay(2500u);
+
+       /* reset Trigger */
+       writel(0x0ul, dmc.reg + REG_DMC_DDR_CA_CTL);
+       writel(0x0ul, dmc.reg + REG_DMC_DDR_ROOT_CTL);
+       writel(0x0ul, dmc.reg + REG_DMC_DDR_SCRATCH_3);
+       writel(0x0ul, dmc.reg + REG_DMC_DDR_SCRATCH_2);
+       writel(0x0ul, dmc.reg + REG_DMC_DDR_SCRATCH_3);
+       writel(0x0ul, dmc.reg + REG_DMC_DDR_SCRATCH_2);
+       writel(0x04010000ul, dmc.reg + REG_DMC_DDR_ROOT_CTL);
+       dmcdelay(2500u);
+       writel(0x10000002ul, dmc.reg + REG_DMC_DDR_CA_CTL);
+       dmcdelay(2500u);
+       writel(0x0ul, dmc.reg + REG_DMC_DDR_CA_CTL);
+       writel(0x0ul, dmc.reg + REG_DMC_DDR_ROOT_CTL);
+       writel(0x0ul, dmc.reg + REG_DMC_DDR_SCRATCH_3);
+       writel(0x0ul, dmc.reg + REG_DMC_DDR_SCRATCH_2);
+       writel(0x0ul, dmc.reg + REG_DMC_DDR_SCRATCH_3);
+       writel(0x50000000ul, dmc.reg + REG_DMC_DDR_SCRATCH_2);
+       writel(0x04010000ul, dmc.reg + REG_DMC_DDR_ROOT_CTL);
+       dmcdelay(2500u);
+       writel(0x10000002ul, dmc.reg + REG_DMC_DDR_CA_CTL);
+       dmcdelay(2500u);
+       writel(0u, dmc.reg + REG_DMC_DDR_CA_CTL);
+       writel(0u, dmc.reg + REG_DMC_DDR_ROOT_CTL);
+       writel(0x0C000004u, dmc.reg + REG_DMC_DDR_CA_CTL);
+       dmcdelay(2500u);
+       writel(BITM_DMC_DDR_ROOT_CTL_TRIG_RD_XFER_ALL,
+              dmc.reg + REG_DMC_DDR_ROOT_CTL);
+       dmcdelay(2500u);
+       writel(0u, dmc.reg + REG_DMC_DDR_CA_CTL);
+       writel(0u, dmc.reg + REG_DMC_DDR_ROOT_CTL);
+       // calculate ODT PU and PD values
+       stat_value = ((readl(dmc.reg + REG_DMC_DDR_SCRATCH_7) & 0x0000FFFFu) <<
+               16);
+       stat_value |= ((readl(dmc.reg + REG_DMC_DDR_SCRATCH_6) & 0xFFFF0000u) >>
+               16);
+       clk_dqs_drv_impedance = ((dmc.dmc_zqctl0_value) &
+               BITM_DMC_DDR_ZQ_CTL0_IMPWRDQ) >> BITP_DMC_DDR_ZQ_CTL0_IMPWRDQ;
+       ro_dt = ((dmc.dmc_zqctl0_value) & BITM_DMC_DDR_ZQ_CTL0_IMPRTT) >>
+               BITP_DMC_DDR_ZQ_CTL0_IMPRTT;
+       drv_pu = stat_value & 0x0000003Fu;
+       drv_pd = (stat_value >> 12) & 0x0000003Fu;
+       odt_pu = (drv_pu * clk_dqs_drv_impedance) / ro_dt;
+       odt_pd = (drv_pd * clk_dqs_drv_impedance) / ro_dt;
+       temp = ((1uL << 24)                   |
+              ((drv_pd & 0x0000003Fu))       |
+              ((odt_pd & 0x0000003Fu) << 6)  |
+              ((drv_pu & 0x0000003Fu) << 12) |
+              ((odt_pu & 0x0000003Fu) << 18));
+       temp |= readl(dmc.reg + REG_DMC_DDR_SCRATCH_2);
+       writel(temp, dmc.reg + REG_DMC_DDR_SCRATCH_2);
+       writel(0x0C010000u, dmc.reg + REG_DMC_DDR_ROOT_CTL);
+       dmcdelay(2500u);
+       writel(0x08000002u, dmc.reg + REG_DMC_DDR_CA_CTL);
+       dmcdelay(2500u);
+       writel(0u, dmc.reg + REG_DMC_DDR_CA_CTL);
+       writel(0u, dmc.reg + REG_DMC_DDR_ROOT_CTL);
+       writel(0x04010000u, dmc.reg + REG_DMC_DDR_ROOT_CTL);
+       dmcdelay(2500u);
+       writel(0x80000002u, dmc.reg + REG_DMC_DDR_CA_CTL);
+       dmcdelay(2500u);
+       writel(0u, dmc.reg + REG_DMC_DDR_CA_CTL);
+       writel(0u, dmc.reg + REG_DMC_DDR_ROOT_CTL);
+#endif
+}
+
+static inline void adi_dmc_lane_reset(bool reset, uint32_t dmc_no)
+{
+#if defined(CONFIG_SC59X) || defined(CONFIG_SC59X_64)
+       u32 temp;
+       phys_addr_t base = (dmc_no == 0) ? REG_DMC0_BASE : REG_DMC1_BASE;
+       phys_addr_t ln0 = base + REG_DMC_DDR_LANE0_CTL0;
+       phys_addr_t ln1 = base + REG_DMC_DDR_LANE1_CTL0;
+
+       if (reset) {
+               temp = readl(ln0);
+               temp |= BITM_DMC_DDR_LANE0_CTL0_CB_RSTDLL;
+               writel(temp, ln0);
+
+               temp = readl(ln1);
+               temp |= BITM_DMC_DDR_LANE1_CTL0_CB_RSTDLL;
+               writel(temp, ln1);
+       } else {
+               temp = readl(ln0);
+               temp &= ~BITM_DMC_DDR_LANE0_CTL0_CB_RSTDLL;
+               writel(temp, ln0);
+
+               temp = readl(ln1);
+               temp &= ~BITM_DMC_DDR_LANE1_CTL0_CB_RSTDLL;
+               writel(temp, ln1);
+       }
+       dmcdelay(9000u);
+#endif
+}
+
+void adi_dmc_reset_lanes(bool reset)
+{
+#ifdef MEM_DDR3
+ #if defined(CONFIG_SC59X) || defined(CONFIG_SC59X_64)
+  #ifdef MEM_DMC0
+       adi_dmc_lane_reset(reset, 0);
+  #endif
+  #ifdef MEM_DMC1
+       adi_dmc_lane_reset(reset, 1);
+  #endif
+ #else
+       u32 temp = reset ? 0x800 : 0x0;
+  #ifdef MEM_DMC0
+       writel(temp, REG_DMC0_BASE + REG_DMC_PHY_CTL0);
+  #endif
+  #ifdef MEM_DMC1
+       writel(temp, REG_DMC1_BASE + REG_DMC_PHY_CTL0);
+  #endif
+ #endif
+#endif //MEM_DDR3
+}
+
+#pragma GCC push_options
+#pragma GCC optimize("O0")
+static inline void dummy_read(void)
+{
+       /* Do not let this be optimized out by compiler */
+       readl(0x80000000);
+}
+
+#pragma GCC pop_options
+
+static inline void dmc_controller_init(void)
+{
+#if defined(CONFIG_SC59X) || defined(CONFIG_SC59X_64)
+       u32 phyphase, rd_cnt, t_EMR1, t_EMR3, t_CTL, data_cyc, temp;
+#endif
+
+       /* 1. Program the DMC controller registers: DMCx_CFG, DMCx_TR0,
+        * DMCx_TR1, DMCx_TR2, DMCx_MR(DDR2/LPDDR)/DMCx_MR0(DDR3),
+        * DMCx_EMR1(DDR2)/DMCx_MR1(DDR3),
+        * DMCx_EMR2(DDR2)/DMCx_EMR(LPDDR)/DMCx_MR2(DDR3)
+        */
+       writel(dmc.dmc_cfg_value, dmc.reg + REG_DMC_CFG);
+       writel(dmc.dmc_tr0_value, dmc.reg + REG_DMC_TR0);
+       writel(dmc.dmc_tr1_value, dmc.reg + REG_DMC_TR1);
+       writel(dmc.dmc_tr2_value, dmc.reg + REG_DMC_TR2);
+       writel(dmc.dmc_mr0_value, dmc.reg + REG_DMC_MR);
+       writel(dmc.dmc_mr1_value, dmc.reg + REG_DMC_EMR1);
+       writel(dmc.dmc_mr2_value, dmc.reg + REG_DMC_EMR2);
+
+#if defined(CONFIG_SC59X) || defined(CONFIG_SC59X_64)
+       writel(dmc.dmc_mr3_value, dmc.reg + REG_DMC_EMR3);
+       writel(dmc.dmc_dllctl_value, dmc.reg + REG_DMC_DLLCTL);
+       dmcdelay(2000u);
+
+       temp = readl(dmc.reg + REG_DMC_DDR_CA_CTL);
+       temp |= BITM_DMC_DDR_CA_CTL_SW_REFRESH;
+       writel(temp, dmc.reg + REG_DMC_DDR_CA_CTL);
+       dmcdelay(5u);
+
+       temp = readl(dmc.reg + REG_DMC_DDR_ROOT_CTL);
+       temp |= BITM_DMC_DDR_ROOT_CTL_SW_REFRESH |
+               (DMC_OFSTDCYCLE << BITP_DMC_DDR_ROOT_CTL_PIPE_OFSTDCYCLE);
+       writel(temp, dmc.reg + REG_DMC_DDR_ROOT_CTL);
+#endif
+
+       /* 2. Make sure that the REG_DMC_DT_CALIB_ADDR register is programmed
+        * to an unused DMC location corresponding to a burst of 16 bytes
+        * (by default it is the starting address of the DMC address range).
+        */
+#ifndef CONFIG_SC59X
+       writel(dmc.dmc_data_calib_add_value, dmc.reg + REG_DMC_DT_CALIB_ADDR);
+#endif
+       /* 3. Program the DMCx_CTL register with INIT bit set to start
+        * the DMC initialization sequence
+        */
+       writel(dmc.dmc_ctl_value, dmc.reg + REG_DMC_CTL);
+       /* 4. Wait for the DMC initialization to complete by polling
+        * DMCx_STAT.INITDONE bit.
+        */
+
+#if defined(CONFIG_SC59X) || defined(CONFIG_SC59X_64)
+       dmcdelay(722000u);
+
+       /* Add necessary delay depending on the configuration */
+       t_EMR1 = (dmc.dmc_mr1_value & BITM_DMC_MR1_WL) >> BITP_DMC_MR1_WL;
+
+       dmcdelay(600u);
+       if (t_EMR1 != 0u)
+               while ((readl(dmc.reg + REG_DMC_EMR1) & BITM_DMC_MR1_WL) != 0)
+                       ;
+
+       t_EMR3 = (dmc.dmc_mr3_value & BITM_DMC_EMR3_MPR) >>
+                BITP_DMC_EMR3_MPR;
+       dmcdelay(2000u);
+       if (t_EMR3 != 0u)
+               while ((readl(dmc.reg + REG_DMC_EMR3) & BITM_DMC_EMR3_MPR) != 0)
+                       ;
+
+       t_CTL = (dmc.dmc_ctl_value & BITM_DMC_CTL_RL_DQS) >> 
BITP_DMC_CTL_RL_DQS;
+       dmcdelay(600u);
+       if (t_CTL != 0u)
+               while ((readl(dmc.reg + REG_DMC_CTL) & BITM_DMC_CTL_RL_DQS) != 
0)
+                       ;
+#endif
+
+       /* check if DMC initialization finished*/
+       while ((readl(dmc.reg + REG_DMC_STAT) & BITM_DMC_STAT_INITDONE) == 0)
+               ;
+
+#if defined(CONFIG_SC59X) || defined(CONFIG_SC59X_64)
+       /* toggle DCYCLE */
+       temp = readl(dmc.reg + REG_DMC_DDR_LANE0_CTL1);
+       temp |= BITM_DMC_DDR_LANE0_CTL1_COMP_DCYCLE;
+       writel(temp, dmc.reg + REG_DMC_DDR_LANE0_CTL1);
+
+       temp = readl(dmc.reg + REG_DMC_DDR_LANE1_CTL1);
+       temp |= BITM_DMC_DDR_LANE1_CTL1_COMP_DCYCLE;
+       writel(temp, dmc.reg + REG_DMC_DDR_LANE1_CTL1);
+
+       dmcdelay(10u);
+
+       temp = readl(dmc.reg + REG_DMC_DDR_LANE0_CTL1);
+       temp &= (~BITM_DMC_DDR_LANE0_CTL1_COMP_DCYCLE);
+       writel(temp, dmc.reg + REG_DMC_DDR_LANE0_CTL1);
+
+       temp = readl(dmc.reg + REG_DMC_DDR_LANE1_CTL1);
+       temp &= (~BITM_DMC_DDR_LANE1_CTL1_COMP_DCYCLE);
+       writel(temp, dmc.reg + REG_DMC_DDR_LANE1_CTL1);
+
+       /* toggle RSTDAT */
+       temp = readl(dmc.reg + REG_DMC_DDR_LANE0_CTL0);
+       temp |= BITM_DMC_DDR_LANE0_CTL0_CB_RSTDAT;
+       writel(temp, dmc.reg + REG_DMC_DDR_LANE0_CTL0);
+
+       temp = readl(dmc.reg + REG_DMC_DDR_LANE0_CTL0);
+       temp &= (~BITM_DMC_DDR_LANE0_CTL0_CB_RSTDAT);
+       writel(temp, dmc.reg + REG_DMC_DDR_LANE0_CTL0);
+
+       temp = readl(dmc.reg + REG_DMC_DDR_LANE1_CTL0);
+       temp |= BITM_DMC_DDR_LANE1_CTL0_CB_RSTDAT;
+       writel(temp, dmc.reg + REG_DMC_DDR_LANE1_CTL0);
+
+       temp = readl(dmc.reg + REG_DMC_DDR_LANE1_CTL0);
+       temp &= (~BITM_DMC_DDR_LANE1_CTL0_CB_RSTDAT);
+       writel(temp, dmc.reg + REG_DMC_DDR_LANE1_CTL0);
+
+       dmcdelay(2500u);
+
+       /* Program phyphase*/
+       phyphase = (readl(dmc.reg + REG_DMC_STAT) &
+                  BITM_DMC_STAT_PHYRDPHASE) >> BITP_DMC_STAT_PHYRDPHASE;
+       data_cyc = (phyphase << BITP_DMC_DLLCTL_DATACYC) &
+                  BITM_DMC_DLLCTL_DATACYC;
+       rd_cnt = dmc.dmc_dllctl_value;
+       rd_cnt <<= BITP_DMC_DLLCTL_DLLCALRDCNT;
+       rd_cnt &= BITM_DMC_DLLCTL_DLLCALRDCNT;
+       writel(rd_cnt | data_cyc, dmc.reg + REG_DMC_DLLCTL);
+       writel((dmc.dmc_ctl_value & (~BITM_DMC_CTL_INIT) &
+              (~BITM_DMC_CTL_RL_DQS)), dmc.reg + REG_DMC_CTL);
+
+#if DELAYTRIM
+       /* DQS delay trim*/
+       u32 stat_value, WL_code_LDQS, WL_code_UDQS;
+
+       /* For LDQS */
+       temp = readl(dmc.reg + REG_DMC_DDR_LANE0_CTL1) | (0x000000D0);
+       writel(temp, dmc.reg + REG_DMC_DDR_LANE0_CTL1);
+       dmcdelay(2500u);
+       writel(0x00400000, dmc.reg + REG_DMC_DDR_ROOT_CTL);
+       dmcdelay(2500u);
+       writel(0x0, dmc.reg + REG_DMC_DDR_ROOT_CTL);
+       stat_value = (readl(dmc.reg + REG_DMC_DDR_SCRATCH_STAT0) &
+                    (0xFFFF0000)) >> 16;
+       WL_code_LDQS = (stat_value) & (0x0000001F);
+
+       temp = readl(dmc.reg + REG_DMC_DDR_LANE0_CTL1);
+       temp &= ~(BITM_DMC_DDR_LANE0_CTL1_BYPCODE |
+                 BITM_DMC_DDR_LANE0_CTL1_BYPDELCHAINEN);
+       writel(temp, dmc.reg + REG_DMC_DDR_LANE0_CTL1);
+
+       /* If write leveling is enabled */
+       if ((dmc.dmc_mr1_value & BITM_DMC_MR1_WL) >> BITP_DMC_MR1_WL) {
+               temp = readl(dmc.reg + REG_DMC_DDR_LANE0_CTL1);
+               temp |= (((WL_code_LDQS + LANE0_DQS_DELAY) <<
+                          BITP_DMC_DDR_LANE0_CTL1_BYPCODE) &
+                           BITM_DMC_DDR_LANE0_CTL1_BYPCODE) |
+                            BITM_DMC_DDR_LANE0_CTL1_BYPDELCHAINEN;
+               writel(temp, dmc.reg + REG_DMC_DDR_LANE0_CTL1);
+       } else {
+               temp = readl(dmc.reg + REG_DMC_DDR_LANE0_CTL1);
+               temp |= (((DQS_DEFAULT_DELAY + LANE0_DQS_DELAY) <<
+                          BITP_DMC_DDR_LANE0_CTL1_BYPCODE) &
+                           BITM_DMC_DDR_LANE0_CTL1_BYPCODE) |
+                            BITM_DMC_DDR_LANE0_CTL1_BYPDELCHAINEN;
+               writel(temp, dmc.reg + REG_DMC_DDR_LANE0_CTL1);
+       }
+       dmcdelay(2500u);
+
+       /* For UDQS */
+       temp = readl(dmc.reg + REG_DMC_DDR_LANE1_CTL1) | (0x000000D0);
+       writel(temp, dmc.reg + REG_DMC_DDR_LANE1_CTL1);
+       dmcdelay(2500u);
+       writel(0x00800000, dmc.reg + REG_DMC_DDR_ROOT_CTL);
+       dmcdelay(2500u);
+       writel(0x0, dmc.reg + REG_DMC_DDR_ROOT_CTL);
+       stat_value = (readl(dmc.reg + REG_DMC_DDR_SCRATCH_STAT1) &
+                    (0xFFFF0000)) >> 16;
+       WL_code_UDQS = (stat_value) & (0x0000001F);
+
+       temp = readl(dmc.reg + REG_DMC_DDR_LANE1_CTL1);
+       temp &= ~(BITM_DMC_DDR_LANE0_CTL1_BYPCODE |
+               BITM_DMC_DDR_LANE0_CTL1_BYPDELCHAINEN);
+       writel(temp, dmc.reg + REG_DMC_DDR_LANE1_CTL1);
+
+       /* If write leveling is enabled */
+       if ((dmc.dmc_mr1_value & BITM_DMC_MR1_WL) >> BITP_DMC_MR1_WL) {
+               temp = readl(dmc.reg + REG_DMC_DDR_LANE1_CTL1);
+               temp |= (((WL_code_UDQS + LANE1_DQS_DELAY) <<
+                          BITP_DMC_DDR_LANE0_CTL1_BYPCODE) &
+                           BITM_DMC_DDR_LANE0_CTL1_BYPCODE) |
+                            BITM_DMC_DDR_LANE0_CTL1_BYPDELCHAINEN;
+               writel(temp, dmc.reg + REG_DMC_DDR_LANE1_CTL1);
+       } else {
+               temp = readl(dmc.reg + REG_DMC_DDR_LANE1_CTL1);
+               temp |= (((DQS_DEFAULT_DELAY + LANE1_DQS_DELAY) <<
+                          BITP_DMC_DDR_LANE0_CTL1_BYPCODE) &
+                           BITM_DMC_DDR_LANE0_CTL1_BYPCODE) |
+                            BITM_DMC_DDR_LANE0_CTL1_BYPDELCHAINEN;
+               writel(temp, dmc.reg + REG_DMC_DDR_LANE1_CTL1);
+       }
+       dmcdelay(2500u);
+#endif
+
+#else
+       /* 5. Program the DMCx_CTL.DLLCTL register with 0x948 value
+        * (DATACYC=9,    DLLCALRDCNT=72).
+        */
+       writel(0x00000948, dmc.reg + REG_DMC_DLLCTL);
+#endif
+
+       /* 6. Workaround for anomaly#20000037 */
+       if (dmc.anomaly_20000037_applicable) {
+               /* Perform dummy read to any DMC location */
+               dummy_read();
+
+               writel(readl(dmc.reg + REG_DMC_PHY_CTL0) | 0x1000,
+                      dmc.reg + REG_DMC_PHY_CTL0);
+               /* Clear DMCx_PHY_CTL0.RESETDAT bit */
+               writel(readl(dmc.reg + REG_DMC_PHY_CTL0) & (~0x1000),
+                      dmc.reg + REG_DMC_PHY_CTL0);
+       }
+}
+
+static inline void dmc_init(void)
+{
+       /* PHY Calibration+Initialization */
+       if (!dmc.phy_init_required)
+               goto out;
+
+       switch (dmc.calib_mode) {
+       case CALIBRATION_LEGACY:
+               calibration_legacy();
+               break;
+       case CALIBRATION_METHOD1:
+               calibration_method1();
+               break;
+       case CALIBRATION_METHOD2:
+               calibration_method2();
+               break;
+       }
+
+#if DQSTRIM
+       /* DQS duty trim */
+       temp = readl(dmc.reg + REG_DMC_DDR_LANE0_CTL0);
+       temp |= ((DQSCODE) << BITP_DMC_DDR_LANE0_CTL0_BYPENB) &
+                (BITM_DMC_DDR_LANE1_CTL0_BYPENB |
+                 BITM_DMC_DDR_LANE0_CTL0_BYPSELP |
+                 BITM_DMC_DDR_LANE0_CTL0_BYPCODE);
+       writel(temp, dmc.reg + REG_DMC_DDR_LANE0_CTL0);
+
+       temp = readl(dmc.reg + REG_DMC_DDR_LANE1_CTL0);
+       temp |= ((DQSCODE) << BITP_DMC_DDR_LANE1_CTL0_BYPENB) &
+                (BITM_DMC_DDR_LANE1_CTL1_BYPCODE |
+                 BITM_DMC_DDR_LANE1_CTL0_BYPSELP |
+                 BITM_DMC_DDR_LANE1_CTL0_BYPCODE);
+       writel(temp, dmc.reg + REG_DMC_DDR_LANE1_CTL0);
+#endif
+
+#if CLKTRIM
+       /* Clock duty trim */
+       temp = readl(dmc.reg + REG_DMC_DDR_CA_CTL);
+       temp |= (((CLKCODE << BITP_DMC_DDR_CA_CTL_BYPCODE1) &
+                  BITM_DMC_DDR_CA_CTL_BYPCODE1) |
+                BITM_DMC_DDR_CA_CTL_BYPENB |
+                ((CLKDIR << BITP_DMC_DDR_CA_CTL_BYPSELP) &
+                 BITM_DMC_DDR_CA_CTL_BYPSELP));
+       writel(temp, dmc.reg + REG_DMC_DDR_CA_CTL);
+#endif
+
+out:
+       /* Controller Initialization */
+       dmc_controller_init();
+}
+
+static inline void __dmc_config(uint32_t dmc_no)
+{
+       if (dmc_no == 0) {
+               dmc.reg = REG_DMC0_BASE;
+               dmc.dmc_data_calib_add_value = DMC0_DATA_CALIB_ADD;
+       } else if (dmc_no == 1) {
+               dmc.reg = REG_DMC1_BASE;
+               dmc.dmc_data_calib_add_value = DMC1_DATA_CALIB_ADD;
+       } else {
+               return;
+       }
+
+#ifdef CONFIG_TARGET_SC584_EZKIT
+       dmc.ddr_mode = DDR2_MODE;
+#else
+       dmc.ddr_mode = DDR3_MODE;
+#endif
+
+       dmc.phy_init_required = true;
+
+#if defined(CONFIG_SC59X) || defined(CONFIG_SC59X_64)
+       dmc.anomaly_20000037_applicable = false;
+       dmc.dmc_dllctl_value = DMC_DLLCTL_VALUE;
+       dmc.calib_mode = CALIBRATION_METHOD2;
+#else
+       dmc.anomaly_20000037_applicable = true;
+       dmc.calib_mode = CALIBRATION_LEGACY;
+#endif
+
+       dmc.dmc_ctl_value = DMC_CTL_VALUE;
+       dmc.dmc_cfg_value = DMC_CFG_VALUE;
+       dmc.dmc_tr0_value = DMC_TR0_VALUE;
+       dmc.dmc_tr1_value = DMC_TR1_VALUE;
+       dmc.dmc_tr2_value = DMC_TR2_VALUE;
+       dmc.dmc_mr0_value = DMC_MR0_VALUE;
+       dmc.dmc_mr1_value = DMC_MR1_VALUE;
+       dmc.dmc_mr2_value = DMC_MR2_VALUE;
+
+#if defined(CONFIG_SC59X) || defined(CONFIG_SC59X_64)
+       dmc.dmc_mr3_value = DMC_MR3_VALUE;
+       dmc.dmc_zqctl0_value = DMC_ZQCTL0_VALUE;
+       dmc.dmc_zqctl1_value = DMC_ZQCTL1_VALUE;
+       dmc.dmc_zqctl2_value = DMC_ZQCTL2_VALUE;
+#endif
+
+       dmc.padctl2_value = DMC_PADCTL2_VALUE;
+       dmc.dmc_cphyctl_value = DMC_CPHYCTL_VALUE;
+
+       /* Initialize DMC now */
+       dmc_init();
+}
+
+void DMC_Config(void)
+{
+#ifdef MEM_DMC0
+       __dmc_config(0);
+#endif
+
+#ifdef MEM_DMC1
+       __dmc_config(1);
+#endif
+}
diff --git a/arch/arm/mach-sc5xx/init/dmcinit.h 
b/arch/arm/mach-sc5xx/init/dmcinit.h
new file mode 100644
index 0000000000..4fc36dd148
--- /dev/null
+++ b/arch/arm/mach-sc5xx/init/dmcinit.h
@@ -0,0 +1,29 @@
+/* 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.morri...@timesys.com>
+ * Contact: Greg Malysa <greg.mal...@timesys.com>
+ */
+
+#ifndef DMCINIT_H_
+#define DMCINIT_H_
+
+#ifdef MEM_MT41K512M16HA
+       #include "mem/mt41k512m16ha.h"
+#elif defined(MEM_MT41K128M16JT)
+       #include "mem/mt41k128m16jt.h"
+#elif defined(MEM_MT47H128M16RT)
+       #include "mem/mt47h128m16rt.h"
+#elif defined(MEM_IS43TR16512BL)
+       #include "mem/is43tr16512bl.h"
+#else
+       #error "No DDR part name is defined for this board."
+#endif
+
+void DMC_Config(void);
+void adi_dmc_reset_lanes(bool reset);
+
+#endif
diff --git a/arch/arm/mach-sc5xx/init/init.c b/arch/arm/mach-sc5xx/init/init.c
new file mode 100644
index 0000000000..8b033bf03a
--- /dev/null
+++ b/arch/arm/mach-sc5xx/init/init.c
@@ -0,0 +1,68 @@
+// 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.morri...@timesys.com>
+ * Contact: Greg Malysa <greg.mal...@timesys.com>
+ */
+
+#include <asm/arch-adi/sc5xx/sc5xx.h>
+#include <asm/io.h>
+#include <config.h>
+#include <linux/types.h>
+#include <asm/io.h>
+#include "clkinit.h"
+#include "dmcinit.h"
+#include "init.h"
+
+static void spu_disable_peripheral_security(void)
+{
+#if !(defined(CONFIG_SC57X) || defined(CONFIG_SC59X_64))
+       u32 i;
+
+       for (i = REG_SPU0_SECUREP_START; i <= REG_SPU0_SECUREP_END; i += 4)
+               writel(0, i);
+#endif
+}
+
+void adi_initcode_shared(void)
+{
+       clks_init();
+
+       //DDR init
+       DMC_Config();
+
+#ifdef CONFIG_SC59X_64
+       // Enable coresight timer
+       writel(1, REG_TSGENWR0_CNTCR);
+#endif
+
+       // Enable non-secure access to SHARC to support remoteproc in Linux
+       writel(0, REG_SPU0_SECUREC0);
+       writel(0, REG_SPU0_SECUREC1);
+       writel(0, REG_SPU0_SECUREC2);
+
+#ifdef CONFIG_SC59X_64
+       //Do not rerun preboot routine --
+       // Without this, hardware resets triggered by RCU0_CTL:SYSRST
+       // lead to a deadlock somewhere in the boot ROM
+       writel(0x200, REG_RCU0_BCODE);
+#endif
+
+#ifndef CONFIG_SC59X_64
+       // Configure PMU for non-secure operation
+       writel(readl(REG_ARMPMU0_PMUSERENR) | 0x01, REG_ARMPMU0_PMUSERENR);
+       writel(0xc5acce55, REG_ARMPMU0_PMLAR);
+       writel(readl(REG_ARMPMU0_PMCR) | (1 << 1), REG_ARMPMU0_PMCR);
+#endif
+
+#if defined(CONFIG_SC59X) || defined(CONFIG_SC59X_64)
+       //Enable board LEDs 7, 9, and 10
+       writel(0xE, 0x3100411C);
+       writel(0xE, 0x3100410C);
+#endif
+
+       spu_disable_peripheral_security();
+}
diff --git a/arch/arm/mach-sc5xx/init/init.h b/arch/arm/mach-sc5xx/init/init.h
new file mode 100644
index 0000000000..4fef49cd13
--- /dev/null
+++ b/arch/arm/mach-sc5xx/init/init.h
@@ -0,0 +1,37 @@
+/* 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.morri...@timesys.com>
+ * Contact: Greg Malysa <greg.mal...@timesys.com>
+ */
+
+#if defined(CONFIG_SC57X) || defined(CONFIG_SC59X)
+#define REG_SPU0_SECUREC0      0x3108B980
+#define REG_SPU0_SECUREC1      0x3108B984
+#define REG_SPU0_SECUREC2      0x3108B988
+#define REG_SPU0_SECUREP_START 0x3108BA00
+#define REG_SPU0_SECUREP_END   0x3108BD24
+#endif
+
+#ifdef CONFIG_SC59X_64
+#define REG_RCU0_BCODE         0x3108C028
+#define REG_TSGENWR0_CNTCR     0x310AE000 /*  TSGENWR0 Counter Control 
Register */
+#endif
+
+#ifdef CONFIG_SC58X
+#define REG_SPU0_SECUREC0      0x3108C980
+#define REG_SPU0_SECUREC1      0x3108C984
+#define REG_SPU0_SECUREC2      0x3108C988
+#define REG_SPU0_SECUREP_START 0x3108CA00
+#define REG_SPU0_SECUREP_END   0x3108CCF0
+#endif
+
+#define REG_ARMPMU0_PMCR       0x31121E04
+#define REG_ARMPMU0_PMUSERENR  0x31121E08
+#define REG_ARMPMU0_PMLAR      0x31121FB0
+
+void adi_initcode(void);
+void adi_initcode_shared(void);
diff --git a/arch/arm/mach-sc5xx/init/mem/is43tr16512bl.h 
b/arch/arm/mach-sc5xx/init/mem/is43tr16512bl.h
new file mode 100644
index 0000000000..bdf6c349d4
--- /dev/null
+++ b/arch/arm/mach-sc5xx/init/mem/is43tr16512bl.h
@@ -0,0 +1,63 @@
+/* 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.morri...@timesys.com>
+ * Contact: Greg Malysa <greg.mal...@timesys.com>
+ */
+
+#ifndef IS43TR16512BL_H
+#define IS43TR16512BL_H
+
+/* DMC0 setup for the EV-21593-SOM and EV-SC594-SOM :
+ * - uses a single 8GB IS43TR16512BL-125KBL DDR3 chip configured for
+ *   800 MHz DCLK.
+ * DMC0 setup for the EV-SC594-SOMS :
+ * - uses a single 4GB IS43TR16256BL-093NBL DDR3 chip configured for
+ *   800 MHz DCLK.
+ */
+#define MEM_DDR3
+#define DMC_DLLCALRDCNT                 240
+#define DMC_DATACYC                     12
+#define DMC_TRCD                        11
+#define DMC_TWTR                        6
+#define DMC_TRP                         11
+#define DMC_TRAS                        28
+#define DMC_TRC                         39
+#define DMC_TMRD                        4
+#define DMC_TREF                        6240
+#define DMC_TRRD                        6
+#define DMC_TFAW                        32
+#define DMC_TRTP                        6
+#define DMC_TWR                         12
+#define DMC_TXP                         5
+#define DMC_TCKE                        4
+#define DMC_CL0                         0
+#define DMC_CL123                       7
+#define DMC_WRRECOV                     6
+#define DMC_MR1_DLLEN                   0
+#define DMC_MR1_DIC0                    0
+#define DMC_MR1_RTT0                    0
+#define DMC_MR1_AL                      0
+#define DMC_MR1_DIC1                    0
+#define DMC_MR1_RTT1                    1
+#define DMC_MR1_WL                      0
+#define DMC_MR1_RTT2                    0
+#define DMC_MR1_TDQS                    0
+#define DMC_MR1_QOFF                    0
+#define DMC_WL                          3
+#define DMC_RDTOWR                      5
+#define DMC_CTL_AL_EN                   1
+#if defined(MEM_ISSI_4Gb_DDR3_800MHZ)
+    #define SDR_CHIP_SIZE                    (ENUM_DMC_CFG_SDRSIZE4G)
+    #define DMC_TRFC                        208ul
+#elif defined(MEM_ISSI_8Gb_DDR3_800MHZ)
+    #define SDR_CHIP_SIZE                    (ENUM_DMC_CFG_SDRSIZE8G)
+    #define DMC_TRFC                        280ul
+#else
+    #error "Need to select MEM_ISSI_4Gb_DDR3_800MHZ or 
MEM_ISSI_8Gb_DDR3_800MHZ"
+#endif
+
+#endif
diff --git a/arch/arm/mach-sc5xx/init/mem/mt41k128m16jt.h 
b/arch/arm/mach-sc5xx/init/mem/mt41k128m16jt.h
new file mode 100644
index 0000000000..7d94788f3a
--- /dev/null
+++ b/arch/arm/mach-sc5xx/init/mem/mt41k128m16jt.h
@@ -0,0 +1,51 @@
+/* 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.morri...@timesys.com>
+ * Contact: Greg Malysa <greg.mal...@timesys.com>
+ */
+
+#ifndef MT41K128M16JT_H
+#define MT41K128M16JT_H
+
+/* Default DDR3 part assumed: MT41K128M16JT-125, 2Gb part */
+/* For DCLK= 450 MHz */
+#define MEM_DDR3
+#define DMC_DLLCALRDCNT                 72
+#define DMC_DATACYC                     9
+#define DMC_TRCD                        6
+#define DMC_TWTR                        4
+#define DMC_TRP                         6
+#define DMC_TRAS                        17
+#define DMC_TRC                         23
+#define DMC_TMRD                        4
+#define DMC_TREF                        3510
+#define DMC_TRFC                        72
+#define DMC_TRRD                        4
+#define DMC_TFAW                        17
+#define DMC_TRTP                        4
+#define DMC_TWR                         7
+#define DMC_TXP                         4
+#define DMC_TCKE                        3
+#define DMC_CL0                         0
+#define DMC_CL123                       3
+#define DMC_WRRECOV                     (DMC_TWR - 1)
+#define DMC_MR1_DLLEN                   0
+#define DMC_MR1_DIC0                    1
+#define DMC_MR1_RTT0                    1
+#define DMC_MR1_AL                      0
+#define DMC_MR1_DIC1                    0
+#define DMC_MR1_RTT1                    0
+#define DMC_MR1_WL                      0
+#define DMC_MR1_RTT2                    0
+#define DMC_MR1_TDQS                    0
+#define DMC_MR1_QOFF                    0
+#define DMC_WL                          1
+#define DMC_RDTOWR                      2
+#define DMC_CTL_AL_EN                   0
+#define SDR_CHIP_SIZE                   ENUM_DMC_CFG_SDRSIZE2G
+
+#endif
diff --git a/arch/arm/mach-sc5xx/init/mem/mt41k512m16ha.h 
b/arch/arm/mach-sc5xx/init/mem/mt41k512m16ha.h
new file mode 100644
index 0000000000..6740e4bf66
--- /dev/null
+++ b/arch/arm/mach-sc5xx/init/mem/mt41k512m16ha.h
@@ -0,0 +1,51 @@
+/* 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.morri...@timesys.com>
+ * Contact: Greg Malysa <greg.mal...@timesys.com>
+ */
+
+#ifndef MT41K512M16HA_H
+#define MT41K512M16HA_H
+
+/* Default DDR3 part assumed: MT41K512M16HA-107, 8Gb part */
+/* For DCLK= 450 MHz */
+#define MEM_DDR3
+#define DMC_DLLCALRDCNT                 72
+#define DMC_DATACYC                     9
+#define DMC_TRCD                        7
+#define DMC_TWTR                        4
+#define DMC_TRP                         7
+#define DMC_TRAS                        10
+#define DMC_TRC                         16
+#define DMC_TMRD                        4
+#define DMC_TREF                        3510
+#define DMC_TRFC                        158
+#define DMC_TRRD                        6
+#define DMC_TFAW                        16
+#define DMC_TRTP                        4
+#define DMC_TWR                         7
+#define DMC_TXP                         3
+#define DMC_TCKE                        3
+#define DMC_CL0                         0
+#define DMC_CL123                       3
+#define DMC_WRRECOV                     (DMC_TWR - 1)
+#define DMC_MR1_DLLEN                   0
+#define DMC_MR1_DIC0                    1
+#define DMC_MR1_RTT0                    1
+#define DMC_MR1_AL                      0
+#define DMC_MR1_DIC1                    0
+#define DMC_MR1_RTT1                    0
+#define DMC_MR1_WL                      0
+#define DMC_MR1_RTT2                    0
+#define DMC_MR1_TDQS                    0
+#define DMC_MR1_QOFF                    0
+#define DMC_WL                          1
+#define DMC_RDTOWR                      2
+#define DMC_CTL_AL_EN                   0
+#define SDR_CHIP_SIZE                   ENUM_DMC_CFG_SDRSIZE8G
+
+#endif
diff --git a/arch/arm/mach-sc5xx/init/mem/mt47h128m16rt.h 
b/arch/arm/mach-sc5xx/init/mem/mt47h128m16rt.h
new file mode 100644
index 0000000000..ddd9c4efba
--- /dev/null
+++ b/arch/arm/mach-sc5xx/init/mem/mt47h128m16rt.h
@@ -0,0 +1,50 @@
+/* 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.morri...@timesys.com>
+ * Contact: Greg Malysa <greg.mal...@timesys.com>
+ */
+
+#ifndef MT47H128M16RT_H
+#define MT47H128M16RT_H
+
+/* Default DDR2 part: MT47H128M16RT-25E XIT:C, 2 Gb part */
+/* For DCLK= 400 MHz */
+#define MEM_DDR2
+#define DMC_DLLCALRDCNT                 72
+#define DMC_DATACYC                     9
+#define DMC_TRCD                        5
+#define DMC_TWTR                        3
+#define DMC_TRP                         5
+#define DMC_TRAS                        16
+#define DMC_TRC                         22
+#define DMC_TMRD                        2
+#define DMC_TREF                        3120
+#define DMC_TRFC                        78
+#define DMC_TRRD                        4
+#define DMC_TFAW                        18
+#define DMC_TRTP                        3
+#define DMC_TWR                         6
+#define DMC_TXP                         2
+#define DMC_TCKE                        3
+#define DMC_CL                          5
+#define DMC_WRRECOV                     (DMC_TWR - 1)
+#define DMC_MR1_DLLEN                   0
+#define DMC_MR1_DIC0                    1
+#define DMC_MR1_RTT0                    1
+#define DMC_MR1_AL                      4
+#define DMC_MR1_DIC1                    0
+#define DMC_MR1_RTT1                    0
+#define DMC_MR1_WL                      0
+#define DMC_MR1_RTT2                    0
+#define DMC_MR1_TDQS                    0
+#define DMC_MR1_QOFF                    0
+#define DMC_BL                          4
+#define DMC_RDTOWR                      2
+#define DMC_CTL_AL_EN                   0
+#define SDR_CHIP_SIZE                   ENUM_DMC_CFG_SDRSIZE2G
+
+#endif
diff --git a/arch/arm/mach-sc5xx/rcu.c b/arch/arm/mach-sc5xx/rcu.c
new file mode 100644
index 0000000000..49357501a9
--- /dev/null
+++ b/arch/arm/mach-sc5xx/rcu.c
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * (C) Copyright 2024 - Analog Devices, Inc.
+ *
+ * Written and/or maintained by Timesys Corporation
+ *
+ * Contact: Ian Roberts <ian.robe...@timesys.com>
+ */
+
+#include <dm.h>
+#include <syscon.h>
+
+static const struct udevice_id adi_syscon_ids[] = {
+       { .compatible = "adi,reset-controller" },
+       { }
+};
+
+U_BOOT_DRIVER(syscon_sc5xx_rcu) = {
+       .name = "sc5xx_rcu",
+       .id = UCLASS_SYSCON,
+       .of_match = adi_syscon_ids,
+};
diff --git a/arch/arm/mach-sc5xx/sc57x.c b/arch/arm/mach-sc5xx/sc57x.c
new file mode 100644
index 0000000000..936f206a01
--- /dev/null
+++ b/arch/arm/mach-sc5xx/sc57x.c
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * (C) Copyright 2024 - Analog Devices, Inc.
+ *
+ * Written and/or maintained by Timesys Corporation
+ *
+ * Contact: Nathan Barrett-Morrison <nathan.morri...@timesys.com>
+ * Contact: Greg Malysa <greg.mal...@timesys.com>
+ */
+
+#include <asm/io.h>
+#include <asm/arch-adi/sc5xx/sc5xx.h>
+
+#define REG_PADS0_PCFG0 0x31004404
+
+adi_rom_boot = (void (*)(void *, uint32_t, int32_t, void *, 
uint32_t))0x000000e1;
+
+void sc5xx_enable_rgmii(void)
+{
+       writel((readl(REG_PADS0_PCFG0) | 0xc), REG_PADS0_PCFG0);
+}
diff --git a/arch/arm/mach-sc5xx/sc58x.c b/arch/arm/mach-sc5xx/sc58x.c
new file mode 100644
index 0000000000..936f206a01
--- /dev/null
+++ b/arch/arm/mach-sc5xx/sc58x.c
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * (C) Copyright 2024 - Analog Devices, Inc.
+ *
+ * Written and/or maintained by Timesys Corporation
+ *
+ * Contact: Nathan Barrett-Morrison <nathan.morri...@timesys.com>
+ * Contact: Greg Malysa <greg.mal...@timesys.com>
+ */
+
+#include <asm/io.h>
+#include <asm/arch-adi/sc5xx/sc5xx.h>
+
+#define REG_PADS0_PCFG0 0x31004404
+
+adi_rom_boot = (void (*)(void *, uint32_t, int32_t, void *, 
uint32_t))0x000000e1;
+
+void sc5xx_enable_rgmii(void)
+{
+       writel((readl(REG_PADS0_PCFG0) | 0xc), REG_PADS0_PCFG0);
+}
diff --git a/arch/arm/mach-sc5xx/sc59x.c b/arch/arm/mach-sc5xx/sc59x.c
new file mode 100644
index 0000000000..0ba3125c5e
--- /dev/null
+++ b/arch/arm/mach-sc5xx/sc59x.c
@@ -0,0 +1,32 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * (C) Copyright 2024 - Analog Devices, Inc.
+ *
+ * Written and/or maintained by Timesys Corporation
+ *
+ * Contact: Nathan Barrett-Morrison <nathan.morri...@timesys.com>
+ * Contact: Greg Malysa <greg.mal...@timesys.com>
+ */
+
+#include <asm/io.h>
+#include <asm/arch-adi/sc5xx/sc5xx.h>
+
+#define REG_PADS0_PCFG0 0x31004604
+
+#define REG_SCB5_SPI2_OSPI_REMAP        0x30400000
+#define BITM_SCB5_SPI2_OSPI_REMAP_REMAP 0x00000003
+#define ENUM_SCB5_SPI2_OSPI_REMAP_OSPI0 0x00000001
+
+adi_rom_boot = (void (*)(void *, uint32_t, int32_t, void *, 
uint32_t))0x000000e9;
+
+void sc5xx_enable_rgmii(void)
+{
+       writel((readl(REG_PADS0_PCFG0) | 0xc), REG_PADS0_PCFG0);
+}
+
+void sc59x_remap_ospi(void)
+{
+       clrsetbits_le32(REG_SCB5_SPI2_OSPI_REMAP,
+                       BITM_SCB5_SPI2_OSPI_REMAP_REMAP,
+                       ENUM_SCB5_SPI2_OSPI_REMAP_OSPI0);
+}
diff --git a/arch/arm/mach-sc5xx/sc59x_64.c b/arch/arm/mach-sc5xx/sc59x_64.c
new file mode 100644
index 0000000000..c084182c8d
--- /dev/null
+++ b/arch/arm/mach-sc5xx/sc59x_64.c
@@ -0,0 +1,36 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * (C) Copyright 2024 - Analog Devices, Inc.
+ *
+ * Written and/or maintained by Timesys Corporation
+ *
+ * Contact: Nathan Barrett-Morrison <nathan.morri...@timesys.com>
+ * Contact: Greg Malysa <greg.mal...@timesys.com>
+ */
+
+#include <asm/io.h>
+#include <asm/arch-adi/sc5xx/sc5xx.h>
+
+#define REG_PADS0_PCFG0 0x31004604
+
+#define REG_SCB5_SPI2_OSPI_REMAP        0x30400000
+#define BITM_SCB5_SPI2_OSPI_REMAP_REMAP 0x00000003
+#define ENUM_SCB5_SPI2_OSPI_REMAP_OSPI0 0x00000001
+
+adi_rom_boot = (void (*)(void *, uint32_t, int32_t, void *, 
uint32_t))0x000000e4;
+
+void sc5xx_enable_rgmii(void)
+{
+       writel((readl(REG_PADS0_PCFG0) | 0xc), REG_PADS0_PCFG0);
+
+       // Set dw for little endian operation as well
+       writel(readl(REG_PADS0_PCFG0) & ~(1 << 19), REG_PADS0_PCFG0);
+       writel(readl(REG_PADS0_PCFG0) & ~(1 << 20), REG_PADS0_PCFG0);
+}
+
+void sc59x_remap_ospi(void)
+{
+       clrsetbits_le32(REG_SCB5_SPI2_OSPI_REMAP,
+                       BITM_SCB5_SPI2_OSPI_REMAP_REMAP,
+                       ENUM_SCB5_SPI2_OSPI_REMAP_OSPI0);
+}
diff --git a/arch/arm/mach-sc5xx/soc.c b/arch/arm/mach-sc5xx/soc.c
new file mode 100644
index 0000000000..bb11668054
--- /dev/null
+++ b/arch/arm/mach-sc5xx/soc.c
@@ -0,0 +1,142 @@
+// 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.morri...@timesys.com>
+ * Contact: Greg Malysa <greg.mal...@timesys.com>
+ */
+
+#include <asm/arch-adi/sc5xx/sc5xx.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <cpu_func.h>
+
+#include <asm/arch-adi/sc5xx/soc.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+void reset_cpu(void)
+{
+       writel(1, RCU0_CTL);
+}
+
+void enable_caches(void)
+{
+       if (!IS_ENABLED(CONFIG_SYS_DCACHE_OFF))
+               dcache_enable();
+}
+
+/*
+ * Don't try to configure the L2 cache in uboot because there's not quite
+ * enough documentation on which implementations we have
+ */
+void v7_outer_cache_enable(void)
+{
+}
+
+int arch_cpu_init(void)
+{
+       return 0;
+}
+
+const char *sc5xx_get_boot_mode(u32 *bmode)
+{
+       static const char * const bmodes[] = {
+               "JTAG/BOOTROM",
+               "QSPI Master",
+               "QSPI Slave",
+               "UART",
+               "LP0 Slave",
+               "OSPI",
+#ifdef CONFIG_SC59X_64
+               "eMMC"
+#endif
+       };
+       u32 local_mode;
+
+       local_mode = (readl(RCU0_STAT) & BITM_RCU_STAT_BMODE) >> 
BITP_RCU_STAT_BMODE;
+
+#if CONFIG_ADI_SPL_FORCE_BMODE != 0
+       /*
+        * In case we want to force boot sequences such as:
+        * QSPI -> OSPI
+        * QSPI -> eMMC
+        * If this is not set, then we will always try to use the BMODE setting
+        * for both stages... i.e.
+        * QSPI -> QSPI
+        */
+
+       // (Don't allow skipping JTAG/UART BMODE settings)
+       if (local_mode != 0 && local_mode != 3)
+               local_mode = CONFIG_ADI_SPL_FORCE_BMODE;
+#endif
+
+       *bmode = local_mode;
+
+       if (local_mode >= 0 && local_mode <= ARRAY_SIZE(bmodes))
+               return bmodes[local_mode];
+       return "unknown";
+}
+
+void print_cpu_id(void)
+{
+       if (!IS_ENABLED(CONFIG_ARM64)) {
+               u32 cpuid = 0;
+
+               __asm__ __volatile__("mrc p15, 0, %0, c0, c0, 0" : "=r"(cpuid));
+
+               printf("Detected Revision: %d.%d\n", cpuid & 0xf00000 >> 20, 
cpuid & 0xf);
+       }
+}
+
+int print_cpuinfo(void)
+{
+       u32 bmode;
+
+       printf("CPU:   ADSP %s (%s boot)\n", CONFIG_LDR_CPU, 
sc5xx_get_boot_mode(&bmode));
+       print_cpu_id();
+
+       return 0;
+}
+
+void fixup_dp83867_phy(struct phy_device *phydev)
+{
+       int phy_data = 0;
+
+       phy_data = phy_read(phydev, MDIO_DEVAD_NONE, 0x32);
+       phy_write(phydev, MDIO_DEVAD_NONE, 0x32, (1 << 7) | phy_data);
+       int cfg3 = 0;
+       #define MII_DP83867_CFG3    (0x1e)
+       /*
+        * Pin INT/PWDN on DP83867 should be configured as an Interrupt Output
+        * instead of a Power-Down Input on ADI SC5XX boards in order to
+        * prevent the signal interference from other peripherals during they
+        * are running at the same time.
+        */
+       cfg3 = phy_read(phydev, MDIO_DEVAD_NONE, MII_DP83867_CFG3);
+       cfg3 |= (1 << 7);
+       phy_write(phydev, MDIO_DEVAD_NONE, MII_DP83867_CFG3, cfg3);
+
+       // Mystery second port fixup on ezkits with two PHYs
+       if (CONFIG_DW_PORTS & 2)
+               phy_write(phydev, MDIO_DEVAD_NONE, 0x11, 3);
+
+       if (IS_ENABLED(CONFIG_ADI_BUG_EZKHW21)) {
+               phydev->advertising &= PHY_BASIC_FEATURES;
+               phydev->speed = SPEED_100;
+       }
+
+       if (phydev->drv->config)
+               phydev->drv->config(phydev);
+
+       if (IS_ENABLED(CONFIG_ADI_BUG_EZKHW21))
+               phy_write(phydev, MDIO_DEVAD_NONE, 0, 0x3100);
+}
+
+int dram_init(void)
+{
+       gd->ram_size = CFG_SYS_SDRAM_SIZE;
+       return 0;
+}
diff --git a/arch/arm/mach-sc5xx/spl.c b/arch/arm/mach-sc5xx/spl.c
new file mode 100644
index 0000000000..d8877110e4
--- /dev/null
+++ b/arch/arm/mach-sc5xx/spl.c
@@ -0,0 +1,140 @@
+// 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.morri...@timesys.com>
+ * Contact: Greg Malysa <greg.mal...@timesys.com>
+ */
+
+#include <spl.h>
+#include <asm/arch-adi/sc5xx/spl.h>
+#include "init/init.h"
+
+static bool adi_start_uboot_proper;
+
+static int adi_sf_default_bus = CONFIG_SF_DEFAULT_BUS;
+static int adi_sf_default_cs = CONFIG_SF_DEFAULT_CS;
+static int adi_sf_default_speed = CONFIG_SF_DEFAULT_SPEED;
+
+u32 bmode;
+
+int spl_start_uboot(void)
+{
+       return adi_start_uboot_proper;
+}
+
+unsigned int spl_spi_get_default_speed(void)
+{
+       return adi_sf_default_speed;
+}
+
+unsigned int spl_spi_get_default_bus(void)
+{
+       return adi_sf_default_bus;
+}
+
+unsigned int spl_spi_get_default_cs(void)
+{
+       return adi_sf_default_cs;
+}
+
+void board_boot_order(u32 *spl_boot_list)
+{
+       const char *bmodestring = sc5xx_get_boot_mode(&bmode);
+
+       printf("ADI Boot Mode: 0x%x (%s)\n", bmode, bmodestring);
+
+       /*
+        * By default everything goes back to the bootrom, where we'll read 
table
+        * parameters and ask for another image to be loaded
+        */
+       spl_boot_list[0] = BOOT_DEVICE_BOOTROM;
+
+       if (bmode == 0) {
+               printf("SPL execution has completed.  Please load U-Boot Proper 
via JTAG");
+               while (1)
+                       ;
+       }
+}
+
+int32_t __weak adi_rom_boot_hook(struct ADI_ROM_BOOT_CONFIG *config, int32_t 
cause)
+{
+       return 0;
+}
+
+int board_return_to_bootrom(struct spl_image_info *spl_image,
+                           struct spl_boot_device *bootdev)
+{
+#if CONFIG_ADI_SPL_FORCE_BMODE != 0
+       // see above
+       if (bmode != 0 && bmode != 3)
+               bmode = CONFIG_ADI_SPL_FORCE_BMODE;
+#endif
+
+       if (bmode >= (ARRAY_SIZE(adi_rom_boot_args)))
+               bmode = 0;
+
+       adi_rom_boot((void *)adi_rom_boot_args[bmode].addr,
+                    adi_rom_boot_args[bmode].flags,
+                    0, &adi_rom_boot_hook,
+                    adi_rom_boot_args[bmode].cmd);
+       return 0;
+};
+
+int dram_init_banksize(void)
+{
+       return 0;
+}
+
+void board_init_f(ulong dummy)
+{
+       int ret;
+
+       if (IS_ENABLED(CONFIG_SC59X_64)) {
+               phys_addr_t smpus[] = {
+                       0x31007800, //SMPU0
+                       0x31083800, //SMPU2
+                       0x31084800, //SMPU3
+                       0x31085800, //SMPU4
+                       0x31086800, //SMPU5
+                       0x31087800, //SMPU6
+                       0x310A0800, //SMPU9
+                       0x310A1800, //SMPU11
+                       0x31012800, //SMPU12
+               };
+               size_t i;
+
+               /* Alter outstanding transactions property of A55*/
+               writel(0x1, 0x30643108); /* SCB6 A55 M0 Ib.fn Mod */
+               isb();
+
+               /* configure DDR prefetch behavior, per ADI */
+               writel(0x1, 0x31076000);
+
+               /* configure smart mode, per ADI */
+               writel(0x1307, 0x31076004);
+
+               /* configure spu0 */
+               for (i = 0; i < 214; ++i)
+                       writel(0, 0x3108BA00 + 4 * i);
+
+               /* configure spu0 wp */
+               for (i = 0; i < 214; ++i)
+                       writel(0, 0x3108B400 + i * 4);
+
+               /* configure smpus permissively */
+               for (i = 0; i < ARRAY_SIZE(smpus); ++i)
+                       writel(0x500, smpus[i]);
+       }
+
+       adi_initcode_shared();
+
+       ret = spl_early_init();
+       if (ret)
+               panic("spl_early_init() failed\n");
+
+       preloader_console_init();
+}
+
diff --git a/include/configs/sc_adi_common.h b/include/configs/sc_adi_common.h
new file mode 100644
index 0000000000..a1d66e92dd
--- /dev/null
+++ b/include/configs/sc_adi_common.h
@@ -0,0 +1,226 @@
+/* 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.morri...@timesys.com>
+ * Contact: Greg Malysa <greg.mal...@timesys.com>
+ *
+ */
+
+#ifndef __CONFIG_SC_ADI_COMMON_H
+#define __CONFIG_SC_ADI_COMMON_H
+
+/*
+ * Env Settings
+ */
+#ifdef CONFIG_SC59X_64
+       #define ADI_EARLYPRINTK "earlycon=adi_uart,0x31003000 "
+       #if !CONFIG_IS_ENABLED(FIT)
+               #define IMAGEFILE "Image"
+               #define ADI_BOOT_INITRD "booti ${loadaddr} ${initramaddr} 
${dtbaddr};"
+               #define ADI_BOOT "booti ${loadaddr} - ${dtbaddr};"
+       #else
+               #define IMAGEFILE "fitImage"
+               #define ADI_BOOT_INITRD "bootm ${loadaddr};"
+               #define ADI_BOOT "bootm ${loadaddr};"
+       #endif
+#else
+       #define ADI_EARLYPRINTK "earlyprintk=serial,uart0," \
+               __stringify(CONFIG_BAUDRATE) " "
+       #if !CONFIG_IS_ENABLED(FIT)
+               #define IMAGEFILE "zImage"
+               #define ADI_BOOT_INITRD "bootz ${loadaddr} ${initramaddr} 
${dtbaddr};"
+               #define ADI_BOOT "bootz ${loadaddr} - ${dtbaddr};"
+       #else
+               #define IMAGEFILE "fitImage"
+               #define ADI_BOOT_INITRD "bootm ${loadaddr};"
+               #define ADI_BOOT "bootm ${loadaddr};"
+       #endif
+#endif
+
+#define ADI_UPDATE_SPI_UBOOT_CMD " run update_spi_uboot;"
+#define ADI_UPDATE_SPI_RFS_CMD " run update_spi_rfs;"
+
+#if CONFIG_IS_ENABLED(FIT)
+       #define ADI_UPDATE_SPI_DTB_CMD ""
+       #define ADI_UPDATE_SPI_IMAGE_CMD ""
+       #define ADI_UPDATE_SPI_FIT_CMD " run update_spi_fit;"
+       #define ADI_SPI_BOOTCMD "sf read ${loadaddr} " ADI_IMG_OFFSET \
+               " ${imagesize}; bootm ${loadaddr};"
+       #define ADI_MMC_LOAD "ext4load mmc 0:1 ${loadaddr} /boot/fitImage;"
+       #define ADI_TFTP_DTB ""
+       #define ADI_TFTP_INITRD ""
+#else
+       #define ADI_UPDATE_SPI_DTB_CMD " run update_spi_dtb;"
+       #define ADI_UPDATE_SPI_IMAGE_CMD " run update_spi_image;"
+       #define ADI_UPDATE_SPI_FIT_CMD ""
+       #define ADI_SPI_BOOTCMD "sf read ${loadaddr} " ADI_IMG_OFFSET \
+               " ${imagesize}; sf read ${dtbaddr} ${dtbloadaddr} ${dtbsize}; " 
\
+               "booti ${loadaddr} - ${dtbaddr}"
+       #define ADI_MMC_LOAD "ext4load mmc 0:1 ${dtbaddr} /boot/" 
CONFIG_DTBNAME "; " \
+               "ext4load mmc 0:1 ${loadaddr} /boot/Image;"
+       #define ADI_TFTP_DTB "tftp ${dtbaddr} ${tftp_dir_prefix}${dtbfile}; "
+       #define ADI_TFTP_INITRD "tftp ${initramaddr} 
${tftp_dir_prefix}${initramfile}; "
+#endif
+
+#define ADI_MMC_BOOTCMD "run mmcargs; " ADI_BOOT ""
+
+#define ADI_BOOTARGS_CONSOLE \
+               ADI_EARLYPRINTK \
+               "console=ttySC" __stringify(CONFIG_UART_CONSOLE) "," \
+                                               __stringify(CONFIG_BAUDRATE) " 
" \
+               "vmalloc=512M "
+
+#define ADI_BOOTARGS_MMC \
+               "root=/dev/mmcblk0p1 rw " \
+               "rootfstype=ext4 rootwait " \
+               ADI_BOOTARGS_CONSOLE
+
+#define ADI_BOOTARGS_SPI \
+               "root=/dev/mtdblock4 rw " \
+               "rootfstype=jffs2 " \
+               ADI_BOOTARGS_CONSOLE
+
+#define ADI_BOOTARGS_NFS       \
+               "root=/dev/nfs rw " \
+               "nfsroot=${serverip}:/romfs,tcp,nfsvers=3 " \
+               ADI_BOOTARGS_CONSOLE
+
+#define UBOOT_ENV_FILE "u-boot-" CONFIG_SYS_BOARD ".ldr"
+
+#define ADI_INIT_ETHERNET \
+       "init_ethernet=mii info; dhcp; setenv serverip ${tftpserverip};\0"
+
+#define ADI_NFS_BOOT \
+       "nfsargs=setenv bootargs " ADI_BOOTARGS_NFS "\0" \
+       "nfsboot=" \
+               "run init_ethernet; " \
+               "tftp ${loadaddr} ${tftp_dir_prefix}${imagefile};" \
+               ADI_TFTP_DTB \
+               "run nfsargs;" \
+               "run addip;" \
+               ADI_BOOT \
+               "\0"
+
+#define ADI_RAM_BOOT \
+       "ramboot=" \
+       "run init_ethernet; " \
+       "tftp ${loadaddr} ${tftp_dir_prefix}${imagefile}; " \
+       ADI_TFTP_DTB \
+       ADI_TFTP_INITRD \
+       "run ramargs; " \
+       ADI_BOOT_INITRD \
+       "\0"
+
+#define STAGE_1_FILE "stage1-boot.ldr"
+#define STAGE_2_FILE "stage2-boot.ldr"
+#define ADI_UPDATE_SPI_UBOOT \
+       "stage1file=" STAGE_1_FILE "\0" \
+       "stage2file=" STAGE_2_FILE "\0" \
+       "update_spi_uboot_stage1=tftp ${loadaddr} 
${tftp_dir_prefix}${stage1file}; " \
+       "sf probe ${sfdev}; sf update ${loadaddr} 0x0 ${filesize};\0" \
+       "update_spi_uboot_stage2=tftp ${loadaddr} 
${tftp_dir_prefix}${stage2file}; " \
+       "sf probe ${sfdev}; sf update ${loadaddr} " ADI_UBOOT_OFFSET " 
${filesize};\0" \
+       "update_spi_uboot=run update_spi_uboot_stage1; run 
update_spi_uboot_stage2;\0"
+
+#if CONFIG_IS_ENABLED(FIT)
+       #define ADI_UPDATE_SPI_DTB ""
+#else
+       #define ADI_UPDATE_SPI_DTB \
+       "update_spi_dtb=tftp ${loadaddr} ${tftp_dir_prefix}${dtbfile}; " \
+       "sf probe ${sfdev}; " \
+       "setexpr dtbloadaddr ${imagesize} + " ADI_IMG_OFFSET "; " \
+       "sf update ${loadaddr} ${dtbloadaddr} ${filesize}; " \
+       "setenv dtbsize ${filesize};\0"
+#endif
+
+#define ADI_ERASE_SPI \
+       "erase_spi=setenv sfdev " __stringify(CONFIG_SC_BOOT_SPI_BUS) \
+       ":" __stringify(CONFIG_SC_BOOT_SPI_SSEL) "; " \
+       "setenv sfsize " ADI_SPI_SIZE "; sf probe ${sfdev}; sf erase 0 
${sfsize};\0"
+
+#define ADI_UPDATE_SPI \
+       "start_update_spi=run init_ethernet; sf probe ${sfdev};" \
+       ADI_UPDATE_SPI_UBOOT_CMD \
+       ADI_UPDATE_SPI_IMAGE_CMD \
+       ADI_UPDATE_SPI_FIT_CMD \
+       ADI_UPDATE_SPI_DTB_CMD \
+       ADI_UPDATE_SPI_RFS_CMD \
+       " sleep 3; saveenv\0" \
+       ADI_UPDATE_SPI_UBOOT \
+       ADI_UPDATE_SPI_DTB \
+       "update_spi_image=tftp ${loadaddr} ${tftp_dir_prefix}${imagefile}; " \
+       "sf probe ${sfdev}; sf update ${loadaddr} " ADI_IMG_OFFSET " 
${filesize}; " \
+       "setenv imagesize ${filesize};\0" \
+       "update_spi_fit=tftp ${loadaddr} ${tftp_dir_prefix}${imagefile}; " \
+       "sf probe ${sfdev}; sf update ${loadaddr} " ADI_IMG_OFFSET " 
${filesize}; " \
+       "setenv imagesize ${filesize};\0" \
+       "update_spi_rfs=tftp ${loadaddr} ${tftp_dir_prefix}${jffs2file}; " \
+       "sf probe ${sfdev}; sf update ${loadaddr} " ADI_RFS_OFFSET " 
${filesize};\0"
+
+#define ADI_UPDATE_SPI_UBOOT_ONLY \
+       "start_update_spi_uboot_only=run init_ethernet; sf probe ${sfdev};" \
+       ADI_UPDATE_SPI_UBOOT_CMD \
+       " sleep 3; saveenv\0" \
+       ADI_UPDATE_SPI_UBOOT \
+
+#define ADI_ERASE_OSPI \
+       "erase_ospi=setenv sfdev " __stringify(CONFIG_SC_BOOT_OSPI_BUS) ":" \
+       __stringify(CONFIG_SC_BOOT_OSPI_SSEL) "; " \
+       "setenv sfsize " ADI_OSPI_SIZE "; sf probe ${sfdev}; sf erase 0 
${sfsize};\0"
+
+#define ADI_OSPI_BOOT \
+       "update_ospi=setenv sfdev " __stringify(CONFIG_SC_BOOT_OSPI_BUS) ":" \
+       __stringify(CONFIG_SC_BOOT_OSPI_SSEL) "; " \
+       "setenv sfsize " ADI_OSPI_SIZE "; setenv bootcmd \'run ospiboot\'; " \
+       "setenv argscmd ospiargs; run start_update_spi;\0" \
+       "update_ospi_uboot_only=setenv sfdev " 
__stringify(CONFIG_SC_BOOT_OSPI_BUS) ":" \
+       __stringify(CONFIG_SC_BOOT_OSPI_SSEL) "; run 
start_update_spi_uboot_only;\0" \
+       "ospiargs=setenv bootargs " ADI_BOOTARGS_SPI "\0" \
+       "ospi_boot=run ospiargs; sf probe ${sfdev};" ADI_SPI_BOOTCMD "\0" \
+       "ospiboot=run ospi_boot\0"
+
+#define ADI_SPI_BOOT \
+       "update_spi=setenv sfdev " __stringify(CONFIG_SC_BOOT_SPI_BUS) ":" \
+       __stringify(CONFIG_SC_BOOT_SPI_SSEL) "; setenv sfsize " ADI_SPI_SIZE "; 
" \
+       "setenv bootcmd \'run spiboot\'; setenv argscmd spiargs; " \
+       "run start_update_spi;\0" \
+       "update_spi_uboot_only=setenv sfdev " 
__stringify(CONFIG_SC_BOOT_SPI_BUS) ":" \
+       __stringify(CONFIG_SC_BOOT_SPI_SSEL) "; run 
start_update_spi_uboot_only;\0" \
+       "spiargs=setenv bootargs " ADI_BOOTARGS_SPI "\0" \
+       "spi_boot=run spiargs; sf probe ${sfdev};" ADI_SPI_BOOTCMD "\0" \
+       "spiboot=run spi_boot\0"
+
+#define ADI_MMC_BOOT \
+       "update_mmc=setenv bootcmd \'run mmcboot\'; saveenv; " \
+       "setenv imagefile fitImage-emmc-tools; run ramboot\0" \
+       "mmcargs=setenv bootargs " ADI_BOOTARGS_MMC "\0" \
+       "mmcload=" ADI_MMC_LOAD "\0" \
+       "mmc_boot=" ADI_MMC_BOOTCMD "\0" \
+       "mmcboot=mmc rescan; run mmcload; run mmc_boot\0"
+
+#define ETH0ADDR "02:80:ad:20:31:e8"
+#define ETH1ADDR "02:80:ad:20:31:e9"
+
+#define CFG_EXTRA_ENV_SETTINGS \
+       "autoload=no\0" \
+       "ubootfile=" UBOOT_ENV_FILE "\0" \
+       "addip=setenv bootargs ${bootargs} " \
+               "ip=${ipaddr}:${serverip}:${gatewayip}:${netmask}:" \
+                  "${hostname}:eth0:off" \
+               "\0" \
+       \
+       "imagefile=" IMAGEFILE "\0" \
+       "initramfile=adsp-sc5xx-ramdisk-adsp-" CONFIG_SYS_BOARD 
".cpio.xz.u-boot\0" \
+       "jffs2file=adsp-sc5xx-" ADI_JFFS2_FILE "-adsp-" CONFIG_SYS_BOARD 
".jffs2\0" \
+       "initramaddr=" INITRAMADDR "\0" \
+       "dtbfile=" DTBNAME "\0" \
+       "dtbaddr=" DTBLOADADDR "\0" \
+       "loadaddr=" __stringify(LOADADDR) "\0" \
+       "ramargs=setenv bootargs " ADI_BOOTARGS_CONSOLE "\0" \
+       "ethaddr=" ETH0ADDR "\0" \
+       ADI_ENV_SETTINGS
+
+#endif
-- 
2.43.2

Reply via email to