[U-Boot] [RFC PATCH v2 14/18] arm: socfpga: gen5: move clock initialization to CLK driver

Simon Goldschmidt simon.k.r.goldschmidt at gmail.com
Tue Oct 15 20:10:27 UTC 2019


This moves setting initial clock values (as defined by Quartus handoff
files) from ad-hoc code in arch to CM_CLK driver.

TODO: CONFIG_CLOCKS and cmd 'clocks' must be fixed for dts access.
Signed-off-by: Simon Goldschmidt <simon.k.r.goldschmidt at gmail.com>
---

Changes in v2: None

 arch/arm/mach-socfpga/Makefile                |   1 -
 arch/arm/mach-socfpga/clock_manager.c         |  31 +-
 arch/arm/mach-socfpga/clock_manager_gen5.c    | 528 ------------------
 .../mach-socfpga/include/mach/clock_manager.h |   2 +
 .../include/mach/clock_manager_gen5.h         |  12 -
 arch/arm/mach-socfpga/spl_gen5.c              |   8 +-
 drivers/clk/altera/clk-gen5.c                 | 361 ++++++++++++
 7 files changed, 388 insertions(+), 555 deletions(-)
 delete mode 100644 arch/arm/mach-socfpga/clock_manager_gen5.c

diff --git a/arch/arm/mach-socfpga/Makefile b/arch/arm/mach-socfpga/Makefile
index fc1181cb27..4b77990f74 100644
--- a/arch/arm/mach-socfpga/Makefile
+++ b/arch/arm/mach-socfpga/Makefile
@@ -10,7 +10,6 @@ obj-y	+= clock_manager.o
 obj-y	+= misc.o
 
 ifdef CONFIG_TARGET_SOCFPGA_GEN5
-obj-y	+= clock_manager_gen5.o
 obj-y	+= misc_gen5.o
 obj-y	+= reset_manager_gen5.o
 obj-y	+= scan_manager.o
diff --git a/arch/arm/mach-socfpga/clock_manager.c b/arch/arm/mach-socfpga/clock_manager.c
index 9f3c643df8..16760c760f 100644
--- a/arch/arm/mach-socfpga/clock_manager.c
+++ b/arch/arm/mach-socfpga/clock_manager.c
@@ -10,6 +10,8 @@
 
 DECLARE_GLOBAL_DATA_PTR;
 
+#ifndef CONFIG_TARGET_SOCFPGA_GEN5
+
 static const struct socfpga_clock_manager *clock_manager_base =
 	(struct socfpga_clock_manager *)SOCFPGA_CLKMGR_ADDRESS;
 
@@ -18,11 +20,7 @@ void cm_wait_for_lock(u32 mask)
 	u32 inter_val;
 	u32 retry = 0;
 	do {
-#if defined(CONFIG_TARGET_SOCFPGA_GEN5)
-		inter_val = readl(&clock_manager_base->inter) & mask;
-#else
 		inter_val = readl(&clock_manager_base->stat) & mask;
-#endif
 		/* Wait for stable lock */
 		if (inter_val == mask)
 			retry++;
@@ -40,14 +38,29 @@ int cm_wait_for_fsm(void)
 				 CLKMGR_STAT_BUSY, false, 20000, false);
 }
 
-int set_cpu_clk_info(void)
+#endif
+
+#ifdef CONFIG_TARGET_SOCFPGA_GEN5
+static unsigned long cm_get_mpu_clk_hz(void)
 {
-#if defined(CONFIG_TARGET_SOCFPGA_GEN5)
-	/* Calculate the clock frequencies required for drivers */
-	cm_get_l4_sp_clk_hz();
-	cm_get_mmc_controller_clk_hz();
+	return 0; // TODO: use devicetree
+}
+
+static unsigned long cm_get_sdram_clk_hz(void)
+{
+	return 0; // TODO: use devicetree
+}
+
+#ifndef CONFIG_SPL_BUILD
+static void cm_print_clock_quick_summary(void)
+{
+	// TODO: use devicetree
+}
+#endif
 #endif
 
