linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/3] Add DVFS support on CPU clock for Armada 37xx
@ 2017-11-30 13:40 Gregory CLEMENT
  2017-11-30 13:40 ` [PATCH 1/3] clk: mvebu: armada-37xx-periph: cosmetic changes Gregory CLEMENT
                   ` (4 more replies)
  0 siblings, 5 replies; 10+ messages in thread
From: Gregory CLEMENT @ 2017-11-30 13:40 UTC (permalink / raw)
  To: Stephen Boyd, Mike Turquette, linux-clk, linux-kernel
  Cc: Jason Cooper, Andrew Lunn, Sebastian Hesselbarth,
	Gregory CLEMENT, Thomas Petazzoni, linux-arm-kernel,
	Antoine Tenart, Miquèl Raynal, Nadav Haklai, Victor Gu,
	Marcin Wojtas, Wilson Ding, Hua Jing, Neta Zur Hershkovits

Hi,

This small series is needed to use DVFS on Armada 37xx. When DVFS is
enabled the CPU clock setting is done using an other set of registers
from the North Bridge Power Management block.

The series adds the possibility to modify the CPU frequency using the
associate load level matching the target frequency. However
configuring the frequencies for each load is done by the cpufreq
driver submitted in a separate series.

Obviously having both series (cpufreq and clk) is needed to support
DVFS on Armada 37xx, but there is no dependencies between the series
(for building or at runtime).

Thanks,

Gregory

Gregory CLEMENT (3):
  clk: mvebu: armada-37xx-periph: cosmetic changes
  clk: mvebu: armada-37xx-periph: prepare cpu clk to be used with DVFS
  clk: mvebu: armada-37xx-periph: add DVFS support for cpu clocks

 drivers/clk/mvebu/armada-37xx-periph.c | 310 +++++++++++++++++++++++++++++++--
 1 file changed, 293 insertions(+), 17 deletions(-)

-- 
2.15.0

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 1/3] clk: mvebu: armada-37xx-periph: cosmetic changes
  2017-11-30 13:40 [PATCH 0/3] Add DVFS support on CPU clock for Armada 37xx Gregory CLEMENT
