Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > linux.kernel > #1589464 > unrolled thread

[PATCH 0/7] clk: meson: update clock controller for audio support

Started byJerome Brunet <jbrunet@baylibre.com>
First post2017-02-28 14:40 +0100
Last post2017-02-28 14:40 +0100
Articles 3 — 1 participant

Back to article view | Back to linux.kernel


Contents

  [PATCH 0/7] clk: meson: update clock controller for audio support Jerome Brunet <jbrunet@baylibre.com> - 2017-02-28 14:40 +0100
    [PATCH 1/7] clk: meson8b: put dividers and muxes in tables Jerome Brunet <jbrunet@baylibre.com> - 2017-02-28 14:40 +0100
    [PATCH 3/7] clk: meson: mpll: add rw operation Jerome Brunet <jbrunet@baylibre.com> - 2017-02-28 14:40 +0100

#1589464 — [PATCH 0/7] clk: meson: update clock controller for audio support

FromJerome Brunet <jbrunet@baylibre.com>
Date2017-02-28 14:40 +0100
Subject[PATCH 0/7] clk: meson: update clock controller for audio support
Message-ID<tfQav-51i-45@gated-at.bofh.it>
This patchset is a first round of update to the meson clock controllers
to bring audio support. The patchset is based on clk-next with two
additional patches from arm-soc next (to avoid conflict later on).
commit d356a86b1b30 ("clk: meson-gxbb: Export HDMI clocks")
commit 7d753a742127 ("clk: gxbb: add the SAR ADC clocks and expose them")

The 2 first patches of the series put the generic muxes and divisors
declaration in tables so the register address fixup works in the same way
as the clock gates. We are going to add more of these clock types for
audio or gpu support, so we can't continue to fix addresses individually
like it is currently done.

Patches 3 to 6 improve the support of the mpll clocks, now allowing the
rate to be set. Among other things, the mplls are the parent clocks of the
i2s and spdif clocks.

Patch 7 expose the clock gates required to power on the i2s output.

These patches have been tested on the meson gxbb p200 board, as part of the
ongoing work to bring audio support for meson SoC family.

Jerome Brunet (7):
  clk: meson8b: put dividers and muxes in tables
  clk: gxbb: put dividers and muxes in tables
  clk: meson: mpll: add rw operation
  clk: meson: gxbb: mpll: use rw operation
  clk: meson8b: add the mplls clocks 0, 1 and 2
  clk: meson: mpll: correct N2 maximum value
  dt-bindings: clk: gxbb: expose i2s output clock gates

 drivers/clk/meson/clk-mpll.c          | 152 ++++++++++++++++++++++++++++++++--
 drivers/clk/meson/clkc.h              |   4 +-
 drivers/clk/meson/gxbb.c              |  64 +++++++++++---
 drivers/clk/meson/gxbb.h              |  10 +--
 drivers/clk/meson/meson8b.c           | 126 +++++++++++++++++++++++++++-
 drivers/clk/meson/meson8b.h           |  20 ++++-
 include/dt-bindings/clock/gxbb-clkc.h |   5 ++
 7 files changed, 354 insertions(+), 27 deletions(-)

-- 
2.9.3

[toc] | [next] | [standalone]


#1589466 — [PATCH 1/7] clk: meson8b: put dividers and muxes in tables

FromJerome Brunet <jbrunet@baylibre.com>
Date2017-02-28 14:40 +0100
Subject[PATCH 1/7] clk: meson8b: put dividers and muxes in tables
Message-ID<tfQav-51i-43@gated-at.bofh.it>
In reply to#1589464
Until now, there was only 1 divider and 1 mux declared for the meson8b
platform. With the ongoing work on various system, including audio, this
is about to change. Use the same approach as gates for dividers and muxes,
putting them in tables to fix the register address at runtime.

Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
---
 drivers/clk/meson/meson8b.c | 23 +++++++++++++++++++----
 1 file changed, 19 insertions(+), 4 deletions(-)

diff --git a/drivers/clk/meson/meson8b.c b/drivers/clk/meson/meson8b.c
index 888494d4fb8a..44c24bf754cd 100644
--- a/drivers/clk/meson/meson8b.c
+++ b/drivers/clk/meson/meson8b.c
@@ -582,6 +582,15 @@ static struct clk_gate *meson8b_clk_gates[] = {
 	&meson8b_ao_iface,
 };
 
