From mboxrd@z Thu Jan 1 00:00:00 1970 From: Dinh Nguyen Date: Mon, 15 Sep 2014 15:09:34 -0500 Subject: [U-Boot] [PATCH 15/35] arm: socfpga: clock: Add code to read clock configuration In-Reply-To: <1410779188-6880-16-git-send-email-marex@denx.de> References: <1410779188-6880-1-git-send-email-marex@denx.de> <1410779188-6880-16-git-send-email-marex@denx.de> Message-ID: <5417477E.70005@opensource.altera.com> List-Id: MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit To: u-boot@lists.denx.de On 09/15/2014 06:06 AM, Marek Vasut wrote: > From: Pavel Machek > > 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 > Signed-off-by: Marek Vasut > Cc: Chin Liang See > Cc: Dinh Nguyen > Cc: Albert Aribaud > Cc: Tom Rini > Cc: Wolfgang Denk > Cc: Pavel Machek > --- > 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 > #include > > +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