179 lines
5.4 KiB
Diff
179 lines
5.4 KiB
Diff
|
From 9818a7a4fd10f72537cdf2a5ec3402f2c245ea24 Mon Sep 17 00:00:00 2001
|
||
|
From: Gregory CLEMENT <gregory.clement@free-electrons.com>
|
||
|
Date: Thu, 30 Nov 2017 14:40:28 +0100
|
||
|
Subject: clk: mvebu: armada-37xx-periph: prepare cpu clk to be
|
||
|
used with DVFS
|
||
|
|
||
|
When DVFS will be enabled then the cpu clk will use a different set of
|
||
|
register at run time. That means that we won't be able to use the common
|
||
|
callback and need to use our own ones.
|
||
|
|
||
|
This patch prepares this change by switching on our own set of callbacks
|
||
|
without modifying the behavior of the clocks.
|
||
|
|
||
|
Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
|
||
|
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
|
||
|
---
|
||
|
drivers/clk/mvebu/armada-37xx-periph.c | 82 ++++++++++++++++++++++++++++++----
|
||
|
1 file changed, 73 insertions(+), 9 deletions(-)
|
||
|
|
||
|
--- a/drivers/clk/mvebu/armada-37xx-periph.c
|
||
|
+++ b/drivers/clk/mvebu/armada-37xx-periph.c
|
||
|
@@ -46,7 +46,17 @@ struct clk_double_div {
|
||
|
u8 shift2;
|
||
|
};
|
||
|
|
||
|
+struct clk_pm_cpu {
|
||
|
+ struct clk_hw hw;
|
||
|
+ void __iomem *reg_mux;
|
||
|
+ u8 shift_mux;
|
||
|
+ u32 mask_mux;
|
||
|
+ void __iomem *reg_div;
|
||
|
+ u8 shift_div;
|
||
|
+};
|
||
|
+
|
||
|
#define to_clk_double_div(_hw) container_of(_hw, struct clk_double_div, hw)
|
||
|
+#define to_clk_pm_cpu(_hw) container_of(_hw, struct clk_pm_cpu, hw)
|
||
|
|
||
|
struct clk_periph_data {
|
||
|
const char *name;
|
||
|
@@ -55,6 +65,7 @@ struct clk_periph_data {
|
||
|
struct clk_hw *mux_hw;
|
||
|
struct clk_hw *rate_hw;
|
||
|
struct clk_hw *gate_hw;
|
||
|
+ struct clk_hw *muxrate_hw;
|
||
|
bool is_double_div;
|
||
|
};
|
||
|
|
||
|
@@ -81,6 +92,7 @@ static const struct clk_div_table clk_ta
|
||
|
};
|
||
|
|
||
|
static const struct clk_ops clk_double_div_ops;
|
||
|
+static const struct clk_ops clk_pm_cpu_ops;
|
||
|
|
||
|
#define PERIPH_GATE(_name, _bit) \
|
||
|
struct clk_gate gate_##_name = { \
|
||
|
@@ -122,6 +134,18 @@ struct clk_divider rate_##_name = { \
|
||
|
} \
|
||
|
};
|
||
|
|
||
|
+#define PERIPH_PM_CPU(_name, _shift1, _reg, _shift2) \
|
||
|
+struct clk_pm_cpu muxrate_##_name = { \
|
||
|
+ .reg_mux = (void *)TBG_SEL, \
|
||
|
+ .mask_mux = 3, \
|
||
|
+ .shift_mux = _shift1, \
|
||
|
+ .reg_div = (void *)_reg, \
|
||
|
+ .shift_div = _shift2, \
|
||
|
+ .hw.init = &(struct clk_init_data){ \
|
||
|
+ .ops = &clk_pm_cpu_ops, \
|
||
|
+ } \
|
||
|
+};
|
||
|
+
|
||
|
#define PERIPH_CLK_FULL_DD(_name, _bit, _shift, _reg1, _reg2, _shift1, _shift2)\
|
||
|
static PERIPH_GATE(_name, _bit); \
|
||
|
static PERIPH_MUX(_name, _shift); \
|
||
|
@@ -136,10 +160,6 @@ static PERIPH_DIV(_name, _reg, _shift1,
|
||
|
static PERIPH_GATE(_name, _bit); \
|
||
|
static PERIPH_DIV(_name, _reg, _shift, _table);
|
||
|
|
||
|
-#define PERIPH_CLK_MUX_DIV(_name, _shift, _reg, _shift_div, _table) \
|
||
|
-static PERIPH_MUX(_name, _shift); \
|
||
|
-static PERIPH_DIV(_name, _reg, _shift_div, _table);
|
||
|
-
|
||
|
#define PERIPH_CLK_MUX_DD(_name, _shift, _reg1, _reg2, _shift1, _shift2)\
|
||
|
static PERIPH_MUX(_name, _shift); \
|
||
|
static PERIPH_DOUBLEDIV(_name, _reg1, _reg2, _shift1, _shift2);
|
||
|
@@ -180,13 +200,12 @@ static PERIPH_DOUBLEDIV(_name, _reg1, _r
|
||
|
.rate_hw = &rate_##_name.hw, \
|
||
|
}
|
||
|
|
||
|
-#define REF_CLK_MUX_DIV(_name) \
|
||
|
+#define REF_CLK_PM_CPU(_name) \
|
||
|
{ .name = #_name, \
|
||
|
.parent_names = (const char *[]){ "TBG-A-P", \
|
||
|
"TBG-B-P", "TBG-A-S", "TBG-B-S"}, \
|
||
|
.num_parents = 4, \
|
||
|
- .mux_hw = &mux_##_name.hw, \
|
||
|
- .rate_hw = &rate_##_name.hw, \
|
||
|
+ .muxrate_hw = &muxrate_##_name.hw, \
|
||
|
}
|
||
|
|
||
|
#define REF_CLK_MUX_DD(_name) \
|
||
|
@@ -216,7 +235,7 @@ PERIPH_CLK_FULL_DD(ddr_fclk, 21, 16, DIV
|
||
|
PERIPH_CLK_FULL(trace, 22, 18, DIV_SEL0, 20, clk_table6);
|
||
|
PERIPH_CLK_FULL(counter, 23, 20, DIV_SEL0, 23, clk_table6);
|
||
|
PERIPH_CLK_FULL_DD(eip97, 24, 24, DIV_SEL2, DIV_SEL2, 22, 19);
|
||
|
-PERIPH_CLK_MUX_DIV(cpu, 22, DIV_SEL0, 28, clk_table6);
|
||
|
+static PERIPH_PM_CPU(cpu, 22, DIV_SEL0, 28);
|
||
|
|
||
|
static struct clk_periph_data data_nb[] = {
|
||
|
REF_CLK_FULL_DD(mmc),
|
||
|
@@ -235,7 +254,7 @@ static struct clk_periph_data data_nb[]
|
||
|
REF_CLK_FULL(trace),
|
||
|
REF_CLK_FULL(counter),
|
||
|
REF_CLK_FULL_DD(eip97),
|
||
|
- REF_CLK_MUX_DIV(cpu),
|
||
|
+ REF_CLK_PM_CPU(cpu),
|
||
|
{ },
|
||
|
};
|
||
|
|
||
|
@@ -297,6 +316,37 @@ static const struct clk_ops clk_double_d
|
||
|
.recalc_rate = clk_double_div_recalc_rate,
|
||
|
};
|
||
|
|
||
|
+static u8 clk_pm_cpu_get_parent(struct clk_hw *hw)
|
||
|
+{
|
||
|
+ struct clk_pm_cpu *pm_cpu = to_clk_pm_cpu(hw);
|
||
|
+ int num_parents = clk_hw_get_num_parents(hw);
|
||
|
+ u32 val;
|
||
|
+
|
||
|
+ val = readl(pm_cpu->reg_mux) >> pm_cpu->shift_mux;
|
||
|
+ val &= pm_cpu->mask_mux;
|
||
|
+
|
||
|
+ if (val >= num_parents)
|
||
|
+ return -EINVAL;
|
||
|
+
|
||
|
+ return val;
|
||
|
+}
|
||
|
+
|
||
|
+static unsigned long clk_pm_cpu_recalc_rate(struct clk_hw *hw,
|
||
|
+ unsigned long parent_rate)
|
||
|
+{
|
||
|
+ struct clk_pm_cpu *pm_cpu = to_clk_pm_cpu(hw);
|
||
|
+ unsigned int div;
|
||
|
+
|
||
|
+ div = get_div(pm_cpu->reg_div, pm_cpu->shift_div);
|
||
|
+
|
||
|
+ return DIV_ROUND_UP_ULL((u64)parent_rate, div);
|
||
|
+}
|
||
|
+
|
||
|
+static const struct clk_ops clk_pm_cpu_ops = {
|
||
|
+ .get_parent = clk_pm_cpu_get_parent,
|
||
|
+ .recalc_rate = clk_pm_cpu_recalc_rate,
|
||
|
+};
|
||
|
+
|
||
|
static const struct of_device_id armada_3700_periph_clock_of_match[] = {
|
||
|
{ .compatible = "marvell,armada-3700-periph-clock-nb",
|
||
|
.data = data_nb, },
|
||
|
@@ -356,6 +406,20 @@ static int armada_3700_add_composite_clk
|
||
|
}
|
||
|
}
|
||
|
|
||
|
+ if (data->muxrate_hw) {
|
||
|
+ struct clk_pm_cpu *pmcpu_clk;
|
||
|
+ struct clk_hw *muxrate_hw = data->muxrate_hw;
|
||
|
+
|
||
|
+ pmcpu_clk = to_clk_pm_cpu(muxrate_hw);
|
||
|
+ pmcpu_clk->reg_mux = reg + (u64)pmcpu_clk->reg_mux;
|
||
|
+ pmcpu_clk->reg_div = reg + (u64)pmcpu_clk->reg_div;
|
||
|
+
|
||
|
+ mux_hw = muxrate_hw;
|
||
|
+ rate_hw = muxrate_hw;
|
||
|
+ mux_ops = muxrate_hw->init->ops;
|
||
|
+ rate_ops = muxrate_hw->init->ops;
|
||
|
+ }
|
||
|
+
|
||
|
*hw = clk_hw_register_composite(dev, data->name, data->parent_names,
|
||
|
data->num_parents, mux_hw,
|
||
|
mux_ops, rate_hw, rate_ops,
|