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