2012-11-17 14:22:22 +00:00
|
|
|
/*
|
|
|
|
* Marvell EBU clock core handling defined at reset
|
|
|
|
*
|
|
|
|
* Copyright (C) 2012 Marvell
|
|
|
|
*
|
|
|
|
* Gregory CLEMENT <gregory.clement@free-electrons.com>
|
|
|
|
* Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
|
|
|
|
*
|
|
|
|
* This file is licensed under the terms of the GNU General Public
|
|
|
|
* License version 2. This program is licensed "as is" without any
|
|
|
|
* warranty of any kind, whether express or implied.
|
|
|
|
*/
|
|
|
|
#include <linux/kernel.h>
|
|
|
|
#include <linux/clk.h>
|
|
|
|
#include <linux/clkdev.h>
|
|
|
|
#include <linux/clk-provider.h>
|
|
|
|
#include <linux/of_address.h>
|
|
|
|
#include <linux/io.h>
|
|
|
|
#include <linux/of.h>
|
|
|
|
#include "clk-core.h"
|
|
|
|
|
|
|
|
struct core_ratio {
|
|
|
|
int id;
|
|
|
|
const char *name;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct core_clocks {
|
|
|
|
u32 (*get_tclk_freq)(void __iomem *sar);
|
|
|
|
u32 (*get_cpu_freq)(void __iomem *sar);
|
|
|
|
void (*get_clk_ratio)(void __iomem *sar, int id, int *mult, int *div);
|
|
|
|
const struct core_ratio *ratios;
|
|
|
|
int num_ratios;
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct clk_onecell_data clk_data;
|
|
|
|
|
|
|
|
static void __init mvebu_clk_core_setup(struct device_node *np,
|
|
|
|
struct core_clocks *coreclk)
|
|
|
|
{
|
|
|
|
const char *tclk_name = "tclk";
|
|
|
|
const char *cpuclk_name = "cpuclk";
|
|
|
|
void __iomem *base;
|
|
|
|
unsigned long rate;
|
|
|
|
int n;
|
|
|
|
|
|
|
|
base = of_iomap(np, 0);
|
|
|
|
if (WARN_ON(!base))
|
|
|
|
return;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Allocate struct for TCLK, cpu clk, and core ratio clocks
|
|
|
|
*/
|
|
|
|
clk_data.clk_num = 2 + coreclk->num_ratios;
|
|
|
|
clk_data.clks = kzalloc(clk_data.clk_num * sizeof(struct clk *),
|
|
|
|
GFP_KERNEL);
|
|
|
|
if (WARN_ON(!clk_data.clks))
|
|
|
|
return;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Register TCLK
|
|
|
|
*/
|
|
|
|
of_property_read_string_index(np, "clock-output-names", 0,
|
|
|
|
&tclk_name);
|
|
|
|
rate = coreclk->get_tclk_freq(base);
|
|
|
|
clk_data.clks[0] = clk_register_fixed_rate(NULL, tclk_name, NULL,
|
|
|
|
CLK_IS_ROOT, rate);
|
|
|
|
WARN_ON(IS_ERR(clk_data.clks[0]));
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Register CPU clock
|
|
|
|
*/
|
|
|
|
of_property_read_string_index(np, "clock-output-names", 1,
|
|
|
|
&cpuclk_name);
|
|
|
|
rate = coreclk->get_cpu_freq(base);
|
|
|
|
clk_data.clks[1] = clk_register_fixed_rate(NULL, cpuclk_name, NULL,
|
|
|
|
CLK_IS_ROOT, rate);
|
|
|
|
WARN_ON(IS_ERR(clk_data.clks[1]));
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Register fixed-factor clocks derived from CPU clock
|
|
|
|
*/
|
|
|
|
for (n = 0; n < coreclk->num_ratios; n++) {
|
|
|
|
const char *rclk_name = coreclk->ratios[n].name;
|
|
|
|
int mult, div;
|
|
|
|
|
|
|
|
of_property_read_string_index(np, "clock-output-names",
|
|
|
|
2+n, &rclk_name);
|
|
|
|
coreclk->get_clk_ratio(base, coreclk->ratios[n].id,
|
|
|
|
&mult, &div);
|
|
|
|
clk_data.clks[2+n] = clk_register_fixed_factor(NULL, rclk_name,
|
|
|
|
cpuclk_name, 0, mult, div);
|
|
|
|
WARN_ON(IS_ERR(clk_data.clks[2+n]));
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* SAR register isn't needed anymore
|
|
|
|
*/
|
|
|
|
iounmap(base);
|
|
|
|
|
|
|
|
of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef CONFIG_MACH_ARMADA_370_XP
|
|
|
|
/*
|
|
|
|
* Armada 370/XP Sample At Reset is a 64 bit bitfiled split in two
|
|
|
|
* register of 32 bits
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define SARL 0 /* Low part [0:31] */
|
|
|
|
#define SARL_AXP_PCLK_FREQ_OPT 21
|
|
|
|
#define SARL_AXP_PCLK_FREQ_OPT_MASK 0x7
|
|
|
|
#define SARL_A370_PCLK_FREQ_OPT 11
|
|
|
|
#define SARL_A370_PCLK_FREQ_OPT_MASK 0xF
|
|
|
|
#define SARL_AXP_FAB_FREQ_OPT 24
|
|
|
|
#define SARL_AXP_FAB_FREQ_OPT_MASK 0xF
|
|
|
|
#define SARL_A370_FAB_FREQ_OPT 15
|
|
|
|
#define SARL_A370_FAB_FREQ_OPT_MASK 0x1F
|
|
|
|
#define SARL_A370_TCLK_FREQ_OPT 20
|
|
|
|
#define SARL_A370_TCLK_FREQ_OPT_MASK 0x1
|
|
|
|
#define SARH 4 /* High part [32:63] */
|
|
|
|
#define SARH_AXP_PCLK_FREQ_OPT (52-32)
|
|
|
|
#define SARH_AXP_PCLK_FREQ_OPT_MASK 0x1
|
|
|
|
#define SARH_AXP_PCLK_FREQ_OPT_SHIFT 3
|
|
|
|
#define SARH_AXP_FAB_FREQ_OPT (51-32)
|
|
|
|
#define SARH_AXP_FAB_FREQ_OPT_MASK 0x1
|
|
|
|
#define SARH_AXP_FAB_FREQ_OPT_SHIFT 4
|
|
|
|
|
|
|
|
static const u32 __initconst armada_370_tclk_frequencies[] = {
|
|
|
|
16600000,
|
|
|
|
20000000,
|
|
|
|
};
|
|
|
|
|
|
|
|
static u32 __init armada_370_get_tclk_freq(void __iomem *sar)
|
|
|
|
{
|
|
|
|
u8 tclk_freq_select = 0;
|
|
|
|
|
|
|
|
tclk_freq_select = ((readl(sar) >> SARL_A370_TCLK_FREQ_OPT) &
|
|
|
|
SARL_A370_TCLK_FREQ_OPT_MASK);
|
|
|
|
return armada_370_tclk_frequencies[tclk_freq_select];
|
|
|
|
}
|
|
|
|
|
|
|
|
static const u32 __initconst armada_370_cpu_frequencies[] = {
|
|
|
|
400000000,
|
|
|
|
533000000,
|
|
|
|
667000000,
|
|
|
|
800000000,
|
|
|
|
1000000000,
|
|
|
|
1067000000,
|
|
|
|
1200000000,
|
|
|
|
};
|
|
|
|
|
|
|
|
static u32 __init armada_370_get_cpu_freq(void __iomem *sar)
|
|
|
|
{
|
|
|
|
u32 cpu_freq;
|
|
|
|
u8 cpu_freq_select = 0;
|
|
|
|
|
|
|
|
cpu_freq_select = ((readl(sar) >> SARL_A370_PCLK_FREQ_OPT) &
|
|
|
|
SARL_A370_PCLK_FREQ_OPT_MASK);
|
2013-04-08 03:43:02 +00:00
|
|
|
if (cpu_freq_select >= ARRAY_SIZE(armada_370_cpu_frequencies)) {
|
2013-03-20 02:00:34 +00:00
|
|
|
pr_err("CPU freq select unsupported %d\n", cpu_freq_select);
|
2012-11-17 14:22:22 +00:00
|
|
|
cpu_freq = 0;
|
|
|
|
} else
|
|
|
|
cpu_freq = armada_370_cpu_frequencies[cpu_freq_select];
|
|
|
|
|
|
|
|
return cpu_freq;
|
|
|
|
}
|
|
|
|
|
|
|
|
enum { A370_XP_NBCLK, A370_XP_HCLK, A370_XP_DRAMCLK };
|
|
|
|
|
|
|
|
static const struct core_ratio __initconst armada_370_xp_core_ratios[] = {
|
|
|
|
{ .id = A370_XP_NBCLK, .name = "nbclk" },
|
|
|
|
{ .id = A370_XP_HCLK, .name = "hclk" },
|
|
|
|
{ .id = A370_XP_DRAMCLK, .name = "dramclk" },
|
|
|
|
};
|
|
|
|
|
|
|
|
static const int __initconst armada_370_xp_nbclk_ratios[32][2] = {
|
|
|
|
{0, 1}, {1, 2}, {2, 2}, {2, 2},
|
|
|
|
{1, 2}, {1, 2}, {1, 1}, {2, 3},
|
|
|
|
{0, 1}, {1, 2}, {2, 4}, {0, 1},
|
|
|
|
{1, 2}, {0, 1}, {0, 1}, {2, 2},
|
|
|
|
{0, 1}, {0, 1}, {0, 1}, {1, 1},
|
|
|
|
{2, 3}, {0, 1}, {0, 1}, {0, 1},
|
|
|
|
{0, 1}, {0, 1}, {0, 1}, {1, 1},
|
|
|
|
{0, 1}, {0, 1}, {0, 1}, {0, 1},
|
|
|
|
};
|
|
|
|
|
|
|
|
static const int __initconst armada_370_xp_hclk_ratios[32][2] = {
|
|
|
|
{0, 1}, {1, 2}, {2, 6}, {2, 3},
|
|
|
|
{1, 3}, {1, 4}, {1, 2}, {2, 6},
|
|
|
|
{0, 1}, {1, 6}, {2, 10}, {0, 1},
|
|
|
|
{1, 4}, {0, 1}, {0, 1}, {2, 5},
|
|
|
|
{0, 1}, {0, 1}, {0, 1}, {1, 2},
|
|
|
|
{2, 6}, {0, 1}, {0, 1}, {0, 1},
|
|
|
|
{0, 1}, {0, 1}, {0, 1}, {1, 1},
|
|
|
|
{0, 1}, {0, 1}, {0, 1}, {0, 1},
|
|
|
|
};
|
|
|
|
|
|
|
|
static const int __initconst armada_370_xp_dramclk_ratios[32][2] = {
|
|
|
|
{0, 1}, {1, 2}, {2, 3}, {2, 3},
|
|
|
|
{1, 3}, {1, 2}, {1, 2}, {2, 6},
|
|
|
|
{0, 1}, {1, 3}, {2, 5}, {0, 1},
|
|
|
|
{1, 4}, {0, 1}, {0, 1}, {2, 5},
|
|
|
|
{0, 1}, {0, 1}, {0, 1}, {1, 1},
|
|
|
|
{2, 3}, {0, 1}, {0, 1}, {0, 1},
|
|
|
|
{0, 1}, {0, 1}, {0, 1}, {1, 1},
|
|
|
|
{0, 1}, {0, 1}, {0, 1}, {0, 1},
|
|
|
|
};
|
|
|
|
|
|
|
|
static void __init armada_370_xp_get_clk_ratio(u32 opt,
|
|
|
|
void __iomem *sar, int id, int *mult, int *div)
|
|
|
|
{
|
|
|
|
switch (id) {
|
|
|
|
case A370_XP_NBCLK:
|
|
|
|
*mult = armada_370_xp_nbclk_ratios[opt][0];
|
|
|
|
*div = armada_370_xp_nbclk_ratios[opt][1];
|
|
|
|
break;
|
|
|
|
case A370_XP_HCLK:
|
|
|
|
*mult = armada_370_xp_hclk_ratios[opt][0];
|
|
|
|
*div = armada_370_xp_hclk_ratios[opt][1];
|
|
|
|
break;
|
|
|
|
case A370_XP_DRAMCLK:
|
|
|
|
*mult = armada_370_xp_dramclk_ratios[opt][0];
|
|
|
|
*div = armada_370_xp_dramclk_ratios[opt][1];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void __init armada_370_get_clk_ratio(
|
|
|
|
void __iomem *sar, int id, int *mult, int *div)
|
|
|
|
{
|
|
|
|
u32 opt = ((readl(sar) >> SARL_A370_FAB_FREQ_OPT) &
|
|
|
|
SARL_A370_FAB_FREQ_OPT_MASK);
|
|
|
|
|
|
|
|
armada_370_xp_get_clk_ratio(opt, sar, id, mult, div);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static const struct core_clocks armada_370_core_clocks = {
|
|
|
|
.get_tclk_freq = armada_370_get_tclk_freq,
|
|
|
|
.get_cpu_freq = armada_370_get_cpu_freq,
|
|
|
|
.get_clk_ratio = armada_370_get_clk_ratio,
|
|
|
|
.ratios = armada_370_xp_core_ratios,
|
|
|
|
.num_ratios = ARRAY_SIZE(armada_370_xp_core_ratios),
|
|
|
|
};
|
|
|
|
|
|
|
|
static const u32 __initconst armada_xp_cpu_frequencies[] = {
|
|
|
|
1000000000,
|
|
|
|
1066000000,
|
|
|
|
1200000000,
|
|
|
|
1333000000,
|
|
|
|
1500000000,
|
|
|
|
1666000000,
|
|
|
|
1800000000,
|
|
|
|
2000000000,
|
|
|
|
667000000,
|
|
|
|
0,
|
|
|
|
800000000,
|
|
|
|
1600000000,
|
|
|
|
};
|
|
|
|
|
|
|
|
/* For Armada XP TCLK frequency is fix: 250MHz */
|
|
|
|
static u32 __init armada_xp_get_tclk_freq(void __iomem *sar)
|
|
|
|
{
|
|
|
|
return 250 * 1000 * 1000;
|
|
|
|
}
|
|
|
|
|
|
|
|
static u32 __init armada_xp_get_cpu_freq(void __iomem *sar)
|
|
|
|
{
|
|
|
|
u32 cpu_freq;
|
|
|
|
u8 cpu_freq_select = 0;
|
|
|
|
|
|
|
|
cpu_freq_select = ((readl(sar) >> SARL_AXP_PCLK_FREQ_OPT) &
|
|
|
|
SARL_AXP_PCLK_FREQ_OPT_MASK);
|
|
|
|
/*
|
|
|
|
* The upper bit is not contiguous to the other ones and
|
|
|
|
* located in the high part of the SAR registers
|
|
|
|
*/
|
|
|
|
cpu_freq_select |= (((readl(sar+4) >> SARH_AXP_PCLK_FREQ_OPT) &
|
|
|
|
SARH_AXP_PCLK_FREQ_OPT_MASK)
|
|
|
|
<< SARH_AXP_PCLK_FREQ_OPT_SHIFT);
|
2013-04-08 03:43:02 +00:00
|
|
|
if (cpu_freq_select >= ARRAY_SIZE(armada_xp_cpu_frequencies)) {
|
2013-03-20 02:00:34 +00:00
|
|
|
pr_err("CPU freq select unsupported: %d\n", cpu_freq_select);
|
2012-11-17 14:22:22 +00:00
|
|
|
cpu_freq = 0;
|
|
|
|
} else
|
|
|
|
cpu_freq = armada_xp_cpu_frequencies[cpu_freq_select];
|
|
|
|
|
|
|
|
return cpu_freq;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void __init armada_xp_get_clk_ratio(
|
|
|
|
void __iomem *sar, int id, int *mult, int *div)
|
|
|
|
{
|
|
|
|
|
|
|
|
u32 opt = ((readl(sar) >> SARL_AXP_FAB_FREQ_OPT) &
|
|
|
|
SARL_AXP_FAB_FREQ_OPT_MASK);
|
|
|
|
/*
|
|
|
|
* The upper bit is not contiguous to the other ones and
|
|
|
|
* located in the high part of the SAR registers
|
|
|
|
*/
|
|
|
|
opt |= (((readl(sar+4) >> SARH_AXP_FAB_FREQ_OPT) &
|
|
|
|
SARH_AXP_FAB_FREQ_OPT_MASK)
|
|
|
|
<< SARH_AXP_FAB_FREQ_OPT_SHIFT);
|
|
|
|
|
|
|
|
armada_370_xp_get_clk_ratio(opt, sar, id, mult, div);
|
|
|
|
}
|
|
|
|
|
|
|
|
static const struct core_clocks armada_xp_core_clocks = {
|
|
|
|
.get_tclk_freq = armada_xp_get_tclk_freq,
|
|
|
|
.get_cpu_freq = armada_xp_get_cpu_freq,
|
|
|
|
.get_clk_ratio = armada_xp_get_clk_ratio,
|
|
|
|
.ratios = armada_370_xp_core_ratios,
|
|
|
|
.num_ratios = ARRAY_SIZE(armada_370_xp_core_ratios),
|
|
|
|
};
|
|
|
|
|
|
|
|
#endif /* CONFIG_MACH_ARMADA_370_XP */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Dove PLL sample-at-reset configuration
|
|
|
|
*
|
|
|
|
* SAR0[8:5] : CPU frequency
|
|
|
|
* 5 = 1000 MHz
|
|
|
|
* 6 = 933 MHz
|
|
|
|
* 7 = 933 MHz
|
|
|
|
* 8 = 800 MHz
|
|
|
|
* 9 = 800 MHz
|
|
|
|
* 10 = 800 MHz
|
|
|
|
* 11 = 1067 MHz
|
|
|
|
* 12 = 667 MHz
|
|
|
|
* 13 = 533 MHz
|
|
|
|
* 14 = 400 MHz
|
|
|
|
* 15 = 333 MHz
|
|
|
|
* others reserved.
|
|
|
|
*
|
|
|
|
* SAR0[11:9] : CPU to L2 Clock divider ratio
|
|
|
|
* 0 = (1/1) * CPU
|
|
|
|
* 2 = (1/2) * CPU
|
|
|
|
* 4 = (1/3) * CPU
|
|
|
|
* 6 = (1/4) * CPU
|
|
|
|
* others reserved.
|
|
|
|
*
|
|
|
|
* SAR0[15:12] : CPU to DDR DRAM Clock divider ratio
|
|
|
|
* 0 = (1/1) * CPU
|
|
|
|
* 2 = (1/2) * CPU
|
|
|
|
* 3 = (2/5) * CPU
|
|
|
|
* 4 = (1/3) * CPU
|
|
|
|
* 6 = (1/4) * CPU
|
|
|
|
* 8 = (1/5) * CPU
|
|
|
|
* 10 = (1/6) * CPU
|
|
|
|
* 12 = (1/7) * CPU
|
|
|
|
* 14 = (1/8) * CPU
|
|
|
|
* 15 = (1/10) * CPU
|
|
|
|
* others reserved.
|
|
|
|
*
|
|
|
|
* SAR0[24:23] : TCLK frequency
|
|
|
|
* 0 = 166 MHz
|
|
|
|
* 1 = 125 MHz
|
|
|
|
* others reserved.
|
|
|
|
*/
|
|
|
|
#ifdef CONFIG_ARCH_DOVE
|
|
|
|
#define SAR_DOVE_CPU_FREQ 5
|
|
|
|
#define SAR_DOVE_CPU_FREQ_MASK 0xf
|
|
|
|
#define SAR_DOVE_L2_RATIO 9
|
|
|
|
#define SAR_DOVE_L2_RATIO_MASK 0x7
|
|
|
|
#define SAR_DOVE_DDR_RATIO 12
|
|
|
|
#define SAR_DOVE_DDR_RATIO_MASK 0xf
|
|
|
|
#define SAR_DOVE_TCLK_FREQ 23
|
|
|
|
#define SAR_DOVE_TCLK_FREQ_MASK 0x3
|
|
|
|
|
|
|
|
static const u32 __initconst dove_tclk_frequencies[] = {
|
|
|
|
166666667,
|
|
|
|
125000000,
|
|
|
|
0, 0
|
|
|
|
};
|
|
|
|
|
|
|
|
static u32 __init dove_get_tclk_freq(void __iomem *sar)
|
|
|
|
{
|
|
|
|
u32 opt = (readl(sar) >> SAR_DOVE_TCLK_FREQ) &
|
|
|
|
SAR_DOVE_TCLK_FREQ_MASK;
|
|
|
|
return dove_tclk_frequencies[opt];
|
|
|
|
}
|
|
|
|
|
|
|
|
static const u32 __initconst dove_cpu_frequencies[] = {
|
|
|
|
0, 0, 0, 0, 0,
|
|
|
|
1000000000,
|
|
|
|
933333333, 933333333,
|
|
|
|
800000000, 800000000, 800000000,
|
|
|
|
1066666667,
|
|
|
|
666666667,
|
|
|
|
533333333,
|
|
|
|
400000000,
|
|
|
|
333333333
|
|
|
|
};
|
|
|
|
|
|
|
|
static u32 __init dove_get_cpu_freq(void __iomem *sar)
|
|
|
|
{
|
|
|
|
u32 opt = (readl(sar) >> SAR_DOVE_CPU_FREQ) &
|
|
|
|
SAR_DOVE_CPU_FREQ_MASK;
|
|
|
|
return dove_cpu_frequencies[opt];
|
|
|
|
}
|
|
|
|
|
|
|
|
enum { DOVE_CPU_TO_L2, DOVE_CPU_TO_DDR };
|
|
|
|
|
|
|
|
static const struct core_ratio __initconst dove_core_ratios[] = {
|
|
|
|
{ .id = DOVE_CPU_TO_L2, .name = "l2clk", },
|
|
|
|
{ .id = DOVE_CPU_TO_DDR, .name = "ddrclk", }
|
|
|
|
};
|
|
|
|
|
|
|
|
static const int __initconst dove_cpu_l2_ratios[8][2] = {
|
|
|
|
{ 1, 1 }, { 0, 1 }, { 1, 2 }, { 0, 1 },
|
|
|
|
{ 1, 3 }, { 0, 1 }, { 1, 4 }, { 0, 1 }
|
|
|
|
};
|
|
|
|
|
|
|
|
static const int __initconst dove_cpu_ddr_ratios[16][2] = {
|
|
|
|
{ 1, 1 }, { 0, 1 }, { 1, 2 }, { 2, 5 },
|
|
|
|
{ 1, 3 }, { 0, 1 }, { 1, 4 }, { 0, 1 },
|
|
|
|
{ 1, 5 }, { 0, 1 }, { 1, 6 }, { 0, 1 },
|
|
|
|
{ 1, 7 }, { 0, 1 }, { 1, 8 }, { 1, 10 }
|
|
|
|
};
|
|
|
|
|
|
|
|
static void __init dove_get_clk_ratio(
|
|
|
|
void __iomem *sar, int id, int *mult, int *div)
|
|
|
|
{
|
|
|
|
switch (id) {
|
|
|
|
case DOVE_CPU_TO_L2:
|
|
|
|
{
|
|
|
|
u32 opt = (readl(sar) >> SAR_DOVE_L2_RATIO) &
|
|
|
|
SAR_DOVE_L2_RATIO_MASK;
|
|
|
|
*mult = dove_cpu_l2_ratios[opt][0];
|
|
|
|
*div = dove_cpu_l2_ratios[opt][1];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case DOVE_CPU_TO_DDR:
|
|
|
|
{
|
|
|
|
u32 opt = (readl(sar) >> SAR_DOVE_DDR_RATIO) &
|
|
|
|
SAR_DOVE_DDR_RATIO_MASK;
|
|
|
|
*mult = dove_cpu_ddr_ratios[opt][0];
|
|
|
|
*div = dove_cpu_ddr_ratios[opt][1];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static const struct core_clocks dove_core_clocks = {
|
|
|
|
.get_tclk_freq = dove_get_tclk_freq,
|
|
|
|
.get_cpu_freq = dove_get_cpu_freq,
|
|
|
|
.get_clk_ratio = dove_get_clk_ratio,
|
|
|
|
.ratios = dove_core_ratios,
|
|
|
|
.num_ratios = ARRAY_SIZE(dove_core_ratios),
|
|
|
|
};
|
|
|
|
#endif /* CONFIG_ARCH_DOVE */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Kirkwood PLL sample-at-reset configuration
|
|
|
|
* (6180 has different SAR layout than other Kirkwood SoCs)
|
|
|
|
*
|
|
|
|
* SAR0[4:3,22,1] : CPU frequency (6281,6292,6282)
|
|
|
|
* 4 = 600 MHz
|
|
|
|
* 6 = 800 MHz
|
|
|
|
* 7 = 1000 MHz
|
|
|
|
* 9 = 1200 MHz
|
|
|
|
* 12 = 1500 MHz
|
|
|
|
* 13 = 1600 MHz
|
|
|
|
* 14 = 1800 MHz
|
|
|
|
* 15 = 2000 MHz
|
|
|
|
* others reserved.
|
|
|
|
*
|
|
|
|
* SAR0[19,10:9] : CPU to L2 Clock divider ratio (6281,6292,6282)
|
|
|
|
* 1 = (1/2) * CPU
|
|
|
|
* 3 = (1/3) * CPU
|
|
|
|
* 5 = (1/4) * CPU
|
|
|
|
* others reserved.
|
|
|
|
*
|
|
|
|
* SAR0[8:5] : CPU to DDR DRAM Clock divider ratio (6281,6292,6282)
|
|
|
|
* 2 = (1/2) * CPU
|
|
|
|
* 4 = (1/3) * CPU
|
|
|
|
* 6 = (1/4) * CPU
|
|
|
|
* 7 = (2/9) * CPU
|
|
|
|
* 8 = (1/5) * CPU
|
|
|
|
* 9 = (1/6) * CPU
|
|
|
|
* others reserved.
|
|
|
|
*
|
|
|
|
* SAR0[4:2] : Kirkwood 6180 cpu/l2/ddr clock configuration (6180 only)
|
|
|
|
* 5 = [CPU = 600 MHz, L2 = (1/2) * CPU, DDR = 200 MHz = (1/3) * CPU]
|
|
|
|
* 6 = [CPU = 800 MHz, L2 = (1/2) * CPU, DDR = 200 MHz = (1/4) * CPU]
|
|
|
|
* 7 = [CPU = 1000 MHz, L2 = (1/2) * CPU, DDR = 200 MHz = (1/5) * CPU]
|
|
|
|
* others reserved.
|
|
|
|
*
|
|
|
|
* SAR0[21] : TCLK frequency
|
|
|
|
* 0 = 200 MHz
|
|
|
|
* 1 = 166 MHz
|
|
|
|
* others reserved.
|
|
|
|
*/
|
|
|
|
#ifdef CONFIG_ARCH_KIRKWOOD
|
|
|
|
#define SAR_KIRKWOOD_CPU_FREQ(x) \
|
|
|
|
(((x & (1 << 1)) >> 1) | \
|
|
|
|
((x & (1 << 22)) >> 21) | \
|
|
|
|
((x & (3 << 3)) >> 1))
|
|
|
|
#define SAR_KIRKWOOD_L2_RATIO(x) \
|
|
|
|
(((x & (3 << 9)) >> 9) | \
|
|
|
|
(((x & (1 << 19)) >> 17)))
|
|
|
|
#define SAR_KIRKWOOD_DDR_RATIO 5
|
|
|
|
#define SAR_KIRKWOOD_DDR_RATIO_MASK 0xf
|
|
|
|
#define SAR_MV88F6180_CLK 2
|
|
|
|
#define SAR_MV88F6180_CLK_MASK 0x7
|
|
|
|
#define SAR_KIRKWOOD_TCLK_FREQ 21
|
|
|
|
#define SAR_KIRKWOOD_TCLK_FREQ_MASK 0x1
|
|
|
|
|
|
|
|
enum { KIRKWOOD_CPU_TO_L2, KIRKWOOD_CPU_TO_DDR };
|
|
|
|
|
|
|
|
static const struct core_ratio __initconst kirkwood_core_ratios[] = {
|
|
|
|
{ .id = KIRKWOOD_CPU_TO_L2, .name = "l2clk", },
|
|
|
|
{ .id = KIRKWOOD_CPU_TO_DDR, .name = "ddrclk", }
|
|
|
|
};
|
|
|
|
|
|
|
|
static u32 __init kirkwood_get_tclk_freq(void __iomem *sar)
|
|
|
|
{
|
|
|
|
u32 opt = (readl(sar) >> SAR_KIRKWOOD_TCLK_FREQ) &
|
|
|
|
SAR_KIRKWOOD_TCLK_FREQ_MASK;
|
|
|
|
return (opt) ? 166666667 : 200000000;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const u32 __initconst kirkwood_cpu_frequencies[] = {
|
|
|
|
0, 0, 0, 0,
|
|
|
|
600000000,
|
|
|
|
0,
|
|
|
|
800000000,
|
|
|
|
1000000000,
|
|
|
|
0,
|
|
|
|
1200000000,
|
|
|
|
0, 0,
|
|
|
|
1500000000,
|
|
|
|
1600000000,
|
|
|
|
1800000000,
|
|
|
|
2000000000
|
|
|
|
};
|
|
|
|
|
|
|
|
static u32 __init kirkwood_get_cpu_freq(void __iomem *sar)
|
|
|
|
{
|
|
|
|
u32 opt = SAR_KIRKWOOD_CPU_FREQ(readl(sar));
|
|
|
|
return kirkwood_cpu_frequencies[opt];
|
|
|
|
}
|
|
|
|
|
|
|
|
static const int __initconst kirkwood_cpu_l2_ratios[8][2] = {
|
|
|
|
{ 0, 1 }, { 1, 2 }, { 0, 1 }, { 1, 3 },
|
|
|
|
{ 0, 1 }, { 1, 4 }, { 0, 1 }, { 0, 1 }
|
|
|
|
};
|
|
|
|
|
|
|
|
static const int __initconst kirkwood_cpu_ddr_ratios[16][2] = {
|
|
|
|
{ 0, 1 }, { 0, 1 }, { 1, 2 }, { 0, 1 },
|
|
|
|
{ 1, 3 }, { 0, 1 }, { 1, 4 }, { 2, 9 },
|
|
|
|
{ 1, 5 }, { 1, 6 }, { 0, 1 }, { 0, 1 },
|
|
|
|
{ 0, 1 }, { 0, 1 }, { 0, 1 }, { 0, 1 }
|
|
|
|
};
|
|
|
|
|
|
|
|
static void __init kirkwood_get_clk_ratio(
|
|
|
|
void __iomem *sar, int id, int *mult, int *div)
|
|
|
|
{
|
|
|
|
switch (id) {
|
|
|
|
case KIRKWOOD_CPU_TO_L2:
|
|
|
|
{
|
|
|
|
u32 opt = SAR_KIRKWOOD_L2_RATIO(readl(sar));
|
|
|
|
*mult = kirkwood_cpu_l2_ratios[opt][0];
|
|
|
|
*div = kirkwood_cpu_l2_ratios[opt][1];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case KIRKWOOD_CPU_TO_DDR:
|
|
|
|
{
|
|
|
|
u32 opt = (readl(sar) >> SAR_KIRKWOOD_DDR_RATIO) &
|
|
|
|
SAR_KIRKWOOD_DDR_RATIO_MASK;
|
|
|
|
*mult = kirkwood_cpu_ddr_ratios[opt][0];
|
|
|
|
*div = kirkwood_cpu_ddr_ratios[opt][1];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static const struct core_clocks kirkwood_core_clocks = {
|
|
|
|
.get_tclk_freq = kirkwood_get_tclk_freq,
|
|
|
|
.get_cpu_freq = kirkwood_get_cpu_freq,
|
|
|
|
.get_clk_ratio = kirkwood_get_clk_ratio,
|
|
|
|
.ratios = kirkwood_core_ratios,
|
|
|
|
.num_ratios = ARRAY_SIZE(kirkwood_core_ratios),
|
|
|
|
};
|
|
|
|
|
|
|
|
static const u32 __initconst mv88f6180_cpu_frequencies[] = {
|
|
|
|
0, 0, 0, 0, 0,
|
|
|
|
600000000,
|
|
|
|
800000000,
|
|
|
|
1000000000
|
|
|
|
};
|
|
|
|
|
|
|
|
static u32 __init mv88f6180_get_cpu_freq(void __iomem *sar)
|
|
|
|
{
|
|
|
|
u32 opt = (readl(sar) >> SAR_MV88F6180_CLK) & SAR_MV88F6180_CLK_MASK;
|
|
|
|
return mv88f6180_cpu_frequencies[opt];
|
|
|
|
}
|
|
|
|
|
|
|
|
static const int __initconst mv88f6180_cpu_ddr_ratios[8][2] = {
|
|
|
|
{ 0, 1 }, { 0, 1 }, { 0, 1 }, { 0, 1 },
|
|
|
|
{ 0, 1 }, { 1, 3 }, { 1, 4 }, { 1, 5 }
|
|
|
|
};
|
|
|
|
|
|
|
|
static void __init mv88f6180_get_clk_ratio(
|
|
|
|
void __iomem *sar, int id, int *mult, int *div)
|
|
|
|
{
|
|
|
|
switch (id) {
|
|
|
|
case KIRKWOOD_CPU_TO_L2:
|
|
|
|
{
|
|
|
|
/* mv88f6180 has a fixed 1:2 CPU-to-L2 ratio */
|
|
|
|
*mult = 1;
|
|
|
|
*div = 2;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case KIRKWOOD_CPU_TO_DDR:
|
|
|
|
{
|
|
|
|
u32 opt = (readl(sar) >> SAR_MV88F6180_CLK) &
|
|
|
|
SAR_MV88F6180_CLK_MASK;
|
|
|
|
*mult = mv88f6180_cpu_ddr_ratios[opt][0];
|
|
|
|
*div = mv88f6180_cpu_ddr_ratios[opt][1];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static const struct core_clocks mv88f6180_core_clocks = {
|
|
|
|
.get_tclk_freq = kirkwood_get_tclk_freq,
|
|
|
|
.get_cpu_freq = mv88f6180_get_cpu_freq,
|
|
|
|
.get_clk_ratio = mv88f6180_get_clk_ratio,
|
|
|
|
.ratios = kirkwood_core_ratios,
|
|
|
|
.num_ratios = ARRAY_SIZE(kirkwood_core_ratios),
|
|
|
|
};
|
|
|
|
#endif /* CONFIG_ARCH_KIRKWOOD */
|
|
|
|
|
|
|
|
static const __initdata struct of_device_id clk_core_match[] = {
|
|
|
|
#ifdef CONFIG_MACH_ARMADA_370_XP
|
|
|
|
{
|
|
|
|
.compatible = "marvell,armada-370-core-clock",
|
|
|
|
.data = &armada_370_core_clocks,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.compatible = "marvell,armada-xp-core-clock",
|
|
|
|
.data = &armada_xp_core_clocks,
|
|
|
|
},
|
|
|
|
#endif
|
|
|
|
#ifdef CONFIG_ARCH_DOVE
|
|
|
|
{
|
|
|
|
.compatible = "marvell,dove-core-clock",
|
|
|
|
.data = &dove_core_clocks,
|
|
|
|
},
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef CONFIG_ARCH_KIRKWOOD
|
|
|
|
{
|
|
|
|
.compatible = "marvell,kirkwood-core-clock",
|
|
|
|
.data = &kirkwood_core_clocks,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.compatible = "marvell,mv88f6180-core-clock",
|
|
|
|
.data = &mv88f6180_core_clocks,
|
|
|
|
},
|
|
|
|
#endif
|
|
|
|
|
|
|
|
{ }
|
|
|
|
};
|
|
|
|
|
|
|
|
void __init mvebu_core_clk_init(void)
|
|
|
|
{
|
|
|
|
struct device_node *np;
|
|
|
|
|
|
|
|
for_each_matching_node(np, clk_core_match) {
|
|
|
|
const struct of_device_id *match =
|
|
|
|
of_match_node(clk_core_match, np);
|
|
|
|
mvebu_clk_core_setup(np, (struct core_clocks *)match->data);
|
|
|
|
}
|
|
|
|
}
|