2017-03-09 10:43:44

by Jerome Brunet

[permalink] [raw]
Subject: [PATCH v2 0/9] clk: meson: update clock controller for audio support

This patchset is a first round of update to the meson clock controllers
to bring audio support. The patchset is based on clk-next. It could be
rebased on amlogic tree later on, if you prefer the patches to go through
Kevin's tree.

First patch fix an issue found while writing patch 5 (Giving ternary
operator to SET_PARM)

Following Stephen comment on the v1, patch 2 adds the const qualifiers
missing upstream.

Patches 3 and 4 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 5 to 8 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 9 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 to meson SoC family.

Changes since v1 [0]:
* Add SET_PARM fix to the series
* Add missing const qualifiers to the clock arrays
* No more additional patches required as SAR clocks have been merged

[0]: http://lkml.kernel.org/r/[email protected]

Jerome Brunet (9):
clk: meson: fix SET_PARM macro
clk: meson: add missing const qualifiers on gate arrays
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 | 6 +-
drivers/clk/meson/gxbb.c | 66 ++++++++++++---
drivers/clk/meson/gxbb.h | 10 +--
drivers/clk/meson/meson8b.c | 127 ++++++++++++++++++++++++++--
drivers/clk/meson/meson8b.h | 20 ++++-
include/dt-bindings/clock/gxbb-clkc.h | 5 ++
7 files changed, 356 insertions(+), 30 deletions(-)

--
2.9.3


2017-03-09 10:43:57

by Jerome Brunet

[permalink] [raw]
Subject: [PATCH v2 1/9] clk: meson: fix SET_PARM macro

parameter val is not enclosed in parenthesis which is buggy when given an
expression instead of a simple value

Signed-off-by: Jerome Brunet <[email protected]>
Reviewed-by: Kevin Hilman <[email protected]>
---
drivers/clk/meson/clkc.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/clk/meson/clkc.h b/drivers/clk/meson/clkc.h
index 9bb70e7a7d6a..c6be77dd8694 100644
--- a/drivers/clk/meson/clkc.h
+++ b/drivers/clk/meson/clkc.h
@@ -25,7 +25,7 @@
#define PARM_GET(width, shift, reg) \
(((reg) & SETPMASK(width, shift)) >> (shift))
#define PARM_SET(width, shift, reg, val) \
- (((reg) & CLRPMASK(width, shift)) | (val << (shift)))
+ (((reg) & CLRPMASK(width, shift)) | ((val) << (shift)))

#define MESON_PARM_APPLICABLE(p) (!!((p)->width))

--
2.9.3

2017-03-09 10:50:34

by Jerome Brunet

[permalink] [raw]
Subject: [PATCH v2 6/9] clk: meson: gxbb: mpll: use rw operation

Use read/write operations for the mpll clocks instead of the
read-only ones.

