arm: socfpga: stratix10: Add clock manager driver for Stratix10 SoC

Add Clock Manager driver support for Stratix SoC

Signed-off-by: Chin Liang See <chin.liang.see@intel.com>
Signed-off-by: Ley Foon Tan <ley.foon.tan@intel.com>
diff --git a/arch/arm/mach-socfpga/Makefile b/arch/arm/mach-socfpga/Makefile
index 89b4fdf..6ee8ce6 100644
--- a/arch/arm/mach-socfpga/Makefile
+++ b/arch/arm/mach-socfpga/Makefile
@@ -28,6 +28,10 @@
 obj-y	+= reset_manager_arria10.o
 endif
 
+ifdef CONFIG_TARGET_SOCFPGA_STRATIX10
+obj-y	+= clock_manager_s10.o
+obj-y	+= wrap_pll_config_s10.o
+endif
 ifdef CONFIG_SPL_BUILD
 obj-y	+= spl.o
 ifdef CONFIG_TARGET_SOCFPGA_GEN5
diff --git a/arch/arm/mach-socfpga/clock_manager.c b/arch/arm/mach-socfpga/clock_manager.c
index bc2c0f8..59ede59 100644
--- a/arch/arm/mach-socfpga/clock_manager.c
+++ b/arch/arm/mach-socfpga/clock_manager.c
@@ -20,7 +20,7 @@
 	do {
 #if defined(CONFIG_TARGET_SOCFPGA_GEN5)
 		inter_val = readl(&clock_manager_base->inter) & mask;
-#elif defined(CONFIG_TARGET_SOCFPGA_ARRIA10)
+#else
 		inter_val = readl(&clock_manager_base->stat) & mask;
 #endif
 		/* Wait for stable lock */
@@ -51,7 +51,7 @@
 
 #if defined(CONFIG_TARGET_SOCFPGA_GEN5)
 	gd->bd->bi_ddr_freq = cm_get_sdram_clk_hz() / 1000000;
-#elif defined(CONFIG_TARGET_SOCFPGA_ARRIA10)
+#else
 	gd->bd->bi_ddr_freq = 0;
 #endif
 
diff --git a/arch/arm/mach-socfpga/clock_manager_s10.c b/arch/arm/mach-socfpga/clock_manager_s10.c
new file mode 100644
index 0000000..3ba2a00
--- /dev/null
+++ b/arch/arm/mach-socfpga/clock_manager_s10.c
@@ -0,0 +1,380 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2016-2018 Intel Corporation <www.intel.com>
+ *
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/clock_manager.h>
+#include <asm/arch/handoff_s10.h>
+#include <asm/arch/system_manager.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static const struct socfpga_clock_manager *clock_manager_base =
+	(struct socfpga_clock_manager *)SOCFPGA_CLKMGR_ADDRESS;
+static const struct socfpga_system_manager *sysmgr_regs =
+		(struct socfpga_system_manager *)SOCFPGA_SYSMGR_ADDRESS;
+
+/*
+ * function to write the bypass register which requires a poll of the
+ * busy bit
+ */
+static void cm_write_bypass_mainpll(u32 val)
+{
+	writel(val, &clock_manager_base->main_pll.bypass);
+	cm_wait_for_fsm();
+}
+
+static void cm_write_bypass_perpll(u32 val)
+{
+	writel(val, &clock_manager_base->per_pll.bypass);
+	cm_wait_for_fsm();
+}
+
+/* function to write the ctrl register which requires a poll of the busy bit */
+static void cm_write_ctrl(u32 val)
+{
+	writel(val, &clock_manager_base->ctrl);
+	cm_wait_for_fsm();
+}
+
+/*
+ * Setup clocks while making no assumptions about previous state of the clocks.
+ */
+void cm_basic_init(const struct cm_config * const cfg)
+{
+	u32 mdiv, refclkdiv, mscnt, hscnt, vcocalib;
+
+	if (cfg == 0)
+		return;
+
+	/* Put all plls in bypass */
+	cm_write_bypass_mainpll(CLKMGR_BYPASS_MAINPLL_ALL);
+	cm_write_bypass_perpll(CLKMGR_BYPASS_PERPLL_ALL);
+
+	/* setup main PLL dividers where calculate the vcocalib value */
+	mdiv = (cfg->main_pll_fdbck >> CLKMGR_FDBCK_MDIV_OFFSET) &
+		CLKMGR_FDBCK_MDIV_MASK;
+	refclkdiv = (cfg->main_pll_pllglob >> CLKMGR_PLLGLOB_REFCLKDIV_OFFSET) &
+		     CLKMGR_PLLGLOB_REFCLKDIV_MASK;
+	mscnt = CLKMGR_MSCNT_CONST / (CLKMGR_MDIV_CONST + mdiv) / refclkdiv;
+	hscnt = (mdiv + CLKMGR_MDIV_CONST) * mscnt / refclkdiv -
+		CLKMGR_HSCNT_CONST;
+	vcocalib = (hscnt & CLKMGR_VCOCALIB_HSCNT_MASK) |
+		   ((mscnt & CLKMGR_VCOCALIB_MSCNT_MASK) <<
+		   CLKMGR_VCOCALIB_MSCNT_OFFSET);
+
+	writel((cfg->main_pll_pllglob & ~CLKMGR_PLLGLOB_PD_MASK &
+		~CLKMGR_PLLGLOB_RST_MASK),
+		&clock_manager_base->main_pll.pllglob);
+	writel(cfg->main_pll_fdbck, &clock_manager_base->main_pll.fdbck);
+	writel(vcocalib, &clock_manager_base->main_pll.vcocalib);
+	writel(cfg->main_pll_pllc0, &clock_manager_base->main_pll.pllc0);
+	writel(cfg->main_pll_pllc1, &clock_manager_base->main_pll.pllc1);
+	writel(cfg->main_pll_nocdiv, &clock_manager_base->main_pll.nocdiv);
+
+	/* setup peripheral PLL dividers */
+	/* calculate the vcocalib value */
+	mdiv = (cfg->per_pll_fdbck >> CLKMGR_FDBCK_MDIV_OFFSET) &
+		CLKMGR_FDBCK_MDIV_MASK;
+	refclkdiv = (cfg->per_pll_pllglob >> CLKMGR_PLLGLOB_REFCLKDIV_OFFSET) &
+		     CLKMGR_PLLGLOB_REFCLKDIV_MASK;
+	mscnt = CLKMGR_MSCNT_CONST / (CLKMGR_MDIV_CONST + mdiv) / refclkdiv;
+	hscnt = (mdiv + CLKMGR_MDIV_CONST) * mscnt / refclkdiv -
+		CLKMGR_HSCNT_CONST;
+	vcocalib = (hscnt & CLKMGR_VCOCALIB_HSCNT_MASK) |
+		   ((mscnt & CLKMGR_VCOCALIB_MSCNT_MASK) <<
+		   CLKMGR_VCOCALIB_MSCNT_OFFSET);
+
+	writel((cfg->per_pll_pllglob & ~CLKMGR_PLLGLOB_PD_MASK &
+		~CLKMGR_PLLGLOB_RST_MASK),
+		&clock_manager_base->per_pll.pllglob);
+	writel(cfg->per_pll_fdbck, &clock_manager_base->per_pll.fdbck);
+	writel(vcocalib, &clock_manager_base->per_pll.vcocalib);
+	writel(cfg->per_pll_pllc0, &clock_manager_base->per_pll.pllc0);
+	writel(cfg->per_pll_pllc1, &clock_manager_base->per_pll.pllc1);
+	writel(cfg->per_pll_emacctl, &clock_manager_base->per_pll.emacctl);
+	writel(cfg->per_pll_gpiodiv, &clock_manager_base->per_pll.gpiodiv);
+
+	/* Take both PLL out of reset and power up */
+	setbits_le32(&clock_manager_base->main_pll.pllglob,
+		     CLKMGR_PLLGLOB_PD_MASK | CLKMGR_PLLGLOB_RST_MASK);
+	setbits_le32(&clock_manager_base->per_pll.pllglob,
+		     CLKMGR_PLLGLOB_PD_MASK | CLKMGR_PLLGLOB_RST_MASK);
+
+#define LOCKED_MASK \
+	(CLKMGR_STAT_MAINPLL_LOCKED | \
+	CLKMGR_STAT_PERPLL_LOCKED)
+
+	cm_wait_for_lock(LOCKED_MASK);
+
+	/*
+	 * Dividers for C2 to C9 only init after PLLs are lock. As dividers
+	 * only take effect upon value change, we shall set a maximum value as
+	 * default value.
+	 */
+	writel(0xff, &clock_manager_base->main_pll.mpuclk);
+	writel(0xff, &clock_manager_base->main_pll.nocclk);
+	writel(0xff, &clock_manager_base->main_pll.cntr2clk);
+	writel(0xff, &clock_manager_base->main_pll.cntr3clk);
+	writel(0xff, &clock_manager_base->main_pll.cntr4clk);
+	writel(0xff, &clock_manager_base->main_pll.cntr5clk);
+	writel(0xff, &clock_manager_base->main_pll.cntr6clk);
+	writel(0xff, &clock_manager_base->main_pll.cntr7clk);
+	writel(0xff, &clock_manager_base->main_pll.cntr8clk);
+	writel(0xff, &clock_manager_base->main_pll.cntr9clk);
+	writel(0xff, &clock_manager_base->per_pll.cntr2clk);
+	writel(0xff, &clock_manager_base->per_pll.cntr3clk);
+	writel(0xff, &clock_manager_base->per_pll.cntr4clk);
+	writel(0xff, &clock_manager_base->per_pll.cntr5clk);
+	writel(0xff, &clock_manager_base->per_pll.cntr6clk);
+	writel(0xff, &clock_manager_base->per_pll.cntr7clk);
+	writel(0xff, &clock_manager_base->per_pll.cntr8clk);
+	writel(0xff, &clock_manager_base->per_pll.cntr9clk);
+
+	writel(cfg->main_pll_mpuclk, &clock_manager_base->main_pll.mpuclk);
+	writel(cfg->main_pll_nocclk, &clock_manager_base->main_pll.nocclk);
+	writel(cfg->main_pll_cntr2clk, &clock_manager_base->main_pll.cntr2clk);
+	writel(cfg->main_pll_cntr3clk, &clock_manager_base->main_pll.cntr3clk);
+	writel(cfg->main_pll_cntr4clk, &clock_manager_base->main_pll.cntr4clk);
+	writel(cfg->main_pll_cntr5clk, &clock_manager_base->main_pll.cntr5clk);
+	writel(cfg->main_pll_cntr6clk, &clock_manager_base->main_pll.cntr6clk);
+	writel(cfg->main_pll_cntr7clk, &clock_manager_base->main_pll.cntr7clk);
+	writel(cfg->main_pll_cntr8clk, &clock_manager_base->main_pll.cntr8clk);
+	writel(cfg->main_pll_cntr9clk, &clock_manager_base->main_pll.cntr9clk);
+	writel(cfg->per_pll_cntr2clk, &clock_manager_base->per_pll.cntr2clk);
+	writel(cfg->per_pll_cntr3clk, &clock_manager_base->per_pll.cntr3clk);
+	writel(cfg->per_pll_cntr4clk, &clock_manager_base->per_pll.cntr4clk);
+	writel(cfg->per_pll_cntr5clk, &clock_manager_base->per_pll.cntr5clk);
+	writel(cfg->per_pll_cntr6clk, &clock_manager_base->per_pll.cntr6clk);
+	writel(cfg->per_pll_cntr7clk, &clock_manager_base->per_pll.cntr7clk);
+	writel(cfg->per_pll_cntr8clk, &clock_manager_base->per_pll.cntr8clk);
+	writel(cfg->per_pll_cntr9clk, &clock_manager_base->per_pll.cntr9clk);
+
+	/* Take all PLLs out of bypass */
+	cm_write_bypass_mainpll(0);
+	cm_write_bypass_perpll(0);
+
+	/* clear safe mode / out of boot mode */
+	cm_write_ctrl(readl(&clock_manager_base->ctrl)
+			& ~(CLKMGR_CTRL_SAFEMODE));
+
+	/* Now ungate non-hw-managed clocks */
+	writel(~0, &clock_manager_base->main_pll.en);
+	writel(~0, &clock_manager_base->per_pll.en);
+
+	/* Clear the loss of lock bits (write 1 to clear) */
+	writel(CLKMGR_INTER_PERPLLLOST_MASK | CLKMGR_INTER_MAINPLLLOST_MASK,
+	       &clock_manager_base->intrclr);
+}
+
+static unsigned long cm_get_main_vco_clk_hz(void)
+{
+	 unsigned long fref, refdiv, mdiv, reg, vco;
+
+	reg = readl(&clock_manager_base->main_pll.pllglob);
+
+	fref = (reg >> CLKMGR_PLLGLOB_VCO_PSRC_OFFSET) &
+		CLKMGR_PLLGLOB_VCO_PSRC_MASK;
+	switch (fref) {
+	case CLKMGR_VCO_PSRC_EOSC1:
+		fref = cm_get_osc_clk_hz();
+		break;
+	case CLKMGR_VCO_PSRC_INTOSC:
+		fref = cm_get_intosc_clk_hz();
+		break;
+	case CLKMGR_VCO_PSRC_F2S:
+		fref = cm_get_fpga_clk_hz();
+		break;
+	}
+
+	refdiv = (reg >> CLKMGR_PLLGLOB_REFCLKDIV_OFFSET) &
+		  CLKMGR_PLLGLOB_REFCLKDIV_MASK;
+
+	reg = readl(&clock_manager_base->main_pll.fdbck);
+	mdiv = (reg >> CLKMGR_FDBCK_MDIV_OFFSET) & CLKMGR_FDBCK_MDIV_MASK;
+
+	vco = fref / refdiv;
+	vco = vco * (CLKMGR_MDIV_CONST + mdiv);
+	return vco;
+}
+
+static unsigned long cm_get_per_vco_clk_hz(void)
+{
+	unsigned long fref, refdiv, mdiv, reg, vco;
+
+	reg = readl(&clock_manager_base->per_pll.pllglob);
+
+	fref = (reg >> CLKMGR_PLLGLOB_VCO_PSRC_OFFSET) &
+		CLKMGR_PLLGLOB_VCO_PSRC_MASK;
+	switch (fref) {
+	case CLKMGR_VCO_PSRC_EOSC1:
+		fref = cm_get_osc_clk_hz();
+		break;
+	case CLKMGR_VCO_PSRC_INTOSC:
+		fref = cm_get_intosc_clk_hz();
+		break;
+	case CLKMGR_VCO_PSRC_F2S:
+		fref = cm_get_fpga_clk_hz();
+		break;
+	}
+
+	refdiv = (reg >> CLKMGR_PLLGLOB_REFCLKDIV_OFFSET) &
+		  CLKMGR_PLLGLOB_REFCLKDIV_MASK;
+
+	reg = readl(&clock_manager_base->per_pll.fdbck);
+	mdiv = (reg >> CLKMGR_FDBCK_MDIV_OFFSET) & CLKMGR_FDBCK_MDIV_MASK;
+
+	vco = fref / refdiv;
+	vco = vco * (CLKMGR_MDIV_CONST + mdiv);
+	return vco;
+}
+
+unsigned long cm_get_mpu_clk_hz(void)
+{
+	unsigned long clock = readl(&clock_manager_base->main_pll.mpuclk);
+
+	clock = (clock >> CLKMGR_CLKSRC_OFFSET) & CLKMGR_CLKSRC_MASK;
+
+	switch (clock) {
+	case CLKMGR_CLKSRC_MAIN:
+		clock = cm_get_main_vco_clk_hz();
+		clock /= (readl(&clock_manager_base->main_pll.pllc0) &
+			  CLKMGR_PLLC0_DIV_MASK);
+		break;
+
+	case CLKMGR_CLKSRC_PER:
+		clock = cm_get_per_vco_clk_hz();
+		clock /= (readl(&clock_manager_base->per_pll.pllc0) &
+			  CLKMGR_CLKCNT_MSK);
+		break;
+
+	case CLKMGR_CLKSRC_OSC1:
+		clock = cm_get_osc_clk_hz();
+		break;
+
+	case CLKMGR_CLKSRC_INTOSC:
+		clock = cm_get_intosc_clk_hz();
+		break;
+
+	case CLKMGR_CLKSRC_FPGA:
+		clock = cm_get_fpga_clk_hz();
+		break;
+	}
+
+	clock /= 1 + (readl(&clock_manager_base->main_pll.mpuclk) &
+		CLKMGR_CLKCNT_MSK);
+	return clock;
+}
+
+unsigned int cm_get_l3_main_clk_hz(void)
+{
+	u32 clock = readl(&clock_manager_base->main_pll.nocclk);
+
+	clock = (clock >> CLKMGR_CLKSRC_OFFSET) & CLKMGR_CLKSRC_MASK;
+
+	switch (clock) {
+	case CLKMGR_CLKSRC_MAIN:
+		clock = cm_get_main_vco_clk_hz();
+		clock /= (readl(&clock_manager_base->main_pll.pllc1) &
+			  CLKMGR_PLLC0_DIV_MASK);
+		break;
+
+	case CLKMGR_CLKSRC_PER:
+		clock = cm_get_per_vco_clk_hz();
+		clock /= (readl(&clock_manager_base->per_pll.pllc1) &
+			  CLKMGR_CLKCNT_MSK);
+		break;
+
+	case CLKMGR_CLKSRC_OSC1:
+		clock = cm_get_osc_clk_hz();
+		break;
+
+	case CLKMGR_CLKSRC_INTOSC:
+		clock = cm_get_intosc_clk_hz();
+		break;
+
+	case CLKMGR_CLKSRC_FPGA:
+		clock = cm_get_fpga_clk_hz();
+		break;
+	}
+
+	clock /= 1 + (readl(&clock_manager_base->main_pll.nocclk) &
+		CLKMGR_CLKCNT_MSK);
+	return clock;
+}
+
+unsigned int cm_get_mmc_controller_clk_hz(void)
+{
+	u32 clock = readl(&clock_manager_base->per_pll.cntr6clk);
+
+	clock = (clock >> CLKMGR_CLKSRC_OFFSET) & CLKMGR_CLKSRC_MASK;
+
+	switch (clock) {
+	case CLKMGR_CLKSRC_MAIN:
+		clock = cm_get_l3_main_clk_hz();
+		clock /= 1 + (readl(&clock_manager_base->main_pll.cntr6clk) &
+			CLKMGR_CLKCNT_MSK);
+		break;
+
+	case CLKMGR_CLKSRC_PER:
+		clock = cm_get_l3_main_clk_hz();
+		clock /= 1 + (readl(&clock_manager_base->per_pll.cntr6clk) &
+			CLKMGR_CLKCNT_MSK);
+		break;
+
+	case CLKMGR_CLKSRC_OSC1:
+		clock = cm_get_osc_clk_hz();
+		break;
+
+	case CLKMGR_CLKSRC_INTOSC:
+		clock = cm_get_intosc_clk_hz();
+		break;
+
+	case CLKMGR_CLKSRC_FPGA:
+		clock = cm_get_fpga_clk_hz();
+		break;
+	}
+	return clock / 4;
+}
+
+unsigned int cm_get_l4_sp_clk_hz(void)
+{
+	u32 clock = cm_get_l3_main_clk_hz();
+
+	clock /= (1 << ((readl(&clock_manager_base->main_pll.nocdiv) >>
+		  CLKMGR_NOCDIV_L4SPCLK_OFFSET) & CLKMGR_CLKCNT_MSK));
+	return clock;
+}
+
+unsigned int cm_get_qspi_controller_clk_hz(void)
+{
+	return readl(&sysmgr_regs->boot_scratch_cold0);
+}
+
+unsigned int cm_get_spi_controller_clk_hz(void)
+{
+	u32 clock = cm_get_l3_main_clk_hz();
+
+	clock /= (1 << ((readl(&clock_manager_base->main_pll.nocdiv) >>
+		  CLKMGR_NOCDIV_L4MAIN_OFFSET) & CLKMGR_CLKCNT_MSK));
+	return clock;
+}
+
+unsigned int cm_get_l4_sys_free_clk_hz(void)
+{
+	return cm_get_l3_main_clk_hz() / 4;
+}
+
+void cm_print_clock_quick_summary(void)
+{
+	printf("MPU         %d kHz\n", (u32)(cm_get_mpu_clk_hz() / 1000));
+	printf("L3 main     %d kHz\n", cm_get_l3_main_clk_hz() / 1000);
+	printf("Main VCO    %d kHz\n", (u32)(cm_get_main_vco_clk_hz() / 1000));
+	printf("Per VCO     %d kHz\n", (u32)(cm_get_per_vco_clk_hz() / 1000));
+	printf("EOSC1       %d kHz\n", cm_get_osc_clk_hz() / 1000);
+	printf("HPS MMC     %d kHz\n", cm_get_mmc_controller_clk_hz() / 1000);
+	printf("UART        %d kHz\n", cm_get_l4_sp_clk_hz() / 1000);
+}
diff --git a/arch/arm/mach-socfpga/include/mach/clock_manager.h b/arch/arm/mach-socfpga/include/mach/clock_manager.h
index 3ace040..dd80e3a 100644
--- a/arch/arm/mach-socfpga/include/mach/clock_manager.h
+++ b/arch/arm/mach-socfpga/include/mach/clock_manager.h
@@ -16,6 +16,8 @@
 #include <asm/arch/clock_manager_gen5.h>
 #elif defined(CONFIG_TARGET_SOCFPGA_ARRIA10)
 #include <asm/arch/clock_manager_arria10.h>
+#elif defined(CONFIG_TARGET_SOCFPGA_STRATIX10)
+#include <asm/arch/clock_manager_s10.h>
 #endif
 
 #endif /* _CLOCK_MANAGER_H_ */
diff --git a/arch/arm/mach-socfpga/include/mach/clock_manager_s10.h b/arch/arm/mach-socfpga/include/mach/clock_manager_s10.h
new file mode 100644
index 0000000..24b20de
--- /dev/null
+++ b/arch/arm/mach-socfpga/include/mach/clock_manager_s10.h
@@ -0,0 +1,210 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Copyright (C) 2016-2018 Intel Corporation <www.intel.com>
+ *
+ */
+
+#ifndef	_CLOCK_MANAGER_S10_
+#define	_CLOCK_MANAGER_S10_
+
+/* Clock speed accessors */
+unsigned long cm_get_mpu_clk_hz(void);
+unsigned long cm_get_sdram_clk_hz(void);
+unsigned int cm_get_l4_sp_clk_hz(void);
+unsigned int cm_get_mmc_controller_clk_hz(void);
+unsigned int cm_get_qspi_controller_clk_hz(void);
+unsigned int cm_get_spi_controller_clk_hz(void);
+const unsigned int cm_get_osc_clk_hz(void);
+const unsigned int cm_get_f2s_per_ref_clk_hz(void);
+const unsigned int cm_get_f2s_sdr_ref_clk_hz(void);
+const unsigned int cm_get_intosc_clk_hz(void);
+const unsigned int cm_get_fpga_clk_hz(void);
+
+#define CLKMGR_EOSC1_HZ		25000000
+#define CLKMGR_INTOSC_HZ	460000000
+#define CLKMGR_FPGA_CLK_HZ	50000000
+
+/* Clock configuration accessors */
+const struct cm_config * const cm_get_default_config(void);
+
+struct cm_config {
+	/* main group */
+	u32 main_pll_mpuclk;
+	u32 main_pll_nocclk;
+	u32 main_pll_cntr2clk;
+	u32 main_pll_cntr3clk;
+	u32 main_pll_cntr4clk;
+	u32 main_pll_cntr5clk;
+	u32 main_pll_cntr6clk;
+	u32 main_pll_cntr7clk;
+	u32 main_pll_cntr8clk;
+	u32 main_pll_cntr9clk;
+	u32 main_pll_nocdiv;
+	u32 main_pll_pllglob;
+	u32 main_pll_fdbck;
+	u32 main_pll_pllc0;
+	u32 main_pll_pllc1;
+	u32 spare;
+
+	/* peripheral group */
+	u32 per_pll_cntr2clk;
+	u32 per_pll_cntr3clk;
+	u32 per_pll_cntr4clk;
+	u32 per_pll_cntr5clk;
+	u32 per_pll_cntr6clk;
+	u32 per_pll_cntr7clk;
+	u32 per_pll_cntr8clk;
+	u32 per_pll_cntr9clk;
+	u32 per_pll_emacctl;
+	u32 per_pll_gpiodiv;
+	u32 per_pll_pllglob;
+	u32 per_pll_fdbck;
+	u32 per_pll_pllc0;
+	u32 per_pll_pllc1;
+
+	/* incoming clock */
+	u32 hps_osc_clk_hz;
+	u32 fpga_clk_hz;
+};
+
+void cm_basic_init(const struct cm_config * const cfg);
+
+struct socfpga_clock_manager_main_pll {
+	u32	en;
+	u32	ens;
+	u32	enr;
+	u32	bypass;
+	u32	bypasss;
+	u32	bypassr;
+	u32	mpuclk;
+	u32	nocclk;
+	u32	cntr2clk;
+	u32	cntr3clk;
+	u32	cntr4clk;
+	u32	cntr5clk;
+	u32	cntr6clk;
+	u32	cntr7clk;
+	u32	cntr8clk;
+	u32	cntr9clk;
+	u32	nocdiv;
+	u32	pllglob;
+	u32	fdbck;
+	u32	mem;
+	u32	memstat;
+	u32	pllc0;
+	u32	pllc1;
+	u32	vcocalib;
+	u32	_pad_0x90_0xA0[5];
+};
+
+struct socfpga_clock_manager_per_pll {
+	u32	en;
+	u32	ens;
+	u32	enr;
+	u32	bypass;
+	u32	bypasss;
+	u32	bypassr;
+	u32	cntr2clk;
+	u32	cntr3clk;
+	u32	cntr4clk;
+	u32	cntr5clk;
+	u32	cntr6clk;
+	u32	cntr7clk;
+	u32	cntr8clk;
+	u32	cntr9clk;
+	u32	emacctl;
+	u32	gpiodiv;
+	u32	pllglob;
+	u32	fdbck;
+	u32	mem;
+	u32	memstat;
+	u32	pllc0;
+	u32	pllc1;
+	u32	vcocalib;
+	u32	_pad_0x100_0x124[10];
+};
+
+struct socfpga_clock_manager {
+	u32	ctrl;
+	u32	stat;
+	u32	testioctrl;
+	u32	intrgen;
+	u32	intrmsk;
+	u32	intrclr;
+	u32	intrsts;
+	u32	intrstk;
+	u32	intrraw;
+	u32	_pad_0x24_0x2c[3];
+	struct socfpga_clock_manager_main_pll main_pll;
+	struct socfpga_clock_manager_per_pll per_pll;
+};
+
+#define CLKMGR_CTRL_SAFEMODE				BIT(0)
+#define CLKMGR_BYPASS_MAINPLL_ALL			0x00000007
+#define CLKMGR_BYPASS_PERPLL_ALL			0x0000007f
+
+#define CLKMGR_INTER_MAINPLLLOCKED_MASK			0x00000001
+#define CLKMGR_INTER_PERPLLLOCKED_MASK			0x00000002
+#define CLKMGR_INTER_MAINPLLLOST_MASK			0x00000004
+#define CLKMGR_INTER_PERPLLLOST_MASK			0x00000008
+#define CLKMGR_STAT_BUSY				BIT(0)
+#define CLKMGR_STAT_MAINPLL_LOCKED			BIT(8)
+#define CLKMGR_STAT_PERPLL_LOCKED			BIT(9)
+
+#define CLKMGR_PLLGLOB_PD_MASK				0x00000001
+#define CLKMGR_PLLGLOB_RST_MASK				0x00000002
+#define CLKMGR_PLLGLOB_VCO_PSRC_MASK			0X3
+#define CLKMGR_PLLGLOB_VCO_PSRC_OFFSET			16
+#define CLKMGR_VCO_PSRC_EOSC1				0
+#define CLKMGR_VCO_PSRC_INTOSC				1
+#define CLKMGR_VCO_PSRC_F2S				2
+#define CLKMGR_PLLGLOB_REFCLKDIV_MASK			0X3f
+#define CLKMGR_PLLGLOB_REFCLKDIV_OFFSET			8
+
+#define CLKMGR_CLKSRC_MASK				0x7
+#define CLKMGR_CLKSRC_OFFSET				16
+#define CLKMGR_CLKSRC_MAIN				0
+#define CLKMGR_CLKSRC_PER				1
+#define CLKMGR_CLKSRC_OSC1				2
+#define CLKMGR_CLKSRC_INTOSC				3
+#define CLKMGR_CLKSRC_FPGA				4
+#define CLKMGR_CLKCNT_MSK				0x7ff
+
+#define CLKMGR_FDBCK_MDIV_MASK				0xff
+#define CLKMGR_FDBCK_MDIV_OFFSET			24
+
+#define CLKMGR_PLLC0_DIV_MASK				0xff
+#define CLKMGR_PLLC1_DIV_MASK				0xff
+#define CLKMGR_PLLC0_EN_OFFSET				27
+#define CLKMGR_PLLC1_EN_OFFSET				24
+
+#define CLKMGR_NOCDIV_L4MAIN_OFFSET			0
+#define CLKMGR_NOCDIV_L4MPCLK_OFFSET			8
+#define CLKMGR_NOCDIV_L4SPCLK_OFFSET			16
+#define CLKMGR_NOCDIV_CSATCLK_OFFSET			24
+#define CLKMGR_NOCDIV_CSTRACECLK_OFFSET			26
+#define CLKMGR_NOCDIV_CSPDBGCLK_OFFSET			28
+
+#define CLKMGR_NOCDIV_L4SPCLK_MASK			0X3
+#define CLKMGR_NOCDIV_DIV1				0
+#define CLKMGR_NOCDIV_DIV2				1
+#define CLKMGR_NOCDIV_DIV4				2
+#define CLKMGR_NOCDIV_DIV8				3
+#define CLKMGR_CSPDBGCLK_DIV1				0
+#define CLKMGR_CSPDBGCLK_DIV4				1
+
+#define CLKMGR_MSCNT_CONST				200
+#define CLKMGR_MDIV_CONST				6
+#define CLKMGR_HSCNT_CONST				9
+
+#define CLKMGR_VCOCALIB_MSCNT_MASK			0xff
+#define CLKMGR_VCOCALIB_MSCNT_OFFSET			9
+#define CLKMGR_VCOCALIB_HSCNT_MASK			0xff
+
+#define CLKMGR_EMACCTL_EMAC0SEL_OFFSET			26
+#define CLKMGR_EMACCTL_EMAC1SEL_OFFSET			27
+#define CLKMGR_EMACCTL_EMAC2SEL_OFFSET			28
+
+#define CLKMGR_PERPLLGRP_EN_SDMMCCLK_MASK		0x00000020
+
+#endif /* _CLOCK_MANAGER_S10_ */
diff --git a/arch/arm/mach-socfpga/include/mach/handoff_s10.h b/arch/arm/mach-socfpga/include/mach/handoff_s10.h
new file mode 100644
index 0000000..ba0f1fd
--- /dev/null
+++ b/arch/arm/mach-socfpga/include/mach/handoff_s10.h
@@ -0,0 +1,34 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Copyright (C) 2016-2018 Intel Corporation <www.intel.com>
+ *
+ */
+
+#ifndef _HANDOFF_S10_H_
+#define _HANDOFF_S10_H_
+
+/*
+ * Offset for HW handoff from Quartus tools
+ */
+#define S10_HANDOFF_BASE		0xFFE3F000
+#define S10_HANDOFF_MUX		(S10_HANDOFF_BASE + 0x10)
+#define S10_HANDOFF_IOCTL		(S10_HANDOFF_BASE + 0x1A0)
+#define S10_HANDOFF_FPGA		(S10_HANDOFF_BASE + 0x330)
+#define S10_HANODFF_DELAY		(S10_HANDOFF_BASE + 0x3F0)
+#define S10_HANDOFF_CLOCK		(S10_HANDOFF_BASE + 0x580)
+#define S10_HANDOFF_MISC		(S10_HANDOFF_BASE + 0x610)
+#define S10_HANDOFF_MAGIC_MUX	0x504D5558
+#define S10_HANDOFF_MAGIC_IOCTL	0x494F4354
+#define S10_HANDOFF_MAGIC_FPGA	0x46504741
+#define S10_HANDOFF_MAGIC_DELAY	0x444C4159
+#define S10_HANDOFF_MAGIC_CLOCK	0x434C4B53
+#define S10_HANDOFF_MAGIC_MISC	0x4D495343
+#define S10_HANDOFF_OFFSET_LENGTH	0x4
+#define S10_HANDOFF_OFFSET_DATA	0x10
+
+#define S10_HANDOFF_CLOCK_OSC	(S10_HANDOFF_BASE + 0x608)
+#define S10_HANDOFF_CLOCK_FPGA	(S10_HANDOFF_BASE + 0x60C)
+
+#define S10_HANDOFF_SIZE	4096
+
+#endif /* _HANDOFF_S10_H_ */
diff --git a/arch/arm/mach-socfpga/wrap_pll_config_s10.c b/arch/arm/mach-socfpga/wrap_pll_config_s10.c
new file mode 100644
index 0000000..7cafc7d
--- /dev/null
+++ b/arch/arm/mach-socfpga/wrap_pll_config_s10.c
@@ -0,0 +1,59 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2016-2018 Intel Corporation <www.intel.com>
+ *
+ */
+
+#include <common.h>
+#include <asm/arch/clock_manager.h>
+#include <asm/io.h>
+#include <asm/arch/handoff_s10.h>
+#include <asm/arch/system_manager.h>
+
+static const struct socfpga_system_manager *sysmgr_regs =
+	(struct socfpga_system_manager *)SOCFPGA_SYSMGR_ADDRESS;
+
+const struct cm_config * const cm_get_default_config(void)
+{
+	struct cm_config *cm_handoff_cfg = (struct cm_config *)
+		(S10_HANDOFF_CLOCK + S10_HANDOFF_OFFSET_DATA);
+	u32 *conversion = (u32 *)cm_handoff_cfg;
+	u32 i;
+	u32 handoff_clk = readl(S10_HANDOFF_CLOCK);
+
+	if (swab32(handoff_clk) == S10_HANDOFF_MAGIC_CLOCK) {
+		writel(swab32(handoff_clk), S10_HANDOFF_CLOCK);
+		for (i = 0; i < (sizeof(*cm_handoff_cfg) / sizeof(u32)); i++)
+			conversion[i] = swab32(conversion[i]);
+		return cm_handoff_cfg;
+	} else if (handoff_clk == S10_HANDOFF_MAGIC_CLOCK) {
+		return cm_handoff_cfg;
+	}
+
+	return NULL;
+}
+
+const unsigned int cm_get_osc_clk_hz(void)
+{
+#ifdef CONFIG_SPL_BUILD
+	u32 clock = readl(S10_HANDOFF_CLOCK_OSC);
+
+	writel(clock, &sysmgr_regs->boot_scratch_cold1);
+#endif
+	return readl(&sysmgr_regs->boot_scratch_cold1);
+}
+
+const unsigned int cm_get_intosc_clk_hz(void)
+{
+	return CLKMGR_INTOSC_HZ;
+}
+
+const unsigned int cm_get_fpga_clk_hz(void)
+{
+#ifdef CONFIG_SPL_BUILD
+	u32 clock = readl(S10_HANDOFF_CLOCK_FPGA);
+
+	writel(clock, &sysmgr_regs->boot_scratch_cold2);
+#endif
+	return readl(&sysmgr_regs->boot_scratch_cold2);
+}