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        0, 0, 0, 0,
  50        1066 * 1000 * 1000, 0, 0, 0,
  51        1332 * 1000 * 1000, 0, 0, 0,
  52        1600 * 1000 * 1000,
  53};
  54
  55static u32 __init armada_38x_get_cpu_freq(void __iomem *sar)
  56{
  57        u8 cpu_freq_select;
  58
  59        cpu_freq_select = ((readl(sar) >> SAR_A380_CPU_DDR_L2_FREQ_OPT) &
  60                           SAR_A380_CPU_DDR_L2_FREQ_OPT_MASK);
  61        if (cpu_freq_select >= ARRAY_SIZE(armada_38x_cpu_frequencies)) {
  62                pr_err("Selected CPU frequency (%d) unsupported\n",
  63                        cpu_freq_select);
  64                return 0;
  65        }
  66
  67        return armada_38x_cpu_frequencies[cpu_freq_select];
  68}
  69
  70enum { A380_CPU_TO_DDR, A380_CPU_TO_L2 };
  71
  72static const struct coreclk_ratio armada_38x_coreclk_ratios[] __initconst = {
  73        { .id = A380_CPU_TO_L2,  .name = "l2clk" },
  74        { .id = A380_CPU_TO_DDR, .name = "ddrclk" },
  75};
  76
  77static const int armada_38x_cpu_l2_ratios[32][2] __initconst = {
  78        {0, 1}, {0, 1}, {0, 1}, {0, 1},
  79        {1, 2}, {0, 1}, {0, 1}, {0, 1},
  80        {1, 2}, {0, 1}, {0, 1}, {0, 1},
  81        {1, 2}, {0, 1}, {0, 1}, {0, 1},
  82        {0, 1}, {0, 1}, {0, 1}, {0, 1},
  83        {0, 1}, {0, 1}, {0, 1}, {0, 1},
  84        {0, 1}, {0, 1}, {0, 1}, {0, 1},
  85        {0, 1}, {0, 1}, {0, 1}, {0, 1},
  86};
  87
  88static const int armada_38x_cpu_ddr_ratios[32][2] __initconst = {
  89        {0, 1}, {0, 1}, {0, 1}, {0, 1},
  90        {1, 2}, {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        {0, 1}, {0, 1}, {0, 1}, {0, 1},
  94        {0, 1}, {0, 1}, {0, 1}, {0, 1},
  95        {0, 1}, {0, 1}, {0, 1}, {0, 1},
  96        {0, 1}, {0, 1}, {0, 1}, {0, 1},
  97};
  98
  99static void __init armada_38x_get_clk_ratio(
 100        void __iomem *sar, int id, int *mult, int *div)
 101{
 102        u32 opt = ((readl(sar) >> SAR_A380_CPU_DDR_L2_FREQ_OPT) &
 103                SAR_A380_CPU_DDR_L2_FREQ_OPT_MASK);
 104
 105        switch (id) {
 106        case A380_CPU_TO_L2:
 107                *mult = armada_38x_cpu_l2_ratios[opt][0];
 108                *div = armada_38x_cpu_l2_ratios[opt][1];
 109                break;
 110        case A380_CPU_TO_DDR:
 111                *mult = armada_38x_cpu_ddr_ratios[opt][0];
 112                *div = armada_38x_cpu_ddr_ratios[opt][1];
 113                break;
 114        }
 115}
 116
 117static const struct coreclk_soc_desc armada_38x_coreclks = {
 118        .get_tclk_freq = armada_38x_get_tclk_freq,
 119        .get_cpu_freq = armada_38x_get_cpu_freq,
 120        .get_clk_ratio = armada_38x_get_clk_ratio,
 121        .ratios = armada_38x_coreclk_ratios,
 122        .num_ratios = ARRAY_SIZE(armada_38x_coreclk_ratios),
 123};
 124
 125static void __init armada_38x_coreclk_init(struct device_node *np)
 126{
 127        mvebu_coreclk_setup(np, &armada_38x_coreclks);
 128}
 129CLK_OF_DECLARE(armada_38x_core_clk, "marvell,armada-380-core-clock",
 130               armada_38x_coreclk_init);
 131
 132/*
 133 * Clock Gating Control
 134 */
 135static const struct clk_gating_soc_desc armada_38x_gating_desc[] __initconst = {
 136        { "audio", NULL, 0 },
 137        { "ge2", NULL, 2 },
 138        { "ge1", NULL, 3 },
 139        { "ge0", NULL, 4 },
 140        { "pex1", NULL, 5 },
 141        { "pex2", NULL, 6 },
 142        { "pex3", NULL, 7 },
 143        { "pex0", NULL, 8 },
 144        { "usb3h0", NULL, 9 },
 145        { "usb3h1", NULL, 10 },
 146        { "usb3d", NULL, 11 },
 147        { "bm", NULL, 13 },
 148        { "crypto0z", NULL, 14 },
 149        { "sata0", NULL, 15 },
 150        { "crypto1z", NULL, 16 },
 151        { "sdio", NULL, 17 },
 152        { "usb2", NULL, 18 },
 153        { "crypto1", NULL, 21 },
 154        { "xor0", NULL, 22 },
 155        { "crypto0", NULL, 23 },
 156        { "tdm", NULL, 25 },
 157        { "xor1", NULL, 28 },
 158        { "sata1", NULL, 30 },
 159        { }
 160};
 161
 162static void __init armada_38x_clk_gating_init(struct device_node *np)
 163{
 164        mvebu_clk_gating_setup(np, armada_38x_gating_desc);
 165}
 166CLK_OF_DECLARE(armada_38x_clk_gating, "marvell,armada-380-gating-clock",
 167               armada_38x_clk_gating_init);
 168