+static struct clk_mux *meson8b_clk_muxes[] = {
+	&meson8b_mpeg_clk_sel,
+};
+
+static struct clk_divider *meson8b_clk_dividers[] = {
+	&meson8b_mpeg_clk_div,
+};
+
+
 static int meson8b_clkc_probe(struct platform_device *pdev)
 {
 	void __iomem *clk_base;
@@ -604,15 +613,21 @@ static int meson8b_clkc_probe(struct platform_device *pdev)
 	/* Populate the base address for CPU clk */
 	meson8b_cpu_clk.base = clk_base;
 
-	/* Populate the base address for the MPEG clks */
-	meson8b_mpeg_clk_sel.reg = clk_base + (u32)meson8b_mpeg_clk_sel.reg;
-	meson8b_mpeg_clk_div.reg = clk_base + (u32)meson8b_mpeg_clk_div.reg;
-
 	/* Populate base address for gates */
 	for (i = 0; i < ARRAY_SIZE(meson8b_clk_gates); i++)
 		meson8b_clk_gates[i]->reg = clk_base +
 			(u32)meson8b_clk_gates[i]->reg;
 
+	/* Populate base address for muxes */
+	for (i = 0; i < ARRAY_SIZE(meson8b_clk_muxes); i++)
+		meson8b_clk_muxes[i]->reg = clk_base +
+			(u32)meson8b_clk_muxes[i]->reg;
+
+	/* Populate base address for dividers */
+	for (i = 0; i < ARRAY_SIZE(meson8b_clk_dividers); i++)
+		meson8b_clk_dividers[i]->reg = clk_base +
+			(u32)meson8b_clk_dividers[i]->reg;
+
 	/*
 	 * register all clks
 	 * CLKID_UNUSED = 0, so skip it and start with CLKID_XTAL = 1
-- 
2.9.3

[toc] | [prev] | [next] | [standalone]


#1589468 — [PATCH 3/7] clk: meson: mpll: add rw operation

FromJerome Brunet <jbrunet@baylibre.com>
Date2017-02-28 14:40 +0100
Subject[PATCH 3/7] clk: meson: mpll: add rw operation
Message-ID<tfQav-51i-49@gated-at.bofh.it>
In reply to#1589464
This patch adds new callbacks to the meson-mpll driver to control
and set the pll rate. For this, we also need to add the enable bit and
sdm enable bit. The corresponding parameters are added to mpll data
structure.

Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
---
 drivers/clk/meson/clk-mpll.c | 152 +++++++++++++++++++++++++++++++++++++++++--
 drivers/clk/meson/clkc.h     |   4 +-
 drivers/clk/meson/gxbb.c     |  30 +++++++++
 3 files changed, 180 insertions(+), 6 deletions(-)

diff --git a/drivers/clk/meson/clk-mpll.c b/drivers/clk/meson/clk-mpll.c
index 03af79005ddb..342b85d4e22a 100644
--- a/drivers/clk/meson/clk-mpll.c
+++ b/drivers/clk/meson/clk-mpll.c
@@ -64,16 +64,50 @@
 #include <linux/clk-provider.h>
 #include "clkc.h"
 
-#define SDM_MAX 16384
+#define SDM_DEN 16384
+#define SDM_MIN 1
+#define SDM_MAX 16383
+#define N2_MIN	4
+#define N2_MAX	127
 
 #define to_meson_clk_mpll(_hw) container_of(_hw, struct meson_clk_mpll, hw)
 
+static unsigned long rate_from_params(unsigned long parent_rate,
+				      unsigned long sdm,
+				      unsigned long n2)
+{
+	return (parent_rate * SDM_DEN) / ((SDM_DEN * n2) + sdm);
+}
+
+static void params_from_rate(unsigned long requested_rate,
+			     unsigned long parent_rate,
+			     unsigned long *sdm,
+			     unsigned long *n2)
+{
+	uint64_t div = parent_rate;
+	unsigned long rem = do_div(div, requested_rate);
+
+	if (div < N2_MIN) {
+		*n2 = N2_MIN;
+		*sdm = SDM_MIN;
+	} else if (div > N2_MAX) {
+		*n2 = N2_MAX;
+		*sdm = SDM_MAX;
+	} else {
+		*n2 = div;
+		*sdm = DIV_ROUND_UP(rem * SDM_DEN, requested_rate);
+		if (*sdm < SDM_MIN)
+			*sdm = SDM_MIN;
+		else if (*sdm > SDM_MAX)
+			*sdm = SDM_MAX;
+	}
+}
+
 static unsigned long mpll_recalc_rate(struct clk_hw *hw,
 		unsigned long parent_rate)
 {
 	struct meson_clk_mpll *mpll = to_meson_clk_mpll(hw);
 	struct parm *p;
-	unsigned long rate = 0;
 	unsigned long reg, sdm, n2;
 
 	p = &mpll->sdm;
@@ -84,11 +118,119 @@ static unsigned long mpll_recalc_rate(struct clk_hw *hw,
 	reg = readl(mpll->base + p->reg_off);
 	n2 = PARM_GET(p->width, p->shift, reg);
 
-	rate = (parent_rate * SDM_MAX) / ((SDM_MAX * n2) + sdm);
+	return rate_from_params(parent_rate, sdm, n2);
+}
+
+static long mpll_round_rate(struct clk_hw *hw,
+			    unsigned long rate,
+			    unsigned long *parent_rate)
+{
+	unsigned long sdm, n2;
+
+	params_from_rate(rate, *parent_rate, &sdm, &n2);
+	return rate_from_params(*parent_rate, sdm, n2);
+}
+
+static int mpll_set_rate(struct clk_hw *hw,
+			 unsigned long rate,
+			 unsigned long parent_rate)
+{
+	struct meson_clk_mpll *mpll = to_meson_clk_mpll(hw);
+	struct parm *p;
+	unsigned long reg, sdm, n2;
+	unsigned long flags = 0;
+
+	params_from_rate(rate, parent_rate, &sdm, &n2);
+
+	if (mpll->lock)
+		spin_lock_irqsave(mpll->lock, flags);
+	else
+		__acquire(mpll->lock);
+
+	p = &mpll->sdm;
+	reg = readl(mpll->base + p->reg_off);
+	reg = PARM_SET(p->width, p->shift, reg, sdm);
+	writel(reg, mpll->base + p->reg_off);
+
+	p = &mpll->sdm_en;
+	reg = readl(mpll->base + p->reg_off);
+	reg = PARM_SET(p->width, p->shift, reg, 1);
+	writel(reg, mpll->base + p->reg_off);
+
+	p = &mpll->n2;
+	reg = readl(mpll->base + p->reg_off);
+	reg = PARM_SET(p->width, p->shift, reg, n2);
+	writel(reg, mpll->base + p->reg_off);
+
+	if (mpll->lock)
+		spin_unlock_irqrestore(mpll->lock, flags);
+	else
+		__release(mpll->lock);
 
-	return rate;
+	return 0;
+}
+
+static void mpll_enable_core(struct clk_hw *hw, int enable)
+{
+	struct meson_clk_mpll *mpll = to_meson_clk_mpll(hw);
+	struct parm *p;
+	unsigned long reg;
+	unsigned long flags = 0;
+
+	if (mpll->lock)
+		spin_lock_irqsave(mpll->lock, flags);
+	else
+		__acquire(mpll->lock);
+
+	p = &mpll->en;
+	reg = readl(mpll->base + p->reg_off);
+	reg = PARM_SET(p->width, p->shift, reg, enable ? 1 : 0);
+	writel(reg, mpll->base + p->reg_off);
+
+	if (mpll->lock)
+		spin_unlock_irqrestore(mpll->lock, flags);
+	else
+		__release(mpll->lock);
+}
+
+
+static int mpll_enable(struct clk_hw *hw)
+{
+	mpll_enable_core(hw, 1);
+
+	return 0;
+}
+
+static void mpll_disable(struct clk_hw *hw)
+{
+	mpll_enable_core(hw, 0);
+}
+
+static int mpll_is_enabled(struct clk_hw *hw)
+{
+	struct meson_clk_mpll *mpll = to_meson_clk_mpll(hw);
+	struct parm *p;
+	unsigned long reg;
+	int en;
+
+	p = &mpll->en;
+	reg = readl(mpll->base + p->reg_off);
+	en = PARM_GET(p->width, p->shift, reg);
+
+	return en;
 }
 
 const struct clk_ops meson_clk_mpll_ro_ops = {
-	.recalc_rate = mpll_recalc_rate,
+	.recalc_rate	= mpll_recalc_rate,
+	.round_rate	= mpll_round_rate,
+	.is_enabled	= mpll_is_enabled,
+};
+
+const struct clk_ops meson_clk_mpll_ops = {
+	.recalc_rate	= mpll_recalc_rate,
+	.round_rate	= mpll_round_rate,
+	.set_rate	= mpll_set_rate,
+	.enable		= mpll_enable,
+	.disable	= mpll_disable,
+	.is_enabled	= mpll_is_enabled,
 };
diff --git a/drivers/clk/meson/clkc.h b/drivers/clk/meson/clkc.h
index 9bb70e7a7d6a..54d58a465039 100644
--- a/drivers/clk/meson/clkc.h
+++ b/drivers/clk/meson/clkc.h
@@ -92,8 +92,9 @@ struct meson_clk_mpll {
 	struct clk_hw hw;
 	void __iomem *base;
 	struct parm sdm;
+	struct parm sdm_en;
 	struct parm n2;
-	/* FIXME ssen gate control? */
+	struct parm en;
 	spinlock_t *lock;
 };
 