@ 2017-11-30 13:40 ` Gregory CLEMENT
  2017-12-21 23:12   ` Stephen Boyd
  2017-11-30 13:40 ` [PATCH 2/3] clk: mvebu: armada-37xx-periph: prepare cpu clk to be used with DVFS Gregory CLEMENT
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 10+ messages in thread
From: Gregory CLEMENT @ 2017-11-30 13:40 UTC (permalink / raw)
  To: Stephen Boyd, Mike Turquette, linux-clk, linux-kernel
  Cc: Jason Cooper, Andrew Lunn, Sebastian Hesselbarth,
	Gregory CLEMENT, Thomas Petazzoni, linux-arm-kernel,
	Antoine Tenart, Miquèl Raynal, Nadav Haklai, Victor Gu,
	Marcin Wojtas, Wilson Ding, Hua Jing, Neta Zur Hershkovits

This patches fixes few cosmetic issues such as alignment, blank lines
and required space.

Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
---
 drivers/clk/mvebu/armada-37xx-periph.c | 17 +++++++++--------
 1 file changed, 9 insertions(+), 8 deletions(-)

diff --git a/drivers/clk/mvebu/armada-37xx-periph.c b/drivers/clk/mvebu/armada-37xx-periph.c
index cecb0fdfaef6..6dae21ced18a 100644
--- a/drivers/clk/mvebu/armada-37xx-periph.c
+++ b/drivers/clk/mvebu/armada-37xx-periph.c
@@ -79,6 +79,7 @@ static const struct clk_div_table clk_table2[] = {
 	{ .val = 1, .div = 4, },
 	{ .val = 0, .div = 0, }, /* last entry */
 };
+
 static const struct clk_ops clk_double_div_ops;
 
 #define PERIPH_GATE(_name, _bit)		\
@@ -217,7 +218,7 @@ 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 struct clk_periph_data data_nb[] ={
+static struct clk_periph_data data_nb[] = {
 	REF_CLK_FULL_DD(mmc),
 	REF_CLK_FULL_DD(sata_host),
 	REF_CLK_FULL_DD(sec_at),
@@ -281,7 +282,7 @@ static unsigned int get_div(void __iomem *reg, int shift)
 }
 
 static unsigned long clk_double_div_recalc_rate(struct clk_hw *hw,
-		unsigned long parent_rate)
+						unsigned long parent_rate)
 {
 	struct clk_double_div *double_div = to_clk_double_div(hw);
 	unsigned int div;
@@ -303,6 +304,7 @@ static const struct of_device_id armada_3700_periph_clock_of_match[] = {
 	.data = data_sb, },
 	{ }
 };
+
 static int armada_3700_add_composite_clk(const struct clk_periph_data *data,
 					 void __iomem *reg, spinlock_t *lock,
 					 struct device *dev, struct clk_hw **hw)
@@ -355,9 +357,9 @@ static int armada_3700_add_composite_clk(const struct clk_periph_data *data,
 	}
 
 	*hw = clk_hw_register_composite(dev, data->name, data->parent_names,
-				       data->num_parents, mux_hw,
-				       mux_ops, rate_hw, rate_ops,
-				       gate_hw, gate_ops, CLK_IGNORE_UNUSED);
+					data->num_parents, mux_hw,
+					mux_ops, rate_hw, rate_ops,
+					gate_hw, gate_ops, CLK_IGNORE_UNUSED);
 
 	if (IS_ERR(*hw))
 		return PTR_ERR(*hw);
@@ -406,12 +408,11 @@ static int armada_3700_periph_clock_probe(struct platform_device *pdev)
 		if (armada_3700_add_composite_clk(&data[i], reg,
 						  &driver_data->lock, dev, hw))
 			dev_err(dev, "Can't register periph clock %s\n",
-			       data[i].name);
-
+				data[i].name);
 	}
 
 	ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get,
-				  driver_data->hw_data);
+				     driver_data->hw_data);
 	if (ret) {
 		for (i = 0; i < num_periph; i++)
 			clk_hw_unregister(driver_data->hw_data->hws[i]);
-- 
2.15.0

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 2/3] clk: mvebu: armada-37xx-periph: prepare cpu clk to be used with DVFS
  2017-11-30 13:40 [PATCH 0/3] Add DVFS support on CPU clock for Armada 37xx Gregory CLEMENT
  2017-11-30 13:40 ` [PATCH 1/3] clk: mvebu: armada-37xx-periph: cosmetic changes Gregory CLEMENT
