1*83d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
2983e3700STom Rini /*
3983e3700STom Rini * clock.c
4983e3700STom Rini *
5983e3700STom Rini * Clock initialization for AM33XX boards.
6983e3700STom Rini * Derived from OMAP4 boards
7983e3700STom Rini *
8983e3700STom Rini * Copyright (C) 2013, Texas Instruments, Incorporated - http://www.ti.com/
9983e3700STom Rini */
10983e3700STom Rini #include <common.h>
11983e3700STom Rini #include <asm/arch/cpu.h>
12983e3700STom Rini #include <asm/arch/clock.h>
13983e3700STom Rini #include <asm/arch/hardware.h>
14983e3700STom Rini #include <asm/arch/sys_proto.h>
15983e3700STom Rini #include <asm/io.h>
16983e3700STom Rini
setup_post_dividers(const struct dpll_regs * dpll_regs,const struct dpll_params * params)17983e3700STom Rini static void setup_post_dividers(const struct dpll_regs *dpll_regs,
18983e3700STom Rini const struct dpll_params *params)
19983e3700STom Rini {
20983e3700STom Rini /* Setup post-dividers */
21983e3700STom Rini if (params->m2 >= 0)
22983e3700STom Rini writel(params->m2, dpll_regs->cm_div_m2_dpll);
23983e3700STom Rini if (params->m3 >= 0)
24983e3700STom Rini writel(params->m3, dpll_regs->cm_div_m3_dpll);
25983e3700STom Rini if (params->m4 >= 0)
26983e3700STom Rini writel(params->m4, dpll_regs->cm_div_m4_dpll);
27983e3700STom Rini if (params->m5 >= 0)
28983e3700STom Rini writel(params->m5, dpll_regs->cm_div_m5_dpll);
29983e3700STom Rini if (params->m6 >= 0)
30983e3700STom Rini writel(params->m6, dpll_regs->cm_div_m6_dpll);
31983e3700STom Rini }
32983e3700STom Rini
do_lock_dpll(const struct dpll_regs * dpll_regs)33983e3700STom Rini static inline void do_lock_dpll(const struct dpll_regs *dpll_regs)
34983e3700STom Rini {
35983e3700STom Rini clrsetbits_le32(dpll_regs->cm_clkmode_dpll,
36983e3700STom Rini CM_CLKMODE_DPLL_DPLL_EN_MASK,
37983e3700STom Rini DPLL_EN_LOCK << CM_CLKMODE_DPLL_EN_SHIFT);
38983e3700STom Rini }
39983e3700STom Rini
wait_for_lock(const struct dpll_regs * dpll_regs)40983e3700STom Rini static inline void wait_for_lock(const struct dpll_regs *dpll_regs)
41983e3700STom Rini {
42983e3700STom Rini if (!wait_on_value(ST_DPLL_CLK_MASK, ST_DPLL_CLK_MASK,
43983e3700STom Rini (void *)dpll_regs->cm_idlest_dpll, LDELAY)) {
44983e3700STom Rini printf("DPLL locking failed for 0x%x\n",
45983e3700STom Rini dpll_regs->cm_clkmode_dpll);
46983e3700STom Rini hang();
47983e3700STom Rini }
48983e3700STom Rini }
49983e3700STom Rini
do_bypass_dpll(const struct dpll_regs * dpll_regs)50983e3700STom Rini static inline void do_bypass_dpll(const struct dpll_regs *dpll_regs)
51983e3700STom Rini {
52983e3700STom Rini clrsetbits_le32(dpll_regs->cm_clkmode_dpll,
53983e3700STom Rini CM_CLKMODE_DPLL_DPLL_EN_MASK,
54983e3700STom Rini DPLL_EN_MN_BYPASS << CM_CLKMODE_DPLL_EN_SHIFT);
55983e3700STom Rini }
56983e3700STom Rini
wait_for_bypass(const struct dpll_regs * dpll_regs)57983e3700STom Rini static inline void wait_for_bypass(const struct dpll_regs *dpll_regs)
58983e3700STom Rini {
59983e3700STom Rini if (!wait_on_value(ST_DPLL_CLK_MASK, 0,
60983e3700STom Rini (void *)dpll_regs->cm_idlest_dpll, LDELAY)) {
61983e3700STom Rini printf("Bypassing DPLL failed 0x%x\n",
62983e3700STom Rini dpll_regs->cm_clkmode_dpll);
63983e3700STom Rini }
64983e3700STom Rini }
65983e3700STom Rini
bypass_dpll(const struct dpll_regs * dpll_regs)66983e3700STom Rini static void bypass_dpll(const struct dpll_regs *dpll_regs)
67983e3700STom Rini {
68983e3700STom Rini do_bypass_dpll(dpll_regs);
69983e3700STom Rini wait_for_bypass(dpll_regs);
70983e3700STom Rini }
71983e3700STom Rini
do_setup_dpll(const struct dpll_regs * dpll_regs,const struct dpll_params * params)72983e3700STom Rini void do_setup_dpll(const struct dpll_regs *dpll_regs,
73983e3700STom Rini const struct dpll_params *params)
74983e3700STom Rini {
75983e3700STom Rini u32 temp;
76983e3700STom Rini
77983e3700STom Rini if (!params)
78983e3700STom Rini return;
79983e3700STom Rini
80983e3700STom Rini temp = readl(dpll_regs->cm_clksel_dpll);
81983e3700STom Rini
82983e3700STom Rini bypass_dpll(dpll_regs);
83983e3700STom Rini
84983e3700STom Rini /* Set M & N */
85983e3700STom Rini temp &= ~CM_CLKSEL_DPLL_M_MASK;
86983e3700STom Rini temp |= (params->m << CM_CLKSEL_DPLL_M_SHIFT) & CM_CLKSEL_DPLL_M_MASK;
87983e3700STom Rini
88983e3700STom Rini temp &= ~CM_CLKSEL_DPLL_N_MASK;
89983e3700STom Rini temp |= (params->n << CM_CLKSEL_DPLL_N_SHIFT) & CM_CLKSEL_DPLL_N_MASK;
90983e3700STom Rini
91983e3700STom Rini writel(temp, dpll_regs->cm_clksel_dpll);
92983e3700STom Rini
93983e3700STom Rini setup_post_dividers(dpll_regs, params);
94983e3700STom Rini
95983e3700STom Rini /* Wait till the DPLL locks */
96983e3700STom Rini do_lock_dpll(dpll_regs);
97983e3700STom Rini wait_for_lock(dpll_regs);
98983e3700STom Rini }
99983e3700STom Rini
setup_dplls(void)100983e3700STom Rini static void setup_dplls(void)
101983e3700STom Rini {
102983e3700STom Rini const struct dpll_params *params;
103983e3700STom Rini
104983e3700STom Rini params = get_dpll_core_params();
105983e3700STom Rini do_setup_dpll(&dpll_core_regs, params);
106983e3700STom Rini
107983e3700STom Rini params = get_dpll_mpu_params();
108983e3700STom Rini do_setup_dpll(&dpll_mpu_regs, params);
109983e3700STom Rini
110983e3700STom Rini params = get_dpll_per_params();
111983e3700STom Rini do_setup_dpll(&dpll_per_regs, params);
112983e3700STom Rini writel(0x300, &cmwkup->clkdcoldodpllper);
113983e3700STom Rini
114983e3700STom Rini params = get_dpll_ddr_params();
115983e3700STom Rini do_setup_dpll(&dpll_ddr_regs, params);
116983e3700STom Rini }
117983e3700STom Rini
wait_for_clk_enable(u32 * clkctrl_addr)118983e3700STom Rini static inline void wait_for_clk_enable(u32 *clkctrl_addr)
119983e3700STom Rini {
120983e3700STom Rini u32 clkctrl, idlest = MODULE_CLKCTRL_IDLEST_DISABLED;
121983e3700STom Rini u32 bound = LDELAY;
122983e3700STom Rini
123983e3700STom Rini while ((idlest == MODULE_CLKCTRL_IDLEST_DISABLED) ||
124983e3700STom Rini (idlest == MODULE_CLKCTRL_IDLEST_TRANSITIONING)) {
125983e3700STom Rini clkctrl = readl(clkctrl_addr);
126983e3700STom Rini idlest = (clkctrl & MODULE_CLKCTRL_IDLEST_MASK) >>
127983e3700STom Rini MODULE_CLKCTRL_IDLEST_SHIFT;
128983e3700STom Rini if (--bound == 0) {
129983e3700STom Rini printf("Clock enable failed for 0x%p idlest 0x%x\n",
130983e3700STom Rini clkctrl_addr, clkctrl);
131983e3700STom Rini return;
132983e3700STom Rini }
133983e3700STom Rini }
134983e3700STom Rini }
135983e3700STom Rini
enable_clock_module(u32 * const clkctrl_addr,u32 enable_mode,u32 wait_for_enable)136983e3700STom Rini static inline void enable_clock_module(u32 *const clkctrl_addr, u32 enable_mode,
137983e3700STom Rini u32 wait_for_enable)
138983e3700STom Rini {
139983e3700STom Rini clrsetbits_le32(clkctrl_addr, MODULE_CLKCTRL_MODULEMODE_MASK,
140983e3700STom Rini enable_mode << MODULE_CLKCTRL_MODULEMODE_SHIFT);
141983e3700STom Rini debug("Enable clock module - %p\n", clkctrl_addr);
142983e3700STom Rini if (wait_for_enable)
143983e3700STom Rini wait_for_clk_enable(clkctrl_addr);
144983e3700STom Rini }
145983e3700STom Rini
wait_for_clk_disable(u32 * clkctrl_addr)146983e3700STom Rini static inline void wait_for_clk_disable(u32 *clkctrl_addr)
147983e3700STom Rini {
148983e3700STom Rini u32 clkctrl, idlest = MODULE_CLKCTRL_IDLEST_FULLY_FUNCTIONAL;
149983e3700STom Rini u32 bound = LDELAY;
150983e3700STom Rini
151983e3700STom Rini while ((idlest != MODULE_CLKCTRL_IDLEST_DISABLED)) {
152983e3700STom Rini clkctrl = readl(clkctrl_addr);
153983e3700STom Rini idlest = (clkctrl & MODULE_CLKCTRL_IDLEST_MASK) >>
154983e3700STom Rini MODULE_CLKCTRL_IDLEST_SHIFT;
155983e3700STom Rini if (--bound == 0) {
156983e3700STom Rini printf("Clock disable failed for 0x%p idlest 0x%x\n",
157983e3700STom Rini clkctrl_addr, clkctrl);
158983e3700STom Rini return;
159983e3700STom Rini }
160983e3700STom Rini }
161983e3700STom Rini }
disable_clock_module(u32 * const clkctrl_addr,u32 wait_for_disable)162983e3700STom Rini static inline void disable_clock_module(u32 *const clkctrl_addr,
163983e3700STom Rini u32 wait_for_disable)
164983e3700STom Rini {
165983e3700STom Rini clrsetbits_le32(clkctrl_addr, MODULE_CLKCTRL_MODULEMODE_MASK,
166983e3700STom Rini MODULE_CLKCTRL_MODULEMODE_SW_DISABLE <<
167983e3700STom Rini MODULE_CLKCTRL_MODULEMODE_SHIFT);
168983e3700STom Rini debug("Disable clock module - %p\n", clkctrl_addr);
169983e3700STom Rini if (wait_for_disable)
170983e3700STom Rini wait_for_clk_disable(clkctrl_addr);
171983e3700STom Rini }
172983e3700STom Rini
enable_clock_domain(u32 * const clkctrl_reg,u32 enable_mode)173983e3700STom Rini static inline void enable_clock_domain(u32 *const clkctrl_reg, u32 enable_mode)
174983e3700STom Rini {
175983e3700STom Rini clrsetbits_le32(clkctrl_reg, CD_CLKCTRL_CLKTRCTRL_MASK,
176983e3700STom Rini enable_mode << CD_CLKCTRL_CLKTRCTRL_SHIFT);
177983e3700STom Rini debug("Enable clock domain - %p\n", clkctrl_reg);
178983e3700STom Rini }
179983e3700STom Rini
disable_clock_domain(u32 * const clkctrl_reg)180983e3700STom Rini static inline void disable_clock_domain(u32 *const clkctrl_reg)
181983e3700STom Rini {
182983e3700STom Rini clrsetbits_le32(clkctrl_reg, CD_CLKCTRL_CLKTRCTRL_MASK,
183983e3700STom Rini CD_CLKCTRL_CLKTRCTRL_SW_SLEEP <<
184983e3700STom Rini CD_CLKCTRL_CLKTRCTRL_SHIFT);
185983e3700STom Rini debug("Disable clock domain - %p\n", clkctrl_reg);
186983e3700STom Rini }
187983e3700STom Rini
do_enable_clocks(u32 * const * clk_domains,u32 * const * clk_modules_explicit_en,u8 wait_for_enable)188983e3700STom Rini void do_enable_clocks(u32 *const *clk_domains,
189983e3700STom Rini u32 *const *clk_modules_explicit_en, u8 wait_for_enable)
190983e3700STom Rini {
191983e3700STom Rini u32 i, max = 100;
192983e3700STom Rini
193983e3700STom Rini /* Put the clock domains in SW_WKUP mode */
194983e3700STom Rini for (i = 0; (i < max) && clk_domains[i]; i++) {
195983e3700STom Rini enable_clock_domain(clk_domains[i],
196983e3700STom Rini CD_CLKCTRL_CLKTRCTRL_SW_WKUP);
197983e3700STom Rini }
198983e3700STom Rini
199983e3700STom Rini /* Clock modules that need to be put in SW_EXPLICIT_EN mode */
200983e3700STom Rini for (i = 0; (i < max) && clk_modules_explicit_en[i]; i++) {
201983e3700STom Rini enable_clock_module(clk_modules_explicit_en[i],
202983e3700STom Rini MODULE_CLKCTRL_MODULEMODE_SW_EXPLICIT_EN,
203983e3700STom Rini wait_for_enable);
204983e3700STom Rini };
205983e3700STom Rini }
206983e3700STom Rini
do_disable_clocks(u32 * const * clk_domains,u32 * const * clk_modules_disable,u8 wait_for_disable)207983e3700STom Rini void do_disable_clocks(u32 *const *clk_domains,
208983e3700STom Rini u32 *const *clk_modules_disable,
209983e3700STom Rini u8 wait_for_disable)
210983e3700STom Rini {
211983e3700STom Rini u32 i, max = 100;
212983e3700STom Rini
213983e3700STom Rini
214983e3700STom Rini /* Clock modules that need to be put in SW_DISABLE */
215983e3700STom Rini for (i = 0; (i < max) && clk_modules_disable[i]; i++)
216983e3700STom Rini disable_clock_module(clk_modules_disable[i],
217983e3700STom Rini wait_for_disable);
218983e3700STom Rini
219983e3700STom Rini /* Put the clock domains in SW_SLEEP mode */
220983e3700STom Rini for (i = 0; (i < max) && clk_domains[i]; i++)
221983e3700STom Rini disable_clock_domain(clk_domains[i]);
222983e3700STom Rini }
223983e3700STom Rini
224983e3700STom Rini /*
225983e3700STom Rini * Before scaling up the clocks we need to have the PMIC scale up the
226983e3700STom Rini * voltages first. This will be dependent on which PMIC is in use
227983e3700STom Rini * and in some cases we may not be scaling things up at all and thus not
228983e3700STom Rini * need to do anything here.
229983e3700STom Rini */
scale_vcores(void)230983e3700STom Rini __weak void scale_vcores(void)
231983e3700STom Rini {
232983e3700STom Rini }
233983e3700STom Rini
setup_early_clocks(void)234983e3700STom Rini void setup_early_clocks(void)
235983e3700STom Rini {
236983e3700STom Rini setup_clocks_for_console();
237983e3700STom Rini enable_basic_clocks();
238983e3700STom Rini timer_init();
239983e3700STom Rini }
240983e3700STom Rini
prcm_init(void)241983e3700STom Rini void prcm_init(void)
242983e3700STom Rini {
243983e3700STom Rini scale_vcores();
244983e3700STom Rini setup_dplls();
245983e3700STom Rini }
2467619badbSTero Kristo
rtc_only_prcm_init(void)2477619badbSTero Kristo void rtc_only_prcm_init(void)
2487619badbSTero Kristo {
2497619badbSTero Kristo const struct dpll_params *params;
2507619badbSTero Kristo
2517619badbSTero Kristo rtc_only_enable_basic_clocks();
2527619badbSTero Kristo
2537619badbSTero Kristo params = get_dpll_ddr_params();
2547619badbSTero Kristo do_setup_dpll(&dpll_ddr_regs, params);
2557619badbSTero Kristo }
256