blob: 30a101fe8621997713d86f504493117fdfe56a47 [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>
Simon Glass0f2af882020-05-10 11:40:05 -060017#include <log.h>
Marek Vasutf3b8bf72017-07-21 23:18:03 +020018#include <wait_bit.h>
19#include <asm/io.h>
Simon Glass4dcacfc2020-05-10 11:40:13 -060020#include <linux/bitops.h>
Marek Vasutf3b8bf72017-07-21 23:18:03 +020021
Marek Vasut4eb4e6e2018-01-08 14:01:40 +010022#include <dt-bindings/clock/renesas-cpg-mssr.h>
23
24#include "renesas-cpg-mssr.h"
Marek Vasute11008b2018-01-15 16:44:39 +010025#include "rcar-gen3-cpg.h"
Marek Vasutf3b8bf72017-07-21 23:18:03 +020026
27#define CPG_RST_MODEMR 0x0060
28
29#define CPG_PLL0CR 0x00d8
30#define CPG_PLL2CR 0x002c
31#define CPG_PLL4CR 0x01f4
32
Marek Vasutc1aee322017-09-15 21:10:29 +020033#define CPG_RPC_PREDIV_MASK 0x3
34#define CPG_RPC_PREDIV_OFFSET 3
35#define CPG_RPC_POSTDIV_MASK 0x7
36#define CPG_RPC_POSTDIV_OFFSET 0
37
Marek Vasutf3b8bf72017-07-21 23:18:03 +020038/*
Marek Vasutf3b8bf72017-07-21 23:18:03 +020039 * SDn Clock
40 */
41#define CPG_SD_STP_HCK BIT(9)
42#define CPG_SD_STP_CK BIT(8)
43
44#define CPG_SD_STP_MASK (CPG_SD_STP_HCK | CPG_SD_STP_CK)
45#define CPG_SD_FC_MASK (0x7 << 2 | 0x3 << 0)
46
47#define CPG_SD_DIV_TABLE_DATA(stp_hck, stp_ck, sd_srcfc, sd_fc, sd_div) \
48{ \
49 .val = ((stp_hck) ? CPG_SD_STP_HCK : 0) | \
50 ((stp_ck) ? CPG_SD_STP_CK : 0) | \
51 ((sd_srcfc) << 2) | \
52 ((sd_fc) << 0), \
53 .div = (sd_div), \
54}
55
56struct sd_div_table {
57 u32 val;
58 unsigned int div;
59};
60
61/* SDn divider
62 * sd_srcfc sd_fc div
63 * stp_hck stp_ck (div) (div) = sd_srcfc x sd_fc
64 *-------------------------------------------------------------------
65 * 0 0 0 (1) 1 (4) 4
66 * 0 0 1 (2) 1 (4) 8
67 * 1 0 2 (4) 1 (4) 16
68 * 1 0 3 (8) 1 (4) 32
69 * 1 0 4 (16) 1 (4) 64
70 * 0 0 0 (1) 0 (2) 2
71 * 0 0 1 (2) 0 (2) 4
72 * 1 0 2 (4) 0 (2) 8
73 * 1 0 3 (8) 0 (2) 16
74 * 1 0 4 (16) 0 (2) 32
75 */
76static const struct sd_div_table cpg_sd_div_table[] = {
77/* CPG_SD_DIV_TABLE_DATA(stp_hck, stp_ck, sd_srcfc, sd_fc, sd_div) */
78 CPG_SD_DIV_TABLE_DATA(0, 0, 0, 1, 4),
79 CPG_SD_DIV_TABLE_DATA(0, 0, 1, 1, 8),
80 CPG_SD_DIV_TABLE_DATA(1, 0, 2, 1, 16),
81 CPG_SD_DIV_TABLE_DATA(1, 0, 3, 1, 32),
82 CPG_SD_DIV_TABLE_DATA(1, 0, 4, 1, 64),
83 CPG_SD_DIV_TABLE_DATA(0, 0, 0, 0, 2),
84 CPG_SD_DIV_TABLE_DATA(0, 0, 1, 0, 4),
85 CPG_SD_DIV_TABLE_DATA(1, 0, 2, 0, 8),
86 CPG_SD_DIV_TABLE_DATA(1, 0, 3, 0, 16),
87 CPG_SD_DIV_TABLE_DATA(1, 0, 4, 0, 32),
88};
89
Marek Vasut69459b22018-05-31 19:47:42 +020090static int gen3_clk_get_parent(struct gen3_clk_priv *priv, struct clk *clk,
91 struct cpg_mssr_info *info, struct clk *parent)
92{
93 const struct cpg_core_clk *core;
94 int ret;
95
96 if (!renesas_clk_is_mod(clk)) {
97 ret = renesas_clk_get_core(clk, info, &core);
98 if (ret)
99 return ret;
100
Marek Vasut78414832019-03-04 21:38:10 +0100101 if (core->type == CLK_TYPE_GEN3_MDSEL) {
Marek Vasut69459b22018-05-31 19:47:42 +0200102 parent->dev = clk->dev;
103 parent->id = core->parent >> (priv->sscg ? 16 : 0);
104 parent->id &= 0xffff;
105 return 0;
106 }
107 }
108
109 return renesas_clk_get_parent(clk, info, parent);
110}
111
Marek Vasutc26bf892018-10-30 17:54:20 +0100112static int gen3_clk_setup_sdif_div(struct clk *clk, ulong rate)
Marek Vasut5a51be52017-09-15 21:10:08 +0200113{
114 struct gen3_clk_priv *priv = dev_get_priv(clk->dev);
Marek Vasute11008b2018-01-15 16:44:39 +0100115 struct cpg_mssr_info *info = priv->info;
Marek Vasut5a51be52017-09-15 21:10:08 +0200116 const struct cpg_core_clk *core;
117 struct clk parent;
118 int ret;
119
Marek Vasut69459b22018-05-31 19:47:42 +0200120 ret = gen3_clk_get_parent(priv, clk, info, &parent);
Marek Vasut5a51be52017-09-15 21:10:08 +0200121 if (ret) {
122 printf("%s[%i] parent fail, ret=%i\n", __func__, __LINE__, ret);
123 return ret;
124 }
125
Marek Vasute11008b2018-01-15 16:44:39 +0100126 if (renesas_clk_is_mod(&parent))
Marek Vasut5a51be52017-09-15 21:10:08 +0200127 return 0;
128
Marek Vasute11008b2018-01-15 16:44:39 +0100129 ret = renesas_clk_get_core(&parent, info, &core);
Marek Vasut5a51be52017-09-15 21:10:08 +0200130 if (ret)
131 return ret;
132
133 if (core->type != CLK_TYPE_GEN3_SD)
134 return 0;
135
136 debug("%s[%i] SDIF offset=%x\n", __func__, __LINE__, core->offset);
137
Marek Vasutc26bf892018-10-30 17:54:20 +0100138 writel((rate == 400000000) ? 0x4 : 0x1, priv->base + core->offset);
Marek Vasut5a51be52017-09-15 21:10:08 +0200139
140 return 0;
141}
142
Marek Vasute11008b2018-01-15 16:44:39 +0100143static int gen3_clk_enable(struct clk *clk)
Marek Vasutf3b8bf72017-07-21 23:18:03 +0200144{
145 struct gen3_clk_priv *priv = dev_get_priv(clk->dev);
Marek Vasutf3b8bf72017-07-21 23:18:03 +0200146
Marek Vasute11008b2018-01-15 16:44:39 +0100147 return renesas_clk_endisable(clk, priv->base, true);
Marek Vasutf3b8bf72017-07-21 23:18:03 +0200148}
149
150static int gen3_clk_disable(struct clk *clk)
151{
Marek Vasute11008b2018-01-15 16:44:39 +0100152 struct gen3_clk_priv *priv = dev_get_priv(clk->dev);
153
154 return renesas_clk_endisable(clk, priv->base, false);
Marek Vasutf3b8bf72017-07-21 23:18:03 +0200155}
156
Marek Vasut7571ac42018-05-31 19:06:02 +0200157static u64 gen3_clk_get_rate64(struct clk *clk)
Marek Vasutf3b8bf72017-07-21 23:18:03 +0200158{
159 struct gen3_clk_priv *priv = dev_get_priv(clk->dev);
Marek Vasutb9234192018-01-08 16:05:28 +0100160 struct cpg_mssr_info *info = priv->info;
Marek Vasutf3b8bf72017-07-21 23:18:03 +0200161 struct clk parent;
162 const struct cpg_core_clk *core;
163 const struct rcar_gen3_cpg_pll_config *pll_config =
164 priv->cpg_pll_config;
Marek Vasut69459b22018-05-31 19:47:42 +0200165 u32 value, mult, div, prediv, postdiv;
Marek Vasut7571ac42018-05-31 19:06:02 +0200166 u64 rate = 0;
Marek Vasutf3b8bf72017-07-21 23:18:03 +0200167 int i, ret;
168
169 debug("%s[%i] Clock: id=%lu\n", __func__, __LINE__, clk->id);
170
Marek Vasut69459b22018-05-31 19:47:42 +0200171 ret = gen3_clk_get_parent(priv, clk, info, &parent);
Marek Vasutf3b8bf72017-07-21 23:18:03 +0200172 if (ret) {
173 printf("%s[%i] parent fail, ret=%i\n", __func__, __LINE__, ret);
174 return ret;
175 }
176
Marek Vasute11008b2018-01-15 16:44:39 +0100177 if (renesas_clk_is_mod(clk)) {
Marek Vasut7571ac42018-05-31 19:06:02 +0200178 rate = gen3_clk_get_rate64(&parent);
179 debug("%s[%i] MOD clk: parent=%lu => rate=%llu\n",
Marek Vasutf3b8bf72017-07-21 23:18:03 +0200180 __func__, __LINE__, parent.id, rate);
181 return rate;
182 }
183
Marek Vasute11008b2018-01-15 16:44:39 +0100184 ret = renesas_clk_get_core(clk, info, &core);
Marek Vasutf3b8bf72017-07-21 23:18:03 +0200185 if (ret)
186 return ret;
187
188 switch (core->type) {
189 case CLK_TYPE_IN:
Marek Vasutb9234192018-01-08 16:05:28 +0100190 if (core->id == info->clk_extal_id) {
Marek Vasutf3b8bf72017-07-21 23:18:03 +0200191 rate = clk_get_rate(&priv->clk_extal);
Marek Vasut7571ac42018-05-31 19:06:02 +0200192 debug("%s[%i] EXTAL clk: rate=%llu\n",
Marek Vasutf3b8bf72017-07-21 23:18:03 +0200193 __func__, __LINE__, rate);
194 return rate;
195 }
196
Marek Vasutb9234192018-01-08 16:05:28 +0100197 if (core->id == info->clk_extalr_id) {
Marek Vasutf3b8bf72017-07-21 23:18:03 +0200198 rate = clk_get_rate(&priv->clk_extalr);
Marek Vasut7571ac42018-05-31 19:06:02 +0200199 debug("%s[%i] EXTALR clk: rate=%llu\n",
Marek Vasutf3b8bf72017-07-21 23:18:03 +0200200 __func__, __LINE__, rate);
201 return rate;
202 }
203
204 return -EINVAL;
205
206 case CLK_TYPE_GEN3_MAIN:
Marek Vasut7571ac42018-05-31 19:06:02 +0200207 rate = gen3_clk_get_rate64(&parent) / pll_config->extal_div;
208 debug("%s[%i] MAIN clk: parent=%i extal_div=%i => rate=%llu\n",
Marek Vasutf3b8bf72017-07-21 23:18:03 +0200209 __func__, __LINE__,
210 core->parent, pll_config->extal_div, rate);
211 return rate;
212
213 case CLK_TYPE_GEN3_PLL0:
214 value = readl(priv->base + CPG_PLL0CR);
215 mult = (((value >> 24) & 0x7f) + 1) * 2;
Marek Vasut7571ac42018-05-31 19:06:02 +0200216 rate = gen3_clk_get_rate64(&parent) * mult;
217 debug("%s[%i] PLL0 clk: parent=%i mult=%u => rate=%llu\n",
Marek Vasutf3b8bf72017-07-21 23:18:03 +0200218 __func__, __LINE__, core->parent, mult, rate);
219 return rate;
220
221 case CLK_TYPE_GEN3_PLL1:
Marek Vasut7571ac42018-05-31 19:06:02 +0200222 rate = gen3_clk_get_rate64(&parent) * pll_config->pll1_mult;
Marek Vasut52389f02018-05-31 19:25:41 +0200223 rate /= pll_config->pll1_div;
224 debug("%s[%i] PLL1 clk: parent=%i mul=%i div=%i => rate=%llu\n",
Marek Vasutf3b8bf72017-07-21 23:18:03 +0200225 __func__, __LINE__,
Marek Vasut52389f02018-05-31 19:25:41 +0200226 core->parent, pll_config->pll1_mult,
227 pll_config->pll1_div, rate);
Marek Vasutf3b8bf72017-07-21 23:18:03 +0200228 return rate;
229
230 case CLK_TYPE_GEN3_PLL2:
231 value = readl(priv->base + CPG_PLL2CR);
232 mult = (((value >> 24) & 0x7f) + 1) * 2;
Marek Vasut7571ac42018-05-31 19:06:02 +0200233 rate = gen3_clk_get_rate64(&parent) * mult;
234 debug("%s[%i] PLL2 clk: parent=%i mult=%u => rate=%llu\n",
Marek Vasutf3b8bf72017-07-21 23:18:03 +0200235 __func__, __LINE__, core->parent, mult, rate);
236 return rate;
237
238 case CLK_TYPE_GEN3_PLL3:
Marek Vasut7571ac42018-05-31 19:06:02 +0200239 rate = gen3_clk_get_rate64(&parent) * pll_config->pll3_mult;
Marek Vasut52389f02018-05-31 19:25:41 +0200240 rate /= pll_config->pll3_div;
241 debug("%s[%i] PLL3 clk: parent=%i mul=%i div=%i => rate=%llu\n",
Marek Vasutf3b8bf72017-07-21 23:18:03 +0200242 __func__, __LINE__,
Marek Vasut52389f02018-05-31 19:25:41 +0200243 core->parent, pll_config->pll3_mult,
244 pll_config->pll3_div, rate);
Marek Vasutf3b8bf72017-07-21 23:18:03 +0200245 return rate;
246
247 case CLK_TYPE_GEN3_PLL4:
248 value = readl(priv->base + CPG_PLL4CR);
249 mult = (((value >> 24) & 0x7f) + 1) * 2;
Marek Vasut7571ac42018-05-31 19:06:02 +0200250 rate = gen3_clk_get_rate64(&parent) * mult;
251 debug("%s[%i] PLL4 clk: parent=%i mult=%u => rate=%llu\n",
Marek Vasutf3b8bf72017-07-21 23:18:03 +0200252 __func__, __LINE__, core->parent, mult, rate);
253 return rate;
254
255 case CLK_TYPE_FF:
Marek Vasut7571ac42018-05-31 19:06:02 +0200256 rate = (gen3_clk_get_rate64(&parent) * core->mult) / core->div;
257 debug("%s[%i] FIXED clk: parent=%i mul=%i div=%i => rate=%llu\n",
Marek Vasutf3b8bf72017-07-21 23:18:03 +0200258 __func__, __LINE__,
259 core->parent, core->mult, core->div, rate);
260 return rate;
261
Marek Vasut78414832019-03-04 21:38:10 +0100262 case CLK_TYPE_GEN3_MDSEL:
Marek Vasut69459b22018-05-31 19:47:42 +0200263 div = (core->div >> (priv->sscg ? 16 : 0)) & 0xffff;
264 rate = gen3_clk_get_rate64(&parent) / div;
265 debug("%s[%i] PE clk: parent=%i div=%u => rate=%llu\n",
266 __func__, __LINE__,
267 (core->parent >> (priv->sscg ? 16 : 0)) & 0xffff,
268 div, rate);
269 return rate;
270
Marek Vasutf3b8bf72017-07-21 23:18:03 +0200271 case CLK_TYPE_GEN3_SD: /* FIXME */
272 value = readl(priv->base + core->offset);
273 value &= CPG_SD_STP_MASK | CPG_SD_FC_MASK;
274
275 for (i = 0; i < ARRAY_SIZE(cpg_sd_div_table); i++) {
276 if (cpg_sd_div_table[i].val != value)
277 continue;
278
Marek Vasut7571ac42018-05-31 19:06:02 +0200279 rate = gen3_clk_get_rate64(&parent) /
Marek Vasutf3b8bf72017-07-21 23:18:03 +0200280 cpg_sd_div_table[i].div;
Marek Vasut7571ac42018-05-31 19:06:02 +0200281 debug("%s[%i] SD clk: parent=%i div=%i => rate=%llu\n",
Marek Vasutf3b8bf72017-07-21 23:18:03 +0200282 __func__, __LINE__,
283 core->parent, cpg_sd_div_table[i].div, rate);
284
285 return rate;
286 }
287
288 return -EINVAL;
Marek Vasutc1aee322017-09-15 21:10:29 +0200289
290 case CLK_TYPE_GEN3_RPC:
Marek Vasut7571ac42018-05-31 19:06:02 +0200291 rate = gen3_clk_get_rate64(&parent);
Marek Vasutc1aee322017-09-15 21:10:29 +0200292
293 value = readl(priv->base + core->offset);
294
295 prediv = (value >> CPG_RPC_PREDIV_OFFSET) &
296 CPG_RPC_PREDIV_MASK;
297 if (prediv == 2)
298 rate /= 5;
299 else if (prediv == 3)
300 rate /= 6;
301 else
302 return -EINVAL;
303
304 postdiv = (value >> CPG_RPC_POSTDIV_OFFSET) &
305 CPG_RPC_POSTDIV_MASK;
306 rate /= postdiv + 1;
307
Marek Vasut7571ac42018-05-31 19:06:02 +0200308 debug("%s[%i] RPC clk: parent=%i prediv=%i postdiv=%i => rate=%llu\n",
Marek Vasutc1aee322017-09-15 21:10:29 +0200309 __func__, __LINE__,
310 core->parent, prediv, postdiv, rate);
311
312 return -EINVAL;
313
Marek Vasutf3b8bf72017-07-21 23:18:03 +0200314 }
315
316 printf("%s[%i] unknown fail\n", __func__, __LINE__);
317
318 return -ENOENT;
319}
320
Marek Vasut7571ac42018-05-31 19:06:02 +0200321static ulong gen3_clk_get_rate(struct clk *clk)
322{
323 return gen3_clk_get_rate64(clk);
324}
325
Marek Vasutf3b8bf72017-07-21 23:18:03 +0200326static ulong gen3_clk_set_rate(struct clk *clk, ulong rate)
327{
Marek Vasut414dbbe2018-01-11 16:28:31 +0100328 /* Force correct SD-IF divider configuration if applicable */
Marek Vasutc26bf892018-10-30 17:54:20 +0100329 gen3_clk_setup_sdif_div(clk, rate);
Marek Vasut7571ac42018-05-31 19:06:02 +0200330 return gen3_clk_get_rate64(clk);
Marek Vasutf3b8bf72017-07-21 23:18:03 +0200331}
332
333static int gen3_clk_of_xlate(struct clk *clk, struct ofnode_phandle_args *args)
334{
335 if (args->args_count != 2) {
336 debug("Invaild args_count: %d\n", args->args_count);
337 return -EINVAL;
338 }
339
340 clk->id = (args->args[0] << 16) | args->args[1];
341
342 return 0;
343}
344
Marek Vasut4eb4e6e2018-01-08 14:01:40 +0100345const struct clk_ops gen3_clk_ops = {
Marek Vasutf3b8bf72017-07-21 23:18:03 +0200346 .enable = gen3_clk_enable,
347 .disable = gen3_clk_disable,
348 .get_rate = gen3_clk_get_rate,
349 .set_rate = gen3_clk_set_rate,
350 .of_xlate = gen3_clk_of_xlate,
351};
352
Marek Vasut4eb4e6e2018-01-08 14:01:40 +0100353int gen3_clk_probe(struct udevice *dev)
Marek Vasutf3b8bf72017-07-21 23:18:03 +0200354{
355 struct gen3_clk_priv *priv = dev_get_priv(dev);
Marek Vasut4eb4e6e2018-01-08 14:01:40 +0100356 struct cpg_mssr_info *info =
357 (struct cpg_mssr_info *)dev_get_driver_data(dev);
Marek Vasutf3b8bf72017-07-21 23:18:03 +0200358 fdt_addr_t rst_base;
359 u32 cpg_mode;
360 int ret;
361
Masahiro Yamada1096ae12020-07-17 14:36:46 +0900362 priv->base = dev_read_addr_ptr(dev);
Marek Vasutf3b8bf72017-07-21 23:18:03 +0200363 if (!priv->base)
364 return -EINVAL;
365
Marek Vasut4eb4e6e2018-01-08 14:01:40 +0100366 priv->info = info;
367 ret = fdt_node_offset_by_compatible(gd->fdt_blob, -1, info->reset_node);
368 if (ret < 0)
369 return ret;
Marek Vasutf3b8bf72017-07-21 23:18:03 +0200370
371 rst_base = fdtdec_get_addr(gd->fdt_blob, ret, "reg");
372 if (rst_base == FDT_ADDR_T_NONE)
373 return -EINVAL;
374
375 cpg_mode = readl(rst_base + CPG_RST_MODEMR);
376
Marek Vasut28f90042018-01-16 19:23:17 +0100377 priv->cpg_pll_config =
378 (struct rcar_gen3_cpg_pll_config *)info->get_pll_config(cpg_mode);
Marek Vasutf3b8bf72017-07-21 23:18:03 +0200379 if (!priv->cpg_pll_config->extal_div)
380 return -EINVAL;
381
Marek Vasut69459b22018-05-31 19:47:42 +0200382 priv->sscg = !(cpg_mode & BIT(12));
383
Marek Vasutf3b8bf72017-07-21 23:18:03 +0200384 ret = clk_get_by_name(dev, "extal", &priv->clk_extal);
385 if (ret < 0)
386 return ret;
387
Marek Vasut4eb4e6e2018-01-08 14:01:40 +0100388 if (info->extalr_node) {
389 ret = clk_get_by_name(dev, info->extalr_node, &priv->clk_extalr);
Marek Vasutfb0aa292017-10-08 21:09:15 +0200390 if (ret < 0)
391 return ret;
392 }
Marek Vasutf3b8bf72017-07-21 23:18:03 +0200393
394 return 0;
395}
396
Marek Vasut4eb4e6e2018-01-08 14:01:40 +0100397int gen3_clk_remove(struct udevice *dev)
Marek Vasutdf6a1142017-11-25 22:08:55 +0100398{
399 struct gen3_clk_priv *priv = dev_get_priv(dev);
Marek Vasutdf6a1142017-11-25 22:08:55 +0100400
Marek Vasute11008b2018-01-15 16:44:39 +0100401 return renesas_clk_remove(priv->base, priv->info);
Marek Vasutdf6a1142017-11-25 22:08:55 +0100402}