blob: 2e11903e7e07a930a1bfe269ec01231d13e5939b [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Vladimir Zapolskiy6b20ef82012-04-19 04:33:08 +00002/*
3 * Copyright (C) 2011 by Vladimir Zapolskiy <vz@mleia.com>
Vladimir Zapolskiy6b20ef82012-04-19 04:33:08 +00004 */
5
Simon Glass85d65312019-12-28 10:44:58 -07006#include <clock_legacy.h>
Vladimir Zapolskiy6b20ef82012-04-19 04:33:08 +00007#include <div64.h>
8#include <asm/arch/cpu.h>
9#include <asm/arch/clk.h>
10#include <asm/io.h>
11
12static struct clk_pm_regs *clk = (struct clk_pm_regs *)CLK_PM_BASE;
13
14unsigned 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
22unsigned 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
Vladimir Zapolskiyc62d1b52015-10-04 23:18:45 +010056 fcco = fref * m_div;
57 fout = fcco;
58 if (val & CLK_HCLK_PLL_FEEDBACK)
59 fcco *= p_div;
60 else
Vladimir Zapolskiy6b20ef82012-04-19 04:33:08 +000061 do_div(fout, p_div);
Vladimir Zapolskiy6b20ef82012-04-19 04:33:08 +000062
63 if (fcco > 320000000ULL || fcco < 156000000ULL)
64 return 0;
65
66 return fout;
67}
68
69unsigned 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
78unsigned int get_hclk_clk_rate(void)
79{
80 return get_hclk_pll_rate() / get_hclk_clk_div();
81}
82
83unsigned 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
92unsigned 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
Albert ARIBAUD \(3ADEV\)ee69a392015-03-31 11:40:51 +0200100unsigned 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
Vladimir Zapolskiy6b20ef82012-04-19 04:33:08 +0000134int get_serial_clock(void)
135{
136 return get_periph_clk_rate();
137}