@ 2017-11-30 13:40 ` Gregory CLEMENT
  2017-12-21 23:12   ` Stephen Boyd
  2017-11-30 13:40 ` [PATCH 3/3] clk: mvebu: armada-37xx-periph: add DVFS support for cpu clocks Gregory CLEMENT
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 10+ messages in thread
From: Gregory CLEMENT @ 2017-11-30 13:40 UTC (permalink / raw)
  To: Stephen Boyd, Mike Turquette, linux-clk, linux-kernel
  Cc: Jason Cooper, Andrew Lunn, Sebastian Hesselbarth,
	Gregory CLEMENT, Thomas Petazzoni, linux-arm-kernel,
	Antoine Tenart, Miquèl Raynal, Nadav Haklai, Victor Gu,
	Marcin Wojtas, Wilson Ding, Hua Jing, Neta Zur Hershkovits

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>
---
 drivers/clk/mvebu/armada-37xx-periph.c | 82 ++++++++++++++++++++++++++++++----
 1 file changed, 73 insertions(+), 9 deletions(-)

diff --git a/drivers/clk/mvebu/armada-37xx-periph.c b/drivers/clk/mvebu/armada-37xx-periph.c
index 6dae21ced18a..ef725ec73c93 100644
--- 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_table2[] = {
 };
 
 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, _table);
 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, _reg2, _shift1, _shift2);
 	  .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_SEL0, DIV_SEL0, 15, 12);
 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_div_ops = {
 	.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(const struct clk_periph_data *data,
 		}
 	}
 
+	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,
-- 
2.15.0

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 3/3] clk: mvebu: armada-37xx-periph: add DVFS support for cpu clocks
  2017-11-30 13:40 [PATCH 0/3] Add DVFS support on CPU clock for Armada 37xx Gregory CLEMENT
  2017-11-30 13:40 ` [PATCH 1/3] clk: mvebu: armada-37xx-periph: cosmetic changes Gregory CLEMENT
  2017-11-30 13:40 ` [PATCH 2/3] clk: mvebu: armada-37xx-periph: prepare cpu clk to be used with DVFS Gregory CLEMENT
@ 2017-11-30 13:40 ` Gregory CLEMENT
  2017-12-21 23:12   ` Stephen Boyd
  2017-12-21 10:53 ` [PATCH 0/3] Add DVFS support on CPU clock for Armada 37xx Gregory CLEMENT
  2017-12-21 23:13 ` Stephen Boyd
  4 siblings, 1 reply; 10+ messages in thread
From: Gregory CLEMENT @ 2017-11-30 13:40 UTC (permalink / raw)
  To: Stephen Boyd, Mike Turquette, linux-clk, linux-kernel
  Cc: Jason Cooper, Andrew Lunn, Sebastian Hesselbarth,
	Gregory CLEMENT, Thomas Petazzoni, linux-arm-kernel,
	Antoine Tenart, Miquèl Raynal, Nadav Haklai, Victor Gu,
	Marcin Wojtas, Wilson Ding, Hua Jing, Neta Zur Hershkovits

When DVFS is enabled the CPU clock setting is done using an other set of
registers.

These Power Management registers are exposed through a syscon as they
will also be used by other drivers such as the cpufreq.

This patch add the possibility to modify the CPU frequency using the
associate load level matching the target frequency. Then all the
frequency switch is handle by the hardware.

Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
---
 drivers/clk/mvebu/armada-37xx-periph.c | 219 ++++++++++++++++++++++++++++++++-
 1 file changed, 215 insertions(+), 4 deletions(-)

diff --git a/drivers/clk/mvebu/armada-37xx-periph.c b/drivers/clk/mvebu/armada-37xx-periph.c
index ef725ec73c93..0fd7a671a76d 100644
--- a/drivers/clk/mvebu/armada-37xx-periph.c
+++ b/drivers/clk/mvebu/armada-37xx-periph.c
@@ -21,9 +21,11 @@
  */
 
 #include <linux/clk-provider.h>
+#include <linux/mfd/syscon.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
+#include <linux/regmap.h>
 #include <linux/slab.h>
 
 #define TBG_SEL		0x0
@@ -33,6 +35,26 @@
 #define CLK_SEL		0x10
 #define CLK_DIS		0x14
 
+#define LOAD_LEVEL_NR	4
+
+#define ARMADA_37XX_NB_L0L1	0x18
+#define ARMADA_37XX_NB_L2L3	0x1C
+#define		ARMADA_37XX_NB_TBG_DIV_OFF	13
+#define		ARMADA_37XX_NB_TBG_DIV_MASK	0x7
+#define		ARMADA_37XX_NB_CLK_SEL_OFF	11
+#define		ARMADA_37XX_NB_CLK_SEL_MASK	0x1
+#define		ARMADA_37XX_NB_TBG_SEL_OFF	9
+#define		ARMADA_37XX_NB_TBG_SEL_MASK	0x3
+#define		ARMADA_37XX_NB_CONFIG_SHIFT	16
+#define ARMADA_37XX_NB_DYN_MOD	0x24
+#define		ARMADA_37XX_NB_DFS_EN	31
+#define ARMADA_37XX_NB_CPU_LOAD	0x30
+#define		ARMADA_37XX_NB_CPU_LOAD_MASK	0x3
+#define		ARMADA_37XX_DVFS_LOAD_0		0
+#define		ARMADA_37XX_DVFS_LOAD_1		1
+#define		ARMADA_37XX_DVFS_LOAD_2		2
+#define		ARMADA_37XX_DVFS_LOAD_3		3
+
 struct clk_periph_driver_data {
 	struct clk_hw_onecell_data *hw_data;
 	spinlock_t lock;
@@ -53,6 +75,7 @@ struct clk_pm_cpu {
 	u32 mask_mux;
 	void __iomem *reg_div;
 	u8 shift_div;
+	struct regmap *nb_pm_base;
 };
 
 #define to_clk_double_div(_hw) container_of(_hw, struct clk_double_div, hw)
@@ -316,14 +339,94 @@ static const struct clk_ops clk_double_div_ops = {
 	.recalc_rate = clk_double_div_recalc_rate,
 };
 
+static void armada_3700_pm_dvfs_update_regs(unsigned int load_level,
+					    unsigned int *reg,
+					    unsigned int *offset)
+{
+	if (load_level <= ARMADA_37XX_DVFS_LOAD_1)
+		*reg = ARMADA_37XX_NB_L0L1;
+	else
+		*reg = ARMADA_37XX_NB_L2L3;
+
+	if (load_level == ARMADA_37XX_DVFS_LOAD_0 ||
+	    load_level ==  ARMADA_37XX_DVFS_LOAD_2)
+		*offset += ARMADA_37XX_NB_CONFIG_SHIFT;
+}
+
+static bool armada_3700_pm_dvfs_is_enabled(struct regmap *base)
+{
+	unsigned int val, reg = ARMADA_37XX_NB_DYN_MOD;
+
+	if (IS_ERR(base))
+		return false;
+
+	regmap_read(base, reg, &val);
+
+	return !!(val & BIT(ARMADA_37XX_NB_DFS_EN));
+}
+
+static unsigned int armada_3700_pm_dvfs_get_cpu_div(struct regmap *base)
+{
+	unsigned int reg = ARMADA_37XX_NB_CPU_LOAD;
+	unsigned int offset = ARMADA_37XX_NB_TBG_DIV_OFF;
+	unsigned int load_level, div;
+
+	/*
+	 * This function is always called after the function
+	 * armada_3700_pm_dvfs_is_enabled, so no need to check again
+	 * if the base is valid.
+	 */
+	regmap_read(base, reg, &load_level);
+
+	/*
+	 * The register and the offset inside this register accessed to
+	 * read the current divider depend on the load level
+	 */
+	load_level &= ARMADA_37XX_NB_CPU_LOAD_MASK;
+	armada_3700_pm_dvfs_update_regs(load_level, &reg, &offset);
+
+	regmap_read(base, reg, &div);
+
+	return (div >> offset) & ARMADA_37XX_NB_TBG_DIV_MASK;
+}
+
+static unsigned int armada_3700_pm_dvfs_get_cpu_parent(struct regmap *base)
+{
+	unsigned int reg = ARMADA_37XX_NB_CPU_LOAD;
+	unsigned int offset = ARMADA_37XX_NB_TBG_SEL_OFF;
+	unsigned int load_level, sel;
+
+	/*
+	 * This function is always called after the function
+	 * armada_3700_pm_dvfs_is_enabled, so no need to check again
+	 * if the base is valid
+	 */
+	regmap_read(base, reg, &load_level);
+
+	/*
+	 * The register and the offset inside this register accessed to
+	 * read the current divider depend on the load level
+	 */
+	load_level &= ARMADA_37XX_NB_CPU_LOAD_MASK;
+	armada_3700_pm_dvfs_update_regs(load_level, &reg, &offset);
+
+	regmap_read(base, reg, &sel);
+
+	return (sel >> offset) & ARMADA_37XX_NB_TBG_SEL_MASK;
+}
+
 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 (armada_3700_pm_dvfs_is_enabled(pm_cpu->nb_pm_base)) {
+		val = armada_3700_pm_dvfs_get_cpu_parent(pm_cpu->nb_pm_base);
+	} else {
+		val = readl(pm_cpu->reg_mux) >> pm_cpu->shift_mux;
+		val &= pm_cpu->mask_mux;
+	}
 
 	if (val >= num_parents)
 		return -EINVAL;
@@ -331,19 +434,124 @@ static u8 clk_pm_cpu_get_parent(struct clk_hw *hw)
 	return val;
 }
 
+static int clk_pm_cpu_set_parent(struct clk_hw *hw, u8 index)
+{
+	struct clk_pm_cpu *pm_cpu = to_clk_pm_cpu(hw);
+	struct regmap *base = pm_cpu->nb_pm_base;
+	int load_level;
+
+	/*
+	 * We set the clock parent only if the DVFS is available but
+	 * not enabled.
+	 */
+	if (IS_ERR(base) || armada_3700_pm_dvfs_is_enabled(base))
+		return -EINVAL;
+
+	/* Set the parent clock for all the load level */
+	for (load_level = 0; load_level < LOAD_LEVEL_NR; load_level++) {
+		unsigned int reg, mask,  val,
+			offset = ARMADA_37XX_NB_TBG_SEL_OFF;
+
+		armada_3700_pm_dvfs_update_regs(load_level, &reg, &offset);
+
+		val = index << offset;
+		mask = ARMADA_37XX_NB_TBG_SEL_MASK << offset;
+		regmap_update_bits(base, reg, mask, val);
+	}
+	return 0;
+}
+
 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);
-
+	if (armada_3700_pm_dvfs_is_enabled(pm_cpu->nb_pm_base))
+		div = armada_3700_pm_dvfs_get_cpu_div(pm_cpu->nb_pm_base);
+	else
+		div = get_div(pm_cpu->reg_div, pm_cpu->shift_div);
 	return DIV_ROUND_UP_ULL((u64)parent_rate, div);
 }
 
+static long clk_pm_cpu_round_rate(struct clk_hw *hw, unsigned long rate,
+				  unsigned long *parent_rate)
+{
+	struct clk_pm_cpu *pm_cpu = to_clk_pm_cpu(hw);
+	struct regmap *base = pm_cpu->nb_pm_base;
+	unsigned int div = *parent_rate / rate;
+	unsigned int load_level;
+	/* only available when DVFS is enabled */
+	if (!armada_3700_pm_dvfs_is_enabled(base))
+		return -EINVAL;
+
+	for (load_level = 0; load_level < LOAD_LEVEL_NR; load_level++) {
+		unsigned int reg, val, offset = ARMADA_37XX_NB_TBG_DIV_OFF;
+
+		armada_3700_pm_dvfs_update_regs(load_level, &reg, &offset);
+
+		regmap_read(base, reg, &val);
+
+		val >>= offset;
+		val &= ARMADA_37XX_NB_TBG_DIV_MASK;
+		if (val == div)
+			/*
+			 * We found a load level matching the target
+			 * divider, switch to this load level and
+			 * return.
+			 */
+			return *parent_rate / div;
+	}
+
+	/* We didn't find any valid divider */
+	return -EINVAL;
+}
+
+static int clk_pm_cpu_set_rate(struct clk_hw *hw, unsigned long rate,
+			       unsigned long parent_rate)
+{
+	struct clk_pm_cpu *pm_cpu = to_clk_pm_cpu(hw);
+	struct regmap *base = pm_cpu->nb_pm_base;
+	unsigned int div = parent_rate / rate;
+	unsigned int load_level;
+
+	/* only available when DVFS is enabled */
+	if (!armada_3700_pm_dvfs_is_enabled(base))
+		return -EINVAL;
+
+	for (load_level = 0; load_level < LOAD_LEVEL_NR; load_level++) {
+		unsigned int reg, mask, val,
+			offset = ARMADA_37XX_NB_TBG_DIV_OFF;
+
+		armada_3700_pm_dvfs_update_regs(load_level, &reg, &offset);
+
+		regmap_read(base, reg, &val);
+		val >>= offset;
+		val &= ARMADA_37XX_NB_TBG_DIV_MASK;
+
+		if (val == div) {
+			/*
+			 * We found a load level matching the target
+			 * divider, switch to this load level and
+			 * return.
+			 */
+			reg = ARMADA_37XX_NB_CPU_LOAD;
+			mask = ARMADA_37XX_NB_CPU_LOAD_MASK;
+			regmap_update_bits(base, reg, mask, load_level);
+
+			return rate;
+		}
+	}
+
+	/* We didn't find any valid divider */
+	return -EINVAL;
+}
+
 static const struct clk_ops clk_pm_cpu_ops = {
 	.get_parent = clk_pm_cpu_get_parent,
+	.set_parent = clk_pm_cpu_set_parent,
+	.round_rate = clk_pm_cpu_round_rate,
+	.set_rate = clk_pm_cpu_set_rate,
 	.recalc_rate = clk_pm_cpu_recalc_rate,
 };
 
@@ -418,6 +626,9 @@ static int armada_3700_add_composite_clk(const struct clk_periph_data *data,
 		rate_hw = muxrate_hw;
 		mux_ops = muxrate_hw->init->ops;
 		rate_ops = muxrate_hw->init->ops;
+
+		pmcpu_clk->nb_pm_base =
+			syscon_regmap_lookup_by_compatible("marvell,armada-3700-nb-pm");
 	}
 
 	*hw = clk_hw_register_composite(dev, data->name, data->parent_names,
-- 
2.15.0

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH 0/3] Add DVFS support on CPU clock for Armada 37xx
  2017-11-30 13:40 [PATCH 0/3] Add DVFS support on CPU clock for Armada 37xx Gregory CLEMENT
                   ` (2 preceding siblings ...)
  2017-11-30 13:40 ` [PATCH 3/3] clk: mvebu: armada-37xx-periph: add DVFS support for cpu clocks Gregory CLEMENT
@ 2017-12-21 10:53 ` Gregory CLEMENT
  2017-12-21 23:13 ` Stephen Boyd
  4 siblings, 0 replies; 10+ messages in thread
From: Gregory CLEMENT @ 2017-12-21 10:53 UTC (permalink / raw)
  To: Stephen Boyd, Mike Turquette
  Cc: linux-clk, linux-kernel, Thomas Petazzoni, Andrew Lunn,
	Jason Cooper, Hua Jing, Antoine Tenart, Nadav Haklai, Victor Gu,
	Neta Zur Hershkovits, Miquèl Raynal, Marcin Wojtas,
	Wilson Ding, linux-arm-kernel, Sebastian Hesselbarth

Hello,
 
 On jeu., nov. 30 2017, Gregory CLEMENT <gregory.clement@free-electrons.com> wrote:

> Hi,
>
> This small series is needed to use DVFS on Armada 37xx. When DVFS is
> enabled the CPU clock setting is done using an other set of registers
> from the North Bridge Power Management block.
>
> The series adds the possibility to modify the CPU frequency using the
> associate load level matching the target frequency. However
> configuring the frequencies for each load is done by the cpufreq
> driver submitted in a separate series.
>
> Obviously having both series (cpufreq and clk) is needed to support
> DVFS on Armada 37xx, but there is no dependencies between the series
> (for building or at runtime).


I sent this series 3 weeks ago and I didn't have any feedback on
it. Does it mean that the series is OK for you and that you wait for a
PR for it?

Thanks,

Gregory



>
> Gregory CLEMENT (3):
>   clk: mvebu: armada-37xx-periph: cosmetic changes
>   clk: mvebu: armada-37xx-periph: prepare cpu clk to be used with DVFS
>   clk: mvebu: armada-37xx-periph: add DVFS support for cpu clocks
>
>  drivers/clk/mvebu/armada-37xx-periph.c | 310 +++++++++++++++++++++++++++++++--
>  1 file changed, 293 insertions(+), 17 deletions(-)
>
> -- 
> 2.15.0
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

-- 
Gregory Clement, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 1/3] clk: mvebu: armada-37xx-periph: cosmetic changes
  2017-11-30 13:40 ` [PATCH 1/3] clk: mvebu: armada-37xx-periph: cosmetic changes Gregory CLEMENT
