xref: /rk3399_rockchip-uboot/arch/arm/mach-omap2/am33xx/clock.c (revision 2d221489df021393654805536be7effcb9d39702)
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