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_FF:
 257                return gen3_clk_get_rate64_pll_mul_reg(priv, &parent, core,
 258                                                0, core->mult, core->div,
 259                                                "FIXED");
 260
 261        case CLK_TYPE_GEN3_MDSEL:
 262                div = (core->div >> (priv->sscg ? 16 : 0)) & 0xffff;
 263                rate = gen3_clk_get_rate64(&parent) / div;
 264                debug("%s[%i] PE clk: parent=%i div=%u => rate=%llu\n",
 265                      __func__, __LINE__,
 266                      (core->parent >> (priv->sscg ? 16 : 0)) & 0xffff,
 267                      div, rate);
 268                return rate;
 269
 270        case CLK_TYPE_GEN3_SD:          /* FIXME */
 271                value = readl(priv->base + core->offset);
 272                value &= CPG_SD_STP_MASK | CPG_SD_FC_MASK;
 273
 274                for (i = 0; i < ARRAY_SIZE(cpg_sd_div_table); i++) {
 275                        if (cpg_sd_div_table[i].val != value)
 276                                continue;
 277
 278                        rate = gen3_clk_get_rate64(&parent) /
 279                               cpg_sd_div_table[i].div;
 280                        debug("%s[%i] SD clk: parent=%i div=%i => rate=%llu\n",
 281                              __func__, __LINE__,
 282                              core->parent, cpg_sd_div_table[i].div, rate);
 283
 284                        return rate;
 285                }
 286
 287                return -EINVAL;
 288
 289        case CLK_TYPE_GEN3_RPC:
 290        case CLK_TYPE_GEN3_RPCD2:
 291                rate = gen3_clk_get_rate64(&parent);
 292
 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
 307                if (postdiv % 2 != 0) {
 308                        rate /= postdiv + 1;
 309
 310                        if (core->type == CLK_TYPE_GEN3_RPCD2)
 311                                rate /= 2;
 312
 313                        debug("%s[%i] RPC clk: parent=%i prediv=%i postdiv=%i => rate=%llu\n",
 314                              __func__, __LINE__,
 315                              core->parent, prediv, postdiv, rate);
 316
 317                        return rate;
 318                }
 319
 320                return -EINVAL;
 321
 322        }
 323
 324        printf("%s[%i] unknown fail\n", __func__, __LINE__);
 325
 326        return -ENOENT;
 327}
 328
 329static ulong gen3_clk_get_rate(struct clk *clk)
 330{
 331        return gen3_clk_get_rate64(clk);
 332}
 333
 334static ulong gen3_clk_set_rate(struct clk *clk, ulong rate)
 335{
 336        /* Force correct SD-IF divider configuration if applicable */
 337        gen3_clk_setup_sdif_div(clk, rate);
 338        return gen3_clk_get_rate64(clk);
 339}
 340
 341static int gen3_clk_of_xlate(struct clk *clk, struct ofnode_phandle_args *args)
 342{
 343        if (args->args_count != 2) {
 344                debug("Invaild args_count: %d\n", args->args_count);
 345                return -EINVAL;
 346        }
 347
 348        clk->id = (args->args[0] << 16) | args->args[1];
 349
 350        return 0;
 351}
 352
 353const struct clk_ops gen3_clk_ops = {
 354        .enable         = gen3_clk_enable,
 355        .disable        = gen3_clk_disable,
 356        .get_rate       = gen3_clk_get_rate,
 357        .set_rate       = gen3_clk_set_rate,
 358        .of_xlate       = gen3_clk_of_xlate,
 359};
 360
 361int gen3_clk_probe(struct udevice *dev)
 362{
 363        struct gen3_clk_priv *priv = dev_get_priv(dev);
 364        struct cpg_mssr_info *info =
 365                (struct cpg_mssr_info *)dev_get_driver_data(dev);
 366        fdt_addr_t rst_base;
 367        u32 cpg_mode;
 368        int ret;
 369
 370        priv->base = dev_read_addr_ptr(dev);
 371        if (!priv->base)
 372                return -EINVAL;
 373
 374        priv->info = info;
 375        ret = fdt_node_offset_by_compatible(gd->fdt_blob, -1, info->reset_node);
 376        if (ret < 0)
 377                return ret;
 378
 379        rst_base = fdtdec_get_addr(gd->fdt_blob, ret, "reg");
 380        if (rst_base == FDT_ADDR_T_NONE)
 381                return -EINVAL;
 382
 383        cpg_mode = readl(rst_base + info->reset_modemr_offset);
 384
 385        priv->cpg_pll_config =
 386                (struct rcar_gen3_cpg_pll_config *)info->get_pll_config(cpg_mode);
 387        if (!priv->cpg_pll_config->extal_div)
 388                return -EINVAL;
 389
 390        priv->sscg = !(cpg_mode & BIT(12));
 391
 392        if (info->reg_layout == CLK_REG_LAYOUT_RCAR_GEN2_AND_GEN3) {
 393                priv->info->status_regs = mstpsr;
 394                priv->info->control_regs = smstpcr;
 395                priv->info->reset_regs = srcr;
 396                priv->info->reset_clear_regs = srstclr;
 397        } else {
 398                return -EINVAL;
 399        }
 400
 401        ret = clk_get_by_name(dev, "extal", &priv->clk_extal);
 402        if (ret < 0)
 403                return ret;
 404
 405        if (info->extalr_node) {
 406                ret = clk_get_by_name(dev, info->extalr_node, &priv->clk_extalr);
 407                if (ret < 0)
 408                        return ret;
 409        }
 410
 411        return 0;
 412}
 413
 414int gen3_clk_remove(struct udevice *dev)
 415{
 416        struct gen3_clk_priv *priv = dev_get_priv(dev);
 417
 418        return renesas_clk_remove(priv->base, priv->info);
 419}
 420