Signed-off-by: Jerome Brunet <[email protected]>
---
drivers/clk/meson/gxbb.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c
index 79fb8989f8dd..5059c7bbdbb3 100644
--- a/drivers/clk/meson/gxbb.c
+++ b/drivers/clk/meson/gxbb.c
@@ -459,7 +459,7 @@ static struct meson_clk_mpll gxbb_mpll0 = {
.lock = &clk_lock,
.hw.init = &(struct clk_init_data){
.name = "mpll0",
- .ops = &meson_clk_mpll_ro_ops,
+ .ops = &meson_clk_mpll_ops,
.parent_names = (const char *[]){ "fixed_pll" },
.num_parents = 1,
},
@@ -489,7 +489,7 @@ static struct meson_clk_mpll gxbb_mpll1 = {
.lock = &clk_lock,
.hw.init = &(struct clk_init_data){
.name = "mpll1",
- .ops = &meson_clk_mpll_ro_ops,
+ .ops = &meson_clk_mpll_ops,
.parent_names = (const char *[]){ "fixed_pll" },
.num_parents = 1,
},
@@ -519,7 +519,7 @@ static struct meson_clk_mpll gxbb_mpll2 = {
.lock = &clk_lock,
.hw.init = &(struct clk_init_data){
.name = "mpll2",
- .ops = &meson_clk_mpll_ro_ops,
+ .ops = &meson_clk_mpll_ops,
.parent_names = (const char *[]){ "fixed_pll" },
.num_parents = 1,
},
--
2.9.3

2017-03-09 10:50:32

by Jerome Brunet

[permalink] [raw]
Subject: [PATCH v2 2/9] clk: meson: add missing const qualifiers on gate arrays

Reported-by: Stephen Boyd <[email protected]>
Signed-off-by: Jerome Brunet <[email protected]>
---
drivers/clk/meson/gxbb.c | 2 +-
drivers/clk/meson/meson8b.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c
index 1c1ec137a3cc..c063287bb0ed 100644
--- a/drivers/clk/meson/gxbb.c
+++ b/drivers/clk/meson/gxbb.c
@@ -816,7 +816,7 @@ static struct meson_clk_mpll *const gxbb_clk_mplls[] = {
&gxbb_mpll2,
};

-static struct clk_gate *gxbb_clk_gates[] = {
+static struct clk_gate *const gxbb_clk_gates[] = {
&gxbb_clk81,
&gxbb_ddr,
&gxbb_dos,
diff --git a/drivers/clk/meson/meson8b.c b/drivers/clk/meson/meson8b.c
index 888494d4fb8a..d1cc4d7cc8ff 100644
--- a/drivers/clk/meson/meson8b.c
+++ b/drivers/clk/meson/meson8b.c
@@ -501,7 +501,7 @@ static struct meson_clk_pll *const meson8b_clk_plls[] = {
&meson8b_sys_pll,
};

-static struct clk_gate *meson8b_clk_gates[] = {
+static struct clk_gate *const meson8b_clk_gates[] = {
&meson8b_clk81,
&meson8b_ddr,
&meson8b_dos,
--
2.9.3

2017-03-09 10:51:35

by Jerome Brunet

[permalink] [raw]
Subject: [PATCH v2 3/9] clk: meson8b: put dividers and muxes in tables

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 <[email protected]>
---
drivers/clk/meson/meson8b.c | 22 ++++++++++++++++++----
1 file changed, 18 insertions(+), 4 deletions(-)

diff --git a/drivers/clk/meson/meson8b.c b/drivers/clk/meson/meson8b.c
index d1cc4d7cc8ff..2937443d4505 100644
--- a/drivers/clk/meson/meson8b.c
+++ b/drivers/clk/meson/meson8b.c
@@ -582,6 +582,14 @@ static struct clk_gate *const meson8b_clk_gates[] = {
&meson8b_ao_iface,
};

+static struct clk_mux *const meson8b_clk_muxes[] = {
+ &meson8b_mpeg_clk_sel,
+};
+
+static struct clk_divider *const meson8b_clk_dividers[] = {
+ &meson8b_mpeg_clk_div,
+};
+
static int meson8b_clkc_probe(struct platform_device *pdev)
{
void __iomem *clk_base;
@@ -604,15 +612,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

2017-03-09 10:50:28

by Jerome Brunet

[permalink] [raw]
Subject: [PATCH v2 7/9] clk: meson8b: add the mplls clocks 0, 1 and 2

Signed-off-by: Jerome Brunet <[email protected]>
---
drivers/clk/meson/meson8b.c | 103 ++++++++++++++++++++++++++++++++++++++++++++
drivers/clk/meson/meson8b.h | 20 ++++++++-
2 files changed, 122 insertions(+), 1 deletion(-)

diff --git a/drivers/clk/meson/meson8b.c b/drivers/clk/meson/meson8b.c
index 2937443d4505..e9985503165c 100644
--- a/drivers/clk/meson/meson8b.c
+++ b/drivers/clk/meson/meson8b.c
@@ -245,6 +245,96 @@ static struct clk_fixed_factor meson8b_fclk_div7 = {
},
};

+static struct meson_clk_mpll meson8b_mpll0 = {
+ .sdm = {
+ .reg_off = HHI_MPLL_CNTL7,
+ .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",
+ .ops = &meson_clk_mpll_ops,
+ .parent_names = (const char *[]){ "fixed_pll" },
+ .num_parents = 1,
+ },
+};
+
+static struct meson_clk_mpll meson8b_mpll1 = {
+ .sdm = {
+ .reg_off = HHI_MPLL_CNTL8,
+ .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",
+ .ops = &meson_clk_mpll_ops,
+ .parent_names = (const char *[]){ "fixed_pll" },
+ .num_parents = 1,
+ },
+};
+
+static struct meson_clk_mpll meson8b_mpll2 = {
+ .sdm = {
+ .reg_off = HHI_MPLL_CNTL9,
+ .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",
+ .ops = &meson_clk_mpll_ops,
+ .parent_names = (const char *[]){ "fixed_pll" },
+ .num_parents = 1,
+ },
+};
+
/*
* FIXME cpu clocks and the legacy composite clocks (e.g. clk81) are both PLL
* post-dividers and should be modeled with their respective PLLs via the
@@ -491,6 +581,9 @@ static struct clk_hw_onecell_data meson8b_hw_onecell_data = {
[CLKID_AO_AHB_SRAM] = &meson8b_ao_ahb_sram.hw,
[CLKID_AO_AHB_BUS] = &meson8b_ao_ahb_bus.hw,
[CLKID_AO_IFACE] = &meson8b_ao_iface.hw,
+ [CLKID_MPLL0] = &meson8b_mpll0.hw,
+ [CLKID_MPLL1] = &meson8b_mpll1.hw,
+ [CLKID_MPLL2] = &meson8b_mpll2.hw,
},
.num = CLK_NR_CLKS,
};
@@ -501,6 +594,12 @@ static struct meson_clk_pll *const meson8b_clk_plls[] = {
&meson8b_sys_pll,
};

+static struct meson_clk_mpll *const meson8b_clk_mplls[] = {
+ &meson8b_mpll0,
+ &meson8b_mpll1,
+ &meson8b_mpll2,
+};
+
static struct clk_gate *const meson8b_clk_gates[] = {
&meson8b_clk81,
&meson8b_ddr,
@@ -609,6 +708,10 @@ static int meson8b_clkc_probe(struct platform_device *pdev)
for (i = 0; i < ARRAY_SIZE(meson8b_clk_plls); i++)
meson8b_clk_plls[i]->base = clk_base;

+ /* Populate base address for MPLLs */
+ for (i = 0; i < ARRAY_SIZE(meson8b_clk_mplls); i++)
+ meson8b_clk_mplls[i]->base = clk_base;
+
/* Populate the base address for CPU clk */
meson8b_cpu_clk.base = clk_base;

diff --git a/drivers/clk/meson/meson8b.h b/drivers/clk/meson/meson8b.h
index 010e9582888d..3881defc8644 100644
--- a/drivers/clk/meson/meson8b.h
+++ b/drivers/clk/meson/meson8b.h
@@ -42,6 +42,21 @@
#define HHI_VID_PLL_CNTL 0x320 /* 0xc8 offset in data sheet */

/*
+ * MPLL register offeset taken from the S905 datasheet. Vendor kernel source
+ * confirm these are the same for the S805.
+ */
+#define HHI_MPLL_CNTL 0x280 /* 0xa0 offset in data sheet */
+#define HHI_MPLL_CNTL2 0x284 /* 0xa1 offset in data sheet */
+#define HHI_MPLL_CNTL3 0x288 /* 0xa2 offset in data sheet */
+#define HHI_MPLL_CNTL4 0x28C /* 0xa3 offset in data sheet */
+#define HHI_MPLL_CNTL5 0x290 /* 0xa4 offset in data sheet */
+#define HHI_MPLL_CNTL6 0x294 /* 0xa5 offset in data sheet */
+#define HHI_MPLL_CNTL7 0x298 /* 0xa6 offset in data sheet */
+#define HHI_MPLL_CNTL8 0x29C /* 0xa7 offset in data sheet */
+#define HHI_MPLL_CNTL9 0x2A0 /* 0xa8 offset in data sheet */
+#define HHI_MPLL_CNTL10 0x2A4 /* 0xa9 offset in data sheet */
+
+/*
* CLKID index values
*
* These indices are entirely contrived and do not map onto the hardware.
@@ -142,8 +157,11 @@
#define CLKID_AO_AHB_SRAM 90
#define CLKID_AO_AHB_BUS 91
#define CLKID_AO_IFACE 92
+#define CLKID_MPLL0 93
+#define CLKID_MPLL1 94
+#define CLKID_MPLL2 95

-#define CLK_NR_CLKS 93
+#define CLK_NR_CLKS 96

/* include the CLKIDs that have been made part of the stable DT binding */
#include <dt-bindings/clock/meson8b-clkc.h>
--
2.9.3

2017-03-09 10:50:25

by Jerome Brunet

[permalink] [raw]
Subject: [PATCH v2 8/9] clk: meson: mpll: correct N2 maximum value

Gxbb datasheet says N2 maximum value is 127 but the register field is
9 bits wide, the maximum value should 511.

Test shows value greater than 127, all the way to 511, works well

Signed-off-by: Jerome Brunet <[email protected]>
---
drivers/clk/meson/clk-mpll.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/clk/meson/clk-mpll.c b/drivers/clk/meson/clk-mpll.c
index 342b85d4e22a..540dabe5adad 100644
--- a/drivers/clk/meson/clk-mpll.c
+++ b/drivers/clk/meson/clk-mpll.c
@@ -68,7 +68,7 @@
#define SDM_MIN 1
#define SDM_MAX 16383
#define N2_MIN 4
-#define N2_MAX 127
+#define N2_MAX 511

#define to_meson_clk_mpll(_hw) container_of(_hw, struct meson_clk_mpll, hw)

--
2.9.3

2017-03-09 10:50:26

by Jerome Brunet

[permalink] [raw]
Subject: [PATCH v2 9/9] dt-bindings: clk: gxbb: expose i2s output clock gates

Signed-off-by: Jerome Brunet <[email protected]>
---
drivers/clk/meson/gxbb.h | 10 +++++-----
include/dt-bindings/clock/gxbb-clkc.h | 5 +++++
2 files changed, 10 insertions(+), 5 deletions(-)

diff --git a/drivers/clk/meson/gxbb.h b/drivers/clk/meson/gxbb.h
index 8ee2022ce5d5..274f58764853 100644
--- a/drivers/clk/meson/gxbb.h
+++ b/drivers/clk/meson/gxbb.h
@@ -206,16 +206,16 @@
#define CLKID_I2S_SPDIF 35
/* CLKID_ETH */
#define CLKID_DEMUX 37
-#define CLKID_AIU_GLUE 38
+/* CLKID_AIU_GLUE */
#define CLKID_IEC958 39
-#define CLKID_I2S_OUT 40
+/* CLKID_I2S_OUT */
#define CLKID_AMCLK 41
#define CLKID_AIFIFO2 42
#define CLKID_MIXER 43
-#define CLKID_MIXER_IFACE 44
+/* CLKID_MIXER_IFACE */
#define CLKID_ADC 45
#define CLKID_BLKMV 46
-#define CLKID_AIU 47
+/* CLKID_AIU */
#define CLKID_UART1 48
#define CLKID_G2D 49
/* CLKID_USB0 */
@@ -248,7 +248,7 @@
/* CLKID_GCLK_VENCI_INT0 */
#define CLKID_GCLK_VENCI_INT 78
#define CLKID_DAC_CLK 79
-#define CLKID_AOCLK_GATE 80
+/* CLKID_AOCLK_GATE */
#define CLKID_IEC958_GATE 81
#define CLKID_ENC480P 82
#define CLKID_RNG1 83
diff --git a/include/dt-bindings/clock/gxbb-clkc.h b/include/dt-bindings/clock/gxbb-clkc.h
index 692846c7941b..f08f06dd7702 100644
--- a/include/dt-bindings/clock/gxbb-clkc.h
+++ b/include/dt-bindings/clock/gxbb-clkc.h
@@ -16,6 +16,10 @@
#define CLKID_I2C 22
#define CLKID_SAR_ADC 23
#define CLKID_ETH 36
+#define CLKID_AIU_GLUE 38
+#define CLKID_I2S_OUT 40
+#define CLKID_MIXER_IFACE 44
+#define CLKID_AIU 47
#define CLKID_USB0 50
#define CLKID_USB1 51
#define CLKID_USB 55
@@ -24,6 +28,7 @@
#define CLKID_USB0_DDR_BRIDGE 65
#define CLKID_SANA 69
#define CLKID_GCLK_VENCI_INT0 77
+#define CLKID_AOCLK_GATE 80
#define CLKID_AO_I2C 93
#define CLKID_SD_EMMC_A 94
#define CLKID_SD_EMMC_B 95
--
2.9.3

2017-03-09 10:50:23

by Jerome Brunet

[permalink] [raw]
Subject: [PATCH v2 4/9] clk: gxbb: put dividers and muxes in tables

Until now, there was only 2 dividers and 2 muxes declared for the gxbb
platform. With the ongoing work on various subsystem, 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 <[email protected]>
---
drivers/clk/meson/gxbb.c | 28 ++++++++++++++++++++--------
1 file changed, 20 insertions(+), 8 deletions(-)

diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c
index c063287bb0ed..79e9313e6703 100644
--- a/drivers/clk/meson/gxbb.c
+++ b/drivers/clk/meson/gxbb.c
@@ -902,6 +902,16 @@ static struct clk_gate *const gxbb_clk_gates[] = {
&gxbb_sar_adc_clk,
};

+static struct clk_mux *const gxbb_clk_muxes[] = {
+ &gxbb_mpeg_clk_sel,
+ &gxbb_sar_adc_clk_sel,
+};
+
+static struct clk_divider *const gxbb_clk_dividers[] = {
+ &gxbb_mpeg_clk_div,
+ &gxbb_sar_adc_clk_div,
+};
+
static int gxbb_clkc_probe(struct platform_device *pdev)
{
void __iomem *clk_base;
@@ -928,19 +938,21 @@ static int gxbb_clkc_probe(struct platform_device *pdev)
/* Populate the base address for CPU clk */
gxbb_cpu_clk.base = clk_base;

- /* Populate the base address for the MPEG clks */
- gxbb_mpeg_clk_sel.reg = clk_base + (u64)gxbb_mpeg_clk_sel.reg;
- gxbb_mpeg_clk_div.reg = clk_base + (u64)gxbb_mpeg_clk_div.reg;
-
- /* Populate the base address for the SAR ADC clks */
- gxbb_sar_adc_clk_sel.reg = clk_base + (u64)gxbb_sar_adc_clk_sel.reg;
- gxbb_sar_adc_clk_div.reg = clk_base + (u64)gxbb_sar_adc_clk_div.reg;
-
/* Populate base address for gates */
for (i = 0; i < ARRAY_SIZE(gxbb_clk_gates); i++)
gxbb_clk_gates[i]->reg = clk_base +
(u64)gxbb_clk_gates[i]->reg;

+ /* Populate base address for muxes */
+ for (i = 0; i < ARRAY_SIZE(gxbb_clk_muxes); i++)
+ gxbb_clk_muxes[i]->reg = clk_base +
+ (u64)gxbb_clk_muxes[i]->reg;
+
+ /* Populate base address for dividers */
+ for (i = 0; i < ARRAY_SIZE(gxbb_clk_dividers); i++)
+ gxbb_clk_dividers[i]->reg = clk_base +
+ (u64)gxbb_clk_dividers[i]->reg;
+
/*
* register all clks
*/
--
2.9.3

2017-03-09 10:48:44

by Jerome Brunet

[permalink] [raw]
Subject: [PATCH v2 5/9] clk: meson: mpll: add rw operation

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 <[email protected]>
---
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 c6be77dd8694..ad254675edd8 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 79e9313e6703..79fb8989f8dd 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

2017-03-11 00:39:36

by Kevin Hilman

[permalink] [raw]
Subject: Re: [PATCH v2 0/9] clk: meson: update clock controller for audio support

Jerome Brunet <[email protected]> writes:

> This patchset is a first round of update to the meson clock controllers
> to bring audio support. The patchset is based on clk-next. It could be
> rebased on amlogic tree later on, if you prefer the patches to go through
> Kevin's tree.

I'd prefer these go through the clk tree, and get an immutable branch
that I can use for my stuff that goes through the arm-soc tree.

Kevin

> First patch fix an issue found while writing patch 5 (Giving ternary
> operator to SET_PARM)
>
> Following Stephen comment on the v1, patch 2 adds the const qualifiers
> missing upstream.
>
> Patches 3 and 4 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 5 to 8 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 9 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 to meson SoC family.
>
> Changes since v1 [0]:
> * Add SET_PARM fix to the series
> * Add missing const qualifiers to the clock arrays
> * No more additional patches required as SAR clocks have been merged
>
> [0]: http://lkml.kernel.org/r/[email protected]
>
> Jerome Brunet (9):
> clk: meson: fix SET_PARM macro
> clk: meson: add missing const qualifiers on gate arrays
> 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 | 6 +-
> drivers/clk/meson/gxbb.c | 66 ++++++++++++---
> drivers/clk/meson/gxbb.h | 10 +--
> drivers/clk/meson/meson8b.c | 127 ++++++++++++++++++++++++++--
> drivers/clk/meson/meson8b.h | 20 ++++-
> include/dt-bindings/clock/gxbb-clkc.h | 5 ++
> 7 files changed, 356 insertions(+), 30 deletions(-)

2017-03-21 23:33:25

by Michael Turquette

[permalink] [raw]
Subject: Re: [PATCH v2 4/9] clk: gxbb: put dividers and muxes in tables

Quoting Jerome Brunet (2017-03-09 02:41:49)
> Until now, there was only 2 dividers and 2 muxes declared for the gxbb
> platform. With the ongoing work on various subsystem, 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 <[email protected]>

Looks good to me.

Regards,
Mike

> ---
> drivers/clk/meson/gxbb.c | 28 ++++++++++++++++++++--------
> 1 file changed, 20 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c
> index c063287bb0ed..79e9313e6703 100644
> --- a/drivers/clk/meson/gxbb.c
> +++ b/drivers/clk/meson/gxbb.c
> @@ -902,6 +902,16 @@ static struct clk_gate *const gxbb_clk_gates[] = {
> &gxbb_sar_adc_clk,
> };
>
> +static struct clk_mux *const gxbb_clk_muxes[] = {
> + &gxbb_mpeg_clk_sel,
> + &gxbb_sar_adc_clk_sel,
> +};
> +
> +static struct clk_divider *const gxbb_clk_dividers[] = {
> + &gxbb_mpeg_clk_div,
> + &gxbb_sar_adc_clk_div,
> +};
> +
> static int gxbb_clkc_probe(struct platform_device *pdev)
> {
> void __iomem *clk_base;
> @@ -928,19 +938,21 @@ static int gxbb_clkc_probe(struct platform_device *pdev)
> /* Populate the base address for CPU clk */
> gxbb_cpu_clk.base = clk_base;
>
> - /* Populate the base address for the MPEG clks */
> - gxbb_mpeg_clk_sel.reg = clk_base + (u64)gxbb_mpeg_clk_sel.reg;
> - gxbb_mpeg_clk_div.reg = clk_base + (u64)gxbb_mpeg_clk_div.reg;
> -
> - /* Populate the base address for the SAR ADC clks */
> - gxbb_sar_adc_clk_sel.reg = clk_base + (u64)gxbb_sar_adc_clk_sel.reg;
> - gxbb_sar_adc_clk_div.reg = clk_base + (u64)gxbb_sar_adc_clk_div.reg;
> -
> /* Populate base address for gates */
> for (i = 0; i < ARRAY_SIZE(gxbb_clk_gates); i++)
> gxbb_clk_gates[i]->reg = clk_base +
> (u64)gxbb_clk_gates[i]->reg;
>
> + /* Populate base address for muxes */
> + for (i = 0; i < ARRAY_SIZE(gxbb_clk_muxes); i++)
> + gxbb_clk_muxes[i]->reg = clk_base +
> + (u64)gxbb_clk_muxes[i]->reg;
> +
> + /* Populate base address for dividers */
> + for (i = 0; i < ARRAY_SIZE(gxbb_clk_dividers); i++)
> + gxbb_clk_dividers[i]->reg = clk_base +
> + (u64)gxbb_clk_dividers[i]->reg;
> +
> /*
> * register all clks
> */
> --
> 2.9.3
>

2017-03-21 23:33:40

by Michael Turquette

[permalink] [raw]
Subject: Re: [PATCH v2 7/9] clk: meson8b: add the mplls clocks 0, 1 and 2

Quoting Jerome Brunet (2017-03-09 02:41:52)
> Signed-off-by: Jerome Brunet <[email protected]>

Hmm, even for obvious patches like this it is still better to have some
sort of changelog :-/

Otherwise patch appears fine to me.

Regards,
Mike

> ---
> drivers/clk/meson/meson8b.c | 103 ++++++++++++++++++++++++++++++++++++++++++++
> drivers/clk/meson/meson8b.h | 20 ++++++++-
> 2 files changed, 122 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/clk/meson/meson8b.c b/drivers/clk/meson/meson8b.c
> index 2937443d4505..e9985503165c 100644
> --- a/drivers/clk/meson/meson8b.c
> +++ b/drivers/clk/meson/meson8b.c
> @@ -245,6 +245,96 @@ static struct clk_fixed_factor meson8b_fclk_div7 = {
> },
> };
>
> +static struct meson_clk_mpll meson8b_mpll0 = {
> + .sdm = {
> + .reg_off = HHI_MPLL_CNTL7,
> + .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",
> + .ops = &meson_clk_mpll_ops,
> + .parent_names = (const char *[]){ "fixed_pll" },
> + .num_parents = 1,
> + },
> +};
> +
> +static struct meson_clk_mpll meson8b_mpll1 = {
> + .sdm = {
> + .reg_off = HHI_MPLL_CNTL8,
> + .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",
> + .ops = &meson_clk_mpll_ops,
> + .parent_names = (const char *[]){ "fixed_pll" },
> + .num_parents = 1,
> + },
> +};
> +
> +static struct meson_clk_mpll meson8b_mpll2 = {
> + .sdm = {
> + .reg_off = HHI_MPLL_CNTL9,
> + .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",
> + .ops = &meson_clk_mpll_ops,
> + .parent_names = (const char *[]){ "fixed_pll" },
> + .num_parents = 1,
> + },
> +};
> +
> /*
> * FIXME cpu clocks and the legacy composite clocks (e.g. clk81) are both PLL
> * post-dividers and should be modeled with their respective PLLs via the
> @@ -491,6 +581,9 @@ static struct clk_hw_onecell_data meson8b_hw_onecell_data = {
> [CLKID_AO_AHB_SRAM] = &meson8b_ao_ahb_sram.hw,
> [CLKID_AO_AHB_BUS] = &meson8b_ao_ahb_bus.hw,
> [CLKID_AO_IFACE] = &meson8b_ao_iface.hw,
> + [CLKID_MPLL0] = &meson8b_mpll0.hw,
> + [CLKID_MPLL1] = &meson8b_mpll1.hw,
> + [CLKID_MPLL2] = &meson8b_mpll2.hw,
> },
> .num = CLK_NR_CLKS,
> };
> @@ -501,6 +594,12 @@ static struct meson_clk_pll *const meson8b_clk_plls[] = {
> &meson8b_sys_pll,
> };
>
> +static struct meson_clk_mpll *const meson8b_clk_mplls[] = {
> + &meson8b_mpll0,
> + &meson8b_mpll1,
> + &meson8b_mpll2,
> +};
> +
> static struct clk_gate *const meson8b_clk_gates[] = {
> &meson8b_clk81,
> &meson8b_ddr,
> @@ -609,6 +708,10 @@ static int meson8b_clkc_probe(struct platform_device *pdev)
> for (i = 0; i < ARRAY_SIZE(meson8b_clk_plls); i++)
> meson8b_clk_plls[i]->base = clk_base;
>
> + /* Populate base address for MPLLs */
> + for (i = 0; i < ARRAY_SIZE(meson8b_clk_mplls); i++)
> + meson8b_clk_mplls[i]->base = clk_base;
> +
> /* Populate the base address for CPU clk */
> meson8b_cpu_clk.base = clk_base;
>
> diff --git a/drivers/clk/meson/meson8b.h b/drivers/clk/meson/meson8b.h
> index 010e9582888d..3881defc8644 100644
> --- a/drivers/clk/meson/meson8b.h
> +++ b/drivers/clk/meson/meson8b.h
> @@ -42,6 +42,21 @@
> #define HHI_VID_PLL_CNTL 0x320 /* 0xc8 offset in data sheet */
>
> /*
> + * MPLL register offeset taken from the S905 datasheet. Vendor kernel source
> + * confirm these are the same for the S805.
> + */
> +#define HHI_MPLL_CNTL 0x280 /* 0xa0 offset in data sheet */
> +#define HHI_MPLL_CNTL2 0x284 /* 0xa1 offset in data sheet */
> +#define HHI_MPLL_CNTL3 0x288 /* 0xa2 offset in data sheet */
> +#define HHI_MPLL_CNTL4 0x28C /* 0xa3 offset in data sheet */
> +#define HHI_MPLL_CNTL5 0x290 /* 0xa4 offset in data sheet */
> +#define HHI_MPLL_CNTL6 0x294 /* 0xa5 offset in data sheet */
> +#define HHI_MPLL_CNTL7 0x298 /* 0xa6 offset in data sheet */
> +#define HHI_MPLL_CNTL8 0x29C /* 0xa7 offset in data sheet */
> +#define HHI_MPLL_CNTL9 0x2A0 /* 0xa8 offset in data sheet */
> +#define HHI_MPLL_CNTL10 0x2A4 /* 0xa9 offset in data sheet */
> +
> +/*
> * CLKID index values
> *
> * These indices are entirely contrived and do not map onto the hardware.
> @@ -142,8 +157,11 @@
> #define CLKID_AO_AHB_SRAM 90
> #define CLKID_AO_AHB_BUS 91
> #define CLKID_AO_IFACE 92
> +#define CLKID_MPLL0 93
> +#define CLKID_MPLL1 94
> +#define CLKID_MPLL2 95
>
> -#define CLK_NR_CLKS 93
> +#define CLK_NR_CLKS 96
>
> /* include the CLKIDs that have been made part of the stable DT binding */
> #include <dt-bindings/clock/meson8b-clkc.h>
> --
> 2.9.3
>

2017-03-21 23:33:35

by Michael Turquette

[permalink] [raw]
Subject: Re: [PATCH v2 5/9] clk: meson: mpll: add rw operation

Quoting Jerome Brunet (2017-03-09 02:41:50)
> 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 <[email protected]>

Patch looks good to me. I'm really happy to see the mpll's get sorted
out finally!

Regards,
Mike

> ---
> 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 c6be77dd8694..ad254675edd8 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 79e9313e6703..79fb8989f8dd 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
>

2017-03-21 23:33:28

by Michael Turquette

[permalink] [raw]
Subject: Re: [PATCH v2 3/9] clk: meson8b: put dividers and muxes in tables

Quoting Jerome Brunet (2017-03-09 02:41:48)
> 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 <[email protected]>

Looks good to me.

Regards,
Mike

> ---
> drivers/clk/meson/meson8b.c | 22 ++++++++++++++++++----
> 1 file changed, 18 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/clk/meson/meson8b.c b/drivers/clk/meson/meson8b.c
> index d1cc4d7cc8ff..2937443d4505 100644
> --- a/drivers/clk/meson/meson8b.c
> +++ b/drivers/clk/meson/meson8b.c
> @@ -582,6 +582,14 @@ static struct clk_gate *const meson8b_clk_gates[] = {
> &meson8b_ao_iface,
> };
>
> +static struct clk_mux *const meson8b_clk_muxes[] = {
> + &meson8b_mpeg_clk_sel,
> +};
> +
> +static struct clk_divider *const meson8b_clk_dividers[] = {
> + &meson8b_mpeg_clk_div,
> +};
> +
> static int meson8b_clkc_probe(struct platform_device *pdev)
> {
> void __iomem *clk_base;
> @@ -604,15 +612,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
>

2017-03-21 23:33:38

by Michael Turquette

[permalink] [raw]
Subject: Re: [PATCH v2 6/9] clk: meson: gxbb: mpll: use rw operation

Quoting Jerome Brunet (2017-03-09 02:41:51)
> Use read/write operations for the mpll clocks instead of the
> read-only ones.
>
> Signed-off-by: Jerome Brunet <[email protected]>

Looks good to me.

Regards,
Mike

> ---
> drivers/clk/meson/gxbb.c | 6 +++---
> 1 file changed, 3 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c
> index 79fb8989f8dd..5059c7bbdbb3 100644
> --- a/drivers/clk/meson/gxbb.c
> +++ b/drivers/clk/meson/gxbb.c
> @@ -459,7 +459,7 @@ static struct meson_clk_mpll gxbb_mpll0 = {
> .lock = &clk_lock,
> .hw.init = &(struct clk_init_data){
> .name = "mpll0",
> - .ops = &meson_clk_mpll_ro_ops,
> + .ops = &meson_clk_mpll_ops,
> .parent_names = (const char *[]){ "fixed_pll" },
> .num_parents = 1,
> },
> @@ -489,7 +489,7 @@ static struct meson_clk_mpll gxbb_mpll1 = {
> .lock = &clk_lock,
> .hw.init = &(struct clk_init_data){
> .name = "mpll1",
> - .ops = &meson_clk_mpll_ro_ops,
> + .ops = &meson_clk_mpll_ops,
> .parent_names = (const char *[]){ "fixed_pll" },
> .num_parents = 1,
> },
> @@ -519,7 +519,7 @@ static struct meson_clk_mpll gxbb_mpll2 = {
> .lock = &clk_lock,
> .hw.init = &(struct clk_init_data){
> .name = "mpll2",
> - .ops = &meson_clk_mpll_ro_ops,
> + .ops = &meson_clk_mpll_ops,
> .parent_names = (const char *[]){ "fixed_pll" },
> .num_parents = 1,
> },
> --
> 2.9.3
>

2017-03-27 19:53:02

by Michael Turquette

[permalink] [raw]
Subject: Re: [PATCH v2 0/9] clk: meson: update clock controller for audio support

Quoting Kevin Hilman (2017-03-10 16:39:27)
> Jerome Brunet <[email protected]> writes:
>
> > This patchset is a first round of update to the meson clock controllers
> > to bring audio support. The patchset is based on clk-next. It could be
> > rebased on amlogic tree later on, if you prefer the patches to go through
> > Kevin's tree.
>
> I'd prefer these go through the clk tree, and get an immutable branch
> that I can use for my stuff that goes through the arm-soc tree.

Applied to clk-meson, a stable branch, which has been merged into
clk-next.

Kevin, feel free to use clk-meson or any commit id therein: they will
not be rebased.

Regards,
Mike

>
> Kevin
>
> > First patch fix an issue found while writing patch 5 (Giving ternary
> > operator to SET_PARM)
> >
> > Following Stephen comment on the v1, patch 2 adds the const qualifiers
> > missing upstream.
> >
> > Patches 3 and 4 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 5 to 8 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 9 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 to meson SoC family.
> >
> > Changes since v1 [0]:
> > * Add SET_PARM fix to the series
> > * Add missing const qualifiers to the clock arrays
> > * No more additional patches required as SAR clocks have been merged
> >
> > [0]: http://lkml.kernel.org/r/[email protected]
> >
> > Jerome Brunet (9):
> > clk: meson: fix SET_PARM macro
> > clk: meson: add missing const qualifiers on gate arrays
> > 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 | 6 +-
> > drivers/clk/meson/gxbb.c | 66 ++++++++++++---
> > drivers/clk/meson/gxbb.h | 10 +--
> > drivers/clk/meson/meson8b.c | 127 ++++++++++++++++++++++++++--
> > drivers/clk/meson/meson8b.h | 20 ++++-
> > include/dt-bindings/clock/gxbb-clkc.h | 5 ++
> > 7 files changed, 356 insertions(+), 30 deletions(-)