+int set_cpu_clk_info(void)
+{
 	gd->bd->bi_arm_freq = cm_get_mpu_clk_hz() / 1000000;
 	gd->bd->bi_dsp_freq = 0;
 
diff --git a/arch/arm/mach-socfpga/clock_manager_gen5.c b/arch/arm/mach-socfpga/clock_manager_gen5.c
deleted file mode 100644
index 3a64600861..0000000000
--- a/arch/arm/mach-socfpga/clock_manager_gen5.c
+++ /dev/null
@@ -1,528 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- *  Copyright (C) 2013-2017 Altera Corporation <www.altera.com>
- */
-
-#include <common.h>
-#include <asm/io.h>
-#include <dm.h>
-#include <asm/arch/clock_manager.h>
-#include <wait_bit.h>
-
-static const struct socfpga_clock_manager *clock_manager_base =
-	(struct socfpga_clock_manager *)SOCFPGA_CLKMGR_ADDRESS;
-
-/*
- * function to write the bypass register which requires a poll of the
- * busy bit
- */
-static void cm_write_bypass(u32 val)
-{
-	writel(val, &clock_manager_base->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();
-}
-
-/* function to write a clock register that has phase information */
-static int cm_write_with_phase(u32 value, const void *reg_address, u32 mask)
-{
-	int ret;
-
-	/* poll until phase is zero */
-	ret = wait_for_bit_le32(reg_address, mask, false, 20000, false);
-	if (ret)
-		return ret;
-
-	writel(value, reg_address);
-
-	return wait_for_bit_le32(reg_address, mask, false, 20000, false);
-}
-
-/*
- * Setup clocks while making no assumptions about previous state of the clocks.
- *
- * Start by being paranoid and gate all sw managed clocks
- * Put all plls in bypass
- * Put all plls VCO registers back to reset value (bandgap power down).
- * Put peripheral and main pll src to reset value to avoid glitch.
- * Delay 5 us.
- * Deassert bandgap power down and set numerator and denominator
- * Start 7 us timer.
- * set internal dividers
- * Wait for 7 us timer.
- * Enable plls
- * Set external dividers while plls are locking
- * Wait for pll lock
- * Assert/deassert outreset all.
- * Take all pll's out of bypass
- * Clear safe mode
- * set source main and peripheral clocks
- * Ungate clocks
- */
-
-int cm_basic_init(const struct cm_config * const cfg)
-{
-	unsigned long end;
-	int ret;
-
-	/* Start by being paranoid and gate all sw managed clocks */
-
-	/*
-	 * We need to disable nandclk
-	 * and then do another apb access before disabling
-	 * gatting off the rest of the periperal clocks.
-	 */
-	writel(~CLKMGR_PERPLLGRP_EN_NANDCLK_MASK &
-		readl(&clock_manager_base->per_pll.en),
-		&clock_manager_base->per_pll.en);
-
-	/* DO NOT GATE OFF DEBUG CLOCKS & BRIDGE CLOCKS */
-	writel(CLKMGR_MAINPLLGRP_EN_DBGTIMERCLK_MASK |
-		CLKMGR_MAINPLLGRP_EN_DBGTRACECLK_MASK |
-		CLKMGR_MAINPLLGRP_EN_DBGCLK_MASK |
-		CLKMGR_MAINPLLGRP_EN_DBGATCLK_MASK |
-		CLKMGR_MAINPLLGRP_EN_S2FUSER0CLK_MASK |
-		CLKMGR_MAINPLLGRP_EN_L4MPCLK_MASK,
-		&clock_manager_base->main_pll.en);
-
-	writel(0, &clock_manager_base->sdr_pll.en);
-
-	/* now we can gate off the rest of the peripheral clocks */
-	writel(0, &clock_manager_base->per_pll.en);
-
-	/* Put all plls in bypass */
-	cm_write_bypass(CLKMGR_BYPASS_PERPLL | CLKMGR_BYPASS_SDRPLL |
-			CLKMGR_BYPASS_MAINPLL);
-
-	/* Put all plls VCO registers back to reset value. */
-	writel(CLKMGR_MAINPLLGRP_VCO_RESET_VALUE &
-	       ~CLKMGR_MAINPLLGRP_VCO_REGEXTSEL_MASK,
-	       &clock_manager_base->main_pll.vco);
-	writel(CLKMGR_PERPLLGRP_VCO_RESET_VALUE &
-	       ~CLKMGR_PERPLLGRP_VCO_REGEXTSEL_MASK,
-	       &clock_manager_base->per_pll.vco);
-	writel(CLKMGR_SDRPLLGRP_VCO_RESET_VALUE &
-	       ~CLKMGR_SDRPLLGRP_VCO_REGEXTSEL_MASK,
-	       &clock_manager_base->sdr_pll.vco);
-
-	/*
-	 * The clocks to the flash devices and the L4_MAIN clocks can
-	 * glitch when coming out of safe mode if their source values
-	 * are different from their reset value.  So the trick it to
-	 * put them back to their reset state, and change input
-	 * after exiting safe mode but before ungating the clocks.
-	 */
-	writel(CLKMGR_PERPLLGRP_SRC_RESET_VALUE,
-	       &clock_manager_base->per_pll.src);
-	writel(CLKMGR_MAINPLLGRP_L4SRC_RESET_VALUE,
-	       &clock_manager_base->main_pll.l4src);
-
-	/* read back for the required 5 us delay. */
-	readl(&clock_manager_base->main_pll.vco);
-	readl(&clock_manager_base->per_pll.vco);
-	readl(&clock_manager_base->sdr_pll.vco);
-
-
-	/*
-	 * We made sure bgpwr down was assert for 5 us. Now deassert BG PWR DN
-	 * with numerator and denominator.
-	 */
-	writel(cfg->main_vco_base, &clock_manager_base->main_pll.vco);
-	writel(cfg->peri_vco_base, &clock_manager_base->per_pll.vco);
-	writel(cfg->sdram_vco_base, &clock_manager_base->sdr_pll.vco);
-
-	/*
-	 * Time starts here. Must wait 7 us from
-	 * BGPWRDN_SET(0) to VCO_ENABLE_SET(1).
-	 */
-	end = timer_get_us() + 7;
-
-	/* main mpu */
-	writel(cfg->mpuclk, &clock_manager_base->main_pll.mpuclk);
-
-	/* altera group mpuclk */
-	writel(cfg->altera_grp_mpuclk, &clock_manager_base->altera.mpuclk);
-
-	/* main main clock */
-	writel(cfg->mainclk, &clock_manager_base->main_pll.mainclk);
-
-	/* main for dbg */
-	writel(cfg->dbgatclk, &clock_manager_base->main_pll.dbgatclk);
-
-	/* main for cfgs2fuser0clk */
-	writel(cfg->cfg2fuser0clk,
-	       &clock_manager_base->main_pll.cfgs2fuser0clk);
-
-	/* Peri emac0 50 MHz default to RMII */
-	writel(cfg->emac0clk, &clock_manager_base->per_pll.emac0clk);
-
-	/* Peri emac1 50 MHz default to RMII */
-	writel(cfg->emac1clk, &clock_manager_base->per_pll.emac1clk);
-
-	/* Peri QSPI */
-	writel(cfg->mainqspiclk, &clock_manager_base->main_pll.mainqspiclk);
-
-	writel(cfg->perqspiclk, &clock_manager_base->per_pll.perqspiclk);
-
-	/* Peri pernandsdmmcclk */
-	writel(cfg->mainnandsdmmcclk,
-	       &clock_manager_base->main_pll.mainnandsdmmcclk);
-
-	writel(cfg->pernandsdmmcclk,
-	       &clock_manager_base->per_pll.pernandsdmmcclk);
-
-	/* Peri perbaseclk */
-	writel(cfg->perbaseclk, &clock_manager_base->per_pll.perbaseclk);
-
-	/* Peri s2fuser1clk */
-	writel(cfg->s2fuser1clk, &clock_manager_base->per_pll.s2fuser1clk);
-
-	/* 7 us must have elapsed before we can enable the VCO */
-	while (timer_get_us() < end)
-		;
-
-	/* Enable vco */
-	/* main pll vco */
-	writel(cfg->main_vco_base | CLKMGR_MAINPLLGRP_VCO_EN,
-	       &clock_manager_base->main_pll.vco);
-
-	/* periferal pll */
-	writel(cfg->peri_vco_base | CLKMGR_MAINPLLGRP_VCO_EN,
-	       &clock_manager_base->per_pll.vco);
-
-	/* sdram pll vco */
-	writel(cfg->sdram_vco_base | CLKMGR_MAINPLLGRP_VCO_EN,
-	       &clock_manager_base->sdr_pll.vco);
-
-	/* L3 MP and L3 SP */
-	writel(cfg->maindiv, &clock_manager_base->main_pll.maindiv);
-
-	writel(cfg->dbgdiv, &clock_manager_base->main_pll.dbgdiv);
-
-	writel(cfg->tracediv, &clock_manager_base->main_pll.tracediv);
-
-	/* L4 MP, L4 SP, can0, and can1 */
-	writel(cfg->perdiv, &clock_manager_base->per_pll.div);
-
-	writel(cfg->gpiodiv, &clock_manager_base->per_pll.gpiodiv);
-
-	cm_wait_for_lock(LOCKED_MASK);
-
-	/* write the sdram clock counters before toggling outreset all */
-	writel(cfg->ddrdqsclk & CLKMGR_SDRPLLGRP_DDRDQSCLK_CNT_MASK,
-	       &clock_manager_base->sdr_pll.ddrdqsclk);
-
-	writel(cfg->ddr2xdqsclk & CLKMGR_SDRPLLGRP_DDR2XDQSCLK_CNT_MASK,
-	       &clock_manager_base->sdr_pll.ddr2xdqsclk);
-
-	writel(cfg->ddrdqclk & CLKMGR_SDRPLLGRP_DDRDQCLK_CNT_MASK,
-	       &clock_manager_base->sdr_pll.ddrdqclk);
-
-	writel(cfg->s2fuser2clk & CLKMGR_SDRPLLGRP_S2FUSER2CLK_CNT_MASK,
-	       &clock_manager_base->sdr_pll.s2fuser2clk);
-
-	/*
-	 * after locking, but before taking out of bypass
-	 * assert/deassert outresetall
-	 */
-	u32 mainvco = readl(&clock_manager_base->main_pll.vco);
-
-	/* assert main outresetall */
-	writel(mainvco | CLKMGR_MAINPLLGRP_VCO_OUTRESETALL_MASK,
-	       &clock_manager_base->main_pll.vco);
-
-	u32 periphvco = readl(&clock_manager_base->per_pll.vco);
-
-	/* assert pheriph outresetall */
-	writel(periphvco | CLKMGR_PERPLLGRP_VCO_OUTRESETALL_MASK,
-	       &clock_manager_base->per_pll.vco);
-
-	/* assert sdram outresetall */
-	writel(cfg->sdram_vco_base | CLKMGR_MAINPLLGRP_VCO_EN|
-		CLKMGR_SDRPLLGRP_VCO_OUTRESETALL,
-		&clock_manager_base->sdr_pll.vco);
-
-	/* deassert main outresetall */
-	writel(mainvco & ~CLKMGR_MAINPLLGRP_VCO_OUTRESETALL_MASK,
-	       &clock_manager_base->main_pll.vco);
-
-	/* deassert pheriph outresetall */
-	writel(periphvco & ~CLKMGR_PERPLLGRP_VCO_OUTRESETALL_MASK,
-	       &clock_manager_base->per_pll.vco);
-
-	/* deassert sdram outresetall */
-	writel(cfg->sdram_vco_base | CLKMGR_MAINPLLGRP_VCO_EN,
-	       &clock_manager_base->sdr_pll.vco);
-
-	/*
-	 * now that we've toggled outreset all, all the clocks
-	 * are aligned nicely; so we can change any phase.
-	 */
-	ret = cm_write_with_phase(cfg->ddrdqsclk,
-				  &clock_manager_base->sdr_pll.ddrdqsclk,
-				  CLKMGR_SDRPLLGRP_DDRDQSCLK_PHASE_MASK);
-	if (ret)
-		return ret;
-
-	/* SDRAM DDR2XDQSCLK */
-	ret = cm_write_with_phase(cfg->ddr2xdqsclk,
-				  &clock_manager_base->sdr_pll.ddr2xdqsclk,
-				  CLKMGR_SDRPLLGRP_DDR2XDQSCLK_PHASE_MASK);
-	if (ret)
-		return ret;
-
-	ret = cm_write_with_phase(cfg->ddrdqclk,
-				  &clock_manager_base->sdr_pll.ddrdqclk,
-				  CLKMGR_SDRPLLGRP_DDRDQCLK_PHASE_MASK);
-	if (ret)
-		return ret;
-
-	ret = cm_write_with_phase(cfg->s2fuser2clk,
-				  &clock_manager_base->sdr_pll.s2fuser2clk,
-				  CLKMGR_SDRPLLGRP_S2FUSER2CLK_PHASE_MASK);
-	if (ret)
-		return ret;
-
-	/* Take all three PLLs out of bypass when safe mode is cleared. */
-	cm_write_bypass(0);
-
-	/* clear safe mode */
-	cm_write_ctrl(readl(&clock_manager_base->ctrl) | CLKMGR_CTRL_SAFEMODE);
-
-	/*
-	 * now that safe mode is clear with clocks gated
-	 * it safe to change the source mux for the flashes the the L4_MAIN
-	 */
-	writel(cfg->persrc, &clock_manager_base->per_pll.src);
-	writel(cfg->l4src, &clock_manager_base->main_pll.l4src);
-
-	/* Now ungate non-hw-managed clocks */
-	writel(~0, &clock_manager_base->main_pll.en);
-	writel(~0, &clock_manager_base->per_pll.en);
-	writel(~0, &clock_manager_base->sdr_pll.en);
-
-	/* Clear the loss of lock bits (write 1 to clear) */
-	writel(CLKMGR_INTER_SDRPLLLOST_MASK | CLKMGR_INTER_PERPLLLOST_MASK |
-	       CLKMGR_INTER_MAINPLLLOST_MASK,
-	       &clock_manager_base->inter);
-
-	return 0;
-}
-
-static unsigned int cm_get_main_vco_clk_hz(void)
-{
-	u32 reg, clock;
-
-	/* get the main VCO clock */
-	reg = readl(&clock_manager_base->main_pll.vco);
-	clock = cm_get_osc_clk_hz(1);
-	clock /= ((reg & CLKMGR_MAINPLLGRP_VCO_DENOM_MASK) >>
-		  CLKMGR_MAINPLLGRP_VCO_DENOM_OFFSET) + 1;
-	clock *= ((reg & CLKMGR_MAINPLLGRP_VCO_NUMER_MASK) >>
-		  CLKMGR_MAINPLLGRP_VCO_NUMER_OFFSET) + 1;
-
-	return clock;
-}
-
-static unsigned int cm_get_per_vco_clk_hz(void)
-{
-	u32 reg, clock = 0;
-
-	/* identify PER PLL clock source */
-	reg = readl(&clock_manager_base->per_pll.vco);
-	reg = (reg & CLKMGR_PERPLLGRP_VCO_SSRC_MASK) >>
-	      CLKMGR_PERPLLGRP_VCO_SSRC_OFFSET;
-	if (reg == CLKMGR_VCO_SSRC_EOSC1)
-		clock = cm_get_osc_clk_hz(1);
-	else if (reg == CLKMGR_VCO_SSRC_EOSC2)
-		clock = cm_get_osc_clk_hz(2);
-	else if (reg == CLKMGR_VCO_SSRC_F2S)
-		clock = cm_get_f2s_per_ref_clk_hz();
-
-	/* get the PER VCO clock */
-	reg = readl(&clock_manager_base->per_pll.vco);
-	clock /= ((reg & CLKMGR_PERPLLGRP_VCO_DENOM_MASK) >>
-		  CLKMGR_PERPLLGRP_VCO_DENOM_OFFSET) + 1;
-	clock *= ((reg & CLKMGR_PERPLLGRP_VCO_NUMER_MASK) >>
-		  CLKMGR_PERPLLGRP_VCO_NUMER_OFFSET) + 1;
-
-	return clock;
-}
-
-unsigned long cm_get_mpu_clk_hz(void)
-{
-	u32 reg, clock;
-
-	clock = cm_get_main_vco_clk_hz();
-
-	/* get the MPU clock */
-	reg = readl(&clock_manager_base->altera.mpuclk);
-	clock /= (reg + 1);
-	reg = readl(&clock_manager_base->main_pll.mpuclk);
-	clock /= (reg + 1);
-	return clock;
-}
-
-unsigned long cm_get_sdram_clk_hz(void)
-{
-	u32 reg, clock = 0;
-
-	/* identify SDRAM PLL clock source */
-	reg = readl(&clock_manager_base->sdr_pll.vco);
-	reg = (reg & CLKMGR_SDRPLLGRP_VCO_SSRC_MASK) >>
-	      CLKMGR_SDRPLLGRP_VCO_SSRC_OFFSET;
-	if (reg == CLKMGR_VCO_SSRC_EOSC1)
-		clock = cm_get_osc_clk_hz(1);
-	else if (reg == CLKMGR_VCO_SSRC_EOSC2)
-		clock = cm_get_osc_clk_hz(2);
-	else if (reg == CLKMGR_VCO_SSRC_F2S)
-		clock = cm_get_f2s_sdr_ref_clk_hz();
-
-	/* get the SDRAM VCO clock */
-	reg = readl(&clock_manager_base->sdr_pll.vco);
-	clock /= ((reg & CLKMGR_SDRPLLGRP_VCO_DENOM_MASK) >>
-		  CLKMGR_SDRPLLGRP_VCO_DENOM_OFFSET) + 1;
-	clock *= ((reg & CLKMGR_SDRPLLGRP_VCO_NUMER_MASK) >>
-		  CLKMGR_SDRPLLGRP_VCO_NUMER_OFFSET) + 1;
-
-	/* get the SDRAM (DDR_DQS) clock */
-	reg = readl(&clock_manager_base->sdr_pll.ddrdqsclk);
-	reg = (reg & CLKMGR_SDRPLLGRP_DDRDQSCLK_CNT_MASK) >>
-	      CLKMGR_SDRPLLGRP_DDRDQSCLK_CNT_OFFSET;
-	clock /= (reg + 1);
-
-	return clock;
-}
-
-unsigned int cm_get_l4_sp_clk_hz(void)
-{
-	u32 reg, clock = 0;
-
-	/* identify the source of L4 SP clock */
-	reg = readl(&clock_manager_base->main_pll.l4src);
-	reg = (reg & CLKMGR_MAINPLLGRP_L4SRC_L4SP) >>
-	      CLKMGR_MAINPLLGRP_L4SRC_L4SP_OFFSET;
-
-	if (reg == CLKMGR_L4_SP_CLK_SRC_MAINPLL) {
-		clock = cm_get_main_vco_clk_hz();
-
-		/* get the clock prior L4 SP divider (main clk) */
-		reg = readl(&clock_manager_base->altera.mainclk);
-		clock /= (reg + 1);
-		reg = readl(&clock_manager_base->main_pll.mainclk);
-		clock /= (reg + 1);
-	} else if (reg == CLKMGR_L4_SP_CLK_SRC_PERPLL) {
-		clock = cm_get_per_vco_clk_hz();
-
-		/* get the clock prior L4 SP divider (periph_base_clk) */
-		reg = readl(&clock_manager_base->per_pll.perbaseclk);
-		clock /= (reg + 1);
-	}
-
-	/* get the L4 SP clock which supplied to UART */
-	reg = readl(&clock_manager_base->main_pll.maindiv);
-	reg = (reg & CLKMGR_MAINPLLGRP_MAINDIV_L4SPCLK_MASK) >>
-	      CLKMGR_MAINPLLGRP_MAINDIV_L4SPCLK_OFFSET;
-	clock = clock / (1 << reg);
-
-	return clock;
-}
-
-unsigned int cm_get_mmc_controller_clk_hz(void)
-{
-	u32 reg, clock = 0;
-
-	/* identify the source of MMC clock */
-	reg = readl(&clock_manager_base->per_pll.src);
-	reg = (reg & CLKMGR_PERPLLGRP_SRC_SDMMC_MASK) >>
-	      CLKMGR_PERPLLGRP_SRC_SDMMC_OFFSET;
-
-	if (reg == CLKMGR_SDMMC_CLK_SRC_F2S) {
-		clock = cm_get_f2s_per_ref_clk_hz();
-	} else if (reg == CLKMGR_SDMMC_CLK_SRC_MAIN) {
-		clock = cm_get_main_vco_clk_hz();
-
-		/* get the SDMMC clock */
-		reg = readl(&clock_manager_base->main_pll.mainnandsdmmcclk);
-		clock /= (reg + 1);
-	} else if (reg == CLKMGR_SDMMC_CLK_SRC_PER) {
-		clock = cm_get_per_vco_clk_hz();
-
-		/* get the SDMMC clock */
-		reg = readl(&clock_manager_base->per_pll.pernandsdmmcclk);
-		clock /= (reg + 1);
-	}
-
-	/* further divide by 4 as we have fixed divider at wrapper */
-	clock /= 4;
-	return clock;
-}
-
-unsigned int cm_get_qspi_controller_clk_hz(void)
-{
-	u32 reg, clock = 0;
-
-	/* identify the source of QSPI clock */
-	reg = readl(&clock_manager_base->per_pll.src);
-	reg = (reg & CLKMGR_PERPLLGRP_SRC_QSPI_MASK) >>
-	      CLKMGR_PERPLLGRP_SRC_QSPI_OFFSET;
-
-	if (reg == CLKMGR_QSPI_CLK_SRC_F2S) {
-		clock = cm_get_f2s_per_ref_clk_hz();
-	} else if (reg == CLKMGR_QSPI_CLK_SRC_MAIN) {
-		clock = cm_get_main_vco_clk_hz();
-
-		/* get the qspi clock */
-		reg = readl(&clock_manager_base->main_pll.mainqspiclk);
-		clock /= (reg + 1);
-	} else if (reg == CLKMGR_QSPI_CLK_SRC_PER) {
-		clock = cm_get_per_vco_clk_hz();
-
-		/* get the qspi clock */
-		reg = readl(&clock_manager_base->per_pll.perqspiclk);
-		clock /= (reg + 1);
-	}
-
-	return clock;
-}
-
-unsigned int cm_get_spi_controller_clk_hz(void)
-{
-	u32 reg, clock = 0;
-
-	clock = cm_get_per_vco_clk_hz();
-
-	/* get the clock prior L4 SP divider (periph_base_clk) */
-	reg = readl(&clock_manager_base->per_pll.perbaseclk);
-	clock /= (reg + 1);
-
-	return clock;
-}
-
-/* Override weak dw_spi_get_clk implementation in designware_spi.c driver */
-int dw_spi_get_clk(struct udevice *bus, ulong *rate)
-{
-	*rate = cm_get_spi_controller_clk_hz();
-
-	return 0;
-}
-
-void cm_print_clock_quick_summary(void)
-{
-	printf("MPU       %10ld kHz\n", cm_get_mpu_clk_hz() / 1000);
-	printf("DDR       %10ld kHz\n", cm_get_sdram_clk_hz() / 1000);
-	printf("EOSC1       %8d kHz\n", cm_get_osc_clk_hz(1) / 1000);
-	printf("EOSC2       %8d kHz\n", cm_get_osc_clk_hz(2) / 1000);
-	printf("F2S_SDR_REF %8d kHz\n", cm_get_f2s_sdr_ref_clk_hz() / 1000);
-	printf("F2S_PER_REF %8d kHz\n", cm_get_f2s_per_ref_clk_hz() / 1000);
-	printf("MMC         %8d kHz\n", cm_get_mmc_controller_clk_hz() / 1000);
-	printf("QSPI        %8d kHz\n", cm_get_qspi_controller_clk_hz() / 1000);
-	printf("UART        %8d kHz\n", cm_get_l4_sp_clk_hz() / 1000);
-	printf("SPI         %8d kHz\n", cm_get_spi_controller_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 dd80e3a767..fff606e099 100644
--- a/arch/arm/mach-socfpga/include/mach/clock_manager.h
+++ b/arch/arm/mach-socfpga/include/mach/clock_manager.h
@@ -6,11 +6,13 @@
 #ifndef _CLOCK_MANAGER_H_
 #define _CLOCK_MANAGER_H_
 
+#ifndef CONFIG_TARGET_SOCFPGA_GEN5
 #ifndef __ASSEMBLER__
 void cm_wait_for_lock(u32 mask);
 int cm_wait_for_fsm(void);
 void cm_print_clock_quick_summary(void);
 #endif
+#endif
 
 #if defined(CONFIG_TARGET_SOCFPGA_GEN5)
 #include <asm/arch/clock_manager_gen5.h>
diff --git a/arch/arm/mach-socfpga/include/mach/clock_manager_gen5.h b/arch/arm/mach-socfpga/include/mach/clock_manager_gen5.h
index 5bedf28cf1..a9efe2a377 100644
--- a/arch/arm/mach-socfpga/include/mach/clock_manager_gen5.h
+++ b/arch/arm/mach-socfpga/include/mach/clock_manager_gen5.h
@@ -111,19 +111,7 @@ struct socfpga_clock_manager {
 	u32	_pad_0xe8_0x200[70];
 };
 
-/* 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(const int osc);
-const unsigned int cm_get_f2s_per_ref_clk_hz(void);
-const unsigned int cm_get_f2s_sdr_ref_clk_hz(void);
-
 /* Clock configuration accessors */
-int cm_basic_init(const struct cm_config * const cfg);
 const struct cm_config * const cm_get_default_config(void);
 #endif /* __ASSEMBLER__ */
 
diff --git a/arch/arm/mach-socfpga/spl_gen5.c b/arch/arm/mach-socfpga/spl_gen5.c
index 1ae8025746..901fd9597e 100644
--- a/arch/arm/mach-socfpga/spl_gen5.c
+++ b/arch/arm/mach-socfpga/spl_gen5.c
@@ -62,7 +62,6 @@ u32 spl_boot_mode(const u32 boot_device)
 
 void board_init_f(ulong dummy)
 {
-	const struct cm_config *cm_default_cfg = cm_get_default_config();
 	unsigned long reg;
 	int ret;
 	struct udevice *dev;
@@ -106,10 +105,9 @@ void board_init_f(ulong dummy)
 	socfpga_per_reset(SOCFPGA_RESET(OSC1TIMER0), 0);
 	timer_init();
 
-	debug("Reconfigure Clock Manager\n");
-	/* reconfigure the PLLs */
-	if (cm_basic_init(cm_default_cfg))
-		hang();
+	ret = uclass_get_device(UCLASS_CLK, 0, &dev);
+	if (ret)
+		debug("Reset init failed: %d\n", ret);
 
 	/* Enable bootrom to configure IOs. */
 	sysmgr_config_warmrstcfgio(1);
diff --git a/drivers/clk/altera/clk-gen5.c b/drivers/clk/altera/clk-gen5.c
index 4c197b81b0..e8f435a798 100644
--- a/drivers/clk/altera/clk-gen5.c
+++ b/drivers/clk/altera/clk-gen5.c
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0
 /*
  * Copyright (C) 2018 Marek Vasut <marex at denx.de>
+ * Copyright (C) 2019 Simon Goldschmidt <simon.k.r.goldschmidt at gmail.com>
  */
 
 #include <common.h>
@@ -9,6 +10,7 @@
 #include <dm.h>
 #include <dm/lists.h>
 #include <dm/util.h>
+#include <wait_bit.h>
 
 #include <asm/arch/clock_manager.h>
 
@@ -41,6 +43,353 @@ struct socfpga_gen5_clk_platdata {
 	u8		src_off;
 };
 
+#ifdef CONFIG_SPL_BUILD
+static void socfpga_gen5_clk_wait_for_lock(
+	const struct socfpga_clock_manager *clock_mgr, u32 mask)
+{
+	u32 inter_val;
+	u32 retry = 0;
+	do {
+#if defined(CONFIG_TARGET_SOCFPGA_GEN5)
+		inter_val = readl(&clock_mgr->inter) & mask;
+#else
+		inter_val = readl(&clock_mgr->stat) & mask;
+#endif
+		/* Wait for stable lock */
+		if (inter_val == mask)
+			retry++;
+		else
+			retry = 0;
+		if (retry >= 10)
+			break;
+	} while (1);
+}
+
+/* function to poll in the fsm busy bit */
+static int socfpga_gen5_clk_wait_for_fsm(
+	const struct socfpga_clock_manager *clock_mgr)
+{
+	return wait_for_bit_le32(&clock_mgr->stat,
+				 CLKMGR_STAT_BUSY, false, 20000, false);
+}
+/*
+ * function to write the bypass register which requires a poll of the
+ * busy bit
+ */
+static void socfpga_gen5_clk_write_bypass(
+	const struct socfpga_clock_manager *clock_mgr, u32 val)
+{
+	writel(val, &clock_mgr->bypass);
+	socfpga_gen5_clk_wait_for_fsm(clock_mgr);
+}
+
+/* function to write the ctrl register which requires a poll of the busy bit */
+static void socfpga_gen5_clk_write_ctrl(
+	const struct socfpga_clock_manager *clock_mgr, u32 val)
+{
+	writel(val, &clock_mgr->ctrl);
+	socfpga_gen5_clk_wait_for_fsm(clock_mgr);
+}
+
+/* function to write a clock register that has phase information */
+static int socfpga_gen5_clk_write_with_phase(
+	const struct socfpga_clock_manager *clock_mgr, u32 value,
+	const void *reg_address, u32 mask)
+{
+	int ret;
+
+	/* poll until phase is zero */
+	ret = wait_for_bit_le32(reg_address, mask, false, 20000, false);
+	if (ret)
+		return ret;
+
+	writel(value, reg_address);
+
+	return wait_for_bit_le32(reg_address, mask, false, 20000, false);
+}
+
+/*
+ * Setup clocks while making no assumptions about previous state of the clocks.
+ *
+ * Start by being paranoid and gate all sw managed clocks
+ * Put all plls in bypass
+ * Put all plls VCO registers back to reset value (bandgap power down).
+ * Put peripheral and main pll src to reset value to avoid glitch.
+ * Delay 5 us.
+ * Deassert bandgap power down and set numerator and denominator
+ * Start 7 us timer.
+ * set internal dividers
+ * Wait for 7 us timer.
+ * Enable plls
+ * Set external dividers while plls are locking
+ * Wait for pll lock
+ * Assert/deassert outreset all.
+ * Take all pll's out of bypass
+ * Clear safe mode
+ * set source main and peripheral clocks
+ * Ungate clocks
+ */
+static int socfpga_gen5_clk_init(struct udevice *dev)
+{
+	unsigned long end;
+	int ret;
+	struct socfpga_gen5_clk_platdata *plat = dev_get_platdata(dev);
+	const struct socfpga_clock_manager *clock_manager_base =
+		(const struct socfpga_clock_manager *)plat->regs;
+	const struct cm_config *cfg = cm_get_default_config();
+
+	/* Start by being paranoid and gate all sw managed clocks */
+
+	/*
+	 * We need to disable nandclk
+	 * and then do another apb access before disabling
+	 * gatting off the rest of the periperal clocks.
+	 */
+	writel(~CLKMGR_PERPLLGRP_EN_NANDCLK_MASK &
+		readl(&clock_manager_base->per_pll.en),
+		&clock_manager_base->per_pll.en);
+
+	/* DO NOT GATE OFF DEBUG CLOCKS & BRIDGE CLOCKS */
+	writel(CLKMGR_MAINPLLGRP_EN_DBGTIMERCLK_MASK |
+		CLKMGR_MAINPLLGRP_EN_DBGTRACECLK_MASK |
+		CLKMGR_MAINPLLGRP_EN_DBGCLK_MASK |
+		CLKMGR_MAINPLLGRP_EN_DBGATCLK_MASK |
+		CLKMGR_MAINPLLGRP_EN_S2FUSER0CLK_MASK |
+		CLKMGR_MAINPLLGRP_EN_L4MPCLK_MASK,
+		&clock_manager_base->main_pll.en);
+
+	writel(0, &clock_manager_base->sdr_pll.en);
+
+	/* now we can gate off the rest of the peripheral clocks */
+	writel(0, &clock_manager_base->per_pll.en);
+
+	/* Put all plls in bypass */
+	socfpga_gen5_clk_write_bypass(clock_manager_base,
+				      CLKMGR_BYPASS_PERPLL |
+				      CLKMGR_BYPASS_SDRPLL |
+				      CLKMGR_BYPASS_MAINPLL);
+
+	/* Put all plls VCO registers back to reset value. */
+	writel(CLKMGR_MAINPLLGRP_VCO_RESET_VALUE &
+	       ~CLKMGR_MAINPLLGRP_VCO_REGEXTSEL_MASK,
+	       &clock_manager_base->main_pll.vco);
+	writel(CLKMGR_PERPLLGRP_VCO_RESET_VALUE &
+	       ~CLKMGR_PERPLLGRP_VCO_REGEXTSEL_MASK,
+	       &clock_manager_base->per_pll.vco);
+	writel(CLKMGR_SDRPLLGRP_VCO_RESET_VALUE &
+	       ~CLKMGR_SDRPLLGRP_VCO_REGEXTSEL_MASK,
+	       &clock_manager_base->sdr_pll.vco);
+
+	/*
+	 * The clocks to the flash devices and the L4_MAIN clocks can
+	 * glitch when coming out of safe mode if their source values
+	 * are different from their reset value.  So the trick it to
+	 * put them back to their reset state, and change input
+	 * after exiting safe mode but before ungating the clocks.
+	 */
+	writel(CLKMGR_PERPLLGRP_SRC_RESET_VALUE,
+	       &clock_manager_base->per_pll.src);
+	writel(CLKMGR_MAINPLLGRP_L4SRC_RESET_VALUE,
+	       &clock_manager_base->main_pll.l4src);
+
+	/* read back for the required 5 us delay. */
+	readl(&clock_manager_base->main_pll.vco);
+	readl(&clock_manager_base->per_pll.vco);
+	readl(&clock_manager_base->sdr_pll.vco);
+
+
+	/*
+	 * We made sure bgpwr down was assert for 5 us. Now deassert BG PWR DN
+	 * with numerator and denominator.
+	 */
+	writel(cfg->main_vco_base, &clock_manager_base->main_pll.vco);
+	writel(cfg->peri_vco_base, &clock_manager_base->per_pll.vco);
+	writel(cfg->sdram_vco_base, &clock_manager_base->sdr_pll.vco);
+
+	/*
+	 * Time starts here. Must wait 7 us from
+	 * BGPWRDN_SET(0) to VCO_ENABLE_SET(1).
+	 */
+	end = timer_get_us() + 7;
+
+	/* main mpu */
+	writel(cfg->mpuclk, &clock_manager_base->main_pll.mpuclk);
+
+	/* altera group mpuclk */
+	writel(cfg->altera_grp_mpuclk, &clock_manager_base->altera.mpuclk);
+
+	/* main main clock */
+	writel(cfg->mainclk, &clock_manager_base->main_pll.mainclk);
+
+	/* main for dbg */
+	writel(cfg->dbgatclk, &clock_manager_base->main_pll.dbgatclk);
+
+	/* main for cfgs2fuser0clk */
+	writel(cfg->cfg2fuser0clk,
+	       &clock_manager_base->main_pll.cfgs2fuser0clk);
+
+	/* Peri emac0 50 MHz default to RMII */
+	writel(cfg->emac0clk, &clock_manager_base->per_pll.emac0clk);
+
+	/* Peri emac1 50 MHz default to RMII */
+	writel(cfg->emac1clk, &clock_manager_base->per_pll.emac1clk);
+
+	/* Peri QSPI */
+	writel(cfg->mainqspiclk, &clock_manager_base->main_pll.mainqspiclk);
+
+	writel(cfg->perqspiclk, &clock_manager_base->per_pll.perqspiclk);
+
+	/* Peri pernandsdmmcclk */
+	writel(cfg->mainnandsdmmcclk,
+	       &clock_manager_base->main_pll.mainnandsdmmcclk);
+
+	writel(cfg->pernandsdmmcclk,
+	       &clock_manager_base->per_pll.pernandsdmmcclk);
+
+	/* Peri perbaseclk */
+	writel(cfg->perbaseclk, &clock_manager_base->per_pll.perbaseclk);
+
+	/* Peri s2fuser1clk */
+	writel(cfg->s2fuser1clk, &clock_manager_base->per_pll.s2fuser1clk);
+
+	/* 7 us must have elapsed before we can enable the VCO */
+	while (timer_get_us() < end)
+		;
+
+	/* Enable vco */
+	/* main pll vco */
+	writel(cfg->main_vco_base | CLKMGR_MAINPLLGRP_VCO_EN,
+	       &clock_manager_base->main_pll.vco);
+
+	/* periferal pll */
+	writel(cfg->peri_vco_base | CLKMGR_MAINPLLGRP_VCO_EN,
+	       &clock_manager_base->per_pll.vco);
+
+	/* sdram pll vco */
+	writel(cfg->sdram_vco_base | CLKMGR_MAINPLLGRP_VCO_EN,
+	       &clock_manager_base->sdr_pll.vco);
+
+	/* L3 MP and L3 SP */
+	writel(cfg->maindiv, &clock_manager_base->main_pll.maindiv);
+
+	writel(cfg->dbgdiv, &clock_manager_base->main_pll.dbgdiv);
+
+	writel(cfg->tracediv, &clock_manager_base->main_pll.tracediv);
+
+	/* L4 MP, L4 SP, can0, and can1 */
+	writel(cfg->perdiv, &clock_manager_base->per_pll.div);
+
+	writel(cfg->gpiodiv, &clock_manager_base->per_pll.gpiodiv);
+
+	socfpga_gen5_clk_wait_for_lock(clock_manager_base, LOCKED_MASK);
+
+	/* write the sdram clock counters before toggling outreset all */
+	writel(cfg->ddrdqsclk & CLKMGR_SDRPLLGRP_DDRDQSCLK_CNT_MASK,
+	       &clock_manager_base->sdr_pll.ddrdqsclk);
+
+	writel(cfg->ddr2xdqsclk & CLKMGR_SDRPLLGRP_DDR2XDQSCLK_CNT_MASK,
+	       &clock_manager_base->sdr_pll.ddr2xdqsclk);
+
+	writel(cfg->ddrdqclk & CLKMGR_SDRPLLGRP_DDRDQCLK_CNT_MASK,
+	       &clock_manager_base->sdr_pll.ddrdqclk);
+
+	writel(cfg->s2fuser2clk & CLKMGR_SDRPLLGRP_S2FUSER2CLK_CNT_MASK,
+	       &clock_manager_base->sdr_pll.s2fuser2clk);
+
+	/*
+	 * after locking, but before taking out of bypass
+	 * assert/deassert outresetall
+	 */
+	u32 mainvco = readl(&clock_manager_base->main_pll.vco);
+
+	/* assert main outresetall */
+	writel(mainvco | CLKMGR_MAINPLLGRP_VCO_OUTRESETALL_MASK,
+	       &clock_manager_base->main_pll.vco);
+
+	u32 periphvco = readl(&clock_manager_base->per_pll.vco);
+
+	/* assert pheriph outresetall */
+	writel(periphvco | CLKMGR_PERPLLGRP_VCO_OUTRESETALL_MASK,
+	       &clock_manager_base->per_pll.vco);
+
+	/* assert sdram outresetall */
+	writel(cfg->sdram_vco_base | CLKMGR_MAINPLLGRP_VCO_EN|
+		CLKMGR_SDRPLLGRP_VCO_OUTRESETALL,
+		&clock_manager_base->sdr_pll.vco);
+
+	/* deassert main outresetall */
+	writel(mainvco & ~CLKMGR_MAINPLLGRP_VCO_OUTRESETALL_MASK,
+	       &clock_manager_base->main_pll.vco);
+
+	/* deassert pheriph outresetall */
+	writel(periphvco & ~CLKMGR_PERPLLGRP_VCO_OUTRESETALL_MASK,
+	       &clock_manager_base->per_pll.vco);
+
+	/* deassert sdram outresetall */
+	writel(cfg->sdram_vco_base | CLKMGR_MAINPLLGRP_VCO_EN,
+	       &clock_manager_base->sdr_pll.vco);
+
+	/*
+	 * now that we've toggled outreset all, all the clocks
+	 * are aligned nicely; so we can change any phase.
+	 */
+	ret = socfpga_gen5_clk_write_with_phase(
+		clock_manager_base, cfg->ddrdqsclk,
+		&clock_manager_base->sdr_pll.ddrdqsclk,
+		CLKMGR_SDRPLLGRP_DDRDQSCLK_PHASE_MASK);
+	if (ret)
+		return ret;
+
+	/* SDRAM DDR2XDQSCLK */
+	ret = socfpga_gen5_clk_write_with_phase(
+		clock_manager_base, cfg->ddr2xdqsclk,
+		&clock_manager_base->sdr_pll.ddr2xdqsclk,
+		CLKMGR_SDRPLLGRP_DDR2XDQSCLK_PHASE_MASK);
+	if (ret)
+		return ret;
+
+	ret = socfpga_gen5_clk_write_with_phase(
+		clock_manager_base, cfg->ddrdqclk,
+		&clock_manager_base->sdr_pll.ddrdqclk,
+		CLKMGR_SDRPLLGRP_DDRDQCLK_PHASE_MASK);
+	if (ret)
+		return ret;
+
+	ret = socfpga_gen5_clk_write_with_phase(
+		clock_manager_base, cfg->s2fuser2clk,
+		&clock_manager_base->sdr_pll.s2fuser2clk,
+		CLKMGR_SDRPLLGRP_S2FUSER2CLK_PHASE_MASK);
+	if (ret)
+		return ret;
+
+	/* Take all three PLLs out of bypass when safe mode is cleared. */
+	socfpga_gen5_clk_write_bypass(clock_manager_base, 0);
+
+	/* clear safe mode */
+	socfpga_gen5_clk_write_ctrl(clock_manager_base,
+				    readl(&clock_manager_base->ctrl) |
+				    CLKMGR_CTRL_SAFEMODE);
+
+	/*
+	 * now that safe mode is clear with clocks gated
+	 * it safe to change the source mux for the flashes the the L4_MAIN
+	 */
+	writel(cfg->persrc, &clock_manager_base->per_pll.src);
+	writel(cfg->l4src, &clock_manager_base->main_pll.l4src);
+
+	/* Now ungate non-hw-managed clocks */
+	writel(~0, &clock_manager_base->main_pll.en);
+	writel(~0, &clock_manager_base->per_pll.en);
+	writel(~0, &clock_manager_base->sdr_pll.en);
+
+	/* Clear the loss of lock bits (write 1 to clear) */
+	writel(CLKMGR_INTER_SDRPLLLOST_MASK | CLKMGR_INTER_PERPLLLOST_MASK |
+	       CLKMGR_INTER_MAINPLLLOST_MASK,
+	       &clock_manager_base->inter);
+	return 0;
+}
+#endif
+
 static int socfpga_gen5_clk_get_upstream(struct clk *clk, struct clk **upclk)
 {
 	struct socfpga_gen5_clk_platdata *plat = dev_get_platdata(clk->dev);
@@ -246,6 +595,18 @@ static int socfpga_gen5_clk_probe(struct udevice *dev)
 
 	clk_get_bulk(dev, &plat->clks);
 
+#ifdef CONFIG_SPL_BUILD
+	/* clock tree init is done only one time, in SPL, before relocation */
+	if (!(gd->flags & GD_FLG_RELOC)) {
+		if (!fdt_node_check_compatible(fdt, offset, "altr,clk-mgr")) {
+			/* assign default clocks */
+			int ret = socfpga_gen5_clk_init(dev);
+			if (ret)
+				return ret;
+		}
+	}
+#endif
+
 	if (!fdt_node_check_compatible(fdt, offset,
 				       "altr,socfpga-pll-clock")) {
 		/* Main PLL has 3 upstream clock */
-- 
2.20.1



More information about the U-Boot mailing list