linux/drivers/clk/mvebu/armada-370.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Marvell Armada 370 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/clk-provider.h>
  15#include <linux/io.h>
  16#include <linux/of.h>
  17#include "common.h"
  18
  19/*
  20 * Core Clocks
  21 */
  22
  23#define SARL                            0       /* Low part [0:31] */
  24#define  SARL_A370_SSCG_ENABLE          BIT(10)
  25#define  SARL_A370_PCLK_FREQ_OPT        11
  26#define  SARL_A370_PCLK_FREQ_OPT_MASK   0xF
  27#define  SARL_A370_FAB_FREQ_OPT         15
  28#define  SARL_A370_FAB_FREQ_OPT_MASK    0x1F
  29#define  SARL_A370_TCLK_FREQ_OPT        20
  30#define  SARL_A370_TCLK_FREQ_OPT_MASK   0x1
  31
  32enum { A370_CPU_TO_NBCLK, A370_CPU_TO_HCLK, A370_CPU_TO_DRAMCLK };
  33
  34static const struct coreclk_ratio a370_coreclk_ratios[] __initconst = {
  35        { .id = A370_CPU_TO_NBCLK, .name = "nbclk" },
  36        { .id = A370_CPU_TO_HCLK, .name = "hclk" },
  37        { .id = A370_CPU_TO_DRAMCLK, .name = "dramclk" },
  38};
  39
  40static const u32 a370_tclk_freqs[] __initconst = {
  41        166000000,
  42        200000000,
  43};
  44
  45static u32 __init a370_get_tclk_freq(void __iomem *sar)
  46{
  47        u8 tclk_freq_select = 0;
  48
  49        tclk_freq_select = ((readl(sar) >> SARL_A370_TCLK_FREQ_OPT) &
  50                            SARL_A370_TCLK_FREQ_OPT_MASK);
  51        return a370_tclk_freqs[tclk_freq_select];
  52}
  53
  54static const u32 a370_cpu_freqs[] __initconst = {
  55        400000000,
  56        533000000,
  57        667000000,
  58        800000000,
  59        1000000000,
  60        1067000000,
  61        1200000000,
  62};
  63
  64static u32 __init a370_get_cpu_freq(void __iomem *sar)
  65{
  66        u32 cpu_freq;
  67        u8 cpu_freq_select = 0;
  68
  69        cpu_freq_select = ((readl(sar) >> SARL_A370_PCLK_FREQ_OPT) &
  70                           SARL_A370_PCLK_FREQ_OPT_MASK);
  71        if (cpu_freq_select >= ARRAY_SIZE(a370_cpu_freqs)) {
  72                pr_err("CPU freq select unsupported %d\n", cpu_freq_select);
  73                cpu_freq = 0;
  74        } else
  75                cpu_freq = a370_cpu_freqs[cpu_freq_select];
  76
  77        return cpu_freq;
  78}
  79
  80static const int a370_nbclk_ratios[32][2] __initconst = {
  81        {0, 1}, {1, 2}, {2, 2}, {2, 2},
  82        {1, 2}, {1, 2}, {1, 1}, {2, 3},
  83        {0, 1}, {1, 2}, {2, 4}, {0, 1},
  84        {1, 2}, {0, 1}, {0, 1}, {2, 2},
  85        {0, 1}, {0, 1}, {0, 1}, {1, 1},
  86        {2, 3}, {0, 1}, {0, 1}, {0, 1},
  87        {0, 1}, {0, 1}, {0, 1}, {1, 1},
  88        {0, 1}, {0, 1}, {0, 1}, {0, 1},
  89};
  90
  91static const int a370_hclk_ratios[32][2] __initconst = {
  92        {0, 1}, {1, 2}, {2, 6}, {2, 3},
  93        {1, 3}, {1, 4}, {1, 2}, {2, 6},
  94        {0, 1}, {1, 6}, {2, 10}, {0, 1},
  95        {1, 4}, {0, 1}, {0, 1}, {2, 5},
  96        {0, 1}, {0, 1}, {0, 1}, {1, 2},
  97        {2, 6}, {0, 1}, {0, 1}, {0, 1},
  98        {0, 1}, {0, 1}, {0, 1}, {1, 1},
  99        {0, 1}, {0, 1}, {0, 1}, {0, 1},
 100};
 101
 102static const int a370_dramclk_ratios[32][2] __initconst = {
 103        {0, 1}, {1, 2}, {2, 3}, {2, 3},
 104        {1, 3}, {1, 2}, {1, 2}, {2, 6},
 105        {0, 1}, {1, 3}, {2, 5}, {0, 1},
 106        {1, 4}, {0, 1}, {0, 1}, {2, 5},
 107        {0, 1}, {0, 1}, {0, 1}, {1, 1},
 108        {2, 3}, {0, 1}, {0, 1}, {0, 1},
 109        {0, 1}, {0, 1}, {0, 1}, {1, 1},
 110        {0, 1}, {0, 1}, {0, 1}, {0, 1},
 111};
 112
 113static void __init a370_get_clk_ratio(
 114        void __iomem *sar, int id, int *mult, int *div)
 115{
 116        u32 opt = ((readl(sar) >> SARL_A370_FAB_FREQ_OPT) &
 117                SARL_A370_FAB_FREQ_OPT_MASK);
 118
 119        switch (id) {
 120        case A370_CPU_TO_NBCLK:
 121                *mult = a370_nbclk_ratios[opt][0];
 122                *div = a370_nbclk_ratios[opt][1];
 123                break;
 124        case A370_CPU_TO_HCLK:
 125                *mult = a370_hclk_ratios[opt][0];
 126                *div = a370_hclk_ratios[opt][1];
 127                break;
 128        case A370_CPU_TO_DRAMCLK:
 129                *mult = a370_dramclk_ratios[opt][0];
 130                *div = a370_dramclk_ratios[opt][1];
 131                break;
 132        }
 133}
 134
 135static bool a370_is_sscg_enabled(void __iomem *sar)
 136{
 137        return !(readl(sar) & SARL_A370_SSCG_ENABLE);
 138}
 139
 140static const struct coreclk_soc_desc a370_coreclks = {
 141        .get_tclk_freq = a370_get_tclk_freq,
 142        .get_cpu_freq = a370_get_cpu_freq,
 143        .get_clk_ratio = a370_get_clk_ratio,
 144        .is_sscg_enabled = a370_is_sscg_enabled,
 145        .fix_sscg_deviation = kirkwood_fix_sscg_deviation,
 146        .ratios = a370_coreclk_ratios,
 147        .num_ratios = ARRAY_SIZE(a370_coreclk_ratios),
 148};
 149
 150/*
 151 * Clock Gating Control
 152 */
 153
 154static const struct clk_gating_soc_desc a370_gating_desc[] __initconst = {
 155        { "audio", NULL, 0, 0 },
 156        { "pex0_en", NULL, 1, 0 },
 157        { "pex1_en", NULL,  2, 0 },
 158        { "ge1", NULL, 3, 0 },
 159        { "ge0", NULL, 4, 0 },
 160        { "pex0", "pex0_en", 5, 0 },
 161        { "pex1", "pex1_en", 9, 0 },
 162        { "sata0", NULL, 15, 0 },
 163        { "sdio", NULL, 17, 0 },
 164        { "crypto", NULL, 23, CLK_IGNORE_UNUSED },
 165        { "tdm", NULL, 25, 0 },
 166        { "ddr", NULL, 28, CLK_IGNORE_UNUSED },
 167        { "sata1", NULL, 30, 0 },
 168        { }
 169};
 170
 171static void __init a370_clk_init(struct device_node *np)
 172{
 173        struct device_node *cgnp =
 174                of_find_compatible_node(NULL, NULL, "marvell,armada-370-gating-clock");
 175
 176        mvebu_coreclk_setup(np, &a370_coreclks);
 177
 178        if (cgnp) {
 179                mvebu_clk_gating_setup(cgnp, a370_gating_desc);
 180                of_node_put(cgnp);
 181        }
 182}
 183CLK_OF_DECLARE(a370_clk, "marvell,armada-370-core-clock", a370_clk_init);
 184
 185