blob: f07003c95bc2954c56b69ee64a9f0d3fb831d2a4 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Lokesh Vutla89a83bf2013-07-30 10:48:52 +05302/*
3 * clock.c
4 *
5 * Clock initialization for AM33XX boards.
6 * Derived from OMAP4 boards
7 *
Nishanth Menoneaa39c62023-11-01 15:56:03 -05008 * Copyright (C) 2013, Texas Instruments, Incorporated - https://www.ti.com/
Lokesh Vutla89a83bf2013-07-30 10:48:52 +05309 */
Simon Glassf11478f2019-12-28 10:45:07 -070010#include <hang.h>
Simon Glass97589732020-05-10 11:40:02 -060011#include <init.h>
Simon Glass0f2af882020-05-10 11:40:05 -060012#include <log.h>
Lokesh Vutla89a83bf2013-07-30 10:48:52 +053013#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
19static 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
35static 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
42static 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
52static 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
59static 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
68static void bypass_dpll(const struct dpll_regs *dpll_regs)
69{
70 do_bypass_dpll(dpll_regs);
71 wait_for_bypass(dpll_regs);
72}
73
74void 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
Lokesh Vutlab1b6fba2013-07-30 10:48:53 +0530102static void setup_dplls(void)
Lokesh Vutla89a83bf2013-07-30 10:48:52 +0530103{
104 const struct dpll_params *params;
Lokesh Vutla42c213a2013-12-10 15:02:20 +0530105
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);
Lokesh Vutla89a83bf2013-07-30 10:48:52 +0530114 writel(0x300, &cmwkup->clkdcoldodpllper);
115
116 params = get_dpll_ddr_params();
117 do_setup_dpll(&dpll_ddr_regs, params);
118}
Lokesh Vutlab1b6fba2013-07-30 10:48:53 +0530119
120static 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
138static 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
Kishon Vijay Abraham Iefc65c82015-08-17 13:29:50 +0530148static 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}
164static 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
Lokesh Vutlab1b6fba2013-07-30 10:48:53 +0530175static 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
Kishon Vijay Abraham Iefc65c82015-08-17 13:29:50 +0530182static 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
Lokesh Vutlab1b6fba2013-07-30 10:48:53 +0530190void 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 */
Dario Binacchi571462e2020-12-30 00:06:38 +0100196 for (i = 0; (i < max) && clk_domains && clk_domains[i]; i++) {
Lokesh Vutlab1b6fba2013-07-30 10:48:53 +0530197 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 */
Dario Binacchi571462e2020-12-30 00:06:38 +0100202 for (i = 0; (i < max) && clk_modules_explicit_en &&
203 clk_modules_explicit_en[i]; i++) {
Lokesh Vutlab1b6fba2013-07-30 10:48:53 +0530204 enable_clock_module(clk_modules_explicit_en[i],
205 MODULE_CLKCTRL_MODULEMODE_SW_EXPLICIT_EN,
206 wait_for_enable);
207 };
208}
209
Kishon Vijay Abraham Iefc65c82015-08-17 13:29:50 +0530210void 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
217 /* Clock modules that need to be put in SW_DISABLE */
Dario Binacchi571462e2020-12-30 00:06:38 +0100218 for (i = 0; (i < max) && clk_modules_disable && clk_modules_disable[i];
219 i++)
Kishon Vijay Abraham Iefc65c82015-08-17 13:29:50 +0530220 disable_clock_module(clk_modules_disable[i],
221 wait_for_disable);
222
223 /* Put the clock domains in SW_SLEEP mode */
Dario Binacchi571462e2020-12-30 00:06:38 +0100224 for (i = 0; (i < max) && clk_domains && clk_domains[i]; i++)
Kishon Vijay Abraham Iefc65c82015-08-17 13:29:50 +0530225 disable_clock_domain(clk_domains[i]);
226}
227
Tom Rini7c37e5c2014-06-05 11:15:28 -0400228/*
229 * Before scaling up the clocks we need to have the PMIC scale up the
230 * voltages first. This will be dependent on which PMIC is in use
231 * and in some cases we may not be scaling things up at all and thus not
232 * need to do anything here.
233 */
234__weak void scale_vcores(void)
235{
236}
237
Lokesh Vutlad33266b2016-10-14 10:35:24 +0530238void setup_early_clocks(void)
Lokesh Vutlab1b6fba2013-07-30 10:48:53 +0530239{
Lokesh Vutlad33266b2016-10-14 10:35:24 +0530240 setup_clocks_for_console();
Lokesh Vutlab1b6fba2013-07-30 10:48:53 +0530241 enable_basic_clocks();
Lokesh Vutlad33266b2016-10-14 10:35:24 +0530242 timer_init();
243}
244
245void prcm_init(void)
246{
Tom Rini7c37e5c2014-06-05 11:15:28 -0400247 scale_vcores();
Lokesh Vutlab1b6fba2013-07-30 10:48:53 +0530248 setup_dplls();
249}
Tero Kristo5d6acae2018-03-17 13:32:52 +0530250
251void rtc_only_prcm_init(void)
252{
253 const struct dpll_params *params;
254
255 rtc_only_enable_basic_clocks();
256
257 params = get_dpll_ddr_params();
258 do_setup_dpll(&dpll_ddr_regs, params);
259}