From c9857ad52a427fa793cd8c68afb4865916fa4316 Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Thu, 3 Jul 2014 15:39:13 +0200 Subject: [PATCH] vf6xx: calculate core clocks Extend the clock controller module with a function to calculate core clocks from the current registers settings. On Vybrid, we assume that the core clocks are setup by the main operating system running on the Cortex-A5. Nevertheless we need to know their actual values in order to calculate other clocks or baud rates. Verified on a Colibri VF61, which calculates following values: ccm_core_clk: 500210526 ccm_platform_bus_clk: 166736842 ccm_ipg_bus_clk: 83368421 --- include/libopencm3/vf6xx/anadig.h | 224 +++++++++++++++++++++++++++ include/libopencm3/vf6xx/ccm.h | 44 ++++-- include/libopencm3/vf6xx/memorymap.h | 2 + lib/vf6xx/ccm.c | 135 ++++++++++++++++ 4 files changed, 394 insertions(+), 11 deletions(-) create mode 100644 include/libopencm3/vf6xx/anadig.h diff --git a/include/libopencm3/vf6xx/anadig.h b/include/libopencm3/vf6xx/anadig.h new file mode 100644 index 0000000000..594da960cf --- /dev/null +++ b/include/libopencm3/vf6xx/anadig.h @@ -0,0 +1,224 @@ +/** @defgroup anadig_defines ANADIG Defines + * + * @brief Defined Constants and Types for the VF6xx Analog components + * control digital interface + * + * @ingroup VF6xx_defines + * + * @version 1.0.0 + * + * @author @htmlonly © @endhtmlonly 2014 + * Stefan Agner + * + * @date 01 July 2014 + * + * LGPL License Terms @ref lgpl_license + * */ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2014 Stefan Agner + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#ifndef LIBOPENCM3_ANADIG_H +#define LIBOPENCM3_ANADIG_H + +#include +#include + +/* --- ANADIG registers ---------------------------------------------------- */ + +#define ANADIG_PLL3_CTRL MMIO32(ANADIG_BASE + 0x010) +#define ANADIG_PLL7_CTRL MMIO32(ANADIG_BASE + 0x020) +#define ANADIG_PLL2_CTRL MMIO32(ANADIG_BASE + 0x030) +#define ANADIG_PLL2_SS MMIO32(ANADIG_BASE + 0x040) +#define ANADIG_PLL2_NUM MMIO32(ANADIG_BASE + 0x050) +#define ANADIG_PLL2_DENOM MMIO32(ANADIG_BASE + 0x060) +#define ANADIG_PLL4_CTRL MMIO32(ANADIG_BASE + 0x070) +#define ANADIG_PLL4_NUM MMIO32(ANADIG_BASE + 0x080) +#define ANADIG_PLL4_DENOM MMIO32(ANADIG_BASE + 0x090) +#define ANADIG_PLL6_CTRL MMIO32(ANADIG_BASE + 0x0A0) +#define ANADIG_PLL6_NUM MMIO32(ANADIG_BASE + 0x0B0) +#define ANADIG_PLL6_DENOM MMIO32(ANADIG_BASE + 0x0C0) +#define ANADIG_PLL5_CTRL MMIO32(ANADIG_BASE + 0x0E0) +#define ANADIG_PLL3_PFD MMIO32(ANADIG_BASE + 0x0F0) +#define ANADIG_PLL2_PFD MMIO32(ANADIG_BASE + 0x100) +#define ANADIG_REG_1P1 MMIO32(ANADIG_BASE + 0x110) +#define ANADIG_REG_3P0 MMIO32(ANADIG_BASE + 0x120) +#define ANADIG_REG_2P5 MMIO32(ANADIG_BASE + 0x130) +#define ANADIG_ANA_MISC0 MMIO32(ANADIG_BASE + 0x150) +#define ANADIG_ANA_MISC1 MMIO32(ANADIG_BASE + 0x160) +#define ANADIG_ANADIG_DIGPROG MMIO32(ANADIG_BASE + 0x260) +#define ANADIG_PLL1_CTRL MMIO32(ANADIG_BASE + 0x270) +#define ANADIG_PLL1_SS MMIO32(ANADIG_BASE + 0x280) +#define ANADIG_PLL1_NUM MMIO32(ANADIG_BASE + 0x290) +#define ANADIG_PLL1_DENOM MMIO32(ANADIG_BASE + 0x2A0) +#define ANADIG_PLL1_PFD MMIO32(ANADIG_BASE + 0x2B0) +#define ANADIG_PLL_LOCK MMIO32(ANADIG_BASE + 0x2C0) + +/* --- ANADIG values -....-------------------------------------------------- */ + +/* ANADIG_PLL3_CTRL: PLL3 Control Register (480MHz PLL of USB0) */ +#define ANADIG_PLL3_CTRL_LOCK (1 << 31) +#define ANADIG_PLL3_CTRL_BYPASS (1 << 16) +#define ANADIG_PLL3_CTRL_BYPASS_CLK_SRC (1 << 14) +#define ANADIG_PLL3_CTRL_ENABLE (1 << 13) +#define ANADIG_PLL3_CTRL_POWER (1 << 12) +#define ANADIG_PLL3_CTRL_EN_USB_CLKS (1 << 6) +#define ANADIG_PLL3_CTRL_DIV_SELECT (1 << 1) + +/* ANADIG_PLL7_CTRL: PLL7 Control Register (480MHz PLL of USB1) */ +#define ANADIG_PLL7_CTRL_LOCK (1 << 31) +#define ANADIG_PLL7_CTRL_BYPASS (1 << 16) +#define ANADIG_PLL7_CTRL_BYPASS_CLK_SRC (1 << 14) +#define ANADIG_PLL7_CTRL_ENABLE (1 << 13) +#define ANADIG_PLL7_CTRL_POWER (1 << 12) +#define ANADIG_PLL7_CTRL_EN_USB_CLKS (1 << 6) +#define ANADIG_PLL7_CTRL_DIV_SELECT (1 << 1) + +/* ANADIG_PLL2_CTRL: PLL2 Control Register (528MHz PLL) */ +#define ANADIG_PLL2_CTRL_LOCK (1 << 31) +#define ANADIG_PLL2_CTRL_PFD_OFFSET_EN (1 << 18) +#define ANADIG_PLL2_CTRL_DITHER_ENABLE (1 << 17) +#define ANADIG_PLL2_CTRL_BYPASS (1 << 16) +#define ANADIG_PLL2_CTRL_BYPASS_CLK_SRC (1 << 14) +#define ANADIG_PLL2_CTRL_ENABLE (1 << 13) +#define ANADIG_PLL2_CTRL_POWERDOWN (1 << 12) +#define ANADIG_PLL2_CTRL_DIV_SELECT (1 << 1) + +/* ANADIG_PLL2_SS: PLL2 Spread Spectrum definition register */ +#define ANADIG_PLL2_SS_STOP_MASK (0xffff << 16) +#define ANADIG_PLL2_SS_ENABLE (1 << 15) +#define ANADIG_PLL2_SS_STEP_MASK 0x8fff + +/* ANADIG_PLL2_NUM: PLL2 Numerator definition register */ +#define ANADIG_PLL2_NUM_MFN_MASK 0x3fffffff + +/* ANADIG_PLL2_DENOM: PLL2 Denominator definition register */ +#define ANADIG_PLL2_DENOM_MFN_MASK 0x3fffffff + +/* ANADIG_PLL4_CTRL: PLL4 Control Register (audio PLL) */ +#define ANADIG_PLL4_CTRL_LOCK (1 << 31) +#define ANADIG_PLL4_CTRL_PFD_OFFSET_EN (1 << 18) +#define ANADIG_PLL4_CTRL_DITHER_ENABLE (1 << 17) +#define ANADIG_PLL4_CTRL_BYPASS (1 << 16) +#define ANADIG_PLL4_CTRL_BYPASS_CLK_SRC (1 << 14) +#define ANADIG_PLL4_CTRL_ENABLE (1 << 13) +#define ANADIG_PLL4_CTRL_POWERDOWN (1 << 12) +#define ANADIG_PLL4_CTRL_DIV_SELECT_MASK (0x7f) + +/* ANADIG_PLL4_NUM: PLL4 Numerator definition register */ +#define ANADIG_PLL4_NUM_MFN_MASK 0x3fffffff + +/* ANADIG_PLL4_DENOM: PLL4 Denominator definition register */ +#define ANADIG_PLL4_DENOM_MFN_MASK 0x3fffffff + +/* ANADIG_PLL6_CTRL: PLL6 Control Register (video PLL) */ +#define ANADIG_PLL6_CTRL_LOCK (1 << 31) +#define ANADIG_PLL6_CTRL_PFD_OFFSET_EN (1 << 18) +#define ANADIG_PLL6_CTRL_DITHER_ENABLE (1 << 17) +#define ANADIG_PLL6_CTRL_BYPASS (1 << 16) +#define ANADIG_PLL6_CTRL_BYPASS_CLK_SRC (1 << 14) +#define ANADIG_PLL6_CTRL_ENABLE (1 << 13) +#define ANADIG_PLL6_CTRL_POWERDOWN (1 << 12) +#define ANADIG_PLL6_CTRL_DIV_SELECT_MASK (0x7f) + +/* ANADIG_PLL6_NUM: PLL6 Numerator definition register */ +#define ANADIG_PLL6_NUM_MFN_MASK 0x3fffffff + +/* ANADIG_PLL6_DENOM: PLL6 Denominator definition register */ +#define ANADIG_PLL6_DENOM_MFN_MASK 0x3fffffff + +/* ANADIG_PLL5_CTRL: PLL5 Control Register (video PLL) */ +#define ANADIG_PLL5_CTRL_LOCK (1 << 31) +#define ANADIG_PLL5_CTRL_PFD_OFFSET_EN (1 << 18) +#define ANADIG_PLL5_CTRL_DITHER_ENABLE (1 << 17) +#define ANADIG_PLL5_CTRL_BYPASS (1 << 16) +#define ANADIG_PLL5_CTRL_BYPASS_CLK_SRC (1 << 14) +#define ANADIG_PLL5_CTRL_ENABLE (1 << 13) +#define ANADIG_PLL5_CTRL_POWERDOWN (1 << 12) +#define ANADIG_PLL5_CTRL_DIV_SELECT_MASK (0x3) + +/* ANADIG_PLL_PFD: PLL1/PLL2/PLL3 PFD Clocks */ +#define ANADIG_PLL_PFD4_CLKGATE (1 << 31) +#define ANADIG_PLL_PFD4_STABLE (1 << 30) +#define ANADIG_PLL_PFD4_FRAC_SHIFT 24 +#define ANADIG_PLL_PFD4_FRAC_MASK (0x3f << 24) +#define ANADIG_PLL_PFD3_CLKGATE (1 << 23) +#define ANADIG_PLL_PFD3_STABLE (1 << 22) +#define ANADIG_PLL_PFD3_FRAC_SHIFT 16 +#define ANADIG_PLL_PFD3_FRAC_MASK (0x3f << 16) +#define ANADIG_PLL_PFD2_CLKGATE (1 << 15) +#define ANADIG_PLL_PFD2_STABLE (1 << 14) +#define ANADIG_PLL_PFD2_FRAC_SHIFT 8 +#define ANADIG_PLL_PFD2_FRAC_MASK (0x3f << 8) +#define ANADIG_PLL_PFD1_CLKGATE (1 << 7) +#define ANADIG_PLL_PFD1_STABLE (1 << 6) +#define ANADIG_PLL_PFD1_FRAC_SHIFT 0 +#define ANADIG_PLL_PFD1_FRAC_MASK (0x3f << 0) + +/* AANADIG_ANA_MISC0: miscellaneous analog blocks */ +#define ANADIG_ANA_MISC0_OSC_XTALOK_EN (1 << 17) +#define ANADIG_ANA_MISC0_OSC_XTALOK (1 << 16) +#define ANADIG_ANA_MISC0_CLK_24M_IRC_XTAL_SEL (1 << 13) +#define ANADIG_ANA_MISC0_STOP_MODE_CONFIG (1 << 12) +#define ANADIG_ANA_MISC0_REFTOP_VBGUP (1 << 7) +#define ANADIG_ANA_MISC0_REFTOP_SELBIASOFF (1 << 3) +#define ANADIG_ANA_MISC0_REFTOP_LOWPOWER (1 << 2) +#define ANADIG_ANA_MISC0_REFTOP_PWDVBGUP (1 << 1) +#define ANADIG_ANA_MISC0_REFTOP_PWD (1 << 0) + +/* AANADIG_ANA_MISC0: miscellaneous analog blocks */ +#define ANADIG_ANA_MISC1_IRQ_ANA_BO (1 << 30) +#define ANADIG_ANA_MISC1_IRQ_TEMPSENSE (1 << 29) +#define ANADIG_ANA_MISC1_LVDSCLK1_IBEN (1 << 12) +#define ANADIG_ANA_MISC1_LVDSCLK1_OBEN (1 << 10) + +/* AANADIG_ANA_DIGPROG: Digital Program register */ +#define ANADIG_ANADIG_DIGPROG_MAJOR_MASK (0xffff << 8) +#define ANADIG_ANADIG_DIGPROG_MINOR_MASK (0xff << 0) + +/* ANADIG_PLL1_CTRL: PLL1 Control Register (video PLL) */ +#define ANADIG_PLL1_CTRL_LOCK (1 << 31) +#define ANADIG_PLL1_CTRL_PFD_OFFSET_EN (1 << 18) +#define ANADIG_PLL1_CTRL_DITHER_ENABLE (1 << 17) +#define ANADIG_PLL1_CTRL_BYPASS (1 << 16) +#define ANADIG_PLL1_CTRL_BYPASS_CLK_SRC (1 << 14) +#define ANADIG_PLL1_CTRL_ENABLE (1 << 13) +#define ANADIG_PLL1_CTRL_POWERDOWN (1 << 12) +#define ANADIG_PLL1_CTRL_DIV_SELECT (1 << 1) + +/* ANADIG_PLL1_SS: PLL1 Spread Spectrum definition register */ +#define ANADIG_PLL1_SS_STOP_MASK (0xffff << 16) +#define ANADIG_PLL1_SS_ENABLE (1 << 15) +#define ANADIG_PLL1_SS_STEP_MASK 0x8fff + +/* ANADIG_PLL1_NUM: PLL1 Numerator definition register */ +#define ANADIG_PLL1_NUM_MFN_MASK 0x3fffffff + +/* ANADIG_PLL1_DENOM: PLL1 Denominator definition register */ +#define ANADIG_PLL1_DENOM_MFN_MASK 0x3fffffff + +/* ANADIG_PLL_LOCK: PLL Lock Register */ +#define ANADIG_PLL_LOCK_PLL1 (1 << 6) +#define ANADIG_PLL_LOCK_PLL2 (1 << 5) +#define ANADIG_PLL_LOCK_PLL4 (1 << 4) +#define ANADIG_PLL_LOCK_PLL6 (1 << 3) +#define ANADIG_PLL_LOCK_PLL5 (1 << 2) +#define ANADIG_PLL_LOCK_PLL3 (1 << 1) +#define ANADIG_PLL_LOCK_PLL7 (1 << 0) + +#endif diff --git a/include/libopencm3/vf6xx/ccm.h b/include/libopencm3/vf6xx/ccm.h index 9451deea47..5793beeb69 100644 --- a/include/libopencm3/vf6xx/ccm.h +++ b/include/libopencm3/vf6xx/ccm.h @@ -81,19 +81,17 @@ #define CCM_CCSR_DAP_EN (1 << 24) +/* PLL1/PLL2 PFD SEL definition */ #define CCM_CCSR_PLL2_PFD_CLK_SEL_SHIFT 19 -#define CCM_CCSR_PLL2_PFD_CLK_SEL_MAIN 0x0 -#define CCM_CCSR_PLL2_PFD_CLK_SEL_PFD1 0x1 -#define CCM_CCSR_PLL2_PFD_CLK_SEL_PFD2 0x2 -#define CCM_CCSR_PLL2_PFD_CLK_SEL_PFD3 0x3 -#define CCM_CCSR_PLL2_PFD_CLK_SEL_PFD4 0x4 - +#define CCM_CCSR_PLL2_PFD_CLK_SEL_MASK (0x7 << 19) #define CCM_CCSR_PLL1_PFD_CLK_SEL_SHIFT 16 -#define CCM_CCSR_PLL1_PFD_CLK_SEL_MAIN 0x0 -#define CCM_CCSR_PLL1_PFD_CLK_SEL_PFD1 0x1 -#define CCM_CCSR_PLL1_PFD_CLK_SEL_PFD2 0x2 -#define CCM_CCSR_PLL1_PFD_CLK_SEL_PFD3 0x3 -#define CCM_CCSR_PLL1_PFD_CLK_SEL_PFD4 0x4 +#define CCM_CCSR_PLL1_PFD_CLK_SEL_MASK (0x7 << 16) + +#define CCM_CCSR_PLL_PFD_CLK_SEL_MAIN 0x0 +#define CCM_CCSR_PLL_PFD_CLK_SEL_PFD1 0x1 +#define CCM_CCSR_PLL_PFD_CLK_SEL_PFD2 0x2 +#define CCM_CCSR_PLL_PFD_CLK_SEL_PFD3 0x3 +#define CCM_CCSR_PLL_PFD_CLK_SEL_PFD4 0x4 #define CCM_CCSR_PLL2_PFDN4_EN (1 << 15) #define CCM_CCSR_PLL2_PFDN3_EN (1 << 14) @@ -110,6 +108,7 @@ #define CCM_CCSR_SLOW_CLK_SEL (1 << 5) #define CCM_CCSR_SYS_CLK_SEL_SHIFT 0 +#define CCM_CCSR_SYS_CLK_SEL_MASK 0x7 #define CCM_CCSR_SYS_CLK_SEL_FAST 0x0 #define CCM_CCSR_SYS_CLK_SEL_SLOW 0x1 #define CCM_CCSR_SYS_CLK_SEL_PLL2_PFD 0x2 @@ -117,7 +116,28 @@ #define CCM_CCSR_SYS_CLK_SEL_PLL1_PFD 0x4 #define CCM_CCSR_SYS_CLK_SEL_PLL3 0x5 +/* CACRR: ARM Clock Root Register */ +#define CCM_CACRR_FLEX_CLK_DIV_SHIFT 22 +#define CCM_CACRR_FLEX_CLK_DIV_MASK (0x7 << 22) +#define CCM_CACRR_PLL6_CLK_DIV (1 << 21) +#define CCM_CACRR_PLL3_CLK_DIV (1 << 20) +#define CCM_CACRR_PLL1_PFD_CLK_DIV_SHIFT 16 +#define CCM_CACRR_PLL1_PFD_CLK_DIV_MASK (0x3 << 16) +#define CCM_CACRR_IPG_CLK_DIV_SHIFT 11 +#define CCM_CACRR_IPG_CLK_DIV_MASK (0x3 << 11) +#define CCM_CACRR_PLL4_CLK_DIV_SHIFT 6 +#define CCM_CACRR_PLL4_CLK_DIV_MASK (0x7 << 6) +#define CCM_CACRR_BUS_CLK_DIV_SHIFT 3 +#define CCM_CACRR_BUS_CLK_DIV_MASK (0x7 << 3) +#define CCM_CACRR_ARM_CLK_DIV_SHIFT 0 +#define CCM_CACRR_ARM_CLK_DIV_MASK (0x7 << 0) + /* --- Variable definitions ------------------------------------------------ */ + +extern uint32_t ccm_core_clk; +extern uint32_t ccm_platform_bus_clk; +extern uint32_t ccm_ipg_bus_clk; + enum ccm_clock_gate { /* AIPS0 */ CG0_FLEXCAN0 = 0, @@ -323,6 +343,8 @@ enum ccm_clock_gate { BEGIN_DECLS void ccm_clock_gate_enable(enum ccm_clock_gate gr); +void ccm_clock_gate_disable(enum ccm_clock_gate gr); +void ccm_calculate_clocks(void); END_DECLS diff --git a/include/libopencm3/vf6xx/memorymap.h b/include/libopencm3/vf6xx/memorymap.h index 830346a046..eeed63ff9d 100644 --- a/include/libopencm3/vf6xx/memorymap.h +++ b/include/libopencm3/vf6xx/memorymap.h @@ -44,6 +44,8 @@ #define SPI0_BASE (PERIPH_BASE_AIPS0 + 0x2C000) #define SPI1_BASE (PERIPH_BASE_AIPS0 + 0x2D000) +#define ANADIG_BASE (PERIPH_BASE_AIPS0 + 0x50000) + #define CCM_BASE (PERIPH_BASE_AIPS0 + 0x6B000) /* AIPS1 */ diff --git a/lib/vf6xx/ccm.c b/lib/vf6xx/ccm.c index cced3137cc..8468d6d8a7 100644 --- a/lib/vf6xx/ccm.c +++ b/lib/vf6xx/ccm.c @@ -37,8 +37,25 @@ #include #include +#include /**@{*/ +static const uint32_t pll1_main_clk = 528000000; +static const uint32_t pll2_main_clk = 528000000; +static const uint32_t pll3_main_clk = 480000000; + +/* ARM Cortex-A5 clock, core clock */ +uint32_t ccm_core_clk = 0; + +/* Platform bus clock and Cortex-M4 core clock */ +uint32_t ccm_platform_bus_clk = 0; + +/* IPS bus clock */ +uint32_t ccm_ipg_bus_clk = 0; + + +uint32_t ccm_get_pll_pfd(uint32_t pfd_sel, uint32_t pll_pfd, uint32_t pll_clk); + /*---------------------------------------------------------------------------*/ /** @brief Enable clock of given device @@ -66,4 +83,122 @@ void ccm_clock_gate_disable(enum ccm_clock_gate gr) uint32_t gr_mask = 0x3 << ((gr % 16) * 2); CCM_CCGR(offset * 4) &= ~gr_mask; } + +/*---------------------------------------------------------------------------*/ +/** @brief Calculate PFD clock + +This function calculates the PFD clock for PLL1/2 or 3. All those PLLs +have the same PFD clock muxing/calculating logic, hence we can use one +function for all of them + +@param[in] pfd_sel uint32_t. The PFD selection (muxing) value +@param[in] pll_pfd uint32_t. The ANADIG PFD register containing the fractions +for all possible PFDs +@param[in] pll_clk uint32_t. PLLs main clock (which the PFDs are derived from) +*/ + +uint32_t ccm_get_pll_pfd(uint32_t pfd_sel, uint32_t pll_pfd, uint32_t pll_clk) +{ + uint64_t pll_pfd_clk; + uint32_t pll_pfd_frac = pll_pfd; + + switch(pfd_sel) + { + case CCM_CCSR_PLL_PFD_CLK_SEL_MAIN: + return pll_clk; + case CCM_CCSR_PLL_PFD_CLK_SEL_PFD1: + pll_pfd_frac &= ANADIG_PLL_PFD1_FRAC_MASK; + pll_pfd_frac >>= ANADIG_PLL_PFD1_FRAC_SHIFT; + break; + case CCM_CCSR_PLL_PFD_CLK_SEL_PFD2: + pll_pfd_frac &= ANADIG_PLL_PFD2_FRAC_MASK; + pll_pfd_frac >>= ANADIG_PLL_PFD2_FRAC_SHIFT; + break; + case CCM_CCSR_PLL_PFD_CLK_SEL_PFD3: + pll_pfd_frac &= ANADIG_PLL_PFD3_FRAC_MASK; + pll_pfd_frac >>= ANADIG_PLL_PFD3_FRAC_SHIFT; + break; + case CCM_CCSR_PLL_PFD_CLK_SEL_PFD4: + pll_pfd_frac &= ANADIG_PLL_PFD4_FRAC_MASK; + pll_pfd_frac >>= ANADIG_PLL_PFD4_FRAC_SHIFT; + break; + } + + /* Calculate using to PLL PFD fraction */ + pll_pfd_clk = pll_clk; + pll_pfd_clk *= 18; + pll_pfd_clk /= pll_pfd_frac; + + return (uint32_t)pll_pfd_clk; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Calculate clocks + +This function calculates the root clocks from the registers. On Vybrid, we +assume that the clocks/device is setup by the main operating system running +on the Cortex-A5 (for instance Linux). However, in order to calculate clocks +for peripherals its important to know the current value of those clocks. + +This are mainly the @ref ccm_core_clk which the Cortex-A5 is running with +and lots of other clocks derive from. +The @ref ccm_platform_bus_clk is the clock which the Cortex-M4 is running +with. +And the @ref ccm_ipg_bus_clk is the clock most peripherals run with. + +*/ + +void ccm_calculate_clocks() +{ + uint32_t ccsr = CCM_CCSR; + uint32_t cacrr = CCM_CACRR; + uint32_t arm_clk_div = (cacrr & CCM_CACRR_ARM_CLK_DIV_MASK) + 1; + uint32_t bus_clk_div = cacrr & CCM_CACRR_BUS_CLK_DIV_MASK; + uint32_t ipg_clk_div = cacrr & CCM_CACRR_IPG_CLK_DIV_MASK; + uint32_t pll_pfd_sel; + + bus_clk_div >>= CCM_CACRR_BUS_CLK_DIV_SHIFT; + bus_clk_div += 1; + + ipg_clk_div >>= CCM_CACRR_IPG_CLK_DIV_SHIFT; + ipg_clk_div += 1; + + /* Get Cortex-A5 core clock from system clock selection */ + switch(ccsr & CCM_CCSR_SYS_CLK_SEL_MASK) + { + case CCM_CCSR_SYS_CLK_SEL_FAST: + ccm_core_clk = 24000000; + break; + case CCM_CCSR_SYS_CLK_SEL_SLOW: + ccm_core_clk = 32000; + break; + case CCM_CCSR_SYS_CLK_SEL_PLL2_PFD: + pll_pfd_sel = ccsr & CCM_CCSR_PLL2_PFD_CLK_SEL_MASK; + pll_pfd_sel >>= CCM_CCSR_PLL2_PFD_CLK_SEL_SHIFT; + + ccm_core_clk = ccm_get_pll_pfd(pll_pfd_sel, ANADIG_PLL2_PFD, + pll2_main_clk); + break; + case CCM_CCSR_SYS_CLK_SEL_PLL2: + ccm_core_clk = pll2_main_clk; + break; + case CCM_CCSR_SYS_CLK_SEL_PLL1_PFD: + pll_pfd_sel = ccsr & CCM_CCSR_PLL1_PFD_CLK_SEL_MASK; + pll_pfd_sel >>= CCM_CCSR_PLL1_PFD_CLK_SEL_SHIFT; + + ccm_core_clk = ccm_get_pll_pfd(pll_pfd_sel, ANADIG_PLL1_PFD, + pll1_main_clk); + break; + case CCM_CCSR_SYS_CLK_SEL_PLL3: + ccm_core_clk = pll3_main_clk; + break; + } + + ccm_core_clk /= arm_clk_div; + ccm_platform_bus_clk = ccm_core_clk / bus_clk_div; + ccm_ipg_bus_clk = ccm_platform_bus_clk / ipg_clk_div; + + return; +} + /**@}*/