@ 2017-12-21 23:12   ` Stephen Boyd
  0 siblings, 0 replies; 10+ messages in thread
From: Stephen Boyd @ 2017-12-21 23:12 UTC (permalink / raw)
  To: Gregory CLEMENT
  Cc: Mike Turquette, linux-clk, linux-kernel, Jason Cooper,
	Andrew Lunn, Sebastian Hesselbarth, Thomas Petazzoni,
	linux-arm-kernel, Antoine Tenart, Miquèl Raynal,
	Nadav Haklai, Victor Gu, Marcin Wojtas, Wilson Ding, Hua Jing,
	Neta Zur Hershkovits

On 11/30, Gregory CLEMENT wrote:
> This patches fixes few cosmetic issues such as alignment, blank lines
> and required space.
> 
> Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
> ---

Applied to clk-next

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 2/3] clk: mvebu: armada-37xx-periph: prepare cpu clk to be used with DVFS
  2017-11-30 13:40 ` [PATCH 2/3] clk: mvebu: armada-37xx-periph: prepare cpu clk to be used with DVFS Gregory CLEMENT
@ 2017-12-21 23:12   ` Stephen Boyd
  0 siblings, 0 replies; 10+ messages in thread
From: Stephen Boyd @ 2017-12-21 23:12 UTC (permalink / raw)
  To: Gregory CLEMENT
  Cc: Mike Turquette, linux-clk, linux-kernel, Jason Cooper,
	Andrew Lunn, Sebastian Hesselbarth, Thomas Petazzoni,
	linux-arm-kernel, Antoine Tenart, Miquèl Raynal,
	Nadav Haklai, Victor Gu, Marcin Wojtas, Wilson Ding, Hua Jing,
	Neta Zur Hershkovits

On 11/30, Gregory CLEMENT wrote:
> 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>
> ---

Applied to clk-next

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 3/3] clk: mvebu: armada-37xx-periph: add DVFS support for cpu clocks
  2017-11-30 13:40 ` [PATCH 3/3] clk: mvebu: armada-37xx-periph: add DVFS support for cpu clocks Gregory CLEMENT
