diff options
-rw-r--r-- | arch/arm/cpu/armv7/socfpga/clock_manager.c | 226 | ||||
-rw-r--r-- | arch/arm/include/asm/arch-socfpga/clock_manager.h | 43 | ||||
-rw-r--r-- | 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..7a6b3b1 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 / (1 << reg); + + return clock; +} + +unsigned int cm_get_mmc_controller_clk_hz(void) +{ + uint32_t reg, clock = 0; + + /* identify the source of MMC clock */ + reg = readl(&clock_manager_base->per_pll.src); + reg = CLKMGR_PERPLLGRP_SRC_SDMMC_GET(reg); + + if (reg == CLKMGR_SDMMC_CLK_SRC_F2S) { + clock = CONFIG_HPS_CLK_F2S_PER_REF_HZ; + } else if (reg == CLKMGR_SDMMC_CLK_SRC_MAIN) { + /* 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 SDMMC clock */ + reg = readl(&clock_manager_base->main_pll.mainnandsdmmcclk); + clock /= (reg + 1); + } else if (reg == CLKMGR_SDMMC_CLK_SRC_PER) { + /* 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 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) +{ + uint32_t reg, clock = 0; + + /* identify the source of QSPI clock */ + reg = readl(&clock_manager_base->per_pll.src); + reg = CLKMGR_PERPLLGRP_SRC_QSPI_GET(reg); + + if (reg == CLKMGR_QSPI_CLK_SRC_F2S) { + clock = CONFIG_HPS_CLK_F2S_PER_REF_HZ; + } else if (reg == CLKMGR_QSPI_CLK_SRC_MAIN) { + /* 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 qspi clock */ + reg = readl(&clock_manager_base->main_pll.mainqspiclk); + clock /= (reg + 1); + } else if (reg == CLKMGR_QSPI_CLK_SRC_PER) { + /* 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 qspi clock */ + reg = readl(&clock_manager_base->per_pll.perqspiclk); + clock /= (reg + 1); + } + + return clock; +} + +static 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", CONFIG_HPS_CLK_OSC1_HZ / 1000); + printf("EOSC2 %8d kHz\n", CONFIG_HPS_CLK_OSC2_HZ / 1000); + printf("F2S_SDR_REF %8d kHz\n", CONFIG_HPS_CLK_F2S_SDR_REF_HZ / 1000); + printf("F2S_PER_REF %8d kHz\n", CONFIG_HPS_CLK_F2S_PER_REF_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); +} + +int set_cpu_clk_info(void) +{ + /* Calculate the clock frequencies required for drivers */ + cm_get_l4_sp_clk_hz(); + cm_get_mmc_controller_clk_hz(); + + gd->bd->bi_arm_freq = cm_get_mpu_clk_hz() / 1000000; + gd->bd->bi_dsp_freq = 0; + gd->bd->bi_ddr_freq = cm_get_sdram_clk_hz() / 1000000; + + return 0; +} + +int do_showclocks(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + cm_print_clock_quick_summary(); + return 0; +} + +U_BOOT_CMD( + clocks, CONFIG_SYS_MAXARGS, 1, do_showclocks, + "display clocks", + "" +); diff --git a/arch/arm/include/asm/arch-socfpga/clock_manager.h b/arch/arm/include/asm/arch-socfpga/clock_manager.h index dea171e..d2a9b48 100644 --- a/arch/arm/include/asm/arch-socfpga/clock_manager.h +++ b/arch/arm/include/asm/arch-socfpga/clock_manager.h @@ -7,6 +7,15 @@ #ifndef _CLOCK_MANAGER_H_ #define _CLOCK_MANAGER_H_ +#ifndef __ASSEMBLER__ +/* 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); +#endif + typedef struct { /* main group */ uint32_t main_vco_base; @@ -89,6 +98,11 @@ struct socfpga_clock_manager_sdr_pll { u32 stat; }; +struct socfpga_clock_manager_altera { + u32 mpuclk; + u32 mainclk; +}; + struct socfpga_clock_manager { u32 ctrl; u32 bypass; @@ -100,7 +114,8 @@ struct socfpga_clock_manager { struct socfpga_clock_manager_main_pll main_pll; struct socfpga_clock_manager_per_pll per_pll; struct socfpga_clock_manager_sdr_pll sdr_pll; - u32 _pad_0xe0_0x200[72]; + struct socfpga_clock_manager_altera altera; + u32 _pad_0xe8_0x200[70]; }; #define CLKMGR_CTRL_SAFEMODE_MASK 0x00000001 @@ -118,8 +133,10 @@ struct socfpga_clock_manager { /* Main PLL */ #define CLKMGR_MAINPLLGRP_VCO_BGPWRDN_SET(x) (((x) << 0) & 0x00000001) +#define CLKMGR_MAINPLLGRP_VCO_DENOM_GET(x) (((x) & 0x003f0000) >> 16) #define CLKMGR_MAINPLLGRP_VCO_DENOM_SET(x) (((x) << 16) & 0x003f0000) #define CLKMGR_MAINPLLGRP_VCO_EN_SET(x) (((x) << 1) & 0x00000002) +#define CLKMGR_MAINPLLGRP_VCO_NUMER_GET(x) (((x) & 0x0000fff8) >> 3) #define CLKMGR_MAINPLLGRP_VCO_NUMER_SET(x) (((x) << 3) & 0x0000fff8) #define CLKMGR_MAINPLLGRP_VCO_OUTRESETALL_MASK 0x01000000 #define CLKMGR_MAINPLLGRP_VCO_PWRDN_SET(x) (((x) << 2) & 0x00000004) @@ -148,7 +165,8 @@ struct socfpga_clock_manager { #define CLKMGR_MAINPLLGRP_MAINDIV_L3MPCLK_SET(x) (((x) << 0) & 0x00000003) #define CLKMGR_MAINPLLGRP_MAINDIV_L3SPCLK_SET(x) (((x) << 2) & 0x0000000c) #define CLKMGR_MAINPLLGRP_MAINDIV_L4MPCLK_SET(x) (((x) << 4) & 0x00000070) -#define CLKMGR_MAINPLLGRP_MAINDIV_L4SPCLK_SET(x) (((x) << 7) & 0x00000380) +#define CLKMGR_MAINPLLGRP_MAINDIV_L4SPCLK_GET(x) (((x) & 0x00000380) >> 7) +#define CLKMGR_MAINPLLGRP_MAINDIV_L4SPCLK_SET(x) (((x) << 7) & 0x00000380) #define CLKMGR_MAINPLLGRP_DBGDIV_DBGATCLK_SET(x) (((x) << 0) & 0x00000003) #define CLKMGR_MAINPLLGRP_DBGDIV_DBGCLK_SET(x) (((x) << 2) & 0x0000000c) @@ -156,16 +174,25 @@ struct socfpga_clock_manager { #define CLKMGR_MAINPLLGRP_TRACEDIV_TRACECLK_SET(x) (((x) << 0) & 0x00000007) #define CLKMGR_MAINPLLGRP_L4SRC_L4MP_SET(x) (((x) << 0) & 0x00000001) +#define CLKMGR_MAINPLLGRP_L4SRC_L4SP_GET(x) (((x) & 0x00000002) >> 1) #define CLKMGR_MAINPLLGRP_L4SRC_L4SP_SET(x) (((x) << 1) & 0x00000002) #define CLKMGR_MAINPLLGRP_L4SRC_RESET_VALUE 0x00000000 +#define CLKMGR_L4_SP_CLK_SRC_MAINPLL 0x0 +#define CLKMGR_L4_SP_CLK_SRC_PERPLL 0x1 /* Per PLL */ +#define CLKMGR_PERPLLGRP_VCO_DENOM_GET(x) (((x) & 0x003f0000) >> 16) #define CLKMGR_PERPLLGRP_VCO_DENOM_SET(x) (((x) << 16) & 0x003f0000) +#define CLKMGR_PERPLLGRP_VCO_NUMER_GET(x) (((x) & 0x0000fff8) >> 3) #define CLKMGR_PERPLLGRP_VCO_NUMER_SET(x) (((x) << 3) & 0x0000fff8) #define CLKMGR_PERPLLGRP_VCO_OUTRESETALL_MASK 0x01000000 #define CLKMGR_PERPLLGRP_VCO_PSRC_SET(x) (((x) << 22) & 0x00c00000) #define CLKMGR_PERPLLGRP_VCO_REGEXTSEL_MASK 0x80000000 #define CLKMGR_PERPLLGRP_VCO_RESET_VALUE 0x8001000d +#define CLKMGR_PERPLLGRP_VCO_SSRC_GET(x) (((x) & 0x00c00000) >> 22) +#define CLKMGR_VCO_SSRC_EOSC1 0x0 +#define CLKMGR_VCO_SSRC_EOSC2 0x1 +#define CLKMGR_VCO_SSRC_F2S 0x2 #define CLKMGR_PERPLLGRP_EMAC0CLK_CNT_SET(x) (((x) << 0) & 0x000001ff) @@ -191,12 +218,22 @@ struct socfpga_clock_manager { #define CLKMGR_PERPLLGRP_GPIODIV_GPIODBCLK_SET(x) (((x) << 0) & 0x00ffffff) #define CLKMGR_PERPLLGRP_SRC_NAND_SET(x) (((x) << 2) & 0x0000000c) +#define CLKMGR_PERPLLGRP_SRC_QSPI_GET(x) (((x) & 0x00000030) >> 4) #define CLKMGR_PERPLLGRP_SRC_QSPI_SET(x) (((x) << 4) & 0x00000030) #define CLKMGR_PERPLLGRP_SRC_RESET_VALUE 0x00000015 +#define CLKMGR_PERPLLGRP_SRC_SDMMC_GET(x) (((x) & 0x00000003) >> 0) #define CLKMGR_PERPLLGRP_SRC_SDMMC_SET(x) (((x) << 0) & 0x00000003) +#define CLKMGR_SDMMC_CLK_SRC_F2S 0x0 +#define CLKMGR_SDMMC_CLK_SRC_MAIN 0x1 +#define CLKMGR_SDMMC_CLK_SRC_PER 0x2 +#define CLKMGR_QSPI_CLK_SRC_F2S 0x0 +#define CLKMGR_QSPI_CLK_SRC_MAIN 0x1 +#define CLKMGR_QSPI_CLK_SRC_PER 0x2 /* SDR PLL */ +#define CLKMGR_SDRPLLGRP_VCO_DENOM_GET(x) (((x) & 0x003f0000) >> 16) #define CLKMGR_SDRPLLGRP_VCO_DENOM_SET(x) (((x) << 16) & 0x003f0000) +#define CLKMGR_SDRPLLGRP_VCO_NUMER_GET(x) (((x) & 0x0000fff8) >> 3) #define CLKMGR_SDRPLLGRP_VCO_NUMER_SET(x) (((x) << 3) & 0x0000fff8) #define CLKMGR_SDRPLLGRP_VCO_OUTRESETALL_SET(x) (((x) << 24) & 0x01000000) #define CLKMGR_SDRPLLGRP_VCO_OUTRESETALL_SET(x) (((x) << 24) & 0x01000000) @@ -204,8 +241,10 @@ struct socfpga_clock_manager { #define CLKMGR_SDRPLLGRP_VCO_OUTRESET_SET(x) (((x) << 25) & 0x7e000000) #define CLKMGR_SDRPLLGRP_VCO_REGEXTSEL_MASK 0x80000000 #define CLKMGR_SDRPLLGRP_VCO_RESET_VALUE 0x8001000d +#define CLKMGR_SDRPLLGRP_VCO_SSRC_GET(x) (((x) & 0x00c00000) >> 22) #define CLKMGR_SDRPLLGRP_VCO_SSRC_SET(x) (((x) << 22) & 0x00c00000) +#define CLKMGR_SDRPLLGRP_DDRDQSCLK_CNT_GET(x) (((x) & 0x000001ff) >> 0) #define CLKMGR_SDRPLLGRP_DDRDQSCLK_CNT_MASK 0x000001ff #define CLKMGR_SDRPLLGRP_DDRDQSCLK_CNT_SET(x) (((x) << 0) & 0x000001ff) #define CLKMGR_SDRPLLGRP_DDRDQSCLK_PHASE_MASK 0x001ffe00 diff --git a/include/configs/socfpga_cyclone5.h b/include/configs/socfpga_cyclone5.h index 39e9368..708309b 100644 --- a/include/configs/socfpga_cyclone5.h +++ b/include/configs/socfpga_cyclone5.h @@ -24,6 +24,7 @@ #define CONFIG_MISC_INIT_R #define CONFIG_SINGLE_BOOTLOADER #define CONFIG_SOCFPGA +#define CONFIG_CLOCKS /* base address for .text section */ #ifdef CONFIG_SOCFPGA_VIRTUAL_TARGET |