blob: 7c666be758af032a0f0591ea22efb9dbde3bf401 [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Lokesh Vutla94d77fb2013-07-30 10:48:52 +05302/*
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/
Lokesh Vutla94d77fb2013-07-30 10:48:52 +05309 */
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
17static 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
33static 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
40static 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
50static 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
57static 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
66static void bypass_dpll(const struct dpll_regs *dpll_regs)
67{
68 do_bypass_dpll(dpll_regs);
69 wait_for_bypass(dpll_regs);
70}
71
72void 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
Lokesh Vutla95cb69f2013-07-30 10:48:53 +0530100static void setup_dplls(void)
Lokesh Vutla94d77fb2013-07-30 10:48:52 +0530101{
102 const struct dpll_params *params;
Lokesh Vutlacf04d032013-12-10 15:02:20 +0530103
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);
Lokesh Vutla94d77fb2013-07-30 10:48:52 +0530112 writel(0x300, &cmwkup->clkdcoldodpllper);
113
114 params = get_dpll_ddr_params();
115 do_setup_dpll(&dpll_ddr_regs, params);
116}
Lokesh Vutla95cb69f2013-07-30 10:48:53 +0530117
118static 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
136static 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
Kishon Vijay Abraham Ifca45722015-08-17 13:29:50 +0530146static 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}
162static 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
Lokesh Vutla95cb69f2013-07-30 10:48:53 +0530173static 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
Kishon Vijay Abraham Ifca45722015-08-17 13:29:50 +0530180static 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
Lokesh Vutla95cb69f2013-07-30 10:48:53 +0530188void 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
Kishon Vijay Abraham Ifca45722015-08-17 13:29:50 +0530207void 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
Tom Rini64ce2fb2014-06-05 11:15:28 -0400224/*
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 */
230__weak void scale_vcores(void)
231{
232}
233
Lokesh Vutlab64a7cb2016-10-14 10:35:24 +0530234void setup_early_clocks(void)
Lokesh Vutla95cb69f2013-07-30 10:48:53 +0530235{
Lokesh Vutlab64a7cb2016-10-14 10:35:24 +0530236 setup_clocks_for_console();
Lokesh Vutla95cb69f2013-07-30 10:48:53 +0530237 enable_basic_clocks();
Lokesh Vutlab64a7cb2016-10-14 10:35:24 +0530238 timer_init();
239}
240
241void prcm_init(void)
242{
Tom Rini64ce2fb2014-06-05 11:15:28 -0400243 scale_vcores();
Lokesh Vutla95cb69f2013-07-30 10:48:53 +0530244 setup_dplls();
245}
Tero Kristo7619bad2018-03-17 13:32:52 +0530246
247void 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}