Merge branch 'master' of git://git.denx.de/u-boot-net
[oweals/u-boot.git] / drivers / clk / exynos / clk-exynos7420.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Samsung Exynos7420 clock driver.
4  * Copyright (C) 2016 Samsung Electronics
5  * Thomas Abraham <thomas.ab@samsung.com>
6  */
7
8 #include <common.h>
9 #include <dm.h>
10 #include <errno.h>
11 #include <clk-uclass.h>
12 #include <asm/io.h>
13 #include <dt-bindings/clock/exynos7420-clk.h>
14 #include "clk-pll.h"
15
16 #define DIVIDER(reg, shift, mask)       \
17         (((readl(reg) >> shift) & mask) + 1)
18
19 /* CMU TOPC block device structure */
20 struct exynos7420_clk_cmu_topc {
21         unsigned int    rsvd1[68];
22         unsigned int    bus0_pll_con[2];
23         unsigned int    rsvd2[2];
24         unsigned int    bus1_pll_con[2];
25         unsigned int    rsvd3[54];
26         unsigned int    mux_sel[6];
27         unsigned int    rsvd4[250];
28         unsigned int    div[4];
29 };
30
31 /* CMU TOP0 block device structure */
32 struct exynos7420_clk_cmu_top0 {
33         unsigned int    rsvd0[128];
34         unsigned int    mux_sel[7];
35         unsigned int    rsvd1[261];
36         unsigned int    div_peric[5];
37 };
38
39 /**
40  * struct exynos7420_clk_topc_priv - private data for CMU topc clock driver.
41  *
42  * @topc: base address of the memory mapped CMU TOPC controller.
43  * @fin_freq: frequency of the Oscillator clock.
44  * @sclk_bus0_pll_a: frequency of sclk_bus0_pll_a clock.
45  * @sclk_bus1_pll_a: frequency of sclk_bus1_pll_a clock.
46  */
47 struct exynos7420_clk_topc_priv {
48         struct exynos7420_clk_cmu_topc *topc;
49         unsigned long fin_freq;
50         unsigned long sclk_bus0_pll_a;
51         unsigned long sclk_bus1_pll_a;
52 };
53
54 /**
55  * struct exynos7420_clk_top0_priv - private data for CMU top0 clock driver.
56  *
57  * @top0: base address of the memory mapped CMU TOP0 controller.
58  * @mout_top0_bus0_pll_half: frequency of mout_top0_bus0_pll_half clock
59  * @sclk_uart2: frequency of sclk_uart2 clock.
60  */
61 struct exynos7420_clk_top0_priv {
62         struct exynos7420_clk_cmu_top0 *top0;
63         unsigned long mout_top0_bus0_pll_half;
64         unsigned long sclk_uart2;
65 };
66
67 static ulong exynos7420_topc_get_rate(struct clk *clk)
68 {
69         struct exynos7420_clk_topc_priv *priv = dev_get_priv(clk->dev);
70
71         switch (clk->id) {
72         case DOUT_SCLK_BUS0_PLL:
73         case SCLK_BUS0_PLL_A:
74         case SCLK_BUS0_PLL_B:
75                 return priv->sclk_bus0_pll_a;
76         case DOUT_SCLK_BUS1_PLL:
77         case SCLK_BUS1_PLL_A:
78         case SCLK_BUS1_PLL_B:
79                 return priv->sclk_bus1_pll_a;
80         default:
81                 return 0;
82         }
83 }
84
85 static struct clk_ops exynos7420_clk_topc_ops = {
86         .get_rate       = exynos7420_topc_get_rate,
87 };
88
89 static int exynos7420_clk_topc_probe(struct udevice *dev)
90 {
91         struct exynos7420_clk_topc_priv *priv = dev_get_priv(dev);
92         struct exynos7420_clk_cmu_topc *topc;
93         struct clk in_clk;
94         unsigned long rate;
95         fdt_addr_t base;
96         int ret;
97
98         base = devfdt_get_addr(dev);
99         if (base == FDT_ADDR_T_NONE)
100                 return -EINVAL;
101
102         topc = (struct exynos7420_clk_cmu_topc *)base;
103         priv->topc = topc;
104
105         ret = clk_get_by_index(dev, 0, &in_clk);
106         if (ret >= 0)
107                 priv->fin_freq = clk_get_rate(&in_clk);
108
109         rate = pll145x_get_rate(&topc->bus0_pll_con[0], priv->fin_freq);
110         if (readl(&topc->mux_sel[1]) & (1 << 16))
111                 rate >>= 1;
112         rate /= DIVIDER(&topc->div[3], 0, 0xf);
113         priv->sclk_bus0_pll_a = rate;
114
115         rate = pll145x_get_rate(&topc->bus1_pll_con[0], priv->fin_freq) /
116                         DIVIDER(&topc->div[3], 8, 0xf);
117         priv->sclk_bus1_pll_a = rate;
118
119         return 0;
120 }
121
122 static ulong exynos7420_top0_get_rate(struct clk *clk)
123 {
124         struct exynos7420_clk_top0_priv *priv = dev_get_priv(clk->dev);
125         struct exynos7420_clk_cmu_top0 *top0 = priv->top0;
126
127         switch (clk->id) {
128         case CLK_SCLK_UART2:
129                 return priv->mout_top0_bus0_pll_half /
130                         DIVIDER(&top0->div_peric[3], 8, 0xf);
131         default:
132                 return 0;
133         }
134 }
135
136 static struct clk_ops exynos7420_clk_top0_ops = {
137         .get_rate       = exynos7420_top0_get_rate,
138 };
139
140 static int exynos7420_clk_top0_probe(struct udevice *dev)
141 {
142         struct exynos7420_clk_top0_priv *priv;
143         struct exynos7420_clk_cmu_top0 *top0;
144         struct clk in_clk;
145         fdt_addr_t base;
146         int ret;
147
148         priv = dev_get_priv(dev);
149         if (!priv)
150                 return -EINVAL;
151
152         base = devfdt_get_addr(dev);
153         if (base == FDT_ADDR_T_NONE)
154                 return -EINVAL;
155
156         top0 = (struct exynos7420_clk_cmu_top0 *)base;
157         priv->top0 = top0;
158
159         ret = clk_get_by_index(dev, 1, &in_clk);
160         if (ret >= 0) {
161                 priv->mout_top0_bus0_pll_half =
162                         clk_get_rate(&in_clk);
163                 if (readl(&top0->mux_sel[1]) & (1 << 16))
164                         priv->mout_top0_bus0_pll_half >>= 1;
165         }
166
167         return 0;
168 }
169
170 static ulong exynos7420_peric1_get_rate(struct clk *clk)
171 {
172         struct clk in_clk;
173         unsigned int ret;
174         unsigned long freq = 0;
175
176         switch (clk->id) {
177         case SCLK_UART2:
178                 ret = clk_get_by_index(clk->dev, 3, &in_clk);
179                 if (ret < 0)
180                         return ret;
181                 freq = clk_get_rate(&in_clk);
182                 break;
183         }
184
185         return freq;
186 }
187
188 static struct clk_ops exynos7420_clk_peric1_ops = {
189         .get_rate       = exynos7420_peric1_get_rate,
190 };
191
192 static const struct udevice_id exynos7420_clk_topc_compat[] = {
193         { .compatible = "samsung,exynos7-clock-topc" },
194         { }
195 };
196
197 U_BOOT_DRIVER(exynos7420_clk_topc) = {
198         .name = "exynos7420-clock-topc",
199         .id = UCLASS_CLK,
200         .of_match = exynos7420_clk_topc_compat,
201         .probe = exynos7420_clk_topc_probe,
202         .priv_auto_alloc_size = sizeof(struct exynos7420_clk_topc_priv),
203         .ops = &exynos7420_clk_topc_ops,
204 };
205
206 static const struct udevice_id exynos7420_clk_top0_compat[] = {
207         { .compatible = "samsung,exynos7-clock-top0" },
208         { }
209 };
210
211 U_BOOT_DRIVER(exynos7420_clk_top0) = {
212         .name = "exynos7420-clock-top0",
213         .id = UCLASS_CLK,
214         .of_match = exynos7420_clk_top0_compat,
215         .probe = exynos7420_clk_top0_probe,
216         .priv_auto_alloc_size = sizeof(struct exynos7420_clk_top0_priv),
217         .ops = &exynos7420_clk_top0_ops,
218 };
219
220 static const struct udevice_id exynos7420_clk_peric1_compat[] = {
221         { .compatible = "samsung,exynos7-clock-peric1" },
222         { }
223 };
224
225 U_BOOT_DRIVER(exynos7420_clk_peric1) = {
226         .name = "exynos7420-clock-peric1",
227         .id = UCLASS_CLK,
228         .of_match = exynos7420_clk_peric1_compat,
229         .ops = &exynos7420_clk_peric1_ops,
230 };