linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/3] clk: rockchip: allow adjusting pll rates on init
@ 2014-11-19 14:11 Heiko Stübner
  2014-11-19 14:12 ` [PATCH 1/3] clk: rockchip: add ability to specify pll-specific flags Heiko Stübner
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Heiko Stübner @ 2014-11-19 14:11 UTC (permalink / raw)
  To: linux-arm-kernel

It was found that some firmware versions initialized the pll rates using
suboptimal parameters to achieve frequencies the actual rate table contained
better parameters for.

Therefore this series first adds the possibility to create pll-specific flags
and then adds a flag to adjust the pll rate on init to the parameters from
the rate table.

This series was tested on rk3066, rk3188 and rk3288 based boards.

Heiko Stuebner (3):
  clk: rockchip: add ability to specify pll-specific flags
  clk: rockchip: add optional sync to pll rate parameters
  clk: rockchip: add ROCKCHIP_PLL_SYNC_RATE flag to some plls

 drivers/clk/rockchip/clk-pll.c    | 54 ++++++++++++++++++++++++++++++++++++++-
 drivers/clk/rockchip/clk-rk3188.c |  8 +++---
 drivers/clk/rockchip/clk-rk3288.c | 10 ++++----
 drivers/clk/rockchip/clk.c        |  3 ++-
 drivers/clk/rockchip/clk.h        | 13 ++++++++--
 5 files changed, 75 insertions(+), 13 deletions(-)

-- 
2.1.1

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

* [PATCH 1/3] clk: rockchip: add ability to specify pll-specific flags
  2014-11-19 14:11 [PATCH 0/3] clk: rockchip: allow adjusting pll rates on init Heiko Stübner
@ 2014-11-19 14:12 ` Heiko Stübner
  2014-11-19 14:13 ` [PATCH 2/3] clk: rockchip: add optional sync to pll rate parameters Heiko Stübner
  2014-11-19 14:13 ` [PATCH 3/3] clk: rockchip: add ROCKCHIP_PLL_SYNC_RATE flag to some plls Heiko Stübner
  2 siblings, 0 replies; 4+ messages in thread
From: Heiko Stübner @ 2014-11-19 14:12 UTC (permalink / raw)
  To: linux-arm-kernel

This adds a flag parameter to plls that allows us to create
special flags to tweak the behaviour of the plls if necessary.

Signed-off-by: Heiko Stuebner <heiko@sntech.de>
---
 drivers/clk/rockchip/clk-pll.c    |  4 +++-
 drivers/clk/rockchip/clk-rk3188.c |  8 ++++----
 drivers/clk/rockchip/clk-rk3288.c | 10 +++++-----
 drivers/clk/rockchip/clk.c        |  3 ++-
 drivers/clk/rockchip/clk.h        |  7 +++++--
 5 files changed, 19 insertions(+), 13 deletions(-)

diff --git a/drivers/clk/rockchip/clk-pll.c b/drivers/clk/rockchip/clk-pll.c
index a3e886a..feb9cad 100644
--- a/drivers/clk/rockchip/clk-pll.c
+++ b/drivers/clk/rockchip/clk-pll.c
@@ -39,6 +39,7 @@ struct rockchip_clk_pll {
 	int			lock_offset;
 	unsigned int		lock_shift;
 	enum rockchip_pll_type	type;
+	u8			flags;
 	const struct rockchip_pll_rate_table *rate_table;
 	unsigned int		rate_count;
 	spinlock_t		*lock;
@@ -282,7 +283,7 @@ struct clk *rockchip_clk_register_pll(enum rockchip_pll_type pll_type,
 		void __iomem *base, int con_offset, int grf_lock_offset,
 		int lock_shift, int mode_offset, int mode_shift,
 		struct rockchip_pll_rate_table *rate_table,
-		spinlock_t *lock)
+		u8 clk_pll_flags, spinlock_t *lock)
 {
 	const char *pll_parents[3];
 	struct clk_init_data init;
@@ -345,6 +346,7 @@ struct clk *rockchip_clk_register_pll(enum rockchip_pll_type pll_type,
 	pll->reg_base = base + con_offset;
 	pll->lock_offset = grf_lock_offset;
 	pll->lock_shift = lock_shift;
+	pll->flags = clk_pll_flags;
 	pll->lock = lock;
 
 	pll_clk = clk_register(NULL, &pll->hw);
diff --git a/drivers/clk/rockchip/clk-rk3188.c b/drivers/clk/rockchip/clk-rk3188.c
index e6cd483..6af5d7f 100644
--- a/drivers/clk/rockchip/clk-rk3188.c
+++ b/drivers/clk/rockchip/clk-rk3188.c
@@ -212,13 +212,13 @@ PNAME(mux_sclk_macref_p)	= { "mac_src", "ext_rmii" };
 
 static struct rockchip_pll_clock rk3188_pll_clks[] __initdata = {
 	[apll] = PLL(pll_rk3066, PLL_APLL, "apll", mux_pll_p, 0, RK2928_PLL_CON(0),
-		     RK2928_MODE_CON, 0, 6, rk3188_pll_rates),
+		     RK2928_MODE_CON, 0, 6, 0, rk3188_pll_rates),
 	[dpll] = PLL(pll_rk3066, PLL_DPLL, "dpll", mux_pll_p, 0, RK2928_PLL_CON(4),
-		     RK2928_MODE_CON, 4, 5, NULL),
+		     RK2928_MODE_CON, 4, 5, 0, NULL),
 	[cpll] = PLL(pll_rk3066, PLL_CPLL, "cpll", mux_pll_p, 0, RK2928_PLL_CON(8),
-		     RK2928_MODE_CON, 8, 7, rk3188_pll_rates),
+		     RK2928_MODE_CON, 8, 7, 0, rk3188_pll_rates),
 	[gpll] = PLL(pll_rk3066, PLL_GPLL, "gpll", mux_pll_p, 0, RK2928_PLL_CON(12),
-		     RK2928_MODE_CON, 12, 8, rk3188_pll_rates),
+		     RK2928_MODE_CON, 12, 8, 0, rk3188_pll_rates),
 };
 
 #define MFLAGS CLK_MUX_HIWORD_MASK
