blob: 3aa751bf4e42b8634dad43d359769602c79bad43 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Thomas Abrahame3fc84c2016-04-23 22:18:09 +05302/*
3 * Samsung Exynos7420 clock driver.
4 * Copyright (C) 2016 Samsung Electronics
5 * Thomas Abraham <thomas.ab@samsung.com>
Thomas Abrahame3fc84c2016-04-23 22:18:09 +05306 */
7
Thomas Abrahame3fc84c2016-04-23 22:18:09 +05308#include <dm.h>
9#include <errno.h>
Stephen Warrena9622432016-06-17 09:44:00 -060010#include <clk-uclass.h>
Thomas Abrahame3fc84c2016-04-23 22:18:09 +053011#include <asm/io.h>
Sam Protsenko8bcc8842024-01-10 21:09:02 -060012#include <div64.h>
Thomas Abrahame3fc84c2016-04-23 22:18:09 +053013#include <dt-bindings/clock/exynos7420-clk.h>
Sam Protsenko8bcc8842024-01-10 21:09:02 -060014
15#define PLL145X_MDIV_SHIFT 16
16#define PLL145X_MDIV_MASK 0x3ff
17#define PLL145X_PDIV_SHIFT 8
18#define PLL145X_PDIV_MASK 0x3f
19#define PLL145X_SDIV_SHIFT 0
20#define PLL145X_SDIV_MASK 0x7
Thomas Abrahame3fc84c2016-04-23 22:18:09 +053021
Thomas Abrahame3fc84c2016-04-23 22:18:09 +053022#define DIVIDER(reg, shift, mask) \
23 (((readl(reg) >> shift) & mask) + 1)
24
25/* CMU TOPC block device structure */
26struct exynos7420_clk_cmu_topc {
27 unsigned int rsvd1[68];
28 unsigned int bus0_pll_con[2];
29 unsigned int rsvd2[2];
30 unsigned int bus1_pll_con[2];
31 unsigned int rsvd3[54];
32 unsigned int mux_sel[6];
33 unsigned int rsvd4[250];
34 unsigned int div[4];
35};
36
37/* CMU TOP0 block device structure */
38struct exynos7420_clk_cmu_top0 {
39 unsigned int rsvd0[128];
40 unsigned int mux_sel[7];
41 unsigned int rsvd1[261];
42 unsigned int div_peric[5];
43};
44
45/**
46 * struct exynos7420_clk_topc_priv - private data for CMU topc clock driver.
47 *
48 * @topc: base address of the memory mapped CMU TOPC controller.
49 * @fin_freq: frequency of the Oscillator clock.
50 * @sclk_bus0_pll_a: frequency of sclk_bus0_pll_a clock.
51 * @sclk_bus1_pll_a: frequency of sclk_bus1_pll_a clock.
52 */
53struct exynos7420_clk_topc_priv {
54 struct exynos7420_clk_cmu_topc *topc;
55 unsigned long fin_freq;
56 unsigned long sclk_bus0_pll_a;
57 unsigned long sclk_bus1_pll_a;
58};
59
60/**
61 * struct exynos7420_clk_top0_priv - private data for CMU top0 clock driver.
62 *
63 * @top0: base address of the memory mapped CMU TOP0 controller.
64 * @mout_top0_bus0_pll_half: frequency of mout_top0_bus0_pll_half clock
65 * @sclk_uart2: frequency of sclk_uart2 clock.
66 */
67struct exynos7420_clk_top0_priv {
68 struct exynos7420_clk_cmu_top0 *top0;
69 unsigned long mout_top0_bus0_pll_half;
70 unsigned long sclk_uart2;
71};
72
Sam Protsenko8bcc8842024-01-10 21:09:02 -060073static unsigned long pll145x_get_rate(unsigned int *con1,
74 unsigned long fin_freq)
75{
76 unsigned long pll_con1 = readl(con1);
77 unsigned long mdiv, sdiv, pdiv;
78 u64 fvco = fin_freq;
79
80 mdiv = (pll_con1 >> PLL145X_MDIV_SHIFT) & PLL145X_MDIV_MASK;
81 pdiv = (pll_con1 >> PLL145X_PDIV_SHIFT) & PLL145X_PDIV_MASK;
82 sdiv = (pll_con1 >> PLL145X_SDIV_SHIFT) & PLL145X_SDIV_MASK;
83
84 fvco *= mdiv;
85 do_div(fvco, (pdiv << sdiv));
86 return (unsigned long)fvco;
87}
88
Stephen Warrena9622432016-06-17 09:44:00 -060089static ulong exynos7420_topc_get_rate(struct clk *clk)
Thomas Abrahame3fc84c2016-04-23 22:18:09 +053090{
Stephen Warrena9622432016-06-17 09:44:00 -060091 struct exynos7420_clk_topc_priv *priv = dev_get_priv(clk->dev);
Thomas Abrahame3fc84c2016-04-23 22:18:09 +053092
Stephen Warrena9622432016-06-17 09:44:00 -060093 switch (clk->id) {
Thomas Abrahame3fc84c2016-04-23 22:18:09 +053094 case DOUT_SCLK_BUS0_PLL:
95 case SCLK_BUS0_PLL_A:
96 case SCLK_BUS0_PLL_B:
97 return priv->sclk_bus0_pll_a;
98 case DOUT_SCLK_BUS1_PLL:
99 case SCLK_BUS1_PLL_A:
100 case SCLK_BUS1_PLL_B:
101 return priv->sclk_bus1_pll_a;
102 default:
103 return 0;
104 }
105}
106
107static struct clk_ops exynos7420_clk_topc_ops = {
Stephen Warrena9622432016-06-17 09:44:00 -0600108 .get_rate = exynos7420_topc_get_rate,
Thomas Abrahame3fc84c2016-04-23 22:18:09 +0530109};
110
111static int exynos7420_clk_topc_probe(struct udevice *dev)
112{
113 struct exynos7420_clk_topc_priv *priv = dev_get_priv(dev);
114 struct exynos7420_clk_cmu_topc *topc;
Stephen Warrena9622432016-06-17 09:44:00 -0600115 struct clk in_clk;
Thomas Abrahame3fc84c2016-04-23 22:18:09 +0530116 unsigned long rate;
117 fdt_addr_t base;
118 int ret;
119
Masahiro Yamadaa89b4de2020-07-17 14:36:48 +0900120 base = dev_read_addr(dev);
Thomas Abrahame3fc84c2016-04-23 22:18:09 +0530121 if (base == FDT_ADDR_T_NONE)
122 return -EINVAL;
123
124 topc = (struct exynos7420_clk_cmu_topc *)base;
125 priv->topc = topc;
126
Stephen Warrena9622432016-06-17 09:44:00 -0600127 ret = clk_get_by_index(dev, 0, &in_clk);
Thomas Abrahame3fc84c2016-04-23 22:18:09 +0530128 if (ret >= 0)
Stephen Warrena9622432016-06-17 09:44:00 -0600129 priv->fin_freq = clk_get_rate(&in_clk);
Thomas Abrahame3fc84c2016-04-23 22:18:09 +0530130
131 rate = pll145x_get_rate(&topc->bus0_pll_con[0], priv->fin_freq);
132 if (readl(&topc->mux_sel[1]) & (1 << 16))
133 rate >>= 1;
134 rate /= DIVIDER(&topc->div[3], 0, 0xf);
135 priv->sclk_bus0_pll_a = rate;
136
137 rate = pll145x_get_rate(&topc->bus1_pll_con[0], priv->fin_freq) /
138 DIVIDER(&topc->div[3], 8, 0xf);
139 priv->sclk_bus1_pll_a = rate;
140
141 return 0;
142}
143
Stephen Warrena9622432016-06-17 09:44:00 -0600144static ulong exynos7420_top0_get_rate(struct clk *clk)
Thomas Abrahame3fc84c2016-04-23 22:18:09 +0530145{
Stephen Warrena9622432016-06-17 09:44:00 -0600146 struct exynos7420_clk_top0_priv *priv = dev_get_priv(clk->dev);
Thomas Abrahame3fc84c2016-04-23 22:18:09 +0530147 struct exynos7420_clk_cmu_top0 *top0 = priv->top0;
148
Stephen Warrena9622432016-06-17 09:44:00 -0600149 switch (clk->id) {
Thomas Abrahame3fc84c2016-04-23 22:18:09 +0530150 case CLK_SCLK_UART2:
151 return priv->mout_top0_bus0_pll_half /
152 DIVIDER(&top0->div_peric[3], 8, 0xf);
153 default:
154 return 0;
155 }
156}
157
158static struct clk_ops exynos7420_clk_top0_ops = {
Stephen Warrena9622432016-06-17 09:44:00 -0600159 .get_rate = exynos7420_top0_get_rate,
Thomas Abrahame3fc84c2016-04-23 22:18:09 +0530160};
161
162static int exynos7420_clk_top0_probe(struct udevice *dev)
163{
164 struct exynos7420_clk_top0_priv *priv;
165 struct exynos7420_clk_cmu_top0 *top0;
Stephen Warrena9622432016-06-17 09:44:00 -0600166 struct clk in_clk;
Thomas Abrahame3fc84c2016-04-23 22:18:09 +0530167 fdt_addr_t base;
168 int ret;
169
170 priv = dev_get_priv(dev);
171 if (!priv)
172 return -EINVAL;
173
Masahiro Yamadaa89b4de2020-07-17 14:36:48 +0900174 base = dev_read_addr(dev);
Thomas Abrahame3fc84c2016-04-23 22:18:09 +0530175 if (base == FDT_ADDR_T_NONE)
176 return -EINVAL;
177
178 top0 = (struct exynos7420_clk_cmu_top0 *)base;
179 priv->top0 = top0;
180
Stephen Warrena9622432016-06-17 09:44:00 -0600181 ret = clk_get_by_index(dev, 1, &in_clk);
Thomas Abrahame3fc84c2016-04-23 22:18:09 +0530182 if (ret >= 0) {
183 priv->mout_top0_bus0_pll_half =
Stephen Warrena9622432016-06-17 09:44:00 -0600184 clk_get_rate(&in_clk);
Thomas Abrahame3fc84c2016-04-23 22:18:09 +0530185 if (readl(&top0->mux_sel[1]) & (1 << 16))
186 priv->mout_top0_bus0_pll_half >>= 1;
187 }
188
189 return 0;
190}
191
Stephen Warrena9622432016-06-17 09:44:00 -0600192static ulong exynos7420_peric1_get_rate(struct clk *clk)
Thomas Abrahame3fc84c2016-04-23 22:18:09 +0530193{
Stephen Warrena9622432016-06-17 09:44:00 -0600194 struct clk in_clk;
Thomas Abrahame3fc84c2016-04-23 22:18:09 +0530195 unsigned int ret;
196 unsigned long freq = 0;
197
Stephen Warrena9622432016-06-17 09:44:00 -0600198 switch (clk->id) {
Thomas Abrahame3fc84c2016-04-23 22:18:09 +0530199 case SCLK_UART2:
Stephen Warrena9622432016-06-17 09:44:00 -0600200 ret = clk_get_by_index(clk->dev, 3, &in_clk);
Thomas Abrahame3fc84c2016-04-23 22:18:09 +0530201 if (ret < 0)
202 return ret;
Stephen Warrena9622432016-06-17 09:44:00 -0600203 freq = clk_get_rate(&in_clk);
Thomas Abrahame3fc84c2016-04-23 22:18:09 +0530204 break;
205 }
206
207 return freq;
208}
209
210static struct clk_ops exynos7420_clk_peric1_ops = {
Stephen Warrena9622432016-06-17 09:44:00 -0600211 .get_rate = exynos7420_peric1_get_rate,
Thomas Abrahame3fc84c2016-04-23 22:18:09 +0530212};
213
214static const struct udevice_id exynos7420_clk_topc_compat[] = {
215 { .compatible = "samsung,exynos7-clock-topc" },
216 { }
217};
218
219U_BOOT_DRIVER(exynos7420_clk_topc) = {
220 .name = "exynos7420-clock-topc",
221 .id = UCLASS_CLK,
222 .of_match = exynos7420_clk_topc_compat,
223 .probe = exynos7420_clk_topc_probe,
Simon Glass8a2b47f2020-12-03 16:55:17 -0700224 .priv_auto = sizeof(struct exynos7420_clk_topc_priv),
Thomas Abrahame3fc84c2016-04-23 22:18:09 +0530225 .ops = &exynos7420_clk_topc_ops,
Thomas Abrahame3fc84c2016-04-23 22:18:09 +0530226};
227
228static const struct udevice_id exynos7420_clk_top0_compat[] = {
229 { .compatible = "samsung,exynos7-clock-top0" },
230 { }
231};
232
233U_BOOT_DRIVER(exynos7420_clk_top0) = {
234 .name = "exynos7420-clock-top0",
235 .id = UCLASS_CLK,
236 .of_match = exynos7420_clk_top0_compat,
237 .probe = exynos7420_clk_top0_probe,
Simon Glass8a2b47f2020-12-03 16:55:17 -0700238 .priv_auto = sizeof(struct exynos7420_clk_top0_priv),
Thomas Abrahame3fc84c2016-04-23 22:18:09 +0530239 .ops = &exynos7420_clk_top0_ops,
Thomas Abrahame3fc84c2016-04-23 22:18:09 +0530240};
241
242static const struct udevice_id exynos7420_clk_peric1_compat[] = {
243 { .compatible = "samsung,exynos7-clock-peric1" },
244 { }
245};
246
247U_BOOT_DRIVER(exynos7420_clk_peric1) = {
248 .name = "exynos7420-clock-peric1",
249 .id = UCLASS_CLK,
250 .of_match = exynos7420_clk_peric1_compat,
251 .ops = &exynos7420_clk_peric1_ops,
Thomas Abrahame3fc84c2016-04-23 22:18:09 +0530252};