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