uboot/drivers/clk/renesas/clk-rcar-gen3.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Renesas RCar Gen3 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 <log.h>
  18#include <wait_bit.h>
  19#include <asm/global_data.h>
  20#include <asm/io.h>
  21#include <linux/bitops.h>
  22
  23#include <dt-bindings/clock/renesas-cpg-mssr.h>
  24
  25#include "renesas-cpg-mssr.h"
  26#include "rcar-gen3-cpg.h"
  27
  28#define CPG_PLL0CR              0x00d8
  29#define CPG_PLL2CR              0x002c
  30#define CPG_PLL4CR              0x01f4
  31
  32#define CPG_RPC_PREDIV_MASK     0x3
  33#define CPG_RPC_PREDIV_OFFSET   3
  34#define CPG_RPC_POSTDIV_MASK    0x7
  35#define CPG_RPC_POSTDIV_OFFSET  0
  36
  37/*
  38 * SDn Clock
  39 */
  40#define CPG_SD_STP_HCK          BIT(9)
  41#define CPG_SD_STP_CK           BIT(8)
  42
  43#define CPG_SD_STP_MASK         (CPG_SD_STP_HCK | CPG_SD_STP_CK)
  44#define CPG_SD_FC_MASK          (0x7 << 2 | 0x3 << 0)
  45
  46#define CPG_SD_DIV_TABLE_DATA(stp_hck, stp_ck, sd_srcfc, sd_fc, sd_div) \
  47{ \
  48        .val = ((stp_hck) ? CPG_SD_STP_HCK : 0) | \
  49               ((stp_ck) ? CPG_SD_STP_CK : 0) | \
  50               ((sd_srcfc) << 2) | \
  51               ((sd_fc) << 0), \
  52        .div = (sd_div), \
  53}
  54
  55struct sd_div_table {
  56        u32 val;
  57        unsigned int div;
  58};
  59
  60/* SDn divider
  61 *                     sd_srcfc   sd_fc   div
  62 * stp_hck   stp_ck    (div)      (div)     = sd_srcfc x sd_fc
  63 *-------------------------------------------------------------------
  64 *  0         0         0 (1)      1 (4)      4
  65 *  0         0         1 (2)      1 (4)      8
  66 *  1         0         2 (4)      1 (4)     16
  67 *  1         0         3 (8)      1 (4)     32
  68 *  1         0         4 (16)     1 (4)     64
  69 *  0         0         0 (1)      0 (2)      2
  70 *  0         0         1 (2)      0 (2)      4
  71 *  1         0         2 (4)      0 (2)      8
  72 *  1         0         3 (8)      0 (2)     16
  73 *  1         0         4 (16)     0 (2)     32
  74 */
  75static const struct sd_div_table cpg_sd_div_table[] = {
  76/*      CPG_SD_DIV_TABLE_DATA(stp_hck,  stp_ck,   sd_srcfc,   sd_fc,  sd_div) */
  77        CPG_SD_DIV_TABLE_DATA(0,        0,        0,          1,        4),
  78        CPG_SD_DIV_TABLE_DATA(0,        0,        1,          1,        8),
  79        CPG_SD_DIV_TABLE_DATA(1,        0,        2,          1,       16),
  80        CPG_SD_DIV_TABLE_DATA(1,        0,        3,          1,       32),
  81        CPG_SD_DIV_TABLE_DATA(1,        0,        4,          1,       64),
  82        CPG_SD_DIV_TABLE_DATA(0,        0,        0,          0,        2),
  83        CPG_SD_DIV_TABLE_DATA(0,        0,        1,          0,        4),
  84        CPG_SD_DIV_TABLE_DATA(1,        0,        2,          0,        8),
  85        CPG_SD_DIV_TABLE_DATA(1,        0,        3,          0,       16),
  86        CPG_SD_DIV_TABLE_DATA(1,        0,        4,          0,       32),
  87};
  88
  89static int gen3_clk_get_parent(struct gen3_clk_priv *priv, struct clk *clk,
  90                               struct cpg_mssr_info *info, struct clk *parent)
  91{
  92        const struct cpg_core_clk *core;
  93        int ret;
  94
  95        if (!renesas_clk_is_mod(clk)) {
  96                ret = renesas_clk_get_core(clk, info, &core);
  97                if (ret)
  98                        return ret;
  99
 100                if (core->type == CLK_TYPE_GEN3_MDSEL) {
 101                        parent->dev = clk->dev;
 102                        parent->id = core->parent >> (priv->sscg ? 16 : 0);
 103                        parent->id &= 0xffff;
 104                        return 0;
 105                }
 106        }
 107
 108        return renesas_clk_get_parent(clk, info, parent);
 109}
 110
 111static int gen3_clk_setup_sdif_div(struct clk *clk, ulong rate)
 112{
 113        struct gen3_clk_priv *priv = dev_get_priv(clk->dev);
 114        struct cpg_mssr_info *info = priv->info;
 115        const struct cpg_core_clk *core;
 116        struct clk parent;
 117        int ret;
 118
 119        ret = gen3_clk_get_parent(priv, clk, info, &parent);
 120        if (ret) {
 121                printf("%s[%i] parent fail, ret=%i\n", __func__, __LINE__, ret);
 122                return ret;
 123        }
 124
 125        if (renesas_clk_is_mod(&parent))
 126                return 0;
 127
 128        ret = renesas_clk_get_core(&parent, info, &core);
 129        if (ret)
 130                return ret;
 131
 132        if (core->type != CLK_TYPE_GEN3_SD)
 133                return 0;
 134
 135        debug("%s[%i] SDIF offset=%x\n", __func__, __LINE__, core->offset);
 136
 137        writel((rate == 400000000) ? 0x4 : 0x1, priv->base + core->offset);
 138
 139        return 0;
 140}
 141
 142static int gen3_clk_enable(struct clk *clk)
 143{
 144        struct gen3_clk_priv *priv = dev_get_priv(clk->dev);
 145
 146        return renesas_clk_endisable(clk, priv->base, priv->info, true);
 147}
 148
 149static int gen3_clk_disable(struct clk *clk)
 150{
 151        struct gen3_clk_priv *priv = dev_get_priv(clk->dev);
 152
 153        return renesas_clk_endisable(clk, priv->base, priv->info, false);
 154}
 155
 156static u64 gen3_clk_get_rate64(struct clk *clk);
 157
 158static u64 gen3_clk_get_rate64_pll_mul_reg(struct gen3_clk_priv *priv,
 159                                           struct clk *parent,
 160                                           const struct cpg_core_clk *core,
 161                                           u32 mul_reg, u32 mult, u32 div,
 162                                           char *name)
 163{
 164        u32 value;
 165        u64 rate;
 166
 167        if (mul_reg) {
 168                value = readl(priv->base + mul_reg);
 169                mult = (((value >> 24) & 0x7f) + 1) * 2;
 170                div = 1;
 171        }
 172
 173        rate = (gen3_clk_get_rate64(parent) * mult) / div;
 174
 175        debug("%s[%i] %s clk: parent=%i mult=%u div=%u => rate=%llu\n",
 176              __func__, __LINE__, name, core->parent, mult, div, rate);
 177        return rate;
 178}
 179
 180static u64 gen3_clk_get_rate64(struct clk *clk)
 181{
 182        struct gen3_clk_priv *priv = dev_get_priv(clk->dev);
 183        struct cpg_mssr_info *info = priv->info;
 184        struct clk parent;
 185        const struct cpg_core_clk *core;
 186        const struct rcar_gen3_cpg_pll_config *pll_config =
 187                                        priv->cpg_pll_config;
 188        u32 value, div, prediv, postdiv;
 189        u64 rate = 0;
 190        int i, ret;
 191
 192        debug("%s[%i] Clock: id=%lu\n", __func__, __LINE__, clk->id);
 193
 194        ret = gen3_clk_get_parent(priv, clk, info, &parent);
 195        if (ret) {
 196                printf("%s[%i] parent fail, ret=%i\n", __func__, __LINE__, ret);
 197                return ret;
 198        }
 199
 200        if (renesas_clk_is_mod(clk)) {
 201                rate = gen3_clk_get_rate64(&parent);
 202                debug("%s[%i] MOD clk: parent=%lu => rate=%llu\n",
 203                      __func__, __LINE__, parent.id, rate);
 204                return rate;
 205        }
 206
 207        ret = renesas_clk_get_core(clk, info, &core);
 208        if (ret)
 209                return ret;
 210
 211        switch (core->type) {
 212        case CLK_TYPE_IN:
 213                if (core->id == info->clk_extal_id) {
 214                        rate = clk_get_rate(&priv->clk_extal);
 215                        debug("%s[%i] EXTAL clk: rate=%llu\n",
 216                              __func__, __LINE__, rate);
 217                        return rate;
 218                }
 219
 220                if (core->id == info->clk_extalr_id) {
 221                        rate = clk_get_rate(&priv->clk_extalr);
 222                        debug("%s[%i] EXTALR clk: rate=%llu\n",
 223                              __func__, __LINE__, rate);
 224                        return rate;
 225                }
 226
 227                return -EINVAL;
 228
 229        case CLK_TYPE_GEN3_MAIN:
 230                return gen3_clk_get_rate64_pll_mul_reg(priv, &parent, core,
 231                                                0, 1, pll_config->extal_div,
 232                                                "MAIN");
 233
 234        case CLK_TYPE_GEN3_PLL0:
 235                return gen3_clk_get_rate64_pll_mul_reg(priv, &parent, core,
 236                                                CPG_PLL0CR, 0, 0, "PLL0");
 237
 238        case CLK_TYPE_GEN3_PLL1:
 239                return gen3_clk_get_rate64_pll_mul_reg(priv, &parent, core,
 240                                                0, pll_config->pll1_mult,
 241                                                pll_config->pll1_div, "PLL1");
 242
 243        case CLK_TYPE_GEN3_PLL2:
 244                return gen3_clk_get_rate64_pll_mul_reg(priv, &parent, core,
 245                                                CPG_PLL2CR, 0, 0, "PLL2");
 246
 247        case CLK_TYPE_GEN3_PLL3:
 248                return gen3_clk_get_rate64_pll_mul_reg(priv, &parent, core,
 249                                                0, pll_config->pll3_mult,
 250                                                pll_config->pll3_div, "PLL3");
 251
 252        case CLK_TYPE_GEN3_PLL4:
 253                return gen3_clk_get_rate64_pll_mul_reg(priv, &parent, core,
 254                                                CPG_PLL4CR, 0, 0, "PLL4");
 255
 256        case CLK_TYPE_R8A779A0_MAIN:
 257                return gen3_clk_get_rate64_pll_mul_reg(priv, &parent, core,
 258                                                0, 1, pll_config->extal_div,
 259                                                "V3U_MAIN");
 260
 261        case CLK_TYPE_R8A779A0_PLL1:
 262                return gen3_clk_get_rate64_pll_mul_reg(priv, &parent, core,
 263                                                0, pll_config->pll1_mult,
 264                                                pll_config->pll1_div,
 265                                                "V3U_PLL1");
 266
 267        case CLK_TYPE_R8A779A0_PLL2X_3X:
 268                return gen3_clk_get_rate64_pll_mul_reg(priv, &parent, core,
 269                                                core->offset, 0, 0,
 270                                                "V3U_PLL2X_3X");
 271
 272        case CLK_TYPE_R8A779A0_PLL5:
 273                return gen3_clk_get_rate64_pll_mul_reg(priv, &parent, core,
 274                                                0, pll_config->pll5_mult,
 275                                                pll_config->pll5_div,
 276                                                "V3U_PLL5");
 277
 278        case CLK_TYPE_FF:
 279                return gen3_clk_get_rate64_pll_mul_reg(priv, &parent, core,
 280                                                0, core->mult, core->div,
 281                                                "FIXED");
 282
 283        case CLK_TYPE_GEN3_MDSEL:
 284                div = (core->div >> (priv->sscg ? 16 : 0)) & 0xffff;
 285                rate = gen3_clk_get_rate64(&parent) / div;
 286                debug("%s[%i] PE clk: parent=%i div=%u => rate=%llu\n",
 287                      __func__, __LINE__,
 288                      (core->parent >> (priv->sscg ? 16 : 0)) & 0xffff,
 289                      div, rate);
 290                return rate;
 291
 292        case CLK_TYPE_GEN3_SD:          /* FIXME */
 293                fallthrough;
 294        case CLK_TYPE_R8A779A0_SD:
 295                value = readl(priv->base + core->offset);
 296                value &= CPG_SD_STP_MASK | CPG_SD_FC_MASK;
 297
 298                for (i = 0; i < ARRAY_SIZE(cpg_sd_div_table); i++) {
 299                        if (cpg_sd_div_table[i].val != value)
 300                                continue;
 301
 302                        rate = gen3_clk_get_rate64(&parent) /
 303                               cpg_sd_div_table[i].div;
 304                        debug("%s[%i] SD clk: parent=%i div=%i => rate=%llu\n",
 305                              __func__, __LINE__,
 306                              core->parent, cpg_sd_div_table[i].div, rate);
 307
 308                        return rate;
 309                }
 310
 311                return -EINVAL;
 312
 313        case CLK_TYPE_GEN3_RPC:
 314        case CLK_TYPE_GEN3_RPCD2:
 315                rate = gen3_clk_get_rate64(&parent);
 316
 317                value = readl(priv->base + core->offset);
 318
 319                prediv = (value >> CPG_RPC_PREDIV_OFFSET) &
 320                         CPG_RPC_PREDIV_MASK;
 321                if (prediv == 2)
 322                        rate /= 5;
 323                else if (prediv == 3)
 324                        rate /= 6;
 325                else
 326                        return -EINVAL;
 327
 328                postdiv = (value >> CPG_RPC_POSTDIV_OFFSET) &
 329                          CPG_RPC_POSTDIV_MASK;
 330
 331                if (postdiv % 2 != 0) {
 332                        rate /= postdiv + 1;
 333
 334                        if (core->type == CLK_TYPE_GEN3_RPCD2)
 335                                rate /= 2;
 336
 337                        debug("%s[%i] RPC clk: parent=%i prediv=%i postdiv=%i => rate=%llu\n",
 338                              __func__, __LINE__,
 339                              core->parent, prediv, postdiv, rate);
 340
 341                        return rate;
 342                }
 343
 344                return -EINVAL;
 345
 346        }
 347
 348        printf("%s[%i] unknown fail\n", __func__, __LINE__);
 349
 350        return -ENOENT;
 351}
 352
 353static ulong gen3_clk_get_rate(struct clk *clk)
 354{
 355        return gen3_clk_get_rate64(clk);
 356}
 357
 358static ulong gen3_clk_set_rate(struct clk *clk, ulong rate)
 359{
 360        /* Force correct SD-IF divider configuration if applicable */
 361        gen3_clk_setup_sdif_div(clk, rate);
 362        return gen3_clk_get_rate64(clk);
 363}
 364
 365static int gen3_clk_of_xlate(struct clk *clk, struct ofnode_phandle_args *args)
 366{
 367        if (args->args_count != 2) {
 368                debug("Invalid args_count: %d\n", args->args_count);
 369                return -EINVAL;
 370        }
 371
 372        clk->id = (args->args[0] << 16) | args->args[1];
 373
 374        return 0;
 375}
 376
 377const struct clk_ops gen3_clk_ops = {
 378        .enable         = gen3_clk_enable,
 379        .disable        = gen3_clk_disable,
 380        .get_rate       = gen3_clk_get_rate,
 381        .set_rate       = gen3_clk_set_rate,
 382        .of_xlate       = gen3_clk_of_xlate,
 383};
 384
 385int gen3_clk_probe(struct udevice *dev)
 386{
 387        struct gen3_clk_priv *priv = dev_get_priv(dev);
 388        struct cpg_mssr_info *info =
 389                (struct cpg_mssr_info *)dev_get_driver_data(dev);
 390        fdt_addr_t rst_base;
 391        u32 cpg_mode;
 392        int ret;
 393
 394        priv->base = dev_read_addr_ptr(dev);
 395        if (!priv->base)
 396                return -EINVAL;
 397
 398        priv->info = info;
 399        ret = fdt_node_offset_by_compatible(gd->fdt_blob, -1, info->reset_node);
 400        if (ret < 0)
 401                return ret;
 402
 403        rst_base = fdtdec_get_addr(gd->fdt_blob, ret, "reg");
 404        if (rst_base == FDT_ADDR_T_NONE)
 405                return -EINVAL;
 406
 407        cpg_mode = readl(rst_base + info->reset_modemr_offset);
 408
 409        priv->cpg_pll_config =
 410                (struct rcar_gen3_cpg_pll_config *)info->get_pll_config(cpg_mode);
 411        if (!priv->cpg_pll_config->extal_div)
 412                return -EINVAL;
 413
 414        priv->sscg = !(cpg_mode & BIT(12));
 415
 416        if (info->reg_layout == CLK_REG_LAYOUT_RCAR_GEN2_AND_GEN3) {
 417                priv->info->status_regs = mstpsr;
 418                priv->info->control_regs = smstpcr;
 419                priv->info->reset_regs = srcr;
 420                priv->info->reset_clear_regs = srstclr;
 421        } else if (info->reg_layout == CLK_REG_LAYOUT_RCAR_V3U) {
 422                priv->info->status_regs = mstpsr_for_v3u;
 423                priv->info->control_regs = mstpcr_for_v3u;
 424                priv->info->reset_regs = srcr_for_v3u;
 425                priv->info->reset_clear_regs = srstclr_for_v3u;
 426        } else {
 427                return -EINVAL;
 428        }
 429
 430        ret = clk_get_by_name(dev, "extal", &priv->clk_extal);
 431        if (ret < 0)
 432                return ret;
 433
 434        if (info->extalr_node) {
 435                ret = clk_get_by_name(dev, info->extalr_node, &priv->clk_extalr);
 436                if (ret < 0)
 437                        return ret;
 438        }
 439
 440        return 0;
 441}
 442
 443int gen3_clk_remove(struct udevice *dev)
 444{
 445        struct gen3_clk_priv *priv = dev_get_priv(dev);
 446
 447        return renesas_clk_remove(priv->base, priv->info);
 448}
 449