@ 2017-12-21 23:12   ` Stephen Boyd
  0 siblings, 0 replies; 10+ messages in thread
From: Stephen Boyd @ 2017-12-21 23:12 UTC (permalink / raw)
  To: Gregory CLEMENT
  Cc: Mike Turquette, linux-clk, linux-kernel, Jason Cooper,
	Andrew Lunn, Sebastian Hesselbarth, Thomas Petazzoni,
	linux-arm-kernel, Antoine Tenart, Miquèl Raynal,
	Nadav Haklai, Victor Gu, Marcin Wojtas, Wilson Ding, Hua Jing,
	Neta Zur Hershkovits

On 11/30, Gregory CLEMENT wrote:
> When DVFS is enabled the CPU clock setting is done using an other set of
> registers.
> 
> These Power Management registers are exposed through a syscon as they
> will also be used by other drivers such as the cpufreq.
> 
> This patch add the possibility to modify the CPU frequency using the
> associate load level matching the target frequency. Then all the
> frequency switch is handle by the hardware.
> 
> Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
> ---

Applied to clk-next + a small fix to regmap getting to make it
shorter.

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 0/3] Add DVFS support on CPU clock for Armada 37xx
  2017-11-30 13:40 [PATCH 0/3] Add DVFS support on CPU clock for Armada 37xx Gregory CLEMENT
                   ` (3 preceding siblings ...)
  2017-12-21 10:53 ` [PATCH 0/3] Add DVFS support on CPU clock for Armada 37xx Gregory CLEMENT
@ 2017-12-21 23:13 ` Stephen Boyd
  2017-12-22 10:02   ` Gregory CLEMENT
  4 siblings, 1 reply; 10+ messages in thread
From: Stephen Boyd @ 2017-12-21 23:13 UTC (permalink / raw)
  To: Gregory CLEMENT
  Cc: Mike Turquette, linux-clk, linux-kernel, Jason Cooper,
	Andrew Lunn, Sebastian Hesselbarth, Thomas Petazzoni,
	linux-arm-kernel, Antoine Tenart, Miquèl Raynal,
	Nadav Haklai, Victor Gu, Marcin Wojtas, Wilson Ding, Hua Jing,
	Neta Zur Hershkovits

On 11/30, Gregory CLEMENT wrote:
> Hi,
> 
> This small series is needed to use DVFS on Armada 37xx. When DVFS is
> enabled the CPU clock setting is done using an other set of registers
> from the North Bridge Power Management block.
> 
> The series adds the possibility to modify the CPU frequency using the
> associate load level matching the target frequency. However
> configuring the frequencies for each load is done by the cpufreq
> driver submitted in a separate series.
> 
> Obviously having both series (cpufreq and clk) is needed to support
> DVFS on Armada 37xx, but there is no dependencies between the series
> (for building or at runtime).
> 

Are you relying on the clk API returning an error to detect if
DVFS is present or not? Just curious why that part of the code
was there.

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 0/3] Add DVFS support on CPU clock for Armada 37xx
  2017-12-21 23:13 ` Stephen Boyd
