1*83d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
2983e3700STom Rini /*
3983e3700STom Rini  * clock.c
4983e3700STom Rini  *
5983e3700STom Rini  * Clock initialization for AM33XX boards.
6983e3700STom Rini  * Derived from OMAP4 boards
7983e3700STom Rini  *
8983e3700STom Rini  * Copyright (C) 2013, Texas Instruments, Incorporated - http://www.ti.com/
9983e3700STom Rini  */
10983e3700STom Rini #include <common.h>
11983e3700STom Rini #include <asm/arch/cpu.h>
12983e3700STom Rini #include <asm/arch/clock.h>
13983e3700STom Rini #include <asm/arch/hardware.h>
14983e3700STom Rini #include <asm/arch/sys_proto.h>
15983e3700STom Rini #include <asm/io.h>
16983e3700STom Rini 
setup_post_dividers(const struct dpll_regs * dpll_regs,const struct dpll_params * params)17983e3700STom Rini static void setup_post_dividers(const struct dpll_regs *dpll_regs,
18983e3700STom Rini 			 const struct dpll_params *params)
19983e3700STom Rini {
20983e3700STom Rini 	/* Setup post-dividers */
21983e3700STom Rini 	if (params->m2 >= 0)
22983e3700STom Rini 		writel(params->m2, dpll_regs->cm_div_m2_dpll);
23983e3700STom Rini 	if (params->m3 >= 0)
24983e3700STom Rini 		writel(params->m3, dpll_regs->cm_div_m3_dpll);
25983e3700STom Rini 	if (params->m4 >= 0)
26983e3700STom Rini 		writel(params->m4, dpll_regs->cm_div_m4_dpll);
27983e3700STom Rini 	if (params->m5 >= 0)
28983e3700STom Rini 		writel(params->m5, dpll_regs->cm_div_m5_dpll);
29983e3700STom Rini 	if (params->m6 >= 0)
30983e3700STom Rini 		writel(params->m6, dpll_regs->cm_div_m6_dpll);
31983e3700STom Rini }
32983e3700STom Rini 
do_lock_dpll(const struct dpll_regs * dpll_regs)33983e3700STom Rini static inline void do_lock_dpll(const struct dpll_regs *dpll_regs)
34983e3700STom Rini {
35983e3700STom Rini 	clrsetbits_le32(dpll_regs->cm_clkmode_dpll,
36983e3700STom Rini 			CM_CLKMODE_DPLL_DPLL_EN_MASK,
37983e3700STom Rini 			DPLL_EN_LOCK << CM_CLKMODE_DPLL_EN_SHIFT);
38983e3700STom Rini }
39983e3700STom Rini 
wait_for_lock(const struct dpll_regs * dpll_regs)40983e3700STom Rini static inline void wait_for_lock(const struct dpll_regs *dpll_regs)
41983e3700STom Rini {
42983e3700STom Rini 	if (!wait_on_value(ST_DPLL_CLK_MASK, ST_DPLL_CLK_MASK,
43983e3700STom Rini 			   (void *)dpll_regs->cm_idlest_dpll, LDELAY)) {
44983e3700STom Rini 		printf("DPLL locking failed for 0x%x\n",
45983e3700STom Rini 		       dpll_regs->cm_clkmode_dpll);
46983e3700STom Rini 		hang();
47983e3700STom Rini 	}
48983e3700STom Rini }
49983e3700STom Rini 
do_bypass_dpll(const struct dpll_regs * dpll_regs)50983e3700STom Rini static inline void do_bypass_dpll(const struct dpll_regs *dpll_regs)
51983e3700STom Rini {
52983e3700STom Rini 	clrsetbits_le32(dpll_regs->cm_clkmode_dpll,
53983e3700STom Rini 			CM_CLKMODE_DPLL_DPLL_EN_MASK,
54983e3700STom Rini 			DPLL_EN_MN_BYPASS << CM_CLKMODE_DPLL_EN_SHIFT);
55983e3700STom Rini }
56983e3700STom Rini 
wait_for_bypass(const struct dpll_regs * dpll_regs)57983e3700STom Rini static inline void wait_for_bypass(const struct dpll_regs *dpll_regs)
58983e3700STom Rini {
59983e3700STom Rini 	if (!wait_on_value(ST_DPLL_CLK_MASK, 0,
60983e3700STom Rini 			   (void *)dpll_regs->cm_idlest_dpll, LDELAY)) {
61983e3700STom Rini 		printf("Bypassing DPLL failed 0x%x\n",
62983e3700STom Rini 		       dpll_regs->cm_clkmode_dpll);
63983e3700STom Rini 	}
64983e3700STom Rini }
65983e3700STom Rini 
bypass_dpll(const struct dpll_regs * dpll_regs)66983e3700STom Rini static void bypass_dpll(const struct dpll_regs *dpll_regs)
67983e3700STom Rini {
68983e3700STom Rini 	do_bypass_dpll(dpll_regs);
69983e3700STom Rini 	wait_for_bypass(dpll_regs);
70983e3700STom Rini }
71983e3700STom Rini 
do_setup_dpll(const struct dpll_regs * dpll_regs,const struct dpll_params * params)72983e3700STom Rini void do_setup_dpll(const struct dpll_regs *dpll_regs,
73983e3700STom Rini 		   const struct dpll_params *params)
74983e3700STom Rini {
75983e3700STom Rini 	u32 temp;
76983e3700STom Rini 
77983e3700STom Rini 	if (!params)
78983e3700STom Rini 		return;
79983e3700STom Rini 
80983e3700STom Rini 	temp = readl(dpll_regs->cm_clksel_dpll);
81983e3700STom Rini 
82983e3700STom Rini 	bypass_dpll(dpll_regs);
83983e3700STom Rini 
84983e3700STom Rini 	/* Set M & N */
85983e3700STom Rini 	temp &= ~CM_CLKSEL_DPLL_M_MASK;
86983e3700STom Rini 	temp |= (params->m << CM_CLKSEL_DPLL_M_SHIFT) & CM_CLKSEL_DPLL_M_MASK;
87983e3700STom Rini 
88983e3700STom Rini 	temp &= ~CM_CLKSEL_DPLL_N_MASK;
89983e3700STom Rini 	temp |= (params->n << CM_CLKSEL_DPLL_N_SHIFT) & CM_CLKSEL_DPLL_N_MASK;
90983e3700STom Rini 
91983e3700STom Rini 	writel(temp, dpll_regs->cm_clksel_dpll);
92983e3700STom Rini 
93983e3700STom Rini 	setup_post_dividers(dpll_regs, params);
94983e3700STom Rini 
95983e3700STom Rini 	/* Wait till the DPLL locks */
96983e3700STom Rini 	do_lock_dpll(dpll_regs);
97983e3700STom Rini 	wait_for_lock(dpll_regs);
98983e3700STom Rini }
99983e3700STom Rini 
setup_dplls(void)100983e3700STom Rini static void setup_dplls(void)
101983e3700STom Rini {
102983e3700STom Rini 	const struct dpll_params *params;
103983e3700STom Rini 
104983e3700STom Rini 	params = get_dpll_core_params();
105983e3700STom Rini 	do_setup_dpll(&dpll_core_regs, params);
106983e3700STom Rini 
107983e3700STom Rini 	params = get_dpll_mpu_params();
108983e3700STom Rini 	do_setup_dpll(&dpll_mpu_regs, params);
109983e3700STom Rini 
110983e3700STom Rini 	params = get_dpll_per_params();
111983e3700STom Rini 	do_setup_dpll(&dpll_per_regs, params);
112983e3700STom Rini 	writel(0x300, &cmwkup->clkdcoldodpllper);
113983e3700STom Rini 
114983e3700STom Rini 	params = get_dpll_ddr_params();
115983e3700STom Rini 	do_setup_dpll(&dpll_ddr_regs, params);
116983e3700STom Rini }
117983e3700STom Rini 
wait_for_clk_enable(u32 * clkctrl_addr)118983e3700STom Rini static inline void wait_for_clk_enable(u32 *clkctrl_addr)
119983e3700STom Rini {
120983e3700STom Rini 	u32 clkctrl, idlest = MODULE_CLKCTRL_IDLEST_DISABLED;
121983e3700STom Rini 	u32 bound = LDELAY;
122983e3700STom Rini 
123983e3700STom Rini 	while ((idlest == MODULE_CLKCTRL_IDLEST_DISABLED) ||
124983e3700STom Rini 		(idlest == MODULE_CLKCTRL_IDLEST_TRANSITIONING)) {
125983e3700STom Rini 		clkctrl = readl(clkctrl_addr);
126983e3700STom Rini 		idlest = (clkctrl & MODULE_CLKCTRL_IDLEST_MASK) >>
127983e3700STom Rini 			 MODULE_CLKCTRL_IDLEST_SHIFT;
128983e3700STom Rini 		if (--bound == 0) {
129983e3700STom Rini 			printf("Clock enable failed for 0x%p idlest 0x%x\n",
130983e3700STom Rini 			       clkctrl_addr, clkctrl);
131983e3700STom Rini 			return;
132983e3700STom Rini 		}
133983e3700STom Rini 	}
134983e3700STom Rini }
135983e3700STom Rini 
enable_clock_module(u32 * const clkctrl_addr,u32 enable_mode,u32 wait_for_enable)136983e3700STom Rini static inline void enable_clock_module(u32 *const clkctrl_addr, u32 enable_mode,
137983e3700STom Rini 				       u32 wait_for_enable)
138983e3700STom Rini {
139983e3700STom Rini 	clrsetbits_le32(clkctrl_addr, MODULE_CLKCTRL_MODULEMODE_MASK,
140983e3700STom Rini 			enable_mode << MODULE_CLKCTRL_MODULEMODE_SHIFT);
141983e3700STom Rini 	debug("Enable clock module - %p\n", clkctrl_addr);
142983e3700STom Rini 	if (wait_for_enable)
143983e3700STom Rini 		wait_for_clk_enable(clkctrl_addr);
144983e3700STom Rini }
145983e3700STom Rini 
wait_for_clk_disable(u32 * clkctrl_addr)146983e3700STom Rini static inline void wait_for_clk_disable(u32 *clkctrl_addr)
147983e3700STom Rini {
148983e3700STom Rini 	u32 clkctrl, idlest = MODULE_CLKCTRL_IDLEST_FULLY_FUNCTIONAL;
149983e3700STom Rini 	u32 bound = LDELAY;
150983e3700STom Rini 
151983e3700STom Rini 	while ((idlest != MODULE_CLKCTRL_IDLEST_DISABLED)) {
152983e3700STom Rini 		clkctrl = readl(clkctrl_addr);
153983e3700STom Rini 		idlest = (clkctrl & MODULE_CLKCTRL_IDLEST_MASK) >>
154983e3700STom Rini 			  MODULE_CLKCTRL_IDLEST_SHIFT;
155983e3700STom Rini 		if (--bound == 0) {
156983e3700STom Rini 			printf("Clock disable failed for 0x%p idlest 0x%x\n",
157983e3700STom Rini 			       clkctrl_addr, clkctrl);
158983e3700STom Rini 			 return;
159983e3700STom Rini 		}
160983e3700STom Rini 	}
161983e3700STom Rini }
disable_clock_module(u32 * const clkctrl_addr,u32 wait_for_disable)162983e3700STom Rini static inline void disable_clock_module(u32 *const clkctrl_addr,
163983e3700STom Rini 					u32 wait_for_disable)
164983e3700STom Rini {
165983e3700STom Rini 	clrsetbits_le32(clkctrl_addr, MODULE_CLKCTRL_MODULEMODE_MASK,
166983e3700STom Rini 			MODULE_CLKCTRL_MODULEMODE_SW_DISABLE <<
167983e3700STom Rini 			MODULE_CLKCTRL_MODULEMODE_SHIFT);
168983e3700STom Rini 	debug("Disable clock module - %p\n", clkctrl_addr);
169983e3700STom Rini 	if (wait_for_disable)
170983e3700STom Rini 		wait_for_clk_disable(clkctrl_addr);
171983e3700STom Rini }
172983e3700STom Rini 
enable_clock_domain(u32 * const clkctrl_reg,u32 enable_mode)173983e3700STom Rini static inline void enable_clock_domain(u32 *const clkctrl_reg, u32 enable_mode)
174983e3700STom Rini {
175983e3700STom Rini 	clrsetbits_le32(clkctrl_reg, CD_CLKCTRL_CLKTRCTRL_MASK,
176983e3700STom Rini 			enable_mode << CD_CLKCTRL_CLKTRCTRL_SHIFT);
177983e3700STom Rini 	debug("Enable clock domain - %p\n", clkctrl_reg);
178983e3700STom Rini }
179983e3700STom Rini 
disable_clock_domain(u32 * const clkctrl_reg)180983e3700STom Rini static inline void disable_clock_domain(u32 *const clkctrl_reg)
181983e3700STom Rini {
182983e3700STom Rini 	clrsetbits_le32(clkctrl_reg, CD_CLKCTRL_CLKTRCTRL_MASK,
183983e3700STom Rini 			CD_CLKCTRL_CLKTRCTRL_SW_SLEEP <<
184983e3700STom Rini 			CD_CLKCTRL_CLKTRCTRL_SHIFT);
185983e3700STom Rini 	debug("Disable clock domain - %p\n", clkctrl_reg);
186983e3700STom Rini }
187983e3700STom Rini 
do_enable_clocks(u32 * const * clk_domains,u32 * const * clk_modules_explicit_en,u8 wait_for_enable)188983e3700STom Rini void do_enable_clocks(u32 *const *clk_domains,
189983e3700STom Rini 		      u32 *const *clk_modules_explicit_en, u8 wait_for_enable)
190983e3700STom Rini {
191983e3700STom Rini 	u32 i, max = 100;
192983e3700STom Rini 
193983e3700STom Rini 	/* Put the clock domains in SW_WKUP mode */
194983e3700STom Rini 	for (i = 0; (i < max) && clk_domains[i]; i++) {
195983e3700STom Rini 		enable_clock_domain(clk_domains[i],
196983e3700STom Rini 				    CD_CLKCTRL_CLKTRCTRL_SW_WKUP);
197983e3700STom Rini 	}
198983e3700STom Rini 
199983e3700STom Rini 	/* Clock modules that need to be put in SW_EXPLICIT_EN mode */
200983e3700STom Rini 	for (i = 0; (i < max) && clk_modules_explicit_en[i]; i++) {
201983e3700STom Rini 		enable_clock_module(clk_modules_explicit_en[i],
202983e3700STom Rini 				    MODULE_CLKCTRL_MODULEMODE_SW_EXPLICIT_EN,
203983e3700STom Rini 				    wait_for_enable);
204983e3700STom Rini 	};
205983e3700STom Rini }
206983e3700STom Rini 
do_disable_clocks(u32 * const * clk_domains,u32 * const * clk_modules_disable,u8 wait_for_disable)207983e3700STom Rini void do_disable_clocks(u32 *const *clk_domains,
208983e3700STom Rini 			u32 *const *clk_modules_disable,
209983e3700STom Rini 			u8 wait_for_disable)
210983e3700STom Rini {
211983e3700STom Rini 	u32 i, max = 100;
212983e3700STom Rini 
213983e3700STom Rini 
214983e3700STom Rini 	/* Clock modules that need to be put in SW_DISABLE */
215983e3700STom Rini 	for (i = 0; (i < max) && clk_modules_disable[i]; i++)
216983e3700STom Rini 		disable_clock_module(clk_modules_disable[i],
217983e3700STom Rini 				     wait_for_disable);
218983e3700STom Rini 
219983e3700STom Rini 	/* Put the clock domains in SW_SLEEP mode */
220983e3700STom Rini 	for (i = 0; (i < max) && clk_domains[i]; i++)
221983e3700STom Rini 		disable_clock_domain(clk_domains[i]);
222983e3700STom Rini }
223983e3700STom Rini 
224983e3700STom Rini /*
225983e3700STom Rini  * Before scaling up the clocks we need to have the PMIC scale up the
226983e3700STom Rini  * voltages first.  This will be dependent on which PMIC is in use
227983e3700STom Rini  * and in some cases we may not be scaling things up at all and thus not
228983e3700STom Rini  * need to do anything here.
229983e3700STom Rini  */
scale_vcores(void)230983e3700STom Rini __weak void scale_vcores(void)
231983e3700STom Rini {
232983e3700STom Rini }
233983e3700STom Rini 
setup_early_clocks(void)234983e3700STom Rini void setup_early_clocks(void)
235983e3700STom Rini {
236983e3700STom Rini 	setup_clocks_for_console();
237983e3700STom Rini 	enable_basic_clocks();
238983e3700STom Rini 	timer_init();
239983e3700STom Rini }
240983e3700STom Rini 
prcm_init(void)241983e3700STom Rini void prcm_init(void)
242983e3700STom Rini {
243983e3700STom Rini 	scale_vcores();
244983e3700STom Rini 	setup_dplls();
245983e3700STom Rini }
2467619badbSTero Kristo 
rtc_only_prcm_init(void)2477619badbSTero Kristo void rtc_only_prcm_init(void)
2487619badbSTero Kristo {
2497619badbSTero Kristo 	const struct dpll_params *params;
2507619badbSTero Kristo 
2517619badbSTero Kristo 	rtc_only_enable_basic_clocks();
2527619badbSTero Kristo 
2537619badbSTero Kristo 	params = get_dpll_ddr_params();
2547619badbSTero Kristo 	do_setup_dpll(&dpll_ddr_regs, params);
2557619badbSTero Kristo }
256