libopencm3
A free/libre/open-source firmware library for various ARM Cortex-M3 microcontrollers.
ccm.c
Go to the documentation of this file.
1/** @defgroup ccm_file CCM
2 *
3 * @ingroup VF6xx
4 *
5 * @section vf6xx_ccm_api_ex Clock Controller Module API.
6 *
7 * @brief <b>VF6xx Clock Controller Module</b>
8 *
9 * @author @htmlonly &copy; @endhtmlonly 2014 Stefan Agner <stefan@agner.ch>
10 *
11 * @date 30 Jun 2014
12 *
13 * This library supports the Clock Controller Module in the VF6xx SoCs
14 * by Freescale.
15 *
16 * LGPL License Terms @ref lgpl_license
17 */
18
19/*
20 * This file is part of the libopencm3 project.
21 *
22 * Copyright (C) 2014 Stefan Agner <stefan@agner.ch>
23 *
24 * This library is free software: you can redistribute it and/or modify
25 * it under the terms of the GNU Lesser General Public License as published by
26 * the Free Software Foundation, either version 3 of the License, or
27 * (at your option) any later version.
28 *
29 * This library is distributed in the hope that it will be useful,
30 * but WITHOUT ANY WARRANTY; without even the implied warranty of
31 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
32 * GNU Lesser General Public License for more details.
33 *
34 * You should have received a copy of the GNU Lesser General Public License
35 * along with this library. If not, see <http://www.gnu.org/licenses/>.
36 */
37
41
42/**@{*/
43static const uint32_t pll1_main_clk = 528000000;
44static const uint32_t pll2_main_clk = 528000000;
45static const uint32_t pll3_main_clk = 480000000;
46
47/* ARM Cortex-A5 clock, core clock */
48uint32_t ccm_core_clk;
49
50/* Platform bus clock and Cortex-M4 core clock */
52
53/* IPS bus clock */
55
56
57uint32_t ccm_get_pll_pfd(uint32_t pfd_sel, uint32_t pll_pfd, uint32_t pll_clk);
58
59
60/*---------------------------------------------------------------------------*/
61/** @brief Enable clock of given device
62
63This enables (gates) the clock for the given device.
64@param[in] gr enum ccm_clock_gate. Device
65*/
67{
68 uint32_t offset = (uint32_t)gr / 16;
69 uint32_t gr_mask = 0x3 << ((gr % 16) * 2);
70 CCM_CCGR(offset * 4) |= gr_mask;
71}
72
73/*---------------------------------------------------------------------------*/
74/** @brief Disable clock of given device
75
76This disables (ungates) the clock for the given device.
77@param[in] gr enum ccm_clock_gate. Device
78*/
79
81{
82 uint32_t offset = (uint32_t)gr / 16;
83 uint32_t gr_mask = 0x3 << ((gr % 16) * 2);
84 CCM_CCGR(offset * 4) &= ~gr_mask;
85}
86
87/*---------------------------------------------------------------------------*/
88/** @brief Calculate PFD clock
89
90This function calculates the PFD clock for PLL1/2 or 3. All those PLLs
91have the same PFD clock muxing/calculating logic, hence we can use one
92function for all of them
93
94@param[in] pfd_sel uint32_t. The PFD selection (muxing) value
95@param[in] pll_pfd uint32_t. The ANADIG PFD register containing the fractions
96for all possible PFDs
97@param[in] pll_clk uint32_t. PLLs main clock (which the PFDs are derived from)
98*/
99
100uint32_t ccm_get_pll_pfd(uint32_t pfd_sel, uint32_t pll_pfd, uint32_t pll_clk)
101{
102 uint64_t pll_pfd_clk;
103 uint32_t pll_pfd_frac = pll_pfd;
104
105 switch (pfd_sel) {
107 return pll_clk;
109 pll_pfd_frac &= ANADIG_PLL_PFD1_FRAC_MASK;
110 pll_pfd_frac >>= ANADIG_PLL_PFD1_FRAC_SHIFT;
111 break;
113 pll_pfd_frac &= ANADIG_PLL_PFD2_FRAC_MASK;
114 pll_pfd_frac >>= ANADIG_PLL_PFD2_FRAC_SHIFT;
115 break;
117 pll_pfd_frac &= ANADIG_PLL_PFD3_FRAC_MASK;
118 pll_pfd_frac >>= ANADIG_PLL_PFD3_FRAC_SHIFT;
119 break;
121 pll_pfd_frac &= ANADIG_PLL_PFD4_FRAC_MASK;
122 pll_pfd_frac >>= ANADIG_PLL_PFD4_FRAC_SHIFT;
123 break;
124 }
125
126 /* Calculate using to PLL PFD fraction */
127 pll_pfd_clk = pll_clk;
128 pll_pfd_clk *= 18;
129 pll_pfd_clk /= pll_pfd_frac;
130
131 return (uint32_t)pll_pfd_clk;
132}
133
134/*---------------------------------------------------------------------------*/
135/** @brief Calculate clocks
136
137This function calculates the root clocks from the registers. On Vybrid, we
138assume that the clocks/device is setup by the main operating system running
139on the Cortex-A5 (for instance Linux). However, in order to calculate clocks
140for peripherals its important to know the current value of those clocks.
141
142This are mainly the @ref ccm_core_clk which the Cortex-A5 is running with
143and lots of other clocks derive from.
144The @ref ccm_platform_bus_clk is the clock which the Cortex-M4 is running
145with.
146And the @ref ccm_ipg_bus_clk is the clock most peripherals run with.
147
148*/
149
151{
152 uint32_t ccsr = CCM_CCSR;
153 uint32_t cacrr = CCM_CACRR;
154 uint32_t arm_clk_div = (cacrr & CCM_CACRR_ARM_CLK_DIV_MASK) + 1;
155 uint32_t bus_clk_div = cacrr & CCM_CACRR_BUS_CLK_DIV_MASK;
156 uint32_t ipg_clk_div = cacrr & CCM_CACRR_IPG_CLK_DIV_MASK;
157 uint32_t pll_pfd_sel;
158
159 bus_clk_div >>= CCM_CACRR_BUS_CLK_DIV_SHIFT;
160 bus_clk_div += 1;
161
162 ipg_clk_div >>= CCM_CACRR_IPG_CLK_DIV_SHIFT;
163 ipg_clk_div += 1;
164
165 /* Get Cortex-A5 core clock from system clock selection */
166 switch (ccsr & CCM_CCSR_SYS_CLK_SEL_MASK) {
168 ccm_core_clk = 24000000;
169 break;
171 ccm_core_clk = 32000;
172 break;
174 pll_pfd_sel = ccsr & CCM_CCSR_PLL2_PFD_CLK_SEL_MASK;
175 pll_pfd_sel >>= CCM_CCSR_PLL2_PFD_CLK_SEL_SHIFT;
176
179 break;
182 break;
184 pll_pfd_sel = ccsr & CCM_CCSR_PLL1_PFD_CLK_SEL_MASK;
185 pll_pfd_sel >>= CCM_CCSR_PLL1_PFD_CLK_SEL_SHIFT;
186
189 break;
192 break;
193 }
194
195 ccm_core_clk /= arm_clk_div;
196 ccm_platform_bus_clk = ccm_core_clk / bus_clk_div;
198
199 return;
200}
201
202/**@}*/
#define ANADIG_PLL_PFD1_FRAC_MASK
Definition: anadig.h:171
#define ANADIG_PLL2_PFD
Definition: anadig.h:58
#define ANADIG_PLL_PFD3_FRAC_MASK
Definition: anadig.h:163
#define ANADIG_PLL_PFD3_FRAC_SHIFT
Definition: anadig.h:162
#define ANADIG_PLL1_PFD
Definition: anadig.h:69
#define ANADIG_PLL_PFD4_FRAC_SHIFT
Definition: anadig.h:158
#define ANADIG_PLL_PFD1_FRAC_SHIFT
Definition: anadig.h:170
#define ANADIG_PLL_PFD4_FRAC_MASK
Definition: anadig.h:159
#define ANADIG_PLL_PFD2_FRAC_MASK
Definition: anadig.h:167
#define ANADIG_PLL_PFD2_FRAC_SHIFT
Definition: anadig.h:166
#define CCM_CCSR_SYS_CLK_SEL_MASK
Definition: ccm.h:111
#define CCM_CCSR_PLL_PFD_CLK_SEL_PFD1
Definition: ccm.h:91
#define CCM_CACRR_BUS_CLK_DIV_MASK
Definition: ccm.h:131
#define CCM_CCSR_PLL1_PFD_CLK_SEL_SHIFT
Definition: ccm.h:87
#define CCM_CACRR_ARM_CLK_DIV_MASK
Definition: ccm.h:133
#define CCM_CCSR_PLL1_PFD_CLK_SEL_MASK
Definition: ccm.h:88
#define CCM_CCSR_SYS_CLK_SEL_SLOW
Definition: ccm.h:113
#define CCM_CACRR_IPG_CLK_DIV_SHIFT
Definition: ccm.h:126
#define CCM_CCSR
Definition: ccm.h:45
#define CCM_CCSR_PLL_PFD_CLK_SEL_PFD3
Definition: ccm.h:93
#define CCM_CCSR_SYS_CLK_SEL_FAST
Definition: ccm.h:112
#define CCM_CCSR_PLL_PFD_CLK_SEL_PFD4
Definition: ccm.h:94
ccm_clock_gate
Definition: ccm.h:141
#define CCM_CCSR_SYS_CLK_SEL_PLL3
Definition: ccm.h:117
#define CCM_CCSR_SYS_CLK_SEL_PLL2_PFD
Definition: ccm.h:114
#define CCM_CCSR_PLL2_PFD_CLK_SEL_MASK
Definition: ccm.h:86
#define CCM_CCGR(offset)
Definition: ccm.h:59
#define CCM_CCSR_PLL_PFD_CLK_SEL_PFD2
Definition: ccm.h:92
#define CCM_CCSR_SYS_CLK_SEL_PLL2
Definition: ccm.h:115
#define CCM_CCSR_PLL2_PFD_CLK_SEL_SHIFT
Definition: ccm.h:85
#define CCM_CACRR_IPG_CLK_DIV_MASK
Definition: ccm.h:127
#define CCM_CCSR_SYS_CLK_SEL_PLL1_PFD
Definition: ccm.h:116
#define CCM_CACRR_BUS_CLK_DIV_SHIFT
Definition: ccm.h:130
#define CCM_CCSR_PLL_PFD_CLK_SEL_MAIN
Definition: ccm.h:90
#define CCM_CACRR
Definition: ccm.h:46
static const uint32_t pll3_main_clk
Definition: ccm.c:45
static const uint32_t pll2_main_clk
Definition: ccm.c:44
void ccm_clock_gate_enable(enum ccm_clock_gate gr)
Enable clock of given device.
Definition: ccm.c:66
uint32_t ccm_core_clk
Definition: ccm.c:48
static const uint32_t pll1_main_clk
Definition: ccm.c:43
uint32_t ccm_get_pll_pfd(uint32_t pfd_sel, uint32_t pll_pfd, uint32_t pll_clk)
Calculate PFD clock.
Definition: ccm.c:100
uint32_t ccm_platform_bus_clk
Definition: ccm.c:51
uint32_t ccm_ipg_bus_clk
Definition: ccm.c:54
void ccm_calculate_clocks()
Calculate clocks.
Definition: ccm.c:150
void ccm_clock_gate_disable(enum ccm_clock_gate gr)
Disable clock of given device.
Definition: ccm.c:80