blob: f2550598a417fe0a65d6d021854cd5920f9984cc [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Marek Vasutf3b8bf72017-07-21 23:18:03 +02002/*
Marek Vasut3f1a3a12017-10-09 20:52:33 +02003 * Renesas RCar Gen3 CPG MSSR driver
Marek Vasutf3b8bf72017-07-21 23:18:03 +02004 *
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
Marek Vasutf3b8bf72017-07-21 23:18:03 +020011 */
12
13#include <common.h>
14#include <clk-uclass.h>
15#include <dm.h>
16#include <errno.h>
17#include <wait_bit.h>
18#include <asm/io.h>
19
Marek Vasut4eb4e6e2018-01-08 14:01:40 +010020#include <dt-bindings/clock/renesas-cpg-mssr.h>
21
22#include "renesas-cpg-mssr.h"
Marek Vasute11008b2018-01-15 16:44:39 +010023#include "rcar-gen3-cpg.h"
Marek Vasutf3b8bf72017-07-21 23:18:03 +020024
25#define CPG_RST_MODEMR 0x0060
26
27#define CPG_PLL0CR 0x00d8
28#define CPG_PLL2CR 0x002c
29#define CPG_PLL4CR 0x01f4
30
Marek Vasutc1aee322017-09-15 21:10:29 +020031#define CPG_RPC_PREDIV_MASK 0x3
32#define CPG_RPC_PREDIV_OFFSET 3
33#define CPG_RPC_POSTDIV_MASK 0x7
34#define CPG_RPC_POSTDIV_OFFSET 0
35
Marek Vasutf3b8bf72017-07-21 23:18:03 +020036/*
Marek Vasutf3b8bf72017-07-21 23:18:03 +020037 * SDn Clock
38 */
39#define CPG_SD_STP_HCK BIT(9)
40#define CPG_SD_STP_CK BIT(8)
41
42#define CPG_SD_STP_MASK (CPG_SD_STP_HCK | CPG_SD_STP_CK)
43#define CPG_SD_FC_MASK (0x7 << 2 | 0x3 << 0)
44
45#define CPG_SD_DIV_TABLE_DATA(stp_hck, stp_ck, sd_srcfc, sd_fc, sd_div) \
46{ \
47 .val = ((stp_hck) ? CPG_SD_STP_HCK : 0) | \
48 ((stp_ck) ? CPG_SD_STP_CK : 0) | \
49 ((sd_srcfc) << 2) | \
50 ((sd_fc) << 0), \
51 .div = (sd_div), \
52}
53
54struct sd_div_table {
55 u32 val;
56 unsigned int div;
57};
58
59/* SDn divider
60 * sd_srcfc sd_fc div
61 * stp_hck stp_ck (div) (div) = sd_srcfc x sd_fc
62 *-------------------------------------------------------------------
63 * 0 0 0 (1) 1 (4) 4
64 * 0 0 1 (2) 1 (4) 8
65 * 1 0 2 (4) 1 (4) 16
66 * 1 0 3 (8) 1 (4) 32
67 * 1 0 4 (16) 1 (4) 64
68 * 0 0 0 (1) 0 (2) 2
69 * 0 0 1 (2) 0 (2) 4
70 * 1 0 2 (4) 0 (2) 8
71 * 1 0 3 (8) 0 (2) 16
72 * 1 0 4 (16) 0 (2) 32
73 */
74static const struct sd_div_table cpg_sd_div_table[] = {
75/* CPG_SD_DIV_TABLE_DATA(stp_hck, stp_ck, sd_srcfc, sd_fc, sd_div) */
76 CPG_SD_DIV_TABLE_DATA(0, 0, 0, 1, 4),
77 CPG_SD_DIV_TABLE_DATA(0, 0, 1, 1, 8),
78 CPG_SD_DIV_TABLE_DATA(1, 0, 2, 1, 16),
79 CPG_SD_DIV_TABLE_DATA(1, 0, 3, 1, 32),
80 CPG_SD_DIV_TABLE_DATA(1, 0, 4, 1, 64),
81 CPG_SD_DIV_TABLE_DATA(0, 0, 0, 0, 2),
82 CPG_SD_DIV_TABLE_DATA(0, 0, 1, 0, 4),
83 CPG_SD_DIV_TABLE_DATA(1, 0, 2, 0, 8),
84 CPG_SD_DIV_TABLE_DATA(1, 0, 3, 0, 16),
85 CPG_SD_DIV_TABLE_DATA(1, 0, 4, 0, 32),
86};
87
Marek Vasut5a51be52017-09-15 21:10:08 +020088static int gen3_clk_setup_sdif_div(struct clk *clk)
89{
90 struct gen3_clk_priv *priv = dev_get_priv(clk->dev);
Marek Vasute11008b2018-01-15 16:44:39 +010091 struct cpg_mssr_info *info = priv->info;
Marek Vasut5a51be52017-09-15 21:10:08 +020092 const struct cpg_core_clk *core;
93 struct clk parent;
94 int ret;
95
Marek Vasute11008b2018-01-15 16:44:39 +010096 ret = renesas_clk_get_parent(clk, info, &parent);
Marek Vasut5a51be52017-09-15 21:10:08 +020097 if (ret) {
98 printf("%s[%i] parent fail, ret=%i\n", __func__, __LINE__, ret);
99 return ret;
100 }
101
Marek Vasute11008b2018-01-15 16:44:39 +0100102 if (renesas_clk_is_mod(&parent))
Marek Vasut5a51be52017-09-15 21:10:08 +0200103 return 0;
104
Marek Vasute11008b2018-01-15 16:44:39 +0100105 ret = renesas_clk_get_core(&parent, info, &core);
Marek Vasut5a51be52017-09-15 21:10:08 +0200106 if (ret)
107 return ret;
108
109 if (core->type != CLK_TYPE_GEN3_SD)
110 return 0;
111
112 debug("%s[%i] SDIF offset=%x\n", __func__, __LINE__, core->offset);
113
114 writel(1, priv->base + core->offset);
115
116 return 0;
117}
118
Marek Vasute11008b2018-01-15 16:44:39 +0100119static int gen3_clk_enable(struct clk *clk)
Marek Vasutf3b8bf72017-07-21 23:18:03 +0200120{
121 struct gen3_clk_priv *priv = dev_get_priv(clk->dev);
Marek Vasute11008b2018-01-15 16:44:39 +0100122 int ret = gen3_clk_setup_sdif_div(clk);
Marek Vasutf3b8bf72017-07-21 23:18:03 +0200123
Marek Vasute11008b2018-01-15 16:44:39 +0100124 if (ret)
125 return ret;
Marek Vasutf3b8bf72017-07-21 23:18:03 +0200126
Marek Vasute11008b2018-01-15 16:44:39 +0100127 return renesas_clk_endisable(clk, priv->base, true);
Marek Vasutf3b8bf72017-07-21 23:18:03 +0200128}
129
130static int gen3_clk_disable(struct clk *clk)
131{
Marek Vasute11008b2018-01-15 16:44:39 +0100132 struct gen3_clk_priv *priv = dev_get_priv(clk->dev);
133
134 return renesas_clk_endisable(clk, priv->base, false);
Marek Vasutf3b8bf72017-07-21 23:18:03 +0200135}
136
Marek Vasut7571ac42018-05-31 19:06:02 +0200137static u64 gen3_clk_get_rate64(struct clk *clk)
Marek Vasutf3b8bf72017-07-21 23:18:03 +0200138{
139 struct gen3_clk_priv *priv = dev_get_priv(clk->dev);
Marek Vasutb9234192018-01-08 16:05:28 +0100140 struct cpg_mssr_info *info = priv->info;
Marek Vasutf3b8bf72017-07-21 23:18:03 +0200141 struct clk parent;
142 const struct cpg_core_clk *core;
143 const struct rcar_gen3_cpg_pll_config *pll_config =
144 priv->cpg_pll_config;
Marek Vasut7571ac42018-05-31 19:06:02 +0200145 u32 value, mult, prediv, postdiv;
146 u64 rate = 0;
Marek Vasutf3b8bf72017-07-21 23:18:03 +0200147 int i, ret;
148
149 debug("%s[%i] Clock: id=%lu\n", __func__, __LINE__, clk->id);
150
Marek Vasute11008b2018-01-15 16:44:39 +0100151 ret = renesas_clk_get_parent(clk, info, &parent);
Marek Vasutf3b8bf72017-07-21 23:18:03 +0200152 if (ret) {
153 printf("%s[%i] parent fail, ret=%i\n", __func__, __LINE__, ret);
154 return ret;
155 }
156
Marek Vasute11008b2018-01-15 16:44:39 +0100157 if (renesas_clk_is_mod(clk)) {
Marek Vasut7571ac42018-05-31 19:06:02 +0200158 rate = gen3_clk_get_rate64(&parent);
159 debug("%s[%i] MOD clk: parent=%lu => rate=%llu\n",
Marek Vasutf3b8bf72017-07-21 23:18:03 +0200160 __func__, __LINE__, parent.id, rate);
161 return rate;
162 }
163
Marek Vasute11008b2018-01-15 16:44:39 +0100164 ret = renesas_clk_get_core(clk, info, &core);
Marek Vasutf3b8bf72017-07-21 23:18:03 +0200165 if (ret)
166 return ret;
167
168 switch (core->type) {
169 case CLK_TYPE_IN:
Marek Vasutb9234192018-01-08 16:05:28 +0100170 if (core->id == info->clk_extal_id) {
Marek Vasutf3b8bf72017-07-21 23:18:03 +0200171 rate = clk_get_rate(&priv->clk_extal);
Marek Vasut7571ac42018-05-31 19:06:02 +0200172 debug("%s[%i] EXTAL clk: rate=%llu\n",
Marek Vasutf3b8bf72017-07-21 23:18:03 +0200173 __func__, __LINE__, rate);
174 return rate;
175 }
176
Marek Vasutb9234192018-01-08 16:05:28 +0100177 if (core->id == info->clk_extalr_id) {
Marek Vasutf3b8bf72017-07-21 23:18:03 +0200178 rate = clk_get_rate(&priv->clk_extalr);
Marek Vasut7571ac42018-05-31 19:06:02 +0200179 debug("%s[%i] EXTALR clk: rate=%llu\n",
Marek Vasutf3b8bf72017-07-21 23:18:03 +0200180 __func__, __LINE__, rate);
181 return rate;
182 }
183
184 return -EINVAL;
185
186 case CLK_TYPE_GEN3_MAIN:
Marek Vasut7571ac42018-05-31 19:06:02 +0200187 rate = gen3_clk_get_rate64(&parent) / pll_config->extal_div;
188 debug("%s[%i] MAIN clk: parent=%i extal_div=%i => rate=%llu\n",
Marek Vasutf3b8bf72017-07-21 23:18:03 +0200189 __func__, __LINE__,
190 core->parent, pll_config->extal_div, rate);
191 return rate;
192
193 case CLK_TYPE_GEN3_PLL0:
194 value = readl(priv->base + CPG_PLL0CR);
195 mult = (((value >> 24) & 0x7f) + 1) * 2;
Marek Vasut7571ac42018-05-31 19:06:02 +0200196 rate = gen3_clk_get_rate64(&parent) * mult;
197 debug("%s[%i] PLL0 clk: parent=%i mult=%u => rate=%llu\n",
Marek Vasutf3b8bf72017-07-21 23:18:03 +0200198 __func__, __LINE__, core->parent, mult, rate);
199 return rate;
200
201 case CLK_TYPE_GEN3_PLL1:
Marek Vasut7571ac42018-05-31 19:06:02 +0200202 rate = gen3_clk_get_rate64(&parent) * pll_config->pll1_mult;
Marek Vasut52389f02018-05-31 19:25:41 +0200203 rate /= pll_config->pll1_div;
204 debug("%s[%i] PLL1 clk: parent=%i mul=%i div=%i => rate=%llu\n",
Marek Vasutf3b8bf72017-07-21 23:18:03 +0200205 __func__, __LINE__,
Marek Vasut52389f02018-05-31 19:25:41 +0200206 core->parent, pll_config->pll1_mult,
207 pll_config->pll1_div, rate);
Marek Vasutf3b8bf72017-07-21 23:18:03 +0200208 return rate;
209
210 case CLK_TYPE_GEN3_PLL2:
211 value = readl(priv->base + CPG_PLL2CR);
212 mult = (((value >> 24) & 0x7f) + 1) * 2;
Marek Vasut7571ac42018-05-31 19:06:02 +0200213 rate = gen3_clk_get_rate64(&parent) * mult;
214 debug("%s[%i] PLL2 clk: parent=%i mult=%u => rate=%llu\n",
Marek Vasutf3b8bf72017-07-21 23:18:03 +0200215 __func__, __LINE__, core->parent, mult, rate);
216 return rate;
217
218 case CLK_TYPE_GEN3_PLL3:
Marek Vasut7571ac42018-05-31 19:06:02 +0200219 rate = gen3_clk_get_rate64(&parent) * pll_config->pll3_mult;
Marek Vasut52389f02018-05-31 19:25:41 +0200220 rate /= pll_config->pll3_div;
221 debug("%s[%i] PLL3 clk: parent=%i mul=%i div=%i => rate=%llu\n",
Marek Vasutf3b8bf72017-07-21 23:18:03 +0200222 __func__, __LINE__,
Marek Vasut52389f02018-05-31 19:25:41 +0200223 core->parent, pll_config->pll3_mult,
224 pll_config->pll3_div, rate);
Marek Vasutf3b8bf72017-07-21 23:18:03 +0200225 return rate;
226
227 case CLK_TYPE_GEN3_PLL4:
228 value = readl(priv->base + CPG_PLL4CR);
229 mult = (((value >> 24) & 0x7f) + 1) * 2;
Marek Vasut7571ac42018-05-31 19:06:02 +0200230 rate = gen3_clk_get_rate64(&parent) * mult;
231 debug("%s[%i] PLL4 clk: parent=%i mult=%u => rate=%llu\n",
Marek Vasutf3b8bf72017-07-21 23:18:03 +0200232 __func__, __LINE__, core->parent, mult, rate);
233 return rate;
234
235 case CLK_TYPE_FF:
Marek Vasutfb0aa292017-10-08 21:09:15 +0200236 case CLK_TYPE_GEN3_PE: /* FIXME */
Marek Vasut7571ac42018-05-31 19:06:02 +0200237 rate = (gen3_clk_get_rate64(&parent) * core->mult) / core->div;
238 debug("%s[%i] FIXED clk: parent=%i mul=%i div=%i => rate=%llu\n",
Marek Vasutf3b8bf72017-07-21 23:18:03 +0200239 __func__, __LINE__,
240 core->parent, core->mult, core->div, rate);
241 return rate;
242
243 case CLK_TYPE_GEN3_SD: /* FIXME */
244 value = readl(priv->base + core->offset);
245 value &= CPG_SD_STP_MASK | CPG_SD_FC_MASK;
246
247 for (i = 0; i < ARRAY_SIZE(cpg_sd_div_table); i++) {
248 if (cpg_sd_div_table[i].val != value)
249 continue;
250
Marek Vasut7571ac42018-05-31 19:06:02 +0200251 rate = gen3_clk_get_rate64(&parent) /
Marek Vasutf3b8bf72017-07-21 23:18:03 +0200252 cpg_sd_div_table[i].div;
Marek Vasut7571ac42018-05-31 19:06:02 +0200253 debug("%s[%i] SD clk: parent=%i div=%i => rate=%llu\n",
Marek Vasutf3b8bf72017-07-21 23:18:03 +0200254 __func__, __LINE__,
255 core->parent, cpg_sd_div_table[i].div, rate);
256
257 return rate;
258 }
259
260 return -EINVAL;
Marek Vasutc1aee322017-09-15 21:10:29 +0200261
262 case CLK_TYPE_GEN3_RPC:
Marek Vasut7571ac42018-05-31 19:06:02 +0200263 rate = gen3_clk_get_rate64(&parent);
Marek Vasutc1aee322017-09-15 21:10:29 +0200264
265 value = readl(priv->base + core->offset);
266
267 prediv = (value >> CPG_RPC_PREDIV_OFFSET) &
268 CPG_RPC_PREDIV_MASK;
269 if (prediv == 2)
270 rate /= 5;
271 else if (prediv == 3)
272 rate /= 6;
273 else
274 return -EINVAL;
275
276 postdiv = (value >> CPG_RPC_POSTDIV_OFFSET) &
277 CPG_RPC_POSTDIV_MASK;
278 rate /= postdiv + 1;
279
Marek Vasut7571ac42018-05-31 19:06:02 +0200280 debug("%s[%i] RPC clk: parent=%i prediv=%i postdiv=%i => rate=%llu\n",
Marek Vasutc1aee322017-09-15 21:10:29 +0200281 __func__, __LINE__,
282 core->parent, prediv, postdiv, rate);
283
284 return -EINVAL;
285
Marek Vasutf3b8bf72017-07-21 23:18:03 +0200286 }
287
288 printf("%s[%i] unknown fail\n", __func__, __LINE__);
289
290 return -ENOENT;
291}
292
Marek Vasut7571ac42018-05-31 19:06:02 +0200293static ulong gen3_clk_get_rate(struct clk *clk)
294{
295 return gen3_clk_get_rate64(clk);
296}
297
Marek Vasutf3b8bf72017-07-21 23:18:03 +0200298static ulong gen3_clk_set_rate(struct clk *clk, ulong rate)
299{
Marek Vasut414dbbe2018-01-11 16:28:31 +0100300 /* Force correct SD-IF divider configuration if applicable */
301 gen3_clk_setup_sdif_div(clk);
Marek Vasut7571ac42018-05-31 19:06:02 +0200302 return gen3_clk_get_rate64(clk);
Marek Vasutf3b8bf72017-07-21 23:18:03 +0200303}
304
305static int gen3_clk_of_xlate(struct clk *clk, struct ofnode_phandle_args *args)
306{
307 if (args->args_count != 2) {
308 debug("Invaild args_count: %d\n", args->args_count);
309 return -EINVAL;
310 }
311
312 clk->id = (args->args[0] << 16) | args->args[1];
313
314 return 0;
315}
316
Marek Vasut4eb4e6e2018-01-08 14:01:40 +0100317const struct clk_ops gen3_clk_ops = {
Marek Vasutf3b8bf72017-07-21 23:18:03 +0200318 .enable = gen3_clk_enable,
319 .disable = gen3_clk_disable,
320 .get_rate = gen3_clk_get_rate,
321 .set_rate = gen3_clk_set_rate,
322 .of_xlate = gen3_clk_of_xlate,
323};
324
Marek Vasut4eb4e6e2018-01-08 14:01:40 +0100325int gen3_clk_probe(struct udevice *dev)
Marek Vasutf3b8bf72017-07-21 23:18:03 +0200326{
327 struct gen3_clk_priv *priv = dev_get_priv(dev);
Marek Vasut4eb4e6e2018-01-08 14:01:40 +0100328 struct cpg_mssr_info *info =
329 (struct cpg_mssr_info *)dev_get_driver_data(dev);
Marek Vasutf3b8bf72017-07-21 23:18:03 +0200330 fdt_addr_t rst_base;
331 u32 cpg_mode;
332 int ret;
333
334 priv->base = (struct gen3_base *)devfdt_get_addr(dev);
335 if (!priv->base)
336 return -EINVAL;
337
Marek Vasut4eb4e6e2018-01-08 14:01:40 +0100338 priv->info = info;
339 ret = fdt_node_offset_by_compatible(gd->fdt_blob, -1, info->reset_node);
340 if (ret < 0)
341 return ret;
Marek Vasutf3b8bf72017-07-21 23:18:03 +0200342
343 rst_base = fdtdec_get_addr(gd->fdt_blob, ret, "reg");
344 if (rst_base == FDT_ADDR_T_NONE)
345 return -EINVAL;
346
347 cpg_mode = readl(rst_base + CPG_RST_MODEMR);
348
Marek Vasut28f90042018-01-16 19:23:17 +0100349 priv->cpg_pll_config =
350 (struct rcar_gen3_cpg_pll_config *)info->get_pll_config(cpg_mode);
Marek Vasutf3b8bf72017-07-21 23:18:03 +0200351 if (!priv->cpg_pll_config->extal_div)
352 return -EINVAL;
353
354 ret = clk_get_by_name(dev, "extal", &priv->clk_extal);
355 if (ret < 0)
356 return ret;
357
Marek Vasut4eb4e6e2018-01-08 14:01:40 +0100358 if (info->extalr_node) {
359 ret = clk_get_by_name(dev, info->extalr_node, &priv->clk_extalr);
Marek Vasutfb0aa292017-10-08 21:09:15 +0200360 if (ret < 0)
361 return ret;
362 }
Marek Vasutf3b8bf72017-07-21 23:18:03 +0200363
364 return 0;
365}
366
Marek Vasut4eb4e6e2018-01-08 14:01:40 +0100367int gen3_clk_remove(struct udevice *dev)
Marek Vasutdf6a1142017-11-25 22:08:55 +0100368{
369 struct gen3_clk_priv *priv = dev_get_priv(dev);
Marek Vasutdf6a1142017-11-25 22:08:55 +0100370
Marek Vasute11008b2018-01-15 16:44:39 +0100371 return renesas_clk_remove(priv->base, priv->info);
Marek Vasutdf6a1142017-11-25 22:08:55 +0100372}