1*983e3700STom Rini /*
2*983e3700STom Rini * clock.c
3*983e3700STom Rini *
4*983e3700STom Rini * Clock initialization for AM33XX boards.
5*983e3700STom Rini * Derived from OMAP4 boards
6*983e3700STom Rini *
7*983e3700STom Rini * Copyright (C) 2013, Texas Instruments, Incorporated - http://www.ti.com/
8*983e3700STom Rini *
9*983e3700STom Rini * SPDX-License-Identifier: GPL-2.0+
10*983e3700STom Rini */
11*983e3700STom Rini #include <common.h>
12*983e3700STom Rini #include <asm/arch/cpu.h>
13*983e3700STom Rini #include <asm/arch/clock.h>
14*983e3700STom Rini #include <asm/arch/hardware.h>
15*983e3700STom Rini #include <asm/arch/sys_proto.h>
16*983e3700STom Rini #include <asm/io.h>
17*983e3700STom Rini
setup_post_dividers(const struct dpll_regs * dpll_regs,const struct dpll_params * params)18*983e3700STom Rini static void setup_post_dividers(const struct dpll_regs *dpll_regs,
19*983e3700STom Rini const struct dpll_params *params)
20*983e3700STom Rini {
21*983e3700STom Rini /* Setup post-dividers */
22*983e3700STom Rini if (params->m2 >= 0)
23*983e3700STom Rini writel(params->m2, dpll_regs->cm_div_m2_dpll);
24*983e3700STom Rini if (params->m3 >= 0)
25*983e3700STom Rini writel(params->m3, dpll_regs->cm_div_m3_dpll);
26*983e3700STom Rini if (params->m4 >= 0)
27*983e3700STom Rini writel(params->m4, dpll_regs->cm_div_m4_dpll);
28*983e3700STom Rini if (params->m5 >= 0)
29*983e3700STom Rini writel(params->m5, dpll_regs->cm_div_m5_dpll);
30*983e3700STom Rini if (params->m6 >= 0)
31*983e3700STom Rini writel(params->m6, dpll_regs->cm_div_m6_dpll);
32*983e3700STom Rini }
33*983e3700STom Rini
do_lock_dpll(const struct dpll_regs * dpll_regs)34*983e3700STom Rini static inline void do_lock_dpll(const struct dpll_regs *dpll_regs)
35*983e3700STom Rini {
36*983e3700STom Rini clrsetbits_le32(dpll_regs->cm_clkmode_dpll,
37*983e3700STom Rini CM_CLKMODE_DPLL_DPLL_EN_MASK,
38*983e3700STom Rini DPLL_EN_LOCK << CM_CLKMODE_DPLL_EN_SHIFT);
39*983e3700STom Rini }
40*983e3700STom Rini
wait_for_lock(const struct dpll_regs * dpll_regs)41*983e3700STom Rini static inline void wait_for_lock(const struct dpll_regs *dpll_regs)
42*983e3700STom Rini {
43*983e3700STom Rini if (!wait_on_value(ST_DPLL_CLK_MASK, ST_DPLL_CLK_MASK,
44*983e3700STom Rini (void *)dpll_regs->cm_idlest_dpll, LDELAY)) {
45*983e3700STom Rini printf("DPLL locking failed for 0x%x\n",
46*983e3700STom Rini dpll_regs->cm_clkmode_dpll);
47*983e3700STom Rini hang();
48*983e3700STom Rini }
49*983e3700STom Rini }
50*983e3700STom Rini
do_bypass_dpll(const struct dpll_regs * dpll_regs)51*983e3700STom Rini static inline void do_bypass_dpll(const struct dpll_regs *dpll_regs)
52*983e3700STom Rini {
53*983e3700STom Rini clrsetbits_le32(dpll_regs->cm_clkmode_dpll,
54*983e3700STom Rini CM_CLKMODE_DPLL_DPLL_EN_MASK,
55*983e3700STom Rini DPLL_EN_MN_BYPASS << CM_CLKMODE_DPLL_EN_SHIFT);
56*983e3700STom Rini }
57*983e3700STom Rini
wait_for_bypass(const struct dpll_regs * dpll_regs)58*983e3700STom Rini static inline void wait_for_bypass(const struct dpll_regs *dpll_regs)
59*983e3700STom Rini {
60*983e3700STom Rini if (!wait_on_value(ST_DPLL_CLK_MASK, 0,
61*983e3700STom Rini (void *)dpll_regs->cm_idlest_dpll, LDELAY)) {
62*983e3700STom Rini printf("Bypassing DPLL failed 0x%x\n",
63*983e3700STom Rini dpll_regs->cm_clkmode_dpll);
64*983e3700STom Rini }
65*983e3700STom Rini }
66*983e3700STom Rini
bypass_dpll(const struct dpll_regs * dpll_regs)67*983e3700STom Rini static void bypass_dpll(const struct dpll_regs *dpll_regs)
68*983e3700STom Rini {
69*983e3700STom Rini do_bypass_dpll(dpll_regs);
70*983e3700STom Rini wait_for_bypass(dpll_regs);
71*983e3700STom Rini }
72*983e3700STom Rini
do_setup_dpll(const struct dpll_regs * dpll_regs,const struct dpll_params * params)73*983e3700STom Rini void do_setup_dpll(const struct dpll_regs *dpll_regs,
74*983e3700STom Rini const struct dpll_params *params)
75*983e3700STom Rini {
76*983e3700STom Rini u32 temp;
77*983e3700STom Rini
78*983e3700STom Rini if (!params)
79*983e3700STom Rini return;
80*983e3700STom Rini
81*983e3700STom Rini temp = readl(dpll_regs->cm_clksel_dpll);
82*983e3700STom Rini
83*983e3700STom Rini bypass_dpll(dpll_regs);
84*983e3700STom Rini
85*983e3700STom Rini /* Set M & N */
86*983e3700STom Rini temp &= ~CM_CLKSEL_DPLL_M_MASK;
87*983e3700STom Rini temp |= (params->m << CM_CLKSEL_DPLL_M_SHIFT) & CM_CLKSEL_DPLL_M_MASK;
88*983e3700STom Rini
89*983e3700STom Rini temp &= ~CM_CLKSEL_DPLL_N_MASK;
90*983e3700STom Rini temp |= (params->n << CM_CLKSEL_DPLL_N_SHIFT) & CM_CLKSEL_DPLL_N_MASK;
91*983e3700STom Rini
92*983e3700STom Rini writel(temp, dpll_regs->cm_clksel_dpll);
93*983e3700STom Rini
94*983e3700STom Rini setup_post_dividers(dpll_regs, params);
95*983e3700STom Rini
96*983e3700STom Rini /* Wait till the DPLL locks */
97*983e3700STom Rini do_lock_dpll(dpll_regs);
98*983e3700STom Rini wait_for_lock(dpll_regs);
99*983e3700STom Rini }
100*983e3700STom Rini
setup_dplls(void)101*983e3700STom Rini static void setup_dplls(void)
102*983e3700STom Rini {
103*983e3700STom Rini const struct dpll_params *params;
104*983e3700STom Rini
105*983e3700STom Rini params = get_dpll_core_params();
106*983e3700STom Rini do_setup_dpll(&dpll_core_regs, params);
107*983e3700STom Rini
108*983e3700STom Rini params = get_dpll_mpu_params();
109*983e3700STom Rini do_setup_dpll(&dpll_mpu_regs, params);
110*983e3700STom Rini
111*983e3700STom Rini params = get_dpll_per_params();
112*983e3700STom Rini do_setup_dpll(&dpll_per_regs, params);
113*983e3700STom Rini writel(0x300, &cmwkup->clkdcoldodpllper);
114*983e3700STom Rini
115*983e3700STom Rini params = get_dpll_ddr_params();
116*983e3700STom Rini do_setup_dpll(&dpll_ddr_regs, params);
117*983e3700STom Rini }
118*983e3700STom Rini
wait_for_clk_enable(u32 * clkctrl_addr)119*983e3700STom Rini static inline void wait_for_clk_enable(u32 *clkctrl_addr)
120*983e3700STom Rini {
121*983e3700STom Rini u32 clkctrl, idlest = MODULE_CLKCTRL_IDLEST_DISABLED;
122*983e3700STom Rini u32 bound = LDELAY;
123*983e3700STom Rini
124*983e3700STom Rini while ((idlest == MODULE_CLKCTRL_IDLEST_DISABLED) ||
125*983e3700STom Rini (idlest == MODULE_CLKCTRL_IDLEST_TRANSITIONING)) {
126*983e3700STom Rini clkctrl = readl(clkctrl_addr);
127*983e3700STom Rini idlest = (clkctrl & MODULE_CLKCTRL_IDLEST_MASK) >>
128*983e3700STom Rini MODULE_CLKCTRL_IDLEST_SHIFT;
129*983e3700STom Rini if (--bound == 0) {
130*983e3700STom Rini printf("Clock enable failed for 0x%p idlest 0x%x\n",
131*983e3700STom Rini clkctrl_addr, clkctrl);
132*983e3700STom Rini return;
133*983e3700STom Rini }
134*983e3700STom Rini }
135*983e3700STom Rini }
136*983e3700STom Rini
enable_clock_module(u32 * const clkctrl_addr,u32 enable_mode,u32 wait_for_enable)137*983e3700STom Rini static inline void enable_clock_module(u32 *const clkctrl_addr, u32 enable_mode,
138*983e3700STom Rini u32 wait_for_enable)
139*983e3700STom Rini {
140*983e3700STom Rini clrsetbits_le32(clkctrl_addr, MODULE_CLKCTRL_MODULEMODE_MASK,
141*983e3700STom Rini enable_mode << MODULE_CLKCTRL_MODULEMODE_SHIFT);
142*983e3700STom Rini debug("Enable clock module - %p\n", clkctrl_addr);
143*983e3700STom Rini if (wait_for_enable)
144*983e3700STom Rini wait_for_clk_enable(clkctrl_addr);
145*983e3700STom Rini }
146*983e3700STom Rini
wait_for_clk_disable(u32 * clkctrl_addr)147*983e3700STom Rini static inline void wait_for_clk_disable(u32 *clkctrl_addr)
148*983e3700STom Rini {
149*983e3700STom Rini u32 clkctrl, idlest = MODULE_CLKCTRL_IDLEST_FULLY_FUNCTIONAL;
150*983e3700STom Rini u32 bound = LDELAY;
151*983e3700STom Rini
152*983e3700STom Rini while ((idlest != MODULE_CLKCTRL_IDLEST_DISABLED)) {
153*983e3700STom Rini clkctrl = readl(clkctrl_addr);
154*983e3700STom Rini idlest = (clkctrl & MODULE_CLKCTRL_IDLEST_MASK) >>
155*983e3700STom Rini MODULE_CLKCTRL_IDLEST_SHIFT;
156*983e3700STom Rini if (--bound == 0) {
157*983e3700STom Rini printf("Clock disable failed for 0x%p idlest 0x%x\n",
158*983e3700STom Rini clkctrl_addr, clkctrl);
159*983e3700STom Rini return;
160*983e3700STom Rini }
161*983e3700STom Rini }
162*983e3700STom Rini }
disable_clock_module(u32 * const clkctrl_addr,u32 wait_for_disable)163*983e3700STom Rini static inline void disable_clock_module(u32 *const clkctrl_addr,
164*983e3700STom Rini u32 wait_for_disable)
165*983e3700STom Rini {
166*983e3700STom Rini clrsetbits_le32(clkctrl_addr, MODULE_CLKCTRL_MODULEMODE_MASK,
167*983e3700STom Rini MODULE_CLKCTRL_MODULEMODE_SW_DISABLE <<
168*983e3700STom Rini MODULE_CLKCTRL_MODULEMODE_SHIFT);
169*983e3700STom Rini debug("Disable clock module - %p\n", clkctrl_addr);
170*983e3700STom Rini if (wait_for_disable)
171*983e3700STom Rini wait_for_clk_disable(clkctrl_addr);
172*983e3700STom Rini }
173*983e3700STom Rini
enable_clock_domain(u32 * const clkctrl_reg,u32 enable_mode)174*983e3700STom Rini static inline void enable_clock_domain(u32 *const clkctrl_reg, u32 enable_mode)
175*983e3700STom Rini {
176*983e3700STom Rini clrsetbits_le32(clkctrl_reg, CD_CLKCTRL_CLKTRCTRL_MASK,
177*983e3700STom Rini enable_mode << CD_CLKCTRL_CLKTRCTRL_SHIFT);
178*983e3700STom Rini debug("Enable clock domain - %p\n", clkctrl_reg);
179*983e3700STom Rini }
180*983e3700STom Rini
disable_clock_domain(u32 * const clkctrl_reg)181*983e3700STom Rini static inline void disable_clock_domain(u32 *const clkctrl_reg)
182*983e3700STom Rini {
183*983e3700STom Rini clrsetbits_le32(clkctrl_reg, CD_CLKCTRL_CLKTRCTRL_MASK,
184*983e3700STom Rini CD_CLKCTRL_CLKTRCTRL_SW_SLEEP <<
185*983e3700STom Rini CD_CLKCTRL_CLKTRCTRL_SHIFT);
186*983e3700STom Rini debug("Disable clock domain - %p\n", clkctrl_reg);
187*983e3700STom Rini }
188*983e3700STom Rini
do_enable_clocks(u32 * const * clk_domains,u32 * const * clk_modules_explicit_en,u8 wait_for_enable)189*983e3700STom Rini void do_enable_clocks(u32 *const *clk_domains,
190*983e3700STom Rini u32 *const *clk_modules_explicit_en, u8 wait_for_enable)
191*983e3700STom Rini {
192*983e3700STom Rini u32 i, max = 100;
193*983e3700STom Rini
194*983e3700STom Rini /* Put the clock domains in SW_WKUP mode */
195*983e3700STom Rini for (i = 0; (i < max) && clk_domains[i]; i++) {
196*983e3700STom Rini enable_clock_domain(clk_domains[i],
197*983e3700STom Rini CD_CLKCTRL_CLKTRCTRL_SW_WKUP);
198*983e3700STom Rini }
199*983e3700STom Rini
200*983e3700STom Rini /* Clock modules that need to be put in SW_EXPLICIT_EN mode */
201*983e3700STom Rini for (i = 0; (i < max) && clk_modules_explicit_en[i]; i++) {
202*983e3700STom Rini enable_clock_module(clk_modules_explicit_en[i],
203*983e3700STom Rini MODULE_CLKCTRL_MODULEMODE_SW_EXPLICIT_EN,
204*983e3700STom Rini wait_for_enable);
205*983e3700STom Rini };
206*983e3700STom Rini }
207*983e3700STom Rini
do_disable_clocks(u32 * const * clk_domains,u32 * const * clk_modules_disable,u8 wait_for_disable)208*983e3700STom Rini void do_disable_clocks(u32 *const *clk_domains,
209*983e3700STom Rini u32 *const *clk_modules_disable,
210*983e3700STom Rini u8 wait_for_disable)
211*983e3700STom Rini {
212*983e3700STom Rini u32 i, max = 100;
213*983e3700STom Rini
214*983e3700STom Rini
215*983e3700STom Rini /* Clock modules that need to be put in SW_DISABLE */
216*983e3700STom Rini for (i = 0; (i < max) && clk_modules_disable[i]; i++)
217*983e3700STom Rini disable_clock_module(clk_modules_disable[i],
218*983e3700STom Rini wait_for_disable);
219*983e3700STom Rini
220*983e3700STom Rini /* Put the clock domains in SW_SLEEP mode */
221*983e3700STom Rini for (i = 0; (i < max) && clk_domains[i]; i++)
222*983e3700STom Rini disable_clock_domain(clk_domains[i]);
223*983e3700STom Rini }
224*983e3700STom Rini
225*983e3700STom Rini /*
226*983e3700STom Rini * Before scaling up the clocks we need to have the PMIC scale up the
227*983e3700STom Rini * voltages first. This will be dependent on which PMIC is in use
228*983e3700STom Rini * and in some cases we may not be scaling things up at all and thus not
229*983e3700STom Rini * need to do anything here.
230*983e3700STom Rini */
scale_vcores(void)231*983e3700STom Rini __weak void scale_vcores(void)
232*983e3700STom Rini {
233*983e3700STom Rini }
234*983e3700STom Rini
setup_early_clocks(void)235*983e3700STom Rini void setup_early_clocks(void)
236*983e3700STom Rini {
237*983e3700STom Rini setup_clocks_for_console();
238*983e3700STom Rini enable_basic_clocks();
239*983e3700STom Rini timer_init();
240*983e3700STom Rini }
241*983e3700STom Rini
prcm_init(void)242*983e3700STom Rini void prcm_init(void)
243*983e3700STom Rini {
244*983e3700STom Rini scale_vcores();
245*983e3700STom Rini setup_dplls();
246*983e3700STom Rini }
247