linux/drivers/clk/mvebu/armada-38x.c
<<
>>
Prefs
   1/*
   2 * Marvell Armada 380/385 SoC clocks
   3 *
   4 * Copyright (C) 2014 Marvell
   5 *
   6 * Gregory CLEMENT <gregory.clement@free-electrons.com>
   7 * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
   8 * Andrew Lunn <andrew@lunn.ch>
   9 *
  10 * This file is licensed under the terms of the GNU General Public
  11 * License version 2.  This program is licensed "as is" without any
  12 * warranty of any kind, whether express or implied.
  13 */
  14
  15#include <linux/kernel.h>
  16#include <linux/clk-provider.h>
  17#include <linux/io.h>
  18#include <linux/of.h>
  19#include "common.h"
  20
  21/*
  22 * SAR[14:10] : Ratios between PCLK0, NBCLK, HCLK and DRAM clocks
  23 *
  24 * SAR[15]    : TCLK frequency
  25 *               0 = 250 MHz
  26 *               1 = 200 MHz
  27 */
  28
  29#define SAR_A380_TCLK_FREQ_OPT            15
  30#define SAR_A380_TCLK_FREQ_OPT_MASK       0x1
  31#define SAR_A380_CPU_DDR_L2_FREQ_OPT      10
  32#define SAR_A380_CPU_DDR_L2_FREQ_OPT_MASK 0x1F
  33
  34static const u32 armada_38x_tclk_frequencies[] __initconst = {
  35        250000000,
  36        200000000,
  37};
  38
  39static u32 __init armada_38x_get_tclk_freq(void __iomem *sar)
  40{
  41        u8 tclk_freq_select;
  42
  43        tclk_freq_select = ((readl(sar) >> SAR_A380_TCLK_FREQ_OPT) &
  44                            SAR_A380_TCLK_FREQ_OPT_MASK);
  45        return armada_38x_tclk_frequencies[tclk_freq_select];
  46}
  47
  48static const u32 armada_38x_cpu_frequencies[] __initconst = {
  49        666 * 1000 * 1000,  0, 800 * 1000 * 1000, 0,
  50        1066 * 1000 * 1000, 0, 1200 * 1000 * 1000, 0,
  51        1332 * 1000 * 1000, 0, 0, 0,
  52        1600 * 1000 * 1000, 0, 0, 0,
  53        1866 * 1000 * 1000, 0, 0, 2000 * 1000 * 1000,
  54};
  55
  56static u32 __init armada_38x_get_cpu_freq(void __iomem *sar)
  57{
  58        u8 cpu_freq_select;
  59
  60        cpu_freq_select = ((readl(sar) >> SAR_A380_CPU_DDR_L2_FREQ_OPT) &
  61                           SAR_A380_CPU_DDR_L2_FREQ_OPT_MASK);
  62        if (cpu_freq_select >= ARRAY_SIZE(armada_38x_cpu_frequencies)) {
  63                pr_err("Selected CPU frequency (%d) unsupported\n",
  64                        cpu_freq_select);
  65                return 0;
  66        }
  67
  68        return armada_38x_cpu_frequencies[cpu_freq_select];
  69}
  70
  71enum { A380_CPU_TO_DDR, A380_CPU_TO_L2 };
  72
  73static const struct coreclk_ratio armada_38x_coreclk_ratios[] __initconst = {
  74        { .id = A380_CPU_TO_L2,  .name = "l2clk" },
  75        { .id = A380_CPU_TO_DDR, .name = "ddrclk" },
  76};
  77
  78static const int armada_38x_cpu_l2_ratios[32][2] __initconst = {
  79        {1, 2}, {0, 1}, {1, 2}, {0, 1},
  80        {1, 2}, {0, 1}, {1, 2}, {0, 1},
  81        {1, 2}, {0, 1}, {0, 1}, {0, 1},
  82        {1, 2}, {0, 1}, {0, 1}, {0, 1},
  83        {1, 2}, {0, 1}, {0, 1}, {1, 2},
  84        {0, 1}, {0, 1}, {0, 1}, {0, 1},
  85        {0, 1}, {0, 1}, {0, 1}, {0, 1},
  86        {0, 1}, {0, 1}, {0, 1}, {0, 1},
  87};
  88
  89static const int armada_38x_cpu_ddr_ratios[32][2] __initconst = {
  90        {0, 1}, {0, 1}, {0, 1}, {0, 1},
  91        {1, 2}, {0, 1}, {0, 1}, {0, 1},
  92        {1, 2}, {0, 1}, {0, 1}, {0, 1},
  93        {1, 2}, {0, 1}, {0, 1}, {0, 1},
  94        {1, 2}, {0, 1}, {0, 1}, {7, 15},
  95        {0, 1}, {0, 1}, {0, 1}, {0, 1},
  96        {0, 1}, {0, 1}, {0, 1}, {0, 1},
  97        {0, 1}, {0, 1}, {0, 1}, {0, 1},
  98};
  99
 100static void __init armada_38x_get_clk_ratio(
 101        void __iomem *sar, int id, int *mult, int *div)
 102{
 103        u32 opt = ((readl(sar) >> SAR_A380_CPU_DDR_L2_FREQ_OPT) &
 104                SAR_A380_CPU_DDR_L2_FREQ_OPT_MASK);
 105
 106        switch (id) {
 107        case A380_CPU_TO_L2:
 108                *mult = armada_38x_cpu_l2_ratios[opt][0];
 109                *div = armada_38x_cpu_l2_ratios[opt][1];
 110                break;
 111        case A380_CPU_TO_DDR:
 112                *mult = armada_38x_cpu_ddr_ratios[opt][0];
 113                *div = armada_38x_cpu_ddr_ratios[opt][1];
 114                break;
 115        }
 116}
 117
 118static const struct coreclk_soc_desc armada_38x_coreclks = {
 119        .get_tclk_freq = armada_38x_get_tclk_freq,
 120        .get_cpu_freq = armada_38x_get_cpu_freq,
 121        .get_clk_ratio = armada_38x_get_clk_ratio,
 122        .ratios = armada_38x_coreclk_ratios,
 123        .num_ratios = ARRAY_SIZE(armada_38x_coreclk_ratios),
 124};
 125
 126static void __init armada_38x_coreclk_init(struct device_node *np)
 127{
 128        mvebu_coreclk_setup(np, &armada_38x_coreclks);
 129}
 130CLK_OF_DECLARE(armada_38x_core_clk, "marvell,armada-380-core-clock",
 131               armada_38x_coreclk_init);
 132
 133/*
 134 * Clock Gating Control
 135 */
 136static const struct clk_gating_soc_desc armada_38x_gating_desc[] __initconst = {
 137        { "audio", NULL, 0 },
 138        { "ge2", NULL, 2 },
 139        { "ge1", NULL, 3 },
 140        { "ge0", NULL, 4 },
 141        { "pex1", NULL, 5 },
 142        { "pex2", NULL, 6 },
 143        { "pex3", NULL, 7 },
 144        { "pex0", NULL, 8 },
 145        { "usb3h0", NULL, 9 },
 146        { "usb3h1", NULL, 10 },
 147        { "usb3d", NULL, 11 },
 148        { "bm", NULL, 13 },
 149        { "crypto0z", NULL, 14 },
 150        { "sata0", NULL, 15 },
 151        { "crypto1z", NULL, 16 },
 152        { "sdio", NULL, 17 },
 153        { "usb2", NULL, 18 },
 154        { "crypto1", NULL, 21 },
 155        { "xor0", NULL, 22 },
 156        { "crypto0", NULL, 23 },
 157        { "tdm", NULL, 25 },
 158        { "xor1", NULL, 28 },
 159        { "sata1", NULL, 30 },
 160        { }
 161};
 162
 163static void __init armada_38x_clk_gating_init(struct device_node *np)
 164{
 165        mvebu_clk_gating_setup(np, armada_38x_gating_desc);
 166}
 167CLK_OF_DECLARE(armada_38x_clk_gating, "marvell,armada-380-gating-clock",
 168               armada_38x_clk_gating_init);
 169