@ 2017-12-22 10:02   ` Gregory CLEMENT
  0 siblings, 0 replies; 10+ messages in thread
From: Gregory CLEMENT @ 2017-12-22 10:02 UTC (permalink / raw)
  To: Stephen Boyd
  Cc: Mike Turquette, linux-clk, linux-kernel, Jason Cooper,
	Andrew Lunn, Sebastian Hesselbarth, Thomas Petazzoni,
	linux-arm-kernel, Antoine Tenart, Miquèl Raynal,
	Nadav Haklai, Victor Gu, Marcin Wojtas, Wilson Ding, Hua Jing,
	Neta Zur Hershkovits

Hi Stephen,
 
 On jeu., déc. 21 2017, Stephen Boyd <sboyd@codeaurora.org> wrote:

> On 11/30, Gregory CLEMENT wrote:
>> Hi,
>> 
>> This small series is needed to use DVFS on Armada 37xx. When DVFS is
>> enabled the CPU clock setting is done using an other set of registers
>> from the North Bridge Power Management block.
>> 
>> The series adds the possibility to modify the CPU frequency using the
>> associate load level matching the target frequency. However
>> configuring the frequencies for each load is done by the cpufreq
>> driver submitted in a separate series.
>> 
>> Obviously having both series (cpufreq and clk) is needed to support
>> DVFS on Armada 37xx, but there is no dependencies between the series
>> (for building or at runtime).
>> 
>
> Are you relying on the clk API returning an error to detect if
> DVFS is present or not? Just curious why that part of the code
> was there.

The cpufreq framework rely on the clk framwork to setup the clk
frequency of the CPU. For this hardware when DVFS is enabled the we
don't directly control the frequency of the CPUs but the "load
level". And it is during the initialization that we associate CPU
frequency to a load level.

The clk part is there to setup this load level for the hardware but by
still using the frequency as an entry point as it was what is expected
by the kernel. So cpufreq will ask a frequency depending of its policy,
then the clk driver will setup the load level matching this frequency.

And to answer your specific question we don't rely on the clk API
returning an error to detect if DVFS is present or not. For this we
directly read the DVFS bit exposed through the syscon.

Gregory

>
> -- 
> Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
> a Linux Foundation Collaborative Project

-- 
Gregory Clement, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2017-12-22 10:02 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-11-30 13:40 [PATCH 0/3] Add DVFS support on CPU clock for Armada 37xx Gregory CLEMENT
2017-11-30 13:40 ` [PATCH 1/3] clk: mvebu: armada-37xx-periph: cosmetic changes Gregory CLEMENT
2017-12-21 23:12   ` Stephen Boyd
2017-11-30 13:40 ` [PATCH 2/3] clk: mvebu: armada-37xx-periph: prepare cpu clk to be used with DVFS Gregory CLEMENT
2017-12-21 23:12   ` Stephen Boyd
2017-11-30 13:40 ` [PATCH 3/3] clk: mvebu: armada-37xx-periph: add DVFS support for cpu clocks Gregory CLEMENT
2017-12-21 23:12   ` Stephen Boyd
2017-12-21 10:53 ` [PATCH 0/3] Add DVFS support on CPU clock for Armada 37xx Gregory CLEMENT
2017-12-21 23:13 ` Stephen Boyd
2017-12-22 10:02   ` Gregory CLEMENT

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).