linux/drivers/clk/mvebu/kirkwood.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Marvell Kirkwood SoC clocks
   4 *
   5 * Copyright (C) 2012 Marvell
   6 *
   7 * Gregory CLEMENT <gregory.clement@free-electrons.com>
   8 * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
   9 * Andrew Lunn <andrew@lunn.ch>
  10 *
  11 */
  12
  13#include <linux/kernel.h>
  14#include <linux/slab.h>
  15#include <linux/clk-provider.h>
  16#include <linux/io.h>
  17#include <linux/of.h>
  18#include <linux/of_address.h>
  19#include "common.h"
  20
  21/*
  22 * Core Clocks
  23 *
  24 * Kirkwood PLL sample-at-reset configuration
  25 * (6180 has different SAR layout than other Kirkwood SoCs)
  26 *
  27 * SAR0[4:3,22,1] : CPU frequency (6281,6292,6282)
  28 *      4  =  600 MHz
  29 *      6  =  800 MHz
  30 *      7  = 1000 MHz
  31 *      9  = 1200 MHz
  32 *      12 = 1500 MHz
  33 *      13 = 1600 MHz
  34 *      14 = 1800 MHz
  35 *      15 = 2000 MHz
  36 *      others reserved.
  37 *
  38 * SAR0[19,10:9] : CPU to L2 Clock divider ratio (6281,6292,6282)
  39 *      1 = (1/2) * CPU
  40 *      3 = (1/3) * CPU
  41 *      5 = (1/4) * CPU
  42 *      others reserved.
  43 *
  44 * SAR0[8:5] : CPU to DDR DRAM Clock divider ratio (6281,6292,6282)
  45 *      2 = (1/2) * CPU
  46 *      4 = (1/3) * CPU
  47 *      6 = (1/4) * CPU
  48 *      7 = (2/9) * CPU
  49 *      8 = (1/5) * CPU
  50 *      9 = (1/6) * CPU
  51 *      others reserved.
  52 *
  53 * SAR0[4:2] : Kirkwood 6180 cpu/l2/ddr clock configuration (6180 only)
  54 *      5 = [CPU =  600 MHz, L2 = (1/2) * CPU, DDR = 200 MHz = (1/3) * CPU]
  55 *      6 = [CPU =  800 MHz, L2 = (1/2) * CPU, DDR = 200 MHz = (1/4) * CPU]
  56 *      7 = [CPU = 1000 MHz, L2 = (1/2) * CPU, DDR = 200 MHz = (1/5) * CPU]
  57 *      others reserved.
  58 *
  59 * SAR0[21] : TCLK frequency
  60 *      0 = 200 MHz
  61 *      1 = 166 MHz
  62 *      others reserved.
  63 */
  64
  65#define SAR_KIRKWOOD_CPU_FREQ(x)        \
  66        (((x & (1 <<  1)) >>  1) |      \
  67         ((x & (1 << 22)) >> 21) |      \
  68         ((x & (3 <<  3)) >>  1))
  69#define SAR_KIRKWOOD_L2_RATIO(x)        \
  70        (((x & (3 <<  9)) >> 9) |       \
  71         (((x & (1 << 19)) >> 17)))
  72#define SAR_KIRKWOOD_DDR_RATIO          5
  73#define SAR_KIRKWOOD_DDR_RATIO_MASK     0xf
  74#define SAR_MV88F6180_CLK               2
  75#define SAR_MV88F6180_CLK_MASK          0x7
  76#define SAR_KIRKWOOD_TCLK_FREQ          21
  77#define SAR_KIRKWOOD_TCLK_FREQ_MASK     0x1
  78
  79enum { KIRKWOOD_CPU_TO_L2, KIRKWOOD_CPU_TO_DDR };
  80
  81static const struct coreclk_ratio kirkwood_coreclk_ratios[] __initconst = {
  82        { .id = KIRKWOOD_CPU_TO_L2, .name = "l2clk", },
  83        { .id = KIRKWOOD_CPU_TO_DDR, .name = "ddrclk", }
  84};
  85
  86static u32 __init kirkwood_get_tclk_freq(void __iomem *sar)
  87{
  88        u32 opt = (readl(sar) >> SAR_KIRKWOOD_TCLK_FREQ) &
  89                SAR_KIRKWOOD_TCLK_FREQ_MASK;
  90        return (opt) ? 166666667 : 200000000;
  91}
  92
  93static const u32 kirkwood_cpu_freqs[] __initconst = {
  94        0, 0, 0, 0,
  95        600000000,
  96        0,
  97        800000000,
  98        1000000000,
  99        0,
 100        1200000000,
 101        0, 0,
 102        1500000000,
 103        1600000000,
 104        1800000000,
 105        2000000000
 106};
 107
 108static u32 __init kirkwood_get_cpu_freq(void __iomem *sar)
 109{
 110        u32 opt = SAR_KIRKWOOD_CPU_FREQ(readl(sar));
 111        return kirkwood_cpu_freqs[opt];
 112}
 113
 114static const int kirkwood_cpu_l2_ratios[8][2] __initconst = {
 115        { 0, 1 }, { 1, 2 }, { 0, 1 }, { 1, 3 },
 116        { 0, 1 }, { 1, 4 }, { 0, 1 }, { 0, 1 }
 117};
 118
 119static const int kirkwood_cpu_ddr_ratios[16][2] __initconst = {
 120        { 0, 1 }, { 0, 1 }, { 1, 2 }, { 0, 1 },
 121        { 1, 3 }, { 0, 1 }, { 1, 4 }, { 2, 9 },
 122        { 1, 5 }, { 1, 6 }, { 0, 1 }, { 0, 1 },
 123        { 0, 1 }, { 0, 1 }, { 0, 1 }, { 0, 1 }
 124};
 125
 126static void __init kirkwood_get_clk_ratio(
 127        void __iomem *sar, int id, int *mult, int *div)
 128{
 129        switch (id) {
 130        case KIRKWOOD_CPU_TO_L2:
 131        {
 132                u32 opt = SAR_KIRKWOOD_L2_RATIO(readl(sar));
 133                *mult = kirkwood_cpu_l2_ratios[opt][0];
 134                *div = kirkwood_cpu_l2_ratios[opt][1];
 135                break;
 136        }
 137        case KIRKWOOD_CPU_TO_DDR:
 138        {
 139                u32 opt = (readl(sar) >> SAR_KIRKWOOD_DDR_RATIO) &
 140                        SAR_KIRKWOOD_DDR_RATIO_MASK;
 141                *mult = kirkwood_cpu_ddr_ratios[opt][0];
 142                *div = kirkwood_cpu_ddr_ratios[opt][1];
 143                break;
 144        }
 145        }
 146}
 147
 148static const u32 mv88f6180_cpu_freqs[] __initconst = {
 149        0, 0, 0, 0, 0,
 150        600000000,
 151        800000000,
 152        1000000000
 153};
 154
 155static u32 __init mv88f6180_get_cpu_freq(void __iomem *sar)
 156{
 157        u32 opt = (readl(sar) >> SAR_MV88F6180_CLK) & SAR_MV88F6180_CLK_MASK;
 158        return mv88f6180_cpu_freqs[opt];
 159}
 160
 161static const int mv88f6180_cpu_ddr_ratios[8][2] __initconst = {
 162        { 0, 1 }, { 0, 1 }, { 0, 1 }, { 0, 1 },
 163        { 0, 1 }, { 1, 3 }, { 1, 4 }, { 1, 5 }
 164};
 165
 166static void __init mv88f6180_get_clk_ratio(
 167        void __iomem *sar, int id, int *mult, int *div)
 168{
 169        switch (id) {
 170        case KIRKWOOD_CPU_TO_L2:
 171        {
 172                /* mv88f6180 has a fixed 1:2 CPU-to-L2 ratio */
 173                *mult = 1;
 174                *div = 2;
 175                break;
 176        }
 177        case KIRKWOOD_CPU_TO_DDR:
 178        {
 179                u32 opt = (readl(sar) >> SAR_MV88F6180_CLK) &
 180                        SAR_MV88F6180_CLK_MASK;
 181                *mult = mv88f6180_cpu_ddr_ratios[opt][0];
 182                *div = mv88f6180_cpu_ddr_ratios[opt][1];
 183                break;
 184        }
 185        }
 186}
 187
 188static u32 __init mv98dx1135_get_tclk_freq(void __iomem *sar)
 189{
 190        return 166666667;
 191}
 192
 193static const struct coreclk_soc_desc kirkwood_coreclks = {
 194        .get_tclk_freq = kirkwood_get_tclk_freq,
 195        .get_cpu_freq = kirkwood_get_cpu_freq,
 196        .get_clk_ratio = kirkwood_get_clk_ratio,
 197        .ratios = kirkwood_coreclk_ratios,
 198        .num_ratios = ARRAY_SIZE(kirkwood_coreclk_ratios),
 199};
 200
 201static const struct coreclk_soc_desc mv88f6180_coreclks = {
 202        .get_tclk_freq = kirkwood_get_tclk_freq,
 203        .get_cpu_freq = mv88f6180_get_cpu_freq,
 204        .get_clk_ratio = mv88f6180_get_clk_ratio,
 205        .ratios = kirkwood_coreclk_ratios,
 206        .num_ratios = ARRAY_SIZE(kirkwood_coreclk_ratios),
 207};
 208
 209static const struct coreclk_soc_desc mv98dx1135_coreclks = {
 210        .get_tclk_freq = mv98dx1135_get_tclk_freq,
 211        .get_cpu_freq = kirkwood_get_cpu_freq,
 212        .get_clk_ratio = kirkwood_get_clk_ratio,
 213        .ratios = kirkwood_coreclk_ratios,
 214        .num_ratios = ARRAY_SIZE(kirkwood_coreclk_ratios),
 215};
 216
 217/*
 218 * Clock Gating Control
 219 */
 220
 221static const struct clk_gating_soc_desc kirkwood_gating_desc[] __initconst = {
 222        { "ge0", NULL, 0, 0 },
 223        { "pex0", NULL, 2, 0 },
 224        { "usb0", NULL, 3, 0 },
 225        { "sdio", NULL, 4, 0 },
 226        { "tsu", NULL, 5, 0 },
 227        { "runit", NULL, 7, 0 },
 228        { "xor0", NULL, 8, 0 },
 229        { "audio", NULL, 9, 0 },
 230        { "sata0", NULL, 14, 0 },
 231        { "sata1", NULL, 15, 0 },
 232        { "xor1", NULL, 16, 0 },
 233        { "crypto", NULL, 17, 0 },
 234        { "pex1", NULL, 18, 0 },
 235        { "ge1", NULL, 19, 0 },
 236        { "tdm", NULL, 20, 0 },
 237        { }
 238};
 239
 240
 241/*
 242 * Clock Muxing Control
 243 */
 244
 245struct clk_muxing_soc_desc {
 246        const char *name;
 247        const char **parents;
 248        int num_parents;
 249        int shift;
 250        int width;
 251        unsigned long flags;
 252};
 253
 254struct clk_muxing_ctrl {
 255        spinlock_t *lock;
 256        struct clk **muxes;
 257        int num_muxes;
 258};
 259
 260static const char *powersave_parents[] = {
 261        "cpuclk",
 262        "ddrclk",
 263};
 264
 265static const struct clk_muxing_soc_desc kirkwood_mux_desc[] __initconst = {
 266        { "powersave", powersave_parents, ARRAY_SIZE(powersave_parents),
 267                11, 1, 0 },
 268        { }
 269};
 270
 271static struct clk *clk_muxing_get_src(
 272        struct of_phandle_args *clkspec, void *data)
 273{
 274        struct clk_muxing_ctrl *ctrl = (struct clk_muxing_ctrl *)data;
 275        int n;
 276
 277        if (clkspec->args_count < 1)
 278                return ERR_PTR(-EINVAL);
 279
 280        for (n = 0; n < ctrl->num_muxes; n++) {
 281                struct clk_mux *mux =
 282                        to_clk_mux(__clk_get_hw(ctrl->muxes[n]));
 283                if (clkspec->args[0] == mux->shift)
 284                        return ctrl->muxes[n];
 285        }
 286        return ERR_PTR(-ENODEV);
 287}
 288
 289static void __init kirkwood_clk_muxing_setup(struct device_node *np,
 290                                   const struct clk_muxing_soc_desc *desc)
 291{
 292        struct clk_muxing_ctrl *ctrl;
 293        void __iomem *base;
 294        int n;
 295
 296        base = of_iomap(np, 0);
 297        if (WARN_ON(!base))
 298                return;
 299
 300        ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL);
 301        if (WARN_ON(!ctrl))
 302                goto ctrl_out;
 303
 304        /* lock must already be initialized */
 305        ctrl->lock = &ctrl_gating_lock;
 306
 307        /* Count, allocate, and register clock muxes */
 308        for (n = 0; desc[n].name;)
 309                n++;
 310
 311        ctrl->num_muxes = n;
 312        ctrl->muxes = kcalloc(ctrl->num_muxes, sizeof(struct clk *),
 313                        GFP_KERNEL);
 314        if (WARN_ON(!ctrl->muxes))
 315                goto muxes_out;
 316
 317        for (n = 0; n < ctrl->num_muxes; n++) {
 318                ctrl->muxes[n] = clk_register_mux(NULL, desc[n].name,
 319                                desc[n].parents, desc[n].num_parents,
 320                                desc[n].flags, base, desc[n].shift,
 321                                desc[n].width, desc[n].flags, ctrl->lock);
 322                WARN_ON(IS_ERR(ctrl->muxes[n]));
 323        }
 324
 325        of_clk_add_provider(np, clk_muxing_get_src, ctrl);
 326
 327        return;
 328muxes_out:
 329        kfree(ctrl);
 330ctrl_out:
 331        iounmap(base);
 332}
 333
 334static void __init kirkwood_clk_init(struct device_node *np)
 335{
 336        struct device_node *cgnp =
 337                of_find_compatible_node(NULL, NULL, "marvell,kirkwood-gating-clock");
 338
 339
 340        if (of_device_is_compatible(np, "marvell,mv88f6180-core-clock"))
 341                mvebu_coreclk_setup(np, &mv88f6180_coreclks);
 342        else if (of_device_is_compatible(np, "marvell,mv98dx1135-core-clock"))
 343                mvebu_coreclk_setup(np, &mv98dx1135_coreclks);
 344        else
 345                mvebu_coreclk_setup(np, &kirkwood_coreclks);
 346
 347        if (cgnp) {
 348                mvebu_clk_gating_setup(cgnp, kirkwood_gating_desc);
 349                kirkwood_clk_muxing_setup(cgnp, kirkwood_mux_desc);
 350
 351                of_node_put(cgnp);
 352        }
 353}
 354CLK_OF_DECLARE(kirkwood_clk, "marvell,kirkwood-core-clock",
 355               kirkwood_clk_init);
 356CLK_OF_DECLARE(mv88f6180_clk, "marvell,mv88f6180-core-clock",
 357               kirkwood_clk_init);
 358CLK_OF_DECLARE(98dx1135_clk, "marvell,mv98dx1135-core-clock",
 359               kirkwood_clk_init);
 360