Restore patch series "arm: dts: am62-beagleplay: Fix Beagleplay Ethernet"

As part of bringing the master branch back in to next, we need to allow
for all of these changes to exist here.

Reported-by: Jonas Karlman <jonas@kwiboo.se>
Signed-off-by: Tom Rini <trini@konsulko.com>
diff --git a/arch/arm/mach-sc5xx/init/Makefile b/arch/arm/mach-sc5xx/init/Makefile
new file mode 100644
index 0000000..9d4920f
--- /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.morrison@timesys.com>
+# Contact: Greg Malysa <greg.malysa@timesys.com>
+#
+
+obj-y += 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 0000000..ae53cd6
--- /dev/null
+++ b/arch/arm/mach-sc5xx/init/clkinit.c
@@ -0,0 +1,558 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * (C) Copyright 2022 - Analog Devices, Inc.
+ *
+ * Written and/or maintained by Timesys Corporation
+ *
+ * Contact: Nathan Barrett-Morrison <nathan.morrison@timesys.com>
+ * Contact: Greg Malysa <greg.malysa@timesys.com>
+ */
+
+#include <asm/arch-adi/sc5xx/sc5xx.h>
+#include <asm/io.h>
+#include <linux/types.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 REG_MISC_REG10_tst_addr     0x310A902C
+
+#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
+
+#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
+
+/*  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 0000000..b05f432
--- /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.morrison@timesys.com>
+ * Contact: Greg Malysa <greg.malysa@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 0000000..e375b5c
--- /dev/null
+++ b/arch/arm/mach-sc5xx/init/dmcinit.c
@@ -0,0 +1,954 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * (C) Copyright 2022 - Analog Devices, Inc.
+ *
+ * Written and/or maintained by Timesys Corporation
+ *
+ * Contact: Nathan Barrett-Morrison <nathan.morrison@timesys.com>
+ * Contact: Greg Malysa <greg.malysa@timesys.com>
+ */
+
+#include <asm/io.h>
+#include <asm/arch-adi/sc5xx/sc5xx.h>
+#include <linux/types.h>
+#include "clkinit.h"
+#include "dmcinit.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 */
+
+#if defined(CONFIG_ADI_USE_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)
+#else
+	#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)
+{
+	if (!IS_ENABLED(CONFIG_ADI_USE_DDR2)) {
+		if (IS_ENABLED(CONFIG_SC59X) || IS_ENABLED(CONFIG_SC59X_64)) {
+			if (IS_ENABLED(CONFIG_ADI_USE_DMC0))
+				adi_dmc_lane_reset(reset, 0);
+			if (IS_ENABLED(CONFIG_ADI_USE_DMC1))
+				adi_dmc_lane_reset(reset, 1);
+		}
+		else {
+			u32 temp = reset ? 0x800 : 0x0;
+
+			if (IS_ENABLED(CONFIG_ADI_USE_DMC0))
+				writel(temp, REG_DMC0_BASE + REG_DMC_PHY_CTL0);
+			if (IS_ENABLED(CONFIG_ADI_USE_DMC1))
+				writel(temp, REG_DMC1_BASE + REG_DMC_PHY_CTL0);
+		}
+	}
+}
+
+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 */
+		readl(0x80000000);
+
+		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;
+	}
+
+	if (IS_ENABLED(CONFIG_ADI_USE_DDR2))
+		dmc.ddr_mode = DDR2_MODE;
+	else
+		dmc.ddr_mode = DDR3_MODE;
+
+	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)
+{
+	if (IS_ENABLED(CONFIG_ADI_USE_DMC0))
+		__dmc_config(0);
+
+	if (IS_ENABLED(CONFIG_ADI_USE_DMC1))
+		__dmc_config(1);
+}
diff --git a/arch/arm/mach-sc5xx/init/dmcinit.h b/arch/arm/mach-sc5xx/init/dmcinit.h
new file mode 100644
index 0000000..46ff729
--- /dev/null
+++ b/arch/arm/mach-sc5xx/init/dmcinit.h
@@ -0,0 +1,31 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * (C) Copyright 2022 - Analog Devices, Inc.
+ *
+ * Written and/or maintained by Timesys Corporation
+ *
+ * Contact: Nathan Barrett-Morrison <nathan.morrison@timesys.com>
+ * Contact: Greg Malysa <greg.malysa@timesys.com>
+ */
+
+#ifndef DMCINIT_H_
+#define DMCINIT_H_
+
+#include <config.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/mem/is43tr16512bl.h b/arch/arm/mach-sc5xx/init/mem/is43tr16512bl.h
new file mode 100644
index 0000000..a583837
--- /dev/null
+++ b/arch/arm/mach-sc5xx/init/mem/is43tr16512bl.h
@@ -0,0 +1,62 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * (C) Copyright 2022 - Analog Devices, Inc.
+ *
+ * Written and/or maintained by Timesys Corporation
+ *
+ * Contact: Nathan Barrett-Morrison <nathan.morrison@timesys.com>
+ * Contact: Greg Malysa <greg.malysa@timesys.com>
+ */
+
+#ifndef 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 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 0000000..8827775
--- /dev/null
+++ b/arch/arm/mach-sc5xx/init/mem/mt41k128m16jt.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.morrison@timesys.com>
+ * Contact: Greg Malysa <greg.malysa@timesys.com>
+ */
+
+#ifndef MT41K128M16JT_H
+#define MT41K128M16JT_H
+
+/* Default DDR3 part assumed: MT41K128M16JT-125, 2Gb part */
+/* For DCLK= 450 MHz */
+#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 0000000..5735b87
--- /dev/null
+++ b/arch/arm/mach-sc5xx/init/mem/mt41k512m16ha.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.morrison@timesys.com>
+ * Contact: Greg Malysa <greg.malysa@timesys.com>
+ */
+
+#ifndef MT41K512M16HA_H
+#define MT41K512M16HA_H
+
+/* Default DDR3 part assumed: MT41K512M16HA-107, 8Gb part */
+/* For DCLK= 450 MHz */
+#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 0000000..5ada7f2
--- /dev/null
+++ b/arch/arm/mach-sc5xx/init/mem/mt47h128m16rt.h
@@ -0,0 +1,49 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * (C) Copyright 2022 - Analog Devices, Inc.
+ *
+ * Written and/or maintained by Timesys Corporation
+ *
+ * Contact: Nathan Barrett-Morrison <nathan.morrison@timesys.com>
+ * Contact: Greg Malysa <greg.malysa@timesys.com>
+ */
+
+#ifndef MT47H128M16RT_H
+#define MT47H128M16RT_H
+
+/* Default DDR2 part: MT47H128M16RT-25E XIT:C, 2 Gb part */
+/* For DCLK= 400 MHz */
+#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