diff --git a/drivers/clk/rockchip/clk-rk3288.c b/drivers/clk/rockchip/clk-rk3288.c
index 174589c..2d31a22 100644
--- a/drivers/clk/rockchip/clk-rk3288.c
+++ b/drivers/clk/rockchip/clk-rk3288.c
@@ -202,15 +202,15 @@ PNAME(mux_hsicphy12m_p)		= { "hsicphy12m_xin12m", "hsicphy12m_usbphy" };
 
 static struct rockchip_pll_clock rk3288_pll_clks[] __initdata = {
 	[apll] = PLL(pll_rk3066, PLL_APLL, "apll", mux_pll_p, 0, RK3288_PLL_CON(0),
-		     RK3288_MODE_CON, 0, 6, rk3288_pll_rates),
+		     RK3288_MODE_CON, 0, 6, 0, rk3288_pll_rates),
 	[dpll] = PLL(pll_rk3066, PLL_DPLL, "dpll", mux_pll_p, 0, RK3288_PLL_CON(4),
-		     RK3288_MODE_CON, 4, 5, NULL),
+		     RK3288_MODE_CON, 4, 5, 0, NULL),
 	[cpll] = PLL(pll_rk3066, PLL_CPLL, "cpll", mux_pll_p, 0, RK3288_PLL_CON(8),
-		     RK3288_MODE_CON, 8, 7, rk3288_pll_rates),
+		     RK3288_MODE_CON, 8, 7, 0, rk3288_pll_rates),
 	[gpll] = PLL(pll_rk3066, PLL_GPLL, "gpll", mux_pll_p, 0, RK3288_PLL_CON(12),
-		     RK3288_MODE_CON, 12, 8, rk3288_pll_rates),
+		     RK3288_MODE_CON, 12, 8, 0, rk3288_pll_rates),
 	[npll] = PLL(pll_rk3066, PLL_NPLL, "npll",  mux_pll_p, 0, RK3288_PLL_CON(16),
-		     RK3288_MODE_CON, 14, 9, rk3288_pll_rates),
+		     RK3288_MODE_CON, 14, 9, 0, rk3288_pll_rates),
 };
 
 static struct clk_div_table div_hclk_cpu_t[] = {
diff --git a/drivers/clk/rockchip/clk.c b/drivers/clk/rockchip/clk.c
index dec6f8d6..3b8f26e 100644
--- a/drivers/clk/rockchip/clk.c
+++ b/drivers/clk/rockchip/clk.c
@@ -199,7 +199,8 @@ void __init rockchip_clk_register_plls(struct rockchip_pll_clock *list,
 				list->parent_names, list->num_parents,
 				reg_base, list->con_offset, grf_lock_offset,
 				list->lock_shift, list->mode_offset,
-				list->mode_shift, list->rate_table, &clk_lock);
+				list->mode_shift, list->rate_table,
+				list->pll_flags, &clk_lock);
 		if (IS_ERR(clk)) {
 			pr_err("%s: failed to register clock %s\n", __func__,
 				list->name);
diff --git a/drivers/clk/rockchip/clk.h b/drivers/clk/rockchip/clk.h
index 6baf665..eefd39a 100644
--- a/drivers/clk/rockchip/clk.h
+++ b/drivers/clk/rockchip/clk.h
@@ -90,6 +90,7 @@ struct rockchip_pll_rate_table {
  * @mode_shift: offset inside the mode-register for the mode of this pll.
  * @lock_shift: offset inside the lock register for the lock status.
  * @type: Type of PLL to be registered.
+ * @pll_flags: hardware-specific flags
  * @rate_table: Table of usable pll rates
  */
 struct rockchip_pll_clock {
@@ -103,11 +104,12 @@ struct rockchip_pll_clock {
 	int			mode_shift;
 	int			lock_shift;
 	enum rockchip_pll_type	type;
+	u8			pll_flags;
 	struct rockchip_pll_rate_table *rate_table;
 };
 
 #define PLL(_type, _id, _name, _pnames, _flags, _con, _mode, _mshift,	\
-		_lshift, _rtable)					\
+		_lshift, _pflags, _rtable)				\
 	{								\
 		.id		= _id,					\
 		.type		= _type,				\
@@ -119,6 +121,7 @@ struct rockchip_pll_clock {
 		.mode_offset	= _mode,				\
 		.mode_shift	= _mshift,				\
 		.lock_shift	= _lshift,				\
+		.pll_flags	= _pflags,				\
 		.rate_table	= _rtable,				\
 	}
 
@@ -127,7 +130,7 @@ struct clk *rockchip_clk_register_pll(enum rockchip_pll_type pll_type,
 		void __iomem *base, int con_offset, int grf_lock_offset,
 		int lock_shift, int reg_mode, int mode_shift,
 		struct rockchip_pll_rate_table *rate_table,
-		spinlock_t *lock);
+		u8 clk_pll_flags, spinlock_t *lock);
 
 struct rockchip_cpuclk_clksel {
 	int reg;
-- 
2.1.1

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

* [PATCH 2/3] clk: rockchip: add optional sync to pll rate parameters
  2014-11-19 14:11 [PATCH 0/3] clk: rockchip: allow adjusting pll rates on init Heiko Stübner
  2014-11-19 14:12 ` [PATCH 1/3] clk: rockchip: add ability to specify pll-specific flags Heiko Stübner
@ 2014-11-19 14:13 ` Heiko Stübner
  2014-11-19 14:13 ` [PATCH 3/3] clk: rockchip: add ROCKCHIP_PLL_SYNC_RATE flag to some plls Heiko Stübner
  2 siblings, 0 replies; 4+ messages in thread
From: Heiko Stübner @ 2014-11-19 14:13 UTC (permalink / raw)
  To: linux-arm-kernel

In some cases firmware brings up plls with different parameters than the ones
noted in the rate table for the specific frequency. These firmware-selected
parameters are worse than the tested ones in the pll rate tables but cannot
be changed by a simple clk_set_rate call when the rate stays the same.

Therefore add a ROCKCHIP_PLL_SYNC_RATE flag and implement an init callback
that checks the runtime-parameters against the matching rate table entry
and adjusts them to the table-ones if necessary.

If no rate table is set or the current rate does not match any rate-table
entry no changes are made.

Being able to limit this adjustment to specific plls is necessary to not
touch the ones supplying core components like the apll and dpll supplying
the armcores and dram.

Signed-off-by: Heiko Stuebner <heiko@sntech.de>
---
 drivers/clk/rockchip/clk-pll.c | 50 ++++++++++++++++++++++++++++++++++++++++++
 drivers/clk/rockchip/clk.h     |  6 +++++
 2 files changed, 56 insertions(+)

diff --git a/drivers/clk/rockchip/clk-pll.c b/drivers/clk/rockchip/clk-pll.c
index feb9cad..e583cae 100644
--- a/drivers/clk/rockchip/clk-pll.c
+++ b/drivers/clk/rockchip/clk-pll.c
@@ -258,6 +258,55 @@ static int rockchip_rk3066_pll_is_enabled(struct clk_hw *hw)
 	return !(pllcon & RK3066_PLLCON3_PWRDOWN);
 }
 
+static void rockchip_rk3066_pll_init(struct clk_hw *hw)
+{
+	struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
+	const struct rockchip_pll_rate_table *rate;
+	unsigned int nf, nr, no, bwadj;
+	unsigned long drate;
+	u32 pllcon;
+
+	if (!(pll->flags & ROCKCHIP_PLL_SYNC_RATE))
+		return;
+
+	drate = __clk_get_rate(hw->clk);
+	rate = rockchip_get_pll_settings(pll, drate);
+
+	/* when no rate setting for the current rate, rely on clk_set_rate */
+	if (!rate)
+		return;
+
+	pllcon = readl_relaxed(pll->reg_base + RK3066_PLLCON(0));
+	nr = ((pllcon >> RK3066_PLLCON0_NR_SHIFT) & RK3066_PLLCON0_NR_MASK) + 1;
+	no = ((pllcon >> RK3066_PLLCON0_OD_SHIFT) & RK3066_PLLCON0_OD_MASK) + 1;
+
+	pllcon = readl_relaxed(pll->reg_base + RK3066_PLLCON(1));
+	nf = ((pllcon >> RK3066_PLLCON1_NF_SHIFT) & RK3066_PLLCON1_NF_MASK) + 1;
+
+	pllcon = readl_relaxed(pll->reg_base + RK3066_PLLCON(2));
+	bwadj = (pllcon >> RK3066_PLLCON2_BWADJ_SHIFT) & RK3066_PLLCON2_BWADJ_MASK;
+
+	pr_debug("%s: pll %s@%lu: nr (%d,%d); no (%d, %d); nf(%d, %d), bwadj(%d,%d)\n",
+		 __func__, __clk_get_name(hw->clk), drate, rate->nr, nr,
+		rate->no, no, rate->nf, nf, rate->bwadj, bwadj);
+	if (rate->nr != nr || rate->no != no || rate->nf != nf
+					     || rate->bwadj != bwadj) {
+		struct clk *parent = __clk_get_parent(hw->clk);
+		unsigned long prate;
+
+		if (!parent) {
+			pr_warn("%s: parent of %s not available\n",
+				__func__, __clk_get_name(hw->clk));
+			return;
+		}
+
+		pr_debug("%s: pll %s: rate params do not match rate table, adjusting\n",
+			 __func__, __clk_get_name(hw->clk));
+		prate = __clk_get_rate(parent);
+		rockchip_rk3066_pll_set_rate(hw, drate, prate);
+	}
+}
+
 static const struct clk_ops rockchip_rk3066_pll_clk_norate_ops = {
 	.recalc_rate = rockchip_rk3066_pll_recalc_rate,
 	.enable = rockchip_rk3066_pll_enable,
@@ -272,6 +321,7 @@ static const struct clk_ops rockchip_rk3066_pll_clk_ops = {
 	.enable = rockchip_rk3066_pll_enable,
 	.disable = rockchip_rk3066_pll_disable,
 	.is_enabled = rockchip_rk3066_pll_is_enabled,
+	.init = rockchip_rk3066_pll_init,
 };
 
 /*
diff --git a/drivers/clk/rockchip/clk.h b/drivers/clk/rockchip/clk.h
index eefd39a..dc94681 100644
--- a/drivers/clk/rockchip/clk.h
+++ b/drivers/clk/rockchip/clk.h
@@ -92,6 +92,10 @@ struct rockchip_pll_rate_table {
  * @type: Type of PLL to be registered.
  * @pll_flags: hardware-specific flags
  * @rate_table: Table of usable pll rates
+ *
+ * Flags:
+ * ROCKCHIP_PLL_SYNC_RATE - check rate parameters to match against the
+ *	rate_table parameters and ajust them if necessary.
  */
 struct rockchip_pll_clock {
 	unsigned int		id;
@@ -108,6 +112,8 @@ struct rockchip_pll_clock {
 	struct rockchip_pll_rate_table *rate_table;
 };
 
+#define ROCKCHIP_PLL_SYNC_RATE		BIT(0)
+
 #define PLL(_type, _id, _name, _pnames, _flags, _con, _mode, _mshift,	\
 		_lshift, _pflags, _rtable)				\
 	{								\
-- 
2.1.1

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

* [PATCH 3/3] clk: rockchip: add ROCKCHIP_PLL_SYNC_RATE flag to some plls
  2014-11-19 14:11 [PATCH 0/3] clk: rockchip: allow adjusting pll rates on init Heiko Stübner
  2014-11-19 14:12 ` [PATCH 1/3] clk: rockchip: add ability to specify pll-specific flags Heiko Stübner
  2014-11-19 14:13 ` [PATCH 2/3] clk: rockchip: add optional sync to pll rate parameters Heiko Stübner
@ 2014-11-19 14:13 ` Heiko Stübner
  2 siblings, 0 replies; 4+ messages in thread
From: Heiko Stübner @ 2014-11-19 14:13 UTC (permalink / raw)
  To: linux-arm-kernel

Add the new flag to gpll and cpll on rk3188 and similar and to
gpll, cpll and npll on rk3288.

Signed-off-by: Heiko Stuebner <heiko@sntech.de>
---
 drivers/clk/rockchip/clk-rk3188.c | 4 ++--
 drivers/clk/rockchip/clk-rk3288.c | 6 +++---
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/drivers/clk/rockchip/clk-rk3188.c b/drivers/clk/rockchip/clk-rk3188.c
index 6af5d7f..37a1988 100644
--- a/drivers/clk/rockchip/clk-rk3188.c
+++ b/drivers/clk/rockchip/clk-rk3188.c
@@ -216,9 +216,9 @@ static struct rockchip_pll_clock rk3188_pll_clks[] __initdata = {
 	[dpll] = PLL(pll_rk3066, PLL_DPLL, "dpll", mux_pll_p, 0, RK2928_PLL_CON(4),
 		     RK2928_MODE_CON, 4, 5, 0, NULL),
 	[cpll] = PLL(pll_rk3066, PLL_CPLL, "cpll", mux_pll_p, 0, RK2928_PLL_CON(8),
-		     RK2928_MODE_CON, 8, 7, 0, rk3188_pll_rates),
+		     RK2928_MODE_CON, 8, 7, ROCKCHIP_PLL_SYNC_RATE, rk3188_pll_rates),
 	[gpll] = PLL(pll_rk3066, PLL_GPLL, "gpll", mux_pll_p, 0, RK2928_PLL_CON(12),
-		     RK2928_MODE_CON, 12, 8, 0, rk3188_pll_rates),
+		     RK2928_MODE_CON, 12, 8, ROCKCHIP_PLL_SYNC_RATE, rk3188_pll_rates),
 };
 
 #define MFLAGS CLK_MUX_HIWORD_MASK
