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