xref: /openbmc/u-boot/arch/arm/cpu/arm926ejs/lpc32xx/clk.c (revision e8f80a5a)
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2011 by Vladimir Zapolskiy <vz@mleia.com>
4  */
5 
6 #include <common.h>
7 #include <div64.h>
8 #include <asm/arch/cpu.h>
9 #include <asm/arch/clk.h>
10 #include <asm/io.h>
11 
12 static struct clk_pm_regs *clk = (struct clk_pm_regs *)CLK_PM_BASE;
13 
get_sys_clk_rate(void)14 unsigned int get_sys_clk_rate(void)
15 {
16 	if (readl(&clk->sysclk_ctrl) & CLK_SYSCLK_PLL397)
17 		return RTC_CLK_FREQUENCY * 397;
18 	else
19 		return OSC_CLK_FREQUENCY;
20 }
21 
get_hclk_pll_rate(void)22 unsigned int get_hclk_pll_rate(void)
23 {
24 	unsigned long long fin, fref, fcco, fout;
25 	u32 val, m_div, n_div, p_div;
26 
27 	/*
28 	 * Valid frequency ranges:
29 	 *     1 * 10^6 <=  Fin <=  20 * 10^6
30 	 *     1 * 10^6 <= Fref <=  27 * 10^6
31 	 *   156 * 10^6 <= Fcco <= 320 * 10^6
32 	 */
33 
34 	fref = fin = get_sys_clk_rate();
35 	if (fin > 20000000ULL || fin < 1000000ULL)
36 		return 0;
37 
38 	val = readl(&clk->hclkpll_ctrl);
39 	m_div = ((val & CLK_HCLK_PLL_FEEDBACK_DIV_MASK) >> 1) + 1;
40 	n_div = ((val & CLK_HCLK_PLL_PREDIV_MASK) >> 9) + 1;
41 	if (val & CLK_HCLK_PLL_DIRECT)
42 		p_div = 0;
43 	else
44 		p_div = ((val & CLK_HCLK_PLL_POSTDIV_MASK) >> 11) + 1;
45 	p_div = 1 << p_div;
46 
47 	if (val & CLK_HCLK_PLL_BYPASS) {
48 		do_div(fin, p_div);
49 		return fin;
50 	}
51 
52 	do_div(fref, n_div);
53 	if (fref > 27000000ULL || fref < 1000000ULL)
54 		return 0;
55 
56 	fcco = fref * m_div;
57 	fout = fcco;
58 	if (val & CLK_HCLK_PLL_FEEDBACK)
59 		fcco *= p_div;
60 	else
61 		do_div(fout, p_div);
62 
63 	if (fcco > 320000000ULL || fcco < 156000000ULL)
64 		return 0;
65 
66 	return fout;
67 }
68 
get_hclk_clk_div(void)69 unsigned int get_hclk_clk_div(void)
70 {
71 	u32 val;
72 
73 	val = readl(&clk->hclkdiv_ctrl) & CLK_HCLK_ARM_PLL_DIV_MASK;
74 
75 	return 1 << val;
76 }
77 
get_hclk_clk_rate(void)78 unsigned int get_hclk_clk_rate(void)
79 {
80 	return get_hclk_pll_rate() / get_hclk_clk_div();
81 }
82 
get_periph_clk_div(void)83 unsigned int get_periph_clk_div(void)
84 {
85 	u32 val;
86 
87 	val = readl(&clk->hclkdiv_ctrl) & CLK_HCLK_PERIPH_DIV_MASK;
88 
89 	return (val >> 2) + 1;
90 }
91 
get_periph_clk_rate(void)92 unsigned int get_periph_clk_rate(void)
93 {
94 	if (!(readl(&clk->pwr_ctrl) & CLK_PWR_NORMAL_RUN))
95 		return get_sys_clk_rate();
96 
97 	return get_hclk_pll_rate() / get_periph_clk_div();
98 }
99 
get_sdram_clk_rate(void)100 unsigned int get_sdram_clk_rate(void)
101 {
102 	unsigned int src_clk;
103 
104 	if (!(readl(&clk->pwr_ctrl) & CLK_PWR_NORMAL_RUN))
105 		return get_sys_clk_rate();
106 
107 	src_clk = get_hclk_pll_rate();
108 
109 	if (readl(&clk->sdramclk_ctrl) & CLK_SDRAM_DDR_SEL) {
110 		/* using DDR */
111 		switch (readl(&clk->hclkdiv_ctrl) & CLK_HCLK_DDRAM_MASK) {
112 		case CLK_HCLK_DDRAM_HALF:
113 			return src_clk/2;
114 		case CLK_HCLK_DDRAM_NOMINAL:
115 			return src_clk;
116 		default:
117 			return 0;
118 		}
119 	} else {
120 		/* using SDR */
121 		switch (readl(&clk->hclkdiv_ctrl) & CLK_HCLK_ARM_PLL_DIV_MASK) {
122 		case CLK_HCLK_ARM_PLL_DIV_4:
123 			return src_clk/4;
124 		case CLK_HCLK_ARM_PLL_DIV_2:
125 			return src_clk/2;
126 		case CLK_HCLK_ARM_PLL_DIV_1:
127 			return src_clk;
128 		default:
129 			return 0;
130 		}
131 	}
132 }
133 
get_serial_clock(void)134 int get_serial_clock(void)
135 {
136 	return get_periph_clk_rate();
137 }
138