diff --git a/drivers/clk/rockchip/clk-rk3288.c b/drivers/clk/rockchip/clk-rk3288.c
index 2d31a22..ad8a27a 100644
--- a/drivers/clk/rockchip/clk-rk3288.c
+++ b/drivers/clk/rockchip/clk-rk3288.c
@@ -206,11 +206,11 @@ static struct rockchip_pll_clock rk3288_pll_clks[] __initdata = {
 	[dpll] = PLL(pll_rk3066, PLL_DPLL, "dpll", mux_pll_p, 0, RK3288_PLL_CON(4),
 		     RK3288_MODE_CON, 4, 5, 0, NULL),
 	[cpll] = PLL(pll_rk3066, PLL_CPLL, "cpll", mux_pll_p, 0, RK3288_PLL_CON(8),
-		     RK3288_MODE_CON, 8, 7, 0, rk3288_pll_rates),
+		     RK3288_MODE_CON, 8, 7, ROCKCHIP_PLL_SYNC_RATE, rk3288_pll_rates),
 	[gpll] = PLL(pll_rk3066, PLL_GPLL, "gpll", mux_pll_p, 0, RK3288_PLL_CON(12),
-		     RK3288_MODE_CON, 12, 8, 0, rk3288_pll_rates),
+		     RK3288_MODE_CON, 12, 8, ROCKCHIP_PLL_SYNC_RATE, rk3288_pll_rates),
 	[npll] = PLL(pll_rk3066, PLL_NPLL, "npll",  mux_pll_p, 0, RK3288_PLL_CON(16),
-		     RK3288_MODE_CON, 14, 9, 0, rk3288_pll_rates),
+		     RK3288_MODE_CON, 14, 9, ROCKCHIP_PLL_SYNC_RATE, rk3288_pll_rates),
 };
 
 static struct clk_div_table div_hclk_cpu_t[] = {
-- 
2.1.1

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

end of thread, other threads:[~2014-11-19 14:13 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-11-19 14:11 [PATCH 0/3] clk: rockchip: allow adjusting pll rates on init Heiko Stübner
2014-11-19 14:12 ` [PATCH 1/3] clk: rockchip: add ability to specify pll-specific flags Heiko Stübner
2014-11-19 14:13 ` [PATCH 2/3] clk: rockchip: add optional sync to pll rate parameters Heiko Stübner
2014-11-19 14:13 ` [PATCH 3/3] clk: rockchip: add ROCKCHIP_PLL_SYNC_RATE flag to some plls Heiko Stübner

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).