blob: 9caa932e12fb4657acfd9997bd3d84adc37f0afc [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Thomas Abraham166097e2016-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 Abraham166097e2016-04-23 22:18:09 +05306 */
7
8#include <common.h>
9#include <dm.h>
10#include <errno.h>
Stephen Warren135aa952016-06-17 09:44:00 -060011#include <clk-uclass.h>
Thomas Abraham166097e2016-04-23 22:18:09 +053012#include <asm/io.h>
Sam Protsenko0caae9f2024-01-10 21:09:02 -060013#include <div64.h>
Thomas Abraham166097e2016-04-23 22:18:09 +053014#include <dt-bindings/clock/exynos7420-clk.h>
Sam Protsenko0caae9f2024-01-10 21:09:02 -060015
16#define PLL145X_MDIV_SHIFT 16
17#define PLL145X_MDIV_MASK 0x3ff
18#define PLL145X_PDIV_SHIFT 8
19#define PLL145X_PDIV_MASK 0x3f
20#define PLL145X_SDIV_SHIFT 0
21#define PLL145X_SDIV_MASK 0x7
Thomas Abraham166097e2016-04-23 22:18:09 +053022
Thomas Abraham166097e2016-04-23 22:18:09 +053023#define DIVIDER(reg, shift, mask) \
24 (((readl(reg) >> shift) & mask) + 1)
25
26/* CMU TOPC block device structure */
27struct exynos7420_clk_cmu_topc {
28 unsigned int rsvd1[68];
29 unsigned int bus0_pll_con[2];
30 unsigned int rsvd2[2];
31 unsigned int bus1_pll_con[2];
32 unsigned int rsvd3[54];
33 unsigned int mux_sel[6];
34 unsigned int rsvd4[250];
35 unsigned int div[4];
36};
37
38/* CMU TOP0 block device structure */
39struct exynos7420_clk_cmu_top0 {
40 unsigned int rsvd0[128];
41 unsigned int mux_sel[7];
42 unsigned int rsvd1[261];
43 unsigned int div_peric[5];
44};
45
46/**
47 * struct exynos7420_clk_topc_priv - private data for CMU topc clock driver.
48 *
49 * @topc: base address of the memory mapped CMU TOPC controller.
50 * @fin_freq: frequency of the Oscillator clock.
51 * @sclk_bus0_pll_a: frequency of sclk_bus0_pll_a clock.
52 * @sclk_bus1_pll_a: frequency of sclk_bus1_pll_a clock.
53 */
54struct exynos7420_clk_topc_priv {
55 struct exynos7420_clk_cmu_topc *topc;
56 unsigned long fin_freq;
57 unsigned long sclk_bus0_pll_a;
58 unsigned long sclk_bus1_pll_a;
59};
60
61/**
62 * struct exynos7420_clk_top0_priv - private data for CMU top0 clock driver.
63 *
64 * @top0: base address of the memory mapped CMU TOP0 controller.
65 * @mout_top0_bus0_pll_half: frequency of mout_top0_bus0_pll_half clock
66 * @sclk_uart2: frequency of sclk_uart2 clock.
67 */
68struct exynos7420_clk_top0_priv {
69 struct exynos7420_clk_cmu_top0 *top0;
70 unsigned long mout_top0_bus0_pll_half;
71 unsigned long sclk_uart2;
72};
73
Sam Protsenko0caae9f2024-01-10 21:09:02 -060074static unsigned long pll145x_get_rate(unsigned int *con1,
75 unsigned long fin_freq)
76{
77 unsigned long pll_con1 = readl(con1);
78 unsigned long mdiv, sdiv, pdiv;
79 u64 fvco = fin_freq;
80
81 mdiv = (pll_con1 >> PLL145X_MDIV_SHIFT) & PLL145X_MDIV_MASK;
82 pdiv = (pll_con1 >> PLL145X_PDIV_SHIFT) & PLL145X_PDIV_MASK;
83 sdiv = (pll_con1 >> PLL145X_SDIV_SHIFT) & PLL145X_SDIV_MASK;
84
85 fvco *= mdiv;
86 do_div(fvco, (pdiv << sdiv));
87 return (unsigned long)fvco;
88}
89
Stephen Warren135aa952016-06-17 09:44:00 -060090static ulong exynos7420_topc_get_rate(struct clk *clk)
Thomas Abraham166097e2016-04-23 22:18:09 +053091{
Stephen Warren135aa952016-06-17 09:44:00 -060092 struct exynos7420_clk_topc_priv *priv = dev_get_priv(clk->dev);
Thomas Abraham166097e2016-04-23 22:18:09 +053093
Stephen Warren135aa952016-06-17 09:44:00 -060094 switch (clk->id) {
Thomas Abraham166097e2016-04-23 22:18:09 +053095 case DOUT_SCLK_BUS0_PLL:
96 case SCLK_BUS0_PLL_A:
97 case SCLK_BUS0_PLL_B:
98 return priv->sclk_bus0_pll_a;
99 case DOUT_SCLK_BUS1_PLL:
100 case SCLK_BUS1_PLL_A:
101 case SCLK_BUS1_PLL_B:
102 return priv->sclk_bus1_pll_a;
103 default:
104 return 0;
105 }
106}
107
108static struct clk_ops exynos7420_clk_topc_ops = {
Stephen Warren135aa952016-06-17 09:44:00 -0600109 .get_rate = exynos7420_topc_get_rate,
Thomas Abraham166097e2016-04-23 22:18:09 +0530110};
111
112static int exynos7420_clk_topc_probe(struct udevice *dev)
113{
114 struct exynos7420_clk_topc_priv *priv = dev_get_priv(dev);
115 struct exynos7420_clk_cmu_topc *topc;
Stephen Warren135aa952016-06-17 09:44:00 -0600116 struct clk in_clk;
Thomas Abraham166097e2016-04-23 22:18:09 +0530117 unsigned long rate;
118 fdt_addr_t base;
119 int ret;
120
Masahiro Yamada25484932020-07-17 14:36:48 +0900121 base = dev_read_addr(dev);
Thomas Abraham166097e2016-04-23 22:18:09 +0530122 if (base == FDT_ADDR_T_NONE)
123 return -EINVAL;
124
125 topc = (struct exynos7420_clk_cmu_topc *)base;
126 priv->topc = topc;
127
Stephen Warren135aa952016-06-17 09:44:00 -0600128 ret = clk_get_by_index(dev, 0, &in_clk);
Thomas Abraham166097e2016-04-23 22:18:09 +0530129 if (ret >= 0)
Stephen Warren135aa952016-06-17 09:44:00 -0600130 priv->fin_freq = clk_get_rate(&in_clk);
Thomas Abraham166097e2016-04-23 22:18:09 +0530131
132 rate = pll145x_get_rate(&topc->bus0_pll_con[0], priv->fin_freq);
133 if (readl(&topc->mux_sel[1]) & (1 << 16))
134 rate >>= 1;
135 rate /= DIVIDER(&topc->div[3], 0, 0xf);
136 priv->sclk_bus0_pll_a = rate;
137
138 rate = pll145x_get_rate(&topc->bus1_pll_con[0], priv->fin_freq) /
139 DIVIDER(&topc->div[3], 8, 0xf);
140 priv->sclk_bus1_pll_a = rate;
141
142 return 0;
143}
144
Stephen Warren135aa952016-06-17 09:44:00 -0600145static ulong exynos7420_top0_get_rate(struct clk *clk)
Thomas Abraham166097e2016-04-23 22:18:09 +0530146{
Stephen Warren135aa952016-06-17 09:44:00 -0600147 struct exynos7420_clk_top0_priv *priv = dev_get_priv(clk->dev);
Thomas Abraham166097e2016-04-23 22:18:09 +0530148 struct exynos7420_clk_cmu_top0 *top0 = priv->top0;
149
Stephen Warren135aa952016-06-17 09:44:00 -0600150 switch (clk->id) {
Thomas Abraham166097e2016-04-23 22:18:09 +0530151 case CLK_SCLK_UART2:
152 return priv->mout_top0_bus0_pll_half /
153 DIVIDER(&top0->div_peric[3], 8, 0xf);
154 default:
155 return 0;
156 }
157}
158
159static struct clk_ops exynos7420_clk_top0_ops = {
Stephen Warren135aa952016-06-17 09:44:00 -0600160 .get_rate = exynos7420_top0_get_rate,
Thomas Abraham166097e2016-04-23 22:18:09 +0530161};
162
163static int exynos7420_clk_top0_probe(struct udevice *dev)
164{
165 struct exynos7420_clk_top0_priv *priv;
166 struct exynos7420_clk_cmu_top0 *top0;
Stephen Warren135aa952016-06-17 09:44:00 -0600167 struct clk in_clk;
Thomas Abraham166097e2016-04-23 22:18:09 +0530168 fdt_addr_t base;
169 int ret;
170
171 priv = dev_get_priv(dev);
172 if (!priv)
173 return -EINVAL;
174
Masahiro Yamada25484932020-07-17 14:36:48 +0900175 base = dev_read_addr(dev);
Thomas Abraham166097e2016-04-23 22:18:09 +0530176 if (base == FDT_ADDR_T_NONE)
177 return -EINVAL;
178
179 top0 = (struct exynos7420_clk_cmu_top0 *)base;
180 priv->top0 = top0;
181
Stephen Warren135aa952016-06-17 09:44:00 -0600182 ret = clk_get_by_index(dev, 1, &in_clk);
Thomas Abraham166097e2016-04-23 22:18:09 +0530183 if (ret >= 0) {
184 priv->mout_top0_bus0_pll_half =
Stephen Warren135aa952016-06-17 09:44:00 -0600185 clk_get_rate(&in_clk);
Thomas Abraham166097e2016-04-23 22:18:09 +0530186 if (readl(&top0->mux_sel[1]) & (1 << 16))
187 priv->mout_top0_bus0_pll_half >>= 1;
188 }
189
190 return 0;
191}
192
Stephen Warren135aa952016-06-17 09:44:00 -0600193static ulong exynos7420_peric1_get_rate(struct clk *clk)
Thomas Abraham166097e2016-04-23 22:18:09 +0530194{
Stephen Warren135aa952016-06-17 09:44:00 -0600195 struct clk in_clk;
Thomas Abraham166097e2016-04-23 22:18:09 +0530196 unsigned int ret;
197 unsigned long freq = 0;
198
Stephen Warren135aa952016-06-17 09:44:00 -0600199 switch (clk->id) {
Thomas Abraham166097e2016-04-23 22:18:09 +0530200 case SCLK_UART2:
Stephen Warren135aa952016-06-17 09:44:00 -0600201 ret = clk_get_by_index(clk->dev, 3, &in_clk);
Thomas Abraham166097e2016-04-23 22:18:09 +0530202 if (ret < 0)
203 return ret;
Stephen Warren135aa952016-06-17 09:44:00 -0600204 freq = clk_get_rate(&in_clk);
Thomas Abraham166097e2016-04-23 22:18:09 +0530205 break;
206 }
207
208 return freq;
209}
210
211static struct clk_ops exynos7420_clk_peric1_ops = {
Stephen Warren135aa952016-06-17 09:44:00 -0600212 .get_rate = exynos7420_peric1_get_rate,
Thomas Abraham166097e2016-04-23 22:18:09 +0530213};
214
215static const struct udevice_id exynos7420_clk_topc_compat[] = {
216 { .compatible = "samsung,exynos7-clock-topc" },
217 { }
218};
219
220U_BOOT_DRIVER(exynos7420_clk_topc) = {
221 .name = "exynos7420-clock-topc",
222 .id = UCLASS_CLK,
223 .of_match = exynos7420_clk_topc_compat,
224 .probe = exynos7420_clk_topc_probe,
Simon Glass41575d82020-12-03 16:55:17 -0700225 .priv_auto = sizeof(struct exynos7420_clk_topc_priv),
Thomas Abraham166097e2016-04-23 22:18:09 +0530226 .ops = &exynos7420_clk_topc_ops,
Thomas Abraham166097e2016-04-23 22:18:09 +0530227};
228
229static const struct udevice_id exynos7420_clk_top0_compat[] = {
230 { .compatible = "samsung,exynos7-clock-top0" },
231 { }
232};
233
234U_BOOT_DRIVER(exynos7420_clk_top0) = {
235 .name = "exynos7420-clock-top0",
236 .id = UCLASS_CLK,
237 .of_match = exynos7420_clk_top0_compat,
238 .probe = exynos7420_clk_top0_probe,
Simon Glass41575d82020-12-03 16:55:17 -0700239 .priv_auto = sizeof(struct exynos7420_clk_top0_priv),
Thomas Abraham166097e2016-04-23 22:18:09 +0530240 .ops = &exynos7420_clk_top0_ops,
Thomas Abraham166097e2016-04-23 22:18:09 +0530241};
242
243static const struct udevice_id exynos7420_clk_peric1_compat[] = {
244 { .compatible = "samsung,exynos7-clock-peric1" },
245 { }
246};
247
248U_BOOT_DRIVER(exynos7420_clk_peric1) = {
249 .name = "exynos7420-clock-peric1",
250 .id = UCLASS_CLK,
251 .of_match = exynos7420_clk_peric1_compat,
252 .ops = &exynos7420_clk_peric1_ops,
Thomas Abraham166097e2016-04-23 22:18:09 +0530253};