summaryrefslogtreecommitdiff
path: root/arch
diff options
context:
space:
mode:
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/cpu/armv7/socfpga/clock_manager.c226
-rw-r--r--arch/arm/include/asm/arch-socfpga/clock_manager.h43
2 files changed, 266 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