@@ -116,5 +117,6 @@ extern const struct clk_ops meson_clk_pll_ro_ops;
 extern const struct clk_ops meson_clk_pll_ops;
 extern const struct clk_ops meson_clk_cpu_ops;
 extern const struct clk_ops meson_clk_mpll_ro_ops;
+extern const struct clk_ops meson_clk_mpll_ops;
 
 #endif /* __CLKC_H */
diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c
index 388b0c8838af..6b97f4da1708 100644
--- a/drivers/clk/meson/gxbb.c
+++ b/drivers/clk/meson/gxbb.c
@@ -441,11 +441,21 @@ static struct meson_clk_mpll gxbb_mpll0 = {
 		.shift   = 0,
 		.width   = 14,
 	},
+	.sdm_en = {
+		.reg_off = HHI_MPLL_CNTL7,
+		.shift   = 15,
+		.width	 = 1,
+	},
 	.n2 = {
 		.reg_off = HHI_MPLL_CNTL7,
 		.shift   = 16,
 		.width   = 9,
 	},
+	.en = {
+		.reg_off = HHI_MPLL_CNTL7,
+		.shift   = 14,
+		.width	 = 1,
+	},
 	.lock = &clk_lock,
 	.hw.init = &(struct clk_init_data){
 		.name = "mpll0",
@@ -461,11 +471,21 @@ static struct meson_clk_mpll gxbb_mpll1 = {
 		.shift   = 0,
 		.width   = 14,
 	},
+	.sdm_en = {
+		.reg_off = HHI_MPLL_CNTL8,
+		.shift   = 15,
+		.width	 = 1,
+	},
 	.n2 = {
 		.reg_off = HHI_MPLL_CNTL8,
 		.shift   = 16,
 		.width   = 9,
 	},
+	.en = {
+		.reg_off = HHI_MPLL_CNTL8,
+		.shift   = 14,
+		.width	 = 1,
+	},
 	.lock = &clk_lock,
 	.hw.init = &(struct clk_init_data){
 		.name = "mpll1",
@@ -481,11 +501,21 @@ static struct meson_clk_mpll gxbb_mpll2 = {
 		.shift   = 0,
 		.width   = 14,
 	},
+	.sdm_en = {
+		.reg_off = HHI_MPLL_CNTL9,
+		.shift   = 15,
+		.width	 = 1,
+	},
 	.n2 = {
 		.reg_off = HHI_MPLL_CNTL9,
 		.shift   = 16,
 		.width   = 9,
 	},
+	.en = {
+		.reg_off = HHI_MPLL_CNTL9,
+		.shift   = 14,
+		.width	 = 1,
+	},
 	.lock = &clk_lock,
 	.hw.init = &(struct clk_init_data){
 		.name = "mpll2",
-- 
2.9.3

[toc] | [prev] | [standalone]


Back to top | Article view | linux.kernel


csiph-web