1 // SPDX-License-Identifier: GPL-2.0+
3 * Renesas RCar Gen3 CPG MSSR driver
5 * Copyright (C) 2017 Marek Vasut <marek.vasut@gmail.com>
7 * Based on the following driver from Linux kernel:
8 * r8a7796 Clock Pulse Generator / Module Standby and Software Reset
10 * Copyright (C) 2016 Glider bvba
14 #include <clk-uclass.h>
20 #include <linux/bitops.h>
22 #include <dt-bindings/clock/renesas-cpg-mssr.h>
24 #include "renesas-cpg-mssr.h"
25 #include "rcar-gen3-cpg.h"
27 #define CPG_RST_MODEMR 0x0060
29 #define CPG_PLL0CR 0x00d8
30 #define CPG_PLL2CR 0x002c
31 #define CPG_PLL4CR 0x01f4
33 #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
41 #define CPG_SD_STP_HCK BIT(9)
42 #define CPG_SD_STP_CK BIT(8)
44 #define CPG_SD_STP_MASK (CPG_SD_STP_HCK | CPG_SD_STP_CK)
45 #define CPG_SD_FC_MASK (0x7 << 2 | 0x3 << 0)
47 #define CPG_SD_DIV_TABLE_DATA(stp_hck, stp_ck, sd_srcfc, sd_fc, sd_div) \
49 .val = ((stp_hck) ? CPG_SD_STP_HCK : 0) | \
50 ((stp_ck) ? CPG_SD_STP_CK : 0) | \
63 * stp_hck stp_ck (div) (div) = sd_srcfc x sd_fc
64 *-------------------------------------------------------------------
76 static 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),
90 static int gen3_clk_get_parent(struct gen3_clk_priv *priv, struct clk *clk,
91 struct cpg_mssr_info *info, struct clk *parent)
93 const struct cpg_core_clk *core;
96 if (!renesas_clk_is_mod(clk)) {
97 ret = renesas_clk_get_core(clk, info, &core);
101 if (core->type == CLK_TYPE_GEN3_MDSEL) {
102 parent->dev = clk->dev;
103 parent->id = core->parent >> (priv->sscg ? 16 : 0);
104 parent->id &= 0xffff;
109 return renesas_clk_get_parent(clk, info, parent);
112 static int gen3_clk_setup_sdif_div(struct clk *clk, ulong rate)
114 struct gen3_clk_priv *priv = dev_get_priv(clk->dev);
115 struct cpg_mssr_info *info = priv->info;
116 const struct cpg_core_clk *core;
120 ret = gen3_clk_get_parent(priv, clk, info, &parent);
122 printf("%s[%i] parent fail, ret=%i\n", __func__, __LINE__, ret);
126 if (renesas_clk_is_mod(&parent))
129 ret = renesas_clk_get_core(&parent, info, &core);
133 if (core->type != CLK_TYPE_GEN3_SD)
136 debug("%s[%i] SDIF offset=%x\n", __func__, __LINE__, core->offset);
138 writel((rate == 400000000) ? 0x4 : 0x1, priv->base + core->offset);
143 static int gen3_clk_enable(struct clk *clk)
145 struct gen3_clk_priv *priv = dev_get_priv(clk->dev);
147 return renesas_clk_endisable(clk, priv->base, true);
150 static int gen3_clk_disable(struct clk *clk)
152 struct gen3_clk_priv *priv = dev_get_priv(clk->dev);
154 return renesas_clk_endisable(clk, priv->base, false);
157 static u64 gen3_clk_get_rate64(struct clk *clk)
159 struct gen3_clk_priv *priv = dev_get_priv(clk->dev);
160 struct cpg_mssr_info *info = priv->info;
162 const struct cpg_core_clk *core;
163 const struct rcar_gen3_cpg_pll_config *pll_config =
164 priv->cpg_pll_config;
165 u32 value, mult, div, prediv, postdiv;
169 debug("%s[%i] Clock: id=%lu\n", __func__, __LINE__, clk->id);
171 ret = gen3_clk_get_parent(priv, clk, info, &parent);
173 printf("%s[%i] parent fail, ret=%i\n", __func__, __LINE__, ret);
177 if (renesas_clk_is_mod(clk)) {
178 rate = gen3_clk_get_rate64(&parent);
179 debug("%s[%i] MOD clk: parent=%lu => rate=%llu\n",
180 __func__, __LINE__, parent.id, rate);
184 ret = renesas_clk_get_core(clk, info, &core);
188 switch (core->type) {
190 if (core->id == info->clk_extal_id) {
191 rate = clk_get_rate(&priv->clk_extal);
192 debug("%s[%i] EXTAL clk: rate=%llu\n",
193 __func__, __LINE__, rate);
197 if (core->id == info->clk_extalr_id) {
198 rate = clk_get_rate(&priv->clk_extalr);
199 debug("%s[%i] EXTALR clk: rate=%llu\n",
200 __func__, __LINE__, rate);
206 case CLK_TYPE_GEN3_MAIN:
207 rate = gen3_clk_get_rate64(&parent) / pll_config->extal_div;
208 debug("%s[%i] MAIN clk: parent=%i extal_div=%i => rate=%llu\n",
210 core->parent, pll_config->extal_div, rate);
213 case CLK_TYPE_GEN3_PLL0:
214 value = readl(priv->base + CPG_PLL0CR);
215 mult = (((value >> 24) & 0x7f) + 1) * 2;
216 rate = gen3_clk_get_rate64(&parent) * mult;
217 debug("%s[%i] PLL0 clk: parent=%i mult=%u => rate=%llu\n",
218 __func__, __LINE__, core->parent, mult, rate);
221 case CLK_TYPE_GEN3_PLL1:
222 rate = gen3_clk_get_rate64(&parent) * pll_config->pll1_mult;
223 rate /= pll_config->pll1_div;
224 debug("%s[%i] PLL1 clk: parent=%i mul=%i div=%i => rate=%llu\n",
226 core->parent, pll_config->pll1_mult,
227 pll_config->pll1_div, rate);
230 case CLK_TYPE_GEN3_PLL2:
231 value = readl(priv->base + CPG_PLL2CR);
232 mult = (((value >> 24) & 0x7f) + 1) * 2;
233 rate = gen3_clk_get_rate64(&parent) * mult;
234 debug("%s[%i] PLL2 clk: parent=%i mult=%u => rate=%llu\n",
235 __func__, __LINE__, core->parent, mult, rate);
238 case CLK_TYPE_GEN3_PLL3:
239 rate = gen3_clk_get_rate64(&parent) * pll_config->pll3_mult;
240 rate /= pll_config->pll3_div;
241 debug("%s[%i] PLL3 clk: parent=%i mul=%i div=%i => rate=%llu\n",
243 core->parent, pll_config->pll3_mult,
244 pll_config->pll3_div, rate);
247 case CLK_TYPE_GEN3_PLL4:
248 value = readl(priv->base + CPG_PLL4CR);
249 mult = (((value >> 24) & 0x7f) + 1) * 2;
250 rate = gen3_clk_get_rate64(&parent) * mult;
251 debug("%s[%i] PLL4 clk: parent=%i mult=%u => rate=%llu\n",
252 __func__, __LINE__, core->parent, mult, rate);
256 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",
259 core->parent, core->mult, core->div, rate);
262 case CLK_TYPE_GEN3_MDSEL:
263 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",
267 (core->parent >> (priv->sscg ? 16 : 0)) & 0xffff,
271 case CLK_TYPE_GEN3_SD: /* FIXME */
272 value = readl(priv->base + core->offset);
273 value &= CPG_SD_STP_MASK | CPG_SD_FC_MASK;
275 for (i = 0; i < ARRAY_SIZE(cpg_sd_div_table); i++) {
276 if (cpg_sd_div_table[i].val != value)
279 rate = gen3_clk_get_rate64(&parent) /
280 cpg_sd_div_table[i].div;
281 debug("%s[%i] SD clk: parent=%i div=%i => rate=%llu\n",
283 core->parent, cpg_sd_div_table[i].div, rate);
290 case CLK_TYPE_GEN3_RPC:
291 rate = gen3_clk_get_rate64(&parent);
293 value = readl(priv->base + core->offset);
295 prediv = (value >> CPG_RPC_PREDIV_OFFSET) &
299 else if (prediv == 3)
304 postdiv = (value >> CPG_RPC_POSTDIV_OFFSET) &
305 CPG_RPC_POSTDIV_MASK;
308 debug("%s[%i] RPC clk: parent=%i prediv=%i postdiv=%i => rate=%llu\n",
310 core->parent, prediv, postdiv, rate);
316 printf("%s[%i] unknown fail\n", __func__, __LINE__);
321 static ulong gen3_clk_get_rate(struct clk *clk)
323 return gen3_clk_get_rate64(clk);
326 static ulong gen3_clk_set_rate(struct clk *clk, ulong rate)
328 /* Force correct SD-IF divider configuration if applicable */
329 gen3_clk_setup_sdif_div(clk, rate);
330 return gen3_clk_get_rate64(clk);
333 static int gen3_clk_of_xlate(struct clk *clk, struct ofnode_phandle_args *args)
335 if (args->args_count != 2) {
336 debug("Invaild args_count: %d\n", args->args_count);
340 clk->id = (args->args[0] << 16) | args->args[1];
345 const struct clk_ops gen3_clk_ops = {
346 .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,
353 int gen3_clk_probe(struct udevice *dev)
355 struct gen3_clk_priv *priv = dev_get_priv(dev);
356 struct cpg_mssr_info *info =
357 (struct cpg_mssr_info *)dev_get_driver_data(dev);
362 priv->base = dev_read_addr_ptr(dev);
367 ret = fdt_node_offset_by_compatible(gd->fdt_blob, -1, info->reset_node);
371 rst_base = fdtdec_get_addr(gd->fdt_blob, ret, "reg");
372 if (rst_base == FDT_ADDR_T_NONE)
375 cpg_mode = readl(rst_base + CPG_RST_MODEMR);
377 priv->cpg_pll_config =
378 (struct rcar_gen3_cpg_pll_config *)info->get_pll_config(cpg_mode);
379 if (!priv->cpg_pll_config->extal_div)
382 priv->sscg = !(cpg_mode & BIT(12));
384 ret = clk_get_by_name(dev, "extal", &priv->clk_extal);
388 if (info->extalr_node) {
389 ret = clk_get_by_name(dev, info->extalr_node, &priv->clk_extalr);
397 int gen3_clk_remove(struct udevice *dev)
399 struct gen3_clk_priv *priv = dev_get_priv(dev);
401 return renesas_clk_remove(priv->base, priv->info);