[U-Boot] [PATCH 15/35] arm: socfpga: clock: Add code to read clock configuration

Dinh Nguyen dinguyen at opensource.altera.com
Mon Sep 15 22:09:34 CEST 2014


On 09/15/2014 06:06 AM, Marek Vasut wrote:
> From: Pavel Machek <pavel at denx.de>
> 
> Add the entire bulk of code to read out clock configuration from the SoCFPGA
> CPU registers. This is important for MMC, QSPI and UART drivers as otherwise
> they cannot determine the frequency of their upstream clock.
> 
> Signed-off-by: Pavel Machek <pavel at denx.de>
> Signed-off-by: Marek Vasut <marex at denx.de>
> Cc: Chin Liang See <clsee at altera.com>
> Cc: Dinh Nguyen <dinguyen at altera.com>
> Cc: Albert Aribaud <albert.u.boot at aribaud.net>
> Cc: Tom Rini <trini at ti.com>
> Cc: Wolfgang Denk <wd at denx.de>
> Cc: Pavel Machek <pavel at denx.de>
> ---
>  arch/arm/cpu/armv7/socfpga/clock_manager.c        | 226 +++++++++++++++++++++-
>  arch/arm/include/asm/arch-socfpga/clock_manager.h |  43 +++-
>  include/configs/socfpga_cyclone5.h                |   1 +
>  3 files changed, 267 insertions(+), 3 deletions(-)
> 
> diff --git a/arch/arm/cpu/armv7/socfpga/clock_manager.c b/arch/arm/cpu/armv7/socfpga/clock_manager.c
> index d032bbd..07cf74c 100644
> --- a/arch/arm/cpu/armv7/socfpga/clock_manager.c
> +++ b/arch/arm/cpu/armv7/socfpga/clock_manager.c
> @@ -8,8 +8,10 @@
>  #include <asm/io.h>
>  #include <asm/arch/clock_manager.h>
>  
> +DECLARE_GLOBAL_DATA_PTR;
> +
>  static const struct socfpga_clock_manager *clock_manager_base =
> -		(void *)SOCFPGA_CLKMGR_ADDRESS;
> +	(struct socfpga_clock_manager *)SOCFPGA_CLKMGR_ADDRESS;
>  
>  #define CLKMGR_BYPASS_ENABLE	1
>  #define CLKMGR_BYPASS_DISABLE	0
> @@ -358,3 +360,225 @@ void cm_basic_init(const cm_config_t *cfg)
>  	writel(~0, &clock_manager_base->per_pll.en);
>  	writel(~0, &clock_manager_base->sdr_pll.en);
>  }
> +
> +unsigned long cm_get_mpu_clk_hz(void)
> +{
> +	uint32_t reg, clock;
> +
> +	/* get the main VCO clock */
> +	reg = readl(&clock_manager_base->main_pll.vco);
> +	clock = CONFIG_HPS_CLK_OSC1_HZ /
> +		(CLKMGR_MAINPLLGRP_VCO_DENOM_GET(reg) + 1);
> +	clock *= (CLKMGR_MAINPLLGRP_VCO_NUMER_GET(reg) + 1);
> +
> +	/* 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)
> +{
> +	uint32_t reg, clock = 0;
> +
> +	/* identify SDRAM PLL clock source */
> +	reg = readl(&clock_manager_base->sdr_pll.vco);
> +	reg = CLKMGR_SDRPLLGRP_VCO_SSRC_GET(reg);
> +	if (reg == CLKMGR_VCO_SSRC_EOSC1)
> +		clock = CONFIG_HPS_CLK_OSC1_HZ;
> +	else if (reg == CLKMGR_VCO_SSRC_EOSC2)
> +		clock = CONFIG_HPS_CLK_OSC2_HZ;
> +	else if (reg == CLKMGR_VCO_SSRC_F2S)
> +		clock = CONFIG_HPS_CLK_F2S_SDR_REF_HZ;
> +
> +	/* get the SDRAM VCO clock */
> +	reg = readl(&clock_manager_base->sdr_pll.vco);
> +	clock /= (CLKMGR_SDRPLLGRP_VCO_DENOM_GET(reg) + 1);
> +	clock *= (CLKMGR_SDRPLLGRP_VCO_NUMER_GET(reg) + 1);
> +
> +	/* get the SDRAM (DDR_DQS) clock */
> +	reg = readl(&clock_manager_base->sdr_pll.ddrdqsclk);
> +	reg = CLKMGR_SDRPLLGRP_DDRDQSCLK_CNT_GET(reg);
> +	clock /= (reg + 1);
> +
> +	return clock;
> +}
> +
> +unsigned int cm_get_l4_sp_clk_hz(void)
> +{
> +	uint32_t reg, clock = 0;
> +
> +	/* identify the source of L4 SP clock */
> +	reg = readl(&clock_manager_base->main_pll.l4src);
> +	reg = CLKMGR_MAINPLLGRP_L4SRC_L4SP_GET(reg);
> +
> +	if (reg == CLKMGR_L4_SP_CLK_SRC_MAINPLL) {
> +		/* get the main VCO clock */
> +		reg = readl(&clock_manager_base->main_pll.vco);
> +		clock = CONFIG_HPS_CLK_OSC1_HZ /
> +			(CLKMGR_MAINPLLGRP_VCO_DENOM_GET(reg) + 1);
> +		clock *= (CLKMGR_MAINPLLGRP_VCO_NUMER_GET(reg) + 1);
> +
> +		/* 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) {
> +		/* identify PER PLL clock source */
> +		reg = readl(&clock_manager_base->per_pll.vco);
> +		reg = CLKMGR_PERPLLGRP_VCO_SSRC_GET(reg);
> +		if (reg == CLKMGR_VCO_SSRC_EOSC1)
> +			clock = CONFIG_HPS_CLK_OSC1_HZ;
> +		else if (reg == CLKMGR_VCO_SSRC_EOSC2)
> +			clock = CONFIG_HPS_CLK_OSC2_HZ;
> +		else if (reg == CLKMGR_VCO_SSRC_F2S)
> +			clock = CONFIG_HPS_CLK_F2S_PER_REF_HZ;
> +
> +		/* get the PER VCO clock */
> +		reg = readl(&clock_manager_base->per_pll.vco);
> +		clock /= (CLKMGR_PERPLLGRP_VCO_DENOM_GET(reg) + 1);
> +		clock *= (CLKMGR_PERPLLGRP_VCO_NUMER_GET(reg) + 1);
> +
> +		/* 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 = CLKMGR_MAINPLLGRP_MAINDIV_L4SPCLK_GET(reg);
> +	clock = clock / (reg + 1);

This is not a +1. The l4 mp clock divider is structured like this:

0x0 = divide by 1
0x1 = divide by 2
0x2 = divide by 4
0x3 = divide by 8
0x4 = divide by 16

So it should be:
clock = clock / (1 << reg);

Dinh


More information about the U-Boot mailing list