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