]> git.sur5r.net Git - u-boot/blob - drivers/clk/renesas/clk-rcar-gen2.c
Merge branch 'master' of git://git.denx.de/u-boot-sunxi
[u-boot] / drivers / clk / renesas / clk-rcar-gen2.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Renesas RCar Gen2 CPG MSSR driver
4  *
5  * Copyright (C) 2017 Marek Vasut <marek.vasut@gmail.com>
6  *
7  * Based on the following driver from Linux kernel:
8  * r8a7796 Clock Pulse Generator / Module Standby and Software Reset
9  *
10  * Copyright (C) 2016 Glider bvba
11  */
12
13 #include <common.h>
14 #include <clk-uclass.h>
15 #include <dm.h>
16 #include <errno.h>
17 #include <asm/io.h>
18
19 #include <dt-bindings/clock/renesas-cpg-mssr.h>
20
21 #include "renesas-cpg-mssr.h"
22 #include "rcar-gen2-cpg.h"
23
24 #define CPG_RST_MODEMR          0x0060
25
26 #define CPG_PLL0CR              0x00d8
27 #define CPG_SDCKCR              0x0074
28
29 struct clk_div_table {
30         u8      val;
31         u8      div;
32 };
33
34 /* SDHI divisors */
35 static const struct clk_div_table cpg_sdh_div_table[] = {
36         {  0,  2 }, {  1,  3 }, {  2,  4 }, {  3,  6 },
37         {  4,  8 }, {  5, 12 }, {  6, 16 }, {  7, 18 },
38         {  8, 24 }, { 10, 36 }, { 11, 48 }, {  0,  0 },
39 };
40
41 static const struct clk_div_table cpg_sd01_div_table[] = {
42         {  4,  8 }, {  5, 12 }, {  6, 16 }, {  7, 18 },
43         {  8, 24 }, { 10, 36 }, { 11, 48 }, { 12, 10 },
44         {  0,  0 },
45 };
46
47 static u8 gen2_clk_get_sdh_div(const struct clk_div_table *table, u8 div)
48 {
49         while ((*table++).val) {
50                 if ((*table).div == div)
51                         return div;
52         }
53         return 0xff;
54 }
55
56 static int gen2_clk_enable(struct clk *clk)
57 {
58         struct gen2_clk_priv *priv = dev_get_priv(clk->dev);
59
60         return renesas_clk_endisable(clk, priv->base, true);
61 }
62
63 static int gen2_clk_disable(struct clk *clk)
64 {
65         struct gen2_clk_priv *priv = dev_get_priv(clk->dev);
66
67         return renesas_clk_endisable(clk, priv->base, false);
68 }
69
70 static ulong gen2_clk_get_rate(struct clk *clk)
71 {
72         struct gen2_clk_priv *priv = dev_get_priv(clk->dev);
73         struct cpg_mssr_info *info = priv->info;
74         struct clk parent;
75         const struct cpg_core_clk *core;
76         const struct rcar_gen2_cpg_pll_config *pll_config =
77                                         priv->cpg_pll_config;
78         u32 value, mult, div, rate = 0;
79         int ret;
80
81         debug("%s[%i] Clock: id=%lu\n", __func__, __LINE__, clk->id);
82
83         ret = renesas_clk_get_parent(clk, info, &parent);
84         if (ret) {
85                 printf("%s[%i] parent fail, ret=%i\n", __func__, __LINE__, ret);
86                 return ret;
87         }
88
89         if (renesas_clk_is_mod(clk)) {
90                 rate = gen2_clk_get_rate(&parent);
91                 debug("%s[%i] MOD clk: parent=%lu => rate=%u\n",
92                       __func__, __LINE__, parent.id, rate);
93                 return rate;
94         }
95
96         ret = renesas_clk_get_core(clk, info, &core);
97         if (ret)
98                 return ret;
99
100         switch (core->type) {
101         case CLK_TYPE_IN:
102                 if (core->id == info->clk_extal_id) {
103                         rate = clk_get_rate(&priv->clk_extal);
104                         debug("%s[%i] EXTAL clk: rate=%u\n",
105                               __func__, __LINE__, rate);
106                         return rate;
107                 }
108
109                 if (core->id == info->clk_extal_usb_id) {
110                         rate = clk_get_rate(&priv->clk_extal_usb);
111                         debug("%s[%i] EXTALR clk: rate=%u\n",
112                               __func__, __LINE__, rate);
113                         return rate;
114                 }
115
116                 return -EINVAL;
117
118         case CLK_TYPE_FF:
119                 rate = (gen2_clk_get_rate(&parent) * core->mult) / core->div;
120                 debug("%s[%i] FIXED clk: parent=%i div=%i mul=%i => rate=%u\n",
121                       __func__, __LINE__,
122                       core->parent, core->mult, core->div, rate);
123                 return rate;
124
125         case CLK_TYPE_DIV6P1:   /* DIV6 Clock with 1 parent clock */
126                 value = (readl(priv->base + core->offset) & 0x3f) + 1;
127                 rate = gen2_clk_get_rate(&parent) / value;
128                 debug("%s[%i] DIV6P1 clk: parent=%i div=%i => rate=%u\n",
129                       __func__, __LINE__,
130                       core->parent, value, rate);
131                 return rate;
132
133         case CLK_TYPE_GEN2_MAIN:
134                 rate = gen2_clk_get_rate(&parent) / pll_config->extal_div;
135                 debug("%s[%i] MAIN clk: parent=%i extal_div=%i => rate=%u\n",
136                       __func__, __LINE__,
137                       core->parent, pll_config->extal_div, rate);
138                 return rate;
139
140         case CLK_TYPE_GEN2_PLL0:
141                 /*
142                  * PLL0 is a  configurable multiplier clock except on R-Car
143                  * V2H/E2. Register the PLL0 clock as a fixed factor clock for
144                  * now as there's no generic multiplier clock implementation and
145                  * we  currently  have no need to change  the multiplier value.
146                  */
147                 mult = pll_config->pll0_mult;
148                 if (!mult) {
149                         value = readl(priv->base + CPG_PLL0CR);
150                         mult = (((value >> 24) & 0x7f) + 1) * 2;
151                 }
152
153                 rate = (gen2_clk_get_rate(&parent) * mult) / info->pll0_div;
154                 debug("%s[%i] PLL0 clk: parent=%i mult=%u => rate=%u\n",
155                       __func__, __LINE__, core->parent, mult, rate);
156                 return rate;
157
158         case CLK_TYPE_GEN2_PLL1:
159                 rate = (gen2_clk_get_rate(&parent) * pll_config->pll1_mult) / 2;
160                 debug("%s[%i] PLL1 clk: parent=%i mul=%i => rate=%u\n",
161                       __func__, __LINE__,
162                       core->parent, pll_config->pll1_mult, rate);
163                 return rate;
164
165         case CLK_TYPE_GEN2_PLL3:
166                 rate = gen2_clk_get_rate(&parent) * pll_config->pll3_mult;
167                 debug("%s[%i] PLL3 clk: parent=%i mul=%i => rate=%u\n",
168                       __func__, __LINE__,
169                       core->parent, pll_config->pll3_mult, rate);
170                 return rate;
171
172         case CLK_TYPE_GEN2_SDH:
173                 value = (readl(priv->base + CPG_SDCKCR) >> 8) & 0xf;
174                 div = gen2_clk_get_sdh_div(cpg_sdh_div_table, value);
175                 rate = gen2_clk_get_rate(&parent) / div;
176                 debug("%s[%i] SDH clk: parent=%i div=%i => rate=%u\n",
177                       __func__, __LINE__,
178                       core->parent, div, rate);
179                 return rate;
180
181         case CLK_TYPE_GEN2_SD0:
182                 value = (readl(priv->base + CPG_SDCKCR) >> 4) & 0xf;
183                 div = gen2_clk_get_sdh_div(cpg_sd01_div_table, value);
184                 rate = gen2_clk_get_rate(&parent) / div;
185                 debug("%s[%i] SD0 clk: parent=%i div=%i => rate=%u\n",
186                       __func__, __LINE__,
187                       core->parent, div, rate);
188                 return rate;
189
190         case CLK_TYPE_GEN2_SD1:
191                 value = (readl(priv->base + CPG_SDCKCR) >> 0) & 0xf;
192                 div = gen2_clk_get_sdh_div(cpg_sd01_div_table, value);
193                 rate = gen2_clk_get_rate(&parent) / div;
194                 debug("%s[%i] SD1 clk: parent=%i div=%i => rate=%u\n",
195                       __func__, __LINE__,
196                       core->parent, div, rate);
197                 return rate;
198         }
199
200         printf("%s[%i] unknown fail\n", __func__, __LINE__);
201
202         return -ENOENT;
203 }
204
205 static ulong gen2_clk_set_rate(struct clk *clk, ulong rate)
206 {
207         return gen2_clk_get_rate(clk);
208 }
209
210 static int gen2_clk_of_xlate(struct clk *clk, struct ofnode_phandle_args *args)
211 {
212         if (args->args_count != 2) {
213                 debug("Invaild args_count: %d\n", args->args_count);
214                 return -EINVAL;
215         }
216
217         clk->id = (args->args[0] << 16) | args->args[1];
218
219         return 0;
220 }
221
222 const struct clk_ops gen2_clk_ops = {
223         .enable         = gen2_clk_enable,
224         .disable        = gen2_clk_disable,
225         .get_rate       = gen2_clk_get_rate,
226         .set_rate       = gen2_clk_set_rate,
227         .of_xlate       = gen2_clk_of_xlate,
228 };
229
230 int gen2_clk_probe(struct udevice *dev)
231 {
232         struct gen2_clk_priv *priv = dev_get_priv(dev);
233         struct cpg_mssr_info *info =
234                 (struct cpg_mssr_info *)dev_get_driver_data(dev);
235         fdt_addr_t rst_base;
236         u32 cpg_mode;
237         int ret;
238
239         priv->base = (struct gen2_base *)devfdt_get_addr(dev);
240         if (!priv->base)
241                 return -EINVAL;
242
243         priv->info = info;
244         ret = fdt_node_offset_by_compatible(gd->fdt_blob, -1, info->reset_node);
245         if (ret < 0)
246                 return ret;
247
248         rst_base = fdtdec_get_addr(gd->fdt_blob, ret, "reg");
249         if (rst_base == FDT_ADDR_T_NONE)
250                 return -EINVAL;
251
252         cpg_mode = readl(rst_base + CPG_RST_MODEMR);
253
254         priv->cpg_pll_config =
255                 (struct rcar_gen2_cpg_pll_config *)info->get_pll_config(cpg_mode);
256         if (!priv->cpg_pll_config->extal_div)
257                 return -EINVAL;
258
259         ret = clk_get_by_name(dev, "extal", &priv->clk_extal);
260         if (ret < 0)
261                 return ret;
262
263         if (info->extal_usb_node) {
264                 ret = clk_get_by_name(dev, info->extal_usb_node,
265                                       &priv->clk_extal_usb);
266                 if (ret < 0)
267                         return ret;
268         }
269
270         return 0;
271 }
272
273 int gen2_clk_remove(struct udevice *dev)
274 {
275         struct gen2_clk_priv *priv = dev_get_priv(dev);
276
277         return renesas_clk_remove(priv->base, priv->info);
278 }