From 840e1a73ccbb2096d1286d72c18ccadd3956b0ae Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Fri, 19 Jan 2018 16:55:21 +0100 Subject: clk: meson: check pll rate param table before using it Make sure the rate param table is available before using it. Some read-only plls don't provide it, which is ok since the table is not used by read-only clocks. R/W clocks are supposed to provide it, but it does not hurt check it. Signed-off-by: Jerome Brunet --- drivers/clk/meson/clk-pll.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/clk/meson/clk-pll.c b/drivers/clk/meson/clk-pll.c index 01341553f50b..2614341fc4ad 100644 --- a/drivers/clk/meson/clk-pll.c +++ b/drivers/clk/meson/clk-pll.c @@ -94,6 +94,13 @@ static long meson_clk_pll_round_rate(struct clk_hw *hw, unsigned long rate, const struct pll_rate_table *rate_table = pll->rate_table; int i; + /* + * if the table is missing, just return the current rate + * since we don't have the other available frequencies + */ + if (!rate_table) + return meson_clk_pll_recalc_rate(hw, *parent_rate); + for (i = 0; i < pll->rate_count; i++) { if (rate <= rate_table[i].rate) return rate_table[i].rate; @@ -109,6 +116,9 @@ static const struct pll_rate_table *meson_clk_get_pll_settings(struct meson_clk_ const struct pll_rate_table *rate_table = pll->rate_table; int i; + if (!rate_table) + return NULL; + for (i = 0; i < pll->rate_count; i++) { if (rate == rate_table[i].rate) return &rate_table[i]; -- cgit From 4ed98e9572ad24a5286d80d71221372b55fa9df5 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Fri, 19 Jan 2018 16:55:22 +0100 Subject: clk: meson: remove useless pll rate params tables Read-only plls don't need param table to recalculate the rate. Providing them with a param table is just a waste of memory. Remove the useless tables from sys_pll on gxbb and axg. Signed-off-by: Jerome Brunet --- drivers/clk/meson/axg.c | 94 ------------------------------------------------ drivers/clk/meson/gxbb.c | 94 ------------------------------------------------ 2 files changed, 188 deletions(-) diff --git a/drivers/clk/meson/axg.c b/drivers/clk/meson/axg.c index 1294f3ad7cd5..8e37bbf305e9 100644 --- a/drivers/clk/meson/axg.c +++ b/drivers/clk/meson/axg.c @@ -21,98 +21,6 @@ static DEFINE_SPINLOCK(meson_clk_lock); -static const struct pll_rate_table sys_pll_rate_table[] = { - PLL_RATE(24000000, 56, 1, 2), - PLL_RATE(48000000, 64, 1, 2), - PLL_RATE(72000000, 72, 1, 2), - PLL_RATE(96000000, 64, 1, 2), - PLL_RATE(120000000, 80, 1, 2), - PLL_RATE(144000000, 96, 1, 2), - PLL_RATE(168000000, 56, 1, 1), - PLL_RATE(192000000, 64, 1, 1), - PLL_RATE(216000000, 72, 1, 1), - PLL_RATE(240000000, 80, 1, 1), - PLL_RATE(264000000, 88, 1, 1), - PLL_RATE(288000000, 96, 1, 1), - PLL_RATE(312000000, 52, 1, 2), - PLL_RATE(336000000, 56, 1, 2), - PLL_RATE(360000000, 60, 1, 2), - PLL_RATE(384000000, 64, 1, 2), - PLL_RATE(408000000, 68, 1, 2), - PLL_RATE(432000000, 72, 1, 2), - PLL_RATE(456000000, 76, 1, 2), - PLL_RATE(480000000, 80, 1, 2), - PLL_RATE(504000000, 84, 1, 2), - PLL_RATE(528000000, 88, 1, 2), - PLL_RATE(552000000, 92, 1, 2), - PLL_RATE(576000000, 96, 1, 2), - PLL_RATE(600000000, 50, 1, 1), - PLL_RATE(624000000, 52, 1, 1), - PLL_RATE(648000000, 54, 1, 1), - PLL_RATE(672000000, 56, 1, 1), - PLL_RATE(696000000, 58, 1, 1), - PLL_RATE(720000000, 60, 1, 1), - PLL_RATE(744000000, 62, 1, 1), - PLL_RATE(768000000, 64, 1, 1), - PLL_RATE(792000000, 66, 1, 1), - PLL_RATE(816000000, 68, 1, 1), - PLL_RATE(840000000, 70, 1, 1), - PLL_RATE(864000000, 72, 1, 1), - PLL_RATE(888000000, 74, 1, 1), - PLL_RATE(912000000, 76, 1, 1), - PLL_RATE(936000000, 78, 1, 1), - PLL_RATE(960000000, 80, 1, 1), - PLL_RATE(984000000, 82, 1, 1), - PLL_RATE(1008000000, 84, 1, 1), - PLL_RATE(1032000000, 86, 1, 1), - PLL_RATE(1056000000, 88, 1, 1), - PLL_RATE(1080000000, 90, 1, 1), - PLL_RATE(1104000000, 92, 1, 1), - PLL_RATE(1128000000, 94, 1, 1), - PLL_RATE(1152000000, 96, 1, 1), - PLL_RATE(1176000000, 98, 1, 1), - PLL_RATE(1200000000, 50, 1, 0), - PLL_RATE(1224000000, 51, 1, 0), - PLL_RATE(1248000000, 52, 1, 0), - PLL_RATE(1272000000, 53, 1, 0), - PLL_RATE(1296000000, 54, 1, 0), - PLL_RATE(1320000000, 55, 1, 0), - PLL_RATE(1344000000, 56, 1, 0), - PLL_RATE(1368000000, 57, 1, 0), - PLL_RATE(1392000000, 58, 1, 0), - PLL_RATE(1416000000, 59, 1, 0), - PLL_RATE(1440000000, 60, 1, 0), - PLL_RATE(1464000000, 61, 1, 0), - PLL_RATE(1488000000, 62, 1, 0), - PLL_RATE(1512000000, 63, 1, 0), - PLL_RATE(1536000000, 64, 1, 0), - PLL_RATE(1560000000, 65, 1, 0), - PLL_RATE(1584000000, 66, 1, 0), - PLL_RATE(1608000000, 67, 1, 0), - PLL_RATE(1632000000, 68, 1, 0), - PLL_RATE(1656000000, 68, 1, 0), - PLL_RATE(1680000000, 68, 1, 0), - PLL_RATE(1704000000, 68, 1, 0), - PLL_RATE(1728000000, 69, 1, 0), - PLL_RATE(1752000000, 69, 1, 0), - PLL_RATE(1776000000, 69, 1, 0), - PLL_RATE(1800000000, 69, 1, 0), - PLL_RATE(1824000000, 70, 1, 0), - PLL_RATE(1848000000, 70, 1, 0), - PLL_RATE(1872000000, 70, 1, 0), - PLL_RATE(1896000000, 70, 1, 0), - PLL_RATE(1920000000, 71, 1, 0), - PLL_RATE(1944000000, 71, 1, 0), - PLL_RATE(1968000000, 71, 1, 0), - PLL_RATE(1992000000, 71, 1, 0), - PLL_RATE(2016000000, 72, 1, 0), - PLL_RATE(2040000000, 72, 1, 0), - PLL_RATE(2064000000, 72, 1, 0), - PLL_RATE(2088000000, 72, 1, 0), - PLL_RATE(2112000000, 73, 1, 0), - { /* sentinel */ }, -}; - static struct meson_clk_pll axg_fixed_pll = { .m = { .reg_off = HHI_MPLL_CNTL, @@ -154,8 +62,6 @@ static struct meson_clk_pll axg_sys_pll = { .shift = 10, .width = 2, }, - .rate_table = sys_pll_rate_table, - .rate_count = ARRAY_SIZE(sys_pll_rate_table), .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "sys_pll", diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c index af24455af5b4..4b5229f656e3 100644 --- a/drivers/clk/meson/gxbb.c +++ b/drivers/clk/meson/gxbb.c @@ -29,98 +29,6 @@ static DEFINE_SPINLOCK(meson_clk_lock); -static const struct pll_rate_table sys_pll_rate_table[] = { - PLL_RATE(24000000, 56, 1, 2), - PLL_RATE(48000000, 64, 1, 2), - PLL_RATE(72000000, 72, 1, 2), - PLL_RATE(96000000, 64, 1, 2), - PLL_RATE(120000000, 80, 1, 2), - PLL_RATE(144000000, 96, 1, 2), - PLL_RATE(168000000, 56, 1, 1), - PLL_RATE(192000000, 64, 1, 1), - PLL_RATE(216000000, 72, 1, 1), - PLL_RATE(240000000, 80, 1, 1), - PLL_RATE(264000000, 88, 1, 1), - PLL_RATE(288000000, 96, 1, 1), - PLL_RATE(312000000, 52, 1, 2), - PLL_RATE(336000000, 56, 1, 2), - PLL_RATE(360000000, 60, 1, 2), - PLL_RATE(384000000, 64, 1, 2), - PLL_RATE(408000000, 68, 1, 2), - PLL_RATE(432000000, 72, 1, 2), - PLL_RATE(456000000, 76, 1, 2), - PLL_RATE(480000000, 80, 1, 2), - PLL_RATE(504000000, 84, 1, 2), - PLL_RATE(528000000, 88, 1, 2), - PLL_RATE(552000000, 92, 1, 2), - PLL_RATE(576000000, 96, 1, 2), - PLL_RATE(600000000, 50, 1, 1), - PLL_RATE(624000000, 52, 1, 1), - PLL_RATE(648000000, 54, 1, 1), - PLL_RATE(672000000, 56, 1, 1), - PLL_RATE(696000000, 58, 1, 1), - PLL_RATE(720000000, 60, 1, 1), - PLL_RATE(744000000, 62, 1, 1), - PLL_RATE(768000000, 64, 1, 1), - PLL_RATE(792000000, 66, 1, 1), - PLL_RATE(816000000, 68, 1, 1), - PLL_RATE(840000000, 70, 1, 1), - PLL_RATE(864000000, 72, 1, 1), - PLL_RATE(888000000, 74, 1, 1), - PLL_RATE(912000000, 76, 1, 1), - PLL_RATE(936000000, 78, 1, 1), - PLL_RATE(960000000, 80, 1, 1), - PLL_RATE(984000000, 82, 1, 1), - PLL_RATE(1008000000, 84, 1, 1), - PLL_RATE(1032000000, 86, 1, 1), - PLL_RATE(1056000000, 88, 1, 1), - PLL_RATE(1080000000, 90, 1, 1), - PLL_RATE(1104000000, 92, 1, 1), - PLL_RATE(1128000000, 94, 1, 1), - PLL_RATE(1152000000, 96, 1, 1), - PLL_RATE(1176000000, 98, 1, 1), - PLL_RATE(1200000000, 50, 1, 0), - PLL_RATE(1224000000, 51, 1, 0), - PLL_RATE(1248000000, 52, 1, 0), - PLL_RATE(1272000000, 53, 1, 0), - PLL_RATE(1296000000, 54, 1, 0), - PLL_RATE(1320000000, 55, 1, 0), - PLL_RATE(1344000000, 56, 1, 0), - PLL_RATE(1368000000, 57, 1, 0), - PLL_RATE(1392000000, 58, 1, 0), - PLL_RATE(1416000000, 59, 1, 0), - PLL_RATE(1440000000, 60, 1, 0), - PLL_RATE(1464000000, 61, 1, 0), - PLL_RATE(1488000000, 62, 1, 0), - PLL_RATE(1512000000, 63, 1, 0), - PLL_RATE(1536000000, 64, 1, 0), - PLL_RATE(1560000000, 65, 1, 0), - PLL_RATE(1584000000, 66, 1, 0), - PLL_RATE(1608000000, 67, 1, 0), - PLL_RATE(1632000000, 68, 1, 0), - PLL_RATE(1656000000, 68, 1, 0), - PLL_RATE(1680000000, 68, 1, 0), - PLL_RATE(1704000000, 68, 1, 0), - PLL_RATE(1728000000, 69, 1, 0), - PLL_RATE(1752000000, 69, 1, 0), - PLL_RATE(1776000000, 69, 1, 0), - PLL_RATE(1800000000, 69, 1, 0), - PLL_RATE(1824000000, 70, 1, 0), - PLL_RATE(1848000000, 70, 1, 0), - PLL_RATE(1872000000, 70, 1, 0), - PLL_RATE(1896000000, 70, 1, 0), - PLL_RATE(1920000000, 71, 1, 0), - PLL_RATE(1944000000, 71, 1, 0), - PLL_RATE(1968000000, 71, 1, 0), - PLL_RATE(1992000000, 71, 1, 0), - PLL_RATE(2016000000, 72, 1, 0), - PLL_RATE(2040000000, 72, 1, 0), - PLL_RATE(2064000000, 72, 1, 0), - PLL_RATE(2088000000, 72, 1, 0), - PLL_RATE(2112000000, 73, 1, 0), - { /* sentinel */ }, -}; - static const struct pll_rate_table gxbb_gp0_pll_rate_table[] = { PLL_RATE(96000000, 32, 1, 3), PLL_RATE(99000000, 33, 1, 3), @@ -356,8 +264,6 @@ static struct meson_clk_pll gxbb_sys_pll = { .shift = 10, .width = 2, }, - .rate_table = sys_pll_rate_table, - .rate_count = ARRAY_SIZE(sys_pll_rate_table), .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "sys_pll", -- cgit From 94aa8a41f1bc807db78567e7031d75998c166150 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Fri, 19 Jan 2018 16:55:23 +0100 Subject: clk: meson: remove unnecessary rounding in the pll clock The pll driver performs the rate calculation in Mhz, which adds an unnecessary rounding down to the Mhz of the rate. Use 64bits long integers to perform this calculation safely on meson8b and perform the calculation in Hz instead Fixes: 7a29a869434e ("clk: meson: Add support for Meson clock controller") Signed-off-by: Jerome Brunet --- drivers/clk/meson/clk-pll.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/clk/meson/clk-pll.c b/drivers/clk/meson/clk-pll.c index 2614341fc4ad..087dfc532ba8 100644 --- a/drivers/clk/meson/clk-pll.c +++ b/drivers/clk/meson/clk-pll.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -51,8 +52,7 @@ static unsigned long meson_clk_pll_recalc_rate(struct clk_hw *hw, { struct meson_clk_pll *pll = to_meson_clk_pll(hw); struct parm *p; - unsigned long parent_rate_mhz = parent_rate / 1000000; - unsigned long rate_mhz; + u64 rate; u16 n, m, frac = 0, od, od2 = 0; u32 reg; @@ -74,17 +74,18 @@ static unsigned long meson_clk_pll_recalc_rate(struct clk_hw *hw, od2 = PARM_GET(p->width, p->shift, reg); } + rate = (u64)parent_rate * m; + p = &pll->frac; if (p->width) { reg = readl(pll->base + p->reg_off); frac = PARM_GET(p->width, p->shift, reg); - rate_mhz = (parent_rate_mhz * m + \ - (parent_rate_mhz * frac >> 12)) * 2 / n; - rate_mhz = rate_mhz >> od >> od2; - } else - rate_mhz = (parent_rate_mhz * m / n) >> od >> od2; - return rate_mhz * 1000000; + rate += mul_u64_u32_shr(parent_rate, frac, 12); + rate *= 2; + } + + return div_u64(rate, n) >> od >> od2; } static long meson_clk_pll_round_rate(struct clk_hw *hw, unsigned long rate, -- cgit From 4c5f67b7ea329ed8b3cf708fde4656b2d3b27dbf Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Fri, 19 Jan 2018 16:55:24 +0100 Subject: clk: meson: use the frac parameter width instead of a constant Use the fractional part width in the calculation instead of 12, which happens to be the witdh right now. This is safer in case the field width ever change in the future Signed-off-by: Jerome Brunet --- drivers/clk/meson/clk-pll.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/meson/clk-pll.c b/drivers/clk/meson/clk-pll.c index 087dfc532ba8..50923d004d96 100644 --- a/drivers/clk/meson/clk-pll.c +++ b/drivers/clk/meson/clk-pll.c @@ -81,7 +81,7 @@ static unsigned long meson_clk_pll_recalc_rate(struct clk_hw *hw, reg = readl(pll->base + p->reg_off); frac = PARM_GET(p->width, p->shift, reg); - rate += mul_u64_u32_shr(parent_rate, frac, 12); + rate += mul_u64_u32_shr(parent_rate, frac, p->width); rate *= 2; } -- cgit From 7d3142e5d64a2bdcd382dac979407f6afc83d685 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Fri, 19 Jan 2018 16:55:25 +0100 Subject: clk: meson: add od3 to the pll driver Some meson plls, such as the hdmi pll, are using a 3rd od parameter, which is yet another "power of 2" post divider. Add it to fix the calculation of the hdmi_pll rate Fixes: 738f66d3211d ("clk: gxbb: add AmLogic GXBB clk controller driver") Signed-off-by: Jerome Brunet --- drivers/clk/meson/clk-pll.c | 19 ++++++++++++++++--- drivers/clk/meson/clkc.h | 2 ++ drivers/clk/meson/gxbb.c | 5 +++++ 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/drivers/clk/meson/clk-pll.c b/drivers/clk/meson/clk-pll.c index 50923d004d96..1595f02f610f 100644 --- a/drivers/clk/meson/clk-pll.c +++ b/drivers/clk/meson/clk-pll.c @@ -53,7 +53,7 @@ static unsigned long meson_clk_pll_recalc_rate(struct clk_hw *hw, struct meson_clk_pll *pll = to_meson_clk_pll(hw); struct parm *p; u64 rate; - u16 n, m, frac = 0, od, od2 = 0; + u16 n, m, frac = 0, od, od2 = 0, od3 = 0; u32 reg; p = &pll->n; @@ -74,7 +74,13 @@ static unsigned long meson_clk_pll_recalc_rate(struct clk_hw *hw, od2 = PARM_GET(p->width, p->shift, reg); } - rate = (u64)parent_rate * m; + p = &pll->od3; + if (p->width) { + reg = readl(pll->base + p->reg_off); + od3 = PARM_GET(p->width, p->shift, reg); + } + + rate = (u64)m * parent_rate; p = &pll->frac; if (p->width) { @@ -85,7 +91,7 @@ static unsigned long meson_clk_pll_recalc_rate(struct clk_hw *hw, rate *= 2; } - return div_u64(rate, n) >> od >> od2; + return div_u64(rate, n) >> od >> od2 >> od3; } static long meson_clk_pll_round_rate(struct clk_hw *hw, unsigned long rate, @@ -226,6 +232,13 @@ static int meson_clk_pll_set_rate(struct clk_hw *hw, unsigned long rate, writel(reg, pll->base + p->reg_off); } + p = &pll->od3; + if (p->width) { + reg = readl(pll->base + p->reg_off); + reg = PARM_SET(p->width, p->shift, reg, rate_set->od3); + writel(reg, pll->base + p->reg_off); + } + p = &pll->frac; if (p->width) { reg = readl(pll->base + p->reg_off); diff --git a/drivers/clk/meson/clkc.h b/drivers/clk/meson/clkc.h index c2ff0520ce53..4acb35bda669 100644 --- a/drivers/clk/meson/clkc.h +++ b/drivers/clk/meson/clkc.h @@ -41,6 +41,7 @@ struct pll_rate_table { u16 n; u16 od; u16 od2; + u16 od3; u16 frac; }; @@ -92,6 +93,7 @@ struct meson_clk_pll { struct parm frac; struct parm od; struct parm od2; + struct parm od3; const struct pll_setup_params params; const struct pll_rate_table *rate_table; unsigned int rate_count; diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c index 4b5229f656e3..e83573b457fc 100644 --- a/drivers/clk/meson/gxbb.c +++ b/drivers/clk/meson/gxbb.c @@ -238,6 +238,11 @@ static struct meson_clk_pll gxbb_hdmi_pll = { .shift = 22, .width = 2, }, + .od3 = { + .reg_off = HHI_HDMI_PLL_CNTL2, + .shift = 18, + .width = 2, + }, .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "hdmi_pll", -- cgit From 69d92293274b3ae60c54271bf6e029e3d1d582e8 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Fri, 19 Jan 2018 16:55:26 +0100 Subject: clk: meson: add the gxl hdmi pll The hdmi pll used in the gxl family is actually different from the gxbb one. The register layout is completely different, which explain why the hdmi pll rate has always been rubbish on the gxl family. Adding the correct register field is the first part of the fix to get a correct rate out the hdmi pll Fixes: 0d48fc558d01 ("clk: meson-gxbb: Add GXL/GXM GP0 Variant") Signed-off-by: Jerome Brunet --- drivers/clk/meson/gxbb.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 48 insertions(+), 2 deletions(-) diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c index e83573b457fc..de1cea7a47fb 100644 --- a/drivers/clk/meson/gxbb.c +++ b/drivers/clk/meson/gxbb.c @@ -253,6 +253,52 @@ static struct meson_clk_pll gxbb_hdmi_pll = { }, }; +static struct meson_clk_pll gxl_hdmi_pll = { + .m = { + .reg_off = HHI_HDMI_PLL_CNTL, + .shift = 0, + .width = 9, + }, + .n = { + .reg_off = HHI_HDMI_PLL_CNTL, + .shift = 9, + .width = 5, + }, + .frac = { + /* + * On gxl, there is a register shift due to HHI_HDMI_PLL_CNTL1 + * which does not exist on gxbb, so we compute the register + * offset based on the PLL base to get it right + */ + .reg_off = HHI_HDMI_PLL_CNTL + 4, + .shift = 0, + .width = 12, + }, + .od = { + .reg_off = HHI_HDMI_PLL_CNTL + 8, + .shift = 21, + .width = 2, + }, + .od2 = { + .reg_off = HHI_HDMI_PLL_CNTL + 8, + .shift = 23, + .width = 2, + }, + .od3 = { + .reg_off = HHI_HDMI_PLL_CNTL + 8, + .shift = 19, + .width = 2, + }, + .lock = &meson_clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll", + .ops = &meson_clk_pll_ro_ops, + .parent_names = (const char *[]){ "xtal" }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + }, +}; + static struct meson_clk_pll gxbb_sys_pll = { .m = { .reg_off = HHI_SYS_PLL_CNTL, @@ -1520,7 +1566,7 @@ static struct clk_hw_onecell_data gxbb_hw_onecell_data = { static struct clk_hw_onecell_data gxl_hw_onecell_data = { .hws = { [CLKID_SYS_PLL] = &gxbb_sys_pll.hw, - [CLKID_HDMI_PLL] = &gxbb_hdmi_pll.hw, + [CLKID_HDMI_PLL] = &gxl_hdmi_pll.hw, [CLKID_FIXED_PLL] = &gxbb_fixed_pll.hw, [CLKID_FCLK_DIV2] = &gxbb_fclk_div2.hw, [CLKID_FCLK_DIV3] = &gxbb_fclk_div3.hw, @@ -1675,7 +1721,7 @@ static struct meson_clk_pll *const gxbb_clk_plls[] = { static struct meson_clk_pll *const gxl_clk_plls[] = { &gxbb_fixed_pll, - &gxbb_hdmi_pll, + &gxl_hdmi_pll, &gxbb_sys_pll, &gxl_gp0_pll, }; -- cgit From 3c4fe763d64db93c0c8ec359cf394cfc491f91f3 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Fri, 19 Jan 2018 16:55:27 +0100 Subject: clk: meson: fix rate calculation of plls with a fractional part The rate of the parent should not be multiplied by 2 when the pll has a fractional part. This is making the rate calculation of the gxl_hdmi_pll wrong (and others as well). This multiplication is specific to the hdmi_pll of gxbb and is most likely due to a multiplier sitting in front of this particular pll. Add a fixed factor clock in front on the gxbb pll and remove this constant from the calculation to fix the problem Fixes: 4a47295144dd ("clk: meson: fractional pll support") Signed-off-by: Jerome Brunet --- drivers/clk/meson/clk-pll.c | 1 - drivers/clk/meson/gxbb.c | 14 +++++++++++++- drivers/clk/meson/gxbb.h | 3 ++- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/drivers/clk/meson/clk-pll.c b/drivers/clk/meson/clk-pll.c index 1595f02f610f..218c769c6d50 100644 --- a/drivers/clk/meson/clk-pll.c +++ b/drivers/clk/meson/clk-pll.c @@ -88,7 +88,6 @@ static unsigned long meson_clk_pll_recalc_rate(struct clk_hw *hw, frac = PARM_GET(p->width, p->shift, reg); rate += mul_u64_u32_shr(parent_rate, frac, p->width); - rate *= 2; } return div_u64(rate, n) >> od >> od2 >> od3; diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c index de1cea7a47fb..119babfa8d14 100644 --- a/drivers/clk/meson/gxbb.c +++ b/drivers/clk/meson/gxbb.c @@ -212,6 +212,17 @@ static struct meson_clk_pll gxbb_fixed_pll = { }, }; +static struct clk_fixed_factor gxbb_hdmi_pll_pre_mult = { + .mult = 2, + .div = 1, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll_pre_mult", + .ops = &clk_fixed_factor_ops, + .parent_names = (const char *[]){ "xtal" }, + .num_parents = 1, + }, +}; + static struct meson_clk_pll gxbb_hdmi_pll = { .m = { .reg_off = HHI_HDMI_PLL_CNTL, @@ -247,7 +258,7 @@ static struct meson_clk_pll gxbb_hdmi_pll = { .hw.init = &(struct clk_init_data){ .name = "hdmi_pll", .ops = &meson_clk_pll_ro_ops, - .parent_names = (const char *[]){ "xtal" }, + .parent_names = (const char *[]){ "hdmi_pll_pre_mult" }, .num_parents = 1, .flags = CLK_GET_RATE_NOCACHE, }, @@ -1558,6 +1569,7 @@ static struct clk_hw_onecell_data gxbb_hw_onecell_data = { [CLKID_VAPB_1] = &gxbb_vapb_1.hw, [CLKID_VAPB_SEL] = &gxbb_vapb_sel.hw, [CLKID_VAPB] = &gxbb_vapb.hw, + [CLKID_HDMI_PLL_PRE_MULT] = &gxbb_hdmi_pll_pre_mult.hw, [NR_CLKS] = NULL, }, .num = NR_CLKS, diff --git a/drivers/clk/meson/gxbb.h b/drivers/clk/meson/gxbb.h index aee6fbba2004..42573b28a137 100644 --- a/drivers/clk/meson/gxbb.h +++ b/drivers/clk/meson/gxbb.h @@ -194,8 +194,9 @@ #define CLKID_VPU_1_DIV 130 #define CLKID_VAPB_0_DIV 134 #define CLKID_VAPB_1_DIV 137 +#define CLKID_HDMI_PLL_PRE_MULT 141 -#define NR_CLKS 141 +#define NR_CLKS 142 /* include the CLKIDs that have been made part of the DT binding */ #include -- cgit From 07f45e2ecc1ba1ce75d80768caf2267256cd135d Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Fri, 19 Jan 2018 16:55:28 +0100 Subject: clk: meson: gxbb: add the fractional part of the fixed_pll The fixed_pll of gxbb and gxl also has a fractional parameter. This has not been a problem so far because the fractional part is actually set to 0 on these platforms, so the rate remains correct when it is ignored. Still, it is better represent the pll the way it is, so add the frac parameter now Signed-off-by: Jerome Brunet --- drivers/clk/meson/gxbb.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c index 119babfa8d14..a5f25cc1944c 100644 --- a/drivers/clk/meson/gxbb.c +++ b/drivers/clk/meson/gxbb.c @@ -202,6 +202,11 @@ static struct meson_clk_pll gxbb_fixed_pll = { .shift = 16, .width = 2, }, + .frac = { + .reg_off = HHI_MPLL_CNTL2, + .shift = 0, + .width = 12, + }, .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "fixed_pll", -- cgit From 6b71aceceb09918daf37a40a1221077599040be3 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Fri, 19 Jan 2018 16:55:29 +0100 Subject: clk: meson: axg: add the fractional part of the fixed_pll The fixed_pll also has a fractional part. On axg s400 board, without this parameter, the calculated rate is off by ~8Mhz (0,4%). The fixed_pll being the root of the peripheral clock tree, this error is propagated to the rest of the clocks Adding the definition of the parameter fixes the problem Fixes: 78b4af312f91 ("clk: meson-axg: add clock controller drivers") Signed-off-by: Jerome Brunet --- drivers/clk/meson/axg.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/clk/meson/axg.c b/drivers/clk/meson/axg.c index 8e37bbf305e9..a1ac0ff67e5f 100644 --- a/drivers/clk/meson/axg.c +++ b/drivers/clk/meson/axg.c @@ -37,6 +37,11 @@ static struct meson_clk_pll axg_fixed_pll = { .shift = 16, .width = 2, }, + .frac = { + .reg_off = HHI_MPLL_CNTL2, + .shift = 0, + .width = 12, + }, .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "fixed_pll", -- cgit From 2fa9b361e500a0e092a9525afbd6a3a363ffa5f0 Mon Sep 17 00:00:00 2001 From: Yixun Lan Date: Fri, 19 Jan 2018 10:09:26 +0800 Subject: clk: meson: axg: fix the od shift of the sys_pll According to the datasheet, the od shift of sys_pll is actually 16. Fixes: 78b4af312f91 ('clk: meson-axg: add clock controller drivers') Signed-off-by: Yixun Lan [fixed commit message] Signed-off-by: Jerome Brunet --- drivers/clk/meson/axg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/meson/axg.c b/drivers/clk/meson/axg.c index a1ac0ff67e5f..455d4d8962bb 100644 --- a/drivers/clk/meson/axg.c +++ b/drivers/clk/meson/axg.c @@ -64,7 +64,7 @@ static struct meson_clk_pll axg_sys_pll = { }, .od = { .reg_off = HHI_SYS_PLL_CNTL, - .shift = 10, + .shift = 16, .width = 2, }, .lock = &meson_clk_lock, -- cgit From 6c00e7b76021fcf4ddb64191ccdf62c722adf0d1 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Fri, 19 Jan 2018 16:42:36 +0100 Subject: clk: meson: add axg misc bit to the mpll driver On axg, the rate of the mpll is stuck as if sdm value was 4 and could not change (expect for mpll2 strangely). Looking at the vendor kernel, it turns out a new magic bit from the undocumented HHI_PLL_TOP_MISC register is required. Setting this bit solves the problem and the mpll rates are back to normal Fixes: 78b4af312f91 ("clk: meson-axg: add clock controller drivers") Signed-off-by: Jerome Brunet --- drivers/clk/meson/axg.c | 20 ++++++++++++++++++++ drivers/clk/meson/clk-mpll.c | 7 +++++++ drivers/clk/meson/clkc.h | 1 + 3 files changed, 28 insertions(+) diff --git a/drivers/clk/meson/axg.c b/drivers/clk/meson/axg.c index 455d4d8962bb..2dc70e0e925c 100644 --- a/drivers/clk/meson/axg.c +++ b/drivers/clk/meson/axg.c @@ -292,6 +292,11 @@ static struct meson_clk_mpll axg_mpll0 = { .shift = 25, .width = 1, }, + .misc = { + .reg_off = HHI_PLL_TOP_MISC, + .shift = 0, + .width = 1, + }, .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "mpll0", @@ -322,6 +327,11 @@ static struct meson_clk_mpll axg_mpll1 = { .shift = 14, .width = 1, }, + .misc = { + .reg_off = HHI_PLL_TOP_MISC, + .shift = 1, + .width = 1, + }, .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "mpll1", @@ -352,6 +362,11 @@ static struct meson_clk_mpll axg_mpll2 = { .shift = 14, .width = 1, }, + .misc = { + .reg_off = HHI_PLL_TOP_MISC, + .shift = 2, + .width = 1, + }, .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "mpll2", @@ -382,6 +397,11 @@ static struct meson_clk_mpll axg_mpll3 = { .shift = 0, .width = 1, }, + .misc = { + .reg_off = HHI_PLL_TOP_MISC, + .shift = 3, + .width = 1, + }, .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "mpll3", diff --git a/drivers/clk/meson/clk-mpll.c b/drivers/clk/meson/clk-mpll.c index 5144360e2c80..6d79d6daadc4 100644 --- a/drivers/clk/meson/clk-mpll.c +++ b/drivers/clk/meson/clk-mpll.c @@ -173,6 +173,13 @@ static int mpll_set_rate(struct clk_hw *hw, reg = PARM_SET(p->width, p->shift, reg, n2); writel(reg, mpll->base + p->reg_off); + p = &mpll->misc; + if (p->width != 0) { + reg = readl(mpll->base + p->reg_off); + reg = PARM_SET(p->width, p->shift, reg, 1); + writel(reg, mpll->base + p->reg_off); + } + if (mpll->lock) spin_unlock_irqrestore(mpll->lock, flags); else diff --git a/drivers/clk/meson/clkc.h b/drivers/clk/meson/clkc.h index 4acb35bda669..07aaba26a857 100644 --- a/drivers/clk/meson/clkc.h +++ b/drivers/clk/meson/clkc.h @@ -121,6 +121,7 @@ struct meson_clk_mpll { struct parm n2; struct parm en; struct parm ssen; + struct parm misc; spinlock_t *lock; }; -- cgit From a377f681324a33bfa58ab88f7bb894cf515b2489 Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Sun, 10 Dec 2017 20:03:19 +0100 Subject: clk: rockchip: fix hclk_vio_niu on rk3328 The clock wrongly was called hclk_vio and exported, while it actually is a clock of the interconnect-vio connection and should therefore be always on till we actually model the interconnect. So fix that and don't export it as HCLK_VIO. Signed-off-by: Heiko Stuebner --- drivers/clk/rockchip/clk-rk3328.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/clk/rockchip/clk-rk3328.c b/drivers/clk/rockchip/clk-rk3328.c index b04f29774ee7..17816aec206a 100644 --- a/drivers/clk/rockchip/clk-rk3328.c +++ b/drivers/clk/rockchip/clk-rk3328.c @@ -727,7 +727,7 @@ static struct rockchip_clk_branch rk3328_clk_branches[] __initdata = { GATE(0, "pclk_vio_h2p", "hclk_vio_pre", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(21), 13, GFLAGS), GATE(0, "hclk_vio_h2p", "hclk_vio_pre", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(21), 14, GFLAGS), GATE(HCLK_HDCP, "hclk_hdcp", "hclk_vio_pre", 0, RK3328_CLKGATE_CON(22), 0, GFLAGS), - GATE(HCLK_VIO, "hclk_vio", "hclk_vio_pre", 0, RK3328_CLKGATE_CON(22), 1, GFLAGS), + GATE(0, "hclk_vio_niu", "hclk_vio_pre", 0, RK3328_CLKGATE_CON(22), 1, GFLAGS), GATE(PCLK_HDMI, "pclk_hdmi", "hclk_vio_pre", 0, RK3328_CLKGATE_CON(22), 4, GFLAGS), GATE(PCLK_HDCP, "pclk_hdcp", "hclk_vio_pre", 0, RK3328_CLKGATE_CON(22), 5, GFLAGS), @@ -861,6 +861,7 @@ static const char *const rk3328_critical_clocks[] __initconst = { "aclk_rga_niu", "pclk_vio_h2p", "hclk_vio_h2p", + "hclk_vio_niu", }; static void __init rk3328_clk_init(struct device_node *np) -- cgit From 224a63844173944817a7f7b966c14466abd2010f Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Sun, 10 Dec 2017 20:07:38 +0100 Subject: clk: rockchip: remove HCLK_VIO from rk3328 dt header This clock is not hclk_vio but hclk_vio_niu, the clock for the interconnect output. The clock got fixed and the id was never used in this incorrect form, so remove it. Signed-off-by: Heiko Stuebner --- include/dt-bindings/clock/rk3328-cru.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/dt-bindings/clock/rk3328-cru.h b/include/dt-bindings/clock/rk3328-cru.h index d2b26a4b43eb..a82a0109faff 100644 --- a/include/dt-bindings/clock/rk3328-cru.h +++ b/include/dt-bindings/clock/rk3328-cru.h @@ -193,7 +193,6 @@ #define HCLK_VPU_PRE 324 #define HCLK_VIO_PRE 325 #define HCLK_VPU 326 -#define HCLK_VIO 327 #define HCLK_BUS_PRE 328 #define HCLK_PERI_PRE 329 #define HCLK_H264 330 -- cgit From 1d334427c924b849d590ea1aea4adaaa43c5fa7f Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Mon, 11 Dec 2017 01:11:14 +0100 Subject: clk: rockchip: export sclk_hdmi_sfc on rk3328 This clock is one of the dw-hdmi supplying clocks and thus needs to be exported. Signed-off-by: Heiko Stuebner --- drivers/clk/rockchip/clk-rk3328.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/rockchip/clk-rk3328.c b/drivers/clk/rockchip/clk-rk3328.c index 17816aec206a..b7a28f2814e2 100644 --- a/drivers/clk/rockchip/clk-rk3328.c +++ b/drivers/clk/rockchip/clk-rk3328.c @@ -588,7 +588,7 @@ static struct rockchip_clk_branch rk3328_clk_branches[] __initdata = { COMPOSITE(ACLK_VOP_PRE, "aclk_vop_pre", mux_4plls_p, 0, RK3328_CLKSEL_CON(39), 6, 2, MFLAGS, 0, 5, DFLAGS, RK3328_CLKGATE_CON(5), 5, GFLAGS), - GATE(0, "clk_hdmi_sfc", "xin24m", 0, + GATE(SCLK_HDMI_SFC, "sclk_hdmi_sfc", "xin24m", 0, RK3328_CLKGATE_CON(5), 4, GFLAGS), COMPOSITE_NODIV(0, "clk_cif_src", mux_2plls_p, 0, -- cgit From 51a70dbf689c913ad6e8efc6917aa669bd57d339 Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Tue, 12 Dec 2017 22:49:11 +0100 Subject: clk: rockchip: protect all remaining rk3328 interconnect clocks NIU clocks are supplying the interconnect connections to specific peripherals and are currently not controlled in any way. So to prevent things falling apart at strange moments, mark all niu clocks as critical. Most of them where marked as CLK_IGNORE_UNUSED, but that doesn't help if a parent clock then gets disabled. Signed-off-by: Heiko Stuebner --- drivers/clk/rockchip/clk-rk3328.c | 56 ++++++++++++++++++++++++++------------- 1 file changed, 37 insertions(+), 19 deletions(-) diff --git a/drivers/clk/rockchip/clk-rk3328.c b/drivers/clk/rockchip/clk-rk3328.c index b7a28f2814e2..c5b381ab23b1 100644 --- a/drivers/clk/rockchip/clk-rk3328.c +++ b/drivers/clk/rockchip/clk-rk3328.c @@ -304,7 +304,7 @@ static struct rockchip_clk_branch rk3328_clk_branches[] __initdata = { COMPOSITE_NOMUX(0, "aclk_core", "armclk", CLK_IGNORE_UNUSED, RK3328_CLKSEL_CON(1), 4, 3, DFLAGS | CLK_DIVIDER_READ_ONLY, RK3328_CLKGATE_CON(7), 1, GFLAGS), - GATE(0, "aclk_core_niu", "aclk_core", CLK_IGNORE_UNUSED, + GATE(0, "aclk_core_niu", "aclk_core", 0, RK3328_CLKGATE_CON(13), 0, GFLAGS), GATE(0, "aclk_gic400", "aclk_core", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(13), 1, GFLAGS), @@ -318,7 +318,7 @@ static struct rockchip_clk_branch rk3328_clk_branches[] __initdata = { RK3328_CLKGATE_CON(6), 6, GFLAGS), GATE(ACLK_GPU, "aclk_gpu", "aclk_gpu_pre", CLK_SET_RATE_PARENT, RK3328_CLKGATE_CON(14), 0, GFLAGS), - GATE(0, "aclk_gpu_niu", "aclk_gpu_pre", CLK_IGNORE_UNUSED, + GATE(0, "aclk_gpu_niu", "aclk_gpu_pre", 0, RK3328_CLKGATE_CON(14), 1, GFLAGS), /* PD_DDR */ @@ -513,9 +513,9 @@ static struct rockchip_clk_branch rk3328_clk_branches[] __initdata = { RK3328_CLKGATE_CON(24), 0, GFLAGS), GATE(HCLK_RKVDEC, "hclk_rkvdec", "hclk_rkvdec_pre", CLK_SET_RATE_PARENT, RK3328_CLKGATE_CON(24), 1, GFLAGS), - GATE(0, "aclk_rkvdec_niu", "aclk_rkvdec_pre", CLK_IGNORE_UNUSED, + GATE(0, "aclk_rkvdec_niu", "aclk_rkvdec_pre", 0, RK3328_CLKGATE_CON(24), 2, GFLAGS), - GATE(0, "hclk_rkvdec_niu", "hclk_rkvdec_pre", CLK_IGNORE_UNUSED, + GATE(0, "hclk_rkvdec_niu", "hclk_rkvdec_pre", 0, RK3328_CLKGATE_CON(24), 3, GFLAGS), COMPOSITE(SCLK_VDEC_CABAC, "sclk_vdec_cabac", mux_4plls_p, 0, @@ -535,9 +535,9 @@ static struct rockchip_clk_branch rk3328_clk_branches[] __initdata = { RK3328_CLKGATE_CON(23), 0, GFLAGS), GATE(HCLK_VPU, "hclk_vpu", "hclk_vpu_pre", CLK_SET_RATE_PARENT, RK3328_CLKGATE_CON(23), 1, GFLAGS), - GATE(0, "aclk_vpu_niu", "aclk_vpu_pre", CLK_IGNORE_UNUSED, + GATE(0, "aclk_vpu_niu", "aclk_vpu_pre", 0, RK3328_CLKGATE_CON(23), 2, GFLAGS), - GATE(0, "hclk_vpu_niu", "hclk_vpu_pre", CLK_IGNORE_UNUSED, + GATE(0, "hclk_vpu_niu", "hclk_vpu_pre", 0, RK3328_CLKGATE_CON(23), 3, GFLAGS), COMPOSITE(ACLK_RKVENC, "aclk_rkvenc", mux_4plls_p, 0, @@ -545,9 +545,9 @@ static struct rockchip_clk_branch rk3328_clk_branches[] __initdata = { RK3328_CLKGATE_CON(6), 3, GFLAGS), FACTOR_GATE(HCLK_RKVENC, "hclk_rkvenc", "aclk_rkvenc", 0, 1, 4, RK3328_CLKGATE_CON(11), 4, GFLAGS), - GATE(0, "aclk_rkvenc_niu", "aclk_rkvenc", CLK_IGNORE_UNUSED, + GATE(0, "aclk_rkvenc_niu", "aclk_rkvenc", 0, RK3328_CLKGATE_CON(25), 0, GFLAGS), - GATE(0, "hclk_rkvenc_niu", "hclk_rkvenc", CLK_IGNORE_UNUSED, + GATE(0, "hclk_rkvenc_niu", "hclk_rkvenc", 0, RK3328_CLKGATE_CON(25), 1, GFLAGS), GATE(ACLK_H265, "aclk_h265", "aclk_rkvenc", 0, RK3328_CLKGATE_CON(25), 0, GFLAGS), @@ -709,14 +709,14 @@ static struct rockchip_clk_branch rk3328_clk_branches[] __initdata = { /* PD_VOP */ GATE(ACLK_RGA, "aclk_rga", "aclk_rga_pre", 0, RK3328_CLKGATE_CON(21), 10, GFLAGS), - GATE(0, "aclk_rga_niu", "aclk_rga_pre", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(22), 3, GFLAGS), + GATE(0, "aclk_rga_niu", "aclk_rga_pre", 0, RK3328_CLKGATE_CON(22), 3, GFLAGS), GATE(ACLK_VOP, "aclk_vop", "aclk_vop_pre", 0, RK3328_CLKGATE_CON(21), 2, GFLAGS), - GATE(0, "aclk_vop_niu", "aclk_vop_pre", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(21), 4, GFLAGS), + GATE(0, "aclk_vop_niu", "aclk_vop_pre", 0, RK3328_CLKGATE_CON(21), 4, GFLAGS), GATE(ACLK_IEP, "aclk_iep", "aclk_vio_pre", 0, RK3328_CLKGATE_CON(21), 6, GFLAGS), GATE(ACLK_CIF, "aclk_cif", "aclk_vio_pre", 0, RK3328_CLKGATE_CON(21), 8, GFLAGS), GATE(ACLK_HDCP, "aclk_hdcp", "aclk_vio_pre", 0, RK3328_CLKGATE_CON(21), 15, GFLAGS), - GATE(0, "aclk_vio_niu", "aclk_vio_pre", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(22), 2, GFLAGS), + GATE(0, "aclk_vio_niu", "aclk_vio_pre", 0, RK3328_CLKGATE_CON(22), 2, GFLAGS), GATE(HCLK_VOP, "hclk_vop", "hclk_vio_pre", 0, RK3328_CLKGATE_CON(21), 3, GFLAGS), GATE(0, "hclk_vop_niu", "hclk_vio_pre", 0, RK3328_CLKGATE_CON(21), 5, GFLAGS), @@ -743,19 +743,19 @@ static struct rockchip_clk_branch rk3328_clk_branches[] __initdata = { GATE(HCLK_HOST0_ARB, "hclk_host0_arb", "hclk_peri", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(19), 7, GFLAGS), GATE(HCLK_OTG, "hclk_otg", "hclk_peri", 0, RK3328_CLKGATE_CON(19), 8, GFLAGS), GATE(HCLK_OTG_PMU, "hclk_otg_pmu", "hclk_peri", 0, RK3328_CLKGATE_CON(19), 9, GFLAGS), - GATE(0, "hclk_peri_niu", "hclk_peri", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(19), 12, GFLAGS), - GATE(0, "pclk_peri_niu", "hclk_peri", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(19), 13, GFLAGS), + GATE(0, "hclk_peri_niu", "hclk_peri", 0, RK3328_CLKGATE_CON(19), 12, GFLAGS), + GATE(0, "pclk_peri_niu", "hclk_peri", 0, RK3328_CLKGATE_CON(19), 13, GFLAGS), /* PD_GMAC */ GATE(ACLK_MAC2PHY, "aclk_mac2phy", "aclk_gmac", 0, RK3328_CLKGATE_CON(26), 0, GFLAGS), GATE(ACLK_MAC2IO, "aclk_mac2io", "aclk_gmac", 0, RK3328_CLKGATE_CON(26), 2, GFLAGS), - GATE(0, "aclk_gmac_niu", "aclk_gmac", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(26), 4, GFLAGS), + GATE(0, "aclk_gmac_niu", "aclk_gmac", 0, RK3328_CLKGATE_CON(26), 4, GFLAGS), GATE(PCLK_MAC2PHY, "pclk_mac2phy", "pclk_gmac", 0, RK3328_CLKGATE_CON(26), 1, GFLAGS), GATE(PCLK_MAC2IO, "pclk_mac2io", "pclk_gmac", 0, RK3328_CLKGATE_CON(26), 3, GFLAGS), - GATE(0, "pclk_gmac_niu", "pclk_gmac", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(26), 5, GFLAGS), + GATE(0, "pclk_gmac_niu", "pclk_gmac", 0, RK3328_CLKGATE_CON(26), 5, GFLAGS), /* PD_BUS */ - GATE(0, "aclk_bus_niu", "aclk_bus_pre", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(15), 12, GFLAGS), + GATE(0, "aclk_bus_niu", "aclk_bus_pre", 0, RK3328_CLKGATE_CON(15), 12, GFLAGS), GATE(ACLK_DCF, "aclk_dcf", "aclk_bus_pre", 0, RK3328_CLKGATE_CON(15), 11, GFLAGS), GATE(ACLK_TSP, "aclk_tsp", "aclk_bus_pre", 0, RK3328_CLKGATE_CON(17), 12, GFLAGS), GATE(0, "aclk_intmem", "aclk_bus_pre", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(15), 0, GFLAGS), @@ -769,10 +769,10 @@ static struct rockchip_clk_branch rk3328_clk_branches[] __initdata = { GATE(HCLK_TSP, "hclk_tsp", "hclk_bus_pre", 0, RK3328_CLKGATE_CON(17), 11, GFLAGS), GATE(HCLK_CRYPTO_MST, "hclk_crypto_mst", "hclk_bus_pre", 0, RK3328_CLKGATE_CON(15), 7, GFLAGS), GATE(HCLK_CRYPTO_SLV, "hclk_crypto_slv", "hclk_bus_pre", 0, RK3328_CLKGATE_CON(15), 8, GFLAGS), - GATE(0, "hclk_bus_niu", "hclk_bus_pre", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(15), 13, GFLAGS), + GATE(0, "hclk_bus_niu", "hclk_bus_pre", 0, RK3328_CLKGATE_CON(15), 13, GFLAGS), GATE(HCLK_PDM, "hclk_pdm", "hclk_bus_pre", 0, RK3328_CLKGATE_CON(28), 0, GFLAGS), - GATE(0, "pclk_bus_niu", "pclk_bus", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(15), 14, GFLAGS), + GATE(0, "pclk_bus_niu", "pclk_bus", 0, RK3328_CLKGATE_CON(15), 14, GFLAGS), GATE(0, "pclk_efuse", "pclk_bus", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(15), 9, GFLAGS), GATE(0, "pclk_otp", "pclk_bus", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(28), 4, GFLAGS), GATE(PCLK_I2C0, "pclk_i2c0", "pclk_bus", 0, RK3328_CLKGATE_CON(15), 10, GFLAGS), @@ -807,7 +807,7 @@ static struct rockchip_clk_branch rk3328_clk_branches[] __initdata = { GATE(0, "pclk_acodecphy", "pclk_phy_pre", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(17), 5, GFLAGS), GATE(PCLK_HDMIPHY, "pclk_hdmiphy", "pclk_phy_pre", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(17), 7, GFLAGS), GATE(0, "pclk_vdacphy", "pclk_phy_pre", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(17), 8, GFLAGS), - GATE(0, "pclk_phy_niu", "pclk_phy_pre", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(15), 15, GFLAGS), + GATE(0, "pclk_phy_niu", "pclk_phy_pre", 0, RK3328_CLKGATE_CON(15), 15, GFLAGS), /* PD_MMC */ MMC(SCLK_SDMMC_DRV, "sdmmc_drv", "sclk_sdmmc", @@ -833,11 +833,16 @@ static struct rockchip_clk_branch rk3328_clk_branches[] __initdata = { static const char *const rk3328_critical_clocks[] __initconst = { "aclk_bus", + "aclk_bus_niu", "pclk_bus", + "pclk_bus_niu", "hclk_bus", + "hclk_bus_niu", "aclk_peri", "hclk_peri", + "hclk_peri_niu", "pclk_peri", + "pclk_peri_niu", "pclk_dbg", "aclk_core_niu", "aclk_gic400", @@ -861,7 +866,20 @@ static const char *const rk3328_critical_clocks[] __initconst = { "aclk_rga_niu", "pclk_vio_h2p", "hclk_vio_h2p", + "aclk_vio_niu", "hclk_vio_niu", + "aclk_vop_niu", + "hclk_vop_niu", + "aclk_gpu_niu", + "aclk_rkvdec_niu", + "hclk_rkvdec_niu", + "aclk_vpu_niu", + "hclk_vpu_niu", + "aclk_rkvenc_niu", + "hclk_rkvenc_niu", + "aclk_gmac_niu", + "pclk_gmac_niu", + "pclk_phy_niu", }; static void __init rk3328_clk_init(struct device_node *np) -- cgit From 7f872cb362d312b0b75975441b3717253e323b81 Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Sat, 23 Dec 2017 16:30:19 +0100 Subject: clk: rockchip: remove ignore_unused flag from rk3328 vio_h2p clocks These are already marked as critical, so there is no need for an additional ignore_unused flag. Signed-off-by: Heiko Stuebner --- drivers/clk/rockchip/clk-rk3328.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/clk/rockchip/clk-rk3328.c b/drivers/clk/rockchip/clk-rk3328.c index c5b381ab23b1..983ad5760ce0 100644 --- a/drivers/clk/rockchip/clk-rk3328.c +++ b/drivers/clk/rockchip/clk-rk3328.c @@ -724,8 +724,8 @@ static struct rockchip_clk_branch rk3328_clk_branches[] __initdata = { GATE(HCLK_CIF, "hclk_cif", "hclk_vio_pre", 0, RK3328_CLKGATE_CON(21), 9, GFLAGS), GATE(HCLK_RGA, "hclk_rga", "hclk_vio_pre", 0, RK3328_CLKGATE_CON(21), 11, GFLAGS), GATE(0, "hclk_ahb1tom", "hclk_vio_pre", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(21), 12, GFLAGS), - GATE(0, "pclk_vio_h2p", "hclk_vio_pre", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(21), 13, GFLAGS), - GATE(0, "hclk_vio_h2p", "hclk_vio_pre", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(21), 14, GFLAGS), + GATE(0, "pclk_vio_h2p", "hclk_vio_pre", 0, RK3328_CLKGATE_CON(21), 13, GFLAGS), + GATE(0, "hclk_vio_h2p", "hclk_vio_pre", 0, RK3328_CLKGATE_CON(21), 14, GFLAGS), GATE(HCLK_HDCP, "hclk_hdcp", "hclk_vio_pre", 0, RK3328_CLKGATE_CON(22), 0, GFLAGS), GATE(0, "hclk_vio_niu", "hclk_vio_pre", 0, RK3328_CLKGATE_CON(22), 1, GFLAGS), GATE(PCLK_HDMI, "pclk_hdmi", "hclk_vio_pre", 0, RK3328_CLKGATE_CON(22), 4, GFLAGS), -- cgit From 36ec03618c12ad3308f7a80994ee4b2129a1e381 Mon Sep 17 00:00:00 2001 From: Zheng Yang Date: Thu, 25 May 2017 18:00:24 +0800 Subject: clk: rockchip: add flags for rk3328 dclk_lcdc dclk_lcdc can be sourced from a general pll source as well as the hdmiphy's pll output. We will want to set this source by hand (to the system-pll-source in most cases) and also want rate changes to this clock to be able to also touch the pll source clock if needed, so add CLK_SET_RATE_PARENT and CLK_SET_RATE_NO_REPARENT for dclk_lcdc. Signed-off-by: Zheng Yang [ammended commit message] Signed-off-by: Heiko Stuebner --- drivers/clk/rockchip/clk-rk3328.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/rockchip/clk-rk3328.c b/drivers/clk/rockchip/clk-rk3328.c index 983ad5760ce0..f680b421b6d5 100644 --- a/drivers/clk/rockchip/clk-rk3328.c +++ b/drivers/clk/rockchip/clk-rk3328.c @@ -602,7 +602,7 @@ static struct rockchip_clk_branch rk3328_clk_branches[] __initdata = { RK3328_CLKGATE_CON(5), 6, GFLAGS), DIV(DCLK_HDMIPHY, "dclk_hdmiphy", "dclk_lcdc_src", 0, RK3328_CLKSEL_CON(40), 3, 3, DFLAGS), - MUX(DCLK_LCDC, "dclk_lcdc", mux_dclk_lcdc_p, 0, + MUX(DCLK_LCDC, "dclk_lcdc", mux_dclk_lcdc_p, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, RK3328_CLKSEL_CON(40), 1, 1, MFLAGS), /* -- cgit From dd5bdb797f0a6e0d3d2aa86af60f92b094705d24 Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Mon, 25 Dec 2017 17:36:00 +0100 Subject: clk: rockchip: document hdmi_phy external input for rk3328 The hdmi-phy block inside the soc also loops its pll output back into the clock controller, so document that already used input clock. Signed-off-by: Heiko Stuebner Reviewed-by: Rob Herring --- Documentation/devicetree/bindings/clock/rockchip,rk3328-cru.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/clock/rockchip,rk3328-cru.txt b/Documentation/devicetree/bindings/clock/rockchip,rk3328-cru.txt index e71c675ba5da..904ae682ea90 100644 --- a/Documentation/devicetree/bindings/clock/rockchip,rk3328-cru.txt +++ b/Documentation/devicetree/bindings/clock/rockchip,rk3328-cru.txt @@ -32,6 +32,7 @@ clock-output-names: - "clkin_i2s" - external I2S clock - optional, - "gmac_clkin" - external GMAC clock - optional - "phy_50m_out" - output clock of the pll in the mac phy + - "hdmi_phy" - output clock of the hdmi phy pll - optional Example: Clock controller node: -- cgit From f1a2879c1c57eb40747db3ff1b7b80cb9041e11b Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 25 Apr 2017 14:04:35 +0200 Subject: clk: renesas: Stop enabling legacy DT clock support by default Since v4.15-rc1, the DTS files for all R-Car Gen2 SoCs have been converted to the new CPG/MSSR bindings. Hence it is now safe to no longer enable legacy DT clock support by default. Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/clk/renesas/Kconfig b/drivers/clk/renesas/Kconfig index 43b5a89c4b28..84b40b95ca0e 100644 --- a/drivers/clk/renesas/Kconfig +++ b/drivers/clk/renesas/Kconfig @@ -24,12 +24,13 @@ if CLK_RENESAS config CLK_RENESAS_LEGACY bool "Legacy DT clock support" depends on CLK_R8A7790 || CLK_R8A7791 || CLK_R8A7792 || CLK_R8A7794 - default y help Enable backward compatibility with old device trees describing a hierarchical representation of the various CPG and MSTP clocks. Say Y if you want your kernel to work with old DTBs. + It is safe to say N if you use the DTS that is supplied with the + current kernel source tree. # SoC config CLK_EMEV2 -- cgit From 3391891fa9c82fd14bcddec2f422299b57ce8091 Mon Sep 17 00:00:00 2001 From: Takeshi Kihara Date: Mon, 29 Jan 2018 19:01:49 +0100 Subject: clk: renesas: rcar-gen3: Add Z clock divider support This patch adds Z clock divider support for R-Car Gen3 SoC. Signed-off-by: Takeshi Kihara Signed-off-by: Simon Horman Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/rcar-gen3-cpg.c | 133 ++++++++++++++++++++++++++++++++++++ drivers/clk/renesas/rcar-gen3-cpg.h | 1 + 2 files changed, 134 insertions(+) diff --git a/drivers/clk/renesas/rcar-gen3-cpg.c b/drivers/clk/renesas/rcar-gen3-cpg.c index 0904886f5501..b85918fa62c6 100644 --- a/drivers/clk/renesas/rcar-gen3-cpg.c +++ b/drivers/clk/renesas/rcar-gen3-cpg.c @@ -13,6 +13,7 @@ */ #include +#include #include #include #include @@ -61,6 +62,134 @@ static void cpg_simple_notifier_register(struct raw_notifier_head *notifiers, raw_notifier_chain_register(notifiers, &csn->nb); } +/* + * Z Clock + * + * Traits of this clock: + * prepare - clk_prepare only ensures that parents are prepared + * enable - clk_enable only ensures that parents are enabled + * rate - rate is adjustable. clk->rate = (parent->rate * mult / 32 ) / 2 + * parent - fixed parent. No clk_set_parent support + */ +#define CPG_FRQCRB 0x00000004 +#define CPG_FRQCRB_KICK BIT(31) +#define CPG_FRQCRC 0x000000e0 +#define CPG_FRQCRC_ZFC_MASK GENMASK(12, 8) + +struct cpg_z_clk { + struct clk_hw hw; + void __iomem *reg; + void __iomem *kick_reg; +}; + +#define to_z_clk(_hw) container_of(_hw, struct cpg_z_clk, hw) + +static unsigned long cpg_z_clk_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct cpg_z_clk *zclk = to_z_clk(hw); + unsigned int mult; + + mult = 32 - FIELD_GET(CPG_FRQCRC_ZFC_MASK, clk_readl(zclk->reg)); + + /* Factor of 2 is for fixed divider */ + return DIV_ROUND_CLOSEST_ULL((u64)parent_rate * mult, 32 * 2); +} + +static long cpg_z_clk_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + /* Factor of 2 is for fixed divider */ + unsigned long prate = *parent_rate / 2; + unsigned int mult; + + mult = div_u64(rate * 32ULL, prate); + mult = clamp(mult, 1U, 32U); + + return (u64)prate * mult / 32; +} + +static int cpg_z_clk_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct cpg_z_clk *zclk = to_z_clk(hw); + unsigned int mult; + unsigned int i; + u32 val, kick; + + /* Factor of 2 is for fixed divider */ + mult = DIV_ROUND_CLOSEST_ULL(rate * 32ULL * 2, parent_rate); + mult = clamp(mult, 1U, 32U); + + if (clk_readl(zclk->kick_reg) & CPG_FRQCRB_KICK) + return -EBUSY; + + val = clk_readl(zclk->reg) & ~CPG_FRQCRC_ZFC_MASK; + val |= FIELD_PREP(CPG_FRQCRC_ZFC_MASK, 32 - mult); + clk_writel(val, zclk->reg); + + /* + * Set KICK bit in FRQCRB to update hardware setting and wait for + * clock change completion. + */ + kick = clk_readl(zclk->kick_reg); + kick |= CPG_FRQCRB_KICK; + clk_writel(kick, zclk->kick_reg); + + /* + * Note: There is no HW information about the worst case latency. + * + * Using experimental measurements, it seems that no more than + * ~10 iterations are needed, independently of the CPU rate. + * Since this value might be dependent of external xtal rate, pll1 + * rate or even the other emulation clocks rate, use 1000 as a + * "super" safe value. + */ + for (i = 1000; i; i--) { + if (!(clk_readl(zclk->kick_reg) & CPG_FRQCRB_KICK)) + return 0; + + cpu_relax(); + } + + return -ETIMEDOUT; +} + +static const struct clk_ops cpg_z_clk_ops = { + .recalc_rate = cpg_z_clk_recalc_rate, + .round_rate = cpg_z_clk_round_rate, + .set_rate = cpg_z_clk_set_rate, +}; + +static struct clk * __init cpg_z_clk_register(const char *name, + const char *parent_name, + void __iomem *reg) +{ + struct clk_init_data init; + struct cpg_z_clk *zclk; + struct clk *clk; + + zclk = kzalloc(sizeof(*zclk), GFP_KERNEL); + if (!zclk) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.ops = &cpg_z_clk_ops; + init.flags = 0; + init.parent_names = &parent_name; + init.num_parents = 1; + + zclk->reg = reg + CPG_FRQCRC; + zclk->kick_reg = reg + CPG_FRQCRB; + zclk->hw.init = &init; + + clk = clk_register(NULL, &zclk->hw); + if (IS_ERR(clk)) + kfree(zclk); + + return clk; +} + /* * SDn Clock */ @@ -420,6 +549,10 @@ struct clk * __init rcar_gen3_cpg_clk_register(struct device *dev, mult = 1; break; + case CLK_TYPE_GEN3_Z: + return cpg_z_clk_register(core->name, __clk_get_name(parent), + base); + default: return ERR_PTR(-EINVAL); } diff --git a/drivers/clk/renesas/rcar-gen3-cpg.h b/drivers/clk/renesas/rcar-gen3-cpg.h index 2e4284399f53..c73d4d6fdc85 100644 --- a/drivers/clk/renesas/rcar-gen3-cpg.h +++ b/drivers/clk/renesas/rcar-gen3-cpg.h @@ -21,6 +21,7 @@ enum rcar_gen3_clk_types { CLK_TYPE_GEN3_SD, CLK_TYPE_GEN3_R, CLK_TYPE_GEN3_PE, + CLK_TYPE_GEN3_Z, }; #define DEF_GEN3_SD(_name, _id, _parent, _offset) \ -- cgit From 41ceeb5fef7719474a17a5a6052cae5b6c9e37c0 Mon Sep 17 00:00:00 2001 From: Takeshi Kihara Date: Mon, 29 Jan 2018 19:01:50 +0100 Subject: clk: renesas: rcar-gen3: Add Z2 clock divider support This patch adds Z2 clock divider support for R-Car Gen3 SoC. Signed-off-by: Takeshi Kihara Signed-off-by: Simon Horman Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/rcar-gen3-cpg.c | 22 ++++++++++++++++------ drivers/clk/renesas/rcar-gen3-cpg.h | 1 + 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/drivers/clk/renesas/rcar-gen3-cpg.c b/drivers/clk/renesas/rcar-gen3-cpg.c index b85918fa62c6..0c8fe10d57fe 100644 --- a/drivers/clk/renesas/rcar-gen3-cpg.c +++ b/drivers/clk/renesas/rcar-gen3-cpg.c @@ -63,7 +63,7 @@ static void cpg_simple_notifier_register(struct raw_notifier_head *notifiers, } /* - * Z Clock + * Z Clock & Z2 Clock * * Traits of this clock: * prepare - clk_prepare only ensures that parents are prepared @@ -75,11 +75,13 @@ static void cpg_simple_notifier_register(struct raw_notifier_head *notifiers, #define CPG_FRQCRB_KICK BIT(31) #define CPG_FRQCRC 0x000000e0 #define CPG_FRQCRC_ZFC_MASK GENMASK(12, 8) +#define CPG_FRQCRC_Z2FC_MASK GENMASK(4, 0) struct cpg_z_clk { struct clk_hw hw; void __iomem *reg; void __iomem *kick_reg; + unsigned long mask; }; #define to_z_clk(_hw) container_of(_hw, struct cpg_z_clk, hw) @@ -89,8 +91,10 @@ static unsigned long cpg_z_clk_recalc_rate(struct clk_hw *hw, { struct cpg_z_clk *zclk = to_z_clk(hw); unsigned int mult; + u32 val; - mult = 32 - FIELD_GET(CPG_FRQCRC_ZFC_MASK, clk_readl(zclk->reg)); + val = clk_readl(zclk->reg) & zclk->mask; + mult = 32 - (val >> __ffs(zclk->mask)); /* Factor of 2 is for fixed divider */ return DIV_ROUND_CLOSEST_ULL((u64)parent_rate * mult, 32 * 2); @@ -124,8 +128,8 @@ static int cpg_z_clk_set_rate(struct clk_hw *hw, unsigned long rate, if (clk_readl(zclk->kick_reg) & CPG_FRQCRB_KICK) return -EBUSY; - val = clk_readl(zclk->reg) & ~CPG_FRQCRC_ZFC_MASK; - val |= FIELD_PREP(CPG_FRQCRC_ZFC_MASK, 32 - mult); + val = clk_readl(zclk->reg) & ~zclk->mask; + val |= ((32 - mult) << __ffs(zclk->mask)) & zclk->mask; clk_writel(val, zclk->reg); /* @@ -163,7 +167,8 @@ static const struct clk_ops cpg_z_clk_ops = { static struct clk * __init cpg_z_clk_register(const char *name, const char *parent_name, - void __iomem *reg) + void __iomem *reg, + unsigned long mask) { struct clk_init_data init; struct cpg_z_clk *zclk; @@ -182,6 +187,7 @@ static struct clk * __init cpg_z_clk_register(const char *name, zclk->reg = reg + CPG_FRQCRC; zclk->kick_reg = reg + CPG_FRQCRB; zclk->hw.init = &init; + zclk->mask = mask; clk = clk_register(NULL, &zclk->hw); if (IS_ERR(clk)) @@ -551,7 +557,11 @@ struct clk * __init rcar_gen3_cpg_clk_register(struct device *dev, case CLK_TYPE_GEN3_Z: return cpg_z_clk_register(core->name, __clk_get_name(parent), - base); + base, CPG_FRQCRC_ZFC_MASK); + + case CLK_TYPE_GEN3_Z2: + return cpg_z_clk_register(core->name, __clk_get_name(parent), + base, CPG_FRQCRC_Z2FC_MASK); default: return ERR_PTR(-EINVAL); diff --git a/drivers/clk/renesas/rcar-gen3-cpg.h b/drivers/clk/renesas/rcar-gen3-cpg.h index c73d4d6fdc85..ea4f8fc3c4c9 100644 --- a/drivers/clk/renesas/rcar-gen3-cpg.h +++ b/drivers/clk/renesas/rcar-gen3-cpg.h @@ -22,6 +22,7 @@ enum rcar_gen3_clk_types { CLK_TYPE_GEN3_R, CLK_TYPE_GEN3_PE, CLK_TYPE_GEN3_Z, + CLK_TYPE_GEN3_Z2, }; #define DEF_GEN3_SD(_name, _id, _parent, _offset) \ -- cgit From 4003508b4f233104a17150463604dc9c36833815 Mon Sep 17 00:00:00 2001 From: Takeshi Kihara Date: Mon, 29 Jan 2018 19:01:51 +0100 Subject: clk: renesas: r8a7795: Add Z clock This patch adds Z clock for R8A7795 SoC. Signed-off-by: Takeshi Kihara Signed-off-by: Simon Horman Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/r8a7795-cpg-mssr.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/renesas/r8a7795-cpg-mssr.c b/drivers/clk/renesas/r8a7795-cpg-mssr.c index b1d9f48eae9e..995a4c4fb01e 100644 --- a/drivers/clk/renesas/r8a7795-cpg-mssr.c +++ b/drivers/clk/renesas/r8a7795-cpg-mssr.c @@ -74,6 +74,7 @@ static struct cpg_core_clk r8a7795_core_clks[] __initdata = { DEF_FIXED(".sdsrc", CLK_SDSRC, CLK_PLL1_DIV2, 2, 1), /* Core Clock Outputs */ + DEF_BASE("z", R8A7795_CLK_Z, CLK_TYPE_GEN3_Z, CLK_PLL0), DEF_FIXED("ztr", R8A7795_CLK_ZTR, CLK_PLL1_DIV2, 6, 1), DEF_FIXED("ztrd2", R8A7795_CLK_ZTRD2, CLK_PLL1_DIV2, 12, 1), DEF_FIXED("zt", R8A7795_CLK_ZT, CLK_PLL1_DIV2, 4, 1), -- cgit From 1eadca3557f77afbb64100e077f48ac338d731dc Mon Sep 17 00:00:00 2001 From: Takeshi Kihara Date: Mon, 29 Jan 2018 19:01:52 +0100 Subject: clk: renesas: r8a7795: Add Z2 clock This patch adds Z2 clock for r8a7795 SoC. Signed-off-by: Takeshi Kihara Signed-off-by: Simon Horman Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/r8a7795-cpg-mssr.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/renesas/r8a7795-cpg-mssr.c b/drivers/clk/renesas/r8a7795-cpg-mssr.c index 995a4c4fb01e..775b0ceaa337 100644 --- a/drivers/clk/renesas/r8a7795-cpg-mssr.c +++ b/drivers/clk/renesas/r8a7795-cpg-mssr.c @@ -75,6 +75,7 @@ static struct cpg_core_clk r8a7795_core_clks[] __initdata = { /* Core Clock Outputs */ DEF_BASE("z", R8A7795_CLK_Z, CLK_TYPE_GEN3_Z, CLK_PLL0), + DEF_BASE("z2", R8A7795_CLK_Z2, CLK_TYPE_GEN3_Z2, CLK_PLL2), DEF_FIXED("ztr", R8A7795_CLK_ZTR, CLK_PLL1_DIV2, 6, 1), DEF_FIXED("ztrd2", R8A7795_CLK_ZTRD2, CLK_PLL1_DIV2, 12, 1), DEF_FIXED("zt", R8A7795_CLK_ZT, CLK_PLL1_DIV2, 4, 1), -- cgit From 72f2a6b31544da1978ab9fb032d0e17ded4af4a7 Mon Sep 17 00:00:00 2001 From: Takeshi Kihara Date: Mon, 29 Jan 2018 19:01:53 +0100 Subject: clk: renesas: r8a7796: Add Z clock This patch adds Z clock for R8A7796 SoC. Signed-off-by: Takeshi Kihara Signed-off-by: Simon Horman Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/r8a7796-cpg-mssr.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/renesas/r8a7796-cpg-mssr.c b/drivers/clk/renesas/r8a7796-cpg-mssr.c index 41e29734126b..799a9e574e79 100644 --- a/drivers/clk/renesas/r8a7796-cpg-mssr.c +++ b/drivers/clk/renesas/r8a7796-cpg-mssr.c @@ -74,6 +74,7 @@ static const struct cpg_core_clk r8a7796_core_clks[] __initconst = { DEF_FIXED(".sdsrc", CLK_SDSRC, CLK_PLL1_DIV2, 2, 1), /* Core Clock Outputs */ + DEF_BASE("z", R8A7796_CLK_Z, CLK_TYPE_GEN3_Z, CLK_PLL0), DEF_FIXED("ztr", R8A7796_CLK_ZTR, CLK_PLL1_DIV2, 6, 1), DEF_FIXED("ztrd2", R8A7796_CLK_ZTRD2, CLK_PLL1_DIV2, 12, 1), DEF_FIXED("zt", R8A7796_CLK_ZT, CLK_PLL1_DIV2, 4, 1), -- cgit From c50378efa9aa16acfe16d7313d29a874c2c86e5e Mon Sep 17 00:00:00 2001 From: Takeshi Kihara Date: Mon, 29 Jan 2018 19:01:54 +0100 Subject: clk: renesas: r8a7796: Add Z2 clock This patch adds Z2 clock for R8A7796 SoC. Signed-off-by: Takeshi Kihara Signed-off-by: Simon Horman Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/r8a7796-cpg-mssr.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/renesas/r8a7796-cpg-mssr.c b/drivers/clk/renesas/r8a7796-cpg-mssr.c index 799a9e574e79..dfb267a92f2a 100644 --- a/drivers/clk/renesas/r8a7796-cpg-mssr.c +++ b/drivers/clk/renesas/r8a7796-cpg-mssr.c @@ -75,6 +75,7 @@ static const struct cpg_core_clk r8a7796_core_clks[] __initconst = { /* Core Clock Outputs */ DEF_BASE("z", R8A7796_CLK_Z, CLK_TYPE_GEN3_Z, CLK_PLL0), + DEF_BASE("z2", R8A7796_CLK_Z2, CLK_TYPE_GEN3_Z2, CLK_PLL2), DEF_FIXED("ztr", R8A7796_CLK_ZTR, CLK_PLL1_DIV2, 6, 1), DEF_FIXED("ztrd2", R8A7796_CLK_ZTRD2, CLK_PLL1_DIV2, 12, 1), DEF_FIXED("zt", R8A7796_CLK_ZT, CLK_PLL1_DIV2, 4, 1), -- cgit From 75af6fa42dc68b730e85f51034512c61e52eb0c0 Mon Sep 17 00:00:00 2001 From: Corentin Labbe Date: Fri, 19 Jan 2018 15:19:06 +0100 Subject: clk: sunxi-ng: remove select on obsolete SUNXI_CCU_X kconfig name The following symbols: SUNXI_CCU_DIV SUNXI_CCU_MULT SUNXI_CCU_NK SUNXI_CCU_NKM SUNXI_CCU_NM SUNXI_CCU_MP SUNXI_CCU_PHASE were removed with the commit 06e226c7fb23 ("clk: sunxi-ng: Move all clock types to a library") So selecting them is useless. Fixes: c84f5683f6e9 ("clk: sunxi-ng: Add sun4i/sun7i CCU driver") Signed-off-by: Corentin Labbe Signed-off-by: Maxime Ripard --- drivers/clk/sunxi-ng/Kconfig | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/clk/sunxi-ng/Kconfig b/drivers/clk/sunxi-ng/Kconfig index 6427d0ebe2de..33168f94ee39 100644 --- a/drivers/clk/sunxi-ng/Kconfig +++ b/drivers/clk/sunxi-ng/Kconfig @@ -13,13 +13,6 @@ config SUN50I_A64_CCU config SUN4I_A10_CCU bool "Support for the Allwinner A10/A20 CCU" - select SUNXI_CCU_DIV - select SUNXI_CCU_MULT - select SUNXI_CCU_NK - select SUNXI_CCU_NKM - select SUNXI_CCU_NM - select SUNXI_CCU_MP - select SUNXI_CCU_PHASE default MACH_SUN4I default MACH_SUN7I depends on MACH_SUN4I || MACH_SUN7I || COMPILE_TEST -- cgit From 35615917ef027386a9acbe3cd8752f02b125b074 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Mon, 27 Nov 2017 11:31:48 +0900 Subject: clk: samsung: s3c: Remove unneeded enumeration This patch just removes the unneeded enumeration for PLL index. Signed-off-by: Chanwoo Choi Signed-off-by: Sylwester Nawrocki --- drivers/clk/samsung/clk-s3c2412.c | 11 ++--------- drivers/clk/samsung/clk-s3c2443.c | 17 ++++------------- drivers/clk/samsung/clk-s3c64xx.c | 17 ++++++----------- 3 files changed, 12 insertions(+), 33 deletions(-) diff --git a/drivers/clk/samsung/clk-s3c2412.c b/drivers/clk/samsung/clk-s3c2412.c index b8340a49921b..1555e407529e 100644 --- a/drivers/clk/samsung/clk-s3c2412.c +++ b/drivers/clk/samsung/clk-s3c2412.c @@ -27,11 +27,6 @@ #define CLKSRC 0x1c #define SWRST 0x30 -/* list of PLLs to be registered */ -enum s3c2412_plls { - mpll, upll, -}; - static void __iomem *reg_base; #ifdef CONFIG_PM_SLEEP @@ -144,10 +139,8 @@ struct samsung_mux_clock s3c2412_muxes[] __initdata = { }; static struct samsung_pll_clock s3c2412_plls[] __initdata = { - [mpll] = PLL(pll_s3c2440_mpll, MPLL, "mpll", "xti", - LOCKTIME, MPLLCON, NULL), - [upll] = PLL(pll_s3c2410_upll, UPLL, "upll", "urefclk", - LOCKTIME, UPLLCON, NULL), + PLL(pll_s3c2440_mpll, MPLL, "mpll", "xti", LOCKTIME, MPLLCON, NULL), + PLL(pll_s3c2410_upll, UPLL, "upll", "urefclk", LOCKTIME, UPLLCON, NULL), }; struct samsung_gate_clock s3c2412_gates[] __initdata = { diff --git a/drivers/clk/samsung/clk-s3c2443.c b/drivers/clk/samsung/clk-s3c2443.c index d94b85a42356..9580a6baf4d7 100644 --- a/drivers/clk/samsung/clk-s3c2443.c +++ b/drivers/clk/samsung/clk-s3c2443.c @@ -41,11 +41,6 @@ enum supported_socs { S3C2450, }; -/* list of PLLs to be registered */ -enum s3c2443_plls { - mpll, epll, -}; - static void __iomem *reg_base; #ifdef CONFIG_PM_SLEEP @@ -225,10 +220,8 @@ struct samsung_clock_alias s3c2443_common_aliases[] __initdata = { /* S3C2416 specific clocks */ static struct samsung_pll_clock s3c2416_pll_clks[] __initdata = { - [mpll] = PLL(pll_6552_s3c2416, MPLL, "mpll", "mpllref", - LOCKCON0, MPLLCON, NULL), - [epll] = PLL(pll_6553, EPLL, "epll", "epllref", - LOCKCON1, EPLLCON, NULL), + PLL(pll_6552_s3c2416, MPLL, "mpll", "mpllref", LOCKCON0, MPLLCON, NULL), + PLL(pll_6553, EPLL, "epll", "epllref", LOCKCON1, EPLLCON, NULL), }; PNAME(s3c2416_hsmmc0_p) = { "sclk_hsmmc0", "sclk_hsmmcext" }; @@ -279,10 +272,8 @@ struct samsung_clock_alias s3c2416_aliases[] __initdata = { /* S3C2443 specific clocks */ static struct samsung_pll_clock s3c2443_pll_clks[] __initdata = { - [mpll] = PLL(pll_3000, MPLL, "mpll", "mpllref", - LOCKCON0, MPLLCON, NULL), - [epll] = PLL(pll_2126, EPLL, "epll", "epllref", - LOCKCON1, EPLLCON, NULL), + PLL(pll_3000, MPLL, "mpll", "mpllref", LOCKCON0, MPLLCON, NULL), + PLL(pll_2126, EPLL, "epll", "epllref", LOCKCON1, EPLLCON, NULL), }; static struct clk_div_table armdiv_s3c2443_d[] = { diff --git a/drivers/clk/samsung/clk-s3c64xx.c b/drivers/clk/samsung/clk-s3c64xx.c index 7306867a0ab8..6db01cf5ab83 100644 --- a/drivers/clk/samsung/clk-s3c64xx.c +++ b/drivers/clk/samsung/clk-s3c64xx.c @@ -56,11 +56,6 @@ #define GATE_ON(_id, cname, pname, o, b) \ GATE(_id, cname, pname, o, b, CLK_IGNORE_UNUSED, 0) -/* list of PLLs to be registered */ -enum s3c64xx_plls { - apll, mpll, epll, -}; - static void __iomem *reg_base; static bool is_s3c6400; @@ -364,12 +359,12 @@ GATE_CLOCKS(s3c6410_gate_clks) __initdata = { /* List of PLL clocks. */ static struct samsung_pll_clock s3c64xx_pll_clks[] __initdata = { - [apll] = PLL(pll_6552, FOUT_APLL, "fout_apll", "fin_pll", - APLL_LOCK, APLL_CON, NULL), - [mpll] = PLL(pll_6552, FOUT_MPLL, "fout_mpll", "fin_pll", - MPLL_LOCK, MPLL_CON, NULL), - [epll] = PLL(pll_6553, FOUT_EPLL, "fout_epll", "fin_pll", - EPLL_LOCK, EPLL_CON0, NULL), + PLL(pll_6552, FOUT_APLL, "fout_apll", "fin_pll", + APLL_LOCK, APLL_CON, NULL), + PLL(pll_6552, FOUT_MPLL, "fout_mpll", "fin_pll", + MPLL_LOCK, MPLL_CON, NULL), + PLL(pll_6553, FOUT_EPLL, "fout_epll", "fin_pll", + EPLL_LOCK, EPLL_CON0, NULL), }; /* Aliases for common s3c64xx clocks. */ -- cgit From a3834c76a24c379347ea7ee316a9154178f98f4d Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Wed, 17 Jan 2018 11:26:27 +0000 Subject: clk: samsung: Remove redundant dev_err call in exynos5433_cmu_probe() There is a error message within devm_ioremap_resource already, so remove the dev_err call to avoid redundant error message. Signed-off-by: Wei Yongjun Signed-off-by: Sylwester Nawrocki --- drivers/clk/samsung/clk-exynos5433.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/clk/samsung/clk-exynos5433.c b/drivers/clk/samsung/clk-exynos5433.c index db270908037a..9323e6b7eed5 100644 --- a/drivers/clk/samsung/clk-exynos5433.c +++ b/drivers/clk/samsung/clk-exynos5433.c @@ -5513,10 +5513,8 @@ static int __init exynos5433_cmu_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); reg_base = devm_ioremap_resource(dev, res); - if (IS_ERR(reg_base)) { - dev_err(dev, "failed to map registers\n"); + if (IS_ERR(reg_base)) return PTR_ERR(reg_base); - } for (i = 0; i < info->nr_clk_ids; ++i) ctx->clk_data.hws[i] = ERR_PTR(-ENOENT); -- cgit From 073f698dbe6bb37b226c22ac8dc69d567a08f4cb Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Wed, 17 Jan 2018 11:26:18 +0000 Subject: clk: samsung: Remove redundant dev_err call in exynos_audss_clk_probe() There is a error message within devm_ioremap_resource already, so remove the dev_err call to avoid redundant error message. Signed-off-by: Wei Yongjun Signed-off-by: Sylwester Nawrocki --- drivers/clk/samsung/clk-exynos-audss.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/clk/samsung/clk-exynos-audss.c b/drivers/clk/samsung/clk-exynos-audss.c index 5bfc92ee3129..b4b057c7301c 100644 --- a/drivers/clk/samsung/clk-exynos-audss.c +++ b/drivers/clk/samsung/clk-exynos-audss.c @@ -143,10 +143,8 @@ static int exynos_audss_clk_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); reg_base = devm_ioremap_resource(dev, res); - if (IS_ERR(reg_base)) { - dev_err(dev, "failed to map audss registers\n"); + if (IS_ERR(reg_base)) return PTR_ERR(reg_base); - } epll = ERR_PTR(-ENODEV); -- cgit From c99fc5a352b24397f50e6e71d26d4e95c2cce776 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Mon, 5 Feb 2018 15:41:58 +0100 Subject: clk: samsung: Add a git tree entry to MAINTAINERS Add a missing git tree entry for drivers/clk/samsung. Signed-off-by: Sylwester Nawrocki Acked-by: Krzysztof Kozlowski Acked-by: Chanwoo Choi --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 3bdc260e36b7..395ea06c427d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -12189,6 +12189,7 @@ M: Tomasz Figa M: Chanwoo Choi S: Supported L: linux-samsung-soc@vger.kernel.org (moderated for non-subscribers) +T: git git://git.kernel.org/pub/scm/linux/kernel/git/snawrocki/clk.git F: drivers/clk/samsung/ F: include/dt-bindings/clock/exynos*.h F: Documentation/devicetree/bindings/clock/exynos*.txt -- cgit From 5c7979246ead98a7269f418d81a637dd056a1be7 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Mon, 5 Feb 2018 15:22:30 +0100 Subject: clk: exynos5433: Add CLK_IGNORE_UNUSED flag to sclk_ioclk_i2s1_bclk The sclk_ioclk_i2s1_bclk clock is not currently handled by any driver and disabling this clock by the clk core prevents proper operation of the I2S1 block. CLK_IGNORE_UNUSED flag is added as a temporary fix. Signed-off-by: Sylwester Nawrocki Reviewed-by: Chanwoo Choi --- drivers/clk/samsung/clk-exynos5433.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/samsung/clk-exynos5433.c b/drivers/clk/samsung/clk-exynos5433.c index 9323e6b7eed5..c84326dc4b05 100644 --- a/drivers/clk/samsung/clk-exynos5433.c +++ b/drivers/clk/samsung/clk-exynos5433.c @@ -1672,7 +1672,7 @@ static const struct samsung_gate_clock peric_gate_clks[] __initconst = { ENABLE_SCLK_PERIC, 11, CLK_SET_RATE_PARENT, 0), GATE(CLK_SCLK_IOCLK_I2S1_BCLK, "sclk_ioclk_i2s1_bclk", "ioclk_i2s1_bclk_in", ENABLE_SCLK_PERIC, 10, - CLK_SET_RATE_PARENT, 0), + CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0), GATE(CLK_SCLK_SPDIF, "sclk_spdif", "sclk_spdif_peric", ENABLE_SCLK_PERIC, 8, CLK_SET_RATE_PARENT, 0), GATE(CLK_SCLK_PCM1, "sclk_pcm1", "sclk_pcm1_peric", -- cgit From 83942bdd992ff347442ec72d86c2d77fe51a0270 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Mon, 12 Feb 2018 16:52:27 +0100 Subject: clk: exynos5433: Extend list of available AUD_PLL output frequencies Add one more entry to the exynos5433_aud_pll_rates table, this allows to support audio sample rates: 48000, 96000, 192000 Hz with minimum error. The M, P, S, K values re confirmed by the HW team. Signed-off-by: Sylwester Nawrocki Acked-by: Chanwoo Choi --- drivers/clk/samsung/clk-exynos5433.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/samsung/clk-exynos5433.c b/drivers/clk/samsung/clk-exynos5433.c index c84326dc4b05..57a41824ee2e 100644 --- a/drivers/clk/samsung/clk-exynos5433.c +++ b/drivers/clk/samsung/clk-exynos5433.c @@ -765,6 +765,7 @@ static const struct samsung_pll_rate_table exynos5433_aud_pll_rates[] __initcons PLL_36XX_RATE(294912000U, 98, 1, 3, 19923), PLL_36XX_RATE(288000000U, 96, 1, 3, 0), PLL_36XX_RATE(252000000U, 84, 1, 3, 0), + PLL_36XX_RATE(196608001U, 197, 3, 3, -25690), { /* sentinel */ } }; -- cgit From d897ef56faf9bdb36e931251d0b70b10ebb03a14 Mon Sep 17 00:00:00 2001 From: Jernej Skrabec Date: Wed, 14 Feb 2018 21:08:55 +0100 Subject: clk: sunxi-ng: Mask nkmp factors when setting register Currently, if one of the factors isn't present, bit 0 gets always set to 1. For example, A83T has NMP PLLs modelled as NKMP PLL without K. Since K is not specified, it's offset, width and shift is 0. Driver assumes that lowest value possible is 1, otherwise we would get division by 0. That situation causes that bit 0 is always set, which may change wanted clock rate. Fix that by masking every factor according to it's specified width. Factors with width set to 0 won't have any influence to final register value. Acked-by: Maxime Ripard Signed-off-by: Jernej Skrabec Signed-off-by: Maxime Ripard --- drivers/clk/sunxi-ng/ccu_nkmp.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/drivers/clk/sunxi-ng/ccu_nkmp.c b/drivers/clk/sunxi-ng/ccu_nkmp.c index e58c95787f94..a99068a08315 100644 --- a/drivers/clk/sunxi-ng/ccu_nkmp.c +++ b/drivers/clk/sunxi-ng/ccu_nkmp.c @@ -134,6 +134,7 @@ static int ccu_nkmp_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) { struct ccu_nkmp *nkmp = hw_to_ccu_nkmp(hw); + u32 n_mask, k_mask, m_mask, p_mask; struct _ccu_nkmp _nkmp; unsigned long flags; u32 reg; @@ -149,18 +150,20 @@ static int ccu_nkmp_set_rate(struct clk_hw *hw, unsigned long rate, ccu_nkmp_find_best(parent_rate, rate, &_nkmp); + n_mask = GENMASK(nkmp->n.width + nkmp->n.shift - 1, nkmp->n.shift); + k_mask = GENMASK(nkmp->k.width + nkmp->k.shift - 1, nkmp->k.shift); + m_mask = GENMASK(nkmp->m.width + nkmp->m.shift - 1, nkmp->m.shift); + p_mask = GENMASK(nkmp->p.width + nkmp->p.shift - 1, nkmp->p.shift); + spin_lock_irqsave(nkmp->common.lock, flags); reg = readl(nkmp->common.base + nkmp->common.reg); - reg &= ~GENMASK(nkmp->n.width + nkmp->n.shift - 1, nkmp->n.shift); - reg &= ~GENMASK(nkmp->k.width + nkmp->k.shift - 1, nkmp->k.shift); - reg &= ~GENMASK(nkmp->m.width + nkmp->m.shift - 1, nkmp->m.shift); - reg &= ~GENMASK(nkmp->p.width + nkmp->p.shift - 1, nkmp->p.shift); - - reg |= (_nkmp.n - nkmp->n.offset) << nkmp->n.shift; - reg |= (_nkmp.k - nkmp->k.offset) << nkmp->k.shift; - reg |= (_nkmp.m - nkmp->m.offset) << nkmp->m.shift; - reg |= ilog2(_nkmp.p) << nkmp->p.shift; + reg &= ~(n_mask | k_mask | m_mask | p_mask); + + reg |= ((_nkmp.n - nkmp->n.offset) << nkmp->n.shift) & n_mask; + reg |= ((_nkmp.k - nkmp->k.offset) << nkmp->k.shift) & k_mask; + reg |= ((_nkmp.m - nkmp->m.offset) << nkmp->m.shift) & m_mask; + reg |= (ilog2(_nkmp.p) << nkmp->p.shift) & p_mask; writel(reg, nkmp->common.base + nkmp->common.reg); -- cgit From a5ebc3368ef7c77da5a03ad52834520a634a36ef Mon Sep 17 00:00:00 2001 From: Jernej Skrabec Date: Wed, 14 Feb 2018 21:08:56 +0100 Subject: clk: sunxi-ng: Use u64 for calculation of nkmp rate When parent rate is 24MHz and multiplier N >= 180, intermediate clock rate doesn't fit in 32 bit variable anymore. Because of that, introduce function for calculating clock rate which uses 64 bit variable for intermediate result. Acked-by: Maxime Ripard Signed-off-by: Jernej Skrabec Signed-off-by: Maxime Ripard --- drivers/clk/sunxi-ng/ccu_nkmp.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/drivers/clk/sunxi-ng/ccu_nkmp.c b/drivers/clk/sunxi-ng/ccu_nkmp.c index a99068a08315..c3f6fe7be565 100644 --- a/drivers/clk/sunxi-ng/ccu_nkmp.c +++ b/drivers/clk/sunxi-ng/ccu_nkmp.c @@ -20,6 +20,18 @@ struct _ccu_nkmp { unsigned long p, min_p, max_p; }; +static unsigned long ccu_nkmp_calc_rate(unsigned long parent, + unsigned long n, unsigned long k, + unsigned long m, unsigned long p) +{ + u64 rate = parent; + + rate *= n * k; + do_div(rate, m * p); + + return rate; +} + static void ccu_nkmp_find_best(unsigned long parent, unsigned long rate, struct _ccu_nkmp *nkmp) { @@ -33,7 +45,9 @@ static void ccu_nkmp_find_best(unsigned long parent, unsigned long rate, for (_p = nkmp->min_p; _p <= nkmp->max_p; _p <<= 1) { unsigned long tmp_rate; - tmp_rate = parent * _n * _k / (_m * _p); + tmp_rate = ccu_nkmp_calc_rate(parent, + _n, _k, + _m, _p); if (tmp_rate > rate) continue; @@ -107,7 +121,7 @@ static unsigned long ccu_nkmp_recalc_rate(struct clk_hw *hw, p = reg >> nkmp->p.shift; p &= (1 << nkmp->p.width) - 1; - return (parent_rate * n * k >> p) / m; + return ccu_nkmp_calc_rate(parent_rate, n, k, m, 1 << p); } static long ccu_nkmp_round_rate(struct clk_hw *hw, unsigned long rate, @@ -127,7 +141,8 @@ static long ccu_nkmp_round_rate(struct clk_hw *hw, unsigned long rate, ccu_nkmp_find_best(*parent_rate, rate, &_nkmp); - return *parent_rate * _nkmp.n * _nkmp.k / (_nkmp.m * _nkmp.p); + return ccu_nkmp_calc_rate(*parent_rate, _nkmp.n, _nkmp.k, + _nkmp.m, _nkmp.p); } static int ccu_nkmp_set_rate(struct clk_hw *hw, unsigned long rate, -- cgit From 039738bf986a516a01e96a4874c172dfe7e66892 Mon Sep 17 00:00:00 2001 From: Fabrizio Castro Date: Mon, 12 Feb 2018 17:44:24 +0000 Subject: clk: renesas: r8a7743: Add rwdt clock Add "rwdt" clock to r8a7743_mod_clks. Also, since we may need to access the watchdog registers at any time, declare the clock as critical. Signed-off-by: Fabrizio Castro Signed-off-by: Ramesh Shanmugasundaram Reviewed-by: Wolfram Sang Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/r8a7743-cpg-mssr.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/clk/renesas/r8a7743-cpg-mssr.c b/drivers/clk/renesas/r8a7743-cpg-mssr.c index 6dc0b3082aa6..d3c8b1e2969f 100644 --- a/drivers/clk/renesas/r8a7743-cpg-mssr.c +++ b/drivers/clk/renesas/r8a7743-cpg-mssr.c @@ -117,6 +117,7 @@ static const struct mssr_mod_clk r8a7743_mod_clks[] __initconst = { DEF_MOD("cmt1", 329, R8A7743_CLK_R), DEF_MOD("usbhs-dmac0", 330, R8A7743_CLK_HP), DEF_MOD("usbhs-dmac1", 331, R8A7743_CLK_HP), + DEF_MOD("rwdt", 402, R8A7743_CLK_R), DEF_MOD("irqc", 407, R8A7743_CLK_CP), DEF_MOD("intc-sys", 408, R8A7743_CLK_ZS), DEF_MOD("audio-dmac1", 501, R8A7743_CLK_HP), @@ -195,6 +196,7 @@ static const struct mssr_mod_clk r8a7743_mod_clks[] __initconst = { }; static const unsigned int r8a7743_crit_mod_clks[] __initconst = { + MOD_CLK_ID(402), /* RWDT */ MOD_CLK_ID(408), /* INTC-SYS (GIC) */ }; -- cgit From e0c0a2c4a2bc7c2959d19600ccd03eec4b27c4be Mon Sep 17 00:00:00 2001 From: Fabrizio Castro Date: Mon, 12 Feb 2018 17:44:25 +0000 Subject: clk: renesas: r8a7745: Add rwdt clock Add "rwdt" clock to r8a7745_mod_clks. Also, since we may need to access the watchdog registers at any time, declare the clock as critical. Signed-off-by: Fabrizio Castro Signed-off-by: Ramesh Shanmugasundaram Reviewed-by: Wolfram Sang Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/r8a7745-cpg-mssr.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/clk/renesas/r8a7745-cpg-mssr.c b/drivers/clk/renesas/r8a7745-cpg-mssr.c index 2859504cc866..87f5a3619e4f 100644 --- a/drivers/clk/renesas/r8a7745-cpg-mssr.c +++ b/drivers/clk/renesas/r8a7745-cpg-mssr.c @@ -114,6 +114,7 @@ static const struct mssr_mod_clk r8a7745_mod_clks[] __initconst = { DEF_MOD("cmt1", 329, R8A7745_CLK_R), DEF_MOD("usbhs-dmac0", 330, R8A7745_CLK_HP), DEF_MOD("usbhs-dmac1", 331, R8A7745_CLK_HP), + DEF_MOD("rwdt", 402, R8A7745_CLK_R), DEF_MOD("irqc", 407, R8A7745_CLK_CP), DEF_MOD("intc-sys", 408, R8A7745_CLK_ZS), DEF_MOD("audio-dmac0", 502, R8A7745_CLK_HP), @@ -180,6 +181,7 @@ static const struct mssr_mod_clk r8a7745_mod_clks[] __initconst = { }; static const unsigned int r8a7745_crit_mod_clks[] __initconst = { + MOD_CLK_ID(402), /* RWDT */ MOD_CLK_ID(408), /* INTC-SYS (GIC) */ }; -- cgit From 30c288bbf55c1356fd939b158a17c8e8612bdc11 Mon Sep 17 00:00:00 2001 From: Fabrizio Castro Date: Mon, 12 Feb 2018 17:44:26 +0000 Subject: clk: renesas: r8a7790: Add rwdt clock Add "rwdt" clock to r8a7790_mod_clks. Also, since we may need to access the watchdog registers at any time, declare the clock as critical. Signed-off-by: Fabrizio Castro Signed-off-by: Ramesh Shanmugasundaram Reviewed-by: Wolfram Sang Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/r8a7790-cpg-mssr.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/clk/renesas/r8a7790-cpg-mssr.c b/drivers/clk/renesas/r8a7790-cpg-mssr.c index 46bb55bb223d..f936cb74b681 100644 --- a/drivers/clk/renesas/r8a7790-cpg-mssr.c +++ b/drivers/clk/renesas/r8a7790-cpg-mssr.c @@ -140,6 +140,7 @@ static const struct mssr_mod_clk r8a7790_mod_clks[] __initconst = { DEF_MOD("cmt1", 329, R8A7790_CLK_R), DEF_MOD("usbhs-dmac0", 330, R8A7790_CLK_HP), DEF_MOD("usbhs-dmac1", 331, R8A7790_CLK_HP), + DEF_MOD("rwdt", 402, R8A7790_CLK_R), DEF_MOD("irqc", 407, R8A7790_CLK_CP), DEF_MOD("intc-sys", 408, R8A7790_CLK_ZS), DEF_MOD("audio-dmac1", 501, R8A7790_CLK_HP), @@ -211,6 +212,7 @@ static const struct mssr_mod_clk r8a7790_mod_clks[] __initconst = { }; static const unsigned int r8a7790_crit_mod_clks[] __initconst = { + MOD_CLK_ID(402), /* RWDT */ MOD_CLK_ID(408), /* INTC-SYS (GIC) */ }; -- cgit From 5ada6bee8c966bf7bdc23512d1571adaeea22f0b Mon Sep 17 00:00:00 2001 From: Fabrizio Castro Date: Mon, 12 Feb 2018 17:44:27 +0000 Subject: clk: renesas: r8a7791/r8a7793: Add rwdt clock Add "rwdt" clock to r8a7791_mod_clks. Also, since we may need to access the watchdog registers at any time, declare the clock as critical. Signed-off-by: Fabrizio Castro Signed-off-by: Ramesh Shanmugasundaram Reviewed-by: Wolfram Sang Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/r8a7791-cpg-mssr.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/clk/renesas/r8a7791-cpg-mssr.c b/drivers/clk/renesas/r8a7791-cpg-mssr.c index c0b51f9bb278..820b220b09cc 100644 --- a/drivers/clk/renesas/r8a7791-cpg-mssr.c +++ b/drivers/clk/renesas/r8a7791-cpg-mssr.c @@ -128,6 +128,7 @@ static const struct mssr_mod_clk r8a7791_mod_clks[] __initconst = { DEF_MOD("cmt1", 329, R8A7791_CLK_R), DEF_MOD("usbhs-dmac0", 330, R8A7791_CLK_HP), DEF_MOD("usbhs-dmac1", 331, R8A7791_CLK_HP), + DEF_MOD("rwdt", 402, R8A7791_CLK_R), DEF_MOD("irqc", 407, R8A7791_CLK_CP), DEF_MOD("intc-sys", 408, R8A7791_CLK_ZS), DEF_MOD("audio-dmac1", 501, R8A7791_CLK_HP), @@ -209,6 +210,7 @@ static const struct mssr_mod_clk r8a7791_mod_clks[] __initconst = { }; static const unsigned int r8a7791_crit_mod_clks[] __initconst = { + MOD_CLK_ID(402), /* RWDT */ MOD_CLK_ID(408), /* INTC-SYS (GIC) */ }; -- cgit From c43d8630fe1a6bb09e005d38793346d989aa4dad Mon Sep 17 00:00:00 2001 From: Fabrizio Castro Date: Mon, 12 Feb 2018 17:44:28 +0000 Subject: clk: renesas: r8a7794: Add rwdt clock Add "rwdt" clock to r8a7794_mod_clks. Also, since we may need to access the watchdog registers at any time, declare the clock as critical. Signed-off-by: Fabrizio Castro Signed-off-by: Ramesh Shanmugasundaram Reviewed-by: Wolfram Sang Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/r8a7794-cpg-mssr.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/clk/renesas/r8a7794-cpg-mssr.c b/drivers/clk/renesas/r8a7794-cpg-mssr.c index ec091a42da54..2a40bbeaeeaf 100644 --- a/drivers/clk/renesas/r8a7794-cpg-mssr.c +++ b/drivers/clk/renesas/r8a7794-cpg-mssr.c @@ -121,6 +121,7 @@ static const struct mssr_mod_clk r8a7794_mod_clks[] __initconst = { DEF_MOD("cmt1", 329, R8A7794_CLK_R), DEF_MOD("usbhs-dmac0", 330, R8A7794_CLK_HP), DEF_MOD("usbhs-dmac1", 331, R8A7794_CLK_HP), + DEF_MOD("rwdt", 402, R8A7794_CLK_R), DEF_MOD("irqc", 407, R8A7794_CLK_CP), DEF_MOD("intc-sys", 408, R8A7794_CLK_ZS), DEF_MOD("audio-dmac0", 502, R8A7794_CLK_HP), @@ -190,6 +191,7 @@ static const struct mssr_mod_clk r8a7794_mod_clks[] __initconst = { }; static const unsigned int r8a7794_crit_mod_clks[] __initconst = { + MOD_CLK_ID(402), /* RWDT */ MOD_CLK_ID(408), /* INTC-SYS (GIC) */ }; -- cgit From 20254c7cea447d2ffba17046e3e80da667d742d3 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 7 Feb 2018 16:43:23 +0100 Subject: clk: renesas: r8a7792: Add rwdt clock Add "rwdt" clock to r8a7792_mod_clks. Also, since we may need to access the watchdog registers at any time, declare the clock as critical. Signed-off-by: Geert Uytterhoeven Acked-by: Fabrizio Castro --- drivers/clk/renesas/r8a7792-cpg-mssr.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/clk/renesas/r8a7792-cpg-mssr.c b/drivers/clk/renesas/r8a7792-cpg-mssr.c index 7f85bbf20bf7..609a54080496 100644 --- a/drivers/clk/renesas/r8a7792-cpg-mssr.c +++ b/drivers/clk/renesas/r8a7792-cpg-mssr.c @@ -98,6 +98,7 @@ static const struct mssr_mod_clk r8a7792_mod_clks[] __initconst = { DEF_MOD("tpu0", 304, R8A7792_CLK_CP), DEF_MOD("sdhi0", 314, R8A7792_CLK_SD), DEF_MOD("cmt1", 329, R8A7792_CLK_R), + DEF_MOD("rwdt", 402, R8A7792_CLK_R), DEF_MOD("irqc", 407, R8A7792_CLK_CP), DEF_MOD("intc-sys", 408, R8A7792_CLK_ZS), DEF_MOD("audio-dmac0", 502, R8A7792_CLK_HP), @@ -154,6 +155,7 @@ static const struct mssr_mod_clk r8a7792_mod_clks[] __initconst = { }; static const unsigned int r8a7792_crit_mod_clks[] __initconst = { + MOD_CLK_ID(402), /* RWDT */ MOD_CLK_ID(408), /* INTC-SYS (GIC) */ }; -- cgit From 35b3c462dae1b451772992d4e43bfef814499b49 Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Thu, 15 Feb 2018 14:56:53 +0300 Subject: dt-bindings: clock: add R8A77980 CPG core clock definitions Add macros usable by the device tree sources to reference the R8A77980 CPG core clocks by index. The data come from the table 8.2e of the R-Car Series, 3rd Generation User's Manual: Hardware (Rev. 0.80, Oct, 2017), however I had to add the Z2 clock which is somehow present only on the figure 8.1e... Based on the original (and large) patch by Vladimir Barinov. Signed-off-by: Vladimir Barinov Signed-off-by: Sergei Shtylyov Reviewed-by: Rob Herring Reviewed-by: Simon Horman Signed-off-by: Geert Uytterhoeven --- include/dt-bindings/clock/r8a77980-cpg-mssr.h | 51 +++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 include/dt-bindings/clock/r8a77980-cpg-mssr.h diff --git a/include/dt-bindings/clock/r8a77980-cpg-mssr.h b/include/dt-bindings/clock/r8a77980-cpg-mssr.h new file mode 100644 index 000000000000..a4c0d76c392e --- /dev/null +++ b/include/dt-bindings/clock/r8a77980-cpg-mssr.h @@ -0,0 +1,51 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2018 Renesas Electronics Corp. + * Copyright (C) 2018 Cogent Embedded, Inc. + */ +#ifndef __DT_BINDINGS_CLOCK_R8A77980_CPG_MSSR_H__ +#define __DT_BINDINGS_CLOCK_R8A77980_CPG_MSSR_H__ + +#include + +/* r8a77980 CPG Core Clocks */ +#define R8A77980_CLK_Z2 0 +#define R8A77980_CLK_ZR 1 +#define R8A77980_CLK_ZTR 2 +#define R8A77980_CLK_ZTRD2 3 +#define R8A77980_CLK_ZT 4 +#define R8A77980_CLK_ZX 5 +#define R8A77980_CLK_S0D1 6 +#define R8A77980_CLK_S0D2 7 +#define R8A77980_CLK_S0D3 8 +#define R8A77980_CLK_S0D4 9 +#define R8A77980_CLK_S0D6 10 +#define R8A77980_CLK_S0D12 11 +#define R8A77980_CLK_S0D24 12 +#define R8A77980_CLK_S1D1 13 +#define R8A77980_CLK_S1D2 14 +#define R8A77980_CLK_S1D4 15 +#define R8A77980_CLK_S2D1 16 +#define R8A77980_CLK_S2D2 17 +#define R8A77980_CLK_S2D4 18 +#define R8A77980_CLK_S3D1 19 +#define R8A77980_CLK_S3D2 20 +#define R8A77980_CLK_S3D4 21 +#define R8A77980_CLK_LB 22 +#define R8A77980_CLK_CL 23 +#define R8A77980_CLK_ZB3 24 +#define R8A77980_CLK_ZB3D2 25 +#define R8A77980_CLK_ZB3D4 26 +#define R8A77980_CLK_SD0H 27 +#define R8A77980_CLK_SD0 28 +#define R8A77980_CLK_RPC 29 +#define R8A77980_CLK_RPCD2 30 +#define R8A77980_CLK_MSO 31 +#define R8A77980_CLK_CANFD 32 +#define R8A77980_CLK_CSI0 33 +#define R8A77980_CLK_CP 34 +#define R8A77980_CLK_CPEX 35 +#define R8A77980_CLK_R 36 +#define R8A77980_CLK_OSC 37 + +#endif /* __DT_BINDINGS_CLOCK_R8A77980_CPG_MSSR_H__ */ -- cgit From ce15783c510a9905545e7708345454c38b725dd8 Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Thu, 15 Feb 2018 14:58:45 +0300 Subject: clk: renesas: cpg-mssr: add R8A77980 support Add R-Car V3H (R8A77980) Clock Pulse Generator / Module Standby and Software Reset support, using the CPG/MSSR driver core and the common R-Car Gen3 code. Based on the original (and large) patch by Vladimir Barinov. Signed-off-by: Vladimir Barinov Signed-off-by: Sergei Shtylyov Reviewed-by: Rob Herring Reviewed-by: Simon Horman Signed-off-by: Geert Uytterhoeven --- .../devicetree/bindings/clock/renesas,cpg-mssr.txt | 5 +- drivers/clk/renesas/Kconfig | 5 + drivers/clk/renesas/Makefile | 1 + drivers/clk/renesas/r8a77980-cpg-mssr.c | 227 +++++++++++++++++++++ drivers/clk/renesas/renesas-cpg-mssr.c | 6 + drivers/clk/renesas/renesas-cpg-mssr.h | 1 + 6 files changed, 243 insertions(+), 2 deletions(-) create mode 100644 drivers/clk/renesas/r8a77980-cpg-mssr.c diff --git a/Documentation/devicetree/bindings/clock/renesas,cpg-mssr.txt b/Documentation/devicetree/bindings/clock/renesas,cpg-mssr.txt index f1890d0777a6..bc4ea0868dbc 100644 --- a/Documentation/devicetree/bindings/clock/renesas,cpg-mssr.txt +++ b/Documentation/devicetree/bindings/clock/renesas,cpg-mssr.txt @@ -23,6 +23,7 @@ Required Properties: - "renesas,r8a7795-cpg-mssr" for the r8a7795 SoC (R-Car H3) - "renesas,r8a7796-cpg-mssr" for the r8a7796 SoC (R-Car M3-W) - "renesas,r8a77970-cpg-mssr" for the r8a77970 SoC (R-Car V3M) + - "renesas,r8a77980-cpg-mssr" for the r8a77980 SoC (R-Car V3H) - "renesas,r8a77995-cpg-mssr" for the r8a77995 SoC (R-Car D3) - reg: Base address and length of the memory resource used by the CPG/MSSR @@ -32,8 +33,8 @@ Required Properties: clock-names - clock-names: List of external parent clock names. Valid names are: - "extal" (r8a7743, r8a7745, r8a7790, r8a7791, r8a7792, r8a7793, r8a7794, - r8a7795, r8a7796, r8a77970, r8a77995) - - "extalr" (r8a7795, r8a7796, r8a77970) + r8a7795, r8a7796, r8a77970, r8a77980, r8a77995) + - "extalr" (r8a7795, r8a7796, r8a77970, r8a77980) - "usb_extal" (r8a7743, r8a7745, r8a7790, r8a7791, r8a7793, r8a7794) - #clock-cells: Must be 2 diff --git a/drivers/clk/renesas/Kconfig b/drivers/clk/renesas/Kconfig index 84b40b95ca0e..43bab4f9c4e2 100644 --- a/drivers/clk/renesas/Kconfig +++ b/drivers/clk/renesas/Kconfig @@ -16,6 +16,7 @@ config CLK_RENESAS select CLK_R8A7795 if ARCH_R8A7795 select CLK_R8A7796 if ARCH_R8A7796 select CLK_R8A77970 if ARCH_R8A77970 + select CLK_R8A77980 if ARCH_R8A77980 select CLK_R8A77995 if ARCH_R8A77995 select CLK_SH73A0 if ARCH_SH73A0 @@ -101,6 +102,10 @@ config CLK_R8A77970 bool "R-Car V3M clock support" if COMPILE_TEST select CLK_RCAR_GEN3_CPG +config CLK_R8A77980 + bool "R-Car V3H clock support" if COMPILE_TEST + select CLK_RCAR_GEN3_CPG + config CLK_R8A77995 bool "R-Car D3 clock support" if COMPILE_TEST select CLK_RCAR_GEN3_CPG diff --git a/drivers/clk/renesas/Makefile b/drivers/clk/renesas/Makefile index 34c4e0b37afa..e20fa195d107 100644 --- a/drivers/clk/renesas/Makefile +++ b/drivers/clk/renesas/Makefile @@ -15,6 +15,7 @@ obj-$(CONFIG_CLK_R8A7794) += r8a7794-cpg-mssr.o obj-$(CONFIG_CLK_R8A7795) += r8a7795-cpg-mssr.o obj-$(CONFIG_CLK_R8A7796) += r8a7796-cpg-mssr.o obj-$(CONFIG_CLK_R8A77970) += r8a77970-cpg-mssr.o +obj-$(CONFIG_CLK_R8A77980) += r8a77980-cpg-mssr.o obj-$(CONFIG_CLK_R8A77995) += r8a77995-cpg-mssr.o obj-$(CONFIG_CLK_SH73A0) += clk-sh73a0.o diff --git a/drivers/clk/renesas/r8a77980-cpg-mssr.c b/drivers/clk/renesas/r8a77980-cpg-mssr.c new file mode 100644 index 000000000000..7aaae73a321a --- /dev/null +++ b/drivers/clk/renesas/r8a77980-cpg-mssr.c @@ -0,0 +1,227 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * r8a77980 Clock Pulse Generator / Module Standby and Software Reset + * + * Copyright (C) 2018 Renesas Electronics Corp. + * Copyright (C) 2018 Cogent Embedded, Inc. + * + * Based on r8a7795-cpg-mssr.c + * + * Copyright (C) 2015 Glider bvba + */ + +#include +#include +#include +#include +#include + +#include + +#include "renesas-cpg-mssr.h" +#include "rcar-gen3-cpg.h" + +enum clk_ids { + /* Core Clock Outputs exported to DT */ + LAST_DT_CORE_CLK = R8A77980_CLK_OSC, + + /* External Input Clocks */ + CLK_EXTAL, + CLK_EXTALR, + + /* Internal Core Clocks */ + CLK_MAIN, + CLK_PLL1, + CLK_PLL2, + CLK_PLL3, + CLK_PLL1_DIV2, + CLK_PLL1_DIV4, + CLK_S0, + CLK_S1, + CLK_S2, + CLK_S3, + CLK_SDSRC, + + /* Module Clocks */ + MOD_CLK_BASE +}; + +static const struct cpg_core_clk r8a77980_core_clks[] __initconst = { + /* External Clock Inputs */ + DEF_INPUT("extal", CLK_EXTAL), + DEF_INPUT("extalr", CLK_EXTALR), + + /* Internal Core Clocks */ + DEF_BASE(".main", CLK_MAIN, CLK_TYPE_GEN3_MAIN, CLK_EXTAL), + DEF_BASE(".pll1", CLK_PLL1, CLK_TYPE_GEN3_PLL1, CLK_MAIN), + DEF_BASE(".pll2", CLK_PLL2, CLK_TYPE_GEN3_PLL2, CLK_MAIN), + DEF_BASE(".pll3", CLK_PLL3, CLK_TYPE_GEN3_PLL3, CLK_MAIN), + + DEF_FIXED(".pll1_div2", CLK_PLL1_DIV2, CLK_PLL1, 2, 1), + DEF_FIXED(".pll1_div4", CLK_PLL1_DIV4, CLK_PLL1_DIV2, 2, 1), + DEF_FIXED(".s0", CLK_S0, CLK_PLL1_DIV2, 2, 1), + DEF_FIXED(".s1", CLK_S1, CLK_PLL1_DIV2, 3, 1), + DEF_FIXED(".s2", CLK_S2, CLK_PLL1_DIV2, 4, 1), + DEF_FIXED(".s3", CLK_S3, CLK_PLL1_DIV2, 6, 1), + DEF_FIXED(".sdsrc", CLK_SDSRC, CLK_PLL1_DIV2, 2, 1), + + /* Core Clock Outputs */ + DEF_FIXED("ztr", R8A77980_CLK_ZTR, CLK_PLL1_DIV2, 6, 1), + DEF_FIXED("ztrd2", R8A77980_CLK_ZTRD2, CLK_PLL1_DIV2, 12, 1), + DEF_FIXED("zt", R8A77980_CLK_ZT, CLK_PLL1_DIV2, 4, 1), + DEF_FIXED("zx", R8A77980_CLK_ZX, CLK_PLL1_DIV2, 2, 1), + DEF_FIXED("s0d1", R8A77980_CLK_S0D1, CLK_S0, 1, 1), + DEF_FIXED("s0d2", R8A77980_CLK_S0D2, CLK_S0, 2, 1), + DEF_FIXED("s0d3", R8A77980_CLK_S0D3, CLK_S0, 3, 1), + DEF_FIXED("s0d4", R8A77980_CLK_S0D4, CLK_S0, 4, 1), + DEF_FIXED("s0d6", R8A77980_CLK_S0D6, CLK_S0, 6, 1), + DEF_FIXED("s0d12", R8A77980_CLK_S0D12, CLK_S0, 12, 1), + DEF_FIXED("s0d24", R8A77980_CLK_S0D24, CLK_S0, 24, 1), + DEF_FIXED("s1d1", R8A77980_CLK_S1D1, CLK_S1, 1, 1), + DEF_FIXED("s1d2", R8A77980_CLK_S1D2, CLK_S1, 2, 1), + DEF_FIXED("s1d4", R8A77980_CLK_S1D4, CLK_S1, 4, 1), + DEF_FIXED("s2d1", R8A77980_CLK_S2D1, CLK_S2, 1, 1), + DEF_FIXED("s2d2", R8A77980_CLK_S2D2, CLK_S2, 2, 1), + DEF_FIXED("s2d4", R8A77980_CLK_S2D4, CLK_S2, 4, 1), + DEF_FIXED("s3d1", R8A77980_CLK_S3D1, CLK_S3, 1, 1), + DEF_FIXED("s3d2", R8A77980_CLK_S3D2, CLK_S3, 2, 1), + DEF_FIXED("s3d4", R8A77980_CLK_S3D4, CLK_S3, 4, 1), + + DEF_GEN3_SD("sd0", R8A77980_CLK_SD0, CLK_SDSRC, 0x0074), + + DEF_FIXED("cl", R8A77980_CLK_CL, CLK_PLL1_DIV2, 48, 1), + DEF_FIXED("cp", R8A77980_CLK_CP, CLK_EXTAL, 2, 1), + DEF_FIXED("cpex", R8A77980_CLK_CPEX, CLK_EXTAL, 2, 1), + + DEF_DIV6P1("canfd", R8A77980_CLK_CANFD, CLK_PLL1_DIV4, 0x244), + DEF_DIV6P1("csi0", R8A77980_CLK_CSI0, CLK_PLL1_DIV4, 0x00c), + DEF_DIV6P1("mso", R8A77980_CLK_MSO, CLK_PLL1_DIV4, 0x014), +}; + +static const struct mssr_mod_clk r8a77980_mod_clks[] __initconst = { + DEF_MOD("tmu4", 121, R8A77980_CLK_S0D6), + DEF_MOD("tmu3", 122, R8A77980_CLK_S0D6), + DEF_MOD("tmu2", 123, R8A77980_CLK_S0D6), + DEF_MOD("tmu1", 124, R8A77980_CLK_S0D6), + DEF_MOD("tmu0", 125, R8A77980_CLK_CP), + DEF_MOD("scif4", 203, R8A77980_CLK_S3D4), + DEF_MOD("scif3", 204, R8A77980_CLK_S3D4), + DEF_MOD("scif1", 206, R8A77980_CLK_S3D4), + DEF_MOD("scif0", 207, R8A77980_CLK_S3D4), + DEF_MOD("msiof3", 208, R8A77980_CLK_MSO), + DEF_MOD("msiof2", 209, R8A77980_CLK_MSO), + DEF_MOD("msiof1", 210, R8A77980_CLK_MSO), + DEF_MOD("msiof0", 211, R8A77980_CLK_MSO), + DEF_MOD("sys-dmac2", 217, R8A77980_CLK_S0D3), + DEF_MOD("sys-dmac1", 218, R8A77980_CLK_S0D3), + DEF_MOD("tpu0", 304, R8A77980_CLK_S3D4), + DEF_MOD("sdif", 314, R8A77980_CLK_SD0), + DEF_MOD("pciec0", 319, R8A77980_CLK_S3D1), + DEF_MOD("intc-ex", 407, R8A77980_CLK_CP), + DEF_MOD("intc-ap", 408, R8A77980_CLK_S0D3), + DEF_MOD("hscif3", 517, R8A77980_CLK_S3D1), + DEF_MOD("hscif2", 518, R8A77980_CLK_S3D1), + DEF_MOD("hscif1", 519, R8A77980_CLK_S3D1), + DEF_MOD("hscif0", 520, R8A77980_CLK_S3D1), + DEF_MOD("imp4", 521, R8A77980_CLK_S1D1), + DEF_MOD("thermal", 522, R8A77980_CLK_CP), + DEF_MOD("pwm", 523, R8A77980_CLK_S0D12), + DEF_MOD("impdma1", 526, R8A77980_CLK_S1D1), + DEF_MOD("impdma0", 527, R8A77980_CLK_S1D1), + DEF_MOD("imp-ocv4", 528, R8A77980_CLK_S1D1), + DEF_MOD("imp-ocv3", 529, R8A77980_CLK_S1D1), + DEF_MOD("imp-ocv2", 531, R8A77980_CLK_S1D1), + DEF_MOD("fcpvd0", 603, R8A77980_CLK_S3D1), + DEF_MOD("vspd0", 623, R8A77980_CLK_S3D1), + DEF_MOD("csi41", 715, R8A77980_CLK_CSI0), + DEF_MOD("csi40", 716, R8A77980_CLK_CSI0), + DEF_MOD("du0", 724, R8A77980_CLK_S2D1), + DEF_MOD("lvds", 727, R8A77980_CLK_S2D1), + DEF_MOD("etheravb", 812, R8A77980_CLK_S3D2), + DEF_MOD("gether", 813, R8A77980_CLK_S3D2), + DEF_MOD("imp3", 824, R8A77980_CLK_S1D1), + DEF_MOD("imp2", 825, R8A77980_CLK_S1D1), + DEF_MOD("imp1", 826, R8A77980_CLK_S1D1), + DEF_MOD("imp0", 827, R8A77980_CLK_S1D1), + DEF_MOD("imp-ocv1", 828, R8A77980_CLK_S1D1), + DEF_MOD("imp-ocv0", 829, R8A77980_CLK_S1D1), + DEF_MOD("impram", 830, R8A77980_CLK_S1D1), + DEF_MOD("impcnn", 831, R8A77980_CLK_S1D1), + DEF_MOD("gpio5", 907, R8A77980_CLK_CP), + DEF_MOD("gpio4", 908, R8A77980_CLK_CP), + DEF_MOD("gpio3", 909, R8A77980_CLK_CP), + DEF_MOD("gpio2", 910, R8A77980_CLK_CP), + DEF_MOD("gpio1", 911, R8A77980_CLK_CP), + DEF_MOD("gpio0", 912, R8A77980_CLK_CP), + DEF_MOD("can-fd", 914, R8A77980_CLK_S3D2), + DEF_MOD("i2c4", 927, R8A77980_CLK_S0D6), + DEF_MOD("i2c3", 928, R8A77980_CLK_S0D6), + DEF_MOD("i2c2", 929, R8A77980_CLK_S3D2), + DEF_MOD("i2c1", 930, R8A77980_CLK_S3D2), + DEF_MOD("i2c0", 931, R8A77980_CLK_S3D2), +}; + +static const unsigned int r8a77980_crit_mod_clks[] __initconst = { + MOD_CLK_ID(408), /* INTC-AP (GIC) */ +}; + + +/* + * CPG Clock Data + */ + +/* + * MD EXTAL PLL2 PLL1 PLL3 + * 14 13 (MHz) + * -------------------------------------------------- + * 0 0 16.66 x 1 x240 x192 x192 + * 0 1 20 x 1 x200 x160 x160 + * 1 0 27 x 1 x148 x118 x118 + * 1 1 33.33 / 2 x240 x192 x192 + */ +#define CPG_PLL_CONFIG_INDEX(md) ((((md) & BIT(14)) >> 13) | \ + (((md) & BIT(13)) >> 13)) + +static const struct rcar_gen3_cpg_pll_config cpg_pll_configs[4] __initconst = { + /* EXTAL div PLL1 mult/div PLL3 mult/div */ + { 1, 192, 1, 192, 1, }, + { 1, 160, 1, 160, 1, }, + { 1, 118, 1, 118, 1, }, + { 2, 192, 1, 192, 1, }, +}; + +static int __init r8a77980_cpg_mssr_init(struct device *dev) +{ + const struct rcar_gen3_cpg_pll_config *cpg_pll_config; + u32 cpg_mode; + int error; + + error = rcar_rst_read_mode_pins(&cpg_mode); + if (error) + return error; + + cpg_pll_config = &cpg_pll_configs[CPG_PLL_CONFIG_INDEX(cpg_mode)]; + + return rcar_gen3_cpg_init(cpg_pll_config, CLK_EXTALR, cpg_mode); +} + +const struct cpg_mssr_info r8a77980_cpg_mssr_info __initconst = { + /* Core Clocks */ + .core_clks = r8a77980_core_clks, + .num_core_clks = ARRAY_SIZE(r8a77980_core_clks), + .last_dt_core_clk = LAST_DT_CORE_CLK, + .num_total_core_clks = MOD_CLK_BASE, + + /* Module Clocks */ + .mod_clks = r8a77980_mod_clks, + .num_mod_clks = ARRAY_SIZE(r8a77980_mod_clks), + .num_hw_mod_clks = 12 * 32, + + /* Critical Module Clocks */ + .crit_mod_clks = r8a77980_crit_mod_clks, + .num_crit_mod_clks = ARRAY_SIZE(r8a77980_crit_mod_clks), + + /* Callbacks */ + .init = r8a77980_cpg_mssr_init, + .cpg_clk_register = rcar_gen3_cpg_clk_register, +}; diff --git a/drivers/clk/renesas/renesas-cpg-mssr.c b/drivers/clk/renesas/renesas-cpg-mssr.c index e3cc72c81311..aadfa6df6c4d 100644 --- a/drivers/clk/renesas/renesas-cpg-mssr.c +++ b/drivers/clk/renesas/renesas-cpg-mssr.c @@ -699,6 +699,12 @@ static const struct of_device_id cpg_mssr_match[] = { .data = &r8a77970_cpg_mssr_info, }, #endif +#ifdef CONFIG_ARCH_R8A77980 + { + .compatible = "renesas,r8a77980-cpg-mssr", + .data = &r8a77980_cpg_mssr_info, + }, +#endif #ifdef CONFIG_CLK_R8A77995 { .compatible = "renesas,r8a77995-cpg-mssr", diff --git a/drivers/clk/renesas/renesas-cpg-mssr.h b/drivers/clk/renesas/renesas-cpg-mssr.h index 0745b0930308..143293e3d193 100644 --- a/drivers/clk/renesas/renesas-cpg-mssr.h +++ b/drivers/clk/renesas/renesas-cpg-mssr.h @@ -140,6 +140,7 @@ extern const struct cpg_mssr_info r8a7794_cpg_mssr_info; extern const struct cpg_mssr_info r8a7795_cpg_mssr_info; extern const struct cpg_mssr_info r8a7796_cpg_mssr_info; extern const struct cpg_mssr_info r8a77970_cpg_mssr_info; +extern const struct cpg_mssr_info r8a77980_cpg_mssr_info; extern const struct cpg_mssr_info r8a77995_cpg_mssr_info; -- cgit From 756a08c360ee68d33c7c5ac6f3dba3264e5529b7 Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Wed, 24 Jan 2018 22:31:21 +0800 Subject: clk: imx: imx6sx: update cko mux options According to latest reference manual (Rev.2, 9/2017), previous CKO1/2's mux options are incorrect, update them. Signed-off-by: Anson Huang Signed-off-by: Shawn Guo --- drivers/clk/imx/clk-imx6sx.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/clk/imx/clk-imx6sx.c b/drivers/clk/imx/clk-imx6sx.c index e6d389e333d7..bc3f9ebf2d9e 100644 --- a/drivers/clk/imx/clk-imx6sx.c +++ b/drivers/clk/imx/clk-imx6sx.c @@ -63,17 +63,17 @@ static const char *lcdif2_sels[] = { "lcdif2_podf", "ipp_di0", "ipp_di1", "ldb_d static const char *display_sels[] = { "pll2_bus", "pll2_pfd2_396m", "pll3_usb_otg", "pll3_pfd1_540m", }; static const char *csi_sels[] = { "osc", "pll2_pfd2_396m", "pll3_120m", "pll3_pfd1_540m", }; static const char *cko1_sels[] = { - "pll3_usb_otg", "pll2_bus", "pll1_sys", "pll5_video_div", - "dummy", "ocram", "dummy", "pxp_axi", "epdc_axi", "lcdif_pix", - "epdc_pix", "ahb", "ipg", "perclk", "ckil", "pll4_audio_div", + "dummy", "dummy", "dummy", "dummy", + "vadc", "ocram", "qspi2", "m4", "enet_ahb", "lcdif2_pix", + "lcdif1_pix", "ahb", "ipg", "perclk", "ckil", "pll4_audio_div", }; static const char *cko2_sels[] = { "dummy", "mmdc_p0_fast", "usdhc4", "usdhc1", "dummy", "wrck", "ecspi_root", "dummy", "usdhc3", "pcie", "arm", "csi_core", - "lcdif_axi", "dummy", "osc", "dummy", "gpu2d_ovg_core", - "usdhc2", "ssi1", "ssi2", "ssi3", "gpu2d_core", "dummy", - "dummy", "dummy", "dummy", "esai_extal", "eim_slow", "uart_serial", - "spdif", "asrc", "dummy", + "display_axi", "dummy", "osc", "dummy", "dummy", + "usdhc2", "ssi1", "ssi2", "ssi3", "gpu_axi_podf", "dummy", + "can_podf", "lvds1_out", "qspi1", "esai_extal", "eim_slow", + "uart_serial", "spdif", "audio", "dummy", }; static const char *cko_sels[] = { "cko1", "cko2", }; static const char *lvds_sels[] = { -- cgit From a8321e7887410a2b2e80ab89d1ef7b30562658ea Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Fri, 16 Feb 2018 15:57:48 +0100 Subject: clk: samsung: exynos3250: Fix PLL rates Rates declared in PLL rate tables should match exactly rates calculated from PLL coefficients. If that is not the case, rate of the PLL's child clock might be set not as expected. For instance, if in the PLL rates table we have a 393216000 Hz entry and the real value as returned by the PLL's recalc_rate callback is 393216003, after setting PLL's clk rate to 393216000 clk_get_rate will return 393216003. If we now attempt to set rate of a PLL's child divider clock to 393216000/2 its rate will be 131072001, rather than 196608000. That is, the divider will be set to 3 instead of 2, because 393216003/2 is greater than 196608000. To fix this issue declared rates are changed to exactly match rates generated by the PLL, as calculated from the P, M, S, K coefficients. In this patch an erroneous P value for 74176002 output frequency is also corrected. Signed-off-by: Andrzej Hajda Acked-by: Chanwoo Choi Acked-by: Tomasz Figa Signed-off-by: Sylwester Nawrocki --- drivers/clk/samsung/clk-exynos3250.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/clk/samsung/clk-exynos3250.c b/drivers/clk/samsung/clk-exynos3250.c index 1b81e283f605..ed36728424a2 100644 --- a/drivers/clk/samsung/clk-exynos3250.c +++ b/drivers/clk/samsung/clk-exynos3250.c @@ -698,7 +698,7 @@ static const struct samsung_pll_rate_table exynos3250_epll_rates[] __initconst = PLL_36XX_RATE(144000000, 96, 2, 3, 0), PLL_36XX_RATE( 96000000, 128, 2, 4, 0), PLL_36XX_RATE( 84000000, 112, 2, 4, 0), - PLL_36XX_RATE( 80000004, 106, 2, 4, 43691), + PLL_36XX_RATE( 80000003, 106, 2, 4, 43691), PLL_36XX_RATE( 73728000, 98, 2, 4, 19923), PLL_36XX_RATE( 67737598, 270, 3, 5, 62285), PLL_36XX_RATE( 65535999, 174, 2, 5, 49982), @@ -734,7 +734,7 @@ static const struct samsung_pll_rate_table exynos3250_vpll_rates[] __initconst = PLL_36XX_RATE(148352005, 98, 2, 3, 59070), PLL_36XX_RATE(108000000, 144, 2, 4, 0), PLL_36XX_RATE( 74250000, 99, 2, 4, 0), - PLL_36XX_RATE( 74176002, 98, 3, 4, 59070), + PLL_36XX_RATE( 74176002, 98, 2, 4, 59070), PLL_36XX_RATE( 54054000, 216, 3, 5, 14156), PLL_36XX_RATE( 54000000, 144, 2, 5, 0), { /* sentinel */ } -- cgit From 2ac051eeabaa411ef89ae7cd5bb8e60cb41ad780 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Fri, 16 Feb 2018 15:57:49 +0100 Subject: clk: samsung: exynos5250: Fix PLL rates Rates declared in PLL rate tables should match exactly rates calculated from PLL coefficients. If that is not the case, rate of the PLL's child clock might be set not as expected. For instance, if in the PLL rates table we have a 393216000 Hz entry and the real value as returned by the PLL's recalc_rate callback is 393216003, after setting PLL's clk rate to 393216000 clk_get_rate will return 393216003. If we now attempt to set rate of a PLL's child divider clock to 393216000/2 its rate will be 131072001, rather than 196608000. That is, the divider will be set to 3 instead of 2, because 393216003/2 is greater than 196608000. To fix this issue declared rates are changed to exactly match rates generated by the PLL, as calculated from the P, M, S, K coefficients. Signed-off-by: Andrzej Hajda Acked-by: Chanwoo Choi Acked-by: Tomasz Figa Signed-off-by: Sylwester Nawrocki --- drivers/clk/samsung/clk-exynos5250.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/clk/samsung/clk-exynos5250.c b/drivers/clk/samsung/clk-exynos5250.c index 9b073c98a891..923c608b1b95 100644 --- a/drivers/clk/samsung/clk-exynos5250.c +++ b/drivers/clk/samsung/clk-exynos5250.c @@ -711,13 +711,13 @@ static const struct samsung_pll_rate_table epll_24mhz_tbl[] __initconst = { /* sorted in descending order */ /* PLL_36XX_RATE(rate, m, p, s, k) */ PLL_36XX_RATE(192000000, 64, 2, 2, 0), - PLL_36XX_RATE(180633600, 90, 3, 2, 20762), + PLL_36XX_RATE(180633605, 90, 3, 2, 20762), PLL_36XX_RATE(180000000, 90, 3, 2, 0), PLL_36XX_RATE(73728000, 98, 2, 4, 19923), - PLL_36XX_RATE(67737600, 90, 2, 4, 20762), + PLL_36XX_RATE(67737602, 90, 2, 4, 20762), PLL_36XX_RATE(49152000, 98, 3, 4, 19923), - PLL_36XX_RATE(45158400, 90, 3, 4, 20762), - PLL_36XX_RATE(32768000, 131, 3, 5, 4719), + PLL_36XX_RATE(45158401, 90, 3, 4, 20762), + PLL_36XX_RATE(32768001, 131, 3, 5, 4719), { }, }; -- cgit From cdb68fbd4e7962be742c4f29475220c5bf28d8a5 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Fri, 16 Feb 2018 15:57:50 +0100 Subject: clk: samsung: exynos5260: Fix PLL rates Rates declared in PLL rate tables should match exactly rates calculated from the PLL coefficients. If that is not the case, rate of the PLL's child clock might be set not as expected. For instance, if in the PLL rates table we have a 393216000 Hz entry and the real value as returned by the PLL's recalc_rate callback is 393216003, after setting PLL's clk rate to 393216000 clk_get_rate will return 393216003. If we now attempt to set rate of a PLL's child divider clock to 393216000/2 its rate will be 131072001, rather than 196608000. That is, the divider will be set to 3 instead of 2, because 393216003/2 is greater than 196608000. To fix this issue declared rates are changed to exactly match rates generated by the PLL, as calculated from the P, M, S, K coefficients. Signed-off-by: Andrzej Hajda Acked-by: Tomasz Figa Acked-by: Chanwoo Choi Signed-off-by: Sylwester Nawrocki --- drivers/clk/samsung/clk-exynos5260.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/samsung/clk-exynos5260.c b/drivers/clk/samsung/clk-exynos5260.c index fd1d9bfc151b..8eae1752d700 100644 --- a/drivers/clk/samsung/clk-exynos5260.c +++ b/drivers/clk/samsung/clk-exynos5260.c @@ -65,7 +65,7 @@ static const struct samsung_pll_rate_table pll2650_24mhz_tbl[] __initconst = { PLL_36XX_RATE(480000000, 160, 2, 2, 0), PLL_36XX_RATE(432000000, 144, 2, 2, 0), PLL_36XX_RATE(400000000, 200, 3, 2, 0), - PLL_36XX_RATE(394073130, 459, 7, 2, 49282), + PLL_36XX_RATE(394073128, 459, 7, 2, 49282), PLL_36XX_RATE(333000000, 111, 2, 2, 0), PLL_36XX_RATE(300000000, 100, 2, 2, 0), PLL_36XX_RATE(266000000, 266, 3, 3, 0), -- cgit From ab0447845cffc0fd752df2ccd6b4e34006000ce4 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Fri, 16 Feb 2018 15:57:51 +0100 Subject: clk: samsung: exynos5433: Fix PLL rates Rates declared in PLL rate tables should match exactly rates calculated from the PLL coefficients. If that is not the case, rate of the PLL's child clock might be set not as expected. For instance, if in the PLL rates table we have a 393216000 Hz entry and the real value as returned by the PLL's recalc_rate callback is 393216003, after setting PLL's clk rate to 393216000 clk_get_rate will return 393216003. If we now attempt to set rate of a PLL's child divider clock to 393216000/2 its rate will be 131072001, rather than 196608000. That is, the divider will be set to 3 instead of 2, because 393216003/2 is greater than 196608000. To fix this issue declared rates are changed to exactly match rates generated by the PLL, as calculated from the P, M, S, K coefficients. Signed-off-by: Andrzej Hajda Acked-by: Tomasz Figa Acked-by: Chanwoo Choi Signed-off-by: Sylwester Nawrocki --- drivers/clk/samsung/clk-exynos5433.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/clk/samsung/clk-exynos5433.c b/drivers/clk/samsung/clk-exynos5433.c index 57a41824ee2e..7985352ceb2f 100644 --- a/drivers/clk/samsung/clk-exynos5433.c +++ b/drivers/clk/samsung/clk-exynos5433.c @@ -729,7 +729,7 @@ static const struct samsung_pll_rate_table exynos5433_pll_rates[] __initconst = PLL_35XX_RATE(800000000U, 400, 6, 1), PLL_35XX_RATE(733000000U, 733, 12, 1), PLL_35XX_RATE(700000000U, 175, 3, 1), - PLL_35XX_RATE(667000000U, 222, 4, 1), + PLL_35XX_RATE(666000000U, 222, 4, 1), PLL_35XX_RATE(633000000U, 211, 4, 1), PLL_35XX_RATE(600000000U, 500, 5, 2), PLL_35XX_RATE(552000000U, 460, 5, 2), @@ -757,12 +757,12 @@ static const struct samsung_pll_rate_table exynos5433_pll_rates[] __initconst = /* AUD_PLL */ static const struct samsung_pll_rate_table exynos5433_aud_pll_rates[] __initconst = { PLL_36XX_RATE(400000000U, 200, 3, 2, 0), - PLL_36XX_RATE(393216000U, 197, 3, 2, -25690), + PLL_36XX_RATE(393216003U, 197, 3, 2, -25690), PLL_36XX_RATE(384000000U, 128, 2, 2, 0), - PLL_36XX_RATE(368640000U, 246, 4, 2, -15729), - PLL_36XX_RATE(361507200U, 181, 3, 2, -16148), - PLL_36XX_RATE(338688000U, 113, 2, 2, -6816), - PLL_36XX_RATE(294912000U, 98, 1, 3, 19923), + PLL_36XX_RATE(368639991U, 246, 4, 2, -15729), + PLL_36XX_RATE(361507202U, 181, 3, 2, -16148), + PLL_36XX_RATE(338687988U, 113, 2, 2, -6816), + PLL_36XX_RATE(294912002U, 98, 1, 3, 19923), PLL_36XX_RATE(288000000U, 96, 1, 3, 0), PLL_36XX_RATE(252000000U, 84, 1, 3, 0), PLL_36XX_RATE(196608001U, 197, 3, 3, -25690), -- cgit From 7e4db0c2836e892766565965207eee051c8037b9 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Fri, 16 Feb 2018 15:57:52 +0100 Subject: clk: samsung: exynos7: Fix PLL rates Rates declared in PLL rate tables should match exactly rates calculated from the PLL coefficients. If that is not the case, rate of the PLL's child clock might be set not as expected. For instance, if in the PLL rates table we have a 393216000 Hz entry and the real value as returned by the PLL's recalc_rate callback is 393216003, after setting PLL's clk rate to 393216000 clk_get_rate will return 393216003. If we now attempt to set rate of a PLL's child divider clock to 393216000/2 its rate will be 131072001, rather than 196608000. That is, the divider will be set to 3 instead of 2, because 393216003/2 is greater than 196608000. To fix this issue declared rates are changed to exactly match rates generated by the PLL, as calculated from the P, M, S, K coefficients. Signed-off-by: Andrzej Hajda Acked-by: Tomasz Figa Acked-by: Chanwoo Choi Signed-off-by: Sylwester Nawrocki --- drivers/clk/samsung/clk-exynos7.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/samsung/clk-exynos7.c b/drivers/clk/samsung/clk-exynos7.c index 5931a4140c3d..bbfa57b4e017 100644 --- a/drivers/clk/samsung/clk-exynos7.c +++ b/drivers/clk/samsung/clk-exynos7.c @@ -140,7 +140,7 @@ static const struct samsung_div_clock topc_div_clks[] __initconst = { }; static const struct samsung_pll_rate_table pll1460x_24mhz_tbl[] __initconst = { - PLL_36XX_RATE(491520000, 20, 1, 0, 31457), + PLL_36XX_RATE(491519897, 20, 1, 0, 31457), {}, }; -- cgit From 179db533c08431f509a3823077549773d519358b Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Fri, 16 Feb 2018 15:57:53 +0100 Subject: clk: samsung: s3c2410: Fix PLL rates Rates declared in PLL rate tables should match exactly rates calculated from the PLL coefficients. If that is not the case, rate of the PLL's child clock might be set not as expected. For instance, if in the PLL rates table we have a 393216000 Hz entry and the real value as returned by the PLL's recalc_rate callback is 393216003, after setting PLL's clk rate to 393216000 clk_get_rate will return 393216003. If we now attempt to set rate of a PLL's child divider clock to 393216000/2 its rate will be 131072001, rather than 196608000. That is, the divider will be set to 3 instead of 2, because 393216003/2 is greater than 196608000. To fix this issue declared rates are changed to exactly match rates generated by the PLL, as calculated from the P, M, S, K coefficients. Signed-off-by: Andrzej Hajda Acked-by: Tomasz Figa Acked-by: Chanwoo Choi Signed-off-by: Sylwester Nawrocki --- drivers/clk/samsung/clk-s3c2410.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/clk/samsung/clk-s3c2410.c b/drivers/clk/samsung/clk-s3c2410.c index e0650c33863b..d8e58a659467 100644 --- a/drivers/clk/samsung/clk-s3c2410.c +++ b/drivers/clk/samsung/clk-s3c2410.c @@ -168,7 +168,7 @@ static struct samsung_pll_rate_table pll_s3c2410_12mhz_tbl[] __initdata = { PLL_35XX_RATE(226000000, 105, 1, 1), PLL_35XX_RATE(210000000, 132, 2, 1), /* 2410 common */ - PLL_35XX_RATE(203000000, 161, 3, 1), + PLL_35XX_RATE(202800000, 161, 3, 1), PLL_35XX_RATE(192000000, 88, 1, 1), PLL_35XX_RATE(186000000, 85, 1, 1), PLL_35XX_RATE(180000000, 82, 1, 1), @@ -178,18 +178,18 @@ static struct samsung_pll_rate_table pll_s3c2410_12mhz_tbl[] __initdata = { PLL_35XX_RATE(147000000, 90, 2, 1), PLL_35XX_RATE(135000000, 82, 2, 1), PLL_35XX_RATE(124000000, 116, 1, 2), - PLL_35XX_RATE(118000000, 150, 2, 2), + PLL_35XX_RATE(118500000, 150, 2, 2), PLL_35XX_RATE(113000000, 105, 1, 2), - PLL_35XX_RATE(101000000, 127, 2, 2), + PLL_35XX_RATE(101250000, 127, 2, 2), PLL_35XX_RATE(90000000, 112, 2, 2), - PLL_35XX_RATE(85000000, 105, 2, 2), + PLL_35XX_RATE(84750000, 105, 2, 2), PLL_35XX_RATE(79000000, 71, 1, 2), - PLL_35XX_RATE(68000000, 82, 2, 2), - PLL_35XX_RATE(56000000, 142, 2, 3), + PLL_35XX_RATE(67500000, 82, 2, 2), + PLL_35XX_RATE(56250000, 142, 2, 3), PLL_35XX_RATE(48000000, 120, 2, 3), - PLL_35XX_RATE(51000000, 161, 3, 3), + PLL_35XX_RATE(50700000, 161, 3, 3), PLL_35XX_RATE(45000000, 82, 1, 3), - PLL_35XX_RATE(34000000, 82, 2, 3), + PLL_35XX_RATE(33750000, 82, 2, 3), { /* sentinel */ }, }; -- cgit From 1d5013f1b64dbd692975be5db0e42bac291c6de9 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Tue, 20 Feb 2018 08:05:39 +0100 Subject: clk: samsung: Add compile time PLL rate validators Rates declared in PLL rate tables should match exactly rates calculated from PLL coefficients. To avoid possible mistakes we can use compile time validation. The patch introduces such validators and expands all initializers with additional input frequency parameter, required to validate rates. Since S3C24xx PLLs requires different validators two new macros have been introduced to deal with it. Also, since PLLs 4502 and 4508 have different formulas PLL_45XX_RATE has been replaced with PLL_4508_RATE. As the patch adds only compile time validators it should not have impact on compiled code. Signed-off-by: Andrzej Hajda Acked-by: Krzysztof Kozlowski Acked-by: Tomasz Figa Acked-by: Chanwoo Choi Signed-off-by: Sylwester Nawrocki --- drivers/clk/samsung/clk-exynos3250.c | 114 +++++++++++++++++----------------- drivers/clk/samsung/clk-exynos4.c | 102 +++++++++++++++--------------- drivers/clk/samsung/clk-exynos5250.c | 54 ++++++++-------- drivers/clk/samsung/clk-exynos5260.c | 90 +++++++++++++-------------- drivers/clk/samsung/clk-exynos5410.c | 20 +++--- drivers/clk/samsung/clk-exynos5420.c | 62 +++++++++---------- drivers/clk/samsung/clk-exynos5433.c | 116 +++++++++++++++++------------------ drivers/clk/samsung/clk-exynos7.c | 2 +- drivers/clk/samsung/clk-pll.h | 48 ++++++++++++--- drivers/clk/samsung/clk-s3c2410.c | 108 ++++++++++++++++---------------- 10 files changed, 372 insertions(+), 344 deletions(-) diff --git a/drivers/clk/samsung/clk-exynos3250.c b/drivers/clk/samsung/clk-exynos3250.c index ed36728424a2..27c9d23657b3 100644 --- a/drivers/clk/samsung/clk-exynos3250.c +++ b/drivers/clk/samsung/clk-exynos3250.c @@ -670,73 +670,73 @@ static const struct samsung_gate_clock gate_clks[] __initconst = { /* APLL & MPLL & BPLL & UPLL */ static const struct samsung_pll_rate_table exynos3250_pll_rates[] __initconst = { - PLL_35XX_RATE(1200000000, 400, 4, 1), - PLL_35XX_RATE(1100000000, 275, 3, 1), - PLL_35XX_RATE(1066000000, 533, 6, 1), - PLL_35XX_RATE(1000000000, 250, 3, 1), - PLL_35XX_RATE( 960000000, 320, 4, 1), - PLL_35XX_RATE( 900000000, 300, 4, 1), - PLL_35XX_RATE( 850000000, 425, 6, 1), - PLL_35XX_RATE( 800000000, 200, 3, 1), - PLL_35XX_RATE( 700000000, 175, 3, 1), - PLL_35XX_RATE( 667000000, 667, 12, 1), - PLL_35XX_RATE( 600000000, 400, 4, 2), - PLL_35XX_RATE( 533000000, 533, 6, 2), - PLL_35XX_RATE( 520000000, 260, 3, 2), - PLL_35XX_RATE( 500000000, 250, 3, 2), - PLL_35XX_RATE( 400000000, 200, 3, 2), - PLL_35XX_RATE( 200000000, 200, 3, 3), - PLL_35XX_RATE( 100000000, 200, 3, 4), + PLL_35XX_RATE(24 * MHZ, 1200000000, 400, 4, 1), + PLL_35XX_RATE(24 * MHZ, 1100000000, 275, 3, 1), + PLL_35XX_RATE(24 * MHZ, 1066000000, 533, 6, 1), + PLL_35XX_RATE(24 * MHZ, 1000000000, 250, 3, 1), + PLL_35XX_RATE(24 * MHZ, 960000000, 320, 4, 1), + PLL_35XX_RATE(24 * MHZ, 900000000, 300, 4, 1), + PLL_35XX_RATE(24 * MHZ, 850000000, 425, 6, 1), + PLL_35XX_RATE(24 * MHZ, 800000000, 200, 3, 1), + PLL_35XX_RATE(24 * MHZ, 700000000, 175, 3, 1), + PLL_35XX_RATE(24 * MHZ, 667000000, 667, 12, 1), + PLL_35XX_RATE(24 * MHZ, 600000000, 400, 4, 2), + PLL_35XX_RATE(24 * MHZ, 533000000, 533, 6, 2), + PLL_35XX_RATE(24 * MHZ, 520000000, 260, 3, 2), + PLL_35XX_RATE(24 * MHZ, 500000000, 250, 3, 2), + PLL_35XX_RATE(24 * MHZ, 400000000, 200, 3, 2), + PLL_35XX_RATE(24 * MHZ, 200000000, 200, 3, 3), + PLL_35XX_RATE(24 * MHZ, 100000000, 200, 3, 4), { /* sentinel */ } }; /* EPLL */ static const struct samsung_pll_rate_table exynos3250_epll_rates[] __initconst = { - PLL_36XX_RATE(800000000, 200, 3, 1, 0), - PLL_36XX_RATE(288000000, 96, 2, 2, 0), - PLL_36XX_RATE(192000000, 128, 2, 3, 0), - PLL_36XX_RATE(144000000, 96, 2, 3, 0), - PLL_36XX_RATE( 96000000, 128, 2, 4, 0), - PLL_36XX_RATE( 84000000, 112, 2, 4, 0), - PLL_36XX_RATE( 80000003, 106, 2, 4, 43691), - PLL_36XX_RATE( 73728000, 98, 2, 4, 19923), - PLL_36XX_RATE( 67737598, 270, 3, 5, 62285), - PLL_36XX_RATE( 65535999, 174, 2, 5, 49982), - PLL_36XX_RATE( 50000000, 200, 3, 5, 0), - PLL_36XX_RATE( 49152002, 131, 2, 5, 4719), - PLL_36XX_RATE( 48000000, 128, 2, 5, 0), - PLL_36XX_RATE( 45158401, 180, 3, 5, 41524), + PLL_36XX_RATE(24 * MHZ, 800000000, 200, 3, 1, 0), + PLL_36XX_RATE(24 * MHZ, 288000000, 96, 2, 2, 0), + PLL_36XX_RATE(24 * MHZ, 192000000, 128, 2, 3, 0), + PLL_36XX_RATE(24 * MHZ, 144000000, 96, 2, 3, 0), + PLL_36XX_RATE(24 * MHZ, 96000000, 128, 2, 4, 0), + PLL_36XX_RATE(24 * MHZ, 84000000, 112, 2, 4, 0), + PLL_36XX_RATE(24 * MHZ, 80000003, 106, 2, 4, 43691), + PLL_36XX_RATE(24 * MHZ, 73728000, 98, 2, 4, 19923), + PLL_36XX_RATE(24 * MHZ, 67737598, 270, 3, 5, 62285), + PLL_36XX_RATE(24 * MHZ, 65535999, 174, 2, 5, 49982), + PLL_36XX_RATE(24 * MHZ, 50000000, 200, 3, 5, 0), + PLL_36XX_RATE(24 * MHZ, 49152002, 131, 2, 5, 4719), + PLL_36XX_RATE(24 * MHZ, 48000000, 128, 2, 5, 0), + PLL_36XX_RATE(24 * MHZ, 45158401, 180, 3, 5, 41524), { /* sentinel */ } }; /* VPLL */ static const struct samsung_pll_rate_table exynos3250_vpll_rates[] __initconst = { - PLL_36XX_RATE(600000000, 100, 2, 1, 0), - PLL_36XX_RATE(533000000, 266, 3, 2, 32768), - PLL_36XX_RATE(519230987, 173, 2, 2, 5046), - PLL_36XX_RATE(500000000, 250, 3, 2, 0), - PLL_36XX_RATE(445500000, 148, 2, 2, 32768), - PLL_36XX_RATE(445055007, 148, 2, 2, 23047), - PLL_36XX_RATE(400000000, 200, 3, 2, 0), - PLL_36XX_RATE(371250000, 123, 2, 2, 49152), - PLL_36XX_RATE(370878997, 185, 3, 2, 28803), - PLL_36XX_RATE(340000000, 170, 3, 2, 0), - PLL_36XX_RATE(335000015, 111, 2, 2, 43691), - PLL_36XX_RATE(333000000, 111, 2, 2, 0), - PLL_36XX_RATE(330000000, 110, 2, 2, 0), - PLL_36XX_RATE(320000015, 106, 2, 2, 43691), - PLL_36XX_RATE(300000000, 100, 2, 2, 0), - PLL_36XX_RATE(275000000, 275, 3, 3, 0), - PLL_36XX_RATE(222750000, 148, 2, 3, 32768), - PLL_36XX_RATE(222528007, 148, 2, 3, 23069), - PLL_36XX_RATE(160000000, 160, 3, 3, 0), - PLL_36XX_RATE(148500000, 99, 2, 3, 0), - PLL_36XX_RATE(148352005, 98, 2, 3, 59070), - PLL_36XX_RATE(108000000, 144, 2, 4, 0), - PLL_36XX_RATE( 74250000, 99, 2, 4, 0), - PLL_36XX_RATE( 74176002, 98, 2, 4, 59070), - PLL_36XX_RATE( 54054000, 216, 3, 5, 14156), - PLL_36XX_RATE( 54000000, 144, 2, 5, 0), + PLL_36XX_RATE(24 * MHZ, 600000000, 100, 2, 1, 0), + PLL_36XX_RATE(24 * MHZ, 533000000, 266, 3, 2, 32768), + PLL_36XX_RATE(24 * MHZ, 519230987, 173, 2, 2, 5046), + PLL_36XX_RATE(24 * MHZ, 500000000, 250, 3, 2, 0), + PLL_36XX_RATE(24 * MHZ, 445500000, 148, 2, 2, 32768), + PLL_36XX_RATE(24 * MHZ, 445055007, 148, 2, 2, 23047), + PLL_36XX_RATE(24 * MHZ, 400000000, 200, 3, 2, 0), + PLL_36XX_RATE(24 * MHZ, 371250000, 123, 2, 2, 49152), + PLL_36XX_RATE(24 * MHZ, 370878997, 185, 3, 2, 28803), + PLL_36XX_RATE(24 * MHZ, 340000000, 170, 3, 2, 0), + PLL_36XX_RATE(24 * MHZ, 335000015, 111, 2, 2, 43691), + PLL_36XX_RATE(24 * MHZ, 333000000, 111, 2, 2, 0), + PLL_36XX_RATE(24 * MHZ, 330000000, 110, 2, 2, 0), + PLL_36XX_RATE(24 * MHZ, 320000015, 106, 2, 2, 43691), + PLL_36XX_RATE(24 * MHZ, 300000000, 100, 2, 2, 0), + PLL_36XX_RATE(24 * MHZ, 275000000, 275, 3, 3, 0), + PLL_36XX_RATE(24 * MHZ, 222750000, 148, 2, 3, 32768), + PLL_36XX_RATE(24 * MHZ, 222528007, 148, 2, 3, 23069), + PLL_36XX_RATE(24 * MHZ, 160000000, 160, 3, 3, 0), + PLL_36XX_RATE(24 * MHZ, 148500000, 99, 2, 3, 0), + PLL_36XX_RATE(24 * MHZ, 148352005, 98, 2, 3, 59070), + PLL_36XX_RATE(24 * MHZ, 108000000, 144, 2, 4, 0), + PLL_36XX_RATE(24 * MHZ, 74250000, 99, 2, 4, 0), + PLL_36XX_RATE(24 * MHZ, 74176002, 98, 2, 4, 59070), + PLL_36XX_RATE(24 * MHZ, 54054000, 216, 3, 5, 14156), + PLL_36XX_RATE(24 * MHZ, 54000000, 144, 2, 5, 0), { /* sentinel */ } }; diff --git a/drivers/clk/samsung/clk-exynos4.c b/drivers/clk/samsung/clk-exynos4.c index 134f25f2a913..edf125525a36 100644 --- a/drivers/clk/samsung/clk-exynos4.c +++ b/drivers/clk/samsung/clk-exynos4.c @@ -1266,77 +1266,77 @@ static const struct of_device_id ext_clk_match[] __initconst = { /* PLLs PMS values */ static const struct samsung_pll_rate_table exynos4210_apll_rates[] __initconst = { - PLL_45XX_RATE(1200000000, 150, 3, 1, 28), - PLL_45XX_RATE(1000000000, 250, 6, 1, 28), - PLL_45XX_RATE( 800000000, 200, 6, 1, 28), - PLL_45XX_RATE( 666857142, 389, 14, 1, 13), - PLL_45XX_RATE( 600000000, 100, 4, 1, 13), - PLL_45XX_RATE( 533000000, 533, 24, 1, 5), - PLL_45XX_RATE( 500000000, 250, 6, 2, 28), - PLL_45XX_RATE( 400000000, 200, 6, 2, 28), - PLL_45XX_RATE( 200000000, 200, 6, 3, 28), + PLL_4508_RATE(24 * MHZ, 1200000000, 150, 3, 1, 28), + PLL_4508_RATE(24 * MHZ, 1000000000, 250, 6, 1, 28), + PLL_4508_RATE(24 * MHZ, 800000000, 200, 6, 1, 28), + PLL_4508_RATE(24 * MHZ, 666857142, 389, 14, 1, 13), + PLL_4508_RATE(24 * MHZ, 600000000, 100, 4, 1, 13), + PLL_4508_RATE(24 * MHZ, 533000000, 533, 24, 1, 5), + PLL_4508_RATE(24 * MHZ, 500000000, 250, 6, 2, 28), + PLL_4508_RATE(24 * MHZ, 400000000, 200, 6, 2, 28), + PLL_4508_RATE(24 * MHZ, 200000000, 200, 6, 3, 28), { /* sentinel */ } }; static const struct samsung_pll_rate_table exynos4210_epll_rates[] __initconst = { - PLL_4600_RATE(192000000, 48, 3, 1, 0, 0), - PLL_4600_RATE(180633605, 45, 3, 1, 10381, 0), - PLL_4600_RATE(180000000, 45, 3, 1, 0, 0), - PLL_4600_RATE( 73727996, 73, 3, 3, 47710, 1), - PLL_4600_RATE( 67737602, 90, 4, 3, 20762, 1), - PLL_4600_RATE( 49151992, 49, 3, 3, 9961, 0), - PLL_4600_RATE( 45158401, 45, 3, 3, 10381, 0), + PLL_4600_RATE(24 * MHZ, 192000000, 48, 3, 1, 0, 0), + PLL_4600_RATE(24 * MHZ, 180633605, 45, 3, 1, 10381, 0), + PLL_4600_RATE(24 * MHZ, 180000000, 45, 3, 1, 0, 0), + PLL_4600_RATE(24 * MHZ, 73727996, 73, 3, 3, 47710, 1), + PLL_4600_RATE(24 * MHZ, 67737602, 90, 4, 3, 20762, 1), + PLL_4600_RATE(24 * MHZ, 49151992, 49, 3, 3, 9961, 0), + PLL_4600_RATE(24 * MHZ, 45158401, 45, 3, 3, 10381, 0), { /* sentinel */ } }; static const struct samsung_pll_rate_table exynos4210_vpll_rates[] __initconst = { - PLL_4650_RATE(360000000, 44, 3, 0, 1024, 0, 14, 0), - PLL_4650_RATE(324000000, 53, 2, 1, 1024, 1, 1, 1), - PLL_4650_RATE(259617187, 63, 3, 1, 1950, 0, 20, 1), - PLL_4650_RATE(110000000, 53, 3, 2, 2048, 0, 17, 0), - PLL_4650_RATE( 55360351, 53, 3, 3, 2417, 0, 17, 0), + PLL_4650_RATE(24 * MHZ, 360000000, 44, 3, 0, 1024, 0, 14, 0), + PLL_4650_RATE(24 * MHZ, 324000000, 53, 2, 1, 1024, 1, 1, 1), + PLL_4650_RATE(24 * MHZ, 259617187, 63, 3, 1, 1950, 0, 20, 1), + PLL_4650_RATE(24 * MHZ, 110000000, 53, 3, 2, 2048, 0, 17, 0), + PLL_4650_RATE(24 * MHZ, 55360351, 53, 3, 3, 2417, 0, 17, 0), { /* sentinel */ } }; static const struct samsung_pll_rate_table exynos4x12_apll_rates[] __initconst = { - PLL_35XX_RATE(1704000000, 213, 3, 0), - PLL_35XX_RATE(1600000000, 200, 3, 0), - PLL_35XX_RATE(1500000000, 250, 4, 0), - PLL_35XX_RATE(1400000000, 175, 3, 0), - PLL_35XX_RATE(1300000000, 325, 6, 0), - PLL_35XX_RATE(1200000000, 200, 4, 0), - PLL_35XX_RATE(1100000000, 275, 6, 0), - PLL_35XX_RATE(1000000000, 125, 3, 0), - PLL_35XX_RATE( 900000000, 150, 4, 0), - PLL_35XX_RATE( 800000000, 100, 3, 0), - PLL_35XX_RATE( 700000000, 175, 3, 1), - PLL_35XX_RATE( 600000000, 200, 4, 1), - PLL_35XX_RATE( 500000000, 125, 3, 1), - PLL_35XX_RATE( 400000000, 100, 3, 1), - PLL_35XX_RATE( 300000000, 200, 4, 2), - PLL_35XX_RATE( 200000000, 100, 3, 2), + PLL_35XX_RATE(24 * MHZ, 1704000000, 213, 3, 0), + PLL_35XX_RATE(24 * MHZ, 1600000000, 200, 3, 0), + PLL_35XX_RATE(24 * MHZ, 1500000000, 250, 4, 0), + PLL_35XX_RATE(24 * MHZ, 1400000000, 175, 3, 0), + PLL_35XX_RATE(24 * MHZ, 1300000000, 325, 6, 0), + PLL_35XX_RATE(24 * MHZ, 1200000000, 200, 4, 0), + PLL_35XX_RATE(24 * MHZ, 1100000000, 275, 6, 0), + PLL_35XX_RATE(24 * MHZ, 1000000000, 125, 3, 0), + PLL_35XX_RATE(24 * MHZ, 900000000, 150, 4, 0), + PLL_35XX_RATE(24 * MHZ, 800000000, 100, 3, 0), + PLL_35XX_RATE(24 * MHZ, 700000000, 175, 3, 1), + PLL_35XX_RATE(24 * MHZ, 600000000, 200, 4, 1), + PLL_35XX_RATE(24 * MHZ, 500000000, 125, 3, 1), + PLL_35XX_RATE(24 * MHZ, 400000000, 100, 3, 1), + PLL_35XX_RATE(24 * MHZ, 300000000, 200, 4, 2), + PLL_35XX_RATE(24 * MHZ, 200000000, 100, 3, 2), { /* sentinel */ } }; static const struct samsung_pll_rate_table exynos4x12_epll_rates[] __initconst = { - PLL_36XX_RATE(192000000, 48, 3, 1, 0), - PLL_36XX_RATE(180633605, 45, 3, 1, 10381), - PLL_36XX_RATE(180000000, 45, 3, 1, 0), - PLL_36XX_RATE( 73727996, 73, 3, 3, 47710), - PLL_36XX_RATE( 67737602, 90, 4, 3, 20762), - PLL_36XX_RATE( 49151992, 49, 3, 3, 9961), - PLL_36XX_RATE( 45158401, 45, 3, 3, 10381), + PLL_36XX_RATE(24 * MHZ, 192000000, 48, 3, 1, 0), + PLL_36XX_RATE(24 * MHZ, 180633605, 45, 3, 1, 10381), + PLL_36XX_RATE(24 * MHZ, 180000000, 45, 3, 1, 0), + PLL_36XX_RATE(24 * MHZ, 73727996, 73, 3, 3, 47710), + PLL_36XX_RATE(24 * MHZ, 67737602, 90, 4, 3, 20762), + PLL_36XX_RATE(24 * MHZ, 49151992, 49, 3, 3, 9961), + PLL_36XX_RATE(24 * MHZ, 45158401, 45, 3, 3, 10381), { /* sentinel */ } }; static const struct samsung_pll_rate_table exynos4x12_vpll_rates[] __initconst = { - PLL_36XX_RATE(533000000, 133, 3, 1, 16384), - PLL_36XX_RATE(440000000, 110, 3, 1, 0), - PLL_36XX_RATE(350000000, 175, 3, 2, 0), - PLL_36XX_RATE(266000000, 133, 3, 2, 0), - PLL_36XX_RATE(160000000, 160, 3, 3, 0), - PLL_36XX_RATE(106031250, 53, 3, 2, 1024), - PLL_36XX_RATE( 53015625, 53, 3, 3, 1024), + PLL_36XX_RATE(24 * MHZ, 533000000, 133, 3, 1, 16384), + PLL_36XX_RATE(24 * MHZ, 440000000, 110, 3, 1, 0), + PLL_36XX_RATE(24 * MHZ, 350000000, 175, 3, 2, 0), + PLL_36XX_RATE(24 * MHZ, 266000000, 133, 3, 2, 0), + PLL_36XX_RATE(24 * MHZ, 160000000, 160, 3, 3, 0), + PLL_36XX_RATE(24 * MHZ, 106031250, 53, 3, 2, 1024), + PLL_36XX_RATE(24 * MHZ, 53015625, 53, 3, 3, 1024), { /* sentinel */ } }; diff --git a/drivers/clk/samsung/clk-exynos5250.c b/drivers/clk/samsung/clk-exynos5250.c index 923c608b1b95..1b3a8f9cd519 100644 --- a/drivers/clk/samsung/clk-exynos5250.c +++ b/drivers/clk/samsung/clk-exynos5250.c @@ -701,45 +701,45 @@ static const struct samsung_gate_clock exynos5250_gate_clks[] __initconst = { static const struct samsung_pll_rate_table vpll_24mhz_tbl[] __initconst = { /* sorted in descending order */ /* PLL_36XX_RATE(rate, m, p, s, k) */ - PLL_36XX_RATE(266000000, 266, 3, 3, 0), + PLL_36XX_RATE(24 * MHZ, 266000000, 266, 3, 3, 0), /* Not in UM, but need for eDP on snow */ - PLL_36XX_RATE(70500000, 94, 2, 4, 0), + PLL_36XX_RATE(24 * MHZ, 70500000, 94, 2, 4, 0), { }, }; static const struct samsung_pll_rate_table epll_24mhz_tbl[] __initconst = { /* sorted in descending order */ /* PLL_36XX_RATE(rate, m, p, s, k) */ - PLL_36XX_RATE(192000000, 64, 2, 2, 0), - PLL_36XX_RATE(180633605, 90, 3, 2, 20762), - PLL_36XX_RATE(180000000, 90, 3, 2, 0), - PLL_36XX_RATE(73728000, 98, 2, 4, 19923), - PLL_36XX_RATE(67737602, 90, 2, 4, 20762), - PLL_36XX_RATE(49152000, 98, 3, 4, 19923), - PLL_36XX_RATE(45158401, 90, 3, 4, 20762), - PLL_36XX_RATE(32768001, 131, 3, 5, 4719), + PLL_36XX_RATE(24 * MHZ, 192000000, 64, 2, 2, 0), + PLL_36XX_RATE(24 * MHZ, 180633605, 90, 3, 2, 20762), + PLL_36XX_RATE(24 * MHZ, 180000000, 90, 3, 2, 0), + PLL_36XX_RATE(24 * MHZ, 73728000, 98, 2, 4, 19923), + PLL_36XX_RATE(24 * MHZ, 67737602, 90, 2, 4, 20762), + PLL_36XX_RATE(24 * MHZ, 49152000, 98, 3, 4, 19923), + PLL_36XX_RATE(24 * MHZ, 45158401, 90, 3, 4, 20762), + PLL_36XX_RATE(24 * MHZ, 32768001, 131, 3, 5, 4719), { }, }; static const struct samsung_pll_rate_table apll_24mhz_tbl[] __initconst = { /* sorted in descending order */ - /* PLL_35XX_RATE(rate, m, p, s) */ - PLL_35XX_RATE(1700000000, 425, 6, 0), - PLL_35XX_RATE(1600000000, 200, 3, 0), - PLL_35XX_RATE(1500000000, 250, 4, 0), - PLL_35XX_RATE(1400000000, 175, 3, 0), - PLL_35XX_RATE(1300000000, 325, 6, 0), - PLL_35XX_RATE(1200000000, 200, 4, 0), - PLL_35XX_RATE(1100000000, 275, 6, 0), - PLL_35XX_RATE(1000000000, 125, 3, 0), - PLL_35XX_RATE(900000000, 150, 4, 0), - PLL_35XX_RATE(800000000, 100, 3, 0), - PLL_35XX_RATE(700000000, 175, 3, 1), - PLL_35XX_RATE(600000000, 200, 4, 1), - PLL_35XX_RATE(500000000, 125, 3, 1), - PLL_35XX_RATE(400000000, 100, 3, 1), - PLL_35XX_RATE(300000000, 200, 4, 2), - PLL_35XX_RATE(200000000, 100, 3, 2), + /* PLL_35XX_RATE(fin, rate, m, p, s) */ + PLL_35XX_RATE(24 * MHZ, 1700000000, 425, 6, 0), + PLL_35XX_RATE(24 * MHZ, 1600000000, 200, 3, 0), + PLL_35XX_RATE(24 * MHZ, 1500000000, 250, 4, 0), + PLL_35XX_RATE(24 * MHZ, 1400000000, 175, 3, 0), + PLL_35XX_RATE(24 * MHZ, 1300000000, 325, 6, 0), + PLL_35XX_RATE(24 * MHZ, 1200000000, 200, 4, 0), + PLL_35XX_RATE(24 * MHZ, 1100000000, 275, 6, 0), + PLL_35XX_RATE(24 * MHZ, 1000000000, 125, 3, 0), + PLL_35XX_RATE(24 * MHZ, 900000000, 150, 4, 0), + PLL_35XX_RATE(24 * MHZ, 800000000, 100, 3, 0), + PLL_35XX_RATE(24 * MHZ, 700000000, 175, 3, 1), + PLL_35XX_RATE(24 * MHZ, 600000000, 200, 4, 1), + PLL_35XX_RATE(24 * MHZ, 500000000, 125, 3, 1), + PLL_35XX_RATE(24 * MHZ, 400000000, 100, 3, 1), + PLL_35XX_RATE(24 * MHZ, 300000000, 200, 4, 2), + PLL_35XX_RATE(24 * MHZ, 200000000, 100, 3, 2), }; static struct samsung_pll_clock exynos5250_plls[nr_plls] __initdata = { diff --git a/drivers/clk/samsung/clk-exynos5260.c b/drivers/clk/samsung/clk-exynos5260.c index 8eae1752d700..2cc2583abd87 100644 --- a/drivers/clk/samsung/clk-exynos5260.c +++ b/drivers/clk/samsung/clk-exynos5260.c @@ -23,57 +23,57 @@ * DISP_PLL, EGL_PLL, KFC_PLL, MEM_PLL, BUS_PLL, MEDIA_PLL, G3D_PLL. */ static const struct samsung_pll_rate_table pll2550_24mhz_tbl[] __initconst = { - PLL_35XX_RATE(1700000000, 425, 6, 0), - PLL_35XX_RATE(1600000000, 200, 3, 0), - PLL_35XX_RATE(1500000000, 250, 4, 0), - PLL_35XX_RATE(1400000000, 175, 3, 0), - PLL_35XX_RATE(1300000000, 325, 6, 0), - PLL_35XX_RATE(1200000000, 400, 4, 1), - PLL_35XX_RATE(1100000000, 275, 3, 1), - PLL_35XX_RATE(1000000000, 250, 3, 1), - PLL_35XX_RATE(933000000, 311, 4, 1), - PLL_35XX_RATE(900000000, 300, 4, 1), - PLL_35XX_RATE(800000000, 200, 3, 1), - PLL_35XX_RATE(733000000, 733, 12, 1), - PLL_35XX_RATE(700000000, 175, 3, 1), - PLL_35XX_RATE(667000000, 667, 12, 1), - PLL_35XX_RATE(633000000, 211, 4, 1), - PLL_35XX_RATE(620000000, 310, 3, 2), - PLL_35XX_RATE(600000000, 400, 4, 2), - PLL_35XX_RATE(543000000, 362, 4, 2), - PLL_35XX_RATE(533000000, 533, 6, 2), - PLL_35XX_RATE(500000000, 250, 3, 2), - PLL_35XX_RATE(450000000, 300, 4, 2), - PLL_35XX_RATE(400000000, 200, 3, 2), - PLL_35XX_RATE(350000000, 175, 3, 2), - PLL_35XX_RATE(300000000, 400, 4, 3), - PLL_35XX_RATE(266000000, 266, 3, 3), - PLL_35XX_RATE(200000000, 200, 3, 3), - PLL_35XX_RATE(160000000, 160, 3, 3), + PLL_35XX_RATE(24 * MHZ, 1700000000, 425, 6, 0), + PLL_35XX_RATE(24 * MHZ, 1600000000, 200, 3, 0), + PLL_35XX_RATE(24 * MHZ, 1500000000, 250, 4, 0), + PLL_35XX_RATE(24 * MHZ, 1400000000, 175, 3, 0), + PLL_35XX_RATE(24 * MHZ, 1300000000, 325, 6, 0), + PLL_35XX_RATE(24 * MHZ, 1200000000, 400, 4, 1), + PLL_35XX_RATE(24 * MHZ, 1100000000, 275, 3, 1), + PLL_35XX_RATE(24 * MHZ, 1000000000, 250, 3, 1), + PLL_35XX_RATE(24 * MHZ, 933000000, 311, 4, 1), + PLL_35XX_RATE(24 * MHZ, 900000000, 300, 4, 1), + PLL_35XX_RATE(24 * MHZ, 800000000, 200, 3, 1), + PLL_35XX_RATE(24 * MHZ, 733000000, 733, 12, 1), + PLL_35XX_RATE(24 * MHZ, 700000000, 175, 3, 1), + PLL_35XX_RATE(24 * MHZ, 667000000, 667, 12, 1), + PLL_35XX_RATE(24 * MHZ, 633000000, 211, 4, 1), + PLL_35XX_RATE(24 * MHZ, 620000000, 310, 3, 2), + PLL_35XX_RATE(24 * MHZ, 600000000, 400, 4, 2), + PLL_35XX_RATE(24 * MHZ, 543000000, 362, 4, 2), + PLL_35XX_RATE(24 * MHZ, 533000000, 533, 6, 2), + PLL_35XX_RATE(24 * MHZ, 500000000, 250, 3, 2), + PLL_35XX_RATE(24 * MHZ, 450000000, 300, 4, 2), + PLL_35XX_RATE(24 * MHZ, 400000000, 200, 3, 2), + PLL_35XX_RATE(24 * MHZ, 350000000, 175, 3, 2), + PLL_35XX_RATE(24 * MHZ, 300000000, 400, 4, 3), + PLL_35XX_RATE(24 * MHZ, 266000000, 266, 3, 3), + PLL_35XX_RATE(24 * MHZ, 200000000, 200, 3, 3), + PLL_35XX_RATE(24 * MHZ, 160000000, 160, 3, 3), }; /* * Applicable for 2650 Type PLL for AUD_PLL. */ static const struct samsung_pll_rate_table pll2650_24mhz_tbl[] __initconst = { - PLL_36XX_RATE(1600000000, 200, 3, 0, 0), - PLL_36XX_RATE(1200000000, 100, 2, 0, 0), - PLL_36XX_RATE(1000000000, 250, 3, 1, 0), - PLL_36XX_RATE(800000000, 200, 3, 1, 0), - PLL_36XX_RATE(600000000, 100, 2, 1, 0), - PLL_36XX_RATE(532000000, 266, 3, 2, 0), - PLL_36XX_RATE(480000000, 160, 2, 2, 0), - PLL_36XX_RATE(432000000, 144, 2, 2, 0), - PLL_36XX_RATE(400000000, 200, 3, 2, 0), - PLL_36XX_RATE(394073128, 459, 7, 2, 49282), - PLL_36XX_RATE(333000000, 111, 2, 2, 0), - PLL_36XX_RATE(300000000, 100, 2, 2, 0), - PLL_36XX_RATE(266000000, 266, 3, 3, 0), - PLL_36XX_RATE(200000000, 200, 3, 3, 0), - PLL_36XX_RATE(166000000, 166, 3, 3, 0), - PLL_36XX_RATE(133000000, 266, 3, 4, 0), - PLL_36XX_RATE(100000000, 200, 3, 4, 0), - PLL_36XX_RATE(66000000, 176, 2, 5, 0), + PLL_36XX_RATE(24 * MHZ, 1600000000, 200, 3, 0, 0), + PLL_36XX_RATE(24 * MHZ, 1200000000, 100, 2, 0, 0), + PLL_36XX_RATE(24 * MHZ, 1000000000, 250, 3, 1, 0), + PLL_36XX_RATE(24 * MHZ, 800000000, 200, 3, 1, 0), + PLL_36XX_RATE(24 * MHZ, 600000000, 100, 2, 1, 0), + PLL_36XX_RATE(24 * MHZ, 532000000, 266, 3, 2, 0), + PLL_36XX_RATE(24 * MHZ, 480000000, 160, 2, 2, 0), + PLL_36XX_RATE(24 * MHZ, 432000000, 144, 2, 2, 0), + PLL_36XX_RATE(24 * MHZ, 400000000, 200, 3, 2, 0), + PLL_36XX_RATE(24 * MHZ, 394073128, 459, 7, 2, 49282), + PLL_36XX_RATE(24 * MHZ, 333000000, 111, 2, 2, 0), + PLL_36XX_RATE(24 * MHZ, 300000000, 100, 2, 2, 0), + PLL_36XX_RATE(24 * MHZ, 266000000, 266, 3, 3, 0), + PLL_36XX_RATE(24 * MHZ, 200000000, 200, 3, 3, 0), + PLL_36XX_RATE(24 * MHZ, 166000000, 166, 3, 3, 0), + PLL_36XX_RATE(24 * MHZ, 133000000, 266, 3, 4, 0), + PLL_36XX_RATE(24 * MHZ, 100000000, 200, 3, 4, 0), + PLL_36XX_RATE(24 * MHZ, 66000000, 176, 2, 5, 0), }; /* CMU_AUD */ diff --git a/drivers/clk/samsung/clk-exynos5410.c b/drivers/clk/samsung/clk-exynos5410.c index fc471a49e8f4..0a0b09591e6f 100644 --- a/drivers/clk/samsung/clk-exynos5410.c +++ b/drivers/clk/samsung/clk-exynos5410.c @@ -226,16 +226,16 @@ static const struct samsung_gate_clock exynos5410_gate_clks[] __initconst = { }; static const struct samsung_pll_rate_table exynos5410_pll2550x_24mhz_tbl[] __initconst = { - PLL_36XX_RATE(400000000U, 200, 3, 2, 0), - PLL_36XX_RATE(333000000U, 111, 2, 2, 0), - PLL_36XX_RATE(300000000U, 100, 2, 2, 0), - PLL_36XX_RATE(266000000U, 266, 3, 3, 0), - PLL_36XX_RATE(200000000U, 200, 3, 3, 0), - PLL_36XX_RATE(192000000U, 192, 3, 3, 0), - PLL_36XX_RATE(166000000U, 166, 3, 3, 0), - PLL_36XX_RATE(133000000U, 266, 3, 4, 0), - PLL_36XX_RATE(100000000U, 200, 3, 4, 0), - PLL_36XX_RATE(66000000U, 176, 2, 5, 0), + PLL_36XX_RATE(24 * MHZ, 400000000U, 200, 3, 2, 0), + PLL_36XX_RATE(24 * MHZ, 333000000U, 111, 2, 2, 0), + PLL_36XX_RATE(24 * MHZ, 300000000U, 100, 2, 2, 0), + PLL_36XX_RATE(24 * MHZ, 266000000U, 266, 3, 3, 0), + PLL_36XX_RATE(24 * MHZ, 200000000U, 200, 3, 3, 0), + PLL_36XX_RATE(24 * MHZ, 192000000U, 192, 3, 3, 0), + PLL_36XX_RATE(24 * MHZ, 166000000U, 166, 3, 3, 0), + PLL_36XX_RATE(24 * MHZ, 133000000U, 266, 3, 4, 0), + PLL_36XX_RATE(24 * MHZ, 100000000U, 200, 3, 4, 0), + PLL_36XX_RATE(24 * MHZ, 66000000U, 176, 2, 5, 0), }; static struct samsung_pll_clock exynos5410_plls[nr_plls] __initdata = { diff --git a/drivers/clk/samsung/clk-exynos5420.c b/drivers/clk/samsung/clk-exynos5420.c index 45d34f601e9e..6b10b70f7d72 100644 --- a/drivers/clk/samsung/clk-exynos5420.c +++ b/drivers/clk/samsung/clk-exynos5420.c @@ -1263,40 +1263,40 @@ static const struct samsung_gate_clock exynos5x_gate_clks[] __initconst = { }; static const struct samsung_pll_rate_table exynos5420_pll2550x_24mhz_tbl[] __initconst = { - PLL_35XX_RATE(2000000000, 250, 3, 0), - PLL_35XX_RATE(1900000000, 475, 6, 0), - PLL_35XX_RATE(1800000000, 225, 3, 0), - PLL_35XX_RATE(1700000000, 425, 6, 0), - PLL_35XX_RATE(1600000000, 200, 3, 0), - PLL_35XX_RATE(1500000000, 250, 4, 0), - PLL_35XX_RATE(1400000000, 175, 3, 0), - PLL_35XX_RATE(1300000000, 325, 6, 0), - PLL_35XX_RATE(1200000000, 200, 2, 1), - PLL_35XX_RATE(1100000000, 275, 3, 1), - PLL_35XX_RATE(1000000000, 250, 3, 1), - PLL_35XX_RATE(900000000, 150, 2, 1), - PLL_35XX_RATE(800000000, 200, 3, 1), - PLL_35XX_RATE(700000000, 175, 3, 1), - PLL_35XX_RATE(600000000, 200, 2, 2), - PLL_35XX_RATE(500000000, 250, 3, 2), - PLL_35XX_RATE(400000000, 200, 3, 2), - PLL_35XX_RATE(300000000, 200, 2, 3), - PLL_35XX_RATE(200000000, 200, 3, 3), + PLL_35XX_RATE(24 * MHZ, 2000000000, 250, 3, 0), + PLL_35XX_RATE(24 * MHZ, 1900000000, 475, 6, 0), + PLL_35XX_RATE(24 * MHZ, 1800000000, 225, 3, 0), + PLL_35XX_RATE(24 * MHZ, 1700000000, 425, 6, 0), + PLL_35XX_RATE(24 * MHZ, 1600000000, 200, 3, 0), + PLL_35XX_RATE(24 * MHZ, 1500000000, 250, 4, 0), + PLL_35XX_RATE(24 * MHZ, 1400000000, 175, 3, 0), + PLL_35XX_RATE(24 * MHZ, 1300000000, 325, 6, 0), + PLL_35XX_RATE(24 * MHZ, 1200000000, 200, 2, 1), + PLL_35XX_RATE(24 * MHZ, 1100000000, 275, 3, 1), + PLL_35XX_RATE(24 * MHZ, 1000000000, 250, 3, 1), + PLL_35XX_RATE(24 * MHZ, 900000000, 150, 2, 1), + PLL_35XX_RATE(24 * MHZ, 800000000, 200, 3, 1), + PLL_35XX_RATE(24 * MHZ, 700000000, 175, 3, 1), + PLL_35XX_RATE(24 * MHZ, 600000000, 200, 2, 2), + PLL_35XX_RATE(24 * MHZ, 500000000, 250, 3, 2), + PLL_35XX_RATE(24 * MHZ, 400000000, 200, 3, 2), + PLL_35XX_RATE(24 * MHZ, 300000000, 200, 2, 3), + PLL_35XX_RATE(24 * MHZ, 200000000, 200, 3, 3), }; static const struct samsung_pll_rate_table exynos5420_epll_24mhz_tbl[] = { - PLL_36XX_RATE(600000000U, 100, 2, 1, 0), - PLL_36XX_RATE(400000000U, 200, 3, 2, 0), - PLL_36XX_RATE(393216003U, 197, 3, 2, -25690), - PLL_36XX_RATE(361267218U, 301, 5, 2, 3671), - PLL_36XX_RATE(200000000U, 200, 3, 3, 0), - PLL_36XX_RATE(196608001U, 197, 3, 3, -25690), - PLL_36XX_RATE(180633609U, 301, 5, 3, 3671), - PLL_36XX_RATE(131072006U, 131, 3, 3, 4719), - PLL_36XX_RATE(100000000U, 200, 3, 4, 0), - PLL_36XX_RATE( 65536003U, 131, 3, 4, 4719), - PLL_36XX_RATE( 49152000U, 197, 3, 5, -25690), - PLL_36XX_RATE( 32768001U, 131, 3, 5, 4719), + PLL_36XX_RATE(24 * MHZ, 600000000U, 100, 2, 1, 0), + PLL_36XX_RATE(24 * MHZ, 400000000U, 200, 3, 2, 0), + PLL_36XX_RATE(24 * MHZ, 393216003U, 197, 3, 2, -25690), + PLL_36XX_RATE(24 * MHZ, 361267218U, 301, 5, 2, 3671), + PLL_36XX_RATE(24 * MHZ, 200000000U, 200, 3, 3, 0), + PLL_36XX_RATE(24 * MHZ, 196608001U, 197, 3, 3, -25690), + PLL_36XX_RATE(24 * MHZ, 180633609U, 301, 5, 3, 3671), + PLL_36XX_RATE(24 * MHZ, 131072006U, 131, 3, 3, 4719), + PLL_36XX_RATE(24 * MHZ, 100000000U, 200, 3, 4, 0), + PLL_36XX_RATE(24 * MHZ, 65536003U, 131, 3, 4, 4719), + PLL_36XX_RATE(24 * MHZ, 49152000U, 197, 3, 5, -25690), + PLL_36XX_RATE(24 * MHZ, 32768001U, 131, 3, 5, 4719), }; static struct samsung_pll_clock exynos5x_plls[nr_plls] __initdata = { diff --git a/drivers/clk/samsung/clk-exynos5433.c b/drivers/clk/samsung/clk-exynos5433.c index 7985352ceb2f..5305ace514b2 100644 --- a/drivers/clk/samsung/clk-exynos5433.c +++ b/drivers/clk/samsung/clk-exynos5433.c @@ -703,69 +703,69 @@ static const struct samsung_gate_clock top_gate_clks[] __initconst = { * & MPHY_PLL & G3D_PLL & DISP_PLL & ISP_PLL */ static const struct samsung_pll_rate_table exynos5433_pll_rates[] __initconst = { - PLL_35XX_RATE(2500000000U, 625, 6, 0), - PLL_35XX_RATE(2400000000U, 500, 5, 0), - PLL_35XX_RATE(2300000000U, 575, 6, 0), - PLL_35XX_RATE(2200000000U, 550, 6, 0), - PLL_35XX_RATE(2100000000U, 350, 4, 0), - PLL_35XX_RATE(2000000000U, 500, 6, 0), - PLL_35XX_RATE(1900000000U, 475, 6, 0), - PLL_35XX_RATE(1800000000U, 375, 5, 0), - PLL_35XX_RATE(1700000000U, 425, 6, 0), - PLL_35XX_RATE(1600000000U, 400, 6, 0), - PLL_35XX_RATE(1500000000U, 250, 4, 0), - PLL_35XX_RATE(1400000000U, 350, 6, 0), - PLL_35XX_RATE(1332000000U, 222, 4, 0), - PLL_35XX_RATE(1300000000U, 325, 6, 0), - PLL_35XX_RATE(1200000000U, 500, 5, 1), - PLL_35XX_RATE(1100000000U, 550, 6, 1), - PLL_35XX_RATE(1086000000U, 362, 4, 1), - PLL_35XX_RATE(1066000000U, 533, 6, 1), - PLL_35XX_RATE(1000000000U, 500, 6, 1), - PLL_35XX_RATE(933000000U, 311, 4, 1), - PLL_35XX_RATE(921000000U, 307, 4, 1), - PLL_35XX_RATE(900000000U, 375, 5, 1), - PLL_35XX_RATE(825000000U, 275, 4, 1), - PLL_35XX_RATE(800000000U, 400, 6, 1), - PLL_35XX_RATE(733000000U, 733, 12, 1), - PLL_35XX_RATE(700000000U, 175, 3, 1), - PLL_35XX_RATE(666000000U, 222, 4, 1), - PLL_35XX_RATE(633000000U, 211, 4, 1), - PLL_35XX_RATE(600000000U, 500, 5, 2), - PLL_35XX_RATE(552000000U, 460, 5, 2), - PLL_35XX_RATE(550000000U, 550, 6, 2), - PLL_35XX_RATE(543000000U, 362, 4, 2), - PLL_35XX_RATE(533000000U, 533, 6, 2), - PLL_35XX_RATE(500000000U, 500, 6, 2), - PLL_35XX_RATE(444000000U, 370, 5, 2), - PLL_35XX_RATE(420000000U, 350, 5, 2), - PLL_35XX_RATE(400000000U, 400, 6, 2), - PLL_35XX_RATE(350000000U, 350, 6, 2), - PLL_35XX_RATE(333000000U, 222, 4, 2), - PLL_35XX_RATE(300000000U, 500, 5, 3), - PLL_35XX_RATE(278000000U, 556, 6, 3), - PLL_35XX_RATE(266000000U, 532, 6, 3), - PLL_35XX_RATE(250000000U, 500, 6, 3), - PLL_35XX_RATE(200000000U, 400, 6, 3), - PLL_35XX_RATE(166000000U, 332, 6, 3), - PLL_35XX_RATE(160000000U, 320, 6, 3), - PLL_35XX_RATE(133000000U, 532, 6, 4), - PLL_35XX_RATE(100000000U, 400, 6, 4), + PLL_35XX_RATE(24 * MHZ, 2500000000U, 625, 6, 0), + PLL_35XX_RATE(24 * MHZ, 2400000000U, 500, 5, 0), + PLL_35XX_RATE(24 * MHZ, 2300000000U, 575, 6, 0), + PLL_35XX_RATE(24 * MHZ, 2200000000U, 550, 6, 0), + PLL_35XX_RATE(24 * MHZ, 2100000000U, 350, 4, 0), + PLL_35XX_RATE(24 * MHZ, 2000000000U, 500, 6, 0), + PLL_35XX_RATE(24 * MHZ, 1900000000U, 475, 6, 0), + PLL_35XX_RATE(24 * MHZ, 1800000000U, 375, 5, 0), + PLL_35XX_RATE(24 * MHZ, 1700000000U, 425, 6, 0), + PLL_35XX_RATE(24 * MHZ, 1600000000U, 400, 6, 0), + PLL_35XX_RATE(24 * MHZ, 1500000000U, 250, 4, 0), + PLL_35XX_RATE(24 * MHZ, 1400000000U, 350, 6, 0), + PLL_35XX_RATE(24 * MHZ, 1332000000U, 222, 4, 0), + PLL_35XX_RATE(24 * MHZ, 1300000000U, 325, 6, 0), + PLL_35XX_RATE(24 * MHZ, 1200000000U, 500, 5, 1), + PLL_35XX_RATE(24 * MHZ, 1100000000U, 550, 6, 1), + PLL_35XX_RATE(24 * MHZ, 1086000000U, 362, 4, 1), + PLL_35XX_RATE(24 * MHZ, 1066000000U, 533, 6, 1), + PLL_35XX_RATE(24 * MHZ, 1000000000U, 500, 6, 1), + PLL_35XX_RATE(24 * MHZ, 933000000U, 311, 4, 1), + PLL_35XX_RATE(24 * MHZ, 921000000U, 307, 4, 1), + PLL_35XX_RATE(24 * MHZ, 900000000U, 375, 5, 1), + PLL_35XX_RATE(24 * MHZ, 825000000U, 275, 4, 1), + PLL_35XX_RATE(24 * MHZ, 800000000U, 400, 6, 1), + PLL_35XX_RATE(24 * MHZ, 733000000U, 733, 12, 1), + PLL_35XX_RATE(24 * MHZ, 700000000U, 175, 3, 1), + PLL_35XX_RATE(24 * MHZ, 666000000U, 222, 4, 1), + PLL_35XX_RATE(24 * MHZ, 633000000U, 211, 4, 1), + PLL_35XX_RATE(24 * MHZ, 600000000U, 500, 5, 2), + PLL_35XX_RATE(24 * MHZ, 552000000U, 460, 5, 2), + PLL_35XX_RATE(24 * MHZ, 550000000U, 550, 6, 2), + PLL_35XX_RATE(24 * MHZ, 543000000U, 362, 4, 2), + PLL_35XX_RATE(24 * MHZ, 533000000U, 533, 6, 2), + PLL_35XX_RATE(24 * MHZ, 500000000U, 500, 6, 2), + PLL_35XX_RATE(24 * MHZ, 444000000U, 370, 5, 2), + PLL_35XX_RATE(24 * MHZ, 420000000U, 350, 5, 2), + PLL_35XX_RATE(24 * MHZ, 400000000U, 400, 6, 2), + PLL_35XX_RATE(24 * MHZ, 350000000U, 350, 6, 2), + PLL_35XX_RATE(24 * MHZ, 333000000U, 222, 4, 2), + PLL_35XX_RATE(24 * MHZ, 300000000U, 500, 5, 3), + PLL_35XX_RATE(24 * MHZ, 278000000U, 556, 6, 3), + PLL_35XX_RATE(24 * MHZ, 266000000U, 532, 6, 3), + PLL_35XX_RATE(24 * MHZ, 250000000U, 500, 6, 3), + PLL_35XX_RATE(24 * MHZ, 200000000U, 400, 6, 3), + PLL_35XX_RATE(24 * MHZ, 166000000U, 332, 6, 3), + PLL_35XX_RATE(24 * MHZ, 160000000U, 320, 6, 3), + PLL_35XX_RATE(24 * MHZ, 133000000U, 532, 6, 4), + PLL_35XX_RATE(24 * MHZ, 100000000U, 400, 6, 4), { /* sentinel */ } }; /* AUD_PLL */ static const struct samsung_pll_rate_table exynos5433_aud_pll_rates[] __initconst = { - PLL_36XX_RATE(400000000U, 200, 3, 2, 0), - PLL_36XX_RATE(393216003U, 197, 3, 2, -25690), - PLL_36XX_RATE(384000000U, 128, 2, 2, 0), - PLL_36XX_RATE(368639991U, 246, 4, 2, -15729), - PLL_36XX_RATE(361507202U, 181, 3, 2, -16148), - PLL_36XX_RATE(338687988U, 113, 2, 2, -6816), - PLL_36XX_RATE(294912002U, 98, 1, 3, 19923), - PLL_36XX_RATE(288000000U, 96, 1, 3, 0), - PLL_36XX_RATE(252000000U, 84, 1, 3, 0), - PLL_36XX_RATE(196608001U, 197, 3, 3, -25690), + PLL_36XX_RATE(24 * MHZ, 400000000U, 200, 3, 2, 0), + PLL_36XX_RATE(24 * MHZ, 393216003U, 197, 3, 2, -25690), + PLL_36XX_RATE(24 * MHZ, 384000000U, 128, 2, 2, 0), + PLL_36XX_RATE(24 * MHZ, 368639991U, 246, 4, 2, -15729), + PLL_36XX_RATE(24 * MHZ, 361507202U, 181, 3, 2, -16148), + PLL_36XX_RATE(24 * MHZ, 338687988U, 113, 2, 2, -6816), + PLL_36XX_RATE(24 * MHZ, 294912002U, 98, 1, 3, 19923), + PLL_36XX_RATE(24 * MHZ, 288000000U, 96, 1, 3, 0), + PLL_36XX_RATE(24 * MHZ, 252000000U, 84, 1, 3, 0), + PLL_36XX_RATE(24 * MHZ, 196608001U, 197, 3, 3, -25690), { /* sentinel */ } }; diff --git a/drivers/clk/samsung/clk-exynos7.c b/drivers/clk/samsung/clk-exynos7.c index bbfa57b4e017..492d51691080 100644 --- a/drivers/clk/samsung/clk-exynos7.c +++ b/drivers/clk/samsung/clk-exynos7.c @@ -140,7 +140,7 @@ static const struct samsung_div_clock topc_div_clks[] __initconst = { }; static const struct samsung_pll_rate_table pll1460x_24mhz_tbl[] __initconst = { - PLL_36XX_RATE(491519897, 20, 1, 0, 31457), + PLL_36XX_RATE(24 * MHZ, 491519897, 20, 1, 0, 31457), {}, }; diff --git a/drivers/clk/samsung/clk-pll.h b/drivers/clk/samsung/clk-pll.h index 61eb8abbfd9c..ca57b3dfa814 100644 --- a/drivers/clk/samsung/clk-pll.h +++ b/drivers/clk/samsung/clk-pll.h @@ -41,35 +41,62 @@ enum samsung_pll_type { pll_1460x, }; -#define PLL_35XX_RATE(_rate, _m, _p, _s) \ +#define PLL_RATE(_fin, _m, _p, _s, _k, _ks) \ + ((u64)(_fin) * (BIT(_ks) * (_m) + (_k)) / BIT(_ks) / ((_p) << (_s))) +#define PLL_VALID_RATE(_fin, _fout, _m, _p, _s, _k, _ks) ((_fout) + \ + BUILD_BUG_ON_ZERO(PLL_RATE(_fin, _m, _p, _s, _k, _ks) != (_fout))) + +#define PLL_35XX_RATE(_fin, _rate, _m, _p, _s) \ + { \ + .rate = PLL_VALID_RATE(_fin, _rate, \ + _m, _p, _s, 0, 16), \ + .mdiv = (_m), \ + .pdiv = (_p), \ + .sdiv = (_s), \ + } + +#define PLL_S3C2410_MPLL_RATE(_fin, _rate, _m, _p, _s) \ + { \ + .rate = PLL_VALID_RATE(_fin, _rate, \ + _m + 8, _p + 2, _s, 0, 16), \ + .mdiv = (_m), \ + .pdiv = (_p), \ + .sdiv = (_s), \ + } + +#define PLL_S3C2440_MPLL_RATE(_fin, _rate, _m, _p, _s) \ { \ - .rate = (_rate), \ + .rate = PLL_VALID_RATE(_fin, _rate, \ + 2 * (_m + 8), _p + 2, _s, 0, 16), \ .mdiv = (_m), \ .pdiv = (_p), \ .sdiv = (_s), \ } -#define PLL_36XX_RATE(_rate, _m, _p, _s, _k) \ +#define PLL_36XX_RATE(_fin, _rate, _m, _p, _s, _k) \ { \ - .rate = (_rate), \ + .rate = PLL_VALID_RATE(_fin, _rate, \ + _m, _p, _s, _k, 16), \ .mdiv = (_m), \ .pdiv = (_p), \ .sdiv = (_s), \ .kdiv = (_k), \ } -#define PLL_45XX_RATE(_rate, _m, _p, _s, _afc) \ +#define PLL_4508_RATE(_fin, _rate, _m, _p, _s, _afc) \ { \ - .rate = (_rate), \ + .rate = PLL_VALID_RATE(_fin, _rate, \ + _m, _p, _s - 1, 0, 16), \ .mdiv = (_m), \ .pdiv = (_p), \ .sdiv = (_s), \ .afc = (_afc), \ } -#define PLL_4600_RATE(_rate, _m, _p, _s, _k, _vsel) \ +#define PLL_4600_RATE(_fin, _rate, _m, _p, _s, _k, _vsel) \ { \ - .rate = (_rate), \ + .rate = PLL_VALID_RATE(_fin, _rate, \ + _m, _p, _s, _k, 16), \ .mdiv = (_m), \ .pdiv = (_p), \ .sdiv = (_s), \ @@ -77,9 +104,10 @@ enum samsung_pll_type { .vsel = (_vsel), \ } -#define PLL_4650_RATE(_rate, _m, _p, _s, _k, _mfr, _mrr, _vsel) \ +#define PLL_4650_RATE(_fin, _rate, _m, _p, _s, _k, _mfr, _mrr, _vsel) \ { \ - .rate = (_rate), \ + .rate = PLL_VALID_RATE(_fin, _rate, \ + _m, _p, _s, _k, 10), \ .mdiv = (_m), \ .pdiv = (_p), \ .sdiv = (_s), \ diff --git a/drivers/clk/samsung/clk-s3c2410.c b/drivers/clk/samsung/clk-s3c2410.c index d8e58a659467..0c6aa3e51336 100644 --- a/drivers/clk/samsung/clk-s3c2410.c +++ b/drivers/clk/samsung/clk-s3c2410.c @@ -162,34 +162,34 @@ struct samsung_clock_alias s3c2410_common_aliases[] __initdata = { static struct samsung_pll_rate_table pll_s3c2410_12mhz_tbl[] __initdata = { /* sorted in descending order */ /* 2410A extras */ - PLL_35XX_RATE(270000000, 127, 1, 1), - PLL_35XX_RATE(268000000, 126, 1, 1), - PLL_35XX_RATE(266000000, 125, 1, 1), - PLL_35XX_RATE(226000000, 105, 1, 1), - PLL_35XX_RATE(210000000, 132, 2, 1), + PLL_S3C2410_MPLL_RATE(12 * MHZ, 270000000, 127, 1, 1), + PLL_S3C2410_MPLL_RATE(12 * MHZ, 268000000, 126, 1, 1), + PLL_S3C2410_MPLL_RATE(12 * MHZ, 266000000, 125, 1, 1), + PLL_S3C2410_MPLL_RATE(12 * MHZ, 226000000, 105, 1, 1), + PLL_S3C2410_MPLL_RATE(12 * MHZ, 210000000, 132, 2, 1), /* 2410 common */ - PLL_35XX_RATE(202800000, 161, 3, 1), - PLL_35XX_RATE(192000000, 88, 1, 1), - PLL_35XX_RATE(186000000, 85, 1, 1), - PLL_35XX_RATE(180000000, 82, 1, 1), - PLL_35XX_RATE(170000000, 77, 1, 1), - PLL_35XX_RATE(158000000, 71, 1, 1), - PLL_35XX_RATE(152000000, 68, 1, 1), - PLL_35XX_RATE(147000000, 90, 2, 1), - PLL_35XX_RATE(135000000, 82, 2, 1), - PLL_35XX_RATE(124000000, 116, 1, 2), - PLL_35XX_RATE(118500000, 150, 2, 2), - PLL_35XX_RATE(113000000, 105, 1, 2), - PLL_35XX_RATE(101250000, 127, 2, 2), - PLL_35XX_RATE(90000000, 112, 2, 2), - PLL_35XX_RATE(84750000, 105, 2, 2), - PLL_35XX_RATE(79000000, 71, 1, 2), - PLL_35XX_RATE(67500000, 82, 2, 2), - PLL_35XX_RATE(56250000, 142, 2, 3), - PLL_35XX_RATE(48000000, 120, 2, 3), - PLL_35XX_RATE(50700000, 161, 3, 3), - PLL_35XX_RATE(45000000, 82, 1, 3), - PLL_35XX_RATE(33750000, 82, 2, 3), + PLL_S3C2410_MPLL_RATE(12 * MHZ, 202800000, 161, 3, 1), + PLL_S3C2410_MPLL_RATE(12 * MHZ, 192000000, 88, 1, 1), + PLL_S3C2410_MPLL_RATE(12 * MHZ, 186000000, 85, 1, 1), + PLL_S3C2410_MPLL_RATE(12 * MHZ, 180000000, 82, 1, 1), + PLL_S3C2410_MPLL_RATE(12 * MHZ, 170000000, 77, 1, 1), + PLL_S3C2410_MPLL_RATE(12 * MHZ, 158000000, 71, 1, 1), + PLL_S3C2410_MPLL_RATE(12 * MHZ, 152000000, 68, 1, 1), + PLL_S3C2410_MPLL_RATE(12 * MHZ, 147000000, 90, 2, 1), + PLL_S3C2410_MPLL_RATE(12 * MHZ, 135000000, 82, 2, 1), + PLL_S3C2410_MPLL_RATE(12 * MHZ, 124000000, 116, 1, 2), + PLL_S3C2410_MPLL_RATE(12 * MHZ, 118500000, 150, 2, 2), + PLL_S3C2410_MPLL_RATE(12 * MHZ, 113000000, 105, 1, 2), + PLL_S3C2410_MPLL_RATE(12 * MHZ, 101250000, 127, 2, 2), + PLL_S3C2410_MPLL_RATE(12 * MHZ, 90000000, 112, 2, 2), + PLL_S3C2410_MPLL_RATE(12 * MHZ, 84750000, 105, 2, 2), + PLL_S3C2410_MPLL_RATE(12 * MHZ, 79000000, 71, 1, 2), + PLL_S3C2410_MPLL_RATE(12 * MHZ, 67500000, 82, 2, 2), + PLL_S3C2410_MPLL_RATE(12 * MHZ, 56250000, 142, 2, 3), + PLL_S3C2410_MPLL_RATE(12 * MHZ, 48000000, 120, 2, 3), + PLL_S3C2410_MPLL_RATE(12 * MHZ, 50700000, 161, 3, 3), + PLL_S3C2410_MPLL_RATE(12 * MHZ, 45000000, 82, 1, 3), + PLL_S3C2410_MPLL_RATE(12 * MHZ, 33750000, 82, 2, 3), { /* sentinel */ }, }; @@ -229,33 +229,33 @@ struct samsung_clock_alias s3c2410_aliases[] __initdata = { static struct samsung_pll_rate_table pll_s3c244x_12mhz_tbl[] __initdata = { /* sorted in descending order */ - PLL_35XX_RATE(400000000, 0x5c, 1, 1), - PLL_35XX_RATE(390000000, 0x7a, 2, 1), - PLL_35XX_RATE(380000000, 0x57, 1, 1), - PLL_35XX_RATE(370000000, 0xb1, 4, 1), - PLL_35XX_RATE(360000000, 0x70, 2, 1), - PLL_35XX_RATE(350000000, 0xa7, 4, 1), - PLL_35XX_RATE(340000000, 0x4d, 1, 1), - PLL_35XX_RATE(330000000, 0x66, 2, 1), - PLL_35XX_RATE(320000000, 0x98, 4, 1), - PLL_35XX_RATE(310000000, 0x93, 4, 1), - PLL_35XX_RATE(300000000, 0x75, 3, 1), - PLL_35XX_RATE(240000000, 0x70, 1, 2), - PLL_35XX_RATE(230000000, 0x6b, 1, 2), - PLL_35XX_RATE(220000000, 0x66, 1, 2), - PLL_35XX_RATE(210000000, 0x84, 2, 2), - PLL_35XX_RATE(200000000, 0x5c, 1, 2), - PLL_35XX_RATE(190000000, 0x57, 1, 2), - PLL_35XX_RATE(180000000, 0x70, 2, 2), - PLL_35XX_RATE(170000000, 0x4d, 1, 2), - PLL_35XX_RATE(160000000, 0x98, 4, 2), - PLL_35XX_RATE(150000000, 0x75, 3, 2), - PLL_35XX_RATE(120000000, 0x70, 1, 3), - PLL_35XX_RATE(110000000, 0x66, 1, 3), - PLL_35XX_RATE(100000000, 0x5c, 1, 3), - PLL_35XX_RATE(90000000, 0x70, 2, 3), - PLL_35XX_RATE(80000000, 0x98, 4, 3), - PLL_35XX_RATE(75000000, 0x75, 3, 3), + PLL_S3C2440_MPLL_RATE(12 * MHZ, 400000000, 0x5c, 1, 1), + PLL_S3C2440_MPLL_RATE(12 * MHZ, 390000000, 0x7a, 2, 1), + PLL_S3C2440_MPLL_RATE(12 * MHZ, 380000000, 0x57, 1, 1), + PLL_S3C2440_MPLL_RATE(12 * MHZ, 370000000, 0xb1, 4, 1), + PLL_S3C2440_MPLL_RATE(12 * MHZ, 360000000, 0x70, 2, 1), + PLL_S3C2440_MPLL_RATE(12 * MHZ, 350000000, 0xa7, 4, 1), + PLL_S3C2440_MPLL_RATE(12 * MHZ, 340000000, 0x4d, 1, 1), + PLL_S3C2440_MPLL_RATE(12 * MHZ, 330000000, 0x66, 2, 1), + PLL_S3C2440_MPLL_RATE(12 * MHZ, 320000000, 0x98, 4, 1), + PLL_S3C2440_MPLL_RATE(12 * MHZ, 310000000, 0x93, 4, 1), + PLL_S3C2440_MPLL_RATE(12 * MHZ, 300000000, 0x75, 3, 1), + PLL_S3C2440_MPLL_RATE(12 * MHZ, 240000000, 0x70, 1, 2), + PLL_S3C2440_MPLL_RATE(12 * MHZ, 230000000, 0x6b, 1, 2), + PLL_S3C2440_MPLL_RATE(12 * MHZ, 220000000, 0x66, 1, 2), + PLL_S3C2440_MPLL_RATE(12 * MHZ, 210000000, 0x84, 2, 2), + PLL_S3C2440_MPLL_RATE(12 * MHZ, 200000000, 0x5c, 1, 2), + PLL_S3C2440_MPLL_RATE(12 * MHZ, 190000000, 0x57, 1, 2), + PLL_S3C2440_MPLL_RATE(12 * MHZ, 180000000, 0x70, 2, 2), + PLL_S3C2440_MPLL_RATE(12 * MHZ, 170000000, 0x4d, 1, 2), + PLL_S3C2440_MPLL_RATE(12 * MHZ, 160000000, 0x98, 4, 2), + PLL_S3C2440_MPLL_RATE(12 * MHZ, 150000000, 0x75, 3, 2), + PLL_S3C2440_MPLL_RATE(12 * MHZ, 120000000, 0x70, 1, 3), + PLL_S3C2440_MPLL_RATE(12 * MHZ, 110000000, 0x66, 1, 3), + PLL_S3C2440_MPLL_RATE(12 * MHZ, 100000000, 0x5c, 1, 3), + PLL_S3C2440_MPLL_RATE(12 * MHZ, 90000000, 0x70, 2, 3), + PLL_S3C2440_MPLL_RATE(12 * MHZ, 80000000, 0x98, 4, 3), + PLL_S3C2440_MPLL_RATE(12 * MHZ, 75000000, 0x75, 3, 3), { /* sentinel */ }, }; -- cgit From 7ce36da900c0a2ff4777d9ba51c4f1cb74205463 Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Tue, 20 Feb 2018 16:12:03 +0100 Subject: clk: renesas: cpg-mssr: Add support for R-Car M3-N Initial support for R-Car M3-N (r8a77965), including core and module clocks. Based on Table 8.2d of "R-Car Series, 3rd Generation User's Manual: Hardware (Rev. 0.80, Oct 31, 2017)". Signed-off-by: Jacopo Mondi Signed-off-by: Geert Uytterhoeven --- .../devicetree/bindings/clock/renesas,cpg-mssr.txt | 5 +- drivers/clk/renesas/Kconfig | 5 + drivers/clk/renesas/Makefile | 1 + drivers/clk/renesas/r8a77965-cpg-mssr.c | 334 +++++++++++++++++++++ drivers/clk/renesas/renesas-cpg-mssr.c | 6 + drivers/clk/renesas/renesas-cpg-mssr.h | 1 + include/dt-bindings/clock/r8a77965-cpg-mssr.h | 62 ++++ 7 files changed, 412 insertions(+), 2 deletions(-) create mode 100644 drivers/clk/renesas/r8a77965-cpg-mssr.c create mode 100644 include/dt-bindings/clock/r8a77965-cpg-mssr.h diff --git a/Documentation/devicetree/bindings/clock/renesas,cpg-mssr.txt b/Documentation/devicetree/bindings/clock/renesas,cpg-mssr.txt index bc4ea0868dbc..773a5226342f 100644 --- a/Documentation/devicetree/bindings/clock/renesas,cpg-mssr.txt +++ b/Documentation/devicetree/bindings/clock/renesas,cpg-mssr.txt @@ -22,6 +22,7 @@ Required Properties: - "renesas,r8a7794-cpg-mssr" for the r8a7794 SoC (R-Car E2) - "renesas,r8a7795-cpg-mssr" for the r8a7795 SoC (R-Car H3) - "renesas,r8a7796-cpg-mssr" for the r8a7796 SoC (R-Car M3-W) + - "renesas,r8a77965-cpg-mssr" for the r8a77965 SoC (R-Car M3-N) - "renesas,r8a77970-cpg-mssr" for the r8a77970 SoC (R-Car V3M) - "renesas,r8a77980-cpg-mssr" for the r8a77980 SoC (R-Car V3H) - "renesas,r8a77995-cpg-mssr" for the r8a77995 SoC (R-Car D3) @@ -33,8 +34,8 @@ Required Properties: clock-names - clock-names: List of external parent clock names. Valid names are: - "extal" (r8a7743, r8a7745, r8a7790, r8a7791, r8a7792, r8a7793, r8a7794, - r8a7795, r8a7796, r8a77970, r8a77980, r8a77995) - - "extalr" (r8a7795, r8a7796, r8a77970, r8a77980) + r8a7795, r8a7796, r8a77965, r8a77970, r8a77980, r8a77995) + - "extalr" (r8a7795, r8a7796, r8a77965, r8a77970, r8a77980) - "usb_extal" (r8a7743, r8a7745, r8a7790, r8a7791, r8a7793, r8a7794) - #clock-cells: Must be 2 diff --git a/drivers/clk/renesas/Kconfig b/drivers/clk/renesas/Kconfig index 43bab4f9c4e2..ef76c861ec84 100644 --- a/drivers/clk/renesas/Kconfig +++ b/drivers/clk/renesas/Kconfig @@ -15,6 +15,7 @@ config CLK_RENESAS select CLK_R8A7794 if ARCH_R8A7794 select CLK_R8A7795 if ARCH_R8A7795 select CLK_R8A7796 if ARCH_R8A7796 + select CLK_R8A77965 if ARCH_R8A77965 select CLK_R8A77970 if ARCH_R8A77970 select CLK_R8A77980 if ARCH_R8A77980 select CLK_R8A77995 if ARCH_R8A77995 @@ -98,6 +99,10 @@ config CLK_R8A7796 bool "R-Car M3-W clock support" if COMPILE_TEST select CLK_RCAR_GEN3_CPG +config CLK_R8A77965 + bool "R-Car M3-N clock support" if COMPILE_TEST + select CLK_RCAR_GEN3_CPG + config CLK_R8A77970 bool "R-Car V3M clock support" if COMPILE_TEST select CLK_RCAR_GEN3_CPG diff --git a/drivers/clk/renesas/Makefile b/drivers/clk/renesas/Makefile index e20fa195d107..6c0f19636e3e 100644 --- a/drivers/clk/renesas/Makefile +++ b/drivers/clk/renesas/Makefile @@ -14,6 +14,7 @@ obj-$(CONFIG_CLK_R8A7792) += r8a7792-cpg-mssr.o obj-$(CONFIG_CLK_R8A7794) += r8a7794-cpg-mssr.o obj-$(CONFIG_CLK_R8A7795) += r8a7795-cpg-mssr.o obj-$(CONFIG_CLK_R8A7796) += r8a7796-cpg-mssr.o +obj-$(CONFIG_CLK_R8A77965) += r8a77965-cpg-mssr.o obj-$(CONFIG_CLK_R8A77970) += r8a77970-cpg-mssr.o obj-$(CONFIG_CLK_R8A77980) += r8a77980-cpg-mssr.o obj-$(CONFIG_CLK_R8A77995) += r8a77995-cpg-mssr.o diff --git a/drivers/clk/renesas/r8a77965-cpg-mssr.c b/drivers/clk/renesas/r8a77965-cpg-mssr.c new file mode 100644 index 000000000000..41e506ab557d --- /dev/null +++ b/drivers/clk/renesas/r8a77965-cpg-mssr.c @@ -0,0 +1,334 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * r8a77965 Clock Pulse Generator / Module Standby and Software Reset + * + * Copyright (C) 2018 Jacopo Mondi + * + * Based on r8a7795-cpg-mssr.c + * + * Copyright (C) 2015 Glider bvba + * Copyright (C) 2015 Renesas Electronics Corp. + */ + +#include +#include +#include +#include + +#include + +#include "renesas-cpg-mssr.h" +#include "rcar-gen3-cpg.h" + +enum clk_ids { + /* Core Clock Outputs exported to DT */ + LAST_DT_CORE_CLK = R8A77965_CLK_OSC, + + /* External Input Clocks */ + CLK_EXTAL, + CLK_EXTALR, + + /* Internal Core Clocks */ + CLK_MAIN, + CLK_PLL0, + CLK_PLL1, + CLK_PLL3, + CLK_PLL4, + CLK_PLL1_DIV2, + CLK_PLL1_DIV4, + CLK_S0, + CLK_S1, + CLK_S2, + CLK_S3, + CLK_SDSRC, + CLK_SSPSRC, + CLK_RINT, + + /* Module Clocks */ + MOD_CLK_BASE +}; + +static const struct cpg_core_clk r8a77965_core_clks[] __initconst = { + /* External Clock Inputs */ + DEF_INPUT("extal", CLK_EXTAL), + DEF_INPUT("extalr", CLK_EXTALR), + + /* Internal Core Clocks */ + DEF_BASE(".main", CLK_MAIN, CLK_TYPE_GEN3_MAIN, CLK_EXTAL), + DEF_BASE(".pll0", CLK_PLL0, CLK_TYPE_GEN3_PLL0, CLK_MAIN), + DEF_BASE(".pll1", CLK_PLL1, CLK_TYPE_GEN3_PLL1, CLK_MAIN), + DEF_BASE(".pll3", CLK_PLL3, CLK_TYPE_GEN3_PLL3, CLK_MAIN), + DEF_BASE(".pll4", CLK_PLL4, CLK_TYPE_GEN3_PLL4, CLK_MAIN), + + DEF_FIXED(".pll1_div2", CLK_PLL1_DIV2, CLK_PLL1, 2, 1), + DEF_FIXED(".pll1_div4", CLK_PLL1_DIV4, CLK_PLL1_DIV2, 2, 1), + DEF_FIXED(".s0", CLK_S0, CLK_PLL1_DIV2, 2, 1), + DEF_FIXED(".s1", CLK_S1, CLK_PLL1_DIV2, 3, 1), + DEF_FIXED(".s2", CLK_S2, CLK_PLL1_DIV2, 4, 1), + DEF_FIXED(".s3", CLK_S3, CLK_PLL1_DIV2, 6, 1), + DEF_FIXED(".sdsrc", CLK_SDSRC, CLK_PLL1_DIV2, 2, 1), + + /* Core Clock Outputs */ + DEF_BASE("z", R8A77965_CLK_Z, CLK_TYPE_GEN3_Z, CLK_PLL0), + DEF_FIXED("ztr", R8A77965_CLK_ZTR, CLK_PLL1_DIV2, 6, 1), + DEF_FIXED("ztrd2", R8A77965_CLK_ZTRD2, CLK_PLL1_DIV2, 12, 1), + DEF_FIXED("zt", R8A77965_CLK_ZT, CLK_PLL1_DIV2, 4, 1), + DEF_FIXED("zx", R8A77965_CLK_ZX, CLK_PLL1_DIV2, 2, 1), + DEF_FIXED("s0d1", R8A77965_CLK_S0D1, CLK_S0, 1, 1), + DEF_FIXED("s0d2", R8A77965_CLK_S0D2, CLK_S0, 2, 1), + DEF_FIXED("s0d3", R8A77965_CLK_S0D3, CLK_S0, 3, 1), + DEF_FIXED("s0d4", R8A77965_CLK_S0D4, CLK_S0, 4, 1), + DEF_FIXED("s0d6", R8A77965_CLK_S0D6, CLK_S0, 6, 1), + DEF_FIXED("s0d8", R8A77965_CLK_S0D8, CLK_S0, 8, 1), + DEF_FIXED("s0d12", R8A77965_CLK_S0D12, CLK_S0, 12, 1), + DEF_FIXED("s1d1", R8A77965_CLK_S1D1, CLK_S1, 1, 1), + DEF_FIXED("s1d2", R8A77965_CLK_S1D2, CLK_S1, 2, 1), + DEF_FIXED("s1d4", R8A77965_CLK_S1D4, CLK_S1, 4, 1), + DEF_FIXED("s2d1", R8A77965_CLK_S2D1, CLK_S2, 1, 1), + DEF_FIXED("s2d2", R8A77965_CLK_S2D2, CLK_S2, 2, 1), + DEF_FIXED("s2d4", R8A77965_CLK_S2D4, CLK_S2, 4, 1), + DEF_FIXED("s3d1", R8A77965_CLK_S3D1, CLK_S3, 1, 1), + DEF_FIXED("s3d2", R8A77965_CLK_S3D2, CLK_S3, 2, 1), + DEF_FIXED("s3d4", R8A77965_CLK_S3D4, CLK_S3, 4, 1), + + DEF_GEN3_SD("sd0", R8A77965_CLK_SD0, CLK_SDSRC, 0x074), + DEF_GEN3_SD("sd1", R8A77965_CLK_SD1, CLK_SDSRC, 0x078), + DEF_GEN3_SD("sd2", R8A77965_CLK_SD2, CLK_SDSRC, 0x268), + DEF_GEN3_SD("sd3", R8A77965_CLK_SD3, CLK_SDSRC, 0x26c), + + DEF_FIXED("cl", R8A77965_CLK_CL, CLK_PLL1_DIV2, 48, 1), + DEF_FIXED("cp", R8A77965_CLK_CP, CLK_EXTAL, 2, 1), + + DEF_DIV6P1("canfd", R8A77965_CLK_CANFD, CLK_PLL1_DIV4, 0x244), + DEF_DIV6P1("csi0", R8A77965_CLK_CSI0, CLK_PLL1_DIV4, 0x00c), + DEF_DIV6P1("mso", R8A77965_CLK_MSO, CLK_PLL1_DIV4, 0x014), + DEF_DIV6P1("hdmi", R8A77965_CLK_HDMI, CLK_PLL1_DIV4, 0x250), + + DEF_DIV6_RO("osc", R8A77965_CLK_OSC, CLK_EXTAL, CPG_RCKCR, 8), + DEF_DIV6_RO("r_int", CLK_RINT, CLK_EXTAL, CPG_RCKCR, 32), + + DEF_BASE("r", R8A77965_CLK_R, CLK_TYPE_GEN3_R, CLK_RINT), +}; + +static const struct mssr_mod_clk r8a77965_mod_clks[] __initconst = { + DEF_MOD("scif5", 202, R8A77965_CLK_S3D4), + DEF_MOD("scif4", 203, R8A77965_CLK_S3D4), + DEF_MOD("scif3", 204, R8A77965_CLK_S3D4), + DEF_MOD("scif1", 206, R8A77965_CLK_S3D4), + DEF_MOD("scif0", 207, R8A77965_CLK_S3D4), + DEF_MOD("sys-dmac2", 217, R8A77965_CLK_S0D3), + DEF_MOD("sys-dmac1", 218, R8A77965_CLK_S0D3), + DEF_MOD("sys-dmac0", 219, R8A77965_CLK_S0D3), + + DEF_MOD("cmt3", 300, R8A77965_CLK_R), + DEF_MOD("cmt2", 301, R8A77965_CLK_R), + DEF_MOD("cmt1", 302, R8A77965_CLK_R), + DEF_MOD("cmt0", 303, R8A77965_CLK_R), + DEF_MOD("scif2", 310, R8A77965_CLK_S3D4), + DEF_MOD("sdif3", 311, R8A77965_CLK_SD3), + DEF_MOD("sdif2", 312, R8A77965_CLK_SD2), + DEF_MOD("sdif1", 313, R8A77965_CLK_SD1), + DEF_MOD("sdif0", 314, R8A77965_CLK_SD0), + DEF_MOD("pcie1", 318, R8A77965_CLK_S3D1), + DEF_MOD("pcie0", 319, R8A77965_CLK_S3D1), + DEF_MOD("usb3-if0", 328, R8A77965_CLK_S3D1), + DEF_MOD("usb-dmac0", 330, R8A77965_CLK_S3D1), + DEF_MOD("usb-dmac1", 331, R8A77965_CLK_S3D1), + + DEF_MOD("rwdt", 402, R8A77965_CLK_R), + DEF_MOD("intc-ex", 407, R8A77965_CLK_CP), + DEF_MOD("intc-ap", 408, R8A77965_CLK_S0D3), + + DEF_MOD("audmac1", 501, R8A77965_CLK_S0D3), + DEF_MOD("audmac0", 502, R8A77965_CLK_S0D3), + DEF_MOD("drif7", 508, R8A77965_CLK_S3D2), + DEF_MOD("drif6", 509, R8A77965_CLK_S3D2), + DEF_MOD("drif5", 510, R8A77965_CLK_S3D2), + DEF_MOD("drif4", 511, R8A77965_CLK_S3D2), + DEF_MOD("drif3", 512, R8A77965_CLK_S3D2), + DEF_MOD("drif2", 513, R8A77965_CLK_S3D2), + DEF_MOD("drif1", 514, R8A77965_CLK_S3D2), + DEF_MOD("drif0", 515, R8A77965_CLK_S3D2), + DEF_MOD("hscif4", 516, R8A77965_CLK_S3D1), + DEF_MOD("hscif3", 517, R8A77965_CLK_S3D1), + DEF_MOD("hscif2", 518, R8A77965_CLK_S3D1), + DEF_MOD("hscif1", 519, R8A77965_CLK_S3D1), + DEF_MOD("hscif0", 520, R8A77965_CLK_S3D1), + DEF_MOD("thermal", 522, R8A77965_CLK_CP), + DEF_MOD("pwm", 523, R8A77965_CLK_S0D12), + + DEF_MOD("fcpvd1", 602, R8A77965_CLK_S0D2), + DEF_MOD("fcpvd0", 603, R8A77965_CLK_S0D2), + DEF_MOD("fcpvb0", 607, R8A77965_CLK_S0D1), + DEF_MOD("fcpvi0", 611, R8A77965_CLK_S0D1), + DEF_MOD("fcpf0", 615, R8A77965_CLK_S0D1), + DEF_MOD("fcpcs", 619, R8A77965_CLK_S0D2), + DEF_MOD("vspd1", 622, R8A77965_CLK_S0D2), + DEF_MOD("vspd0", 623, R8A77965_CLK_S0D2), + DEF_MOD("vspb", 626, R8A77965_CLK_S0D1), + DEF_MOD("vspi0", 631, R8A77965_CLK_S0D1), + + DEF_MOD("ehci1", 702, R8A77965_CLK_S3D4), + DEF_MOD("ehci0", 703, R8A77965_CLK_S3D4), + DEF_MOD("hsusb", 704, R8A77965_CLK_S3D4), + DEF_MOD("csi20", 714, R8A77965_CLK_CSI0), + DEF_MOD("csi40", 716, R8A77965_CLK_CSI0), + DEF_MOD("du2", 722, R8A77965_CLK_S2D1), + DEF_MOD("du1", 723, R8A77965_CLK_S2D1), + DEF_MOD("du0", 724, R8A77965_CLK_S2D1), + DEF_MOD("lvds", 727, R8A77965_CLK_S2D1), + DEF_MOD("hdmi0", 729, R8A77965_CLK_HDMI), + + DEF_MOD("vin7", 804, R8A77965_CLK_S0D2), + DEF_MOD("vin6", 805, R8A77965_CLK_S0D2), + DEF_MOD("vin5", 806, R8A77965_CLK_S0D2), + DEF_MOD("vin4", 807, R8A77965_CLK_S0D2), + DEF_MOD("vin3", 808, R8A77965_CLK_S0D2), + DEF_MOD("vin2", 809, R8A77965_CLK_S0D2), + DEF_MOD("vin1", 810, R8A77965_CLK_S0D2), + DEF_MOD("vin0", 811, R8A77965_CLK_S0D2), + DEF_MOD("etheravb", 812, R8A77965_CLK_S0D6), + DEF_MOD("imr1", 822, R8A77965_CLK_S0D2), + DEF_MOD("imr0", 823, R8A77965_CLK_S0D2), + + DEF_MOD("gpio7", 905, R8A77965_CLK_S3D4), + DEF_MOD("gpio6", 906, R8A77965_CLK_S3D4), + DEF_MOD("gpio5", 907, R8A77965_CLK_S3D4), + DEF_MOD("gpio4", 908, R8A77965_CLK_S3D4), + DEF_MOD("gpio3", 909, R8A77965_CLK_S3D4), + DEF_MOD("gpio2", 910, R8A77965_CLK_S3D4), + DEF_MOD("gpio1", 911, R8A77965_CLK_S3D4), + DEF_MOD("gpio0", 912, R8A77965_CLK_S3D4), + DEF_MOD("can-fd", 914, R8A77965_CLK_S3D2), + DEF_MOD("can-if1", 915, R8A77965_CLK_S3D4), + DEF_MOD("can-if0", 916, R8A77965_CLK_S3D4), + DEF_MOD("i2c6", 918, R8A77965_CLK_S0D6), + DEF_MOD("i2c5", 919, R8A77965_CLK_S0D6), + DEF_MOD("i2c-dvfs", 926, R8A77965_CLK_CP), + DEF_MOD("i2c4", 927, R8A77965_CLK_S0D6), + DEF_MOD("i2c3", 928, R8A77965_CLK_S0D6), + DEF_MOD("i2c2", 929, R8A77965_CLK_S3D2), + DEF_MOD("i2c1", 930, R8A77965_CLK_S3D2), + DEF_MOD("i2c0", 931, R8A77965_CLK_S3D2), + + DEF_MOD("ssi-all", 1005, R8A77965_CLK_S3D4), + DEF_MOD("ssi9", 1006, MOD_CLK_ID(1005)), + DEF_MOD("ssi8", 1007, MOD_CLK_ID(1005)), + DEF_MOD("ssi7", 1008, MOD_CLK_ID(1005)), + DEF_MOD("ssi6", 1009, MOD_CLK_ID(1005)), + DEF_MOD("ssi5", 1010, MOD_CLK_ID(1005)), + DEF_MOD("ssi4", 1011, MOD_CLK_ID(1005)), + DEF_MOD("ssi3", 1012, MOD_CLK_ID(1005)), + DEF_MOD("ssi2", 1013, MOD_CLK_ID(1005)), + DEF_MOD("ssi1", 1014, MOD_CLK_ID(1005)), + DEF_MOD("ssi0", 1015, MOD_CLK_ID(1005)), + DEF_MOD("scu-all", 1017, R8A77965_CLK_S3D4), + DEF_MOD("scu-dvc1", 1018, MOD_CLK_ID(1017)), + DEF_MOD("scu-dvc0", 1019, MOD_CLK_ID(1017)), + DEF_MOD("scu-ctu1-mix1", 1020, MOD_CLK_ID(1017)), + DEF_MOD("scu-ctu0-mix0", 1021, MOD_CLK_ID(1017)), + DEF_MOD("scu-src9", 1022, MOD_CLK_ID(1017)), + DEF_MOD("scu-src8", 1023, MOD_CLK_ID(1017)), + DEF_MOD("scu-src7", 1024, MOD_CLK_ID(1017)), + DEF_MOD("scu-src6", 1025, MOD_CLK_ID(1017)), + DEF_MOD("scu-src5", 1026, MOD_CLK_ID(1017)), + DEF_MOD("scu-src4", 1027, MOD_CLK_ID(1017)), + DEF_MOD("scu-src3", 1028, MOD_CLK_ID(1017)), + DEF_MOD("scu-src2", 1029, MOD_CLK_ID(1017)), + DEF_MOD("scu-src1", 1030, MOD_CLK_ID(1017)), + DEF_MOD("scu-src0", 1031, MOD_CLK_ID(1017)), +}; + +static const unsigned int r8a77965_crit_mod_clks[] __initconst = { + MOD_CLK_ID(408), /* INTC-AP (GIC) */ +}; + +/* + * CPG Clock Data + */ + +/* + * MD EXTAL PLL0 PLL1 PLL3 PLL4 + * 14 13 19 17 (MHz) + *----------------------------------------------------------- + * 0 0 0 0 16.66 x 1 x180 x192 x192 x144 + * 0 0 0 1 16.66 x 1 x180 x192 x128 x144 + * 0 0 1 0 Prohibited setting + * 0 0 1 1 16.66 x 1 x180 x192 x192 x144 + * 0 1 0 0 20 x 1 x150 x160 x160 x120 + * 0 1 0 1 20 x 1 x150 x160 x106 x120 + * 0 1 1 0 Prohibited setting + * 0 1 1 1 20 x 1 x150 x160 x160 x120 + * 1 0 0 0 25 x 1 x120 x128 x128 x96 + * 1 0 0 1 25 x 1 x120 x128 x84 x96 + * 1 0 1 0 Prohibited setting + * 1 0 1 1 25 x 1 x120 x128 x128 x96 + * 1 1 0 0 33.33 / 2 x180 x192 x192 x144 + * 1 1 0 1 33.33 / 2 x180 x192 x128 x144 + * 1 1 1 0 Prohibited setting + * 1 1 1 1 33.33 / 2 x180 x192 x192 x144 + */ +#define CPG_PLL_CONFIG_INDEX(md) ((((md) & BIT(14)) >> 11) | \ + (((md) & BIT(13)) >> 11) | \ + (((md) & BIT(19)) >> 18) | \ + (((md) & BIT(17)) >> 17)) + +static const struct rcar_gen3_cpg_pll_config cpg_pll_configs[16] __initconst = { + /* EXTAL div PLL1 mult/div PLL3 mult/div */ + { 1, 192, 1, 192, 1, }, + { 1, 192, 1, 128, 1, }, + { 0, /* Prohibited setting */ }, + { 1, 192, 1, 192, 1, }, + { 1, 160, 1, 160, 1, }, + { 1, 160, 1, 106, 1, }, + { 0, /* Prohibited setting */ }, + { 1, 160, 1, 160, 1, }, + { 1, 128, 1, 128, 1, }, + { 1, 128, 1, 84, 1, }, + { 0, /* Prohibited setting */ }, + { 1, 128, 1, 128, 1, }, + { 2, 192, 1, 192, 1, }, + { 2, 192, 1, 128, 1, }, + { 0, /* Prohibited setting */ }, + { 2, 192, 1, 192, 1, }, +}; + +static int __init r8a77965_cpg_mssr_init(struct device *dev) +{ + const struct rcar_gen3_cpg_pll_config *cpg_pll_config; + u32 cpg_mode; + int error; + + error = rcar_rst_read_mode_pins(&cpg_mode); + if (error) + return error; + + cpg_pll_config = &cpg_pll_configs[CPG_PLL_CONFIG_INDEX(cpg_mode)]; + if (!cpg_pll_config->extal_div) { + dev_err(dev, "Prohibited setting (cpg_mode=0x%x)\n", cpg_mode); + return -EINVAL; + } + + return rcar_gen3_cpg_init(cpg_pll_config, CLK_EXTALR, cpg_mode); +}; + +const struct cpg_mssr_info r8a77965_cpg_mssr_info __initconst = { + /* Core Clocks */ + .core_clks = r8a77965_core_clks, + .num_core_clks = ARRAY_SIZE(r8a77965_core_clks), + .last_dt_core_clk = LAST_DT_CORE_CLK, + .num_total_core_clks = MOD_CLK_BASE, + + /* Module Clocks */ + .mod_clks = r8a77965_mod_clks, + .num_mod_clks = ARRAY_SIZE(r8a77965_mod_clks), + .num_hw_mod_clks = 12 * 32, + + /* Critical Module Clocks */ + .crit_mod_clks = r8a77965_crit_mod_clks, + .num_crit_mod_clks = ARRAY_SIZE(r8a77965_crit_mod_clks), + + /* Callbacks */ + .init = r8a77965_cpg_mssr_init, + .cpg_clk_register = rcar_gen3_cpg_clk_register, +}; diff --git a/drivers/clk/renesas/renesas-cpg-mssr.c b/drivers/clk/renesas/renesas-cpg-mssr.c index aadfa6df6c4d..96c678799623 100644 --- a/drivers/clk/renesas/renesas-cpg-mssr.c +++ b/drivers/clk/renesas/renesas-cpg-mssr.c @@ -693,6 +693,12 @@ static const struct of_device_id cpg_mssr_match[] = { .data = &r8a7796_cpg_mssr_info, }, #endif +#ifdef CONFIG_CLK_R8A77965 + { + .compatible = "renesas,r8a77965-cpg-mssr", + .data = &r8a77965_cpg_mssr_info, + }, +#endif #ifdef CONFIG_CLK_R8A77970 { .compatible = "renesas,r8a77970-cpg-mssr", diff --git a/drivers/clk/renesas/renesas-cpg-mssr.h b/drivers/clk/renesas/renesas-cpg-mssr.h index 143293e3d193..97ccb093c10f 100644 --- a/drivers/clk/renesas/renesas-cpg-mssr.h +++ b/drivers/clk/renesas/renesas-cpg-mssr.h @@ -139,6 +139,7 @@ extern const struct cpg_mssr_info r8a7792_cpg_mssr_info; extern const struct cpg_mssr_info r8a7794_cpg_mssr_info; extern const struct cpg_mssr_info r8a7795_cpg_mssr_info; extern const struct cpg_mssr_info r8a7796_cpg_mssr_info; +extern const struct cpg_mssr_info r8a77965_cpg_mssr_info; extern const struct cpg_mssr_info r8a77970_cpg_mssr_info; extern const struct cpg_mssr_info r8a77980_cpg_mssr_info; extern const struct cpg_mssr_info r8a77995_cpg_mssr_info; diff --git a/include/dt-bindings/clock/r8a77965-cpg-mssr.h b/include/dt-bindings/clock/r8a77965-cpg-mssr.h new file mode 100644 index 000000000000..6d3b5a9a6084 --- /dev/null +++ b/include/dt-bindings/clock/r8a77965-cpg-mssr.h @@ -0,0 +1,62 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2018 Jacopo Mondi + */ +#ifndef __DT_BINDINGS_CLOCK_R8A77965_CPG_MSSR_H__ +#define __DT_BINDINGS_CLOCK_R8A77965_CPG_MSSR_H__ + +#include + +/* r8a77965 CPG Core Clocks */ +#define R8A77965_CLK_Z 0 +#define R8A77965_CLK_ZR 1 +#define R8A77965_CLK_ZG 2 +#define R8A77965_CLK_ZTR 3 +#define R8A77965_CLK_ZTRD2 4 +#define R8A77965_CLK_ZT 5 +#define R8A77965_CLK_ZX 6 +#define R8A77965_CLK_S0D1 7 +#define R8A77965_CLK_S0D2 8 +#define R8A77965_CLK_S0D3 9 +#define R8A77965_CLK_S0D4 10 +#define R8A77965_CLK_S0D6 11 +#define R8A77965_CLK_S0D8 12 +#define R8A77965_CLK_S0D12 13 +#define R8A77965_CLK_S1D1 14 +#define R8A77965_CLK_S1D2 15 +#define R8A77965_CLK_S1D4 16 +#define R8A77965_CLK_S2D1 17 +#define R8A77965_CLK_S2D2 18 +#define R8A77965_CLK_S2D4 19 +#define R8A77965_CLK_S3D1 20 +#define R8A77965_CLK_S3D2 21 +#define R8A77965_CLK_S3D4 22 +#define R8A77965_CLK_LB 23 +#define R8A77965_CLK_CL 24 +#define R8A77965_CLK_ZB3 25 +#define R8A77965_CLK_ZB3D2 26 +#define R8A77965_CLK_CR 27 +#define R8A77965_CLK_CRD2 28 +#define R8A77965_CLK_SD0H 29 +#define R8A77965_CLK_SD0 30 +#define R8A77965_CLK_SD1H 31 +#define R8A77965_CLK_SD1 32 +#define R8A77965_CLK_SD2H 33 +#define R8A77965_CLK_SD2 34 +#define R8A77965_CLK_SD3H 35 +#define R8A77965_CLK_SD3 36 +#define R8A77965_CLK_SSP2 37 +#define R8A77965_CLK_SSP1 38 +#define R8A77965_CLK_SSPRS 39 +#define R8A77965_CLK_RPC 40 +#define R8A77965_CLK_RPCD2 41 +#define R8A77965_CLK_MSO 42 +#define R8A77965_CLK_CANFD 43 +#define R8A77965_CLK_HDMI 44 +#define R8A77965_CLK_CSI0 45 +#define R8A77965_CLK_CP 46 +#define R8A77965_CLK_CPEX 47 +#define R8A77965_CLK_R 48 +#define R8A77965_CLK_OSC 49 + +#endif /* __DT_BINDINGS_CLOCK_R8A77965_CPG_MSSR_H__ */ -- cgit From 055d56891ea7a6bb39444db58ea30eafa5a1cb40 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Wed, 24 Jan 2018 19:48:23 +0800 Subject: clk: hi3798cv200: fix unregister call sequence in error path The unregister call sequence in error path of function hi3798cv200_clk_register() should be opposite to the order of register calls. Let's reverse the call sequence to fix the problem. Signed-off-by: Shawn Guo --- drivers/clk/hisilicon/crg-hi3798cv200.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/clk/hisilicon/crg-hi3798cv200.c b/drivers/clk/hisilicon/crg-hi3798cv200.c index 8478948e858e..c586c79f4623 100644 --- a/drivers/clk/hisilicon/crg-hi3798cv200.c +++ b/drivers/clk/hisilicon/crg-hi3798cv200.c @@ -202,18 +202,17 @@ static struct hisi_clock_data *hi3798cv200_clk_register( return clk_data; -unregister_fixed_rate: - hisi_clk_unregister_fixed_rate(hi3798cv200_fixed_rate_clks, - ARRAY_SIZE(hi3798cv200_fixed_rate_clks), +unregister_gate: + hisi_clk_unregister_gate(hi3798cv200_gate_clks, + ARRAY_SIZE(hi3798cv200_gate_clks), clk_data); - unregister_mux: hisi_clk_unregister_mux(hi3798cv200_mux_clks, ARRAY_SIZE(hi3798cv200_mux_clks), clk_data); -unregister_gate: - hisi_clk_unregister_gate(hi3798cv200_gate_clks, - ARRAY_SIZE(hi3798cv200_gate_clks), +unregister_fixed_rate: + hisi_clk_unregister_fixed_rate(hi3798cv200_fixed_rate_clks, + ARRAY_SIZE(hi3798cv200_fixed_rate_clks), clk_data); return ERR_PTR(ret); } -- cgit From 47629f676518f1808dc98c5740a31d8d23c940c7 Mon Sep 17 00:00:00 2001 From: Younian Wang Date: Wed, 24 Jan 2018 19:48:24 +0800 Subject: clk: hi3798cv200: correct IR clock parent The IR clock is sourced from '24m' rather than '100m'. Correct it. Signed-off-by: Younian Wang Signed-off-by: Shawn Guo --- drivers/clk/hisilicon/crg-hi3798cv200.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/hisilicon/crg-hi3798cv200.c b/drivers/clk/hisilicon/crg-hi3798cv200.c index c586c79f4623..d7d1ba0153ec 100644 --- a/drivers/clk/hisilicon/crg-hi3798cv200.c +++ b/drivers/clk/hisilicon/crg-hi3798cv200.c @@ -244,7 +244,7 @@ static const struct hisi_crg_funcs hi3798cv200_crg_funcs = { #define HI3798CV200_SYSCTRL_NR_CLKS 16 static const struct hisi_gate_clock hi3798cv200_sysctrl_gate_clks[] = { - { HISTB_IR_CLK, "clk_ir", "100m", + { HISTB_IR_CLK, "clk_ir", "24m", CLK_SET_RATE_PARENT, 0x48, 4, 0, }, { HISTB_TIMER01_CLK, "clk_timer01", "24m", CLK_SET_RATE_PARENT, 0x48, 6, 0, }, -- cgit From 50fd588ae4a6808d9ecd09c3ffe587e306bfa6a9 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Wed, 24 Jan 2018 19:48:25 +0800 Subject: clk: hi3798cv200: add support for HISTB_USB2_OTG_UTMI_CLK The clock HISTB_USB2_OTG_UTMI_CLK is defined by device tree bindings in include/dt-bindings/clock/histb-clock.h, but hasn't been supported by hi3798cv200 clock driver. Let's add the support for it. Signed-off-by: Shawn Guo --- drivers/clk/hisilicon/crg-hi3798cv200.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/clk/hisilicon/crg-hi3798cv200.c b/drivers/clk/hisilicon/crg-hi3798cv200.c index d7d1ba0153ec..6017ade0cd92 100644 --- a/drivers/clk/hisilicon/crg-hi3798cv200.c +++ b/drivers/clk/hisilicon/crg-hi3798cv200.c @@ -161,6 +161,8 @@ static const struct hisi_gate_clock hi3798cv200_gate_clks[] = { CLK_SET_RATE_PARENT, 0xb8, 1, 0 }, { HISTB_USB2_UTMI_CLK, "clk_u2_utmi", "60m", CLK_SET_RATE_PARENT, 0xb8, 5, 0 }, + { HISTB_USB2_OTG_UTMI_CLK, "clk_u2_otg_utmi", "60m", + CLK_SET_RATE_PARENT, 0xb8, 3, 0 }, { HISTB_USB2_PHY1_REF_CLK, "clk_u2_phy1_ref", "24m", CLK_SET_RATE_PARENT, 0xbc, 0, 0 }, { HISTB_USB2_PHY2_REF_CLK, "clk_u2_phy2_ref", "24m", -- cgit From a44d1f531a39da8cd6497372e713f5998b2d67af Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Wed, 24 Jan 2018 19:48:26 +0800 Subject: clk: hi3798cv200: fix define indentation It's a coding-style fix, which corrects the indentation for all those clock definitions, so that the code looks nicer and new definitions can be added with a recommended indentation. Signed-off-by: Shawn Guo --- drivers/clk/hisilicon/crg-hi3798cv200.c | 48 ++++++++++++++--------------- include/dt-bindings/clock/histb-clock.h | 54 ++++++++++++++++----------------- 2 files changed, 51 insertions(+), 51 deletions(-) diff --git a/drivers/clk/hisilicon/crg-hi3798cv200.c b/drivers/clk/hisilicon/crg-hi3798cv200.c index 6017ade0cd92..451830e08375 100644 --- a/drivers/clk/hisilicon/crg-hi3798cv200.c +++ b/drivers/clk/hisilicon/crg-hi3798cv200.c @@ -27,30 +27,30 @@ #include "reset.h" /* hi3798CV200 core CRG */ -#define HI3798CV200_INNER_CLK_OFFSET 64 -#define HI3798CV200_FIXED_24M 65 -#define HI3798CV200_FIXED_25M 66 -#define HI3798CV200_FIXED_50M 67 -#define HI3798CV200_FIXED_75M 68 -#define HI3798CV200_FIXED_100M 69 -#define HI3798CV200_FIXED_150M 70 -#define HI3798CV200_FIXED_200M 71 -#define HI3798CV200_FIXED_250M 72 -#define HI3798CV200_FIXED_300M 73 -#define HI3798CV200_FIXED_400M 74 -#define HI3798CV200_MMC_MUX 75 -#define HI3798CV200_ETH_PUB_CLK 76 -#define HI3798CV200_ETH_BUS_CLK 77 -#define HI3798CV200_ETH_BUS0_CLK 78 -#define HI3798CV200_ETH_BUS1_CLK 79 -#define HI3798CV200_COMBPHY1_MUX 80 -#define HI3798CV200_FIXED_12M 81 -#define HI3798CV200_FIXED_48M 82 -#define HI3798CV200_FIXED_60M 83 -#define HI3798CV200_FIXED_166P5M 84 -#define HI3798CV200_SDIO0_MUX 85 - -#define HI3798CV200_CRG_NR_CLKS 128 +#define HI3798CV200_INNER_CLK_OFFSET 64 +#define HI3798CV200_FIXED_24M 65 +#define HI3798CV200_FIXED_25M 66 +#define HI3798CV200_FIXED_50M 67 +#define HI3798CV200_FIXED_75M 68 +#define HI3798CV200_FIXED_100M 69 +#define HI3798CV200_FIXED_150M 70 +#define HI3798CV200_FIXED_200M 71 +#define HI3798CV200_FIXED_250M 72 +#define HI3798CV200_FIXED_300M 73 +#define HI3798CV200_FIXED_400M 74 +#define HI3798CV200_MMC_MUX 75 +#define HI3798CV200_ETH_PUB_CLK 76 +#define HI3798CV200_ETH_BUS_CLK 77 +#define HI3798CV200_ETH_BUS0_CLK 78 +#define HI3798CV200_ETH_BUS1_CLK 79 +#define HI3798CV200_COMBPHY1_MUX 80 +#define HI3798CV200_FIXED_12M 81 +#define HI3798CV200_FIXED_48M 82 +#define HI3798CV200_FIXED_60M 83 +#define HI3798CV200_FIXED_166P5M 84 +#define HI3798CV200_SDIO0_MUX 85 + +#define HI3798CV200_CRG_NR_CLKS 128 static const struct hisi_fixed_rate_clock hi3798cv200_fixed_rate_clks[] = { { HISTB_OSC_CLK, "clk_osc", NULL, 0, 24000000, }, diff --git a/include/dt-bindings/clock/histb-clock.h b/include/dt-bindings/clock/histb-clock.h index 067f5e501b0c..eba850ff0017 100644 --- a/include/dt-bindings/clock/histb-clock.h +++ b/include/dt-bindings/clock/histb-clock.h @@ -22,18 +22,18 @@ #define HISTB_OSC_CLK 0 #define HISTB_APB_CLK 1 #define HISTB_AHB_CLK 2 -#define HISTB_UART1_CLK 3 -#define HISTB_UART2_CLK 4 -#define HISTB_UART3_CLK 5 -#define HISTB_I2C0_CLK 6 -#define HISTB_I2C1_CLK 7 -#define HISTB_I2C2_CLK 8 -#define HISTB_I2C3_CLK 9 -#define HISTB_I2C4_CLK 10 -#define HISTB_I2C5_CLK 11 -#define HISTB_SPI0_CLK 12 -#define HISTB_SPI1_CLK 13 -#define HISTB_SPI2_CLK 14 +#define HISTB_UART1_CLK 3 +#define HISTB_UART2_CLK 4 +#define HISTB_UART3_CLK 5 +#define HISTB_I2C0_CLK 6 +#define HISTB_I2C1_CLK 7 +#define HISTB_I2C2_CLK 8 +#define HISTB_I2C3_CLK 9 +#define HISTB_I2C4_CLK 10 +#define HISTB_I2C5_CLK 11 +#define HISTB_SPI0_CLK 12 +#define HISTB_SPI1_CLK 13 +#define HISTB_SPI2_CLK 14 #define HISTB_SCI_CLK 15 #define HISTB_FMC_CLK 16 #define HISTB_MMC_BIU_CLK 17 @@ -43,7 +43,7 @@ #define HISTB_SDIO0_BIU_CLK 21 #define HISTB_SDIO0_CIU_CLK 22 #define HISTB_SDIO0_DRV_CLK 23 -#define HISTB_SDIO0_SAMPLE_CLK 24 +#define HISTB_SDIO0_SAMPLE_CLK 24 #define HISTB_PCIE_AUX_CLK 25 #define HISTB_PCIE_PIPE_CLK 26 #define HISTB_PCIE_SYS_CLK 27 @@ -53,21 +53,21 @@ #define HISTB_ETH1_MAC_CLK 31 #define HISTB_ETH1_MACIF_CLK 32 #define HISTB_COMBPHY1_CLK 33 -#define HISTB_USB2_BUS_CLK 34 -#define HISTB_USB2_PHY_CLK 35 -#define HISTB_USB2_UTMI_CLK 36 -#define HISTB_USB2_12M_CLK 37 -#define HISTB_USB2_48M_CLK 38 -#define HISTB_USB2_OTG_UTMI_CLK 39 -#define HISTB_USB2_PHY1_REF_CLK 40 -#define HISTB_USB2_PHY2_REF_CLK 41 +#define HISTB_USB2_BUS_CLK 34 +#define HISTB_USB2_PHY_CLK 35 +#define HISTB_USB2_UTMI_CLK 36 +#define HISTB_USB2_12M_CLK 37 +#define HISTB_USB2_48M_CLK 38 +#define HISTB_USB2_OTG_UTMI_CLK 39 +#define HISTB_USB2_PHY1_REF_CLK 40 +#define HISTB_USB2_PHY2_REF_CLK 41 /* clocks provided by mcu CRG */ -#define HISTB_MCE_CLK 1 -#define HISTB_IR_CLK 2 -#define HISTB_TIMER01_CLK 3 -#define HISTB_LEDC_CLK 4 -#define HISTB_UART0_CLK 5 -#define HISTB_LSADC_CLK 6 +#define HISTB_MCE_CLK 1 +#define HISTB_IR_CLK 2 +#define HISTB_TIMER01_CLK 3 +#define HISTB_LEDC_CLK 4 +#define HISTB_UART0_CLK 5 +#define HISTB_LSADC_CLK 6 #endif /* __DTS_HISTB_CLOCK_H */ -- cgit From 80f8ce589517c478abdae07a758b37b362886cb2 Mon Sep 17 00:00:00 2001 From: Jianguo Sun Date: Wed, 24 Jan 2018 19:48:27 +0800 Subject: clk: hi3798cv200: add COMBPHY0 clock support The clock COMBPHY1 has already been supported by hi3798cv200 driver, but COMBPHY0 is missing. It adds COMBPHY0 clock support. Since the mux table is being shared by COMBPHY0 and COMBPHY1, it renames comphy1_mux_p and comphy1_mux_table a bit to drop instance number '1' from there. Signed-off-by: Jianguo Sun Signed-off-by: Shawn Guo --- drivers/clk/hisilicon/crg-hi3798cv200.c | 15 +++++++++++---- include/dt-bindings/clock/histb-clock.h | 1 + 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/drivers/clk/hisilicon/crg-hi3798cv200.c b/drivers/clk/hisilicon/crg-hi3798cv200.c index 451830e08375..d6e3971bac9e 100644 --- a/drivers/clk/hisilicon/crg-hi3798cv200.c +++ b/drivers/clk/hisilicon/crg-hi3798cv200.c @@ -49,6 +49,7 @@ #define HI3798CV200_FIXED_60M 83 #define HI3798CV200_FIXED_166P5M 84 #define HI3798CV200_SDIO0_MUX 85 +#define HI3798CV200_COMBPHY0_MUX 86 #define HI3798CV200_CRG_NR_CLKS 128 @@ -74,9 +75,9 @@ static const char *const mmc_mux_p[] = { "100m", "50m", "25m", "200m", "150m" }; static u32 mmc_mux_table[] = {0, 1, 2, 3, 6}; -static const char *const comphy1_mux_p[] = { +static const char *const comphy_mux_p[] = { "100m", "25m"}; -static u32 comphy1_mux_table[] = {2, 3}; +static u32 comphy_mux_table[] = {2, 3}; static const char *const sdio_mux_p[] = { "100m", "50m", "150m", "166p5m" }; @@ -85,9 +86,12 @@ static u32 sdio_mux_table[] = {0, 1, 2, 3}; static struct hisi_mux_clock hi3798cv200_mux_clks[] = { { HI3798CV200_MMC_MUX, "mmc_mux", mmc_mux_p, ARRAY_SIZE(mmc_mux_p), CLK_SET_RATE_PARENT, 0xa0, 8, 3, 0, mmc_mux_table, }, + { HI3798CV200_COMBPHY0_MUX, "combphy0_mux", + comphy_mux_p, ARRAY_SIZE(comphy_mux_p), + CLK_SET_RATE_PARENT, 0x188, 2, 2, 0, comphy_mux_table, }, { HI3798CV200_COMBPHY1_MUX, "combphy1_mux", - comphy1_mux_p, ARRAY_SIZE(comphy1_mux_p), - CLK_SET_RATE_PARENT, 0x188, 10, 2, 0, comphy1_mux_table, }, + comphy_mux_p, ARRAY_SIZE(comphy_mux_p), + CLK_SET_RATE_PARENT, 0x188, 10, 2, 0, comphy_mux_table, }, { HI3798CV200_SDIO0_MUX, "sdio0_mux", sdio_mux_p, ARRAY_SIZE(sdio_mux_p), CLK_SET_RATE_PARENT, 0x9c, 8, 2, 0, sdio_mux_table, }, @@ -147,6 +151,9 @@ static const struct hisi_gate_clock hi3798cv200_gate_clks[] = { CLK_SET_RATE_PARENT, 0xcc, 4, 0, }, { HISTB_ETH1_MACIF_CLK, "clk_macif1", "clk_bus_m1", CLK_SET_RATE_PARENT, 0xcc, 25, 0, }, + /* COMBPHY0 */ + { HISTB_COMBPHY0_CLK, "clk_combphy0", "combphy0_mux", + CLK_SET_RATE_PARENT, 0x188, 0, 0, }, /* COMBPHY1 */ { HISTB_COMBPHY1_CLK, "clk_combphy1", "combphy1_mux", CLK_SET_RATE_PARENT, 0x188, 8, 0, }, diff --git a/include/dt-bindings/clock/histb-clock.h b/include/dt-bindings/clock/histb-clock.h index eba850ff0017..fab30b3f78b2 100644 --- a/include/dt-bindings/clock/histb-clock.h +++ b/include/dt-bindings/clock/histb-clock.h @@ -61,6 +61,7 @@ #define HISTB_USB2_OTG_UTMI_CLK 39 #define HISTB_USB2_PHY1_REF_CLK 40 #define HISTB_USB2_PHY2_REF_CLK 41 +#define HISTB_COMBPHY0_CLK 42 /* clocks provided by mcu CRG */ #define HISTB_MCE_CLK 1 -- cgit From b716aad97eb5119e73cec351179c3a23f96c7aaa Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Thu, 4 Jan 2018 01:09:21 +0800 Subject: clk: imx: imx7d: correct video pll clock tree There is a test divider and post divider in video PLL, test divider is placed before post divider, all clocks that can select parent from video PLL should be from post divider, NOT from pll_video_main, below are clock tree dump before and after this patch: Before: pll_video_main pll_video_main_bypass pll_video_main_clk lcdif_pixel_src lcdif_pixel_cg lcdif_pixel_pre_div lcdif_pixel_post_div lcdif_pixel_root_clk After: pll_video_main pll_video_main_bypass pll_video_main_clk pll_video_test_div pll_video_post_div lcdif_pixel_src lcdif_pixel_cg lcdif_pixel_pre_div lcdif_pixel_post_div lcdif_pixel_root_clk Signed-off-by: Anson Huang Reviewed-by: Fabio Estevam Acked-by: Dong Aisheng Signed-off-by: Shawn Guo --- drivers/clk/imx/clk-imx7d.c | 84 ++++++++++++++++++++++++--------------------- 1 file changed, 44 insertions(+), 40 deletions(-) diff --git a/drivers/clk/imx/clk-imx7d.c b/drivers/clk/imx/clk-imx7d.c index 80dc211eb74b..992938b8696f 100644 --- a/drivers/clk/imx/clk-imx7d.c +++ b/drivers/clk/imx/clk-imx7d.c @@ -51,20 +51,20 @@ static const char *arm_a7_sel[] = { "osc", "pll_arm_main_clk", static const char *arm_m4_sel[] = { "osc", "pll_sys_main_240m_clk", "pll_enet_250m_clk", "pll_sys_pfd2_270m_clk", - "pll_dram_533m_clk", "pll_audio_post_div", "pll_video_main_clk", + "pll_dram_533m_clk", "pll_audio_post_div", "pll_video_post_div", "pll_usb_main_clk", }; static const char *axi_sel[] = { "osc", "pll_sys_pfd1_332m_clk", "pll_dram_533m_clk", "pll_enet_250m_clk", "pll_sys_pfd5_clk", - "pll_audio_post_div", "pll_video_main_clk", "pll_sys_pfd7_clk", }; + "pll_audio_post_div", "pll_video_post_div", "pll_sys_pfd7_clk", }; static const char *disp_axi_sel[] = { "osc", "pll_sys_pfd1_332m_clk", "pll_dram_533m_clk", "pll_enet_250m_clk", "pll_sys_pfd6_clk", - "pll_sys_pfd7_clk", "pll_audio_post_div", "pll_video_main_clk", }; + "pll_sys_pfd7_clk", "pll_audio_post_div", "pll_video_post_div", }; static const char *enet_axi_sel[] = { "osc", "pll_sys_pfd2_270m_clk", "pll_dram_533m_clk", "pll_enet_250m_clk", - "pll_sys_main_240m_clk", "pll_audio_post_div", "pll_video_main_clk", + "pll_sys_main_240m_clk", "pll_audio_post_div", "pll_video_post_div", "pll_sys_pfd4_clk", }; static const char *nand_usdhc_bus_sel[] = { "osc", "pll_sys_pfd2_270m_clk", @@ -75,7 +75,7 @@ static const char *nand_usdhc_bus_sel[] = { "osc", "pll_sys_pfd2_270m_clk", static const char *ahb_channel_sel[] = { "osc", "pll_sys_pfd2_270m_clk", "pll_dram_533m_clk", "pll_sys_pfd0_392m_clk", "pll_enet_125m_clk", "pll_usb_main_clk", "pll_audio_post_div", - "pll_video_main_clk", }; + "pll_video_post_div", }; static const char *dram_phym_sel[] = { "pll_dram_main_clk", "dram_phym_alt_clk", }; @@ -86,7 +86,7 @@ static const char *dram_sel[] = { "pll_dram_main_clk", static const char *dram_phym_alt_sel[] = { "osc", "pll_dram_533m_clk", "pll_sys_main_clk", "pll_enet_500m_clk", "pll_usb_main_clk", "pll_sys_pfd7_clk", "pll_audio_post_div", - "pll_video_main_clk", }; + "pll_video_post_div", }; static const char *dram_alt_sel[] = { "osc", "pll_dram_533m_clk", "pll_sys_main_clk", "pll_enet_500m_clk", @@ -108,62 +108,62 @@ static const char *pcie_phy_sel[] = { "osc", "pll_enet_100m_clk", static const char *epdc_pixel_sel[] = { "osc", "pll_sys_pfd1_332m_clk", "pll_dram_533m_clk", "pll_sys_main_clk", "pll_sys_pfd5_clk", - "pll_sys_pfd6_clk", "pll_sys_pfd7_clk", "pll_video_main_clk", }; + "pll_sys_pfd6_clk", "pll_sys_pfd7_clk", "pll_video_post_div", }; static const char *lcdif_pixel_sel[] = { "osc", "pll_sys_pfd5_clk", "pll_dram_533m_clk", "ext_clk_3", "pll_sys_pfd4_clk", - "pll_sys_pfd2_270m_clk", "pll_video_main_clk", + "pll_sys_pfd2_270m_clk", "pll_video_post_div", "pll_usb_main_clk", }; static const char *mipi_dsi_sel[] = { "osc", "pll_sys_pfd5_clk", "pll_sys_pfd3_clk", "pll_sys_main_clk", "pll_sys_pfd0_196m_clk", - "pll_dram_533m_clk", "pll_video_main_clk", "pll_audio_post_div", }; + "pll_dram_533m_clk", "pll_video_post_div", "pll_audio_post_div", }; static const char *mipi_csi_sel[] = { "osc", "pll_sys_pfd4_clk", "pll_sys_pfd3_clk", "pll_sys_main_clk", "pll_sys_pfd0_196m_clk", - "pll_dram_533m_clk", "pll_video_main_clk", "pll_audio_post_div", }; + "pll_dram_533m_clk", "pll_video_post_div", "pll_audio_post_div", }; static const char *mipi_dphy_sel[] = { "osc", "pll_sys_main_120m_clk", "pll_dram_533m_clk", "pll_sys_pfd5_clk", "ref_1m_clk", "ext_clk_2", - "pll_video_main_clk", "ext_clk_3", }; + "pll_video_post_div", "ext_clk_3", }; static const char *sai1_sel[] = { "osc", "pll_sys_pfd2_135m_clk", - "pll_audio_post_div", "pll_dram_533m_clk", "pll_video_main_clk", + "pll_audio_post_div", "pll_dram_533m_clk", "pll_video_post_div", "pll_sys_pfd4_clk", "pll_enet_125m_clk", "ext_clk_2", }; static const char *sai2_sel[] = { "osc", "pll_sys_pfd2_135m_clk", - "pll_audio_post_div", "pll_dram_533m_clk", "pll_video_main_clk", + "pll_audio_post_div", "pll_dram_533m_clk", "pll_video_post_div", "pll_sys_pfd4_clk", "pll_enet_125m_clk", "ext_clk_2", }; static const char *sai3_sel[] = { "osc", "pll_sys_pfd2_135m_clk", - "pll_audio_post_div", "pll_dram_533m_clk", "pll_video_main_clk", + "pll_audio_post_div", "pll_dram_533m_clk", "pll_video_post_div", "pll_sys_pfd4_clk", "pll_enet_125m_clk", "ext_clk_3", }; static const char *spdif_sel[] = { "osc", "pll_sys_pfd2_135m_clk", - "pll_audio_post_div", "pll_dram_533m_clk", "pll_video_main_clk", + "pll_audio_post_div", "pll_dram_533m_clk", "pll_video_post_div", "pll_sys_pfd4_clk", "pll_enet_125m_clk", "ext_3_clk", }; static const char *enet1_ref_sel[] = { "osc", "pll_enet_125m_clk", "pll_enet_50m_clk", "pll_enet_25m_clk", - "pll_sys_main_120m_clk", "pll_audio_post_div", "pll_video_main_clk", + "pll_sys_main_120m_clk", "pll_audio_post_div", "pll_video_post_div", "ext_clk_4", }; static const char *enet1_time_sel[] = { "osc", "pll_enet_100m_clk", "pll_audio_post_div", "ext_clk_1", "ext_clk_2", "ext_clk_3", - "ext_clk_4", "pll_video_main_clk", }; + "ext_clk_4", "pll_video_post_div", }; static const char *enet2_ref_sel[] = { "osc", "pll_enet_125m_clk", "pll_enet_50m_clk", "pll_enet_25m_clk", - "pll_sys_main_120m_clk", "pll_audio_post_div", "pll_video_main_clk", + "pll_sys_main_120m_clk", "pll_audio_post_div", "pll_video_post_div", "ext_clk_4", }; static const char *enet2_time_sel[] = { "osc", "pll_enet_100m_clk", "pll_audio_post_div", "ext_clk_1", "ext_clk_2", "ext_clk_3", - "ext_clk_4", "pll_video_main_clk", }; + "ext_clk_4", "pll_video_post_div", }; static const char *enet_phy_ref_sel[] = { "osc", "pll_enet_25m_clk", "pll_enet_50m_clk", "pll_enet_125m_clk", - "pll_dram_533m_clk", "pll_audio_post_div", "pll_video_main_clk", + "pll_dram_533m_clk", "pll_audio_post_div", "pll_video_post_div", "pll_sys_pfd3_clk", }; static const char *eim_sel[] = { "osc", "pll_sys_pfd2_135m_clk", @@ -174,7 +174,7 @@ static const char *eim_sel[] = { "osc", "pll_sys_pfd2_135m_clk", static const char *nand_sel[] = { "osc", "pll_sys_main_clk", "pll_dram_533m_clk", "pll_sys_pfd0_392m_clk", "pll_sys_pfd3_clk", "pll_enet_500m_clk", "pll_enet_250m_clk", - "pll_video_main_clk", }; + "pll_video_post_div", }; static const char *qspi_sel[] = { "osc", "pll_sys_pfd4_clk", "pll_dram_533m_clk", "pll_enet_500m_clk", "pll_sys_pfd3_clk", @@ -204,22 +204,22 @@ static const char *can2_sel[] = { "osc", "pll_sys_main_120m_clk", static const char *i2c1_sel[] = { "osc", "pll_sys_main_120m_clk", "pll_enet_50m_clk", "pll_dram_533m_clk", - "pll_audio_post_div", "pll_video_main_clk", "pll_usb_main_clk", + "pll_audio_post_div", "pll_video_post_div", "pll_usb_main_clk", "pll_sys_pfd2_135m_clk", }; static const char *i2c2_sel[] = { "osc", "pll_sys_main_120m_clk", "pll_enet_50m_clk", "pll_dram_533m_clk", - "pll_audio_post_div", "pll_video_main_clk", "pll_usb_main_clk", + "pll_audio_post_div", "pll_video_post_div", "pll_usb_main_clk", "pll_sys_pfd2_135m_clk", }; static const char *i2c3_sel[] = { "osc", "pll_sys_main_120m_clk", "pll_enet_50m_clk", "pll_dram_533m_clk", - "pll_audio_post_div", "pll_video_main_clk", "pll_usb_main_clk", + "pll_audio_post_div", "pll_video_post_div", "pll_usb_main_clk", "pll_sys_pfd2_135m_clk", }; static const char *i2c4_sel[] = { "osc", "pll_sys_main_120m_clk", "pll_enet_50m_clk", "pll_dram_533m_clk", - "pll_audio_post_div", "pll_video_main_clk", "pll_usb_main_clk", + "pll_audio_post_div", "pll_video_post_div", "pll_usb_main_clk", "pll_sys_pfd2_135m_clk", }; static const char *uart1_sel[] = { "osc", "pll_sys_main_240m_clk", @@ -279,27 +279,27 @@ static const char *ecspi4_sel[] = { "osc", "pll_sys_main_240m_clk", static const char *pwm1_sel[] = { "osc", "pll_enet_100m_clk", "pll_sys_main_120m_clk", "pll_enet_40m_clk", "pll_audio_post_div", - "ext_clk_1", "ref_1m_clk", "pll_video_main_clk", }; + "ext_clk_1", "ref_1m_clk", "pll_video_post_div", }; static const char *pwm2_sel[] = { "osc", "pll_enet_100m_clk", "pll_sys_main_120m_clk", "pll_enet_40m_clk", "pll_audio_post_div", - "ext_clk_1", "ref_1m_clk", "pll_video_main_clk", }; + "ext_clk_1", "ref_1m_clk", "pll_video_post_div", }; static const char *pwm3_sel[] = { "osc", "pll_enet_100m_clk", "pll_sys_main_120m_clk", "pll_enet_40m_clk", "pll_audio_post_div", - "ext_clk_2", "ref_1m_clk", "pll_video_main_clk", }; + "ext_clk_2", "ref_1m_clk", "pll_video_post_div", }; static const char *pwm4_sel[] = { "osc", "pll_enet_100m_clk", "pll_sys_main_120m_clk", "pll_enet_40m_clk", "pll_audio_post_div", - "ext_clk_2", "ref_1m_clk", "pll_video_main_clk", }; + "ext_clk_2", "ref_1m_clk", "pll_video_post_div", }; static const char *flextimer1_sel[] = { "osc", "pll_enet_100m_clk", "pll_sys_main_120m_clk", "pll_enet_40m_clk", "pll_audio_post_div", - "ext_clk_3", "ref_1m_clk", "pll_video_main_clk", }; + "ext_clk_3", "ref_1m_clk", "pll_video_post_div", }; static const char *flextimer2_sel[] = { "osc", "pll_enet_100m_clk", "pll_sys_main_120m_clk", "pll_enet_40m_clk", "pll_audio_post_div", - "ext_clk_3", "ref_1m_clk", "pll_video_main_clk", }; + "ext_clk_3", "ref_1m_clk", "pll_video_post_div", }; static const char *sim1_sel[] = { "osc", "pll_sys_pfd2_135m_clk", "pll_sys_main_120m_clk", "pll_dram_533m_clk", @@ -308,23 +308,23 @@ static const char *sim1_sel[] = { "osc", "pll_sys_pfd2_135m_clk", static const char *sim2_sel[] = { "osc", "pll_sys_pfd2_135m_clk", "pll_sys_main_120m_clk", "pll_dram_533m_clk", - "pll_usb_main_clk", "pll_video_main_clk", "pll_enet_125m_clk", + "pll_usb_main_clk", "pll_video_post_div", "pll_enet_125m_clk", "pll_sys_pfd7_clk", }; static const char *gpt1_sel[] = { "osc", "pll_enet_100m_clk", - "pll_sys_pfd0_392m_clk", "pll_enet_40m_clk", "pll_video_main_clk", + "pll_sys_pfd0_392m_clk", "pll_enet_40m_clk", "pll_video_post_div", "ref_1m_clk", "pll_audio_post_div", "ext_clk_1", }; static const char *gpt2_sel[] = { "osc", "pll_enet_100m_clk", - "pll_sys_pfd0_392m_clk", "pll_enet_40m_clk", "pll_video_main_clk", + "pll_sys_pfd0_392m_clk", "pll_enet_40m_clk", "pll_video_post_div", "ref_1m_clk", "pll_audio_post_div", "ext_clk_2", }; static const char *gpt3_sel[] = { "osc", "pll_enet_100m_clk", - "pll_sys_pfd0_392m_clk", "pll_enet_40m_clk", "pll_video_main_clk", + "pll_sys_pfd0_392m_clk", "pll_enet_40m_clk", "pll_video_post_div", "ref_1m_clk", "pll_audio_post_div", "ext_clk_3", }; static const char *gpt4_sel[] = { "osc", "pll_enet_100m_clk", - "pll_sys_pfd0_392m_clk", "pll_enet_40m_clk", "pll_video_main_clk", + "pll_sys_pfd0_392m_clk", "pll_enet_40m_clk", "pll_video_post_div", "ref_1m_clk", "pll_audio_post_div", "ext_clk_4", }; static const char *trace_sel[] = { "osc", "pll_sys_pfd2_135m_clk", @@ -339,12 +339,12 @@ static const char *wdog_sel[] = { "osc", "pll_sys_pfd2_135m_clk", static const char *csi_mclk_sel[] = { "osc", "pll_sys_pfd2_135m_clk", "pll_sys_main_120m_clk", "pll_dram_533m_clk", - "pll_enet_125m_clk", "pll_audio_post_div", "pll_video_main_clk", + "pll_enet_125m_clk", "pll_audio_post_div", "pll_video_post_div", "pll_usb_main_clk", }; static const char *audio_mclk_sel[] = { "osc", "pll_sys_pfd2_135m_clk", "pll_sys_main_120m_clk", "pll_dram_533m_clk", - "pll_enet_125m_clk", "pll_audio_post_div", "pll_video_main_clk", + "pll_enet_125m_clk", "pll_audio_post_div", "pll_video_post_div", "pll_usb_main_clk", }; static const char *wrclk_sel[] = { "osc", "pll_enet_40m_clk", @@ -358,13 +358,13 @@ static const char *clko1_sel[] = { "osc", "pll_sys_main_clk", static const char *clko2_sel[] = { "osc", "pll_sys_main_240m_clk", "pll_sys_pfd0_392m_clk", "pll_sys_pfd1_166m_clk", "pll_sys_pfd4_clk", - "pll_audio_post_div", "pll_video_main_clk", "ckil", }; + "pll_audio_post_div", "pll_video_post_div", "ckil", }; static const char *lvds1_sel[] = { "pll_arm_main_clk", "pll_sys_main_clk", "pll_sys_pfd0_392m_clk", "pll_sys_pfd1_332m_clk", "pll_sys_pfd2_270m_clk", "pll_sys_pfd3_clk", "pll_sys_pfd4_clk", "pll_sys_pfd5_clk", "pll_sys_pfd6_clk", "pll_sys_pfd7_clk", - "pll_audio_post_div", "pll_video_main_clk", "pll_enet_500m_clk", + "pll_audio_post_div", "pll_video_post_div", "pll_enet_500m_clk", "pll_enet_250m_clk", "pll_enet_125m_clk", "pll_enet_100m_clk", "pll_enet_50m_clk", "pll_enet_40m_clk", "pll_enet_25m_clk", "pll_dram_main_clk", }; @@ -450,6 +450,10 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node) CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0xf0, 19, 2, 0, test_div_table, &imx_ccm_lock); clks[IMX7D_PLL_AUDIO_POST_DIV] = clk_register_divider_table(NULL, "pll_audio_post_div", "pll_audio_test_div", CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0xf0, 22, 2, 0, post_div_table, &imx_ccm_lock); + clks[IMX7D_PLL_VIDEO_TEST_DIV] = clk_register_divider_table(NULL, "pll_video_test_div", "pll_video_main_clk", + CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0x130, 19, 2, 0, test_div_table, &imx_ccm_lock); + clks[IMX7D_PLL_VIDEO_POST_DIV] = clk_register_divider_table(NULL, "pll_video_post_div", "pll_video_test_div", + CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0x130, 22, 2, 0, post_div_table, &imx_ccm_lock); clks[IMX7D_PLL_SYS_PFD0_392M_CLK] = imx_clk_pfd("pll_sys_pfd0_392m_clk", "pll_sys_main_clk", base + 0xc0, 0); clks[IMX7D_PLL_SYS_PFD1_332M_CLK] = imx_clk_pfd("pll_sys_pfd1_332m_clk", "pll_sys_main_clk", base + 0xc0, 1); -- cgit From 2d2b61c13a4b39c8ba6b9c1daa79d5891689864e Mon Sep 17 00:00:00 2001 From: Jernej Skrabec Date: Thu, 1 Mar 2018 22:34:27 +0100 Subject: clk: sunxi-ng: Add check for minimal rate to NM PLLs Some NM PLLs doesn't work well when their output clock rate is set below certain rate. Add support for that constrain. Signed-off-by: Jernej Skrabec Signed-off-by: Maxime Ripard --- drivers/clk/sunxi-ng/ccu_nm.c | 7 +++++++ drivers/clk/sunxi-ng/ccu_nm.h | 27 +++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/drivers/clk/sunxi-ng/ccu_nm.c b/drivers/clk/sunxi-ng/ccu_nm.c index a16de092bf94..4e2073307f34 100644 --- a/drivers/clk/sunxi-ng/ccu_nm.c +++ b/drivers/clk/sunxi-ng/ccu_nm.c @@ -117,6 +117,13 @@ static long ccu_nm_round_rate(struct clk_hw *hw, unsigned long rate, if (nm->common.features & CCU_FEATURE_FIXED_POSTDIV) rate *= nm->fixed_post_div; + if (rate < nm->min_rate) { + rate = nm->min_rate; + if (nm->common.features & CCU_FEATURE_FIXED_POSTDIV) + rate /= nm->fixed_post_div; + return rate; + } + if (ccu_frac_helper_has_rate(&nm->common, &nm->frac, rate)) { if (nm->common.features & CCU_FEATURE_FIXED_POSTDIV) rate /= nm->fixed_post_div; diff --git a/drivers/clk/sunxi-ng/ccu_nm.h b/drivers/clk/sunxi-ng/ccu_nm.h index eba586b4c7d0..1d8b459c50b7 100644 --- a/drivers/clk/sunxi-ng/ccu_nm.h +++ b/drivers/clk/sunxi-ng/ccu_nm.h @@ -37,6 +37,7 @@ struct ccu_nm { struct ccu_sdm_internal sdm; unsigned int fixed_post_div; + unsigned int min_rate; struct ccu_common common; }; @@ -88,6 +89,32 @@ struct ccu_nm { }, \ } +#define SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN(_struct, _name, _parent, \ + _reg, _min_rate, \ + _nshift, _nwidth, \ + _mshift, _mwidth, \ + _frac_en, _frac_sel, \ + _frac_rate_0, _frac_rate_1,\ + _gate, _lock, _flags) \ + struct ccu_nm _struct = { \ + .enable = _gate, \ + .lock = _lock, \ + .n = _SUNXI_CCU_MULT(_nshift, _nwidth), \ + .m = _SUNXI_CCU_DIV(_mshift, _mwidth), \ + .frac = _SUNXI_CCU_FRAC(_frac_en, _frac_sel, \ + _frac_rate_0, \ + _frac_rate_1), \ + .min_rate = _min_rate, \ + .common = { \ + .reg = _reg, \ + .features = CCU_FEATURE_FRACTIONAL, \ + .hw.init = CLK_HW_INIT(_name, \ + _parent, \ + &ccu_nm_ops, \ + _flags), \ + }, \ + } + #define SUNXI_CCU_NM_WITH_GATE_LOCK(_struct, _name, _parent, _reg, \ _nshift, _nwidth, \ _mshift, _mwidth, \ -- cgit From 4fd8ae912f9829c4324fa85d945cc0288c218bc5 Mon Sep 17 00:00:00 2001 From: Jernej Skrabec Date: Thu, 1 Mar 2018 22:34:28 +0100 Subject: clk: sunxi-ng: h3: h5: Add minimal rate for video PLL Although user manuals for H3 and H5 SoCs state that minimal rate supported by video PLL is around 30 MHz, it seems that in reality minimal rate is around 192 MHz. Experiments showed that any rate below 96 MHz doesn't produce any video output at all. Even at this frequency, stable output depends on right factors. For example, when N = 4 and M = 1, output is stable and when N = 8 and M = 2, it's not. BSP clock driver suggest that minimum stable frequency is 192 MHz. That would also be in line with A64 SoC, which has similar periphery. Set minimal video PLL rate for H3/H5 to 192 MHz. Signed-off-by: Jernej Skrabec Signed-off-by: Maxime Ripard --- drivers/clk/sunxi-ng/ccu-sun8i-h3.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-h3.c b/drivers/clk/sunxi-ng/ccu-sun8i-h3.c index 29bc0566b776..b9f39078c0b2 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-h3.c +++ b/drivers/clk/sunxi-ng/ccu-sun8i-h3.c @@ -69,17 +69,18 @@ static SUNXI_CCU_NM_WITH_SDM_GATE_LOCK(pll_audio_base_clk, "pll-audio-base", BIT(28), /* lock */ CLK_SET_RATE_UNGATE); -static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_video_clk, "pll-video", - "osc24M", 0x0010, - 8, 7, /* N */ - 0, 4, /* M */ - BIT(24), /* frac enable */ - BIT(25), /* frac select */ - 270000000, /* frac rate 0 */ - 297000000, /* frac rate 1 */ - BIT(31), /* gate */ - BIT(28), /* lock */ - CLK_SET_RATE_UNGATE); +static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN(pll_video_clk, "pll-video", + "osc24M", 0x0010, + 192000000, /* Minimum rate */ + 8, 7, /* N */ + 0, 4, /* M */ + BIT(24), /* frac enable */ + BIT(25), /* frac select */ + 270000000, /* frac rate 0 */ + 297000000, /* frac rate 1 */ + BIT(31), /* gate */ + BIT(28), /* lock */ + CLK_SET_RATE_UNGATE); static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_ve_clk, "pll-ve", "osc24M", 0x0018, -- cgit From b1a1ad4b75b876ccf200f2351ae61364bf856613 Mon Sep 17 00:00:00 2001 From: Jernej Skrabec Date: Thu, 1 Mar 2018 22:34:29 +0100 Subject: clk: sunxi-ng: h3: h5: Allow some clocks to set parent rate Some units have to be able to set it's own clock precisely to work correctly. Allow them to do so by adding CLK_SET_RATE_PARENT flag. Add this flag to DE, TCON and HDMI clocks. Signed-off-by: Jernej Skrabec Signed-off-by: Maxime Ripard --- drivers/clk/sunxi-ng/ccu-sun8i-h3.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-h3.c b/drivers/clk/sunxi-ng/ccu-sun8i-h3.c index b9f39078c0b2..77ed0b0ba681 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-h3.c +++ b/drivers/clk/sunxi-ng/ccu-sun8i-h3.c @@ -452,11 +452,13 @@ static SUNXI_CCU_GATE(dram_ts_clk, "dram-ts", "dram", static const char * const de_parents[] = { "pll-periph0-2x", "pll-de" }; static SUNXI_CCU_M_WITH_MUX_GATE(de_clk, "de", de_parents, - 0x104, 0, 4, 24, 3, BIT(31), 0); + 0x104, 0, 4, 24, 3, BIT(31), + CLK_SET_RATE_PARENT); static const char * const tcon_parents[] = { "pll-video" }; static SUNXI_CCU_M_WITH_MUX_GATE(tcon_clk, "tcon", tcon_parents, - 0x118, 0, 4, 24, 3, BIT(31), 0); + 0x118, 0, 4, 24, 3, BIT(31), + CLK_SET_RATE_PARENT); static const char * const tve_parents[] = { "pll-de", "pll-periph1" }; static SUNXI_CCU_M_WITH_MUX_GATE(tve_clk, "tve", tve_parents, @@ -487,7 +489,8 @@ static SUNXI_CCU_GATE(avs_clk, "avs", "osc24M", static const char * const hdmi_parents[] = { "pll-video" }; static SUNXI_CCU_M_WITH_MUX_GATE(hdmi_clk, "hdmi", hdmi_parents, - 0x150, 0, 4, 24, 2, BIT(31), 0); + 0x150, 0, 4, 24, 2, BIT(31), + CLK_SET_RATE_PARENT); static SUNXI_CCU_GATE(hdmi_ddc_clk, "hdmi-ddc", "osc24M", 0x154, BIT(31), 0); -- cgit From 55de0f31df1a31b346edfe98d061f11162ff1ad4 Mon Sep 17 00:00:00 2001 From: Jernej Skrabec Date: Thu, 1 Mar 2018 22:34:30 +0100 Subject: clk: sunxi-ng: h3: h5: export CLK_PLL_VIDEO CLK_PLL_VIDEO needs to be referenced in HDMI DT entry as a possible PHY clock parent. Export it so it can be used later in DT. Signed-off-by: Jernej Skrabec Signed-off-by: Maxime Ripard --- drivers/clk/sunxi-ng/ccu-sun8i-h3.h | 4 +++- include/dt-bindings/clock/sun8i-h3-ccu.h | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-h3.h b/drivers/clk/sunxi-ng/ccu-sun8i-h3.h index 1b4baea37d81..73d7392c968c 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-h3.h +++ b/drivers/clk/sunxi-ng/ccu-sun8i-h3.h @@ -26,7 +26,9 @@ #define CLK_PLL_AUDIO_2X 3 #define CLK_PLL_AUDIO_4X 4 #define CLK_PLL_AUDIO_8X 5 -#define CLK_PLL_VIDEO 6 + +/* PLL_VIDEO is exported */ + #define CLK_PLL_VE 7 #define CLK_PLL_DDR 8 diff --git a/include/dt-bindings/clock/sun8i-h3-ccu.h b/include/dt-bindings/clock/sun8i-h3-ccu.h index e139fe5c62ec..c5f7e9a70968 100644 --- a/include/dt-bindings/clock/sun8i-h3-ccu.h +++ b/include/dt-bindings/clock/sun8i-h3-ccu.h @@ -43,6 +43,8 @@ #ifndef _DT_BINDINGS_CLK_SUN8I_H3_H_ #define _DT_BINDINGS_CLK_SUN8I_H3_H_ +#define CLK_PLL_VIDEO 6 + #define CLK_PLL_PERIPH0 9 #define CLK_CPUX 14 -- cgit From fd3cbbfb76a422a5b0f85649b677477a308866db Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Wed, 28 Feb 2018 14:56:48 +0800 Subject: clk: rockchip: Free the memory on the error path rockchip_clk_register_branch() and rockchip_clk_register_frac_branch() should free the memory internally when seeing any failure. Signed-off-by: Shawn Lin Signed-off-by: Heiko Stuebner --- drivers/clk/rockchip/clk.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/drivers/clk/rockchip/clk.c b/drivers/clk/rockchip/clk.c index 35dbd63c2f49..3cd8ad59e0b7 100644 --- a/drivers/clk/rockchip/clk.c +++ b/drivers/clk/rockchip/clk.c @@ -57,6 +57,7 @@ static struct clk *rockchip_clk_register_branch(const char *name, struct clk_divider *div = NULL; const struct clk_ops *mux_ops = NULL, *div_ops = NULL, *gate_ops = NULL; + int ret; if (num_parents > 1) { mux = kzalloc(sizeof(*mux), GFP_KERNEL); @@ -74,8 +75,10 @@ static struct clk *rockchip_clk_register_branch(const char *name, if (gate_offset >= 0) { gate = kzalloc(sizeof(*gate), GFP_KERNEL); - if (!gate) + if (!gate) { + ret = -ENOMEM; goto err_gate; + } gate->flags = gate_flags; gate->reg = base + gate_offset; @@ -86,8 +89,10 @@ static struct clk *rockchip_clk_register_branch(const char *name, if (div_width > 0) { div = kzalloc(sizeof(*div), GFP_KERNEL); - if (!div) + if (!div) { + ret = -ENOMEM; goto err_div; + } div->flags = div_flags; div->reg = base + muxdiv_offset; @@ -106,12 +111,19 @@ static struct clk *rockchip_clk_register_branch(const char *name, gate ? &gate->hw : NULL, gate_ops, flags); + if (IS_ERR(clk)) { + ret = PTR_ERR(clk); + goto err_composite; + } + return clk; +err_composite: + kfree(div); err_div: kfree(gate); err_gate: kfree(mux); - return ERR_PTR(-ENOMEM); + return ERR_PTR(ret); } struct rockchip_clk_frac { @@ -291,8 +303,10 @@ static struct clk *rockchip_clk_register_frac_branch( init.num_parents = child->num_parents; mux_clk = clk_register(NULL, &frac_mux->hw); - if (IS_ERR(mux_clk)) + if (IS_ERR(mux_clk)) { + kfree(frac); return clk; + } rockchip_clk_add_lookup(ctx, mux_clk, child->id); -- cgit From 4bf59902b50012b1dddeeaa23b217d9c4956cdda Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Mon, 5 Mar 2018 11:25:58 +0800 Subject: clk: rockchip: Prevent calculating mmc phase if clock rate is zero The MMC sample and drv clock for rockchip platforms are derived from the bus clock output to the MMC/SDIO card. So it should never happens that the clk rate is zero given it should inherits the clock rate from its parent. If something goes wrong and makes the clock rate to be zero, the calculation would be wrong but may still make the mmc tuning process work luckily. However it makes people harder to debug when the following data transfer is unstable. Signed-off-by: Shawn Lin Signed-off-by: Heiko Stuebner --- drivers/clk/rockchip/clk-mmc-phase.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/drivers/clk/rockchip/clk-mmc-phase.c b/drivers/clk/rockchip/clk-mmc-phase.c index 077fcdc7908b..fe7d9ed1d436 100644 --- a/drivers/clk/rockchip/clk-mmc-phase.c +++ b/drivers/clk/rockchip/clk-mmc-phase.c @@ -58,6 +58,12 @@ static int rockchip_mmc_get_phase(struct clk_hw *hw) u16 degrees; u32 delay_num = 0; + /* See the comment for rockchip_mmc_set_phase below */ + if (!rate) { + pr_err("%s: invalid clk rate\n", __func__); + return -EINVAL; + } + raw_value = readl(mmc_clock->reg) >> (mmc_clock->shift); degrees = (raw_value & ROCKCHIP_MMC_DEGREE_MASK) * 90; @@ -84,6 +90,23 @@ static int rockchip_mmc_set_phase(struct clk_hw *hw, int degrees) u32 raw_value; u32 delay; + /* + * The below calculation is based on the output clock from + * MMC host to the card, which expects the phase clock inherits + * the clock rate from its parent, namely the output clock + * provider of MMC host. However, things may go wrong if + * (1) It is orphan. + * (2) It is assigned to the wrong parent. + * + * This check help debug the case (1), which seems to be the + * most likely problem we often face and which makes it difficult + * for people to debug unstable mmc tuning results. + */ + if (!rate) { + pr_err("%s: invalid clk rate\n", __func__); + return -EINVAL; + } + nineties = degrees / 90; remainder = (degrees % 90); -- cgit From af8d30ac64e1ddef50981dc039f5773f57338b1a Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Wed, 21 Feb 2018 11:15:22 +0100 Subject: soc: samsung: pm_domains: Add blacklisting clock handling Handling of clock reparenting will be move to clock controller driver, so add possibility to blacklist clock handling on systems, where the clock controller already does all needed operations. This is needed to avoid potential deadlock on clock reparenting during power domain on/off procedure. Signed-off-by: Marek Szyprowski Reviewed-by: Krzysztof Kozlowski Signed-off-by: Sylwester Nawrocki --- drivers/soc/samsung/pm_domains.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/soc/samsung/pm_domains.c b/drivers/soc/samsung/pm_domains.c index b6a436594a19..cef30bdf19b1 100644 --- a/drivers/soc/samsung/pm_domains.c +++ b/drivers/soc/samsung/pm_domains.c @@ -147,6 +147,9 @@ static __init const char *exynos_get_domain_name(struct device_node *node) return kstrdup_const(name, GFP_KERNEL); } +static const char *soc_force_no_clk[] = { +}; + static __init int exynos4_pm_init_power_domain(void) { struct device_node *np; @@ -183,6 +186,11 @@ static __init int exynos4_pm_init_power_domain(void) pd->pd.power_on = exynos_pd_power_on; pd->local_pwr_cfg = pm_domain_cfg->local_pwr_cfg; + for (i = 0; i < ARRAY_SIZE(soc_force_no_clk); i++) + if (of_find_compatible_node(NULL, NULL, + soc_force_no_clk[i])) + goto no_clk; + for (i = 0; i < MAX_CLK_PER_DOMAIN; i++) { char clk_name[8]; -- cgit From b06a532bf1fa99af0d9364e5dfb8654fa78d490b Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Tue, 6 Mar 2018 15:33:08 +0100 Subject: clk: samsung: Add Exynos5 sub-CMU clock driver Exynos5250/5420/5800 have only one clock controller, but some of their clock depends on respective power domains. Handling integration of clock controller and power domain can be done using runtime PM feature of CCF framework. This however needs a separate struct device for each power domain. This patch adds such separate driver for a group of such clocks, which can be instantiated more than once, each time for a different power domain. Signed-off-by: Marek Szyprowski Reviewed-by: Krzysztof Kozlowski Signed-off-by: Sylwester Nawrocki --- drivers/clk/samsung/clk-exynos5-subcmu.c | 186 +++++++++++++++++++++++++++++++ drivers/clk/samsung/clk-exynos5-subcmu.h | 26 +++++ 2 files changed, 212 insertions(+) create mode 100644 drivers/clk/samsung/clk-exynos5-subcmu.c create mode 100644 drivers/clk/samsung/clk-exynos5-subcmu.h diff --git a/drivers/clk/samsung/clk-exynos5-subcmu.c b/drivers/clk/samsung/clk-exynos5-subcmu.c new file mode 100644 index 000000000000..ac3983c8adf2 --- /dev/null +++ b/drivers/clk/samsung/clk-exynos5-subcmu.c @@ -0,0 +1,186 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (c) 2018 Samsung Electronics Co., Ltd. +// Author: Marek Szyprowski +// Common Clock Framework support for Exynos5 power-domain dependent clocks + +#include +#include +#include +#include + +#include "clk.h" +#include "clk-exynos5-subcmu.h" + +static struct samsung_clk_provider *ctx; +static const struct exynos5_subcmu_info *cmu; +static int nr_cmus; + +static void exynos5_subcmu_clk_save(void __iomem *base, + struct exynos5_subcmu_reg_dump *rd, + unsigned int num_regs) +{ + for (; num_regs > 0; --num_regs, ++rd) { + rd->save = readl(base + rd->offset); + writel((rd->save & ~rd->mask) | rd->value, base + rd->offset); + rd->save &= rd->mask; + } +}; + +static void exynos5_subcmu_clk_restore(void __iomem *base, + struct exynos5_subcmu_reg_dump *rd, + unsigned int num_regs) +{ + for (; num_regs > 0; --num_regs, ++rd) + writel((readl(base + rd->offset) & ~rd->mask) | rd->save, + base + rd->offset); +} + +static void exynos5_subcmu_defer_gate(struct samsung_clk_provider *ctx, + const struct samsung_gate_clock *list, int nr_clk) +{ + while (nr_clk--) + samsung_clk_add_lookup(ctx, ERR_PTR(-EPROBE_DEFER), list++->id); +} + +/* + * Pass the needed clock provider context and register sub-CMU clocks + * + * NOTE: This function has to be called from the main, OF_CLK_DECLARE- + * initialized clock provider driver. This happens very early during boot + * process. Then this driver, during core_initcall registers two platform + * drivers: one which binds to the same device-tree node as OF_CLK_DECLARE + * driver and second, for handling its per-domain child-devices. Those + * platform drivers are bound to their devices a bit later in arch_initcall, + * when OF-core populates all device-tree nodes. + */ +void exynos5_subcmus_init(struct samsung_clk_provider *_ctx, int _nr_cmus, + const struct exynos5_subcmu_info *_cmu) +{ + ctx = _ctx; + cmu = _cmu; + nr_cmus = _nr_cmus; + + for (; _nr_cmus--; _cmu++) { + exynos5_subcmu_defer_gate(ctx, _cmu->gate_clks, + _cmu->nr_gate_clks); + exynos5_subcmu_clk_save(ctx->reg_base, _cmu->suspend_regs, + _cmu->nr_suspend_regs); + } +} + +static int __maybe_unused exynos5_subcmu_suspend(struct device *dev) +{ + struct exynos5_subcmu_info *info = dev_get_drvdata(dev); + unsigned long flags; + + spin_lock_irqsave(&ctx->lock, flags); + exynos5_subcmu_clk_save(ctx->reg_base, info->suspend_regs, + info->nr_suspend_regs); + spin_unlock_irqrestore(&ctx->lock, flags); + + return 0; +} + +static int __maybe_unused exynos5_subcmu_resume(struct device *dev) +{ + struct exynos5_subcmu_info *info = dev_get_drvdata(dev); + unsigned long flags; + + spin_lock_irqsave(&ctx->lock, flags); + exynos5_subcmu_clk_restore(ctx->reg_base, info->suspend_regs, + info->nr_suspend_regs); + spin_unlock_irqrestore(&ctx->lock, flags); + + return 0; +} + +static int __init exynos5_subcmu_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct exynos5_subcmu_info *info = dev_get_drvdata(dev); + + pm_runtime_set_suspended(dev); + pm_runtime_enable(dev); + pm_runtime_get(dev); + + ctx->dev = dev; + samsung_clk_register_div(ctx, info->div_clks, info->nr_div_clks); + samsung_clk_register_gate(ctx, info->gate_clks, info->nr_gate_clks); + ctx->dev = NULL; + + pm_runtime_put_sync(dev); + + return 0; +} + +static const struct dev_pm_ops exynos5_subcmu_pm_ops = { + SET_RUNTIME_PM_OPS(exynos5_subcmu_suspend, + exynos5_subcmu_resume, NULL) + SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) +}; + +static struct platform_driver exynos5_subcmu_driver __refdata = { + .driver = { + .name = "exynos5-subcmu", + .suppress_bind_attrs = true, + .pm = &exynos5_subcmu_pm_ops, + }, + .probe = exynos5_subcmu_probe, +}; + +static int __init exynos5_clk_register_subcmu(struct device *parent, + const struct exynos5_subcmu_info *info, + struct device_node *pd_node) +{ + struct of_phandle_args genpdspec = { .np = pd_node }; + struct platform_device *pdev; + + pdev = platform_device_alloc(info->pd_name, -1); + pdev->dev.parent = parent; + pdev->driver_override = "exynos5-subcmu"; + platform_set_drvdata(pdev, (void *)info); + of_genpd_add_device(&genpdspec, &pdev->dev); + platform_device_add(pdev); + + return 0; +} + +static int __init exynos5_clk_probe(struct platform_device *pdev) +{ + struct device_node *np; + const char *name; + int i; + + for_each_compatible_node(np, NULL, "samsung,exynos4210-pd") { + if (of_property_read_string(np, "label", &name) < 0) + continue; + for (i = 0; i < nr_cmus; i++) + if (strcmp(cmu[i].pd_name, name) == 0) + exynos5_clk_register_subcmu(&pdev->dev, + &cmu[i], np); + } + return 0; +} + +static const struct of_device_id exynos5_clk_of_match[] = { + { }, +}; + +static struct platform_driver exynos5_clk_driver __refdata = { + .driver = { + .name = "exynos5-clock", + .of_match_table = exynos5_clk_of_match, + .suppress_bind_attrs = true, + }, + .probe = exynos5_clk_probe, +}; + +static int __init exynos5_clk_drv_init(void) +{ + platform_driver_register(&exynos5_clk_driver); + platform_driver_register(&exynos5_subcmu_driver); + return 0; +} +core_initcall(exynos5_clk_drv_init); diff --git a/drivers/clk/samsung/clk-exynos5-subcmu.h b/drivers/clk/samsung/clk-exynos5-subcmu.h new file mode 100644 index 000000000000..755ee8aaa3de --- /dev/null +++ b/drivers/clk/samsung/clk-exynos5-subcmu.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef __CLK_EXYNOS5_SUBCMU_H +#define __CLK_EXYNOS5_SUBCMU_H + +struct exynos5_subcmu_reg_dump { + u32 offset; + u32 value; + u32 mask; + u32 save; +}; + +struct exynos5_subcmu_info { + const struct samsung_div_clock *div_clks; + unsigned int nr_div_clks; + const struct samsung_gate_clock *gate_clks; + unsigned int nr_gate_clks; + struct exynos5_subcmu_reg_dump *suspend_regs; + unsigned int nr_suspend_regs; + const char *pd_name; +}; + +void exynos5_subcmus_init(struct samsung_clk_provider *ctx, int nr_cmus, + const struct exynos5_subcmu_info *cmu); + +#endif -- cgit From ec4016ff6e60fffab2e34fe87578c6362147cb98 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Tue, 6 Mar 2018 15:33:09 +0100 Subject: clk: samsung: exynos5420: Move PD-dependent clocks to Exynos5 sub-CMU Clocks related to DISP, GSC and MFC blocks require special handling for power domain turn on/off sequences. Till now this was handled by Exynos power domain driver, but that approach was limited only to some special cases. This patch moves handling of those operations to clock controller driver. This gives more flexibility and allows fine tune values of some clock-specific registers. This patch moves handling of those mentioned clocks to Exynos5 sub-CMU driver instantiated from Exynos5420 driver. Signed-off-by: Marek Szyprowski Acked-by: Krzysztof Kozlowski Signed-off-by: Sylwester Nawrocki --- drivers/clk/samsung/Makefile | 1 + drivers/clk/samsung/clk-exynos5-subcmu.c | 2 + drivers/clk/samsung/clk-exynos5420.c | 121 ++++++++++++++++++++++++------- drivers/soc/samsung/pm_domains.c | 2 + 4 files changed, 100 insertions(+), 26 deletions(-) diff --git a/drivers/clk/samsung/Makefile b/drivers/clk/samsung/Makefile index ef8900bc077f..b23d6cfac723 100644 --- a/drivers/clk/samsung/Makefile +++ b/drivers/clk/samsung/Makefile @@ -11,6 +11,7 @@ obj-$(CONFIG_SOC_EXYNOS5250) += clk-exynos5250.o obj-$(CONFIG_SOC_EXYNOS5260) += clk-exynos5260.o obj-$(CONFIG_SOC_EXYNOS5410) += clk-exynos5410.o obj-$(CONFIG_SOC_EXYNOS5420) += clk-exynos5420.o +obj-$(CONFIG_SOC_EXYNOS5420) += clk-exynos5-subcmu.o obj-$(CONFIG_EXYNOS_ARM64_COMMON_CLK) += clk-exynos5433.o obj-$(CONFIG_SOC_EXYNOS5440) += clk-exynos5440.o obj-$(CONFIG_EXYNOS_AUDSS_CLK_CON) += clk-exynos-audss.o diff --git a/drivers/clk/samsung/clk-exynos5-subcmu.c b/drivers/clk/samsung/clk-exynos5-subcmu.c index ac3983c8adf2..bea10f4b3ee2 100644 --- a/drivers/clk/samsung/clk-exynos5-subcmu.c +++ b/drivers/clk/samsung/clk-exynos5-subcmu.c @@ -165,6 +165,8 @@ static int __init exynos5_clk_probe(struct platform_device *pdev) } static const struct of_device_id exynos5_clk_of_match[] = { + { .compatible = "samsung,exynos5420-clock", }, + { .compatible = "samsung,exynos5800-clock", }, { }, }; diff --git a/drivers/clk/samsung/clk-exynos5420.c b/drivers/clk/samsung/clk-exynos5420.c index 6b10b70f7d72..c7b0f55dfbb6 100644 --- a/drivers/clk/samsung/clk-exynos5420.c +++ b/drivers/clk/samsung/clk-exynos5420.c @@ -19,6 +19,7 @@ #include "clk.h" #include "clk-cpu.h" +#include "clk-exynos5-subcmu.h" #define APLL_LOCK 0x0 #define APLL_CON0 0x100 @@ -863,7 +864,6 @@ static const struct samsung_div_clock exynos5x_div_clks[] __initconst = { DIV(0, "dout_mipi1", "mout_mipi1", DIV_DISP10, 16, 8), DIV(0, "dout_dp1", "mout_dp1", DIV_DISP10, 24, 4), DIV(CLK_DOUT_PIXEL, "dout_hdmi_pixel", "mout_pixel", DIV_DISP10, 28, 4), - DIV(0, "dout_disp1_blk", "aclk200_disp1", DIV2_RATIO0, 16, 2), DIV(CLK_DOUT_ACLK400_DISP1, "dout_aclk400_disp1", "mout_aclk400_disp1", DIV_TOP2, 4, 3), @@ -912,8 +912,6 @@ static const struct samsung_div_clock exynos5x_div_clks[] __initconst = { DIV(0, "dout_spi1", "mout_spi1", DIV_PERIC1, 24, 4), DIV(0, "dout_spi2", "mout_spi2", DIV_PERIC1, 28, 4), - /* Mfc Block */ - DIV(0, "dout_mfc_blk", "mout_user_aclk333", DIV4_RATIO, 0, 2), /* PCM */ DIV(0, "dout_pcm1", "dout_audio1", DIV_PERIC2, 16, 8), @@ -932,8 +930,6 @@ static const struct samsung_div_clock exynos5x_div_clks[] __initconst = { DIV(0, "dout_spi2_pre", "dout_spi2", DIV_PERIC4, 24, 8), /* GSCL Block */ - DIV(0, "dout_gscl_blk_300", "mout_user_aclk300_gscl", - DIV2_RATIO0, 4, 2), DIV(0, "dout_gscl_blk_333", "aclk333_432_gscl", DIV2_RATIO0, 6, 2), /* MSCL Block */ @@ -1190,8 +1186,6 @@ static const struct samsung_gate_clock exynos5x_gate_clks[] __initconst = { GATE(CLK_SCLK_GSCL_WB, "sclk_gscl_wb", "mout_user_aclk333_432_gscl", GATE_TOP_SCLK_GSCL, 7, 0, 0), - GATE(CLK_GSCL0, "gscl0", "aclk300_gscl", GATE_IP_GSCL0, 0, 0, 0), - GATE(CLK_GSCL1, "gscl1", "aclk300_gscl", GATE_IP_GSCL0, 1, 0, 0), GATE(CLK_FIMC_3AA, "fimc_3aa", "aclk333_432_gscl", GATE_IP_GSCL0, 4, 0, 0), GATE(CLK_FIMC_LITE0, "fimc_lite0", "aclk333_432_gscl", @@ -1205,10 +1199,6 @@ static const struct samsung_gate_clock exynos5x_gate_clks[] __initconst = { GATE_IP_GSCL1, 3, 0, 0), GATE(CLK_SMMU_FIMCL1, "smmu_fimcl1", "dout_gscl_blk_333", GATE_IP_GSCL1, 4, 0, 0), - GATE(CLK_SMMU_GSCL0, "smmu_gscl0", "dout_gscl_blk_300", - GATE_IP_GSCL1, 6, 0, 0), - GATE(CLK_SMMU_GSCL1, "smmu_gscl1", "dout_gscl_blk_300", - GATE_IP_GSCL1, 7, 0, 0), GATE(CLK_GSCL_WA, "gscl_wa", "sclk_gscl_wa", GATE_IP_GSCL1, 12, 0, 0), GATE(CLK_GSCL_WB, "gscl_wb", "sclk_gscl_wb", GATE_IP_GSCL1, 13, 0, 0), GATE(CLK_SMMU_FIMCL3, "smmu_fimcl3,", "dout_gscl_blk_333", @@ -1227,18 +1217,6 @@ static const struct samsung_gate_clock exynos5x_gate_clks[] __initconst = { GATE(CLK_SMMU_MSCL2, "smmu_mscl2", "dout_mscl_blk", GATE_IP_MSCL, 10, 0, 0), - GATE(CLK_FIMD1, "fimd1", "aclk300_disp1", GATE_IP_DISP1, 0, 0, 0), - GATE(CLK_DSIM1, "dsim1", "aclk200_disp1", GATE_IP_DISP1, 3, 0, 0), - GATE(CLK_DP1, "dp1", "aclk200_disp1", GATE_IP_DISP1, 4, 0, 0), - GATE(CLK_MIXER, "mixer", "aclk200_disp1", GATE_IP_DISP1, 5, 0, 0), - GATE(CLK_HDMI, "hdmi", "aclk200_disp1", GATE_IP_DISP1, 6, 0, 0), - GATE(CLK_SMMU_FIMD1M0, "smmu_fimd1m0", "dout_disp1_blk", - GATE_IP_DISP1, 7, 0, 0), - GATE(CLK_SMMU_FIMD1M1, "smmu_fimd1m1", "dout_disp1_blk", - GATE_IP_DISP1, 8, 0, 0), - GATE(CLK_SMMU_MIXER, "smmu_mixer", "aclk200_disp1", - GATE_IP_DISP1, 9, 0, 0), - /* ISP */ GATE(CLK_SCLK_UART_ISP, "sclk_uart_isp", "dout_uart_isp", GATE_TOP_SCLK_ISP, 0, CLK_SET_RATE_PARENT, 0), @@ -1255,11 +1233,98 @@ static const struct samsung_gate_clock exynos5x_gate_clks[] __initconst = { GATE(CLK_SCLK_ISP_SENSOR2, "sclk_isp_sensor2", "dout_isp_sensor2", GATE_TOP_SCLK_ISP, 12, CLK_SET_RATE_PARENT, 0), + GATE(CLK_G3D, "g3d", "mout_user_aclk_g3d", GATE_IP_G3D, 9, 0, 0), +}; + +static const struct samsung_div_clock exynos5x_disp_div_clks[] __initconst = { + DIV(0, "dout_disp1_blk", "aclk200_disp1", DIV2_RATIO0, 16, 2), +}; + +static const struct samsung_gate_clock exynos5x_disp_gate_clks[] __initconst = { + GATE(CLK_FIMD1, "fimd1", "aclk300_disp1", GATE_IP_DISP1, 0, 0, 0), + GATE(CLK_DSIM1, "dsim1", "aclk200_disp1", GATE_IP_DISP1, 3, 0, 0), + GATE(CLK_DP1, "dp1", "aclk200_disp1", GATE_IP_DISP1, 4, 0, 0), + GATE(CLK_MIXER, "mixer", "aclk200_disp1", GATE_IP_DISP1, 5, 0, 0), + GATE(CLK_HDMI, "hdmi", "aclk200_disp1", GATE_IP_DISP1, 6, 0, 0), + GATE(CLK_SMMU_FIMD1M0, "smmu_fimd1m0", "dout_disp1_blk", + GATE_IP_DISP1, 7, 0, 0), + GATE(CLK_SMMU_FIMD1M1, "smmu_fimd1m1", "dout_disp1_blk", + GATE_IP_DISP1, 8, 0, 0), + GATE(CLK_SMMU_MIXER, "smmu_mixer", "aclk200_disp1", + GATE_IP_DISP1, 9, 0, 0), +}; + +static struct exynos5_subcmu_reg_dump exynos5x_disp_suspend_regs[] = { + { GATE_IP_DISP1, 0xffffffff, 0xffffffff }, /* DISP1 gates */ + { SRC_TOP5, 0, BIT(0) }, /* MUX mout_user_aclk400_disp1 */ + { SRC_TOP5, 0, BIT(24) }, /* MUX mout_user_aclk300_disp1 */ + { SRC_TOP3, 0, BIT(8) }, /* MUX mout_user_aclk200_disp1 */ + { DIV2_RATIO0, 0, 0x30000 }, /* DIV dout_disp1_blk */ +}; + +static const struct samsung_div_clock exynos5x_gsc_div_clks[] __initconst = { + DIV(0, "dout_gscl_blk_300", "mout_user_aclk300_gscl", + DIV2_RATIO0, 4, 2), +}; + +static const struct samsung_gate_clock exynos5x_gsc_gate_clks[] __initconst = { + GATE(CLK_GSCL0, "gscl0", "aclk300_gscl", GATE_IP_GSCL0, 0, 0, 0), + GATE(CLK_GSCL1, "gscl1", "aclk300_gscl", GATE_IP_GSCL0, 1, 0, 0), + GATE(CLK_SMMU_GSCL0, "smmu_gscl0", "dout_gscl_blk_300", + GATE_IP_GSCL1, 6, 0, 0), + GATE(CLK_SMMU_GSCL1, "smmu_gscl1", "dout_gscl_blk_300", + GATE_IP_GSCL1, 7, 0, 0), +}; + +static struct exynos5_subcmu_reg_dump exynos5x_gsc_suspend_regs[] = { + { GATE_IP_GSCL0, 0x3, 0x3 }, /* GSC gates */ + { GATE_IP_GSCL1, 0xc0, 0xc0 }, /* GSC gates */ + { SRC_TOP5, 0, BIT(28) }, /* MUX mout_user_aclk300_gscl */ + { DIV2_RATIO0, 0, 0x30 }, /* DIV dout_gscl_blk_300 */ +}; + +static const struct samsung_div_clock exynos5x_mfc_div_clks[] __initconst = { + DIV(0, "dout_mfc_blk", "mout_user_aclk333", DIV4_RATIO, 0, 2), +}; + +static const struct samsung_gate_clock exynos5x_mfc_gate_clks[] __initconst = { GATE(CLK_MFC, "mfc", "aclk333", GATE_IP_MFC, 0, 0, 0), GATE(CLK_SMMU_MFCL, "smmu_mfcl", "dout_mfc_blk", GATE_IP_MFC, 1, 0, 0), GATE(CLK_SMMU_MFCR, "smmu_mfcr", "dout_mfc_blk", GATE_IP_MFC, 2, 0, 0), +}; - GATE(CLK_G3D, "g3d", "mout_user_aclk_g3d", GATE_IP_G3D, 9, 0, 0), +static struct exynos5_subcmu_reg_dump exynos5x_mfc_suspend_regs[] = { + { GATE_IP_MFC, 0xffffffff, 0xffffffff }, /* MFC gates */ + { SRC_TOP4, 0, BIT(28) }, /* MUX mout_user_aclk333 */ + { DIV4_RATIO, 0, 0x3 }, /* DIV dout_mfc_blk */ +}; + +static const struct exynos5_subcmu_info exynos5x_subcmus[] = { + { + .div_clks = exynos5x_disp_div_clks, + .nr_div_clks = ARRAY_SIZE(exynos5x_disp_div_clks), + .gate_clks = exynos5x_disp_gate_clks, + .nr_gate_clks = ARRAY_SIZE(exynos5x_disp_gate_clks), + .suspend_regs = exynos5x_disp_suspend_regs, + .nr_suspend_regs = ARRAY_SIZE(exynos5x_disp_suspend_regs), + .pd_name = "DISP", + }, { + .div_clks = exynos5x_gsc_div_clks, + .nr_div_clks = ARRAY_SIZE(exynos5x_gsc_div_clks), + .gate_clks = exynos5x_gsc_gate_clks, + .nr_gate_clks = ARRAY_SIZE(exynos5x_gsc_gate_clks), + .suspend_regs = exynos5x_gsc_suspend_regs, + .nr_suspend_regs = ARRAY_SIZE(exynos5x_gsc_suspend_regs), + .pd_name = "GSC", + }, { + .div_clks = exynos5x_mfc_div_clks, + .nr_div_clks = ARRAY_SIZE(exynos5x_mfc_div_clks), + .gate_clks = exynos5x_mfc_gate_clks, + .nr_gate_clks = ARRAY_SIZE(exynos5x_mfc_gate_clks), + .suspend_regs = exynos5x_mfc_suspend_regs, + .nr_suspend_regs = ARRAY_SIZE(exynos5x_mfc_suspend_regs), + .pd_name = "MFC", + }, }; static const struct samsung_pll_rate_table exynos5420_pll2550x_24mhz_tbl[] __initconst = { @@ -1472,6 +1537,8 @@ static void __init exynos5x_clk_init(struct device_node *np, exynos5420_kfcclk_d, ARRAY_SIZE(exynos5420_kfcclk_d), 0); exynos5420_clk_sleep_init(); + exynos5_subcmus_init(ctx, ARRAY_SIZE(exynos5x_subcmus), + exynos5x_subcmus); samsung_clk_of_add_provider(np, ctx); } @@ -1480,10 +1547,12 @@ static void __init exynos5420_clk_init(struct device_node *np) { exynos5x_clk_init(np, EXYNOS5420); } -CLK_OF_DECLARE(exynos5420_clk, "samsung,exynos5420-clock", exynos5420_clk_init); +CLK_OF_DECLARE_DRIVER(exynos5420_clk, "samsung,exynos5420-clock", + exynos5420_clk_init); static void __init exynos5800_clk_init(struct device_node *np) { exynos5x_clk_init(np, EXYNOS5800); } -CLK_OF_DECLARE(exynos5800_clk, "samsung,exynos5800-clock", exynos5800_clk_init); +CLK_OF_DECLARE_DRIVER(exynos5800_clk, "samsung,exynos5800-clock", + exynos5800_clk_init); diff --git a/drivers/soc/samsung/pm_domains.c b/drivers/soc/samsung/pm_domains.c index cef30bdf19b1..f2d6d7a09c16 100644 --- a/drivers/soc/samsung/pm_domains.c +++ b/drivers/soc/samsung/pm_domains.c @@ -148,6 +148,8 @@ static __init const char *exynos_get_domain_name(struct device_node *node) } static const char *soc_force_no_clk[] = { + "samsung,exynos5420-clock", + "samsung,exynos5800-clock", }; static __init int exynos4_pm_init_power_domain(void) -- cgit From edcefb96fb07f6742fd47ac60915e76c1b77768e Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Tue, 6 Mar 2018 15:33:10 +0100 Subject: clk: samsung: exynos5250: Move PD-dependent clocks to Exynos5 sub-CMU Clocks related to DISP1 block require special handling for power domain turn on/off sequences. Till now this was handled by Exynos power domain driver, but that approach was limited only to some special cases. This patch moves handling of those operations to clock controller driver. This gives more flexibility and allows fine tune values of some clock-specific registers. This patch moves handling of those mentioned clocks to Exynos5 sub-CMU driver instantiated from Exynos5250 driver. Signed-off-by: Marek Szyprowski Acked-by: Krzysztof Kozlowski Signed-off-by: Sylwester Nawrocki --- drivers/clk/samsung/Makefile | 1 + drivers/clk/samsung/clk-exynos5-subcmu.c | 1 + drivers/clk/samsung/clk-exynos5250.c | 51 ++++++++++++++++++++++---------- drivers/soc/samsung/pm_domains.c | 1 + 4 files changed, 38 insertions(+), 16 deletions(-) diff --git a/drivers/clk/samsung/Makefile b/drivers/clk/samsung/Makefile index b23d6cfac723..513826393158 100644 --- a/drivers/clk/samsung/Makefile +++ b/drivers/clk/samsung/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_SOC_EXYNOS3250) += clk-exynos3250.o obj-$(CONFIG_ARCH_EXYNOS4) += clk-exynos4.o obj-$(CONFIG_ARCH_EXYNOS4) += clk-exynos4412-isp.o obj-$(CONFIG_SOC_EXYNOS5250) += clk-exynos5250.o +obj-$(CONFIG_SOC_EXYNOS5250) += clk-exynos5-subcmu.o obj-$(CONFIG_SOC_EXYNOS5260) += clk-exynos5260.o obj-$(CONFIG_SOC_EXYNOS5410) += clk-exynos5410.o obj-$(CONFIG_SOC_EXYNOS5420) += clk-exynos5420.o diff --git a/drivers/clk/samsung/clk-exynos5-subcmu.c b/drivers/clk/samsung/clk-exynos5-subcmu.c index bea10f4b3ee2..93306283d764 100644 --- a/drivers/clk/samsung/clk-exynos5-subcmu.c +++ b/drivers/clk/samsung/clk-exynos5-subcmu.c @@ -165,6 +165,7 @@ static int __init exynos5_clk_probe(struct platform_device *pdev) } static const struct of_device_id exynos5_clk_of_match[] = { + { .compatible = "samsung,exynos5250-clock", }, { .compatible = "samsung,exynos5420-clock", }, { .compatible = "samsung,exynos5800-clock", }, { }, diff --git a/drivers/clk/samsung/clk-exynos5250.c b/drivers/clk/samsung/clk-exynos5250.c index 1b3a8f9cd519..06e5ddcb30db 100644 --- a/drivers/clk/samsung/clk-exynos5250.c +++ b/drivers/clk/samsung/clk-exynos5250.c @@ -18,6 +18,7 @@ #include "clk.h" #include "clk-cpu.h" +#include "clk-exynos5-subcmu.h" #define APLL_LOCK 0x0 #define APLL_CON0 0x100 @@ -571,17 +572,6 @@ static const struct samsung_gate_clock exynos5250_gate_clks[] __initconst = { GATE(CLK_SMMU_GSCL3, "smmu_gscl3", "mout_aclk266_gscl_sub", GATE_IP_GSCL, 10, 0, 0), - GATE(CLK_FIMD1, "fimd1", "mout_aclk200_disp1_sub", GATE_IP_DISP1, 0, 0, - 0), - GATE(CLK_MIE1, "mie1", "mout_aclk200_disp1_sub", GATE_IP_DISP1, 1, 0, - 0), - GATE(CLK_DSIM0, "dsim0", "mout_aclk200_disp1_sub", GATE_IP_DISP1, 3, 0, - 0), - GATE(CLK_DP, "dp", "mout_aclk200_disp1_sub", GATE_IP_DISP1, 4, 0, 0), - GATE(CLK_MIXER, "mixer", "mout_aclk200_disp1_sub", GATE_IP_DISP1, 5, 0, - 0), - GATE(CLK_HDMI, "hdmi", "mout_aclk200_disp1_sub", GATE_IP_DISP1, 6, 0, - 0), GATE(CLK_MFC, "mfc", "mout_aclk333_sub", GATE_IP_MFC, 0, 0, 0), GATE(CLK_SMMU_MFCR, "smmu_mfcr", "mout_aclk333_sub", GATE_IP_MFC, 1, 0, @@ -671,10 +661,6 @@ static const struct samsung_gate_clock exynos5250_gate_clks[] __initconst = { GATE(CLK_WDT, "wdt", "div_aclk66", GATE_IP_PERIS, 19, 0, 0), GATE(CLK_RTC, "rtc", "div_aclk66", GATE_IP_PERIS, 20, 0, 0), GATE(CLK_TMU, "tmu", "div_aclk66", GATE_IP_PERIS, 21, 0, 0), - GATE(CLK_SMMU_TV, "smmu_tv", "mout_aclk200_disp1_sub", - GATE_IP_DISP1, 9, 0, 0), - GATE(CLK_SMMU_FIMD1, "smmu_fimd1", "mout_aclk200_disp1_sub", - GATE_IP_DISP1, 8, 0, 0), GATE(CLK_SMMU_2D, "smmu_2d", "div_aclk200", GATE_IP_ACP, 7, 0, 0), GATE(CLK_SMMU_FIMC_ISP, "smmu_fimc_isp", "mout_aclk_266_isp_sub", GATE_IP_ISP0, 8, 0, 0), @@ -698,6 +684,38 @@ static const struct samsung_gate_clock exynos5250_gate_clks[] __initconst = { GATE_IP_ISP1, 7, 0, 0), }; +static const struct samsung_gate_clock exynos5250_disp_gate_clks[] __initconst = { + GATE(CLK_FIMD1, "fimd1", "mout_aclk200_disp1_sub", GATE_IP_DISP1, 0, 0, + 0), + GATE(CLK_MIE1, "mie1", "mout_aclk200_disp1_sub", GATE_IP_DISP1, 1, 0, + 0), + GATE(CLK_DSIM0, "dsim0", "mout_aclk200_disp1_sub", GATE_IP_DISP1, 3, 0, + 0), + GATE(CLK_DP, "dp", "mout_aclk200_disp1_sub", GATE_IP_DISP1, 4, 0, 0), + GATE(CLK_MIXER, "mixer", "mout_aclk200_disp1_sub", GATE_IP_DISP1, 5, 0, + 0), + GATE(CLK_HDMI, "hdmi", "mout_aclk200_disp1_sub", GATE_IP_DISP1, 6, 0, + 0), + GATE(CLK_SMMU_TV, "smmu_tv", "mout_aclk200_disp1_sub", + GATE_IP_DISP1, 9, 0, 0), + GATE(CLK_SMMU_FIMD1, "smmu_fimd1", "mout_aclk200_disp1_sub", + GATE_IP_DISP1, 8, 0, 0), +}; + +static struct exynos5_subcmu_reg_dump exynos5250_disp_suspend_regs[] = { + { GATE_IP_DISP1, 0xffffffff, 0xffffffff }, /* DISP1 gates */ + { SRC_TOP3, 0, BIT(4) }, /* MUX mout_aclk200_disp1_sub */ + { SRC_TOP3, 0, BIT(6) }, /* MUX mout_aclk300_disp1_sub */ +}; + +static const struct exynos5_subcmu_info exynos5250_disp_subcmu = { + .gate_clks = exynos5250_disp_gate_clks, + .nr_gate_clks = ARRAY_SIZE(exynos5250_disp_gate_clks), + .suspend_regs = exynos5250_disp_suspend_regs, + .nr_suspend_regs = ARRAY_SIZE(exynos5250_disp_suspend_regs), + .pd_name = "DISP1", +}; + static const struct samsung_pll_rate_table vpll_24mhz_tbl[] __initconst = { /* sorted in descending order */ /* PLL_36XX_RATE(rate, m, p, s, k) */ @@ -859,10 +877,11 @@ static void __init exynos5250_clk_init(struct device_node *np) __raw_writel(tmp, reg_base + PWR_CTRL2); exynos5250_clk_sleep_init(); + exynos5_subcmus_init(ctx, 1, &exynos5250_disp_subcmu); samsung_clk_of_add_provider(np, ctx); pr_info("Exynos5250: clock setup completed, armclk=%ld\n", _get_rate("div_arm2")); } -CLK_OF_DECLARE(exynos5250_clk, "samsung,exynos5250-clock", exynos5250_clk_init); +CLK_OF_DECLARE_DRIVER(exynos5250_clk, "samsung,exynos5250-clock", exynos5250_clk_init); diff --git a/drivers/soc/samsung/pm_domains.c b/drivers/soc/samsung/pm_domains.c index f2d6d7a09c16..caf45cf7aa8e 100644 --- a/drivers/soc/samsung/pm_domains.c +++ b/drivers/soc/samsung/pm_domains.c @@ -148,6 +148,7 @@ static __init const char *exynos_get_domain_name(struct device_node *node) } static const char *soc_force_no_clk[] = { + "samsung,exynos5250-clock", "samsung,exynos5420-clock", "samsung,exynos5800-clock", }; -- cgit From be02637f6b741875aa0779c35f31591738aa2cd9 Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Thu, 15 Feb 2018 09:44:52 +0200 Subject: dt-bindings: clock: ti: add latching support to mux and divider clocks Certain hardware configurations, like dra76x, have some of the clock registers partitioned in a funky manner that requires the clock control setup to be latched for PRCM to be notified of the change. This is accomplished with a separate control bit under the register. Add support for this clock latching support to divider and mux clocks. Signed-off-by: Tero Kristo Reviewed-by: Rob Herring --- Documentation/devicetree/bindings/clock/ti/divider.txt | 3 +++ Documentation/devicetree/bindings/clock/ti/mux.txt | 3 +++ 2 files changed, 6 insertions(+) diff --git a/Documentation/devicetree/bindings/clock/ti/divider.txt b/Documentation/devicetree/bindings/clock/ti/divider.txt index 35a6f5c7e5c2..9b13b32974f9 100644 --- a/Documentation/devicetree/bindings/clock/ti/divider.txt +++ b/Documentation/devicetree/bindings/clock/ti/divider.txt @@ -75,6 +75,9 @@ Optional properties: - ti,invert-autoidle-bit : autoidle is enabled by setting the bit to 0, see [2] - ti,set-rate-parent : clk_set_rate is propagated to parent +- ti,latch-bit : latch the divider value to HW, only needed if the register + access requires this. As an example dra76x DPLL_GMAC H14 divider implements + such behavior. Examples: dpll_usb_m2_ck: dpll_usb_m2_ck@4a008190 { diff --git a/Documentation/devicetree/bindings/clock/ti/mux.txt b/Documentation/devicetree/bindings/clock/ti/mux.txt index 2d0d170f8001..eec8994b9be8 100644 --- a/Documentation/devicetree/bindings/clock/ti/mux.txt +++ b/Documentation/devicetree/bindings/clock/ti/mux.txt @@ -48,6 +48,9 @@ Optional properties: zero - ti,set-rate-parent : clk_set_rate is propagated to parent clock, not supported by the composite-mux-clock subtype +- ti,latch-bit : latch the mux value to HW, only needed if the register + access requires this. As an example, dra7x DPLL_GMAC H14 muxing + implements such behavior. Examples: -- cgit From 4902c2025b8ade9c230d4bca25ec5f691e91cb1f Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Wed, 26 Jul 2017 16:47:27 +0300 Subject: clk: ti: add support for register read-modify-write low-level operation Useful for changing few bits on a register, this makes sure for example that the operation is done atomically in case of syscon. Signed-off-by: Tero Kristo --- drivers/clk/ti/clk.c | 24 ++++++++++++++++++++++++ include/linux/clk/ti.h | 2 ++ 2 files changed, 26 insertions(+) diff --git a/drivers/clk/ti/clk.c b/drivers/clk/ti/clk.c index f4d6802a8544..4efa2c9ea908 100644 --- a/drivers/clk/ti/clk.c +++ b/drivers/clk/ti/clk.c @@ -55,6 +55,29 @@ static void clk_memmap_writel(u32 val, const struct clk_omap_reg *reg) writel_relaxed(val, io->mem + reg->offset); } +static void _clk_rmw(u32 val, u32 mask, void __iomem *ptr) +{ + u32 v; + + v = readl_relaxed(ptr); + v &= ~mask; + v |= val; + writel_relaxed(v, ptr); +} + +static void clk_memmap_rmw(u32 val, u32 mask, const struct clk_omap_reg *reg) +{ + struct clk_iomap *io = clk_memmaps[reg->index]; + + if (reg->ptr) { + _clk_rmw(val, mask, reg->ptr); + } else if (io->regmap) { + regmap_update_bits(io->regmap, reg->offset, mask, val); + } else { + _clk_rmw(val, mask, io->mem + reg->offset); + } +} + static u32 clk_memmap_readl(const struct clk_omap_reg *reg) { u32 val; @@ -89,6 +112,7 @@ int ti_clk_setup_ll_ops(struct ti_clk_ll_ops *ops) ti_clk_ll_ops = ops; ops->clk_readl = clk_memmap_readl; ops->clk_writel = clk_memmap_writel; + ops->clk_rmw = clk_memmap_rmw; return 0; } diff --git a/include/linux/clk/ti.h b/include/linux/clk/ti.h index d18da839b810..9e8611470187 100644 --- a/include/linux/clk/ti.h +++ b/include/linux/clk/ti.h @@ -211,6 +211,7 @@ enum { * struct ti_clk_ll_ops - low-level ops for clocks * @clk_readl: pointer to register read function * @clk_writel: pointer to register write function + * @clk_rmw: pointer to register read-modify-write function * @clkdm_clk_enable: pointer to clockdomain enable function * @clkdm_clk_disable: pointer to clockdomain disable function * @clkdm_lookup: pointer to clockdomain lookup function @@ -226,6 +227,7 @@ enum { struct ti_clk_ll_ops { u32 (*clk_readl)(const struct clk_omap_reg *reg); void (*clk_writel)(u32 val, const struct clk_omap_reg *reg); + void (*clk_rmw)(u32 val, u32 mask, const struct clk_omap_reg *reg); int (*clkdm_clk_enable)(struct clockdomain *clkdm, struct clk *clk); int (*clkdm_clk_disable)(struct clockdomain *clkdm, struct clk *clk); -- cgit From e31922eda18c950d6b51450711ae459b97eae097 Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Wed, 26 Jul 2017 16:47:28 +0300 Subject: clk: ti: add generic support for clock latching Certain clocks require latching to be done, so that the actual settings get updated on the HW that generates the clock signal. One example of such a clock is the dra76x GMAC DPLL H14 output, which requires its divider settings to be latched when updated. Signed-off-by: Tero Kristo --- drivers/clk/ti/clk.c | 14 ++++++++++++++ drivers/clk/ti/clock.h | 2 ++ 2 files changed, 16 insertions(+) diff --git a/drivers/clk/ti/clk.c b/drivers/clk/ti/clk.c index 4efa2c9ea908..7d22e1af2247 100644 --- a/drivers/clk/ti/clk.c +++ b/drivers/clk/ti/clk.c @@ -275,6 +275,20 @@ int ti_clk_get_reg_addr(struct device_node *node, int index, return 0; } +void ti_clk_latch(struct clk_omap_reg *reg, s8 shift) +{ + u32 latch; + + if (shift < 0) + return; + + latch = 1 << shift; + + ti_clk_ll_ops->clk_rmw(latch, latch, reg); + ti_clk_ll_ops->clk_rmw(0, latch, reg); + ti_clk_ll_ops->clk_readl(reg); /* OCP barrier */ +} + /** * omap2_clk_provider_init - init master clock provider * @parent: master node diff --git a/drivers/clk/ti/clock.h b/drivers/clk/ti/clock.h index d9b43bfc2532..2f8af8fd886a 100644 --- a/drivers/clk/ti/clock.h +++ b/drivers/clk/ti/clock.h @@ -194,6 +194,8 @@ struct clk *ti_clk_register(struct device *dev, struct clk_hw *hw, int ti_clk_add_alias(struct device *dev, struct clk *clk, const char *con); void ti_clk_add_aliases(void); +void ti_clk_latch(struct clk_omap_reg *reg, s8 shift); + struct clk_hw *ti_clk_build_component_mux(struct ti_clk_mux *setup); int ti_clk_parse_divider_data(int *div_table, int num_dividers, int max_div, -- cgit From b44a03008da5e20e24c0d11d566796fb9b0f912e Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Thu, 15 Feb 2018 09:49:27 +0200 Subject: clk: ti: add support for clock latching to divider clocks Latching the clock settings is needed with certain clocks, where the setting is "cached" in HW before doing the actual re-programming of the clock source. This patch adds support for clock latching to the divider clock. Signed-off-by: Tero Kristo --- drivers/clk/ti/clock.h | 1 + drivers/clk/ti/divider.c | 26 ++++++++++++++++++++------ 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/drivers/clk/ti/clock.h b/drivers/clk/ti/clock.h index 2f8af8fd886a..62b108cc10de 100644 --- a/drivers/clk/ti/clock.h +++ b/drivers/clk/ti/clock.h @@ -22,6 +22,7 @@ struct clk_omap_divider { u8 shift; u8 width; u8 flags; + s8 latch; const struct clk_div_table *table; }; diff --git a/drivers/clk/ti/divider.c b/drivers/clk/ti/divider.c index 77f93f6d2806..aaa277dd6d99 100644 --- a/drivers/clk/ti/divider.c +++ b/drivers/clk/ti/divider.c @@ -263,6 +263,8 @@ static int ti_clk_divider_set_rate(struct clk_hw *hw, unsigned long rate, val |= value << divider->shift; ti_clk_ll_ops->clk_writel(val, ÷r->reg); + ti_clk_latch(÷r->reg, divider->latch); + return 0; } @@ -276,7 +278,8 @@ static struct clk *_register_divider(struct device *dev, const char *name, const char *parent_name, unsigned long flags, struct clk_omap_reg *reg, - u8 shift, u8 width, u8 clk_divider_flags, + u8 shift, u8 width, s8 latch, + u8 clk_divider_flags, const struct clk_div_table *table) { struct clk_omap_divider *div; @@ -305,6 +308,7 @@ static struct clk *_register_divider(struct device *dev, const char *name, memcpy(&div->reg, reg, sizeof(*reg)); div->shift = shift; div->width = width; + div->latch = latch; div->flags = clk_divider_flags; div->hw.init = &init; div->table = table; @@ -420,6 +424,7 @@ struct clk_hw *ti_clk_build_component_div(struct ti_clk_divider *setup) div->table = _get_div_table_from_setup(setup, &div->width); div->shift = setup->bit_shift; + div->latch = -EINVAL; return &div->hw; } @@ -452,7 +457,7 @@ struct clk *ti_clk_register_divider(struct ti_clk *setup) clk = _register_divider(NULL, setup->name, div->parent, flags, ®, div->bit_shift, - width, div_flags, table); + width, -EINVAL, div_flags, table); if (IS_ERR(clk)) kfree(table); @@ -556,7 +561,7 @@ static int _get_divider_width(struct device_node *node, static int __init ti_clk_divider_populate(struct device_node *node, struct clk_omap_reg *reg, const struct clk_div_table **table, - u32 *flags, u8 *div_flags, u8 *width, u8 *shift) + u32 *flags, u8 *div_flags, u8 *width, u8 *shift, s8 *latch) { u32 val; int ret; @@ -570,6 +575,13 @@ static int __init ti_clk_divider_populate(struct device_node *node, else *shift = 0; + if (latch) { + if (!of_property_read_u32(node, "ti,latch-bit", &val)) + *latch = val; + else + *latch = -EINVAL; + } + *flags = 0; *div_flags = 0; @@ -606,17 +618,18 @@ static void __init of_ti_divider_clk_setup(struct device_node *node) u8 clk_divider_flags = 0; u8 width = 0; u8 shift = 0; + s8 latch = -EINVAL; const struct clk_div_table *table = NULL; u32 flags = 0; parent_name = of_clk_get_parent_name(node, 0); if (ti_clk_divider_populate(node, ®, &table, &flags, - &clk_divider_flags, &width, &shift)) + &clk_divider_flags, &width, &shift, &latch)) goto cleanup; clk = _register_divider(NULL, node->name, parent_name, flags, ®, - shift, width, clk_divider_flags, table); + shift, width, latch, clk_divider_flags, table); if (!IS_ERR(clk)) { of_clk_add_provider(node, of_clk_src_simple_get, clk); @@ -639,7 +652,8 @@ static void __init of_ti_composite_divider_clk_setup(struct device_node *node) return; if (ti_clk_divider_populate(node, &div->reg, &div->table, &val, - &div->flags, &div->width, &div->shift) < 0) + &div->flags, &div->width, &div->shift, + NULL) < 0) goto cleanup; if (!ti_clk_add_component(node, &div->hw, CLK_COMPONENT_TYPE_DIVIDER)) -- cgit From ee2fc3c5ca8dad3906dd1d578e72d5272083220c Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Thu, 15 Feb 2018 09:50:02 +0200 Subject: clk: ti: add support for clock latching to mux clocks Latching the clock settings is needed with certain clocks, where the setting is "cached" in HW before doing the actual re-programming of the clock source. This patch adds support for clock latching to the mux clock. Signed-off-by: Tero Kristo --- drivers/clk/ti/clock.h | 1 + drivers/clk/ti/mux.c | 13 ++++++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/clk/ti/clock.h b/drivers/clk/ti/clock.h index 62b108cc10de..90b86aadfda7 100644 --- a/drivers/clk/ti/clock.h +++ b/drivers/clk/ti/clock.h @@ -34,6 +34,7 @@ struct clk_omap_mux { u32 *table; u32 mask; u8 shift; + s8 latch; u8 flags; }; diff --git a/drivers/clk/ti/mux.c b/drivers/clk/ti/mux.c index d4705803f3d3..69a4308a5a98 100644 --- a/drivers/clk/ti/mux.c +++ b/drivers/clk/ti/mux.c @@ -86,6 +86,7 @@ static int ti_clk_mux_set_parent(struct clk_hw *hw, u8 index) } val |= index << mux->shift; ti_clk_ll_ops->clk_writel(val, &mux->reg); + ti_clk_latch(&mux->reg, mux->latch); return 0; } @@ -100,7 +101,7 @@ static struct clk *_register_mux(struct device *dev, const char *name, const char * const *parent_names, u8 num_parents, unsigned long flags, struct clk_omap_reg *reg, u8 shift, u32 mask, - u8 clk_mux_flags, u32 *table) + s8 latch, u8 clk_mux_flags, u32 *table) { struct clk_omap_mux *mux; struct clk *clk; @@ -121,6 +122,7 @@ static struct clk *_register_mux(struct device *dev, const char *name, memcpy(&mux->reg, reg, sizeof(*reg)); mux->shift = shift; mux->mask = mask; + mux->latch = latch; mux->flags = clk_mux_flags; mux->table = table; mux->hw.init = &init; @@ -160,7 +162,7 @@ struct clk *ti_clk_register_mux(struct ti_clk *setup) flags |= CLK_SET_RATE_PARENT; return _register_mux(NULL, setup->name, mux->parents, mux->num_parents, - flags, ®, mux->bit_shift, mask, + flags, ®, mux->bit_shift, mask, -EINVAL, mux_flags, NULL); } @@ -179,6 +181,7 @@ static void of_mux_clk_setup(struct device_node *node) u8 clk_mux_flags = 0; u32 mask = 0; u32 shift = 0; + s32 latch = -EINVAL; u32 flags = CLK_SET_RATE_NO_REPARENT; num_parents = of_clk_get_parent_count(node); @@ -197,6 +200,8 @@ static void of_mux_clk_setup(struct device_node *node) of_property_read_u32(node, "ti,bit-shift", &shift); + of_property_read_u32(node, "ti,latch-bit", &latch); + if (of_property_read_bool(node, "ti,index-starts-at-one")) clk_mux_flags |= CLK_MUX_INDEX_ONE; @@ -211,7 +216,8 @@ static void of_mux_clk_setup(struct device_node *node) mask = (1 << fls(mask)) - 1; clk = _register_mux(NULL, node->name, parent_names, num_parents, - flags, ®, shift, mask, clk_mux_flags, NULL); + flags, ®, shift, mask, latch, clk_mux_flags, + NULL); if (!IS_ERR(clk)) of_clk_add_provider(node, of_clk_src_simple_get, clk); @@ -234,6 +240,7 @@ struct clk_hw *ti_clk_build_component_mux(struct ti_clk_mux *setup) return ERR_PTR(-ENOMEM); mux->shift = setup->bit_shift; + mux->latch = -EINVAL; mux->reg.index = setup->module; mux->reg.offset = setup->reg; -- cgit From 3c13933c60338ce6fb2369bd0e93f91e52ddc17d Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Tue, 12 Dec 2017 10:31:15 +0200 Subject: clk: keystone: sci-clk: add support for dynamically probing clocks Currently, the driver contains a large hints table for clocks that exist on a device, however, it is possible to probe the clocks from the firmware also. Add support for this, and drop the clock hints table support from the driver completely. This causes the driver to send a few extra sci-clk messages during boot, basically one extra for each device that exists on the SoC; on K2G this is approx 80. Signed-off-by: Tero Kristo Acked-by: Santosh Shilimkar --- drivers/clk/keystone/sci-clk.c | 380 ++++++++++------------------------------- 1 file changed, 90 insertions(+), 290 deletions(-) diff --git a/drivers/clk/keystone/sci-clk.c b/drivers/clk/keystone/sci-clk.c index 9cdf9d5050ac..4cb70bed89a9 100644 --- a/drivers/clk/keystone/sci-clk.c +++ b/drivers/clk/keystone/sci-clk.c @@ -28,22 +28,11 @@ #define SCI_CLK_ALLOW_FREQ_CHANGE BIT(1) #define SCI_CLK_INPUT_TERMINATION BIT(2) -/** - * struct sci_clk_data - TI SCI clock data - * @dev: device index - * @num_clks: number of clocks for this device - */ -struct sci_clk_data { - u16 dev; - u16 num_clks; -}; - /** * struct sci_clk_provider - TI SCI clock provider representation * @sci: Handle to the System Control Interface protocol handler * @ops: Pointer to the SCI ops to be used by the clocks * @dev: Device pointer for the clock provider - * @clk_data: Clock data * @clocks: Clocks array for this device * @num_clocks: Total number of clocks for this provider */ @@ -51,8 +40,7 @@ struct sci_clk_provider { const struct ti_sci_handle *sci; const struct ti_sci_clk_ops *ops; struct device *dev; - const struct sci_clk_data *clk_data; - struct clk_hw **clocks; + struct sci_clk **clocks; int num_clocks; }; @@ -61,6 +49,7 @@ struct sci_clk_provider { * @hw: Hardware clock cookie for common clock framework * @dev_id: Device index * @clk_id: Clock index + * @num_parents: Number of parents for this clock * @provider: Master clock provider * @flags: Flags for the clock */ @@ -68,6 +57,7 @@ struct sci_clk { struct clk_hw hw; u16 dev_id; u8 clk_id; + u8 num_parents; struct sci_clk_provider *provider; u8 flags; }; @@ -273,38 +263,22 @@ static const struct clk_ops sci_clk_ops = { /** * _sci_clk_get - Gets a handle for an SCI clock * @provider: Handle to SCI clock provider - * @dev_id: device ID for the clock to register - * @clk_id: clock ID for the clock to register + * @sci_clk: Handle to the SCI clock to populate * * Gets a handle to an existing TI SCI hw clock, or builds a new clock * entry and registers it with the common clock framework. Called from * the common clock framework, when a corresponding of_clk_get call is * executed, or recursively from itself when parsing parent clocks. - * Returns a pointer to the hw clock struct, or ERR_PTR value in failure. + * Returns 0 on success, negative error code on failure. */ -static struct clk_hw *_sci_clk_build(struct sci_clk_provider *provider, - u16 dev_id, u8 clk_id) +static int _sci_clk_build(struct sci_clk_provider *provider, + struct sci_clk *sci_clk) { struct clk_init_data init = { NULL }; - struct sci_clk *sci_clk = NULL; char *name = NULL; char **parent_names = NULL; int i; - int ret; - - sci_clk = devm_kzalloc(provider->dev, sizeof(*sci_clk), GFP_KERNEL); - if (!sci_clk) - return ERR_PTR(-ENOMEM); - - sci_clk->dev_id = dev_id; - sci_clk->clk_id = clk_id; - sci_clk->provider = provider; - - ret = provider->ops->get_num_parents(provider->sci, dev_id, - clk_id, - &init.num_parents); - if (ret) - goto err; + int ret = 0; name = kasprintf(GFP_KERNEL, "%s:%d:%d", dev_name(provider->dev), sci_clk->dev_id, sci_clk->clk_id); @@ -317,11 +291,11 @@ static struct clk_hw *_sci_clk_build(struct sci_clk_provider *provider, * to have mux functionality. Otherwise it is going to act as a root * clock. */ - if (init.num_parents < 2) - init.num_parents = 0; + if (sci_clk->num_parents < 2) + sci_clk->num_parents = 0; - if (init.num_parents) { - parent_names = kcalloc(init.num_parents, sizeof(char *), + if (sci_clk->num_parents) { + parent_names = kcalloc(sci_clk->num_parents, sizeof(char *), GFP_KERNEL); if (!parent_names) { @@ -329,7 +303,7 @@ static struct clk_hw *_sci_clk_build(struct sci_clk_provider *provider, goto err; } - for (i = 0; i < init.num_parents; i++) { + for (i = 0; i < sci_clk->num_parents; i++) { char *parent_name; parent_name = kasprintf(GFP_KERNEL, "%s:%d:%d", @@ -346,6 +320,7 @@ static struct clk_hw *_sci_clk_build(struct sci_clk_provider *provider, } init.ops = &sci_clk_ops; + init.num_parents = sci_clk->num_parents; sci_clk->hw.init = &init; ret = devm_clk_hw_register(provider->dev, &sci_clk->hw); @@ -354,7 +329,7 @@ static struct clk_hw *_sci_clk_build(struct sci_clk_provider *provider, err: if (parent_names) { - for (i = 0; i < init.num_parents; i++) + for (i = 0; i < sci_clk->num_parents; i++) kfree(parent_names[i]); kfree(parent_names); @@ -362,10 +337,7 @@ err: kfree(name); - if (ret) - return ERR_PTR(ret); - - return &sci_clk->hw; + return ret; } static int _cmp_sci_clk(const void *a, const void *b) @@ -414,253 +386,20 @@ static struct clk_hw *sci_clk_get(struct of_phandle_args *clkspec, void *data) static int ti_sci_init_clocks(struct sci_clk_provider *p) { - const struct sci_clk_data *data = p->clk_data; - struct clk_hw *hw; int i; - int num_clks = 0; - - while (data->num_clks) { - num_clks += data->num_clks; - data++; - } - - p->num_clocks = num_clks; - - p->clocks = devm_kcalloc(p->dev, num_clks, sizeof(struct sci_clk), - GFP_KERNEL); - if (!p->clocks) - return -ENOMEM; - - num_clks = 0; - - data = p->clk_data; - - while (data->num_clks) { - for (i = 0; i < data->num_clks; i++) { - hw = _sci_clk_build(p, data->dev, i); - if (!IS_ERR(hw)) { - p->clocks[num_clks++] = hw; - continue; - } - - /* Skip any holes in the clock lists */ - if (PTR_ERR(hw) == -ENODEV) - continue; + int ret; - return PTR_ERR(hw); - } - data++; + for (i = 0; i < p->num_clocks; i++) { + ret = _sci_clk_build(p, p->clocks[i]); + if (ret) + return ret; } return 0; } -static const struct sci_clk_data k2g_clk_data[] = { - /* pmmc */ - { .dev = 0x0, .num_clks = 4 }, - - /* mlb0 */ - { .dev = 0x1, .num_clks = 5 }, - - /* dss0 */ - { .dev = 0x2, .num_clks = 2 }, - - /* mcbsp0 */ - { .dev = 0x3, .num_clks = 8 }, - - /* mcasp0 */ - { .dev = 0x4, .num_clks = 8 }, - - /* mcasp1 */ - { .dev = 0x5, .num_clks = 8 }, - - /* mcasp2 */ - { .dev = 0x6, .num_clks = 8 }, - - /* dcan0 */ - { .dev = 0x8, .num_clks = 2 }, - - /* dcan1 */ - { .dev = 0x9, .num_clks = 2 }, - - /* emif0 */ - { .dev = 0xa, .num_clks = 6 }, - - /* mmchs0 */ - { .dev = 0xb, .num_clks = 3 }, - - /* mmchs1 */ - { .dev = 0xc, .num_clks = 3 }, - - /* gpmc0 */ - { .dev = 0xd, .num_clks = 1 }, - - /* elm0 */ - { .dev = 0xe, .num_clks = 1 }, - - /* spi0 */ - { .dev = 0x10, .num_clks = 1 }, - - /* spi1 */ - { .dev = 0x11, .num_clks = 1 }, - - /* spi2 */ - { .dev = 0x12, .num_clks = 1 }, - - /* spi3 */ - { .dev = 0x13, .num_clks = 1 }, - - /* icss0 */ - { .dev = 0x14, .num_clks = 6 }, - - /* icss1 */ - { .dev = 0x15, .num_clks = 6 }, - - /* usb0 */ - { .dev = 0x16, .num_clks = 7 }, - - /* usb1 */ - { .dev = 0x17, .num_clks = 7 }, - - /* nss0 */ - { .dev = 0x18, .num_clks = 14 }, - - /* pcie0 */ - { .dev = 0x19, .num_clks = 1 }, - - /* gpio0 */ - { .dev = 0x1b, .num_clks = 1 }, - - /* gpio1 */ - { .dev = 0x1c, .num_clks = 1 }, - - /* timer64_0 */ - { .dev = 0x1d, .num_clks = 9 }, - - /* timer64_1 */ - { .dev = 0x1e, .num_clks = 9 }, - - /* timer64_2 */ - { .dev = 0x1f, .num_clks = 9 }, - - /* timer64_3 */ - { .dev = 0x20, .num_clks = 9 }, - - /* timer64_4 */ - { .dev = 0x21, .num_clks = 9 }, - - /* timer64_5 */ - { .dev = 0x22, .num_clks = 9 }, - - /* timer64_6 */ - { .dev = 0x23, .num_clks = 9 }, - - /* msgmgr0 */ - { .dev = 0x25, .num_clks = 1 }, - - /* bootcfg0 */ - { .dev = 0x26, .num_clks = 1 }, - - /* arm_bootrom0 */ - { .dev = 0x27, .num_clks = 1 }, - - /* dsp_bootrom0 */ - { .dev = 0x29, .num_clks = 1 }, - - /* debugss0 */ - { .dev = 0x2b, .num_clks = 8 }, - - /* uart0 */ - { .dev = 0x2c, .num_clks = 1 }, - - /* uart1 */ - { .dev = 0x2d, .num_clks = 1 }, - - /* uart2 */ - { .dev = 0x2e, .num_clks = 1 }, - - /* ehrpwm0 */ - { .dev = 0x2f, .num_clks = 1 }, - - /* ehrpwm1 */ - { .dev = 0x30, .num_clks = 1 }, - - /* ehrpwm2 */ - { .dev = 0x31, .num_clks = 1 }, - - /* ehrpwm3 */ - { .dev = 0x32, .num_clks = 1 }, - - /* ehrpwm4 */ - { .dev = 0x33, .num_clks = 1 }, - - /* ehrpwm5 */ - { .dev = 0x34, .num_clks = 1 }, - - /* eqep0 */ - { .dev = 0x35, .num_clks = 1 }, - - /* eqep1 */ - { .dev = 0x36, .num_clks = 1 }, - - /* eqep2 */ - { .dev = 0x37, .num_clks = 1 }, - - /* ecap0 */ - { .dev = 0x38, .num_clks = 1 }, - - /* ecap1 */ - { .dev = 0x39, .num_clks = 1 }, - - /* i2c0 */ - { .dev = 0x3a, .num_clks = 1 }, - - /* i2c1 */ - { .dev = 0x3b, .num_clks = 1 }, - - /* i2c2 */ - { .dev = 0x3c, .num_clks = 1 }, - - /* edma0 */ - { .dev = 0x3f, .num_clks = 2 }, - - /* semaphore0 */ - { .dev = 0x40, .num_clks = 1 }, - - /* intc0 */ - { .dev = 0x41, .num_clks = 1 }, - - /* gic0 */ - { .dev = 0x42, .num_clks = 1 }, - - /* qspi0 */ - { .dev = 0x43, .num_clks = 5 }, - - /* arm_64b_counter0 */ - { .dev = 0x44, .num_clks = 2 }, - - /* tetris0 */ - { .dev = 0x45, .num_clks = 2 }, - - /* cgem0 */ - { .dev = 0x46, .num_clks = 2 }, - - /* msmc0 */ - { .dev = 0x47, .num_clks = 1 }, - - /* cbass0 */ - { .dev = 0x49, .num_clks = 1 }, - - /* board0 */ - { .dev = 0x4c, .num_clks = 36 }, - - /* edma1 */ - { .dev = 0x4f, .num_clks = 2 }, - { .num_clks = 0 }, -}; - static const struct of_device_id ti_sci_clk_of_match[] = { - { .compatible = "ti,k2g-sci-clk", .data = &k2g_clk_data }, + { .compatible = "ti,k2g-sci-clk" }, { /* Sentinel */ }, }; MODULE_DEVICE_TABLE(of, ti_sci_clk_of_match); @@ -681,12 +420,16 @@ static int ti_sci_clk_probe(struct platform_device *pdev) struct device_node *np = dev->of_node; struct sci_clk_provider *provider; const struct ti_sci_handle *handle; - const struct sci_clk_data *data; int ret; - - data = of_device_get_match_data(dev); - if (!data) - return -EINVAL; + int num_clks = 0; + struct sci_clk **clks = NULL; + struct sci_clk **tmp_clks; + struct sci_clk *sci_clk; + int max_clks = 0; + int clk_id = 0; + int dev_id = 0; + u8 num_parents; + int gap_size = 0; handle = devm_ti_sci_get_handle(dev); if (IS_ERR(handle)) @@ -696,12 +439,69 @@ static int ti_sci_clk_probe(struct platform_device *pdev) if (!provider) return -ENOMEM; - provider->clk_data = data; - provider->sci = handle; provider->ops = &handle->ops.clk_ops; provider->dev = dev; + while (1) { + ret = provider->ops->get_num_parents(provider->sci, dev_id, + clk_id, &num_parents); + if (ret) { + gap_size++; + if (!clk_id) { + if (gap_size >= 5) + break; + dev_id++; + } else { + if (gap_size >= 2) { + dev_id++; + clk_id = 0; + gap_size = 0; + } else { + clk_id++; + } + } + continue; + } + + gap_size = 0; + + if (num_clks == max_clks) { + tmp_clks = devm_kmalloc_array(dev, max_clks + 64, + sizeof(sci_clk), + GFP_KERNEL); + memcpy(tmp_clks, clks, max_clks * sizeof(sci_clk)); + if (max_clks) + devm_kfree(dev, clks); + max_clks += 64; + clks = tmp_clks; + } + + sci_clk = devm_kzalloc(dev, sizeof(*sci_clk), GFP_KERNEL); + if (!sci_clk) + return -ENOMEM; + sci_clk->dev_id = dev_id; + sci_clk->clk_id = clk_id; + sci_clk->provider = provider; + sci_clk->num_parents = num_parents; + + clks[num_clks] = sci_clk; + + clk_id++; + num_clks++; + } + + provider->clocks = devm_kmalloc_array(dev, num_clks, sizeof(sci_clk), + GFP_KERNEL); + if (!provider->clocks) + return -ENOMEM; + + memcpy(provider->clocks, clks, num_clks * sizeof(sci_clk)); + + provider->num_clocks = num_clks; + + devm_kfree(dev, clks); + ret = ti_sci_init_clocks(provider); if (ret) { pr_err("ti-sci-init-clocks failed.\n"); -- cgit From 89e423c3f14c4a87d124e4a5437dc337b90b6f29 Mon Sep 17 00:00:00 2001 From: Peter De Schrijver Date: Thu, 25 Jan 2018 16:00:10 +0200 Subject: clk: tegra: Add la clock for Tegra210 This clock is needed by the memory built-in self test work around. Signed-off-by: Peter De Schrijver Reviewed-by: Jon Hunter Tested-by: Jon Hunter Tested-by: Hector Martin Tested-by: Andre Heider Tested-by: Mikko Perttunen Signed-off-by: Thierry Reding --- drivers/clk/tegra/clk-tegra210.c | 14 ++++++++++++++ include/dt-bindings/clock/tegra210-car.h | 2 +- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/drivers/clk/tegra/clk-tegra210.c b/drivers/clk/tegra/clk-tegra210.c index 9e6260869eb9..f790c2dc5b5d 100644 --- a/drivers/clk/tegra/clk-tegra210.c +++ b/drivers/clk/tegra/clk-tegra210.c @@ -41,6 +41,7 @@ #define CLK_SOURCE_CSITE 0x1d4 #define CLK_SOURCE_EMC 0x19c #define CLK_SOURCE_SOR1 0x410 +#define CLK_SOURCE_LA 0x1f8 #define PLLC_BASE 0x80 #define PLLC_OUT 0x84 @@ -2654,6 +2655,13 @@ static struct tegra_periph_init_data tegra210_periph[] = { sor1_parents_idx, 0, &sor1_lock), }; +static const char * const la_parents[] = { + "pll_p", "pll_c2", "pll_c", "pll_c3", "pll_re_out1", "pll_a1", "clk_m", "pll_c4_out0" +}; + +static struct tegra_clk_periph tegra210_la = + TEGRA_CLK_PERIPH(29, 7, 9, 0, 8, 1, TEGRA_DIVIDER_ROUND_UP, 76, 0, NULL, 0); + static __init void tegra210_periph_clk_init(void __iomem *clk_base, void __iomem *pmc_base) { @@ -2700,6 +2708,12 @@ static __init void tegra210_periph_clk_init(void __iomem *clk_base, periph_clk_enb_refcnt); clks[TEGRA210_CLK_DSIB] = clk; + /* la */ + clk = tegra_clk_register_periph("la", la_parents, + ARRAY_SIZE(la_parents), &tegra210_la, clk_base, + CLK_SOURCE_LA, 0); + clks[TEGRA210_CLK_LA] = clk; + /* emc mux */ clk = clk_register_mux(NULL, "emc_mux", mux_pllmcp_clkm, ARRAY_SIZE(mux_pllmcp_clkm), 0, diff --git a/include/dt-bindings/clock/tegra210-car.h b/include/dt-bindings/clock/tegra210-car.h index 6422314e46eb..6b77e721f6b1 100644 --- a/include/dt-bindings/clock/tegra210-car.h +++ b/include/dt-bindings/clock/tegra210-car.h @@ -95,7 +95,7 @@ #define TEGRA210_CLK_CSITE 73 /* 74 */ /* 75 */ -/* 76 */ +#define TEGRA210_CLK_LA 76 /* 77 */ #define TEGRA210_CLK_SOC_THERM 78 #define TEGRA210_CLK_DTV 79 -- cgit From cbfc8d0a85aa72ad66227c69b08904143dc73bbb Mon Sep 17 00:00:00 2001 From: Peter De Schrijver Date: Thu, 25 Jan 2018 16:00:11 +0200 Subject: clk: tegra: add fence_delay for clock registers To ensure writes to clock registers have properly propagated through the clock control logic and state machines, we need to ensure the writes have been posted in the registers and wait for 1us after that. Signed-off-by: Peter De Schrijver Reviewed-by: Jon Hunter Tested-by: Jon Hunter Tested-by: Hector Martin Tested-by: Andre Heider Tested-by: Mikko Perttunen Signed-off-by: Thierry Reding --- drivers/clk/tegra/clk.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h index 3b2763df51c2..ba7e20e6a82b 100644 --- a/drivers/clk/tegra/clk.h +++ b/drivers/clk/tegra/clk.h @@ -812,4 +812,11 @@ int tegra_pll_wait_for_lock(struct tegra_clk_pll *pll); u16 tegra_pll_get_fixed_mdiv(struct clk_hw *hw, unsigned long input_rate); int tegra_pll_p_div_to_hw(struct tegra_clk_pll *pll, u8 p_div); +/* Combined read fence with delay */ +#define fence_udelay(delay, reg) \ + do { \ + readl(reg); \ + udelay(delay); \ + } while (0) + #endif /* TEGRA_CLK_H */ -- cgit From e403d00573431e1e3de1710a91c6090c60ec16af Mon Sep 17 00:00:00 2001 From: Peter De Schrijver Date: Thu, 25 Jan 2018 16:00:12 +0200 Subject: clk: tegra: MBIST work around for Tegra210 Tegra210 has a hw bug which can cause IP blocks to lock up when ungating a domain. The reason is that the logic responsible for resetting the memory built-in self test mode can come up in an undefined state because its clock is gated by a second level clock gate (SLCG). Work around this by making sure the logic will get some clock edges by ensuring the relevant clock is enabled and temporarily override the relevant SLCGs. Unfortunately for some IP blocks, the control bits for overriding the SLCGs are not in CAR, but in the IP block itself. This means we need to map a few extra register banks in the clock code. Signed-off-by: Peter De Schrijver Reviewed-by: Jon Hunter Tested-by: Jon Hunter Tested-by: Hector Martin Tested-by: Andre Heider Tested-by: Mikko Perttunen Signed-off-by: Thierry Reding fixup mbist --- drivers/clk/tegra/clk-tegra210.c | 344 ++++++++++++++++++++++++++++++++++++++- include/linux/clk/tegra.h | 1 + 2 files changed, 343 insertions(+), 2 deletions(-) diff --git a/drivers/clk/tegra/clk-tegra210.c b/drivers/clk/tegra/clk-tegra210.c index f790c2dc5b5d..946d708add1e 100644 --- a/drivers/clk/tegra/clk-tegra210.c +++ b/drivers/clk/tegra/clk-tegra210.c @@ -22,10 +22,12 @@ #include #include #include +#include #include #include #include #include +#include #include "clk.h" #include "clk-id.h" @@ -232,6 +234,30 @@ #define CLK_RST_CONTROLLER_RST_DEV_Y_SET 0x2a8 #define CLK_RST_CONTROLLER_RST_DEV_Y_CLR 0x2ac +#define LVL2_CLK_GATE_OVRA 0xf8 +#define LVL2_CLK_GATE_OVRC 0x3a0 +#define LVL2_CLK_GATE_OVRD 0x3a4 +#define LVL2_CLK_GATE_OVRE 0x554 + +/* I2S registers to handle during APE MBIST WAR */ +#define TEGRA210_I2S_BASE 0x1000 +#define TEGRA210_I2S_SIZE 0x100 +#define TEGRA210_I2S_CTRLS 5 +#define TEGRA210_I2S_CG 0x88 +#define TEGRA210_I2S_CTRL 0xa0 + +/* DISPA registers to handle during MBIST WAR */ +#define DC_CMD_DISPLAY_COMMAND 0xc8 +#define DC_COM_DSC_TOP_CTL 0xcf8 + +/* VIC register to handle during MBIST WAR */ +#define NV_PVIC_THI_SLCG_OVERRIDE_LOW 0x8c + +/* APE, DISPA and VIC base addesses needed for MBIST WAR */ +#define TEGRA210_AHUB_BASE 0x702d0000 +#define TEGRA210_DISPA_BASE 0x54200000 +#define TEGRA210_VIC_BASE 0x54340000 + /* * SDM fractional divisor is 16-bit 2's complement signed number within * (-2^12 ... 2^12-1) range. Represented in PLL data structure as unsigned @@ -256,8 +282,22 @@ static struct cpu_clk_suspend_context { } tegra210_cpu_clk_sctx; #endif +struct tegra210_domain_mbist_war { + void (*handle_lvl2_ovr)(struct tegra210_domain_mbist_war *mbist); + const u32 lvl2_offset; + const u32 lvl2_mask; + const unsigned int num_clks; + const unsigned int *clk_init_data; + struct clk_bulk_data *clks; +}; + +static struct clk **clks; + static void __iomem *clk_base; static void __iomem *pmc_base; +static void __iomem *ahub_base; +static void __iomem *dispa_base; +static void __iomem *vic_base; static unsigned long osc_freq; static unsigned long pll_ref_freq; @@ -268,6 +308,7 @@ static DEFINE_SPINLOCK(pll_re_lock); static DEFINE_SPINLOCK(pll_u_lock); static DEFINE_SPINLOCK(sor1_lock); static DEFINE_SPINLOCK(emc_lock); +static DEFINE_MUTEX(lvl2_ovr_lock); /* possible OSC frequencies in Hz */ static unsigned long tegra210_input_freq[] = { @@ -311,6 +352,8 @@ static const char *mux_pllmcp_clkm[] = { #define PLLA_MISC2_WRITE_MASK 0x06ffffff /* PLLD */ +#define PLLD_BASE_CSI_CLKSOURCE (1 << 23) + #define PLLD_MISC0_EN_SDM (1 << 16) #define PLLD_MISC0_LOCK_OVERRIDE (1 << 17) #define PLLD_MISC0_LOCK_ENABLE (1 << 18) @@ -514,6 +557,115 @@ void tegra210_set_sata_pll_seq_sw(bool state) } EXPORT_SYMBOL_GPL(tegra210_set_sata_pll_seq_sw); +static void tegra210_generic_mbist_war(struct tegra210_domain_mbist_war *mbist) +{ + u32 val; + + val = readl_relaxed(clk_base + mbist->lvl2_offset); + writel_relaxed(val | mbist->lvl2_mask, clk_base + mbist->lvl2_offset); + fence_udelay(1, clk_base); + writel_relaxed(val, clk_base + mbist->lvl2_offset); + fence_udelay(1, clk_base); +} + +static void tegra210_venc_mbist_war(struct tegra210_domain_mbist_war *mbist) +{ + u32 csi_src, ovra, ovre; + unsigned long flags = 0; + + spin_lock_irqsave(&pll_d_lock, flags); + + csi_src = readl_relaxed(clk_base + PLLD_BASE); + writel_relaxed(csi_src | PLLD_BASE_CSI_CLKSOURCE, clk_base + PLLD_BASE); + fence_udelay(1, clk_base); + + ovra = readl_relaxed(clk_base + LVL2_CLK_GATE_OVRA); + writel_relaxed(ovra | BIT(15), clk_base + LVL2_CLK_GATE_OVRA); + ovre = readl_relaxed(clk_base + LVL2_CLK_GATE_OVRE); + writel_relaxed(ovre | BIT(3), clk_base + LVL2_CLK_GATE_OVRE); + fence_udelay(1, clk_base); + + writel_relaxed(ovra, clk_base + LVL2_CLK_GATE_OVRA); + writel_relaxed(ovre, clk_base + LVL2_CLK_GATE_OVRE); + writel_relaxed(csi_src, clk_base + PLLD_BASE); + fence_udelay(1, clk_base); + + spin_unlock_irqrestore(&pll_d_lock, flags); +} + +static void tegra210_disp_mbist_war(struct tegra210_domain_mbist_war *mbist) +{ + u32 ovra, dsc_top_ctrl; + + ovra = readl_relaxed(clk_base + LVL2_CLK_GATE_OVRA); + writel_relaxed(ovra | BIT(1), clk_base + LVL2_CLK_GATE_OVRA); + fence_udelay(1, clk_base); + + dsc_top_ctrl = readl_relaxed(dispa_base + DC_COM_DSC_TOP_CTL); + writel_relaxed(dsc_top_ctrl | BIT(2), dispa_base + DC_COM_DSC_TOP_CTL); + readl_relaxed(dispa_base + DC_CMD_DISPLAY_COMMAND); + writel_relaxed(dsc_top_ctrl, dispa_base + DC_COM_DSC_TOP_CTL); + readl_relaxed(dispa_base + DC_CMD_DISPLAY_COMMAND); + + writel_relaxed(ovra, clk_base + LVL2_CLK_GATE_OVRA); + fence_udelay(1, clk_base); +} + +static void tegra210_vic_mbist_war(struct tegra210_domain_mbist_war *mbist) +{ + u32 ovre, val; + + ovre = readl_relaxed(clk_base + LVL2_CLK_GATE_OVRE); + writel_relaxed(ovre | BIT(5), clk_base + LVL2_CLK_GATE_OVRE); + fence_udelay(1, clk_base); + + val = readl_relaxed(vic_base + NV_PVIC_THI_SLCG_OVERRIDE_LOW); + writel_relaxed(val | BIT(0) | GENMASK(7, 2) | BIT(24), + vic_base + NV_PVIC_THI_SLCG_OVERRIDE_LOW); + fence_udelay(1, vic_base + NV_PVIC_THI_SLCG_OVERRIDE_LOW); + + writel_relaxed(val, vic_base + NV_PVIC_THI_SLCG_OVERRIDE_LOW); + readl(vic_base + NV_PVIC_THI_SLCG_OVERRIDE_LOW); + + writel_relaxed(ovre, clk_base + LVL2_CLK_GATE_OVRE); + fence_udelay(1, clk_base); +} + +static void tegra210_ape_mbist_war(struct tegra210_domain_mbist_war *mbist) +{ + void __iomem *i2s_base; + unsigned int i; + u32 ovrc, ovre; + + ovrc = readl_relaxed(clk_base + LVL2_CLK_GATE_OVRC); + ovre = readl_relaxed(clk_base + LVL2_CLK_GATE_OVRE); + writel_relaxed(ovrc | BIT(1), clk_base + LVL2_CLK_GATE_OVRC); + writel_relaxed(ovre | BIT(10) | BIT(11), + clk_base + LVL2_CLK_GATE_OVRE); + fence_udelay(1, clk_base); + + i2s_base = ahub_base + TEGRA210_I2S_BASE; + + for (i = 0; i < TEGRA210_I2S_CTRLS; i++) { + u32 i2s_ctrl; + + i2s_ctrl = readl_relaxed(i2s_base + TEGRA210_I2S_CTRL); + writel_relaxed(i2s_ctrl | BIT(10), + i2s_base + TEGRA210_I2S_CTRL); + writel_relaxed(0, i2s_base + TEGRA210_I2S_CG); + readl(i2s_base + TEGRA210_I2S_CG); + writel_relaxed(1, i2s_base + TEGRA210_I2S_CG); + writel_relaxed(i2s_ctrl, i2s_base + TEGRA210_I2S_CTRL); + readl(i2s_base + TEGRA210_I2S_CTRL); + + i2s_base += TEGRA210_I2S_SIZE; + } + + writel_relaxed(ovrc, clk_base + LVL2_CLK_GATE_OVRC); + writel_relaxed(ovre, clk_base + LVL2_CLK_GATE_OVRE); + fence_udelay(1, clk_base); +} + static inline void _pll_misc_chk_default(void __iomem *base, struct tegra_clk_pll_params *params, u8 misc_num, u32 default_val, u32 mask) @@ -2412,13 +2564,150 @@ static struct tegra_audio_clk_info tegra210_audio_plls[] = { { "pll_a1", &pll_a1_params, tegra_clk_pll_a1, "pll_ref" }, }; -static struct clk **clks; - static const char * const aclk_parents[] = { "pll_a1", "pll_c", "pll_p", "pll_a_out0", "pll_c2", "pll_c3", "clk_m" }; +static const unsigned int nvjpg_slcg_clkids[] = { TEGRA210_CLK_NVDEC }; +static const unsigned int nvdec_slcg_clkids[] = { TEGRA210_CLK_NVJPG }; +static const unsigned int sor_slcg_clkids[] = { TEGRA210_CLK_HDA2CODEC_2X, + TEGRA210_CLK_HDA2HDMI, TEGRA210_CLK_DISP1, TEGRA210_CLK_DISP2 }; +static const unsigned int disp_slcg_clkids[] = { TEGRA210_CLK_LA, + TEGRA210_CLK_HOST1X}; +static const unsigned int xusba_slcg_clkids[] = { TEGRA210_CLK_XUSB_HOST, + TEGRA210_CLK_XUSB_DEV }; +static const unsigned int xusbb_slcg_clkids[] = { TEGRA210_CLK_XUSB_HOST, + TEGRA210_CLK_XUSB_SS }; +static const unsigned int xusbc_slcg_clkids[] = { TEGRA210_CLK_XUSB_DEV, + TEGRA210_CLK_XUSB_SS }; +static const unsigned int venc_slcg_clkids[] = { TEGRA210_CLK_HOST1X, + TEGRA210_CLK_PLL_D }; +static const unsigned int ape_slcg_clkids[] = { TEGRA210_CLK_ACLK, + TEGRA210_CLK_I2S0, TEGRA210_CLK_I2S1, TEGRA210_CLK_I2S2, + TEGRA210_CLK_I2S3, TEGRA210_CLK_I2S4, TEGRA210_CLK_SPDIF_OUT, + TEGRA210_CLK_D_AUDIO }; +static const unsigned int vic_slcg_clkids[] = { TEGRA210_CLK_HOST1X }; + +static struct tegra210_domain_mbist_war tegra210_pg_mbist_war[] = { + [TEGRA_POWERGATE_VENC] = { + .handle_lvl2_ovr = tegra210_venc_mbist_war, + .num_clks = ARRAY_SIZE(venc_slcg_clkids), + .clk_init_data = venc_slcg_clkids, + }, + [TEGRA_POWERGATE_SATA] = { + .handle_lvl2_ovr = tegra210_generic_mbist_war, + .lvl2_offset = LVL2_CLK_GATE_OVRC, + .lvl2_mask = BIT(0) | BIT(17) | BIT(19), + }, + [TEGRA_POWERGATE_MPE] = { + .handle_lvl2_ovr = tegra210_generic_mbist_war, + .lvl2_offset = LVL2_CLK_GATE_OVRE, + .lvl2_mask = BIT(2), + }, + [TEGRA_POWERGATE_SOR] = { + .handle_lvl2_ovr = tegra210_generic_mbist_war, + .num_clks = ARRAY_SIZE(sor_slcg_clkids), + .clk_init_data = sor_slcg_clkids, + .lvl2_offset = LVL2_CLK_GATE_OVRA, + .lvl2_mask = BIT(1) | BIT(2), + }, + [TEGRA_POWERGATE_DIS] = { + .handle_lvl2_ovr = tegra210_disp_mbist_war, + .num_clks = ARRAY_SIZE(disp_slcg_clkids), + .clk_init_data = disp_slcg_clkids, + }, + [TEGRA_POWERGATE_DISB] = { + .num_clks = ARRAY_SIZE(disp_slcg_clkids), + .clk_init_data = disp_slcg_clkids, + .handle_lvl2_ovr = tegra210_generic_mbist_war, + .lvl2_offset = LVL2_CLK_GATE_OVRA, + .lvl2_mask = BIT(2), + }, + [TEGRA_POWERGATE_XUSBA] = { + .num_clks = ARRAY_SIZE(xusba_slcg_clkids), + .clk_init_data = xusba_slcg_clkids, + .handle_lvl2_ovr = tegra210_generic_mbist_war, + .lvl2_offset = LVL2_CLK_GATE_OVRC, + .lvl2_mask = BIT(30) | BIT(31), + }, + [TEGRA_POWERGATE_XUSBB] = { + .num_clks = ARRAY_SIZE(xusbb_slcg_clkids), + .clk_init_data = xusbb_slcg_clkids, + .handle_lvl2_ovr = tegra210_generic_mbist_war, + .lvl2_offset = LVL2_CLK_GATE_OVRC, + .lvl2_mask = BIT(30) | BIT(31), + }, + [TEGRA_POWERGATE_XUSBC] = { + .num_clks = ARRAY_SIZE(xusbc_slcg_clkids), + .clk_init_data = xusbc_slcg_clkids, + .handle_lvl2_ovr = tegra210_generic_mbist_war, + .lvl2_offset = LVL2_CLK_GATE_OVRC, + .lvl2_mask = BIT(30) | BIT(31), + }, + [TEGRA_POWERGATE_VIC] = { + .num_clks = ARRAY_SIZE(vic_slcg_clkids), + .clk_init_data = vic_slcg_clkids, + .handle_lvl2_ovr = tegra210_vic_mbist_war, + }, + [TEGRA_POWERGATE_NVDEC] = { + .num_clks = ARRAY_SIZE(nvdec_slcg_clkids), + .clk_init_data = nvdec_slcg_clkids, + .handle_lvl2_ovr = tegra210_generic_mbist_war, + .lvl2_offset = LVL2_CLK_GATE_OVRC, + .lvl2_mask = BIT(9) | BIT(31), + }, + [TEGRA_POWERGATE_NVJPG] = { + .num_clks = ARRAY_SIZE(nvjpg_slcg_clkids), + .clk_init_data = nvjpg_slcg_clkids, + .handle_lvl2_ovr = tegra210_generic_mbist_war, + .lvl2_offset = LVL2_CLK_GATE_OVRC, + .lvl2_mask = BIT(9) | BIT(31), + }, + [TEGRA_POWERGATE_AUD] = { + .num_clks = ARRAY_SIZE(ape_slcg_clkids), + .clk_init_data = ape_slcg_clkids, + .handle_lvl2_ovr = tegra210_ape_mbist_war, + }, + [TEGRA_POWERGATE_VE2] = { + .handle_lvl2_ovr = tegra210_generic_mbist_war, + .lvl2_offset = LVL2_CLK_GATE_OVRD, + .lvl2_mask = BIT(22), + }, +}; + +int tegra210_clk_handle_mbist_war(unsigned int id) +{ + int err; + struct tegra210_domain_mbist_war *mbist_war; + + if (id >= ARRAY_SIZE(tegra210_pg_mbist_war)) { + WARN(1, "unknown domain id in MBIST WAR handler\n"); + return -EINVAL; + } + + mbist_war = &tegra210_pg_mbist_war[id]; + if (!mbist_war->handle_lvl2_ovr) + return 0; + + if (mbist_war->num_clks && !mbist_war->clks) + return -ENODEV; + + err = clk_bulk_prepare_enable(mbist_war->num_clks, mbist_war->clks); + if (err < 0) + return err; + + mutex_lock(&lvl2_ovr_lock); + + mbist_war->handle_lvl2_ovr(mbist_war); + + mutex_unlock(&lvl2_ovr_lock); + + clk_bulk_disable_unprepare(mbist_war->num_clks, mbist_war->clks); + + return 0; +} + void tegra210_put_utmipll_in_iddq(void) { u32 reg; @@ -3163,6 +3452,37 @@ static int tegra210_reset_deassert(unsigned long id) return 0; } +static void tegra210_mbist_clk_init(void) +{ + unsigned int i, j; + + for (i = 0; i < ARRAY_SIZE(tegra210_pg_mbist_war); i++) { + unsigned int num_clks = tegra210_pg_mbist_war[i].num_clks; + struct clk_bulk_data *clk_data; + + if (!num_clks) + continue; + + clk_data = kmalloc_array(num_clks, sizeof(*clk_data), + GFP_KERNEL); + if (WARN_ON(!clk_data)) + return; + + tegra210_pg_mbist_war[i].clks = clk_data; + for (j = 0; j < num_clks; j++) { + int clk_id = tegra210_pg_mbist_war[i].clk_init_data[j]; + struct clk *clk = clks[clk_id]; + + if (WARN(IS_ERR(clk), "clk_id: %d\n", clk_id)) { + kfree(clk_data); + tegra210_pg_mbist_war[i].clks = NULL; + break; + } + clk_data[j].clk = clk; + } + } +} + /** * tegra210_clock_init - Tegra210-specific clock initialization * @np: struct device_node * of the DT node for the SoC CAR IP block @@ -3197,6 +3517,24 @@ static void __init tegra210_clock_init(struct device_node *np) return; } + ahub_base = ioremap(TEGRA210_AHUB_BASE, SZ_64K); + if (!ahub_base) { + pr_err("ioremap tegra210 APE failed\n"); + return; + } + + dispa_base = ioremap(TEGRA210_DISPA_BASE, SZ_256K); + if (!dispa_base) { + pr_err("ioremap tegra210 DISPA failed\n"); + return; + } + + vic_base = ioremap(TEGRA210_VIC_BASE, SZ_256K); + if (!vic_base) { + pr_err("ioremap tegra210 VIC failed\n"); + return; + } + clks = tegra_clk_init(clk_base, TEGRA210_CLK_CLK_MAX, TEGRA210_CAR_BANK_COUNT); if (!clks) @@ -3233,6 +3571,8 @@ static void __init tegra210_clock_init(struct device_node *np) tegra_add_of_provider(np); tegra_register_devclks(devclks, ARRAY_SIZE(devclks)); + tegra210_mbist_clk_init(); + tegra_cpu_car_ops = &tegra210_cpu_car_ops; } CLK_OF_DECLARE(tegra210, "nvidia,tegra210-car", tegra210_clock_init); diff --git a/include/linux/clk/tegra.h b/include/linux/clk/tegra.h index d23c9cf26993..afb9edfa5d58 100644 --- a/include/linux/clk/tegra.h +++ b/include/linux/clk/tegra.h @@ -128,5 +128,6 @@ extern void tegra210_sata_pll_hw_sequence_start(void); extern void tegra210_set_sata_pll_seq_sw(bool state); extern void tegra210_put_utmipll_in_iddq(void); extern void tegra210_put_utmipll_out_iddq(void); +extern int tegra210_clk_handle_mbist_war(unsigned int id); #endif /* __LINUX_CLK_TEGRA_H_ */ -- cgit From 605add0c7bbf5ecb9eeef02c605e47dfd2980acb Mon Sep 17 00:00:00 2001 From: Gabriel Fernandez Date: Thu, 8 Mar 2018 17:53:54 +0100 Subject: dt-bindings: Document STM32MP1 Reset Clock Controller (RCC) bindings The RCC block is responsible of the management of the clock and reset generation for the complete circuit. Signed-off-by: Gabriel Fernandez Reviewed-by: Rob Herring Signed-off-by: Michael Turquette --- .../devicetree/bindings/clock/st,stm32mp1-rcc.txt | 60 ++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/st,stm32mp1-rcc.txt diff --git a/Documentation/devicetree/bindings/clock/st,stm32mp1-rcc.txt b/Documentation/devicetree/bindings/clock/st,stm32mp1-rcc.txt new file mode 100644 index 000000000000..fb9495ea582c --- /dev/null +++ b/Documentation/devicetree/bindings/clock/st,stm32mp1-rcc.txt @@ -0,0 +1,60 @@ +STMicroelectronics STM32 Peripheral Reset Clock Controller +========================================================== + +The RCC IP is both a reset and a clock controller. + +RCC makes also power management (resume/supend and wakeup interrupt). + +Please also refer to reset.txt for common reset controller binding usage. + +Please also refer to clock-bindings.txt for common clock controller +binding usage. + + +Required properties: +- compatible: "st,stm32mp1-rcc", "syscon" +- reg: should be register base and length as documented in the datasheet +- #clock-cells: 1, device nodes should specify the clock in their + "clocks" property, containing a phandle to the clock device node, + an index specifying the clock to use. +- #reset-cells: Shall be 1 +- interrupts: Should contain a general interrupt line and a interrupt line + to the wake-up of processor (CSTOP). + +Example: + rcc: rcc@50000000 { + compatible = "st,stm32mp1-rcc", "syscon"; + reg = <0x50000000 0x1000>; + #clock-cells = <1>; + #reset-cells = <1>; + interrupts = , + ; + }; + +Specifying clocks +================= + +All available clocks are defined as preprocessor macros in +dt-bindings/clock/stm32mp1-clks.h header and can be used in device +tree sources. + +Specifying softreset control of devices +======================================= + +Device nodes should specify the reset channel required in their "resets" +property, containing a phandle to the reset device node and an index specifying +which channel to use. +The index is the bit number within the RCC registers bank, starting from RCC +base address. +It is calculated as: index = register_offset / 4 * 32 + bit_offset. +Where bit_offset is the bit offset within the register. + +For example on STM32MP1, for LTDC reset: + ltdc = APB4_RSTSETR_offset / 4 * 32 + LTDC_bit_offset + = 0x180 / 4 * 32 + 0 = 3072 + +The list of valid indices for STM32MP1 is available in: +include/dt-bindings/reset-controller/stm32mp1-resets.h + +This file implements defines like: +#define LTDC_R 3072 -- cgit From 9bee94e7b7dac0bb049c488b8eaa9a48854ddb8f Mon Sep 17 00:00:00 2001 From: Gabriel Fernandez Date: Thu, 8 Mar 2018 17:53:55 +0100 Subject: clk: stm32mp1: Introduce STM32MP1 clock driver This patch introduces the mechanism to probe stm32mp1 driver. It also defines registers definition. This patch also introduces the generic mechanism to register a clock (a simple gate, divider and fixed factor). All clocks will be defined in one table. Signed-off-by: Gabriel Fernandez Signed-off-by: Michael Turquette --- drivers/clk/Kconfig | 6 + drivers/clk/Makefile | 1 + drivers/clk/clk-stm32mp1.c | 364 ++++++++++++++++++++++++++++++ include/dt-bindings/clock/stm32mp1-clks.h | 254 +++++++++++++++++++++ 4 files changed, 625 insertions(+) create mode 100644 drivers/clk/clk-stm32mp1.c create mode 100644 include/dt-bindings/clock/stm32mp1-clks.h diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index 98ce9fc6e6c0..cbb9b0c05442 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -238,6 +238,12 @@ config COMMON_CLK_VC5 This driver supports the IDT VersaClock 5 and VersaClock 6 programmable clock generators. +config COMMON_CLK_STM32MP157 + def_bool COMMON_CLK && MACH_STM32MP157 + help + ---help--- + Support for stm32mp157 SoC family clocks + source "drivers/clk/bcm/Kconfig" source "drivers/clk/hisilicon/Kconfig" source "drivers/clk/imgtec/Kconfig" diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 71ec41e6364f..8d812c701aa6 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -47,6 +47,7 @@ obj-$(CONFIG_COMMON_CLK_SI514) += clk-si514.o obj-$(CONFIG_COMMON_CLK_SI570) += clk-si570.o obj-$(CONFIG_ARCH_STM32) += clk-stm32f4.o obj-$(CONFIG_ARCH_STM32) += clk-stm32h7.o +obj-$(CONFIG_COMMON_CLK_STM32MP157) += clk-stm32mp1.o obj-$(CONFIG_ARCH_TANGO) += clk-tango4.o obj-$(CONFIG_CLK_TWL6040) += clk-twl6040.o obj-$(CONFIG_ARCH_U300) += clk-u300.o diff --git a/drivers/clk/clk-stm32mp1.c b/drivers/clk/clk-stm32mp1.c new file mode 100644 index 000000000000..6261a92bbdc0 --- /dev/null +++ b/drivers/clk/clk-stm32mp1.c @@ -0,0 +1,364 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) STMicroelectronics 2018 - All Rights Reserved + * Author: Olivier Bideau for STMicroelectronics. + * Author: Gabriel Fernandez for STMicroelectronics. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +static DEFINE_SPINLOCK(rlock); + +#define RCC_OCENSETR 0x0C +#define RCC_HSICFGR 0x18 +#define RCC_RDLSICR 0x144 +#define RCC_PLL1CR 0x80 +#define RCC_PLL1CFGR1 0x84 +#define RCC_PLL1CFGR2 0x88 +#define RCC_PLL2CR 0x94 +#define RCC_PLL2CFGR1 0x98 +#define RCC_PLL2CFGR2 0x9C +#define RCC_PLL3CR 0x880 +#define RCC_PLL3CFGR1 0x884 +#define RCC_PLL3CFGR2 0x888 +#define RCC_PLL4CR 0x894 +#define RCC_PLL4CFGR1 0x898 +#define RCC_PLL4CFGR2 0x89C +#define RCC_APB1ENSETR 0xA00 +#define RCC_APB2ENSETR 0xA08 +#define RCC_APB3ENSETR 0xA10 +#define RCC_APB4ENSETR 0x200 +#define RCC_APB5ENSETR 0x208 +#define RCC_AHB2ENSETR 0xA18 +#define RCC_AHB3ENSETR 0xA20 +#define RCC_AHB4ENSETR 0xA28 +#define RCC_AHB5ENSETR 0x210 +#define RCC_AHB6ENSETR 0x218 +#define RCC_AHB6LPENSETR 0x318 +#define RCC_RCK12SELR 0x28 +#define RCC_RCK3SELR 0x820 +#define RCC_RCK4SELR 0x824 +#define RCC_MPCKSELR 0x20 +#define RCC_ASSCKSELR 0x24 +#define RCC_MSSCKSELR 0x48 +#define RCC_SPI6CKSELR 0xC4 +#define RCC_SDMMC12CKSELR 0x8F4 +#define RCC_SDMMC3CKSELR 0x8F8 +#define RCC_FMCCKSELR 0x904 +#define RCC_I2C46CKSELR 0xC0 +#define RCC_I2C12CKSELR 0x8C0 +#define RCC_I2C35CKSELR 0x8C4 +#define RCC_UART1CKSELR 0xC8 +#define RCC_QSPICKSELR 0x900 +#define RCC_ETHCKSELR 0x8FC +#define RCC_RNG1CKSELR 0xCC +#define RCC_RNG2CKSELR 0x920 +#define RCC_GPUCKSELR 0x938 +#define RCC_USBCKSELR 0x91C +#define RCC_STGENCKSELR 0xD4 +#define RCC_SPDIFCKSELR 0x914 +#define RCC_SPI2S1CKSELR 0x8D8 +#define RCC_SPI2S23CKSELR 0x8DC +#define RCC_SPI2S45CKSELR 0x8E0 +#define RCC_CECCKSELR 0x918 +#define RCC_LPTIM1CKSELR 0x934 +#define RCC_LPTIM23CKSELR 0x930 +#define RCC_LPTIM45CKSELR 0x92C +#define RCC_UART24CKSELR 0x8E8 +#define RCC_UART35CKSELR 0x8EC +#define RCC_UART6CKSELR 0x8E4 +#define RCC_UART78CKSELR 0x8F0 +#define RCC_FDCANCKSELR 0x90C +#define RCC_SAI1CKSELR 0x8C8 +#define RCC_SAI2CKSELR 0x8CC +#define RCC_SAI3CKSELR 0x8D0 +#define RCC_SAI4CKSELR 0x8D4 +#define RCC_ADCCKSELR 0x928 +#define RCC_MPCKDIVR 0x2C +#define RCC_DSICKSELR 0x924 +#define RCC_CPERCKSELR 0xD0 +#define RCC_MCO1CFGR 0x800 +#define RCC_MCO2CFGR 0x804 +#define RCC_BDCR 0x140 +#define RCC_AXIDIVR 0x30 +#define RCC_MCUDIVR 0x830 +#define RCC_APB1DIVR 0x834 +#define RCC_APB2DIVR 0x838 +#define RCC_APB3DIVR 0x83C +#define RCC_APB4DIVR 0x3C +#define RCC_APB5DIVR 0x40 +#define RCC_TIMG1PRER 0x828 +#define RCC_TIMG2PRER 0x82C +#define RCC_RTCDIVR 0x44 +#define RCC_DBGCFGR 0x80C + +#define RCC_CLR 0x4 + +struct clock_config { + u32 id; + const char *name; + union { + const char *parent_name; + const char * const *parent_names; + }; + int num_parents; + unsigned long flags; + void *cfg; + struct clk_hw * (*func)(struct device *dev, + struct clk_hw_onecell_data *clk_data, + void __iomem *base, spinlock_t *lock, + const struct clock_config *cfg); +}; + +#define NO_ID ~0 + +struct gate_cfg { + u32 reg_off; + u8 bit_idx; + u8 gate_flags; +}; + +struct fixed_factor_cfg { + unsigned int mult; + unsigned int div; +}; + +struct div_cfg { + u32 reg_off; + u8 shift; + u8 width; + u8 div_flags; + const struct clk_div_table *table; +}; + +static struct clk_hw * +_clk_hw_register_gate(struct device *dev, + struct clk_hw_onecell_data *clk_data, + void __iomem *base, spinlock_t *lock, + const struct clock_config *cfg) +{ + struct gate_cfg *gate_cfg = cfg->cfg; + + return clk_hw_register_gate(dev, + cfg->name, + cfg->parent_name, + cfg->flags, + gate_cfg->reg_off + base, + gate_cfg->bit_idx, + gate_cfg->gate_flags, + lock); +} + +static struct clk_hw * +_clk_hw_register_fixed_factor(struct device *dev, + struct clk_hw_onecell_data *clk_data, + void __iomem *base, spinlock_t *lock, + const struct clock_config *cfg) +{ + struct fixed_factor_cfg *ff_cfg = cfg->cfg; + + return clk_hw_register_fixed_factor(dev, cfg->name, cfg->parent_name, + cfg->flags, ff_cfg->mult, + ff_cfg->div); +} + +static struct clk_hw * +_clk_hw_register_divider_table(struct device *dev, + struct clk_hw_onecell_data *clk_data, + void __iomem *base, spinlock_t *lock, + const struct clock_config *cfg) +{ + struct div_cfg *div_cfg = cfg->cfg; + + return clk_hw_register_divider_table(dev, + cfg->name, + cfg->parent_name, + cfg->flags, + div_cfg->reg_off + base, + div_cfg->shift, + div_cfg->width, + div_cfg->div_flags, + div_cfg->table, + lock); +} + +#define GATE(_id, _name, _parent, _flags, _offset, _bit_idx, _gate_flags)\ +{\ + .id = _id,\ + .name = _name,\ + .parent_name = _parent,\ + .flags = _flags,\ + .cfg = &(struct gate_cfg) {\ + .reg_off = _offset,\ + .bit_idx = _bit_idx,\ + .gate_flags = _gate_flags,\ + },\ + .func = _clk_hw_register_gate,\ +} + +#define FIXED_FACTOR(_id, _name, _parent, _flags, _mult, _div)\ +{\ + .id = _id,\ + .name = _name,\ + .parent_name = _parent,\ + .flags = _flags,\ + .cfg = &(struct fixed_factor_cfg) {\ + .mult = _mult,\ + .div = _div,\ + },\ + .func = _clk_hw_register_fixed_factor,\ +} + +#define DIV_TABLE(_id, _name, _parent, _flags, _offset, _shift, _width,\ + _div_flags, _div_table)\ +{\ + .id = _id,\ + .name = _name,\ + .parent_name = _parent,\ + .flags = _flags,\ + .cfg = &(struct div_cfg) {\ + .reg_off = _offset,\ + .shift = _shift,\ + .width = _width,\ + .div_flags = _div_flags,\ + .table = _div_table,\ + },\ + .func = _clk_hw_register_divider_table,\ +} + +#define DIV(_id, _name, _parent, _flags, _offset, _shift, _width, _div_flags)\ + DIV_TABLE(_id, _name, _parent, _flags, _offset, _shift, _width,\ + _div_flags, NULL) + +static const struct clock_config stm32mp1_clock_cfg[] = { + /* Oscillator divider */ + DIV(NO_ID, "clk-hsi-div", "clk-hsi", 0, RCC_HSICFGR, 0, 2, + CLK_DIVIDER_READ_ONLY), + + /* External / Internal Oscillators */ + GATE(CK_LSI, "ck_lsi", "clk-lsi", 0, RCC_RDLSICR, 0, 0), + GATE(CK_LSE, "ck_lse", "clk-lse", 0, RCC_BDCR, 0, 0), + + FIXED_FACTOR(CK_HSE_DIV2, "clk-hse-div2", "ck_hse", 0, 1, 2), +}; + +struct stm32_clock_match_data { + const struct clock_config *cfg; + unsigned int num; + unsigned int maxbinding; +}; + +static struct stm32_clock_match_data stm32mp1_data = { + .cfg = stm32mp1_clock_cfg, + .num = ARRAY_SIZE(stm32mp1_clock_cfg), + .maxbinding = STM32MP1_LAST_CLK, +}; + +static const struct of_device_id stm32mp1_match_data[] = { + { + .compatible = "st,stm32mp1-rcc", + .data = &stm32mp1_data, + }, + { } +}; + +static int stm32_register_hw_clk(struct device *dev, + struct clk_hw_onecell_data *clk_data, + void __iomem *base, spinlock_t *lock, + const struct clock_config *cfg) +{ + static struct clk_hw **hws; + struct clk_hw *hw = ERR_PTR(-ENOENT); + + hws = clk_data->hws; + + if (cfg->func) + hw = (*cfg->func)(dev, clk_data, base, lock, cfg); + + if (IS_ERR(hw)) { + pr_err("Unable to register %s\n", cfg->name); + return PTR_ERR(hw); + } + + if (cfg->id != NO_ID) + hws[cfg->id] = hw; + + return 0; +} + +static int stm32_rcc_init(struct device_node *np, + void __iomem *base, + const struct of_device_id *match_data) +{ + struct clk_hw_onecell_data *clk_data; + struct clk_hw **hws; + const struct of_device_id *match; + const struct stm32_clock_match_data *data; + int err, n, max_binding; + + match = of_match_node(match_data, np); + if (!match) { + pr_err("%s: match data not found\n", __func__); + return -ENODEV; + } + + data = match->data; + + max_binding = data->maxbinding; + + clk_data = kzalloc(sizeof(*clk_data) + + sizeof(*clk_data->hws) * max_binding, + GFP_KERNEL); + if (!clk_data) + return -ENOMEM; + + clk_data->num = max_binding; + + hws = clk_data->hws; + + for (n = 0; n < max_binding; n++) + hws[n] = ERR_PTR(-ENOENT); + + for (n = 0; n < data->num; n++) { + err = stm32_register_hw_clk(NULL, clk_data, base, &rlock, + &data->cfg[n]); + if (err) { + pr_err("%s: can't register %s\n", __func__, + data->cfg[n].name); + + kfree(clk_data); + + return err; + } + } + + return of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_data); +} + +static void stm32mp1_rcc_init(struct device_node *np) +{ + void __iomem *base; + + base = of_iomap(np, 0); + if (!base) { + pr_err("%s: unable to map resource", np->name); + of_node_put(np); + return; + } + + if (stm32_rcc_init(np, base, stm32mp1_match_data)) { + iounmap(base); + of_node_put(np); + } +} + +CLK_OF_DECLARE_DRIVER(stm32mp1_rcc, "st,stm32mp1-rcc", stm32mp1_rcc_init); diff --git a/include/dt-bindings/clock/stm32mp1-clks.h b/include/dt-bindings/clock/stm32mp1-clks.h new file mode 100644 index 000000000000..86e3ec662ef4 --- /dev/null +++ b/include/dt-bindings/clock/stm32mp1-clks.h @@ -0,0 +1,254 @@ +/* SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause */ +/* + * Copyright (C) STMicroelectronics 2018 - All Rights Reserved + * Author: Gabriel Fernandez for STMicroelectronics. + */ + +#ifndef _DT_BINDINGS_STM32MP1_CLKS_H_ +#define _DT_BINDINGS_STM32MP1_CLKS_H_ + +/* OSCILLATOR clocks */ +#define CK_HSE 0 +#define CK_CSI 1 +#define CK_LSI 2 +#define CK_LSE 3 +#define CK_HSI 4 +#define CK_HSE_DIV2 5 + +/* Bus clocks */ +#define TIM2 6 +#define TIM3 7 +#define TIM4 8 +#define TIM5 9 +#define TIM6 10 +#define TIM7 11 +#define TIM12 12 +#define TIM13 13 +#define TIM14 14 +#define LPTIM1 15 +#define SPI2 16 +#define SPI3 17 +#define USART2 18 +#define USART3 19 +#define UART4 20 +#define UART5 21 +#define UART7 22 +#define UART8 23 +#define I2C1 24 +#define I2C2 25 +#define I2C3 26 +#define I2C5 27 +#define SPDIF 28 +#define CEC 29 +#define DAC12 30 +#define MDIO 31 +#define TIM1 32 +#define TIM8 33 +#define TIM15 34 +#define TIM16 35 +#define TIM17 36 +#define SPI1 37 +#define SPI4 38 +#define SPI5 39 +#define USART6 40 +#define SAI1 41 +#define SAI2 42 +#define SAI3 43 +#define DFSDM 44 +#define FDCAN 45 +#define LPTIM2 46 +#define LPTIM3 47 +#define LPTIM4 48 +#define LPTIM5 49 +#define SAI4 50 +#define SYSCFG 51 +#define VREF 52 +#define TMPSENS 53 +#define PMBCTRL 54 +#define HDP 55 +#define LTDC 56 +#define DSI 57 +#define IWDG2 58 +#define USBPHY 59 +#define STGENRO 60 +#define SPI6 61 +#define I2C4 62 +#define I2C6 63 +#define USART1 64 +#define RTCAPB 65 +#define TZC 66 +#define TZPC 67 +#define IWDG1 68 +#define BSEC 69 +#define STGEN 70 +#define DMA1 71 +#define DMA2 72 +#define DMAMUX 73 +#define ADC12 74 +#define USBO 75 +#define SDMMC3 76 +#define DCMI 77 +#define CRYP2 78 +#define HASH2 79 +#define RNG2 80 +#define CRC2 81 +#define HSEM 82 +#define IPCC 83 +#define GPIOA 84 +#define GPIOB 85 +#define GPIOC 86 +#define GPIOD 87 +#define GPIOE 88 +#define GPIOF 89 +#define GPIOG 90 +#define GPIOH 91 +#define GPIOI 92 +#define GPIOJ 93 +#define GPIOK 94 +#define GPIOZ 95 +#define CRYP1 96 +#define HASH1 97 +#define RNG1 98 +#define BKPSRAM 99 +#define MDMA 100 +#define GPU 101 +#define ETHCK 102 +#define ETHTX 103 +#define ETHRX 104 +#define ETHMAC 105 +#define FMC 106 +#define QSPI 107 +#define SDMMC1 108 +#define SDMMC2 109 +#define CRC1 110 +#define USBH 111 +#define ETHSTP 112 + +/* Kernel clocks */ +#define SDMMC1_K 118 +#define SDMMC2_K 119 +#define SDMMC3_K 120 +#define FMC_K 121 +#define QSPI_K 122 +#define ETHCK_K 123 +#define RNG1_K 124 +#define RNG2_K 125 +#define GPU_K 126 +#define USBPHY_K 127 +#define STGEN_K 128 +#define SPDIF_K 129 +#define SPI1_K 130 +#define SPI2_K 131 +#define SPI3_K 132 +#define SPI4_K 133 +#define SPI5_K 134 +#define SPI6_K 135 +#define CEC_K 136 +#define I2C1_K 137 +#define I2C2_K 138 +#define I2C3_K 139 +#define I2C4_K 140 +#define I2C5_K 141 +#define I2C6_K 142 +#define LPTIM1_K 143 +#define LPTIM2_K 144 +#define LPTIM3_K 145 +#define LPTIM4_K 146 +#define LPTIM5_K 147 +#define USART1_K 148 +#define USART2_K 149 +#define USART3_K 150 +#define UART4_K 151 +#define UART5_K 152 +#define USART6_K 153 +#define UART7_K 154 +#define UART8_K 155 +#define DFSDM_K 156 +#define FDCAN_K 157 +#define SAI1_K 158 +#define SAI2_K 159 +#define SAI3_K 160 +#define SAI4_K 161 +#define ADC12_K 162 +#define DSI_K 163 +#define DSI_PX 164 +#define ADFSDM_K 165 +#define USBO_K 166 +#define LTDC_PX 167 +#define DAC12_K 168 +#define ETHPTP_K 169 + +/* PLL */ +#define PLL1 176 +#define PLL2 177 +#define PLL3 178 +#define PLL4 179 + +/* ODF */ +#define PLL1_P 180 +#define PLL1_Q 181 +#define PLL1_R 182 +#define PLL2_P 183 +#define PLL2_Q 184 +#define PLL2_R 185 +#define PLL3_P 186 +#define PLL3_Q 187 +#define PLL3_R 188 +#define PLL4_P 189 +#define PLL4_Q 190 +#define PLL4_R 191 + +/* AUX */ +#define RTC 192 + +/* MCLK */ +#define CK_PER 193 +#define CK_MPU 194 +#define CK_AXI 195 +#define CK_MCU 196 + +/* Time base */ +#define TIM2_K 197 +#define TIM3_K 198 +#define TIM4_K 199 +#define TIM5_K 200 +#define TIM6_K 201 +#define TIM7_K 202 +#define TIM12_K 203 +#define TIM13_K 204 +#define TIM14_K 205 +#define TIM1_K 206 +#define TIM8_K 207 +#define TIM15_K 208 +#define TIM16_K 209 +#define TIM17_K 210 + +/* MCO clocks */ +#define CK_MCO1 211 +#define CK_MCO2 212 + +/* TRACE & DEBUG clocks */ +#define DBG 213 +#define CK_DBG 214 +#define CK_TRACE 215 + +/* DDR */ +#define DDRC1 220 +#define DDRC1LP 221 +#define DDRC2 222 +#define DDRC2LP 223 +#define DDRPHYC 224 +#define DDRPHYCLP 225 +#define DDRCAPB 226 +#define DDRCAPBLP 227 +#define AXIDCG 228 +#define DDRPHYCAPB 229 +#define DDRPHYCAPBLP 230 +#define DDRPERFM 231 + +#define STM32MP1_LAST_CLK 232 + +#define LTDC_K LTDC_PX +#define ETHMAC_K ETHCK_K + +#endif /* _DT_BINDINGS_STM32MP1_CLKS_H_ */ -- cgit From 8e6c27c0d79ae42f845892206a47c42531e14141 Mon Sep 17 00:00:00 2001 From: Gabriel Fernandez Date: Thu, 8 Mar 2018 17:53:56 +0100 Subject: clk: stm32mp1: add MP1 gate for hse/hsi/csi oscillators MP1 Gate is a gate with a set and a clear register. Signed-off-by: Gabriel Fernandez Signed-off-by: Michael Turquette --- drivers/clk/clk-stm32mp1.c | 143 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 143 insertions(+) diff --git a/drivers/clk/clk-stm32mp1.c b/drivers/clk/clk-stm32mp1.c index 6261a92bbdc0..56b738ee660b 100644 --- a/drivers/clk/clk-stm32mp1.c +++ b/drivers/clk/clk-stm32mp1.c @@ -140,6 +140,11 @@ struct div_cfg { const struct clk_div_table *table; }; +struct stm32_gate_cfg { + struct gate_cfg *gate; + const struct clk_ops *ops; +}; + static struct clk_hw * _clk_hw_register_gate(struct device *dev, struct clk_hw_onecell_data *clk_data, @@ -191,6 +196,112 @@ _clk_hw_register_divider_table(struct device *dev, lock); } +/* MP1 Gate clock with set & clear registers */ + +static int mp1_gate_clk_enable(struct clk_hw *hw) +{ + if (!clk_gate_ops.is_enabled(hw)) + clk_gate_ops.enable(hw); + + return 0; +} + +static void mp1_gate_clk_disable(struct clk_hw *hw) +{ + struct clk_gate *gate = to_clk_gate(hw); + unsigned long flags = 0; + + if (clk_gate_ops.is_enabled(hw)) { + spin_lock_irqsave(gate->lock, flags); + writel_relaxed(BIT(gate->bit_idx), gate->reg + RCC_CLR); + spin_unlock_irqrestore(gate->lock, flags); + } +} + +const struct clk_ops mp1_gate_clk_ops = { + .enable = mp1_gate_clk_enable, + .disable = mp1_gate_clk_disable, + .is_enabled = clk_gate_is_enabled, +}; + +static struct clk_hw * +_get_stm32_gate(void __iomem *base, + const struct stm32_gate_cfg *cfg, spinlock_t *lock) +{ + struct clk_gate *gate; + struct clk_hw *gate_hw; + + gate = kzalloc(sizeof(*gate), GFP_KERNEL); + if (!gate) + return ERR_PTR(-ENOMEM); + + gate->reg = cfg->gate->reg_off + base; + gate->bit_idx = cfg->gate->bit_idx; + gate->flags = cfg->gate->gate_flags; + gate->lock = lock; + gate_hw = &gate->hw; + + return gate_hw; +} + +static struct clk_hw * +clk_stm32_register_gate_ops(struct device *dev, + const char *name, + const char *parent_name, + unsigned long flags, + void __iomem *base, + const struct stm32_gate_cfg *cfg, + spinlock_t *lock) +{ + struct clk_init_data init = { NULL }; + struct clk_gate *gate; + struct clk_hw *hw; + int ret; + + gate = kzalloc(sizeof(*gate), GFP_KERNEL); + if (!gate) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.parent_names = &parent_name; + init.num_parents = 1; + init.flags = flags; + + init.ops = &clk_gate_ops; + + if (cfg->ops) + init.ops = cfg->ops; + + hw = _get_stm32_gate(base, cfg, lock); + if (IS_ERR(hw)) + return ERR_PTR(-ENOMEM); + + hw->init = &init; + + ret = clk_hw_register(dev, hw); + if (ret) { + kfree(gate); + hw = ERR_PTR(ret); + } + + return hw; +} + +static struct clk_hw * +_clk_stm32_register_gate(struct device *dev, + struct clk_hw_onecell_data *clk_data, + void __iomem *base, spinlock_t *lock, + const struct clock_config *cfg) +{ + return clk_stm32_register_gate_ops(dev, + cfg->name, + cfg->parent_name, + cfg->flags, + base, + cfg->cfg, + lock); +} + #define GATE(_id, _name, _parent, _flags, _offset, _bit_idx, _gate_flags)\ {\ .id = _id,\ @@ -239,12 +350,44 @@ _clk_hw_register_divider_table(struct device *dev, DIV_TABLE(_id, _name, _parent, _flags, _offset, _shift, _width,\ _div_flags, NULL) +/* STM32 GATE */ +#define STM32_GATE(_id, _name, _parent, _flags, _gate)\ +{\ + .id = _id,\ + .name = _name,\ + .parent_name = _parent,\ + .flags = _flags,\ + .cfg = (struct stm32_gate_cfg *) {_gate},\ + .func = _clk_stm32_register_gate,\ +} + +#define _STM32_GATE(_gate_offset, _gate_bit_idx, _gate_flags, _ops)\ + (&(struct stm32_gate_cfg) {\ + &(struct gate_cfg) {\ + .reg_off = _gate_offset,\ + .bit_idx = _gate_bit_idx,\ + .gate_flags = _gate_flags,\ + },\ + .ops = _ops,\ + }) + +#define _GATE_MP1(_gate_offset, _gate_bit_idx, _gate_flags)\ + _STM32_GATE(_gate_offset, _gate_bit_idx, _gate_flags,\ + &mp1_gate_clk_ops)\ + +#define GATE_MP1(_id, _name, _parent, _flags, _offset, _bit_idx, _gate_flags)\ + STM32_GATE(_id, _name, _parent, _flags,\ + _GATE_MP1(_offset, _bit_idx, _gate_flags)) + static const struct clock_config stm32mp1_clock_cfg[] = { /* Oscillator divider */ DIV(NO_ID, "clk-hsi-div", "clk-hsi", 0, RCC_HSICFGR, 0, 2, CLK_DIVIDER_READ_ONLY), /* External / Internal Oscillators */ + GATE_MP1(CK_HSE, "ck_hse", "clk-hse", 0, RCC_OCENSETR, 8, 0), + GATE_MP1(CK_CSI, "ck_csi", "clk-csi", 0, RCC_OCENSETR, 4, 0), + GATE_MP1(CK_HSI, "ck_hsi", "clk-hsi-div", 0, RCC_OCENSETR, 0, 0), GATE(CK_LSI, "ck_lsi", "clk-lsi", 0, RCC_RDLSICR, 0, 0), GATE(CK_LSE, "ck_lse", "clk-lse", 0, RCC_BDCR, 0, 0), -- cgit From dc32eaac4926b02fddba3ff02030827429394ad7 Mon Sep 17 00:00:00 2001 From: Gabriel Fernandez Date: Thu, 8 Mar 2018 17:53:57 +0100 Subject: clk: stm32mp1: add Source Clocks for PLLs This patch adds source clocks for PLLs This patch also introduces MUX clock API. Signed-off-by: Gabriel Fernandez Signed-off-by: Michael Turquette --- drivers/clk/clk-stm32mp1.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/drivers/clk/clk-stm32mp1.c b/drivers/clk/clk-stm32mp1.c index 56b738ee660b..47984f36494b 100644 --- a/drivers/clk/clk-stm32mp1.c +++ b/drivers/clk/clk-stm32mp1.c @@ -103,6 +103,18 @@ static DEFINE_SPINLOCK(rlock); #define RCC_CLR 0x4 +static const char * const ref12_parents[] = { + "ck_hsi", "ck_hse" +}; + +static const char * const ref3_parents[] = { + "ck_hsi", "ck_hse", "ck_csi" +}; + +static const char * const ref4_parents[] = { + "ck_hsi", "ck_hse", "ck_csi" +}; + struct clock_config { u32 id; const char *name; @@ -140,6 +152,14 @@ struct div_cfg { const struct clk_div_table *table; }; +struct mux_cfg { + u32 reg_off; + u8 shift; + u8 width; + u8 mux_flags; + u32 *table; +}; + struct stm32_gate_cfg { struct gate_cfg *gate; const struct clk_ops *ops; @@ -196,6 +216,20 @@ _clk_hw_register_divider_table(struct device *dev, lock); } +static struct clk_hw * +_clk_hw_register_mux(struct device *dev, + struct clk_hw_onecell_data *clk_data, + void __iomem *base, spinlock_t *lock, + const struct clock_config *cfg) +{ + struct mux_cfg *mux_cfg = cfg->cfg; + + return clk_hw_register_mux(dev, cfg->name, cfg->parent_names, + cfg->num_parents, cfg->flags, + mux_cfg->reg_off + base, mux_cfg->shift, + mux_cfg->width, mux_cfg->mux_flags, lock); +} + /* MP1 Gate clock with set & clear registers */ static int mp1_gate_clk_enable(struct clk_hw *hw) @@ -350,6 +384,22 @@ _clk_stm32_register_gate(struct device *dev, DIV_TABLE(_id, _name, _parent, _flags, _offset, _shift, _width,\ _div_flags, NULL) +#define MUX(_id, _name, _parents, _flags, _offset, _shift, _width, _mux_flags)\ +{\ + .id = _id,\ + .name = _name,\ + .parent_names = _parents,\ + .num_parents = ARRAY_SIZE(_parents),\ + .flags = _flags,\ + .cfg = &(struct mux_cfg) {\ + .reg_off = _offset,\ + .shift = _shift,\ + .width = _width,\ + .mux_flags = _mux_flags,\ + },\ + .func = _clk_hw_register_mux,\ +} + /* STM32 GATE */ #define STM32_GATE(_id, _name, _parent, _flags, _gate)\ {\ @@ -392,6 +442,16 @@ static const struct clock_config stm32mp1_clock_cfg[] = { GATE(CK_LSE, "ck_lse", "clk-lse", 0, RCC_BDCR, 0, 0), FIXED_FACTOR(CK_HSE_DIV2, "clk-hse-div2", "ck_hse", 0, 1, 2), + + /* ref clock pll */ + MUX(NO_ID, "ref1", ref12_parents, CLK_OPS_PARENT_ENABLE, RCC_RCK12SELR, + 0, 2, CLK_MUX_READ_ONLY), + + MUX(NO_ID, "ref3", ref3_parents, CLK_OPS_PARENT_ENABLE, RCC_RCK3SELR, + 0, 2, CLK_MUX_READ_ONLY), + + MUX(NO_ID, "ref4", ref4_parents, CLK_OPS_PARENT_ENABLE, RCC_RCK4SELR, + 0, 2, CLK_MUX_READ_ONLY), }; struct stm32_clock_match_data { -- cgit From c6cf4d3248980c5e1998ce21f3c2d86502f7e1a9 Mon Sep 17 00:00:00 2001 From: Gabriel Fernandez Date: Thu, 8 Mar 2018 17:53:58 +0100 Subject: clk: stm32mp1: add PLL clocks STMP32MP1 has 4 PLLs. PLL supports integer and fractional mode. Each PLL has 3 output dividers (p, q, r) Signed-off-by: Gabriel Fernandez Signed-off-by: Michael Turquette --- drivers/clk/clk-stm32mp1.c | 209 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 209 insertions(+) diff --git a/drivers/clk/clk-stm32mp1.c b/drivers/clk/clk-stm32mp1.c index 47984f36494b..d62a3a94cc67 100644 --- a/drivers/clk/clk-stm32mp1.c +++ b/drivers/clk/clk-stm32mp1.c @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -321,6 +322,196 @@ clk_stm32_register_gate_ops(struct device *dev, return hw; } +/* STM32 PLL */ + +struct stm32_pll_obj { + /* lock pll enable/disable registers */ + spinlock_t *lock; + void __iomem *reg; + struct clk_hw hw; +}; + +#define to_pll(_hw) container_of(_hw, struct stm32_pll_obj, hw) + +#define PLL_ON BIT(0) +#define PLL_RDY BIT(1) +#define DIVN_MASK 0x1FF +#define DIVM_MASK 0x3F +#define DIVM_SHIFT 16 +#define DIVN_SHIFT 0 +#define FRAC_OFFSET 0xC +#define FRAC_MASK 0x1FFF +#define FRAC_SHIFT 3 +#define FRACLE BIT(16) + +static int __pll_is_enabled(struct clk_hw *hw) +{ + struct stm32_pll_obj *clk_elem = to_pll(hw); + + return readl_relaxed(clk_elem->reg) & PLL_ON; +} + +#define TIMEOUT 5 + +static int pll_enable(struct clk_hw *hw) +{ + struct stm32_pll_obj *clk_elem = to_pll(hw); + u32 reg; + unsigned long flags = 0; + unsigned int timeout = TIMEOUT; + int bit_status = 0; + + spin_lock_irqsave(clk_elem->lock, flags); + + if (__pll_is_enabled(hw)) + goto unlock; + + reg = readl_relaxed(clk_elem->reg); + reg |= PLL_ON; + writel_relaxed(reg, clk_elem->reg); + + /* We can't use readl_poll_timeout() because we can be blocked if + * someone enables this clock before clocksource changes. + * Only jiffies counter is available. Jiffies are incremented by + * interruptions and enable op does not allow to be interrupted. + */ + do { + bit_status = !(readl_relaxed(clk_elem->reg) & PLL_RDY); + + if (bit_status) + udelay(120); + + } while (bit_status && --timeout); + +unlock: + spin_unlock_irqrestore(clk_elem->lock, flags); + + return bit_status; +} + +static void pll_disable(struct clk_hw *hw) +{ + struct stm32_pll_obj *clk_elem = to_pll(hw); + u32 reg; + unsigned long flags = 0; + + spin_lock_irqsave(clk_elem->lock, flags); + + reg = readl_relaxed(clk_elem->reg); + reg &= ~PLL_ON; + writel_relaxed(reg, clk_elem->reg); + + spin_unlock_irqrestore(clk_elem->lock, flags); +} + +static u32 pll_frac_val(struct clk_hw *hw) +{ + struct stm32_pll_obj *clk_elem = to_pll(hw); + u32 reg, frac = 0; + + reg = readl_relaxed(clk_elem->reg + FRAC_OFFSET); + if (reg & FRACLE) + frac = (reg >> FRAC_SHIFT) & FRAC_MASK; + + return frac; +} + +static unsigned long pll_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct stm32_pll_obj *clk_elem = to_pll(hw); + u32 reg; + u32 frac, divm, divn; + u64 rate, rate_frac = 0; + + reg = readl_relaxed(clk_elem->reg + 4); + + divm = ((reg >> DIVM_SHIFT) & DIVM_MASK) + 1; + divn = ((reg >> DIVN_SHIFT) & DIVN_MASK) + 1; + rate = (u64)parent_rate * divn; + + do_div(rate, divm); + + frac = pll_frac_val(hw); + if (frac) { + rate_frac = (u64)parent_rate * (u64)frac; + do_div(rate_frac, (divm * 8192)); + } + + return rate + rate_frac; +} + +static int pll_is_enabled(struct clk_hw *hw) +{ + struct stm32_pll_obj *clk_elem = to_pll(hw); + unsigned long flags = 0; + int ret; + + spin_lock_irqsave(clk_elem->lock, flags); + ret = __pll_is_enabled(hw); + spin_unlock_irqrestore(clk_elem->lock, flags); + + return ret; +} + +static const struct clk_ops pll_ops = { + .enable = pll_enable, + .disable = pll_disable, + .recalc_rate = pll_recalc_rate, + .is_enabled = pll_is_enabled, +}; + +static struct clk_hw *clk_register_pll(struct device *dev, const char *name, + const char *parent_name, + void __iomem *reg, + unsigned long flags, + spinlock_t *lock) +{ + struct stm32_pll_obj *element; + struct clk_init_data init; + struct clk_hw *hw; + int err; + + element = kzalloc(sizeof(*element), GFP_KERNEL); + if (!element) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.ops = &pll_ops; + init.flags = flags; + init.parent_names = &parent_name; + init.num_parents = 1; + + element->hw.init = &init; + element->reg = reg; + element->lock = lock; + + hw = &element->hw; + err = clk_hw_register(dev, hw); + + if (err) { + kfree(element); + return ERR_PTR(err); + } + + return hw; +} + +struct stm32_pll_cfg { + u32 offset; +}; + +struct clk_hw *_clk_register_pll(struct device *dev, + struct clk_hw_onecell_data *clk_data, + void __iomem *base, spinlock_t *lock, + const struct clock_config *cfg) +{ + struct stm32_pll_cfg *stm_pll_cfg = cfg->cfg; + + return clk_register_pll(dev, cfg->name, cfg->parent_name, + base + stm_pll_cfg->offset, cfg->flags, lock); +} + static struct clk_hw * _clk_stm32_register_gate(struct device *dev, struct clk_hw_onecell_data *clk_data, @@ -400,6 +591,18 @@ _clk_stm32_register_gate(struct device *dev, .func = _clk_hw_register_mux,\ } +#define PLL(_id, _name, _parent, _flags, _offset)\ +{\ + .id = _id,\ + .name = _name,\ + .parent_name = _parent,\ + .flags = _flags,\ + .cfg = &(struct stm32_pll_cfg) {\ + .offset = _offset,\ + },\ + .func = _clk_register_pll,\ +} + /* STM32 GATE */ #define STM32_GATE(_id, _name, _parent, _flags, _gate)\ {\ @@ -452,6 +655,12 @@ static const struct clock_config stm32mp1_clock_cfg[] = { MUX(NO_ID, "ref4", ref4_parents, CLK_OPS_PARENT_ENABLE, RCC_RCK4SELR, 0, 2, CLK_MUX_READ_ONLY), + + /* PLLs */ + PLL(PLL1, "pll1", "ref1", CLK_IGNORE_UNUSED, RCC_PLL1CR), + PLL(PLL2, "pll2", "ref1", CLK_IGNORE_UNUSED, RCC_PLL2CR), + PLL(PLL3, "pll3", "ref3", CLK_IGNORE_UNUSED, RCC_PLL3CR), + PLL(PLL4, "pll4", "ref4", CLK_IGNORE_UNUSED, RCC_PLL4CR), }; struct stm32_clock_match_data { -- cgit From a97703c59f653f75814865c22ae6b16f5c477530 Mon Sep 17 00:00:00 2001 From: Gabriel Fernandez Date: Thu, 8 Mar 2018 17:53:59 +0100 Subject: clk: stm32mp1: add Post-dividers for PLL Each PLL has 3 outputs with post-dividers. pll1_p is dedicated for Cortex-A7 pll1_q is not connected pll1_r is not connected pll2_p is dedicated for AXI pll2_q is dedicated for GPU pll2_r is dedicated for DDR pll3_p is dedicated for mcu pll3_q is for Peripheral Kernel Clock pll3_r is for Peripheral Kernel Clock pll4_p is for Peripheral Kernel Clock pll4_q is for Peripheral Kernel Clock pll4_r is for Peripheral Kernel Clock Signed-off-by: Gabriel Fernandez Signed-off-by: Michael Turquette --- drivers/clk/clk-stm32mp1.c | 221 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 221 insertions(+) diff --git a/drivers/clk/clk-stm32mp1.c b/drivers/clk/clk-stm32mp1.c index d62a3a94cc67..3a99ad7f7048 100644 --- a/drivers/clk/clk-stm32mp1.c +++ b/drivers/clk/clk-stm32mp1.c @@ -166,6 +166,23 @@ struct stm32_gate_cfg { const struct clk_ops *ops; }; +struct stm32_div_cfg { + struct div_cfg *div; + const struct clk_ops *ops; +}; + +struct stm32_mux_cfg { + struct mux_cfg *mux; + const struct clk_ops *ops; +}; + +/* STM32 Composite clock */ +struct stm32_composite_cfg { + const struct stm32_gate_cfg *gate; + const struct stm32_div_cfg *div; + const struct stm32_mux_cfg *mux; +}; + static struct clk_hw * _clk_hw_register_gate(struct device *dev, struct clk_hw_onecell_data *clk_data, @@ -259,6 +276,51 @@ const struct clk_ops mp1_gate_clk_ops = { .is_enabled = clk_gate_is_enabled, }; +static struct clk_hw *_get_stm32_mux(void __iomem *base, + const struct stm32_mux_cfg *cfg, + spinlock_t *lock) +{ + struct clk_mux *mux; + struct clk_hw *mux_hw; + + mux = kzalloc(sizeof(*mux), GFP_KERNEL); + if (!mux) + return ERR_PTR(-ENOMEM); + + mux->reg = cfg->mux->reg_off + base; + mux->shift = cfg->mux->shift; + mux->mask = (1 << cfg->mux->width) - 1; + mux->flags = cfg->mux->mux_flags; + mux->table = cfg->mux->table; + + mux->lock = lock; + + mux_hw = &mux->hw; + + return mux_hw; +} + +static struct clk_hw *_get_stm32_div(void __iomem *base, + const struct stm32_div_cfg *cfg, + spinlock_t *lock) +{ + struct clk_divider *div; + + div = kzalloc(sizeof(*div), GFP_KERNEL); + + if (!div) + return ERR_PTR(-ENOMEM); + + div->reg = cfg->div->reg_off + base; + div->shift = cfg->div->shift; + div->width = cfg->div->width; + div->flags = cfg->div->div_flags; + div->table = cfg->div->table; + div->lock = lock; + + return &div->hw; +} + static struct clk_hw * _get_stm32_gate(void __iomem *base, const struct stm32_gate_cfg *cfg, spinlock_t *lock) @@ -322,6 +384,61 @@ clk_stm32_register_gate_ops(struct device *dev, return hw; } +static struct clk_hw * +clk_stm32_register_composite(struct device *dev, + const char *name, const char * const *parent_names, + int num_parents, void __iomem *base, + const struct stm32_composite_cfg *cfg, + unsigned long flags, spinlock_t *lock) +{ + const struct clk_ops *mux_ops, *div_ops, *gate_ops; + struct clk_hw *mux_hw, *div_hw, *gate_hw; + + mux_hw = NULL; + div_hw = NULL; + gate_hw = NULL; + mux_ops = NULL; + div_ops = NULL; + gate_ops = NULL; + + if (cfg->mux) { + mux_hw = _get_stm32_mux(base, cfg->mux, lock); + + if (!IS_ERR(mux_hw)) { + mux_ops = &clk_mux_ops; + + if (cfg->mux->ops) + mux_ops = cfg->mux->ops; + } + } + + if (cfg->div) { + div_hw = _get_stm32_div(base, cfg->div, lock); + + if (!IS_ERR(div_hw)) { + div_ops = &clk_divider_ops; + + if (cfg->div->ops) + div_ops = cfg->div->ops; + } + } + + if (cfg->gate) { + gate_hw = _get_stm32_gate(base, cfg->gate, lock); + + if (!IS_ERR(gate_hw)) { + gate_ops = &clk_gate_ops; + + if (cfg->gate->ops) + gate_ops = cfg->gate->ops; + } + } + + return clk_hw_register_composite(dev, name, parent_names, num_parents, + mux_hw, mux_ops, div_hw, div_ops, + gate_hw, gate_ops, flags); +} + /* STM32 PLL */ struct stm32_pll_obj { @@ -527,6 +644,17 @@ _clk_stm32_register_gate(struct device *dev, lock); } +static struct clk_hw * +_clk_stm32_register_composite(struct device *dev, + struct clk_hw_onecell_data *clk_data, + void __iomem *base, spinlock_t *lock, + const struct clock_config *cfg) +{ + return clk_stm32_register_composite(dev, cfg->name, cfg->parent_names, + cfg->num_parents, base, cfg->cfg, + cfg->flags, lock); +} + #define GATE(_id, _name, _parent, _flags, _offset, _bit_idx, _gate_flags)\ {\ .id = _id,\ @@ -624,6 +752,10 @@ _clk_stm32_register_gate(struct device *dev, .ops = _ops,\ }) +#define _GATE(_gate_offset, _gate_bit_idx, _gate_flags)\ + _STM32_GATE(_gate_offset, _gate_bit_idx, _gate_flags,\ + NULL)\ + #define _GATE_MP1(_gate_offset, _gate_bit_idx, _gate_flags)\ _STM32_GATE(_gate_offset, _gate_bit_idx, _gate_flags,\ &mp1_gate_clk_ops)\ @@ -632,6 +764,44 @@ _clk_stm32_register_gate(struct device *dev, STM32_GATE(_id, _name, _parent, _flags,\ _GATE_MP1(_offset, _bit_idx, _gate_flags)) +#define _STM32_DIV(_div_offset, _div_shift, _div_width,\ + _div_flags, _div_table, _ops)\ + .div = &(struct stm32_div_cfg) {\ + &(struct div_cfg) {\ + .reg_off = _div_offset,\ + .shift = _div_shift,\ + .width = _div_width,\ + .div_flags = _div_flags,\ + .table = _div_table,\ + },\ + .ops = _ops,\ + } + +#define _DIV(_div_offset, _div_shift, _div_width, _div_flags, _div_table)\ + _STM32_DIV(_div_offset, _div_shift, _div_width,\ + _div_flags, _div_table, NULL)\ + +#define PARENT(_parent) ((const char *[]) { _parent}) + +#define _NO_MUX .mux = NULL +#define _NO_DIV .div = NULL +#define _NO_GATE .gate = NULL + +#define COMPOSITE(_id, _name, _parents, _flags, _gate, _mux, _div)\ +{\ + .id = _id,\ + .name = _name,\ + .parent_names = _parents,\ + .num_parents = ARRAY_SIZE(_parents),\ + .flags = _flags,\ + .cfg = &(struct stm32_composite_cfg) {\ + _gate,\ + _mux,\ + _div,\ + },\ + .func = _clk_stm32_register_composite,\ +} + static const struct clock_config stm32mp1_clock_cfg[] = { /* Oscillator divider */ DIV(NO_ID, "clk-hsi-div", "clk-hsi", 0, RCC_HSICFGR, 0, 2, @@ -661,6 +831,57 @@ static const struct clock_config stm32mp1_clock_cfg[] = { PLL(PLL2, "pll2", "ref1", CLK_IGNORE_UNUSED, RCC_PLL2CR), PLL(PLL3, "pll3", "ref3", CLK_IGNORE_UNUSED, RCC_PLL3CR), PLL(PLL4, "pll4", "ref4", CLK_IGNORE_UNUSED, RCC_PLL4CR), + + /* ODF */ + COMPOSITE(PLL1_P, "pll1_p", PARENT("pll1"), 0, + _GATE(RCC_PLL1CR, 4, 0), + _NO_MUX, + _DIV(RCC_PLL1CFGR2, 0, 7, 0, NULL)), + + COMPOSITE(PLL2_P, "pll2_p", PARENT("pll2"), 0, + _GATE(RCC_PLL2CR, 4, 0), + _NO_MUX, + _DIV(RCC_PLL2CFGR2, 0, 7, 0, NULL)), + + COMPOSITE(PLL2_Q, "pll2_q", PARENT("pll2"), 0, + _GATE(RCC_PLL2CR, 5, 0), + _NO_MUX, + _DIV(RCC_PLL2CFGR2, 8, 7, 0, NULL)), + + COMPOSITE(PLL2_R, "pll2_r", PARENT("pll2"), CLK_IS_CRITICAL, + _GATE(RCC_PLL2CR, 6, 0), + _NO_MUX, + _DIV(RCC_PLL2CFGR2, 16, 7, 0, NULL)), + + COMPOSITE(PLL3_P, "pll3_p", PARENT("pll3"), 0, + _GATE(RCC_PLL3CR, 4, 0), + _NO_MUX, + _DIV(RCC_PLL3CFGR2, 0, 7, 0, NULL)), + + COMPOSITE(PLL3_Q, "pll3_q", PARENT("pll3"), 0, + _GATE(RCC_PLL3CR, 5, 0), + _NO_MUX, + _DIV(RCC_PLL3CFGR2, 8, 7, 0, NULL)), + + COMPOSITE(PLL3_R, "pll3_r", PARENT("pll3"), 0, + _GATE(RCC_PLL3CR, 6, 0), + _NO_MUX, + _DIV(RCC_PLL3CFGR2, 16, 7, 0, NULL)), + + COMPOSITE(PLL4_P, "pll4_p", PARENT("pll4"), 0, + _GATE(RCC_PLL4CR, 4, 0), + _NO_MUX, + _DIV(RCC_PLL4CFGR2, 0, 7, 0, NULL)), + + COMPOSITE(PLL4_Q, "pll4_q", PARENT("pll4"), 0, + _GATE(RCC_PLL4CR, 5, 0), + _NO_MUX, + _DIV(RCC_PLL4CFGR2, 8, 7, 0, NULL)), + + COMPOSITE(PLL4_R, "pll4_r", PARENT("pll4"), 0, + _GATE(RCC_PLL4CR, 6, 0), + _NO_MUX, + _DIV(RCC_PLL4CFGR2, 16, 7, 0, NULL)), }; struct stm32_clock_match_data { -- cgit From e51d297e9a923556e45e5491f5dd29888e38889e Mon Sep 17 00:00:00 2001 From: Gabriel Fernandez Date: Thu, 8 Mar 2018 17:54:00 +0100 Subject: clk: stm32mp1: add Sub System clocks The RCC handles three sub-system clocks: ck_mpuss, ck_axiss and ck_mcuss. This patch adds also some MUX system and several prescalers. Signed-off-by: Gabriel Fernandez Signed-off-by: Michael Turquette --- drivers/clk/clk-stm32mp1.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) diff --git a/drivers/clk/clk-stm32mp1.c b/drivers/clk/clk-stm32mp1.c index 3a99ad7f7048..77d96d9acad6 100644 --- a/drivers/clk/clk-stm32mp1.c +++ b/drivers/clk/clk-stm32mp1.c @@ -116,6 +116,42 @@ static const char * const ref4_parents[] = { "ck_hsi", "ck_hse", "ck_csi" }; +static const char * const cpu_src[] = { + "ck_hsi", "ck_hse", "pll1_p" +}; + +static const char * const axi_src[] = { + "ck_hsi", "ck_hse", "pll2_p", "pll3_p" +}; + +static const char * const per_src[] = { + "ck_hsi", "ck_csi", "ck_hse" +}; + +static const char * const mcu_src[] = { + "ck_hsi", "ck_hse", "ck_csi", "pll3_p" +}; + +static const struct clk_div_table axi_div_table[] = { + { 0, 1 }, { 1, 2 }, { 2, 3 }, { 3, 4 }, + { 4, 4 }, { 5, 4 }, { 6, 4 }, { 7, 4 }, + { 0 }, +}; + +static const struct clk_div_table mcu_div_table[] = { + { 0, 1 }, { 1, 2 }, { 2, 4 }, { 3, 8 }, + { 4, 16 }, { 5, 32 }, { 6, 64 }, { 7, 128 }, + { 8, 512 }, { 9, 512 }, { 10, 512}, { 11, 512 }, + { 12, 512 }, { 13, 512 }, { 14, 512}, { 15, 512 }, + { 0 }, +}; + +static const struct clk_div_table apb_div_table[] = { + { 0, 1 }, { 1, 2 }, { 2, 4 }, { 3, 8 }, + { 4, 16 }, { 5, 16 }, { 6, 16 }, { 7, 16 }, + { 0 }, +}; + struct clock_config { u32 id; const char *name; @@ -781,6 +817,21 @@ _clk_stm32_register_composite(struct device *dev, _STM32_DIV(_div_offset, _div_shift, _div_width,\ _div_flags, _div_table, NULL)\ +#define _STM32_MUX(_offset, _shift, _width, _mux_flags, _ops)\ + .mux = &(struct stm32_mux_cfg) {\ + &(struct mux_cfg) {\ + .reg_off = _offset,\ + .shift = _shift,\ + .width = _width,\ + .mux_flags = _mux_flags,\ + .table = NULL,\ + },\ + .ops = _ops,\ + } + +#define _MUX(_offset, _shift, _width, _mux_flags)\ + _STM32_MUX(_offset, _shift, _width, _mux_flags, NULL)\ + #define PARENT(_parent) ((const char *[]) { _parent}) #define _NO_MUX .mux = NULL @@ -882,6 +933,40 @@ static const struct clock_config stm32mp1_clock_cfg[] = { _GATE(RCC_PLL4CR, 6, 0), _NO_MUX, _DIV(RCC_PLL4CFGR2, 16, 7, 0, NULL)), + + /* MUX system clocks */ + MUX(CK_PER, "ck_per", per_src, CLK_OPS_PARENT_ENABLE, + RCC_CPERCKSELR, 0, 2, 0), + + MUX(CK_MPU, "ck_mpu", cpu_src, CLK_OPS_PARENT_ENABLE | + CLK_IS_CRITICAL, RCC_MPCKSELR, 0, 2, 0), + + COMPOSITE(CK_AXI, "ck_axi", axi_src, CLK_IS_CRITICAL | + CLK_OPS_PARENT_ENABLE, + _NO_GATE, + _MUX(RCC_ASSCKSELR, 0, 2, 0), + _DIV(RCC_AXIDIVR, 0, 3, 0, axi_div_table)), + + COMPOSITE(CK_MCU, "ck_mcu", mcu_src, CLK_IS_CRITICAL | + CLK_OPS_PARENT_ENABLE, + _NO_GATE, + _MUX(RCC_MSSCKSELR, 0, 2, 0), + _DIV(RCC_MCUDIVR, 0, 4, 0, mcu_div_table)), + + DIV_TABLE(NO_ID, "pclk1", "ck_mcu", CLK_IGNORE_UNUSED, RCC_APB1DIVR, 0, + 3, CLK_DIVIDER_READ_ONLY, apb_div_table), + + DIV_TABLE(NO_ID, "pclk2", "ck_mcu", CLK_IGNORE_UNUSED, RCC_APB2DIVR, 0, + 3, CLK_DIVIDER_READ_ONLY, apb_div_table), + + DIV_TABLE(NO_ID, "pclk3", "ck_mcu", CLK_IGNORE_UNUSED, RCC_APB3DIVR, 0, + 3, CLK_DIVIDER_READ_ONLY, apb_div_table), + + DIV_TABLE(NO_ID, "pclk4", "ck_axi", CLK_IGNORE_UNUSED, RCC_APB4DIVR, 0, + 3, CLK_DIVIDER_READ_ONLY, apb_div_table), + + DIV_TABLE(NO_ID, "pclk5", "ck_axi", CLK_IGNORE_UNUSED, RCC_APB5DIVR, 0, + 3, CLK_DIVIDER_READ_ONLY, apb_div_table), }; struct stm32_clock_match_data { -- cgit From 799b6a125ef0187579611bc153558bf01766d103 Mon Sep 17 00:00:00 2001 From: Gabriel Fernandez Date: Thu, 8 Mar 2018 17:54:01 +0100 Subject: clk: stm32mp1: add Kernel timers This patch adds Kernel timers. This patch adds timers kernel clock. Timers are gather into two groups corresponding to the APB bus they are attached to. Each group has its own prescaler, managed in this patch. Signed-off-by: Gabriel Fernandez Signed-off-by: Michael Turquette --- drivers/clk/clk-stm32mp1.c | 185 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 185 insertions(+) diff --git a/drivers/clk/clk-stm32mp1.c b/drivers/clk/clk-stm32mp1.c index 77d96d9acad6..0470a1364eee 100644 --- a/drivers/clk/clk-stm32mp1.c +++ b/drivers/clk/clk-stm32mp1.c @@ -650,6 +650,138 @@ static struct clk_hw *clk_register_pll(struct device *dev, const char *name, return hw; } +/* Kernel Timer */ +struct timer_cker { + /* lock the kernel output divider register */ + spinlock_t *lock; + void __iomem *apbdiv; + void __iomem *timpre; + struct clk_hw hw; +}; + +#define to_timer_cker(_hw) container_of(_hw, struct timer_cker, hw) + +#define APB_DIV_MASK 0x07 +#define TIM_PRE_MASK 0x01 + +static unsigned long __bestmult(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct timer_cker *tim_ker = to_timer_cker(hw); + u32 prescaler; + unsigned int mult = 0; + + prescaler = readl_relaxed(tim_ker->apbdiv) & APB_DIV_MASK; + if (prescaler < 2) + return 1; + + mult = 2; + + if (rate / parent_rate >= 4) + mult = 4; + + return mult; +} + +static long timer_ker_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + unsigned long factor = __bestmult(hw, rate, *parent_rate); + + return *parent_rate * factor; +} + +static int timer_ker_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct timer_cker *tim_ker = to_timer_cker(hw); + unsigned long flags = 0; + unsigned long factor = __bestmult(hw, rate, parent_rate); + int ret = 0; + + spin_lock_irqsave(tim_ker->lock, flags); + + switch (factor) { + case 1: + break; + case 2: + writel_relaxed(0, tim_ker->timpre); + break; + case 4: + writel_relaxed(1, tim_ker->timpre); + break; + default: + ret = -EINVAL; + } + spin_unlock_irqrestore(tim_ker->lock, flags); + + return ret; +} + +static unsigned long timer_ker_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct timer_cker *tim_ker = to_timer_cker(hw); + u32 prescaler, timpre; + u32 mul; + + prescaler = readl_relaxed(tim_ker->apbdiv) & APB_DIV_MASK; + + timpre = readl_relaxed(tim_ker->timpre) & TIM_PRE_MASK; + + if (!prescaler) + return parent_rate; + + mul = (timpre + 1) * 2; + + return parent_rate * mul; +} + +static const struct clk_ops timer_ker_ops = { + .recalc_rate = timer_ker_recalc_rate, + .round_rate = timer_ker_round_rate, + .set_rate = timer_ker_set_rate, + +}; + +static struct clk_hw *clk_register_cktim(struct device *dev, const char *name, + const char *parent_name, + unsigned long flags, + void __iomem *apbdiv, + void __iomem *timpre, + spinlock_t *lock) +{ + struct timer_cker *tim_ker; + struct clk_init_data init; + struct clk_hw *hw; + int err; + + tim_ker = kzalloc(sizeof(*tim_ker), GFP_KERNEL); + if (!tim_ker) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.ops = &timer_ker_ops; + init.flags = flags; + init.parent_names = &parent_name; + init.num_parents = 1; + + tim_ker->hw.init = &init; + tim_ker->lock = lock; + tim_ker->apbdiv = apbdiv; + tim_ker->timpre = timpre; + + hw = &tim_ker->hw; + err = clk_hw_register(dev, hw); + + if (err) { + kfree(tim_ker); + return ERR_PTR(err); + } + + return hw; +} + struct stm32_pll_cfg { u32 offset; }; @@ -665,6 +797,23 @@ struct clk_hw *_clk_register_pll(struct device *dev, base + stm_pll_cfg->offset, cfg->flags, lock); } +struct stm32_cktim_cfg { + u32 offset_apbdiv; + u32 offset_timpre; +}; + +static struct clk_hw *_clk_register_cktim(struct device *dev, + struct clk_hw_onecell_data *clk_data, + void __iomem *base, spinlock_t *lock, + const struct clock_config *cfg) +{ + struct stm32_cktim_cfg *cktim_cfg = cfg->cfg; + + return clk_register_cktim(dev, cfg->name, cfg->parent_name, cfg->flags, + cktim_cfg->offset_apbdiv + base, + cktim_cfg->offset_timpre + base, lock); +} + static struct clk_hw * _clk_stm32_register_gate(struct device *dev, struct clk_hw_onecell_data *clk_data, @@ -767,6 +916,23 @@ _clk_stm32_register_composite(struct device *dev, .func = _clk_register_pll,\ } +#define STM32_CKTIM(_name, _parent, _flags, _offset_apbdiv, _offset_timpre)\ +{\ + .id = NO_ID,\ + .name = _name,\ + .parent_name = _parent,\ + .flags = _flags,\ + .cfg = &(struct stm32_cktim_cfg) {\ + .offset_apbdiv = _offset_apbdiv,\ + .offset_timpre = _offset_timpre,\ + },\ + .func = _clk_register_cktim,\ +} + +#define STM32_TIM(_id, _name, _parent, _offset_set, _bit_idx)\ + GATE_MP1(_id, _name, _parent, CLK_SET_RATE_PARENT,\ + _offset_set, _bit_idx, 0) + /* STM32 GATE */ #define STM32_GATE(_id, _name, _parent, _flags, _gate)\ {\ @@ -967,6 +1133,25 @@ static const struct clock_config stm32mp1_clock_cfg[] = { DIV_TABLE(NO_ID, "pclk5", "ck_axi", CLK_IGNORE_UNUSED, RCC_APB5DIVR, 0, 3, CLK_DIVIDER_READ_ONLY, apb_div_table), + + /* Kernel Timers */ + STM32_CKTIM("ck1_tim", "pclk1", 0, RCC_APB1DIVR, RCC_TIMG1PRER), + STM32_CKTIM("ck2_tim", "pclk2", 0, RCC_APB2DIVR, RCC_TIMG2PRER), + + STM32_TIM(TIM2_K, "tim2_k", "ck1_tim", RCC_APB1ENSETR, 0), + STM32_TIM(TIM3_K, "tim3_k", "ck1_tim", RCC_APB1ENSETR, 1), + STM32_TIM(TIM4_K, "tim4_k", "ck1_tim", RCC_APB1ENSETR, 2), + STM32_TIM(TIM5_K, "tim5_k", "ck1_tim", RCC_APB1ENSETR, 3), + STM32_TIM(TIM6_K, "tim6_k", "ck1_tim", RCC_APB1ENSETR, 4), + STM32_TIM(TIM7_K, "tim7_k", "ck1_tim", RCC_APB1ENSETR, 5), + STM32_TIM(TIM12_K, "tim12_k", "ck1_tim", RCC_APB1ENSETR, 6), + STM32_TIM(TIM13_K, "tim13_k", "ck1_tim", RCC_APB1ENSETR, 7), + STM32_TIM(TIM14_K, "tim14_k", "ck1_tim", RCC_APB1ENSETR, 8), + STM32_TIM(TIM1_K, "tim1_k", "ck2_tim", RCC_APB2ENSETR, 0), + STM32_TIM(TIM8_K, "tim8_k", "ck2_tim", RCC_APB2ENSETR, 1), + STM32_TIM(TIM15_K, "tim15_k", "ck2_tim", RCC_APB2ENSETR, 2), + STM32_TIM(TIM16_K, "tim16_k", "ck2_tim", RCC_APB2ENSETR, 3), + STM32_TIM(TIM17_K, "tim17_k", "ck2_tim", RCC_APB2ENSETR, 4), }; struct stm32_clock_match_data { -- cgit From 1f80590b6bdabffc90b9ed6a2d05dd9d24122879 Mon Sep 17 00:00:00 2001 From: Gabriel Fernandez Date: Thu, 8 Mar 2018 17:54:02 +0100 Subject: clk: stm32mp1: add Peripheral & Kernel Clocks Each peripheral requires a bus interface clock. Some peripherals need also a dedicated clock for their communication interface, this clock is generally asynchronous with respect to the bus interface clock (peripheral clock), and is named kernel clock. For each IP, Peripheral clock and Kernel are generally gating with same gate. Also, Kernel clocks can share a same multiplexer. This patch introduces a mechanism to manage a gate with several clocks and to manage a shared multiplexer (mgate and mmux). Signed-off-by: Gabriel Fernandez Signed-off-by: Michael Turquette --- drivers/clk/clk-stm32mp1.c | 847 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 820 insertions(+), 27 deletions(-) diff --git a/drivers/clk/clk-stm32mp1.c b/drivers/clk/clk-stm32mp1.c index 0470a1364eee..b5379a224183 100644 --- a/drivers/clk/clk-stm32mp1.c +++ b/drivers/clk/clk-stm32mp1.c @@ -132,6 +132,122 @@ static const char * const mcu_src[] = { "ck_hsi", "ck_hse", "ck_csi", "pll3_p" }; +static const char * const sdmmc12_src[] = { + "ck_axi", "pll3_r", "pll4_p", "ck_hsi" +}; + +static const char * const sdmmc3_src[] = { + "ck_mcu", "pll3_r", "pll4_p", "ck_hsi" +}; + +static const char * const fmc_src[] = { + "ck_axi", "pll3_r", "pll4_p", "ck_per" +}; + +static const char * const qspi_src[] = { + "ck_axi", "pll3_r", "pll4_p", "ck_per" +}; + +static const char * const eth_src[] = { + "pll4_p", "pll3_q" +}; + +static const char * const rng_src[] = { + "ck_csi", "pll4_r", "ck_lse", "ck_lsi" +}; + +static const char * const usbphy_src[] = { + "ck_hse", "pll4_r", "clk-hse-div2" +}; + +static const char * const usbo_src[] = { + "pll4_r", "ck_usbo_48m" +}; + +static const char * const stgen_src[] = { + "ck_hsi", "ck_hse" +}; + +static const char * const spdif_src[] = { + "pll4_p", "pll3_q", "ck_hsi" +}; + +static const char * const spi123_src[] = { + "pll4_p", "pll3_q", "i2s_ckin", "ck_per", "pll3_r" +}; + +static const char * const spi45_src[] = { + "pclk2", "pll4_q", "ck_hsi", "ck_csi", "ck_hse" +}; + +static const char * const spi6_src[] = { + "pclk5", "pll4_q", "ck_hsi", "ck_csi", "ck_hse", "pll3_q" +}; + +static const char * const cec_src[] = { + "ck_lse", "ck_lsi", "ck_csi" +}; + +static const char * const i2c12_src[] = { + "pclk1", "pll4_r", "ck_hsi", "ck_csi" +}; + +static const char * const i2c35_src[] = { + "pclk1", "pll4_r", "ck_hsi", "ck_csi" +}; + +static const char * const i2c46_src[] = { + "pclk5", "pll3_q", "ck_hsi", "ck_csi" +}; + +static const char * const lptim1_src[] = { + "pclk1", "pll4_p", "pll3_q", "ck_lse", "ck_lsi", "ck_per" +}; + +static const char * const lptim23_src[] = { + "pclk3", "pll4_q", "ck_per", "ck_lse", "ck_lsi" +}; + +static const char * const lptim45_src[] = { + "pclk3", "pll4_p", "pll3_q", "ck_lse", "ck_lsi", "ck_per" +}; + +static const char * const usart1_src[] = { + "pclk5", "pll3_q", "ck_hsi", "ck_csi", "pll4_q", "ck_hse" +}; + +const char * const usart234578_src[] = { + "pclk1", "pll4_q", "ck_hsi", "ck_csi", "ck_hse" +}; + +static const char * const usart6_src[] = { + "pclk2", "pll4_q", "ck_hsi", "ck_csi", "ck_hse" +}; + +static const char * const dfsdm_src[] = { + "pclk2", "ck_mcu" +}; + +static const char * const fdcan_src[] = { + "ck_hse", "pll3_q", "pll4_q" +}; + +static const char * const sai_src[] = { + "pll4_q", "pll3_q", "i2s_ckin", "ck_per" +}; + +static const char * const sai2_src[] = { + "pll4_q", "pll3_q", "i2s_ckin", "ck_per", "spdif_ck_symb" +}; + +static const char * const adc12_src[] = { + "pll4_q", "ck_per" +}; + +static const char * const dsi_src[] = { + "ck_dsi_phy", "pll4_p" +}; + static const struct clk_div_table axi_div_table[] = { { 0, 1 }, { 1, 2 }, { 2, 3 }, { 3, 4 }, { 4, 4 }, { 5, 4 }, { 6, 4 }, { 7, 4 }, @@ -152,6 +268,29 @@ static const struct clk_div_table apb_div_table[] = { { 0 }, }; +#define MAX_MUX_CLK 2 + +struct stm32_mmux { + u8 nbr_clk; + struct clk_hw *hws[MAX_MUX_CLK]; +}; + +struct stm32_clk_mmux { + struct clk_mux mux; + struct stm32_mmux *mmux; +}; + +struct stm32_mgate { + u8 nbr_clk; + u32 flag; +}; + +struct stm32_clk_mgate { + struct clk_gate gate; + struct stm32_mgate *mgate; + u32 mask; +}; + struct clock_config { u32 id; const char *name; @@ -199,6 +338,7 @@ struct mux_cfg { struct stm32_gate_cfg { struct gate_cfg *gate; + struct stm32_mgate *mgate; const struct clk_ops *ops; }; @@ -209,6 +349,7 @@ struct stm32_div_cfg { struct stm32_mux_cfg { struct mux_cfg *mux; + struct stm32_mmux *mmux; const struct clk_ops *ops; }; @@ -316,22 +457,38 @@ static struct clk_hw *_get_stm32_mux(void __iomem *base, const struct stm32_mux_cfg *cfg, spinlock_t *lock) { + struct stm32_clk_mmux *mmux; struct clk_mux *mux; struct clk_hw *mux_hw; - mux = kzalloc(sizeof(*mux), GFP_KERNEL); - if (!mux) - return ERR_PTR(-ENOMEM); - - mux->reg = cfg->mux->reg_off + base; - mux->shift = cfg->mux->shift; - mux->mask = (1 << cfg->mux->width) - 1; - mux->flags = cfg->mux->mux_flags; - mux->table = cfg->mux->table; - - mux->lock = lock; - - mux_hw = &mux->hw; + if (cfg->mmux) { + mmux = kzalloc(sizeof(*mmux), GFP_KERNEL); + if (!mmux) + return ERR_PTR(-ENOMEM); + + mmux->mux.reg = cfg->mux->reg_off + base; + mmux->mux.shift = cfg->mux->shift; + mmux->mux.mask = (1 << cfg->mux->width) - 1; + mmux->mux.flags = cfg->mux->mux_flags; + mmux->mux.table = cfg->mux->table; + mmux->mux.lock = lock; + mmux->mmux = cfg->mmux; + mux_hw = &mmux->mux.hw; + cfg->mmux->hws[cfg->mmux->nbr_clk++] = mux_hw; + + } else { + mux = kzalloc(sizeof(*mux), GFP_KERNEL); + if (!mux) + return ERR_PTR(-ENOMEM); + + mux->reg = cfg->mux->reg_off + base; + mux->shift = cfg->mux->shift; + mux->mask = (1 << cfg->mux->width) - 1; + mux->flags = cfg->mux->mux_flags; + mux->table = cfg->mux->table; + mux->lock = lock; + mux_hw = &mux->hw; + } return mux_hw; } @@ -361,18 +518,37 @@ static struct clk_hw * _get_stm32_gate(void __iomem *base, const struct stm32_gate_cfg *cfg, spinlock_t *lock) { + struct stm32_clk_mgate *mgate; struct clk_gate *gate; struct clk_hw *gate_hw; - gate = kzalloc(sizeof(*gate), GFP_KERNEL); - if (!gate) - return ERR_PTR(-ENOMEM); + if (cfg->mgate) { + mgate = kzalloc(sizeof(*mgate), GFP_KERNEL); + if (!mgate) + return ERR_PTR(-ENOMEM); + + mgate->gate.reg = cfg->gate->reg_off + base; + mgate->gate.bit_idx = cfg->gate->bit_idx; + mgate->gate.flags = cfg->gate->gate_flags; + mgate->gate.lock = lock; + mgate->mask = BIT(cfg->mgate->nbr_clk++); + + mgate->mgate = cfg->mgate; + + gate_hw = &mgate->gate.hw; + + } else { + gate = kzalloc(sizeof(*gate), GFP_KERNEL); + if (!gate) + return ERR_PTR(-ENOMEM); - gate->reg = cfg->gate->reg_off + base; - gate->bit_idx = cfg->gate->bit_idx; - gate->flags = cfg->gate->gate_flags; - gate->lock = lock; - gate_hw = &gate->hw; + gate->reg = cfg->gate->reg_off + base; + gate->bit_idx = cfg->gate->bit_idx; + gate->flags = cfg->gate->gate_flags; + gate->lock = lock; + + gate_hw = &gate->hw; + } return gate_hw; } @@ -475,8 +651,72 @@ clk_stm32_register_composite(struct device *dev, gate_hw, gate_ops, flags); } -/* STM32 PLL */ +#define to_clk_mgate(_gate) container_of(_gate, struct stm32_clk_mgate, gate) + +static int mp1_mgate_clk_enable(struct clk_hw *hw) +{ + struct clk_gate *gate = to_clk_gate(hw); + struct stm32_clk_mgate *clk_mgate = to_clk_mgate(gate); + + clk_mgate->mgate->flag |= clk_mgate->mask; + + mp1_gate_clk_enable(hw); + + return 0; +} + +static void mp1_mgate_clk_disable(struct clk_hw *hw) +{ + struct clk_gate *gate = to_clk_gate(hw); + struct stm32_clk_mgate *clk_mgate = to_clk_mgate(gate); + + clk_mgate->mgate->flag &= ~clk_mgate->mask; + + if (clk_mgate->mgate->flag == 0) + mp1_gate_clk_disable(hw); +} + +const struct clk_ops mp1_mgate_clk_ops = { + .enable = mp1_mgate_clk_enable, + .disable = mp1_mgate_clk_disable, + .is_enabled = clk_gate_is_enabled, + +}; + +#define to_clk_mmux(_mux) container_of(_mux, struct stm32_clk_mmux, mux) + +static u8 clk_mmux_get_parent(struct clk_hw *hw) +{ + return clk_mux_ops.get_parent(hw); +} + +static int clk_mmux_set_parent(struct clk_hw *hw, u8 index) +{ + struct clk_mux *mux = to_clk_mux(hw); + struct stm32_clk_mmux *clk_mmux = to_clk_mmux(mux); + struct clk_hw *hwp; + int ret, n; + + ret = clk_mux_ops.set_parent(hw, index); + if (ret) + return ret; + + hwp = clk_hw_get_parent(hw); + + for (n = 0; n < clk_mmux->mmux->nbr_clk; n++) + if (clk_mmux->mmux->hws[n] != hw) + clk_hw_reparent(clk_mmux->mmux->hws[n], hwp); + + return 0; +} +const struct clk_ops clk_mmux_ops = { + .get_parent = clk_mmux_get_parent, + .set_parent = clk_mmux_set_parent, + .determine_rate = __clk_mux_determine_rate, +}; + +/* STM32 PLL */ struct stm32_pll_obj { /* lock pll enable/disable registers */ spinlock_t *lock; @@ -944,28 +1184,39 @@ _clk_stm32_register_composite(struct device *dev, .func = _clk_stm32_register_gate,\ } -#define _STM32_GATE(_gate_offset, _gate_bit_idx, _gate_flags, _ops)\ +#define _STM32_GATE(_gate_offset, _gate_bit_idx, _gate_flags, _mgate, _ops)\ (&(struct stm32_gate_cfg) {\ &(struct gate_cfg) {\ .reg_off = _gate_offset,\ .bit_idx = _gate_bit_idx,\ .gate_flags = _gate_flags,\ },\ + .mgate = _mgate,\ .ops = _ops,\ }) +#define _STM32_MGATE(_mgate)\ + (&per_gate_cfg[_mgate]) + #define _GATE(_gate_offset, _gate_bit_idx, _gate_flags)\ _STM32_GATE(_gate_offset, _gate_bit_idx, _gate_flags,\ - NULL)\ + NULL, NULL)\ #define _GATE_MP1(_gate_offset, _gate_bit_idx, _gate_flags)\ _STM32_GATE(_gate_offset, _gate_bit_idx, _gate_flags,\ - &mp1_gate_clk_ops)\ + NULL, &mp1_gate_clk_ops)\ + +#define _MGATE_MP1(_mgate)\ + .gate = &per_gate_cfg[_mgate] #define GATE_MP1(_id, _name, _parent, _flags, _offset, _bit_idx, _gate_flags)\ STM32_GATE(_id, _name, _parent, _flags,\ _GATE_MP1(_offset, _bit_idx, _gate_flags)) +#define MGATE_MP1(_id, _name, _parent, _flags, _mgate)\ + STM32_GATE(_id, _name, _parent, _flags,\ + _STM32_MGATE(_mgate)) + #define _STM32_DIV(_div_offset, _div_shift, _div_width,\ _div_flags, _div_table, _ops)\ .div = &(struct stm32_div_cfg) {\ @@ -983,7 +1234,7 @@ _clk_stm32_register_composite(struct device *dev, _STM32_DIV(_div_offset, _div_shift, _div_width,\ _div_flags, _div_table, NULL)\ -#define _STM32_MUX(_offset, _shift, _width, _mux_flags, _ops)\ +#define _STM32_MUX(_offset, _shift, _width, _mux_flags, _mmux, _ops)\ .mux = &(struct stm32_mux_cfg) {\ &(struct mux_cfg) {\ .reg_off = _offset,\ @@ -992,11 +1243,14 @@ _clk_stm32_register_composite(struct device *dev, .mux_flags = _mux_flags,\ .table = NULL,\ },\ + .mmux = _mmux,\ .ops = _ops,\ } #define _MUX(_offset, _shift, _width, _mux_flags)\ - _STM32_MUX(_offset, _shift, _width, _mux_flags, NULL)\ + _STM32_MUX(_offset, _shift, _width, _mux_flags, NULL, NULL)\ + +#define _MMUX(_mmux) .mux = &ker_mux_cfg[_mmux] #define PARENT(_parent) ((const char *[]) { _parent}) @@ -1019,6 +1273,375 @@ _clk_stm32_register_composite(struct device *dev, .func = _clk_stm32_register_composite,\ } +#define PCLK(_id, _name, _parent, _flags, _mgate)\ + MGATE_MP1(_id, _name, _parent, _flags, _mgate) + +#define KCLK(_id, _name, _parents, _flags, _mgate, _mmux)\ + COMPOSITE(_id, _name, _parents, CLK_OPS_PARENT_ENABLE | _flags,\ + _MGATE_MP1(_mgate),\ + _MMUX(_mmux),\ + _NO_DIV) + +enum { + G_SAI1, + G_SAI2, + G_SAI3, + G_SAI4, + G_SPI1, + G_SPI2, + G_SPI3, + G_SPI4, + G_SPI5, + G_SPI6, + G_SPDIF, + G_I2C1, + G_I2C2, + G_I2C3, + G_I2C4, + G_I2C5, + G_I2C6, + G_USART2, + G_UART4, + G_USART3, + G_UART5, + G_USART1, + G_USART6, + G_UART7, + G_UART8, + G_LPTIM1, + G_LPTIM2, + G_LPTIM3, + G_LPTIM4, + G_LPTIM5, + G_LTDC, + G_DSI, + G_QSPI, + G_FMC, + G_SDMMC1, + G_SDMMC2, + G_SDMMC3, + G_USBO, + G_USBPHY, + G_RNG1, + G_RNG2, + G_FDCAN, + G_DAC12, + G_CEC, + G_ADC12, + G_GPU, + G_STGEN, + G_DFSDM, + G_ADFSDM, + G_TIM2, + G_TIM3, + G_TIM4, + G_TIM5, + G_TIM6, + G_TIM7, + G_TIM12, + G_TIM13, + G_TIM14, + G_MDIO, + G_TIM1, + G_TIM8, + G_TIM15, + G_TIM16, + G_TIM17, + G_SYSCFG, + G_VREF, + G_TMPSENS, + G_PMBCTRL, + G_HDP, + G_IWDG2, + G_STGENRO, + G_DMA1, + G_DMA2, + G_DMAMUX, + G_DCMI, + G_CRYP2, + G_HASH2, + G_CRC2, + G_HSEM, + G_IPCC, + G_GPIOA, + G_GPIOB, + G_GPIOC, + G_GPIOD, + G_GPIOE, + G_GPIOF, + G_GPIOG, + G_GPIOH, + G_GPIOI, + G_GPIOJ, + G_GPIOK, + G_MDMA, + G_ETHCK, + G_ETHTX, + G_ETHRX, + G_ETHMAC, + G_CRC1, + G_USBH, + G_ETHSTP, + G_RTCAPB, + G_TZC, + G_TZPC, + G_IWDG1, + G_BSEC, + G_GPIOZ, + G_CRYP1, + G_HASH1, + G_BKPSRAM, + + G_LAST +}; + +struct stm32_mgate mp1_mgate[G_LAST]; + +#define _K_GATE(_id, _gate_offset, _gate_bit_idx, _gate_flags,\ + _mgate, _ops)\ + [_id] = {\ + &(struct gate_cfg) {\ + .reg_off = _gate_offset,\ + .bit_idx = _gate_bit_idx,\ + .gate_flags = _gate_flags,\ + },\ + .mgate = _mgate,\ + .ops = _ops,\ + } + +#define K_GATE(_id, _gate_offset, _gate_bit_idx, _gate_flags)\ + _K_GATE(_id, _gate_offset, _gate_bit_idx, _gate_flags,\ + NULL, &mp1_gate_clk_ops) + +#define K_MGATE(_id, _gate_offset, _gate_bit_idx, _gate_flags)\ + _K_GATE(_id, _gate_offset, _gate_bit_idx, _gate_flags,\ + &mp1_mgate[_id], &mp1_mgate_clk_ops) + +/* Peripheral gates */ +struct stm32_gate_cfg per_gate_cfg[G_LAST] = { + /* Multi gates */ + K_GATE(G_MDIO, RCC_APB1ENSETR, 31, 0), + K_MGATE(G_DAC12, RCC_APB1ENSETR, 29, 0), + K_MGATE(G_CEC, RCC_APB1ENSETR, 27, 0), + K_MGATE(G_SPDIF, RCC_APB1ENSETR, 26, 0), + K_MGATE(G_I2C5, RCC_APB1ENSETR, 24, 0), + K_MGATE(G_I2C3, RCC_APB1ENSETR, 23, 0), + K_MGATE(G_I2C2, RCC_APB1ENSETR, 22, 0), + K_MGATE(G_I2C1, RCC_APB1ENSETR, 21, 0), + K_MGATE(G_UART8, RCC_APB1ENSETR, 19, 0), + K_MGATE(G_UART7, RCC_APB1ENSETR, 18, 0), + K_MGATE(G_UART5, RCC_APB1ENSETR, 17, 0), + K_MGATE(G_UART4, RCC_APB1ENSETR, 16, 0), + K_MGATE(G_USART3, RCC_APB1ENSETR, 15, 0), + K_MGATE(G_USART2, RCC_APB1ENSETR, 14, 0), + K_MGATE(G_SPI3, RCC_APB1ENSETR, 12, 0), + K_MGATE(G_SPI2, RCC_APB1ENSETR, 11, 0), + K_MGATE(G_LPTIM1, RCC_APB1ENSETR, 9, 0), + K_GATE(G_TIM14, RCC_APB1ENSETR, 8, 0), + K_GATE(G_TIM13, RCC_APB1ENSETR, 7, 0), + K_GATE(G_TIM12, RCC_APB1ENSETR, 6, 0), + K_GATE(G_TIM7, RCC_APB1ENSETR, 5, 0), + K_GATE(G_TIM6, RCC_APB1ENSETR, 4, 0), + K_GATE(G_TIM5, RCC_APB1ENSETR, 3, 0), + K_GATE(G_TIM4, RCC_APB1ENSETR, 2, 0), + K_GATE(G_TIM3, RCC_APB1ENSETR, 1, 0), + K_GATE(G_TIM2, RCC_APB1ENSETR, 0, 0), + + K_MGATE(G_FDCAN, RCC_APB2ENSETR, 24, 0), + K_GATE(G_ADFSDM, RCC_APB2ENSETR, 21, 0), + K_GATE(G_DFSDM, RCC_APB2ENSETR, 20, 0), + K_MGATE(G_SAI3, RCC_APB2ENSETR, 18, 0), + K_MGATE(G_SAI2, RCC_APB2ENSETR, 17, 0), + K_MGATE(G_SAI1, RCC_APB2ENSETR, 16, 0), + K_MGATE(G_USART6, RCC_APB2ENSETR, 13, 0), + K_MGATE(G_SPI5, RCC_APB2ENSETR, 10, 0), + K_MGATE(G_SPI4, RCC_APB2ENSETR, 9, 0), + K_MGATE(G_SPI1, RCC_APB2ENSETR, 8, 0), + K_GATE(G_TIM17, RCC_APB2ENSETR, 4, 0), + K_GATE(G_TIM16, RCC_APB2ENSETR, 3, 0), + K_GATE(G_TIM15, RCC_APB2ENSETR, 2, 0), + K_GATE(G_TIM8, RCC_APB2ENSETR, 1, 0), + K_GATE(G_TIM1, RCC_APB2ENSETR, 0, 0), + + K_GATE(G_HDP, RCC_APB3ENSETR, 20, 0), + K_GATE(G_PMBCTRL, RCC_APB3ENSETR, 17, 0), + K_GATE(G_TMPSENS, RCC_APB3ENSETR, 16, 0), + K_GATE(G_VREF, RCC_APB3ENSETR, 13, 0), + K_GATE(G_SYSCFG, RCC_APB3ENSETR, 11, 0), + K_MGATE(G_SAI4, RCC_APB3ENSETR, 8, 0), + K_MGATE(G_LPTIM5, RCC_APB3ENSETR, 3, 0), + K_MGATE(G_LPTIM4, RCC_APB3ENSETR, 2, 0), + K_MGATE(G_LPTIM3, RCC_APB3ENSETR, 1, 0), + K_MGATE(G_LPTIM2, RCC_APB3ENSETR, 0, 0), + + K_GATE(G_STGENRO, RCC_APB4ENSETR, 20, 0), + K_MGATE(G_USBPHY, RCC_APB4ENSETR, 16, 0), + K_GATE(G_IWDG2, RCC_APB4ENSETR, 15, 0), + K_MGATE(G_DSI, RCC_APB4ENSETR, 4, 0), + K_MGATE(G_LTDC, RCC_APB4ENSETR, 0, 0), + + K_GATE(G_STGEN, RCC_APB5ENSETR, 20, 0), + K_GATE(G_BSEC, RCC_APB5ENSETR, 16, 0), + K_GATE(G_IWDG1, RCC_APB5ENSETR, 15, 0), + K_GATE(G_TZPC, RCC_APB5ENSETR, 13, 0), + K_GATE(G_TZC, RCC_APB5ENSETR, 12, 0), + K_GATE(G_RTCAPB, RCC_APB5ENSETR, 8, 0), + K_MGATE(G_USART1, RCC_APB5ENSETR, 4, 0), + K_MGATE(G_I2C6, RCC_APB5ENSETR, 3, 0), + K_MGATE(G_I2C4, RCC_APB5ENSETR, 2, 0), + K_MGATE(G_SPI6, RCC_APB5ENSETR, 0, 0), + + K_MGATE(G_SDMMC3, RCC_AHB2ENSETR, 16, 0), + K_MGATE(G_USBO, RCC_AHB2ENSETR, 8, 0), + K_MGATE(G_ADC12, RCC_AHB2ENSETR, 5, 0), + K_GATE(G_DMAMUX, RCC_AHB2ENSETR, 2, 0), + K_GATE(G_DMA2, RCC_AHB2ENSETR, 1, 0), + K_GATE(G_DMA1, RCC_AHB2ENSETR, 0, 0), + + K_GATE(G_IPCC, RCC_AHB3ENSETR, 12, 0), + K_GATE(G_HSEM, RCC_AHB3ENSETR, 11, 0), + K_GATE(G_CRC2, RCC_AHB3ENSETR, 7, 0), + K_MGATE(G_RNG2, RCC_AHB3ENSETR, 6, 0), + K_GATE(G_HASH2, RCC_AHB3ENSETR, 5, 0), + K_GATE(G_CRYP2, RCC_AHB3ENSETR, 4, 0), + K_GATE(G_DCMI, RCC_AHB3ENSETR, 0, 0), + + K_GATE(G_GPIOK, RCC_AHB4ENSETR, 10, 0), + K_GATE(G_GPIOJ, RCC_AHB4ENSETR, 9, 0), + K_GATE(G_GPIOI, RCC_AHB4ENSETR, 8, 0), + K_GATE(G_GPIOH, RCC_AHB4ENSETR, 7, 0), + K_GATE(G_GPIOG, RCC_AHB4ENSETR, 6, 0), + K_GATE(G_GPIOF, RCC_AHB4ENSETR, 5, 0), + K_GATE(G_GPIOE, RCC_AHB4ENSETR, 4, 0), + K_GATE(G_GPIOD, RCC_AHB4ENSETR, 3, 0), + K_GATE(G_GPIOC, RCC_AHB4ENSETR, 2, 0), + K_GATE(G_GPIOB, RCC_AHB4ENSETR, 1, 0), + K_GATE(G_GPIOA, RCC_AHB4ENSETR, 0, 0), + + K_GATE(G_BKPSRAM, RCC_AHB5ENSETR, 8, 0), + K_MGATE(G_RNG1, RCC_AHB5ENSETR, 6, 0), + K_GATE(G_HASH1, RCC_AHB5ENSETR, 5, 0), + K_GATE(G_CRYP1, RCC_AHB5ENSETR, 4, 0), + K_GATE(G_GPIOZ, RCC_AHB5ENSETR, 0, 0), + + K_GATE(G_USBH, RCC_AHB6ENSETR, 24, 0), + K_GATE(G_CRC1, RCC_AHB6ENSETR, 20, 0), + K_MGATE(G_SDMMC2, RCC_AHB6ENSETR, 17, 0), + K_MGATE(G_SDMMC1, RCC_AHB6ENSETR, 16, 0), + K_MGATE(G_QSPI, RCC_AHB6ENSETR, 14, 0), + K_MGATE(G_FMC, RCC_AHB6ENSETR, 12, 0), + K_GATE(G_ETHMAC, RCC_AHB6ENSETR, 10, 0), + K_GATE(G_ETHRX, RCC_AHB6ENSETR, 9, 0), + K_GATE(G_ETHTX, RCC_AHB6ENSETR, 8, 0), + K_GATE(G_ETHCK, RCC_AHB6ENSETR, 7, 0), + K_MGATE(G_GPU, RCC_AHB6ENSETR, 5, 0), + K_GATE(G_MDMA, RCC_AHB6ENSETR, 0, 0), + K_GATE(G_ETHSTP, RCC_AHB6LPENSETR, 11, 0), +}; + +enum { + M_SDMMC12, + M_SDMMC3, + M_FMC, + M_QSPI, + M_RNG1, + M_RNG2, + M_USBPHY, + M_USBO, + M_STGEN, + M_SPDIF, + M_SPI1, + M_SPI23, + M_SPI45, + M_SPI6, + M_CEC, + M_I2C12, + M_I2C35, + M_I2C46, + M_LPTIM1, + M_LPTIM23, + M_LPTIM45, + M_USART1, + M_UART24, + M_UART35, + M_USART6, + M_UART78, + M_SAI1, + M_SAI2, + M_SAI3, + M_SAI4, + M_DSI, + M_FDCAN, + M_ADC12, + M_ETHCK, + M_CKPER, + M_LAST +}; + +struct stm32_mmux ker_mux[M_LAST]; + +#define _K_MUX(_id, _offset, _shift, _width, _mux_flags, _mmux, _ops)\ + [_id] = {\ + &(struct mux_cfg) {\ + .reg_off = _offset,\ + .shift = _shift,\ + .width = _width,\ + .mux_flags = _mux_flags,\ + .table = NULL,\ + },\ + .mmux = _mmux,\ + .ops = _ops,\ + } + +#define K_MUX(_id, _offset, _shift, _width, _mux_flags)\ + _K_MUX(_id, _offset, _shift, _width, _mux_flags,\ + NULL, NULL) + +#define K_MMUX(_id, _offset, _shift, _width, _mux_flags)\ + _K_MUX(_id, _offset, _shift, _width, _mux_flags,\ + &ker_mux[_id], &clk_mmux_ops) + +const struct stm32_mux_cfg ker_mux_cfg[M_LAST] = { + /* Kernel multi mux */ + K_MMUX(M_SDMMC12, RCC_SDMMC12CKSELR, 0, 3, 0), + K_MMUX(M_SPI23, RCC_SPI2S23CKSELR, 0, 3, 0), + K_MMUX(M_SPI45, RCC_SPI2S45CKSELR, 0, 3, 0), + K_MMUX(M_I2C12, RCC_I2C12CKSELR, 0, 3, 0), + K_MMUX(M_I2C35, RCC_I2C35CKSELR, 0, 3, 0), + K_MMUX(M_LPTIM23, RCC_LPTIM23CKSELR, 0, 3, 0), + K_MMUX(M_LPTIM45, RCC_LPTIM45CKSELR, 0, 3, 0), + K_MMUX(M_UART24, RCC_UART24CKSELR, 0, 3, 0), + K_MMUX(M_UART35, RCC_UART35CKSELR, 0, 3, 0), + K_MMUX(M_UART78, RCC_UART78CKSELR, 0, 3, 0), + K_MMUX(M_SAI1, RCC_SAI1CKSELR, 0, 3, 0), + K_MMUX(M_ETHCK, RCC_ETHCKSELR, 0, 2, 0), + K_MMUX(M_I2C46, RCC_I2C46CKSELR, 0, 3, 0), + + /* Kernel simple mux */ + K_MUX(M_RNG2, RCC_RNG2CKSELR, 0, 2, 0), + K_MUX(M_SDMMC3, RCC_SDMMC3CKSELR, 0, 3, 0), + K_MUX(M_FMC, RCC_FMCCKSELR, 0, 2, 0), + K_MUX(M_QSPI, RCC_QSPICKSELR, 0, 2, 0), + K_MUX(M_USBPHY, RCC_USBCKSELR, 0, 2, 0), + K_MUX(M_USBO, RCC_USBCKSELR, 4, 1, 0), + K_MUX(M_SPDIF, RCC_SPDIFCKSELR, 0, 2, 0), + K_MUX(M_SPI1, RCC_SPI2S1CKSELR, 0, 3, 0), + K_MUX(M_CEC, RCC_CECCKSELR, 0, 2, 0), + K_MUX(M_LPTIM1, RCC_LPTIM1CKSELR, 0, 3, 0), + K_MUX(M_USART6, RCC_UART6CKSELR, 0, 3, 0), + K_MUX(M_FDCAN, RCC_FDCANCKSELR, 0, 2, 0), + K_MUX(M_SAI2, RCC_SAI2CKSELR, 0, 3, 0), + K_MUX(M_SAI3, RCC_SAI3CKSELR, 0, 3, 0), + K_MUX(M_SAI4, RCC_SAI4CKSELR, 0, 3, 0), + K_MUX(M_ADC12, RCC_ADCCKSELR, 0, 2, 0), + K_MUX(M_DSI, RCC_DSICKSELR, 0, 1, 0), + K_MUX(M_CKPER, RCC_CPERCKSELR, 0, 2, 0), + K_MUX(M_RNG1, RCC_RNG1CKSELR, 0, 2, 0), + K_MUX(M_STGEN, RCC_STGENCKSELR, 0, 2, 0), + K_MUX(M_USART1, RCC_UART1CKSELR, 0, 3, 0), + K_MUX(M_SPI6, RCC_SPI6CKSELR, 0, 3, 0), +}; + static const struct clock_config stm32mp1_clock_cfg[] = { /* Oscillator divider */ DIV(NO_ID, "clk-hsi-div", "clk-hsi", 0, RCC_HSICFGR, 0, 2, @@ -1152,6 +1775,176 @@ static const struct clock_config stm32mp1_clock_cfg[] = { STM32_TIM(TIM15_K, "tim15_k", "ck2_tim", RCC_APB2ENSETR, 2), STM32_TIM(TIM16_K, "tim16_k", "ck2_tim", RCC_APB2ENSETR, 3), STM32_TIM(TIM17_K, "tim17_k", "ck2_tim", RCC_APB2ENSETR, 4), + + /* Peripheral clocks */ + PCLK(TIM2, "tim2", "pclk1", CLK_IGNORE_UNUSED, G_TIM2), + PCLK(TIM3, "tim3", "pclk1", CLK_IGNORE_UNUSED, G_TIM3), + PCLK(TIM4, "tim4", "pclk1", CLK_IGNORE_UNUSED, G_TIM4), + PCLK(TIM5, "tim5", "pclk1", CLK_IGNORE_UNUSED, G_TIM5), + PCLK(TIM6, "tim6", "pclk1", CLK_IGNORE_UNUSED, G_TIM6), + PCLK(TIM7, "tim7", "pclk1", CLK_IGNORE_UNUSED, G_TIM7), + PCLK(TIM12, "tim12", "pclk1", CLK_IGNORE_UNUSED, G_TIM12), + PCLK(TIM13, "tim13", "pclk1", CLK_IGNORE_UNUSED, G_TIM13), + PCLK(TIM14, "tim14", "pclk1", CLK_IGNORE_UNUSED, G_TIM14), + PCLK(LPTIM1, "lptim1", "pclk1", 0, G_LPTIM1), + PCLK(SPI2, "spi2", "pclk1", 0, G_SPI2), + PCLK(SPI3, "spi3", "pclk1", 0, G_SPI3), + PCLK(USART2, "usart2", "pclk1", 0, G_USART2), + PCLK(USART3, "usart3", "pclk1", 0, G_USART3), + PCLK(UART4, "uart4", "pclk1", 0, G_UART4), + PCLK(UART5, "uart5", "pclk1", 0, G_UART5), + PCLK(UART7, "uart7", "pclk1", 0, G_UART7), + PCLK(UART8, "uart8", "pclk1", 0, G_UART8), + PCLK(I2C1, "i2c1", "pclk1", 0, G_I2C1), + PCLK(I2C2, "i2c2", "pclk1", 0, G_I2C2), + PCLK(I2C3, "i2c3", "pclk1", 0, G_I2C3), + PCLK(I2C5, "i2c5", "pclk1", 0, G_I2C5), + PCLK(SPDIF, "spdif", "pclk1", 0, G_SPDIF), + PCLK(CEC, "cec", "pclk1", 0, G_CEC), + PCLK(DAC12, "dac12", "pclk1", 0, G_DAC12), + PCLK(MDIO, "mdio", "pclk1", 0, G_MDIO), + PCLK(TIM1, "tim1", "pclk2", CLK_IGNORE_UNUSED, G_TIM1), + PCLK(TIM8, "tim8", "pclk2", CLK_IGNORE_UNUSED, G_TIM8), + PCLK(TIM15, "tim15", "pclk2", CLK_IGNORE_UNUSED, G_TIM15), + PCLK(TIM16, "tim16", "pclk2", CLK_IGNORE_UNUSED, G_TIM16), + PCLK(TIM17, "tim17", "pclk2", CLK_IGNORE_UNUSED, G_TIM17), + PCLK(SPI1, "spi1", "pclk2", 0, G_SPI1), + PCLK(SPI4, "spi4", "pclk2", 0, G_SPI4), + PCLK(SPI5, "spi5", "pclk2", 0, G_SPI5), + PCLK(USART6, "usart6", "pclk2", 0, G_USART6), + PCLK(SAI1, "sai1", "pclk2", 0, G_SAI1), + PCLK(SAI2, "sai2", "pclk2", 0, G_SAI2), + PCLK(SAI3, "sai3", "pclk2", 0, G_SAI3), + PCLK(DFSDM, "dfsdm", "pclk2", 0, G_DFSDM), + PCLK(FDCAN, "fdcan", "pclk2", 0, G_FDCAN), + PCLK(LPTIM2, "lptim2", "pclk3", 0, G_LPTIM2), + PCLK(LPTIM3, "lptim3", "pclk3", 0, G_LPTIM3), + PCLK(LPTIM4, "lptim4", "pclk3", 0, G_LPTIM4), + PCLK(LPTIM5, "lptim5", "pclk3", 0, G_LPTIM5), + PCLK(SAI4, "sai4", "pclk3", 0, G_SAI4), + PCLK(SYSCFG, "syscfg", "pclk3", 0, G_SYSCFG), + PCLK(VREF, "vref", "pclk3", 13, G_VREF), + PCLK(TMPSENS, "tmpsens", "pclk3", 0, G_TMPSENS), + PCLK(PMBCTRL, "pmbctrl", "pclk3", 0, G_PMBCTRL), + PCLK(HDP, "hdp", "pclk3", 0, G_HDP), + PCLK(LTDC, "ltdc", "pclk4", 0, G_LTDC), + PCLK(DSI, "dsi", "pclk4", 0, G_DSI), + PCLK(IWDG2, "iwdg2", "pclk4", 0, G_IWDG2), + PCLK(USBPHY, "usbphy", "pclk4", 0, G_USBPHY), + PCLK(STGENRO, "stgenro", "pclk4", 0, G_STGENRO), + PCLK(SPI6, "spi6", "pclk5", 0, G_SPI6), + PCLK(I2C4, "i2c4", "pclk5", 0, G_I2C4), + PCLK(I2C6, "i2c6", "pclk5", 0, G_I2C6), + PCLK(USART1, "usart1", "pclk5", 0, G_USART1), + PCLK(RTCAPB, "rtcapb", "pclk5", CLK_IGNORE_UNUSED | + CLK_IS_CRITICAL, G_RTCAPB), + PCLK(TZC, "tzc", "pclk5", CLK_IGNORE_UNUSED, G_TZC), + PCLK(TZPC, "tzpc", "pclk5", CLK_IGNORE_UNUSED, G_TZPC), + PCLK(IWDG1, "iwdg1", "pclk5", 0, G_IWDG1), + PCLK(BSEC, "bsec", "pclk5", CLK_IGNORE_UNUSED, G_BSEC), + PCLK(STGEN, "stgen", "pclk5", CLK_IGNORE_UNUSED, G_STGEN), + PCLK(DMA1, "dma1", "ck_mcu", 0, G_DMA1), + PCLK(DMA2, "dma2", "ck_mcu", 0, G_DMA2), + PCLK(DMAMUX, "dmamux", "ck_mcu", 0, G_DMAMUX), + PCLK(ADC12, "adc12", "ck_mcu", 0, G_ADC12), + PCLK(USBO, "usbo", "ck_mcu", 0, G_USBO), + PCLK(SDMMC3, "sdmmc3", "ck_mcu", 0, G_SDMMC3), + PCLK(DCMI, "dcmi", "ck_mcu", 0, G_DCMI), + PCLK(CRYP2, "cryp2", "ck_mcu", 0, G_CRYP2), + PCLK(HASH2, "hash2", "ck_mcu", 0, G_HASH2), + PCLK(RNG2, "rng2", "ck_mcu", 0, G_RNG2), + PCLK(CRC2, "crc2", "ck_mcu", 0, G_CRC2), + PCLK(HSEM, "hsem", "ck_mcu", 0, G_HSEM), + PCLK(IPCC, "ipcc", "ck_mcu", 0, G_IPCC), + PCLK(GPIOA, "gpioa", "ck_mcu", 0, G_GPIOA), + PCLK(GPIOB, "gpiob", "ck_mcu", 0, G_GPIOB), + PCLK(GPIOC, "gpioc", "ck_mcu", 0, G_GPIOC), + PCLK(GPIOD, "gpiod", "ck_mcu", 0, G_GPIOD), + PCLK(GPIOE, "gpioe", "ck_mcu", 0, G_GPIOE), + PCLK(GPIOF, "gpiof", "ck_mcu", 0, G_GPIOF), + PCLK(GPIOG, "gpiog", "ck_mcu", 0, G_GPIOG), + PCLK(GPIOH, "gpioh", "ck_mcu", 0, G_GPIOH), + PCLK(GPIOI, "gpioi", "ck_mcu", 0, G_GPIOI), + PCLK(GPIOJ, "gpioj", "ck_mcu", 0, G_GPIOJ), + PCLK(GPIOK, "gpiok", "ck_mcu", 0, G_GPIOK), + PCLK(GPIOZ, "gpioz", "ck_axi", CLK_IGNORE_UNUSED, G_GPIOZ), + PCLK(CRYP1, "cryp1", "ck_axi", CLK_IGNORE_UNUSED, G_CRYP1), + PCLK(HASH1, "hash1", "ck_axi", CLK_IGNORE_UNUSED, G_HASH1), + PCLK(RNG1, "rng1", "ck_axi", 0, G_RNG1), + PCLK(BKPSRAM, "bkpsram", "ck_axi", CLK_IGNORE_UNUSED, G_BKPSRAM), + PCLK(MDMA, "mdma", "ck_axi", 0, G_MDMA), + PCLK(GPU, "gpu", "ck_axi", 0, G_GPU), + PCLK(ETHTX, "ethtx", "ck_axi", 0, G_ETHTX), + PCLK(ETHRX, "ethrx", "ck_axi", 0, G_ETHRX), + PCLK(ETHMAC, "ethmac", "ck_axi", 0, G_ETHMAC), + PCLK(FMC, "fmc", "ck_axi", CLK_IGNORE_UNUSED, G_FMC), + PCLK(QSPI, "qspi", "ck_axi", CLK_IGNORE_UNUSED, G_QSPI), + PCLK(SDMMC1, "sdmmc1", "ck_axi", 0, G_SDMMC1), + PCLK(SDMMC2, "sdmmc2", "ck_axi", 0, G_SDMMC2), + PCLK(CRC1, "crc1", "ck_axi", 0, G_CRC1), + PCLK(USBH, "usbh", "ck_axi", 0, G_USBH), + PCLK(ETHSTP, "ethstp", "ck_axi", 0, G_ETHSTP), + + /* Kernel clocks */ + KCLK(SDMMC1_K, "sdmmc1_k", sdmmc12_src, 0, G_SDMMC1, M_SDMMC12), + KCLK(SDMMC2_K, "sdmmc2_k", sdmmc12_src, 0, G_SDMMC2, M_SDMMC12), + KCLK(SDMMC3_K, "sdmmc3_k", sdmmc3_src, 0, G_SDMMC3, M_SDMMC3), + KCLK(FMC_K, "fmc_k", fmc_src, 0, G_FMC, M_FMC), + KCLK(QSPI_K, "qspi_k", qspi_src, 0, G_QSPI, M_QSPI), + KCLK(RNG1_K, "rng1_k", rng_src, 0, G_RNG1, M_RNG1), + KCLK(RNG2_K, "rng2_k", rng_src, 0, G_RNG2, M_RNG2), + KCLK(USBPHY_K, "usbphy_k", usbphy_src, 0, G_USBPHY, M_USBPHY), + KCLK(STGEN_K, "stgen_k", stgen_src, CLK_IGNORE_UNUSED, + G_STGEN, M_STGEN), + KCLK(SPDIF_K, "spdif_k", spdif_src, 0, G_SPDIF, M_SPDIF), + KCLK(SPI1_K, "spi1_k", spi123_src, 0, G_SPI1, M_SPI1), + KCLK(SPI2_K, "spi2_k", spi123_src, 0, G_SPI2, M_SPI23), + KCLK(SPI3_K, "spi3_k", spi123_src, 0, G_SPI3, M_SPI23), + KCLK(SPI4_K, "spi4_k", spi45_src, 0, G_SPI4, M_SPI45), + KCLK(SPI5_K, "spi5_k", spi45_src, 0, G_SPI5, M_SPI45), + KCLK(SPI6_K, "spi6_k", spi6_src, 0, G_SPI6, M_SPI6), + KCLK(CEC_K, "cec_k", cec_src, 0, G_CEC, M_CEC), + KCLK(I2C1_K, "i2c1_k", i2c12_src, 0, G_I2C1, M_I2C12), + KCLK(I2C2_K, "i2c2_k", i2c12_src, 0, G_I2C2, M_I2C12), + KCLK(I2C3_K, "i2c3_k", i2c35_src, 0, G_I2C3, M_I2C35), + KCLK(I2C5_K, "i2c5_k", i2c35_src, 0, G_I2C5, M_I2C35), + KCLK(I2C4_K, "i2c4_k", i2c46_src, 0, G_I2C4, M_I2C46), + KCLK(I2C6_K, "i2c6_k", i2c46_src, 0, G_I2C6, M_I2C46), + KCLK(LPTIM1_K, "lptim1_k", lptim1_src, 0, G_LPTIM1, M_LPTIM1), + KCLK(LPTIM2_K, "lptim2_k", lptim23_src, 0, G_LPTIM2, M_LPTIM23), + KCLK(LPTIM3_K, "lptim3_k", lptim23_src, 0, G_LPTIM3, M_LPTIM23), + KCLK(LPTIM4_K, "lptim4_k", lptim45_src, 0, G_LPTIM4, M_LPTIM45), + KCLK(LPTIM5_K, "lptim5_k", lptim45_src, 0, G_LPTIM5, M_LPTIM45), + KCLK(USART1_K, "usart1_k", usart1_src, 0, G_USART1, M_USART1), + KCLK(USART2_K, "usart2_k", usart234578_src, 0, G_USART2, M_UART24), + KCLK(USART3_K, "usart3_k", usart234578_src, 0, G_USART3, M_UART35), + KCLK(UART4_K, "uart4_k", usart234578_src, 0, G_UART4, M_UART24), + KCLK(UART5_K, "uart5_k", usart234578_src, 0, G_UART5, M_UART35), + KCLK(USART6_K, "uart6_k", usart6_src, 0, G_USART6, M_USART6), + KCLK(UART7_K, "uart7_k", usart234578_src, 0, G_UART7, M_UART78), + KCLK(UART8_K, "uart8_k", usart234578_src, 0, G_UART8, M_UART78), + KCLK(FDCAN_K, "fdcan_k", fdcan_src, 0, G_FDCAN, M_FDCAN), + KCLK(SAI1_K, "sai1_k", sai_src, 0, G_SAI1, M_SAI1), + KCLK(SAI2_K, "sai2_k", sai2_src, 0, G_SAI2, M_SAI2), + KCLK(SAI3_K, "sai3_k", sai_src, 0, G_SAI2, M_SAI3), + KCLK(SAI4_K, "sai4_k", sai_src, 0, G_SAI2, M_SAI4), + KCLK(ADC12_K, "adc12_k", adc12_src, 0, G_ADC12, M_ADC12), + KCLK(DSI_K, "dsi_k", dsi_src, 0, G_DSI, M_DSI), + KCLK(ADFSDM_K, "adfsdm_k", sai_src, 0, G_ADFSDM, M_SAI1), + KCLK(USBO_K, "usbo_k", usbo_src, 0, G_USBO, M_USBO), + KCLK(ETHCK_K, "ethck_k", eth_src, 0, G_ETHCK, M_ETHCK), + + /* Particulary Kernel Clocks (no mux or no gate) */ + MGATE_MP1(DFSDM_K, "dfsdm_k", "ck_mcu", 0, G_DFSDM), + MGATE_MP1(DSI_PX, "dsi_px", "pll4_q", CLK_SET_RATE_PARENT, G_DSI), + MGATE_MP1(LTDC_PX, "ltdc_px", "pll4_q", CLK_SET_RATE_PARENT, G_LTDC), + MGATE_MP1(GPU_K, "gpu_k", "pll2_q", 0, G_GPU), + MGATE_MP1(DAC12_K, "dac12_k", "ck_lsi", 0, G_DAC12), + + COMPOSITE(ETHPTP_K, "ethptp_k", eth_src, CLK_OPS_PARENT_ENABLE, + _NO_GATE, + _MMUX(M_ETHCK), + _DIV(RCC_ETHCKSELR, 4, 4, CLK_DIVIDER_ALLOW_ZERO, NULL)), }; struct stm32_clock_match_data { -- cgit From 2c87c9d33117446dab774a7e1b23806802f95c98 Mon Sep 17 00:00:00 2001 From: Gabriel Fernandez Date: Thu, 8 Mar 2018 17:54:03 +0100 Subject: clk: stm32mp1: add RTC clock This patch adds the RTC clock. Signed-off-by: Gabriel Fernandez Signed-off-by: Michael Turquette --- drivers/clk/clk-stm32mp1.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/clk/clk-stm32mp1.c b/drivers/clk/clk-stm32mp1.c index b5379a224183..51e3e76b8fa5 100644 --- a/drivers/clk/clk-stm32mp1.c +++ b/drivers/clk/clk-stm32mp1.c @@ -248,6 +248,10 @@ static const char * const dsi_src[] = { "ck_dsi_phy", "pll4_p" }; +static const char * const rtc_src[] = { + "off", "ck_lse", "ck_lsi", "ck_hse_rtc" +}; + static const struct clk_div_table axi_div_table[] = { { 0, 1 }, { 1, 2 }, { 2, 3 }, { 3, 4 }, { 4, 4 }, { 5, 4 }, { 6, 4 }, { 7, 4 }, @@ -1945,6 +1949,17 @@ static const struct clock_config stm32mp1_clock_cfg[] = { _NO_GATE, _MMUX(M_ETHCK), _DIV(RCC_ETHCKSELR, 4, 4, CLK_DIVIDER_ALLOW_ZERO, NULL)), + + /* RTC clock */ + DIV(NO_ID, "ck_hse_rtc", "ck_hse", 0, RCC_RTCDIVR, 0, 7, + CLK_DIVIDER_ALLOW_ZERO), + + COMPOSITE(RTC, "ck_rtc", rtc_src, CLK_OPS_PARENT_ENABLE | + CLK_SET_RATE_PARENT, + _GATE(RCC_BDCR, 20, 0), + _MUX(RCC_BDCR, 16, 2, 0), + _NO_DIV), + }; struct stm32_clock_match_data { -- cgit From 44cd455a8edb4026ae2c1c6fb6895523712c4896 Mon Sep 17 00:00:00 2001 From: Gabriel Fernandez Date: Thu, 8 Mar 2018 17:54:04 +0100 Subject: clk: stm32mp1: add MCO clocks Two micro-controller clock output (MCO) pins are available: MCO1 and MCO2. For each output, it is possible to select a clock source. The selected clock can be divided thanks to configurable prescaler. Signed-off-by: Gabriel Fernandez Signed-off-by: Michael Turquette --- drivers/clk/clk-stm32mp1.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/drivers/clk/clk-stm32mp1.c b/drivers/clk/clk-stm32mp1.c index 51e3e76b8fa5..b3a6ec4d9e9e 100644 --- a/drivers/clk/clk-stm32mp1.c +++ b/drivers/clk/clk-stm32mp1.c @@ -252,6 +252,14 @@ static const char * const rtc_src[] = { "off", "ck_lse", "ck_lsi", "ck_hse_rtc" }; +static const char * const mco1_src[] = { + "ck_hsi", "ck_hse", "ck_csi", "ck_lsi", "ck_lse" +}; + +static const char * const mco2_src[] = { + "ck_mpu", "ck_axi", "ck_mcu", "pll4_p", "ck_hse", "ck_hsi" +}; + static const struct clk_div_table axi_div_table[] = { { 0, 1 }, { 1, 2 }, { 2, 3 }, { 3, 4 }, { 4, 4 }, { 5, 4 }, { 6, 4 }, { 7, 4 }, @@ -1960,6 +1968,18 @@ static const struct clock_config stm32mp1_clock_cfg[] = { _MUX(RCC_BDCR, 16, 2, 0), _NO_DIV), + /* MCO clocks */ + COMPOSITE(CK_MCO1, "ck_mco1", mco1_src, CLK_OPS_PARENT_ENABLE | + CLK_SET_RATE_NO_REPARENT, + _GATE(RCC_MCO1CFGR, 12, 0), + _MUX(RCC_MCO1CFGR, 0, 3, 0), + _DIV(RCC_MCO1CFGR, 4, 4, 0, NULL)), + + COMPOSITE(CK_MCO2, "ck_mco2", mco2_src, CLK_OPS_PARENT_ENABLE | + CLK_SET_RATE_NO_REPARENT, + _GATE(RCC_MCO2CFGR, 12, 0), + _MUX(RCC_MCO2CFGR, 0, 3, 0), + _DIV(RCC_MCO2CFGR, 4, 4, 0, NULL)), }; struct stm32_clock_match_data { -- cgit From 3a430067838a4e47ff473999b2f6a5a7be92dba7 Mon Sep 17 00:00:00 2001 From: Gabriel Fernandez Date: Thu, 8 Mar 2018 17:54:05 +0100 Subject: clk: stm32mp1: add Debug clocks RCC manages clock for debug and trace. Signed-off-by: Gabriel Fernandez Signed-off-by: Michael Turquette --- drivers/clk/clk-stm32mp1.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/drivers/clk/clk-stm32mp1.c b/drivers/clk/clk-stm32mp1.c index b3a6ec4d9e9e..f1d5967b4b39 100644 --- a/drivers/clk/clk-stm32mp1.c +++ b/drivers/clk/clk-stm32mp1.c @@ -260,6 +260,10 @@ static const char * const mco2_src[] = { "ck_mpu", "ck_axi", "ck_mcu", "pll4_p", "ck_hse", "ck_hsi" }; +static const char * const ck_trace_src[] = { + "ck_axi" +}; + static const struct clk_div_table axi_div_table[] = { { 0, 1 }, { 1, 2 }, { 2, 3 }, { 3, 4 }, { 4, 4 }, { 5, 4 }, { 6, 4 }, { 7, 4 }, @@ -280,6 +284,12 @@ static const struct clk_div_table apb_div_table[] = { { 0 }, }; +static const struct clk_div_table ck_trace_div_table[] = { + { 0, 1 }, { 1, 2 }, { 2, 4 }, { 3, 8 }, + { 4, 16 }, { 5, 16 }, { 6, 16 }, { 7, 16 }, + { 0 }, +}; + #define MAX_MUX_CLK 2 struct stm32_mmux { @@ -1980,6 +1990,18 @@ static const struct clock_config stm32mp1_clock_cfg[] = { _GATE(RCC_MCO2CFGR, 12, 0), _MUX(RCC_MCO2CFGR, 0, 3, 0), _DIV(RCC_MCO2CFGR, 4, 4, 0, NULL)), + + /* Debug clocks */ + FIXED_FACTOR(NO_ID, "ck_axi_div2", "ck_axi", 0, 1, 2), + + GATE(DBG, "ck_apb_dbg", "ck_axi_div2", 0, RCC_DBGCFGR, 8, 0), + + GATE(CK_DBG, "ck_sys_dbg", "ck_axi", 0, RCC_DBGCFGR, 8, 0), + + COMPOSITE(CK_TRACE, "ck_trace", ck_trace_src, CLK_OPS_PARENT_ENABLE, + _GATE(RCC_DBGCFGR, 9, 0), + _NO_MUX, + _DIV(RCC_DBGCFGR, 0, 3, 0, ck_trace_div_table)), }; struct stm32_clock_match_data { -- cgit From 811f67cc16ec76c3953ca1b9d7c34e3f0c17f779 Mon Sep 17 00:00:00 2001 From: tianshuliang Date: Mon, 5 Mar 2018 15:01:31 +0800 Subject: clk: hisilicon: add hisi phase clock support Add a phase clock type for HiSilicon SoCs,which supports clk_set_phase operation. Signed-off-by: tianshuliang Signed-off-by: Jiancheng Xue Signed-off-by: Shawn Guo --- drivers/clk/hisilicon/Makefile | 2 +- drivers/clk/hisilicon/clk-hisi-phase.c | 121 +++++++++++++++++++++++++++++++++ drivers/clk/hisilicon/clk.c | 24 +++++++ drivers/clk/hisilicon/clk.h | 19 ++++++ 4 files changed, 165 insertions(+), 1 deletion(-) create mode 100644 drivers/clk/hisilicon/clk-hisi-phase.c diff --git a/drivers/clk/hisilicon/Makefile b/drivers/clk/hisilicon/Makefile index 4806fc2cb4ac..2a714c0f9657 100644 --- a/drivers/clk/hisilicon/Makefile +++ b/drivers/clk/hisilicon/Makefile @@ -3,7 +3,7 @@ # Hisilicon Clock specific Makefile # -obj-y += clk.o clkgate-separated.o clkdivider-hi6220.o +obj-y += clk.o clkgate-separated.o clkdivider-hi6220.o clk-hisi-phase.o obj-$(CONFIG_ARCH_HI3xxx) += clk-hi3620.o obj-$(CONFIG_ARCH_HIP04) += clk-hip04.o diff --git a/drivers/clk/hisilicon/clk-hisi-phase.c b/drivers/clk/hisilicon/clk-hisi-phase.c new file mode 100644 index 000000000000..42ce157ff828 --- /dev/null +++ b/drivers/clk/hisilicon/clk-hisi-phase.c @@ -0,0 +1,121 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2017 HiSilicon Technologies Co., Ltd. + * + * Simple HiSilicon phase clock implementation. + */ + +#include +#include +#include +#include +#include + +#include "clk.h" + +struct clk_hisi_phase { + struct clk_hw hw; + void __iomem *reg; + u32 *phase_degrees; + u32 *phase_regvals; + u8 phase_num; + u32 mask; + u8 shift; + u8 flags; + spinlock_t *lock; +}; + +#define to_clk_hisi_phase(_hw) container_of(_hw, struct clk_hisi_phase, hw) + +static int hisi_phase_regval_to_degrees(struct clk_hisi_phase *phase, + u32 regval) +{ + int i; + + for (i = 0; i < phase->phase_num; i++) + if (phase->phase_regvals[i] == regval) + return phase->phase_degrees[i]; + + return -EINVAL; +} + +static int hisi_clk_get_phase(struct clk_hw *hw) +{ + struct clk_hisi_phase *phase = to_clk_hisi_phase(hw); + u32 regval; + + regval = readl(phase->reg); + regval = (regval & phase->mask) >> phase->shift; + + return hisi_phase_regval_to_degrees(phase, regval); +} + +static int hisi_phase_degrees_to_regval(struct clk_hisi_phase *phase, + int degrees) +{ + int i; + + for (i = 0; i < phase->phase_num; i++) + if (phase->phase_degrees[i] == degrees) + return phase->phase_regvals[i]; + + return -EINVAL; +} + +static int hisi_clk_set_phase(struct clk_hw *hw, int degrees) +{ + struct clk_hisi_phase *phase = to_clk_hisi_phase(hw); + unsigned long flags = 0; + int regval; + u32 val; + + regval = hisi_phase_degrees_to_regval(phase, degrees); + if (regval < 0) + return regval; + + spin_lock_irqsave(phase->lock, flags); + + val = clk_readl(phase->reg); + val &= ~phase->mask; + val |= regval << phase->shift; + clk_writel(val, phase->reg); + + spin_unlock_irqrestore(phase->lock, flags); + + return 0; +} + +const struct clk_ops clk_phase_ops = { + .get_phase = hisi_clk_get_phase, + .set_phase = hisi_clk_set_phase, +}; + +struct clk *clk_register_hisi_phase(struct device *dev, + const struct hisi_phase_clock *clks, + void __iomem *base, spinlock_t *lock) +{ + struct clk_hisi_phase *phase; + struct clk_init_data init; + + phase = devm_kzalloc(dev, sizeof(struct clk_hisi_phase), GFP_KERNEL); + if (!phase) + return ERR_PTR(-ENOMEM); + + init.name = clks->name; + init.ops = &clk_phase_ops; + init.flags = clks->flags | CLK_IS_BASIC; + init.parent_names = clks->parent_names ? &clks->parent_names : NULL; + init.num_parents = clks->parent_names ? 1 : 0; + + phase->reg = base + clks->offset; + phase->shift = clks->shift; + phase->mask = (BIT(clks->width) - 1) << clks->shift; + phase->lock = lock; + phase->phase_degrees = clks->phase_degrees; + phase->phase_regvals = clks->phase_regvals; + phase->phase_num = clks->phase_num; + phase->hw.init = &init; + + return devm_clk_register(dev, &phase->hw); +} +EXPORT_SYMBOL_GPL(clk_register_hisi_phase); diff --git a/drivers/clk/hisilicon/clk.c b/drivers/clk/hisilicon/clk.c index b73c1dfae7f1..29046b8334c2 100644 --- a/drivers/clk/hisilicon/clk.c +++ b/drivers/clk/hisilicon/clk.c @@ -197,6 +197,30 @@ err: } EXPORT_SYMBOL_GPL(hisi_clk_register_mux); +int hisi_clk_register_phase(struct device *dev, + const struct hisi_phase_clock *clks, + int nums, struct hisi_clock_data *data) +{ + void __iomem *base = data->base; + struct clk *clk; + int i; + + for (i = 0; i < nums; i++) { + clk = clk_register_hisi_phase(dev, &clks[i], base, + &hisi_clk_lock); + if (IS_ERR(clk)) { + pr_err("%s: failed to register clock %s\n", __func__, + clks[i].name); + return PTR_ERR(clk); + } + + data->clk_data.clks[clks[i].id] = clk; + } + + return 0; +} +EXPORT_SYMBOL_GPL(hisi_clk_register_phase); + int hisi_clk_register_divider(const struct hisi_divider_clock *clks, int nums, struct hisi_clock_data *data) { diff --git a/drivers/clk/hisilicon/clk.h b/drivers/clk/hisilicon/clk.h index 4e1d1affc6f5..8d7ee5c3231b 100644 --- a/drivers/clk/hisilicon/clk.h +++ b/drivers/clk/hisilicon/clk.h @@ -68,6 +68,19 @@ struct hisi_mux_clock { const char *alias; }; +struct hisi_phase_clock { + unsigned int id; + const char *name; + const char *parent_names; + unsigned long flags; + unsigned long offset; + u8 shift; + u8 width; + u32 *phase_degrees; + u32 *phase_regvals; + u8 phase_num; +}; + struct hisi_divider_clock { unsigned int id; const char *name; @@ -120,6 +133,12 @@ int hisi_clk_register_fixed_factor(const struct hisi_fixed_factor_clock *, int, struct hisi_clock_data *); int hisi_clk_register_mux(const struct hisi_mux_clock *, int, struct hisi_clock_data *); +struct clk *clk_register_hisi_phase(struct device *dev, + const struct hisi_phase_clock *clks, + void __iomem *base, spinlock_t *lock); +int hisi_clk_register_phase(struct device *dev, + const struct hisi_phase_clock *clks, + int nums, struct hisi_clock_data *data); int hisi_clk_register_divider(const struct hisi_divider_clock *, int, struct hisi_clock_data *); int hisi_clk_register_gate(const struct hisi_gate_clock *, -- cgit From d1b0399543cec5fa5d3a2d33b525a7cd7912e635 Mon Sep 17 00:00:00 2001 From: tianshuliang Date: Mon, 5 Mar 2018 15:01:32 +0800 Subject: clk: hi3798cv200: add emmc sample and drive clock It adds eMMC sample clock HISTB_MMC_SAMPLE_CLK and drive clock HISTB_MMC_DRV_CLK support for Hi3798cv200 SoC. Signed-off-by: tianshuliang Signed-off-by: Jiancheng Xue Signed-off-by: Shawn Guo --- drivers/clk/hisilicon/crg-hi3798cv200.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/drivers/clk/hisilicon/crg-hi3798cv200.c b/drivers/clk/hisilicon/crg-hi3798cv200.c index d6e3971bac9e..743eec131528 100644 --- a/drivers/clk/hisilicon/crg-hi3798cv200.c +++ b/drivers/clk/hisilicon/crg-hi3798cv200.c @@ -97,6 +97,18 @@ static struct hisi_mux_clock hi3798cv200_mux_clks[] = { 0x9c, 8, 2, 0, sdio_mux_table, }, }; +static u32 mmc_phase_regvals[] = {0, 1, 2, 3, 4, 5, 6, 7}; +static u32 mmc_phase_degrees[] = {0, 45, 90, 135, 180, 225, 270, 315}; + +static struct hisi_phase_clock hi3798cv200_phase_clks[] = { + { HISTB_MMC_SAMPLE_CLK, "mmc_sample", "clk_mmc_ciu", + CLK_SET_RATE_PARENT, 0xa0, 12, 3, mmc_phase_degrees, + mmc_phase_regvals, ARRAY_SIZE(mmc_phase_regvals) }, + { HISTB_MMC_DRV_CLK, "mmc_drive", "clk_mmc_ciu", + CLK_SET_RATE_PARENT, 0xa0, 16, 3, mmc_phase_degrees, + mmc_phase_regvals, ARRAY_SIZE(mmc_phase_regvals) }, +}; + static const struct hisi_gate_clock hi3798cv200_gate_clks[] = { /* UART */ { HISTB_UART2_CLK, "clk_uart2", "75m", @@ -186,6 +198,14 @@ static struct hisi_clock_data *hi3798cv200_clk_register( if (!clk_data) return ERR_PTR(-ENOMEM); + /* hisi_phase_clock is resource managed */ + ret = hisi_clk_register_phase(&pdev->dev, + hi3798cv200_phase_clks, + ARRAY_SIZE(hi3798cv200_phase_clks), + clk_data); + if (ret) + return ERR_PTR(ret); + ret = hisi_clk_register_fixed_rate(hi3798cv200_fixed_rate_clks, ARRAY_SIZE(hi3798cv200_fixed_rate_clks), clk_data); -- cgit From 06255a92793925474ea806d0c46ed8a82c49bcc7 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Wed, 7 Mar 2018 17:46:55 +0100 Subject: clk: samsung: exynos5420: Add CLK_SET_RATE_PARENT flag to mout_mau_epll_clk This allows changing the EPLL output frequency through the audio subsystem clock tree leaf clocks. This change is needed to support audio on the HDMI interface on Peach-Pi(t) Chromebook. Signed-off-by: Sylwester Nawrocki Acked-by: Chanwoo Choi Signed-off-by: Sylwester Nawrocki --- drivers/clk/samsung/clk-exynos5420.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/clk/samsung/clk-exynos5420.c b/drivers/clk/samsung/clk-exynos5420.c index c7b0f55dfbb6..1bb6e103509f 100644 --- a/drivers/clk/samsung/clk-exynos5420.c +++ b/drivers/clk/samsung/clk-exynos5420.c @@ -621,7 +621,8 @@ static const struct samsung_mux_clock exynos5420_mux_clks[] __initconst = { MUX(CLK_MOUT_MX_MSPLL_CCORE, "mout_mx_mspll_ccore", mout_group5_5800_p, SRC_TOP7, 16, 2), - MUX(0, "mout_mau_epll_clk", mout_mau_epll_clk_p, SRC_TOP7, 20, 2), + MUX_F(0, "mout_mau_epll_clk", mout_mau_epll_clk_p, SRC_TOP7, 20, 2, + CLK_SET_RATE_PARENT, 0), MUX(0, "mout_fimd1", mout_group3_p, SRC_DISP10, 4, 1), }; -- cgit From 948e068454568789792f9f10c3242c2bfb8ddbdc Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Mon, 12 Mar 2018 11:23:27 +0100 Subject: clk: samsung: exynos5420: Add more entries to EPLL rate table Adding these EPLL output frequency entries allows to support all required audio sample rates on the CODEC and the HDMI interface on Peach-Pit Chromebook. Signed-off-by: Sylwester Nawrocki Acked-by: Chanwoo Choi Signed-off-by: Sylwester Nawrocki --- drivers/clk/samsung/clk-exynos5420.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/clk/samsung/clk-exynos5420.c b/drivers/clk/samsung/clk-exynos5420.c index 1bb6e103509f..95e1bf69449b 100644 --- a/drivers/clk/samsung/clk-exynos5420.c +++ b/drivers/clk/samsung/clk-exynos5420.c @@ -1360,8 +1360,11 @@ static const struct samsung_pll_rate_table exynos5420_epll_24mhz_tbl[] = { PLL_36XX_RATE(24 * MHZ, 180633609U, 301, 5, 3, 3671), PLL_36XX_RATE(24 * MHZ, 131072006U, 131, 3, 3, 4719), PLL_36XX_RATE(24 * MHZ, 100000000U, 200, 3, 4, 0), + PLL_36XX_RATE(24 * MHZ, 73728000U, 98, 2, 4, 19923), + PLL_36XX_RATE(24 * MHZ, 67737602U, 90, 2, 4, 20762), PLL_36XX_RATE(24 * MHZ, 65536003U, 131, 3, 4, 4719), PLL_36XX_RATE(24 * MHZ, 49152000U, 197, 3, 5, -25690), + PLL_36XX_RATE(24 * MHZ, 45158401U, 90, 3, 4, 20762), PLL_36XX_RATE(24 * MHZ, 32768001U, 131, 3, 5, 4719), }; -- cgit From 2dcabf053c6ecde46f7aa3612c5a57fb8bd185c4 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Wed, 10 Jan 2018 16:59:42 +0300 Subject: clk: tegra: Mark HCLK, SCLK and EMC as critical Machine dies if HCLK, SCLK or EMC is disabled. Hence mark these clocks as critical. Signed-off-by: Dmitry Osipenko Acked-by: Peter De Schrijver Cc: # v4.16 Signed-off-by: Thierry Reding --- drivers/clk/tegra/clk-emc.c | 2 +- drivers/clk/tegra/clk-tegra-periph.c | 2 +- drivers/clk/tegra/clk-tegra-super-gen4.c | 8 +++++--- drivers/clk/tegra/clk-tegra114.c | 3 +-- drivers/clk/tegra/clk-tegra124.c | 7 +++---- drivers/clk/tegra/clk-tegra20.c | 23 ++++++++++------------- drivers/clk/tegra/clk-tegra210.c | 3 +-- drivers/clk/tegra/clk-tegra30.c | 14 ++++---------- 8 files changed, 26 insertions(+), 36 deletions(-) diff --git a/drivers/clk/tegra/clk-emc.c b/drivers/clk/tegra/clk-emc.c index 11a5066e5c27..5234acd30e89 100644 --- a/drivers/clk/tegra/clk-emc.c +++ b/drivers/clk/tegra/clk-emc.c @@ -515,7 +515,7 @@ struct clk *tegra_clk_register_emc(void __iomem *base, struct device_node *np, init.name = "emc"; init.ops = &tegra_clk_emc_ops; - init.flags = 0; + init.flags = CLK_IS_CRITICAL; init.parent_names = emc_parent_clk_names; init.num_parents = ARRAY_SIZE(emc_parent_clk_names); diff --git a/drivers/clk/tegra/clk-tegra-periph.c b/drivers/clk/tegra/clk-tegra-periph.c index c02711927d79..2acba2986bc6 100644 --- a/drivers/clk/tegra/clk-tegra-periph.c +++ b/drivers/clk/tegra/clk-tegra-periph.c @@ -830,7 +830,7 @@ static struct tegra_periph_init_data gate_clks[] = { GATE("xusb_host", "xusb_host_src", 89, 0, tegra_clk_xusb_host, 0), GATE("xusb_ss", "xusb_ss_src", 156, 0, tegra_clk_xusb_ss, 0), GATE("xusb_dev", "xusb_dev_src", 95, 0, tegra_clk_xusb_dev, 0), - GATE("emc", "emc_mux", 57, 0, tegra_clk_emc, CLK_IGNORE_UNUSED), + GATE("emc", "emc_mux", 57, 0, tegra_clk_emc, CLK_IS_CRITICAL), GATE("sata_cold", "clk_m", 129, TEGRA_PERIPH_ON_APB, tegra_clk_sata_cold, 0), GATE("ispa", "isp", 23, 0, tegra_clk_ispa, 0), GATE("ispb", "isp", 3, 0, tegra_clk_ispb, 0), diff --git a/drivers/clk/tegra/clk-tegra-super-gen4.c b/drivers/clk/tegra/clk-tegra-super-gen4.c index 10047107c1dc..89d6b47a27a8 100644 --- a/drivers/clk/tegra/clk-tegra-super-gen4.c +++ b/drivers/clk/tegra/clk-tegra-super-gen4.c @@ -125,7 +125,8 @@ static void __init tegra_sclk_init(void __iomem *clk_base, /* SCLK */ dt_clk = tegra_lookup_dt_id(tegra_clk_sclk, tegra_clks); if (dt_clk) { - clk = clk_register_divider(NULL, "sclk", "sclk_mux", 0, + clk = clk_register_divider(NULL, "sclk", "sclk_mux", + CLK_IS_CRITICAL, clk_base + SCLK_DIVIDER, 0, 8, 0, &sysrate_lock); *dt_clk = clk; @@ -137,7 +138,8 @@ static void __init tegra_sclk_init(void __iomem *clk_base, clk = tegra_clk_register_super_mux("sclk", gen_info->sclk_parents, gen_info->num_sclk_parents, - CLK_SET_RATE_PARENT, + CLK_SET_RATE_PARENT | + CLK_IS_CRITICAL, clk_base + SCLK_BURST_POLICY, 0, 4, 0, 0, NULL); *dt_clk = clk; @@ -151,7 +153,7 @@ static void __init tegra_sclk_init(void __iomem *clk_base, clk_base + SYSTEM_CLK_RATE, 4, 2, 0, &sysrate_lock); clk = clk_register_gate(NULL, "hclk", "hclk_div", - CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, clk_base + SYSTEM_CLK_RATE, 7, CLK_GATE_SET_TO_DISABLE, &sysrate_lock); *dt_clk = clk; diff --git a/drivers/clk/tegra/clk-tegra114.c b/drivers/clk/tegra/clk-tegra114.c index 63087d17c3e2..c3945c683f60 100644 --- a/drivers/clk/tegra/clk-tegra114.c +++ b/drivers/clk/tegra/clk-tegra114.c @@ -955,8 +955,7 @@ static void __init tegra114_pll_init(void __iomem *clk_base, /* PLLM */ clk = tegra_clk_register_pllm("pll_m", "pll_ref", clk_base, pmc, - CLK_IGNORE_UNUSED | CLK_SET_RATE_GATE, - &pll_m_params, NULL); + CLK_SET_RATE_GATE, &pll_m_params, NULL); clks[TEGRA114_CLK_PLL_M] = clk; /* PLLM_OUT1 */ diff --git a/drivers/clk/tegra/clk-tegra124.c b/drivers/clk/tegra/clk-tegra124.c index e81ea5b11577..230f9a2c1abf 100644 --- a/drivers/clk/tegra/clk-tegra124.c +++ b/drivers/clk/tegra/clk-tegra124.c @@ -1089,8 +1089,7 @@ static void __init tegra124_pll_init(void __iomem *clk_base, /* PLLM */ clk = tegra_clk_register_pllm("pll_m", "pll_ref", clk_base, pmc, - CLK_IGNORE_UNUSED | CLK_SET_RATE_GATE, - &pll_m_params, NULL); + CLK_SET_RATE_GATE, &pll_m_params, NULL); clk_register_clkdev(clk, "pll_m", NULL); clks[TEGRA124_CLK_PLL_M] = clk; @@ -1099,7 +1098,7 @@ static void __init tegra124_pll_init(void __iomem *clk_base, clk_base + PLLM_OUT, 0, TEGRA_DIVIDER_ROUND_UP, 8, 8, 1, NULL); clk = tegra_clk_register_pll_out("pll_m_out1", "pll_m_out1_div", - clk_base + PLLM_OUT, 1, 0, CLK_IGNORE_UNUSED | + clk_base + PLLM_OUT, 1, 0, CLK_SET_RATE_PARENT, 0, NULL); clk_register_clkdev(clk, "pll_m_out1", NULL); clks[TEGRA124_CLK_PLL_M_OUT1] = clk; @@ -1272,7 +1271,7 @@ static struct tegra_clk_init_table common_init_table[] __initdata = { { TEGRA124_CLK_HOST1X, TEGRA124_CLK_PLL_P, 136000000, 1 }, { TEGRA124_CLK_DSIALP, TEGRA124_CLK_PLL_P, 68000000, 0 }, { TEGRA124_CLK_DSIBLP, TEGRA124_CLK_PLL_P, 68000000, 0 }, - { TEGRA124_CLK_SCLK, TEGRA124_CLK_PLL_P_OUT2, 102000000, 1 }, + { TEGRA124_CLK_SCLK, TEGRA124_CLK_PLL_P_OUT2, 102000000, 0 }, { TEGRA124_CLK_DFLL_SOC, TEGRA124_CLK_PLL_P, 51000000, 1 }, { TEGRA124_CLK_DFLL_REF, TEGRA124_CLK_PLL_P, 51000000, 1 }, { TEGRA124_CLK_PLL_C, TEGRA124_CLK_CLK_MAX, 768000000, 0 }, diff --git a/drivers/clk/tegra/clk-tegra20.c b/drivers/clk/tegra/clk-tegra20.c index cbd5a2e5c569..e3392ca2c2fc 100644 --- a/drivers/clk/tegra/clk-tegra20.c +++ b/drivers/clk/tegra/clk-tegra20.c @@ -576,6 +576,7 @@ static struct tegra_clk tegra20_clks[tegra_clk_max] __initdata = { [tegra_clk_afi] = { .dt_id = TEGRA20_CLK_AFI, .present = true }, [tegra_clk_fuse] = { .dt_id = TEGRA20_CLK_FUSE, .present = true }, [tegra_clk_kfuse] = { .dt_id = TEGRA20_CLK_KFUSE, .present = true }, + [tegra_clk_emc] = { .dt_id = TEGRA20_CLK_EMC, .present = true }, }; static unsigned long tegra20_clk_measure_input_freq(void) @@ -651,8 +652,7 @@ static void tegra20_pll_init(void) /* PLLM */ clk = tegra_clk_register_pll("pll_m", "pll_ref", clk_base, NULL, - CLK_IGNORE_UNUSED | CLK_SET_RATE_GATE, - &pll_m_params, NULL); + CLK_SET_RATE_GATE, &pll_m_params, NULL); clks[TEGRA20_CLK_PLL_M] = clk; /* PLLM_OUT1 */ @@ -660,7 +660,7 @@ static void tegra20_pll_init(void) clk_base + PLLM_OUT, 0, TEGRA_DIVIDER_ROUND_UP, 8, 8, 1, NULL); clk = tegra_clk_register_pll_out("pll_m_out1", "pll_m_out1_div", - clk_base + PLLM_OUT, 1, 0, CLK_IGNORE_UNUSED | + clk_base + PLLM_OUT, 1, 0, CLK_SET_RATE_PARENT, 0, NULL); clks[TEGRA20_CLK_PLL_M_OUT1] = clk; @@ -723,7 +723,8 @@ static void tegra20_super_clk_init(void) /* SCLK */ clk = tegra_clk_register_super_mux("sclk", sclk_parents, - ARRAY_SIZE(sclk_parents), CLK_SET_RATE_PARENT, + ARRAY_SIZE(sclk_parents), + CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, clk_base + SCLK_BURST_POLICY, 0, 4, 0, 0, NULL); clks[TEGRA20_CLK_SCLK] = clk; @@ -814,9 +815,6 @@ static void __init tegra20_periph_clk_init(void) CLK_SET_RATE_NO_REPARENT, clk_base + CLK_SOURCE_EMC, 30, 2, 0, &emc_lock); - clk = tegra_clk_register_periph_gate("emc", "emc_mux", 0, clk_base, 0, - 57, periph_clk_enb_refcnt); - clks[TEGRA20_CLK_EMC] = clk; clk = tegra_clk_register_mc("mc", "emc_mux", clk_base + CLK_SOURCE_EMC, &emc_lock); @@ -1019,13 +1017,12 @@ static struct tegra_clk_init_table init_table[] __initdata = { { TEGRA20_CLK_PLL_P_OUT2, TEGRA20_CLK_CLK_MAX, 48000000, 1 }, { TEGRA20_CLK_PLL_P_OUT3, TEGRA20_CLK_CLK_MAX, 72000000, 1 }, { TEGRA20_CLK_PLL_P_OUT4, TEGRA20_CLK_CLK_MAX, 24000000, 1 }, - { TEGRA20_CLK_PLL_C, TEGRA20_CLK_CLK_MAX, 600000000, 1 }, - { TEGRA20_CLK_PLL_C_OUT1, TEGRA20_CLK_CLK_MAX, 216000000, 1 }, - { TEGRA20_CLK_SCLK, TEGRA20_CLK_PLL_C_OUT1, 0, 1 }, - { TEGRA20_CLK_HCLK, TEGRA20_CLK_CLK_MAX, 0, 1 }, - { TEGRA20_CLK_PCLK, TEGRA20_CLK_CLK_MAX, 60000000, 1 }, + { TEGRA20_CLK_PLL_C, TEGRA20_CLK_CLK_MAX, 600000000, 0 }, + { TEGRA20_CLK_PLL_C_OUT1, TEGRA20_CLK_CLK_MAX, 216000000, 0 }, + { TEGRA20_CLK_SCLK, TEGRA20_CLK_PLL_C_OUT1, 0, 0 }, + { TEGRA20_CLK_HCLK, TEGRA20_CLK_CLK_MAX, 0, 0 }, + { TEGRA20_CLK_PCLK, TEGRA20_CLK_CLK_MAX, 60000000, 0 }, { TEGRA20_CLK_CSITE, TEGRA20_CLK_CLK_MAX, 0, 1 }, - { TEGRA20_CLK_EMC, TEGRA20_CLK_CLK_MAX, 0, 1 }, { TEGRA20_CLK_CCLK, TEGRA20_CLK_CLK_MAX, 0, 1 }, { TEGRA20_CLK_UARTA, TEGRA20_CLK_PLL_P, 0, 0 }, { TEGRA20_CLK_UARTB, TEGRA20_CLK_PLL_P, 0, 0 }, diff --git a/drivers/clk/tegra/clk-tegra210.c b/drivers/clk/tegra/clk-tegra210.c index 946d708add1e..9fb5d51ccce4 100644 --- a/drivers/clk/tegra/clk-tegra210.c +++ b/drivers/clk/tegra/clk-tegra210.c @@ -3328,7 +3328,7 @@ static struct tegra_clk_init_table init_table[] __initdata = { { TEGRA210_CLK_I2S4, TEGRA210_CLK_PLL_A_OUT0, 11289600, 0 }, { TEGRA210_CLK_HOST1X, TEGRA210_CLK_PLL_P, 136000000, 1 }, { TEGRA210_CLK_SCLK_MUX, TEGRA210_CLK_PLL_P, 0, 1 }, - { TEGRA210_CLK_SCLK, TEGRA210_CLK_CLK_MAX, 102000000, 1 }, + { TEGRA210_CLK_SCLK, TEGRA210_CLK_CLK_MAX, 102000000, 0 }, { TEGRA210_CLK_DFLL_SOC, TEGRA210_CLK_PLL_P, 51000000, 1 }, { TEGRA210_CLK_DFLL_REF, TEGRA210_CLK_PLL_P, 51000000, 1 }, { TEGRA210_CLK_SBC4, TEGRA210_CLK_PLL_P, 12000000, 1 }, @@ -3343,7 +3343,6 @@ static struct tegra_clk_init_table init_table[] __initdata = { { TEGRA210_CLK_XUSB_DEV_SRC, TEGRA210_CLK_PLL_P_OUT_XUSB, 102000000, 0 }, { TEGRA210_CLK_SATA, TEGRA210_CLK_PLL_P, 104000000, 0 }, { TEGRA210_CLK_SATA_OOB, TEGRA210_CLK_PLL_P, 204000000, 0 }, - { TEGRA210_CLK_EMC, TEGRA210_CLK_CLK_MAX, 0, 1 }, { TEGRA210_CLK_MSELECT, TEGRA210_CLK_CLK_MAX, 0, 1 }, { TEGRA210_CLK_CSITE, TEGRA210_CLK_CLK_MAX, 0, 1 }, /* TODO find a way to enable this on-demand */ diff --git a/drivers/clk/tegra/clk-tegra30.c b/drivers/clk/tegra/clk-tegra30.c index bee84c554932..8428895ad475 100644 --- a/drivers/clk/tegra/clk-tegra30.c +++ b/drivers/clk/tegra/clk-tegra30.c @@ -819,6 +819,7 @@ static struct tegra_clk tegra30_clks[tegra_clk_max] __initdata = { [tegra_clk_pll_a] = { .dt_id = TEGRA30_CLK_PLL_A, .present = true }, [tegra_clk_pll_a_out0] = { .dt_id = TEGRA30_CLK_PLL_A_OUT0, .present = true }, [tegra_clk_cec] = { .dt_id = TEGRA30_CLK_CEC, .present = true }, + [tegra_clk_emc] = { .dt_id = TEGRA30_CLK_EMC, .present = true }, }; static const char *pll_e_parents[] = { "pll_ref", "pll_p" }; @@ -843,8 +844,7 @@ static void __init tegra30_pll_init(void) /* PLLM */ clk = tegra_clk_register_pll("pll_m", "pll_ref", clk_base, pmc_base, - CLK_IGNORE_UNUSED | CLK_SET_RATE_GATE, - &pll_m_params, NULL); + CLK_SET_RATE_GATE, &pll_m_params, NULL); clks[TEGRA30_CLK_PLL_M] = clk; /* PLLM_OUT1 */ @@ -852,7 +852,7 @@ static void __init tegra30_pll_init(void) clk_base + PLLM_OUT, 0, TEGRA_DIVIDER_ROUND_UP, 8, 8, 1, NULL); clk = tegra_clk_register_pll_out("pll_m_out1", "pll_m_out1_div", - clk_base + PLLM_OUT, 1, 0, CLK_IGNORE_UNUSED | + clk_base + PLLM_OUT, 1, 0, CLK_SET_RATE_PARENT, 0, NULL); clks[TEGRA30_CLK_PLL_M_OUT1] = clk; @@ -990,7 +990,7 @@ static void __init tegra30_super_clk_init(void) /* SCLK */ clk = tegra_clk_register_super_mux("sclk", sclk_parents, ARRAY_SIZE(sclk_parents), - CLK_SET_RATE_PARENT, + CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, clk_base + SCLK_BURST_POLICY, 0, 4, 0, 0, NULL); clks[TEGRA30_CLK_SCLK] = clk; @@ -1060,9 +1060,6 @@ static void __init tegra30_periph_clk_init(void) CLK_SET_RATE_NO_REPARENT, clk_base + CLK_SOURCE_EMC, 30, 2, 0, &emc_lock); - clk = tegra_clk_register_periph_gate("emc", "emc_mux", 0, clk_base, 0, - 57, periph_clk_enb_refcnt); - clks[TEGRA30_CLK_EMC] = clk; clk = tegra_clk_register_mc("mc", "emc_mux", clk_base + CLK_SOURCE_EMC, &emc_lock); @@ -1252,10 +1249,7 @@ static struct tegra_clk_init_table init_table[] __initdata = { { TEGRA30_CLK_SDMMC1, TEGRA30_CLK_PLL_P, 48000000, 0 }, { TEGRA30_CLK_SDMMC2, TEGRA30_CLK_PLL_P, 48000000, 0 }, { TEGRA30_CLK_SDMMC3, TEGRA30_CLK_PLL_P, 48000000, 0 }, - { TEGRA30_CLK_PLL_M, TEGRA30_CLK_CLK_MAX, 0, 1 }, - { TEGRA30_CLK_PCLK, TEGRA30_CLK_CLK_MAX, 0, 1 }, { TEGRA30_CLK_CSITE, TEGRA30_CLK_CLK_MAX, 0, 1 }, - { TEGRA30_CLK_EMC, TEGRA30_CLK_CLK_MAX, 0, 1 }, { TEGRA30_CLK_MSELECT, TEGRA30_CLK_CLK_MAX, 0, 1 }, { TEGRA30_CLK_SBC1, TEGRA30_CLK_PLL_P, 100000000, 0 }, { TEGRA30_CLK_SBC2, TEGRA30_CLK_PLL_P, 100000000, 0 }, -- cgit From ea141d5819db989eb688cee2713b664faba4f1ca Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Wed, 10 Jan 2018 16:59:43 +0300 Subject: clk: tegra20: Correct PLL_C_OUT1 setup PLL_C_OUT_1 can't produce 216 MHz defined in the init_table. Let's set it to 240 MHz and explicitly specify HCLK rate for consistency. Signed-off-by: Dmitry Osipenko Acked-by: Peter De Schrijver Signed-off-by: Thierry Reding --- drivers/clk/tegra/clk-tegra20.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/clk/tegra/clk-tegra20.c b/drivers/clk/tegra/clk-tegra20.c index e3392ca2c2fc..dec95919fbff 100644 --- a/drivers/clk/tegra/clk-tegra20.c +++ b/drivers/clk/tegra/clk-tegra20.c @@ -1018,9 +1018,9 @@ static struct tegra_clk_init_table init_table[] __initdata = { { TEGRA20_CLK_PLL_P_OUT3, TEGRA20_CLK_CLK_MAX, 72000000, 1 }, { TEGRA20_CLK_PLL_P_OUT4, TEGRA20_CLK_CLK_MAX, 24000000, 1 }, { TEGRA20_CLK_PLL_C, TEGRA20_CLK_CLK_MAX, 600000000, 0 }, - { TEGRA20_CLK_PLL_C_OUT1, TEGRA20_CLK_CLK_MAX, 216000000, 0 }, - { TEGRA20_CLK_SCLK, TEGRA20_CLK_PLL_C_OUT1, 0, 0 }, - { TEGRA20_CLK_HCLK, TEGRA20_CLK_CLK_MAX, 0, 0 }, + { TEGRA20_CLK_PLL_C_OUT1, TEGRA20_CLK_CLK_MAX, 240000000, 0 }, + { TEGRA20_CLK_SCLK, TEGRA20_CLK_PLL_C_OUT1, 240000000, 0 }, + { TEGRA20_CLK_HCLK, TEGRA20_CLK_CLK_MAX, 240000000, 0 }, { TEGRA20_CLK_PCLK, TEGRA20_CLK_CLK_MAX, 60000000, 0 }, { TEGRA20_CLK_CSITE, TEGRA20_CLK_CLK_MAX, 0, 1 }, { TEGRA20_CLK_CCLK, TEGRA20_CLK_CLK_MAX, 0, 1 }, -- cgit From c485ad63abb4b30a3654e80fef9708a181447965 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Wed, 10 Jan 2018 16:59:44 +0300 Subject: clk: tegra: Specify VDE clock rate Currently VDE clock rate is determined by clock config left from bootloader, let's not rely on it and explicitly specify the clock rate in the CCF driver. Signed-off-by: Dmitry Osipenko Acked-by: Peter De Schrijver Signed-off-by: Thierry Reding --- drivers/clk/tegra/clk-tegra114.c | 1 + drivers/clk/tegra/clk-tegra124.c | 2 +- drivers/clk/tegra/clk-tegra20.c | 1 + drivers/clk/tegra/clk-tegra30.c | 1 + 4 files changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/clk/tegra/clk-tegra114.c b/drivers/clk/tegra/clk-tegra114.c index c3945c683f60..5d5a22d529f5 100644 --- a/drivers/clk/tegra/clk-tegra114.c +++ b/drivers/clk/tegra/clk-tegra114.c @@ -1189,6 +1189,7 @@ static struct tegra_clk_init_table init_table[] __initdata = { { TEGRA114_CLK_XUSB_HS_SRC, TEGRA114_CLK_XUSB_SS_DIV2, 61200000, 0 }, { TEGRA114_CLK_XUSB_FALCON_SRC, TEGRA114_CLK_PLL_P, 204000000, 0 }, { TEGRA114_CLK_XUSB_HOST_SRC, TEGRA114_CLK_PLL_P, 102000000, 0 }, + { TEGRA114_CLK_VDE, TEGRA114_CLK_CLK_MAX, 600000000, 0 }, /* must be the last entry */ { TEGRA114_CLK_CLK_MAX, TEGRA114_CLK_CLK_MAX, 0, 0 }, }; diff --git a/drivers/clk/tegra/clk-tegra124.c b/drivers/clk/tegra/clk-tegra124.c index 230f9a2c1abf..50088e976611 100644 --- a/drivers/clk/tegra/clk-tegra124.c +++ b/drivers/clk/tegra/clk-tegra124.c @@ -1267,7 +1267,7 @@ static struct tegra_clk_init_table common_init_table[] __initdata = { { TEGRA124_CLK_I2S2, TEGRA124_CLK_PLL_A_OUT0, 11289600, 0 }, { TEGRA124_CLK_I2S3, TEGRA124_CLK_PLL_A_OUT0, 11289600, 0 }, { TEGRA124_CLK_I2S4, TEGRA124_CLK_PLL_A_OUT0, 11289600, 0 }, - { TEGRA124_CLK_VDE, TEGRA124_CLK_PLL_P, 0, 0 }, + { TEGRA124_CLK_VDE, TEGRA124_CLK_CLK_MAX, 600000000, 0 }, { TEGRA124_CLK_HOST1X, TEGRA124_CLK_PLL_P, 136000000, 1 }, { TEGRA124_CLK_DSIALP, TEGRA124_CLK_PLL_P, 68000000, 0 }, { TEGRA124_CLK_DSIBLP, TEGRA124_CLK_PLL_P, 68000000, 0 }, diff --git a/drivers/clk/tegra/clk-tegra20.c b/drivers/clk/tegra/clk-tegra20.c index dec95919fbff..0ee56dd04cec 100644 --- a/drivers/clk/tegra/clk-tegra20.c +++ b/drivers/clk/tegra/clk-tegra20.c @@ -1048,6 +1048,7 @@ static struct tegra_clk_init_table init_table[] __initdata = { { TEGRA20_CLK_DISP2, TEGRA20_CLK_PLL_P, 600000000, 0 }, { TEGRA20_CLK_GR2D, TEGRA20_CLK_PLL_C, 300000000, 0 }, { TEGRA20_CLK_GR3D, TEGRA20_CLK_PLL_C, 300000000, 0 }, + { TEGRA20_CLK_VDE, TEGRA20_CLK_CLK_MAX, 300000000, 0 }, /* must be the last entry */ { TEGRA20_CLK_CLK_MAX, TEGRA20_CLK_CLK_MAX, 0, 0 }, }; diff --git a/drivers/clk/tegra/clk-tegra30.c b/drivers/clk/tegra/clk-tegra30.c index 8428895ad475..b316dfb6f6c7 100644 --- a/drivers/clk/tegra/clk-tegra30.c +++ b/drivers/clk/tegra/clk-tegra30.c @@ -1266,6 +1266,7 @@ static struct tegra_clk_init_table init_table[] __initdata = { { TEGRA30_CLK_GR3D, TEGRA30_CLK_PLL_C, 300000000, 0 }, { TEGRA30_CLK_GR3D2, TEGRA30_CLK_PLL_C, 300000000, 0 }, { TEGRA30_CLK_PLL_U, TEGRA30_CLK_CLK_MAX, 480000000, 0 }, + { TEGRA30_CLK_VDE, TEGRA30_CLK_CLK_MAX, 600000000, 0 }, /* must be the last entry */ { TEGRA30_CLK_CLK_MAX, TEGRA30_CLK_CLK_MAX, 0, 0 }, }; -- cgit From c35b518f9ba06c9de79fb3ff62eed7462d804995 Mon Sep 17 00:00:00 2001 From: Marcel Ziswiler Date: Fri, 23 Feb 2018 00:04:51 +0100 Subject: clk: tegra: Fix pll_u rate configuration Turns out latest upstream U-Boot does not configure/enable pll_u which leaves it at some default rate of 500 kHz: root@apalis-t30:~# cat /sys/kernel/debug/clk/clk_summary | grep pll_u pll_u 3 3 0 500000 0 Of course this won't quite work leading to the following messages: [ 6.559593] usb 2-1: new full-speed USB device number 2 using tegra- ehci [ 11.759173] usb 2-1: device descriptor read/64, error -110 [ 27.119453] usb 2-1: device descriptor read/64, error -110 [ 27.389217] usb 2-1: new full-speed USB device number 3 using tegra- ehci [ 32.559454] usb 2-1: device descriptor read/64, error -110 [ 47.929777] usb 2-1: device descriptor read/64, error -110 [ 48.049658] usb usb2-port1: attempt power cycle [ 48.759475] usb 2-1: new full-speed USB device number 4 using tegra- ehci [ 59.349457] usb 2-1: device not accepting address 4, error -110 [ 59.509449] usb 2-1: new full-speed USB device number 5 using tegra- ehci [ 70.069457] usb 2-1: device not accepting address 5, error -110 [ 70.079721] usb usb2-port1: unable to enumerate USB device Fix this by actually allowing the rate also being set from within the Linux kernel. Signed-off-by: Marcel Ziswiler Tested-by: Jon Hunter Signed-off-by: Thierry Reding --- drivers/clk/tegra/clk-pll.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c index 7c369e21c91c..830d1c87fa7c 100644 --- a/drivers/clk/tegra/clk-pll.c +++ b/drivers/clk/tegra/clk-pll.c @@ -1151,6 +1151,8 @@ static const struct clk_ops tegra_clk_pllu_ops = { .enable = clk_pllu_enable, .disable = clk_pll_disable, .recalc_rate = clk_pll_recalc_rate, + .round_rate = clk_pll_round_rate, + .set_rate = clk_pll_set_rate, }; static int _pll_fixed_mdiv(struct tegra_clk_pll_params *pll_params, -- cgit From e6d3cc7b1fac3d7f1313faf8ac9b23830113e3ec Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Wed, 14 Feb 2018 14:43:33 +0100 Subject: clk: divider: export clk_div_mask() helper Export clk_div_mask() in clk-provider header so every clock providers derived from the generic clock divider may share the definition instead of redefining it. Signed-off-by: Jerome Brunet Signed-off-by: Michael Turquette Signed-off-by: Stephen Boyd --- drivers/clk/clk-divider.c | 24 +++++++++++------------- include/linux/clk-provider.h | 1 + 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c index b49942b9fe50..3c98d2650fa3 100644 --- a/drivers/clk/clk-divider.c +++ b/drivers/clk/clk-divider.c @@ -28,12 +28,10 @@ * parent - fixed parent. No clk_set_parent support */ -#define div_mask(width) ((1 << (width)) - 1) - static unsigned int _get_table_maxdiv(const struct clk_div_table *table, u8 width) { - unsigned int maxdiv = 0, mask = div_mask(width); + unsigned int maxdiv = 0, mask = clk_div_mask(width); const struct clk_div_table *clkt; for (clkt = table; clkt->div; clkt++) @@ -57,12 +55,12 @@ static unsigned int _get_maxdiv(const struct clk_div_table *table, u8 width, unsigned long flags) { if (flags & CLK_DIVIDER_ONE_BASED) - return div_mask(width); + return clk_div_mask(width); if (flags & CLK_DIVIDER_POWER_OF_TWO) - return 1 << div_mask(width); + return 1 << clk_div_mask(width); if (table) return _get_table_maxdiv(table, width); - return div_mask(width) + 1; + return clk_div_mask(width) + 1; } static unsigned int _get_table_div(const struct clk_div_table *table, @@ -84,7 +82,7 @@ static unsigned int _get_div(const struct clk_div_table *table, if (flags & CLK_DIVIDER_POWER_OF_TWO) return 1 << val; if (flags & CLK_DIVIDER_MAX_AT_ZERO) - return val ? val : div_mask(width) + 1; + return val ? val : clk_div_mask(width) + 1; if (table) return _get_table_div(table, val); return val + 1; @@ -109,7 +107,7 @@ static unsigned int _get_val(const struct clk_div_table *table, if (flags & CLK_DIVIDER_POWER_OF_TWO) return __ffs(div); if (flags & CLK_DIVIDER_MAX_AT_ZERO) - return (div == div_mask(width) + 1) ? 0 : div; + return (div == clk_div_mask(width) + 1) ? 0 : div; if (table) return _get_table_val(table, div); return div - 1; @@ -141,7 +139,7 @@ static unsigned long clk_divider_recalc_rate(struct clk_hw *hw, unsigned int val; val = clk_readl(divider->reg) >> divider->shift; - val &= div_mask(divider->width); + val &= clk_div_mask(divider->width); return divider_recalc_rate(hw, parent_rate, val, divider->table, divider->flags, divider->width); @@ -353,7 +351,7 @@ static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate, /* if read only, just return current value */ if (divider->flags & CLK_DIVIDER_READ_ONLY) { bestdiv = clk_readl(divider->reg) >> divider->shift; - bestdiv &= div_mask(divider->width); + bestdiv &= clk_div_mask(divider->width); bestdiv = _get_div(divider->table, bestdiv, divider->flags, divider->width); return DIV_ROUND_UP_ULL((u64)*prate, bestdiv); @@ -376,7 +374,7 @@ int divider_get_val(unsigned long rate, unsigned long parent_rate, value = _get_val(table, div, flags, width); - return min_t(unsigned int, value, div_mask(width)); + return min_t(unsigned int, value, clk_div_mask(width)); } EXPORT_SYMBOL_GPL(divider_get_val); @@ -399,10 +397,10 @@ static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate, __acquire(divider->lock); if (divider->flags & CLK_DIVIDER_HIWORD_MASK) { - val = div_mask(divider->width) << (divider->shift + 16); + val = clk_div_mask(divider->width) << (divider->shift + 16); } else { val = clk_readl(divider->reg); - val &= ~(div_mask(divider->width) << divider->shift); + val &= ~(clk_div_mask(divider->width) << divider->shift); } val |= (u32)value << divider->shift; clk_writel(val, divider->reg); diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index f711be6e8c44..d8ba26d03332 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -399,6 +399,7 @@ struct clk_divider { spinlock_t *lock; }; +#define clk_div_mask(width) ((1 << (width)) - 1) #define to_clk_divider(_hw) container_of(_hw, struct clk_divider, hw) #define CLK_DIVIDER_ONE_BASED BIT(0) -- cgit From 77deb66d262f8512130ff75ec5ea8e31070b41ed Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Wed, 14 Feb 2018 14:43:34 +0100 Subject: clk: mux: add helper function for index/value translation Add helper functions for the translation between parent index and register value in the generic multiplexer function. The purpose of this change is avoid duplicating the code in other clock providers, using the same generic logic. Signed-off-by: Jerome Brunet Signed-off-by: Michael Turquette Signed-off-by: Stephen Boyd --- drivers/clk/clk-mux.c | 75 +++++++++++++++++++++++++------------------- include/linux/clk-provider.h | 4 +++ 2 files changed, 47 insertions(+), 32 deletions(-) diff --git a/drivers/clk/clk-mux.c b/drivers/clk/clk-mux.c index 39cabe157163..ac4a042f8658 100644 --- a/drivers/clk/clk-mux.c +++ b/drivers/clk/clk-mux.c @@ -26,35 +26,24 @@ * parent - parent is adjustable through clk_set_parent */ -static u8 clk_mux_get_parent(struct clk_hw *hw) +int clk_mux_val_to_index(struct clk_hw *hw, u32 *table, unsigned int flags, + unsigned int val) { - struct clk_mux *mux = to_clk_mux(hw); int num_parents = clk_hw_get_num_parents(hw); - u32 val; - /* - * FIXME need a mux-specific flag to determine if val is bitwise or numeric - * e.g. sys_clkin_ck's clksel field is 3 bits wide, but ranges from 0x1 - * to 0x7 (index starts at one) - * OTOH, pmd_trace_clk_mux_ck uses a separate bit for each clock, so - * val = 0x4 really means "bit 2, index starts at bit 0" - */ - val = clk_readl(mux->reg) >> mux->shift; - val &= mux->mask; - - if (mux->table) { + if (table) { int i; for (i = 0; i < num_parents; i++) - if (mux->table[i] == val) + if (table[i] == val) return i; return -EINVAL; } - if (val && (mux->flags & CLK_MUX_INDEX_BIT)) + if (val && (flags & CLK_MUX_INDEX_BIT)) val = ffs(val) - 1; - if (val && (mux->flags & CLK_MUX_INDEX_ONE)) + if (val && (flags & CLK_MUX_INDEX_ONE)) val--; if (val >= num_parents) @@ -62,36 +51,58 @@ static u8 clk_mux_get_parent(struct clk_hw *hw) return val; } +EXPORT_SYMBOL_GPL(clk_mux_val_to_index); -static int clk_mux_set_parent(struct clk_hw *hw, u8 index) +unsigned int clk_mux_index_to_val(u32 *table, unsigned int flags, u8 index) { - struct clk_mux *mux = to_clk_mux(hw); - u32 val; - unsigned long flags = 0; + unsigned int val = index; - if (mux->table) { - index = mux->table[index]; + if (table) { + val = table[index]; } else { - if (mux->flags & CLK_MUX_INDEX_BIT) - index = 1 << index; + if (flags & CLK_MUX_INDEX_BIT) + val = 1 << index; - if (mux->flags & CLK_MUX_INDEX_ONE) - index++; + if (flags & CLK_MUX_INDEX_ONE) + val++; } + return val; +} +EXPORT_SYMBOL_GPL(clk_mux_index_to_val); + +static u8 clk_mux_get_parent(struct clk_hw *hw) +{ + struct clk_mux *mux = to_clk_mux(hw); + u32 val; + + val = clk_readl(mux->reg) >> mux->shift; + val &= mux->mask; + + return clk_mux_val_to_index(hw, mux->table, mux->flags, val); +} + +static int clk_mux_set_parent(struct clk_hw *hw, u8 index) +{ + struct clk_mux *mux = to_clk_mux(hw); + u32 val = clk_mux_index_to_val(mux->table, mux->flags, index); + unsigned long flags = 0; + u32 reg; + if (mux->lock) spin_lock_irqsave(mux->lock, flags); else __acquire(mux->lock); if (mux->flags & CLK_MUX_HIWORD_MASK) { - val = mux->mask << (mux->shift + 16); + reg = mux->mask << (mux->shift + 16); } else { - val = clk_readl(mux->reg); - val &= ~(mux->mask << mux->shift); + reg = clk_readl(mux->reg); + reg &= ~(mux->mask << mux->shift); } - val |= index << mux->shift; - clk_writel(val, mux->reg); + val = val << mux->shift; + reg |= val; + clk_writel(reg, mux->reg); if (mux->lock) spin_unlock_irqrestore(mux->lock, flags); diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index d8ba26d03332..fe720d679c31 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -511,6 +511,10 @@ struct clk_hw *clk_hw_register_mux_table(struct device *dev, const char *name, void __iomem *reg, u8 shift, u32 mask, u8 clk_mux_flags, u32 *table, spinlock_t *lock); +int clk_mux_val_to_index(struct clk_hw *hw, u32 *table, unsigned int flags, + unsigned int val); +unsigned int clk_mux_index_to_val(u32 *table, unsigned int flags, u8 index); + void clk_unregister_mux(struct clk *clk); void clk_hw_unregister_mux(struct clk_hw *hw); -- cgit From 541debae0adf0bee96137724fa1ce81d3102d14c Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Wed, 14 Feb 2018 14:43:37 +0100 Subject: clk: call the clock init() callback before any other ops callback Some clocks may need to initialize things, whatever it is, before being able to properly operate. Move the .init() call before any other callback, such recalc_rate() or get_phase(), so the clock is properly setup before being used. Signed-off-by: Jerome Brunet Signed-off-by: Michael Turquette Signed-off-by: Stephen Boyd --- drivers/clk/clk.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index cca05ea2c058..9d56be6ead39 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -2929,6 +2929,17 @@ static int __clk_core_init(struct clk_core *core) core->orphan = true; } + /* + * optional platform-specific magic + * + * The .init callback is not used by any of the basic clock types, but + * exists for weird hardware that must perform initialization magic. + * Please consider other ways of solving initialization problems before + * using this callback, as its use is discouraged. + */ + if (core->ops->init) + core->ops->init(core->hw); + /* * Set clk's accuracy. The preferred method is to use * .recalc_accuracy. For simple clocks and lazy developers the default @@ -3006,17 +3017,6 @@ static int __clk_core_init(struct clk_core *core) } } - /* - * optional platform-specific magic - * - * The .init callback is not used by any of the basic clock types, but - * exists for weird hardware that must perform initialization magic. - * Please consider other ways of solving initialization problems before - * using this callback, as its use is discouraged. - */ - if (core->ops->init) - core->ops->init(core->hw); - kref_init(&core->ref); out: clk_pm_runtime_put(core); -- cgit From fe3f338f0cb2ed4d4f06da054c21ae2f8a36ef2d Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Wed, 14 Feb 2018 14:43:38 +0100 Subject: clk: fix mux clock documentation The mux documentation mentions the non-existing parameter width instead of mask, so just sed this. The table field is missing in the documentation of clk_mux. Add a small blurb explaining what it is Fixes: 9d9f78ed9af0 ("clk: basic clock hardware types") Signed-off-by: Jerome Brunet Signed-off-by: Michael Turquette Signed-off-by: Stephen Boyd --- include/linux/clk-provider.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index fe720d679c31..cb18526d69cb 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -450,8 +450,9 @@ void clk_hw_unregister_divider(struct clk_hw *hw); * * @hw: handle between common and hardware-specific interfaces * @reg: register controlling multiplexer + * @table: array of register values corresponding to the parent index * @shift: shift to multiplexer bit field - * @width: width of mutliplexer bit field + * @mask: mask of mutliplexer bit field * @flags: hardware-specific flags * @lock: register lock * -- cgit From b15ee490e16324c35b51f04bad54ae45a2cefd29 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Wed, 14 Feb 2018 14:43:39 +0100 Subject: clk: divider: read-only divider can propagate rate change When a divider clock has CLK_DIVIDER_READ_ONLY set, it means that the register shall be left un-touched, but it does not mean the clock should stop rate propagation if CLK_SET_RATE_PARENT is set This is properly handled in qcom clk-regmap-divider but it was not in the generic divider To fix this situation, introduce a new helper function divider_ro_round_rate, on the same model as divider_round_rate. Fixes: e6d5e7d90be9 ("clk-divider: Fix READ_ONLY when divider > 1") Signed-off-by: Jerome Brunet Tested-By: David Lechner Signed-off-by: Michael Turquette Signed-off-by: Stephen Boyd --- drivers/clk/clk-divider.c | 36 ++++++++++++++++++++++++++++++------ include/linux/clk-provider.h | 15 +++++++++++++++ 2 files changed, 45 insertions(+), 6 deletions(-) diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c index 3c98d2650fa3..b6234a5da12d 100644 --- a/drivers/clk/clk-divider.c +++ b/drivers/clk/clk-divider.c @@ -342,19 +342,43 @@ long divider_round_rate_parent(struct clk_hw *hw, struct clk_hw *parent, } EXPORT_SYMBOL_GPL(divider_round_rate_parent); +long divider_ro_round_rate_parent(struct clk_hw *hw, struct clk_hw *parent, + unsigned long rate, unsigned long *prate, + const struct clk_div_table *table, u8 width, + unsigned long flags, unsigned int val) +{ + int div; + + div = _get_div(table, val, flags, width); + + /* Even a read-only clock can propagate a rate change */ + if (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) { + if (!parent) + return -EINVAL; + + *prate = clk_hw_round_rate(parent, rate * div); + } + + return DIV_ROUND_UP_ULL((u64)*prate, div); +} +EXPORT_SYMBOL_GPL(divider_ro_round_rate_parent); + + static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *prate) { struct clk_divider *divider = to_clk_divider(hw); - int bestdiv; /* if read only, just return current value */ if (divider->flags & CLK_DIVIDER_READ_ONLY) { - bestdiv = clk_readl(divider->reg) >> divider->shift; - bestdiv &= clk_div_mask(divider->width); - bestdiv = _get_div(divider->table, bestdiv, divider->flags, - divider->width); - return DIV_ROUND_UP_ULL((u64)*prate, bestdiv); + u32 val; + + val = clk_readl(divider->reg) >> divider->shift; + val &= clk_div_mask(divider->width); + + return divider_ro_round_rate(hw, rate, prate, divider->table, + divider->width, divider->flags, + val); } return divider_round_rate(hw, rate, prate, divider->table, diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index cb18526d69cb..210a890008f9 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -420,6 +420,10 @@ long divider_round_rate_parent(struct clk_hw *hw, struct clk_hw *parent, unsigned long rate, unsigned long *prate, const struct clk_div_table *table, u8 width, unsigned long flags); +long divider_ro_round_rate_parent(struct clk_hw *hw, struct clk_hw *parent, + unsigned long rate, unsigned long *prate, + const struct clk_div_table *table, u8 width, + unsigned long flags, unsigned int val); int divider_get_val(unsigned long rate, unsigned long parent_rate, const struct clk_div_table *table, u8 width, unsigned long flags); @@ -780,6 +784,17 @@ static inline long divider_round_rate(struct clk_hw *hw, unsigned long rate, rate, prate, table, width, flags); } +static inline long divider_ro_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate, + const struct clk_div_table *table, + u8 width, unsigned long flags, + unsigned int val) +{ + return divider_ro_round_rate_parent(hw, clk_hw_get_parent(hw), + rate, prate, table, width, flags, + val); +} + /* * FIXME clock api without lock protection */ -- cgit From f5edaefee2d621f4e7628f1421c58a2361572d3a Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Wed, 14 Feb 2018 14:43:40 +0100 Subject: clk: qcom: use divider_ro_round_rate helper There is now an helper function to round the rate when the divider is read-only. Let's use it Signed-off-by: Jerome Brunet Signed-off-by: Michael Turquette Signed-off-by: Stephen Boyd --- drivers/clk/qcom/clk-regmap-divider.c | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/drivers/clk/qcom/clk-regmap-divider.c b/drivers/clk/qcom/clk-regmap-divider.c index 4e9b8c2c8980..1ee75a5e93f4 100644 --- a/drivers/clk/qcom/clk-regmap-divider.c +++ b/drivers/clk/qcom/clk-regmap-divider.c @@ -28,22 +28,14 @@ static long div_round_ro_rate(struct clk_hw *hw, unsigned long rate, { struct clk_regmap_div *divider = to_clk_regmap_div(hw); struct clk_regmap *clkr = ÷r->clkr; - u32 div; - struct clk_hw *hw_parent = clk_hw_get_parent(hw); - - regmap_read(clkr->regmap, divider->reg, &div); - div >>= divider->shift; - div &= BIT(divider->width) - 1; - div += 1; - - if (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) { - if (!hw_parent) - return -EINVAL; + u32 val; - *prate = clk_hw_round_rate(hw_parent, rate * div); - } + regmap_read(clkr->regmap, divider->reg, &val); + val >>= divider->shift; + val &= BIT(divider->width) - 1; - return DIV_ROUND_UP_ULL((u64)*prate, div); + return divider_ro_round_rate(hw, rate, prate, NULL, divider->width, + CLK_DIVIDER_ROUND_CLOSEST, val); } static long div_round_rate(struct clk_hw *hw, unsigned long rate, -- cgit From a5510399e9535b9348adb70c09faa3de51541f9b Mon Sep 17 00:00:00 2001 From: Leonard Crestez Date: Mon, 12 Mar 2018 16:59:25 +0200 Subject: clk: imx6ull: Add epdc_podf instead of sim_podf This is one of the differences between 6ul and 6ull: imx6ull has no sim but has epdc and this clock is redefined on the same bit. This can be verified in the Reference Manuals. Signed-off-by: Leonard Crestez Signed-off-by: Shawn Guo --- drivers/clk/imx/clk-imx6ul.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/clk/imx/clk-imx6ul.c b/drivers/clk/imx/clk-imx6ul.c index 85c118164469..114ecbb94ec5 100644 --- a/drivers/clk/imx/clk-imx6ul.c +++ b/drivers/clk/imx/clk-imx6ul.c @@ -308,7 +308,10 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node) clks[IMX6UL_CLK_SAI2_PODF] = imx_clk_divider("sai2_podf", "sai2_pred", base + 0x2c, 0, 6); clks[IMX6UL_CLK_SPDIF_PRED] = imx_clk_divider("spdif_pred", "spdif_sel", base + 0x30, 25, 3); clks[IMX6UL_CLK_SPDIF_PODF] = imx_clk_divider("spdif_podf", "spdif_pred", base + 0x30, 22, 3); - clks[IMX6UL_CLK_SIM_PODF] = imx_clk_divider("sim_podf", "sim_pre_sel", base + 0x34, 12, 3); + if (clk_on_imx6ul()) + clks[IMX6UL_CLK_SIM_PODF] = imx_clk_divider("sim_podf", "sim_pre_sel", base + 0x34, 12, 3); + else if (clk_on_imx6ull()) + clks[IMX6ULL_CLK_EPDC_PODF] = imx_clk_divider("epdc_podf", "epdc_pre_sel", base + 0x34, 12, 3); clks[IMX6UL_CLK_ECSPI_PODF] = imx_clk_divider("ecspi_podf", "ecspi_sel", base + 0x38, 19, 6); clks[IMX6UL_CLK_LCDIF_PRED] = imx_clk_divider("lcdif_pred", "lcdif_pre_sel", base + 0x38, 12, 3); clks[IMX6UL_CLK_CSI_PODF] = imx_clk_divider("csi_podf", "csi_sel", base + 0x3c, 11, 3); -- cgit From 323346d31d68542b133088c7fe043c234f26eee4 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Mon, 12 Feb 2018 15:58:28 +0100 Subject: clk: meson: use dev pointer where possible The 'dev' pointer is directly available in gxbb and axg clock controller, so consistently use it instead of going the through the 'pdev' pointer once in while Signed-off-by: Jerome Brunet Signed-off-by: Neil Armstrong --- drivers/clk/meson/axg.c | 8 ++++---- drivers/clk/meson/gxbb.c | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/clk/meson/axg.c b/drivers/clk/meson/axg.c index 2dc70e0e925c..1f48649a7d2a 100644 --- a/drivers/clk/meson/axg.c +++ b/drivers/clk/meson/axg.c @@ -804,7 +804,7 @@ static int axg_clkc_probe(struct platform_device *pdev) void __iomem *clk_base; int ret, clkid, i; - clkc_data = of_device_get_match_data(&pdev->dev); + clkc_data = of_device_get_match_data(dev); if (!clkc_data) return -EINVAL; @@ -812,9 +812,9 @@ static int axg_clkc_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) return -EINVAL; - clk_base = devm_ioremap(&pdev->dev, res->start, resource_size(res)); + clk_base = devm_ioremap(dev, res->start, resource_size(res)); if (!clk_base) { - dev_err(&pdev->dev, "Unable to map clk base\n"); + dev_err(dev, "Unable to map clk base\n"); return -ENXIO; } @@ -849,7 +849,7 @@ static int axg_clkc_probe(struct platform_device *pdev) ret = devm_clk_hw_register(dev, clkc_data->hw_onecell_data->hws[clkid]); if (ret) { - dev_err(&pdev->dev, "Clock registration failed\n"); + dev_err(dev, "Clock registration failed\n"); return ret; } } diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c index a5f25cc1944c..423abcb8ef88 100644 --- a/drivers/clk/meson/gxbb.c +++ b/drivers/clk/meson/gxbb.c @@ -1950,7 +1950,7 @@ static int gxbb_clkc_probe(struct platform_device *pdev) int ret, clkid, i; struct device *dev = &pdev->dev; - clkc_data = of_device_get_match_data(&pdev->dev); + clkc_data = of_device_get_match_data(dev); if (!clkc_data) return -EINVAL; -- cgit From 332b32a23225e01cdfac4fb6cb1c76553f906cb5 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Mon, 12 Feb 2018 15:58:29 +0100 Subject: clk: meson: use devm_of_clk_add_hw_provider There is no remove callbacks in meson's clock controllers and of_clk_del_provider is never called if of_clk_add_hw_provider has been executed, introducing a potential memory leak. Fixing this by the using the devm variant. In reality, the leak would never happen since these controllers are never unloaded once in use ... still, this is worth cleaning. Signed-off-by: Jerome Brunet Signed-off-by: Neil Armstrong --- drivers/clk/meson/axg.c | 4 ++-- drivers/clk/meson/gxbb.c | 5 +++-- drivers/clk/meson/meson8b.c | 4 ++-- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/clk/meson/axg.c b/drivers/clk/meson/axg.c index 1f48649a7d2a..e16d53b6be30 100644 --- a/drivers/clk/meson/axg.c +++ b/drivers/clk/meson/axg.c @@ -854,8 +854,8 @@ static int axg_clkc_probe(struct platform_device *pdev) } } - return of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get, - clkc_data->hw_onecell_data); + return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, + clkc_data->hw_onecell_data); } static struct platform_driver axg_driver = { diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c index 423abcb8ef88..17f44ac751b3 100644 --- a/drivers/clk/meson/gxbb.c +++ b/drivers/clk/meson/gxbb.c @@ -2002,8 +2002,9 @@ static int gxbb_clkc_probe(struct platform_device *pdev) goto iounmap; } - return of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get, - clkc_data->hw_onecell_data); + + return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, + clkc_data->hw_onecell_data); iounmap: iounmap(clk_base); diff --git a/drivers/clk/meson/meson8b.c b/drivers/clk/meson/meson8b.c index 3ffea80c1308..abac079ff77f 100644 --- a/drivers/clk/meson/meson8b.c +++ b/drivers/clk/meson/meson8b.c @@ -878,8 +878,8 @@ static int meson8b_clkc_probe(struct platform_device *pdev) return ret; } - return of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get, - &meson8b_hw_onecell_data); + return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, + &meson8b_hw_onecell_data); } static const struct of_device_id meson8b_clkc_match_table[] = { -- cgit From 14bd7b9c8d3f4cc1f06563630b30adae7838f301 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Mon, 12 Feb 2018 15:58:30 +0100 Subject: clk: meson: only one loop index is necessary in probe We don't need several loop index variables in the probe function This is far from being critical but since we are doing a vast rework of meson clock controllers, now is the time to lower the entropy a bit Signed-off-by: Jerome Brunet Signed-off-by: Neil Armstrong --- drivers/clk/meson/axg.c | 8 ++++---- drivers/clk/meson/gxbb.c | 13 ++++++------- drivers/clk/meson/meson8b.c | 8 ++++---- 3 files changed, 14 insertions(+), 15 deletions(-) diff --git a/drivers/clk/meson/axg.c b/drivers/clk/meson/axg.c index e16d53b6be30..3bb77b4f1e8d 100644 --- a/drivers/clk/meson/axg.c +++ b/drivers/clk/meson/axg.c @@ -802,7 +802,7 @@ static int axg_clkc_probe(struct platform_device *pdev) const struct clkc_data *clkc_data; struct resource *res; void __iomem *clk_base; - int ret, clkid, i; + int ret, i; clkc_data = of_device_get_match_data(dev); if (!clkc_data) @@ -841,13 +841,13 @@ static int axg_clkc_probe(struct platform_device *pdev) clkc_data->clk_dividers[i]->reg = clk_base + (u64)clkc_data->clk_dividers[i]->reg; - for (clkid = 0; clkid < clkc_data->hw_onecell_data->num; clkid++) { + for (i = 0; i < clkc_data->hw_onecell_data->num; i++) { /* array might be sparse */ - if (!clkc_data->hw_onecell_data->hws[clkid]) + if (!clkc_data->hw_onecell_data->hws[i]) continue; ret = devm_clk_hw_register(dev, - clkc_data->hw_onecell_data->hws[clkid]); + clkc_data->hw_onecell_data->hws[i]); if (ret) { dev_err(dev, "Clock registration failed\n"); return ret; diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c index 17f44ac751b3..e6adab49c0ba 100644 --- a/drivers/clk/meson/gxbb.c +++ b/drivers/clk/meson/gxbb.c @@ -1947,7 +1947,7 @@ static int gxbb_clkc_probe(struct platform_device *pdev) { const struct clkc_data *clkc_data; void __iomem *clk_base; - int ret, clkid, i; + int ret, i; struct device *dev = &pdev->dev; clkc_data = of_device_get_match_data(dev); @@ -1988,16 +1988,15 @@ static int gxbb_clkc_probe(struct platform_device *pdev) for (i = 0; i < clkc_data->clk_audio_dividers_count; i++) clkc_data->clk_audio_dividers[i]->base = clk_base; - /* - * register all clks - */ - for (clkid = 0; clkid < clkc_data->hw_onecell_data->num; clkid++) { + + /* Register all clks */ + for (i = 0; i < clkc_data->hw_onecell_data->num; i++) { /* array might be sparse */ - if (!clkc_data->hw_onecell_data->hws[clkid]) + if (!clkc_data->hw_onecell_data->hws[i]) continue; ret = devm_clk_hw_register(dev, - clkc_data->hw_onecell_data->hws[clkid]); + clkc_data->hw_onecell_data->hws[i]); if (ret) goto iounmap; } diff --git a/drivers/clk/meson/meson8b.c b/drivers/clk/meson/meson8b.c index abac079ff77f..ffadad27375e 100644 --- a/drivers/clk/meson/meson8b.c +++ b/drivers/clk/meson/meson8b.c @@ -806,7 +806,7 @@ static const struct reset_control_ops meson8b_clk_reset_ops = { static int meson8b_clkc_probe(struct platform_device *pdev) { - int ret, clkid, i; + int ret, i; struct clk_hw *parent_hw; struct clk *parent_clk; struct device *dev = &pdev->dev; @@ -844,13 +844,13 @@ static int meson8b_clkc_probe(struct platform_device *pdev) * register all clks * CLKID_UNUSED = 0, so skip it and start with CLKID_XTAL = 1 */ - for (clkid = CLKID_XTAL; clkid < CLK_NR_CLKS; clkid++) { + for (i = CLKID_XTAL; i < CLK_NR_CLKS; i++) { /* array might be sparse */ - if (!meson8b_hw_onecell_data.hws[clkid]) + if (!meson8b_hw_onecell_data.hws[i]) continue; /* FIXME convert to devm_clk_register */ - ret = devm_clk_hw_register(dev, meson8b_hw_onecell_data.hws[clkid]); + ret = devm_clk_hw_register(dev, meson8b_hw_onecell_data.hws[i]); if (ret) return ret; } -- cgit From 7b174c5ebe46c739b0802d0781a32788f5259d2c Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Mon, 12 Feb 2018 15:58:31 +0100 Subject: clk: meson: remove obsolete comments Over time things changes in CCF and issues have been fixed in meson controllers. Now, clk81 is decently modeled by read-only PLLs, a mux, a divider and a gate. We can remove the FIXME comments related to clk81. Also remove the comment about devm_clk_hw_register, as there is apparently nothing wrong with it. Signed-off-by: Jerome Brunet Signed-off-by: Neil Armstrong --- drivers/clk/meson/axg.c | 5 ----- drivers/clk/meson/gxbb.c | 6 ------ drivers/clk/meson/meson8b.c | 1 - 3 files changed, 12 deletions(-) diff --git a/drivers/clk/meson/axg.c b/drivers/clk/meson/axg.c index 3bb77b4f1e8d..bc5c29f13282 100644 --- a/drivers/clk/meson/axg.c +++ b/drivers/clk/meson/axg.c @@ -411,11 +411,6 @@ static struct meson_clk_mpll axg_mpll3 = { }, }; -/* - * FIXME The legacy composite clocks (e.g. clk81) are both PLL post-dividers - * and should be modeled with their respective PLLs via the forthcoming - * coordinated clock rates feature - */ static u32 mux_table_clk81[] = { 0, 2, 3, 4, 5, 6, 7 }; static const char * const clk81_parent_names[] = { "xtal", "fclk_div7", "mpll1", "mpll2", "fclk_div4", diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c index e6adab49c0ba..6609024eee00 100644 --- a/drivers/clk/meson/gxbb.c +++ b/drivers/clk/meson/gxbb.c @@ -575,12 +575,6 @@ static struct meson_clk_mpll gxbb_mpll2 = { }, }; -/* - * FIXME The legacy composite clocks (e.g. clk81) are both PLL post-dividers - * and should be modeled with their respective PLLs via the forthcoming - * coordinated clock rates feature - */ - static u32 mux_table_clk81[] = { 0, 2, 3, 4, 5, 6, 7 }; static const char * const clk81_parent_names[] = { "xtal", "fclk_div7", "mpll1", "mpll2", "fclk_div4", diff --git a/drivers/clk/meson/meson8b.c b/drivers/clk/meson/meson8b.c index ffadad27375e..db017c29a84c 100644 --- a/drivers/clk/meson/meson8b.c +++ b/drivers/clk/meson/meson8b.c @@ -849,7 +849,6 @@ static int meson8b_clkc_probe(struct platform_device *pdev) if (!meson8b_hw_onecell_data.hws[i]) continue; - /* FIXME convert to devm_clk_register */ ret = devm_clk_hw_register(dev, meson8b_hw_onecell_data.hws[i]); if (ret) return ret; -- cgit From ea11dda9e091aba0fe6497108477699286a2d036 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Mon, 12 Feb 2018 15:58:32 +0100 Subject: clk: meson: add regmap clocks Meson clock controllers need to move the classical iomem registers to regmap. This is triggered because the HHI controllers found on the GXBB and GXL host more than just clocks. To properly handle this, we would like to migrate HHI to syscon. Also GXBB AO clock controller already use regmap, AXG AO and Audio clock controllers will as well. The purpose of this change is to provide a common structure to these meson controllers (and possibly others) for regmap based clocks. This change provides the basic gate, mux and divider, based on the helpers provided by the related generic clocks Signed-off-by: Jerome Brunet Signed-off-by: Neil Armstrong --- drivers/clk/meson/Kconfig | 4 + drivers/clk/meson/Makefile | 1 + drivers/clk/meson/clk-regmap.c | 166 +++++++++++++++++++++++++++++++++++++++++ drivers/clk/meson/clk-regmap.h | 111 +++++++++++++++++++++++++++ 4 files changed, 282 insertions(+) create mode 100644 drivers/clk/meson/clk-regmap.c create mode 100644 drivers/clk/meson/clk-regmap.h diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig index 7694302c70a4..e97e85077da1 100644 --- a/drivers/clk/meson/Kconfig +++ b/drivers/clk/meson/Kconfig @@ -3,6 +3,10 @@ config COMMON_CLK_AMLOGIC depends on OF depends on ARCH_MESON || COMPILE_TEST +config COMMON_CLK_REGMAP_MESON + bool + select REGMAP + config COMMON_CLK_MESON8B bool depends on COMMON_CLK_AMLOGIC diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile index 3c03ce583798..11a50586666a 100644 --- a/drivers/clk/meson/Makefile +++ b/drivers/clk/meson/Makefile @@ -6,3 +6,4 @@ obj-$(CONFIG_COMMON_CLK_AMLOGIC) += clk-pll.o clk-cpu.o clk-mpll.o clk-audio-div obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b.o obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o gxbb-aoclk-regmap.o gxbb-aoclk-32k.o obj-$(CONFIG_COMMON_CLK_AXG) += axg.o +obj-$(CONFIG_COMMON_CLK_REGMAP_MESON) += clk-regmap.o diff --git a/drivers/clk/meson/clk-regmap.c b/drivers/clk/meson/clk-regmap.c new file mode 100644 index 000000000000..3645fdb62343 --- /dev/null +++ b/drivers/clk/meson/clk-regmap.c @@ -0,0 +1,166 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2018 BayLibre, SAS. +// Author: Jerome Brunet + +#include "clk-regmap.h" + +static int clk_regmap_gate_endisable(struct clk_hw *hw, int enable) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct clk_regmap_gate_data *gate = clk_get_regmap_gate_data(clk); + int set = gate->flags & CLK_GATE_SET_TO_DISABLE ? 1 : 0; + + set ^= enable; + + return regmap_update_bits(clk->map, gate->offset, BIT(gate->bit_idx), + set ? BIT(gate->bit_idx) : 0); +} + +static int clk_regmap_gate_enable(struct clk_hw *hw) +{ + return clk_regmap_gate_endisable(hw, 1); +} + +static void clk_regmap_gate_disable(struct clk_hw *hw) +{ + clk_regmap_gate_endisable(hw, 0); +} + +static int clk_regmap_gate_is_enabled(struct clk_hw *hw) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct clk_regmap_gate_data *gate = clk_get_regmap_gate_data(clk); + unsigned int val; + + regmap_read(clk->map, gate->offset, &val); + if (gate->flags & CLK_GATE_SET_TO_DISABLE) + val ^= BIT(gate->bit_idx); + + val &= BIT(gate->bit_idx); + + return val ? 1 : 0; +} + +const struct clk_ops clk_regmap_gate_ops = { + .enable = clk_regmap_gate_enable, + .disable = clk_regmap_gate_disable, + .is_enabled = clk_regmap_gate_is_enabled, +}; +EXPORT_SYMBOL_GPL(clk_regmap_gate_ops); + +static unsigned long clk_regmap_div_recalc_rate(struct clk_hw *hw, + unsigned long prate) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct clk_regmap_div_data *div = clk_get_regmap_div_data(clk); + unsigned int val; + int ret; + + ret = regmap_read(clk->map, div->offset, &val); + if (ret) + /* Gives a hint that something is wrong */ + return 0; + + val >>= div->shift; + val &= clk_div_mask(div->width); + return divider_recalc_rate(hw, prate, val, div->table, div->flags, + div->width); +} + +static long clk_regmap_div_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct clk_regmap_div_data *div = clk_get_regmap_div_data(clk); + unsigned int val; + int ret; + + /* if read only, just return current value */ + if (div->flags & CLK_DIVIDER_READ_ONLY) { + ret = regmap_read(clk->map, div->offset, &val); + if (ret) + /* Gives a hint that something is wrong */ + return 0; + + val >>= div->shift; + val &= clk_div_mask(div->width); + + return divider_ro_round_rate(hw, rate, prate, div->table, + div->width, div->flags, val); + } + + return divider_round_rate(hw, rate, prate, div->table, div->width, + div->flags); +} + +static int clk_regmap_div_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct clk_regmap_div_data *div = clk_get_regmap_div_data(clk); + unsigned int val; + int ret; + + ret = divider_get_val(rate, parent_rate, div->table, div->width, + div->flags); + if (ret < 0) + return ret; + + val = (unsigned int)ret << div->shift; + return regmap_update_bits(clk->map, div->offset, + clk_div_mask(div->width) << div->shift, val); +}; + +/* Would prefer clk_regmap_div_ro_ops but clashes with qcom */ + +const struct clk_ops clk_regmap_divider_ops = { + .recalc_rate = clk_regmap_div_recalc_rate, + .round_rate = clk_regmap_div_round_rate, + .set_rate = clk_regmap_div_set_rate, +}; +EXPORT_SYMBOL_GPL(clk_regmap_divider_ops); + +const struct clk_ops clk_regmap_divider_ro_ops = { + .recalc_rate = clk_regmap_div_recalc_rate, + .round_rate = clk_regmap_div_round_rate, +}; +EXPORT_SYMBOL_GPL(clk_regmap_divider_ro_ops); + +static u8 clk_regmap_mux_get_parent(struct clk_hw *hw) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct clk_regmap_mux_data *mux = clk_get_regmap_mux_data(clk); + unsigned int val; + int ret; + + ret = regmap_read(clk->map, mux->offset, &val); + if (ret) + return ret; + + val >>= mux->shift; + val &= mux->mask; + return clk_mux_val_to_index(hw, mux->table, mux->flags, val); +} + +static int clk_regmap_mux_set_parent(struct clk_hw *hw, u8 index) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct clk_regmap_mux_data *mux = clk_get_regmap_mux_data(clk); + unsigned int val = clk_mux_index_to_val(mux->table, mux->flags, index); + + return regmap_update_bits(clk->map, mux->offset, + mux->mask << mux->shift, + val << mux->shift); +} + +const struct clk_ops clk_regmap_mux_ops = { + .get_parent = clk_regmap_mux_get_parent, + .set_parent = clk_regmap_mux_set_parent, + .determine_rate = __clk_mux_determine_rate, +}; +EXPORT_SYMBOL_GPL(clk_regmap_mux_ops); + +const struct clk_ops clk_regmap_mux_ro_ops = { + .get_parent = clk_regmap_mux_get_parent, +}; +EXPORT_SYMBOL_GPL(clk_regmap_mux_ro_ops); diff --git a/drivers/clk/meson/clk-regmap.h b/drivers/clk/meson/clk-regmap.h new file mode 100644 index 000000000000..627c888026d7 --- /dev/null +++ b/drivers/clk/meson/clk-regmap.h @@ -0,0 +1,111 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2018 BayLibre, SAS. +// Author: Jerome Brunet + +#ifndef __CLK_REGMAP_H +#define __CLK_REGMAP_H + +#include +#include + +/** + * struct clk_regmap - regmap backed clock + * + * @hw: handle between common and hardware-specific interfaces + * @map: pointer to the regmap structure controlling the clock + * @data: data specific to the clock type + * + * Clock which is controlled by regmap backed registers. The actual type of + * of the clock is controlled by the clock_ops and data. + */ +struct clk_regmap { + struct clk_hw hw; + struct regmap *map; + void *data; +}; + +#define to_clk_regmap(_hw) container_of(_hw, struct clk_regmap, hw) + +/** + * struct clk_regmap_gate_data - regmap backed gate specific data + * + * @offset: offset of the register controlling gate + * @bit_idx: single bit controlling gate + * @flags: hardware-specific flags + * + * Flags: + * Same as clk_gate except CLK_GATE_HIWORD_MASK which is ignored + */ +struct clk_regmap_gate_data { + unsigned int offset; + u8 bit_idx; + u8 flags; +}; + +static inline struct clk_regmap_gate_data * +clk_get_regmap_gate_data(struct clk_regmap *clk) +{ + return (struct clk_regmap_gate_data *)clk->data; +} + +extern const struct clk_ops clk_regmap_gate_ops; + +/** + * struct clk_regmap_div_data - regmap backed adjustable divider specific data + * + * @offset: offset of the register controlling the divider + * @shift: shift to the divider bit field + * @width: width of the divider bit field + * @table: array of value/divider pairs, last entry should have div = 0 + * + * Flags: + * Same as clk_divider except CLK_DIVIDER_HIWORD_MASK which is ignored + */ +struct clk_regmap_div_data { + unsigned int offset; + u8 shift; + u8 width; + u8 flags; + const struct clk_div_table *table; +}; + +static inline struct clk_regmap_div_data * +clk_get_regmap_div_data(struct clk_regmap *clk) +{ + return (struct clk_regmap_div_data *)clk->data; +} + +extern const struct clk_ops clk_regmap_divider_ops; +extern const struct clk_ops clk_regmap_divider_ro_ops; + +/** + * struct clk_regmap_mux_data - regmap backed multiplexer clock specific data + * + * @hw: handle between common and hardware-specific interfaces + * @offset: offset of theregister controlling multiplexer + * @table: array of parent indexed register values + * @shift: shift to multiplexer bit field + * @mask: mask of mutliplexer bit field + * @flags: hardware-specific flags + * + * Flags: + * Same as clk_divider except CLK_MUX_HIWORD_MASK which is ignored + */ +struct clk_regmap_mux_data { + unsigned int offset; + u32 *table; + u32 mask; + u8 shift; + u8 flags; +}; + +static inline struct clk_regmap_mux_data * +clk_get_regmap_mux_data(struct clk_regmap *clk) +{ + return (struct clk_regmap_mux_data *)clk->data; +} + +extern const struct clk_ops clk_regmap_mux_ops; +extern const struct clk_ops clk_regmap_mux_ro_ops; + +#endif /* __CLK_REGMAP_H */ -- cgit From 81c7fcac9b5ffe5744bb1437d991739be7053528 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Mon, 12 Feb 2018 15:58:33 +0100 Subject: clk: meson: switch gxbb ao_clk to clk_regmap Drop the gxbb ao specific regmap based clock and use the meson clk_regmap based clock instead. Signed-off-by: Jerome Brunet Signed-off-by: Neil Armstrong --- drivers/clk/meson/Kconfig | 1 + drivers/clk/meson/Makefile | 2 +- drivers/clk/meson/gxbb-aoclk.c | 20 ++++++++++---------- drivers/clk/meson/gxbb-aoclk.h | 1 - 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig index e97e85077da1..33d148e19066 100644 --- a/drivers/clk/meson/Kconfig +++ b/drivers/clk/meson/Kconfig @@ -20,6 +20,7 @@ config COMMON_CLK_GXBB bool depends on COMMON_CLK_AMLOGIC select RESET_CONTROLLER + select COMMON_CLK_REGMAP_MESON help Support for the clock controller on AmLogic S905 devices, aka gxbb. Say Y if you want peripherals and CPU frequency scaling to work. diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile index 11a50586666a..465086118d62 100644 --- a/drivers/clk/meson/Makefile +++ b/drivers/clk/meson/Makefile @@ -4,6 +4,6 @@ obj-$(CONFIG_COMMON_CLK_AMLOGIC) += clk-pll.o clk-cpu.o clk-mpll.o clk-audio-divider.o obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b.o -obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o gxbb-aoclk-regmap.o gxbb-aoclk-32k.o +obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o gxbb-aoclk-32k.o obj-$(CONFIG_COMMON_CLK_AXG) += axg.o obj-$(CONFIG_COMMON_CLK_REGMAP_MESON) += clk-regmap.o diff --git a/drivers/clk/meson/gxbb-aoclk.c b/drivers/clk/meson/gxbb-aoclk.c index 6c161e0a8e59..9ec23ae9a219 100644 --- a/drivers/clk/meson/gxbb-aoclk.c +++ b/drivers/clk/meson/gxbb-aoclk.c @@ -62,10 +62,9 @@ #include #include #include +#include "clk-regmap.h" #include "gxbb-aoclk.h" -static DEFINE_SPINLOCK(gxbb_aoclk_lock); - struct gxbb_aoclk_reset_controller { struct reset_controller_dev reset; unsigned int *data; @@ -87,12 +86,14 @@ static const struct reset_control_ops gxbb_aoclk_reset_ops = { }; #define GXBB_AO_GATE(_name, _bit) \ -static struct aoclk_gate_regmap _name##_ao = { \ - .bit_idx = (_bit), \ - .lock = &gxbb_aoclk_lock, \ +static struct clk_regmap _name##_ao = { \ + .data = &(struct clk_regmap_gate_data) { \ + .offset = AO_RTI_GEN_CNTL_REG0, \ + .bit_idx = (_bit), \ + }, \ .hw.init = &(struct clk_init_data) { \ .name = #_name "_ao", \ - .ops = &meson_aoclk_gate_regmap_ops, \ + .ops = &clk_regmap_gate_ops, \ .parent_names = (const char *[]){ "clk81" }, \ .num_parents = 1, \ .flags = (CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED), \ @@ -107,7 +108,6 @@ GXBB_AO_GATE(uart2, 5); GXBB_AO_GATE(ir_blaster, 6); static struct aoclk_cec_32k cec_32k_ao = { - .lock = &gxbb_aoclk_lock, .hw.init = &(struct clk_init_data) { .name = "cec_32k_ao", .ops = &meson_aoclk_cec_32k_ops, @@ -126,7 +126,7 @@ static unsigned int gxbb_aoclk_reset[] = { [RESET_AO_IR_BLASTER] = 23, }; -static struct aoclk_gate_regmap *gxbb_aoclk_gate[] = { +static struct clk_regmap *gxbb_aoclk_gate[] = { [CLKID_AO_REMOTE] = &remote_ao, [CLKID_AO_I2C_MASTER] = &i2c_master_ao, [CLKID_AO_I2C_SLAVE] = &i2c_slave_ao, @@ -177,10 +177,10 @@ static int gxbb_aoclkc_probe(struct platform_device *pdev) * Populate regmap and register all clks */ for (clkid = 0; clkid < ARRAY_SIZE(gxbb_aoclk_gate); clkid++) { - gxbb_aoclk_gate[clkid]->regmap = regmap; + gxbb_aoclk_gate[clkid]->map = regmap; ret = devm_clk_hw_register(dev, - gxbb_aoclk_onecell_data.hws[clkid]); + gxbb_aoclk_onecell_data.hws[clkid]); if (ret) return ret; } diff --git a/drivers/clk/meson/gxbb-aoclk.h b/drivers/clk/meson/gxbb-aoclk.h index e8604c8f7eee..127d58954cca 100644 --- a/drivers/clk/meson/gxbb-aoclk.h +++ b/drivers/clk/meson/gxbb-aoclk.h @@ -32,7 +32,6 @@ extern const struct clk_ops meson_aoclk_gate_regmap_ops; struct aoclk_cec_32k { struct clk_hw hw; struct regmap *regmap; - spinlock_t *lock; }; #define to_aoclk_cec_32k(_hw) container_of(_hw, struct aoclk_cec_32k, hw) -- cgit From 1f932d99710d70572f8703641db9a878a6dbd063 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Mon, 12 Feb 2018 15:58:34 +0100 Subject: clk: meson: remove superseded aoclk_gate_regmap aoclk_gate_regmap has been replaced by meson's clk_regmap. It is no longer necessary so, remove it Signed-off-by: Jerome Brunet Signed-off-by: Neil Armstrong --- drivers/clk/meson/gxbb-aoclk-regmap.c | 46 ----------------------------------- drivers/clk/meson/gxbb-aoclk.h | 10 -------- 2 files changed, 56 deletions(-) delete mode 100644 drivers/clk/meson/gxbb-aoclk-regmap.c diff --git a/drivers/clk/meson/gxbb-aoclk-regmap.c b/drivers/clk/meson/gxbb-aoclk-regmap.c deleted file mode 100644 index 2515fbfa0467..000000000000 --- a/drivers/clk/meson/gxbb-aoclk-regmap.c +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2017 BayLibre, SAS. - * Author: Neil Armstrong - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include -#include -#include -#include "gxbb-aoclk.h" - -static int aoclk_gate_regmap_enable(struct clk_hw *hw) -{ - struct aoclk_gate_regmap *gate = to_aoclk_gate_regmap(hw); - - return regmap_update_bits(gate->regmap, AO_RTI_GEN_CNTL_REG0, - BIT(gate->bit_idx), BIT(gate->bit_idx)); -} - -static void aoclk_gate_regmap_disable(struct clk_hw *hw) -{ - struct aoclk_gate_regmap *gate = to_aoclk_gate_regmap(hw); - - regmap_update_bits(gate->regmap, AO_RTI_GEN_CNTL_REG0, - BIT(gate->bit_idx), 0); -} - -static int aoclk_gate_regmap_is_enabled(struct clk_hw *hw) -{ - struct aoclk_gate_regmap *gate = to_aoclk_gate_regmap(hw); - unsigned int val; - int ret; - - ret = regmap_read(gate->regmap, AO_RTI_GEN_CNTL_REG0, &val); - if (ret) - return ret; - - return (val & BIT(gate->bit_idx)) != 0; -} - -const struct clk_ops meson_aoclk_gate_regmap_ops = { - .enable = aoclk_gate_regmap_enable, - .disable = aoclk_gate_regmap_disable, - .is_enabled = aoclk_gate_regmap_is_enabled, -}; diff --git a/drivers/clk/meson/gxbb-aoclk.h b/drivers/clk/meson/gxbb-aoclk.h index 127d58954cca..0be78383f257 100644 --- a/drivers/clk/meson/gxbb-aoclk.h +++ b/drivers/clk/meson/gxbb-aoclk.h @@ -17,16 +17,6 @@ #define AO_RTC_ALT_CLK_CNTL0 0x94 #define AO_RTC_ALT_CLK_CNTL1 0x98 -struct aoclk_gate_regmap { - struct clk_hw hw; - unsigned bit_idx; - struct regmap *regmap; - spinlock_t *lock; -}; - -#define to_aoclk_gate_regmap(_hw) \ - container_of(_hw, struct aoclk_gate_regmap, hw) - extern const struct clk_ops meson_aoclk_gate_regmap_ops; struct aoclk_cec_32k { -- cgit From 161f6e5baabdecb7057696bc4ce006d0d94091ec Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Mon, 12 Feb 2018 15:58:35 +0100 Subject: clk: meson: add regmap to the clock controllers This change registers a regmap in meson8b, gxbb and axg controllers. The clock are still accessing their registers directly through iomem. Once all clocks handled by these controllers have been move to regmap, the regmap register will be removed and replaced with a syscon request. This is needed because other drivers, such as the HDMI driver, need to access the HHI register region Acked-by: Martin Blumenstingl Signed-off-by: Jerome Brunet Signed-off-by: Neil Armstrong --- drivers/clk/meson/Kconfig | 2 ++ drivers/clk/meson/axg.c | 15 ++++++++++++++- drivers/clk/meson/gxbb.c | 33 +++++++++++++++++++++++---------- drivers/clk/meson/meson8b.c | 14 +++++++++++++- 4 files changed, 52 insertions(+), 12 deletions(-) diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig index 33d148e19066..9735335b17a9 100644 --- a/drivers/clk/meson/Kconfig +++ b/drivers/clk/meson/Kconfig @@ -11,6 +11,7 @@ config COMMON_CLK_MESON8B bool depends on COMMON_CLK_AMLOGIC select RESET_CONTROLLER + select REGMAP help Support for the clock controller on AmLogic S802 (Meson8), S805 (Meson8b) and S812 (Meson8m2) devices. Say Y if you @@ -29,6 +30,7 @@ config COMMON_CLK_AXG bool depends on COMMON_CLK_AMLOGIC select RESET_CONTROLLER + select REGMAP help Support for the clock controller on AmLogic A113D devices, aka axg. Say Y if you want peripherals and CPU frequency scaling to work. diff --git a/drivers/clk/meson/axg.c b/drivers/clk/meson/axg.c index bc5c29f13282..aed0f9e64f71 100644 --- a/drivers/clk/meson/axg.c +++ b/drivers/clk/meson/axg.c @@ -11,10 +11,11 @@ #include #include +#include #include #include #include -#include +#include #include "clkc.h" #include "axg.h" @@ -791,12 +792,19 @@ static const struct of_device_id clkc_match_table[] = { {} }; +static const struct regmap_config clkc_regmap_config = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, +}; + static int axg_clkc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; const struct clkc_data *clkc_data; struct resource *res; void __iomem *clk_base; + struct regmap *map; int ret, i; clkc_data = of_device_get_match_data(dev); @@ -807,12 +815,17 @@ static int axg_clkc_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) return -EINVAL; + clk_base = devm_ioremap(dev, res->start, resource_size(res)); if (!clk_base) { dev_err(dev, "Unable to map clk base\n"); return -ENXIO; } + map = devm_regmap_init_mmio(dev, clk_base, &clkc_regmap_config); + if (IS_ERR(map)) + return PTR_ERR(map); + /* Populate base address for PLLs */ for (i = 0; i < clkc_data->clk_plls_count; i++) clkc_data->clk_plls[i]->base = clk_base; diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c index 6609024eee00..e3faf0a0fdb7 100644 --- a/drivers/clk/meson/gxbb.c +++ b/drivers/clk/meson/gxbb.c @@ -19,10 +19,11 @@ #include #include +#include #include #include #include -#include +#include #include "clkc.h" #include "gxbb.h" @@ -1937,10 +1938,18 @@ static const struct of_device_id clkc_match_table[] = { {}, }; +static const struct regmap_config clkc_regmap_config = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, +}; + static int gxbb_clkc_probe(struct platform_device *pdev) { const struct clkc_data *clkc_data; + struct resource *res; void __iomem *clk_base; + struct regmap *map; int ret, i; struct device *dev = &pdev->dev; @@ -1948,13 +1957,20 @@ static int gxbb_clkc_probe(struct platform_device *pdev) if (!clkc_data) return -EINVAL; - /* Generic clocks and PLLs */ - clk_base = of_iomap(dev->of_node, 0); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -EINVAL; + + clk_base = devm_ioremap(dev, res->start, resource_size(res)); if (!clk_base) { pr_err("%s: Unable to map clk base\n", __func__); return -ENXIO; } + map = devm_regmap_init_mmio(dev, clk_base, &clkc_regmap_config); + if (IS_ERR(map)) + return PTR_ERR(map); + /* Populate base address for PLLs */ for (i = 0; i < clkc_data->clk_plls_count; i++) clkc_data->clk_plls[i]->base = clk_base; @@ -1991,17 +2007,14 @@ static int gxbb_clkc_probe(struct platform_device *pdev) ret = devm_clk_hw_register(dev, clkc_data->hw_onecell_data->hws[i]); - if (ret) - goto iounmap; + if (ret) { + dev_err(dev, "Clock registration failed\n"); + return ret; + } } - return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, clkc_data->hw_onecell_data); - -iounmap: - iounmap(clk_base); - return ret; } static struct platform_driver gxbb_driver = { diff --git a/drivers/clk/meson/meson8b.c b/drivers/clk/meson/meson8b.c index db017c29a84c..0981e970de3d 100644 --- a/drivers/clk/meson/meson8b.c +++ b/drivers/clk/meson/meson8b.c @@ -23,11 +23,12 @@ #include #include +#include #include #include #include #include -#include +#include #include "clkc.h" #include "meson8b.h" @@ -804,16 +805,27 @@ static const struct reset_control_ops meson8b_clk_reset_ops = { .deassert = meson8b_clk_reset_deassert, }; +static const struct regmap_config clkc_regmap_config = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, +}; + static int meson8b_clkc_probe(struct platform_device *pdev) { int ret, i; struct clk_hw *parent_hw; struct clk *parent_clk; struct device *dev = &pdev->dev; + struct regmap *map; if (!clk_base) return -ENXIO; + map = devm_regmap_init_mmio(dev, clk_base, &clkc_regmap_config); + if (IS_ERR(map)) + return PTR_ERR(map); + /* Populate base address for PLLs */ for (i = 0; i < ARRAY_SIZE(meson8b_clk_plls); i++) meson8b_clk_plls[i]->base = clk_base; -- cgit From 7f9768a5405192d49c5d963f5e29c740315efca7 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Mon, 12 Feb 2018 15:58:36 +0100 Subject: clk: meson: migrate gates to clk_regmap Move meson8b, gxbb and axg clocks using clk_gate to clk_regmap Signed-off-by: Jerome Brunet Signed-off-by: Neil Armstrong --- drivers/clk/meson/Kconfig | 4 +- drivers/clk/meson/axg.c | 72 ++++++------ drivers/clk/meson/clkc.h | 20 ++-- drivers/clk/meson/gxbb.c | 266 +++++++++++++++++++++++--------------------- drivers/clk/meson/meson8b.c | 39 +++---- 5 files changed, 206 insertions(+), 195 deletions(-) diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig index 9735335b17a9..936afddae406 100644 --- a/drivers/clk/meson/Kconfig +++ b/drivers/clk/meson/Kconfig @@ -11,7 +11,7 @@ config COMMON_CLK_MESON8B bool depends on COMMON_CLK_AMLOGIC select RESET_CONTROLLER - select REGMAP + select COMMON_CLK_REGMAP_MESON help Support for the clock controller on AmLogic S802 (Meson8), S805 (Meson8b) and S812 (Meson8m2) devices. Say Y if you @@ -30,7 +30,7 @@ config COMMON_CLK_AXG bool depends on COMMON_CLK_AMLOGIC select RESET_CONTROLLER - select REGMAP + select COMMON_CLK_REGMAP_MESON help Support for the clock controller on AmLogic A113D devices, aka axg. Say Y if you want peripherals and CPU frequency scaling to work. diff --git a/drivers/clk/meson/axg.c b/drivers/clk/meson/axg.c index aed0f9e64f71..ed14f6ea7b07 100644 --- a/drivers/clk/meson/axg.c +++ b/drivers/clk/meson/axg.c @@ -447,13 +447,14 @@ static struct clk_divider axg_mpeg_clk_div = { }, }; -static struct clk_gate axg_clk81 = { - .reg = (void *)HHI_MPEG_CLK_CNTL, - .bit_idx = 7, - .lock = &meson_clk_lock, +static struct clk_regmap axg_clk81 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPEG_CLK_CNTL, + .bit_idx = 7, + }, .hw.init = &(struct clk_init_data){ .name = "clk81", - .ops = &clk_gate_ops, + .ops = &clk_regmap_gate_ops, .parent_names = (const char *[]){ "mpeg_clk_div" }, .num_parents = 1, .flags = (CLK_SET_RATE_PARENT | CLK_IS_CRITICAL), @@ -501,13 +502,14 @@ static struct clk_divider axg_sd_emmc_b_clk0_div = { }, }; -static struct clk_gate axg_sd_emmc_b_clk0 = { - .reg = (void *)HHI_SD_EMMC_CLK_CNTL, - .bit_idx = 23, - .lock = &meson_clk_lock, +static struct clk_regmap axg_sd_emmc_b_clk0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_SD_EMMC_CLK_CNTL, + .bit_idx = 23, + }, .hw.init = &(struct clk_init_data){ .name = "sd_emmc_b_clk0", - .ops = &clk_gate_ops, + .ops = &clk_regmap_gate_ops, .parent_names = (const char *[]){ "sd_emmc_b_clk0_div" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, @@ -544,13 +546,14 @@ static struct clk_divider axg_sd_emmc_c_clk0_div = { }, }; -static struct clk_gate axg_sd_emmc_c_clk0 = { - .reg = (void *)HHI_NAND_CLK_CNTL, - .bit_idx = 7, - .lock = &meson_clk_lock, +static struct clk_regmap axg_sd_emmc_c_clk0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_NAND_CLK_CNTL, + .bit_idx = 7, + }, .hw.init = &(struct clk_init_data){ .name = "sd_emmc_c_clk0", - .ops = &clk_gate_ops, + .ops = &clk_regmap_gate_ops, .parent_names = (const char *[]){ "sd_emmc_c_clk0_div" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, @@ -697,7 +700,19 @@ static struct meson_clk_mpll *const axg_clk_mplls[] = { &axg_mpll3, }; -static struct clk_gate *const axg_clk_gates[] = { +static struct clk_mux *const axg_clk_muxes[] = { + &axg_mpeg_clk_sel, + &axg_sd_emmc_b_clk0_sel, + &axg_sd_emmc_c_clk0_sel, +}; + +static struct clk_divider *const axg_clk_dividers[] = { + &axg_mpeg_clk_div, + &axg_sd_emmc_b_clk0_div, + &axg_sd_emmc_c_clk0_div, +}; + +static struct clk_regmap *const axg_clk_regmaps[] = { &axg_clk81, &axg_ddr, &axg_audio_locker, @@ -747,21 +762,7 @@ static struct clk_gate *const axg_clk_gates[] = { &axg_sd_emmc_c_clk0, }; -static struct clk_mux *const axg_clk_muxes[] = { - &axg_mpeg_clk_sel, - &axg_sd_emmc_b_clk0_sel, - &axg_sd_emmc_c_clk0_sel, -}; - -static struct clk_divider *const axg_clk_dividers[] = { - &axg_mpeg_clk_div, - &axg_sd_emmc_b_clk0_div, - &axg_sd_emmc_c_clk0_div, -}; - struct clkc_data { - struct clk_gate *const *clk_gates; - unsigned int clk_gates_count; struct meson_clk_mpll *const *clk_mplls; unsigned int clk_mplls_count; struct meson_clk_pll *const *clk_plls; @@ -774,8 +775,6 @@ struct clkc_data { }; static const struct clkc_data axg_clkc_data = { - .clk_gates = axg_clk_gates, - .clk_gates_count = ARRAY_SIZE(axg_clk_gates), .clk_mplls = axg_clk_mplls, .clk_mplls_count = ARRAY_SIZE(axg_clk_mplls), .clk_plls = axg_clk_plls, @@ -834,11 +833,6 @@ static int axg_clkc_probe(struct platform_device *pdev) for (i = 0; i < clkc_data->clk_mplls_count; i++) clkc_data->clk_mplls[i]->base = clk_base; - /* Populate base address for gates */ - for (i = 0; i < clkc_data->clk_gates_count; i++) - clkc_data->clk_gates[i]->reg = clk_base + - (u64)clkc_data->clk_gates[i]->reg; - /* Populate base address for muxes */ for (i = 0; i < clkc_data->clk_muxes_count; i++) clkc_data->clk_muxes[i]->reg = clk_base + @@ -849,6 +843,10 @@ static int axg_clkc_probe(struct platform_device *pdev) clkc_data->clk_dividers[i]->reg = clk_base + (u64)clkc_data->clk_dividers[i]->reg; + /* Populate regmap for the regmap backed clocks */ + for (i = 0; i < ARRAY_SIZE(axg_clk_regmaps); i++) + axg_clk_regmaps[i]->map = map; + for (i = 0; i < clkc_data->hw_onecell_data->num; i++) { /* array might be sparse */ if (!clkc_data->hw_onecell_data->hws[i]) diff --git a/drivers/clk/meson/clkc.h b/drivers/clk/meson/clkc.h index 07aaba26a857..aa2dfa0ff89f 100644 --- a/drivers/clk/meson/clkc.h +++ b/drivers/clk/meson/clkc.h @@ -18,6 +18,9 @@ #ifndef __CLKC_H #define __CLKC_H +#include +#include "clk-regmap.h" + #define PMASK(width) GENMASK(width - 1, 0) #define SETPMASK(width, shift) GENMASK(shift + width - 1, shift) #define CLRPMASK(width, shift) (~SETPMASK(width, shift)) @@ -134,16 +137,17 @@ struct meson_clk_audio_divider { }; #define MESON_GATE(_name, _reg, _bit) \ -struct clk_gate _name = { \ - .reg = (void __iomem *) _reg, \ - .bit_idx = (_bit), \ - .lock = &meson_clk_lock, \ - .hw.init = &(struct clk_init_data) { \ - .name = #_name, \ - .ops = &clk_gate_ops, \ +struct clk_regmap _name = { \ + .data = &(struct clk_regmap_gate_data){ \ + .offset = (_reg), \ + .bit_idx = (_bit), \ + }, \ + .hw.init = &(struct clk_init_data) { \ + .name = #_name, \ + .ops = &clk_regmap_gate_ops, \ .parent_names = (const char *[]){ "clk81" }, \ .num_parents = 1, \ - .flags = (CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED), \ + .flags = (CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED), \ }, \ }; diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c index e3faf0a0fdb7..ccbbebb6a69b 100644 --- a/drivers/clk/meson/gxbb.c +++ b/drivers/clk/meson/gxbb.c @@ -27,6 +27,7 @@ #include "clkc.h" #include "gxbb.h" +#include "clk-regmap.h" static DEFINE_SPINLOCK(meson_clk_lock); @@ -617,14 +618,15 @@ static struct clk_divider gxbb_mpeg_clk_div = { }, }; -/* the mother of dragons^W gates */ -static struct clk_gate gxbb_clk81 = { - .reg = (void *)HHI_MPEG_CLK_CNTL, - .bit_idx = 7, - .lock = &meson_clk_lock, +/* the mother of dragons gates */ +static struct clk_regmap gxbb_clk81 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPEG_CLK_CNTL, + .bit_idx = 7, + }, .hw.init = &(struct clk_init_data){ .name = "clk81", - .ops = &clk_gate_ops, + .ops = &clk_regmap_gate_ops, .parent_names = (const char *[]){ "mpeg_clk_div" }, .num_parents = 1, .flags = (CLK_SET_RATE_PARENT | CLK_IS_CRITICAL), @@ -658,13 +660,14 @@ static struct clk_divider gxbb_sar_adc_clk_div = { }, }; -static struct clk_gate gxbb_sar_adc_clk = { - .reg = (void *)HHI_SAR_CLK_CNTL, - .bit_idx = 8, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_sar_adc_clk = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_SAR_CLK_CNTL, + .bit_idx = 8, + }, .hw.init = &(struct clk_init_data){ .name = "sar_adc_clk", - .ops = &clk_gate_ops, + .ops = &clk_regmap_gate_ops, .parent_names = (const char *[]){ "sar_adc_clk_div" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, @@ -716,13 +719,14 @@ static struct clk_divider gxbb_mali_0_div = { }, }; -static struct clk_gate gxbb_mali_0 = { - .reg = (void *)HHI_MALI_CLK_CNTL, - .bit_idx = 8, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_mali_0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MALI_CLK_CNTL, + .bit_idx = 8, + }, .hw.init = &(struct clk_init_data){ .name = "mali_0", - .ops = &clk_gate_ops, + .ops = &clk_regmap_gate_ops, .parent_names = (const char *[]){ "mali_0_div" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, @@ -763,13 +767,14 @@ static struct clk_divider gxbb_mali_1_div = { }, }; -static struct clk_gate gxbb_mali_1 = { - .reg = (void *)HHI_MALI_CLK_CNTL, - .bit_idx = 24, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_mali_1 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MALI_CLK_CNTL, + .bit_idx = 24, + }, .hw.init = &(struct clk_init_data){ .name = "mali_1", - .ops = &clk_gate_ops, + .ops = &clk_regmap_gate_ops, .parent_names = (const char *[]){ "mali_1_div" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, @@ -829,13 +834,14 @@ static struct meson_clk_audio_divider gxbb_cts_amclk_div = { }, }; -static struct clk_gate gxbb_cts_amclk = { - .reg = (void *) HHI_AUD_CLK_CNTL, - .bit_idx = 8, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_cts_amclk = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_AUD_CLK_CNTL, + .bit_idx = 8, + }, .hw.init = &(struct clk_init_data){ .name = "cts_amclk", - .ops = &clk_gate_ops, + .ops = &clk_regmap_gate_ops, .parent_names = (const char *[]){ "cts_amclk_div" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, @@ -873,13 +879,14 @@ static struct clk_divider gxbb_cts_mclk_i958_div = { }, }; -static struct clk_gate gxbb_cts_mclk_i958 = { - .reg = (void *)HHI_AUD_CLK_CNTL2, - .bit_idx = 24, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_cts_mclk_i958 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_AUD_CLK_CNTL2, + .bit_idx = 24, + }, .hw.init = &(struct clk_init_data){ .name = "cts_mclk_i958", - .ops = &clk_gate_ops, + .ops = &clk_regmap_gate_ops, .parent_names = (const char *[]){ "cts_mclk_i958_div" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, @@ -918,13 +925,14 @@ static struct clk_divider gxbb_32k_clk_div = { }, }; -static struct clk_gate gxbb_32k_clk = { - .reg = (void *)HHI_32K_CLK_CNTL, - .bit_idx = 15, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_32k_clk = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_32K_CLK_CNTL, + .bit_idx = 15, + }, .hw.init = &(struct clk_init_data){ .name = "32k_clk", - .ops = &clk_gate_ops, + .ops = &clk_regmap_gate_ops, .parent_names = (const char *[]){ "32k_clk_div" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, @@ -990,13 +998,14 @@ static struct clk_divider gxbb_sd_emmc_a_clk0_div = { }, }; -static struct clk_gate gxbb_sd_emmc_a_clk0 = { - .reg = (void *)HHI_SD_EMMC_CLK_CNTL, - .bit_idx = 7, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_sd_emmc_a_clk0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_SD_EMMC_CLK_CNTL, + .bit_idx = 7, + }, .hw.init = &(struct clk_init_data){ .name = "sd_emmc_a_clk0", - .ops = &clk_gate_ops, + .ops = &clk_regmap_gate_ops, .parent_names = (const char *[]){ "sd_emmc_a_clk0_div" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, @@ -1033,13 +1042,14 @@ static struct clk_divider gxbb_sd_emmc_b_clk0_div = { }, }; -static struct clk_gate gxbb_sd_emmc_b_clk0 = { - .reg = (void *)HHI_SD_EMMC_CLK_CNTL, - .bit_idx = 23, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_sd_emmc_b_clk0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_SD_EMMC_CLK_CNTL, + .bit_idx = 23, + }, .hw.init = &(struct clk_init_data){ .name = "sd_emmc_b_clk0", - .ops = &clk_gate_ops, + .ops = &clk_regmap_gate_ops, .parent_names = (const char *[]){ "sd_emmc_b_clk0_div" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, @@ -1076,13 +1086,14 @@ static struct clk_divider gxbb_sd_emmc_c_clk0_div = { }, }; -static struct clk_gate gxbb_sd_emmc_c_clk0 = { - .reg = (void *)HHI_NAND_CLK_CNTL, - .bit_idx = 7, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_sd_emmc_c_clk0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_NAND_CLK_CNTL, + .bit_idx = 7, + }, .hw.init = &(struct clk_init_data){ .name = "sd_emmc_c_clk0", - .ops = &clk_gate_ops, + .ops = &clk_regmap_gate_ops, .parent_names = (const char *[]){ "sd_emmc_c_clk0_div" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, @@ -1129,13 +1140,14 @@ static struct clk_divider gxbb_vpu_0_div = { }, }; -static struct clk_gate gxbb_vpu_0 = { - .reg = (void *)HHI_VPU_CLK_CNTL, - .bit_idx = 8, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_vpu_0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VPU_CLK_CNTL, + .bit_idx = 8, + }, .hw.init = &(struct clk_init_data) { .name = "vpu_0", - .ops = &clk_gate_ops, + .ops = &clk_regmap_gate_ops, .parent_names = (const char *[]){ "vpu_0_div" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, @@ -1175,13 +1187,14 @@ static struct clk_divider gxbb_vpu_1_div = { }, }; -static struct clk_gate gxbb_vpu_1 = { - .reg = (void *)HHI_VPU_CLK_CNTL, - .bit_idx = 24, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_vpu_1 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VPU_CLK_CNTL, + .bit_idx = 24, + }, .hw.init = &(struct clk_init_data) { .name = "vpu_1", - .ops = &clk_gate_ops, + .ops = &clk_regmap_gate_ops, .parent_names = (const char *[]){ "vpu_1_div" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, @@ -1246,13 +1259,14 @@ static struct clk_divider gxbb_vapb_0_div = { }, }; -static struct clk_gate gxbb_vapb_0 = { - .reg = (void *)HHI_VAPBCLK_CNTL, - .bit_idx = 8, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_vapb_0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VAPBCLK_CNTL, + .bit_idx = 8, + }, .hw.init = &(struct clk_init_data) { .name = "vapb_0", - .ops = &clk_gate_ops, + .ops = &clk_regmap_gate_ops, .parent_names = (const char *[]){ "vapb_0_div" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, @@ -1292,13 +1306,14 @@ static struct clk_divider gxbb_vapb_1_div = { }, }; -static struct clk_gate gxbb_vapb_1 = { - .reg = (void *)HHI_VAPBCLK_CNTL, - .bit_idx = 24, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_vapb_1 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VAPBCLK_CNTL, + .bit_idx = 24, + }, .hw.init = &(struct clk_init_data) { .name = "vapb_1", - .ops = &clk_gate_ops, + .ops = &clk_regmap_gate_ops, .parent_names = (const char *[]){ "vapb_1_div" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, @@ -1323,13 +1338,14 @@ static struct clk_mux gxbb_vapb_sel = { }, }; -static struct clk_gate gxbb_vapb = { - .reg = (void *)HHI_VAPBCLK_CNTL, - .bit_idx = 30, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_vapb = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VAPBCLK_CNTL, + .bit_idx = 30, + }, .hw.init = &(struct clk_init_data) { .name = "vapb", - .ops = &clk_gate_ops, + .ops = &clk_regmap_gate_ops, .parent_names = (const char *[]){ "vapb_sel" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, @@ -1744,7 +1760,48 @@ static struct meson_clk_mpll *const gxbb_clk_mplls[] = { &gxbb_mpll2, }; -static struct clk_gate *const gxbb_clk_gates[] = { +static struct clk_mux *const gxbb_clk_muxes[] = { + &gxbb_mpeg_clk_sel, + &gxbb_sar_adc_clk_sel, + &gxbb_mali_0_sel, + &gxbb_mali_1_sel, + &gxbb_mali, + &gxbb_cts_amclk_sel, + &gxbb_cts_mclk_i958_sel, + &gxbb_cts_i958, + &gxbb_32k_clk_sel, + &gxbb_sd_emmc_a_clk0_sel, + &gxbb_sd_emmc_b_clk0_sel, + &gxbb_sd_emmc_c_clk0_sel, + &gxbb_vpu_0_sel, + &gxbb_vpu_1_sel, + &gxbb_vpu, + &gxbb_vapb_0_sel, + &gxbb_vapb_1_sel, + &gxbb_vapb_sel, +}; + +static struct clk_divider *const gxbb_clk_dividers[] = { + &gxbb_mpeg_clk_div, + &gxbb_sar_adc_clk_div, + &gxbb_mali_0_div, + &gxbb_mali_1_div, + &gxbb_cts_mclk_i958_div, + &gxbb_32k_clk_div, + &gxbb_sd_emmc_a_clk0_div, + &gxbb_sd_emmc_b_clk0_div, + &gxbb_sd_emmc_c_clk0_div, + &gxbb_vpu_0_div, + &gxbb_vpu_1_div, + &gxbb_vapb_0_div, + &gxbb_vapb_1_div, +}; + +static struct meson_clk_audio_divider *const gxbb_audio_dividers[] = { + &gxbb_cts_amclk_div, +}; + +static struct clk_regmap *const gx_clk_regmaps[] = { &gxbb_clk81, &gxbb_ddr, &gxbb_dos, @@ -1843,50 +1900,7 @@ static struct clk_gate *const gxbb_clk_gates[] = { &gxbb_vapb, }; -static struct clk_mux *const gxbb_clk_muxes[] = { - &gxbb_mpeg_clk_sel, - &gxbb_sar_adc_clk_sel, - &gxbb_mali_0_sel, - &gxbb_mali_1_sel, - &gxbb_mali, - &gxbb_cts_amclk_sel, - &gxbb_cts_mclk_i958_sel, - &gxbb_cts_i958, - &gxbb_32k_clk_sel, - &gxbb_sd_emmc_a_clk0_sel, - &gxbb_sd_emmc_b_clk0_sel, - &gxbb_sd_emmc_c_clk0_sel, - &gxbb_vpu_0_sel, - &gxbb_vpu_1_sel, - &gxbb_vpu, - &gxbb_vapb_0_sel, - &gxbb_vapb_1_sel, - &gxbb_vapb_sel, -}; - -static struct clk_divider *const gxbb_clk_dividers[] = { - &gxbb_mpeg_clk_div, - &gxbb_sar_adc_clk_div, - &gxbb_mali_0_div, - &gxbb_mali_1_div, - &gxbb_cts_mclk_i958_div, - &gxbb_32k_clk_div, - &gxbb_sd_emmc_a_clk0_div, - &gxbb_sd_emmc_b_clk0_div, - &gxbb_sd_emmc_c_clk0_div, - &gxbb_vpu_0_div, - &gxbb_vpu_1_div, - &gxbb_vapb_0_div, - &gxbb_vapb_1_div, -}; - -static struct meson_clk_audio_divider *const gxbb_audio_dividers[] = { - &gxbb_cts_amclk_div, -}; - struct clkc_data { - struct clk_gate *const *clk_gates; - unsigned int clk_gates_count; struct meson_clk_mpll *const *clk_mplls; unsigned int clk_mplls_count; struct meson_clk_pll *const *clk_plls; @@ -1901,8 +1915,6 @@ struct clkc_data { }; static const struct clkc_data gxbb_clkc_data = { - .clk_gates = gxbb_clk_gates, - .clk_gates_count = ARRAY_SIZE(gxbb_clk_gates), .clk_mplls = gxbb_clk_mplls, .clk_mplls_count = ARRAY_SIZE(gxbb_clk_mplls), .clk_plls = gxbb_clk_plls, @@ -1917,8 +1929,6 @@ static const struct clkc_data gxbb_clkc_data = { }; static const struct clkc_data gxl_clkc_data = { - .clk_gates = gxbb_clk_gates, - .clk_gates_count = ARRAY_SIZE(gxbb_clk_gates), .clk_mplls = gxbb_clk_mplls, .clk_mplls_count = ARRAY_SIZE(gxbb_clk_mplls), .clk_plls = gxl_clk_plls, @@ -1979,11 +1989,6 @@ static int gxbb_clkc_probe(struct platform_device *pdev) for (i = 0; i < clkc_data->clk_mplls_count; i++) clkc_data->clk_mplls[i]->base = clk_base; - /* Populate base address for gates */ - for (i = 0; i < clkc_data->clk_gates_count; i++) - clkc_data->clk_gates[i]->reg = clk_base + - (u64)clkc_data->clk_gates[i]->reg; - /* Populate base address for muxes */ for (i = 0; i < clkc_data->clk_muxes_count; i++) clkc_data->clk_muxes[i]->reg = clk_base + @@ -1998,6 +2003,9 @@ static int gxbb_clkc_probe(struct platform_device *pdev) for (i = 0; i < clkc_data->clk_audio_dividers_count; i++) clkc_data->clk_audio_dividers[i]->base = clk_base; + /* Populate regmap for the common regmap backed clocks */ + for (i = 0; i < ARRAY_SIZE(gx_clk_regmaps); i++) + gx_clk_regmaps[i]->map = map; /* Register all clks */ for (i = 0; i < clkc_data->hw_onecell_data->num; i++) { diff --git a/drivers/clk/meson/meson8b.c b/drivers/clk/meson/meson8b.c index 0981e970de3d..835dbb1d2c9d 100644 --- a/drivers/clk/meson/meson8b.c +++ b/drivers/clk/meson/meson8b.c @@ -32,6 +32,7 @@ #include "clkc.h" #include "meson8b.h" +#include "clk-regmap.h" static DEFINE_SPINLOCK(meson_clk_lock); @@ -406,13 +407,14 @@ struct clk_divider meson8b_mpeg_clk_div = { }, }; -struct clk_gate meson8b_clk81 = { - .reg = (void *)HHI_MPEG_CLK_CNTL, - .bit_idx = 7, - .lock = &meson_clk_lock, +struct clk_regmap meson8b_clk81 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPEG_CLK_CNTL, + .bit_idx = 7, + }, .hw.init = &(struct clk_init_data){ .name = "clk81", - .ops = &clk_gate_ops, + .ops = &clk_regmap_gate_ops, .parent_names = (const char *[]){ "mpeg_clk_div" }, .num_parents = 1, .flags = (CLK_SET_RATE_PARENT | CLK_IS_CRITICAL), @@ -617,7 +619,15 @@ static struct meson_clk_mpll *const meson8b_clk_mplls[] = { &meson8b_mpll2, }; -static struct clk_gate *const meson8b_clk_gates[] = { +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 struct clk_regmap *const meson8b_clk_regmaps[] = { &meson8b_clk81, &meson8b_ddr, &meson8b_dos, @@ -698,14 +708,6 @@ 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 const struct meson8b_clk_reset_line { u32 reg; u8 bit_idx; @@ -837,11 +839,6 @@ static int meson8b_clkc_probe(struct platform_device *pdev) /* Populate the base address for CPU clk */ meson8b_cpu_clk.base = clk_base; - /* 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 + @@ -852,6 +849,10 @@ static int meson8b_clkc_probe(struct platform_device *pdev) meson8b_clk_dividers[i]->reg = clk_base + (u32)meson8b_clk_dividers[i]->reg; + /* Populate regmap for the regmap backed clocks */ + for (i = 0; i < ARRAY_SIZE(meson8b_clk_regmaps); i++) + meson8b_clk_regmaps[i]->map = map; + /* * register all clks * CLKID_UNUSED = 0, so skip it and start with CLKID_XTAL = 1 -- cgit From f06ddd2852b3f45cf37e2abd6b0de4f9cec80f0f Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Mon, 12 Feb 2018 15:58:37 +0100 Subject: clk: meson: migrate dividers to clk_regmap Move meson8b, gxbb and axg clocks using clk_divider to clk_regmap Signed-off-by: Jerome Brunet Signed-off-by: Neil Armstrong --- drivers/clk/meson/axg.c | 61 ++++++------- drivers/clk/meson/gxbb.c | 217 ++++++++++++++++++++++---------------------- drivers/clk/meson/meson8b.c | 23 ++--- 3 files changed, 142 insertions(+), 159 deletions(-) diff --git a/drivers/clk/meson/axg.c b/drivers/clk/meson/axg.c index ed14f6ea7b07..f8b8ff2eba6c 100644 --- a/drivers/clk/meson/axg.c +++ b/drivers/clk/meson/axg.c @@ -433,14 +433,15 @@ static struct clk_mux axg_mpeg_clk_sel = { }, }; -static struct clk_divider axg_mpeg_clk_div = { - .reg = (void *)HHI_MPEG_CLK_CNTL, - .shift = 0, - .width = 7, - .lock = &meson_clk_lock, +static struct clk_regmap axg_mpeg_clk_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_MPEG_CLK_CNTL, + .shift = 0, + .width = 7, + }, .hw.init = &(struct clk_init_data){ .name = "mpeg_clk_div", - .ops = &clk_divider_ops, + .ops = &clk_regmap_divider_ops, .parent_names = (const char *[]){ "mpeg_clk_sel" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, @@ -487,15 +488,16 @@ static struct clk_mux axg_sd_emmc_b_clk0_sel = { }, }; -static struct clk_divider axg_sd_emmc_b_clk0_div = { - .reg = (void *)HHI_SD_EMMC_CLK_CNTL, - .shift = 16, - .width = 7, - .lock = &meson_clk_lock, - .flags = CLK_DIVIDER_ROUND_CLOSEST, +static struct clk_regmap axg_sd_emmc_b_clk0_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_SD_EMMC_CLK_CNTL, + .shift = 16, + .width = 7, + .flags = CLK_DIVIDER_ROUND_CLOSEST, + }, .hw.init = &(struct clk_init_data) { .name = "sd_emmc_b_clk0_div", - .ops = &clk_divider_ops, + .ops = &clk_regmap_divider_ops, .parent_names = (const char *[]){ "sd_emmc_b_clk0_sel" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, @@ -531,15 +533,16 @@ static struct clk_mux axg_sd_emmc_c_clk0_sel = { }, }; -static struct clk_divider axg_sd_emmc_c_clk0_div = { - .reg = (void *)HHI_NAND_CLK_CNTL, - .shift = 0, - .width = 7, - .lock = &meson_clk_lock, - .flags = CLK_DIVIDER_ROUND_CLOSEST, +static struct clk_regmap axg_sd_emmc_c_clk0_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_NAND_CLK_CNTL, + .shift = 0, + .width = 7, + .flags = CLK_DIVIDER_ROUND_CLOSEST, + }, .hw.init = &(struct clk_init_data) { .name = "sd_emmc_c_clk0_div", - .ops = &clk_divider_ops, + .ops = &clk_regmap_divider_ops, .parent_names = (const char *[]){ "sd_emmc_c_clk0_sel" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, @@ -706,12 +709,6 @@ static struct clk_mux *const axg_clk_muxes[] = { &axg_sd_emmc_c_clk0_sel, }; -static struct clk_divider *const axg_clk_dividers[] = { - &axg_mpeg_clk_div, - &axg_sd_emmc_b_clk0_div, - &axg_sd_emmc_c_clk0_div, -}; - static struct clk_regmap *const axg_clk_regmaps[] = { &axg_clk81, &axg_ddr, @@ -760,6 +757,9 @@ static struct clk_regmap *const axg_clk_regmaps[] = { &axg_ao_i2c, &axg_sd_emmc_b_clk0, &axg_sd_emmc_c_clk0, + &axg_mpeg_clk_div, + &axg_sd_emmc_b_clk0_div, + &axg_sd_emmc_c_clk0_div, }; struct clkc_data { @@ -769,8 +769,6 @@ struct clkc_data { unsigned int clk_plls_count; struct clk_mux *const *clk_muxes; unsigned int clk_muxes_count; - struct clk_divider *const *clk_dividers; - unsigned int clk_dividers_count; struct clk_hw_onecell_data *hw_onecell_data; }; @@ -781,8 +779,6 @@ static const struct clkc_data axg_clkc_data = { .clk_plls_count = ARRAY_SIZE(axg_clk_plls), .clk_muxes = axg_clk_muxes, .clk_muxes_count = ARRAY_SIZE(axg_clk_muxes), - .clk_dividers = axg_clk_dividers, - .clk_dividers_count = ARRAY_SIZE(axg_clk_dividers), .hw_onecell_data = &axg_hw_onecell_data, }; @@ -838,11 +834,6 @@ static int axg_clkc_probe(struct platform_device *pdev) clkc_data->clk_muxes[i]->reg = clk_base + (u64)clkc_data->clk_muxes[i]->reg; - /* Populate base address for dividers */ - for (i = 0; i < clkc_data->clk_dividers_count; i++) - clkc_data->clk_dividers[i]->reg = clk_base + - (u64)clkc_data->clk_dividers[i]->reg; - /* Populate regmap for the regmap backed clocks */ for (i = 0; i < ARRAY_SIZE(axg_clk_regmaps); i++) axg_clk_regmaps[i]->map = map; diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c index ccbbebb6a69b..ec515dc71476 100644 --- a/drivers/clk/meson/gxbb.c +++ b/drivers/clk/meson/gxbb.c @@ -604,14 +604,15 @@ static struct clk_mux gxbb_mpeg_clk_sel = { }, }; -static struct clk_divider gxbb_mpeg_clk_div = { - .reg = (void *)HHI_MPEG_CLK_CNTL, - .shift = 0, - .width = 7, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_mpeg_clk_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_MPEG_CLK_CNTL, + .shift = 0, + .width = 7, + }, .hw.init = &(struct clk_init_data){ .name = "mpeg_clk_div", - .ops = &clk_divider_ops, + .ops = &clk_regmap_divider_ops, .parent_names = (const char *[]){ "mpeg_clk_sel" }, .num_parents = 1, .flags = (CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED), @@ -647,14 +648,15 @@ static struct clk_mux gxbb_sar_adc_clk_sel = { }, }; -static struct clk_divider gxbb_sar_adc_clk_div = { - .reg = (void *)HHI_SAR_CLK_CNTL, - .shift = 0, - .width = 8, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_sar_adc_clk_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_SAR_CLK_CNTL, + .shift = 0, + .width = 8, + }, .hw.init = &(struct clk_init_data){ .name = "sar_adc_clk_div", - .ops = &clk_divider_ops, + .ops = &clk_regmap_divider_ops, .parent_names = (const char *[]){ "sar_adc_clk_sel" }, .num_parents = 1, }, @@ -705,14 +707,15 @@ static struct clk_mux gxbb_mali_0_sel = { }, }; -static struct clk_divider gxbb_mali_0_div = { - .reg = (void *)HHI_MALI_CLK_CNTL, - .shift = 0, - .width = 7, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_mali_0_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_MALI_CLK_CNTL, + .shift = 0, + .width = 7, + }, .hw.init = &(struct clk_init_data){ .name = "mali_0_div", - .ops = &clk_divider_ops, + .ops = &clk_regmap_divider_ops, .parent_names = (const char *[]){ "mali_0_sel" }, .num_parents = 1, .flags = CLK_SET_RATE_NO_REPARENT, @@ -753,14 +756,15 @@ static struct clk_mux gxbb_mali_1_sel = { }, }; -static struct clk_divider gxbb_mali_1_div = { - .reg = (void *)HHI_MALI_CLK_CNTL, - .shift = 16, - .width = 7, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_mali_1_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_MALI_CLK_CNTL, + .shift = 16, + .width = 7, + }, .hw.init = &(struct clk_init_data){ .name = "mali_1_div", - .ops = &clk_divider_ops, + .ops = &clk_regmap_divider_ops, .parent_names = (const char *[]){ "mali_1_sel" }, .num_parents = 1, .flags = CLK_SET_RATE_NO_REPARENT, @@ -864,15 +868,16 @@ static struct clk_mux gxbb_cts_mclk_i958_sel = { }, }; -static struct clk_divider gxbb_cts_mclk_i958_div = { - .reg = (void *)HHI_AUD_CLK_CNTL2, - .shift = 16, - .width = 8, - .lock = &meson_clk_lock, - .flags = CLK_DIVIDER_ROUND_CLOSEST, +static struct clk_regmap gxbb_cts_mclk_i958_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_AUD_CLK_CNTL2, + .shift = 16, + .width = 8, + .flags = CLK_DIVIDER_ROUND_CLOSEST, + }, .hw.init = &(struct clk_init_data) { .name = "cts_mclk_i958_div", - .ops = &clk_divider_ops, + .ops = &clk_regmap_divider_ops, .parent_names = (const char *[]){ "cts_mclk_i958_sel" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, @@ -911,14 +916,15 @@ static struct clk_mux gxbb_cts_i958 = { }, }; -static struct clk_divider gxbb_32k_clk_div = { - .reg = (void *)HHI_32K_CLK_CNTL, - .shift = 0, - .width = 14, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_32k_clk_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_32K_CLK_CNTL, + .shift = 0, + .width = 14, + }, .hw.init = &(struct clk_init_data){ .name = "32k_clk_div", - .ops = &clk_divider_ops, + .ops = &clk_regmap_divider_ops, .parent_names = (const char *[]){ "32k_clk_sel" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT | CLK_DIVIDER_ROUND_CLOSEST, @@ -983,15 +989,16 @@ static struct clk_mux gxbb_sd_emmc_a_clk0_sel = { }, }; -static struct clk_divider gxbb_sd_emmc_a_clk0_div = { - .reg = (void *)HHI_SD_EMMC_CLK_CNTL, - .shift = 0, - .width = 7, - .lock = &meson_clk_lock, - .flags = CLK_DIVIDER_ROUND_CLOSEST, +static struct clk_regmap gxbb_sd_emmc_a_clk0_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_SD_EMMC_CLK_CNTL, + .shift = 0, + .width = 7, + .flags = CLK_DIVIDER_ROUND_CLOSEST, + }, .hw.init = &(struct clk_init_data) { .name = "sd_emmc_a_clk0_div", - .ops = &clk_divider_ops, + .ops = &clk_regmap_divider_ops, .parent_names = (const char *[]){ "sd_emmc_a_clk0_sel" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, @@ -1027,15 +1034,16 @@ static struct clk_mux gxbb_sd_emmc_b_clk0_sel = { }, }; -static struct clk_divider gxbb_sd_emmc_b_clk0_div = { - .reg = (void *)HHI_SD_EMMC_CLK_CNTL, - .shift = 16, - .width = 7, - .lock = &meson_clk_lock, - .flags = CLK_DIVIDER_ROUND_CLOSEST, +static struct clk_regmap gxbb_sd_emmc_b_clk0_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_SD_EMMC_CLK_CNTL, + .shift = 16, + .width = 7, + .flags = CLK_DIVIDER_ROUND_CLOSEST, + }, .hw.init = &(struct clk_init_data) { .name = "sd_emmc_b_clk0_div", - .ops = &clk_divider_ops, + .ops = &clk_regmap_divider_ops, .parent_names = (const char *[]){ "sd_emmc_b_clk0_sel" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, @@ -1071,15 +1079,16 @@ static struct clk_mux gxbb_sd_emmc_c_clk0_sel = { }, }; -static struct clk_divider gxbb_sd_emmc_c_clk0_div = { - .reg = (void *)HHI_NAND_CLK_CNTL, - .shift = 0, - .width = 7, - .lock = &meson_clk_lock, - .flags = CLK_DIVIDER_ROUND_CLOSEST, +static struct clk_regmap gxbb_sd_emmc_c_clk0_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_NAND_CLK_CNTL, + .shift = 0, + .width = 7, + .flags = CLK_DIVIDER_ROUND_CLOSEST, + }, .hw.init = &(struct clk_init_data) { .name = "sd_emmc_c_clk0_div", - .ops = &clk_divider_ops, + .ops = &clk_regmap_divider_ops, .parent_names = (const char *[]){ "sd_emmc_c_clk0_sel" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, @@ -1126,14 +1135,15 @@ static struct clk_mux gxbb_vpu_0_sel = { }, }; -static struct clk_divider gxbb_vpu_0_div = { - .reg = (void *)HHI_VPU_CLK_CNTL, - .shift = 0, - .width = 7, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_vpu_0_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_VPU_CLK_CNTL, + .shift = 0, + .width = 7, + }, .hw.init = &(struct clk_init_data){ .name = "vpu_0_div", - .ops = &clk_divider_ops, + .ops = &clk_regmap_divider_ops, .parent_names = (const char *[]){ "vpu_0_sel" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, @@ -1173,14 +1183,15 @@ static struct clk_mux gxbb_vpu_1_sel = { }, }; -static struct clk_divider gxbb_vpu_1_div = { - .reg = (void *)HHI_VPU_CLK_CNTL, - .shift = 16, - .width = 7, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_vpu_1_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_VPU_CLK_CNTL, + .shift = 16, + .width = 7, + }, .hw.init = &(struct clk_init_data){ .name = "vpu_1_div", - .ops = &clk_divider_ops, + .ops = &clk_regmap_divider_ops, .parent_names = (const char *[]){ "vpu_1_sel" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, @@ -1245,14 +1256,15 @@ static struct clk_mux gxbb_vapb_0_sel = { }, }; -static struct clk_divider gxbb_vapb_0_div = { - .reg = (void *)HHI_VAPBCLK_CNTL, - .shift = 0, - .width = 7, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_vapb_0_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_VAPBCLK_CNTL, + .shift = 0, + .width = 7, + }, .hw.init = &(struct clk_init_data){ .name = "vapb_0_div", - .ops = &clk_divider_ops, + .ops = &clk_regmap_divider_ops, .parent_names = (const char *[]){ "vapb_0_sel" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, @@ -1292,14 +1304,15 @@ static struct clk_mux gxbb_vapb_1_sel = { }, }; -static struct clk_divider gxbb_vapb_1_div = { - .reg = (void *)HHI_VAPBCLK_CNTL, - .shift = 16, - .width = 7, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_vapb_1_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_VAPBCLK_CNTL, + .shift = 16, + .width = 7, + }, .hw.init = &(struct clk_init_data){ .name = "vapb_1_div", - .ops = &clk_divider_ops, + .ops = &clk_regmap_divider_ops, .parent_names = (const char *[]){ "vapb_1_sel" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, @@ -1781,22 +1794,6 @@ static struct clk_mux *const gxbb_clk_muxes[] = { &gxbb_vapb_sel, }; -static struct clk_divider *const gxbb_clk_dividers[] = { - &gxbb_mpeg_clk_div, - &gxbb_sar_adc_clk_div, - &gxbb_mali_0_div, - &gxbb_mali_1_div, - &gxbb_cts_mclk_i958_div, - &gxbb_32k_clk_div, - &gxbb_sd_emmc_a_clk0_div, - &gxbb_sd_emmc_b_clk0_div, - &gxbb_sd_emmc_c_clk0_div, - &gxbb_vpu_0_div, - &gxbb_vpu_1_div, - &gxbb_vapb_0_div, - &gxbb_vapb_1_div, -}; - static struct meson_clk_audio_divider *const gxbb_audio_dividers[] = { &gxbb_cts_amclk_div, }; @@ -1898,6 +1895,19 @@ static struct clk_regmap *const gx_clk_regmaps[] = { &gxbb_vapb_0, &gxbb_vapb_1, &gxbb_vapb, + &gxbb_mpeg_clk_div, + &gxbb_sar_adc_clk_div, + &gxbb_mali_0_div, + &gxbb_mali_1_div, + &gxbb_cts_mclk_i958_div, + &gxbb_32k_clk_div, + &gxbb_sd_emmc_a_clk0_div, + &gxbb_sd_emmc_b_clk0_div, + &gxbb_sd_emmc_c_clk0_div, + &gxbb_vpu_0_div, + &gxbb_vpu_1_div, + &gxbb_vapb_0_div, + &gxbb_vapb_1_div, }; struct clkc_data { @@ -1907,8 +1917,6 @@ struct clkc_data { unsigned int clk_plls_count; struct clk_mux *const *clk_muxes; unsigned int clk_muxes_count; - struct clk_divider *const *clk_dividers; - unsigned int clk_dividers_count; struct meson_clk_audio_divider *const *clk_audio_dividers; unsigned int clk_audio_dividers_count; struct clk_hw_onecell_data *hw_onecell_data; @@ -1921,8 +1929,6 @@ static const struct clkc_data gxbb_clkc_data = { .clk_plls_count = ARRAY_SIZE(gxbb_clk_plls), .clk_muxes = gxbb_clk_muxes, .clk_muxes_count = ARRAY_SIZE(gxbb_clk_muxes), - .clk_dividers = gxbb_clk_dividers, - .clk_dividers_count = ARRAY_SIZE(gxbb_clk_dividers), .clk_audio_dividers = gxbb_audio_dividers, .clk_audio_dividers_count = ARRAY_SIZE(gxbb_audio_dividers), .hw_onecell_data = &gxbb_hw_onecell_data, @@ -1935,8 +1941,6 @@ static const struct clkc_data gxl_clkc_data = { .clk_plls_count = ARRAY_SIZE(gxl_clk_plls), .clk_muxes = gxbb_clk_muxes, .clk_muxes_count = ARRAY_SIZE(gxbb_clk_muxes), - .clk_dividers = gxbb_clk_dividers, - .clk_dividers_count = ARRAY_SIZE(gxbb_clk_dividers), .clk_audio_dividers = gxbb_audio_dividers, .clk_audio_dividers_count = ARRAY_SIZE(gxbb_audio_dividers), .hw_onecell_data = &gxl_hw_onecell_data, @@ -1994,11 +1998,6 @@ static int gxbb_clkc_probe(struct platform_device *pdev) clkc_data->clk_muxes[i]->reg = clk_base + (u64)clkc_data->clk_muxes[i]->reg; - /* Populate base address for dividers */ - for (i = 0; i < clkc_data->clk_dividers_count; i++) - clkc_data->clk_dividers[i]->reg = clk_base + - (u64)clkc_data->clk_dividers[i]->reg; - /* Populate base address for the audio dividers */ for (i = 0; i < clkc_data->clk_audio_dividers_count; i++) clkc_data->clk_audio_dividers[i]->base = clk_base; diff --git a/drivers/clk/meson/meson8b.c b/drivers/clk/meson/meson8b.c index 835dbb1d2c9d..e9c5278072cd 100644 --- a/drivers/clk/meson/meson8b.c +++ b/drivers/clk/meson/meson8b.c @@ -393,14 +393,15 @@ struct clk_mux meson8b_mpeg_clk_sel = { }, }; -struct clk_divider meson8b_mpeg_clk_div = { - .reg = (void *)HHI_MPEG_CLK_CNTL, - .shift = 0, - .width = 7, - .lock = &meson_clk_lock, +struct clk_regmap meson8b_mpeg_clk_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_MPEG_CLK_CNTL, + .shift = 0, + .width = 7, + }, .hw.init = &(struct clk_init_data){ .name = "mpeg_clk_div", - .ops = &clk_divider_ops, + .ops = &clk_regmap_divider_ops, .parent_names = (const char *[]){ "mpeg_clk_sel" }, .num_parents = 1, .flags = (CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED), @@ -623,10 +624,6 @@ 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 struct clk_regmap *const meson8b_clk_regmaps[] = { &meson8b_clk81, &meson8b_ddr, @@ -706,6 +703,7 @@ static struct clk_regmap *const meson8b_clk_regmaps[] = { &meson8b_ao_ahb_sram, &meson8b_ao_ahb_bus, &meson8b_ao_iface, + &meson8b_mpeg_clk_div, }; static const struct meson8b_clk_reset_line { @@ -844,11 +842,6 @@ static int meson8b_clkc_probe(struct platform_device *pdev) 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; - /* Populate regmap for the regmap backed clocks */ for (i = 0; i < ARRAY_SIZE(meson8b_clk_regmaps); i++) meson8b_clk_regmaps[i]->map = map; -- cgit From 2513a28c108b0584989927195ba5230e296762ec Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Mon, 12 Feb 2018 15:58:38 +0100 Subject: clk: meson: migrate muxes to clk_regmap Move meson8b, gxbb and axg clocks using clk_mux to clk_regmap Also remove a few useless tables in the process Signed-off-by: Jerome Brunet Signed-off-by: Neil Armstrong --- drivers/clk/meson/axg.c | 60 ++++----- drivers/clk/meson/gxbb.c | 310 +++++++++++++++++++++----------------------- drivers/clk/meson/meson8b.c | 27 ++-- 3 files changed, 184 insertions(+), 213 deletions(-) diff --git a/drivers/clk/meson/axg.c b/drivers/clk/meson/axg.c index f8b8ff2eba6c..9f0c36e12cb8 100644 --- a/drivers/clk/meson/axg.c +++ b/drivers/clk/meson/axg.c @@ -418,16 +418,16 @@ static const char * const clk81_parent_names[] = { "fclk_div3", "fclk_div5" }; -static struct clk_mux axg_mpeg_clk_sel = { - .reg = (void *)HHI_MPEG_CLK_CNTL, - .mask = 0x7, - .shift = 12, - .flags = CLK_MUX_READ_ONLY, - .table = mux_table_clk81, - .lock = &meson_clk_lock, +static struct clk_regmap axg_mpeg_clk_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_MPEG_CLK_CNTL, + .mask = 0x7, + .shift = 12, + .table = mux_table_clk81, + }, .hw.init = &(struct clk_init_data){ .name = "mpeg_clk_sel", - .ops = &clk_mux_ro_ops, + .ops = &clk_regmap_mux_ro_ops, .parent_names = clk81_parent_names, .num_parents = ARRAY_SIZE(clk81_parent_names), }, @@ -474,14 +474,15 @@ static const char * const axg_sd_emmc_clk0_parent_names[] = { }; /* SDcard clock */ -static struct clk_mux axg_sd_emmc_b_clk0_sel = { - .reg = (void *)HHI_SD_EMMC_CLK_CNTL, - .mask = 0x7, - .shift = 25, - .lock = &meson_clk_lock, +static struct clk_regmap axg_sd_emmc_b_clk0_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_SD_EMMC_CLK_CNTL, + .mask = 0x7, + .shift = 25, + }, .hw.init = &(struct clk_init_data) { .name = "sd_emmc_b_clk0_sel", - .ops = &clk_mux_ops, + .ops = &clk_regmap_mux_ops, .parent_names = axg_sd_emmc_clk0_parent_names, .num_parents = ARRAY_SIZE(axg_sd_emmc_clk0_parent_names), .flags = CLK_SET_RATE_PARENT, @@ -519,14 +520,15 @@ static struct clk_regmap axg_sd_emmc_b_clk0 = { }; /* EMMC/NAND clock */ -static struct clk_mux axg_sd_emmc_c_clk0_sel = { - .reg = (void *)HHI_NAND_CLK_CNTL, - .mask = 0x7, - .shift = 9, - .lock = &meson_clk_lock, +static struct clk_regmap axg_sd_emmc_c_clk0_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_NAND_CLK_CNTL, + .mask = 0x7, + .shift = 9, + }, .hw.init = &(struct clk_init_data) { .name = "sd_emmc_c_clk0_sel", - .ops = &clk_mux_ops, + .ops = &clk_regmap_mux_ops, .parent_names = axg_sd_emmc_clk0_parent_names, .num_parents = ARRAY_SIZE(axg_sd_emmc_clk0_parent_names), .flags = CLK_SET_RATE_PARENT, @@ -703,12 +705,6 @@ static struct meson_clk_mpll *const axg_clk_mplls[] = { &axg_mpll3, }; -static struct clk_mux *const axg_clk_muxes[] = { - &axg_mpeg_clk_sel, - &axg_sd_emmc_b_clk0_sel, - &axg_sd_emmc_c_clk0_sel, -}; - static struct clk_regmap *const axg_clk_regmaps[] = { &axg_clk81, &axg_ddr, @@ -760,6 +756,9 @@ static struct clk_regmap *const axg_clk_regmaps[] = { &axg_mpeg_clk_div, &axg_sd_emmc_b_clk0_div, &axg_sd_emmc_c_clk0_div, + &axg_mpeg_clk_sel, + &axg_sd_emmc_b_clk0_sel, + &axg_sd_emmc_c_clk0_sel, }; struct clkc_data { @@ -767,8 +766,6 @@ struct clkc_data { unsigned int clk_mplls_count; struct meson_clk_pll *const *clk_plls; unsigned int clk_plls_count; - struct clk_mux *const *clk_muxes; - unsigned int clk_muxes_count; struct clk_hw_onecell_data *hw_onecell_data; }; @@ -777,8 +774,6 @@ static const struct clkc_data axg_clkc_data = { .clk_mplls_count = ARRAY_SIZE(axg_clk_mplls), .clk_plls = axg_clk_plls, .clk_plls_count = ARRAY_SIZE(axg_clk_plls), - .clk_muxes = axg_clk_muxes, - .clk_muxes_count = ARRAY_SIZE(axg_clk_muxes), .hw_onecell_data = &axg_hw_onecell_data, }; @@ -829,11 +824,6 @@ static int axg_clkc_probe(struct platform_device *pdev) for (i = 0; i < clkc_data->clk_mplls_count; i++) clkc_data->clk_mplls[i]->base = clk_base; - /* Populate base address for muxes */ - for (i = 0; i < clkc_data->clk_muxes_count; i++) - clkc_data->clk_muxes[i]->reg = clk_base + - (u64)clkc_data->clk_muxes[i]->reg; - /* Populate regmap for the regmap backed clocks */ for (i = 0; i < ARRAY_SIZE(axg_clk_regmaps); i++) axg_clk_regmaps[i]->map = map; diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c index ec515dc71476..d9f426265774 100644 --- a/drivers/clk/meson/gxbb.c +++ b/drivers/clk/meson/gxbb.c @@ -583,16 +583,16 @@ static const char * const clk81_parent_names[] = { "fclk_div3", "fclk_div5" }; -static struct clk_mux gxbb_mpeg_clk_sel = { - .reg = (void *)HHI_MPEG_CLK_CNTL, - .mask = 0x7, - .shift = 12, - .flags = CLK_MUX_READ_ONLY, - .table = mux_table_clk81, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_mpeg_clk_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_MPEG_CLK_CNTL, + .mask = 0x7, + .shift = 12, + .table = mux_table_clk81, + }, .hw.init = &(struct clk_init_data){ .name = "mpeg_clk_sel", - .ops = &clk_mux_ro_ops, + .ops = &clk_regmap_mux_ro_ops, /* * bits 14:12 selects from 8 possible parents: * xtal, 1'b0 (wtf), fclk_div7, mpll_clkout1, mpll_clkout2, @@ -634,14 +634,15 @@ static struct clk_regmap gxbb_clk81 = { }, }; -static struct clk_mux gxbb_sar_adc_clk_sel = { - .reg = (void *)HHI_SAR_CLK_CNTL, - .mask = 0x3, - .shift = 9, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_sar_adc_clk_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_SAR_CLK_CNTL, + .mask = 0x3, + .shift = 9, + }, .hw.init = &(struct clk_init_data){ .name = "sar_adc_clk_sel", - .ops = &clk_mux_ops, + .ops = &clk_regmap_mux_ops, /* NOTE: The datasheet doesn't list the parents for bit 10 */ .parent_names = (const char *[]){ "xtal", "clk81", }, .num_parents = 2, @@ -681,21 +682,20 @@ static struct clk_regmap gxbb_sar_adc_clk = { * muxed by a glitch-free switch. */ -static u32 mux_table_mali_0_1[] = {0, 1, 2, 3, 4, 5, 6, 7}; static const char * const gxbb_mali_0_1_parent_names[] = { "xtal", "gp0_pll", "mpll2", "mpll1", "fclk_div7", "fclk_div4", "fclk_div3", "fclk_div5" }; -static struct clk_mux gxbb_mali_0_sel = { - .reg = (void *)HHI_MALI_CLK_CNTL, - .mask = 0x7, - .shift = 9, - .table = mux_table_mali_0_1, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_mali_0_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_MALI_CLK_CNTL, + .mask = 0x7, + .shift = 9, + }, .hw.init = &(struct clk_init_data){ .name = "mali_0_sel", - .ops = &clk_mux_ops, + .ops = &clk_regmap_mux_ops, /* * bits 10:9 selects from 8 possible parents: * xtal, gp0_pll, mpll2, mpll1, fclk_div7, @@ -736,15 +736,15 @@ static struct clk_regmap gxbb_mali_0 = { }, }; -static struct clk_mux gxbb_mali_1_sel = { - .reg = (void *)HHI_MALI_CLK_CNTL, - .mask = 0x7, - .shift = 25, - .table = mux_table_mali_0_1, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_mali_1_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_MALI_CLK_CNTL, + .mask = 0x7, + .shift = 25, + }, .hw.init = &(struct clk_init_data){ .name = "mali_1_sel", - .ops = &clk_mux_ops, + .ops = &clk_regmap_mux_ops, /* * bits 10:9 selects from 8 possible parents: * xtal, gp0_pll, mpll2, mpll1, fclk_div7, @@ -785,36 +785,35 @@ static struct clk_regmap gxbb_mali_1 = { }, }; -static u32 mux_table_mali[] = {0, 1}; static const char * const gxbb_mali_parent_names[] = { "mali_0", "mali_1" }; -static struct clk_mux gxbb_mali = { - .reg = (void *)HHI_MALI_CLK_CNTL, - .mask = 1, - .shift = 31, - .table = mux_table_mali, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_mali = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_MALI_CLK_CNTL, + .mask = 1, + .shift = 31, + }, .hw.init = &(struct clk_init_data){ .name = "mali", - .ops = &clk_mux_ops, + .ops = &clk_regmap_mux_ops, .parent_names = gxbb_mali_parent_names, .num_parents = 2, .flags = CLK_SET_RATE_NO_REPARENT, }, }; -static struct clk_mux gxbb_cts_amclk_sel = { - .reg = (void *) HHI_AUD_CLK_CNTL, - .mask = 0x3, - .shift = 9, - /* Default parent unknown (register reset value: 0) */ - .table = (u32[]){ 1, 2, 3 }, - .lock = &meson_clk_lock, - .hw.init = &(struct clk_init_data){ +static struct clk_regmap gxbb_cts_amclk_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_AUD_CLK_CNTL, + .mask = 0x3, + .shift = 9, + .table = (u32[]){ 1, 2, 3 }, + }, + .hw.init = &(struct clk_init_data){ .name = "cts_amclk_sel", - .ops = &clk_mux_ops, + .ops = &clk_regmap_mux_ops, .parent_names = (const char *[]){ "mpll0", "mpll1", "mpll2" }, .num_parents = 3, .flags = CLK_SET_RATE_PARENT, @@ -852,16 +851,16 @@ static struct clk_regmap gxbb_cts_amclk = { }, }; -static struct clk_mux gxbb_cts_mclk_i958_sel = { - .reg = (void *)HHI_AUD_CLK_CNTL2, - .mask = 0x3, - .shift = 25, - /* Default parent unknown (register reset value: 0) */ - .table = (u32[]){ 1, 2, 3 }, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_cts_mclk_i958_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_AUD_CLK_CNTL2, + .mask = 0x3, + .shift = 25, + .table = (u32[]){ 1, 2, 3 }, + }, .hw.init = &(struct clk_init_data) { .name = "cts_mclk_i958_sel", - .ops = &clk_mux_ops, + .ops = &clk_regmap_mux_ops, .parent_names = (const char *[]){ "mpll0", "mpll1", "mpll2" }, .num_parents = 3, .flags = CLK_SET_RATE_PARENT, @@ -898,14 +897,15 @@ static struct clk_regmap gxbb_cts_mclk_i958 = { }, }; -static struct clk_mux gxbb_cts_i958 = { - .reg = (void *)HHI_AUD_CLK_CNTL2, - .mask = 0x1, - .shift = 27, - .lock = &meson_clk_lock, - .hw.init = &(struct clk_init_data){ +static struct clk_regmap gxbb_cts_i958 = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_AUD_CLK_CNTL2, + .mask = 0x1, + .shift = 27, + }, + .hw.init = &(struct clk_init_data){ .name = "cts_i958", - .ops = &clk_mux_ops, + .ops = &clk_regmap_mux_ops, .parent_names = (const char *[]){ "cts_amclk", "cts_mclk_i958" }, .num_parents = 2, /* @@ -949,14 +949,15 @@ static const char * const gxbb_32k_clk_parent_names[] = { "xtal", "cts_slow_oscin", "fclk_div3", "fclk_div5" }; -static struct clk_mux gxbb_32k_clk_sel = { - .reg = (void *)HHI_32K_CLK_CNTL, - .mask = 0x3, - .shift = 16, - .lock = &meson_clk_lock, - .hw.init = &(struct clk_init_data){ +static struct clk_regmap gxbb_32k_clk_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_32K_CLK_CNTL, + .mask = 0x3, + .shift = 16, + }, + .hw.init = &(struct clk_init_data){ .name = "32k_clk_sel", - .ops = &clk_mux_ops, + .ops = &clk_regmap_mux_ops, .parent_names = gxbb_32k_clk_parent_names, .num_parents = 4, .flags = CLK_SET_RATE_PARENT, @@ -975,14 +976,15 @@ static const char * const gxbb_sd_emmc_clk0_parent_names[] = { }; /* SDIO clock */ -static struct clk_mux gxbb_sd_emmc_a_clk0_sel = { - .reg = (void *)HHI_SD_EMMC_CLK_CNTL, - .mask = 0x7, - .shift = 9, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_sd_emmc_a_clk0_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_SD_EMMC_CLK_CNTL, + .mask = 0x7, + .shift = 9, + }, .hw.init = &(struct clk_init_data) { .name = "sd_emmc_a_clk0_sel", - .ops = &clk_mux_ops, + .ops = &clk_regmap_mux_ops, .parent_names = gxbb_sd_emmc_clk0_parent_names, .num_parents = ARRAY_SIZE(gxbb_sd_emmc_clk0_parent_names), .flags = CLK_SET_RATE_PARENT, @@ -1020,14 +1022,15 @@ static struct clk_regmap gxbb_sd_emmc_a_clk0 = { }; /* SDcard clock */ -static struct clk_mux gxbb_sd_emmc_b_clk0_sel = { - .reg = (void *)HHI_SD_EMMC_CLK_CNTL, - .mask = 0x7, - .shift = 25, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_sd_emmc_b_clk0_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_SD_EMMC_CLK_CNTL, + .mask = 0x7, + .shift = 25, + }, .hw.init = &(struct clk_init_data) { .name = "sd_emmc_b_clk0_sel", - .ops = &clk_mux_ops, + .ops = &clk_regmap_mux_ops, .parent_names = gxbb_sd_emmc_clk0_parent_names, .num_parents = ARRAY_SIZE(gxbb_sd_emmc_clk0_parent_names), .flags = CLK_SET_RATE_PARENT, @@ -1065,14 +1068,15 @@ static struct clk_regmap gxbb_sd_emmc_b_clk0 = { }; /* EMMC/NAND clock */ -static struct clk_mux gxbb_sd_emmc_c_clk0_sel = { - .reg = (void *)HHI_NAND_CLK_CNTL, - .mask = 0x7, - .shift = 9, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_sd_emmc_c_clk0_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_NAND_CLK_CNTL, + .mask = 0x7, + .shift = 9, + }, .hw.init = &(struct clk_init_data) { .name = "sd_emmc_c_clk0_sel", - .ops = &clk_mux_ops, + .ops = &clk_regmap_mux_ops, .parent_names = gxbb_sd_emmc_clk0_parent_names, .num_parents = ARRAY_SIZE(gxbb_sd_emmc_clk0_parent_names), .flags = CLK_SET_RATE_PARENT, @@ -1111,20 +1115,19 @@ static struct clk_regmap gxbb_sd_emmc_c_clk0 = { /* VPU Clock */ -static u32 mux_table_vpu[] = {0, 1, 2, 3}; static const char * const gxbb_vpu_parent_names[] = { "fclk_div4", "fclk_div3", "fclk_div5", "fclk_div7" }; -static struct clk_mux gxbb_vpu_0_sel = { - .reg = (void *)HHI_VPU_CLK_CNTL, - .mask = 0x3, - .shift = 9, - .lock = &meson_clk_lock, - .table = mux_table_vpu, +static struct clk_regmap gxbb_vpu_0_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VPU_CLK_CNTL, + .mask = 0x3, + .shift = 9, + }, .hw.init = &(struct clk_init_data){ .name = "vpu_0_sel", - .ops = &clk_mux_ops, + .ops = &clk_regmap_mux_ops, /* * bits 9:10 selects from 4 possible parents: * fclk_div4, fclk_div3, fclk_div5, fclk_div7, @@ -1164,15 +1167,15 @@ static struct clk_regmap gxbb_vpu_0 = { }, }; -static struct clk_mux gxbb_vpu_1_sel = { - .reg = (void *)HHI_VPU_CLK_CNTL, - .mask = 0x3, - .shift = 25, - .lock = &meson_clk_lock, - .table = mux_table_vpu, +static struct clk_regmap gxbb_vpu_1_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VPU_CLK_CNTL, + .mask = 0x3, + .shift = 25, + }, .hw.init = &(struct clk_init_data){ .name = "vpu_1_sel", - .ops = &clk_mux_ops, + .ops = &clk_regmap_mux_ops, /* * bits 25:26 selects from 4 possible parents: * fclk_div4, fclk_div3, fclk_div5, fclk_div7, @@ -1212,14 +1215,15 @@ static struct clk_regmap gxbb_vpu_1 = { }, }; -static struct clk_mux gxbb_vpu = { - .reg = (void *)HHI_VPU_CLK_CNTL, - .mask = 1, - .shift = 31, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_vpu = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VPU_CLK_CNTL, + .mask = 1, + .shift = 31, + }, .hw.init = &(struct clk_init_data){ .name = "vpu", - .ops = &clk_mux_ops, + .ops = &clk_regmap_mux_ops, /* * bit 31 selects from 2 possible parents: * vpu_0 or vpu_1 @@ -1232,20 +1236,19 @@ static struct clk_mux gxbb_vpu = { /* VAPB Clock */ -static u32 mux_table_vapb[] = {0, 1, 2, 3}; static const char * const gxbb_vapb_parent_names[] = { "fclk_div4", "fclk_div3", "fclk_div5", "fclk_div7" }; -static struct clk_mux gxbb_vapb_0_sel = { - .reg = (void *)HHI_VAPBCLK_CNTL, - .mask = 0x3, - .shift = 9, - .lock = &meson_clk_lock, - .table = mux_table_vapb, +static struct clk_regmap gxbb_vapb_0_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VAPBCLK_CNTL, + .mask = 0x3, + .shift = 9, + }, .hw.init = &(struct clk_init_data){ .name = "vapb_0_sel", - .ops = &clk_mux_ops, + .ops = &clk_regmap_mux_ops, /* * bits 9:10 selects from 4 possible parents: * fclk_div4, fclk_div3, fclk_div5, fclk_div7, @@ -1285,15 +1288,15 @@ static struct clk_regmap gxbb_vapb_0 = { }, }; -static struct clk_mux gxbb_vapb_1_sel = { - .reg = (void *)HHI_VAPBCLK_CNTL, - .mask = 0x3, - .shift = 25, - .lock = &meson_clk_lock, - .table = mux_table_vapb, +static struct clk_regmap gxbb_vapb_1_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VAPBCLK_CNTL, + .mask = 0x3, + .shift = 25, + }, .hw.init = &(struct clk_init_data){ .name = "vapb_1_sel", - .ops = &clk_mux_ops, + .ops = &clk_regmap_mux_ops, /* * bits 25:26 selects from 4 possible parents: * fclk_div4, fclk_div3, fclk_div5, fclk_div7, @@ -1333,14 +1336,15 @@ static struct clk_regmap gxbb_vapb_1 = { }, }; -static struct clk_mux gxbb_vapb_sel = { - .reg = (void *)HHI_VAPBCLK_CNTL, - .mask = 1, - .shift = 31, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_vapb_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VAPBCLK_CNTL, + .mask = 1, + .shift = 31, + }, .hw.init = &(struct clk_init_data){ .name = "vapb_sel", - .ops = &clk_mux_ops, + .ops = &clk_regmap_mux_ops, /* * bit 31 selects from 2 possible parents: * vapb_0 or vapb_1 @@ -1773,27 +1777,6 @@ static struct meson_clk_mpll *const gxbb_clk_mplls[] = { &gxbb_mpll2, }; -static struct clk_mux *const gxbb_clk_muxes[] = { - &gxbb_mpeg_clk_sel, - &gxbb_sar_adc_clk_sel, - &gxbb_mali_0_sel, - &gxbb_mali_1_sel, - &gxbb_mali, - &gxbb_cts_amclk_sel, - &gxbb_cts_mclk_i958_sel, - &gxbb_cts_i958, - &gxbb_32k_clk_sel, - &gxbb_sd_emmc_a_clk0_sel, - &gxbb_sd_emmc_b_clk0_sel, - &gxbb_sd_emmc_c_clk0_sel, - &gxbb_vpu_0_sel, - &gxbb_vpu_1_sel, - &gxbb_vpu, - &gxbb_vapb_0_sel, - &gxbb_vapb_1_sel, - &gxbb_vapb_sel, -}; - static struct meson_clk_audio_divider *const gxbb_audio_dividers[] = { &gxbb_cts_amclk_div, }; @@ -1908,6 +1891,24 @@ static struct clk_regmap *const gx_clk_regmaps[] = { &gxbb_vpu_1_div, &gxbb_vapb_0_div, &gxbb_vapb_1_div, + &gxbb_mpeg_clk_sel, + &gxbb_sar_adc_clk_sel, + &gxbb_mali_0_sel, + &gxbb_mali_1_sel, + &gxbb_mali, + &gxbb_cts_amclk_sel, + &gxbb_cts_mclk_i958_sel, + &gxbb_cts_i958, + &gxbb_32k_clk_sel, + &gxbb_sd_emmc_a_clk0_sel, + &gxbb_sd_emmc_b_clk0_sel, + &gxbb_sd_emmc_c_clk0_sel, + &gxbb_vpu_0_sel, + &gxbb_vpu_1_sel, + &gxbb_vpu, + &gxbb_vapb_0_sel, + &gxbb_vapb_1_sel, + &gxbb_vapb_sel, }; struct clkc_data { @@ -1915,8 +1916,6 @@ struct clkc_data { unsigned int clk_mplls_count; struct meson_clk_pll *const *clk_plls; unsigned int clk_plls_count; - struct clk_mux *const *clk_muxes; - unsigned int clk_muxes_count; struct meson_clk_audio_divider *const *clk_audio_dividers; unsigned int clk_audio_dividers_count; struct clk_hw_onecell_data *hw_onecell_data; @@ -1927,8 +1926,6 @@ static const struct clkc_data gxbb_clkc_data = { .clk_mplls_count = ARRAY_SIZE(gxbb_clk_mplls), .clk_plls = gxbb_clk_plls, .clk_plls_count = ARRAY_SIZE(gxbb_clk_plls), - .clk_muxes = gxbb_clk_muxes, - .clk_muxes_count = ARRAY_SIZE(gxbb_clk_muxes), .clk_audio_dividers = gxbb_audio_dividers, .clk_audio_dividers_count = ARRAY_SIZE(gxbb_audio_dividers), .hw_onecell_data = &gxbb_hw_onecell_data, @@ -1939,8 +1936,6 @@ static const struct clkc_data gxl_clkc_data = { .clk_mplls_count = ARRAY_SIZE(gxbb_clk_mplls), .clk_plls = gxl_clk_plls, .clk_plls_count = ARRAY_SIZE(gxl_clk_plls), - .clk_muxes = gxbb_clk_muxes, - .clk_muxes_count = ARRAY_SIZE(gxbb_clk_muxes), .clk_audio_dividers = gxbb_audio_dividers, .clk_audio_dividers_count = ARRAY_SIZE(gxbb_audio_dividers), .hw_onecell_data = &gxl_hw_onecell_data, @@ -1993,11 +1988,6 @@ static int gxbb_clkc_probe(struct platform_device *pdev) for (i = 0; i < clkc_data->clk_mplls_count; i++) clkc_data->clk_mplls[i]->base = clk_base; - /* Populate base address for muxes */ - for (i = 0; i < clkc_data->clk_muxes_count; i++) - clkc_data->clk_muxes[i]->reg = clk_base + - (u64)clkc_data->clk_muxes[i]->reg; - /* Populate base address for the audio dividers */ for (i = 0; i < clkc_data->clk_audio_dividers_count; i++) clkc_data->clk_audio_dividers[i]->base = clk_base; diff --git a/drivers/clk/meson/meson8b.c b/drivers/clk/meson/meson8b.c index e9c5278072cd..e643f7556f5e 100644 --- a/drivers/clk/meson/meson8b.c +++ b/drivers/clk/meson/meson8b.c @@ -370,17 +370,16 @@ static struct meson_clk_cpu meson8b_cpu_clk = { }; static u32 mux_table_clk81[] = { 6, 5, 7 }; - -struct clk_mux meson8b_mpeg_clk_sel = { - .reg = (void *)HHI_MPEG_CLK_CNTL, - .mask = 0x7, - .shift = 12, - .flags = CLK_MUX_READ_ONLY, - .table = mux_table_clk81, - .lock = &meson_clk_lock, +static struct clk_regmap meson8b_mpeg_clk_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_MPEG_CLK_CNTL, + .mask = 0x7, + .shift = 12, + .table = mux_table_clk81, + }, .hw.init = &(struct clk_init_data){ .name = "mpeg_clk_sel", - .ops = &clk_mux_ro_ops, + .ops = &clk_regmap_mux_ro_ops, /* * FIXME bits 14:12 selects from 8 possible parents: * xtal, 1'b0 (wtf), fclk_div7, mpll_clkout1, mpll_clkout2, @@ -620,10 +619,6 @@ static struct meson_clk_mpll *const meson8b_clk_mplls[] = { &meson8b_mpll2, }; -static struct clk_mux *const meson8b_clk_muxes[] = { - &meson8b_mpeg_clk_sel, -}; - static struct clk_regmap *const meson8b_clk_regmaps[] = { &meson8b_clk81, &meson8b_ddr, @@ -704,6 +699,7 @@ static struct clk_regmap *const meson8b_clk_regmaps[] = { &meson8b_ao_ahb_bus, &meson8b_ao_iface, &meson8b_mpeg_clk_div, + &meson8b_mpeg_clk_sel, }; static const struct meson8b_clk_reset_line { @@ -837,11 +833,6 @@ static int meson8b_clkc_probe(struct platform_device *pdev) /* Populate the base address for CPU clk */ meson8b_cpu_clk.base = clk_base; - /* 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 regmap for the regmap backed clocks */ for (i = 0; i < ARRAY_SIZE(meson8b_clk_regmaps); i++) meson8b_clk_regmaps[i]->map = map; -- cgit From f510c32a6af6123bc0638bfe869728bf8be71027 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Mon, 12 Feb 2018 15:58:39 +0100 Subject: clk: meson: add regmap helpers for parm Meson clock drivers are using struct parm to describe each field of the clock provider. Providing helpers to access these fields with regmap helps to keep drivers readable Signed-off-by: Jerome Brunet Signed-off-by: Neil Armstrong --- drivers/clk/meson/clkc.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/clk/meson/clkc.h b/drivers/clk/meson/clkc.h index aa2dfa0ff89f..8edc25297422 100644 --- a/drivers/clk/meson/clkc.h +++ b/drivers/clk/meson/clkc.h @@ -38,6 +38,22 @@ struct parm { u8 width; }; +static inline unsigned int meson_parm_read(struct regmap *map, struct parm *p) +{ + unsigned int val; + + regmap_read(map, p->reg_off, &val); + return PARM_GET(p->width, p->shift, val); +} + +static inline void meson_parm_write(struct regmap *map, struct parm *p, + unsigned int val) +{ + regmap_update_bits(map, p->reg_off, SETPMASK(p->width, p->shift), + val << p->shift); +} + + struct pll_rate_table { unsigned long rate; u16 m; -- cgit From c763e61ae8cbc9424e95b23a4d4ad5d2d7a71dcd Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Mon, 12 Feb 2018 15:58:40 +0100 Subject: clk: meson: migrate mplls clocks to clk_regmap Rework meson mpll driver to use clk_regmap and move meson8b, gxbb and axg clocks using meson_clk_mpll to clk_regmap Signed-off-by: Jerome Brunet Signed-off-by: Neil Armstrong --- drivers/clk/meson/axg.c | 245 +++++++++++++++++++++---------------------- drivers/clk/meson/clk-mpll.c | 102 +++++++----------- drivers/clk/meson/clkc.h | 4 +- drivers/clk/meson/gxbb.c | 161 ++++++++++++++-------------- drivers/clk/meson/meson8b.c | 155 ++++++++++++++------------- 5 files changed, 313 insertions(+), 354 deletions(-) diff --git a/drivers/clk/meson/axg.c b/drivers/clk/meson/axg.c index 9f0c36e12cb8..85f9466ce006 100644 --- a/drivers/clk/meson/axg.c +++ b/drivers/clk/meson/axg.c @@ -267,38 +267,40 @@ static struct clk_fixed_factor axg_fclk_div7 = { }, }; -static struct meson_clk_mpll axg_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, +static struct clk_regmap axg_mpll0 = { + .data = &(struct meson_clk_mpll_data){ + .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, + }, + .ssen = { + .reg_off = HHI_MPLL_CNTL, + .shift = 25, + .width = 1, + }, + .misc = { + .reg_off = HHI_PLL_TOP_MISC, + .shift = 0, + .width = 1, + }, + .lock = &meson_clk_lock, }, - .ssen = { - .reg_off = HHI_MPLL_CNTL, - .shift = 25, - .width = 1, - }, - .misc = { - .reg_off = HHI_PLL_TOP_MISC, - .shift = 0, - .width = 1, - }, - .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "mpll0", .ops = &meson_clk_mpll_ops, @@ -307,33 +309,35 @@ static struct meson_clk_mpll axg_mpll0 = { }, }; -static struct meson_clk_mpll axg_mpll1 = { - .sdm = { - .reg_off = HHI_MPLL_CNTL8, - .shift = 0, - .width = 14, +static struct clk_regmap axg_mpll1 = { + .data = &(struct meson_clk_mpll_data){ + .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, + }, + .misc = { + .reg_off = HHI_PLL_TOP_MISC, + .shift = 1, + .width = 1, + }, + .lock = &meson_clk_lock, }, - .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, - }, - .misc = { - .reg_off = HHI_PLL_TOP_MISC, - .shift = 1, - .width = 1, - }, - .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "mpll1", .ops = &meson_clk_mpll_ops, @@ -342,33 +346,35 @@ static struct meson_clk_mpll axg_mpll1 = { }, }; -static struct meson_clk_mpll axg_mpll2 = { - .sdm = { - .reg_off = HHI_MPLL_CNTL9, - .shift = 0, - .width = 14, - }, - .sdm_en = { - .reg_off = HHI_MPLL_CNTL9, - .shift = 15, - .width = 1, +static struct clk_regmap axg_mpll2 = { + .data = &(struct meson_clk_mpll_data){ + .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, + }, + .misc = { + .reg_off = HHI_PLL_TOP_MISC, + .shift = 2, + .width = 1, + }, + .lock = &meson_clk_lock, }, - .n2 = { - .reg_off = HHI_MPLL_CNTL9, - .shift = 16, - .width = 9, - }, - .en = { - .reg_off = HHI_MPLL_CNTL9, - .shift = 14, - .width = 1, - }, - .misc = { - .reg_off = HHI_PLL_TOP_MISC, - .shift = 2, - .width = 1, - }, - .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "mpll2", .ops = &meson_clk_mpll_ops, @@ -377,33 +383,35 @@ static struct meson_clk_mpll axg_mpll2 = { }, }; -static struct meson_clk_mpll axg_mpll3 = { - .sdm = { - .reg_off = HHI_MPLL3_CNTL0, - .shift = 12, - .width = 14, - }, - .sdm_en = { - .reg_off = HHI_MPLL3_CNTL0, - .shift = 11, - .width = 1, +static struct clk_regmap axg_mpll3 = { + .data = &(struct meson_clk_mpll_data){ + .sdm = { + .reg_off = HHI_MPLL3_CNTL0, + .shift = 12, + .width = 14, + }, + .sdm_en = { + .reg_off = HHI_MPLL3_CNTL0, + .shift = 11, + .width = 1, + }, + .n2 = { + .reg_off = HHI_MPLL3_CNTL0, + .shift = 2, + .width = 9, + }, + .en = { + .reg_off = HHI_MPLL3_CNTL0, + .shift = 0, + .width = 1, + }, + .misc = { + .reg_off = HHI_PLL_TOP_MISC, + .shift = 3, + .width = 1, + }, + .lock = &meson_clk_lock, }, - .n2 = { - .reg_off = HHI_MPLL3_CNTL0, - .shift = 2, - .width = 9, - }, - .en = { - .reg_off = HHI_MPLL3_CNTL0, - .shift = 0, - .width = 1, - }, - .misc = { - .reg_off = HHI_PLL_TOP_MISC, - .shift = 3, - .width = 1, - }, - .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "mpll3", .ops = &meson_clk_mpll_ops, @@ -698,13 +706,6 @@ static struct meson_clk_pll *const axg_clk_plls[] = { &axg_gp0_pll, }; -static struct meson_clk_mpll *const axg_clk_mplls[] = { - &axg_mpll0, - &axg_mpll1, - &axg_mpll2, - &axg_mpll3, -}; - static struct clk_regmap *const axg_clk_regmaps[] = { &axg_clk81, &axg_ddr, @@ -759,19 +760,19 @@ static struct clk_regmap *const axg_clk_regmaps[] = { &axg_mpeg_clk_sel, &axg_sd_emmc_b_clk0_sel, &axg_sd_emmc_c_clk0_sel, + &axg_mpll0, + &axg_mpll1, + &axg_mpll2, + &axg_mpll3, }; struct clkc_data { - struct meson_clk_mpll *const *clk_mplls; - unsigned int clk_mplls_count; struct meson_clk_pll *const *clk_plls; unsigned int clk_plls_count; struct clk_hw_onecell_data *hw_onecell_data; }; static const struct clkc_data axg_clkc_data = { - .clk_mplls = axg_clk_mplls, - .clk_mplls_count = ARRAY_SIZE(axg_clk_mplls), .clk_plls = axg_clk_plls, .clk_plls_count = ARRAY_SIZE(axg_clk_plls), .hw_onecell_data = &axg_hw_onecell_data, @@ -820,10 +821,6 @@ static int axg_clkc_probe(struct platform_device *pdev) for (i = 0; i < clkc_data->clk_plls_count; i++) clkc_data->clk_plls[i]->base = clk_base; - /* Populate base address for MPLLs */ - for (i = 0; i < clkc_data->clk_mplls_count; i++) - clkc_data->clk_mplls[i]->base = clk_base; - /* Populate regmap for the regmap backed clocks */ for (i = 0; i < ARRAY_SIZE(axg_clk_regmaps); i++) axg_clk_regmaps[i]->map = map; diff --git a/drivers/clk/meson/clk-mpll.c b/drivers/clk/meson/clk-mpll.c index 6d79d6daadc4..66998ff47635 100644 --- a/drivers/clk/meson/clk-mpll.c +++ b/drivers/clk/meson/clk-mpll.c @@ -68,11 +68,15 @@ #define N2_MIN 4 #define N2_MAX 511 -#define to_meson_clk_mpll(_hw) container_of(_hw, struct meson_clk_mpll, hw) +static inline struct meson_clk_mpll_data * +meson_clk_mpll_data(struct clk_regmap *clk) +{ + return (struct meson_clk_mpll_data *)clk->data; +} static long rate_from_params(unsigned long parent_rate, - unsigned long sdm, - unsigned long n2) + unsigned int sdm, + unsigned int n2) { unsigned long divisor = (SDM_DEN * n2) + sdm; @@ -84,8 +88,8 @@ static long rate_from_params(unsigned long parent_rate, static void params_from_rate(unsigned long requested_rate, unsigned long parent_rate, - unsigned long *sdm, - unsigned long *n2) + unsigned int *sdm, + unsigned int *n2) { uint64_t div = parent_rate; unsigned long rem = do_div(div, requested_rate); @@ -105,31 +109,23 @@ static void params_from_rate(unsigned long requested_rate, 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 reg, sdm, n2; + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_clk_mpll_data *mpll = meson_clk_mpll_data(clk); + unsigned int sdm, n2; long rate; - p = &mpll->sdm; - reg = readl(mpll->base + p->reg_off); - sdm = PARM_GET(p->width, p->shift, reg); - - p = &mpll->n2; - reg = readl(mpll->base + p->reg_off); - n2 = PARM_GET(p->width, p->shift, reg); + sdm = meson_parm_read(clk->map, &mpll->sdm); + n2 = meson_parm_read(clk->map, &mpll->n2); rate = rate_from_params(parent_rate, sdm, n2); - if (rate < 0) - return 0; - - return rate; + return rate < 0 ? 0 : rate; } static long mpll_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *parent_rate) { - unsigned long sdm, n2; + unsigned int sdm, n2; params_from_rate(rate, *parent_rate, &sdm, &n2); return rate_from_params(*parent_rate, sdm, n2); @@ -139,9 +135,9 @@ 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; + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_clk_mpll_data *mpll = meson_clk_mpll_data(clk); + unsigned int sdm, n2; unsigned long flags = 0; params_from_rate(rate, parent_rate, &sdm, &n2); @@ -151,34 +147,20 @@ static int mpll_set_rate(struct clk_hw *hw, 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->ssen; - if (p->width != 0) { - reg = readl(mpll->base + p->reg_off); - reg = PARM_SET(p->width, p->shift, reg, 1); - writel(reg, mpll->base + p->reg_off); - } + /* Enable and set the fractional part */ + meson_parm_write(clk->map, &mpll->sdm, sdm); + meson_parm_write(clk->map, &mpll->sdm_en, 1); - 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); + /* Set additional fractional part enable if required */ + if (MESON_PARM_APPLICABLE(&mpll->ssen)) + meson_parm_write(clk->map, &mpll->ssen, 1); - p = &mpll->misc; - if (p->width != 0) { - reg = readl(mpll->base + p->reg_off); - reg = PARM_SET(p->width, p->shift, reg, 1); - writel(reg, mpll->base + p->reg_off); - } + /* Set the integer divider part */ + meson_parm_write(clk->map, &mpll->n2, n2); + + /* Set the magic misc bit if required */ + if (MESON_PARM_APPLICABLE(&mpll->misc)) + meson_parm_write(clk->map, &mpll->misc, 1); if (mpll->lock) spin_unlock_irqrestore(mpll->lock, flags); @@ -190,9 +172,8 @@ static int mpll_set_rate(struct clk_hw *hw, 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; + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_clk_mpll_data *mpll = meson_clk_mpll_data(clk); unsigned long flags = 0; if (mpll->lock) @@ -200,10 +181,7 @@ static void mpll_enable_core(struct clk_hw *hw, int enable) 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); + meson_parm_write(clk->map, &mpll->en, enable ? 1 : 0); if (mpll->lock) spin_unlock_irqrestore(mpll->lock, flags); @@ -226,16 +204,10 @@ static void mpll_disable(struct clk_hw *hw) 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); + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_clk_mpll_data *mpll = meson_clk_mpll_data(clk); - return en; + return meson_parm_read(clk->map, &mpll->en); } const struct clk_ops meson_clk_mpll_ro_ops = { diff --git a/drivers/clk/meson/clkc.h b/drivers/clk/meson/clkc.h index 8edc25297422..08a1ebfc65dc 100644 --- a/drivers/clk/meson/clkc.h +++ b/drivers/clk/meson/clkc.h @@ -132,9 +132,7 @@ struct meson_clk_cpu { int meson_clk_cpu_notifier_cb(struct notifier_block *nb, unsigned long event, void *data); -struct meson_clk_mpll { - struct clk_hw hw; - void __iomem *base; +struct meson_clk_mpll_data { struct parm sdm; struct parm sdm_en; struct parm n2; diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c index d9f426265774..d2724a7ce9e7 100644 --- a/drivers/clk/meson/gxbb.c +++ b/drivers/clk/meson/gxbb.c @@ -482,33 +482,35 @@ static struct clk_fixed_factor gxbb_fclk_div7 = { }, }; -static struct meson_clk_mpll gxbb_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, - }, - .ssen = { - .reg_off = HHI_MPLL_CNTL, - .shift = 25, - .width = 1, +static struct clk_regmap gxbb_mpll0 = { + .data = &(struct meson_clk_mpll_data){ + .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, + }, + .ssen = { + .reg_off = HHI_MPLL_CNTL, + .shift = 25, + .width = 1, + }, + .lock = &meson_clk_lock, }, - .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "mpll0", .ops = &meson_clk_mpll_ops, @@ -517,28 +519,30 @@ static struct meson_clk_mpll gxbb_mpll0 = { }, }; -static struct meson_clk_mpll gxbb_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, +static struct clk_regmap gxbb_mpll1 = { + .data = &(struct meson_clk_mpll_data){ + .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 = &meson_clk_lock, }, - .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "mpll1", .ops = &meson_clk_mpll_ops, @@ -547,28 +551,30 @@ static struct meson_clk_mpll gxbb_mpll1 = { }, }; -static struct meson_clk_mpll gxbb_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, +static struct clk_regmap gxbb_mpll2 = { + .data = &(struct meson_clk_mpll_data){ + .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 = &meson_clk_lock, }, - .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "mpll2", .ops = &meson_clk_mpll_ops, @@ -1771,12 +1777,6 @@ static struct meson_clk_pll *const gxl_clk_plls[] = { &gxl_gp0_pll, }; -static struct meson_clk_mpll *const gxbb_clk_mplls[] = { - &gxbb_mpll0, - &gxbb_mpll1, - &gxbb_mpll2, -}; - static struct meson_clk_audio_divider *const gxbb_audio_dividers[] = { &gxbb_cts_amclk_div, }; @@ -1909,11 +1909,12 @@ static struct clk_regmap *const gx_clk_regmaps[] = { &gxbb_vapb_0_sel, &gxbb_vapb_1_sel, &gxbb_vapb_sel, + &gxbb_mpll0, + &gxbb_mpll1, + &gxbb_mpll2, }; struct clkc_data { - struct meson_clk_mpll *const *clk_mplls; - unsigned int clk_mplls_count; struct meson_clk_pll *const *clk_plls; unsigned int clk_plls_count; struct meson_clk_audio_divider *const *clk_audio_dividers; @@ -1922,8 +1923,6 @@ struct clkc_data { }; static const struct clkc_data gxbb_clkc_data = { - .clk_mplls = gxbb_clk_mplls, - .clk_mplls_count = ARRAY_SIZE(gxbb_clk_mplls), .clk_plls = gxbb_clk_plls, .clk_plls_count = ARRAY_SIZE(gxbb_clk_plls), .clk_audio_dividers = gxbb_audio_dividers, @@ -1932,8 +1931,6 @@ static const struct clkc_data gxbb_clkc_data = { }; static const struct clkc_data gxl_clkc_data = { - .clk_mplls = gxbb_clk_mplls, - .clk_mplls_count = ARRAY_SIZE(gxbb_clk_mplls), .clk_plls = gxl_clk_plls, .clk_plls_count = ARRAY_SIZE(gxl_clk_plls), .clk_audio_dividers = gxbb_audio_dividers, @@ -1984,10 +1981,6 @@ static int gxbb_clkc_probe(struct platform_device *pdev) for (i = 0; i < clkc_data->clk_plls_count; i++) clkc_data->clk_plls[i]->base = clk_base; - /* Populate base address for MPLLs */ - for (i = 0; i < clkc_data->clk_mplls_count; i++) - clkc_data->clk_mplls[i]->base = clk_base; - /* Populate base address for the audio dividers */ for (i = 0; i < clkc_data->clk_audio_dividers_count; i++) clkc_data->clk_audio_dividers[i]->base = clk_base; diff --git a/drivers/clk/meson/meson8b.c b/drivers/clk/meson/meson8b.c index e643f7556f5e..4bb51c8f3102 100644 --- a/drivers/clk/meson/meson8b.c +++ b/drivers/clk/meson/meson8b.c @@ -257,33 +257,35 @@ 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, - }, - .ssen = { - .reg_off = HHI_MPLL_CNTL, - .shift = 25, - .width = 1, +static struct clk_regmap meson8b_mpll0 = { + .data = &(struct meson_clk_mpll_data){ + .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, + }, + .ssen = { + .reg_off = HHI_MPLL_CNTL, + .shift = 25, + .width = 1, + }, + .lock = &meson_clk_lock, }, - .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "mpll0", .ops = &meson_clk_mpll_ops, @@ -292,28 +294,30 @@ static struct meson_clk_mpll meson8b_mpll0 = { }, }; -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, +static struct clk_regmap meson8b_mpll1 = { + .data = &(struct meson_clk_mpll_data){ + .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 = &meson_clk_lock, }, - .en = { - .reg_off = HHI_MPLL_CNTL8, - .shift = 14, - .width = 1, - }, - .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "mpll1", .ops = &meson_clk_mpll_ops, @@ -322,28 +326,30 @@ static struct meson_clk_mpll meson8b_mpll1 = { }, }; -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, +static struct clk_regmap meson8b_mpll2 = { + .data = &(struct meson_clk_mpll_data){ + .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 = &meson_clk_lock, }, - .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "mpll2", .ops = &meson_clk_mpll_ops, @@ -613,12 +619,6 @@ 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_regmap *const meson8b_clk_regmaps[] = { &meson8b_clk81, &meson8b_ddr, @@ -700,6 +700,9 @@ static struct clk_regmap *const meson8b_clk_regmaps[] = { &meson8b_ao_iface, &meson8b_mpeg_clk_div, &meson8b_mpeg_clk_sel, + &meson8b_mpll0, + &meson8b_mpll1, + &meson8b_mpll2, }; static const struct meson8b_clk_reset_line { @@ -826,10 +829,6 @@ 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; -- cgit From 88a4e1283681e0f07048b2bd867cc81fbbae57cc Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Mon, 12 Feb 2018 15:58:41 +0100 Subject: clk: meson: migrate the audio divider clock to clk_regmap Rework meson audio divider driver to use clk_regmap and move gxbb clock using meson_clk_audio_divider to clk_regmap. Signed-off-by: Jerome Brunet Signed-off-by: Neil Armstrong --- drivers/clk/meson/clk-audio-divider.c | 63 +++++++++++------------------------ drivers/clk/meson/clkc.h | 5 +-- drivers/clk/meson/gxbb.c | 30 +++++------------ 3 files changed, 30 insertions(+), 68 deletions(-) diff --git a/drivers/clk/meson/clk-audio-divider.c b/drivers/clk/meson/clk-audio-divider.c index 6c07db06642d..f7ab5b1db342 100644 --- a/drivers/clk/meson/clk-audio-divider.c +++ b/drivers/clk/meson/clk-audio-divider.c @@ -28,8 +28,11 @@ #include #include "clkc.h" -#define to_meson_clk_audio_divider(_hw) container_of(_hw, \ - struct meson_clk_audio_divider, hw) +static inline struct meson_clk_audio_div_data * +meson_clk_audio_div_data(struct clk_regmap *clk) +{ + return (struct meson_clk_audio_div_data *)clk->data; +} static int _div_round(unsigned long parent_rate, unsigned long rate, unsigned long flags) @@ -45,15 +48,9 @@ static int _get_val(unsigned long parent_rate, unsigned long rate) return DIV_ROUND_UP_ULL((u64)parent_rate, rate) - 1; } -static int _valid_divider(struct clk_hw *hw, int divider) +static int _valid_divider(unsigned int width, int divider) { - struct meson_clk_audio_divider *adiv = - to_meson_clk_audio_divider(hw); - int max_divider; - u8 width; - - width = adiv->div.width; - max_divider = 1 << width; + int max_divider = 1 << width; return clamp(divider, 1, max_divider); } @@ -61,14 +58,11 @@ static int _valid_divider(struct clk_hw *hw, int divider) static unsigned long audio_divider_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { - struct meson_clk_audio_divider *adiv = - to_meson_clk_audio_divider(hw); - struct parm *p; - unsigned long reg, divider; + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_clk_audio_div_data *adiv = meson_clk_audio_div_data(clk); + unsigned long divider; - p = &adiv->div; - reg = readl(adiv->base + p->reg_off); - divider = PARM_GET(p->width, p->shift, reg) + 1; + divider = meson_parm_read(clk->map, &adiv->div); return DIV_ROUND_UP_ULL((u64)parent_rate, divider); } @@ -77,14 +71,14 @@ static long audio_divider_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *parent_rate) { - struct meson_clk_audio_divider *adiv = - to_meson_clk_audio_divider(hw); + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_clk_audio_div_data *adiv = meson_clk_audio_div_data(clk); unsigned long max_prate; int divider; if (!(clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT)) { divider = _div_round(*parent_rate, rate, adiv->flags); - divider = _valid_divider(hw, divider); + divider = _valid_divider(adiv->div.width, divider); return DIV_ROUND_UP_ULL((u64)*parent_rate, divider); } @@ -93,7 +87,7 @@ static long audio_divider_round_rate(struct clk_hw *hw, /* Get the corresponding rounded down divider */ divider = max_prate / rate; - divider = _valid_divider(hw, divider); + divider = _valid_divider(adiv->div.width, divider); /* Get actual rate of the parent */ *parent_rate = clk_hw_round_rate(clk_hw_get_parent(hw), @@ -106,28 +100,11 @@ static int audio_divider_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) { - struct meson_clk_audio_divider *adiv = - to_meson_clk_audio_divider(hw); - struct parm *p; - unsigned long reg, flags = 0; - int val; - - val = _get_val(parent_rate, rate); - - if (adiv->lock) - spin_lock_irqsave(adiv->lock, flags); - else - __acquire(adiv->lock); - - p = &adiv->div; - reg = readl(adiv->base + p->reg_off); - reg = PARM_SET(p->width, p->shift, reg, val); - writel(reg, adiv->base + p->reg_off); - - if (adiv->lock) - spin_unlock_irqrestore(adiv->lock, flags); - else - __release(adiv->lock); + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_clk_audio_div_data *adiv = meson_clk_audio_div_data(clk); + int val = _get_val(parent_rate, rate); + + meson_parm_write(clk->map, &adiv->div, val); return 0; } diff --git a/drivers/clk/meson/clkc.h b/drivers/clk/meson/clkc.h index 08a1ebfc65dc..a4a526cbca4c 100644 --- a/drivers/clk/meson/clkc.h +++ b/drivers/clk/meson/clkc.h @@ -142,12 +142,9 @@ struct meson_clk_mpll_data { spinlock_t *lock; }; -struct meson_clk_audio_divider { - struct clk_hw hw; - void __iomem *base; +struct meson_clk_audio_div_data { struct parm div; u8 flags; - spinlock_t *lock; }; #define MESON_GATE(_name, _reg, _bit) \ diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c index d2724a7ce9e7..196557f11608 100644 --- a/drivers/clk/meson/gxbb.c +++ b/drivers/clk/meson/gxbb.c @@ -826,14 +826,15 @@ static struct clk_regmap gxbb_cts_amclk_sel = { }, }; -static struct meson_clk_audio_divider gxbb_cts_amclk_div = { - .div = { - .reg_off = HHI_AUD_CLK_CNTL, - .shift = 0, - .width = 8, +static struct clk_regmap gxbb_cts_amclk_div = { + .data = &(struct meson_clk_audio_div_data){ + .div = { + .reg_off = HHI_AUD_CLK_CNTL, + .shift = 0, + .width = 8, + }, + .flags = CLK_DIVIDER_ROUND_CLOSEST, }, - .flags = CLK_DIVIDER_ROUND_CLOSEST, - .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "cts_amclk_div", .ops = &meson_clk_audio_divider_ops, @@ -1777,10 +1778,6 @@ static struct meson_clk_pll *const gxl_clk_plls[] = { &gxl_gp0_pll, }; -static struct meson_clk_audio_divider *const gxbb_audio_dividers[] = { - &gxbb_cts_amclk_div, -}; - static struct clk_regmap *const gx_clk_regmaps[] = { &gxbb_clk81, &gxbb_ddr, @@ -1912,29 +1909,24 @@ static struct clk_regmap *const gx_clk_regmaps[] = { &gxbb_mpll0, &gxbb_mpll1, &gxbb_mpll2, + &gxbb_cts_amclk_div, }; struct clkc_data { struct meson_clk_pll *const *clk_plls; unsigned int clk_plls_count; - struct meson_clk_audio_divider *const *clk_audio_dividers; - unsigned int clk_audio_dividers_count; struct clk_hw_onecell_data *hw_onecell_data; }; static const struct clkc_data gxbb_clkc_data = { .clk_plls = gxbb_clk_plls, .clk_plls_count = ARRAY_SIZE(gxbb_clk_plls), - .clk_audio_dividers = gxbb_audio_dividers, - .clk_audio_dividers_count = ARRAY_SIZE(gxbb_audio_dividers), .hw_onecell_data = &gxbb_hw_onecell_data, }; static const struct clkc_data gxl_clkc_data = { .clk_plls = gxl_clk_plls, .clk_plls_count = ARRAY_SIZE(gxl_clk_plls), - .clk_audio_dividers = gxbb_audio_dividers, - .clk_audio_dividers_count = ARRAY_SIZE(gxbb_audio_dividers), .hw_onecell_data = &gxl_hw_onecell_data, }; @@ -1981,10 +1973,6 @@ static int gxbb_clkc_probe(struct platform_device *pdev) for (i = 0; i < clkc_data->clk_plls_count; i++) clkc_data->clk_plls[i]->base = clk_base; - /* Populate base address for the audio dividers */ - for (i = 0; i < clkc_data->clk_audio_dividers_count; i++) - clkc_data->clk_audio_dividers[i]->base = clk_base; - /* Populate regmap for the common regmap backed clocks */ for (i = 0; i < ARRAY_SIZE(gx_clk_regmaps); i++) gx_clk_regmaps[i]->map = map; -- cgit From 722825dcd54b2e427c1aee54a7992eb4ab04a49d Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Mon, 12 Feb 2018 15:58:42 +0100 Subject: clk: meson: migrate plls clocks to clk_regmap Rework meson pll driver to use clk_regmap and move meson8b, gxbb and axg's clock using meson_clk_pll to clk_regmap. This rework is not just about clk_regmap, there a serious clean-up of the driver code: * Add lock and reset field: Previously inferred from the n field. * Simplify the reset logic: Code seemed to apply reset differently but in fact it was always the same -> assert reset, apply params, de-assert reset. The 2 lock checking loops have been kept for now, as they seem to be necessary. * Do the sequence of init register pokes only at .init() instead of in .set_rate(). Redoing the init on every set_rate() is not necessary Signed-off-by: Jerome Brunet Signed-off-by: Neil Armstrong --- drivers/clk/meson/axg.c | 213 +++++++++++----------- drivers/clk/meson/clk-pll.c | 243 ++++++++++--------------- drivers/clk/meson/clkc.h | 36 +--- drivers/clk/meson/gxbb.c | 424 +++++++++++++++++++++++++------------------- drivers/clk/meson/meson8b.c | 149 +++++++++------- 5 files changed, 535 insertions(+), 530 deletions(-) diff --git a/drivers/clk/meson/axg.c b/drivers/clk/meson/axg.c index 85f9466ce006..8c27ceffda4a 100644 --- a/drivers/clk/meson/axg.c +++ b/drivers/clk/meson/axg.c @@ -22,28 +22,39 @@ static DEFINE_SPINLOCK(meson_clk_lock); -static struct meson_clk_pll axg_fixed_pll = { - .m = { - .reg_off = HHI_MPLL_CNTL, - .shift = 0, - .width = 9, - }, - .n = { - .reg_off = HHI_MPLL_CNTL, - .shift = 9, - .width = 5, - }, - .od = { - .reg_off = HHI_MPLL_CNTL, - .shift = 16, - .width = 2, - }, - .frac = { - .reg_off = HHI_MPLL_CNTL2, - .shift = 0, - .width = 12, - }, - .lock = &meson_clk_lock, +static struct clk_regmap axg_fixed_pll = { + .data = &(struct meson_clk_pll_data){ + .m = { + .reg_off = HHI_MPLL_CNTL, + .shift = 0, + .width = 9, + }, + .n = { + .reg_off = HHI_MPLL_CNTL, + .shift = 9, + .width = 5, + }, + .od = { + .reg_off = HHI_MPLL_CNTL, + .shift = 16, + .width = 2, + }, + .frac = { + .reg_off = HHI_MPLL_CNTL2, + .shift = 0, + .width = 12, + }, + .l = { + .reg_off = HHI_MPLL_CNTL, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = HHI_MPLL_CNTL, + .shift = 29, + .width = 1, + }, + }, .hw.init = &(struct clk_init_data){ .name = "fixed_pll", .ops = &meson_clk_pll_ro_ops, @@ -52,23 +63,34 @@ static struct meson_clk_pll axg_fixed_pll = { }, }; -static struct meson_clk_pll axg_sys_pll = { - .m = { - .reg_off = HHI_SYS_PLL_CNTL, - .shift = 0, - .width = 9, - }, - .n = { - .reg_off = HHI_SYS_PLL_CNTL, - .shift = 9, - .width = 5, - }, - .od = { - .reg_off = HHI_SYS_PLL_CNTL, - .shift = 16, - .width = 2, +static struct clk_regmap axg_sys_pll = { + .data = &(struct meson_clk_pll_data){ + .m = { + .reg_off = HHI_SYS_PLL_CNTL, + .shift = 0, + .width = 9, + }, + .n = { + .reg_off = HHI_SYS_PLL_CNTL, + .shift = 9, + .width = 5, + }, + .od = { + .reg_off = HHI_SYS_PLL_CNTL, + .shift = 16, + .width = 2, + }, + .l = { + .reg_off = HHI_SYS_PLL_CNTL, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = HHI_SYS_PLL_CNTL, + .shift = 29, + .width = 1, + }, }, - .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "sys_pll", .ops = &meson_clk_pll_ro_ops, @@ -169,40 +191,47 @@ static const struct pll_rate_table axg_gp0_pll_rate_table[] = { { /* sentinel */ }, }; -static struct pll_params_table axg_gp0_params_table[] = { - PLL_PARAM(HHI_GP0_PLL_CNTL, 0x40010250), - PLL_PARAM(HHI_GP0_PLL_CNTL1, 0xc084a000), - PLL_PARAM(HHI_GP0_PLL_CNTL2, 0xb75020be), - PLL_PARAM(HHI_GP0_PLL_CNTL3, 0x0a59a288), - PLL_PARAM(HHI_GP0_PLL_CNTL4, 0xc000004d), - PLL_PARAM(HHI_GP0_PLL_CNTL5, 0x00078000), +const struct reg_sequence axg_gp0_init_regs[] = { + { .reg = HHI_GP0_PLL_CNTL, .def = 0x40010250 }, + { .reg = HHI_GP0_PLL_CNTL1, .def = 0xc084a000 }, + { .reg = HHI_GP0_PLL_CNTL2, .def = 0xb75020be }, + { .reg = HHI_GP0_PLL_CNTL3, .def = 0x0a59a288 }, + { .reg = HHI_GP0_PLL_CNTL4, .def = 0xc000004d }, + { .reg = HHI_GP0_PLL_CNTL5, .def = 0x00078000 }, }; -static struct meson_clk_pll axg_gp0_pll = { - .m = { - .reg_off = HHI_GP0_PLL_CNTL, - .shift = 0, - .width = 9, - }, - .n = { - .reg_off = HHI_GP0_PLL_CNTL, - .shift = 9, - .width = 5, - }, - .od = { - .reg_off = HHI_GP0_PLL_CNTL, - .shift = 16, - .width = 2, - }, - .params = { - .params_table = axg_gp0_params_table, - .params_count = ARRAY_SIZE(axg_gp0_params_table), - .no_init_reset = true, - .reset_lock_loop = true, - }, - .rate_table = axg_gp0_pll_rate_table, - .rate_count = ARRAY_SIZE(axg_gp0_pll_rate_table), - .lock = &meson_clk_lock, +static struct clk_regmap axg_gp0_pll = { + .data = &(struct meson_clk_pll_data){ + .m = { + .reg_off = HHI_GP0_PLL_CNTL, + .shift = 0, + .width = 9, + }, + .n = { + .reg_off = HHI_GP0_PLL_CNTL, + .shift = 9, + .width = 5, + }, + .od = { + .reg_off = HHI_GP0_PLL_CNTL, + .shift = 16, + .width = 2, + }, + .l = { + .reg_off = HHI_GP0_PLL_CNTL, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = HHI_GP0_PLL_CNTL, + .shift = 29, + .width = 1, + }, + .table = axg_gp0_pll_rate_table, + .init_regs = axg_gp0_init_regs, + .init_count = ARRAY_SIZE(axg_gp0_init_regs), + .flags = CLK_MESON_PLL_LOCK_LOOP_RST, + }, .hw.init = &(struct clk_init_data){ .name = "gp0_pll", .ops = &meson_clk_pll_ops, @@ -698,14 +727,7 @@ static struct clk_hw_onecell_data axg_hw_onecell_data = { .num = NR_CLKS, }; -/* Convenience tables to populate base addresses in .probe */ - -static struct meson_clk_pll *const axg_clk_plls[] = { - &axg_fixed_pll, - &axg_sys_pll, - &axg_gp0_pll, -}; - +/* Convenience table to populate regmap in .probe */ static struct clk_regmap *const axg_clk_regmaps[] = { &axg_clk81, &axg_ddr, @@ -764,22 +786,13 @@ static struct clk_regmap *const axg_clk_regmaps[] = { &axg_mpll1, &axg_mpll2, &axg_mpll3, -}; - -struct clkc_data { - struct meson_clk_pll *const *clk_plls; - unsigned int clk_plls_count; - struct clk_hw_onecell_data *hw_onecell_data; -}; - -static const struct clkc_data axg_clkc_data = { - .clk_plls = axg_clk_plls, - .clk_plls_count = ARRAY_SIZE(axg_clk_plls), - .hw_onecell_data = &axg_hw_onecell_data, + &axg_fixed_pll, + &axg_sys_pll, + &axg_gp0_pll, }; static const struct of_device_id clkc_match_table[] = { - { .compatible = "amlogic,axg-clkc", .data = &axg_clkc_data }, + { .compatible = "amlogic,axg-clkc" }, {} }; @@ -792,16 +805,11 @@ static const struct regmap_config clkc_regmap_config = { static int axg_clkc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - const struct clkc_data *clkc_data; struct resource *res; void __iomem *clk_base; struct regmap *map; int ret, i; - clkc_data = of_device_get_match_data(dev); - if (!clkc_data) - return -EINVAL; - /* Generic clocks and PLLs */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) @@ -817,21 +825,16 @@ static int axg_clkc_probe(struct platform_device *pdev) if (IS_ERR(map)) return PTR_ERR(map); - /* Populate base address for PLLs */ - for (i = 0; i < clkc_data->clk_plls_count; i++) - clkc_data->clk_plls[i]->base = clk_base; - /* Populate regmap for the regmap backed clocks */ for (i = 0; i < ARRAY_SIZE(axg_clk_regmaps); i++) axg_clk_regmaps[i]->map = map; - for (i = 0; i < clkc_data->hw_onecell_data->num; i++) { + for (i = 0; i < axg_hw_onecell_data.num; i++) { /* array might be sparse */ - if (!clkc_data->hw_onecell_data->hws[i]) + if (!axg_hw_onecell_data.hws[i]) continue; - ret = devm_clk_hw_register(dev, - clkc_data->hw_onecell_data->hws[i]); + ret = devm_clk_hw_register(dev, axg_hw_onecell_data.hws[i]); if (ret) { dev_err(dev, "Clock registration failed\n"); return ret; @@ -839,7 +842,7 @@ static int axg_clkc_probe(struct platform_device *pdev) } return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, - clkc_data->hw_onecell_data); + &axg_hw_onecell_data); } static struct platform_driver axg_driver = { diff --git a/drivers/clk/meson/clk-pll.c b/drivers/clk/meson/clk-pll.c index 218c769c6d50..f3d909719111 100644 --- a/drivers/clk/meson/clk-pll.c +++ b/drivers/clk/meson/clk-pll.c @@ -42,52 +42,36 @@ #include "clkc.h" -#define MESON_PLL_RESET BIT(29) -#define MESON_PLL_LOCK BIT(31) - -#define to_meson_clk_pll(_hw) container_of(_hw, struct meson_clk_pll, hw) +static inline struct meson_clk_pll_data * +meson_clk_pll_data(struct clk_regmap *clk) +{ + return (struct meson_clk_pll_data *)clk->data; +} static unsigned long meson_clk_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { - struct meson_clk_pll *pll = to_meson_clk_pll(hw); - struct parm *p; + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_clk_pll_data *pll = meson_clk_pll_data(clk); u64 rate; u16 n, m, frac = 0, od, od2 = 0, od3 = 0; - u32 reg; - - p = &pll->n; - reg = readl(pll->base + p->reg_off); - n = PARM_GET(p->width, p->shift, reg); - p = &pll->m; - reg = readl(pll->base + p->reg_off); - m = PARM_GET(p->width, p->shift, reg); + n = meson_parm_read(clk->map, &pll->n); + m = meson_parm_read(clk->map, &pll->m); + od = meson_parm_read(clk->map, &pll->od); - p = &pll->od; - reg = readl(pll->base + p->reg_off); - od = PARM_GET(p->width, p->shift, reg); + if (MESON_PARM_APPLICABLE(&pll->od2)) + od2 = meson_parm_read(clk->map, &pll->od2); - p = &pll->od2; - if (p->width) { - reg = readl(pll->base + p->reg_off); - od2 = PARM_GET(p->width, p->shift, reg); - } - - p = &pll->od3; - if (p->width) { - reg = readl(pll->base + p->reg_off); - od3 = PARM_GET(p->width, p->shift, reg); - } + if (MESON_PARM_APPLICABLE(&pll->od3)) + od3 = meson_parm_read(clk->map, &pll->od3); rate = (u64)m * parent_rate; - p = &pll->frac; - if (p->width) { - reg = readl(pll->base + p->reg_off); - frac = PARM_GET(p->width, p->shift, reg); + if (MESON_PARM_APPLICABLE(&pll->frac)) { + frac = meson_parm_read(clk->map, &pll->frac); - rate += mul_u64_u32_shr(parent_rate, frac, p->width); + rate += mul_u64_u32_shr(parent_rate, frac, pll->frac.width); } return div_u64(rate, n) >> od >> od2 >> od3; @@ -96,177 +80,136 @@ static unsigned long meson_clk_pll_recalc_rate(struct clk_hw *hw, static long meson_clk_pll_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *parent_rate) { - struct meson_clk_pll *pll = to_meson_clk_pll(hw); - const struct pll_rate_table *rate_table = pll->rate_table; - int i; + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_clk_pll_data *pll = meson_clk_pll_data(clk); + const struct pll_rate_table *pllt; /* * if the table is missing, just return the current rate * since we don't have the other available frequencies */ - if (!rate_table) + if (!pll->table) return meson_clk_pll_recalc_rate(hw, *parent_rate); - for (i = 0; i < pll->rate_count; i++) { - if (rate <= rate_table[i].rate) - return rate_table[i].rate; + for (pllt = pll->table; pllt->rate; pllt++) { + if (rate <= pllt->rate) + return pllt->rate; } /* else return the smallest value */ - return rate_table[0].rate; + return pll->table[0].rate; } -static const struct pll_rate_table *meson_clk_get_pll_settings(struct meson_clk_pll *pll, - unsigned long rate) +static const struct pll_rate_table * +meson_clk_get_pll_settings(const struct pll_rate_table *table, + unsigned long rate) { - const struct pll_rate_table *rate_table = pll->rate_table; - int i; + const struct pll_rate_table *pllt; - if (!rate_table) + if (!table) return NULL; - for (i = 0; i < pll->rate_count; i++) { - if (rate == rate_table[i].rate) - return &rate_table[i]; + for (pllt = table; pllt->rate; pllt++) { + if (rate == pllt->rate) + return pllt; } + return NULL; } -/* Specific wait loop for GXL/GXM GP0 PLL */ -static int meson_clk_pll_wait_lock_reset(struct meson_clk_pll *pll, - struct parm *p_n) +static int meson_clk_pll_wait_lock(struct clk_hw *hw) { - int delay = 100; - u32 reg; - - while (delay > 0) { - reg = readl(pll->base + p_n->reg_off); - writel(reg | MESON_PLL_RESET, pll->base + p_n->reg_off); - udelay(10); - writel(reg & ~MESON_PLL_RESET, pll->base + p_n->reg_off); - - /* This delay comes from AMLogic tree clk-gp0-gxl driver */ - mdelay(1); - - reg = readl(pll->base + p_n->reg_off); - if (reg & MESON_PLL_LOCK) + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_clk_pll_data *pll = meson_clk_pll_data(clk); + int delay = pll->flags & CLK_MESON_PLL_LOCK_LOOP_RST ? + 100 : 24000000; + + do { + /* Specific wait loop for GXL/GXM GP0 PLL */ + if (pll->flags & CLK_MESON_PLL_LOCK_LOOP_RST) { + /* Procedure taken from the vendor kernel */ + meson_parm_write(clk->map, &pll->rst, 1); + udelay(10); + meson_parm_write(clk->map, &pll->rst, 0); + mdelay(1); + } + + /* Is the clock locked now ? */ + if (meson_parm_read(clk->map, &pll->l)) return 0; - delay--; - } - return -ETIMEDOUT; -} -static int meson_clk_pll_wait_lock(struct meson_clk_pll *pll, - struct parm *p_n) -{ - int delay = 24000000; - u32 reg; - - while (delay > 0) { - reg = readl(pll->base + p_n->reg_off); - - if (reg & MESON_PLL_LOCK) - return 0; delay--; - } + } while (delay > 0); + return -ETIMEDOUT; } -static void meson_clk_pll_init_params(struct meson_clk_pll *pll) +static void meson_clk_pll_init(struct clk_hw *hw) { - int i; - - for (i = 0 ; i < pll->params.params_count ; ++i) - writel(pll->params.params_table[i].value, - pll->base + pll->params.params_table[i].reg_off); + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_clk_pll_data *pll = meson_clk_pll_data(clk); + + if (pll->init_count) { + meson_parm_write(clk->map, &pll->rst, 1); + regmap_multi_reg_write(clk->map, pll->init_regs, + pll->init_count); + meson_parm_write(clk->map, &pll->rst, 0); + } } static int meson_clk_pll_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) { - struct meson_clk_pll *pll = to_meson_clk_pll(hw); - struct parm *p; - const struct pll_rate_table *rate_set; + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_clk_pll_data *pll = meson_clk_pll_data(clk); + const struct pll_rate_table *pllt; unsigned long old_rate; - int ret = 0; - u32 reg; if (parent_rate == 0 || rate == 0) return -EINVAL; old_rate = rate; - rate_set = meson_clk_get_pll_settings(pll, rate); - if (!rate_set) + pllt = meson_clk_get_pll_settings(pll->table, rate); + if (!pllt) return -EINVAL; - /* Initialize the PLL in a clean state if specified */ - if (pll->params.params_count) - meson_clk_pll_init_params(pll); - - /* PLL reset */ - p = &pll->n; - reg = readl(pll->base + p->reg_off); - /* If no_init_reset is provided, avoid resetting at this point */ - if (!pll->params.no_init_reset) - writel(reg | MESON_PLL_RESET, pll->base + p->reg_off); - - reg = PARM_SET(p->width, p->shift, reg, rate_set->n); - writel(reg, pll->base + p->reg_off); - - p = &pll->m; - reg = readl(pll->base + p->reg_off); - reg = PARM_SET(p->width, p->shift, reg, rate_set->m); - writel(reg, pll->base + p->reg_off); - - p = &pll->od; - reg = readl(pll->base + p->reg_off); - reg = PARM_SET(p->width, p->shift, reg, rate_set->od); - writel(reg, pll->base + p->reg_off); - - p = &pll->od2; - if (p->width) { - reg = readl(pll->base + p->reg_off); - reg = PARM_SET(p->width, p->shift, reg, rate_set->od2); - writel(reg, pll->base + p->reg_off); - } + /* Put the pll in reset to write the params */ + meson_parm_write(clk->map, &pll->rst, 1); - p = &pll->od3; - if (p->width) { - reg = readl(pll->base + p->reg_off); - reg = PARM_SET(p->width, p->shift, reg, rate_set->od3); - writel(reg, pll->base + p->reg_off); - } + meson_parm_write(clk->map, &pll->n, pllt->n); + meson_parm_write(clk->map, &pll->m, pllt->m); + meson_parm_write(clk->map, &pll->od, pllt->od); - p = &pll->frac; - if (p->width) { - reg = readl(pll->base + p->reg_off); - reg = PARM_SET(p->width, p->shift, reg, rate_set->frac); - writel(reg, pll->base + p->reg_off); - } + if (MESON_PARM_APPLICABLE(&pll->od2)) + meson_parm_write(clk->map, &pll->od2, pllt->od2); - p = &pll->n; - /* If clear_reset_for_lock is provided, remove the reset bit here */ - if (pll->params.clear_reset_for_lock) { - reg = readl(pll->base + p->reg_off); - writel(reg & ~MESON_PLL_RESET, pll->base + p->reg_off); - } + if (MESON_PARM_APPLICABLE(&pll->od3)) + meson_parm_write(clk->map, &pll->od3, pllt->od3); + + if (MESON_PARM_APPLICABLE(&pll->frac)) + meson_parm_write(clk->map, &pll->frac, pllt->frac); + + /* make sure the reset is cleared at this point */ + meson_parm_write(clk->map, &pll->rst, 0); - /* If reset_lock_loop, use a special loop including resetting */ - if (pll->params.reset_lock_loop) - ret = meson_clk_pll_wait_lock_reset(pll, p); - else - ret = meson_clk_pll_wait_lock(pll, p); - if (ret) { + if (meson_clk_pll_wait_lock(hw)) { pr_warn("%s: pll did not lock, trying to restore old rate %lu\n", __func__, old_rate); + /* + * FIXME: Do we really need/want this HACK ? + * It looks unsafe. what happens if the clock gets into a + * broken state and we can't lock back on the old_rate ? Looks + * like an infinite recursion is possible + */ meson_clk_pll_set_rate(hw, old_rate, parent_rate); } - return ret; + return 0; } const struct clk_ops meson_clk_pll_ops = { + .init = meson_clk_pll_init, .recalc_rate = meson_clk_pll_recalc_rate, .round_rate = meson_clk_pll_round_rate, .set_rate = meson_clk_pll_set_rate, diff --git a/drivers/clk/meson/clkc.h b/drivers/clk/meson/clkc.h index a4a526cbca4c..f0d70eaffcf3 100644 --- a/drivers/clk/meson/clkc.h +++ b/drivers/clk/meson/clkc.h @@ -82,41 +82,21 @@ struct pll_rate_table { .frac = (_frac), \ } \ -struct pll_params_table { - unsigned int reg_off; - unsigned int value; -}; - -#define PLL_PARAM(_reg, _val) \ - { \ - .reg_off = (_reg), \ - .value = (_val), \ - } - -struct pll_setup_params { - struct pll_params_table *params_table; - unsigned int params_count; - /* Workaround for GP0, do not reset before configuring */ - bool no_init_reset; - /* Workaround for GP0, unreset right before checking for lock */ - bool clear_reset_for_lock; - /* Workaround for GXL GP0, reset in the lock checking loop */ - bool reset_lock_loop; -}; +#define CLK_MESON_PLL_LOCK_LOOP_RST BIT(0) -struct meson_clk_pll { - struct clk_hw hw; - void __iomem *base; +struct meson_clk_pll_data { struct parm m; struct parm n; struct parm frac; struct parm od; struct parm od2; struct parm od3; - const struct pll_setup_params params; - const struct pll_rate_table *rate_table; - unsigned int rate_count; - spinlock_t *lock; + struct parm l; + struct parm rst; + const struct reg_sequence *init_regs; + unsigned int init_count; + const struct pll_rate_table *table; + u8 flags; }; #define to_meson_clk_pll(_hw) container_of(_hw, struct meson_clk_pll, hw) diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c index 196557f11608..49f5716ce8b6 100644 --- a/drivers/clk/meson/gxbb.c +++ b/drivers/clk/meson/gxbb.c @@ -188,28 +188,39 @@ static const struct pll_rate_table gxl_gp0_pll_rate_table[] = { { /* sentinel */ }, }; -static struct meson_clk_pll gxbb_fixed_pll = { - .m = { - .reg_off = HHI_MPLL_CNTL, - .shift = 0, - .width = 9, - }, - .n = { - .reg_off = HHI_MPLL_CNTL, - .shift = 9, - .width = 5, - }, - .od = { - .reg_off = HHI_MPLL_CNTL, - .shift = 16, - .width = 2, - }, - .frac = { - .reg_off = HHI_MPLL_CNTL2, - .shift = 0, - .width = 12, - }, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_fixed_pll = { + .data = &(struct meson_clk_pll_data){ + .m = { + .reg_off = HHI_MPLL_CNTL, + .shift = 0, + .width = 9, + }, + .n = { + .reg_off = HHI_MPLL_CNTL, + .shift = 9, + .width = 5, + }, + .od = { + .reg_off = HHI_MPLL_CNTL, + .shift = 16, + .width = 2, + }, + .frac = { + .reg_off = HHI_MPLL_CNTL2, + .shift = 0, + .width = 12, + }, + .l = { + .reg_off = HHI_MPLL_CNTL, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = HHI_MPLL_CNTL, + .shift = 29, + .width = 1, + }, + }, .hw.init = &(struct clk_init_data){ .name = "fixed_pll", .ops = &meson_clk_pll_ro_ops, @@ -230,38 +241,49 @@ static struct clk_fixed_factor gxbb_hdmi_pll_pre_mult = { }, }; -static struct meson_clk_pll gxbb_hdmi_pll = { - .m = { - .reg_off = HHI_HDMI_PLL_CNTL, - .shift = 0, - .width = 9, - }, - .n = { - .reg_off = HHI_HDMI_PLL_CNTL, - .shift = 9, - .width = 5, - }, - .frac = { - .reg_off = HHI_HDMI_PLL_CNTL2, - .shift = 0, - .width = 12, - }, - .od = { - .reg_off = HHI_HDMI_PLL_CNTL2, - .shift = 16, - .width = 2, - }, - .od2 = { - .reg_off = HHI_HDMI_PLL_CNTL2, - .shift = 22, - .width = 2, - }, - .od3 = { - .reg_off = HHI_HDMI_PLL_CNTL2, - .shift = 18, - .width = 2, +static struct clk_regmap gxbb_hdmi_pll = { + .data = &(struct meson_clk_pll_data){ + .m = { + .reg_off = HHI_HDMI_PLL_CNTL, + .shift = 0, + .width = 9, + }, + .n = { + .reg_off = HHI_HDMI_PLL_CNTL, + .shift = 9, + .width = 5, + }, + .frac = { + .reg_off = HHI_HDMI_PLL_CNTL2, + .shift = 0, + .width = 12, + }, + .od = { + .reg_off = HHI_HDMI_PLL_CNTL2, + .shift = 16, + .width = 2, + }, + .od2 = { + .reg_off = HHI_HDMI_PLL_CNTL2, + .shift = 22, + .width = 2, + }, + .od3 = { + .reg_off = HHI_HDMI_PLL_CNTL2, + .shift = 18, + .width = 2, + }, + .l = { + .reg_off = HHI_HDMI_PLL_CNTL, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = HHI_HDMI_PLL_CNTL, + .shift = 28, + .width = 1, + }, }, - .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "hdmi_pll", .ops = &meson_clk_pll_ro_ops, @@ -271,43 +293,55 @@ static struct meson_clk_pll gxbb_hdmi_pll = { }, }; -static struct meson_clk_pll gxl_hdmi_pll = { - .m = { - .reg_off = HHI_HDMI_PLL_CNTL, - .shift = 0, - .width = 9, - }, - .n = { - .reg_off = HHI_HDMI_PLL_CNTL, - .shift = 9, - .width = 5, +static struct clk_regmap gxl_hdmi_pll = { + .data = &(struct meson_clk_pll_data){ + .m = { + .reg_off = HHI_HDMI_PLL_CNTL, + .shift = 0, + .width = 9, + }, + .n = { + .reg_off = HHI_HDMI_PLL_CNTL, + .shift = 9, + .width = 5, + }, + .frac = { + /* + * On gxl, there is a register shift due to + * HHI_HDMI_PLL_CNTL1 which does not exist on gxbb, + * so we compute the register offset based on the PLL + * base to get it right + */ + .reg_off = HHI_HDMI_PLL_CNTL + 4, + .shift = 0, + .width = 12, + }, + .od = { + .reg_off = HHI_HDMI_PLL_CNTL + 8, + .shift = 21, + .width = 2, + }, + .od2 = { + .reg_off = HHI_HDMI_PLL_CNTL + 8, + .shift = 23, + .width = 2, + }, + .od3 = { + .reg_off = HHI_HDMI_PLL_CNTL + 8, + .shift = 19, + .width = 2, + }, + .l = { + .reg_off = HHI_HDMI_PLL_CNTL, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = HHI_HDMI_PLL_CNTL, + .shift = 29, + .width = 1, + }, }, - .frac = { - /* - * On gxl, there is a register shift due to HHI_HDMI_PLL_CNTL1 - * which does not exist on gxbb, so we compute the register - * offset based on the PLL base to get it right - */ - .reg_off = HHI_HDMI_PLL_CNTL + 4, - .shift = 0, - .width = 12, - }, - .od = { - .reg_off = HHI_HDMI_PLL_CNTL + 8, - .shift = 21, - .width = 2, - }, - .od2 = { - .reg_off = HHI_HDMI_PLL_CNTL + 8, - .shift = 23, - .width = 2, - }, - .od3 = { - .reg_off = HHI_HDMI_PLL_CNTL + 8, - .shift = 19, - .width = 2, - }, - .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "hdmi_pll", .ops = &meson_clk_pll_ro_ops, @@ -317,23 +351,34 @@ static struct meson_clk_pll gxl_hdmi_pll = { }, }; -static struct meson_clk_pll gxbb_sys_pll = { - .m = { - .reg_off = HHI_SYS_PLL_CNTL, - .shift = 0, - .width = 9, - }, - .n = { - .reg_off = HHI_SYS_PLL_CNTL, - .shift = 9, - .width = 5, - }, - .od = { - .reg_off = HHI_SYS_PLL_CNTL, - .shift = 10, - .width = 2, +static struct clk_regmap gxbb_sys_pll = { + .data = &(struct meson_clk_pll_data){ + .m = { + .reg_off = HHI_SYS_PLL_CNTL, + .shift = 0, + .width = 9, + }, + .n = { + .reg_off = HHI_SYS_PLL_CNTL, + .shift = 9, + .width = 5, + }, + .od = { + .reg_off = HHI_SYS_PLL_CNTL, + .shift = 10, + .width = 2, + }, + .l = { + .reg_off = HHI_SYS_PLL_CNTL, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = HHI_SYS_PLL_CNTL, + .shift = 29, + .width = 1, + }, }, - .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "sys_pll", .ops = &meson_clk_pll_ro_ops, @@ -343,38 +388,44 @@ static struct meson_clk_pll gxbb_sys_pll = { }, }; -struct pll_params_table gxbb_gp0_params_table[] = { - PLL_PARAM(HHI_GP0_PLL_CNTL, 0x6a000228), - PLL_PARAM(HHI_GP0_PLL_CNTL2, 0x69c80000), - PLL_PARAM(HHI_GP0_PLL_CNTL3, 0x0a5590c4), - PLL_PARAM(HHI_GP0_PLL_CNTL4, 0x0000500d), +const struct reg_sequence gxbb_gp0_init_regs[] = { + { .reg = HHI_GP0_PLL_CNTL, .def = 0x6a000228 }, + { .reg = HHI_GP0_PLL_CNTL2, .def = 0x69c80000 }, + { .reg = HHI_GP0_PLL_CNTL3, .def = 0x0a5590c4 }, + { .reg = HHI_GP0_PLL_CNTL4, .def = 0x0000500d }, }; -static struct meson_clk_pll gxbb_gp0_pll = { - .m = { - .reg_off = HHI_GP0_PLL_CNTL, - .shift = 0, - .width = 9, - }, - .n = { - .reg_off = HHI_GP0_PLL_CNTL, - .shift = 9, - .width = 5, - }, - .od = { - .reg_off = HHI_GP0_PLL_CNTL, - .shift = 16, - .width = 2, - }, - .params = { - .params_table = gxbb_gp0_params_table, - .params_count = ARRAY_SIZE(gxbb_gp0_params_table), - .no_init_reset = true, - .clear_reset_for_lock = true, +static struct clk_regmap gxbb_gp0_pll = { + .data = &(struct meson_clk_pll_data){ + .m = { + .reg_off = HHI_GP0_PLL_CNTL, + .shift = 0, + .width = 9, + }, + .n = { + .reg_off = HHI_GP0_PLL_CNTL, + .shift = 9, + .width = 5, + }, + .od = { + .reg_off = HHI_GP0_PLL_CNTL, + .shift = 16, + .width = 2, + }, + .l = { + .reg_off = HHI_GP0_PLL_CNTL, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = HHI_GP0_PLL_CNTL, + .shift = 29, + .width = 1, + }, + .table = gxbb_gp0_pll_rate_table, + .init_regs = gxbb_gp0_init_regs, + .init_count = ARRAY_SIZE(gxbb_gp0_init_regs), }, - .rate_table = gxbb_gp0_pll_rate_table, - .rate_count = ARRAY_SIZE(gxbb_gp0_pll_rate_table), - .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "gp0_pll", .ops = &meson_clk_pll_ops, @@ -384,40 +435,47 @@ static struct meson_clk_pll gxbb_gp0_pll = { }, }; -struct pll_params_table gxl_gp0_params_table[] = { - PLL_PARAM(HHI_GP0_PLL_CNTL, 0x40010250), - PLL_PARAM(HHI_GP0_PLL_CNTL1, 0xc084a000), - PLL_PARAM(HHI_GP0_PLL_CNTL2, 0xb75020be), - PLL_PARAM(HHI_GP0_PLL_CNTL3, 0x0a59a288), - PLL_PARAM(HHI_GP0_PLL_CNTL4, 0xc000004d), - PLL_PARAM(HHI_GP0_PLL_CNTL5, 0x00078000), +const struct reg_sequence gxl_gp0_init_regs[] = { + { .reg = HHI_GP0_PLL_CNTL, .def = 0x40010250 }, + { .reg = HHI_GP0_PLL_CNTL1, .def = 0xc084a000 }, + { .reg = HHI_GP0_PLL_CNTL2, .def = 0xb75020be }, + { .reg = HHI_GP0_PLL_CNTL3, .def = 0x0a59a288 }, + { .reg = HHI_GP0_PLL_CNTL4, .def = 0xc000004d }, + { .reg = HHI_GP0_PLL_CNTL5, .def = 0x00078000 }, }; -static struct meson_clk_pll gxl_gp0_pll = { - .m = { - .reg_off = HHI_GP0_PLL_CNTL, - .shift = 0, - .width = 9, - }, - .n = { - .reg_off = HHI_GP0_PLL_CNTL, - .shift = 9, - .width = 5, - }, - .od = { - .reg_off = HHI_GP0_PLL_CNTL, - .shift = 16, - .width = 2, - }, - .params = { - .params_table = gxl_gp0_params_table, - .params_count = ARRAY_SIZE(gxl_gp0_params_table), - .no_init_reset = true, - .reset_lock_loop = true, +static struct clk_regmap gxl_gp0_pll = { + .data = &(struct meson_clk_pll_data){ + .m = { + .reg_off = HHI_GP0_PLL_CNTL, + .shift = 0, + .width = 9, + }, + .n = { + .reg_off = HHI_GP0_PLL_CNTL, + .shift = 9, + .width = 5, + }, + .od = { + .reg_off = HHI_GP0_PLL_CNTL, + .shift = 16, + .width = 2, + }, + .l = { + .reg_off = HHI_GP0_PLL_CNTL, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = HHI_GP0_PLL_CNTL, + .shift = 29, + .width = 1, + }, + .table = gxl_gp0_pll_rate_table, + .init_regs = gxl_gp0_init_regs, + .init_count = ARRAY_SIZE(gxl_gp0_init_regs), + .flags = CLK_MESON_PLL_LOCK_LOOP_RST, }, - .rate_table = gxl_gp0_pll_rate_table, - .rate_count = ARRAY_SIZE(gxl_gp0_pll_rate_table), - .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "gp0_pll", .ops = &meson_clk_pll_ops, @@ -1762,20 +1820,14 @@ static struct clk_hw_onecell_data gxl_hw_onecell_data = { .num = NR_CLKS, }; -/* Convenience tables to populate base addresses in .probe */ - -static struct meson_clk_pll *const gxbb_clk_plls[] = { - &gxbb_fixed_pll, - &gxbb_hdmi_pll, - &gxbb_sys_pll, +static struct clk_regmap *const gxbb_clk_regmaps[] = { &gxbb_gp0_pll, + &gxbb_hdmi_pll, }; -static struct meson_clk_pll *const gxl_clk_plls[] = { - &gxbb_fixed_pll, - &gxl_hdmi_pll, - &gxbb_sys_pll, +static struct clk_regmap *const gxl_clk_regmaps[] = { &gxl_gp0_pll, + &gxl_hdmi_pll, }; static struct clk_regmap *const gx_clk_regmaps[] = { @@ -1910,23 +1962,25 @@ static struct clk_regmap *const gx_clk_regmaps[] = { &gxbb_mpll1, &gxbb_mpll2, &gxbb_cts_amclk_div, + &gxbb_fixed_pll, + &gxbb_sys_pll, }; struct clkc_data { - struct meson_clk_pll *const *clk_plls; - unsigned int clk_plls_count; + struct clk_regmap *const *regmap_clks; + unsigned int regmap_clks_count; struct clk_hw_onecell_data *hw_onecell_data; }; static const struct clkc_data gxbb_clkc_data = { - .clk_plls = gxbb_clk_plls, - .clk_plls_count = ARRAY_SIZE(gxbb_clk_plls), + .regmap_clks = gxbb_clk_regmaps, + .regmap_clks_count = ARRAY_SIZE(gxbb_clk_regmaps), .hw_onecell_data = &gxbb_hw_onecell_data, }; static const struct clkc_data gxl_clkc_data = { - .clk_plls = gxl_clk_plls, - .clk_plls_count = ARRAY_SIZE(gxl_clk_plls), + .regmap_clks = gxl_clk_regmaps, + .regmap_clks_count = ARRAY_SIZE(gxl_clk_regmaps), .hw_onecell_data = &gxl_hw_onecell_data, }; @@ -1969,14 +2023,14 @@ static int gxbb_clkc_probe(struct platform_device *pdev) if (IS_ERR(map)) return PTR_ERR(map); - /* Populate base address for PLLs */ - for (i = 0; i < clkc_data->clk_plls_count; i++) - clkc_data->clk_plls[i]->base = clk_base; - /* Populate regmap for the common regmap backed clocks */ for (i = 0; i < ARRAY_SIZE(gx_clk_regmaps); i++) gx_clk_regmaps[i]->map = map; + /* Populate regmap for soc specific clocks */ + for (i = 0; i < clkc_data->regmap_clks_count; i++) + clkc_data->regmap_clks[i]->map = map; + /* Register all clks */ for (i = 0; i < clkc_data->hw_onecell_data->num; i++) { /* array might be sparse */ diff --git a/drivers/clk/meson/meson8b.c b/drivers/clk/meson/meson8b.c index 4bb51c8f3102..4fd8253c54bb 100644 --- a/drivers/clk/meson/meson8b.c +++ b/drivers/clk/meson/meson8b.c @@ -122,23 +122,34 @@ static struct clk_fixed_rate meson8b_xtal = { }, }; -static struct meson_clk_pll meson8b_fixed_pll = { - .m = { - .reg_off = HHI_MPLL_CNTL, - .shift = 0, - .width = 9, - }, - .n = { - .reg_off = HHI_MPLL_CNTL, - .shift = 9, - .width = 5, - }, - .od = { - .reg_off = HHI_MPLL_CNTL, - .shift = 16, - .width = 2, - }, - .lock = &meson_clk_lock, +static struct clk_regmap meson8b_fixed_pll = { + .data = &(struct meson_clk_pll_data){ + .m = { + .reg_off = HHI_MPLL_CNTL, + .shift = 0, + .width = 9, + }, + .n = { + .reg_off = HHI_MPLL_CNTL, + .shift = 9, + .width = 5, + }, + .od = { + .reg_off = HHI_MPLL_CNTL, + .shift = 16, + .width = 2, + }, + .l = { + .reg_off = HHI_MPLL_CNTL, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = HHI_MPLL_CNTL, + .shift = 29, + .width = 1, + }, + }, .hw.init = &(struct clk_init_data){ .name = "fixed_pll", .ops = &meson_clk_pll_ro_ops, @@ -148,23 +159,34 @@ static struct meson_clk_pll meson8b_fixed_pll = { }, }; -static struct meson_clk_pll meson8b_vid_pll = { - .m = { - .reg_off = HHI_VID_PLL_CNTL, - .shift = 0, - .width = 9, - }, - .n = { - .reg_off = HHI_VID_PLL_CNTL, - .shift = 9, - .width = 5, - }, - .od = { - .reg_off = HHI_VID_PLL_CNTL, - .shift = 16, - .width = 2, +static struct clk_regmap meson8b_vid_pll = { + .data = &(struct meson_clk_pll_data){ + .m = { + .reg_off = HHI_VID_PLL_CNTL, + .shift = 0, + .width = 9, + }, + .n = { + .reg_off = HHI_VID_PLL_CNTL, + .shift = 9, + .width = 5, + }, + .od = { + .reg_off = HHI_VID_PLL_CNTL, + .shift = 16, + .width = 2, + }, + .l = { + .reg_off = HHI_VID_PLL_CNTL, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = HHI_VID_PLL_CNTL, + .shift = 29, + .width = 1, + }, }, - .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "vid_pll", .ops = &meson_clk_pll_ro_ops, @@ -174,25 +196,35 @@ static struct meson_clk_pll meson8b_vid_pll = { }, }; -static struct meson_clk_pll meson8b_sys_pll = { - .m = { - .reg_off = HHI_SYS_PLL_CNTL, - .shift = 0, - .width = 9, - }, - .n = { - .reg_off = HHI_SYS_PLL_CNTL, - .shift = 9, - .width = 5, - }, - .od = { - .reg_off = HHI_SYS_PLL_CNTL, - .shift = 16, - .width = 2, - }, - .rate_table = sys_pll_rate_table, - .rate_count = ARRAY_SIZE(sys_pll_rate_table), - .lock = &meson_clk_lock, +static struct clk_regmap meson8b_sys_pll = { + .data = &(struct meson_clk_pll_data){ + .m = { + .reg_off = HHI_SYS_PLL_CNTL, + .shift = 0, + .width = 9, + }, + .n = { + .reg_off = HHI_SYS_PLL_CNTL, + .shift = 9, + .width = 5, + }, + .od = { + .reg_off = HHI_SYS_PLL_CNTL, + .shift = 16, + .width = 2, + }, + .l = { + .reg_off = HHI_SYS_PLL_CNTL, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = HHI_SYS_PLL_CNTL, + .shift = 29, + .width = 1, + }, + .table = sys_pll_rate_table, + }, .hw.init = &(struct clk_init_data){ .name = "sys_pll", .ops = &meson_clk_pll_ops, @@ -613,12 +645,6 @@ static struct clk_hw_onecell_data meson8b_hw_onecell_data = { .num = CLK_NR_CLKS, }; -static struct meson_clk_pll *const meson8b_clk_plls[] = { - &meson8b_fixed_pll, - &meson8b_vid_pll, - &meson8b_sys_pll, -}; - static struct clk_regmap *const meson8b_clk_regmaps[] = { &meson8b_clk81, &meson8b_ddr, @@ -703,6 +729,9 @@ static struct clk_regmap *const meson8b_clk_regmaps[] = { &meson8b_mpll0, &meson8b_mpll1, &meson8b_mpll2, + &meson8b_fixed_pll, + &meson8b_vid_pll, + &meson8b_sys_pll, }; static const struct meson8b_clk_reset_line { @@ -825,10 +854,6 @@ static int meson8b_clkc_probe(struct platform_device *pdev) if (IS_ERR(map)) return PTR_ERR(map); - /* Populate base address for PLLs */ - for (i = 0; i < ARRAY_SIZE(meson8b_clk_plls); i++) - meson8b_clk_plls[i]->base = clk_base; - /* Populate the base address for CPU clk */ meson8b_cpu_clk.base = clk_base; -- cgit From d610b54f77002bbddca54c10d9488c2faa7ff102 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Mon, 12 Feb 2018 15:58:43 +0100 Subject: clk: meson: split divider and gate part of mpll The mpll clock is a kind of fractional divider which can gate. When the RW operation have been added, enable/disable ops have been mistakenly inserted in this driver. These ops are essentially a poor copy/paste of the generic gate ops. This change removes the gate ops from the mpll driver and inserts a generic gate clock on each mpll divider, simplifying the mpll driver and reducing code duplication. Signed-off-by: Jerome Brunet Signed-off-by: Neil Armstrong --- drivers/clk/meson/axg.c | 100 +++++++++++++++++++++++++++++++------------ drivers/clk/meson/axg.h | 6 ++- drivers/clk/meson/clk-mpll.c | 44 ------------------- drivers/clk/meson/clkc.h | 1 - drivers/clk/meson/gxbb.c | 78 ++++++++++++++++++++++++--------- drivers/clk/meson/gxbb.h | 5 ++- drivers/clk/meson/meson8b.c | 75 +++++++++++++++++++++++--------- drivers/clk/meson/meson8b.h | 6 ++- 8 files changed, 197 insertions(+), 118 deletions(-) diff --git a/drivers/clk/meson/axg.c b/drivers/clk/meson/axg.c index 8c27ceffda4a..6813b632c1a9 100644 --- a/drivers/clk/meson/axg.c +++ b/drivers/clk/meson/axg.c @@ -296,7 +296,7 @@ static struct clk_fixed_factor axg_fclk_div7 = { }, }; -static struct clk_regmap axg_mpll0 = { +static struct clk_regmap axg_mpll0_div = { .data = &(struct meson_clk_mpll_data){ .sdm = { .reg_off = HHI_MPLL_CNTL7, @@ -313,11 +313,6 @@ static struct clk_regmap axg_mpll0 = { .shift = 16, .width = 9, }, - .en = { - .reg_off = HHI_MPLL_CNTL7, - .shift = 14, - .width = 1, - }, .ssen = { .reg_off = HHI_MPLL_CNTL, .shift = 25, @@ -331,14 +326,28 @@ static struct clk_regmap axg_mpll0 = { .lock = &meson_clk_lock, }, .hw.init = &(struct clk_init_data){ - .name = "mpll0", + .name = "mpll0_div", .ops = &meson_clk_mpll_ops, .parent_names = (const char *[]){ "fixed_pll" }, .num_parents = 1, }, }; -static struct clk_regmap axg_mpll1 = { +static struct clk_regmap axg_mpll0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL7, + .bit_idx = 14, + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll0", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "mpll0_div" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap axg_mpll1_div = { .data = &(struct meson_clk_mpll_data){ .sdm = { .reg_off = HHI_MPLL_CNTL8, @@ -355,11 +364,6 @@ static struct clk_regmap axg_mpll1 = { .shift = 16, .width = 9, }, - .en = { - .reg_off = HHI_MPLL_CNTL8, - .shift = 14, - .width = 1, - }, .misc = { .reg_off = HHI_PLL_TOP_MISC, .shift = 1, @@ -368,14 +372,28 @@ static struct clk_regmap axg_mpll1 = { .lock = &meson_clk_lock, }, .hw.init = &(struct clk_init_data){ - .name = "mpll1", + .name = "mpll1_div", .ops = &meson_clk_mpll_ops, .parent_names = (const char *[]){ "fixed_pll" }, .num_parents = 1, }, }; -static struct clk_regmap axg_mpll2 = { +static struct clk_regmap axg_mpll1 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL8, + .bit_idx = 14, + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll1", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "mpll1_div" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap axg_mpll2_div = { .data = &(struct meson_clk_mpll_data){ .sdm = { .reg_off = HHI_MPLL_CNTL9, @@ -392,11 +410,6 @@ static struct clk_regmap axg_mpll2 = { .shift = 16, .width = 9, }, - .en = { - .reg_off = HHI_MPLL_CNTL9, - .shift = 14, - .width = 1, - }, .misc = { .reg_off = HHI_PLL_TOP_MISC, .shift = 2, @@ -405,14 +418,28 @@ static struct clk_regmap axg_mpll2 = { .lock = &meson_clk_lock, }, .hw.init = &(struct clk_init_data){ - .name = "mpll2", + .name = "mpll2_div", .ops = &meson_clk_mpll_ops, .parent_names = (const char *[]){ "fixed_pll" }, .num_parents = 1, }, }; -static struct clk_regmap axg_mpll3 = { +static struct clk_regmap axg_mpll2 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL9, + .bit_idx = 14, + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll2", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "mpll2_div" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap axg_mpll3_div = { .data = &(struct meson_clk_mpll_data){ .sdm = { .reg_off = HHI_MPLL3_CNTL0, @@ -429,11 +456,6 @@ static struct clk_regmap axg_mpll3 = { .shift = 2, .width = 9, }, - .en = { - .reg_off = HHI_MPLL3_CNTL0, - .shift = 0, - .width = 1, - }, .misc = { .reg_off = HHI_PLL_TOP_MISC, .shift = 3, @@ -442,13 +464,27 @@ static struct clk_regmap axg_mpll3 = { .lock = &meson_clk_lock, }, .hw.init = &(struct clk_init_data){ - .name = "mpll3", + .name = "mpll3_div", .ops = &meson_clk_mpll_ops, .parent_names = (const char *[]){ "fixed_pll" }, .num_parents = 1, }, }; +static struct clk_regmap axg_mpll3 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL3_CNTL0, + .bit_idx = 0, + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll3", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "mpll3_div" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + static u32 mux_table_clk81[] = { 0, 2, 3, 4, 5, 6, 7 }; static const char * const clk81_parent_names[] = { "xtal", "fclk_div7", "mpll1", "mpll2", "fclk_div4", @@ -722,6 +758,10 @@ static struct clk_hw_onecell_data axg_hw_onecell_data = { [CLKID_SD_EMMC_C_CLK0_SEL] = &axg_sd_emmc_c_clk0_sel.hw, [CLKID_SD_EMMC_C_CLK0_DIV] = &axg_sd_emmc_c_clk0_div.hw, [CLKID_SD_EMMC_C_CLK0] = &axg_sd_emmc_c_clk0.hw, + [CLKID_MPLL0_DIV] = &axg_mpll0_div.hw, + [CLKID_MPLL1_DIV] = &axg_mpll1_div.hw, + [CLKID_MPLL2_DIV] = &axg_mpll2_div.hw, + [CLKID_MPLL3_DIV] = &axg_mpll3_div.hw, [NR_CLKS] = NULL, }, .num = NR_CLKS, @@ -786,6 +826,10 @@ static struct clk_regmap *const axg_clk_regmaps[] = { &axg_mpll1, &axg_mpll2, &axg_mpll3, + &axg_mpll0_div, + &axg_mpll1_div, + &axg_mpll2_div, + &axg_mpll3_div, &axg_fixed_pll, &axg_sys_pll, &axg_gp0_pll, diff --git a/drivers/clk/meson/axg.h b/drivers/clk/meson/axg.h index ce0bafdb6b28..4c1502a8b8c9 100644 --- a/drivers/clk/meson/axg.h +++ b/drivers/clk/meson/axg.h @@ -117,8 +117,12 @@ #define CLKID_SD_EMMC_B_CLK0_DIV 62 #define CLKID_SD_EMMC_C_CLK0_SEL 63 #define CLKID_SD_EMMC_C_CLK0_DIV 64 +#define CLKID_MPLL0_DIV 65 +#define CLKID_MPLL1_DIV 66 +#define CLKID_MPLL2_DIV 67 +#define CLKID_MPLL3_DIV 68 -#define NR_CLKS 65 +#define NR_CLKS 69 /* include the CLKIDs that have been made part of the DT binding */ #include diff --git a/drivers/clk/meson/clk-mpll.c b/drivers/clk/meson/clk-mpll.c index 66998ff47635..0df1227b65b3 100644 --- a/drivers/clk/meson/clk-mpll.c +++ b/drivers/clk/meson/clk-mpll.c @@ -170,57 +170,13 @@ static int mpll_set_rate(struct clk_hw *hw, return 0; } -static void mpll_enable_core(struct clk_hw *hw, int enable) -{ - struct clk_regmap *clk = to_clk_regmap(hw); - struct meson_clk_mpll_data *mpll = meson_clk_mpll_data(clk); - unsigned long flags = 0; - - if (mpll->lock) - spin_lock_irqsave(mpll->lock, flags); - else - __acquire(mpll->lock); - - meson_parm_write(clk->map, &mpll->en, enable ? 1 : 0); - - 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 clk_regmap *clk = to_clk_regmap(hw); - struct meson_clk_mpll_data *mpll = meson_clk_mpll_data(clk); - - return meson_parm_read(clk->map, &mpll->en); -} - const struct clk_ops meson_clk_mpll_ro_ops = { .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 f0d70eaffcf3..cc1a964cd4d7 100644 --- a/drivers/clk/meson/clkc.h +++ b/drivers/clk/meson/clkc.h @@ -116,7 +116,6 @@ struct meson_clk_mpll_data { struct parm sdm; struct parm sdm_en; struct parm n2; - struct parm en; struct parm ssen; struct parm misc; spinlock_t *lock; diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c index 49f5716ce8b6..5ab8338eb894 100644 --- a/drivers/clk/meson/gxbb.c +++ b/drivers/clk/meson/gxbb.c @@ -540,7 +540,7 @@ static struct clk_fixed_factor gxbb_fclk_div7 = { }, }; -static struct clk_regmap gxbb_mpll0 = { +static struct clk_regmap gxbb_mpll0_div = { .data = &(struct meson_clk_mpll_data){ .sdm = { .reg_off = HHI_MPLL_CNTL7, @@ -557,11 +557,6 @@ static struct clk_regmap gxbb_mpll0 = { .shift = 16, .width = 9, }, - .en = { - .reg_off = HHI_MPLL_CNTL7, - .shift = 14, - .width = 1, - }, .ssen = { .reg_off = HHI_MPLL_CNTL, .shift = 25, @@ -570,14 +565,28 @@ static struct clk_regmap gxbb_mpll0 = { .lock = &meson_clk_lock, }, .hw.init = &(struct clk_init_data){ - .name = "mpll0", + .name = "mpll0_div", .ops = &meson_clk_mpll_ops, .parent_names = (const char *[]){ "fixed_pll" }, .num_parents = 1, }, }; -static struct clk_regmap gxbb_mpll1 = { +static struct clk_regmap gxbb_mpll0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL7, + .bit_idx = 14, + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll0", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "mpll0_div" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap gxbb_mpll1_div = { .data = &(struct meson_clk_mpll_data){ .sdm = { .reg_off = HHI_MPLL_CNTL8, @@ -594,22 +603,31 @@ static struct clk_regmap gxbb_mpll1 = { .shift = 16, .width = 9, }, - .en = { - .reg_off = HHI_MPLL_CNTL8, - .shift = 14, - .width = 1, - }, .lock = &meson_clk_lock, }, .hw.init = &(struct clk_init_data){ - .name = "mpll1", + .name = "mpll1_div", .ops = &meson_clk_mpll_ops, .parent_names = (const char *[]){ "fixed_pll" }, .num_parents = 1, }, }; -static struct clk_regmap gxbb_mpll2 = { +static struct clk_regmap gxbb_mpll1 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL8, + .bit_idx = 14, + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll1", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "mpll1_div" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap gxbb_mpll2_div = { .data = &(struct meson_clk_mpll_data){ .sdm = { .reg_off = HHI_MPLL_CNTL9, @@ -626,21 +644,30 @@ static struct clk_regmap gxbb_mpll2 = { .shift = 16, .width = 9, }, - .en = { - .reg_off = HHI_MPLL_CNTL9, - .shift = 14, - .width = 1, - }, .lock = &meson_clk_lock, }, .hw.init = &(struct clk_init_data){ - .name = "mpll2", + .name = "mpll2_div", .ops = &meson_clk_mpll_ops, .parent_names = (const char *[]){ "fixed_pll" }, .num_parents = 1, }, }; +static struct clk_regmap gxbb_mpll2 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL9, + .bit_idx = 14, + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll2", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "mpll2_div" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + static u32 mux_table_clk81[] = { 0, 2, 3, 4, 5, 6, 7 }; static const char * const clk81_parent_names[] = { "xtal", "fclk_div7", "mpll1", "mpll2", "fclk_div4", @@ -1668,6 +1695,9 @@ static struct clk_hw_onecell_data gxbb_hw_onecell_data = { [CLKID_VAPB_SEL] = &gxbb_vapb_sel.hw, [CLKID_VAPB] = &gxbb_vapb.hw, [CLKID_HDMI_PLL_PRE_MULT] = &gxbb_hdmi_pll_pre_mult.hw, + [CLKID_MPLL0_DIV] = &gxbb_mpll0_div.hw, + [CLKID_MPLL1_DIV] = &gxbb_mpll1_div.hw, + [CLKID_MPLL2_DIV] = &gxbb_mpll2_div.hw, [NR_CLKS] = NULL, }, .num = NR_CLKS, @@ -1815,6 +1845,9 @@ static struct clk_hw_onecell_data gxl_hw_onecell_data = { [CLKID_VAPB_1] = &gxbb_vapb_1.hw, [CLKID_VAPB_SEL] = &gxbb_vapb_sel.hw, [CLKID_VAPB] = &gxbb_vapb.hw, + [CLKID_MPLL0_DIV] = &gxbb_mpll0_div.hw, + [CLKID_MPLL1_DIV] = &gxbb_mpll1_div.hw, + [CLKID_MPLL2_DIV] = &gxbb_mpll2_div.hw, [NR_CLKS] = NULL, }, .num = NR_CLKS, @@ -1961,6 +1994,9 @@ static struct clk_regmap *const gx_clk_regmaps[] = { &gxbb_mpll0, &gxbb_mpll1, &gxbb_mpll2, + &gxbb_mpll0_div, + &gxbb_mpll1_div, + &gxbb_mpll2_div, &gxbb_cts_amclk_div, &gxbb_fixed_pll, &gxbb_sys_pll, diff --git a/drivers/clk/meson/gxbb.h b/drivers/clk/meson/gxbb.h index 42573b28a137..a8e7b8884e95 100644 --- a/drivers/clk/meson/gxbb.h +++ b/drivers/clk/meson/gxbb.h @@ -195,8 +195,11 @@ #define CLKID_VAPB_0_DIV 134 #define CLKID_VAPB_1_DIV 137 #define CLKID_HDMI_PLL_PRE_MULT 141 +#define CLKID_MPLL0_DIV 142 +#define CLKID_MPLL1_DIV 143 +#define CLKID_MPLL2_DIV 144 -#define NR_CLKS 142 +#define NR_CLKS 145 /* include the CLKIDs that have been made part of the DT binding */ #include diff --git a/drivers/clk/meson/meson8b.c b/drivers/clk/meson/meson8b.c index 4fd8253c54bb..625d953511be 100644 --- a/drivers/clk/meson/meson8b.c +++ b/drivers/clk/meson/meson8b.c @@ -289,7 +289,7 @@ static struct clk_fixed_factor meson8b_fclk_div7 = { }, }; -static struct clk_regmap meson8b_mpll0 = { +static struct clk_regmap meson8b_mpll0_div = { .data = &(struct meson_clk_mpll_data){ .sdm = { .reg_off = HHI_MPLL_CNTL7, @@ -306,11 +306,6 @@ static struct clk_regmap meson8b_mpll0 = { .shift = 16, .width = 9, }, - .en = { - .reg_off = HHI_MPLL_CNTL7, - .shift = 14, - .width = 1, - }, .ssen = { .reg_off = HHI_MPLL_CNTL, .shift = 25, @@ -319,14 +314,28 @@ static struct clk_regmap meson8b_mpll0 = { .lock = &meson_clk_lock, }, .hw.init = &(struct clk_init_data){ - .name = "mpll0", + .name = "mpll0_div", .ops = &meson_clk_mpll_ops, .parent_names = (const char *[]){ "fixed_pll" }, .num_parents = 1, }, }; -static struct clk_regmap meson8b_mpll1 = { +static struct clk_regmap meson8b_mpll0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL7, + .bit_idx = 14, + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll0", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "mpll0_div" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_mpll1_div = { .data = &(struct meson_clk_mpll_data){ .sdm = { .reg_off = HHI_MPLL_CNTL8, @@ -343,22 +352,31 @@ static struct clk_regmap meson8b_mpll1 = { .shift = 16, .width = 9, }, - .en = { - .reg_off = HHI_MPLL_CNTL8, - .shift = 14, - .width = 1, - }, .lock = &meson_clk_lock, }, .hw.init = &(struct clk_init_data){ - .name = "mpll1", + .name = "mpll1_div", .ops = &meson_clk_mpll_ops, .parent_names = (const char *[]){ "fixed_pll" }, .num_parents = 1, }, }; -static struct clk_regmap meson8b_mpll2 = { +static struct clk_regmap meson8b_mpll1 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL8, + .bit_idx = 14, + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll1", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "mpll1_div" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_mpll2_div = { .data = &(struct meson_clk_mpll_data){ .sdm = { .reg_off = HHI_MPLL_CNTL9, @@ -375,21 +393,30 @@ static struct clk_regmap meson8b_mpll2 = { .shift = 16, .width = 9, }, - .en = { - .reg_off = HHI_MPLL_CNTL9, - .shift = 14, - .width = 1, - }, .lock = &meson_clk_lock, }, .hw.init = &(struct clk_init_data){ - .name = "mpll2", + .name = "mpll2_div", .ops = &meson_clk_mpll_ops, .parent_names = (const char *[]){ "fixed_pll" }, .num_parents = 1, }, }; +static struct clk_regmap meson8b_mpll2 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL9, + .bit_idx = 14, + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll2", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "mpll2_div" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + /* * 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 @@ -640,6 +667,9 @@ static struct clk_hw_onecell_data meson8b_hw_onecell_data = { [CLKID_MPLL0] = &meson8b_mpll0.hw, [CLKID_MPLL1] = &meson8b_mpll1.hw, [CLKID_MPLL2] = &meson8b_mpll2.hw, + [CLKID_MPLL0_DIV] = &meson8b_mpll0_div.hw, + [CLKID_MPLL1_DIV] = &meson8b_mpll1_div.hw, + [CLKID_MPLL2_DIV] = &meson8b_mpll2_div.hw, [CLK_NR_CLKS] = NULL, }, .num = CLK_NR_CLKS, @@ -729,6 +759,9 @@ static struct clk_regmap *const meson8b_clk_regmaps[] = { &meson8b_mpll0, &meson8b_mpll1, &meson8b_mpll2, + &meson8b_mpll0_div, + &meson8b_mpll1_div, + &meson8b_mpll2_div, &meson8b_fixed_pll, &meson8b_vid_pll, &meson8b_sys_pll, diff --git a/drivers/clk/meson/meson8b.h b/drivers/clk/meson/meson8b.h index 2eaf8a52e7dd..f2780508edec 100644 --- a/drivers/clk/meson/meson8b.h +++ b/drivers/clk/meson/meson8b.h @@ -69,7 +69,11 @@ * will remain defined here. */ -#define CLK_NR_CLKS 96 +#define CLKID_MPLL0_DIV 96 +#define CLKID_MPLL1_DIV 97 +#define CLKID_MPLL2_DIV 98 + +#define CLK_NR_CLKS 99 /* * include the CLKID and RESETID that have -- cgit From 251b6fd38bcb9c8fafdc67851d09fddb79efb049 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Mon, 12 Feb 2018 15:58:44 +0100 Subject: clk: meson: rework meson8b cpu clock Instead of migrating meson cpu_clk to clk_regmap, like the other meson clock drivers, we take advantage of the massive rework to get rid of it completely, and solve (the first part) of the related FIXME notice. As pointed out in the code comments, the cpu_clk should be modeled with dividers and muxes it is made of, instead of one big composite clock. The cpu_clk was not working correctly to enable dvfs on meson8b. It hangs quite often when changing the cpu clock rate. This new implementation, based on simple elements improves the situation but the platform will still hang from time to time. This is not acceptable so, until we can make the mechanism around the cpu clock stable, the cpu clock subtree has been put in read-only mode, preventing any change of the cpu clock The notifier and read-write operation will be added back when we have a solution to the problem. Cc: Martin Blumenstingl Signed-off-by: Jerome Brunet Signed-off-by: Neil Armstrong --- drivers/clk/meson/meson8b.c | 173 +++++++++++++++++++++++++++++--------------- drivers/clk/meson/meson8b.h | 7 +- 2 files changed, 119 insertions(+), 61 deletions(-) diff --git a/drivers/clk/meson/meson8b.c b/drivers/clk/meson/meson8b.c index 625d953511be..ea73b5de9672 100644 --- a/drivers/clk/meson/meson8b.c +++ b/drivers/clk/meson/meson8b.c @@ -99,20 +99,6 @@ static const struct pll_rate_table sys_pll_rate_table[] = { { /* sentinel */ }, }; -static const struct clk_div_table cpu_div_table[] = { - { .val = 1, .div = 1 }, - { .val = 2, .div = 2 }, - { .val = 3, .div = 3 }, - { .val = 2, .div = 4 }, - { .val = 3, .div = 6 }, - { .val = 4, .div = 8 }, - { .val = 5, .div = 10 }, - { .val = 6, .div = 12 }, - { .val = 7, .div = 14 }, - { .val = 8, .div = 16 }, - { /* sentinel */ }, -}; - static struct clk_fixed_rate meson8b_xtal = { .fixed_rate = 24000000, .hw.init = &(struct clk_init_data){ @@ -227,7 +213,7 @@ static struct clk_regmap meson8b_sys_pll = { }, .hw.init = &(struct clk_init_data){ .name = "sys_pll", - .ops = &meson_clk_pll_ops, + .ops = &meson_clk_pll_ro_ops, .parent_names = (const char *[]){ "xtal" }, .num_parents = 1, .flags = CLK_GET_RATE_NOCACHE, @@ -417,23 +403,6 @@ static struct clk_regmap meson8b_mpll2 = { }, }; -/* - * 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 - * forthcoming coordinated clock rates feature - */ -static struct meson_clk_cpu meson8b_cpu_clk = { - .reg_off = HHI_SYS_CPU_CLK_CNTL1, - .div_table = cpu_div_table, - .clk_nb.notifier_call = meson_clk_cpu_notifier_cb, - .hw.init = &(struct clk_init_data){ - .name = "cpu_clk", - .ops = &meson_clk_cpu_ops, - .parent_names = (const char *[]){ "sys_pll" }, - .num_parents = 1, - }, -}; - static u32 mux_table_clk81[] = { 6, 5, 7 }; static struct clk_regmap meson8b_mpeg_clk_sel = { .data = &(struct clk_regmap_mux_data){ @@ -486,6 +455,108 @@ struct clk_regmap meson8b_clk81 = { }, }; +struct clk_regmap meson8b_cpu_in_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_SYS_CPU_CLK_CNTL0, + .mask = 0x1, + .shift = 0, + }, + .hw.init = &(struct clk_init_data){ + .name = "cpu_in_sel", + .ops = &clk_regmap_mux_ro_ops, + .parent_names = (const char *[]){ "xtal", "sys_pll" }, + .num_parents = 2, + .flags = (CLK_SET_RATE_PARENT | + CLK_SET_RATE_NO_REPARENT), + }, +}; + +static struct clk_fixed_factor meson8b_cpu_div2 = { + .mult = 1, + .div = 2, + .hw.init = &(struct clk_init_data){ + .name = "cpu_div2", + .ops = &clk_fixed_factor_ops, + .parent_names = (const char *[]){ "cpu_in_sel" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_fixed_factor meson8b_cpu_div3 = { + .mult = 1, + .div = 3, + .hw.init = &(struct clk_init_data){ + .name = "cpu_div3", + .ops = &clk_fixed_factor_ops, + .parent_names = (const char *[]){ "cpu_in_sel" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct clk_div_table cpu_scale_table[] = { + { .val = 2, .div = 4 }, + { .val = 3, .div = 6 }, + { .val = 4, .div = 8 }, + { .val = 5, .div = 10 }, + { .val = 6, .div = 12 }, + { .val = 7, .div = 14 }, + { .val = 8, .div = 16 }, + { /* sentinel */ }, +}; + +struct clk_regmap meson8b_cpu_scale_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_SYS_CPU_CLK_CNTL1, + .shift = 20, + .width = 9, + .table = cpu_scale_table, + .flags = CLK_DIVIDER_ALLOW_ZERO, + }, + .hw.init = &(struct clk_init_data){ + .name = "cpu_scale_div", + .ops = &clk_regmap_divider_ro_ops, + .parent_names = (const char *[]){ "cpu_in_sel" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +struct clk_regmap meson8b_cpu_scale_out_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_SYS_CPU_CLK_CNTL0, + .mask = 0x3, + .shift = 2, + }, + .hw.init = &(struct clk_init_data){ + .name = "cpu_scale_out_sel", + .ops = &clk_regmap_mux_ro_ops, + .parent_names = (const char *[]) { "cpu_in_sel", + "cpu_div2", + "cpu_div3", + "cpu_scale_div" }, + .num_parents = 4, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +struct clk_regmap meson8b_cpu_clk = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_SYS_CPU_CLK_CNTL0, + .mask = 0x1, + .shift = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "cpu_clk", + .ops = &clk_regmap_mux_ro_ops, + .parent_names = (const char *[]){ "xtal", "cpu_out_sel" }, + .num_parents = 2, + .flags = (CLK_SET_RATE_PARENT | + CLK_SET_RATE_NO_REPARENT), + }, +}; + /* Everything Else (EE) domain gates */ static MESON_GATE(meson8b_ddr, HHI_GCLK_MPEG0, 0); @@ -670,6 +741,11 @@ static struct clk_hw_onecell_data meson8b_hw_onecell_data = { [CLKID_MPLL0_DIV] = &meson8b_mpll0_div.hw, [CLKID_MPLL1_DIV] = &meson8b_mpll1_div.hw, [CLKID_MPLL2_DIV] = &meson8b_mpll2_div.hw, + [CLKID_CPU_IN_SEL] = &meson8b_cpu_in_sel.hw, + [CLKID_CPU_DIV2] = &meson8b_cpu_div2.hw, + [CLKID_CPU_DIV3] = &meson8b_cpu_div3.hw, + [CLKID_CPU_SCALE_DIV] = &meson8b_cpu_scale_div.hw, + [CLKID_CPU_SCALE_OUT_SEL] = &meson8b_cpu_scale_out_sel.hw, [CLK_NR_CLKS] = NULL, }, .num = CLK_NR_CLKS, @@ -765,6 +841,10 @@ static struct clk_regmap *const meson8b_clk_regmaps[] = { &meson8b_fixed_pll, &meson8b_vid_pll, &meson8b_sys_pll, + &meson8b_cpu_in_sel, + &meson8b_cpu_scale_div, + &meson8b_cpu_scale_out_sel, + &meson8b_cpu_clk, }; static const struct meson8b_clk_reset_line { @@ -875,8 +955,7 @@ static const struct regmap_config clkc_regmap_config = { static int meson8b_clkc_probe(struct platform_device *pdev) { int ret, i; - struct clk_hw *parent_hw; - struct clk *parent_clk; + struct clk *clk; struct device *dev = &pdev->dev; struct regmap *map; @@ -887,9 +966,6 @@ static int meson8b_clkc_probe(struct platform_device *pdev) if (IS_ERR(map)) return PTR_ERR(map); - /* Populate the base address for CPU clk */ - meson8b_cpu_clk.base = clk_base; - /* Populate regmap for the regmap backed clocks */ for (i = 0; i < ARRAY_SIZE(meson8b_clk_regmaps); i++) meson8b_clk_regmaps[i]->map = map; @@ -908,29 +984,6 @@ static int meson8b_clkc_probe(struct platform_device *pdev) return ret; } - /* - * Register CPU clk notifier - * - * FIXME this is wrong for a lot of reasons. First, the muxes should be - * struct clk_hw objects. Second, we shouldn't program the muxes in - * notifier handlers. The tricky programming sequence will be handled - * by the forthcoming coordinated clock rates mechanism once that - * feature is released. - * - * Furthermore, looking up the parent this way is terrible. At some - * point we will stop allocating a default struct clk when registering - * a new clk_hw, and this hack will no longer work. Releasing the ccr - * feature before that time solves the problem :-) - */ - parent_hw = clk_hw_get_parent(&meson8b_cpu_clk.hw); - parent_clk = parent_hw->clk; - ret = clk_notifier_register(parent_clk, &meson8b_cpu_clk.clk_nb); - if (ret) { - pr_err("%s: failed to register clock notifier for cpu_clk\n", - __func__); - return ret; - } - return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, &meson8b_hw_onecell_data); } diff --git a/drivers/clk/meson/meson8b.h b/drivers/clk/meson/meson8b.h index f2780508edec..73dae83d9932 100644 --- a/drivers/clk/meson/meson8b.h +++ b/drivers/clk/meson/meson8b.h @@ -72,8 +72,13 @@ #define CLKID_MPLL0_DIV 96 #define CLKID_MPLL1_DIV 97 #define CLKID_MPLL2_DIV 98 +#define CLKID_CPU_IN_SEL 99 +#define CLKID_CPU_DIV2 100 +#define CLKID_CPU_DIV3 101 +#define CLKID_CPU_SCALE_DIV 102 +#define CLKID_CPU_SCALE_OUT_SEL 103 -#define CLK_NR_CLKS 99 +#define CLK_NR_CLKS 104 /* * include the CLKID and RESETID that have -- cgit From 03a6519e9cd4d04f1ec2b0cb77d4ebbf7680c3a5 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Mon, 12 Feb 2018 15:58:45 +0100 Subject: clk: meson: remove obsolete cpu_clk meson8b cpu_clk has been replaced by a set of divider and mux clocks. meson_cpu_clk is no longer used and can be removed Acked-by: Martin Blumenstingl Signed-off-by: Jerome Brunet Signed-off-by: Neil Armstrong --- drivers/clk/meson/Makefile | 2 +- drivers/clk/meson/clk-cpu.c | 178 -------------------------------------------- drivers/clk/meson/clkc.h | 11 --- 3 files changed, 1 insertion(+), 190 deletions(-) delete mode 100644 drivers/clk/meson/clk-cpu.c diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile index 465086118d62..ffee82e60b7a 100644 --- a/drivers/clk/meson/Makefile +++ b/drivers/clk/meson/Makefile @@ -2,7 +2,7 @@ # Makefile for Meson specific clk # -obj-$(CONFIG_COMMON_CLK_AMLOGIC) += clk-pll.o clk-cpu.o clk-mpll.o clk-audio-divider.o +obj-$(CONFIG_COMMON_CLK_AMLOGIC) += clk-pll.o clk-mpll.o clk-audio-divider.o obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b.o obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o gxbb-aoclk-32k.o obj-$(CONFIG_COMMON_CLK_AXG) += axg.o diff --git a/drivers/clk/meson/clk-cpu.c b/drivers/clk/meson/clk-cpu.c deleted file mode 100644 index f8b2b7efd016..000000000000 --- a/drivers/clk/meson/clk-cpu.c +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright (c) 2015 Endless Mobile, Inc. - * Author: Carlo Caione - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - */ - -/* - * CPU clock path: - * - * +-[/N]-----|3| - * MUX2 +--[/3]-+----------|2| MUX1 - * [sys_pll]---|1| |--[/2]------------|1|-|1| - * | |---+------------------|0| | |----- [a5_clk] - * +--|0| | | - * [xtal]---+-------------------------------|0| - * - * - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#define MESON_CPU_CLK_CNTL1 0x00 -#define MESON_CPU_CLK_CNTL 0x40 - -#define MESON_CPU_CLK_MUX1 BIT(7) -#define MESON_CPU_CLK_MUX2 BIT(0) - -#define MESON_N_WIDTH 9 -#define MESON_N_SHIFT 20 -#define MESON_SEL_WIDTH 2 -#define MESON_SEL_SHIFT 2 - -#include "clkc.h" - -#define to_meson_clk_cpu_hw(_hw) container_of(_hw, struct meson_clk_cpu, hw) -#define to_meson_clk_cpu_nb(_nb) container_of(_nb, struct meson_clk_cpu, clk_nb) - -static long meson_clk_cpu_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) -{ - struct meson_clk_cpu *clk_cpu = to_meson_clk_cpu_hw(hw); - - return divider_round_rate(hw, rate, prate, clk_cpu->div_table, - MESON_N_WIDTH, CLK_DIVIDER_ROUND_CLOSEST); -} - -static int meson_clk_cpu_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate) -{ - struct meson_clk_cpu *clk_cpu = to_meson_clk_cpu_hw(hw); - unsigned int div, sel, N = 0; - u32 reg; - - div = DIV_ROUND_UP(parent_rate, rate); - - if (div <= 3) { - sel = div - 1; - } else { - sel = 3; - N = div / 2; - } - - reg = readl(clk_cpu->base + clk_cpu->reg_off + MESON_CPU_CLK_CNTL1); - reg = PARM_SET(MESON_N_WIDTH, MESON_N_SHIFT, reg, N); - writel(reg, clk_cpu->base + clk_cpu->reg_off + MESON_CPU_CLK_CNTL1); - - reg = readl(clk_cpu->base + clk_cpu->reg_off + MESON_CPU_CLK_CNTL); - reg = PARM_SET(MESON_SEL_WIDTH, MESON_SEL_SHIFT, reg, sel); - writel(reg, clk_cpu->base + clk_cpu->reg_off + MESON_CPU_CLK_CNTL); - - return 0; -} - -static unsigned long meson_clk_cpu_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) -{ - struct meson_clk_cpu *clk_cpu = to_meson_clk_cpu_hw(hw); - unsigned int N, sel; - unsigned int div = 1; - u32 reg; - - reg = readl(clk_cpu->base + clk_cpu->reg_off + MESON_CPU_CLK_CNTL1); - N = PARM_GET(MESON_N_WIDTH, MESON_N_SHIFT, reg); - - reg = readl(clk_cpu->base + clk_cpu->reg_off + MESON_CPU_CLK_CNTL); - sel = PARM_GET(MESON_SEL_WIDTH, MESON_SEL_SHIFT, reg); - - if (sel < 3) - div = sel + 1; - else - div = 2 * N; - - return parent_rate / div; -} - -/* FIXME MUX1 & MUX2 should be struct clk_hw objects */ -static int meson_clk_cpu_pre_rate_change(struct meson_clk_cpu *clk_cpu, - struct clk_notifier_data *ndata) -{ - u32 cpu_clk_cntl; - - /* switch MUX1 to xtal */ - cpu_clk_cntl = readl(clk_cpu->base + clk_cpu->reg_off - + MESON_CPU_CLK_CNTL); - cpu_clk_cntl &= ~MESON_CPU_CLK_MUX1; - writel(cpu_clk_cntl, clk_cpu->base + clk_cpu->reg_off - + MESON_CPU_CLK_CNTL); - udelay(100); - - /* switch MUX2 to sys-pll */ - cpu_clk_cntl |= MESON_CPU_CLK_MUX2; - writel(cpu_clk_cntl, clk_cpu->base + clk_cpu->reg_off - + MESON_CPU_CLK_CNTL); - - return 0; -} - -/* FIXME MUX1 & MUX2 should be struct clk_hw objects */ -static int meson_clk_cpu_post_rate_change(struct meson_clk_cpu *clk_cpu, - struct clk_notifier_data *ndata) -{ - u32 cpu_clk_cntl; - - /* switch MUX1 to divisors' output */ - cpu_clk_cntl = readl(clk_cpu->base + clk_cpu->reg_off - + MESON_CPU_CLK_CNTL); - cpu_clk_cntl |= MESON_CPU_CLK_MUX1; - writel(cpu_clk_cntl, clk_cpu->base + clk_cpu->reg_off - + MESON_CPU_CLK_CNTL); - udelay(100); - - return 0; -} - -/* - * This clock notifier is called when the frequency of the of the parent - * PLL clock is to be changed. We use the xtal input as temporary parent - * while the PLL frequency is stabilized. - */ -int meson_clk_cpu_notifier_cb(struct notifier_block *nb, - unsigned long event, void *data) -{ - struct clk_notifier_data *ndata = data; - struct meson_clk_cpu *clk_cpu = to_meson_clk_cpu_nb(nb); - int ret = 0; - - if (event == PRE_RATE_CHANGE) - ret = meson_clk_cpu_pre_rate_change(clk_cpu, ndata); - else if (event == POST_RATE_CHANGE) - ret = meson_clk_cpu_post_rate_change(clk_cpu, ndata); - - return notifier_from_errno(ret); -} - -const struct clk_ops meson_clk_cpu_ops = { - .recalc_rate = meson_clk_cpu_recalc_rate, - .round_rate = meson_clk_cpu_round_rate, - .set_rate = meson_clk_cpu_set_rate, -}; diff --git a/drivers/clk/meson/clkc.h b/drivers/clk/meson/clkc.h index cc1a964cd4d7..8d8fe608cff4 100644 --- a/drivers/clk/meson/clkc.h +++ b/drivers/clk/meson/clkc.h @@ -101,17 +101,6 @@ struct meson_clk_pll_data { #define to_meson_clk_pll(_hw) container_of(_hw, struct meson_clk_pll, hw) -struct meson_clk_cpu { - struct clk_hw hw; - void __iomem *base; - u16 reg_off; - struct notifier_block clk_nb; - const struct clk_div_table *div_table; -}; - -int meson_clk_cpu_notifier_cb(struct notifier_block *nb, unsigned long event, - void *data); - struct meson_clk_mpll_data { struct parm sdm; struct parm sdm_en; -- cgit From 4162dd5b3a17f2bf20abbaa7229028e7bc021523 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Mon, 12 Feb 2018 15:58:46 +0100 Subject: clk: meson: use hhi syscon if available On gxbb and axg, try to get the hhi regmap from the parent DT node, which should be the HHI system controller once the necessary changes have been made in amlogic's DTs Until then, if getting regmap through the system controller fails, the clock controller will fall back to the old way, requesting memory region directly and then registering the regmap itself. This should allow a smooth transition to syscon Signed-off-by: Jerome Brunet Signed-off-by: Neil Armstrong --- drivers/clk/meson/Kconfig | 2 ++ drivers/clk/meson/axg.c | 43 ++++++++++++++++++++++++++++++------------- drivers/clk/meson/gxbb.c | 39 ++++++++++++++++++++++++++++----------- 3 files changed, 60 insertions(+), 24 deletions(-) diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig index 936afddae406..d5cbec522aec 100644 --- a/drivers/clk/meson/Kconfig +++ b/drivers/clk/meson/Kconfig @@ -22,6 +22,7 @@ config COMMON_CLK_GXBB depends on COMMON_CLK_AMLOGIC select RESET_CONTROLLER select COMMON_CLK_REGMAP_MESON + select MFD_SYSCON help Support for the clock controller on AmLogic S905 devices, aka gxbb. Say Y if you want peripherals and CPU frequency scaling to work. @@ -31,6 +32,7 @@ config COMMON_CLK_AXG depends on COMMON_CLK_AMLOGIC select RESET_CONTROLLER select COMMON_CLK_REGMAP_MESON + select MFD_SYSCON help Support for the clock controller on AmLogic A113D devices, aka axg. Say Y if you want peripherals and CPU frequency scaling to work. diff --git a/drivers/clk/meson/axg.c b/drivers/clk/meson/axg.c index 6813b632c1a9..acb63c8e0fd8 100644 --- a/drivers/clk/meson/axg.c +++ b/drivers/clk/meson/axg.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -850,25 +851,41 @@ static int axg_clkc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct resource *res; - void __iomem *clk_base; + void __iomem *clk_base = NULL; struct regmap *map; int ret, i; - /* Generic clocks and PLLs */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -EINVAL; + /* Get the hhi system controller node if available */ + map = syscon_node_to_regmap(of_get_parent(dev->of_node)); + if (IS_ERR(map)) { + dev_err(dev, + "failed to get HHI regmap - Trying obsolete regs\n"); + + /* + * FIXME: HHI registers should be accessed through + * the appropriate system controller. This is required because + * there is more than just clocks in this register space + * + * This fallback method is only provided temporarily until + * all the platform DTs are properly using the syscon node + */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -EINVAL; + + + clk_base = devm_ioremap(dev, res->start, resource_size(res)); + if (!clk_base) { + dev_err(dev, "Unable to map clk base\n"); + return -ENXIO; + } - clk_base = devm_ioremap(dev, res->start, resource_size(res)); - if (!clk_base) { - dev_err(dev, "Unable to map clk base\n"); - return -ENXIO; + map = devm_regmap_init_mmio(dev, clk_base, + &clkc_regmap_config); + if (IS_ERR(map)) + return PTR_ERR(map); } - map = devm_regmap_init_mmio(dev, clk_base, &clkc_regmap_config); - if (IS_ERR(map)) - return PTR_ERR(map); - /* Populate regmap for the regmap backed clocks */ for (i = 0; i < ARRAY_SIZE(axg_clk_regmaps); i++) axg_clk_regmaps[i]->map = map; diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c index 5ab8338eb894..bb0b0529ca81 100644 --- a/drivers/clk/meson/gxbb.c +++ b/drivers/clk/meson/gxbb.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -2045,19 +2046,35 @@ static int gxbb_clkc_probe(struct platform_device *pdev) if (!clkc_data) return -EINVAL; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -EINVAL; + /* Get the hhi system controller node if available */ + map = syscon_node_to_regmap(of_get_parent(dev->of_node)); + if (IS_ERR(map)) { + dev_err(dev, + "failed to get HHI regmap - Trying obsolete regs\n"); - clk_base = devm_ioremap(dev, res->start, resource_size(res)); - if (!clk_base) { - pr_err("%s: Unable to map clk base\n", __func__); - return -ENXIO; - } + /* + * FIXME: HHI registers should be accessed through + * the appropriate system controller. This is required because + * there is more than just clocks in this register space + * + * This fallback method is only provided temporarily until + * all the platform DTs are properly using the syscon node + */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -EINVAL; + + clk_base = devm_ioremap(dev, res->start, resource_size(res)); + if (!clk_base) { + dev_err(dev, "Unable to map clk base\n"); + return -ENXIO; + } - map = devm_regmap_init_mmio(dev, clk_base, &clkc_regmap_config); - if (IS_ERR(map)) - return PTR_ERR(map); + map = devm_regmap_init_mmio(dev, clk_base, + &clkc_regmap_config); + if (IS_ERR(map)) + return PTR_ERR(map); + } /* Populate regmap for the common regmap backed clocks */ for (i = 0; i < ARRAY_SIZE(gx_clk_regmaps); i++) -- cgit From 2eab2d7cab2804f767b84cbdd06d291214d61df4 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Mon, 19 Feb 2018 12:21:36 +0100 Subject: clk: meson: add fractional part of meson8b fixed_pll Add the missing frac parameter to the meson8b fixed_pll. It seems to be always on this platform, so the rate remains unchanged Signed-off-by: Jerome Brunet Signed-off-by: Neil Armstrong --- drivers/clk/meson/meson8b.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/clk/meson/meson8b.c b/drivers/clk/meson/meson8b.c index ea73b5de9672..62c54a75a1d2 100644 --- a/drivers/clk/meson/meson8b.c +++ b/drivers/clk/meson/meson8b.c @@ -125,6 +125,11 @@ static struct clk_regmap meson8b_fixed_pll = { .shift = 16, .width = 2, }, + .frac = { + .reg_off = HHI_MPLL_CNTL2, + .shift = 0, + .width = 12, + }, .l = { .reg_off = HHI_MPLL_CNTL, .shift = 31, -- cgit From 117863e8424791e310f299072080d7b745dbec83 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Mon, 19 Feb 2018 12:21:37 +0100 Subject: clk: meson: poke pll CNTL last Poking CNTL first may take the PLL out of reset while we are still applying the initial settings, including the filter values initialization. This is the case for the axg and gxl gp0 pll. Doing this poke last ensures the pll stays in reset while the initial settings are applied. Signed-off-by: Jerome Brunet Signed-off-by: Neil Armstrong --- drivers/clk/meson/axg.c | 2 +- drivers/clk/meson/gxbb.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/clk/meson/axg.c b/drivers/clk/meson/axg.c index acb63c8e0fd8..8226b82c67fd 100644 --- a/drivers/clk/meson/axg.c +++ b/drivers/clk/meson/axg.c @@ -193,12 +193,12 @@ static const struct pll_rate_table axg_gp0_pll_rate_table[] = { }; const struct reg_sequence axg_gp0_init_regs[] = { - { .reg = HHI_GP0_PLL_CNTL, .def = 0x40010250 }, { .reg = HHI_GP0_PLL_CNTL1, .def = 0xc084a000 }, { .reg = HHI_GP0_PLL_CNTL2, .def = 0xb75020be }, { .reg = HHI_GP0_PLL_CNTL3, .def = 0x0a59a288 }, { .reg = HHI_GP0_PLL_CNTL4, .def = 0xc000004d }, { .reg = HHI_GP0_PLL_CNTL5, .def = 0x00078000 }, + { .reg = HHI_GP0_PLL_CNTL, .def = 0x40010250 }, }; static struct clk_regmap axg_gp0_pll = { diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c index bb0b0529ca81..3cd07f960489 100644 --- a/drivers/clk/meson/gxbb.c +++ b/drivers/clk/meson/gxbb.c @@ -390,10 +390,10 @@ static struct clk_regmap gxbb_sys_pll = { }; const struct reg_sequence gxbb_gp0_init_regs[] = { - { .reg = HHI_GP0_PLL_CNTL, .def = 0x6a000228 }, { .reg = HHI_GP0_PLL_CNTL2, .def = 0x69c80000 }, { .reg = HHI_GP0_PLL_CNTL3, .def = 0x0a5590c4 }, { .reg = HHI_GP0_PLL_CNTL4, .def = 0x0000500d }, + { .reg = HHI_GP0_PLL_CNTL, .def = 0x4a000228 }, }; static struct clk_regmap gxbb_gp0_pll = { @@ -437,12 +437,12 @@ static struct clk_regmap gxbb_gp0_pll = { }; const struct reg_sequence gxl_gp0_init_regs[] = { - { .reg = HHI_GP0_PLL_CNTL, .def = 0x40010250 }, { .reg = HHI_GP0_PLL_CNTL1, .def = 0xc084a000 }, { .reg = HHI_GP0_PLL_CNTL2, .def = 0xb75020be }, { .reg = HHI_GP0_PLL_CNTL3, .def = 0x0a59a288 }, { .reg = HHI_GP0_PLL_CNTL4, .def = 0xc000004d }, { .reg = HHI_GP0_PLL_CNTL5, .def = 0x00078000 }, + { .reg = HHI_GP0_PLL_CNTL, .def = 0x40010250 }, }; static struct clk_regmap gxl_gp0_pll = { -- cgit From c178b003bfcfde5a973c6ba6a45ca60fb1470fc6 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Mon, 19 Feb 2018 12:21:38 +0100 Subject: clk: meson: remove special gp0 lock loop After testing, it appears that the gxl (and axg) does not require the special locking/reset loop which was initially added for it. All the values present in the gxl table can locked with the simple lock checking loop. The change switches the gxl and axg gp0 back to the simple lock checking loop and removes the code no longer required. Signed-off-by: Jerome Brunet Signed-off-by: Neil Armstrong --- drivers/clk/meson/axg.c | 1 - drivers/clk/meson/clk-pll.c | 12 +----------- drivers/clk/meson/clkc.h | 2 -- drivers/clk/meson/gxbb.c | 1 - 4 files changed, 1 insertion(+), 15 deletions(-) diff --git a/drivers/clk/meson/axg.c b/drivers/clk/meson/axg.c index 8226b82c67fd..4f13929cd594 100644 --- a/drivers/clk/meson/axg.c +++ b/drivers/clk/meson/axg.c @@ -231,7 +231,6 @@ static struct clk_regmap axg_gp0_pll = { .table = axg_gp0_pll_rate_table, .init_regs = axg_gp0_init_regs, .init_count = ARRAY_SIZE(axg_gp0_init_regs), - .flags = CLK_MESON_PLL_LOCK_LOOP_RST, }, .hw.init = &(struct clk_init_data){ .name = "gp0_pll", diff --git a/drivers/clk/meson/clk-pll.c b/drivers/clk/meson/clk-pll.c index f3d909719111..0b9b4422c968 100644 --- a/drivers/clk/meson/clk-pll.c +++ b/drivers/clk/meson/clk-pll.c @@ -121,19 +121,9 @@ static int meson_clk_pll_wait_lock(struct clk_hw *hw) { struct clk_regmap *clk = to_clk_regmap(hw); struct meson_clk_pll_data *pll = meson_clk_pll_data(clk); - int delay = pll->flags & CLK_MESON_PLL_LOCK_LOOP_RST ? - 100 : 24000000; + int delay = 24000000; do { - /* Specific wait loop for GXL/GXM GP0 PLL */ - if (pll->flags & CLK_MESON_PLL_LOCK_LOOP_RST) { - /* Procedure taken from the vendor kernel */ - meson_parm_write(clk->map, &pll->rst, 1); - udelay(10); - meson_parm_write(clk->map, &pll->rst, 0); - mdelay(1); - } - /* Is the clock locked now ? */ if (meson_parm_read(clk->map, &pll->l)) return 0; diff --git a/drivers/clk/meson/clkc.h b/drivers/clk/meson/clkc.h index 8d8fe608cff4..ebd88afe1eb5 100644 --- a/drivers/clk/meson/clkc.h +++ b/drivers/clk/meson/clkc.h @@ -82,8 +82,6 @@ struct pll_rate_table { .frac = (_frac), \ } \ -#define CLK_MESON_PLL_LOCK_LOOP_RST BIT(0) - struct meson_clk_pll_data { struct parm m; struct parm n; diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c index 3cd07f960489..ac48eef0f490 100644 --- a/drivers/clk/meson/gxbb.c +++ b/drivers/clk/meson/gxbb.c @@ -475,7 +475,6 @@ static struct clk_regmap gxl_gp0_pll = { .table = gxl_gp0_pll_rate_table, .init_regs = gxl_gp0_init_regs, .init_count = ARRAY_SIZE(gxl_gp0_init_regs), - .flags = CLK_MESON_PLL_LOCK_LOOP_RST, }, .hw.init = &(struct clk_init_data){ .name = "gp0_pll", -- cgit From 8289aafa4f361050b05f77a35d3167259530a473 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Mon, 19 Feb 2018 12:21:39 +0100 Subject: clk: meson: improve pll driver results with frac Finding the appropriate settings of meson plls is too tricky to be done entirely at runtime, using calculation only. Many combination of m, n and od won't lock which is why we are using a table for this. However, for plls having a fractional parameters, it is possible to improve on the result provided by the table by calculating the frac parameter. This change adds the calculation of frac when the parameter is available and the rate provided by the table is not an exact match for the requested rate. Signed-off-by: Jerome Brunet Signed-off-by: Neil Armstrong --- drivers/clk/meson/clk-pll.c | 137 +++++++++++++++++++++++++++++--------------- drivers/clk/meson/clkc.h | 13 +---- 2 files changed, 91 insertions(+), 59 deletions(-) diff --git a/drivers/clk/meson/clk-pll.c b/drivers/clk/meson/clk-pll.c index 0b9b4422c968..d58961f35b71 100644 --- a/drivers/clk/meson/clk-pll.c +++ b/drivers/clk/meson/clk-pll.c @@ -2,6 +2,9 @@ * Copyright (c) 2015 Endless Mobile, Inc. * Author: Carlo Caione * + * Copyright (c) 2018 Baylibre, SAS. + * Author: Jerome Brunet + * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. @@ -27,7 +30,7 @@ * | | * FREF VCO * - * out = (in * M / N) >> OD + * out = in * (m + frac / frac_max) / (n << sum(ods)) */ #include @@ -48,73 +51,110 @@ meson_clk_pll_data(struct clk_regmap *clk) return (struct meson_clk_pll_data *)clk->data; } +static unsigned long __pll_params_to_rate(unsigned long parent_rate, + const struct pll_rate_table *pllt, + u16 frac, + struct meson_clk_pll_data *pll) +{ + u64 rate = (u64)parent_rate * pllt->m; + unsigned int od = pllt->od + pllt->od2 + pllt->od3; + + if (frac && MESON_PARM_APPLICABLE(&pll->frac)) { + u64 frac_rate = (u64)parent_rate * frac; + + rate += DIV_ROUND_UP_ULL(frac_rate, + (1 << pll->frac.width)); + } + + return DIV_ROUND_UP_ULL(rate, pllt->n << od); +} + static unsigned long meson_clk_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { struct clk_regmap *clk = to_clk_regmap(hw); struct meson_clk_pll_data *pll = meson_clk_pll_data(clk); - u64 rate; - u16 n, m, frac = 0, od, od2 = 0, od3 = 0; - - n = meson_parm_read(clk->map, &pll->n); - m = meson_parm_read(clk->map, &pll->m); - od = meson_parm_read(clk->map, &pll->od); - - if (MESON_PARM_APPLICABLE(&pll->od2)) - od2 = meson_parm_read(clk->map, &pll->od2); + struct pll_rate_table pllt; + u16 frac; - if (MESON_PARM_APPLICABLE(&pll->od3)) - od3 = meson_parm_read(clk->map, &pll->od3); + pllt.n = meson_parm_read(clk->map, &pll->n); + pllt.m = meson_parm_read(clk->map, &pll->m); + pllt.od = meson_parm_read(clk->map, &pll->od); - rate = (u64)m * parent_rate; + pllt.od2 = MESON_PARM_APPLICABLE(&pll->od2) ? + meson_parm_read(clk->map, &pll->od2) : + 0; - if (MESON_PARM_APPLICABLE(&pll->frac)) { - frac = meson_parm_read(clk->map, &pll->frac); + pllt.od3 = MESON_PARM_APPLICABLE(&pll->od3) ? + meson_parm_read(clk->map, &pll->od3) : + 0; - rate += mul_u64_u32_shr(parent_rate, frac, pll->frac.width); - } + frac = MESON_PARM_APPLICABLE(&pll->frac) ? + meson_parm_read(clk->map, &pll->frac) : + 0; - return div_u64(rate, n) >> od >> od2 >> od3; + return __pll_params_to_rate(parent_rate, &pllt, frac, pll); } -static long meson_clk_pll_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static u16 __pll_params_with_frac(unsigned long rate, + unsigned long parent_rate, + const struct pll_rate_table *pllt, + struct meson_clk_pll_data *pll) { - struct clk_regmap *clk = to_clk_regmap(hw); - struct meson_clk_pll_data *pll = meson_clk_pll_data(clk); - const struct pll_rate_table *pllt; - - /* - * if the table is missing, just return the current rate - * since we don't have the other available frequencies - */ - if (!pll->table) - return meson_clk_pll_recalc_rate(hw, *parent_rate); + u16 frac_max = (1 << pll->frac.width); + u64 val = (u64)rate * pllt->n; - for (pllt = pll->table; pllt->rate; pllt++) { - if (rate <= pllt->rate) - return pllt->rate; - } + val <<= pllt->od + pllt->od2 + pllt->od3; + val = div_u64(val * frac_max, parent_rate); + val -= pllt->m * frac_max; - /* else return the smallest value */ - return pll->table[0].rate; + return min((u16)val, (u16)(frac_max - 1)); } static const struct pll_rate_table * -meson_clk_get_pll_settings(const struct pll_rate_table *table, - unsigned long rate) +meson_clk_get_pll_settings(unsigned long rate, + struct meson_clk_pll_data *pll) { - const struct pll_rate_table *pllt; + const struct pll_rate_table *table = pll->table; + unsigned int i = 0; if (!table) return NULL; - for (pllt = table; pllt->rate; pllt++) { - if (rate == pllt->rate) - return pllt; - } + /* Find the first table element exceeding rate */ + while (table[i].rate && table[i].rate <= rate) + i++; + + /* Select the setting of the rounded down rate */ + if (i != 0) + i--; + + return (struct pll_rate_table *)&table[i]; +} + +static long meson_clk_pll_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_clk_pll_data *pll = meson_clk_pll_data(clk); + const struct pll_rate_table *pllt = + meson_clk_get_pll_settings(rate, pll); + u16 frac; + + if (!pllt) + return meson_clk_pll_recalc_rate(hw, *parent_rate); + + if (!MESON_PARM_APPLICABLE(&pll->frac) + || rate == pllt->rate) + return pllt->rate; - return NULL; + /* + * The rate provided by the setting is not an exact match, let's + * try to improve the result using the fractional parameter + */ + frac = __pll_params_with_frac(rate, *parent_rate, pllt, pll); + + return __pll_params_to_rate(*parent_rate, pllt, frac, pll); } static int meson_clk_pll_wait_lock(struct clk_hw *hw) @@ -154,13 +194,14 @@ static int meson_clk_pll_set_rate(struct clk_hw *hw, unsigned long rate, struct meson_clk_pll_data *pll = meson_clk_pll_data(clk); const struct pll_rate_table *pllt; unsigned long old_rate; + u16 frac = 0; if (parent_rate == 0 || rate == 0) return -EINVAL; old_rate = rate; - pllt = meson_clk_get_pll_settings(pll->table, rate); + pllt = meson_clk_get_pll_settings(rate, pll); if (!pllt) return -EINVAL; @@ -177,8 +218,10 @@ static int meson_clk_pll_set_rate(struct clk_hw *hw, unsigned long rate, if (MESON_PARM_APPLICABLE(&pll->od3)) meson_parm_write(clk->map, &pll->od3, pllt->od3); - if (MESON_PARM_APPLICABLE(&pll->frac)) - meson_parm_write(clk->map, &pll->frac, pllt->frac); + if (MESON_PARM_APPLICABLE(&pll->frac)) { + frac = __pll_params_with_frac(rate, parent_rate, pllt, pll); + meson_parm_write(clk->map, &pll->frac, frac); + } /* make sure the reset is cleared at this point */ meson_parm_write(clk->map, &pll->rst, 0); diff --git a/drivers/clk/meson/clkc.h b/drivers/clk/meson/clkc.h index ebd88afe1eb5..9cdcd9b6c16c 100644 --- a/drivers/clk/meson/clkc.h +++ b/drivers/clk/meson/clkc.h @@ -61,7 +61,6 @@ struct pll_rate_table { u16 od; u16 od2; u16 od3; - u16 frac; }; #define PLL_RATE(_r, _m, _n, _od) \ @@ -70,17 +69,7 @@ struct pll_rate_table { .m = (_m), \ .n = (_n), \ .od = (_od), \ - } \ - -#define PLL_FRAC_RATE(_r, _m, _n, _od, _od2, _frac) \ - { \ - .rate = (_r), \ - .m = (_m), \ - .n = (_n), \ - .od = (_od), \ - .od2 = (_od2), \ - .frac = (_frac), \ - } \ + } struct meson_clk_pll_data { struct parm m; -- cgit From c77de0e5c95a249fd2d4105dbc619f436ec96345 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Mon, 19 Feb 2018 12:21:40 +0100 Subject: clk: meson: add gp0 frac parameter for axg and gxl Add the frac parameter for the gp0 pll of the axg and gxl. This allows to achieve rates between the fixed settings provided by the table. Signed-off-by: Jerome Brunet Signed-off-by: Neil Armstrong --- drivers/clk/meson/axg.c | 7 ++++++- drivers/clk/meson/gxbb.c | 7 ++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/clk/meson/axg.c b/drivers/clk/meson/axg.c index 4f13929cd594..892572a2d70f 100644 --- a/drivers/clk/meson/axg.c +++ b/drivers/clk/meson/axg.c @@ -193,7 +193,7 @@ static const struct pll_rate_table axg_gp0_pll_rate_table[] = { }; const struct reg_sequence axg_gp0_init_regs[] = { - { .reg = HHI_GP0_PLL_CNTL1, .def = 0xc084a000 }, + { .reg = HHI_GP0_PLL_CNTL1, .def = 0xc084b000 }, { .reg = HHI_GP0_PLL_CNTL2, .def = 0xb75020be }, { .reg = HHI_GP0_PLL_CNTL3, .def = 0x0a59a288 }, { .reg = HHI_GP0_PLL_CNTL4, .def = 0xc000004d }, @@ -218,6 +218,11 @@ static struct clk_regmap axg_gp0_pll = { .shift = 16, .width = 2, }, + .frac = { + .reg_off = HHI_GP0_PLL_CNTL1, + .shift = 0, + .width = 10, + }, .l = { .reg_off = HHI_GP0_PLL_CNTL, .shift = 31, diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c index ac48eef0f490..fdeb372863de 100644 --- a/drivers/clk/meson/gxbb.c +++ b/drivers/clk/meson/gxbb.c @@ -437,7 +437,7 @@ static struct clk_regmap gxbb_gp0_pll = { }; const struct reg_sequence gxl_gp0_init_regs[] = { - { .reg = HHI_GP0_PLL_CNTL1, .def = 0xc084a000 }, + { .reg = HHI_GP0_PLL_CNTL1, .def = 0xc084b000 }, { .reg = HHI_GP0_PLL_CNTL2, .def = 0xb75020be }, { .reg = HHI_GP0_PLL_CNTL3, .def = 0x0a59a288 }, { .reg = HHI_GP0_PLL_CNTL4, .def = 0xc000004d }, @@ -462,6 +462,11 @@ static struct clk_regmap gxl_gp0_pll = { .shift = 16, .width = 2, }, + .frac = { + .reg_off = HHI_GP0_PLL_CNTL1, + .shift = 0, + .width = 10, + }, .l = { .reg_off = HHI_GP0_PLL_CNTL, .shift = 31, -- cgit From 0a1be867b92a5afb93bce62e12ef76b7c2b777fd Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Mon, 19 Feb 2018 12:21:41 +0100 Subject: clk: meson: add ROUND_CLOSEST to the pll driver Provide an option for the pll driver to round to the rate closest to the requested rate, instead of systematically rounding down. This may allow the provided rate to be closer to the requested rate when rounding up is not an issue Signed-off-by: Jerome Brunet Signed-off-by: Neil Armstrong --- drivers/clk/meson/clk-pll.c | 17 +++++++++++++---- drivers/clk/meson/clkc.h | 2 ++ 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/drivers/clk/meson/clk-pll.c b/drivers/clk/meson/clk-pll.c index d58961f35b71..65a7bd903551 100644 --- a/drivers/clk/meson/clk-pll.c +++ b/drivers/clk/meson/clk-pll.c @@ -105,7 +105,12 @@ static u16 __pll_params_with_frac(unsigned long rate, u64 val = (u64)rate * pllt->n; val <<= pllt->od + pllt->od2 + pllt->od3; - val = div_u64(val * frac_max, parent_rate); + + if (pll->flags & CLK_MESON_PLL_ROUND_CLOSEST) + val = DIV_ROUND_CLOSEST_ULL(val * frac_max, parent_rate); + else + val = div_u64(val * frac_max, parent_rate); + val -= pllt->m * frac_max; return min((u16)val, (u16)(frac_max - 1)); @@ -125,9 +130,13 @@ meson_clk_get_pll_settings(unsigned long rate, while (table[i].rate && table[i].rate <= rate) i++; - /* Select the setting of the rounded down rate */ - if (i != 0) - i--; + if (i != 0) { + if (MESON_PARM_APPLICABLE(&pll->frac) || + !(pll->flags & CLK_MESON_PLL_ROUND_CLOSEST) || + (abs(rate - table[i - 1].rate) < + abs(rate - table[i].rate))) + i--; + } return (struct pll_rate_table *)&table[i]; } diff --git a/drivers/clk/meson/clkc.h b/drivers/clk/meson/clkc.h index 9cdcd9b6c16c..8fe73c4edca8 100644 --- a/drivers/clk/meson/clkc.h +++ b/drivers/clk/meson/clkc.h @@ -71,6 +71,8 @@ struct pll_rate_table { .od = (_od), \ } +#define CLK_MESON_PLL_ROUND_CLOSEST BIT(0) + struct meson_clk_pll_data { struct parm m; struct parm n; -- cgit From a4fb7df25de26d12feec4e96687121ec28480a71 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Mon, 19 Feb 2018 12:21:42 +0100 Subject: clk: meson: axg: add hifi clock bindings Add the new HIFI pll to axg clock bindings Signed-off-by: Jerome Brunet Signed-off-by: Neil Armstrong --- include/dt-bindings/clock/axg-clkc.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/dt-bindings/clock/axg-clkc.h b/include/dt-bindings/clock/axg-clkc.h index 941ac70e7f30..555937a25504 100644 --- a/include/dt-bindings/clock/axg-clkc.h +++ b/include/dt-bindings/clock/axg-clkc.h @@ -67,5 +67,6 @@ #define CLKID_AO_I2C 58 #define CLKID_SD_EMMC_B_CLK0 59 #define CLKID_SD_EMMC_C_CLK0 60 +#define CLKID_HIFI_PLL 69 #endif /* __AXG_CLKC_H */ -- cgit From 093c3fac4619d267136dc4cb87b916c692fa07db Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Mon, 19 Feb 2018 12:21:43 +0100 Subject: clk: meson: axg: add hifi pll clock Add the hifi pll to the axg clock controller. This clock maybe used as an input of the axg audio clock controller. It uses the same settings table as the gp0 pll but has a frac parameter allowing more precision. Signed-off-by: Jerome Brunet Signed-off-by: Neil Armstrong --- drivers/clk/meson/axg.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++++ drivers/clk/meson/axg.h | 2 +- 2 files changed, 56 insertions(+), 1 deletion(-) diff --git a/drivers/clk/meson/axg.c b/drivers/clk/meson/axg.c index 892572a2d70f..ed4a645753c4 100644 --- a/drivers/clk/meson/axg.c +++ b/drivers/clk/meson/axg.c @@ -245,6 +245,59 @@ static struct clk_regmap axg_gp0_pll = { }, }; +const struct reg_sequence axg_hifi_init_regs[] = { + { .reg = HHI_HIFI_PLL_CNTL1, .def = 0xc084b000 }, + { .reg = HHI_HIFI_PLL_CNTL2, .def = 0xb75020be }, + { .reg = HHI_HIFI_PLL_CNTL3, .def = 0x0a6a3a88 }, + { .reg = HHI_HIFI_PLL_CNTL4, .def = 0xc000004d }, + { .reg = HHI_HIFI_PLL_CNTL5, .def = 0x00058000 }, + { .reg = HHI_HIFI_PLL_CNTL, .def = 0x40010250 }, +}; + +static struct clk_regmap axg_hifi_pll = { + .data = &(struct meson_clk_pll_data){ + .m = { + .reg_off = HHI_HIFI_PLL_CNTL, + .shift = 0, + .width = 9, + }, + .n = { + .reg_off = HHI_HIFI_PLL_CNTL, + .shift = 9, + .width = 5, + }, + .od = { + .reg_off = HHI_HIFI_PLL_CNTL, + .shift = 16, + .width = 2, + }, + .frac = { + .reg_off = HHI_HIFI_PLL_CNTL5, + .shift = 0, + .width = 13, + }, + .l = { + .reg_off = HHI_HIFI_PLL_CNTL, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = HHI_HIFI_PLL_CNTL, + .shift = 29, + .width = 1, + }, + .table = axg_gp0_pll_rate_table, + .init_regs = axg_hifi_init_regs, + .init_count = ARRAY_SIZE(axg_hifi_init_regs), + .flags = CLK_MESON_PLL_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "hifi_pll", + .ops = &meson_clk_pll_ops, + .parent_names = (const char *[]){ "xtal" }, + .num_parents = 1, + }, +}; static struct clk_fixed_factor axg_fclk_div2 = { .mult = 1, @@ -767,6 +820,7 @@ static struct clk_hw_onecell_data axg_hw_onecell_data = { [CLKID_MPLL1_DIV] = &axg_mpll1_div.hw, [CLKID_MPLL2_DIV] = &axg_mpll2_div.hw, [CLKID_MPLL3_DIV] = &axg_mpll3_div.hw, + [CLKID_HIFI_PLL] = &axg_hifi_pll.hw, [NR_CLKS] = NULL, }, .num = NR_CLKS, @@ -838,6 +892,7 @@ static struct clk_regmap *const axg_clk_regmaps[] = { &axg_fixed_pll, &axg_sys_pll, &axg_gp0_pll, + &axg_hifi_pll, }; static const struct of_device_id clkc_match_table[] = { diff --git a/drivers/clk/meson/axg.h b/drivers/clk/meson/axg.h index 4c1502a8b8c9..4916c7045c48 100644 --- a/drivers/clk/meson/axg.h +++ b/drivers/clk/meson/axg.h @@ -122,7 +122,7 @@ #define CLKID_MPLL2_DIV 67 #define CLKID_MPLL3_DIV 68 -#define NR_CLKS 69 +#define NR_CLKS 70 /* include the CLKIDs that have been made part of the DT binding */ #include -- cgit From 513b67ac39b0ef91761d94d1d6e31bb84e380744 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Mon, 19 Feb 2018 12:21:44 +0100 Subject: clk: meson: add mpll pre-divider mpll clocks parent can actually be divided by 1 or 2. So far, this divider has always been set to 1, so the calculation was correct. Now that we know it exists, model the tree correctly. If we ever get a platform where the divider is different, we won't get into trouble Signed-off-by: Jerome Brunet Signed-off-by: Neil Armstrong --- drivers/clk/meson/axg.c | 24 ++++++++++++++++++++---- drivers/clk/meson/axg.h | 3 ++- drivers/clk/meson/gxbb.c | 23 ++++++++++++++++++++--- drivers/clk/meson/gxbb.h | 3 ++- drivers/clk/meson/meson8b.c | 22 +++++++++++++++++++--- drivers/clk/meson/meson8b.h | 3 ++- 6 files changed, 65 insertions(+), 13 deletions(-) diff --git a/drivers/clk/meson/axg.c b/drivers/clk/meson/axg.c index ed4a645753c4..2989087fb52d 100644 --- a/drivers/clk/meson/axg.c +++ b/drivers/clk/meson/axg.c @@ -354,6 +354,20 @@ static struct clk_fixed_factor axg_fclk_div7 = { }, }; +static struct clk_regmap axg_mpll_prediv = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_MPLL_CNTL5, + .shift = 12, + .width = 1, + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll_prediv", + .ops = &clk_regmap_divider_ro_ops, + .parent_names = (const char *[]){ "fixed_pll" }, + .num_parents = 1, + }, +}; + static struct clk_regmap axg_mpll0_div = { .data = &(struct meson_clk_mpll_data){ .sdm = { @@ -386,7 +400,7 @@ static struct clk_regmap axg_mpll0_div = { .hw.init = &(struct clk_init_data){ .name = "mpll0_div", .ops = &meson_clk_mpll_ops, - .parent_names = (const char *[]){ "fixed_pll" }, + .parent_names = (const char *[]){ "mpll_prediv" }, .num_parents = 1, }, }; @@ -432,7 +446,7 @@ static struct clk_regmap axg_mpll1_div = { .hw.init = &(struct clk_init_data){ .name = "mpll1_div", .ops = &meson_clk_mpll_ops, - .parent_names = (const char *[]){ "fixed_pll" }, + .parent_names = (const char *[]){ "mpll_prediv" }, .num_parents = 1, }, }; @@ -478,7 +492,7 @@ static struct clk_regmap axg_mpll2_div = { .hw.init = &(struct clk_init_data){ .name = "mpll2_div", .ops = &meson_clk_mpll_ops, - .parent_names = (const char *[]){ "fixed_pll" }, + .parent_names = (const char *[]){ "mpll_prediv" }, .num_parents = 1, }, }; @@ -524,7 +538,7 @@ static struct clk_regmap axg_mpll3_div = { .hw.init = &(struct clk_init_data){ .name = "mpll3_div", .ops = &meson_clk_mpll_ops, - .parent_names = (const char *[]){ "fixed_pll" }, + .parent_names = (const char *[]){ "mpll_prediv" }, .num_parents = 1, }, }; @@ -821,6 +835,7 @@ static struct clk_hw_onecell_data axg_hw_onecell_data = { [CLKID_MPLL2_DIV] = &axg_mpll2_div.hw, [CLKID_MPLL3_DIV] = &axg_mpll3_div.hw, [CLKID_HIFI_PLL] = &axg_hifi_pll.hw, + [CLKID_MPLL_PREDIV] = &axg_mpll_prediv.hw, [NR_CLKS] = NULL, }, .num = NR_CLKS, @@ -893,6 +908,7 @@ static struct clk_regmap *const axg_clk_regmaps[] = { &axg_sys_pll, &axg_gp0_pll, &axg_hifi_pll, + &axg_mpll_prediv, }; static const struct of_device_id clkc_match_table[] = { diff --git a/drivers/clk/meson/axg.h b/drivers/clk/meson/axg.h index 4916c7045c48..6e5dc65041b5 100644 --- a/drivers/clk/meson/axg.h +++ b/drivers/clk/meson/axg.h @@ -121,8 +121,9 @@ #define CLKID_MPLL1_DIV 66 #define CLKID_MPLL2_DIV 67 #define CLKID_MPLL3_DIV 68 +#define CLKID_MPLL_PREDIV 70 -#define NR_CLKS 70 +#define NR_CLKS 71 /* include the CLKIDs that have been made part of the DT binding */ #include diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c index fdeb372863de..b62d181a6d33 100644 --- a/drivers/clk/meson/gxbb.c +++ b/drivers/clk/meson/gxbb.c @@ -545,6 +545,20 @@ static struct clk_fixed_factor gxbb_fclk_div7 = { }, }; +static struct clk_regmap gxbb_mpll_prediv = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_MPLL_CNTL5, + .shift = 12, + .width = 1, + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll_prediv", + .ops = &clk_regmap_divider_ro_ops, + .parent_names = (const char *[]){ "fixed_pll" }, + .num_parents = 1, + }, +}; + static struct clk_regmap gxbb_mpll0_div = { .data = &(struct meson_clk_mpll_data){ .sdm = { @@ -572,7 +586,7 @@ static struct clk_regmap gxbb_mpll0_div = { .hw.init = &(struct clk_init_data){ .name = "mpll0_div", .ops = &meson_clk_mpll_ops, - .parent_names = (const char *[]){ "fixed_pll" }, + .parent_names = (const char *[]){ "mpll_prediv" }, .num_parents = 1, }, }; @@ -613,7 +627,7 @@ static struct clk_regmap gxbb_mpll1_div = { .hw.init = &(struct clk_init_data){ .name = "mpll1_div", .ops = &meson_clk_mpll_ops, - .parent_names = (const char *[]){ "fixed_pll" }, + .parent_names = (const char *[]){ "mpll_prediv" }, .num_parents = 1, }, }; @@ -654,7 +668,7 @@ static struct clk_regmap gxbb_mpll2_div = { .hw.init = &(struct clk_init_data){ .name = "mpll2_div", .ops = &meson_clk_mpll_ops, - .parent_names = (const char *[]){ "fixed_pll" }, + .parent_names = (const char *[]){ "mpll_prediv" }, .num_parents = 1, }, }; @@ -1703,6 +1717,7 @@ static struct clk_hw_onecell_data gxbb_hw_onecell_data = { [CLKID_MPLL0_DIV] = &gxbb_mpll0_div.hw, [CLKID_MPLL1_DIV] = &gxbb_mpll1_div.hw, [CLKID_MPLL2_DIV] = &gxbb_mpll2_div.hw, + [CLKID_MPLL_PREDIV] = &gxbb_mpll_prediv.hw, [NR_CLKS] = NULL, }, .num = NR_CLKS, @@ -1853,6 +1868,7 @@ static struct clk_hw_onecell_data gxl_hw_onecell_data = { [CLKID_MPLL0_DIV] = &gxbb_mpll0_div.hw, [CLKID_MPLL1_DIV] = &gxbb_mpll1_div.hw, [CLKID_MPLL2_DIV] = &gxbb_mpll2_div.hw, + [CLKID_MPLL_PREDIV] = &gxbb_mpll_prediv.hw, [NR_CLKS] = NULL, }, .num = NR_CLKS, @@ -2005,6 +2021,7 @@ static struct clk_regmap *const gx_clk_regmaps[] = { &gxbb_cts_amclk_div, &gxbb_fixed_pll, &gxbb_sys_pll, + &gxbb_mpll_prediv, }; struct clkc_data { diff --git a/drivers/clk/meson/gxbb.h b/drivers/clk/meson/gxbb.h index a8e7b8884e95..afae007ae1ec 100644 --- a/drivers/clk/meson/gxbb.h +++ b/drivers/clk/meson/gxbb.h @@ -198,8 +198,9 @@ #define CLKID_MPLL0_DIV 142 #define CLKID_MPLL1_DIV 143 #define CLKID_MPLL2_DIV 144 +#define CLKID_MPLL_PREDIV 145 -#define NR_CLKS 145 +#define NR_CLKS 146 /* include the CLKIDs that have been made part of the DT binding */ #include diff --git a/drivers/clk/meson/meson8b.c b/drivers/clk/meson/meson8b.c index 62c54a75a1d2..f8b2f23c49de 100644 --- a/drivers/clk/meson/meson8b.c +++ b/drivers/clk/meson/meson8b.c @@ -280,6 +280,20 @@ static struct clk_fixed_factor meson8b_fclk_div7 = { }, }; +static struct clk_regmap meson8b_mpll_prediv = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_MPLL_CNTL5, + .shift = 12, + .width = 1, + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll_prediv", + .ops = &clk_regmap_divider_ro_ops, + .parent_names = (const char *[]){ "fixed_pll" }, + .num_parents = 1, + }, +}; + static struct clk_regmap meson8b_mpll0_div = { .data = &(struct meson_clk_mpll_data){ .sdm = { @@ -307,7 +321,7 @@ static struct clk_regmap meson8b_mpll0_div = { .hw.init = &(struct clk_init_data){ .name = "mpll0_div", .ops = &meson_clk_mpll_ops, - .parent_names = (const char *[]){ "fixed_pll" }, + .parent_names = (const char *[]){ "mpll_prediv" }, .num_parents = 1, }, }; @@ -348,7 +362,7 @@ static struct clk_regmap meson8b_mpll1_div = { .hw.init = &(struct clk_init_data){ .name = "mpll1_div", .ops = &meson_clk_mpll_ops, - .parent_names = (const char *[]){ "fixed_pll" }, + .parent_names = (const char *[]){ "mpll_prediv" }, .num_parents = 1, }, }; @@ -389,7 +403,7 @@ static struct clk_regmap meson8b_mpll2_div = { .hw.init = &(struct clk_init_data){ .name = "mpll2_div", .ops = &meson_clk_mpll_ops, - .parent_names = (const char *[]){ "fixed_pll" }, + .parent_names = (const char *[]){ "mpll_prediv" }, .num_parents = 1, }, }; @@ -751,6 +765,7 @@ static struct clk_hw_onecell_data meson8b_hw_onecell_data = { [CLKID_CPU_DIV3] = &meson8b_cpu_div3.hw, [CLKID_CPU_SCALE_DIV] = &meson8b_cpu_scale_div.hw, [CLKID_CPU_SCALE_OUT_SEL] = &meson8b_cpu_scale_out_sel.hw, + [CLKID_MPLL_PREDIV] = &meson8b_mpll_prediv.hw, [CLK_NR_CLKS] = NULL, }, .num = CLK_NR_CLKS, @@ -850,6 +865,7 @@ static struct clk_regmap *const meson8b_clk_regmaps[] = { &meson8b_cpu_scale_div, &meson8b_cpu_scale_out_sel, &meson8b_cpu_clk, + &meson8b_mpll_prediv, }; static const struct meson8b_clk_reset_line { diff --git a/drivers/clk/meson/meson8b.h b/drivers/clk/meson/meson8b.h index 73dae83d9932..839ffc9da5f7 100644 --- a/drivers/clk/meson/meson8b.h +++ b/drivers/clk/meson/meson8b.h @@ -77,8 +77,9 @@ #define CLKID_CPU_DIV3 101 #define CLKID_CPU_SCALE_DIV 102 #define CLKID_CPU_SCALE_OUT_SEL 103 +#define CLKID_MPLL_PREDIV 104 -#define CLK_NR_CLKS 104 +#define CLK_NR_CLKS 105 /* * include the CLKID and RESETID that have -- cgit From 05f814402d6174369b3b29832cbb5eb5ed287059 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Mon, 19 Feb 2018 12:21:45 +0100 Subject: clk: meson: add fdiv clock gates Fdiv fixed dividers clocks of the fixed_pll can actually gate independently. We never had an issue so far because these clocks were provided 'enabled' by the bootloader. Add these gates to enable/disable the clocks when required. Signed-off-by: Jerome Brunet Signed-off-by: Neil Armstrong --- drivers/clk/meson/axg.c | 95 ++++++++++++++++++++++++++++++++++++----- drivers/clk/meson/axg.h | 7 +++- drivers/clk/meson/gxbb.c | 100 +++++++++++++++++++++++++++++++++++++++----- drivers/clk/meson/gxbb.h | 7 +++- drivers/clk/meson/meson8b.c | 95 ++++++++++++++++++++++++++++++++++++----- drivers/clk/meson/meson8b.h | 7 +++- 6 files changed, 278 insertions(+), 33 deletions(-) diff --git a/drivers/clk/meson/axg.c b/drivers/clk/meson/axg.c index 2989087fb52d..99b2738c204f 100644 --- a/drivers/clk/meson/axg.c +++ b/drivers/clk/meson/axg.c @@ -299,61 +299,126 @@ static struct clk_regmap axg_hifi_pll = { }, }; -static struct clk_fixed_factor axg_fclk_div2 = { +static struct clk_fixed_factor axg_fclk_div2_div = { .mult = 1, .div = 2, .hw.init = &(struct clk_init_data){ - .name = "fclk_div2", + .name = "fclk_div2_div", .ops = &clk_fixed_factor_ops, .parent_names = (const char *[]){ "fixed_pll" }, .num_parents = 1, }, }; -static struct clk_fixed_factor axg_fclk_div3 = { +static struct clk_regmap axg_fclk_div2 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL6, + .bit_idx = 27, + }, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div2", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "fclk_div2_div" }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor axg_fclk_div3_div = { .mult = 1, .div = 3, .hw.init = &(struct clk_init_data){ - .name = "fclk_div3", + .name = "fclk_div3_div", .ops = &clk_fixed_factor_ops, .parent_names = (const char *[]){ "fixed_pll" }, .num_parents = 1, }, }; -static struct clk_fixed_factor axg_fclk_div4 = { +static struct clk_regmap axg_fclk_div3 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL6, + .bit_idx = 28, + }, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div3", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "fclk_div3_div" }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor axg_fclk_div4_div = { .mult = 1, .div = 4, .hw.init = &(struct clk_init_data){ - .name = "fclk_div4", + .name = "fclk_div4_div", .ops = &clk_fixed_factor_ops, .parent_names = (const char *[]){ "fixed_pll" }, .num_parents = 1, }, }; -static struct clk_fixed_factor axg_fclk_div5 = { +static struct clk_regmap axg_fclk_div4 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL6, + .bit_idx = 29, + }, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div4", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "fclk_div4_div" }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor axg_fclk_div5_div = { .mult = 1, .div = 5, .hw.init = &(struct clk_init_data){ - .name = "fclk_div5", + .name = "fclk_div5_div", .ops = &clk_fixed_factor_ops, .parent_names = (const char *[]){ "fixed_pll" }, .num_parents = 1, }, }; -static struct clk_fixed_factor axg_fclk_div7 = { +static struct clk_regmap axg_fclk_div5 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL6, + .bit_idx = 30, + }, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div5", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "fclk_div5_div" }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor axg_fclk_div7_div = { .mult = 1, .div = 7, .hw.init = &(struct clk_init_data){ - .name = "fclk_div7", + .name = "fclk_div7_div", .ops = &clk_fixed_factor_ops, .parent_names = (const char *[]){ "fixed_pll" }, .num_parents = 1, }, }; +static struct clk_regmap axg_fclk_div7 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL6, + .bit_idx = 31, + }, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div7", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "fclk_div7_div" }, + .num_parents = 1, + }, +}; + static struct clk_regmap axg_mpll_prediv = { .data = &(struct clk_regmap_div_data){ .offset = HHI_MPLL_CNTL5, @@ -836,6 +901,11 @@ static struct clk_hw_onecell_data axg_hw_onecell_data = { [CLKID_MPLL3_DIV] = &axg_mpll3_div.hw, [CLKID_HIFI_PLL] = &axg_hifi_pll.hw, [CLKID_MPLL_PREDIV] = &axg_mpll_prediv.hw, + [CLKID_FCLK_DIV2_DIV] = &axg_fclk_div2_div.hw, + [CLKID_FCLK_DIV3_DIV] = &axg_fclk_div3_div.hw, + [CLKID_FCLK_DIV4_DIV] = &axg_fclk_div4_div.hw, + [CLKID_FCLK_DIV5_DIV] = &axg_fclk_div5_div.hw, + [CLKID_FCLK_DIV7_DIV] = &axg_fclk_div7_div.hw, [NR_CLKS] = NULL, }, .num = NR_CLKS, @@ -909,6 +979,11 @@ static struct clk_regmap *const axg_clk_regmaps[] = { &axg_gp0_pll, &axg_hifi_pll, &axg_mpll_prediv, + &axg_fclk_div2, + &axg_fclk_div3, + &axg_fclk_div4, + &axg_fclk_div5, + &axg_fclk_div7, }; static const struct of_device_id clkc_match_table[] = { diff --git a/drivers/clk/meson/axg.h b/drivers/clk/meson/axg.h index 6e5dc65041b5..b421df6a7ea0 100644 --- a/drivers/clk/meson/axg.h +++ b/drivers/clk/meson/axg.h @@ -122,8 +122,13 @@ #define CLKID_MPLL2_DIV 67 #define CLKID_MPLL3_DIV 68 #define CLKID_MPLL_PREDIV 70 +#define CLKID_FCLK_DIV2_DIV 71 +#define CLKID_FCLK_DIV3_DIV 72 +#define CLKID_FCLK_DIV4_DIV 73 +#define CLKID_FCLK_DIV5_DIV 74 +#define CLKID_FCLK_DIV7_DIV 75 -#define NR_CLKS 71 +#define NR_CLKS 76 /* include the CLKIDs that have been made part of the DT binding */ #include diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c index b62d181a6d33..70b4669cf7d6 100644 --- a/drivers/clk/meson/gxbb.c +++ b/drivers/clk/meson/gxbb.c @@ -490,61 +490,126 @@ static struct clk_regmap gxl_gp0_pll = { }, }; -static struct clk_fixed_factor gxbb_fclk_div2 = { +static struct clk_fixed_factor gxbb_fclk_div2_div = { .mult = 1, .div = 2, .hw.init = &(struct clk_init_data){ - .name = "fclk_div2", + .name = "fclk_div2_div", .ops = &clk_fixed_factor_ops, .parent_names = (const char *[]){ "fixed_pll" }, .num_parents = 1, }, }; -static struct clk_fixed_factor gxbb_fclk_div3 = { +static struct clk_regmap gxbb_fclk_div2 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL6, + .bit_idx = 27, + }, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div2", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "fclk_div2_div" }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor gxbb_fclk_div3_div = { .mult = 1, .div = 3, .hw.init = &(struct clk_init_data){ - .name = "fclk_div3", + .name = "fclk_div3_div", .ops = &clk_fixed_factor_ops, .parent_names = (const char *[]){ "fixed_pll" }, .num_parents = 1, }, }; -static struct clk_fixed_factor gxbb_fclk_div4 = { +static struct clk_regmap gxbb_fclk_div3 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL6, + .bit_idx = 28, + }, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div3", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "fclk_div3_div" }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor gxbb_fclk_div4_div = { .mult = 1, .div = 4, .hw.init = &(struct clk_init_data){ - .name = "fclk_div4", + .name = "fclk_div4_div", .ops = &clk_fixed_factor_ops, .parent_names = (const char *[]){ "fixed_pll" }, .num_parents = 1, }, }; -static struct clk_fixed_factor gxbb_fclk_div5 = { +static struct clk_regmap gxbb_fclk_div4 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL6, + .bit_idx = 29, + }, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div4", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "fclk_div4_div" }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor gxbb_fclk_div5_div = { .mult = 1, .div = 5, .hw.init = &(struct clk_init_data){ - .name = "fclk_div5", + .name = "fclk_div5_div", .ops = &clk_fixed_factor_ops, .parent_names = (const char *[]){ "fixed_pll" }, .num_parents = 1, }, }; -static struct clk_fixed_factor gxbb_fclk_div7 = { +static struct clk_regmap gxbb_fclk_div5 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL6, + .bit_idx = 30, + }, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div5", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "fclk_div5_div" }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor gxbb_fclk_div7_div = { .mult = 1, .div = 7, .hw.init = &(struct clk_init_data){ - .name = "fclk_div7", + .name = "fclk_div7_div", .ops = &clk_fixed_factor_ops, .parent_names = (const char *[]){ "fixed_pll" }, .num_parents = 1, }, }; +static struct clk_regmap gxbb_fclk_div7 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL6, + .bit_idx = 31, + }, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div7", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "fclk_div7_div" }, + .num_parents = 1, + }, +}; + static struct clk_regmap gxbb_mpll_prediv = { .data = &(struct clk_regmap_div_data){ .offset = HHI_MPLL_CNTL5, @@ -1718,6 +1783,11 @@ static struct clk_hw_onecell_data gxbb_hw_onecell_data = { [CLKID_MPLL1_DIV] = &gxbb_mpll1_div.hw, [CLKID_MPLL2_DIV] = &gxbb_mpll2_div.hw, [CLKID_MPLL_PREDIV] = &gxbb_mpll_prediv.hw, + [CLKID_FCLK_DIV2_DIV] = &gxbb_fclk_div2_div.hw, + [CLKID_FCLK_DIV3_DIV] = &gxbb_fclk_div3_div.hw, + [CLKID_FCLK_DIV4_DIV] = &gxbb_fclk_div4_div.hw, + [CLKID_FCLK_DIV5_DIV] = &gxbb_fclk_div5_div.hw, + [CLKID_FCLK_DIV7_DIV] = &gxbb_fclk_div7_div.hw, [NR_CLKS] = NULL, }, .num = NR_CLKS, @@ -1869,6 +1939,11 @@ static struct clk_hw_onecell_data gxl_hw_onecell_data = { [CLKID_MPLL1_DIV] = &gxbb_mpll1_div.hw, [CLKID_MPLL2_DIV] = &gxbb_mpll2_div.hw, [CLKID_MPLL_PREDIV] = &gxbb_mpll_prediv.hw, + [CLKID_FCLK_DIV2_DIV] = &gxbb_fclk_div2_div.hw, + [CLKID_FCLK_DIV3_DIV] = &gxbb_fclk_div3_div.hw, + [CLKID_FCLK_DIV4_DIV] = &gxbb_fclk_div4_div.hw, + [CLKID_FCLK_DIV5_DIV] = &gxbb_fclk_div5_div.hw, + [CLKID_FCLK_DIV7_DIV] = &gxbb_fclk_div7_div.hw, [NR_CLKS] = NULL, }, .num = NR_CLKS, @@ -2022,6 +2097,11 @@ static struct clk_regmap *const gx_clk_regmaps[] = { &gxbb_fixed_pll, &gxbb_sys_pll, &gxbb_mpll_prediv, + &gxbb_fclk_div2, + &gxbb_fclk_div3, + &gxbb_fclk_div4, + &gxbb_fclk_div5, + &gxbb_fclk_div7, }; struct clkc_data { diff --git a/drivers/clk/meson/gxbb.h b/drivers/clk/meson/gxbb.h index afae007ae1ec..9febf3f03739 100644 --- a/drivers/clk/meson/gxbb.h +++ b/drivers/clk/meson/gxbb.h @@ -199,8 +199,13 @@ #define CLKID_MPLL1_DIV 143 #define CLKID_MPLL2_DIV 144 #define CLKID_MPLL_PREDIV 145 +#define CLKID_FCLK_DIV2_DIV 146 +#define CLKID_FCLK_DIV3_DIV 147 +#define CLKID_FCLK_DIV4_DIV 148 +#define CLKID_FCLK_DIV5_DIV 149 +#define CLKID_FCLK_DIV7_DIV 150 -#define NR_CLKS 146 +#define NR_CLKS 151 /* include the CLKIDs that have been made part of the DT binding */ #include diff --git a/drivers/clk/meson/meson8b.c b/drivers/clk/meson/meson8b.c index f8b2f23c49de..9c9e3d180120 100644 --- a/drivers/clk/meson/meson8b.c +++ b/drivers/clk/meson/meson8b.c @@ -225,61 +225,126 @@ static struct clk_regmap meson8b_sys_pll = { }, }; -static struct clk_fixed_factor meson8b_fclk_div2 = { +static struct clk_fixed_factor meson8b_fclk_div2_div = { .mult = 1, .div = 2, .hw.init = &(struct clk_init_data){ - .name = "fclk_div2", + .name = "fclk_div2_div", .ops = &clk_fixed_factor_ops, .parent_names = (const char *[]){ "fixed_pll" }, .num_parents = 1, }, }; -static struct clk_fixed_factor meson8b_fclk_div3 = { +static struct clk_regmap meson8b_fclk_div2 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL6, + .bit_idx = 27, + }, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div2", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "fclk_div2_div" }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor meson8b_fclk_div3_div = { .mult = 1, .div = 3, .hw.init = &(struct clk_init_data){ - .name = "fclk_div3", + .name = "fclk_div_div3", .ops = &clk_fixed_factor_ops, .parent_names = (const char *[]){ "fixed_pll" }, .num_parents = 1, }, }; -static struct clk_fixed_factor meson8b_fclk_div4 = { +static struct clk_regmap meson8b_fclk_div3 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL6, + .bit_idx = 28, + }, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div3", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "fclk_div3_div" }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor meson8b_fclk_div4_div = { .mult = 1, .div = 4, .hw.init = &(struct clk_init_data){ - .name = "fclk_div4", + .name = "fclk_div4_div", .ops = &clk_fixed_factor_ops, .parent_names = (const char *[]){ "fixed_pll" }, .num_parents = 1, }, }; -static struct clk_fixed_factor meson8b_fclk_div5 = { +static struct clk_regmap meson8b_fclk_div4 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL6, + .bit_idx = 29, + }, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div4", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "fclk_div4_div" }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor meson8b_fclk_div5_div = { .mult = 1, .div = 5, .hw.init = &(struct clk_init_data){ - .name = "fclk_div5", + .name = "fclk_div5_div", .ops = &clk_fixed_factor_ops, .parent_names = (const char *[]){ "fixed_pll" }, .num_parents = 1, }, }; -static struct clk_fixed_factor meson8b_fclk_div7 = { +static struct clk_regmap meson8b_fclk_div5 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL6, + .bit_idx = 30, + }, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div5", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "fclk_div5_div" }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor meson8b_fclk_div7_div = { .mult = 1, .div = 7, .hw.init = &(struct clk_init_data){ - .name = "fclk_div7", + .name = "fclk_div7_div", .ops = &clk_fixed_factor_ops, .parent_names = (const char *[]){ "fixed_pll" }, .num_parents = 1, }, }; +static struct clk_regmap meson8b_fclk_div7 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL6, + .bit_idx = 31, + }, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div7", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "fclk_div7_div" }, + .num_parents = 1, + }, +}; + static struct clk_regmap meson8b_mpll_prediv = { .data = &(struct clk_regmap_div_data){ .offset = HHI_MPLL_CNTL5, @@ -766,6 +831,11 @@ static struct clk_hw_onecell_data meson8b_hw_onecell_data = { [CLKID_CPU_SCALE_DIV] = &meson8b_cpu_scale_div.hw, [CLKID_CPU_SCALE_OUT_SEL] = &meson8b_cpu_scale_out_sel.hw, [CLKID_MPLL_PREDIV] = &meson8b_mpll_prediv.hw, + [CLKID_FCLK_DIV2_DIV] = &meson8b_fclk_div2_div.hw, + [CLKID_FCLK_DIV3_DIV] = &meson8b_fclk_div3_div.hw, + [CLKID_FCLK_DIV4_DIV] = &meson8b_fclk_div4_div.hw, + [CLKID_FCLK_DIV5_DIV] = &meson8b_fclk_div5_div.hw, + [CLKID_FCLK_DIV7_DIV] = &meson8b_fclk_div7_div.hw, [CLK_NR_CLKS] = NULL, }, .num = CLK_NR_CLKS, @@ -866,6 +936,11 @@ static struct clk_regmap *const meson8b_clk_regmaps[] = { &meson8b_cpu_scale_out_sel, &meson8b_cpu_clk, &meson8b_mpll_prediv, + &meson8b_fclk_div2, + &meson8b_fclk_div3, + &meson8b_fclk_div4, + &meson8b_fclk_div5, + &meson8b_fclk_div7, }; static const struct meson8b_clk_reset_line { diff --git a/drivers/clk/meson/meson8b.h b/drivers/clk/meson/meson8b.h index 839ffc9da5f7..6e414bd36981 100644 --- a/drivers/clk/meson/meson8b.h +++ b/drivers/clk/meson/meson8b.h @@ -78,8 +78,13 @@ #define CLKID_CPU_SCALE_DIV 102 #define CLKID_CPU_SCALE_OUT_SEL 103 #define CLKID_MPLL_PREDIV 104 +#define CLKID_FCLK_DIV2_DIV 105 +#define CLKID_FCLK_DIV3_DIV 106 +#define CLKID_FCLK_DIV4_DIV 107 +#define CLKID_FCLK_DIV5_DIV 108 +#define CLKID_FCLK_DIV7_DIV 109 -#define CLK_NR_CLKS 105 +#define CLK_NR_CLKS 110 /* * include the CLKID and RESETID that have -- cgit From 5b13ef64eebdc9e989fac2a3eb9aaa252a3edda6 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Mon, 19 Feb 2018 12:21:46 +0100 Subject: clk: meson: clean-up clk81 clocks clk81 is a composite clock which parents all the peripheral clocks of the platform. It is a critical clock which is used as provided by the bootloader. We don't want to change its rate or reparent it, ever. Remove the CLK_IGNORE_UNUSED on the mux and divider. These clock can't gate so the flag is useless, and the gate is already critical, so the clock won't ever be unused. Remove CLK_SET_RATE_NO_REPARENT from mux, it is useless since the mux is read-only. Remove CLK_SET_RATE_PARENT from the gate and divider and use ro_ops for the divider. A peripheral clock should not try to change the rate of clk81. Stopping the rate propagation is good way to make sure such request would be ignored. Signed-off-by: Jerome Brunet Signed-off-by: Neil Armstrong --- drivers/clk/meson/gxbb.c | 6 ++---- drivers/clk/meson/meson8b.c | 6 ++---- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c index 70b4669cf7d6..db5e0dcbb5aa 100644 --- a/drivers/clk/meson/gxbb.c +++ b/drivers/clk/meson/gxbb.c @@ -775,7 +775,6 @@ static struct clk_regmap gxbb_mpeg_clk_sel = { */ .parent_names = clk81_parent_names, .num_parents = ARRAY_SIZE(clk81_parent_names), - .flags = (CLK_SET_RATE_NO_REPARENT | CLK_IGNORE_UNUSED), }, }; @@ -787,10 +786,9 @@ static struct clk_regmap gxbb_mpeg_clk_div = { }, .hw.init = &(struct clk_init_data){ .name = "mpeg_clk_div", - .ops = &clk_regmap_divider_ops, + .ops = &clk_regmap_divider_ro_ops, .parent_names = (const char *[]){ "mpeg_clk_sel" }, .num_parents = 1, - .flags = (CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED), }, }; @@ -805,7 +803,7 @@ static struct clk_regmap gxbb_clk81 = { .ops = &clk_regmap_gate_ops, .parent_names = (const char *[]){ "mpeg_clk_div" }, .num_parents = 1, - .flags = (CLK_SET_RATE_PARENT | CLK_IS_CRITICAL), + .flags = CLK_IS_CRITICAL, }, }; diff --git a/drivers/clk/meson/meson8b.c b/drivers/clk/meson/meson8b.c index 9c9e3d180120..b324c44d36eb 100644 --- a/drivers/clk/meson/meson8b.c +++ b/drivers/clk/meson/meson8b.c @@ -506,7 +506,6 @@ static struct clk_regmap meson8b_mpeg_clk_sel = { .parent_names = (const char *[]){ "fclk_div3", "fclk_div4", "fclk_div5" }, .num_parents = 3, - .flags = (CLK_SET_RATE_NO_REPARENT | CLK_IGNORE_UNUSED), }, }; @@ -518,10 +517,9 @@ struct clk_regmap meson8b_mpeg_clk_div = { }, .hw.init = &(struct clk_init_data){ .name = "mpeg_clk_div", - .ops = &clk_regmap_divider_ops, + .ops = &clk_regmap_divider_ro_ops, .parent_names = (const char *[]){ "mpeg_clk_sel" }, .num_parents = 1, - .flags = (CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED), }, }; @@ -535,7 +533,7 @@ struct clk_regmap meson8b_clk81 = { .ops = &clk_regmap_gate_ops, .parent_names = (const char *[]){ "mpeg_clk_div" }, .num_parents = 1, - .flags = (CLK_SET_RATE_PARENT | CLK_IS_CRITICAL), + .flags = CLK_IS_CRITICAL, }, }; -- cgit From 60cf09e45fbcbbbb3162f02e0923a25ae7f5627e Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Fri, 9 Mar 2018 09:51:03 +0800 Subject: clk: rockchip: Restore the clock phase after the rate was changed There are many factors affecting the clock phase, including clock rate, temperature, logic voltage and silicon process, etc. But clock rate is the most significant one here, and the driver should be aware of the change of the clock rate. As mmc controller need a fixed phase after tuning was completed, at least before explicitly doing re-tune, so this patch try to restore the clock phase by monitoring the event of rate change. Signed-off-by: Shawn Lin Signed-off-by: Heiko Stuebner --- drivers/clk/rockchip/clk-mmc-phase.c | 39 +++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/drivers/clk/rockchip/clk-mmc-phase.c b/drivers/clk/rockchip/clk-mmc-phase.c index fe7d9ed1d436..dc4c227732bd 100644 --- a/drivers/clk/rockchip/clk-mmc-phase.c +++ b/drivers/clk/rockchip/clk-mmc-phase.c @@ -25,6 +25,8 @@ struct rockchip_mmc_clock { void __iomem *reg; int id; int shift; + int cached_phase; + struct notifier_block clk_rate_change_nb; }; #define to_mmc_clock(_hw) container_of(_hw, struct rockchip_mmc_clock, hw) @@ -162,6 +164,29 @@ static const struct clk_ops rockchip_mmc_clk_ops = { .set_phase = rockchip_mmc_set_phase, }; +#define to_rockchip_mmc_clock(x) \ + container_of(x, struct rockchip_mmc_clock, clk_rate_change_nb) +static int rockchip_mmc_clk_rate_notify(struct notifier_block *nb, + unsigned long event, void *data) +{ + struct rockchip_mmc_clock *mmc_clock = to_rockchip_mmc_clock(nb); + + /* + * rockchip_mmc_clk is mostly used by mmc controllers to sample + * the intput data, which expects the fixed phase after the tuning + * process. However if the clock rate is changed, the phase is stale + * and may break the data sampling. So here we try to restore the phase + * for that case. + */ + if (event == PRE_RATE_CHANGE) + mmc_clock->cached_phase = + rockchip_mmc_get_phase(&mmc_clock->hw); + else if (event == POST_RATE_CHANGE) + rockchip_mmc_set_phase(&mmc_clock->hw, mmc_clock->cached_phase); + + return NOTIFY_DONE; +} + struct clk *rockchip_clk_register_mmc(const char *name, const char *const *parent_names, u8 num_parents, void __iomem *reg, int shift) @@ -169,6 +194,7 @@ struct clk *rockchip_clk_register_mmc(const char *name, struct clk_init_data init; struct rockchip_mmc_clock *mmc_clock; struct clk *clk; + int ret; mmc_clock = kmalloc(sizeof(*mmc_clock), GFP_KERNEL); if (!mmc_clock) @@ -186,7 +212,18 @@ struct clk *rockchip_clk_register_mmc(const char *name, clk = clk_register(NULL, &mmc_clock->hw); if (IS_ERR(clk)) - kfree(mmc_clock); + goto err_register; + mmc_clock->clk_rate_change_nb.notifier_call = + &rockchip_mmc_clk_rate_notify; + ret = clk_notifier_register(clk, &mmc_clock->clk_rate_change_nb); + if (ret) + goto err_notifier; + + return clk; +err_notifier: + clk_unregister(clk); +err_register: + kfree(mmc_clock); return clk; } -- cgit From 1e04204eff99b520737315af882f7fb61a9443be Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Tue, 13 Mar 2018 16:18:20 +0100 Subject: clk: renesas: r8a77965: Replace DU2 clock R-Car M3-N does not have the DU2 unit but it has DU3 instead. Fix the module clock definition to reflect that. Fixes: 7ce36da900c0a2ff ("clk: renesas: cpg-mssr: Add support for R-Car M3-N") Reported-by: Yoshihiro Shimoda Signed-off-by: Jacopo Mondi Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/r8a77965-cpg-mssr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/renesas/r8a77965-cpg-mssr.c b/drivers/clk/renesas/r8a77965-cpg-mssr.c index 41e506ab557d..b1acfb60351c 100644 --- a/drivers/clk/renesas/r8a77965-cpg-mssr.c +++ b/drivers/clk/renesas/r8a77965-cpg-mssr.c @@ -173,7 +173,7 @@ static const struct mssr_mod_clk r8a77965_mod_clks[] __initconst = { DEF_MOD("hsusb", 704, R8A77965_CLK_S3D4), DEF_MOD("csi20", 714, R8A77965_CLK_CSI0), DEF_MOD("csi40", 716, R8A77965_CLK_CSI0), - DEF_MOD("du2", 722, R8A77965_CLK_S2D1), + DEF_MOD("du3", 721, R8A77965_CLK_S2D1), DEF_MOD("du1", 723, R8A77965_CLK_S2D1), DEF_MOD("du0", 724, R8A77965_CLK_S2D1), DEF_MOD("lvds", 727, R8A77965_CLK_S2D1), -- cgit From 4ee3fd4abeca30d530fe67972f1964f7454259d6 Mon Sep 17 00:00:00 2001 From: Derek Basehore Date: Tue, 13 Mar 2018 13:37:19 -0700 Subject: clk: rockchip: Add 1.6GHz PLL rate for rk3399 We need this rate to generate 100, 200, and 228.57MHz from the same PLL. 228.57MHz is useful for a pixel clock when the VPLL is used for an external display. Signed-off-by: Derek Basehore Reviewed-by: Douglas Anderson Signed-off-by: Heiko Stuebner --- drivers/clk/rockchip/clk-rk3399.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/rockchip/clk-rk3399.c b/drivers/clk/rockchip/clk-rk3399.c index 6847120b61cd..3e57c6eef93d 100644 --- a/drivers/clk/rockchip/clk-rk3399.c +++ b/drivers/clk/rockchip/clk-rk3399.c @@ -57,6 +57,7 @@ static struct rockchip_pll_rate_table rk3399_pll_rates[] = { RK3036_PLL_RATE(1656000000, 1, 69, 1, 1, 1, 0), RK3036_PLL_RATE(1632000000, 1, 68, 1, 1, 1, 0), RK3036_PLL_RATE(1608000000, 1, 67, 1, 1, 1, 0), + RK3036_PLL_RATE(1600000000, 3, 200, 1, 1, 1, 0), RK3036_PLL_RATE(1584000000, 1, 66, 1, 1, 1, 0), RK3036_PLL_RATE(1560000000, 1, 65, 1, 1, 1, 0), RK3036_PLL_RATE(1536000000, 1, 64, 1, 1, 1, 0), -- cgit From 5b23fceec1ff94305c5d1accde018cae27448005 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Tue, 13 Mar 2018 11:46:12 +0100 Subject: clk: samsung: exynos5250: Add missing clocks for FIMC LITE SYSMMU devices FIMC LITE SYSMMU devices are defined in exynos5250.dtsi, but clocks for them are not instantiated by Exynos5250 clock provider driver. Add needed definitions for those clocks to fix IOMMU probe failure: ERROR: could not get clock /soc/sysmmu@13c40000:sysmmu(0) exynos-sysmmu 13c40000.sysmmu: Failed to get device clock(s)! exynos-sysmmu: probe of 13c40000.sysmmu failed with error -38 ERROR: could not get clock /soc/sysmmu@13c50000:sysmmu(0) exynos-sysmmu 13c50000.sysmmu: Failed to get device clock(s)! exynos-sysmmu: probe of 13c50000.sysmmu failed with error -38 Signed-off-by: Marek Szyprowski Fixes: bfed1074f213 ("clk: exynos5250: Add missing sysmmu clocks for DISP and ISP blocks") Acked-by: Chanwoo Choi Signed-off-by: Sylwester Nawrocki --- drivers/clk/samsung/clk-exynos5250.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/clk/samsung/clk-exynos5250.c b/drivers/clk/samsung/clk-exynos5250.c index 06e5ddcb30db..347fd80c351b 100644 --- a/drivers/clk/samsung/clk-exynos5250.c +++ b/drivers/clk/samsung/clk-exynos5250.c @@ -561,6 +561,8 @@ static const struct samsung_gate_clock exynos5250_gate_clks[] __initconst = { 0), GATE(CLK_GSCL3, "gscl3", "mout_aclk266_gscl_sub", GATE_IP_GSCL, 3, 0, 0), + GATE(CLK_CAMIF_TOP, "camif_top", "mout_aclk266_gscl_sub", + GATE_IP_GSCL, 4, 0, 0), GATE(CLK_GSCL_WA, "gscl_wa", "div_gscl_wa", GATE_IP_GSCL, 5, 0, 0), GATE(CLK_GSCL_WB, "gscl_wb", "div_gscl_wb", GATE_IP_GSCL, 6, 0, 0), GATE(CLK_SMMU_GSCL0, "smmu_gscl0", "mout_aclk266_gscl_sub", @@ -571,6 +573,10 @@ static const struct samsung_gate_clock exynos5250_gate_clks[] __initconst = { GATE_IP_GSCL, 9, 0, 0), GATE(CLK_SMMU_GSCL3, "smmu_gscl3", "mout_aclk266_gscl_sub", GATE_IP_GSCL, 10, 0, 0), + GATE(CLK_SMMU_FIMC_LITE0, "smmu_fimc_lite0", "mout_aclk266_gscl_sub", + GATE_IP_GSCL, 11, 0, 0), + GATE(CLK_SMMU_FIMC_LITE1, "smmu_fimc_lite1", "mout_aclk266_gscl_sub", + GATE_IP_GSCL, 12, 0, 0), GATE(CLK_MFC, "mfc", "mout_aclk333_sub", GATE_IP_MFC, 0, 0, 0), -- cgit From a91f77ef155e90b738c0d716844e31e136e9c6b4 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 14 Mar 2018 14:34:16 -0700 Subject: clk: hisilicon: Mark phase_ops static Sparse rightfully complains: drivers/clk/hisilicon/clk-hisi-phase.c:88:22: warning: symbol 'clk_phase_ops' was not declared. Should it be static? drivers/clk/hisilicon/clk-hisi-phase.c:88:22: warning: symbol 'clk_phase_ops' was not declared. Should it be static? Signed-off-by: Stephen Boyd --- drivers/clk/hisilicon/clk-hisi-phase.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/hisilicon/clk-hisi-phase.c b/drivers/clk/hisilicon/clk-hisi-phase.c index 42ce157ff828..5bce9297b78b 100644 --- a/drivers/clk/hisilicon/clk-hisi-phase.c +++ b/drivers/clk/hisilicon/clk-hisi-phase.c @@ -85,7 +85,7 @@ static int hisi_clk_set_phase(struct clk_hw *hw, int degrees) return 0; } -const struct clk_ops clk_phase_ops = { +static const struct clk_ops clk_phase_ops = { .get_phase = hisi_clk_get_phase, .set_phase = hisi_clk_set_phase, }; -- cgit From 5d1c04dde0eb396aec781c825a025e69c48b67cd Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 14 Mar 2018 15:36:31 -0700 Subject: clk: meson: Drop unused local variable and add static Fixes the following warnings: drivers/clk/meson/meson8b.c:512:19: warning: symbol 'meson8b_mpeg_clk_div' was not declared. Should it be static? drivers/clk/meson/meson8b.c:526:19: warning: symbol 'meson8b_clk81' was not declared. Should it be static? drivers/clk/meson/meson8b.c:540:19: warning: symbol 'meson8b_cpu_in_sel' was not declared. Should it be static? drivers/clk/meson/meson8b.c:591:19: warning: symbol 'meson8b_cpu_scale_div' was not declared. Should it be static? drivers/clk/meson/meson8b.c:608:19: warning: symbol 'meson8b_cpu_scale_out_sel' was not declared. Should it be static? drivers/clk/meson/meson8b.c:626:19: warning: symbol 'meson8b_cpu_clk' was not declared. Should it be static? drivers/clk/meson/gxbb.c:392:27: warning: symbol 'gxbb_gp0_init_regs' was not declared. Should it be static? drivers/clk/meson/gxbb.c:439:27: warning: symbol 'gxl_gp0_init_regs' was not declared. Should it be static? drivers/clk/meson/axg.c:195:27: warning: symbol 'axg_gp0_init_regs' was not declared. Should it be static? drivers/clk/meson/axg.c:248:27: warning: symbol 'axg_hifi_init_regs' was not declared. Should it be static? drivers/clk/meson/meson8b.c: In function 'meson8b_clkc_probe': drivers/clk/meson/meson8b.c:1052:14: warning: unused variable 'clk' [-Wunused-variable] Signed-off-by: Stephen Boyd --- drivers/clk/meson/axg.c | 4 ++-- drivers/clk/meson/gxbb.c | 4 ++-- drivers/clk/meson/meson8b.c | 13 ++++++------- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/drivers/clk/meson/axg.c b/drivers/clk/meson/axg.c index 99b2738c204f..5f5d468c1efe 100644 --- a/drivers/clk/meson/axg.c +++ b/drivers/clk/meson/axg.c @@ -192,7 +192,7 @@ static const struct pll_rate_table axg_gp0_pll_rate_table[] = { { /* sentinel */ }, }; -const struct reg_sequence axg_gp0_init_regs[] = { +static const struct reg_sequence axg_gp0_init_regs[] = { { .reg = HHI_GP0_PLL_CNTL1, .def = 0xc084b000 }, { .reg = HHI_GP0_PLL_CNTL2, .def = 0xb75020be }, { .reg = HHI_GP0_PLL_CNTL3, .def = 0x0a59a288 }, @@ -245,7 +245,7 @@ static struct clk_regmap axg_gp0_pll = { }, }; -const struct reg_sequence axg_hifi_init_regs[] = { +static const struct reg_sequence axg_hifi_init_regs[] = { { .reg = HHI_HIFI_PLL_CNTL1, .def = 0xc084b000 }, { .reg = HHI_HIFI_PLL_CNTL2, .def = 0xb75020be }, { .reg = HHI_HIFI_PLL_CNTL3, .def = 0x0a6a3a88 }, diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c index db5e0dcbb5aa..b1e4d9557610 100644 --- a/drivers/clk/meson/gxbb.c +++ b/drivers/clk/meson/gxbb.c @@ -389,7 +389,7 @@ static struct clk_regmap gxbb_sys_pll = { }, }; -const struct reg_sequence gxbb_gp0_init_regs[] = { +static const struct reg_sequence gxbb_gp0_init_regs[] = { { .reg = HHI_GP0_PLL_CNTL2, .def = 0x69c80000 }, { .reg = HHI_GP0_PLL_CNTL3, .def = 0x0a5590c4 }, { .reg = HHI_GP0_PLL_CNTL4, .def = 0x0000500d }, @@ -436,7 +436,7 @@ static struct clk_regmap gxbb_gp0_pll = { }, }; -const struct reg_sequence gxl_gp0_init_regs[] = { +static const struct reg_sequence gxl_gp0_init_regs[] = { { .reg = HHI_GP0_PLL_CNTL1, .def = 0xc084b000 }, { .reg = HHI_GP0_PLL_CNTL2, .def = 0xb75020be }, { .reg = HHI_GP0_PLL_CNTL3, .def = 0x0a59a288 }, diff --git a/drivers/clk/meson/meson8b.c b/drivers/clk/meson/meson8b.c index b324c44d36eb..cc2992493e0b 100644 --- a/drivers/clk/meson/meson8b.c +++ b/drivers/clk/meson/meson8b.c @@ -509,7 +509,7 @@ static struct clk_regmap meson8b_mpeg_clk_sel = { }, }; -struct clk_regmap meson8b_mpeg_clk_div = { +static struct clk_regmap meson8b_mpeg_clk_div = { .data = &(struct clk_regmap_div_data){ .offset = HHI_MPEG_CLK_CNTL, .shift = 0, @@ -523,7 +523,7 @@ struct clk_regmap meson8b_mpeg_clk_div = { }, }; -struct clk_regmap meson8b_clk81 = { +static struct clk_regmap meson8b_clk81 = { .data = &(struct clk_regmap_gate_data){ .offset = HHI_MPEG_CLK_CNTL, .bit_idx = 7, @@ -537,7 +537,7 @@ struct clk_regmap meson8b_clk81 = { }, }; -struct clk_regmap meson8b_cpu_in_sel = { +static struct clk_regmap meson8b_cpu_in_sel = { .data = &(struct clk_regmap_mux_data){ .offset = HHI_SYS_CPU_CLK_CNTL0, .mask = 0x1, @@ -588,7 +588,7 @@ static const struct clk_div_table cpu_scale_table[] = { { /* sentinel */ }, }; -struct clk_regmap meson8b_cpu_scale_div = { +static struct clk_regmap meson8b_cpu_scale_div = { .data = &(struct clk_regmap_div_data){ .offset = HHI_SYS_CPU_CLK_CNTL1, .shift = 20, @@ -605,7 +605,7 @@ struct clk_regmap meson8b_cpu_scale_div = { }, }; -struct clk_regmap meson8b_cpu_scale_out_sel = { +static struct clk_regmap meson8b_cpu_scale_out_sel = { .data = &(struct clk_regmap_mux_data){ .offset = HHI_SYS_CPU_CLK_CNTL0, .mask = 0x3, @@ -623,7 +623,7 @@ struct clk_regmap meson8b_cpu_scale_out_sel = { }, }; -struct clk_regmap meson8b_cpu_clk = { +static struct clk_regmap meson8b_cpu_clk = { .data = &(struct clk_regmap_mux_data){ .offset = HHI_SYS_CPU_CLK_CNTL0, .mask = 0x1, @@ -1049,7 +1049,6 @@ static const struct regmap_config clkc_regmap_config = { static int meson8b_clkc_probe(struct platform_device *pdev) { int ret, i; - struct clk *clk; struct device *dev = &pdev->dev; struct regmap *map; -- cgit From 182c084da5d1e4d7c02d913de154cf5167521580 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Wed, 14 Mar 2018 12:32:26 +0100 Subject: clk: samsung: Add fout=196608001 Hz EPLL rate entry for exynos4412 This additional frequency is required for HDMI audio support on Odroid U3 board. Signed-off-by: Sylwester Nawrocki --- drivers/clk/samsung/clk-exynos4.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/samsung/clk-exynos4.c b/drivers/clk/samsung/clk-exynos4.c index edf125525a36..0421960eb963 100644 --- a/drivers/clk/samsung/clk-exynos4.c +++ b/drivers/clk/samsung/clk-exynos4.c @@ -1319,6 +1319,7 @@ static const struct samsung_pll_rate_table exynos4x12_apll_rates[] __initconst = }; static const struct samsung_pll_rate_table exynos4x12_epll_rates[] __initconst = { + PLL_36XX_RATE(24 * MHZ, 196608001, 197, 3, 3, -25690), PLL_36XX_RATE(24 * MHZ, 192000000, 48, 3, 1, 0), PLL_36XX_RATE(24 * MHZ, 180633605, 45, 3, 1, 10381), PLL_36XX_RATE(24 * MHZ, 180000000, 45, 3, 1, 0), -- cgit From 1871f0fcba5debf21d5b0475e6a064dc5c21a026 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 16 Mar 2018 09:21:40 -0700 Subject: clk: samsung: Mark a few things static Running sparse on the samsung clk directory has some noise that we can fix to look for future problems easier. drivers/clk/samsung/clk-s3c2443.c:111:26: warning: symbol 's3c2443_common_muxes' was not declared. Should it be static? drivers/clk/samsung/clk-s3c2443.c:139:26: warning: symbol 's3c2443_common_dividers' was not declared. Should it be static? drivers/clk/samsung/clk-s3c2443.c:152:27: warning: symbol 's3c2443_common_gates' was not declared. Should it be static? drivers/clk/samsung/clk-s3c2443.c:186:28: warning: symbol 's3c2443_common_aliases' was not declared. Should it be static? drivers/clk/samsung/clk-s3c2443.c:241:26: warning: symbol 's3c2416_dividers' was not declared. Should it be static? drivers/clk/samsung/clk-s3c2443.c:247:26: warning: symbol 's3c2416_muxes' was not declared. Should it be static? drivers/clk/samsung/clk-s3c2443.c:253:27: warning: symbol 's3c2416_gates' was not declared. Should it be static? drivers/clk/samsung/clk-s3c2443.c:263:28: warning: symbol 's3c2416_aliases' was not declared. Should it be static? drivers/clk/samsung/clk-s3c2443.c:291:26: warning: symbol 's3c2443_dividers' was not declared. Should it be static? drivers/clk/samsung/clk-s3c2443.c:296:27: warning: symbol 's3c2443_gates' was not declared. Should it be static? drivers/clk/samsung/clk-s3c2443.c:305:28: warning: symbol 's3c2443_aliases' was not declared. Should it be static? drivers/clk/samsung/clk-s3c2443.c:321:26: warning: symbol 's3c2450_dividers' was not declared. Should it be static? drivers/clk/samsung/clk-s3c2443.c:328:26: warning: symbol 's3c2450_muxes' was not declared. Should it be static? drivers/clk/samsung/clk-s3c2443.c:334:27: warning: symbol 's3c2450_gates' was not declared. Should it be static? drivers/clk/samsung/clk-s3c2443.c:345:28: warning: symbol 's3c2450_aliases' was not declared. Should it be static? drivers/clk/samsung/clk-s3c2443.c:368:33: warning: symbol 's3c2443_common_frate_clks' was not declared. Should it be static? drivers/clk/samsung/clk-s3c2443.c:464:49: warning: Using plain integer as NULL pointer drivers/clk/samsung/clk-s3c2443.c:470:49: warning: Using plain integer as NULL pointer drivers/clk/samsung/clk-s3c2443.c:476:49: warning: Using plain integer as NULL pointer drivers/clk/samsung/clk-s3c2412.c:96:26: warning: symbol 's3c2412_dividers' was not declared. Should it be static? drivers/clk/samsung/clk-s3c2412.c:108:35: warning: symbol 's3c2412_ffactor' was not declared. Should it be static? drivers/clk/samsung/clk-s3c2412.c:128:26: warning: symbol 's3c2412_muxes' was not declared. Should it be static? drivers/clk/samsung/clk-s3c2412.c:146:27: warning: symbol 's3c2412_gates' was not declared. Should it be static? drivers/clk/samsung/clk-s3c2412.c:177:28: warning: symbol 's3c2412_aliases' was not declared. Should it be static? drivers/clk/samsung/clk-s3c2412.c:227:33: warning: symbol 's3c2412_common_frate_clks' was not declared. Should it be static? drivers/clk/samsung/clk-s3c2412.c:292:43: warning: Using plain integer as NULL pointer drivers/clk/samsung/clk-s3c2410.c:98:26: warning: symbol 's3c2410_common_muxes' was not declared. Should it be static? drivers/clk/samsung/clk-s3c2410.c:114:26: warning: symbol 's3c2410_common_dividers' was not declared. Should it be static? drivers/clk/samsung/clk-s3c2410.c:119:27: warning: symbol 's3c2410_common_gates' was not declared. Should it be static? drivers/clk/samsung/clk-s3c2410.c:138:28: warning: symbol 's3c2410_common_aliases' was not declared. Should it be static? drivers/clk/samsung/clk-s3c2410.c:203:26: warning: symbol 's3c2410_dividers' was not declared. Should it be static? drivers/clk/samsung/clk-s3c2410.c:207:35: warning: symbol 's3c2410_ffactor' was not declared. Should it be static? drivers/clk/samsung/clk-s3c2410.c:218:28: warning: symbol 's3c2410_aliases' was not declared. Should it be static? drivers/clk/samsung/clk-s3c2410.c:272:26: warning: symbol 's3c244x_common_muxes' was not declared. Should it be static? drivers/clk/samsung/clk-s3c2410.c:277:35: warning: symbol 's3c244x_common_ffactor' was not declared. Should it be static? drivers/clk/samsung/clk-s3c2410.c:294:26: warning: symbol 's3c244x_common_dividers' was not declared. Should it be static? drivers/clk/samsung/clk-s3c2410.c:302:27: warning: symbol 's3c244x_common_gates' was not declared. Should it be static? drivers/clk/samsung/clk-s3c2410.c:306:28: warning: symbol 's3c244x_common_aliases' was not declared. Should it be static? drivers/clk/samsung/clk-s3c2410.c:321:26: warning: symbol 's3c2440_muxes' was not declared. Should it be static? drivers/clk/samsung/clk-s3c2410.c:325:27: warning: symbol 's3c2440_gates' was not declared. Should it be static? drivers/clk/samsung/clk-s3c2410.c:331:35: warning: symbol 's3c2442_ffactor' was not declared. Should it be static? drivers/clk/samsung/clk-s3c2410.c:337:26: warning: symbol 's3c2442_muxes' was not declared. Should it be static? drivers/clk/samsung/clk-s3c2410.c:346:33: warning: symbol 's3c2410_common_frate_clks' was not declared. Should it be static? drivers/clk/samsung/clk-s3c2410.c:471:49: warning: Using plain integer as NULL pointer drivers/clk/samsung/clk-s3c2410.c:477:49: warning: Using plain integer as NULL pointer drivers/clk/samsung/clk-s3c2410.c:483:49: warning: Using plain integer as NULL pointer Signed-off-by: Stephen Boyd --- drivers/clk/samsung/clk-s3c2410.c | 40 +++++++++++++++++++-------------------- drivers/clk/samsung/clk-s3c2412.c | 14 +++++++------- drivers/clk/samsung/clk-s3c2443.c | 38 ++++++++++++++++++------------------- 3 files changed, 46 insertions(+), 46 deletions(-) diff --git a/drivers/clk/samsung/clk-s3c2410.c b/drivers/clk/samsung/clk-s3c2410.c index 0c6aa3e51336..a9c887475054 100644 --- a/drivers/clk/samsung/clk-s3c2410.c +++ b/drivers/clk/samsung/clk-s3c2410.c @@ -95,7 +95,7 @@ static void __init s3c2410_clk_sleep_init(void) {} PNAME(fclk_p) = { "mpll", "div_slow" }; -struct samsung_mux_clock s3c2410_common_muxes[] __initdata = { +static struct samsung_mux_clock s3c2410_common_muxes[] __initdata = { MUX(FCLK, "fclk", fclk_p, CLKSLOW, 4, 1), }; @@ -111,12 +111,12 @@ static struct clk_div_table divslow_d[] = { { /* sentinel */ }, }; -struct samsung_div_clock s3c2410_common_dividers[] __initdata = { +static struct samsung_div_clock s3c2410_common_dividers[] __initdata = { DIV_T(0, "div_slow", "xti", CLKSLOW, 0, 3, divslow_d), DIV(PCLK, "pclk", "hclk", CLKDIVN, 0, 1), }; -struct samsung_gate_clock s3c2410_common_gates[] __initdata = { +static struct samsung_gate_clock s3c2410_common_gates[] __initdata = { GATE(PCLK_SPI, "spi", "pclk", CLKCON, 18, 0, 0), GATE(PCLK_I2S, "i2s", "pclk", CLKCON, 17, 0, 0), GATE(PCLK_I2C, "i2c", "pclk", CLKCON, 16, 0, 0), @@ -135,7 +135,7 @@ struct samsung_gate_clock s3c2410_common_gates[] __initdata = { }; /* should be added _after_ the soc-specific clocks are created */ -struct samsung_clock_alias s3c2410_common_aliases[] __initdata = { +static struct samsung_clock_alias s3c2410_common_aliases[] __initdata = { ALIAS(PCLK_I2C, "s3c2410-i2c.0", "i2c"), ALIAS(PCLK_ADC, NULL, "adc"), ALIAS(PCLK_RTC, NULL, "rtc"), @@ -200,11 +200,11 @@ static struct samsung_pll_clock s3c2410_plls[] __initdata = { LOCKTIME, UPLLCON, NULL), }; -struct samsung_div_clock s3c2410_dividers[] __initdata = { +static struct samsung_div_clock s3c2410_dividers[] __initdata = { DIV(HCLK, "hclk", "mpll", CLKDIVN, 1, 1), }; -struct samsung_fixed_factor_clock s3c2410_ffactor[] __initdata = { +static struct samsung_fixed_factor_clock s3c2410_ffactor[] __initdata = { /* * armclk is directly supplied by the fclk, without * switching possibility like on the s3c244x below. @@ -215,7 +215,7 @@ struct samsung_fixed_factor_clock s3c2410_ffactor[] __initdata = { FFACTOR(UCLK, "uclk", "upll", 1, 1, 0), }; -struct samsung_clock_alias s3c2410_aliases[] __initdata = { +static struct samsung_clock_alias s3c2410_aliases[] __initdata = { ALIAS(PCLK_UART0, "s3c2410-uart.0", "uart"), ALIAS(PCLK_UART1, "s3c2410-uart.1", "uart"), ALIAS(PCLK_UART2, "s3c2410-uart.2", "uart"), @@ -269,12 +269,12 @@ static struct samsung_pll_clock s3c244x_common_plls[] __initdata = { PNAME(hclk_p) = { "fclk", "div_hclk_2", "div_hclk_4", "div_hclk_3" }; PNAME(armclk_p) = { "fclk", "hclk" }; -struct samsung_mux_clock s3c244x_common_muxes[] __initdata = { +static struct samsung_mux_clock s3c244x_common_muxes[] __initdata = { MUX(HCLK, "hclk", hclk_p, CLKDIVN, 1, 2), MUX(ARMCLK, "armclk", armclk_p, CAMDIVN, 12, 1), }; -struct samsung_fixed_factor_clock s3c244x_common_ffactor[] __initdata = { +static struct samsung_fixed_factor_clock s3c244x_common_ffactor[] __initdata = { FFACTOR(0, "div_hclk_2", "fclk", 1, 2, 0), FFACTOR(0, "ff_cam", "div_cam", 2, 1, CLK_SET_RATE_PARENT), }; @@ -291,7 +291,7 @@ static struct clk_div_table div_hclk_3_d[] = { { /* sentinel */ }, }; -struct samsung_div_clock s3c244x_common_dividers[] __initdata = { +static struct samsung_div_clock s3c244x_common_dividers[] __initdata = { DIV(UCLK, "uclk", "upll", CLKDIVN, 3, 1), DIV(0, "div_hclk", "fclk", CLKDIVN, 1, 1), DIV_T(0, "div_hclk_4", "fclk", CAMDIVN, 9, 1, div_hclk_4_d), @@ -299,11 +299,11 @@ struct samsung_div_clock s3c244x_common_dividers[] __initdata = { DIV(0, "div_cam", "upll", CAMDIVN, 0, 3), }; -struct samsung_gate_clock s3c244x_common_gates[] __initdata = { +static struct samsung_gate_clock s3c244x_common_gates[] __initdata = { GATE(HCLK_CAM, "cam", "hclk", CLKCON, 19, 0, 0), }; -struct samsung_clock_alias s3c244x_common_aliases[] __initdata = { +static struct samsung_clock_alias s3c244x_common_aliases[] __initdata = { ALIAS(PCLK_UART0, "s3c2440-uart.0", "uart"), ALIAS(PCLK_UART1, "s3c2440-uart.1", "uart"), ALIAS(PCLK_UART2, "s3c2440-uart.2", "uart"), @@ -318,23 +318,23 @@ struct samsung_clock_alias s3c244x_common_aliases[] __initdata = { PNAME(s3c2440_camif_p) = { "upll", "ff_cam" }; -struct samsung_mux_clock s3c2440_muxes[] __initdata = { +static struct samsung_mux_clock s3c2440_muxes[] __initdata = { MUX(CAMIF, "camif", s3c2440_camif_p, CAMDIVN, 4, 1), }; -struct samsung_gate_clock s3c2440_gates[] __initdata = { +static struct samsung_gate_clock s3c2440_gates[] __initdata = { GATE(PCLK_AC97, "ac97", "pclk", CLKCON, 20, 0, 0), }; /* S3C2442 specific clocks */ -struct samsung_fixed_factor_clock s3c2442_ffactor[] __initdata = { +static struct samsung_fixed_factor_clock s3c2442_ffactor[] __initdata = { FFACTOR(0, "upll_3", "upll", 1, 3, 0), }; PNAME(s3c2442_camif_p) = { "upll", "ff_cam", "upll", "upll_3" }; -struct samsung_mux_clock s3c2442_muxes[] __initdata = { +static struct samsung_mux_clock s3c2442_muxes[] __initdata = { MUX(CAMIF, "camif", s3c2442_camif_p, CAMDIVN, 4, 2), }; @@ -343,7 +343,7 @@ struct samsung_mux_clock s3c2442_muxes[] __initdata = { * Only necessary until the devicetree-move is complete */ #define XTI 1 -struct samsung_fixed_rate_clock s3c2410_common_frate_clks[] __initdata = { +static struct samsung_fixed_rate_clock s3c2410_common_frate_clks[] __initdata = { FRATE(XTI, "xti", NULL, 0, 0), }; @@ -468,18 +468,18 @@ void __init s3c2410_common_clk_init(struct device_node *np, unsigned long xti_f, static void __init s3c2410_clk_init(struct device_node *np) { - s3c2410_common_clk_init(np, 0, S3C2410, 0); + s3c2410_common_clk_init(np, 0, S3C2410, NULL); } CLK_OF_DECLARE(s3c2410_clk, "samsung,s3c2410-clock", s3c2410_clk_init); static void __init s3c2440_clk_init(struct device_node *np) { - s3c2410_common_clk_init(np, 0, S3C2440, 0); + s3c2410_common_clk_init(np, 0, S3C2440, NULL); } CLK_OF_DECLARE(s3c2440_clk, "samsung,s3c2440-clock", s3c2440_clk_init); static void __init s3c2442_clk_init(struct device_node *np) { - s3c2410_common_clk_init(np, 0, S3C2442, 0); + s3c2410_common_clk_init(np, 0, S3C2442, NULL); } CLK_OF_DECLARE(s3c2442_clk, "samsung,s3c2442-clock", s3c2442_clk_init); diff --git a/drivers/clk/samsung/clk-s3c2412.c b/drivers/clk/samsung/clk-s3c2412.c index 1555e407529e..6bc94d3aff78 100644 --- a/drivers/clk/samsung/clk-s3c2412.c +++ b/drivers/clk/samsung/clk-s3c2412.c @@ -93,7 +93,7 @@ static struct clk_div_table divxti_d[] = { { /* sentinel */ }, }; -struct samsung_div_clock s3c2412_dividers[] __initdata = { +static struct samsung_div_clock s3c2412_dividers[] __initdata = { DIV_T(0, "div_xti", "xti", CLKSRC, 0, 3, divxti_d), DIV(0, "div_cam", "mux_cam", CLKDIVN, 16, 4), DIV(0, "div_i2s", "mux_i2s", CLKDIVN, 12, 4), @@ -105,7 +105,7 @@ struct samsung_div_clock s3c2412_dividers[] __initdata = { DIV(HCLK, "hclk", "armdiv", CLKDIVN, 0, 2), }; -struct samsung_fixed_factor_clock s3c2412_ffactor[] __initdata = { +static struct samsung_fixed_factor_clock s3c2412_ffactor[] __initdata = { FFACTOR(0, "ff_hclk", "hclk", 2, 1, CLK_SET_RATE_PARENT), }; @@ -125,7 +125,7 @@ PNAME(msysclk_p) = { "mdivclk", "mpll" }; PNAME(mdivclk_p) = { "xti", "div_xti" }; PNAME(armclk_p) = { "armdiv", "hclk" }; -struct samsung_mux_clock s3c2412_muxes[] __initdata = { +static struct samsung_mux_clock s3c2412_muxes[] __initdata = { MUX(0, "erefclk", erefclk_p, CLKSRC, 14, 2), MUX(0, "urefclk", urefclk_p, CLKSRC, 12, 2), MUX(0, "mux_cam", camclk_p, CLKSRC, 11, 1), @@ -143,7 +143,7 @@ static struct samsung_pll_clock s3c2412_plls[] __initdata = { PLL(pll_s3c2410_upll, UPLL, "upll", "urefclk", LOCKTIME, UPLLCON, NULL), }; -struct samsung_gate_clock s3c2412_gates[] __initdata = { +static struct samsung_gate_clock s3c2412_gates[] __initdata = { GATE(PCLK_WDT, "wdt", "pclk", CLKCON, 28, 0, 0), GATE(PCLK_SPI, "spi", "pclk", CLKCON, 27, 0, 0), GATE(PCLK_I2S, "i2s", "pclk", CLKCON, 26, 0, 0), @@ -174,7 +174,7 @@ struct samsung_gate_clock s3c2412_gates[] __initdata = { GATE(HCLK_DMA0, "dma0", "hclk", CLKCON, 0, CLK_IGNORE_UNUSED, 0), }; -struct samsung_clock_alias s3c2412_aliases[] __initdata = { +static struct samsung_clock_alias s3c2412_aliases[] __initdata = { ALIAS(PCLK_UART0, "s3c2412-uart.0", "uart"), ALIAS(PCLK_UART1, "s3c2412-uart.1", "uart"), ALIAS(PCLK_UART2, "s3c2412-uart.2", "uart"), @@ -224,7 +224,7 @@ static struct notifier_block s3c2412_restart_handler = { * Only necessary until the devicetree-move is complete */ #define XTI 1 -struct samsung_fixed_rate_clock s3c2412_common_frate_clks[] __initdata = { +static struct samsung_fixed_rate_clock s3c2412_common_frate_clks[] __initdata = { FRATE(XTI, "xti", NULL, 0, 0), FRATE(0, "ext", NULL, 0, 0), }; @@ -289,6 +289,6 @@ void __init s3c2412_common_clk_init(struct device_node *np, unsigned long xti_f, static void __init s3c2412_clk_init(struct device_node *np) { - s3c2412_common_clk_init(np, 0, 0, 0); + s3c2412_common_clk_init(np, 0, 0, NULL); } CLK_OF_DECLARE(s3c2412_clk, "samsung,s3c2412-clock", s3c2412_clk_init); diff --git a/drivers/clk/samsung/clk-s3c2443.c b/drivers/clk/samsung/clk-s3c2443.c index 9580a6baf4d7..c46e6d5bc9bc 100644 --- a/drivers/clk/samsung/clk-s3c2443.c +++ b/drivers/clk/samsung/clk-s3c2443.c @@ -108,7 +108,7 @@ PNAME(msysclk_p) = { "mpllref", "mpll" }; PNAME(armclk_p) = { "armdiv" , "hclk" }; PNAME(i2s0_p) = { "div_i2s0", "ext_i2s", "epllref", "epllref" }; -struct samsung_mux_clock s3c2443_common_muxes[] __initdata = { +static struct samsung_mux_clock s3c2443_common_muxes[] __initdata = { MUX(0, "epllref", epllref_p, CLKSRC, 7, 2), MUX(ESYSCLK, "esysclk", esysclk_p, CLKSRC, 6, 1), MUX(0, "mpllref", mpllref_p, CLKSRC, 3, 1), @@ -136,7 +136,7 @@ static struct clk_div_table mdivclk_d[] = { { /* sentinel */ }, }; -struct samsung_div_clock s3c2443_common_dividers[] __initdata = { +static struct samsung_div_clock s3c2443_common_dividers[] __initdata = { DIV_T(0, "mdivclk", "xti", CLKDIV0, 6, 3, mdivclk_d), DIV(0, "prediv", "msysclk", CLKDIV0, 4, 2), DIV_T(HCLK, "hclk", "prediv", CLKDIV0, 0, 2, hclk_d), @@ -149,7 +149,7 @@ struct samsung_div_clock s3c2443_common_dividers[] __initdata = { DIV(0, "div_usbhost", "esysclk", CLKDIV1, 4, 2), }; -struct samsung_gate_clock s3c2443_common_gates[] __initdata = { +static struct samsung_gate_clock s3c2443_common_gates[] __initdata = { GATE(SCLK_HSMMC_EXT, "sclk_hsmmcext", "ext", SCLKCON, 13, 0, 0), GATE(SCLK_HSMMC1, "sclk_hsmmc1", "div_hsmmc1", SCLKCON, 12, 0, 0), GATE(SCLK_FIMD, "sclk_fimd", "div_fimd", SCLKCON, 10, 0, 0), @@ -183,7 +183,7 @@ struct samsung_gate_clock s3c2443_common_gates[] __initdata = { GATE(PCLK_UART0, "uart0", "pclk", PCLKCON, 0, 0, 0), }; -struct samsung_clock_alias s3c2443_common_aliases[] __initdata = { +static struct samsung_clock_alias s3c2443_common_aliases[] __initdata = { ALIAS(MSYSCLK, NULL, "msysclk"), ALIAS(ARMCLK, NULL, "armclk"), ALIAS(MPLL, NULL, "mpll"), @@ -238,19 +238,19 @@ static struct clk_div_table armdiv_s3c2416_d[] = { { /* sentinel */ }, }; -struct samsung_div_clock s3c2416_dividers[] __initdata = { +static struct samsung_div_clock s3c2416_dividers[] __initdata = { DIV_T(ARMDIV, "armdiv", "msysclk", CLKDIV0, 9, 3, armdiv_s3c2416_d), DIV(0, "div_hsspi0_mpll", "msysclk", CLKDIV2, 0, 4), DIV(0, "div_hsmmc0", "esysclk", CLKDIV2, 6, 2), }; -struct samsung_mux_clock s3c2416_muxes[] __initdata = { +static struct samsung_mux_clock s3c2416_muxes[] __initdata = { MUX(MUX_HSMMC0, "mux_hsmmc0", s3c2416_hsmmc0_p, CLKSRC, 16, 1), MUX(MUX_HSMMC1, "mux_hsmmc1", s3c2416_hsmmc1_p, CLKSRC, 17, 1), MUX(MUX_HSSPI0, "mux_hsspi0", s3c2416_hsspi0_p, CLKSRC, 18, 1), }; -struct samsung_gate_clock s3c2416_gates[] __initdata = { +static struct samsung_gate_clock s3c2416_gates[] __initdata = { GATE(0, "hsspi0_mpll", "div_hsspi0_mpll", SCLKCON, 19, 0, 0), GATE(0, "hsspi0_epll", "div_hsspi0_epll", SCLKCON, 14, 0, 0), GATE(0, "sclk_hsmmc0", "div_hsmmc0", SCLKCON, 6, 0, 0), @@ -260,7 +260,7 @@ struct samsung_gate_clock s3c2416_gates[] __initdata = { GATE(PCLK_PCM, "pcm", "pclk", PCLKCON, 19, 0, 0), }; -struct samsung_clock_alias s3c2416_aliases[] __initdata = { +static struct samsung_clock_alias s3c2416_aliases[] __initdata = { ALIAS(HCLK_HSMMC0, "s3c-sdhci.0", "hsmmc"), ALIAS(HCLK_HSMMC0, "s3c-sdhci.0", "mmc_busclk.0"), ALIAS(MUX_HSMMC0, "s3c-sdhci.0", "mmc_busclk.2"), @@ -288,12 +288,12 @@ static struct clk_div_table armdiv_s3c2443_d[] = { { /* sentinel */ }, }; -struct samsung_div_clock s3c2443_dividers[] __initdata = { +static struct samsung_div_clock s3c2443_dividers[] __initdata = { DIV_T(ARMDIV, "armdiv", "msysclk", CLKDIV0, 9, 4, armdiv_s3c2443_d), DIV(0, "div_cam", "esysclk", CLKDIV1, 26, 4), }; -struct samsung_gate_clock s3c2443_gates[] __initdata = { +static struct samsung_gate_clock s3c2443_gates[] __initdata = { GATE(SCLK_HSSPI0, "sclk_hsspi0", "div_hsspi0_epll", SCLKCON, 14, 0, 0), GATE(SCLK_CAM, "sclk_cam", "div_cam", SCLKCON, 11, 0, 0), GATE(HCLK_CFC, "cfc", "hclk", HCLKCON, 17, CLK_IGNORE_UNUSED, 0), @@ -302,7 +302,7 @@ struct samsung_gate_clock s3c2443_gates[] __initdata = { GATE(PCLK_SDI, "sdi", "pclk", PCLKCON, 5, 0, 0), }; -struct samsung_clock_alias s3c2443_aliases[] __initdata = { +static struct samsung_clock_alias s3c2443_aliases[] __initdata = { ALIAS(SCLK_HSSPI0, "s3c2443-spi.0", "spi_busclk2"), ALIAS(SCLK_HSMMC1, "s3c-sdhci.1", "mmc_busclk.2"), ALIAS(SCLK_CAM, NULL, "camif-upll"), @@ -318,20 +318,20 @@ PNAME(s3c2450_cam_p) = { "div_cam", "hclk" }; PNAME(s3c2450_hsspi1_p) = { "hsspi1_epll", "hsspi1_mpll" }; PNAME(i2s1_p) = { "div_i2s1", "ext_i2s", "epllref", "epllref" }; -struct samsung_div_clock s3c2450_dividers[] __initdata = { +static struct samsung_div_clock s3c2450_dividers[] __initdata = { DIV(0, "div_cam", "esysclk", CLKDIV1, 26, 4), DIV(0, "div_hsspi1_epll", "esysclk", CLKDIV2, 24, 2), DIV(0, "div_hsspi1_mpll", "msysclk", CLKDIV2, 16, 4), DIV(0, "div_i2s1", "esysclk", CLKDIV2, 12, 4), }; -struct samsung_mux_clock s3c2450_muxes[] __initdata = { +static struct samsung_mux_clock s3c2450_muxes[] __initdata = { MUX(0, "mux_cam", s3c2450_cam_p, CLKSRC, 20, 1), MUX(MUX_HSSPI1, "mux_hsspi1", s3c2450_hsspi1_p, CLKSRC, 19, 1), MUX(0, "mux_i2s1", i2s1_p, CLKSRC, 12, 2), }; -struct samsung_gate_clock s3c2450_gates[] __initdata = { +static struct samsung_gate_clock s3c2450_gates[] __initdata = { GATE(SCLK_I2S1, "sclk_i2s1", "div_i2s1", SCLKCON, 5, 0, 0), GATE(HCLK_CFC, "cfc", "hclk", HCLKCON, 17, 0, 0), GATE(HCLK_CAM, "cam", "hclk", HCLKCON, 8, 0, 0), @@ -342,7 +342,7 @@ struct samsung_gate_clock s3c2450_gates[] __initdata = { GATE(PCLK_SPI1, "spi1", "pclk", PCLKCON, 14, 0, 0), }; -struct samsung_clock_alias s3c2450_aliases[] __initdata = { +static struct samsung_clock_alias s3c2450_aliases[] __initdata = { ALIAS(PCLK_SPI1, "s3c2443-spi.1", "spi"), ALIAS(PCLK_SPI1, "s3c2443-spi.1", "spi_busclk0"), ALIAS(MUX_HSSPI1, "s3c2443-spi.1", "spi_busclk2"), @@ -365,7 +365,7 @@ static struct notifier_block s3c2443_restart_handler = { * fixed rate clocks generated outside the soc * Only necessary until the devicetree-move is complete */ -struct samsung_fixed_rate_clock s3c2443_common_frate_clks[] __initdata = { +static struct samsung_fixed_rate_clock s3c2443_common_frate_clks[] __initdata = { FRATE(0, "xti", NULL, 0, 0), FRATE(0, "ext", NULL, 0, 0), FRATE(0, "ext_i2s", NULL, 0, 0), @@ -461,18 +461,18 @@ void __init s3c2443_common_clk_init(struct device_node *np, unsigned long xti_f, static void __init s3c2416_clk_init(struct device_node *np) { - s3c2443_common_clk_init(np, 0, S3C2416, 0); + s3c2443_common_clk_init(np, 0, S3C2416, NULL); } CLK_OF_DECLARE(s3c2416_clk, "samsung,s3c2416-clock", s3c2416_clk_init); static void __init s3c2443_clk_init(struct device_node *np) { - s3c2443_common_clk_init(np, 0, S3C2443, 0); + s3c2443_common_clk_init(np, 0, S3C2443, NULL); } CLK_OF_DECLARE(s3c2443_clk, "samsung,s3c2443-clock", s3c2443_clk_init); static void __init s3c2450_clk_init(struct device_node *np) { - s3c2443_common_clk_init(np, 0, S3C2450, 0); + s3c2443_common_clk_init(np, 0, S3C2450, NULL); } CLK_OF_DECLARE(s3c2450_clk, "samsung,s3c2450-clock", s3c2450_clk_init); -- cgit From aff2dc6b49fc642906eaa5523c5227c50fd77c50 Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Fri, 10 Nov 2017 16:06:57 +0000 Subject: clk: versatile: add min/max rate boundaries for vexpress osc clock Clock framework has a provider API(clk_hw_set_rate_range) to set the min/max rate of a clock. Use the same to set the boundaries for the vexpress osc clock. Cc: Michael Turquette Cc: Stephen Boyd Cc: linux-clk@vger.kernel.org Signed-off-by: Sudeep Holla Signed-off-by: Stephen Boyd --- drivers/clk/versatile/clk-vexpress-osc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/versatile/clk-vexpress-osc.c b/drivers/clk/versatile/clk-vexpress-osc.c index e7a868b83fe5..d3b5af2a02ab 100644 --- a/drivers/clk/versatile/clk-vexpress-osc.c +++ b/drivers/clk/versatile/clk-vexpress-osc.c @@ -104,6 +104,7 @@ static int vexpress_osc_probe(struct platform_device *pdev) return PTR_ERR(clk); of_clk_add_provider(pdev->dev.of_node, of_clk_src_simple_get, clk); + clk_hw_set_rate_range(&osc->hw, osc->rate_min, osc->rate_max); dev_dbg(&pdev->dev, "Registered clock '%s'\n", init.name); -- cgit From a1d803d78b9e1ff82a0e5ef9d81202b23377f9e0 Mon Sep 17 00:00:00 2001 From: Brian Starkey Date: Mon, 13 Nov 2017 15:27:51 +0000 Subject: clk: versatile: Remove WARNs in ->round_rate() clk_round_rate() is intended to be used to round a given clock rate to the closest one achievable by the actual clock. This implies that the input to clk_round_rate() is expected to be unachievable - and such cases shouldn't be treated as exceptional. To reflect this, remove the WARN_ONs which trigger when an unachievable clock rate is passed to vexpress_osc_round_rate(). Reported-by: Vladimir Murzin Signed-off-by: Brian Starkey Acked-by: Sudeep Holla Signed-off-by: Stephen Boyd --- drivers/clk/versatile/clk-vexpress-osc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/clk/versatile/clk-vexpress-osc.c b/drivers/clk/versatile/clk-vexpress-osc.c index d3b5af2a02ab..dd08ecb498be 100644 --- a/drivers/clk/versatile/clk-vexpress-osc.c +++ b/drivers/clk/versatile/clk-vexpress-osc.c @@ -44,10 +44,10 @@ static long vexpress_osc_round_rate(struct clk_hw *hw, unsigned long rate, { struct vexpress_osc *osc = to_vexpress_osc(hw); - if (WARN_ON(osc->rate_min && rate < osc->rate_min)) + if (osc->rate_min && rate < osc->rate_min) rate = osc->rate_min; - if (WARN_ON(osc->rate_max && rate > osc->rate_max)) + if (osc->rate_max && rate > osc->rate_max) rate = osc->rate_max; return rate; -- cgit From 496037c015079ece7ebc1344fcab80f0618eae5e Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Thu, 7 Dec 2017 10:59:22 +0000 Subject: clk: qcom: gcc-msm8996: Mark aggre0 noc clks as critical aggre0 bus clks are not associated with any of the drivers, so its important that these clks are always on to get peripherals on this bus working. So mark them as critical. Eventually when we have a proper bus driver these clks can be marked appropriately. Without this patch pcie on db820c is not functional. Signed-off-by: Srinivas Kandagatla Signed-off-by: Stephen Boyd --- drivers/clk/qcom/gcc-msm8996.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/clk/qcom/gcc-msm8996.c b/drivers/clk/qcom/gcc-msm8996.c index 5d7451209206..3d6452932797 100644 --- a/drivers/clk/qcom/gcc-msm8996.c +++ b/drivers/clk/qcom/gcc-msm8996.c @@ -2895,7 +2895,7 @@ static struct clk_branch gcc_aggre0_snoc_axi_clk = { .name = "gcc_aggre0_snoc_axi_clk", .parent_names = (const char *[]){ "system_noc_clk_src" }, .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, + .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, .ops = &clk_branch2_ops, }, }, @@ -2910,7 +2910,7 @@ static struct clk_branch gcc_aggre0_cnoc_ahb_clk = { .name = "gcc_aggre0_cnoc_ahb_clk", .parent_names = (const char *[]){ "config_noc_clk_src" }, .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, + .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, .ops = &clk_branch2_ops, }, }, @@ -2925,7 +2925,7 @@ static struct clk_branch gcc_smmu_aggre0_axi_clk = { .name = "gcc_smmu_aggre0_axi_clk", .parent_names = (const char *[]){ "system_noc_clk_src" }, .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, + .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, .ops = &clk_branch2_ops, }, }, @@ -2940,7 +2940,7 @@ static struct clk_branch gcc_smmu_aggre0_ahb_clk = { .name = "gcc_smmu_aggre0_ahb_clk", .parent_names = (const char *[]){ "config_noc_clk_src" }, .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, + .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, .ops = &clk_branch2_ops, }, }, -- cgit From 93abad369a44f3b68f0581a00c4608500f293d93 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Wed, 17 Jan 2018 16:02:56 +0100 Subject: clk: imx: pllv2: avoid using uninitialized values Forward the errors returned by __clk_pllv2_set_rate() in the recalc rate function, to avoid using uninitialized values for the rate calculation. Signed-off-by: Lucas Stach Reviewed-by: Fabio Estevam Signed-off-by: Stephen Boyd --- drivers/clk/imx/clk-pllv2.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/clk/imx/clk-pllv2.c b/drivers/clk/imx/clk-pllv2.c index 85b5cbe9744c..eeba3cb14e2d 100644 --- a/drivers/clk/imx/clk-pllv2.c +++ b/drivers/clk/imx/clk-pllv2.c @@ -182,8 +182,12 @@ static long clk_pllv2_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *prate) { u32 dp_op, dp_mfd, dp_mfn; + int ret; + + ret = __clk_pllv2_set_rate(rate, *prate, &dp_op, &dp_mfd, &dp_mfn); + if (ret) + return ret; - __clk_pllv2_set_rate(rate, *prate, &dp_op, &dp_mfd, &dp_mfn); return __clk_pllv2_recalc_rate(*prate, MXC_PLL_DP_CTL_DPDCK0_2_EN, dp_op, dp_mfd, dp_mfn); } -- cgit From 5bc5673c098b03e8de29b9f87187bed7643bd5c6 Mon Sep 17 00:00:00 2001 From: Dong Aisheng Date: Fri, 19 Jan 2018 21:37:15 +0800 Subject: Documentation: clk: enable lock is not held for clk_is_enabled API The core does not need to hold enable lock for clk_is_enabled API. Update the doc to reflect it. Cc: Jonathan Corbet Cc: Stephen Boyd Suggested-by: Stephen Boyd Signed-off-by: Dong Aisheng [sboyd: Clarified the last sentence a little more and fixed a spelling error] Signed-off-by: Stephen Boyd --- Documentation/clk.txt | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/Documentation/clk.txt b/Documentation/clk.txt index be909ed45970..511628bb3d3a 100644 --- a/Documentation/clk.txt +++ b/Documentation/clk.txt @@ -268,9 +268,19 @@ The common clock framework uses two global locks, the prepare lock and the enable lock. The enable lock is a spinlock and is held across calls to the .enable, -.disable and .is_enabled operations. Those operations are thus not allowed to -sleep, and calls to the clk_enable(), clk_disable() and clk_is_enabled() API -functions are allowed in atomic context. +.disable operations. Those operations are thus not allowed to sleep, +and calls to the clk_enable(), clk_disable() API functions are allowed in +atomic context. + +For clk_is_enabled() API, it is also designed to be allowed to be used in +atomic context. However, it doesn't really make any sense to hold the enable +lock in core, unless you want to do something else with the information of +the enable state with that lock held. Otherwise, seeing if a clk is enabled is +a one-shot read of the enabled state, which could just as easily change after +the function returns because the lock is released. Thus the user of this API +needs to handle synchronizing the read of the state with whatever they're +using it for to make sure that the enable state doesn't change during that +time. The prepare lock is a mutex and is held across calls to all other operations. All those operations are allowed to sleep, and calls to the corresponding API -- cgit From 6e0d4ff4580c1272f4e4860bf22841ef31fd31ba Mon Sep 17 00:00:00 2001 From: Dong Aisheng Date: Tue, 23 Jan 2018 20:24:45 +0800 Subject: clk: add more __must_check for bulk APIs we need it even when !CONFIG_HAVE_CLK because it allows us to catch missing checking return values in the non-clk compile configurations too. More test coverage. Cc: Stephen Boyd Suggested-by: Stephen Boyd Signed-off-by: Dong Aisheng Signed-off-by: Stephen Boyd --- include/linux/clk.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/include/linux/clk.h b/include/linux/clk.h index 4c4ef9f34db3..0dbd0885b2c2 100644 --- a/include/linux/clk.h +++ b/include/linux/clk.h @@ -209,7 +209,7 @@ static inline int clk_prepare(struct clk *clk) return 0; } -static inline int clk_bulk_prepare(int num_clks, struct clk_bulk_data *clks) +static inline int __must_check clk_bulk_prepare(int num_clks, struct clk_bulk_data *clks) { might_sleep(); return 0; @@ -603,8 +603,8 @@ static inline struct clk *clk_get(struct device *dev, const char *id) return NULL; } -static inline int clk_bulk_get(struct device *dev, int num_clks, - struct clk_bulk_data *clks) +static inline int __must_check clk_bulk_get(struct device *dev, int num_clks, + struct clk_bulk_data *clks) { return 0; } @@ -614,8 +614,8 @@ static inline struct clk *devm_clk_get(struct device *dev, const char *id) return NULL; } -static inline int devm_clk_bulk_get(struct device *dev, int num_clks, - struct clk_bulk_data *clks) +static inline int __must_check devm_clk_bulk_get(struct device *dev, int num_clks, + struct clk_bulk_data *clks) { return 0; } @@ -645,7 +645,7 @@ static inline int clk_enable(struct clk *clk) return 0; } -static inline int clk_bulk_enable(int num_clks, struct clk_bulk_data *clks) +static inline int __must_check clk_bulk_enable(int num_clks, struct clk_bulk_data *clks) { return 0; } @@ -719,8 +719,8 @@ static inline void clk_disable_unprepare(struct clk *clk) clk_unprepare(clk); } -static inline int clk_bulk_prepare_enable(int num_clks, - struct clk_bulk_data *clks) +static inline int __must_check clk_bulk_prepare_enable(int num_clks, + struct clk_bulk_data *clks) { int ret; -- cgit From 91927ff6446c281a3aa5cf8875cf7f0853a2bb55 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Thu, 1 Feb 2018 16:33:26 -0800 Subject: clk: qcom: smd-rpm: Migrate to devm_of_clk_add_hw_provider() Signed-off-by: Stephen Boyd Signed-off-by: Stephen Boyd --- drivers/clk/qcom/clk-smd-rpm.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/drivers/clk/qcom/clk-smd-rpm.c b/drivers/clk/qcom/clk-smd-rpm.c index c26d9007bfc4..850c02a52248 100644 --- a/drivers/clk/qcom/clk-smd-rpm.c +++ b/drivers/clk/qcom/clk-smd-rpm.c @@ -686,7 +686,7 @@ static int rpm_smd_clk_probe(struct platform_device *pdev) goto err; } - ret = of_clk_add_hw_provider(pdev->dev.of_node, qcom_smdrpm_clk_hw_get, + ret = devm_of_clk_add_hw_provider(&pdev->dev, qcom_smdrpm_clk_hw_get, rcc); if (ret) goto err; @@ -697,19 +697,12 @@ err: return ret; } -static int rpm_smd_clk_remove(struct platform_device *pdev) -{ - of_clk_del_provider(pdev->dev.of_node); - return 0; -} - static struct platform_driver rpm_smd_clk_driver = { .driver = { .name = "qcom-clk-smd-rpm", .of_match_table = rpm_smd_clk_match_table, }, .probe = rpm_smd_clk_probe, - .remove = rpm_smd_clk_remove, }; static int __init rpm_smd_clk_init(void) -- cgit From f7c14dd5b1291abaec3dda97867c5018e1b6aa01 Mon Sep 17 00:00:00 2001 From: Chunyan Zhang Date: Fri, 9 Feb 2018 17:48:10 +0800 Subject: dt-bindings: clocks: add APB RTC gate for SC9860 Added index of RTC gate clocks which are used by some devices on aon area of SC9860, for example the Watchdog timer. Signed-off-by: Chunyan Zhang Reviewed-by: Rob Herring Signed-off-by: Stephen Boyd --- include/dt-bindings/clock/sprd,sc9860-clk.h | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/include/dt-bindings/clock/sprd,sc9860-clk.h b/include/dt-bindings/clock/sprd,sc9860-clk.h index 4cb202f090c2..f2ab4631df0d 100644 --- a/include/dt-bindings/clock/sprd,sc9860-clk.h +++ b/include/dt-bindings/clock/sprd,sc9860-clk.h @@ -229,7 +229,26 @@ #define CLK_SDIO1_2X_EN 65 #define CLK_SDIO2_2X_EN 66 #define CLK_EMMC_2X_EN 67 -#define CLK_AON_GATE_NUM (CLK_EMMC_2X_EN + 1) +#define CLK_ARCH_RTC_EB 68 +#define CLK_KPB_RTC_EB 69 +#define CLK_AON_SYST_RTC_EB 70 +#define CLK_AP_SYST_RTC_EB 71 +#define CLK_AON_TMR_RTC_EB 72 +#define CLK_AP_TMR0_RTC_EB 73 +#define CLK_EIC_RTC_EB 74 +#define CLK_EIC_RTCDV5_EB 75 +#define CLK_AP_WDG_RTC_EB 76 +#define CLK_AP_TMR1_RTC_EB 77 +#define CLK_AP_TMR2_RTC_EB 78 +#define CLK_DCXO_TMR_RTC_EB 79 +#define CLK_BB_CAL_RTC_EB 80 +#define CLK_AVS_BIG_RTC_EB 81 +#define CLK_AVS_LIT_RTC_EB 82 +#define CLK_AVS_GPU0_RTC_EB 83 +#define CLK_AVS_GPU1_RTC_EB 84 +#define CLK_GPU_TS_EB 85 +#define CLK_RTCDV10_EB 86 +#define CLK_AON_GATE_NUM (CLK_RTCDV10_EB + 1) #define CLK_LIT_MCU 0 #define CLK_BIG_MCU 1 -- cgit From b3316a672bfbedbe0437b21937c1d6aeacbaabe4 Mon Sep 17 00:00:00 2001 From: Chunyan Zhang Date: Fri, 9 Feb 2018 17:55:09 +0800 Subject: clk: sprd: add RTC gate for SC9860 Add a few gate clocks which are used for gating RTC for some devices on AON area of SC9860. This patch has been tested on SC9860, with this patch and proper DT configurations, the watchdog can be initialized and work well. Signed-off-by: Chunyan Zhang Signed-off-by: Stephen Boyd --- drivers/clk/sprd/sc9860-clk.c | 76 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/drivers/clk/sprd/sc9860-clk.c b/drivers/clk/sprd/sc9860-clk.c index ed5c027df0f4..9980ab55271b 100644 --- a/drivers/clk/sprd/sc9860-clk.c +++ b/drivers/clk/sprd/sc9860-clk.c @@ -959,6 +959,44 @@ static SPRD_SC_GATE_CLK(sdio2_2x_en, "sdio2-2x-en", "aon-apb", 0x13c, 0x1000, BIT(6), 0, 0); static SPRD_SC_GATE_CLK(emmc_2x_en, "emmc-2x-en", "aon-apb", 0x13c, 0x1000, BIT(9), 0, 0); +static SPRD_SC_GATE_CLK(arch_rtc_eb, "arch-rtc-eb", "aon-apb", 0x10, + 0x1000, BIT(0), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(kpb_rtc_eb, "kpb-rtc-eb", "aon-apb", 0x10, + 0x1000, BIT(1), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(aon_syst_rtc_eb, "aon-syst-rtc-eb", "aon-apb", 0x10, + 0x1000, BIT(2), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(ap_syst_rtc_eb, "ap-syst-rtc-eb", "aon-apb", 0x10, + 0x1000, BIT(3), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(aon_tmr_rtc_eb, "aon-tmr-rtc-eb", "aon-apb", 0x10, + 0x1000, BIT(4), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(ap_tmr0_rtc_eb, "ap-tmr0-rtc-eb", "aon-apb", 0x10, + 0x1000, BIT(5), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(eic_rtc_eb, "eic-rtc-eb", "aon-apb", 0x10, + 0x1000, BIT(6), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(eic_rtcdv5_eb, "eic-rtcdv5-eb", "aon-apb", 0x10, + 0x1000, BIT(7), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(ap_wdg_rtc_eb, "ap-wdg-rtc-eb", "aon-apb", 0x10, + 0x1000, BIT(9), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(ap_tmr1_rtc_eb, "ap-tmr1-rtc-eb", "aon-apb", 0x10, + 0x1000, BIT(15), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(ap_tmr2_rtc_eb, "ap-tmr2-rtc-eb", "aon-apb", 0x10, + 0x1000, BIT(16), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(dcxo_tmr_rtc_eb, "dcxo-tmr-rtc-eb", "aon-apb", 0x10, + 0x1000, BIT(17), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(bb_cal_rtc_eb, "bb-cal-rtc-eb", "aon-apb", 0x10, + 0x1000, BIT(18), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(avs_big_rtc_eb, "avs-big-rtc-eb", "aon-apb", 0x10, + 0x1000, BIT(20), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(avs_lit_rtc_eb, "avs-lit-rtc-eb", "aon-apb", 0x10, + 0x1000, BIT(21), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(avs_gpu0_rtc_eb, "avs-gpu0-rtc-eb", "aon-apb", 0x10, + 0x1000, BIT(22), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(avs_gpu1_rtc_eb, "avs-gpu1-rtc-eb", "aon-apb", 0x10, + 0x1000, BIT(23), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(gpu_ts_eb, "gpu-ts-eb", "aon-apb", 0x10, + 0x1000, BIT(24), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(rtcdv10_eb, "rtcdv10-eb", "aon-apb", 0x10, + 0x1000, BIT(27), CLK_IGNORE_UNUSED, 0); static struct sprd_clk_common *sc9860_aon_gate[] = { /* address base is 0x402e0000 */ @@ -1030,6 +1068,25 @@ static struct sprd_clk_common *sc9860_aon_gate[] = { &sdio1_2x_en.common, &sdio2_2x_en.common, &emmc_2x_en.common, + &arch_rtc_eb.common, + &kpb_rtc_eb.common, + &aon_syst_rtc_eb.common, + &ap_syst_rtc_eb.common, + &aon_tmr_rtc_eb.common, + &ap_tmr0_rtc_eb.common, + &eic_rtc_eb.common, + &eic_rtcdv5_eb.common, + &ap_wdg_rtc_eb.common, + &ap_tmr1_rtc_eb.common, + &ap_tmr2_rtc_eb.common, + &dcxo_tmr_rtc_eb.common, + &bb_cal_rtc_eb.common, + &avs_big_rtc_eb.common, + &avs_lit_rtc_eb.common, + &avs_gpu0_rtc_eb.common, + &avs_gpu1_rtc_eb.common, + &gpu_ts_eb.common, + &rtcdv10_eb.common, }; static struct clk_hw_onecell_data sc9860_aon_gate_hws = { @@ -1102,6 +1159,25 @@ static struct clk_hw_onecell_data sc9860_aon_gate_hws = { [CLK_SDIO1_2X_EN] = &sdio1_2x_en.common.hw, [CLK_SDIO2_2X_EN] = &sdio2_2x_en.common.hw, [CLK_EMMC_2X_EN] = &emmc_2x_en.common.hw, + [CLK_ARCH_RTC_EB] = &arch_rtc_eb.common.hw, + [CLK_KPB_RTC_EB] = &kpb_rtc_eb.common.hw, + [CLK_AON_SYST_RTC_EB] = &aon_syst_rtc_eb.common.hw, + [CLK_AP_SYST_RTC_EB] = &ap_syst_rtc_eb.common.hw, + [CLK_AON_TMR_RTC_EB] = &aon_tmr_rtc_eb.common.hw, + [CLK_AP_TMR0_RTC_EB] = &ap_tmr0_rtc_eb.common.hw, + [CLK_EIC_RTC_EB] = &eic_rtc_eb.common.hw, + [CLK_EIC_RTCDV5_EB] = &eic_rtcdv5_eb.common.hw, + [CLK_AP_WDG_RTC_EB] = &ap_wdg_rtc_eb.common.hw, + [CLK_AP_TMR1_RTC_EB] = &ap_tmr1_rtc_eb.common.hw, + [CLK_AP_TMR2_RTC_EB] = &ap_tmr2_rtc_eb.common.hw, + [CLK_DCXO_TMR_RTC_EB] = &dcxo_tmr_rtc_eb.common.hw, + [CLK_BB_CAL_RTC_EB] = &bb_cal_rtc_eb.common.hw, + [CLK_AVS_BIG_RTC_EB] = &avs_big_rtc_eb.common.hw, + [CLK_AVS_LIT_RTC_EB] = &avs_lit_rtc_eb.common.hw, + [CLK_AVS_GPU0_RTC_EB] = &avs_gpu0_rtc_eb.common.hw, + [CLK_AVS_GPU1_RTC_EB] = &avs_gpu1_rtc_eb.common.hw, + [CLK_GPU_TS_EB] = &gpu_ts_eb.common.hw, + [CLK_RTCDV10_EB] = &rtcdv10_eb.common.hw, }, .num = CLK_AON_GATE_NUM, }; -- cgit From ce33f284935e08229046b30635e6aadcbab02b53 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 16 Feb 2018 16:27:47 +0100 Subject: clk: fix false-positive Wmaybe-uninitialized warning When we build this driver with on x86-32, gcc produces a false-positive warning: drivers/clk/renesas/clk-sh73a0.c: In function 'sh73a0_cpg_clocks_init': drivers/clk/renesas/clk-sh73a0.c:155:10: error: 'parent_name' may be used uninitialized in this function [-Werror=maybe-uninitialized] return clk_register_fixed_factor(NULL, name, parent_name, 0, We can work around that warning by adding a fake initialization, I tried and failed to come up with any better workaround. This is currently one of few remaining warnings for a 4.14.y randconfig build, so it would be good to also have it backported at least to that version. Older versions have more randconfig warnings, so we might not care. I had not noticed this earlier, because one patch in my randconfig test tree removes the '-ffreestanding' option on x86-32, and that avoids the warning. The -ffreestanding flag was originally global but moved into arch/i386 by Andi Kleen in commit 6edfba1b33c7 ("[PATCH] x86_64: Don't define string functions to builtin") as a 'temporary workaround'. Like many temporary hacks, this turned out to be rather long-lived, from all I can tell we still need a simple fix to asm/string_32.h before it can be removed, but I'm not sure about how to best do that. Cc: stable@vger.kernel.org Cc: Andi Kleen Signed-off-by: Arnd Bergmann Acked-by: Geert Uytterhoeven Signed-off-by: Stephen Boyd --- drivers/clk/renesas/clk-sh73a0.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/clk/renesas/clk-sh73a0.c b/drivers/clk/renesas/clk-sh73a0.c index eea38f6ea77e..3892346c4fcc 100644 --- a/drivers/clk/renesas/clk-sh73a0.c +++ b/drivers/clk/renesas/clk-sh73a0.c @@ -46,7 +46,7 @@ struct div4_clk { unsigned int shift; }; -static struct div4_clk div4_clks[] = { +static const struct div4_clk div4_clks[] = { { "zg", "pll0", CPG_FRQCRA, 16 }, { "m3", "pll1", CPG_FRQCRA, 12 }, { "b", "pll1", CPG_FRQCRA, 8 }, @@ -79,7 +79,7 @@ sh73a0_cpg_register_clock(struct device_node *np, struct sh73a0_cpg *cpg, { const struct clk_div_table *table = NULL; unsigned int shift, reg, width; - const char *parent_name; + const char *parent_name = NULL; unsigned int mult = 1; unsigned int div = 1; @@ -135,7 +135,7 @@ sh73a0_cpg_register_clock(struct device_node *np, struct sh73a0_cpg *cpg, shift = 24; width = 5; } else { - struct div4_clk *c; + const struct div4_clk *c; for (c = div4_clks; c->name; c++) { if (!strcmp(name, c->name)) { -- cgit From df934cbcbff7afbc024bf05f02615917c61f6470 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 20 Feb 2018 16:15:21 +0100 Subject: clk: hisilicon: mark wdt_mux_p[] as const The symbol is in the __initconst section but not marked init, which caused a warning when building with LTO. This makes it 'const' as was obviously intended. Signed-off-by: Arnd Bergmann Fixes: c80dfd9bf54e ("clk: hisilicon: add CRG driver for Hi3516CV300 SoC") Signed-off-by: Stephen Boyd --- drivers/clk/hisilicon/crg-hi3516cv300.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/hisilicon/crg-hi3516cv300.c b/drivers/clk/hisilicon/crg-hi3516cv300.c index 2007123832bb..53450b651e4c 100644 --- a/drivers/clk/hisilicon/crg-hi3516cv300.c +++ b/drivers/clk/hisilicon/crg-hi3516cv300.c @@ -204,7 +204,7 @@ static const struct hisi_crg_funcs hi3516cv300_crg_funcs = { /* hi3516CV300 sysctrl CRG */ #define HI3516CV300_SYSCTRL_NR_CLKS 16 -static const char *wdt_mux_p[] __initconst = { "3m", "apb" }; +static const char *const wdt_mux_p[] __initconst = { "3m", "apb" }; static u32 wdt_mux_table[] = {0, 1}; static const struct hisi_mux_clock hi3516cv300_sysctrl_mux_clks[] = { -- cgit From a910f251ee084230e2f8d214f1621346cec94e69 Mon Sep 17 00:00:00 2001 From: Icenowy Zheng Date: Fri, 16 Mar 2018 22:02:11 +0800 Subject: clk: sunxi-ng: Support fixed post-dividers on NKMP style clocks On the new Allwinner H6 SoC, multiple PLL's are NMP style clocks (modelled as NKMP with no K) and have fixed post-dividers. Add fixed post divider support to the NKMP style clocks. Signed-off-by: Icenowy Zheng Signed-off-by: Maxime Ripard --- drivers/clk/sunxi-ng/ccu_nkmp.c | 20 +++++++++++++++++--- drivers/clk/sunxi-ng/ccu_nkmp.h | 2 ++ 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/drivers/clk/sunxi-ng/ccu_nkmp.c b/drivers/clk/sunxi-ng/ccu_nkmp.c index c3f6fe7be565..ebd9436d2c7c 100644 --- a/drivers/clk/sunxi-ng/ccu_nkmp.c +++ b/drivers/clk/sunxi-ng/ccu_nkmp.c @@ -95,7 +95,7 @@ static unsigned long ccu_nkmp_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { struct ccu_nkmp *nkmp = hw_to_ccu_nkmp(hw); - unsigned long n, m, k, p; + unsigned long n, m, k, p, rate; u32 reg; reg = readl(nkmp->common.base + nkmp->common.reg); @@ -121,7 +121,11 @@ static unsigned long ccu_nkmp_recalc_rate(struct clk_hw *hw, p = reg >> nkmp->p.shift; p &= (1 << nkmp->p.width) - 1; - return ccu_nkmp_calc_rate(parent_rate, n, k, m, 1 << p); + rate = ccu_nkmp_calc_rate(parent_rate, n, k, m, 1 << p); + if (nkmp->common.features & CCU_FEATURE_FIXED_POSTDIV) + rate /= nkmp->fixed_post_div; + + return rate; } static long ccu_nkmp_round_rate(struct clk_hw *hw, unsigned long rate, @@ -130,6 +134,9 @@ static long ccu_nkmp_round_rate(struct clk_hw *hw, unsigned long rate, struct ccu_nkmp *nkmp = hw_to_ccu_nkmp(hw); struct _ccu_nkmp _nkmp; + if (nkmp->common.features & CCU_FEATURE_FIXED_POSTDIV) + rate *= nkmp->fixed_post_div; + _nkmp.min_n = nkmp->n.min ?: 1; _nkmp.max_n = nkmp->n.max ?: 1 << nkmp->n.width; _nkmp.min_k = nkmp->k.min ?: 1; @@ -141,8 +148,12 @@ static long ccu_nkmp_round_rate(struct clk_hw *hw, unsigned long rate, ccu_nkmp_find_best(*parent_rate, rate, &_nkmp); - return ccu_nkmp_calc_rate(*parent_rate, _nkmp.n, _nkmp.k, + rate = ccu_nkmp_calc_rate(*parent_rate, _nkmp.n, _nkmp.k, _nkmp.m, _nkmp.p); + if (nkmp->common.features & CCU_FEATURE_FIXED_POSTDIV) + rate = rate / nkmp->fixed_post_div; + + return rate; } static int ccu_nkmp_set_rate(struct clk_hw *hw, unsigned long rate, @@ -154,6 +165,9 @@ static int ccu_nkmp_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long flags; u32 reg; + if (nkmp->common.features & CCU_FEATURE_FIXED_POSTDIV) + rate = rate * nkmp->fixed_post_div; + _nkmp.min_n = nkmp->n.min ?: 1; _nkmp.max_n = nkmp->n.max ?: 1 << nkmp->n.width; _nkmp.min_k = nkmp->k.min ?: 1; diff --git a/drivers/clk/sunxi-ng/ccu_nkmp.h b/drivers/clk/sunxi-ng/ccu_nkmp.h index a82facbc6144..6940503e7fc4 100644 --- a/drivers/clk/sunxi-ng/ccu_nkmp.h +++ b/drivers/clk/sunxi-ng/ccu_nkmp.h @@ -34,6 +34,8 @@ struct ccu_nkmp { struct ccu_div_internal m; struct ccu_div_internal p; + unsigned int fixed_post_div; + struct ccu_common common; }; -- cgit From 2e08e4d2ff488424919d69dd211ac860a019ac1d Mon Sep 17 00:00:00 2001 From: Icenowy Zheng Date: Fri, 16 Mar 2018 22:02:12 +0800 Subject: dt-bindings: add device tree binding for Allwinner H6 main CCU The Allwinner H6 main CCU uses the internal oscillator of the SoC, which is different with old SoCs' main CCU. Add device tree binding for the Allwinner H6 main CCU. Signed-off-by: Icenowy Zheng Signed-off-by: Maxime Ripard --- Documentation/devicetree/bindings/clock/sunxi-ccu.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Documentation/devicetree/bindings/clock/sunxi-ccu.txt b/Documentation/devicetree/bindings/clock/sunxi-ccu.txt index 4ca21c3a6fc9..460ef27b1008 100644 --- a/Documentation/devicetree/bindings/clock/sunxi-ccu.txt +++ b/Documentation/devicetree/bindings/clock/sunxi-ccu.txt @@ -20,6 +20,7 @@ Required properties : - "allwinner,sun50i-a64-ccu" - "allwinner,sun50i-a64-r-ccu" - "allwinner,sun50i-h5-ccu" + - "allwinner,sun50i-h6-ccu" - "nextthing,gr8-ccu" - reg: Must contain the registers base address and length @@ -31,6 +32,9 @@ Required properties : - #clock-cells : must contain 1 - #reset-cells : must contain 1 +For the main CCU on H6, one more clock is needed: +- "iosc": the SoC's internal frequency oscillator + For the PRCM CCUs on A83T/H3/A64, two more clocks are needed: - "pll-periph": the SoC's peripheral PLL from the main CCU - "iosc": the SoC's internal frequency oscillator -- cgit From 524353ea480b0094c16f2b5684ce7e0a23ab3685 Mon Sep 17 00:00:00 2001 From: Icenowy Zheng Date: Fri, 16 Mar 2018 22:02:13 +0800 Subject: clk: sunxi-ng: add support for the Allwinner H6 CCU The Allwinner H6 SoC has a CCU which has been largely rearranged. Add support for it in the sunxi-ng CCU framework. Signed-off-by: Icenowy Zheng Acked-by: Maxime Ripard Signed-off-by: Maxime Ripard --- drivers/clk/sunxi-ng/Kconfig | 5 + drivers/clk/sunxi-ng/Makefile | 1 + drivers/clk/sunxi-ng/ccu-sun50i-h6.c | 1207 +++++++++++++++++++++++++++++ drivers/clk/sunxi-ng/ccu-sun50i-h6.h | 56 ++ include/dt-bindings/clock/sun50i-h6-ccu.h | 124 +++ include/dt-bindings/reset/sun50i-h6-ccu.h | 73 ++ 6 files changed, 1466 insertions(+) create mode 100644 drivers/clk/sunxi-ng/ccu-sun50i-h6.c create mode 100644 drivers/clk/sunxi-ng/ccu-sun50i-h6.h create mode 100644 include/dt-bindings/clock/sun50i-h6-ccu.h create mode 100644 include/dt-bindings/reset/sun50i-h6-ccu.h diff --git a/drivers/clk/sunxi-ng/Kconfig b/drivers/clk/sunxi-ng/Kconfig index 33168f94ee39..79dfd296c3d1 100644 --- a/drivers/clk/sunxi-ng/Kconfig +++ b/drivers/clk/sunxi-ng/Kconfig @@ -11,6 +11,11 @@ config SUN50I_A64_CCU default ARM64 && ARCH_SUNXI depends on (ARM64 && ARCH_SUNXI) || COMPILE_TEST +config SUN50I_H6_CCU + bool "Support for the Allwinner H6 CCU" + default ARM64 && ARCH_SUNXI + depends on (ARM64 && ARCH_SUNXI) || COMPILE_TEST + config SUN4I_A10_CCU bool "Support for the Allwinner A10/A20 CCU" default MACH_SUN4I diff --git a/drivers/clk/sunxi-ng/Makefile b/drivers/clk/sunxi-ng/Makefile index 4141c3fe08ae..128a40ee5c5e 100644 --- a/drivers/clk/sunxi-ng/Makefile +++ b/drivers/clk/sunxi-ng/Makefile @@ -22,6 +22,7 @@ lib-$(CONFIG_SUNXI_CCU) += ccu_mp.o # SoC support obj-$(CONFIG_SUN50I_A64_CCU) += ccu-sun50i-a64.o +obj-$(CONFIG_SUN50I_H6_CCU) += ccu-sun50i-h6.o obj-$(CONFIG_SUN4I_A10_CCU) += ccu-sun4i-a10.o obj-$(CONFIG_SUN5I_CCU) += ccu-sun5i.o obj-$(CONFIG_SUN6I_A31_CCU) += ccu-sun6i-a31.o diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-h6.c b/drivers/clk/sunxi-ng/ccu-sun50i-h6.c new file mode 100644 index 000000000000..d5eab49e6350 --- /dev/null +++ b/drivers/clk/sunxi-ng/ccu-sun50i-h6.c @@ -0,0 +1,1207 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2017 Icenowy Zheng + */ + +#include +#include +#include + +#include "ccu_common.h" +#include "ccu_reset.h" + +#include "ccu_div.h" +#include "ccu_gate.h" +#include "ccu_mp.h" +#include "ccu_mult.h" +#include "ccu_nk.h" +#include "ccu_nkm.h" +#include "ccu_nkmp.h" +#include "ccu_nm.h" + +#include "ccu-sun50i-h6.h" + +/* + * The CPU PLL is actually NP clock, with P being /1, /2 or /4. However + * P should only be used for output frequencies lower than 288 MHz. + * + * For now we can just model it as a multiplier clock, and force P to /1. + * + * The M factor is present in the register's description, but not in the + * frequency formula, and it's documented as "M is only used for backdoor + * testing", so it's not modelled and then force to 0. + */ +#define SUN50I_H6_PLL_CPUX_REG 0x000 +static struct ccu_mult pll_cpux_clk = { + .enable = BIT(31), + .lock = BIT(28), + .mult = _SUNXI_CCU_MULT_MIN(8, 8, 12), + .common = { + .reg = 0x000, + .hw.init = CLK_HW_INIT("pll-cpux", "osc24M", + &ccu_mult_ops, + CLK_SET_RATE_UNGATE), + }, +}; + +/* Some PLLs are input * N / div1 / P. Model them as NKMP with no K */ +#define SUN50I_H6_PLL_DDR0_REG 0x010 +static struct ccu_nkmp pll_ddr0_clk = { + .enable = BIT(31), + .lock = BIT(28), + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ + .p = _SUNXI_CCU_DIV(0, 1), /* output divider */ + .common = { + .reg = 0x010, + .hw.init = CLK_HW_INIT("pll-ddr0", "osc24M", + &ccu_nkmp_ops, + CLK_SET_RATE_UNGATE), + }, +}; + +#define SUN50I_H6_PLL_PERIPH0_REG 0x020 +static struct ccu_nkmp pll_periph0_clk = { + .enable = BIT(31), + .lock = BIT(28), + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ + .p = _SUNXI_CCU_DIV(0, 1), /* output divider */ + .fixed_post_div = 4, + .common = { + .reg = 0x020, + .features = CCU_FEATURE_FIXED_POSTDIV, + .hw.init = CLK_HW_INIT("pll-periph0", "osc24M", + &ccu_nkmp_ops, + CLK_SET_RATE_UNGATE), + }, +}; + +#define SUN50I_H6_PLL_PERIPH1_REG 0x028 +static struct ccu_nkmp pll_periph1_clk = { + .enable = BIT(31), + .lock = BIT(28), + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ + .p = _SUNXI_CCU_DIV(0, 1), /* output divider */ + .fixed_post_div = 4, + .common = { + .reg = 0x028, + .features = CCU_FEATURE_FIXED_POSTDIV, + .hw.init = CLK_HW_INIT("pll-periph1", "osc24M", + &ccu_nkmp_ops, + CLK_SET_RATE_UNGATE), + }, +}; + +#define SUN50I_H6_PLL_GPU_REG 0x030 +static struct ccu_nkmp pll_gpu_clk = { + .enable = BIT(31), + .lock = BIT(28), + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ + .p = _SUNXI_CCU_DIV(0, 1), /* output divider */ + .common = { + .reg = 0x030, + .hw.init = CLK_HW_INIT("pll-gpu", "osc24M", + &ccu_nkmp_ops, + CLK_SET_RATE_UNGATE), + }, +}; + +/* + * For Video PLLs, the output divider is described as "used for testing" + * in the user manual. So it's not modelled and forced to 0. + */ +#define SUN50I_H6_PLL_VIDEO0_REG 0x040 +static struct ccu_nm pll_video0_clk = { + .enable = BIT(31), + .lock = BIT(28), + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ + .fixed_post_div = 4, + .common = { + .reg = 0x040, + .features = CCU_FEATURE_FIXED_POSTDIV, + .hw.init = CLK_HW_INIT("pll-video0", "osc24M", + &ccu_nm_ops, + CLK_SET_RATE_UNGATE), + }, +}; + +#define SUN50I_H6_PLL_VIDEO1_REG 0x048 +static struct ccu_nm pll_video1_clk = { + .enable = BIT(31), + .lock = BIT(28), + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ + .fixed_post_div = 4, + .common = { + .reg = 0x048, + .features = CCU_FEATURE_FIXED_POSTDIV, + .hw.init = CLK_HW_INIT("pll-video1", "osc24M", + &ccu_nm_ops, + CLK_SET_RATE_UNGATE), + }, +}; + +#define SUN50I_H6_PLL_VE_REG 0x058 +static struct ccu_nkmp pll_ve_clk = { + .enable = BIT(31), + .lock = BIT(28), + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ + .p = _SUNXI_CCU_DIV(0, 1), /* output divider */ + .common = { + .reg = 0x058, + .hw.init = CLK_HW_INIT("pll-ve", "osc24M", + &ccu_nkmp_ops, + CLK_SET_RATE_UNGATE), + }, +}; + +#define SUN50I_H6_PLL_DE_REG 0x060 +static struct ccu_nkmp pll_de_clk = { + .enable = BIT(31), + .lock = BIT(28), + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ + .p = _SUNXI_CCU_DIV(0, 1), /* output divider */ + .common = { + .reg = 0x060, + .hw.init = CLK_HW_INIT("pll-de", "osc24M", + &ccu_nkmp_ops, + CLK_SET_RATE_UNGATE), + }, +}; + +#define SUN50I_H6_PLL_HSIC_REG 0x070 +static struct ccu_nkmp pll_hsic_clk = { + .enable = BIT(31), + .lock = BIT(28), + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ + .p = _SUNXI_CCU_DIV(0, 1), /* output divider */ + .common = { + .reg = 0x070, + .hw.init = CLK_HW_INIT("pll-hsic", "osc24M", + &ccu_nkmp_ops, + CLK_SET_RATE_UNGATE), + }, +}; + +/* + * The Audio PLL is supposed to have 3 outputs: 2 fixed factors from + * the base (2x and 4x), and one variable divider (the one true pll audio). + * + * We don't have any need for the variable divider for now, so we just + * hardcode it to match with the clock names. + */ +#define SUN50I_H6_PLL_AUDIO_REG 0x078 +static struct ccu_nm pll_audio_base_clk = { + .enable = BIT(31), + .lock = BIT(28), + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ + .common = { + .reg = 0x078, + .hw.init = CLK_HW_INIT("pll-audio-base", "osc24M", + &ccu_nm_ops, + CLK_SET_RATE_UNGATE), + }, +}; + +static const char * const cpux_parents[] = { "osc24M", "osc32k", + "iosc", "pll-cpux" }; +static SUNXI_CCU_MUX(cpux_clk, "cpux", cpux_parents, + 0x500, 24, 2, CLK_SET_RATE_PARENT | CLK_IS_CRITICAL); +static SUNXI_CCU_M(axi_clk, "axi", "cpux", 0x500, 0, 2, 0); +static SUNXI_CCU_M(cpux_apb_clk, "cpux-apb", "cpux", 0x500, 8, 2, 0); + +static const char * const psi_ahb1_ahb2_parents[] = { "osc24M", "osc32k", + "iosc", "pll-periph0" }; +static SUNXI_CCU_MP_WITH_MUX(psi_ahb1_ahb2_clk, "psi-ahb1-ahb2", + psi_ahb1_ahb2_parents, + 0x510, + 0, 5, /* M */ + 16, 2, /* P */ + 24, 2, /* mux */ + 0); + +static const char * const ahb3_apb1_apb2_parents[] = { "osc24M", "osc32k", + "psi-ahb1-ahb2", + "pll-periph0" }; +static SUNXI_CCU_MP_WITH_MUX(ahb3_clk, "ahb3", ahb3_apb1_apb2_parents, 0x51c, + 0, 5, /* M */ + 16, 2, /* P */ + 24, 2, /* mux */ + 0); + +static SUNXI_CCU_MP_WITH_MUX(apb1_clk, "apb1", ahb3_apb1_apb2_parents, 0x520, + 0, 5, /* M */ + 16, 2, /* P */ + 24, 2, /* mux */ + 0); + +static SUNXI_CCU_MP_WITH_MUX(apb2_clk, "apb2", ahb3_apb1_apb2_parents, 0x524, + 0, 5, /* M */ + 16, 2, /* P */ + 24, 2, /* mux */ + 0); + +static const char * const mbus_parents[] = { "osc24M", "pll-periph0-2x", + "pll-ddr0", "pll-periph0-4x" }; +static SUNXI_CCU_M_WITH_MUX_GATE(mbus_clk, "mbus", mbus_parents, 0x540, + 0, 3, /* M */ + 24, 2, /* mux */ + BIT(31), /* gate */ + CLK_IS_CRITICAL); + +static const char * const de_parents[] = { "pll-de", "pll-periph0-2x" }; +static SUNXI_CCU_M_WITH_MUX_GATE(de_clk, "de", de_parents, 0x600, + 0, 4, /* M */ + 24, 1, /* mux */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_GATE(bus_de_clk, "bus-de", "psi-ahb1-ahb2", + 0x60c, BIT(0), 0); + +static const char * const deinterlace_parents[] = { "pll-periph0", + "pll-periph1" }; +static SUNXI_CCU_M_WITH_MUX_GATE(deinterlace_clk, "deinterlace", + deinterlace_parents, + 0x620, + 0, 4, /* M */ + 24, 1, /* mux */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_GATE(bus_deinterlace_clk, "bus-deinterlace", "psi-ahb1-ahb2", + 0x62c, BIT(0), 0); + +static const char * const gpu_parents[] = { "pll-gpu" }; +static SUNXI_CCU_M_WITH_MUX_GATE(gpu_clk, "gpu", gpu_parents, 0x670, + 0, 3, /* M */ + 24, 1, /* mux */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_GATE(bus_gpu_clk, "bus-gpu", "psi-ahb1-ahb2", + 0x67c, BIT(0), 0); + +/* Also applies to EMCE */ +static const char * const ce_parents[] = { "osc24M", "pll-periph0-2x" }; +static SUNXI_CCU_MP_WITH_MUX_GATE(ce_clk, "ce", ce_parents, 0x680, + 0, 4, /* M */ + 8, 2, /* N */ + 24, 1, /* mux */ + BIT(31),/* gate */ + 0); + +static SUNXI_CCU_GATE(bus_ce_clk, "bus-ce", "psi-ahb1-ahb2", + 0x68c, BIT(0), 0); + +static const char * const ve_parents[] = { "pll-ve" }; +static SUNXI_CCU_M_WITH_MUX_GATE(ve_clk, "ve", ve_parents, 0x690, + 0, 3, /* M */ + 24, 1, /* mux */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_GATE(bus_ve_clk, "bus-ve", "psi-ahb1-ahb2", + 0x69c, BIT(0), 0); + +static SUNXI_CCU_MP_WITH_MUX_GATE(emce_clk, "emce", ce_parents, 0x6b0, + 0, 4, /* M */ + 8, 2, /* N */ + 24, 1, /* mux */ + BIT(31),/* gate */ + 0); + +static SUNXI_CCU_GATE(bus_emce_clk, "bus-emce", "psi-ahb1-ahb2", + 0x6bc, BIT(0), 0); + +static const char * const vp9_parents[] = { "pll-ve", "pll-periph0-2x" }; +static SUNXI_CCU_M_WITH_MUX_GATE(vp9_clk, "vp9", vp9_parents, 0x6c0, + 0, 3, /* M */ + 24, 1, /* mux */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_GATE(bus_vp9_clk, "bus-vp9", "psi-ahb1-ahb2", + 0x6cc, BIT(0), 0); + +static SUNXI_CCU_GATE(bus_dma_clk, "bus-dma", "psi-ahb1-ahb2", + 0x70c, BIT(0), 0); + +static SUNXI_CCU_GATE(bus_msgbox_clk, "bus-msgbox", "psi-ahb1-ahb2", + 0x71c, BIT(0), 0); + +static SUNXI_CCU_GATE(bus_spinlock_clk, "bus-spinlock", "psi-ahb1-ahb2", + 0x72c, BIT(0), 0); + +static SUNXI_CCU_GATE(bus_hstimer_clk, "bus-hstimer", "psi-ahb1-ahb2", + 0x73c, BIT(0), 0); + +static SUNXI_CCU_GATE(avs_clk, "avs", "osc24M", 0x740, BIT(31), 0); + +static SUNXI_CCU_GATE(bus_dbg_clk, "bus-dbg", "psi-ahb1-ahb2", + 0x78c, BIT(0), 0); + +static SUNXI_CCU_GATE(bus_psi_clk, "bus-psi", "psi-ahb1-ahb2", + 0x79c, BIT(0), 0); + +static SUNXI_CCU_GATE(bus_pwm_clk, "bus-pwm", "apb1", 0x79c, BIT(0), 0); + +static SUNXI_CCU_GATE(bus_iommu_clk, "bus-iommu", "apb1", 0x7bc, BIT(0), 0); + +static const char * const dram_parents[] = { "pll-ddr0" }; +static struct ccu_div dram_clk = { + .div = _SUNXI_CCU_DIV(0, 2), + .mux = _SUNXI_CCU_MUX(24, 2), + .common = { + .reg = 0x800, + .hw.init = CLK_HW_INIT_PARENTS("dram", + dram_parents, + &ccu_div_ops, + CLK_IS_CRITICAL), + }, +}; + +static SUNXI_CCU_GATE(mbus_dma_clk, "mbus-dma", "mbus", + 0x804, BIT(0), 0); +static SUNXI_CCU_GATE(mbus_ve_clk, "mbus-ve", "mbus", + 0x804, BIT(1), 0); +static SUNXI_CCU_GATE(mbus_ce_clk, "mbus-ce", "mbus", + 0x804, BIT(2), 0); +static SUNXI_CCU_GATE(mbus_ts_clk, "mbus-ts", "mbus", + 0x804, BIT(3), 0); +static SUNXI_CCU_GATE(mbus_nand_clk, "mbus-nand", "mbus", + 0x804, BIT(5), 0); +static SUNXI_CCU_GATE(mbus_csi_clk, "mbus-csi", "mbus", + 0x804, BIT(8), 0); +static SUNXI_CCU_GATE(mbus_deinterlace_clk, "mbus-deinterlace", "mbus", + 0x804, BIT(11), 0); + +static SUNXI_CCU_GATE(bus_dram_clk, "bus-dram", "psi-ahb1-ahb2", + 0x80c, BIT(0), CLK_IS_CRITICAL); + +static const char * const nand_spi_parents[] = { "osc24M", "pll-periph0", + "pll-periph1", "pll-periph0-2x", + "pll-periph1-2x" }; +static SUNXI_CCU_MP_WITH_MUX_GATE(nand0_clk, "nand0", nand_spi_parents, 0x810, + 0, 4, /* M */ + 8, 2, /* N */ + 24, 3, /* mux */ + BIT(31),/* gate */ + 0); + +static SUNXI_CCU_MP_WITH_MUX_GATE(nand1_clk, "nand1", nand_spi_parents, 0x814, + 0, 4, /* M */ + 8, 2, /* N */ + 24, 3, /* mux */ + BIT(31),/* gate */ + 0); + +static SUNXI_CCU_GATE(bus_nand_clk, "bus-nand", "ahb3", 0x82c, BIT(0), 0); + +static const char * const mmc_parents[] = { "osc24M", "pll-periph0-2x", + "pll-periph1-2x" }; +static SUNXI_CCU_MP_WITH_MUX_GATE(mmc0_clk, "mmc0", mmc_parents, 0x830, + 0, 4, /* M */ + 8, 2, /* N */ + 24, 3, /* mux */ + BIT(31),/* gate */ + 0); + +static SUNXI_CCU_MP_WITH_MUX_GATE(mmc1_clk, "mmc1", mmc_parents, 0x834, + 0, 4, /* M */ + 8, 2, /* N */ + 24, 3, /* mux */ + BIT(31),/* gate */ + 0); + +static SUNXI_CCU_MP_WITH_MUX_GATE(mmc2_clk, "mmc2", mmc_parents, 0x838, + 0, 4, /* M */ + 8, 2, /* N */ + 24, 3, /* mux */ + BIT(31),/* gate */ + 0); + +static SUNXI_CCU_GATE(bus_mmc0_clk, "bus-mmc0", "ahb3", 0x84c, BIT(0), 0); +static SUNXI_CCU_GATE(bus_mmc1_clk, "bus-mmc1", "ahb3", 0x84c, BIT(1), 0); +static SUNXI_CCU_GATE(bus_mmc2_clk, "bus-mmc2", "ahb3", 0x84c, BIT(2), 0); + +static SUNXI_CCU_GATE(bus_uart0_clk, "bus-uart0", "apb2", 0x90c, BIT(0), 0); +static SUNXI_CCU_GATE(bus_uart1_clk, "bus-uart1", "apb2", 0x90c, BIT(1), 0); +static SUNXI_CCU_GATE(bus_uart2_clk, "bus-uart2", "apb2", 0x90c, BIT(2), 0); +static SUNXI_CCU_GATE(bus_uart3_clk, "bus-uart3", "apb2", 0x90c, BIT(3), 0); + +static SUNXI_CCU_GATE(bus_i2c0_clk, "bus-i2c0", "apb2", 0x91c, BIT(0), 0); +static SUNXI_CCU_GATE(bus_i2c1_clk, "bus-i2c1", "apb2", 0x91c, BIT(1), 0); +static SUNXI_CCU_GATE(bus_i2c2_clk, "bus-i2c2", "apb2", 0x91c, BIT(2), 0); +static SUNXI_CCU_GATE(bus_i2c3_clk, "bus-i2c3", "apb2", 0x91c, BIT(3), 0); + +static SUNXI_CCU_GATE(bus_scr0_clk, "bus-scr0", "apb2", 0x93c, BIT(0), 0); +static SUNXI_CCU_GATE(bus_scr1_clk, "bus-scr1", "apb2", 0x93c, BIT(1), 0); + +static SUNXI_CCU_MP_WITH_MUX_GATE(spi0_clk, "spi0", nand_spi_parents, 0x940, + 0, 4, /* M */ + 8, 2, /* N */ + 24, 3, /* mux */ + BIT(31),/* gate */ + 0); + +static SUNXI_CCU_MP_WITH_MUX_GATE(spi1_clk, "spi1", nand_spi_parents, 0x944, + 0, 4, /* M */ + 8, 2, /* N */ + 24, 3, /* mux */ + BIT(31),/* gate */ + 0); + +static SUNXI_CCU_GATE(bus_spi0_clk, "bus-spi0", "ahb3", 0x96c, BIT(0), 0); +static SUNXI_CCU_GATE(bus_spi1_clk, "bus-spi1", "ahb3", 0x96c, BIT(1), 0); + +static SUNXI_CCU_GATE(bus_emac_clk, "bus-emac", "ahb3", 0x97c, BIT(0), 0); + +static const char * const ts_parents[] = { "osc24M", "pll-periph0" }; +static SUNXI_CCU_MP_WITH_MUX_GATE(ts_clk, "ts", ts_parents, 0x9b0, + 0, 4, /* M */ + 8, 2, /* N */ + 24, 1, /* mux */ + BIT(31),/* gate */ + 0); + +static SUNXI_CCU_GATE(bus_ts_clk, "bus-ts", "ahb3", 0x9bc, BIT(0), 0); + +static const char * const ir_tx_parents[] = { "osc32k", "osc24M" }; +static SUNXI_CCU_MP_WITH_MUX_GATE(ir_tx_clk, "ir-tx", ir_tx_parents, 0x9c0, + 0, 4, /* M */ + 8, 2, /* N */ + 24, 1, /* mux */ + BIT(31),/* gate */ + 0); + +static SUNXI_CCU_GATE(bus_ir_tx_clk, "bus-ir-tx", "apb1", 0x9cc, BIT(0), 0); + +static SUNXI_CCU_GATE(bus_ths_clk, "bus-ths", "apb1", 0x9fc, BIT(0), 0); + +static const char * const audio_parents[] = { "pll-audio", "pll-audio-2x", "pll-audio-4x" }; +static struct ccu_div i2s3_clk = { + .enable = BIT(31), + .div = _SUNXI_CCU_DIV_FLAGS(8, 2, CLK_DIVIDER_POWER_OF_TWO), + .mux = _SUNXI_CCU_MUX(24, 2), + .common = { + .reg = 0xa0c, + .hw.init = CLK_HW_INIT_PARENTS("i2s3", + audio_parents, + &ccu_div_ops, + 0), + }, +}; + +static struct ccu_div i2s0_clk = { + .enable = BIT(31), + .div = _SUNXI_CCU_DIV_FLAGS(8, 2, CLK_DIVIDER_POWER_OF_TWO), + .mux = _SUNXI_CCU_MUX(24, 2), + .common = { + .reg = 0xa10, + .hw.init = CLK_HW_INIT_PARENTS("i2s0", + audio_parents, + &ccu_div_ops, + 0), + }, +}; + +static struct ccu_div i2s1_clk = { + .enable = BIT(31), + .div = _SUNXI_CCU_DIV_FLAGS(8, 2, CLK_DIVIDER_POWER_OF_TWO), + .mux = _SUNXI_CCU_MUX(24, 2), + .common = { + .reg = 0xa14, + .hw.init = CLK_HW_INIT_PARENTS("i2s1", + audio_parents, + &ccu_div_ops, + 0), + }, +}; + +static struct ccu_div i2s2_clk = { + .enable = BIT(31), + .div = _SUNXI_CCU_DIV_FLAGS(8, 2, CLK_DIVIDER_POWER_OF_TWO), + .mux = _SUNXI_CCU_MUX(24, 2), + .common = { + .reg = 0xa18, + .hw.init = CLK_HW_INIT_PARENTS("i2s2", + audio_parents, + &ccu_div_ops, + 0), + }, +}; + +static SUNXI_CCU_GATE(bus_i2s0_clk, "bus-i2s0", "apb1", 0xa1c, BIT(0), 0); +static SUNXI_CCU_GATE(bus_i2s1_clk, "bus-i2s1", "apb1", 0xa1c, BIT(1), 0); +static SUNXI_CCU_GATE(bus_i2s2_clk, "bus-i2s2", "apb1", 0xa1c, BIT(2), 0); +static SUNXI_CCU_GATE(bus_i2s3_clk, "bus-i2s3", "apb1", 0xa1c, BIT(3), 0); + +static struct ccu_div spdif_clk = { + .enable = BIT(31), + .div = _SUNXI_CCU_DIV_FLAGS(8, 2, CLK_DIVIDER_POWER_OF_TWO), + .mux = _SUNXI_CCU_MUX(24, 2), + .common = { + .reg = 0xa20, + .hw.init = CLK_HW_INIT_PARENTS("spdif", + audio_parents, + &ccu_div_ops, + 0), + }, +}; + +static SUNXI_CCU_GATE(bus_spdif_clk, "bus-spdif", "apb1", 0xa2c, BIT(0), 0); + +static struct ccu_div dmic_clk = { + .enable = BIT(31), + .div = _SUNXI_CCU_DIV_FLAGS(8, 2, CLK_DIVIDER_POWER_OF_TWO), + .mux = _SUNXI_CCU_MUX(24, 2), + .common = { + .reg = 0xa40, + .hw.init = CLK_HW_INIT_PARENTS("dmic", + audio_parents, + &ccu_div_ops, + 0), + }, +}; + +static SUNXI_CCU_GATE(bus_dmic_clk, "bus-dmic", "apb1", 0xa4c, BIT(0), 0); + +static struct ccu_div audio_hub_clk = { + .enable = BIT(31), + .div = _SUNXI_CCU_DIV_FLAGS(8, 2, CLK_DIVIDER_POWER_OF_TWO), + .mux = _SUNXI_CCU_MUX(24, 2), + .common = { + .reg = 0xa60, + .hw.init = CLK_HW_INIT_PARENTS("audio-hub", + audio_parents, + &ccu_div_ops, + 0), + }, +}; + +static SUNXI_CCU_GATE(bus_audio_hub_clk, "bus-audio-hub", "apb1", 0xa6c, BIT(0), 0); + +/* + * There are OHCI 12M clock source selection bits for 2 USB 2.0 ports. + * We will force them to 0 (12M divided from 48M). + */ +#define SUN50I_H6_USB0_CLK_REG 0xa70 +#define SUN50I_H6_USB3_CLK_REG 0xa7c + +static SUNXI_CCU_GATE(usb_ohci0_clk, "usb-ohci0", "osc12M", 0xa70, BIT(31), 0); +static SUNXI_CCU_GATE(usb_phy0_clk, "usb-phy0", "osc24M", 0xa70, BIT(29), 0); + +static SUNXI_CCU_GATE(usb_phy1_clk, "usb-phy1", "osc24M", 0xa74, BIT(29), 0); + +static SUNXI_CCU_GATE(usb_ohci3_clk, "usb-ohci3", "osc12M", 0xa7c, BIT(31), 0); +static SUNXI_CCU_GATE(usb_phy3_clk, "usb-phy3", "osc12M", 0xa7c, BIT(29), 0); +static SUNXI_CCU_GATE(usb_hsic_12m_clk, "usb-hsic-12M", "osc12M", 0xa7c, BIT(27), 0); +static SUNXI_CCU_GATE(usb_hsic_clk, "usb-hsic", "pll-hsic", 0xa7c, BIT(26), 0); + +static SUNXI_CCU_GATE(bus_ohci0_clk, "bus-ohci0", "ahb3", 0xa8c, BIT(0), 0); +static SUNXI_CCU_GATE(bus_ohci3_clk, "bus-ohci3", "ahb3", 0xa8c, BIT(3), 0); +static SUNXI_CCU_GATE(bus_ehci0_clk, "bus-ehci0", "ahb3", 0xa8c, BIT(4), 0); +static SUNXI_CCU_GATE(bus_xhci_clk, "bus-xhci", "ahb3", 0xa8c, BIT(5), 0); +static SUNXI_CCU_GATE(bus_ehci3_clk, "bus-ehci3", "ahb3", 0xa8c, BIT(7), 0); +static SUNXI_CCU_GATE(bus_otg_clk, "bus-otg", "ahb3", 0xa8c, BIT(8), 0); + +static CLK_FIXED_FACTOR(pcie_ref_100m_clk, "pcie-ref-100M", + "pll-periph0-4x", 24, 1, 0); +static SUNXI_CCU_GATE(pcie_ref_clk, "pcie-ref", "pcie-ref-100M", + 0xab0, BIT(31), 0); +static SUNXI_CCU_GATE(pcie_ref_out_clk, "pcie-ref-out", "pcie-ref", + 0xab0, BIT(30), 0); + +static SUNXI_CCU_M_WITH_GATE(pcie_maxi_clk, "pcie-maxi", + "pll-periph0", 0xab4, + 0, 4, /* M */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_M_WITH_GATE(pcie_aux_clk, "pcie-aux", "osc24M", 0xab8, + 0, 5, /* M */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_GATE(bus_pcie_clk, "bus-pcie", "psi-ahb1-ahb2", + 0xabc, BIT(0), 0); + +static const char * const hdmi_parents[] = { "pll-video0", "pll-video1", + "pll-video1-4x" }; +static SUNXI_CCU_M_WITH_MUX_GATE(hdmi_clk, "hdmi", hdmi_parents, 0xb00, + 0, 4, /* M */ + 24, 2, /* mux */ + BIT(31), /* gate */ + 0); + +static const char * const hdmi_cec_parents[] = { "osc32k", "pll-periph0-2x" }; +static const struct ccu_mux_fixed_prediv hdmi_cec_predivs[] = { + { .index = 1, .div = 36621 }, +}; +static struct ccu_mux hdmi_cec_clk = { + .enable = BIT(31), + + .mux = { + .shift = 24, + .width = 2, + + .fixed_predivs = hdmi_cec_predivs, + .n_predivs = ARRAY_SIZE(hdmi_cec_predivs), + }, + + .common = { + .reg = 0xb10, + .features = CCU_FEATURE_VARIABLE_PREDIV, + .hw.init = CLK_HW_INIT_PARENTS("hdmi-cec", + hdmi_cec_parents, + &ccu_mux_ops, + 0), + }, +}; + +static SUNXI_CCU_GATE(bus_hdmi_clk, "bus-hdmi", "ahb3", 0xb1c, BIT(0), 0); + +static SUNXI_CCU_GATE(bus_tcon_top_clk, "bus-tcon-top", "ahb3", + 0xb5c, BIT(0), 0); + +static const char * const tcon_lcd0_parents[] = { "pll-video0", + "pll-video0-4x", + "pll-video1" }; +static SUNXI_CCU_MUX_WITH_GATE(tcon_lcd0_clk, "tcon-lcd0", + tcon_lcd0_parents, 0xb60, + 24, 3, /* mux */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_GATE(bus_tcon_lcd0_clk, "bus-tcon-lcd0", "ahb3", + 0xb7c, BIT(0), 0); + +static const char * const tcon_tv0_parents[] = { "pll-video0", + "pll-video0-4x", + "pll-video1", + "pll-video1-4x" }; +static SUNXI_CCU_MP_WITH_MUX_GATE(tcon_tv0_clk, "tcon-tv0", + tcon_tv0_parents, 0xb80, + 0, 4, /* M */ + 8, 2, /* P */ + 24, 3, /* mux */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_GATE(bus_tcon_tv0_clk, "bus-tcon-tv0", "ahb3", + 0xb9c, BIT(0), 0); + +static SUNXI_CCU_GATE(csi_cci_clk, "csi-cci", "osc24M", 0xc00, BIT(0), 0); + +static const char * const csi_top_parents[] = { "pll-video0", "pll-ve", + "pll-periph0" }; +static const u8 csi_top_table[] = { 0, 2, 3 }; +static SUNXI_CCU_M_WITH_MUX_TABLE_GATE(csi_top_clk, "csi-top", + csi_top_parents, csi_top_table, 0xc04, + 0, 4, /* M */ + 24, 3, /* mux */ + BIT(31), /* gate */ + 0); + +static const char * const csi_mclk_parents[] = { "osc24M", "pll-video0", + "pll-periph0", "pll-periph1" }; +static SUNXI_CCU_M_WITH_MUX_GATE(csi_mclk_clk, "csi-mclk", + csi_mclk_parents, 0xc08, + 0, 5, /* M */ + 24, 3, /* mux */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_GATE(bus_csi_clk, "bus-csi", "ahb3", 0xc2c, BIT(0), 0); + +static const char * const hdcp_parents[] = { "pll-periph0", "pll-periph1" }; +static SUNXI_CCU_M_WITH_MUX_GATE(hdcp_clk, "hdcp", hdcp_parents, 0xc40, + 0, 4, /* M */ + 24, 2, /* mux */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_GATE(bus_hdcp_clk, "bus-hdcp", "ahb3", 0xc4c, BIT(0), 0); + +/* Fixed factor clocks */ +static CLK_FIXED_FACTOR(osc12M_clk, "osc12M", "osc24M", 2, 1, 0); + +/* + * The divider of pll-audio is fixed to 8 now, as pll-audio-4x has a + * fixed post-divider 2. + */ +static CLK_FIXED_FACTOR(pll_audio_clk, "pll-audio", + "pll-audio-base", 8, 1, CLK_SET_RATE_PARENT); +static CLK_FIXED_FACTOR(pll_audio_2x_clk, "pll-audio-2x", + "pll-audio-base", 4, 1, CLK_SET_RATE_PARENT); +static CLK_FIXED_FACTOR(pll_audio_4x_clk, "pll-audio-4x", + "pll-audio-base", 2, 1, CLK_SET_RATE_PARENT); + +static CLK_FIXED_FACTOR(pll_periph0_4x_clk, "pll-periph0-4x", + "pll-periph0", 1, 4, 0); +static CLK_FIXED_FACTOR(pll_periph0_2x_clk, "pll-periph0-2x", + "pll-periph0", 1, 2, 0); + +static CLK_FIXED_FACTOR(pll_periph1_4x_clk, "pll-periph1-4x", + "pll-periph1", 1, 4, 0); +static CLK_FIXED_FACTOR(pll_periph1_2x_clk, "pll-periph1-2x", + "pll-periph1", 1, 2, 0); + +static CLK_FIXED_FACTOR(pll_video0_4x_clk, "pll-video0-4x", + "pll-video0", 1, 4, CLK_SET_RATE_PARENT); + +static CLK_FIXED_FACTOR(pll_video1_4x_clk, "pll-video1-4x", + "pll-video1", 1, 4, CLK_SET_RATE_PARENT); + +static struct ccu_common *sun50i_h6_ccu_clks[] = { + &pll_cpux_clk.common, + &pll_ddr0_clk.common, + &pll_periph0_clk.common, + &pll_periph1_clk.common, + &pll_gpu_clk.common, + &pll_video0_clk.common, + &pll_video1_clk.common, + &pll_ve_clk.common, + &pll_de_clk.common, + &pll_hsic_clk.common, + &pll_audio_base_clk.common, + &cpux_clk.common, + &axi_clk.common, + &cpux_apb_clk.common, + &psi_ahb1_ahb2_clk.common, + &ahb3_clk.common, + &apb1_clk.common, + &apb2_clk.common, + &mbus_clk.common, + &de_clk.common, + &bus_de_clk.common, + &deinterlace_clk.common, + &bus_deinterlace_clk.common, + &gpu_clk.common, + &bus_gpu_clk.common, + &ce_clk.common, + &bus_ce_clk.common, + &ve_clk.common, + &bus_ve_clk.common, + &emce_clk.common, + &bus_emce_clk.common, + &vp9_clk.common, + &bus_vp9_clk.common, + &bus_dma_clk.common, + &bus_msgbox_clk.common, + &bus_spinlock_clk.common, + &bus_hstimer_clk.common, + &avs_clk.common, + &bus_dbg_clk.common, + &bus_psi_clk.common, + &bus_pwm_clk.common, + &bus_iommu_clk.common, + &dram_clk.common, + &mbus_dma_clk.common, + &mbus_ve_clk.common, + &mbus_ce_clk.common, + &mbus_ts_clk.common, + &mbus_nand_clk.common, + &mbus_csi_clk.common, + &mbus_deinterlace_clk.common, + &bus_dram_clk.common, + &nand0_clk.common, + &nand1_clk.common, + &bus_nand_clk.common, + &mmc0_clk.common, + &mmc1_clk.common, + &mmc2_clk.common, + &bus_mmc0_clk.common, + &bus_mmc1_clk.common, + &bus_mmc2_clk.common, + &bus_uart0_clk.common, + &bus_uart1_clk.common, + &bus_uart2_clk.common, + &bus_uart3_clk.common, + &bus_i2c0_clk.common, + &bus_i2c1_clk.common, + &bus_i2c2_clk.common, + &bus_i2c3_clk.common, + &bus_scr0_clk.common, + &bus_scr1_clk.common, + &spi0_clk.common, + &spi1_clk.common, + &bus_spi0_clk.common, + &bus_spi1_clk.common, + &bus_emac_clk.common, + &ts_clk.common, + &bus_ts_clk.common, + &ir_tx_clk.common, + &bus_ir_tx_clk.common, + &bus_ths_clk.common, + &i2s3_clk.common, + &i2s0_clk.common, + &i2s1_clk.common, + &i2s2_clk.common, + &bus_i2s0_clk.common, + &bus_i2s1_clk.common, + &bus_i2s2_clk.common, + &bus_i2s3_clk.common, + &spdif_clk.common, + &bus_spdif_clk.common, + &dmic_clk.common, + &bus_dmic_clk.common, + &audio_hub_clk.common, + &bus_audio_hub_clk.common, + &usb_ohci0_clk.common, + &usb_phy0_clk.common, + &usb_phy1_clk.common, + &usb_ohci3_clk.common, + &usb_phy3_clk.common, + &usb_hsic_12m_clk.common, + &usb_hsic_clk.common, + &bus_ohci0_clk.common, + &bus_ohci3_clk.common, + &bus_ehci0_clk.common, + &bus_xhci_clk.common, + &bus_ehci3_clk.common, + &bus_otg_clk.common, + &pcie_ref_clk.common, + &pcie_ref_out_clk.common, + &pcie_maxi_clk.common, + &pcie_aux_clk.common, + &bus_pcie_clk.common, + &hdmi_clk.common, + &hdmi_cec_clk.common, + &bus_hdmi_clk.common, + &bus_tcon_top_clk.common, + &tcon_lcd0_clk.common, + &bus_tcon_lcd0_clk.common, + &tcon_tv0_clk.common, + &bus_tcon_tv0_clk.common, + &csi_cci_clk.common, + &csi_top_clk.common, + &csi_mclk_clk.common, + &bus_csi_clk.common, + &hdcp_clk.common, + &bus_hdcp_clk.common, +}; + +static struct clk_hw_onecell_data sun50i_h6_hw_clks = { + .hws = { + [CLK_OSC12M] = &osc12M_clk.hw, + [CLK_PLL_CPUX] = &pll_cpux_clk.common.hw, + [CLK_PLL_DDR0] = &pll_ddr0_clk.common.hw, + [CLK_PLL_PERIPH0] = &pll_periph0_clk.common.hw, + [CLK_PLL_PERIPH0_2X] = &pll_periph0_2x_clk.hw, + [CLK_PLL_PERIPH0_4X] = &pll_periph0_4x_clk.hw, + [CLK_PLL_PERIPH1] = &pll_periph1_clk.common.hw, + [CLK_PLL_PERIPH1_2X] = &pll_periph1_2x_clk.hw, + [CLK_PLL_PERIPH1_4X] = &pll_periph1_4x_clk.hw, + [CLK_PLL_GPU] = &pll_gpu_clk.common.hw, + [CLK_PLL_VIDEO0] = &pll_video0_clk.common.hw, + [CLK_PLL_VIDEO0_4X] = &pll_video0_4x_clk.hw, + [CLK_PLL_VIDEO1] = &pll_video1_clk.common.hw, + [CLK_PLL_VIDEO1_4X] = &pll_video1_4x_clk.hw, + [CLK_PLL_VE] = &pll_ve_clk.common.hw, + [CLK_PLL_DE] = &pll_de_clk.common.hw, + [CLK_PLL_HSIC] = &pll_hsic_clk.common.hw, + [CLK_PLL_AUDIO_BASE] = &pll_audio_base_clk.common.hw, + [CLK_PLL_AUDIO] = &pll_audio_clk.hw, + [CLK_PLL_AUDIO_2X] = &pll_audio_2x_clk.hw, + [CLK_PLL_AUDIO_4X] = &pll_audio_4x_clk.hw, + [CLK_CPUX] = &cpux_clk.common.hw, + [CLK_AXI] = &axi_clk.common.hw, + [CLK_CPUX_APB] = &cpux_apb_clk.common.hw, + [CLK_PSI_AHB1_AHB2] = &psi_ahb1_ahb2_clk.common.hw, + [CLK_AHB3] = &ahb3_clk.common.hw, + [CLK_APB1] = &apb1_clk.common.hw, + [CLK_APB2] = &apb2_clk.common.hw, + [CLK_MBUS] = &mbus_clk.common.hw, + [CLK_DE] = &de_clk.common.hw, + [CLK_BUS_DE] = &bus_de_clk.common.hw, + [CLK_DEINTERLACE] = &deinterlace_clk.common.hw, + [CLK_BUS_DEINTERLACE] = &bus_deinterlace_clk.common.hw, + [CLK_GPU] = &gpu_clk.common.hw, + [CLK_BUS_GPU] = &bus_gpu_clk.common.hw, + [CLK_CE] = &ce_clk.common.hw, + [CLK_BUS_CE] = &bus_ce_clk.common.hw, + [CLK_VE] = &ve_clk.common.hw, + [CLK_BUS_VE] = &bus_ve_clk.common.hw, + [CLK_EMCE] = &emce_clk.common.hw, + [CLK_BUS_EMCE] = &bus_emce_clk.common.hw, + [CLK_VP9] = &vp9_clk.common.hw, + [CLK_BUS_VP9] = &bus_vp9_clk.common.hw, + [CLK_BUS_DMA] = &bus_dma_clk.common.hw, + [CLK_BUS_MSGBOX] = &bus_msgbox_clk.common.hw, + [CLK_BUS_SPINLOCK] = &bus_spinlock_clk.common.hw, + [CLK_BUS_HSTIMER] = &bus_hstimer_clk.common.hw, + [CLK_AVS] = &avs_clk.common.hw, + [CLK_BUS_DBG] = &bus_dbg_clk.common.hw, + [CLK_BUS_PSI] = &bus_psi_clk.common.hw, + [CLK_BUS_PWM] = &bus_pwm_clk.common.hw, + [CLK_BUS_IOMMU] = &bus_iommu_clk.common.hw, + [CLK_DRAM] = &dram_clk.common.hw, + [CLK_MBUS_DMA] = &mbus_dma_clk.common.hw, + [CLK_MBUS_VE] = &mbus_ve_clk.common.hw, + [CLK_MBUS_CE] = &mbus_ce_clk.common.hw, + [CLK_MBUS_TS] = &mbus_ts_clk.common.hw, + [CLK_MBUS_NAND] = &mbus_nand_clk.common.hw, + [CLK_MBUS_CSI] = &mbus_csi_clk.common.hw, + [CLK_MBUS_DEINTERLACE] = &mbus_deinterlace_clk.common.hw, + [CLK_BUS_DRAM] = &bus_dram_clk.common.hw, + [CLK_NAND0] = &nand0_clk.common.hw, + [CLK_NAND1] = &nand1_clk.common.hw, + [CLK_BUS_NAND] = &bus_nand_clk.common.hw, + [CLK_MMC0] = &mmc0_clk.common.hw, + [CLK_MMC1] = &mmc1_clk.common.hw, + [CLK_MMC2] = &mmc2_clk.common.hw, + [CLK_BUS_MMC0] = &bus_mmc0_clk.common.hw, + [CLK_BUS_MMC1] = &bus_mmc1_clk.common.hw, + [CLK_BUS_MMC2] = &bus_mmc2_clk.common.hw, + [CLK_BUS_UART0] = &bus_uart0_clk.common.hw, + [CLK_BUS_UART1] = &bus_uart1_clk.common.hw, + [CLK_BUS_UART2] = &bus_uart2_clk.common.hw, + [CLK_BUS_UART3] = &bus_uart3_clk.common.hw, + [CLK_BUS_I2C0] = &bus_i2c0_clk.common.hw, + [CLK_BUS_I2C1] = &bus_i2c1_clk.common.hw, + [CLK_BUS_I2C2] = &bus_i2c2_clk.common.hw, + [CLK_BUS_I2C3] = &bus_i2c3_clk.common.hw, + [CLK_BUS_SCR0] = &bus_scr0_clk.common.hw, + [CLK_BUS_SCR1] = &bus_scr1_clk.common.hw, + [CLK_SPI0] = &spi0_clk.common.hw, + [CLK_SPI1] = &spi1_clk.common.hw, + [CLK_BUS_SPI0] = &bus_spi0_clk.common.hw, + [CLK_BUS_SPI1] = &bus_spi1_clk.common.hw, + [CLK_BUS_EMAC] = &bus_emac_clk.common.hw, + [CLK_TS] = &ts_clk.common.hw, + [CLK_BUS_TS] = &bus_ts_clk.common.hw, + [CLK_IR_TX] = &ir_tx_clk.common.hw, + [CLK_BUS_IR_TX] = &bus_ir_tx_clk.common.hw, + [CLK_BUS_THS] = &bus_ths_clk.common.hw, + [CLK_I2S3] = &i2s3_clk.common.hw, + [CLK_I2S0] = &i2s0_clk.common.hw, + [CLK_I2S1] = &i2s1_clk.common.hw, + [CLK_I2S2] = &i2s2_clk.common.hw, + [CLK_BUS_I2S0] = &bus_i2s0_clk.common.hw, + [CLK_BUS_I2S1] = &bus_i2s1_clk.common.hw, + [CLK_BUS_I2S2] = &bus_i2s2_clk.common.hw, + [CLK_BUS_I2S3] = &bus_i2s3_clk.common.hw, + [CLK_SPDIF] = &spdif_clk.common.hw, + [CLK_BUS_SPDIF] = &bus_spdif_clk.common.hw, + [CLK_DMIC] = &dmic_clk.common.hw, + [CLK_BUS_DMIC] = &bus_dmic_clk.common.hw, + [CLK_AUDIO_HUB] = &audio_hub_clk.common.hw, + [CLK_BUS_AUDIO_HUB] = &bus_audio_hub_clk.common.hw, + [CLK_USB_OHCI0] = &usb_ohci0_clk.common.hw, + [CLK_USB_PHY0] = &usb_phy0_clk.common.hw, + [CLK_USB_PHY1] = &usb_phy1_clk.common.hw, + [CLK_USB_OHCI3] = &usb_ohci3_clk.common.hw, + [CLK_USB_PHY3] = &usb_phy3_clk.common.hw, + [CLK_USB_HSIC_12M] = &usb_hsic_12m_clk.common.hw, + [CLK_USB_HSIC] = &usb_hsic_clk.common.hw, + [CLK_BUS_OHCI0] = &bus_ohci0_clk.common.hw, + [CLK_BUS_OHCI3] = &bus_ohci3_clk.common.hw, + [CLK_BUS_EHCI0] = &bus_ehci0_clk.common.hw, + [CLK_BUS_XHCI] = &bus_xhci_clk.common.hw, + [CLK_BUS_EHCI3] = &bus_ehci3_clk.common.hw, + [CLK_BUS_OTG] = &bus_otg_clk.common.hw, + [CLK_PCIE_REF_100M] = &pcie_ref_100m_clk.hw, + [CLK_PCIE_REF] = &pcie_ref_clk.common.hw, + [CLK_PCIE_REF_OUT] = &pcie_ref_out_clk.common.hw, + [CLK_PCIE_MAXI] = &pcie_maxi_clk.common.hw, + [CLK_PCIE_AUX] = &pcie_aux_clk.common.hw, + [CLK_BUS_PCIE] = &bus_pcie_clk.common.hw, + [CLK_HDMI] = &hdmi_clk.common.hw, + [CLK_HDMI_CEC] = &hdmi_cec_clk.common.hw, + [CLK_BUS_HDMI] = &bus_hdmi_clk.common.hw, + [CLK_BUS_TCON_TOP] = &bus_tcon_top_clk.common.hw, + [CLK_TCON_LCD0] = &tcon_lcd0_clk.common.hw, + [CLK_BUS_TCON_LCD0] = &bus_tcon_lcd0_clk.common.hw, + [CLK_TCON_TV0] = &tcon_tv0_clk.common.hw, + [CLK_BUS_TCON_TV0] = &bus_tcon_tv0_clk.common.hw, + [CLK_CSI_CCI] = &csi_cci_clk.common.hw, + [CLK_CSI_TOP] = &csi_top_clk.common.hw, + [CLK_CSI_MCLK] = &csi_mclk_clk.common.hw, + [CLK_BUS_CSI] = &bus_csi_clk.common.hw, + [CLK_HDCP] = &hdcp_clk.common.hw, + [CLK_BUS_HDCP] = &bus_hdcp_clk.common.hw, + }, + .num = CLK_NUMBER, +}; + +static struct ccu_reset_map sun50i_h6_ccu_resets[] = { + [RST_MBUS] = { 0x540, BIT(30) }, + + [RST_BUS_DE] = { 0x60c, BIT(16) }, + [RST_BUS_DEINTERLACE] = { 0x62c, BIT(16) }, + [RST_BUS_GPU] = { 0x67c, BIT(16) }, + [RST_BUS_CE] = { 0x68c, BIT(16) }, + [RST_BUS_VE] = { 0x69c, BIT(16) }, + [RST_BUS_EMCE] = { 0x6bc, BIT(16) }, + [RST_BUS_VP9] = { 0x6cc, BIT(16) }, + [RST_BUS_DMA] = { 0x70c, BIT(16) }, + [RST_BUS_MSGBOX] = { 0x71c, BIT(16) }, + [RST_BUS_SPINLOCK] = { 0x72c, BIT(16) }, + [RST_BUS_HSTIMER] = { 0x73c, BIT(16) }, + [RST_BUS_DBG] = { 0x78c, BIT(16) }, + [RST_BUS_PSI] = { 0x79c, BIT(16) }, + [RST_BUS_PWM] = { 0x7ac, BIT(16) }, + [RST_BUS_IOMMU] = { 0x7bc, BIT(16) }, + [RST_BUS_DRAM] = { 0x80c, BIT(16) }, + [RST_BUS_NAND] = { 0x82c, BIT(16) }, + [RST_BUS_MMC0] = { 0x84c, BIT(16) }, + [RST_BUS_MMC1] = { 0x84c, BIT(17) }, + [RST_BUS_MMC2] = { 0x84c, BIT(18) }, + [RST_BUS_UART0] = { 0x90c, BIT(16) }, + [RST_BUS_UART1] = { 0x90c, BIT(17) }, + [RST_BUS_UART2] = { 0x90c, BIT(18) }, + [RST_BUS_UART3] = { 0x90c, BIT(19) }, + [RST_BUS_I2C0] = { 0x91c, BIT(16) }, + [RST_BUS_I2C1] = { 0x91c, BIT(17) }, + [RST_BUS_I2C2] = { 0x91c, BIT(18) }, + [RST_BUS_I2C3] = { 0x91c, BIT(19) }, + [RST_BUS_SCR0] = { 0x93c, BIT(16) }, + [RST_BUS_SCR1] = { 0x93c, BIT(17) }, + [RST_BUS_SPI0] = { 0x96c, BIT(16) }, + [RST_BUS_SPI1] = { 0x96c, BIT(17) }, + [RST_BUS_EMAC] = { 0x97c, BIT(16) }, + [RST_BUS_TS] = { 0x9bc, BIT(16) }, + [RST_BUS_IR_TX] = { 0x9cc, BIT(16) }, + [RST_BUS_THS] = { 0x9fc, BIT(16) }, + [RST_BUS_I2S0] = { 0xa1c, BIT(16) }, + [RST_BUS_I2S1] = { 0xa1c, BIT(17) }, + [RST_BUS_I2S2] = { 0xa1c, BIT(18) }, + [RST_BUS_I2S3] = { 0xa1c, BIT(19) }, + [RST_BUS_SPDIF] = { 0xa2c, BIT(16) }, + [RST_BUS_DMIC] = { 0xa4c, BIT(16) }, + [RST_BUS_AUDIO_HUB] = { 0xa6c, BIT(16) }, + + [RST_USB_PHY0] = { 0xa70, BIT(30) }, + [RST_USB_PHY1] = { 0xa74, BIT(30) }, + [RST_USB_PHY3] = { 0xa7c, BIT(30) }, + [RST_USB_HSIC] = { 0xa7c, BIT(28) }, + + [RST_BUS_OHCI0] = { 0xa8c, BIT(16) }, + [RST_BUS_OHCI3] = { 0xa8c, BIT(19) }, + [RST_BUS_EHCI0] = { 0xa8c, BIT(20) }, + [RST_BUS_XHCI] = { 0xa8c, BIT(21) }, + [RST_BUS_EHCI3] = { 0xa8c, BIT(23) }, + [RST_BUS_OTG] = { 0xa8c, BIT(24) }, + [RST_BUS_PCIE] = { 0xabc, BIT(16) }, + + [RST_PCIE_POWERUP] = { 0xabc, BIT(17) }, + + [RST_BUS_HDMI] = { 0xb1c, BIT(16) }, + [RST_BUS_HDMI_SUB] = { 0xb1c, BIT(17) }, + [RST_BUS_TCON_TOP] = { 0xb5c, BIT(16) }, + [RST_BUS_TCON_LCD0] = { 0xb7c, BIT(16) }, + [RST_BUS_TCON_TV0] = { 0xb9c, BIT(16) }, + [RST_BUS_CSI] = { 0xc2c, BIT(16) }, + [RST_BUS_HDCP] = { 0xc4c, BIT(16) }, +}; + +static const struct sunxi_ccu_desc sun50i_h6_ccu_desc = { + .ccu_clks = sun50i_h6_ccu_clks, + .num_ccu_clks = ARRAY_SIZE(sun50i_h6_ccu_clks), + + .hw_clks = &sun50i_h6_hw_clks, + + .resets = sun50i_h6_ccu_resets, + .num_resets = ARRAY_SIZE(sun50i_h6_ccu_resets), +}; + +static const u32 pll_regs[] = { + SUN50I_H6_PLL_CPUX_REG, + SUN50I_H6_PLL_DDR0_REG, + SUN50I_H6_PLL_PERIPH0_REG, + SUN50I_H6_PLL_PERIPH1_REG, + SUN50I_H6_PLL_GPU_REG, + SUN50I_H6_PLL_VIDEO0_REG, + SUN50I_H6_PLL_VIDEO1_REG, + SUN50I_H6_PLL_VE_REG, + SUN50I_H6_PLL_DE_REG, + SUN50I_H6_PLL_HSIC_REG, + SUN50I_H6_PLL_AUDIO_REG, +}; + +static const u32 pll_video_regs[] = { + SUN50I_H6_PLL_VIDEO0_REG, + SUN50I_H6_PLL_VIDEO1_REG, +}; + +static const u32 usb2_clk_regs[] = { + SUN50I_H6_USB0_CLK_REG, + SUN50I_H6_USB3_CLK_REG, +}; + +static int sun50i_h6_ccu_probe(struct platform_device *pdev) +{ + struct resource *res; + void __iomem *reg; + u32 val; + int i; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + reg = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(reg)) + return PTR_ERR(reg); + + /* Enable the lock bits on all PLLs */ + for (i = 0; i < ARRAY_SIZE(pll_regs); i++) { + val = readl(reg + pll_regs[i]); + val |= BIT(29); + writel(val, reg + pll_regs[i]); + } + + /* + * Force the output divider of video PLLs to 0. + * + * See the comment before pll-video0 definition for the reason. + */ + for (i = 0; i < ARRAY_SIZE(pll_video_regs); i++) { + val = readl(reg + pll_video_regs[i]); + val &= ~BIT(0); + writel(val, reg + pll_video_regs[i]); + } + + /* + * Force OHCI 12M clock sources to 00 (12MHz divided from 48MHz) + * + * This clock mux is still mysterious, and the code just enforces + * it to have a valid clock parent. + */ + for (i = 0; i < ARRAY_SIZE(usb2_clk_regs); i++) { + val = readl(reg + usb2_clk_regs[i]); + val &= ~GENMASK(25, 24); + writel (val, reg + usb2_clk_regs[i]); + } + + /* + * Force the post-divider of pll-audio to 8 and the output divider + * of it to 1, to make the clock name represents the real frequency. + */ + val = readl(reg + SUN50I_H6_PLL_AUDIO_REG); + val &= ~(GENMASK(21, 16) | BIT(0)); + writel(val | (7 << 16), reg + SUN50I_H6_PLL_AUDIO_REG); + + return sunxi_ccu_probe(pdev->dev.of_node, reg, &sun50i_h6_ccu_desc); +} + +static const struct of_device_id sun50i_h6_ccu_ids[] = { + { .compatible = "allwinner,sun50i-h6-ccu" }, + { } +}; + +static struct platform_driver sun50i_h6_ccu_driver = { + .probe = sun50i_h6_ccu_probe, + .driver = { + .name = "sun50i-h6-ccu", + .of_match_table = sun50i_h6_ccu_ids, + }, +}; +builtin_platform_driver(sun50i_h6_ccu_driver); diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-h6.h b/drivers/clk/sunxi-ng/ccu-sun50i-h6.h new file mode 100644 index 000000000000..ad6da4aa733c --- /dev/null +++ b/drivers/clk/sunxi-ng/ccu-sun50i-h6.h @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2016 Icenowy Zheng + */ + +#ifndef _CCU_SUN50I_H6_H_ +#define _CCU_SUN50I_H6_H_ + +#include +#include + +#define CLK_OSC12M 0 +#define CLK_PLL_CPUX 1 +#define CLK_PLL_DDR0 2 + +/* PLL_PERIPH0 exported for PRCM */ + +#define CLK_PLL_PERIPH0_2X 4 +#define CLK_PLL_PERIPH0_4X 5 +#define CLK_PLL_PERIPH1 6 +#define CLK_PLL_PERIPH1_2X 7 +#define CLK_PLL_PERIPH1_4X 8 +#define CLK_PLL_GPU 9 +#define CLK_PLL_VIDEO0 10 +#define CLK_PLL_VIDEO0_4X 11 +#define CLK_PLL_VIDEO1 12 +#define CLK_PLL_VIDEO1_4X 13 +#define CLK_PLL_VE 14 +#define CLK_PLL_DE 15 +#define CLK_PLL_HSIC 16 +#define CLK_PLL_AUDIO_BASE 17 +#define CLK_PLL_AUDIO 18 +#define CLK_PLL_AUDIO_2X 19 +#define CLK_PLL_AUDIO_4X 20 + +/* CPUX clock exported for DVFS */ + +#define CLK_AXI 22 +#define CLK_CPUX_APB 23 +#define CLK_PSI_AHB1_AHB2 24 +#define CLK_AHB3 25 + +/* APB1 clock exported for PIO */ + +#define CLK_APB2 27 +#define CLK_MBUS 28 + +/* All module clocks and bus gates are exported except DRAM */ + +#define CLK_DRAM 52 + +#define CLK_BUS_DRAM 60 + +#define CLK_NUMBER 137 + +#endif /* _CCU_SUN50I_H6_H_ */ diff --git a/include/dt-bindings/clock/sun50i-h6-ccu.h b/include/dt-bindings/clock/sun50i-h6-ccu.h new file mode 100644 index 000000000000..6045735a2821 --- /dev/null +++ b/include/dt-bindings/clock/sun50i-h6-ccu.h @@ -0,0 +1,124 @@ +// SPDX-License-Identifier: (GPL-2.0+ or MIT) +/* + * Copyright (C) 2017 Icenowy Zheng + */ + +#ifndef _DT_BINDINGS_CLK_SUN50I_H6_H_ +#define _DT_BINDINGS_CLK_SUN50I_H6_H_ + +#define CLK_PLL_PERIPH0 3 + +#define CLK_CPUX 21 + +#define CLK_APB1 26 + +#define CLK_DE 29 +#define CLK_BUS_DE 30 +#define CLK_DEINTERLACE 31 +#define CLK_BUS_DEINTERLACE 32 +#define CLK_GPU 33 +#define CLK_BUS_GPU 34 +#define CLK_CE 35 +#define CLK_BUS_CE 36 +#define CLK_VE 37 +#define CLK_BUS_VE 38 +#define CLK_EMCE 39 +#define CLK_BUS_EMCE 40 +#define CLK_VP9 41 +#define CLK_BUS_VP9 42 +#define CLK_BUS_DMA 43 +#define CLK_BUS_MSGBOX 44 +#define CLK_BUS_SPINLOCK 45 +#define CLK_BUS_HSTIMER 46 +#define CLK_AVS 47 +#define CLK_BUS_DBG 48 +#define CLK_BUS_PSI 49 +#define CLK_BUS_PWM 50 +#define CLK_BUS_IOMMU 51 + +#define CLK_MBUS_DMA 53 +#define CLK_MBUS_VE 54 +#define CLK_MBUS_CE 55 +#define CLK_MBUS_TS 56 +#define CLK_MBUS_NAND 57 +#define CLK_MBUS_CSI 58 +#define CLK_MBUS_DEINTERLACE 59 + +#define CLK_NAND0 61 +#define CLK_NAND1 62 +#define CLK_BUS_NAND 63 +#define CLK_MMC0 64 +#define CLK_MMC1 65 +#define CLK_MMC2 66 +#define CLK_BUS_MMC0 67 +#define CLK_BUS_MMC1 68 +#define CLK_BUS_MMC2 69 +#define CLK_BUS_UART0 70 +#define CLK_BUS_UART1 71 +#define CLK_BUS_UART2 72 +#define CLK_BUS_UART3 73 +#define CLK_BUS_I2C0 74 +#define CLK_BUS_I2C1 75 +#define CLK_BUS_I2C2 76 +#define CLK_BUS_I2C3 77 +#define CLK_BUS_SCR0 78 +#define CLK_BUS_SCR1 79 +#define CLK_SPI0 80 +#define CLK_SPI1 81 +#define CLK_BUS_SPI0 82 +#define CLK_BUS_SPI1 83 +#define CLK_BUS_EMAC 84 +#define CLK_TS 85 +#define CLK_BUS_TS 86 +#define CLK_IR_TX 87 +#define CLK_BUS_IR_TX 88 +#define CLK_BUS_THS 89 +#define CLK_I2S3 90 +#define CLK_I2S0 91 +#define CLK_I2S1 92 +#define CLK_I2S2 93 +#define CLK_BUS_I2S0 94 +#define CLK_BUS_I2S1 95 +#define CLK_BUS_I2S2 96 +#define CLK_BUS_I2S3 97 +#define CLK_SPDIF 98 +#define CLK_BUS_SPDIF 99 +#define CLK_DMIC 100 +#define CLK_BUS_DMIC 101 +#define CLK_AUDIO_HUB 102 +#define CLK_BUS_AUDIO_HUB 103 +#define CLK_USB_OHCI0 104 +#define CLK_USB_PHY0 105 +#define CLK_USB_PHY1 106 +#define CLK_USB_OHCI3 107 +#define CLK_USB_PHY3 108 +#define CLK_USB_HSIC_12M 109 +#define CLK_USB_HSIC 110 +#define CLK_BUS_OHCI0 111 +#define CLK_BUS_OHCI3 112 +#define CLK_BUS_EHCI0 113 +#define CLK_BUS_XHCI 114 +#define CLK_BUS_EHCI3 115 +#define CLK_BUS_OTG 116 +#define CLK_PCIE_REF_100M 117 +#define CLK_PCIE_REF 118 +#define CLK_PCIE_REF_OUT 119 +#define CLK_PCIE_MAXI 120 +#define CLK_PCIE_AUX 121 +#define CLK_BUS_PCIE 122 +#define CLK_HDMI 123 +#define CLK_HDMI_CEC 124 +#define CLK_BUS_HDMI 125 +#define CLK_BUS_TCON_TOP 126 +#define CLK_TCON_LCD0 127 +#define CLK_BUS_TCON_LCD0 128 +#define CLK_TCON_TV0 129 +#define CLK_BUS_TCON_TV0 130 +#define CLK_CSI_CCI 131 +#define CLK_CSI_TOP 132 +#define CLK_CSI_MCLK 133 +#define CLK_BUS_CSI 134 +#define CLK_HDCP 135 +#define CLK_BUS_HDCP 136 + +#endif /* _DT_BINDINGS_CLK_SUN50I_H6_H_ */ diff --git a/include/dt-bindings/reset/sun50i-h6-ccu.h b/include/dt-bindings/reset/sun50i-h6-ccu.h new file mode 100644 index 000000000000..81106f455097 --- /dev/null +++ b/include/dt-bindings/reset/sun50i-h6-ccu.h @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: (GPL-2.0+ or MIT) +/* + * Copyright (C) 2017 Icenowy Zheng + */ + +#ifndef _DT_BINDINGS_RESET_SUN50I_H6_H_ +#define _DT_BINDINGS_RESET_SUN50I_H6_H_ + +#define RST_MBUS 0 +#define RST_BUS_DE 1 +#define RST_BUS_DEINTERLACE 2 +#define RST_BUS_GPU 3 +#define RST_BUS_CE 4 +#define RST_BUS_VE 5 +#define RST_BUS_EMCE 6 +#define RST_BUS_VP9 7 +#define RST_BUS_DMA 8 +#define RST_BUS_MSGBOX 9 +#define RST_BUS_SPINLOCK 10 +#define RST_BUS_HSTIMER 11 +#define RST_BUS_DBG 12 +#define RST_BUS_PSI 13 +#define RST_BUS_PWM 14 +#define RST_BUS_IOMMU 15 +#define RST_BUS_DRAM 16 +#define RST_BUS_NAND 17 +#define RST_BUS_MMC0 18 +#define RST_BUS_MMC1 19 +#define RST_BUS_MMC2 20 +#define RST_BUS_UART0 21 +#define RST_BUS_UART1 22 +#define RST_BUS_UART2 23 +#define RST_BUS_UART3 24 +#define RST_BUS_I2C0 25 +#define RST_BUS_I2C1 26 +#define RST_BUS_I2C2 27 +#define RST_BUS_I2C3 28 +#define RST_BUS_SCR0 29 +#define RST_BUS_SCR1 30 +#define RST_BUS_SPI0 31 +#define RST_BUS_SPI1 32 +#define RST_BUS_EMAC 33 +#define RST_BUS_TS 34 +#define RST_BUS_IR_TX 35 +#define RST_BUS_THS 36 +#define RST_BUS_I2S0 37 +#define RST_BUS_I2S1 38 +#define RST_BUS_I2S2 39 +#define RST_BUS_I2S3 40 +#define RST_BUS_SPDIF 41 +#define RST_BUS_DMIC 42 +#define RST_BUS_AUDIO_HUB 43 +#define RST_USB_PHY0 44 +#define RST_USB_PHY1 45 +#define RST_USB_PHY3 46 +#define RST_USB_HSIC 47 +#define RST_BUS_OHCI0 48 +#define RST_BUS_OHCI3 49 +#define RST_BUS_EHCI0 50 +#define RST_BUS_XHCI 51 +#define RST_BUS_EHCI3 52 +#define RST_BUS_OTG 53 +#define RST_BUS_PCIE 54 +#define RST_PCIE_POWERUP 55 +#define RST_BUS_HDMI 56 +#define RST_BUS_HDMI_SUB 57 +#define RST_BUS_TCON_TOP 58 +#define RST_BUS_TCON_LCD0 59 +#define RST_BUS_TCON_TV0 60 +#define RST_BUS_CSI 61 +#define RST_BUS_HDCP 62 + +#endif /* _DT_BINDINGS_RESET_SUN50I_H6_H_ */ -- cgit From fec0ef3f52735e1e9ac60f8644d4015ae21c0928 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 14 Feb 2018 17:48:00 +0200 Subject: clk: Re-use DEFINE_SHOW_ATTRIBUTE() macro ...instead of open coding file operations followed by custom ->open() callbacks per each attribute. Signed-off-by: Andy Shevchenko Signed-off-by: Stephen Boyd --- drivers/clk/clk.c | 60 +++++++------------------------------------------------ 1 file changed, 7 insertions(+), 53 deletions(-) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 0f686a9dac3e..cc97b18ac31f 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -2486,19 +2486,7 @@ static int clk_summary_show(struct seq_file *s, void *data) return 0; } - - -static int clk_summary_open(struct inode *inode, struct file *file) -{ - return single_open(file, clk_summary_show, inode->i_private); -} - -static const struct file_operations clk_summary_fops = { - .open = clk_summary_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; +DEFINE_SHOW_ATTRIBUTE(clk_summary); static void clk_dump_one(struct seq_file *s, struct clk_core *c, int level) { @@ -2532,7 +2520,7 @@ static void clk_dump_subtree(struct seq_file *s, struct clk_core *c, int level) seq_putc(s, '}'); } -static int clk_dump(struct seq_file *s, void *data) +static int clk_dump_show(struct seq_file *s, void *data) { struct clk_core *c; bool first_node = true; @@ -2555,19 +2543,7 @@ static int clk_dump(struct seq_file *s, void *data) seq_puts(s, "}\n"); return 0; } - - -static int clk_dump_open(struct inode *inode, struct file *file) -{ - return single_open(file, clk_dump, inode->i_private); -} - -static const struct file_operations clk_dump_fops = { - .open = clk_dump_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; +DEFINE_SHOW_ATTRIBUTE(clk_dump); static const struct { unsigned long flag; @@ -2589,7 +2565,7 @@ static const struct { #undef ENTRY }; -static int clk_flags_dump(struct seq_file *s, void *data) +static int clk_flags_show(struct seq_file *s, void *data) { struct clk_core *core = s->private; unsigned long flags = core->flags; @@ -2608,20 +2584,9 @@ static int clk_flags_dump(struct seq_file *s, void *data) return 0; } +DEFINE_SHOW_ATTRIBUTE(clk_flags); -static int clk_flags_open(struct inode *inode, struct file *file) -{ - return single_open(file, clk_flags_dump, inode->i_private); -} - -static const struct file_operations clk_flags_fops = { - .open = clk_flags_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static int possible_parents_dump(struct seq_file *s, void *data) +static int possible_parents_show(struct seq_file *s, void *data) { struct clk_core *core = s->private; int i; @@ -2633,18 +2598,7 @@ static int possible_parents_dump(struct seq_file *s, void *data) return 0; } - -static int possible_parents_open(struct inode *inode, struct file *file) -{ - return single_open(file, possible_parents_dump, inode->i_private); -} - -static const struct file_operations possible_parents_fops = { - .open = possible_parents_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; +DEFINE_SHOW_ATTRIBUTE(possible_parents); static int clk_debug_create_one(struct clk_core *core, struct dentry *pdentry) { -- cgit From c7e92def1ef4dad7a45f0fcca283da1afd003966 Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Wed, 28 Feb 2018 15:07:51 +0100 Subject: clk: mvebu: cp110: Fix clock tree representation Thanks to new documentation, we have a better view of the clock tree. There were few mistakes in the first version of this driver, the main one being the parental link between the clocks. Actually the tree is more flat that we though. Most of the IP blocks require two clocks: one for the IP itself and one for accessing the registers, and unlike what we wrote there is no link between these two clocks. The other mistakes were about the name of the clocks: the root clock is not the Audio PLL but the PLL0, and what we called the EIP clock is named the x2 Core clock and is used by other IP block than the EIP ones. Signed-off-by: Gregory CLEMENT Signed-off-by: Stephen Boyd --- drivers/clk/mvebu/cp110-system-controller.c | 94 ++++++++++++----------------- 1 file changed, 39 insertions(+), 55 deletions(-) diff --git a/drivers/clk/mvebu/cp110-system-controller.c b/drivers/clk/mvebu/cp110-system-controller.c index ca9a0a536174..75bf7b8f282f 100644 --- a/drivers/clk/mvebu/cp110-system-controller.c +++ b/drivers/clk/mvebu/cp110-system-controller.c @@ -13,18 +13,17 @@ /* * CP110 has 6 core clocks: * - * - APLL (1 Ghz) - * - PPv2 core (1/3 APLL) - * - EIP (1/2 APLL) - * - Core (1/2 EIP) - * - SDIO (2/5 APLL) + * - PLL0 (1 Ghz) + * - PPv2 core (1/3 PLL0) + * - x2 Core (1/2 PLL0) + * - Core (1/2 x2 Core) + * - SDIO (2/5 PLL0) * * - NAND clock, which is either: * - Equal to SDIO clock - * - 2/5 APLL + * - 2/5 PLL0 * - * CP110 has 32 gatable clocks, for the various peripherals in the - * IP. They have fairly complicated parent/child relationships. + * CP110 has 32 gatable clocks, for the various peripherals in the IP. */ #define pr_fmt(fmt) "cp110-system-controller: " fmt @@ -53,9 +52,9 @@ enum { #define CP110_CLK_NUM \ (CP110_MAX_CORE_CLOCKS + CP110_MAX_GATABLE_CLOCKS) -#define CP110_CORE_APLL 0 +#define CP110_CORE_PLL0 0 #define CP110_CORE_PPV2 1 -#define CP110_CORE_EIP 2 +#define CP110_CORE_X2CORE 2 #define CP110_CORE_CORE 3 #define CP110_CORE_NAND 4 #define CP110_CORE_SDIO 5 @@ -237,7 +236,7 @@ static int cp110_syscon_common_probe(struct platform_device *pdev, struct regmap *regmap; struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; - const char *ppv2_name, *apll_name, *core_name, *eip_name, *nand_name, + const char *ppv2_name, *pll0_name, *core_name, *x2core_name, *nand_name, *sdio_name; struct clk_hw_onecell_data *cp110_clk_data; struct clk_hw *hw, **cp110_clks; @@ -263,20 +262,20 @@ static int cp110_syscon_common_probe(struct platform_device *pdev, cp110_clks = cp110_clk_data->hws; cp110_clk_data->num = CP110_CLK_NUM; - /* Register the APLL which is the root of the hw tree */ - apll_name = cp110_unique_name(dev, syscon_node, "apll"); - hw = clk_hw_register_fixed_rate(NULL, apll_name, NULL, 0, + /* Register the PLL0 which is the root of the hw tree */ + pll0_name = cp110_unique_name(dev, syscon_node, "pll0"); + hw = clk_hw_register_fixed_rate(NULL, pll0_name, NULL, 0, 1000 * 1000 * 1000); if (IS_ERR(hw)) { ret = PTR_ERR(hw); - goto fail_apll; + goto fail_pll0; } - cp110_clks[CP110_CORE_APLL] = hw; + cp110_clks[CP110_CORE_PLL0] = hw; - /* PPv2 is APLL/3 */ + /* PPv2 is PLL0/3 */ ppv2_name = cp110_unique_name(dev, syscon_node, "ppv2-core"); - hw = clk_hw_register_fixed_factor(NULL, ppv2_name, apll_name, 0, 1, 3); + hw = clk_hw_register_fixed_factor(NULL, ppv2_name, pll0_name, 0, 1, 3); if (IS_ERR(hw)) { ret = PTR_ERR(hw); goto fail_ppv2; @@ -284,30 +283,32 @@ static int cp110_syscon_common_probe(struct platform_device *pdev, cp110_clks[CP110_CORE_PPV2] = hw; - /* EIP clock is APLL/2 */ - eip_name = cp110_unique_name(dev, syscon_node, "eip"); - hw = clk_hw_register_fixed_factor(NULL, eip_name, apll_name, 0, 1, 2); + /* X2CORE clock is PLL0/2 */ + x2core_name = cp110_unique_name(dev, syscon_node, "x2core"); + hw = clk_hw_register_fixed_factor(NULL, x2core_name, pll0_name, + 0, 1, 2); if (IS_ERR(hw)) { ret = PTR_ERR(hw); goto fail_eip; } - cp110_clks[CP110_CORE_EIP] = hw; + cp110_clks[CP110_CORE_X2CORE] = hw; - /* Core clock is EIP/2 */ + /* Core clock is X2CORE/2 */ core_name = cp110_unique_name(dev, syscon_node, "core"); - hw = clk_hw_register_fixed_factor(NULL, core_name, eip_name, 0, 1, 2); + hw = clk_hw_register_fixed_factor(NULL, core_name, x2core_name, + 0, 1, 2); if (IS_ERR(hw)) { ret = PTR_ERR(hw); goto fail_core; } cp110_clks[CP110_CORE_CORE] = hw; - /* NAND can be either APLL/2.5 or core clock */ + /* NAND can be either PLL0/2.5 or core clock */ nand_name = cp110_unique_name(dev, syscon_node, "nand-core"); if (nand_clk_ctrl & NF_CLOCK_SEL_400_MASK) hw = clk_hw_register_fixed_factor(NULL, nand_name, - apll_name, 0, 2, 5); + pll0_name, 0, 2, 5); else hw = clk_hw_register_fixed_factor(NULL, nand_name, core_name, 0, 1, 1); @@ -318,10 +319,10 @@ static int cp110_syscon_common_probe(struct platform_device *pdev, cp110_clks[CP110_CORE_NAND] = hw; - /* SDIO clock is APLL/2.5 */ + /* SDIO clock is PLL0/2.5 */ sdio_name = cp110_unique_name(dev, syscon_node, "sdio-core"); hw = clk_hw_register_fixed_factor(NULL, sdio_name, - apll_name, 0, 2, 5); + pll0_name, 0, 2, 5); if (IS_ERR(hw)) { ret = PTR_ERR(hw); goto fail_sdio; @@ -341,40 +342,23 @@ static int cp110_syscon_common_probe(struct platform_device *pdev, continue; switch (i) { - case CP110_GATE_AUDIO: - case CP110_GATE_COMM_UNIT: - case CP110_GATE_EIP150: - case CP110_GATE_EIP197: - case CP110_GATE_SLOW_IO: - parent = gate_name[CP110_GATE_MAIN]; - break; - case CP110_GATE_MG: - parent = gate_name[CP110_GATE_MG_CORE]; - break; case CP110_GATE_NAND: parent = nand_name; break; + case CP110_GATE_MG: + case CP110_GATE_GOP_DP: case CP110_GATE_PPV2: parent = ppv2_name; break; case CP110_GATE_SDIO: parent = sdio_name; break; - case CP110_GATE_GOP_DP: - parent = gate_name[CP110_GATE_SDMMC_GOP]; - break; - case CP110_GATE_XOR1: - case CP110_GATE_XOR0: - case CP110_GATE_PCIE_X1_0: - case CP110_GATE_PCIE_X1_1: + case CP110_GATE_MAIN: + case CP110_GATE_PCIE_XOR: case CP110_GATE_PCIE_X4: - parent = gate_name[CP110_GATE_PCIE_XOR]; - break; - case CP110_GATE_SATA: - case CP110_GATE_USB3H0: - case CP110_GATE_USB3H1: - case CP110_GATE_USB3DEV: - parent = gate_name[CP110_GATE_SATA_USB]; + case CP110_GATE_EIP150: + case CP110_GATE_EIP197: + parent = x2core_name; break; default: parent = core_name; @@ -413,12 +397,12 @@ fail_sdio: fail_nand: clk_hw_unregister_fixed_factor(cp110_clks[CP110_CORE_CORE]); fail_core: - clk_hw_unregister_fixed_factor(cp110_clks[CP110_CORE_EIP]); + clk_hw_unregister_fixed_factor(cp110_clks[CP110_CORE_X2CORE]); fail_eip: clk_hw_unregister_fixed_factor(cp110_clks[CP110_CORE_PPV2]); fail_ppv2: - clk_hw_unregister_fixed_rate(cp110_clks[CP110_CORE_APLL]); -fail_apll: + clk_hw_unregister_fixed_rate(cp110_clks[CP110_CORE_PLL0]); +fail_pll0: return ret; } -- cgit From 55a5fcafe3a94e8a0777bb993d09107d362258d2 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Thu, 1 Mar 2018 11:27:50 +0800 Subject: dt-bindings: clock: mediatek: add binding for fixed-factor clock axisel_d4 Just add binding for a fixed-factor clock axisel_d4, which would be referenced by PWM devices on MT7623 or MT2701 SoC. Cc: stable@vger.kernel.org Fixes: 1de9b21633d6 ("clk: mediatek: Add dt-bindings for MT2701 clocks") Signed-off-by: Sean Wang Reviewed-by: Rob Herring Cc: Mark Rutland Cc: devicetree@vger.kernel.org Signed-off-by: Stephen Boyd --- include/dt-bindings/clock/mt2701-clk.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/dt-bindings/clock/mt2701-clk.h b/include/dt-bindings/clock/mt2701-clk.h index 551f7600ab58..24e93dfcee9f 100644 --- a/include/dt-bindings/clock/mt2701-clk.h +++ b/include/dt-bindings/clock/mt2701-clk.h @@ -176,7 +176,8 @@ #define CLK_TOP_AUD_EXT1 156 #define CLK_TOP_AUD_EXT2 157 #define CLK_TOP_NFI1X_PAD 158 -#define CLK_TOP_NR 159 +#define CLK_TOP_AXISEL_D4 159 +#define CLK_TOP_NR 160 /* APMIXEDSYS */ -- cgit From 89cd7aec21af26fd0c117bfc4bfc781724f201de Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Thu, 1 Mar 2018 11:27:51 +0800 Subject: clk: mediatek: fix PWM clock source by adding a fixed-factor clock The clock for which all PWM devices on MT7623 or MT2701 actually depending on has to be divided by four from its parent clock axi_sel in the clock path prior to PWM devices. Consequently, adding a fixed-factor clock axisel_d4 as one-fourth of clock axi_sel allows that PWM devices can have the correct resolution calculation. Cc: stable@vger.kernel.org Fixes: e9862118272a ("clk: mediatek: Add MT2701 clock support") Signed-off-by: Sean Wang Signed-off-by: Stephen Boyd --- drivers/clk/mediatek/clk-mt2701.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/drivers/clk/mediatek/clk-mt2701.c b/drivers/clk/mediatek/clk-mt2701.c index 8e7f16fd87c9..deca7527f92f 100644 --- a/drivers/clk/mediatek/clk-mt2701.c +++ b/drivers/clk/mediatek/clk-mt2701.c @@ -148,6 +148,7 @@ static const struct mtk_fixed_factor top_fixed_divs[] = { FACTOR(CLK_TOP_CLK26M_D8, "clk26m_d8", "clk26m", 1, 8), FACTOR(CLK_TOP_32K_INTERNAL, "32k_internal", "clk26m", 1, 793), FACTOR(CLK_TOP_32K_EXTERNAL, "32k_external", "rtc32k", 1, 1), + FACTOR(CLK_TOP_AXISEL_D4, "axisel_d4", "axi_sel", 1, 4), }; static const char * const axi_parents[] = { @@ -857,13 +858,13 @@ static const struct mtk_gate peri_clks[] = { GATE_PERI0(CLK_PERI_USB1, "usb1_ck", "usb20_sel", 11), GATE_PERI0(CLK_PERI_USB0, "usb0_ck", "usb20_sel", 10), GATE_PERI0(CLK_PERI_PWM, "pwm_ck", "axi_sel", 9), - GATE_PERI0(CLK_PERI_PWM7, "pwm7_ck", "axi_sel", 8), - GATE_PERI0(CLK_PERI_PWM6, "pwm6_ck", "axi_sel", 7), - GATE_PERI0(CLK_PERI_PWM5, "pwm5_ck", "axi_sel", 6), - GATE_PERI0(CLK_PERI_PWM4, "pwm4_ck", "axi_sel", 5), - GATE_PERI0(CLK_PERI_PWM3, "pwm3_ck", "axi_sel", 4), - GATE_PERI0(CLK_PERI_PWM2, "pwm2_ck", "axi_sel", 3), - GATE_PERI0(CLK_PERI_PWM1, "pwm1_ck", "axi_sel", 2), + GATE_PERI0(CLK_PERI_PWM7, "pwm7_ck", "axisel_d4", 8), + GATE_PERI0(CLK_PERI_PWM6, "pwm6_ck", "axisel_d4", 7), + GATE_PERI0(CLK_PERI_PWM5, "pwm5_ck", "axisel_d4", 6), + GATE_PERI0(CLK_PERI_PWM4, "pwm4_ck", "axisel_d4", 5), + GATE_PERI0(CLK_PERI_PWM3, "pwm3_ck", "axisel_d4", 4), + GATE_PERI0(CLK_PERI_PWM2, "pwm2_ck", "axisel_d4", 3), + GATE_PERI0(CLK_PERI_PWM1, "pwm1_ck", "axisel_d4", 2), GATE_PERI0(CLK_PERI_THERM, "therm_ck", "axi_sel", 1), GATE_PERI0(CLK_PERI_NFI, "nfi_ck", "nfi2x_sel", 0), -- cgit From 936ceb12c5f72cd087149e3cf01347969a472801 Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Tue, 6 Mar 2018 17:09:26 +0800 Subject: clk: mediatek: update missing clock data for MT7622 audsys Add missing clock data 'CLK_AUDIO_AFE_CONN' for MT7622 audsys. Signed-off-by: Ryder Lee Reviewed-by: Rob Herring Reviewed-by: Matthias Brugger Signed-off-by: Stephen Boyd --- drivers/clk/mediatek/clk-mt7622-aud.c | 1 + include/dt-bindings/clock/mt7622-clk.h | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/clk/mediatek/clk-mt7622-aud.c b/drivers/clk/mediatek/clk-mt7622-aud.c index fad7d9fc53ba..13f752de7adc 100644 --- a/drivers/clk/mediatek/clk-mt7622-aud.c +++ b/drivers/clk/mediatek/clk-mt7622-aud.c @@ -106,6 +106,7 @@ static const struct mtk_gate audio_clks[] = { GATE_AUDIO1(CLK_AUDIO_INTDIR, "audio_intdir", "intdir_sel", 20), GATE_AUDIO1(CLK_AUDIO_A1SYS, "audio_a1sys", "a1sys_hp_sel", 21), GATE_AUDIO1(CLK_AUDIO_A2SYS, "audio_a2sys", "a2sys_hp_sel", 22), + GATE_AUDIO1(CLK_AUDIO_AFE_CONN, "audio_afe_conn", "a1sys_hp_sel", 23), /* AUDIO2 */ GATE_AUDIO2(CLK_AUDIO_UL1, "audio_ul1", "a1sys_hp_sel", 0), GATE_AUDIO2(CLK_AUDIO_UL2, "audio_ul2", "a1sys_hp_sel", 1), diff --git a/include/dt-bindings/clock/mt7622-clk.h b/include/dt-bindings/clock/mt7622-clk.h index 3e514ed51d15..e9d77f0e8bce 100644 --- a/include/dt-bindings/clock/mt7622-clk.h +++ b/include/dt-bindings/clock/mt7622-clk.h @@ -235,7 +235,8 @@ #define CLK_AUDIO_MEM_ASRC3 43 #define CLK_AUDIO_MEM_ASRC4 44 #define CLK_AUDIO_MEM_ASRC5 45 -#define CLK_AUDIO_NR_CLK 46 +#define CLK_AUDIO_AFE_CONN 46 +#define CLK_AUDIO_NR_CLK 47 /* SSUSBSYS */ -- cgit From 2817a92dd90ab8c53f2c03b7c4d5f8590ee36940 Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Tue, 6 Mar 2018 17:09:29 +0800 Subject: dt-bindings: clock: mediatek: update audsys documentation to adapt MFD device The MediaTek audio hardware block that exposes functionalities that are handled by separate subsystems in the kernel. These functions are all mapped somewhere at 0x112xxxxx, and there are some control bits are mixed up with other functions within the same registers. This patch modifies example to illustrate child nodes. Signed-off-by: Ryder Lee Signed-off-by: Stephen Boyd --- .../bindings/arm/mediatek/mediatek,audsys.txt | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,audsys.txt b/Documentation/devicetree/bindings/arm/mediatek/mediatek,audsys.txt index 9b8f578d5e19..97b304eaa47c 100644 --- a/Documentation/devicetree/bindings/arm/mediatek/mediatek,audsys.txt +++ b/Documentation/devicetree/bindings/arm/mediatek/mediatek,audsys.txt @@ -13,10 +13,19 @@ The AUDSYS controller uses the common clk binding from Documentation/devicetree/bindings/clock/clock-bindings.txt The available clocks are defined in dt-bindings/clock/mt*-clk.h. +Required sub-nodes: +------- +For common binding part and usage, refer to +../sonud/mt2701-afe-pcm.txt. + Example: -audsys: audsys@11220000 { - compatible = "mediatek,mt7622-audsys", "syscon"; - reg = <0 0x11220000 0 0x1000>; - #clock-cells = <1>; -}; + audsys: clock-controller@11220000 { + compatible = "mediatek,mt7622-audsys", "syscon"; + reg = <0 0x11220000 0 0x2000>; + #clock-cells = <1>; + + afe: audio-controller { + ... + }; + }; -- cgit From 9cb12501f38f924567ea7ba10041d32ecd7bf809 Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Tue, 6 Mar 2018 17:09:30 +0800 Subject: dt-bindings: clock: mediatek: add audsys support for MT2701 This patch adds a compatible string for MT2701. Signed-off-by: Ryder Lee Signed-off-by: Stephen Boyd --- Documentation/devicetree/bindings/arm/mediatek/mediatek,audsys.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,audsys.txt b/Documentation/devicetree/bindings/arm/mediatek/mediatek,audsys.txt index 97b304eaa47c..34a69ba67f13 100644 --- a/Documentation/devicetree/bindings/arm/mediatek/mediatek,audsys.txt +++ b/Documentation/devicetree/bindings/arm/mediatek/mediatek,audsys.txt @@ -6,6 +6,7 @@ The MediaTek AUDSYS controller provides various clocks to the system. Required Properties: - compatible: Should be one of: + - "mediatek,mt2701-audsys", "syscon" - "mediatek,mt7622-audsys", "syscon" - #clock-cells: Must be 1 -- cgit From afeb079bc8d8331a18c5371519279682f563f4bf Mon Sep 17 00:00:00 2001 From: Katsuhiro Suzuki Date: Thu, 8 Mar 2018 17:23:32 +0900 Subject: clk: uniphier: add Pro4/Pro5/PXs2 audio system clock Add clock for audio subsystem (AIO) on UniPhier Pro4/Pro5/PXs2 SoCs. Signed-off-by: Katsuhiro Suzuki Acked-by: Masahiro Yamada Signed-off-by: Stephen Boyd --- drivers/clk/uniphier/clk-uniphier-sys.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/clk/uniphier/clk-uniphier-sys.c b/drivers/clk/uniphier/clk-uniphier-sys.c index d244e724e198..06c5269f63f5 100644 --- a/drivers/clk/uniphier/clk-uniphier-sys.c +++ b/drivers/clk/uniphier/clk-uniphier-sys.c @@ -57,6 +57,14 @@ #define UNIPHIER_PRO4_SYS_CLK_USB3(idx, ch) \ UNIPHIER_CLK_GATE("usb3" #ch, (idx), NULL, 0x2104, 16 + (ch)) +#define UNIPHIER_PRO4_SYS_CLK_AIO(idx) \ + UNIPHIER_CLK_FACTOR("aio-io200m", -1, "spll", 1, 8), \ + UNIPHIER_CLK_GATE("aio", (idx), "aio-io200m", 0x2104, 13) + +#define UNIPHIER_PRO5_SYS_CLK_AIO(idx) \ + UNIPHIER_CLK_FACTOR("aio-io200m", -1, "spll", 1, 12), \ + UNIPHIER_CLK_GATE("aio", (idx), "aio-io200m", 0x2104, 13) + #define UNIPHIER_LD11_SYS_CLK_AIO(idx) \ UNIPHIER_CLK_FACTOR("aio-io200m", -1, "spll", 1, 10), \ UNIPHIER_CLK_GATE("aio", (idx), "aio-io200m", 0x2108, 0) @@ -104,6 +112,7 @@ const struct uniphier_clk_data uniphier_pro4_sys_clk_data[] = { UNIPHIER_PRO4_SYS_CLK_GIO(12), /* Ether, SATA, USB3 */ UNIPHIER_PRO4_SYS_CLK_USB3(14, 0), UNIPHIER_PRO4_SYS_CLK_USB3(15, 1), + UNIPHIER_PRO4_SYS_CLK_AIO(40), { /* sentinel */ } }; @@ -132,6 +141,7 @@ const struct uniphier_clk_data uniphier_pro5_sys_clk_data[] = { UNIPHIER_PRO4_SYS_CLK_GIO(12), /* PCIe, USB3 */ UNIPHIER_PRO4_SYS_CLK_USB3(14, 0), UNIPHIER_PRO4_SYS_CLK_USB3(15, 1), + UNIPHIER_PRO5_SYS_CLK_AIO(40), { /* sentinel */ } }; @@ -149,6 +159,7 @@ const struct uniphier_clk_data uniphier_pxs2_sys_clk_data[] = { /* The document mentions 0x2104 bit 18, but not functional */ UNIPHIER_CLK_GATE("usb30-phy", 16, NULL, 0x2104, 19), UNIPHIER_CLK_GATE("usb31-phy", 20, NULL, 0x2104, 20), + UNIPHIER_PRO5_SYS_CLK_AIO(40), { /* sentinel */ } }; -- cgit From fa6f3985056eb70ecd8051e560b726495cd1ddf0 Mon Sep 17 00:00:00 2001 From: Gabriel Fernandez Date: Fri, 9 Mar 2018 07:57:30 +0100 Subject: clk: stm32: END_PRIMARY_CLK should be declare after CLK_SYSCLK Update of END_PRIMARY_CLK was missed, it should be after CLK_SYSCLK hsi and sysclk are overwritten by gpioa and gpiob. Signed-off-by: Gabriel Fernandez Tested-by: Philippe Cornu Reviewed-by: Rob Herring Signed-off-by: Stephen Boyd --- include/dt-bindings/clock/stm32fx-clock.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/dt-bindings/clock/stm32fx-clock.h b/include/dt-bindings/clock/stm32fx-clock.h index 49bb3c203e5c..4d523b09aa92 100644 --- a/include/dt-bindings/clock/stm32fx-clock.h +++ b/include/dt-bindings/clock/stm32fx-clock.h @@ -33,11 +33,11 @@ #define CLK_SAI2 11 #define CLK_I2SQ_PDIV 12 #define CLK_SAIQ_PDIV 13 - -#define END_PRIMARY_CLK 14 - #define CLK_HSI 14 #define CLK_SYSCLK 15 + +#define END_PRIMARY_CLK 16 + #define CLK_HDMI_CEC 16 #define CLK_SPDIF 17 #define CLK_USART1 18 -- cgit From 2f05b6b9208470fdd842a362135809df09834208 Mon Sep 17 00:00:00 2001 From: Gabriel Fernandez Date: Fri, 9 Mar 2018 07:57:31 +0100 Subject: clk: stm32: Add DSI clock for STM32F469 Board This patch adds DSI clock for STM32F469 board Signed-off-by: Gabriel Fernandez Reviewed-by: Rob Herring Signed-off-by: Stephen Boyd --- drivers/clk/clk-stm32f4.c | 11 ++++++++++- include/dt-bindings/clock/stm32fx-clock.h | 3 ++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/clk/clk-stm32f4.c b/drivers/clk/clk-stm32f4.c index da44f8dc1d29..3c287980ffb6 100644 --- a/drivers/clk/clk-stm32f4.c +++ b/drivers/clk/clk-stm32f4.c @@ -521,7 +521,7 @@ static const struct stm32f4_pll_data stm32f429_pll[MAX_PLL_DIV] = { }; static const struct stm32f4_pll_data stm32f469_pll[MAX_PLL_DIV] = { - { PLL, 50, { "pll", "pll-q", NULL } }, + { PLL, 50, { "pll", "pll-q", "pll-r" } }, { PLL_I2S, 50, { "plli2s-p", "plli2s-q", "plli2s-r" } }, { PLL_SAI, 50, { "pllsai-p", "pllsai-q", "pllsai-r" } }, }; @@ -1047,6 +1047,8 @@ static const char *rtc_parents[4] = { "no-clock", "lse", "lsi", "hse-rtc" }; +static const char *dsi_parent[2] = { NULL, "pll-r" }; + static const char *lcd_parent[1] = { "pllsai-r-div" }; static const char *i2s_parents[2] = { "plli2s-r", NULL }; @@ -1156,6 +1158,12 @@ static const struct stm32_aux_clk stm32f469_aux_clk[] = { NO_GATE, 0, 0 }, + { + CLK_F469_DSI, "dsi", dsi_parent, ARRAY_SIZE(dsi_parent), + STM32F4_RCC_DCKCFGR, 29, 1, + STM32F4_RCC_APB2ENR, 27, + CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT + }, }; static const struct stm32_aux_clk stm32f746_aux_clk[] = { @@ -1450,6 +1458,7 @@ static void __init stm32f4_rcc_init(struct device_node *np) stm32f4_gate_map = data->gates_map; hse_clk = of_clk_get_parent_name(np, 0); + dsi_parent[0] = hse_clk; i2s_in_clk = of_clk_get_parent_name(np, 1); diff --git a/include/dt-bindings/clock/stm32fx-clock.h b/include/dt-bindings/clock/stm32fx-clock.h index 4d523b09aa92..58d8b515be55 100644 --- a/include/dt-bindings/clock/stm32fx-clock.h +++ b/include/dt-bindings/clock/stm32fx-clock.h @@ -35,8 +35,9 @@ #define CLK_SAIQ_PDIV 13 #define CLK_HSI 14 #define CLK_SYSCLK 15 +#define CLK_F469_DSI 16 -#define END_PRIMARY_CLK 16 +#define END_PRIMARY_CLK 17 #define CLK_HDMI_CEC 16 #define CLK_SPDIF 17 -- cgit From f9acf1057d5bfe56fcc0b8ee36787223ed3fc8be Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Mon, 12 Mar 2018 10:04:07 +0100 Subject: clk: stm32: Add clk entry for SDMMC2 on stm32F769 STM32F769 has 2 SDMMC port, add clock entry for the second one. Signed-off-by: Alexandre TORGUE Signed-off-by: Patrice Chotard Signed-off-by: Stephen Boyd --- drivers/clk/clk-stm32f4.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/clk/clk-stm32f4.c b/drivers/clk/clk-stm32f4.c index 3c287980ffb6..294850bdc195 100644 --- a/drivers/clk/clk-stm32f4.c +++ b/drivers/clk/clk-stm32f4.c @@ -282,6 +282,7 @@ static const struct stm32f4_gate_data stm32f746_gates[] __initconst = { { STM32F4_RCC_APB2ENR, 0, "tim1", "apb2_mul" }, { STM32F4_RCC_APB2ENR, 1, "tim8", "apb2_mul" }, + { STM32F4_RCC_APB2ENR, 7, "sdmmc2", "sdmux" }, { STM32F4_RCC_APB2ENR, 8, "adc1", "apb2_div" }, { STM32F4_RCC_APB2ENR, 9, "adc2", "apb2_div" }, { STM32F4_RCC_APB2ENR, 10, "adc3", "apb2_div" }, @@ -315,7 +316,7 @@ static const u64 stm32f46xx_gate_map[MAX_GATE_MAP] = { 0x000000f17ef417ffull, static const u64 stm32f746_gate_map[MAX_GATE_MAP] = { 0x000000f17ef417ffull, 0x0000000000000003ull, - 0x04f77f033e01c9ffull }; + 0x04f77f833e01c9ffull }; static const u64 *stm32f4_gate_map; -- cgit From da32d3539fca54f36f6069fafe6ee0e4bc7117d0 Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Mon, 12 Mar 2018 10:32:48 +0100 Subject: clk: stm32: add configuration flags for each of the stm32 drivers Add two configuration flags to be able to not compile all the time stm32f and stm32h7 drivers when ARCH_STM32 is set. That help to save some space on those small platforms. Signed-off-by: Benjamin Gaignard Acked-by: Gabriel Fernandez Signed-off-by: Stephen Boyd --- drivers/clk/Kconfig | 14 ++++++++++++++ drivers/clk/Makefile | 4 ++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index cbb9b0c05442..a26cde051158 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -244,6 +244,20 @@ config COMMON_CLK_STM32MP157 ---help--- Support for stm32mp157 SoC family clocks +config COMMON_CLK_STM32F + bool "Clock driver for stm32f4 and stm32f7 SoC families" + depends on MACH_STM32F429 || MACH_STM32F469 || MACH_STM32F746 + help + ---help--- + Support for stm32f4 and stm32f7 SoC families clocks + +config COMMON_CLK_STM32H7 + bool "Clock driver for stm32h7 SoC family" + depends on MACH_STM32H743 + help + ---help--- + Support for stm32h7 SoC family clocks + source "drivers/clk/bcm/Kconfig" source "drivers/clk/hisilicon/Kconfig" source "drivers/clk/imgtec/Kconfig" diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 8d812c701aa6..e0c106ed9407 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -45,8 +45,8 @@ obj-$(CONFIG_COMMON_CLK_SCPI) += clk-scpi.o obj-$(CONFIG_COMMON_CLK_SI5351) += clk-si5351.o obj-$(CONFIG_COMMON_CLK_SI514) += clk-si514.o obj-$(CONFIG_COMMON_CLK_SI570) += clk-si570.o -obj-$(CONFIG_ARCH_STM32) += clk-stm32f4.o -obj-$(CONFIG_ARCH_STM32) += clk-stm32h7.o +obj-$(CONFIG_COMMON_CLK_STM32F) += clk-stm32f4.o +obj-$(CONFIG_COMMON_CLK_STM32H7) += clk-stm32h7.o obj-$(CONFIG_COMMON_CLK_STM32MP157) += clk-stm32mp1.o obj-$(CONFIG_ARCH_TANGO) += clk-tango4.o obj-$(CONFIG_CLK_TWL6040) += clk-twl6040.o -- cgit From 3a49afb84ca074ea4cc537e80d50ee8e5484e7cd Mon Sep 17 00:00:00 2001 From: Riku Voipio Date: Mon, 12 Mar 2018 12:49:45 +0200 Subject: clk: enable hi655x common clk automatically Without COMMON_CLK_HI655X Wifi and bluetooth are non-functional on Hikey. As suggested by Arnd, enable the driver automatically when the parent driver is selected. With sensible defaults in place, we can leave other choices for EXPERT. Cc: John Stultz Cc: Wei Xu Cc: Daniel Lezcano Suggested-by: Arnd Bergmann Signed-off-by: Riku Voipio Reviewed-by: Ulf Hansson Signed-off-by: Stephen Boyd --- drivers/clk/Kconfig | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index 98ce9fc6e6c0..448ce83b334d 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -55,8 +55,10 @@ config COMMON_CLK_RK808 by control register. config COMMON_CLK_HI655X - tristate "Clock driver for Hi655x" - depends on MFD_HI655X_PMIC || COMPILE_TEST + tristate "Clock driver for Hi655x" if EXPERT + depends on (MFD_HI655X_PMIC || COMPILE_TEST) + depends on REGMAP + default MFD_HI655X_PMIC ---help--- This driver supports the hi655x PMIC clock. This multi-function device has one fixed-rate oscillator, clocked -- cgit From 2e838e7f3a8979f9f323214dccb9263fde526b11 Mon Sep 17 00:00:00 2001 From: Mike Looijmans Date: Tue, 13 Mar 2018 09:54:03 +0100 Subject: clk: clk-gpio: Allow GPIO to sleep in set/get_parent When changing or retrieving clock parents, the caller is in a sleepable state (like prepare) so the GPIO operation need not be atomic. Replace gpiod_{g|s}et_value with gpiod_{g|s}et_value_cansleep in the {g|s}et_parent calls for the GPIO based clock mux. This fixes a "slowpath" warning when the GPIO controller is an I2C expander or something similar. Signed-off-by: Mike Looijmans Signed-off-by: Stephen Boyd --- drivers/clk/clk-gpio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/clk/clk-gpio.c b/drivers/clk/clk-gpio.c index 151513c655c3..40af4fbab4d2 100644 --- a/drivers/clk/clk-gpio.c +++ b/drivers/clk/clk-gpio.c @@ -73,14 +73,14 @@ static u8 clk_gpio_mux_get_parent(struct clk_hw *hw) { struct clk_gpio *clk = to_clk_gpio(hw); - return gpiod_get_value(clk->gpiod); + return gpiod_get_value_cansleep(clk->gpiod); } static int clk_gpio_mux_set_parent(struct clk_hw *hw, u8 index) { struct clk_gpio *clk = to_clk_gpio(hw); - gpiod_set_value(clk->gpiod, index); + gpiod_set_value_cansleep(clk->gpiod, index); return 0; } -- cgit From 6a4a4595804548e173f0763a0e7274a3521c59a9 Mon Sep 17 00:00:00 2001 From: Richard Genoud Date: Tue, 13 Mar 2018 16:27:02 +0100 Subject: clk: mvebu: armada-38x: add support for missing clocks Clearfog boards can come with a CPU clocked at 1600MHz (commercial) or 1333MHz (industrial). They have also some dip-switches to select a different clock (666, 800, 1066, 1200). The funny thing is that the recovery button is on the MPP34 fq selector. So, when booting an industrial board with this button down, the frequency 666MHz is selected (and the kernel didn't boot). This patch add all the missing clocks. The only mode I didn't test is 2GHz (uboot found 4294MHz instead :/ ). Fixes: 0e85aeced4d6 ("clk: mvebu: add clock support for Armada 380/385") Cc: # 3.16.x: 9593f4f56cf5: clk: mvebu: armada-38x: add support for 1866MHz variants Cc: # 3.16.x Signed-off-by: Richard Genoud Acked-by: Gregory CLEMENT Signed-off-by: Stephen Boyd --- drivers/clk/mvebu/armada-38x.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/clk/mvebu/armada-38x.c b/drivers/clk/mvebu/armada-38x.c index 394aa6f03f01..9ff4ea63932d 100644 --- a/drivers/clk/mvebu/armada-38x.c +++ b/drivers/clk/mvebu/armada-38x.c @@ -46,11 +46,11 @@ static u32 __init armada_38x_get_tclk_freq(void __iomem *sar) } static const u32 armada_38x_cpu_frequencies[] __initconst = { - 0, 0, 0, 0, - 1066 * 1000 * 1000, 0, 0, 0, + 666 * 1000 * 1000, 0, 800 * 1000 * 1000, 0, + 1066 * 1000 * 1000, 0, 1200 * 1000 * 1000, 0, 1332 * 1000 * 1000, 0, 0, 0, 1600 * 1000 * 1000, 0, 0, 0, - 1866 * 1000 * 1000, + 1866 * 1000 * 1000, 0, 0, 2000 * 1000 * 1000, }; static u32 __init armada_38x_get_cpu_freq(void __iomem *sar) @@ -76,11 +76,11 @@ static const struct coreclk_ratio armada_38x_coreclk_ratios[] __initconst = { }; static const int armada_38x_cpu_l2_ratios[32][2] __initconst = { - {0, 1}, {0, 1}, {0, 1}, {0, 1}, - {1, 2}, {0, 1}, {0, 1}, {0, 1}, - {1, 2}, {0, 1}, {0, 1}, {0, 1}, + {1, 2}, {0, 1}, {1, 2}, {0, 1}, + {1, 2}, {0, 1}, {1, 2}, {0, 1}, {1, 2}, {0, 1}, {0, 1}, {0, 1}, {1, 2}, {0, 1}, {0, 1}, {0, 1}, + {1, 2}, {0, 1}, {0, 1}, {1, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, @@ -91,7 +91,7 @@ static const int armada_38x_cpu_ddr_ratios[32][2] __initconst = { {1, 2}, {0, 1}, {0, 1}, {0, 1}, {1, 2}, {0, 1}, {0, 1}, {0, 1}, {1, 2}, {0, 1}, {0, 1}, {0, 1}, - {1, 2}, {0, 1}, {0, 1}, {0, 1}, + {1, 2}, {0, 1}, {0, 1}, {7, 15}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, -- cgit From 1f9c63e8de3d7b377c9d74e4a17524cfb60e6384 Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Wed, 14 Mar 2018 08:28:31 +0800 Subject: clk: Don't show the incorrect clock phase It's found that the clock phase output from clk_summary is wrong compared to the actual phase reading from the register. cat /sys/kernel/debug/clk/clk_summary | grep sdio_sample sdio_sample 0 1 0 50000000 0 -22 It exposes an issue that clk core, clk_core_get_phase, always returns the cached core->phase which should be either updated by calling clk_set_phase or directly from the first place the clk was registered. When registering the clk, the core->phase geting from ->get_phase() may return negative value indicating error. This is quite common since the clk's phase may be highly related to its parent chain, but it was temporarily orphan when registered, since its parent chains hadn't be ready at that time, so the clk drivers decide to return error in this case. However, if no clk_set_phase is called or maybe the ->set_phase() isn't even implemented, the core->phase would never be updated. This is wrong, and we should try to update it when all its parent chains are settled down, like the way of updating clock rate for that. But it's not deserved to complicate the code now and just update it anyway when calling clk_core_get_phase, which would be much simple and enough. Signed-off-by: Shawn Lin Acked-by: Jerome Brunet Signed-off-by: Stephen Boyd --- drivers/clk/clk.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 617e56268b18..d5c477c7bcf1 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -2373,6 +2373,9 @@ static int clk_core_get_phase(struct clk_core *core) int ret; clk_prepare_lock(); + /* Always try to update cached phase if possible */ + if (core->ops->get_phase) + core->phase = core->ops->get_phase(core->hw); ret = core->phase; clk_prepare_unlock(); -- cgit From cef7b18c3e8bd709b6b4b7bb67ceca662aa5f60e Mon Sep 17 00:00:00 2001 From: Jeffy Chen Date: Mon, 19 Mar 2018 11:58:54 +0800 Subject: clk: lpc32xx: Set name of regmap_config We are now allowing to register debugfs without a valid device, and not having a valid name will end up using "dummy*" to create debugfs dir. Signed-off-by: Jeffy Chen Acked-by: Vladimir Zapolskiy Signed-off-by: Stephen Boyd --- drivers/clk/nxp/clk-lpc32xx.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/nxp/clk-lpc32xx.c b/drivers/clk/nxp/clk-lpc32xx.c index f5d815f577e0..5eeecee17b69 100644 --- a/drivers/clk/nxp/clk-lpc32xx.c +++ b/drivers/clk/nxp/clk-lpc32xx.c @@ -67,6 +67,7 @@ #define LPC32XX_USB_CLK_STS 0xF8 static struct regmap_config lpc32xx_scb_regmap_config = { + .name = "scb", .reg_bits = 32, .val_bits = 32, .reg_stride = 4, -- cgit From 8465baaecafc3d5c5b209a571ffbcc12983216f8 Mon Sep 17 00:00:00 2001 From: Weiyi Lu Date: Mon, 12 Mar 2018 15:03:40 +0800 Subject: dt-bindings: clock: add clocks for MT2712 add new clocks according to ECO design change Signed-off-by: Weiyi Lu Reviewed-by: Rob Herring Signed-off-by: Stephen Boyd --- include/dt-bindings/clock/mt2712-clk.h | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/include/dt-bindings/clock/mt2712-clk.h b/include/dt-bindings/clock/mt2712-clk.h index 48a8e797a617..76265836a1e1 100644 --- a/include/dt-bindings/clock/mt2712-clk.h +++ b/include/dt-bindings/clock/mt2712-clk.h @@ -222,7 +222,13 @@ #define CLK_TOP_APLL_DIV_PDN5 183 #define CLK_TOP_APLL_DIV_PDN6 184 #define CLK_TOP_APLL_DIV_PDN7 185 -#define CLK_TOP_NR_CLK 186 +#define CLK_TOP_APLL1_D3 186 +#define CLK_TOP_APLL1_REF_SEL 187 +#define CLK_TOP_APLL2_REF_SEL 188 +#define CLK_TOP_NFI2X_EN 189 +#define CLK_TOP_NFIECC_EN 190 +#define CLK_TOP_NFI1X_CK_EN 191 +#define CLK_TOP_NR_CLK 192 /* INFRACFG */ @@ -281,7 +287,9 @@ #define CLK_PERI_MSDC30_3_EN 41 #define CLK_PERI_MSDC50_0_HCLK_EN 42 #define CLK_PERI_MSDC50_3_HCLK_EN 43 -#define CLK_PERI_NR_CLK 44 +#define CLK_PERI_MSDC30_0_QTR_EN 44 +#define CLK_PERI_MSDC30_3_QTR_EN 45 +#define CLK_PERI_NR_CLK 46 /* MCUCFG */ -- cgit From f72595cf441bb534e601c609b687451cc9143f13 Mon Sep 17 00:00:00 2001 From: Weiyi Lu Date: Mon, 12 Mar 2018 15:03:42 +0800 Subject: clk: mediatek: update clock driver of MT2712 According to ECO design change, 1. add new clock mux data and change some 2. add new clock gate data and clock factor data 3. change status register offset of infra subsystem Signed-off-by: Weiyi Lu Signed-off-by: Stephen Boyd --- drivers/clk/mediatek/clk-mt2712.c | 69 +++++++++++++++++++++++++++++++-------- 1 file changed, 55 insertions(+), 14 deletions(-) diff --git a/drivers/clk/mediatek/clk-mt2712.c b/drivers/clk/mediatek/clk-mt2712.c index 498d13799388..991d4093726e 100644 --- a/drivers/clk/mediatek/clk-mt2712.c +++ b/drivers/clk/mediatek/clk-mt2712.c @@ -221,6 +221,8 @@ static const struct mtk_fixed_factor top_divs[] = { 4), FACTOR(CLK_TOP_D2A_ULCLK_6P5M, "d2a_ulclk_6p5m", "clk26m", 1, 4), + FACTOR(CLK_TOP_APLL1_D3, "apll1_d3", "apll1_ck", 1, + 3), }; static const char * const axi_parents[] = { @@ -625,7 +627,7 @@ static const char * const ether_125m_parents[] = { static const char * const ether_50m_parents[] = { "clk26m", "etherpll_50m", - "univpll_d26", + "apll1_d3", "univpll3_d4" }; @@ -686,7 +688,7 @@ static const char * const i2c_parents[] = { static const char * const msdc0p_aes_parents[] = { "clk26m", - "msdcpll_ck", + "syspll_d2", "univpll_d3", "vcodecpll_ck" }; @@ -719,6 +721,17 @@ static const char * const aud_apll2_parents[] = { "clkaud_ext_i_2" }; +static const char * const apll1_ref_parents[] = { + "clkaud_ext_i_2", + "clkaud_ext_i_1", + "clki2si0_mck_i", + "clki2si1_mck_i", + "clki2si2_mck_i", + "clktdmin_mclk_i", + "clki2si2_mck_i", + "clktdmin_mclk_i" +}; + static const char * const audull_vtx_parents[] = { "d2a_ulclk_6p5m", "clkaud_ext_i_0" @@ -886,6 +899,10 @@ static struct mtk_composite top_muxes[] = { aud_apll2_parents, 0x134, 1, 1), MUX(CLK_TOP_DA_AUDULL_VTX_6P5M_SEL, "audull_vtx_sel", audull_vtx_parents, 0x134, 31, 1), + MUX(CLK_TOP_APLL1_REF_SEL, "apll1_ref_sel", + apll1_ref_parents, 0x134, 4, 3), + MUX(CLK_TOP_APLL2_REF_SEL, "apll2_ref_sel", + apll1_ref_parents, 0x134, 7, 3), }; static const char * const mcu_mp0_parents[] = { @@ -932,36 +949,56 @@ static const struct mtk_clk_divider top_adj_divs[] = { DIV_ADJ(CLK_TOP_APLL_DIV7, "apll_div7", "i2si3_sel", 0x128, 24, 8), }; -static const struct mtk_gate_regs top_cg_regs = { +static const struct mtk_gate_regs top0_cg_regs = { .set_ofs = 0x120, .clr_ofs = 0x120, .sta_ofs = 0x120, }; -#define GATE_TOP(_id, _name, _parent, _shift) { \ +static const struct mtk_gate_regs top1_cg_regs = { + .set_ofs = 0x424, + .clr_ofs = 0x424, + .sta_ofs = 0x424, +}; + +#define GATE_TOP0(_id, _name, _parent, _shift) { \ .id = _id, \ .name = _name, \ .parent_name = _parent, \ - .regs = &top_cg_regs, \ + .regs = &top0_cg_regs, \ .shift = _shift, \ .ops = &mtk_clk_gate_ops_no_setclr, \ } +#define GATE_TOP1(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &top1_cg_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_ops_no_setclr_inv, \ + } + static const struct mtk_gate top_clks[] = { - GATE_TOP(CLK_TOP_APLL_DIV_PDN0, "apll_div_pdn0", "i2so1_sel", 0), - GATE_TOP(CLK_TOP_APLL_DIV_PDN1, "apll_div_pdn1", "i2so2_sel", 1), - GATE_TOP(CLK_TOP_APLL_DIV_PDN2, "apll_div_pdn2", "i2so3_sel", 2), - GATE_TOP(CLK_TOP_APLL_DIV_PDN3, "apll_div_pdn3", "tdmo0_sel", 3), - GATE_TOP(CLK_TOP_APLL_DIV_PDN4, "apll_div_pdn4", "tdmo1_sel", 4), - GATE_TOP(CLK_TOP_APLL_DIV_PDN5, "apll_div_pdn5", "i2si1_sel", 5), - GATE_TOP(CLK_TOP_APLL_DIV_PDN6, "apll_div_pdn6", "i2si2_sel", 6), - GATE_TOP(CLK_TOP_APLL_DIV_PDN7, "apll_div_pdn7", "i2si3_sel", 7), + /* TOP0 */ + GATE_TOP0(CLK_TOP_APLL_DIV_PDN0, "apll_div_pdn0", "i2so1_sel", 0), + GATE_TOP0(CLK_TOP_APLL_DIV_PDN1, "apll_div_pdn1", "i2so2_sel", 1), + GATE_TOP0(CLK_TOP_APLL_DIV_PDN2, "apll_div_pdn2", "i2so3_sel", 2), + GATE_TOP0(CLK_TOP_APLL_DIV_PDN3, "apll_div_pdn3", "tdmo0_sel", 3), + GATE_TOP0(CLK_TOP_APLL_DIV_PDN4, "apll_div_pdn4", "tdmo1_sel", 4), + GATE_TOP0(CLK_TOP_APLL_DIV_PDN5, "apll_div_pdn5", "i2si1_sel", 5), + GATE_TOP0(CLK_TOP_APLL_DIV_PDN6, "apll_div_pdn6", "i2si2_sel", 6), + GATE_TOP0(CLK_TOP_APLL_DIV_PDN7, "apll_div_pdn7", "i2si3_sel", 7), + /* TOP1 */ + GATE_TOP1(CLK_TOP_NFI2X_EN, "nfi2x_en", "nfi2x_sel", 0), + GATE_TOP1(CLK_TOP_NFIECC_EN, "nfiecc_en", "nfiecc_sel", 1), + GATE_TOP1(CLK_TOP_NFI1X_CK_EN, "nfi1x_ck_en", "nfi2x_sel", 2), }; static const struct mtk_gate_regs infra_cg_regs = { .set_ofs = 0x40, .clr_ofs = 0x44, - .sta_ofs = 0x40, + .sta_ofs = 0x48, }; #define GATE_INFRA(_id, _name, _parent, _shift) { \ @@ -1120,6 +1157,10 @@ static const struct mtk_gate peri_clks[] = { "msdc50_0_h_sel", 4), GATE_PERI2(CLK_PERI_MSDC50_3_HCLK_EN, "per_msdc50_3_h", "msdc50_3_h_sel", 5), + GATE_PERI2(CLK_PERI_MSDC30_0_QTR_EN, "per_msdc30_0_q", + "axi_sel", 6), + GATE_PERI2(CLK_PERI_MSDC30_3_QTR_EN, "per_msdc30_3_q", + "mem_sel", 7), }; #define MT2712_PLL_FMAX (3000UL * MHZ) -- cgit From 8bcde6582c908bc6567c9d38f7b000d199f7f009 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Sun, 18 Mar 2018 14:44:01 +0000 Subject: clk: qcom: rpmcc: Add support to XO buffered clocks XO is onchip buffer clock to generate 19.2MHz. This patch adds support to 5 XO buffer clocks found on PMIC8921, these buffer clocks can be controlled from external pin or in manual mode. Signed-off-by: Srinivas Kandagatla Signed-off-by: Stephen Boyd --- drivers/clk/qcom/clk-rpm.c | 79 +++++++++++++++++++++++++++++++++- include/dt-bindings/clock/qcom,rpmcc.h | 5 +++ 2 files changed, 83 insertions(+), 1 deletion(-) diff --git a/drivers/clk/qcom/clk-rpm.c b/drivers/clk/qcom/clk-rpm.c index c60f61b10c7f..b94981447664 100644 --- a/drivers/clk/qcom/clk-rpm.c +++ b/drivers/clk/qcom/clk-rpm.c @@ -29,6 +29,7 @@ #define QCOM_RPM_MISC_CLK_TYPE 0x306b6c63 #define QCOM_RPM_SCALING_ENABLE_ID 0x2 +#define QCOM_RPM_XO_MODE_ON 0x2 #define DEFINE_CLK_RPM(_platform, _name, _active, r_id) \ static struct clk_rpm _platform##_##_active; \ @@ -56,6 +57,18 @@ }, \ } +#define DEFINE_CLK_RPM_XO_BUFFER(_platform, _name, _active, offset) \ + static struct clk_rpm _platform##_##_name = { \ + .rpm_clk_id = QCOM_RPM_CXO_BUFFERS, \ + .xo_offset = (offset), \ + .hw.init = &(struct clk_init_data){ \ + .ops = &clk_rpm_xo_ops, \ + .name = #_name, \ + .parent_names = (const char *[]){ "cxo_board" }, \ + .num_parents = 1, \ + }, \ + } + #define DEFINE_CLK_RPM_FIXED(_platform, _name, _active, r_id, r) \ static struct clk_rpm _platform##_##_name = { \ .rpm_clk_id = (r_id), \ @@ -126,8 +139,11 @@ #define to_clk_rpm(_hw) container_of(_hw, struct clk_rpm, hw) +struct rpm_cc; + struct clk_rpm { const int rpm_clk_id; + const int xo_offset; const bool active_only; unsigned long rate; bool enabled; @@ -135,12 +151,15 @@ struct clk_rpm { struct clk_rpm *peer; struct clk_hw hw; struct qcom_rpm *rpm; + struct rpm_cc *rpm_cc; }; struct rpm_cc { struct qcom_rpm *rpm; struct clk_rpm **clks; size_t num_clks; + u32 xo_buffer_value; + struct mutex xo_lock; }; struct rpm_clk_desc { @@ -159,7 +178,8 @@ static int clk_rpm_handoff(struct clk_rpm *r) * The vendor tree simply reads the status for this * RPM clock. */ - if (r->rpm_clk_id == QCOM_RPM_PLL_4) + if (r->rpm_clk_id == QCOM_RPM_PLL_4 || + r->rpm_clk_id == QCOM_RPM_CXO_BUFFERS) return 0; ret = qcom_rpm_write(r->rpm, QCOM_RPM_ACTIVE_STATE, @@ -288,6 +308,46 @@ out: mutex_unlock(&rpm_clk_lock); } +static int clk_rpm_xo_prepare(struct clk_hw *hw) +{ + struct clk_rpm *r = to_clk_rpm(hw); + struct rpm_cc *rcc = r->rpm_cc; + int ret, clk_id = r->rpm_clk_id; + u32 value; + + mutex_lock(&rcc->xo_lock); + + value = rcc->xo_buffer_value | (QCOM_RPM_XO_MODE_ON << r->xo_offset); + ret = qcom_rpm_write(r->rpm, QCOM_RPM_ACTIVE_STATE, clk_id, &value, 1); + if (!ret) { + r->enabled = true; + rcc->xo_buffer_value = value; + } + + mutex_unlock(&rcc->xo_lock); + + return ret; +} + +static void clk_rpm_xo_unprepare(struct clk_hw *hw) +{ + struct clk_rpm *r = to_clk_rpm(hw); + struct rpm_cc *rcc = r->rpm_cc; + int ret, clk_id = r->rpm_clk_id; + u32 value; + + mutex_lock(&rcc->xo_lock); + + value = rcc->xo_buffer_value & ~(QCOM_RPM_XO_MODE_ON << r->xo_offset); + ret = qcom_rpm_write(r->rpm, QCOM_RPM_ACTIVE_STATE, clk_id, &value, 1); + if (!ret) { + r->enabled = false; + rcc->xo_buffer_value = value; + } + + mutex_unlock(&rcc->xo_lock); +} + static int clk_rpm_fixed_prepare(struct clk_hw *hw) { struct clk_rpm *r = to_clk_rpm(hw); @@ -378,6 +438,11 @@ static unsigned long clk_rpm_recalc_rate(struct clk_hw *hw, return r->rate; } +static const struct clk_ops clk_rpm_xo_ops = { + .prepare = clk_rpm_xo_prepare, + .unprepare = clk_rpm_xo_unprepare, +}; + static const struct clk_ops clk_rpm_fixed_ops = { .prepare = clk_rpm_fixed_prepare, .unprepare = clk_rpm_fixed_unprepare, @@ -449,6 +514,11 @@ DEFINE_CLK_RPM(apq8064, mmfpb_clk, mmfpb_a_clk, QCOM_RPM_MMFPB_CLK); DEFINE_CLK_RPM(apq8064, sfab_clk, sfab_a_clk, QCOM_RPM_SYS_FABRIC_CLK); DEFINE_CLK_RPM(apq8064, sfpb_clk, sfpb_a_clk, QCOM_RPM_SFPB_CLK); DEFINE_CLK_RPM(apq8064, qdss_clk, qdss_a_clk, QCOM_RPM_QDSS_CLK); +DEFINE_CLK_RPM_XO_BUFFER(apq8064, xo_d0_clk, xo_d0_a_clk, 0); +DEFINE_CLK_RPM_XO_BUFFER(apq8064, xo_d1_clk, xo_d1_a_clk, 8); +DEFINE_CLK_RPM_XO_BUFFER(apq8064, xo_a0_clk, xo_a0_a_clk, 16); +DEFINE_CLK_RPM_XO_BUFFER(apq8064, xo_a1_clk, xo_a1_a_clk, 24); +DEFINE_CLK_RPM_XO_BUFFER(apq8064, xo_a2_clk, xo_a2_a_clk, 28); static struct clk_rpm *apq8064_clks[] = { [RPM_APPS_FABRIC_CLK] = &apq8064_afab_clk, @@ -469,6 +539,11 @@ static struct clk_rpm *apq8064_clks[] = { [RPM_SFPB_A_CLK] = &apq8064_sfpb_a_clk, [RPM_QDSS_CLK] = &apq8064_qdss_clk, [RPM_QDSS_A_CLK] = &apq8064_qdss_a_clk, + [RPM_XO_D0] = &apq8064_xo_d0_clk, + [RPM_XO_D1] = &apq8064_xo_d1_clk, + [RPM_XO_A0] = &apq8064_xo_a0_clk, + [RPM_XO_A1] = &apq8064_xo_a1_clk, + [RPM_XO_A2] = &apq8064_xo_a2_clk, }; static const struct rpm_clk_desc rpm_clk_apq8064 = { @@ -526,12 +601,14 @@ static int rpm_clk_probe(struct platform_device *pdev) rcc->clks = rpm_clks; rcc->num_clks = num_clks; + mutex_init(&rcc->xo_lock); for (i = 0; i < num_clks; i++) { if (!rpm_clks[i]) continue; rpm_clks[i]->rpm = rpm; + rpm_clks[i]->rpm_cc = rcc; ret = clk_rpm_handoff(rpm_clks[i]); if (ret) diff --git a/include/dt-bindings/clock/qcom,rpmcc.h b/include/dt-bindings/clock/qcom,rpmcc.h index b8337a5fa347..c585b82b9c05 100644 --- a/include/dt-bindings/clock/qcom,rpmcc.h +++ b/include/dt-bindings/clock/qcom,rpmcc.h @@ -40,6 +40,11 @@ #define RPM_SMI_CLK 22 #define RPM_SMI_A_CLK 23 #define RPM_PLL4_CLK 24 +#define RPM_XO_D0 25 +#define RPM_XO_D1 26 +#define RPM_XO_A0 27 +#define RPM_XO_A1 28 +#define RPM_XO_A2 29 /* SMD RPM clocks */ #define RPM_SMD_XO_CLK_SRC 0 -- cgit From 037b21133e5367c833908db0226d77138ba4c5eb Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Tue, 20 Mar 2018 11:16:51 +0800 Subject: clk: mediatek: add devm_of_platform_populate() for MT7622 audsys Add devm_of_platform_populate() to populate devices which are children of the root node. Signed-off-by: Ryder Lee Signed-off-by: Stephen Boyd --- drivers/clk/mediatek/clk-mt7622-aud.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/clk/mediatek/clk-mt7622-aud.c b/drivers/clk/mediatek/clk-mt7622-aud.c index 13f752de7adc..4f3d47b41b3e 100644 --- a/drivers/clk/mediatek/clk-mt7622-aud.c +++ b/drivers/clk/mediatek/clk-mt7622-aud.c @@ -150,11 +150,23 @@ static int clk_mt7622_audiosys_init(struct platform_device *pdev) clk_data); r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); - if (r) + if (r) { dev_err(&pdev->dev, "could not register clock provider: %s: %d\n", pdev->name, r); + goto err_clk_provider; + } + + r = devm_of_platform_populate(&pdev->dev); + if (r) + goto err_plat_populate; + + return 0; + +err_plat_populate: + of_clk_del_provider(node); +err_clk_provider: return r; } -- cgit From b572f6393ee54bd4173a4313da8f2fb986a11089 Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Tue, 20 Mar 2018 11:16:52 +0800 Subject: clk: mediatek: add audsys support for MT2701 Add clock driver support for MT2701 audsys. Signed-off-by: Ryder Lee Signed-off-by: Stephen Boyd --- drivers/clk/mediatek/Kconfig | 6 ++ drivers/clk/mediatek/Makefile | 1 + drivers/clk/mediatek/clk-mt2701-aud.c | 186 ++++++++++++++++++++++++++++++++++ 3 files changed, 193 insertions(+) create mode 100644 drivers/clk/mediatek/clk-mt2701-aud.c diff --git a/drivers/clk/mediatek/Kconfig b/drivers/clk/mediatek/Kconfig index 1f9ea0f21df1..92afe5989e97 100644 --- a/drivers/clk/mediatek/Kconfig +++ b/drivers/clk/mediatek/Kconfig @@ -54,6 +54,12 @@ config COMMON_CLK_MT2701_BDPSYS ---help--- This driver supports MediaTek MT2701 bdpsys clocks. +config COMMON_CLK_MT2701_AUDSYS + bool "Clock driver for Mediatek MT2701 audsys" + depends on COMMON_CLK_MT2701 + ---help--- + This driver supports Mediatek MT2701 audsys clocks. + config COMMON_CLK_MT2712 bool "Clock driver for MediaTek MT2712" depends on (ARCH_MEDIATEK && ARM64) || COMPILE_TEST diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile index 5160fdc4bbb8..b80eff2abb31 100644 --- a/drivers/clk/mediatek/Makefile +++ b/drivers/clk/mediatek/Makefile @@ -6,6 +6,7 @@ obj-$(CONFIG_COMMON_CLK_MT6797_MMSYS) += clk-mt6797-mm.o obj-$(CONFIG_COMMON_CLK_MT6797_VDECSYS) += clk-mt6797-vdec.o obj-$(CONFIG_COMMON_CLK_MT6797_VENCSYS) += clk-mt6797-venc.o obj-$(CONFIG_COMMON_CLK_MT2701) += clk-mt2701.o +obj-$(CONFIG_COMMON_CLK_MT2701_AUDSYS) += clk-mt2701-aud.o obj-$(CONFIG_COMMON_CLK_MT2701_BDPSYS) += clk-mt2701-bdp.o obj-$(CONFIG_COMMON_CLK_MT2701_ETHSYS) += clk-mt2701-eth.o obj-$(CONFIG_COMMON_CLK_MT2701_HIFSYS) += clk-mt2701-hif.o diff --git a/drivers/clk/mediatek/clk-mt2701-aud.c b/drivers/clk/mediatek/clk-mt2701-aud.c new file mode 100644 index 000000000000..e66896a44fad --- /dev/null +++ b/drivers/clk/mediatek/clk-mt2701-aud.c @@ -0,0 +1,186 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2018 MediaTek Inc. + * Author: Ryder Lee + */ + +#include +#include +#include +#include +#include + +#include "clk-mtk.h" +#include "clk-gate.h" + +#include + +#define GATE_AUDIO0(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &audio0_cg_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_ops_no_setclr, \ + } + +#define GATE_AUDIO1(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &audio1_cg_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_ops_no_setclr, \ + } + +#define GATE_AUDIO2(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &audio2_cg_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_ops_no_setclr, \ + } + +#define GATE_AUDIO3(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &audio3_cg_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_ops_no_setclr, \ + } + +static const struct mtk_gate_regs audio0_cg_regs = { + .set_ofs = 0x0, + .clr_ofs = 0x0, + .sta_ofs = 0x0, +}; + +static const struct mtk_gate_regs audio1_cg_regs = { + .set_ofs = 0x10, + .clr_ofs = 0x10, + .sta_ofs = 0x10, +}; + +static const struct mtk_gate_regs audio2_cg_regs = { + .set_ofs = 0x14, + .clr_ofs = 0x14, + .sta_ofs = 0x14, +}; + +static const struct mtk_gate_regs audio3_cg_regs = { + .set_ofs = 0x634, + .clr_ofs = 0x634, + .sta_ofs = 0x634, +}; + +static const struct mtk_gate audio_clks[] = { + /* AUDIO0 */ + GATE_AUDIO0(CLK_AUD_AFE, "audio_afe", "aud_intbus_sel", 2), + GATE_AUDIO0(CLK_AUD_HDMI, "audio_hdmi", "audpll_sel", 20), + GATE_AUDIO0(CLK_AUD_SPDF, "audio_spdf", "audpll_sel", 21), + GATE_AUDIO0(CLK_AUD_SPDF2, "audio_spdf2", "audpll_sel", 22), + GATE_AUDIO0(CLK_AUD_APLL, "audio_apll", "audpll_sel", 23), + /* AUDIO1 */ + GATE_AUDIO1(CLK_AUD_I2SIN1, "audio_i2sin1", "aud_mux1_sel", 0), + GATE_AUDIO1(CLK_AUD_I2SIN2, "audio_i2sin2", "aud_mux1_sel", 1), + GATE_AUDIO1(CLK_AUD_I2SIN3, "audio_i2sin3", "aud_mux1_sel", 2), + GATE_AUDIO1(CLK_AUD_I2SIN4, "audio_i2sin4", "aud_mux1_sel", 3), + GATE_AUDIO1(CLK_AUD_I2SIN5, "audio_i2sin5", "aud_mux1_sel", 4), + GATE_AUDIO1(CLK_AUD_I2SIN6, "audio_i2sin6", "aud_mux1_sel", 5), + GATE_AUDIO1(CLK_AUD_I2SO1, "audio_i2so1", "aud_mux1_sel", 6), + GATE_AUDIO1(CLK_AUD_I2SO2, "audio_i2so2", "aud_mux1_sel", 7), + GATE_AUDIO1(CLK_AUD_I2SO3, "audio_i2so3", "aud_mux1_sel", 8), + GATE_AUDIO1(CLK_AUD_I2SO4, "audio_i2so4", "aud_mux1_sel", 9), + GATE_AUDIO1(CLK_AUD_I2SO5, "audio_i2so5", "aud_mux1_sel", 10), + GATE_AUDIO1(CLK_AUD_I2SO6, "audio_i2so6", "aud_mux1_sel", 11), + GATE_AUDIO1(CLK_AUD_ASRCI1, "audio_asrci1", "asm_h_sel", 12), + GATE_AUDIO1(CLK_AUD_ASRCI2, "audio_asrci2", "asm_h_sel", 13), + GATE_AUDIO1(CLK_AUD_ASRCO1, "audio_asrco1", "asm_h_sel", 14), + GATE_AUDIO1(CLK_AUD_ASRCO2, "audio_asrco2", "asm_h_sel", 15), + GATE_AUDIO1(CLK_AUD_INTDIR, "audio_intdir", "intdir_sel", 20), + GATE_AUDIO1(CLK_AUD_A1SYS, "audio_a1sys", "aud_mux1_sel", 21), + GATE_AUDIO1(CLK_AUD_A2SYS, "audio_a2sys", "aud_mux2_sel", 22), + GATE_AUDIO1(CLK_AUD_AFE_CONN, "audio_afe_conn", "aud_mux1_sel", 23), + GATE_AUDIO1(CLK_AUD_AFE_MRGIF, "audio_afe_mrgif", "aud_mux1_sel", 25), + /* AUDIO2 */ + GATE_AUDIO2(CLK_AUD_MMIF_UL1, "audio_ul1", "aud_mux1_sel", 0), + GATE_AUDIO2(CLK_AUD_MMIF_UL2, "audio_ul2", "aud_mux1_sel", 1), + GATE_AUDIO2(CLK_AUD_MMIF_UL3, "audio_ul3", "aud_mux1_sel", 2), + GATE_AUDIO2(CLK_AUD_MMIF_UL4, "audio_ul4", "aud_mux1_sel", 3), + GATE_AUDIO2(CLK_AUD_MMIF_UL5, "audio_ul5", "aud_mux1_sel", 4), + GATE_AUDIO2(CLK_AUD_MMIF_UL6, "audio_ul6", "aud_mux1_sel", 5), + GATE_AUDIO2(CLK_AUD_MMIF_DL1, "audio_dl1", "aud_mux1_sel", 6), + GATE_AUDIO2(CLK_AUD_MMIF_DL2, "audio_dl2", "aud_mux1_sel", 7), + GATE_AUDIO2(CLK_AUD_MMIF_DL3, "audio_dl3", "aud_mux1_sel", 8), + GATE_AUDIO2(CLK_AUD_MMIF_DL4, "audio_dl4", "aud_mux1_sel", 9), + GATE_AUDIO2(CLK_AUD_MMIF_DL5, "audio_dl5", "aud_mux1_sel", 10), + GATE_AUDIO2(CLK_AUD_MMIF_DL6, "audio_dl6", "aud_mux1_sel", 11), + GATE_AUDIO2(CLK_AUD_MMIF_DLMCH, "audio_dlmch", "aud_mux1_sel", 12), + GATE_AUDIO2(CLK_AUD_MMIF_ARB1, "audio_arb1", "aud_mux1_sel", 13), + GATE_AUDIO2(CLK_AUD_MMIF_AWB1, "audio_awb", "aud_mux1_sel", 14), + GATE_AUDIO2(CLK_AUD_MMIF_AWB2, "audio_awb2", "aud_mux1_sel", 15), + GATE_AUDIO2(CLK_AUD_MMIF_DAI, "audio_dai", "aud_mux1_sel", 16), + /* AUDIO3 */ + GATE_AUDIO3(CLK_AUD_ASRCI3, "audio_asrci3", "asm_h_sel", 2), + GATE_AUDIO3(CLK_AUD_ASRCI4, "audio_asrci4", "asm_h_sel", 3), + GATE_AUDIO3(CLK_AUD_ASRCI5, "audio_asrci5", "asm_h_sel", 4), + GATE_AUDIO3(CLK_AUD_ASRCI6, "audio_asrci6", "asm_h_sel", 5), + GATE_AUDIO3(CLK_AUD_ASRCO3, "audio_asrco3", "asm_h_sel", 6), + GATE_AUDIO3(CLK_AUD_ASRCO4, "audio_asrco4", "asm_h_sel", 7), + GATE_AUDIO3(CLK_AUD_ASRCO5, "audio_asrco5", "asm_h_sel", 8), + GATE_AUDIO3(CLK_AUD_ASRCO6, "audio_asrco6", "asm_h_sel", 9), + GATE_AUDIO3(CLK_AUD_MEM_ASRC1, "audio_mem_asrc1", "asm_h_sel", 10), + GATE_AUDIO3(CLK_AUD_MEM_ASRC2, "audio_mem_asrc2", "asm_h_sel", 11), + GATE_AUDIO3(CLK_AUD_MEM_ASRC3, "audio_mem_asrc3", "asm_h_sel", 12), + GATE_AUDIO3(CLK_AUD_MEM_ASRC4, "audio_mem_asrc4", "asm_h_sel", 13), + GATE_AUDIO3(CLK_AUD_MEM_ASRC5, "audio_mem_asrc5", "asm_h_sel", 14), +}; + +static const struct of_device_id of_match_clk_mt2701_aud[] = { + { .compatible = "mediatek,mt2701-audsys", }, + {} +}; + +static int clk_mt2701_aud_probe(struct platform_device *pdev) +{ + struct clk_onecell_data *clk_data; + struct device_node *node = pdev->dev.of_node; + int r; + + clk_data = mtk_alloc_clk_data(CLK_AUD_NR); + + mtk_clk_register_gates(node, audio_clks, ARRAY_SIZE(audio_clks), + clk_data); + + r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); + if (r) { + dev_err(&pdev->dev, + "could not register clock provider: %s: %d\n", + pdev->name, r); + + goto err_clk_provider; + } + + r = devm_of_platform_populate(&pdev->dev); + if (r) + goto err_plat_populate; + + return 0; + +err_plat_populate: + of_clk_del_provider(node); +err_clk_provider: + return r; +} + +static struct platform_driver clk_mt2701_aud_drv = { + .probe = clk_mt2701_aud_probe, + .driver = { + .name = "clk-mt2701-aud", + .of_match_table = of_match_clk_mt2701_aud, + }, +}; + +builtin_platform_driver(clk_mt2701_aud_drv); -- cgit From b6e37ce2371dac0d696332d8e74c110030ab47c3 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Thu, 15 Mar 2018 21:52:17 -0500 Subject: dt-bindings: clock: Add new bindings for TI Davinci PLL clocks This adds a new binding for the PLL IP blocks in the mach-davinci family of processors. Currently, only da850 has device tree support but these bindings can also work for other SoCs in this family just by adding new compatible strings. Note: Although these PLL controllers are very similar to the TI Keystone SoCs, we are not re-using those bindings. The Keystone bindings use a legacy one-node-per-clock binding. Furthermore, the mach-davinici SoCs have a slightly different PLL register layout and a number of quirks that can't be handled by the existing bindings, so the keystone bindings could not be used as-is anyway. Signed-off-by: David Lechner Reviewed-by: Rob Herring Signed-off-by: Stephen Boyd --- .../devicetree/bindings/clock/ti/davinci/pll.txt | 96 ++++++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/ti/davinci/pll.txt diff --git a/Documentation/devicetree/bindings/clock/ti/davinci/pll.txt b/Documentation/devicetree/bindings/clock/ti/davinci/pll.txt new file mode 100644 index 000000000000..36998e184821 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/ti/davinci/pll.txt @@ -0,0 +1,96 @@ +Binding for TI DaVinci PLL Controllers + +The PLL provides clocks to most of the components on the SoC. In addition +to the PLL itself, this controller also contains bypasses, gates, dividers, +an multiplexers for various clock signals. + +Required properties: +- compatible: shall be one of: + - "ti,da850-pll0" for PLL0 on DA850/OMAP-L138/AM18XX + - "ti,da850-pll1" for PLL1 on DA850/OMAP-L138/AM18XX +- reg: physical base address and size of the controller's register area. +- clocks: phandles corresponding to the clock names +- clock-names: names of the clock sources - depends on compatible string + - for "ti,da850-pll0", shall be "clksrc", "extclksrc" + - for "ti,da850-pll1", shall be "clksrc" + +Optional properties: +- ti,clkmode-square-wave: Indicates that the the board is supplying a square + wave input on the OSCIN pin instead of using a crystal oscillator. + This property is only valid when compatible = "ti,da850-pll0". + + +Optional child nodes: + +pllout + Describes the main PLL clock output (before POSTDIV). The node name must + be "pllout". + + Required properties: + - #clock-cells: shall be 0 + +sysclk + Describes the PLLDIVn divider clocks that provide the SYSCLKn clock + domains. The node name must be "sysclk". Consumers of this node should + use "n" in "SYSCLKn" as the index parameter for the clock cell. + + Required properties: + - #clock-cells: shall be 1 + +auxclk + Describes the AUXCLK output of the PLL. The node name must be "auxclk". + This child node is only valid when compatible = "ti,da850-pll0". + + Required properties: + - #clock-cells: shall be 0 + +obsclk + Describes the OBSCLK output of the PLL. The node name must be "obsclk". + + Required properties: + - #clock-cells: shall be 0 + + +Examples: + + pll0: clock-controller@11000 { + compatible = "ti,da850-pll0"; + reg = <0x11000 0x1000>; + clocks = <&ref_clk>, <&pll1_sysclk 3>; + clock-names = "clksrc", "extclksrc"; + ti,clkmode-square-wave; + + pll0_pllout: pllout { + #clock-cells = <0>; + }; + + pll0_sysclk: sysclk { + #clock-cells = <1>; + }; + + pll0_auxclk: auxclk { + #clock-cells = <0>; + }; + + pll0_obsclk: obsclk { + #clock-cells = <0>; + }; + }; + + pll1: clock-controller@21a000 { + compatible = "ti,da850-pll1"; + reg = <0x21a000 0x1000>; + clocks = <&ref_clk>; + clock-names = "clksrc"; + + pll0_sysclk: sysclk { + #clock-cells = <1>; + }; + + pll0_obsclk: obsclk { + #clock-cells = <0>; + }; + }; + +Also see: +- Documentation/devicetree/bindings/clock/clock-bindings.txt -- cgit From 2d172691515961cad2abb4bf1b15d187bf2106cf Mon Sep 17 00:00:00 2001 From: David Lechner Date: Thu, 15 Mar 2018 21:52:18 -0500 Subject: clk: davinci: New driver for davinci PLL clocks This adds a new driver for mach-davinci PLL clocks. This is porting the code from arch/arm/mach-davinci/clock.c to the common clock framework. Additionally, it adds device tree support for these clocks. The ifeq ($(CONFIG_COMMON_CLK), y) in the Makefile is needed to prevent compile errors until the clock code in arch/arm/mach-davinci is removed. Note: although there are similar clocks for TI Keystone we are not able to share the code for a few reasons. The keystone clocks are device tree only and use legacy one-node-per-clock bindings. Also the register layouts are a bit different, which would add even more if/else mess to the keystone clocks. And the keystone PLL driver doesn't support setting clock rates. Signed-off-by: David Lechner Signed-off-by: Stephen Boyd --- MAINTAINERS | 7 + drivers/clk/Makefile | 1 + drivers/clk/davinci/Makefile | 5 + drivers/clk/davinci/pll.c | 888 ++++++++++++++++++++++++++ drivers/clk/davinci/pll.h | 120 ++++ include/linux/platform_data/clk-davinci-pll.h | 21 + 6 files changed, 1042 insertions(+) create mode 100644 drivers/clk/davinci/Makefile create mode 100644 drivers/clk/davinci/pll.c create mode 100644 drivers/clk/davinci/pll.h create mode 100644 include/linux/platform_data/clk-davinci-pll.h diff --git a/MAINTAINERS b/MAINTAINERS index 3bdc260e36b7..e6b9f169a243 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -13792,6 +13792,13 @@ F: arch/arm/mach-davinci/ F: drivers/i2c/busses/i2c-davinci.c F: arch/arm/boot/dts/da850* +TI DAVINCI SERIES CLOCK DRIVER +M: David Lechner +R: Sekhar Nori +S: Maintained +F: Documentation/devicetree/bindings/clock/ti/davinci/ +F: drivers/clk/davinci/ + TI DAVINCI SERIES GPIO DRIVER M: Keerthy L: linux-gpio@vger.kernel.org diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 71ec41e6364f..07ac0fdb71a9 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -61,6 +61,7 @@ obj-$(CONFIG_ARCH_ARTPEC) += axis/ obj-$(CONFIG_ARC_PLAT_AXS10X) += axs10x/ obj-y += bcm/ obj-$(CONFIG_ARCH_BERLIN) += berlin/ +obj-$(CONFIG_ARCH_DAVINCI) += davinci/ obj-$(CONFIG_H8300) += h8300/ obj-$(CONFIG_ARCH_HISI) += hisilicon/ obj-y += imgtec/ diff --git a/drivers/clk/davinci/Makefile b/drivers/clk/davinci/Makefile new file mode 100644 index 000000000000..d9673bd321e0 --- /dev/null +++ b/drivers/clk/davinci/Makefile @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0 + +ifeq ($(CONFIG_COMMON_CLK), y) +obj-y += pll.o +endif diff --git a/drivers/clk/davinci/pll.c b/drivers/clk/davinci/pll.c new file mode 100644 index 000000000000..bfa5b7e52d3d --- /dev/null +++ b/drivers/clk/davinci/pll.c @@ -0,0 +1,888 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * PLL clock driver for TI Davinci SoCs + * + * Copyright (C) 2018 David Lechner + * + * Based on arch/arm/mach-davinci/clock.c + * Copyright (C) 2006-2007 Texas Instruments. + * Copyright (C) 2008-2009 Deep Root Systems, LLC + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pll.h" + +#define MAX_NAME_SIZE 20 +#define OSCIN_CLK_NAME "oscin" + +#define REVID 0x000 +#define PLLCTL 0x100 +#define OCSEL 0x104 +#define PLLSECCTL 0x108 +#define PLLM 0x110 +#define PREDIV 0x114 +#define PLLDIV1 0x118 +#define PLLDIV2 0x11c +#define PLLDIV3 0x120 +#define OSCDIV 0x124 +#define POSTDIV 0x128 +#define BPDIV 0x12c +#define PLLCMD 0x138 +#define PLLSTAT 0x13c +#define ALNCTL 0x140 +#define DCHANGE 0x144 +#define CKEN 0x148 +#define CKSTAT 0x14c +#define SYSTAT 0x150 +#define PLLDIV4 0x160 +#define PLLDIV5 0x164 +#define PLLDIV6 0x168 +#define PLLDIV7 0x16c +#define PLLDIV8 0x170 +#define PLLDIV9 0x174 + +#define PLLCTL_PLLEN BIT(0) +#define PLLCTL_PLLPWRDN BIT(1) +#define PLLCTL_PLLRST BIT(3) +#define PLLCTL_PLLDIS BIT(4) +#define PLLCTL_PLLENSRC BIT(5) +#define PLLCTL_CLKMODE BIT(8) + +/* shared by most *DIV registers */ +#define DIV_RATIO_SHIFT 0 +#define DIV_RATIO_WIDTH 5 +#define DIV_ENABLE_SHIFT 15 + +#define PLLCMD_GOSET BIT(0) +#define PLLSTAT_GOSTAT BIT(0) + +#define CKEN_OBSCLK_SHIFT 1 +#define CKEN_AUXEN_SHIFT 0 + +/* + * OMAP-L138 system reference guide recommends a wait for 4 OSCIN/CLKIN + * cycles to ensure that the PLLC has switched to bypass mode. Delay of 1us + * ensures we are good for all > 4MHz OSCIN/CLKIN inputs. Typically the input + * is ~25MHz. Units are micro seconds. + */ +#define PLL_BYPASS_TIME 1 + +/* From OMAP-L138 datasheet table 6-4. Units are micro seconds */ +#define PLL_RESET_TIME 1 + +/* + * From OMAP-L138 datasheet table 6-4; assuming prediv = 1, sqrt(pllm) = 4 + * Units are micro seconds. + */ +#define PLL_LOCK_TIME 20 + +/** + * struct davinci_pll_clk - Main PLL clock (aka PLLOUT) + * @hw: clk_hw for the pll + * @base: Base memory address + * @pllm_min: The minimum allowable PLLM[PLLM] value + * @pllm_max: The maxiumum allowable PLLM[PLLM] value + * @pllm_mask: Bitmask for PLLM[PLLM] value + */ +struct davinci_pll_clk { + struct clk_hw hw; + void __iomem *base; + u32 pllm_min; + u32 pllm_max; + u32 pllm_mask; +}; + +#define to_davinci_pll_clk(_hw) \ + container_of((_hw), struct davinci_pll_clk, hw) + +static unsigned long davinci_pll_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct davinci_pll_clk *pll = to_davinci_pll_clk(hw); + unsigned long rate = parent_rate; + u32 mult; + + mult = readl(pll->base + PLLM) & pll->pllm_mask; + rate *= mult + 1; + + return rate; +} + +static int davinci_pll_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + struct davinci_pll_clk *pll = to_davinci_pll_clk(hw); + struct clk_hw *parent = req->best_parent_hw; + unsigned long parent_rate = req->best_parent_rate; + unsigned long rate = req->rate; + unsigned long best_rate, r; + u32 mult; + + /* there is a limited range of valid outputs (see datasheet) */ + if (rate < req->min_rate) + return -EINVAL; + + rate = min(rate, req->max_rate); + mult = rate / parent_rate; + best_rate = parent_rate * mult; + + /* easy case when there is no PREDIV */ + if (!(clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT)) { + if (best_rate < req->min_rate) + return -EINVAL; + + if (mult < pll->pllm_min || mult > pll->pllm_max) + return -EINVAL; + + req->rate = best_rate; + + return 0; + } + + /* see if the PREDIV clock can help us */ + best_rate = 0; + + for (mult = pll->pllm_min; mult <= pll->pllm_max; mult++) { + parent_rate = clk_hw_round_rate(parent, rate / mult); + r = parent_rate * mult; + if (r < req->min_rate) + continue; + if (r > rate || r > req->max_rate) + break; + if (r > best_rate) { + best_rate = r; + req->rate = best_rate; + req->best_parent_rate = parent_rate; + if (best_rate == rate) + break; + } + } + + return 0; +} + +static int davinci_pll_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct davinci_pll_clk *pll = to_davinci_pll_clk(hw); + u32 mult; + + mult = rate / parent_rate; + writel(mult - 1, pll->base + PLLM); + + return 0; +} + +#ifdef CONFIG_DEBUG_FS +static int davinci_pll_debug_init(struct clk_hw *hw, struct dentry *dentry); +#else +#define davinci_pll_debug_init NULL +#endif + +static const struct clk_ops davinci_pll_ops = { + .recalc_rate = davinci_pll_recalc_rate, + .determine_rate = davinci_pll_determine_rate, + .set_rate = davinci_pll_set_rate, + .debug_init = davinci_pll_debug_init, +}; + +/* PLLM works differently on DM365 */ +static unsigned long dm365_pll_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct davinci_pll_clk *pll = to_davinci_pll_clk(hw); + unsigned long rate = parent_rate; + u32 mult; + + mult = readl(pll->base + PLLM) & pll->pllm_mask; + rate *= mult * 2; + + return rate; +} + +static const struct clk_ops dm365_pll_ops = { + .recalc_rate = dm365_pll_recalc_rate, + .debug_init = davinci_pll_debug_init, +}; + +/** + * davinci_pll_div_register - common *DIV clock implementation + * @name: the clock name + * @parent_name: the parent clock name + * @reg: the *DIV register + * @fixed: if true, the divider is a fixed value + * @flags: bitmap of CLK_* flags from clock-provider.h + */ +static struct clk *davinci_pll_div_register(struct device *dev, + const char *name, + const char *parent_name, + void __iomem *reg, + bool fixed, u32 flags) +{ + const char * const *parent_names = parent_name ? &parent_name : NULL; + int num_parents = parent_name ? 1 : 0; + const struct clk_ops *divider_ops = &clk_divider_ops; + struct clk_gate *gate; + struct clk_divider *divider; + + gate = devm_kzalloc(dev, sizeof(*gate), GFP_KERNEL); + if (!gate) + return ERR_PTR(-ENOMEM); + + gate->reg = reg; + gate->bit_idx = DIV_ENABLE_SHIFT; + + divider = devm_kzalloc(dev, sizeof(*divider), GFP_KERNEL); + if (!divider) + return ERR_PTR(-ENOMEM); + + divider->reg = reg; + divider->shift = DIV_RATIO_SHIFT; + divider->width = DIV_RATIO_WIDTH; + + if (fixed) { + divider->flags |= CLK_DIVIDER_READ_ONLY; + divider_ops = &clk_divider_ro_ops; + } + + return clk_register_composite(dev, name, parent_names, num_parents, + NULL, NULL, ÷r->hw, divider_ops, + &gate->hw, &clk_gate_ops, flags); +} + +struct davinci_pllen_clk { + struct clk_hw hw; + void __iomem *base; +}; + +#define to_davinci_pllen_clk(_hw) \ + container_of((_hw), struct davinci_pllen_clk, hw) + +static const struct clk_ops davinci_pllen_ops = { + /* this clocks just uses the clock notification feature */ +}; + +/* + * The PLL has to be switched into bypass mode while we are chaning the rate, + * so we do that on the PLLEN clock since it is the end of the line. This will + * switch to bypass before any of the parent clocks (PREDIV, PLL, POSTDIV) are + * changed and will switch back to the PLL after the changes have been made. + */ +static int davinci_pllen_rate_change(struct notifier_block *nb, + unsigned long flags, void *data) +{ + struct clk_notifier_data *cnd = data; + struct clk_hw *hw = __clk_get_hw(cnd->clk); + struct davinci_pllen_clk *pll = to_davinci_pllen_clk(hw); + u32 ctrl; + + ctrl = readl(pll->base + PLLCTL); + + if (flags == PRE_RATE_CHANGE) { + /* Switch the PLL to bypass mode */ + ctrl &= ~(PLLCTL_PLLENSRC | PLLCTL_PLLEN); + writel(ctrl, pll->base + PLLCTL); + + udelay(PLL_BYPASS_TIME); + + /* Reset and enable PLL */ + ctrl &= ~(PLLCTL_PLLRST | PLLCTL_PLLDIS); + writel(ctrl, pll->base + PLLCTL); + } else { + udelay(PLL_RESET_TIME); + + /* Bring PLL out of reset */ + ctrl |= PLLCTL_PLLRST; + writel(ctrl, pll->base + PLLCTL); + + udelay(PLL_LOCK_TIME); + + /* Remove PLL from bypass mode */ + ctrl |= PLLCTL_PLLEN; + writel(ctrl, pll->base + PLLCTL); + } + + return NOTIFY_OK; +} + +static struct davinci_pll_platform_data *davinci_pll_get_pdata(struct device *dev) +{ + struct davinci_pll_platform_data *pdata = dev_get_platdata(dev); + + /* + * Platform data is optional, so allocate a new struct if one was not + * provided. For device tree, this will always be the case. + */ + if (!pdata) + pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return NULL; + + /* for device tree, we need to fill in the struct */ + if (dev->of_node) + pdata->cfgchip = + syscon_regmap_lookup_by_compatible("ti,da830-cfgchip"); + + return pdata; +} + +static struct notifier_block davinci_pllen_notifier = { + .notifier_call = davinci_pllen_rate_change, +}; + +/** + * davinci_pll_clk_register - Register a PLL clock + * @info: The device-specific clock info + * @parent_name: The parent clock name + * @base: The PLL's memory region + * + * This creates a series of clocks that represent the PLL. + * + * OSCIN > [PREDIV >] PLL > [POSTDIV >] PLLEN + * + * - OSCIN is the parent clock (on secondary PLL, may come from primary PLL) + * - PREDIV and POSTDIV are optional (depends on the PLL controller) + * - PLL is the PLL output (aka PLLOUT) + * - PLLEN is the bypass multiplexer + * + * Returns: The PLLOUT clock or a negative error code. + */ +struct clk *davinci_pll_clk_register(struct device *dev, + const struct davinci_pll_clk_info *info, + const char *parent_name, + void __iomem *base) +{ + struct davinci_pll_platform_data *pdata; + char prediv_name[MAX_NAME_SIZE]; + char pllout_name[MAX_NAME_SIZE]; + char postdiv_name[MAX_NAME_SIZE]; + char pllen_name[MAX_NAME_SIZE]; + struct clk_init_data init; + struct davinci_pll_clk *pllout; + struct davinci_pllen_clk *pllen; + struct clk *pllout_clk, *clk; + + pdata = davinci_pll_get_pdata(dev); + if (!pdata) + return ERR_PTR(-ENOMEM); + + if (info->flags & PLL_HAS_CLKMODE) { + /* + * If a PLL has PLLCTL[CLKMODE], then it is the primary PLL. + * We register a clock named "oscin" that serves as the internal + * "input clock" domain shared by both PLLs (if there are 2) + * and will be the parent clock to the AUXCLK, SYSCLKBP and + * OBSCLK domains. NB: The various TRMs use "OSCIN" to mean + * a number of different things. In this driver we use it to + * mean the signal after the PLLCTL[CLKMODE] switch. + */ + clk = clk_register_fixed_factor(dev, OSCIN_CLK_NAME, + parent_name, 0, 1, 1); + if (IS_ERR(clk)) + return clk; + + parent_name = OSCIN_CLK_NAME; + } + + if (info->flags & PLL_HAS_PREDIV) { + bool fixed = info->flags & PLL_PREDIV_FIXED_DIV; + u32 flags = 0; + + snprintf(prediv_name, MAX_NAME_SIZE, "%s_prediv", info->name); + + if (info->flags & PLL_PREDIV_ALWAYS_ENABLED) + flags |= CLK_IS_CRITICAL; + + /* Some? DM355 chips don't correctly report the PREDIV value */ + if (info->flags & PLL_PREDIV_FIXED8) + clk = clk_register_fixed_factor(dev, prediv_name, + parent_name, flags, 1, 8); + else + clk = davinci_pll_div_register(dev, prediv_name, + parent_name, base + PREDIV, fixed, flags); + if (IS_ERR(clk)) + return clk; + + parent_name = prediv_name; + } + + /* Unlock writing to PLL registers */ + if (info->unlock_reg) { + if (IS_ERR_OR_NULL(pdata->cfgchip)) + dev_warn(dev, "Failed to get CFGCHIP (%ld)\n", + PTR_ERR(pdata->cfgchip)); + else + regmap_write_bits(pdata->cfgchip, info->unlock_reg, + info->unlock_mask, 0); + } + + pllout = devm_kzalloc(dev, sizeof(*pllout), GFP_KERNEL); + if (!pllout) + return ERR_PTR(-ENOMEM); + + snprintf(pllout_name, MAX_NAME_SIZE, "%s_pllout", info->name); + + init.name = pllout_name; + if (info->flags & PLL_PLLM_2X) + init.ops = &dm365_pll_ops; + else + init.ops = &davinci_pll_ops; + init.parent_names = &parent_name; + init.num_parents = 1; + init.flags = 0; + + if (info->flags & PLL_HAS_PREDIV) + init.flags |= CLK_SET_RATE_PARENT; + + pllout->hw.init = &init; + pllout->base = base; + pllout->pllm_mask = info->pllm_mask; + pllout->pllm_min = info->pllm_min; + pllout->pllm_max = info->pllm_max; + + pllout_clk = devm_clk_register(dev, &pllout->hw); + if (IS_ERR(pllout_clk)) + return pllout_clk; + + clk_hw_set_rate_range(&pllout->hw, info->pllout_min_rate, + info->pllout_max_rate); + + parent_name = pllout_name; + + if (info->flags & PLL_HAS_POSTDIV) { + bool fixed = info->flags & PLL_POSTDIV_FIXED_DIV; + u32 flags = CLK_SET_RATE_PARENT; + + snprintf(postdiv_name, MAX_NAME_SIZE, "%s_postdiv", info->name); + + if (info->flags & PLL_POSTDIV_ALWAYS_ENABLED) + flags |= CLK_IS_CRITICAL; + + clk = davinci_pll_div_register(dev, postdiv_name, parent_name, + base + POSTDIV, fixed, flags); + if (IS_ERR(clk)) + return clk; + + parent_name = postdiv_name; + } + + pllen = devm_kzalloc(dev, sizeof(*pllout), GFP_KERNEL); + if (!pllen) + return ERR_PTR(-ENOMEM); + + snprintf(pllen_name, MAX_NAME_SIZE, "%s_pllen", info->name); + + init.name = pllen_name; + init.ops = &davinci_pllen_ops; + init.parent_names = &parent_name; + init.num_parents = 1; + init.flags = CLK_SET_RATE_PARENT; + + pllen->hw.init = &init; + pllen->base = base; + + clk = devm_clk_register(dev, &pllen->hw); + if (IS_ERR(clk)) + return clk; + + clk_notifier_register(clk, &davinci_pllen_notifier); + + return pllout_clk; +} + +/** + * davinci_pll_auxclk_register - Register bypass clock (AUXCLK) + * @name: The clock name + * @base: The PLL memory region + */ +struct clk *davinci_pll_auxclk_register(struct device *dev, + const char *name, + void __iomem *base) +{ + return clk_register_gate(dev, name, OSCIN_CLK_NAME, 0, base + CKEN, + CKEN_AUXEN_SHIFT, 0, NULL); +} + +/** + * davinci_pll_sysclkbp_clk_register - Register bypass divider clock (SYSCLKBP) + * @name: The clock name + * @base: The PLL memory region + */ +struct clk *davinci_pll_sysclkbp_clk_register(struct device *dev, + const char *name, + void __iomem *base) +{ + return clk_register_divider(dev, name, OSCIN_CLK_NAME, 0, base + BPDIV, + DIV_RATIO_SHIFT, DIV_RATIO_WIDTH, + CLK_DIVIDER_READ_ONLY, NULL); +} + +/** + * davinci_pll_obsclk_register - Register oscillator divider clock (OBSCLK) + * @info: The clock info + * @base: The PLL memory region + */ +struct clk * +davinci_pll_obsclk_register(struct device *dev, + const struct davinci_pll_obsclk_info *info, + void __iomem *base) +{ + struct clk_mux *mux; + struct clk_gate *gate; + struct clk_divider *divider; + u32 oscdiv; + + mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL); + if (!mux) + return ERR_PTR(-ENOMEM); + + mux->reg = base + OCSEL; + mux->table = info->table; + mux->mask = info->ocsrc_mask; + + gate = devm_kzalloc(dev, sizeof(*gate), GFP_KERNEL); + if (!gate) + return ERR_PTR(-ENOMEM); + + gate->reg = base + CKEN; + gate->bit_idx = CKEN_OBSCLK_SHIFT; + + divider = devm_kzalloc(dev, sizeof(*divider), GFP_KERNEL); + if (!divider) + return ERR_PTR(-ENOMEM); + + divider->reg = base + OSCDIV; + divider->shift = DIV_RATIO_SHIFT; + divider->width = DIV_RATIO_WIDTH; + + /* make sure divider is enabled just in case bootloader disabled it */ + oscdiv = readl(base + OSCDIV); + oscdiv |= BIT(DIV_ENABLE_SHIFT); + writel(oscdiv, base + OSCDIV); + + return clk_register_composite(dev, info->name, info->parent_names, + info->num_parents, + &mux->hw, &clk_mux_ops, + ÷r->hw, &clk_divider_ops, + &gate->hw, &clk_gate_ops, 0); +} + +/* The PLL SYSCLKn clocks have a mechanism for synchronizing rate changes. */ +static int davinci_pll_sysclk_rate_change(struct notifier_block *nb, + unsigned long flags, void *data) +{ + struct clk_notifier_data *cnd = data; + struct clk_hw *hw = __clk_get_hw(clk_get_parent(cnd->clk)); + struct davinci_pllen_clk *pll = to_davinci_pllen_clk(hw); + u32 pllcmd, pllstat; + + switch (flags) { + case POST_RATE_CHANGE: + /* apply the changes */ + pllcmd = readl(pll->base + PLLCMD); + pllcmd |= PLLCMD_GOSET; + writel(pllcmd, pll->base + PLLCMD); + /* fallthrough */ + case PRE_RATE_CHANGE: + /* Wait until for outstanding changes to take effect */ + do { + pllstat = readl(pll->base + PLLSTAT); + } while (pllstat & PLLSTAT_GOSTAT); + break; + } + + return NOTIFY_OK; +} + +static struct notifier_block davinci_pll_sysclk_notifier = { + .notifier_call = davinci_pll_sysclk_rate_change, +}; + +/** + * davinci_pll_sysclk_register - Register divider clocks (SYSCLKn) + * @info: The clock info + * @base: The PLL memory region + */ +struct clk * +davinci_pll_sysclk_register(struct device *dev, + const struct davinci_pll_sysclk_info *info, + void __iomem *base) +{ + const struct clk_ops *divider_ops = &clk_divider_ops; + struct clk_gate *gate; + struct clk_divider *divider; + struct clk *clk; + u32 reg; + u32 flags = 0; + + /* PLLDIVn registers are not entirely consecutive */ + if (info->id < 4) + reg = PLLDIV1 + 4 * (info->id - 1); + else + reg = PLLDIV4 + 4 * (info->id - 4); + + gate = devm_kzalloc(dev, sizeof(*gate), GFP_KERNEL); + if (!gate) + return ERR_PTR(-ENOMEM); + + gate->reg = base + reg; + gate->bit_idx = DIV_ENABLE_SHIFT; + + divider = devm_kzalloc(dev, sizeof(*divider), GFP_KERNEL); + if (!divider) + return ERR_PTR(-ENOMEM); + + divider->reg = base + reg; + divider->shift = DIV_RATIO_SHIFT; + divider->width = info->ratio_width; + divider->flags = 0; + + if (info->flags & SYSCLK_FIXED_DIV) { + divider->flags |= CLK_DIVIDER_READ_ONLY; + divider_ops = &clk_divider_ro_ops; + } + + /* Only the ARM clock can change the parent PLL rate */ + if (info->flags & SYSCLK_ARM_RATE) + flags |= CLK_SET_RATE_PARENT; + + if (info->flags & SYSCLK_ALWAYS_ENABLED) + flags |= CLK_IS_CRITICAL; + + clk = clk_register_composite(dev, info->name, &info->parent_name, 1, + NULL, NULL, ÷r->hw, divider_ops, + &gate->hw, &clk_gate_ops, flags); + if (IS_ERR(clk)) + return clk; + + clk_notifier_register(clk, &davinci_pll_sysclk_notifier); + + return clk; +} + +int of_davinci_pll_init(struct device *dev, + const struct davinci_pll_clk_info *info, + const struct davinci_pll_obsclk_info *obsclk_info, + const struct davinci_pll_sysclk_info **div_info, + u8 max_sysclk_id, + void __iomem *base) +{ + struct device_node *node = dev->of_node; + struct device_node *child; + const char *parent_name; + struct clk *clk; + + if (info->flags & PLL_HAS_CLKMODE) + parent_name = of_clk_get_parent_name(node, 0); + else + parent_name = OSCIN_CLK_NAME; + + clk = davinci_pll_clk_register(dev, info, parent_name, base); + if (IS_ERR(clk)) { + dev_err(dev, "failed to register %s\n", info->name); + return PTR_ERR(clk); + } + + child = of_get_child_by_name(node, "pllout"); + if (of_device_is_available(child)) + of_clk_add_provider(child, of_clk_src_simple_get, clk); + of_node_put(child); + + child = of_get_child_by_name(node, "sysclk"); + if (of_device_is_available(child)) { + struct clk_onecell_data *clk_data; + struct clk **clks; + int n_clks = max_sysclk_id + 1; + int i; + + clk_data = devm_kzalloc(dev, sizeof(*clk_data), GFP_KERNEL); + if (!clk_data) + return -ENOMEM; + + clks = devm_kmalloc_array(dev, n_clks, sizeof(*clks), GFP_KERNEL); + if (!clks) + return -ENOMEM; + + clk_data->clks = clks; + clk_data->clk_num = n_clks; + + for (i = 0; i < n_clks; i++) + clks[i] = ERR_PTR(-ENOENT); + + for (; *div_info; div_info++) { + clk = davinci_pll_sysclk_register(dev, *div_info, base); + if (IS_ERR(clk)) + dev_warn(dev, "failed to register %s (%ld)\n", + (*div_info)->name, PTR_ERR(clk)); + else + clks[(*div_info)->id] = clk; + } + of_clk_add_provider(child, of_clk_src_onecell_get, clk_data); + } + of_node_put(child); + + child = of_get_child_by_name(node, "auxclk"); + if (of_device_is_available(child)) { + char child_name[MAX_NAME_SIZE]; + + snprintf(child_name, MAX_NAME_SIZE, "%s_auxclk", info->name); + + clk = davinci_pll_auxclk_register(dev, child_name, base); + if (IS_ERR(clk)) + dev_warn(dev, "failed to register %s (%ld)\n", + child_name, PTR_ERR(clk)); + else + of_clk_add_provider(child, of_clk_src_simple_get, clk); + } + of_node_put(child); + + child = of_get_child_by_name(node, "obsclk"); + if (of_device_is_available(child)) { + if (obsclk_info) + clk = davinci_pll_obsclk_register(dev, obsclk_info, base); + else + clk = ERR_PTR(-EINVAL); + + if (IS_ERR(clk)) + dev_warn(dev, "failed to register obsclk (%ld)\n", + PTR_ERR(clk)); + else + of_clk_add_provider(child, of_clk_src_simple_get, clk); + } + of_node_put(child); + + return 0; +} + +static const struct of_device_id davinci_pll_of_match[] = { + { } +}; + +static const struct platform_device_id davinci_pll_id_table[] = { + { } +}; + +typedef int (*davinci_pll_init)(struct device *dev, void __iomem *base); + +static int davinci_pll_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + const struct of_device_id *of_id; + davinci_pll_init pll_init = NULL; + struct resource *res; + void __iomem *base; + + of_id = of_match_device(davinci_pll_of_match, dev); + if (of_id) + pll_init = of_id->data; + else if (pdev->id_entry) + pll_init = (void *)pdev->id_entry->driver_data; + + if (!pll_init) { + dev_err(dev, "unable to find driver data\n"); + return -EINVAL; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(dev, res); + if (IS_ERR(base)) { + dev_err(dev, "ioremap failed\n"); + return PTR_ERR(base); + } + + return pll_init(dev, base); +} + +static struct platform_driver davinci_pll_driver = { + .probe = davinci_pll_probe, + .driver = { + .name = "davinci-pll-clk", + .of_match_table = davinci_pll_of_match, + }, + .id_table = davinci_pll_id_table, +}; + +static int __init davinci_pll_driver_init(void) +{ + return platform_driver_register(&davinci_pll_driver); +} + +/* has to be postcore_initcall because PSC devices depend on PLL parent clocks */ +postcore_initcall(davinci_pll_driver_init); + +#ifdef CONFIG_DEBUG_FS +#include + +#define DEBUG_REG(n) \ +{ \ + .name = #n, \ + .offset = n, \ +} + +static const struct debugfs_reg32 davinci_pll_regs[] = { + DEBUG_REG(REVID), + DEBUG_REG(PLLCTL), + DEBUG_REG(OCSEL), + DEBUG_REG(PLLSECCTL), + DEBUG_REG(PLLM), + DEBUG_REG(PREDIV), + DEBUG_REG(PLLDIV1), + DEBUG_REG(PLLDIV2), + DEBUG_REG(PLLDIV3), + DEBUG_REG(OSCDIV), + DEBUG_REG(POSTDIV), + DEBUG_REG(BPDIV), + DEBUG_REG(PLLCMD), + DEBUG_REG(PLLSTAT), + DEBUG_REG(ALNCTL), + DEBUG_REG(DCHANGE), + DEBUG_REG(CKEN), + DEBUG_REG(CKSTAT), + DEBUG_REG(SYSTAT), + DEBUG_REG(PLLDIV4), + DEBUG_REG(PLLDIV5), + DEBUG_REG(PLLDIV6), + DEBUG_REG(PLLDIV7), + DEBUG_REG(PLLDIV8), + DEBUG_REG(PLLDIV9), +}; + +static int davinci_pll_debug_init(struct clk_hw *hw, struct dentry *dentry) +{ + struct davinci_pll_clk *pll = to_davinci_pll_clk(hw); + struct debugfs_regset32 *regset; + struct dentry *d; + + regset = kzalloc(sizeof(*regset), GFP_KERNEL); + if (!regset) + return -ENOMEM; + + regset->regs = davinci_pll_regs; + regset->nregs = ARRAY_SIZE(davinci_pll_regs); + regset->base = pll->base; + + d = debugfs_create_regset32("registers", 0400, dentry, regset); + if (IS_ERR(d)) { + kfree(regset); + return PTR_ERR(d); + } + + return 0; +} +#endif diff --git a/drivers/clk/davinci/pll.h b/drivers/clk/davinci/pll.h new file mode 100644 index 000000000000..52103aeeceec --- /dev/null +++ b/drivers/clk/davinci/pll.h @@ -0,0 +1,120 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Clock driver for TI Davinci PSC controllers + * + * Copyright (C) 2018 David Lechner + */ + +#ifndef __CLK_DAVINCI_PLL_H___ +#define __CLK_DAVINCI_PLL_H___ + +#include +#include +#include +#include + +#define PLL_HAS_CLKMODE BIT(0) /* PLL has PLLCTL[CLKMODE] */ +#define PLL_HAS_PREDIV BIT(1) /* has prediv before PLL */ +#define PLL_PREDIV_ALWAYS_ENABLED BIT(2) /* don't clear DEN bit */ +#define PLL_PREDIV_FIXED_DIV BIT(3) /* fixed divider value */ +#define PLL_HAS_POSTDIV BIT(4) /* has postdiv after PLL */ +#define PLL_POSTDIV_ALWAYS_ENABLED BIT(5) /* don't clear DEN bit */ +#define PLL_POSTDIV_FIXED_DIV BIT(6) /* fixed divider value */ +#define PLL_HAS_EXTCLKSRC BIT(7) /* has selectable bypass */ +#define PLL_PLLM_2X BIT(8) /* PLLM value is 2x (DM365) */ +#define PLL_PREDIV_FIXED8 BIT(9) /* DM355 quirk */ + +/** davinci_pll_clk_info - controller-specific PLL info + * @name: The name of the PLL + * @unlock_reg: Option CFGCHIP register for unlocking PLL + * @unlock_mask: Bitmask used with @unlock_reg + * @pllm_mask: Bitmask for PLLM[PLLM] value + * @pllm_min: Minimum allowable value for PLLM[PLLM] + * @pllm_max: Maximum allowable value for PLLM[PLLM] + * @pllout_min_rate: Minimum allowable rate for PLLOUT + * @pllout_max_rate: Maximum allowable rate for PLLOUT + * @flags: Bitmap of PLL_* flags. + */ +struct davinci_pll_clk_info { + const char *name; + u32 unlock_reg; + u32 unlock_mask; + u32 pllm_mask; + u32 pllm_min; + u32 pllm_max; + unsigned long pllout_min_rate; + unsigned long pllout_max_rate; + u32 flags; +}; + +#define SYSCLK_ARM_RATE BIT(0) /* Controls ARM rate */ +#define SYSCLK_ALWAYS_ENABLED BIT(1) /* Or bad things happen */ +#define SYSCLK_FIXED_DIV BIT(2) /* Fixed divider */ + +/** davinci_pll_sysclk_info - SYSCLKn-specific info + * @name: The name of the clock + * @parent_name: The name of the parent clock + * @id: "n" in "SYSCLKn" + * @ratio_width: Width (in bits) of RATIO in PLLDIVn register + * @flags: Bitmap of SYSCLK_* flags. + */ +struct davinci_pll_sysclk_info { + const char *name; + const char *parent_name; + u32 id; + u32 ratio_width; + u32 flags; +}; + +#define SYSCLK(i, n, p, w, f) \ +static const struct davinci_pll_sysclk_info n = { \ + .name = #n, \ + .parent_name = #p, \ + .id = (i), \ + .ratio_width = (w), \ + .flags = (f), \ +} + +/** davinci_pll_obsclk_info - OBSCLK-specific info + * @name: The name of the clock + * @parent_names: Array of names of the parent clocks + * @num_parents: Length of @parent_names + * @table: Array of values to write to OCSEL[OCSRC] cooresponding to + * @parent_names + * @ocsrc_mask: Bitmask for OCSEL[OCSRC] + */ +struct davinci_pll_obsclk_info { + const char *name; + const char * const *parent_names; + u8 num_parents; + u32 *table; + u32 ocsrc_mask; +}; + +struct clk *davinci_pll_clk_register(struct device *dev, + const struct davinci_pll_clk_info *info, + const char *parent_name, + void __iomem *base); +struct clk *davinci_pll_auxclk_register(struct device *dev, + const char *name, + void __iomem *base); +struct clk *davinci_pll_sysclkbp_clk_register(struct device *dev, + const char *name, + void __iomem *base); +struct clk * +davinci_pll_obsclk_register(struct device *dev, + const struct davinci_pll_obsclk_info *info, + void __iomem *base); +struct clk * +davinci_pll_sysclk_register(struct device *dev, + const struct davinci_pll_sysclk_info *info, + void __iomem *base); + +int of_davinci_pll_init(struct device *dev, + const struct davinci_pll_clk_info *info, + const struct davinci_pll_obsclk_info *obsclk_info, + const struct davinci_pll_sysclk_info **div_info, + u8 max_sysclk_id, + void __iomem *base); + +#endif /* __CLK_DAVINCI_PLL_H___ */ diff --git a/include/linux/platform_data/clk-davinci-pll.h b/include/linux/platform_data/clk-davinci-pll.h new file mode 100644 index 000000000000..e55dab1d578b --- /dev/null +++ b/include/linux/platform_data/clk-davinci-pll.h @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * PLL clock driver for TI Davinci SoCs + * + * Copyright (C) 2018 David Lechner + */ + +#ifndef __LINUX_PLATFORM_DATA_CLK_DAVINCI_PLL_H__ +#define __LINUX_PLATFORM_DATA_CLK_DAVINCI_PLL_H__ + +#include + +/** + * davinci_pll_platform_data + * @cfgchip: CFGCHIP syscon regmap + */ +struct davinci_pll_platform_data { + struct regmap *cfgchip; +}; + +#endif /* __LINUX_PLATFORM_DATA_CLK_DAVINCI_PLL_H__ */ -- cgit From c92765fdb8ffd2efc7693d5d83bb71ab8dfcad5e Mon Sep 17 00:00:00 2001 From: David Lechner Date: Thu, 15 Mar 2018 21:52:19 -0500 Subject: clk: davinci: Add platform information for TI DA830 PLL This adds platform-specific declarations for the PLL clocks on TI DA830/ OMAP-L137/AM17XX SoCs. Signed-off-by: David Lechner Signed-off-by: Stephen Boyd --- drivers/clk/davinci/Makefile | 1 + drivers/clk/davinci/pll-da830.c | 70 +++++++++++++++++++++++++++++++++++++++++ drivers/clk/davinci/pll.c | 1 + drivers/clk/davinci/pll.h | 4 +++ 4 files changed, 76 insertions(+) create mode 100644 drivers/clk/davinci/pll-da830.c diff --git a/drivers/clk/davinci/Makefile b/drivers/clk/davinci/Makefile index d9673bd321e0..9061e197ff1c 100644 --- a/drivers/clk/davinci/Makefile +++ b/drivers/clk/davinci/Makefile @@ -2,4 +2,5 @@ ifeq ($(CONFIG_COMMON_CLK), y) obj-y += pll.o +obj-$(CONFIG_ARCH_DAVINCI_DA830) += pll-da830.o endif diff --git a/drivers/clk/davinci/pll-da830.c b/drivers/clk/davinci/pll-da830.c new file mode 100644 index 000000000000..929a3d3a9adb --- /dev/null +++ b/drivers/clk/davinci/pll-da830.c @@ -0,0 +1,70 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * PLL clock descriptions for TI DA830/OMAP-L137/AM17XX + * + * Copyright (C) 2018 David Lechner + */ + +#include +#include +#include +#include + +#include "pll.h" + +static const struct davinci_pll_clk_info da830_pll_info = { + .name = "pll0", + .pllm_mask = GENMASK(4, 0), + .pllm_min = 4, + .pllm_max = 32, + .pllout_min_rate = 300000000, + .pllout_max_rate = 600000000, + .flags = PLL_HAS_CLKMODE | PLL_HAS_PREDIV | PLL_HAS_POSTDIV, +}; + +/* + * NB: Technically, the clocks flagged as SYSCLK_FIXED_DIV are "fixed ratio", + * meaning that we could change the divider as long as we keep the correct + * ratio between all of the clocks, but we don't support that because there is + * currently not a need for it. + */ + +SYSCLK(2, pll0_sysclk2, pll0_pllen, 5, SYSCLK_FIXED_DIV); +SYSCLK(3, pll0_sysclk3, pll0_pllen, 5, 0); +SYSCLK(4, pll0_sysclk4, pll0_pllen, 5, SYSCLK_FIXED_DIV); +SYSCLK(5, pll0_sysclk5, pll0_pllen, 5, 0); +SYSCLK(6, pll0_sysclk6, pll0_pllen, 5, SYSCLK_FIXED_DIV); +SYSCLK(7, pll0_sysclk7, pll0_pllen, 5, 0); + +int da830_pll_init(struct device *dev, void __iomem *base) +{ + struct clk *clk; + + davinci_pll_clk_register(dev, &da830_pll_info, "ref_clk", base); + + clk = davinci_pll_sysclk_register(dev, &pll0_sysclk2, base); + clk_register_clkdev(clk, "pll0_sysclk2", "da830-psc0"); + clk_register_clkdev(clk, "pll0_sysclk2", "da830-psc1"); + + clk = davinci_pll_sysclk_register(dev, &pll0_sysclk3, base); + clk_register_clkdev(clk, "pll0_sysclk3", "da830-psc0"); + + clk = davinci_pll_sysclk_register(dev, &pll0_sysclk4, base); + clk_register_clkdev(clk, "pll0_sysclk4", "da830-psc0"); + clk_register_clkdev(clk, "pll0_sysclk4", "da830-psc1"); + + clk = davinci_pll_sysclk_register(dev, &pll0_sysclk5, base); + clk_register_clkdev(clk, "pll0_sysclk5", "da830-psc1"); + + clk = davinci_pll_sysclk_register(dev, &pll0_sysclk6, base); + clk_register_clkdev(clk, "pll0_sysclk6", "da830-psc0"); + + clk = davinci_pll_sysclk_register(dev, &pll0_sysclk7, base); + + clk = davinci_pll_auxclk_register(dev, "pll0_auxclk", base); + clk_register_clkdev(clk, NULL, "i2c_davinci.1"); + clk_register_clkdev(clk, "timer0", NULL); + clk_register_clkdev(clk, NULL, "davinci-wdt"); + + return 0; +} diff --git a/drivers/clk/davinci/pll.c b/drivers/clk/davinci/pll.c index bfa5b7e52d3d..d91cb9d5bc1f 100644 --- a/drivers/clk/davinci/pll.c +++ b/drivers/clk/davinci/pll.c @@ -775,6 +775,7 @@ static const struct of_device_id davinci_pll_of_match[] = { }; static const struct platform_device_id davinci_pll_id_table[] = { + { .name = "da830-pll", .driver_data = (kernel_ulong_t)da830_pll_init }, { } }; diff --git a/drivers/clk/davinci/pll.h b/drivers/clk/davinci/pll.h index 52103aeeceec..0de2c61cb135 100644 --- a/drivers/clk/davinci/pll.h +++ b/drivers/clk/davinci/pll.h @@ -117,4 +117,8 @@ int of_davinci_pll_init(struct device *dev, u8 max_sysclk_id, void __iomem *base); +/* Platform-specific callbacks */ + +int da830_pll_init(struct device *dev, void __iomem *base); + #endif /* __CLK_DAVINCI_PLL_H___ */ -- cgit From 55b3caed2bf6edd5d44ccae92ed37cff00951a91 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Thu, 15 Mar 2018 21:52:20 -0500 Subject: clk: davinci: Add platform information for TI DA850 PLL This adds platform-specific declarations for the PLL clocks on TI DA850/ OMAP-L138/AM18XX SoCs. Signed-off-by: David Lechner Signed-off-by: Stephen Boyd --- drivers/clk/davinci/Makefile | 1 + drivers/clk/davinci/pll-da850.c | 212 ++++++++++++++++++++++++++++++++++++++++ drivers/clk/davinci/pll.c | 4 + drivers/clk/davinci/pll.h | 5 + 4 files changed, 222 insertions(+) create mode 100644 drivers/clk/davinci/pll-da850.c diff --git a/drivers/clk/davinci/Makefile b/drivers/clk/davinci/Makefile index 9061e197ff1c..13049d43215e 100644 --- a/drivers/clk/davinci/Makefile +++ b/drivers/clk/davinci/Makefile @@ -3,4 +3,5 @@ ifeq ($(CONFIG_COMMON_CLK), y) obj-y += pll.o obj-$(CONFIG_ARCH_DAVINCI_DA830) += pll-da830.o +obj-$(CONFIG_ARCH_DAVINCI_DA850) += pll-da850.o endif diff --git a/drivers/clk/davinci/pll-da850.c b/drivers/clk/davinci/pll-da850.c new file mode 100644 index 000000000000..2a038b7908cc --- /dev/null +++ b/drivers/clk/davinci/pll-da850.c @@ -0,0 +1,212 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * PLL clock descriptions for TI DA850/OMAP-L138/AM18XX + * + * Copyright (C) 2018 David Lechner + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pll.h" + +#define OCSEL_OCSRC_OSCIN 0x14 +#define OCSEL_OCSRC_PLL0_SYSCLK(n) (0x16 + (n)) +#define OCSEL_OCSRC_PLL1_OBSCLK 0x1e +#define OCSEL_OCSRC_PLL1_SYSCLK(n) (0x16 + (n)) + +static const struct davinci_pll_clk_info da850_pll0_info = { + .name = "pll0", + .unlock_reg = CFGCHIP(0), + .unlock_mask = CFGCHIP0_PLL_MASTER_LOCK, + .pllm_mask = GENMASK(4, 0), + .pllm_min = 4, + .pllm_max = 32, + .pllout_min_rate = 300000000, + .pllout_max_rate = 600000000, + .flags = PLL_HAS_CLKMODE | PLL_HAS_PREDIV | PLL_HAS_POSTDIV | + PLL_HAS_EXTCLKSRC, +}; + +/* + * NB: Technically, the clocks flagged as SYSCLK_FIXED_DIV are "fixed ratio", + * meaning that we could change the divider as long as we keep the correct + * ratio between all of the clocks, but we don't support that because there is + * currently not a need for it. + */ + +SYSCLK(1, pll0_sysclk1, pll0_pllen, 5, SYSCLK_FIXED_DIV); +SYSCLK(2, pll0_sysclk2, pll0_pllen, 5, SYSCLK_FIXED_DIV); +SYSCLK(3, pll0_sysclk3, pll0_pllen, 5, 0); +SYSCLK(4, pll0_sysclk4, pll0_pllen, 5, SYSCLK_FIXED_DIV); +SYSCLK(5, pll0_sysclk5, pll0_pllen, 5, 0); +SYSCLK(6, pll0_sysclk6, pll0_pllen, 5, SYSCLK_ARM_RATE | SYSCLK_FIXED_DIV); +SYSCLK(7, pll0_sysclk7, pll0_pllen, 5, 0); + +static const char * const da850_pll0_obsclk_parent_names[] = { + "oscin", + "pll0_sysclk1", + "pll0_sysclk2", + "pll0_sysclk3", + "pll0_sysclk4", + "pll0_sysclk5", + "pll0_sysclk6", + "pll0_sysclk7", + "pll1_obsclk", +}; + +static u32 da850_pll0_obsclk_table[] = { + OCSEL_OCSRC_OSCIN, + OCSEL_OCSRC_PLL0_SYSCLK(1), + OCSEL_OCSRC_PLL0_SYSCLK(2), + OCSEL_OCSRC_PLL0_SYSCLK(3), + OCSEL_OCSRC_PLL0_SYSCLK(4), + OCSEL_OCSRC_PLL0_SYSCLK(5), + OCSEL_OCSRC_PLL0_SYSCLK(6), + OCSEL_OCSRC_PLL0_SYSCLK(7), + OCSEL_OCSRC_PLL1_OBSCLK, +}; + +static const struct davinci_pll_obsclk_info da850_pll0_obsclk_info = { + .name = "pll0_obsclk", + .parent_names = da850_pll0_obsclk_parent_names, + .num_parents = ARRAY_SIZE(da850_pll0_obsclk_parent_names), + .table = da850_pll0_obsclk_table, + .ocsrc_mask = GENMASK(4, 0), +}; + +int da850_pll0_init(struct device *dev, void __iomem *base) +{ + struct clk *clk; + + davinci_pll_clk_register(dev, &da850_pll0_info, "ref_clk", base); + + clk = davinci_pll_sysclk_register(dev, &pll0_sysclk1, base); + clk_register_clkdev(clk, "pll0_sysclk1", "da850-psc0"); + + clk = davinci_pll_sysclk_register(dev, &pll0_sysclk2, base); + clk_register_clkdev(clk, "pll0_sysclk2", "da850-psc0"); + clk_register_clkdev(clk, "pll0_sysclk2", "da850-psc1"); + clk_register_clkdev(clk, "pll0_sysclk2", "da850-async3-clksrc"); + + clk = davinci_pll_sysclk_register(dev, &pll0_sysclk3, base); + clk_register_clkdev(clk, "pll0_sysclk3", "da850-async1-clksrc"); + + clk = davinci_pll_sysclk_register(dev, &pll0_sysclk4, base); + clk_register_clkdev(clk, "pll0_sysclk4", "da850-psc0"); + clk_register_clkdev(clk, "pll0_sysclk4", "da850-psc1"); + + davinci_pll_sysclk_register(dev, &pll0_sysclk5, base); + + clk = davinci_pll_sysclk_register(dev, &pll0_sysclk6, base); + clk_register_clkdev(clk, "pll0_sysclk6", "da850-psc0"); + + davinci_pll_sysclk_register(dev, &pll0_sysclk7, base); + + davinci_pll_auxclk_register(dev, "pll0_auxclk", base); + + clk = clk_register_fixed_factor(dev, "async2", "pll0_auxclk", + CLK_IS_CRITICAL, 1, 1); + + clk_register_clkdev(clk, NULL, "i2c_davinci.1"); + clk_register_clkdev(clk, "timer0", NULL); + clk_register_clkdev(clk, NULL, "davinci-wdt"); + + davinci_pll_obsclk_register(dev, &da850_pll0_obsclk_info, base); + + return 0; +} + +static const struct davinci_pll_sysclk_info *da850_pll0_sysclk_info[] = { + &pll0_sysclk1, + &pll0_sysclk2, + &pll0_sysclk3, + &pll0_sysclk4, + &pll0_sysclk5, + &pll0_sysclk6, + &pll0_sysclk7, + NULL +}; + +int of_da850_pll0_init(struct device *dev, void __iomem *base) +{ + return of_davinci_pll_init(dev, &da850_pll0_info, + &da850_pll0_obsclk_info, + da850_pll0_sysclk_info, 7, base); +} + +static const struct davinci_pll_clk_info da850_pll1_info = { + .name = "pll1", + .unlock_reg = CFGCHIP(3), + .unlock_mask = CFGCHIP3_PLL1_MASTER_LOCK, + .pllm_mask = GENMASK(4, 0), + .pllm_min = 4, + .pllm_max = 32, + .pllout_min_rate = 300000000, + .pllout_max_rate = 600000000, + .flags = PLL_HAS_POSTDIV, +}; + +SYSCLK(1, pll1_sysclk1, pll1_pllen, 5, SYSCLK_ALWAYS_ENABLED); +SYSCLK(2, pll1_sysclk2, pll1_pllen, 5, 0); +SYSCLK(3, pll1_sysclk3, pll1_pllen, 5, 0); + +static const char * const da850_pll1_obsclk_parent_names[] = { + "oscin", + "pll1_sysclk1", + "pll1_sysclk2", + "pll1_sysclk3", +}; + +static u32 da850_pll1_obsclk_table[] = { + OCSEL_OCSRC_OSCIN, + OCSEL_OCSRC_PLL1_SYSCLK(1), + OCSEL_OCSRC_PLL1_SYSCLK(2), + OCSEL_OCSRC_PLL1_SYSCLK(3), +}; + +static const struct davinci_pll_obsclk_info da850_pll1_obsclk_info = { + .name = "pll1_obsclk", + .parent_names = da850_pll1_obsclk_parent_names, + .num_parents = ARRAY_SIZE(da850_pll1_obsclk_parent_names), + .table = da850_pll1_obsclk_table, + .ocsrc_mask = GENMASK(4, 0), +}; + +int da850_pll1_init(struct device *dev, void __iomem *base) +{ + struct clk *clk; + + davinci_pll_clk_register(dev, &da850_pll1_info, "oscin", base); + + davinci_pll_sysclk_register(dev, &pll1_sysclk1, base); + + clk = davinci_pll_sysclk_register(dev, &pll1_sysclk2, base); + clk_register_clkdev(clk, "pll1_sysclk2", "da850-async3-clksrc"); + + davinci_pll_sysclk_register(dev, &pll1_sysclk3, base); + + davinci_pll_obsclk_register(dev, &da850_pll1_obsclk_info, base); + + return 0; +} + +static const struct davinci_pll_sysclk_info *da850_pll1_sysclk_info[] = { + &pll1_sysclk1, + &pll1_sysclk2, + &pll1_sysclk3, + NULL +}; + +int of_da850_pll1_init(struct device *dev, void __iomem *base) +{ + return of_davinci_pll_init(dev, &da850_pll1_info, + &da850_pll1_obsclk_info, + da850_pll1_sysclk_info, 3, base); +} diff --git a/drivers/clk/davinci/pll.c b/drivers/clk/davinci/pll.c index d91cb9d5bc1f..124bbd2c39e0 100644 --- a/drivers/clk/davinci/pll.c +++ b/drivers/clk/davinci/pll.c @@ -771,11 +771,15 @@ int of_davinci_pll_init(struct device *dev, } static const struct of_device_id davinci_pll_of_match[] = { + { .compatible = "ti,da850-pll0", .data = of_da850_pll0_init }, + { .compatible = "ti,da850-pll1", .data = of_da850_pll1_init }, { } }; static const struct platform_device_id davinci_pll_id_table[] = { { .name = "da830-pll", .driver_data = (kernel_ulong_t)da830_pll_init }, + { .name = "da850-pll0", .driver_data = (kernel_ulong_t)da850_pll0_init }, + { .name = "da850-pll1", .driver_data = (kernel_ulong_t)da850_pll1_init }, { } }; diff --git a/drivers/clk/davinci/pll.h b/drivers/clk/davinci/pll.h index 0de2c61cb135..53b8d513d726 100644 --- a/drivers/clk/davinci/pll.h +++ b/drivers/clk/davinci/pll.h @@ -121,4 +121,9 @@ int of_davinci_pll_init(struct device *dev, int da830_pll_init(struct device *dev, void __iomem *base); +int da850_pll0_init(struct device *dev, void __iomem *base); +int da850_pll1_init(struct device *dev, void __iomem *base); +int of_da850_pll0_init(struct device *dev, void __iomem *base); +int of_da850_pll1_init(struct device *dev, void __iomem *base); + #endif /* __CLK_DAVINCI_PLL_H___ */ -- cgit From dcdd19b269e0de71a60b50516b95b39341a0795a Mon Sep 17 00:00:00 2001 From: David Lechner Date: Thu, 15 Mar 2018 21:52:21 -0500 Subject: clk: davinci: Add platform information for TI DM355 PLL This adds platform-specific declarations for the PLL clocks on TI DM355 based systems. Signed-off-by: David Lechner Signed-off-by: Stephen Boyd --- drivers/clk/davinci/Makefile | 1 + drivers/clk/davinci/pll-dm355.c | 79 +++++++++++++++++++++++++++++++++++++++++ drivers/clk/davinci/pll.c | 2 ++ drivers/clk/davinci/pll.h | 3 ++ 4 files changed, 85 insertions(+) create mode 100644 drivers/clk/davinci/pll-dm355.c diff --git a/drivers/clk/davinci/Makefile b/drivers/clk/davinci/Makefile index 13049d43215e..6720bd073a27 100644 --- a/drivers/clk/davinci/Makefile +++ b/drivers/clk/davinci/Makefile @@ -4,4 +4,5 @@ ifeq ($(CONFIG_COMMON_CLK), y) obj-y += pll.o obj-$(CONFIG_ARCH_DAVINCI_DA830) += pll-da830.o obj-$(CONFIG_ARCH_DAVINCI_DA850) += pll-da850.o +obj-$(CONFIG_ARCH_DAVINCI_DM355) += pll-dm355.o endif diff --git a/drivers/clk/davinci/pll-dm355.c b/drivers/clk/davinci/pll-dm355.c new file mode 100644 index 000000000000..5345f8286c50 --- /dev/null +++ b/drivers/clk/davinci/pll-dm355.c @@ -0,0 +1,79 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * PLL clock descriptions for TI DM355 + * + * Copyright (C) 2018 David Lechner + */ + +#include +#include +#include +#include + +#include "pll.h" + +static const struct davinci_pll_clk_info dm355_pll1_info = { + .name = "pll1", + .pllm_mask = GENMASK(7, 0), + .pllm_min = 92, + .pllm_max = 184, + .flags = PLL_HAS_CLKMODE | PLL_HAS_PREDIV | PLL_PREDIV_ALWAYS_ENABLED | + PLL_PREDIV_FIXED8 | PLL_HAS_POSTDIV | + PLL_POSTDIV_ALWAYS_ENABLED | PLL_POSTDIV_FIXED_DIV, +}; + +SYSCLK(1, pll1_sysclk1, pll1, 5, SYSCLK_FIXED_DIV | SYSCLK_ALWAYS_ENABLED); +SYSCLK(2, pll1_sysclk2, pll1, 5, SYSCLK_FIXED_DIV | SYSCLK_ALWAYS_ENABLED); +SYSCLK(3, pll1_sysclk3, pll1, 5, SYSCLK_ALWAYS_ENABLED); +SYSCLK(4, pll1_sysclk4, pll1, 5, SYSCLK_ALWAYS_ENABLED); + +int dm355_pll1_init(struct device *dev, void __iomem *base) +{ + struct clk *clk; + + davinci_pll_clk_register(dev, &dm355_pll1_info, "ref_clk", base); + + clk = davinci_pll_sysclk_register(dev, &pll1_sysclk1, base); + clk_register_clkdev(clk, "pll1_sysclk1", "dm355-psc"); + + clk = davinci_pll_sysclk_register(dev, &pll1_sysclk2, base); + clk_register_clkdev(clk, "pll1_sysclk2", "dm355-psc"); + + clk = davinci_pll_sysclk_register(dev, &pll1_sysclk3, base); + clk_register_clkdev(clk, "pll1_sysclk3", "dm355-psc"); + + clk = davinci_pll_sysclk_register(dev, &pll1_sysclk4, base); + clk_register_clkdev(clk, "pll1_sysclk4", "dm355-psc"); + + clk = davinci_pll_auxclk_register(dev, "pll1_auxclk", base); + clk_register_clkdev(clk, "pll1_auxclk", "dm355-psc"); + + davinci_pll_sysclkbp_clk_register(dev, "pll1_sysclkbp", base); + + return 0; +} + +static const struct davinci_pll_clk_info dm355_pll2_info = { + .name = "pll2", + .pllm_mask = GENMASK(7, 0), + .pllm_min = 92, + .pllm_max = 184, + .flags = PLL_HAS_PREDIV | PLL_PREDIV_ALWAYS_ENABLED | PLL_HAS_POSTDIV | + PLL_POSTDIV_ALWAYS_ENABLED | PLL_POSTDIV_FIXED_DIV, +}; + +SYSCLK(1, pll2_sysclk1, pll2, 5, SYSCLK_FIXED_DIV); +SYSCLK(2, pll2_sysclk2, pll2, 5, SYSCLK_FIXED_DIV | SYSCLK_ALWAYS_ENABLED); + +int dm355_pll2_init(struct device *dev, void __iomem *base) +{ + davinci_pll_clk_register(dev, &dm355_pll2_info, "oscin", base); + + davinci_pll_sysclk_register(dev, &pll2_sysclk1, base); + + davinci_pll_sysclk_register(dev, &pll2_sysclk2, base); + + davinci_pll_sysclkbp_clk_register(dev, "pll2_sysclkbp", base); + + return 0; +} diff --git a/drivers/clk/davinci/pll.c b/drivers/clk/davinci/pll.c index 124bbd2c39e0..4a506a970c52 100644 --- a/drivers/clk/davinci/pll.c +++ b/drivers/clk/davinci/pll.c @@ -780,6 +780,8 @@ static const struct platform_device_id davinci_pll_id_table[] = { { .name = "da830-pll", .driver_data = (kernel_ulong_t)da830_pll_init }, { .name = "da850-pll0", .driver_data = (kernel_ulong_t)da850_pll0_init }, { .name = "da850-pll1", .driver_data = (kernel_ulong_t)da850_pll1_init }, + { .name = "dm355-pll1", .driver_data = (kernel_ulong_t)dm355_pll1_init }, + { .name = "dm355-pll2", .driver_data = (kernel_ulong_t)dm355_pll2_init }, { } }; diff --git a/drivers/clk/davinci/pll.h b/drivers/clk/davinci/pll.h index 53b8d513d726..d90d3080fcda 100644 --- a/drivers/clk/davinci/pll.h +++ b/drivers/clk/davinci/pll.h @@ -126,4 +126,7 @@ int da850_pll1_init(struct device *dev, void __iomem *base); int of_da850_pll0_init(struct device *dev, void __iomem *base); int of_da850_pll1_init(struct device *dev, void __iomem *base); +int dm355_pll1_init(struct device *dev, void __iomem *base); +int dm355_pll2_init(struct device *dev, void __iomem *base); + #endif /* __CLK_DAVINCI_PLL_H___ */ -- cgit From 650bba61fc3611e4a349fb323011fd3e7a228860 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Thu, 15 Mar 2018 21:52:22 -0500 Subject: clk: davinci: Add platform information for TI DM365 PLL This adds platform-specific declarations for the PLL clocks on TI DM365 based systems. Signed-off-by: David Lechner Signed-off-by: Stephen Boyd --- drivers/clk/davinci/Makefile | 1 + drivers/clk/davinci/pll-dm365.c | 145 ++++++++++++++++++++++++++++++++++++++++ drivers/clk/davinci/pll.c | 2 + drivers/clk/davinci/pll.h | 3 + 4 files changed, 151 insertions(+) create mode 100644 drivers/clk/davinci/pll-dm365.c diff --git a/drivers/clk/davinci/Makefile b/drivers/clk/davinci/Makefile index 6720bd073a27..353aa021d3c2 100644 --- a/drivers/clk/davinci/Makefile +++ b/drivers/clk/davinci/Makefile @@ -5,4 +5,5 @@ obj-y += pll.o obj-$(CONFIG_ARCH_DAVINCI_DA830) += pll-da830.o obj-$(CONFIG_ARCH_DAVINCI_DA850) += pll-da850.o obj-$(CONFIG_ARCH_DAVINCI_DM355) += pll-dm355.o +obj-$(CONFIG_ARCH_DAVINCI_DM365) += pll-dm365.o endif diff --git a/drivers/clk/davinci/pll-dm365.c b/drivers/clk/davinci/pll-dm365.c new file mode 100644 index 000000000000..5f8d9f42d0f3 --- /dev/null +++ b/drivers/clk/davinci/pll-dm365.c @@ -0,0 +1,145 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * PLL clock descriptions for TI DM365 + * + * Copyright (C) 2018 David Lechner + */ + +#include +#include +#include +#include +#include + +#include "pll.h" + +#define OCSEL_OCSRC_ENABLE 0 + +static const struct davinci_pll_clk_info dm365_pll1_info = { + .name = "pll1", + .pllm_mask = GENMASK(9, 0), + .pllm_min = 1, + .pllm_max = 1023, + .flags = PLL_HAS_CLKMODE | PLL_HAS_PREDIV | PLL_HAS_POSTDIV | + PLL_POSTDIV_ALWAYS_ENABLED | PLL_PLLM_2X, +}; + +SYSCLK(1, pll1_sysclk1, pll1_pllen, 5, SYSCLK_ALWAYS_ENABLED); +SYSCLK(2, pll1_sysclk2, pll1_pllen, 5, SYSCLK_ALWAYS_ENABLED); +SYSCLK(3, pll1_sysclk3, pll1_pllen, 5, SYSCLK_ALWAYS_ENABLED); +SYSCLK(4, pll1_sysclk4, pll1_pllen, 5, SYSCLK_ALWAYS_ENABLED); +SYSCLK(5, pll1_sysclk5, pll1_pllen, 5, SYSCLK_ALWAYS_ENABLED); +SYSCLK(6, pll1_sysclk6, pll1_pllen, 5, SYSCLK_ALWAYS_ENABLED); +SYSCLK(7, pll1_sysclk7, pll1_pllen, 5, SYSCLK_ALWAYS_ENABLED); +SYSCLK(8, pll1_sysclk8, pll1_pllen, 5, SYSCLK_ALWAYS_ENABLED); +SYSCLK(9, pll1_sysclk9, pll1_pllen, 5, SYSCLK_ALWAYS_ENABLED); + +/* + * This is a bit of a hack to make OCSEL[OCSRC] on DM365 look like OCSEL[OCSRC] + * on DA850. On DM365, OCSEL[OCSRC] is just an enable/disable bit instead of a + * multiplexer. By modeling it as a single parent mux clock, the clock code will + * still do the right thing in this case. + */ +static const char * const dm365_pll_obsclk_parent_names[] = { + "oscin", +}; + +static u32 dm365_pll_obsclk_table[] = { + OCSEL_OCSRC_ENABLE, +}; + +static const struct davinci_pll_obsclk_info dm365_pll1_obsclk_info = { + .name = "pll1_obsclk", + .parent_names = dm365_pll_obsclk_parent_names, + .num_parents = ARRAY_SIZE(dm365_pll_obsclk_parent_names), + .table = dm365_pll_obsclk_table, + .ocsrc_mask = BIT(4), +}; + +int dm365_pll1_init(struct device *dev, void __iomem *base) +{ + struct clk *clk; + + davinci_pll_clk_register(dev, &dm365_pll1_info, "ref_clk", base); + + clk = davinci_pll_sysclk_register(dev, &pll1_sysclk1, base); + clk_register_clkdev(clk, "pll1_sysclk1", "dm365-psc"); + + clk = davinci_pll_sysclk_register(dev, &pll1_sysclk2, base); + clk_register_clkdev(clk, "pll1_sysclk2", "dm365-psc"); + + clk = davinci_pll_sysclk_register(dev, &pll1_sysclk3, base); + clk_register_clkdev(clk, "pll1_sysclk3", "dm365-psc"); + + clk = davinci_pll_sysclk_register(dev, &pll1_sysclk4, base); + clk_register_clkdev(clk, "pll1_sysclk4", "dm365-psc"); + + clk = davinci_pll_sysclk_register(dev, &pll1_sysclk5, base); + clk_register_clkdev(clk, "pll1_sysclk5", "dm365-psc"); + + davinci_pll_sysclk_register(dev, &pll1_sysclk6, base); + + davinci_pll_sysclk_register(dev, &pll1_sysclk7, base); + + clk = davinci_pll_sysclk_register(dev, &pll1_sysclk8, base); + clk_register_clkdev(clk, "pll1_sysclk8", "dm365-psc"); + + davinci_pll_sysclk_register(dev, &pll1_sysclk9, base); + + clk = davinci_pll_auxclk_register(dev, "pll1_auxclk", base); + clk_register_clkdev(clk, "pll1_auxclk", "dm355-psc"); + + davinci_pll_sysclkbp_clk_register(dev, "pll1_sysclkbp", base); + + davinci_pll_obsclk_register(dev, &dm365_pll1_obsclk_info, base); + + return 0; +} + +static const struct davinci_pll_clk_info dm365_pll2_info = { + .name = "pll2", + .pllm_mask = GENMASK(9, 0), + .pllm_min = 1, + .pllm_max = 1023, + .flags = PLL_HAS_PREDIV | PLL_HAS_POSTDIV | PLL_POSTDIV_ALWAYS_ENABLED | + PLL_PLLM_2X, +}; + +SYSCLK(1, pll2_sysclk1, pll2_pllen, 5, SYSCLK_ALWAYS_ENABLED); +SYSCLK(2, pll2_sysclk2, pll2_pllen, 5, SYSCLK_ALWAYS_ENABLED); +SYSCLK(3, pll2_sysclk3, pll2_pllen, 5, SYSCLK_ALWAYS_ENABLED); +SYSCLK(4, pll2_sysclk4, pll2_pllen, 5, SYSCLK_ALWAYS_ENABLED); +SYSCLK(5, pll2_sysclk5, pll2_pllen, 5, SYSCLK_ALWAYS_ENABLED); + +static const struct davinci_pll_obsclk_info dm365_pll2_obsclk_info = { + .name = "pll2_obsclk", + .parent_names = dm365_pll_obsclk_parent_names, + .num_parents = ARRAY_SIZE(dm365_pll_obsclk_parent_names), + .table = dm365_pll_obsclk_table, + .ocsrc_mask = BIT(4), +}; + +int dm365_pll2_init(struct device *dev, void __iomem *base) +{ + struct clk *clk; + + davinci_pll_clk_register(dev, &dm365_pll2_info, "oscin", base); + + davinci_pll_sysclk_register(dev, &pll2_sysclk1, base); + + clk = davinci_pll_sysclk_register(dev, &pll2_sysclk2, base); + clk_register_clkdev(clk, "pll1_sysclk2", "dm365-psc"); + + davinci_pll_sysclk_register(dev, &pll2_sysclk3, base); + + clk = davinci_pll_sysclk_register(dev, &pll2_sysclk4, base); + clk_register_clkdev(clk, "pll1_sysclk4", "dm365-psc"); + + davinci_pll_sysclk_register(dev, &pll2_sysclk5, base); + + davinci_pll_auxclk_register(dev, "pll2_auxclk", base); + + davinci_pll_obsclk_register(dev, &dm365_pll2_obsclk_info, base); + + return 0; +} diff --git a/drivers/clk/davinci/pll.c b/drivers/clk/davinci/pll.c index 4a506a970c52..7e1f6721533a 100644 --- a/drivers/clk/davinci/pll.c +++ b/drivers/clk/davinci/pll.c @@ -782,6 +782,8 @@ static const struct platform_device_id davinci_pll_id_table[] = { { .name = "da850-pll1", .driver_data = (kernel_ulong_t)da850_pll1_init }, { .name = "dm355-pll1", .driver_data = (kernel_ulong_t)dm355_pll1_init }, { .name = "dm355-pll2", .driver_data = (kernel_ulong_t)dm355_pll2_init }, + { .name = "dm365-pll1", .driver_data = (kernel_ulong_t)dm365_pll1_init }, + { .name = "dm365-pll2", .driver_data = (kernel_ulong_t)dm365_pll2_init }, { } }; diff --git a/drivers/clk/davinci/pll.h b/drivers/clk/davinci/pll.h index d90d3080fcda..bf9fdc896fbc 100644 --- a/drivers/clk/davinci/pll.h +++ b/drivers/clk/davinci/pll.h @@ -129,4 +129,7 @@ int of_da850_pll1_init(struct device *dev, void __iomem *base); int dm355_pll1_init(struct device *dev, void __iomem *base); int dm355_pll2_init(struct device *dev, void __iomem *base); +int dm365_pll1_init(struct device *dev, void __iomem *base); +int dm365_pll2_init(struct device *dev, void __iomem *base); + #endif /* __CLK_DAVINCI_PLL_H___ */ -- cgit From d67c13eaf79b35bedb1e0bc405416afa3bd6ee04 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Thu, 15 Mar 2018 21:52:23 -0500 Subject: clk: davinci: Add platform information for TI DM644x PLL This adds platform-specific declarations for the PLL clocks on TI DM644x based systems. Signed-off-by: David Lechner Signed-off-by: Stephen Boyd --- drivers/clk/davinci/Makefile | 1 + drivers/clk/davinci/pll-dm644x.c | 80 ++++++++++++++++++++++++++++++++++++++++ drivers/clk/davinci/pll.c | 2 + drivers/clk/davinci/pll.h | 3 ++ 4 files changed, 86 insertions(+) create mode 100644 drivers/clk/davinci/pll-dm644x.c diff --git a/drivers/clk/davinci/Makefile b/drivers/clk/davinci/Makefile index 353aa021d3c2..59d8ab68c9ec 100644 --- a/drivers/clk/davinci/Makefile +++ b/drivers/clk/davinci/Makefile @@ -6,4 +6,5 @@ obj-$(CONFIG_ARCH_DAVINCI_DA830) += pll-da830.o obj-$(CONFIG_ARCH_DAVINCI_DA850) += pll-da850.o obj-$(CONFIG_ARCH_DAVINCI_DM355) += pll-dm355.o obj-$(CONFIG_ARCH_DAVINCI_DM365) += pll-dm365.o +obj-$(CONFIG_ARCH_DAVINCI_DM644x) += pll-dm644x.o endif diff --git a/drivers/clk/davinci/pll-dm644x.c b/drivers/clk/davinci/pll-dm644x.c new file mode 100644 index 000000000000..69bf785377cf --- /dev/null +++ b/drivers/clk/davinci/pll-dm644x.c @@ -0,0 +1,80 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * PLL clock descriptions for TI DM644X + * + * Copyright (C) 2018 David Lechner + */ + +#include +#include +#include +#include + +#include "pll.h" + +static const struct davinci_pll_clk_info dm644x_pll1_info = { + .name = "pll1", + .pllm_mask = GENMASK(4, 0), + .pllm_min = 1, + .pllm_max = 32, + .pllout_min_rate = 400000000, + .pllout_max_rate = 600000000, /* 810MHz @ 1.3V, -810 only */ + .flags = PLL_HAS_CLKMODE | PLL_HAS_POSTDIV, +}; + +SYSCLK(1, pll1_sysclk1, pll1_pllen, 4, SYSCLK_FIXED_DIV); +SYSCLK(2, pll1_sysclk2, pll1_pllen, 4, SYSCLK_FIXED_DIV); +SYSCLK(3, pll1_sysclk3, pll1_pllen, 4, SYSCLK_FIXED_DIV); +SYSCLK(5, pll1_sysclk5, pll1_pllen, 4, SYSCLK_FIXED_DIV); + +int dm644x_pll1_init(struct device *dev, void __iomem *base) +{ + struct clk *clk; + + davinci_pll_clk_register(dev, &dm644x_pll1_info, "ref_clk", base); + + clk = davinci_pll_sysclk_register(dev, &pll1_sysclk1, base); + clk_register_clkdev(clk, "pll1_sysclk1", "dm644x-psc"); + + clk = davinci_pll_sysclk_register(dev, &pll1_sysclk2, base); + clk_register_clkdev(clk, "pll1_sysclk2", "dm644x-psc"); + + clk = davinci_pll_sysclk_register(dev, &pll1_sysclk3, base); + clk_register_clkdev(clk, "pll1_sysclk3", "dm644x-psc"); + + clk = davinci_pll_sysclk_register(dev, &pll1_sysclk5, base); + clk_register_clkdev(clk, "pll1_sysclk5", "dm644x-psc"); + + clk = davinci_pll_auxclk_register(dev, "pll1_auxclk", base); + clk_register_clkdev(clk, "pll1_auxclk", "dm644x-psc"); + + davinci_pll_sysclkbp_clk_register(dev, "pll1_sysclkbp", base); + + return 0; +} + +static const struct davinci_pll_clk_info dm644x_pll2_info = { + .name = "pll2", + .pllm_mask = GENMASK(4, 0), + .pllm_min = 1, + .pllm_max = 32, + .pllout_min_rate = 400000000, + .pllout_max_rate = 900000000, + .flags = PLL_HAS_POSTDIV | PLL_POSTDIV_FIXED_DIV, +}; + +SYSCLK(1, pll2_sysclk1, pll2_pllen, 4, 0); +SYSCLK(2, pll2_sysclk2, pll2_pllen, 4, 0); + +int dm644x_pll2_init(struct device *dev, void __iomem *base) +{ + davinci_pll_clk_register(dev, &dm644x_pll2_info, "oscin", base); + + davinci_pll_sysclk_register(dev, &pll2_sysclk1, base); + + davinci_pll_sysclk_register(dev, &pll2_sysclk2, base); + + davinci_pll_sysclkbp_clk_register(dev, "pll2_sysclkbp", base); + + return 0; +} diff --git a/drivers/clk/davinci/pll.c b/drivers/clk/davinci/pll.c index 7e1f6721533a..4f86f35a70fd 100644 --- a/drivers/clk/davinci/pll.c +++ b/drivers/clk/davinci/pll.c @@ -784,6 +784,8 @@ static const struct platform_device_id davinci_pll_id_table[] = { { .name = "dm355-pll2", .driver_data = (kernel_ulong_t)dm355_pll2_init }, { .name = "dm365-pll1", .driver_data = (kernel_ulong_t)dm365_pll1_init }, { .name = "dm365-pll2", .driver_data = (kernel_ulong_t)dm365_pll2_init }, + { .name = "dm644x-pll1", .driver_data = (kernel_ulong_t)dm644x_pll1_init }, + { .name = "dm644x-pll2", .driver_data = (kernel_ulong_t)dm644x_pll2_init }, { } }; diff --git a/drivers/clk/davinci/pll.h b/drivers/clk/davinci/pll.h index bf9fdc896fbc..d8af4f516253 100644 --- a/drivers/clk/davinci/pll.h +++ b/drivers/clk/davinci/pll.h @@ -132,4 +132,7 @@ int dm355_pll2_init(struct device *dev, void __iomem *base); int dm365_pll1_init(struct device *dev, void __iomem *base); int dm365_pll2_init(struct device *dev, void __iomem *base); +int dm644x_pll1_init(struct device *dev, void __iomem *base); +int dm644x_pll2_init(struct device *dev, void __iomem *base); + #endif /* __CLK_DAVINCI_PLL_H___ */ -- cgit From 6ef35851a0147372e70b8a6115f4d712f30ca200 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Thu, 15 Mar 2018 21:52:24 -0500 Subject: clk: davinci: Add platform information for TI DM646x PLL This adds platform-specific declarations for the PLL clocks on TI DM646x based systems. Signed-off-by: David Lechner Signed-off-by: Stephen Boyd --- drivers/clk/davinci/Makefile | 1 + drivers/clk/davinci/pll-dm646x.c | 84 ++++++++++++++++++++++++++++++++++++++++ drivers/clk/davinci/pll.c | 2 + drivers/clk/davinci/pll.h | 3 ++ 4 files changed, 90 insertions(+) create mode 100644 drivers/clk/davinci/pll-dm646x.c diff --git a/drivers/clk/davinci/Makefile b/drivers/clk/davinci/Makefile index 59d8ab68c9ec..d471386301be 100644 --- a/drivers/clk/davinci/Makefile +++ b/drivers/clk/davinci/Makefile @@ -7,4 +7,5 @@ obj-$(CONFIG_ARCH_DAVINCI_DA850) += pll-da850.o obj-$(CONFIG_ARCH_DAVINCI_DM355) += pll-dm355.o obj-$(CONFIG_ARCH_DAVINCI_DM365) += pll-dm365.o obj-$(CONFIG_ARCH_DAVINCI_DM644x) += pll-dm644x.o +obj-$(CONFIG_ARCH_DAVINCI_DM646x) += pll-dm646x.o endif diff --git a/drivers/clk/davinci/pll-dm646x.c b/drivers/clk/davinci/pll-dm646x.c new file mode 100644 index 000000000000..a61cc3256418 --- /dev/null +++ b/drivers/clk/davinci/pll-dm646x.c @@ -0,0 +1,84 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * PLL clock descriptions for TI DM646X + * + * Copyright (C) 2018 David Lechner + */ + +#include +#include +#include +#include + +#include "pll.h" + +static const struct davinci_pll_clk_info dm646x_pll1_info = { + .name = "pll1", + .pllm_mask = GENMASK(4, 0), + .pllm_min = 14, + .pllm_max = 32, + .flags = PLL_HAS_CLKMODE, +}; + +SYSCLK(1, pll1_sysclk1, pll1_pllen, 4, SYSCLK_FIXED_DIV); +SYSCLK(2, pll1_sysclk2, pll1_pllen, 4, SYSCLK_FIXED_DIV); +SYSCLK(3, pll1_sysclk3, pll1_pllen, 4, SYSCLK_FIXED_DIV); +SYSCLK(4, pll1_sysclk4, pll1_pllen, 4, 0); +SYSCLK(5, pll1_sysclk5, pll1_pllen, 4, 0); +SYSCLK(6, pll1_sysclk6, pll1_pllen, 4, 0); +SYSCLK(8, pll1_sysclk8, pll1_pllen, 4, 0); +SYSCLK(9, pll1_sysclk9, pll1_pllen, 4, 0); + +int dm646x_pll1_init(struct device *dev, void __iomem *base) +{ + struct clk *clk; + + davinci_pll_clk_register(dev, &dm646x_pll1_info, "ref_clk", base); + + clk = davinci_pll_sysclk_register(dev, &pll1_sysclk1, base); + clk_register_clkdev(clk, "pll1_sysclk1", "dm646x-psc"); + + clk = davinci_pll_sysclk_register(dev, &pll1_sysclk2, base); + clk_register_clkdev(clk, "pll1_sysclk2", "dm646x-psc"); + + clk = davinci_pll_sysclk_register(dev, &pll1_sysclk3, base); + clk_register_clkdev(clk, "pll1_sysclk3", "dm646x-psc"); + clk_register_clkdev(clk, NULL, "davinci-wdt"); + + clk = davinci_pll_sysclk_register(dev, &pll1_sysclk4, base); + clk_register_clkdev(clk, "pll1_sysclk4", "dm646x-psc"); + + clk = davinci_pll_sysclk_register(dev, &pll1_sysclk5, base); + clk_register_clkdev(clk, "pll1_sysclk5", "dm646x-psc"); + + davinci_pll_sysclk_register(dev, &pll1_sysclk6, base); + + davinci_pll_sysclk_register(dev, &pll1_sysclk8, base); + + davinci_pll_sysclk_register(dev, &pll1_sysclk9, base); + + davinci_pll_sysclkbp_clk_register(dev, "pll1_sysclkbp", base); + + davinci_pll_auxclk_register(dev, "pll1_auxclk", base); + + return 0; +} + +static const struct davinci_pll_clk_info dm646x_pll2_info = { + .name = "pll2", + .pllm_mask = GENMASK(4, 0), + .pllm_min = 14, + .pllm_max = 32, + .flags = 0, +}; + +SYSCLK(1, pll2_sysclk1, pll2_pllen, 4, 0); + +int dm646x_pll2_init(struct device *dev, void __iomem *base) +{ + davinci_pll_clk_register(dev, &dm646x_pll2_info, "oscin", base); + + davinci_pll_sysclk_register(dev, &pll2_sysclk1, base); + + return 0; +} diff --git a/drivers/clk/davinci/pll.c b/drivers/clk/davinci/pll.c index 4f86f35a70fd..89d30bf95102 100644 --- a/drivers/clk/davinci/pll.c +++ b/drivers/clk/davinci/pll.c @@ -786,6 +786,8 @@ static const struct platform_device_id davinci_pll_id_table[] = { { .name = "dm365-pll2", .driver_data = (kernel_ulong_t)dm365_pll2_init }, { .name = "dm644x-pll1", .driver_data = (kernel_ulong_t)dm644x_pll1_init }, { .name = "dm644x-pll2", .driver_data = (kernel_ulong_t)dm644x_pll2_init }, + { .name = "dm646x-pll1", .driver_data = (kernel_ulong_t)dm646x_pll1_init }, + { .name = "dm646x-pll2", .driver_data = (kernel_ulong_t)dm646x_pll2_init }, { } }; diff --git a/drivers/clk/davinci/pll.h b/drivers/clk/davinci/pll.h index d8af4f516253..b1b6fb23f972 100644 --- a/drivers/clk/davinci/pll.h +++ b/drivers/clk/davinci/pll.h @@ -135,4 +135,7 @@ int dm365_pll2_init(struct device *dev, void __iomem *base); int dm644x_pll1_init(struct device *dev, void __iomem *base); int dm644x_pll2_init(struct device *dev, void __iomem *base); +int dm646x_pll1_init(struct device *dev, void __iomem *base); +int dm646x_pll2_init(struct device *dev, void __iomem *base); + #endif /* __CLK_DAVINCI_PLL_H___ */ -- cgit From 21cdf7269f9dcd8dc22d152fbfee85e4ea57289f Mon Sep 17 00:00:00 2001 From: David Lechner Date: Thu, 15 Mar 2018 21:52:25 -0500 Subject: dt-bindings: clock: New bindings for TI Davinci PSC This adds a new binding for the Power Sleep Controller (PSC) for the mach-davinci family of processors. Note: Although TI Keystone has a very similar PSC, we are not using the existing bindings. Keystone is using a legacy one-node-per-clock binding (actually two nodes if you count the separate reset binding for the same IP block). Also, some davinci LPSCs have quirks that aren't handled by the keystone bindings, so we would be adding one compatible string per clock with quirks instead of just a new compatible string for each controller. Signed-off-by: David Lechner Reviewed-by: Rob Herring Signed-off-by: Stephen Boyd --- .../devicetree/bindings/clock/ti/davinci/psc.txt | 71 ++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/ti/davinci/psc.txt diff --git a/Documentation/devicetree/bindings/clock/ti/davinci/psc.txt b/Documentation/devicetree/bindings/clock/ti/davinci/psc.txt new file mode 100644 index 000000000000..dae4ad8e198c --- /dev/null +++ b/Documentation/devicetree/bindings/clock/ti/davinci/psc.txt @@ -0,0 +1,71 @@ +Binding for TI DaVinci Power Sleep Controller (PSC) + +The PSC provides power management, clock gating and reset functionality. It is +primarily used for clocking. + +Required properties: +- compatible: shall be one of: + - "ti,da850-psc0" for PSC0 on DA850/OMAP-L138/AM18XX + - "ti,da850-psc1" for PSC1 on DA850/OMAP-L138/AM18XX +- reg: physical base address and size of the controller's register area +- #clock-cells: from common clock binding; shall be set to 1 +- #power-domain-cells: from generic power domain binding; shall be set to 1. +- clocks: phandles to clocks corresponding to the clock-names property +- clock-names: list of parent clock names - depends on compatible value + - for "ti,da850-psc0", shall be "pll0_sysclk1", "pll0_sysclk2", + "pll0_sysclk4", "pll0_sysclk6", "async1" + - for "ti,da850-psc1", shall be "pll0_sysclk2", "pll0_sysclk4", "async3" + +Optional properties: +- #reset-cells: from reset binding; shall be set to 1 - only applicable when + at least one local domain provides a local reset. + +Consumers: + + Clock, power domain and reset consumers shall use the local power domain + module ID (LPSC) as the index corresponding to the clock cell. Refer to + the device-specific datasheet to find these numbers. NB: Most local + domains only provide a clock/power domain and not a reset. + +Examples: + + psc0: clock-controller@10000 { + compatible = "ti,da850-psc0"; + reg = <0x10000 0x1000>; + #clock-cells = <1>; + #power-domain-cells = <1>; + #reset-cells = <1>; + clocks = <&pll0_sysclk 1>, <&pll0_sysclk 2>, + <&pll0_sysclk 4>, <&pll0_sysclk 6>, <&async1_clk>; + clock_names = "pll0_sysclk1", "pll0_sysclk2", + "pll0_sysclk4", "pll0_sysclk6", "async1"; + }; + psc1: clock-controller@227000 { + compatible = "ti,da850-psc1"; + reg = <0x227000 0x1000>; + #clock-cells = <1>; + #power-domain-cells = <1>; + clocks = <&pll0_sysclk 2>, <&pll0_sysclk 4>, <&async3_clk>; + clock_names = "pll0_sysclk2", "pll0_sysclk4", "async3"; + }; + + /* consumer */ + dsp: dsp@11800000 { + compatible = "ti,da850-dsp"; + reg = <0x11800000 0x40000>, + <0x11e00000 0x8000>, + <0x11f00000 0x8000>, + <0x01c14044 0x4>, + <0x01c14174 0x8>; + reg-names = "l2sram", "l1pram", "l1dram", "host1cfg", "chipsig"; + interrupt-parent = <&intc>; + interrupts = <28>; + clocks = <&psc0 15>; + power-domains = <&psc0 15>; + resets = <&psc0 15>; + }; + +Also see: +- Documentation/devicetree/bindings/clock/clock-bindings.txt +- Documentation/devicetree/bindings/power/power_domain.txt +- Documentation/devicetree/bindings/reset/reset.txt -- cgit From c6ed4d734bc7f731709dab0ffd69eed499dd5277 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Thu, 15 Mar 2018 21:52:26 -0500 Subject: clk: davinci: New driver for davinci PSC clocks This adds a new driver for mach-davinci PSC clocks. This is porting the code from arch/arm/mach-davinci/psc.c to the common clock framework and is converting it to use regmap to simplify the code. Additionally, it adds device tree support for these clocks. Note: although there are similar clocks for TI Keystone we are not able to share the code for a few reasons. The keystone clocks are device tree only and use legacy one-node-per-clock bindings. Also the keystone driver makes the assumption that there is only one PSC per SoC and uses global variables, but here we have two controllers per SoC. Signed-off-by: David Lechner Signed-off-by: Stephen Boyd --- drivers/clk/davinci/Makefile | 2 + drivers/clk/davinci/psc.c | 542 +++++++++++++++++++++++++++++++++++++++++++ drivers/clk/davinci/psc.h | 97 ++++++++ 3 files changed, 641 insertions(+) create mode 100644 drivers/clk/davinci/psc.c create mode 100644 drivers/clk/davinci/psc.h diff --git a/drivers/clk/davinci/Makefile b/drivers/clk/davinci/Makefile index d471386301be..cd1bf2cefc05 100644 --- a/drivers/clk/davinci/Makefile +++ b/drivers/clk/davinci/Makefile @@ -8,4 +8,6 @@ obj-$(CONFIG_ARCH_DAVINCI_DM355) += pll-dm355.o obj-$(CONFIG_ARCH_DAVINCI_DM365) += pll-dm365.o obj-$(CONFIG_ARCH_DAVINCI_DM644x) += pll-dm644x.o obj-$(CONFIG_ARCH_DAVINCI_DM646x) += pll-dm646x.o + +obj-y += psc.o endif diff --git a/drivers/clk/davinci/psc.c b/drivers/clk/davinci/psc.c new file mode 100644 index 000000000000..5613607f7757 --- /dev/null +++ b/drivers/clk/davinci/psc.c @@ -0,0 +1,542 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Clock driver for TI Davinci PSC controllers + * + * Copyright (C) 2017 David Lechner + * + * Based on: drivers/clk/keystone/gate.c + * Copyright (C) 2013 Texas Instruments. + * Murali Karicheri + * Santosh Shilimkar + * + * And: arch/arm/mach-davinci/psc.c + * Copyright (C) 2006 Texas Instruments. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "psc.h" + +/* PSC register offsets */ +#define EPCPR 0x070 +#define PTCMD 0x120 +#define PTSTAT 0x128 +#define PDSTAT(n) (0x200 + 4 * (n)) +#define PDCTL(n) (0x300 + 4 * (n)) +#define MDSTAT(n) (0x800 + 4 * (n)) +#define MDCTL(n) (0xa00 + 4 * (n)) + +/* PSC module states */ +enum davinci_lpsc_state { + LPSC_STATE_SWRSTDISABLE = 0, + LPSC_STATE_SYNCRST = 1, + LPSC_STATE_DISABLE = 2, + LPSC_STATE_ENABLE = 3, +}; + +#define MDSTAT_STATE_MASK GENMASK(5, 0) +#define MDSTAT_MCKOUT BIT(12) +#define PDSTAT_STATE_MASK GENMASK(4, 0) +#define MDCTL_FORCE BIT(31) +#define MDCTL_LRESET BIT(8) +#define PDCTL_EPCGOOD BIT(8) +#define PDCTL_NEXT BIT(0) + +struct davinci_psc_data { + struct clk_onecell_data clk_data; + struct genpd_onecell_data pm_data; + struct reset_controller_dev rcdev; +}; + +/** + * struct davinci_lpsc_clk - LPSC clock structure + * @dev: the device that provides this LPSC + * @hw: clk_hw for the LPSC + * @pm_domain: power domain for the LPSC + * @genpd_clk: clock reference owned by @pm_domain + * @regmap: PSC MMIO region + * @md: Module domain (LPSC module id) + * @pd: Power domain + * @flags: LPSC_* quirk flags + */ +struct davinci_lpsc_clk { + struct device *dev; + struct clk_hw hw; + struct generic_pm_domain pm_domain; + struct clk *genpd_clk; + struct regmap *regmap; + u32 md; + u32 pd; + u32 flags; +}; + +#define to_davinci_psc_data(x) container_of(x, struct davinci_psc_data, x) +#define to_davinci_lpsc_clk(x) container_of(x, struct davinci_lpsc_clk, x) + +/** + * best_dev_name - get the "best" device name. + * @dev: the device + * + * Returns the device tree compatible name if the device has a DT node, + * otherwise return the device name. This is mainly needed because clkdev + * lookups are limited to 20 chars for dev_id and when using device tree, + * dev_name(dev) is much longer than that. + */ +static inline const char *best_dev_name(struct device *dev) +{ + const char *compatible; + + if (!of_property_read_string(dev->of_node, "compatible", &compatible)) + return compatible; + + return dev_name(dev); +} + +static void davinci_lpsc_config(struct davinci_lpsc_clk *lpsc, + enum davinci_lpsc_state next_state) +{ + u32 epcpr, pdstat, mdstat, ptstat; + + regmap_write_bits(lpsc->regmap, MDCTL(lpsc->md), MDSTAT_STATE_MASK, + next_state); + + if (lpsc->flags & LPSC_FORCE) + regmap_write_bits(lpsc->regmap, MDCTL(lpsc->md), MDCTL_FORCE, + MDCTL_FORCE); + + regmap_read(lpsc->regmap, PDSTAT(lpsc->pd), &pdstat); + if ((pdstat & PDSTAT_STATE_MASK) == 0) { + regmap_write_bits(lpsc->regmap, PDCTL(lpsc->pd), PDCTL_NEXT, + PDCTL_NEXT); + + regmap_write(lpsc->regmap, PTCMD, BIT(lpsc->pd)); + + regmap_read_poll_timeout(lpsc->regmap, EPCPR, epcpr, + epcpr & BIT(lpsc->pd), 0, 0); + + regmap_write_bits(lpsc->regmap, PDCTL(lpsc->pd), PDCTL_EPCGOOD, + PDCTL_EPCGOOD); + } else { + regmap_write(lpsc->regmap, PTCMD, BIT(lpsc->pd)); + } + + regmap_read_poll_timeout(lpsc->regmap, PTSTAT, ptstat, + !(ptstat & BIT(lpsc->pd)), 0, 0); + + regmap_read_poll_timeout(lpsc->regmap, MDSTAT(lpsc->md), mdstat, + (mdstat & MDSTAT_STATE_MASK) == next_state, + 0, 0); +} + +static int davinci_lpsc_clk_enable(struct clk_hw *hw) +{ + struct davinci_lpsc_clk *lpsc = to_davinci_lpsc_clk(hw); + + davinci_lpsc_config(lpsc, LPSC_STATE_ENABLE); + + return 0; +} + +static void davinci_lpsc_clk_disable(struct clk_hw *hw) +{ + struct davinci_lpsc_clk *lpsc = to_davinci_lpsc_clk(hw); + + davinci_lpsc_config(lpsc, LPSC_STATE_DISABLE); +} + +static int davinci_lpsc_clk_is_enabled(struct clk_hw *hw) +{ + struct davinci_lpsc_clk *lpsc = to_davinci_lpsc_clk(hw); + u32 mdstat; + + regmap_read(lpsc->regmap, MDSTAT(lpsc->md), &mdstat); + + return (mdstat & MDSTAT_MCKOUT) ? 1 : 0; +} + +static const struct clk_ops davinci_lpsc_clk_ops = { + .enable = davinci_lpsc_clk_enable, + .disable = davinci_lpsc_clk_disable, + .is_enabled = davinci_lpsc_clk_is_enabled, +}; + +static int davinci_psc_genpd_attach_dev(struct generic_pm_domain *pm_domain, + struct device *dev) +{ + struct davinci_lpsc_clk *lpsc = to_davinci_lpsc_clk(pm_domain); + struct clk *clk; + int ret; + + /* + * pm_clk_remove_clk() will call clk_put(), so we have to use clk_get() + * to get the clock instead of using lpsc->hw.clk directly. + */ + clk = clk_get_sys(best_dev_name(lpsc->dev), clk_hw_get_name(&lpsc->hw)); + if (IS_ERR(clk)) + return (PTR_ERR(clk)); + + ret = pm_clk_create(dev); + if (ret < 0) + goto fail_clk_put; + + ret = pm_clk_add_clk(dev, clk); + if (ret < 0) + goto fail_pm_clk_destroy; + + lpsc->genpd_clk = clk; + + return 0; + +fail_pm_clk_destroy: + pm_clk_destroy(dev); +fail_clk_put: + clk_put(clk); + + return ret; +} + +static void davinci_psc_genpd_detach_dev(struct generic_pm_domain *pm_domain, + struct device *dev) +{ + struct davinci_lpsc_clk *lpsc = to_davinci_lpsc_clk(pm_domain); + + pm_clk_remove_clk(dev, lpsc->genpd_clk); + pm_clk_destroy(dev); + + lpsc->genpd_clk = NULL; +} + +/** + * davinci_lpsc_clk_register - register LPSC clock + * @name: name of this clock + * @parent_name: name of clock's parent + * @regmap: PSC MMIO region + * @md: local PSC number + * @pd: power domain + * @flags: LPSC_* flags + */ +static struct davinci_lpsc_clk * +davinci_lpsc_clk_register(struct device *dev, const char *name, + const char *parent_name, struct regmap *regmap, + u32 md, u32 pd, u32 flags) +{ + struct clk_init_data init; + struct davinci_lpsc_clk *lpsc; + int ret; + bool is_on; + + lpsc = devm_kzalloc(dev, sizeof(*lpsc), GFP_KERNEL); + if (!lpsc) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.ops = &davinci_lpsc_clk_ops; + init.parent_names = (parent_name ? &parent_name : NULL); + init.num_parents = (parent_name ? 1 : 0); + init.flags = 0; + + if (flags & LPSC_ALWAYS_ENABLED) + init.flags |= CLK_IS_CRITICAL; + + if (flags & LPSC_SET_RATE_PARENT) + init.flags |= CLK_SET_RATE_PARENT; + + lpsc->dev = dev; + lpsc->regmap = regmap; + lpsc->hw.init = &init; + lpsc->md = md; + lpsc->pd = pd; + lpsc->flags = flags; + + ret = devm_clk_hw_register(dev, &lpsc->hw); + if (ret < 0) + return ERR_PTR(ret); + + /* genpd attach needs a way to look up this clock */ + ret = clk_hw_register_clkdev(&lpsc->hw, name, best_dev_name(dev)); + + lpsc->pm_domain.name = devm_kasprintf(dev, GFP_KERNEL, "%s: %s", + best_dev_name(dev), name); + lpsc->pm_domain.attach_dev = davinci_psc_genpd_attach_dev; + lpsc->pm_domain.detach_dev = davinci_psc_genpd_detach_dev; + lpsc->pm_domain.flags = GENPD_FLAG_PM_CLK; + + is_on = davinci_lpsc_clk_is_enabled(&lpsc->hw); + pm_genpd_init(&lpsc->pm_domain, NULL, is_on); + + return lpsc; +} + +static int davinci_lpsc_clk_reset(struct clk *clk, bool reset) +{ + struct clk_hw *hw = __clk_get_hw(clk); + struct davinci_lpsc_clk *lpsc = to_davinci_lpsc_clk(hw); + u32 mdctl; + + if (IS_ERR_OR_NULL(lpsc)) + return -EINVAL; + + mdctl = reset ? 0 : MDCTL_LRESET; + regmap_write_bits(lpsc->regmap, MDCTL(lpsc->md), MDCTL_LRESET, mdctl); + + return 0; +} + +/* + * REVISIT: These exported functions can be removed after a non-DT lookup is + * added to the reset controller framework and the davinci-rproc driver is + * updated to use the generic reset controller framework. + */ + +int davinci_clk_reset_assert(struct clk *clk) +{ + return davinci_lpsc_clk_reset(clk, true); +} +EXPORT_SYMBOL(davinci_clk_reset_assert); + +int davinci_clk_reset_deassert(struct clk *clk) +{ + return davinci_lpsc_clk_reset(clk, false); +} +EXPORT_SYMBOL(davinci_clk_reset_deassert); + +static int davinci_psc_reset_assert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct davinci_psc_data *psc = to_davinci_psc_data(rcdev); + struct clk *clk = psc->clk_data.clks[id]; + + return davinci_lpsc_clk_reset(clk, true); +} + +static int davinci_psc_reset_deassert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct davinci_psc_data *psc = to_davinci_psc_data(rcdev); + struct clk *clk = psc->clk_data.clks[id]; + + return davinci_lpsc_clk_reset(clk, false); +} + +static const struct reset_control_ops davinci_psc_reset_ops = { + .assert = davinci_psc_reset_assert, + .deassert = davinci_psc_reset_deassert, +}; + +static int davinci_psc_reset_of_xlate(struct reset_controller_dev *rcdev, + const struct of_phandle_args *reset_spec) +{ + struct of_phandle_args clkspec = *reset_spec; /* discard const qualifier */ + struct clk *clk; + struct clk_hw *hw; + struct davinci_lpsc_clk *lpsc; + + /* the clock node is the same as the reset node */ + clk = of_clk_get_from_provider(&clkspec); + if (IS_ERR(clk)) + return PTR_ERR(clk); + + hw = __clk_get_hw(clk); + lpsc = to_davinci_lpsc_clk(hw); + clk_put(clk); + + /* not all modules support local reset */ + if (!(lpsc->flags & LPSC_LOCAL_RESET)) + return -EINVAL; + + return lpsc->md; +} + +static const struct regmap_config davinci_psc_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, +}; + +static struct davinci_psc_data * +__davinci_psc_register_clocks(struct device *dev, + const struct davinci_lpsc_clk_info *info, + int num_clks, + void __iomem *base) +{ + struct davinci_psc_data *psc; + struct clk **clks; + struct generic_pm_domain **pm_domains; + struct regmap *regmap; + int i, ret; + + psc = devm_kzalloc(dev, sizeof(*psc), GFP_KERNEL); + if (!psc) + return ERR_PTR(-ENOMEM); + + clks = devm_kmalloc_array(dev, num_clks, sizeof(*clks), GFP_KERNEL); + if (!clks) + return ERR_PTR(-ENOMEM); + + psc->clk_data.clks = clks; + psc->clk_data.clk_num = num_clks; + + /* + * init array with error so that of_clk_src_onecell_get() doesn't + * return NULL for gaps in the sparse array + */ + for (i = 0; i < num_clks; i++) + clks[i] = ERR_PTR(-ENOENT); + + pm_domains = devm_kcalloc(dev, num_clks, sizeof(*pm_domains), GFP_KERNEL); + if (!pm_domains) + return ERR_PTR(-ENOMEM); + + psc->pm_data.domains = pm_domains; + psc->pm_data.num_domains = num_clks; + + regmap = devm_regmap_init_mmio(dev, base, &davinci_psc_regmap_config); + if (IS_ERR(regmap)) + return ERR_CAST(regmap); + + for (; info->name; info++) { + struct davinci_lpsc_clk *lpsc; + + lpsc = davinci_lpsc_clk_register(dev, info->name, info->parent, + regmap, info->md, info->pd, + info->flags); + if (IS_ERR(lpsc)) { + dev_warn(dev, "Failed to register %s (%ld)\n", + info->name, PTR_ERR(lpsc)); + continue; + } + + clks[info->md] = lpsc->hw.clk; + pm_domains[info->md] = &lpsc->pm_domain; + } + + psc->rcdev.ops = &davinci_psc_reset_ops; + psc->rcdev.owner = THIS_MODULE; + psc->rcdev.of_node = dev->of_node; + psc->rcdev.of_reset_n_cells = 1; + psc->rcdev.of_xlate = davinci_psc_reset_of_xlate; + psc->rcdev.nr_resets = num_clks; + + ret = devm_reset_controller_register(dev, &psc->rcdev); + if (ret < 0) + dev_warn(dev, "Failed to register reset controller (%d)\n", ret); + + return psc; +} + +int davinci_psc_register_clocks(struct device *dev, + const struct davinci_lpsc_clk_info *info, + u8 num_clks, + void __iomem *base) +{ + struct davinci_psc_data *psc; + + psc = __davinci_psc_register_clocks(dev, info, num_clks, base); + if (IS_ERR(psc)) + return PTR_ERR(psc); + + for (; info->name; info++) { + const struct davinci_lpsc_clkdev_info *cdevs = info->cdevs; + struct clk *clk = psc->clk_data.clks[info->md]; + + if (!cdevs || IS_ERR_OR_NULL(clk)) + continue; + + for (; cdevs->con_id || cdevs->dev_id; cdevs++) + clk_register_clkdev(clk, cdevs->con_id, cdevs->dev_id); + } + + return 0; +} + +int of_davinci_psc_clk_init(struct device *dev, + const struct davinci_lpsc_clk_info *info, + u8 num_clks, + void __iomem *base) +{ + struct device_node *node = dev->of_node; + struct davinci_psc_data *psc; + + psc = __davinci_psc_register_clocks(dev, info, num_clks, base); + if (IS_ERR(psc)) + return PTR_ERR(psc); + + of_genpd_add_provider_onecell(node, &psc->pm_data); + + of_clk_add_provider(node, of_clk_src_onecell_get, &psc->clk_data); + + return 0; +} + +static const struct of_device_id davinci_psc_of_match[] = { + { } +}; + +static const struct platform_device_id davinci_psc_id_table[] = { + { } +}; + +static int davinci_psc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + const struct of_device_id *of_id; + const struct davinci_psc_init_data *init_data = NULL; + struct resource *res; + void __iomem *base; + int ret; + + of_id = of_match_device(davinci_psc_of_match, dev); + if (of_id) + init_data = of_id->data; + else if (pdev->id_entry) + init_data = (void *)pdev->id_entry->driver_data; + + if (!init_data) { + dev_err(dev, "unable to find driver init data\n"); + return -EINVAL; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(dev, res); + if (IS_ERR(base)) { + dev_err(dev, "ioremap failed\n"); + return PTR_ERR(base); + } + + ret = devm_clk_bulk_get(dev, init_data->num_parent_clks, + init_data->parent_clks); + if (ret < 0) + return ret; + + return init_data->psc_init(dev, base); +} + +static struct platform_driver davinci_psc_driver = { + .probe = davinci_psc_probe, + .driver = { + .name = "davinci-psc-clk", + .of_match_table = davinci_psc_of_match, + }, + .id_table = davinci_psc_id_table, +}; + +static int __init davinci_psc_driver_init(void) +{ + return platform_driver_register(&davinci_psc_driver); +} + +/* has to be postcore_initcall because davinci_gpio depend on PSC clocks */ +postcore_initcall(davinci_psc_driver_init); diff --git a/drivers/clk/davinci/psc.h b/drivers/clk/davinci/psc.h new file mode 100644 index 000000000000..4240134fdb04 --- /dev/null +++ b/drivers/clk/davinci/psc.h @@ -0,0 +1,97 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Clock driver for TI Davinci PSC controllers + * + * Copyright (C) 2018 David Lechner + */ + +#ifndef __CLK_DAVINCI_PSC_H__ +#define __CLK_DAVINCI_PSC_H__ + +#include +#include + +/* PSC quirk flags */ +#define LPSC_ALWAYS_ENABLED BIT(0) /* never disable this clock */ +#define LPSC_SET_RATE_PARENT BIT(1) /* propagate set_rate to parent clock */ +#define LPSC_FORCE BIT(2) /* requires MDCTL FORCE bit */ +#define LPSC_LOCAL_RESET BIT(3) /* acts as reset provider */ + +struct davinci_lpsc_clkdev_info { + const char *con_id; + const char *dev_id; +}; + +#define LPSC_CLKDEV(c, d) { \ + .con_id = (c), \ + .dev_id = (d) \ +} + +#define LPSC_CLKDEV1(n, c, d) \ +static const struct davinci_lpsc_clkdev_info n[] __initconst = { \ + LPSC_CLKDEV((c), (d)), \ + { } \ +} + +#define LPSC_CLKDEV2(n, c1, d1, c2, d2) \ +static const struct davinci_lpsc_clkdev_info n[] __initconst = { \ + LPSC_CLKDEV((c1), (d1)), \ + LPSC_CLKDEV((c2), (d2)), \ + { } \ +} + +#define LPSC_CLKDEV3(n, c1, d1, c2, d2, c3, d3) \ +static const struct davinci_lpsc_clkdev_info n[] __initconst = { \ + LPSC_CLKDEV((c1), (d1)), \ + LPSC_CLKDEV((c2), (d2)), \ + LPSC_CLKDEV((c3), (d3)), \ + { } \ +} + +/** + * davinci_lpsc_clk_info - LPSC module-specific clock information + * @name: the clock name + * @parent: the parent clock name + * @cdevs: optional array of clkdev lookup table info + * @md: the local module domain (LPSC id) + * @pd: the power domain id + * @flags: bitmask of LPSC_* flags + */ +struct davinci_lpsc_clk_info { + const char *name; + const char *parent; + const struct davinci_lpsc_clkdev_info *cdevs; + u32 md; + u32 pd; + unsigned long flags; +}; + +#define LPSC(m, d, n, p, c, f) \ +{ \ + .name = #n, \ + .parent = #p, \ + .cdevs = (c), \ + .md = (m), \ + .pd = (d), \ + .flags = (f), \ +} + +int davinci_psc_register_clocks(struct device *dev, + const struct davinci_lpsc_clk_info *info, + u8 num_clks, + void __iomem *base); + +int of_davinci_psc_clk_init(struct device *dev, + const struct davinci_lpsc_clk_info *info, + u8 num_clks, + void __iomem *base); + +/* Device-specific data */ + +struct davinci_psc_init_data { + struct clk_bulk_data *parent_clks; + int num_parent_clks; + int (*psc_init)(struct device *dev, void __iomem *base); +}; + +#endif /* __CLK_DAVINCI_PSC_H__ */ -- cgit From c2952e271b94f805e8cb73d18e50394689cae508 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Thu, 15 Mar 2018 21:52:27 -0500 Subject: clk: davinci: Add platform information for TI DA830 PSC This adds platform-specific declarations for the PSC clocks on TI DA830/ OMAP-L137/AM17XX SoCs. Signed-off-by: David Lechner Signed-off-by: Stephen Boyd --- drivers/clk/davinci/Makefile | 1 + drivers/clk/davinci/psc-da830.c | 116 ++++++++++++++++++++++++++++++++++++++++ drivers/clk/davinci/psc.c | 2 + drivers/clk/davinci/psc.h | 3 ++ 4 files changed, 122 insertions(+) create mode 100644 drivers/clk/davinci/psc-da830.c diff --git a/drivers/clk/davinci/Makefile b/drivers/clk/davinci/Makefile index cd1bf2cefc05..fb14c8c9216d 100644 --- a/drivers/clk/davinci/Makefile +++ b/drivers/clk/davinci/Makefile @@ -10,4 +10,5 @@ obj-$(CONFIG_ARCH_DAVINCI_DM644x) += pll-dm644x.o obj-$(CONFIG_ARCH_DAVINCI_DM646x) += pll-dm646x.o obj-y += psc.o +obj-$(CONFIG_ARCH_DAVINCI_DA830) += psc-da830.o endif diff --git a/drivers/clk/davinci/psc-da830.c b/drivers/clk/davinci/psc-da830.c new file mode 100644 index 000000000000..f61abf5632ff --- /dev/null +++ b/drivers/clk/davinci/psc-da830.c @@ -0,0 +1,116 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * PSC clock descriptions for TI DA830/OMAP-L137/AM17XX + * + * Copyright (C) 2018 David Lechner + */ + +#include +#include +#include +#include +#include +#include + +#include "psc.h" + +LPSC_CLKDEV1(spi0_clkdev, NULL, "spi_davinci.0"); +LPSC_CLKDEV1(mmcsd_clkdev, NULL, "da830-mmc.0"); +LPSC_CLKDEV1(uart0_clkdev, NULL, "serial8250.0"); + +static const struct davinci_lpsc_clk_info da830_psc0_info[] = { + LPSC(0, 0, tpcc, pll0_sysclk2, NULL, LPSC_ALWAYS_ENABLED), + LPSC(1, 0, tptc0, pll0_sysclk2, NULL, LPSC_ALWAYS_ENABLED), + LPSC(2, 0, tptc1, pll0_sysclk2, NULL, LPSC_ALWAYS_ENABLED), + LPSC(3, 0, aemif, pll0_sysclk3, NULL, LPSC_ALWAYS_ENABLED), + LPSC(4, 0, spi0, pll0_sysclk2, spi0_clkdev, 0), + LPSC(5, 0, mmcsd, pll0_sysclk2, mmcsd_clkdev, 0), + LPSC(6, 0, aintc, pll0_sysclk4, NULL, LPSC_ALWAYS_ENABLED), + LPSC(7, 0, arm_rom, pll0_sysclk2, NULL, LPSC_ALWAYS_ENABLED), + LPSC(8, 0, secu_mgr, pll0_sysclk4, NULL, LPSC_ALWAYS_ENABLED), + LPSC(9, 0, uart0, pll0_sysclk2, uart0_clkdev, 0), + LPSC(10, 0, scr0_ss, pll0_sysclk2, NULL, LPSC_ALWAYS_ENABLED), + LPSC(11, 0, scr1_ss, pll0_sysclk2, NULL, LPSC_ALWAYS_ENABLED), + LPSC(12, 0, scr2_ss, pll0_sysclk2, NULL, LPSC_ALWAYS_ENABLED), + LPSC(13, 0, pruss, pll0_sysclk2, NULL, LPSC_ALWAYS_ENABLED), + LPSC(14, 0, arm, pll0_sysclk6, NULL, LPSC_ALWAYS_ENABLED), + { } +}; + +static int da830_psc0_init(struct device *dev, void __iomem *base) +{ + return davinci_psc_register_clocks(dev, da830_psc0_info, 16, base); +} + +static struct clk_bulk_data da830_psc0_parent_clks[] = { + { .id = "pll0_sysclk2" }, + { .id = "pll0_sysclk3" }, + { .id = "pll0_sysclk4" }, + { .id = "pll0_sysclk6" }, +}; + +const struct davinci_psc_init_data da830_psc0_init_data = { + .parent_clks = da830_psc0_parent_clks, + .num_parent_clks = ARRAY_SIZE(da830_psc0_parent_clks), + .psc_init = &da830_psc0_init, +}; + +LPSC_CLKDEV2(usb0_clkdev, NULL, "musb-da8xx", + NULL, "cppi41-dmaengine"); +LPSC_CLKDEV1(usb1_clkdev, NULL, "ohci-da8xx"); +/* REVISIT: gpio-davinci.c should be modified to drop con_id */ +LPSC_CLKDEV1(gpio_clkdev, "gpio", NULL); +LPSC_CLKDEV2(emac_clkdev, NULL, "davinci_emac.1", + "fck", "davinci_mdio.0"); +LPSC_CLKDEV1(mcasp0_clkdev, NULL, "davinci-mcasp.0"); +LPSC_CLKDEV1(mcasp1_clkdev, NULL, "davinci-mcasp.1"); +LPSC_CLKDEV1(mcasp2_clkdev, NULL, "davinci-mcasp.2"); +LPSC_CLKDEV1(spi1_clkdev, NULL, "spi_davinci.1"); +LPSC_CLKDEV1(i2c1_clkdev, NULL, "i2c_davinci.2"); +LPSC_CLKDEV1(uart1_clkdev, NULL, "serial8250.1"); +LPSC_CLKDEV1(uart2_clkdev, NULL, "serial8250.2"); +LPSC_CLKDEV1(lcdc_clkdev, "fck", "da8xx_lcdc.0"); +LPSC_CLKDEV2(pwm_clkdev, "fck", "ehrpwm.0", + "fck", "ehrpwm.1"); +LPSC_CLKDEV3(ecap_clkdev, "fck", "ecap.0", + "fck", "ecap.1", + "fck", "ecap.2"); +LPSC_CLKDEV2(eqep_clkdev, NULL, "eqep.0", + NULL, "eqep.1"); + +static const struct davinci_lpsc_clk_info da830_psc1_info[] = { + LPSC(1, 0, usb0, pll0_sysclk2, usb0_clkdev, 0), + LPSC(2, 0, usb1, pll0_sysclk4, usb1_clkdev, 0), + LPSC(3, 0, gpio, pll0_sysclk4, gpio_clkdev, 0), + LPSC(5, 0, emac, pll0_sysclk4, emac_clkdev, 0), + LPSC(6, 0, emif3, pll0_sysclk5, NULL, LPSC_ALWAYS_ENABLED), + LPSC(7, 0, mcasp0, pll0_sysclk2, mcasp0_clkdev, 0), + LPSC(8, 0, mcasp1, pll0_sysclk2, mcasp1_clkdev, 0), + LPSC(9, 0, mcasp2, pll0_sysclk2, mcasp2_clkdev, 0), + LPSC(10, 0, spi1, pll0_sysclk2, spi1_clkdev, 0), + LPSC(11, 0, i2c1, pll0_sysclk4, i2c1_clkdev, 0), + LPSC(12, 0, uart1, pll0_sysclk2, uart1_clkdev, 0), + LPSC(13, 0, uart2, pll0_sysclk2, uart2_clkdev, 0), + LPSC(16, 0, lcdc, pll0_sysclk2, lcdc_clkdev, 0), + LPSC(17, 0, pwm, pll0_sysclk2, pwm_clkdev, 0), + LPSC(20, 0, ecap, pll0_sysclk2, ecap_clkdev, 0), + LPSC(21, 0, eqep, pll0_sysclk2, eqep_clkdev, 0), + { } +}; + +static int da830_psc1_init(struct device *dev, void __iomem *base) +{ + return davinci_psc_register_clocks(dev, da830_psc1_info, 32, base); +} + +static struct clk_bulk_data da830_psc1_parent_clks[] = { + { .id = "pll0_sysclk2" }, + { .id = "pll0_sysclk4" }, + { .id = "pll0_sysclk5" }, +}; + +const struct davinci_psc_init_data da830_psc1_init_data = { + .parent_clks = da830_psc1_parent_clks, + .num_parent_clks = ARRAY_SIZE(da830_psc1_parent_clks), + .psc_init = &da830_psc1_init, +}; diff --git a/drivers/clk/davinci/psc.c b/drivers/clk/davinci/psc.c index 5613607f7757..d4cff877aa8a 100644 --- a/drivers/clk/davinci/psc.c +++ b/drivers/clk/davinci/psc.c @@ -486,6 +486,8 @@ static const struct of_device_id davinci_psc_of_match[] = { }; static const struct platform_device_id davinci_psc_id_table[] = { + { .name = "da830-psc0", .driver_data = (kernel_ulong_t)&da830_psc0_init_data }, + { .name = "da830-psc1", .driver_data = (kernel_ulong_t)&da830_psc1_init_data }, { } }; diff --git a/drivers/clk/davinci/psc.h b/drivers/clk/davinci/psc.h index 4240134fdb04..852e9aaa62f6 100644 --- a/drivers/clk/davinci/psc.h +++ b/drivers/clk/davinci/psc.h @@ -94,4 +94,7 @@ struct davinci_psc_init_data { int (*psc_init)(struct device *dev, void __iomem *base); }; +extern const struct davinci_psc_init_data da830_psc0_init_data; +extern const struct davinci_psc_init_data da830_psc1_init_data; + #endif /* __CLK_DAVINCI_PSC_H__ */ -- cgit From a47d6040629f26e0b6f8a85b4dd2dbb91de405af Mon Sep 17 00:00:00 2001 From: David Lechner Date: Thu, 15 Mar 2018 21:52:28 -0500 Subject: clk: davinci: Add platform information for TI DA850 PSC This adds platform-specific declarations for the PSC clocks on TI DA850/ OMAP-L138/AM18XX SoCs. Signed-off-by: David Lechner Signed-off-by: Stephen Boyd --- drivers/clk/davinci/Makefile | 1 + drivers/clk/davinci/psc-da850.c | 149 ++++++++++++++++++++++++++++++++++++++++ drivers/clk/davinci/psc.c | 4 ++ drivers/clk/davinci/psc.h | 4 ++ 4 files changed, 158 insertions(+) create mode 100644 drivers/clk/davinci/psc-da850.c diff --git a/drivers/clk/davinci/Makefile b/drivers/clk/davinci/Makefile index fb14c8c9216d..aef0390f710e 100644 --- a/drivers/clk/davinci/Makefile +++ b/drivers/clk/davinci/Makefile @@ -11,4 +11,5 @@ obj-$(CONFIG_ARCH_DAVINCI_DM646x) += pll-dm646x.o obj-y += psc.o obj-$(CONFIG_ARCH_DAVINCI_DA830) += psc-da830.o +obj-$(CONFIG_ARCH_DAVINCI_DA850) += psc-da850.o endif diff --git a/drivers/clk/davinci/psc-da850.c b/drivers/clk/davinci/psc-da850.c new file mode 100644 index 000000000000..ccc7eb17bf3a --- /dev/null +++ b/drivers/clk/davinci/psc-da850.c @@ -0,0 +1,149 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * PSC clock descriptions for TI DA850/OMAP-L138/AM18XX + * + * Copyright (C) 2018 David Lechner + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "psc.h" + +LPSC_CLKDEV2(emifa_clkdev, NULL, "ti-aemif", + "aemif", "davinci_nand.0"); +LPSC_CLKDEV1(spi0_clkdev, NULL, "spi_davinci.0"); +LPSC_CLKDEV1(mmcsd0_clkdev, NULL, "da830-mmc.0"); +LPSC_CLKDEV1(uart0_clkdev, NULL, "serial8250.0"); +/* REVISIT: used dev_id instead of con_id */ +LPSC_CLKDEV1(arm_clkdev, "arm", NULL); +LPSC_CLKDEV1(dsp_clkdev, NULL, "davinci-rproc.0"); + +static const struct davinci_lpsc_clk_info da850_psc0_info[] = { + LPSC(0, 0, tpcc0, pll0_sysclk2, NULL, LPSC_ALWAYS_ENABLED), + LPSC(1, 0, tptc0, pll0_sysclk2, NULL, LPSC_ALWAYS_ENABLED), + LPSC(2, 0, tptc1, pll0_sysclk2, NULL, LPSC_ALWAYS_ENABLED), + LPSC(3, 0, emifa, async1, emifa_clkdev, 0), + LPSC(4, 0, spi0, pll0_sysclk2, spi0_clkdev, 0), + LPSC(5, 0, mmcsd0, pll0_sysclk2, mmcsd0_clkdev, 0), + LPSC(6, 0, aintc, pll0_sysclk4, NULL, LPSC_ALWAYS_ENABLED), + LPSC(7, 0, arm_rom, pll0_sysclk2, NULL, LPSC_ALWAYS_ENABLED), + LPSC(9, 0, uart0, pll0_sysclk2, uart0_clkdev, 0), + LPSC(13, 0, pruss, pll0_sysclk2, NULL, 0), + LPSC(14, 0, arm, pll0_sysclk6, arm_clkdev, LPSC_ALWAYS_ENABLED | LPSC_SET_RATE_PARENT), + LPSC(15, 1, dsp, pll0_sysclk1, dsp_clkdev, LPSC_FORCE | LPSC_LOCAL_RESET), + { } +}; + +LPSC_CLKDEV3(usb0_clkdev, "fck", "da830-usb-phy-clks", + NULL, "musb-da8xx", + NULL, "cppi41-dmaengine"); +LPSC_CLKDEV1(usb1_clkdev, NULL, "ohci-da8xx"); +/* REVISIT: gpio-davinci.c should be modified to drop con_id */ +LPSC_CLKDEV1(gpio_clkdev, "gpio", NULL); +LPSC_CLKDEV2(emac_clkdev, NULL, "davinci_emac.1", + "fck", "davinci_mdio.0"); +LPSC_CLKDEV1(mcasp0_clkdev, NULL, "davinci-mcasp.0"); +LPSC_CLKDEV1(sata_clkdev, "fck", "ahci_da850"); +LPSC_CLKDEV1(vpif_clkdev, NULL, "vpif"); +LPSC_CLKDEV1(spi1_clkdev, NULL, "spi_davinci.1"); +LPSC_CLKDEV1(i2c1_clkdev, NULL, "i2c_davinci.2"); +LPSC_CLKDEV1(uart1_clkdev, NULL, "serial8250.1"); +LPSC_CLKDEV1(uart2_clkdev, NULL, "serial8250.2"); +LPSC_CLKDEV1(mcbsp0_clkdev, NULL, "davinci-mcbsp.0"); +LPSC_CLKDEV1(mcbsp1_clkdev, NULL, "davinci-mcbsp.1"); +LPSC_CLKDEV1(lcdc_clkdev, "fck", "da8xx_lcdc.0"); +LPSC_CLKDEV3(ehrpwm_clkdev, "fck", "ehrpwm.0", + "fck", "ehrpwm.1", + NULL, "da830-tbclksync"); +LPSC_CLKDEV1(mmcsd1_clkdev, NULL, "da830-mmc.1"); +LPSC_CLKDEV3(ecap_clkdev, "fck", "ecap.0", + "fck", "ecap.1", + "fck", "ecap.2"); + +static int da850_psc0_init(struct device *dev, void __iomem *base) +{ + return davinci_psc_register_clocks(dev, da850_psc0_info, 16, base); +} + +static int of_da850_psc0_init(struct device *dev, void __iomem *base) +{ + return of_davinci_psc_clk_init(dev, da850_psc0_info, 16, base); +} + +static struct clk_bulk_data da850_psc0_parent_clks[] = { + { .id = "pll0_sysclk1" }, + { .id = "pll0_sysclk2" }, + { .id = "pll0_sysclk4" }, + { .id = "pll0_sysclk6" }, + { .id = "async1" }, +}; + +const struct davinci_psc_init_data da850_psc0_init_data = { + .parent_clks = da850_psc0_parent_clks, + .num_parent_clks = ARRAY_SIZE(da850_psc0_parent_clks), + .psc_init = &da850_psc0_init, +}; + +const struct davinci_psc_init_data of_da850_psc0_init_data = { + .parent_clks = da850_psc0_parent_clks, + .num_parent_clks = ARRAY_SIZE(da850_psc0_parent_clks), + .psc_init = &of_da850_psc0_init, +}; + +static const struct davinci_lpsc_clk_info da850_psc1_info[] = { + LPSC(0, 0, tpcc1, pll0_sysclk2, NULL, LPSC_ALWAYS_ENABLED), + LPSC(1, 0, usb0, pll0_sysclk2, usb0_clkdev, 0), + LPSC(2, 0, usb1, pll0_sysclk4, usb1_clkdev, 0), + LPSC(3, 0, gpio, pll0_sysclk4, gpio_clkdev, 0), + LPSC(5, 0, emac, pll0_sysclk4, emac_clkdev, 0), + LPSC(6, 0, ddr, pll0_sysclk2, NULL, LPSC_ALWAYS_ENABLED), + LPSC(7, 0, mcasp0, async3, mcasp0_clkdev, 0), + LPSC(8, 0, sata, pll0_sysclk2, sata_clkdev, LPSC_FORCE), + LPSC(9, 0, vpif, pll0_sysclk2, vpif_clkdev, 0), + LPSC(10, 0, spi1, async3, spi1_clkdev, 0), + LPSC(11, 0, i2c1, pll0_sysclk4, i2c1_clkdev, 0), + LPSC(12, 0, uart1, async3, uart1_clkdev, 0), + LPSC(13, 0, uart2, async3, uart2_clkdev, 0), + LPSC(14, 0, mcbsp0, async3, mcbsp0_clkdev, 0), + LPSC(15, 0, mcbsp1, async3, mcbsp1_clkdev, 0), + LPSC(16, 0, lcdc, pll0_sysclk2, lcdc_clkdev, 0), + LPSC(17, 0, ehrpwm, async3, ehrpwm_clkdev, 0), + LPSC(18, 0, mmcsd1, pll0_sysclk2, mmcsd1_clkdev, 0), + LPSC(20, 0, ecap, async3, ecap_clkdev, 0), + LPSC(21, 0, tptc2, pll0_sysclk2, NULL, LPSC_ALWAYS_ENABLED), + { } +}; + +static int da850_psc1_init(struct device *dev, void __iomem *base) +{ + return davinci_psc_register_clocks(dev, da850_psc1_info, 32, base); +} + +static int of_da850_psc1_init(struct device *dev, void __iomem *base) +{ + return of_davinci_psc_clk_init(dev, da850_psc1_info, 32, base); +} + +static struct clk_bulk_data da850_psc1_parent_clks[] = { + { .id = "pll0_sysclk2" }, + { .id = "pll0_sysclk4" }, + { .id = "async3" }, +}; + +const struct davinci_psc_init_data da850_psc1_init_data = { + .parent_clks = da850_psc1_parent_clks, + .num_parent_clks = ARRAY_SIZE(da850_psc1_parent_clks), + .psc_init = &da850_psc1_init, +}; + +const struct davinci_psc_init_data of_da850_psc1_init_data = { + .parent_clks = da850_psc1_parent_clks, + .num_parent_clks = ARRAY_SIZE(da850_psc1_parent_clks), + .psc_init = &of_da850_psc1_init, +}; diff --git a/drivers/clk/davinci/psc.c b/drivers/clk/davinci/psc.c index d4cff877aa8a..fa3953685384 100644 --- a/drivers/clk/davinci/psc.c +++ b/drivers/clk/davinci/psc.c @@ -482,12 +482,16 @@ int of_davinci_psc_clk_init(struct device *dev, } static const struct of_device_id davinci_psc_of_match[] = { + { .compatible = "ti,da850-psc0", .data = &of_da850_psc0_init_data }, + { .compatible = "ti,da850-psc1", .data = &of_da850_psc1_init_data }, { } }; static const struct platform_device_id davinci_psc_id_table[] = { { .name = "da830-psc0", .driver_data = (kernel_ulong_t)&da830_psc0_init_data }, { .name = "da830-psc1", .driver_data = (kernel_ulong_t)&da830_psc1_init_data }, + { .name = "da850-psc0", .driver_data = (kernel_ulong_t)&da850_psc0_init_data }, + { .name = "da850-psc1", .driver_data = (kernel_ulong_t)&da850_psc1_init_data }, { } }; diff --git a/drivers/clk/davinci/psc.h b/drivers/clk/davinci/psc.h index 852e9aaa62f6..476bd74c7f50 100644 --- a/drivers/clk/davinci/psc.h +++ b/drivers/clk/davinci/psc.h @@ -96,5 +96,9 @@ struct davinci_psc_init_data { extern const struct davinci_psc_init_data da830_psc0_init_data; extern const struct davinci_psc_init_data da830_psc1_init_data; +extern const struct davinci_psc_init_data da850_psc0_init_data; +extern const struct davinci_psc_init_data da850_psc1_init_data; +extern const struct davinci_psc_init_data of_da850_psc0_init_data; +extern const struct davinci_psc_init_data of_da850_psc1_init_data; #endif /* __CLK_DAVINCI_PSC_H__ */ -- cgit From b99bfca56ecb186c71ad2fe0377c99357f4e9bf5 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Thu, 15 Mar 2018 21:52:29 -0500 Subject: clk: davinci: Add platform information for TI DM355 PSC This adds platform-specific declarations for the PSC clocks on TI DM355 based systems. Signed-off-by: David Lechner Signed-off-by: Stephen Boyd --- drivers/clk/davinci/Makefile | 1 + drivers/clk/davinci/psc-dm355.c | 88 +++++++++++++++++++++++++++++++++++++++++ drivers/clk/davinci/psc.c | 1 + drivers/clk/davinci/psc.h | 1 + 4 files changed, 91 insertions(+) create mode 100644 drivers/clk/davinci/psc-dm355.c diff --git a/drivers/clk/davinci/Makefile b/drivers/clk/davinci/Makefile index aef0390f710e..e0da5c3859e2 100644 --- a/drivers/clk/davinci/Makefile +++ b/drivers/clk/davinci/Makefile @@ -12,4 +12,5 @@ obj-$(CONFIG_ARCH_DAVINCI_DM646x) += pll-dm646x.o obj-y += psc.o obj-$(CONFIG_ARCH_DAVINCI_DA830) += psc-da830.o obj-$(CONFIG_ARCH_DAVINCI_DA850) += psc-da850.o +obj-$(CONFIG_ARCH_DAVINCI_DM355) += psc-dm355.o endif diff --git a/drivers/clk/davinci/psc-dm355.c b/drivers/clk/davinci/psc-dm355.c new file mode 100644 index 000000000000..6995ecea2677 --- /dev/null +++ b/drivers/clk/davinci/psc-dm355.c @@ -0,0 +1,88 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * PSC clock descriptions for TI DaVinci DM355 + * + * Copyright (C) 2018 David Lechner + */ + +#include +#include +#include +#include +#include +#include + +#include "psc.h" + +LPSC_CLKDEV1(vpss_master_clkdev, "master", "vpss"); +LPSC_CLKDEV1(vpss_slave_clkdev, "slave", "vpss"); +LPSC_CLKDEV1(spi1_clkdev, NULL, "spi_davinci.1"); +LPSC_CLKDEV1(mmcsd1_clkdev, NULL, "dm6441-mmc.1"); +LPSC_CLKDEV1(mcbsp1_clkdev, NULL, "davinci-mcbsp.1"); +LPSC_CLKDEV1(usb_clkdev, "usb", NULL); +LPSC_CLKDEV1(spi2_clkdev, NULL, "spi_davinci.2"); +LPSC_CLKDEV1(aemif_clkdev, "aemif", NULL); +LPSC_CLKDEV1(mmcsd0_clkdev, NULL, "dm6441-mmc.0"); +LPSC_CLKDEV1(mcbsp0_clkdev, NULL, "davinci-mcbsp.0"); +LPSC_CLKDEV1(i2c_clkdev, NULL, "i2c_davinci.1"); +LPSC_CLKDEV1(uart0_clkdev, NULL, "serial8250.0"); +LPSC_CLKDEV1(uart1_clkdev, NULL, "serial8250.1"); +LPSC_CLKDEV1(uart2_clkdev, NULL, "serial8250.2"); +LPSC_CLKDEV1(spi0_clkdev, NULL, "spi_davinci.0"); +/* REVISIT: gpio-davinci.c should be modified to drop con_id */ +LPSC_CLKDEV1(gpio_clkdev, "gpio", NULL); +LPSC_CLKDEV1(timer0_clkdev, "timer0", NULL); +LPSC_CLKDEV1(timer2_clkdev, NULL, "davinci-wdt"); +LPSC_CLKDEV1(vpss_dac_clkdev, "vpss_dac", NULL); + +static const struct davinci_lpsc_clk_info dm355_psc_info[] = { + LPSC(0, 0, vpss_master, pll1_sysclk4, vpss_master_clkdev, 0), + LPSC(1, 0, vpss_slave, pll1_sysclk4, vpss_slave_clkdev, 0), + LPSC(5, 0, timer3, pll1_auxclk, NULL, 0), + LPSC(6, 0, spi1, pll1_sysclk2, spi1_clkdev, 0), + LPSC(7, 0, mmcsd1, pll1_sysclk2, mmcsd1_clkdev, 0), + LPSC(8, 0, asp1, pll1_sysclk2, NULL, 0), + LPSC(9, 0, usb, pll1_sysclk2, usb_clkdev, 0), + LPSC(10, 0, pwm3, pll1_auxclk, NULL, 0), + LPSC(11, 0, spi2, pll1_sysclk2, spi2_clkdev, 0), + LPSC(12, 0, rto, pll1_auxclk, NULL, 0), + LPSC(14, 0, aemif, pll1_sysclk2, aemif_clkdev, 0), + LPSC(15, 0, mmcsd0, pll1_sysclk2, mmcsd0_clkdev, 0), + LPSC(17, 0, asp0, pll1_sysclk2, NULL, 0), + LPSC(18, 0, i2c, pll1_auxclk, i2c_clkdev, 0), + LPSC(19, 0, uart0, pll1_auxclk, uart0_clkdev, 0), + LPSC(20, 0, uart1, pll1_auxclk, uart1_clkdev, 0), + LPSC(21, 0, uart2, pll1_sysclk2, uart2_clkdev, 0), + LPSC(22, 0, spi0, pll1_sysclk2, spi0_clkdev, 0), + LPSC(23, 0, pwm0, pll1_auxclk, NULL, 0), + LPSC(24, 0, pwm1, pll1_auxclk, NULL, 0), + LPSC(25, 0, pwm2, pll1_auxclk, NULL, 0), + LPSC(26, 0, gpio, pll1_sysclk2, gpio_clkdev, 0), + LPSC(27, 0, timer0, pll1_auxclk, timer0_clkdev, LPSC_ALWAYS_ENABLED), + LPSC(28, 0, timer1, pll1_auxclk, NULL, 0), + /* REVISIT: why can't this be disabled? */ + LPSC(29, 0, timer2, pll1_auxclk, timer2_clkdev, LPSC_ALWAYS_ENABLED), + LPSC(31, 0, arm, pll1_sysclk1, NULL, LPSC_ALWAYS_ENABLED), + LPSC(40, 0, mjcp, pll1_sysclk1, NULL, 0), + LPSC(41, 0, vpss_dac, pll1_sysclk3, vpss_dac_clkdev, 0), + { } +}; + +static int dm355_psc_init(struct device *dev, void __iomem *base) +{ + return davinci_psc_register_clocks(dev, dm355_psc_info, 42, base); +} + +static struct clk_bulk_data dm355_psc_parent_clks[] = { + { .id = "pll1_sysclk1" }, + { .id = "pll1_sysclk2" }, + { .id = "pll1_sysclk3" }, + { .id = "pll1_sysclk4" }, + { .id = "pll1_auxclk" }, +}; + +const struct davinci_psc_init_data dm355_psc_init_data = { + .parent_clks = dm355_psc_parent_clks, + .num_parent_clks = ARRAY_SIZE(dm355_psc_parent_clks), + .psc_init = &dm355_psc_init, +}; diff --git a/drivers/clk/davinci/psc.c b/drivers/clk/davinci/psc.c index fa3953685384..0825b62c1f3d 100644 --- a/drivers/clk/davinci/psc.c +++ b/drivers/clk/davinci/psc.c @@ -492,6 +492,7 @@ static const struct platform_device_id davinci_psc_id_table[] = { { .name = "da830-psc1", .driver_data = (kernel_ulong_t)&da830_psc1_init_data }, { .name = "da850-psc0", .driver_data = (kernel_ulong_t)&da850_psc0_init_data }, { .name = "da850-psc1", .driver_data = (kernel_ulong_t)&da850_psc1_init_data }, + { .name = "dm355-psc", .driver_data = (kernel_ulong_t)&dm355_psc_init_data }, { } }; diff --git a/drivers/clk/davinci/psc.h b/drivers/clk/davinci/psc.h index 476bd74c7f50..d672e72ec227 100644 --- a/drivers/clk/davinci/psc.h +++ b/drivers/clk/davinci/psc.h @@ -100,5 +100,6 @@ extern const struct davinci_psc_init_data da850_psc0_init_data; extern const struct davinci_psc_init_data da850_psc1_init_data; extern const struct davinci_psc_init_data of_da850_psc0_init_data; extern const struct davinci_psc_init_data of_da850_psc1_init_data; +extern const struct davinci_psc_init_data dm355_psc_init_data; #endif /* __CLK_DAVINCI_PSC_H__ */ -- cgit From 9ab1102cceef22c7386664f114d2713cb021d186 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Thu, 15 Mar 2018 21:52:30 -0500 Subject: clk: davinci: Add platform information for TI DM365 PSC This adds platform-specific declarations for the PSC clocks on TI DM365 based systems. Signed-off-by: David Lechner Reviewed-by: Sekhar Nori Signed-off-by: Stephen Boyd --- drivers/clk/davinci/Makefile | 1 + drivers/clk/davinci/psc-dm365.c | 96 +++++++++++++++++++++++++++++++++++++++++ drivers/clk/davinci/psc.c | 1 + drivers/clk/davinci/psc.h | 1 + 4 files changed, 99 insertions(+) create mode 100644 drivers/clk/davinci/psc-dm365.c diff --git a/drivers/clk/davinci/Makefile b/drivers/clk/davinci/Makefile index e0da5c3859e2..78dc1eba4058 100644 --- a/drivers/clk/davinci/Makefile +++ b/drivers/clk/davinci/Makefile @@ -13,4 +13,5 @@ obj-y += psc.o obj-$(CONFIG_ARCH_DAVINCI_DA830) += psc-da830.o obj-$(CONFIG_ARCH_DAVINCI_DA850) += psc-da850.o obj-$(CONFIG_ARCH_DAVINCI_DM355) += psc-dm355.o +obj-$(CONFIG_ARCH_DAVINCI_DM365) += psc-dm365.o endif diff --git a/drivers/clk/davinci/psc-dm365.c b/drivers/clk/davinci/psc-dm365.c new file mode 100644 index 000000000000..3ad915f37376 --- /dev/null +++ b/drivers/clk/davinci/psc-dm365.c @@ -0,0 +1,96 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * PSC clock descriptions for TI DaVinci DM365 + * + * Copyright (C) 2018 David Lechner + */ + +#include +#include +#include +#include +#include +#include + +#include "psc.h" + +LPSC_CLKDEV1(vpss_slave_clkdev, "slave", "vpss"); +LPSC_CLKDEV1(spi1_clkdev, NULL, "spi_davinci.1"); +LPSC_CLKDEV1(mmcsd1_clkdev, NULL, "da830-mmc.1"); +LPSC_CLKDEV1(asp0_clkdev, NULL, "davinci-mcbsp"); +LPSC_CLKDEV1(usb_clkdev, "usb", NULL); +LPSC_CLKDEV1(spi2_clkdev, NULL, "spi_davinci.2"); +LPSC_CLKDEV1(aemif_clkdev, "aemif", NULL); +LPSC_CLKDEV1(mmcsd0_clkdev, NULL, "da830-mmc.0"); +LPSC_CLKDEV1(i2c_clkdev, NULL, "i2c_davinci.1"); +LPSC_CLKDEV1(uart0_clkdev, NULL, "serial8250.0"); +LPSC_CLKDEV1(uart1_clkdev, NULL, "serial8250.1"); +LPSC_CLKDEV1(spi0_clkdev, NULL, "spi_davinci.0"); +/* REVISIT: gpio-davinci.c should be modified to drop con_id */ +LPSC_CLKDEV1(gpio_clkdev, "gpio", NULL); +LPSC_CLKDEV1(timer0_clkdev, "timer0", NULL); +LPSC_CLKDEV1(timer2_clkdev, NULL, "davinci-wdt"); +LPSC_CLKDEV1(spi3_clkdev, NULL, "spi_davinci.3"); +LPSC_CLKDEV1(spi4_clkdev, NULL, "spi_davinci.4"); +LPSC_CLKDEV2(emac_clkdev, NULL, "davinci_emac.1", + "fck", "davinci_mdio.0"); +LPSC_CLKDEV1(voice_codec_clkdev, NULL, "davinci_voicecodec"); +LPSC_CLKDEV1(vpss_dac_clkdev, "vpss_dac", NULL); +LPSC_CLKDEV1(vpss_master_clkdev, "master", "vpss"); + +static const struct davinci_lpsc_clk_info dm365_psc_info[] = { + LPSC(1, 0, vpss_slave, pll1_sysclk5, vpss_slave_clkdev, 0), + LPSC(5, 0, timer3, pll1_auxclk, NULL, 0), + LPSC(6, 0, spi1, pll1_sysclk4, spi1_clkdev, 0), + LPSC(7, 0, mmcsd1, pll1_sysclk4, mmcsd1_clkdev, 0), + LPSC(8, 0, asp0, pll1_sysclk4, asp0_clkdev, 0), + LPSC(9, 0, usb, pll1_auxclk, usb_clkdev, 0), + LPSC(10, 0, pwm3, pll1_auxclk, NULL, 0), + LPSC(11, 0, spi2, pll1_sysclk4, spi2_clkdev, 0), + LPSC(12, 0, rto, pll1_sysclk4, NULL, 0), + LPSC(14, 0, aemif, pll1_sysclk4, aemif_clkdev, 0), + LPSC(15, 0, mmcsd0, pll1_sysclk8, mmcsd0_clkdev, 0), + LPSC(18, 0, i2c, pll1_auxclk, i2c_clkdev, 0), + LPSC(19, 0, uart0, pll1_auxclk, uart0_clkdev, 0), + LPSC(20, 0, uart1, pll1_sysclk4, uart1_clkdev, 0), + LPSC(22, 0, spi0, pll1_sysclk4, spi0_clkdev, 0), + LPSC(23, 0, pwm0, pll1_auxclk, NULL, 0), + LPSC(24, 0, pwm1, pll1_auxclk, NULL, 0), + LPSC(25, 0, pwm2, pll1_auxclk, NULL, 0), + LPSC(26, 0, gpio, pll1_sysclk4, gpio_clkdev, 0), + LPSC(27, 0, timer0, pll1_auxclk, timer0_clkdev, LPSC_ALWAYS_ENABLED), + LPSC(28, 0, timer1, pll1_auxclk, NULL, 0), + /* REVISIT: why can't this be disabled? */ + LPSC(29, 0, timer2, pll1_auxclk, timer2_clkdev, LPSC_ALWAYS_ENABLED), + LPSC(31, 0, arm, pll2_sysclk2, NULL, LPSC_ALWAYS_ENABLED), + LPSC(38, 0, spi3, pll1_sysclk4, spi3_clkdev, 0), + LPSC(39, 0, spi4, pll1_auxclk, spi4_clkdev, 0), + LPSC(40, 0, emac, pll2_sysclk4, emac_clkdev, 0), + LPSC(44, 1, voice_codec, pll1_sysclk3, voice_codec_clkdev, 0), + LPSC(46, 1, vpss_dac, pll1_sysclk3, vpss_dac_clkdev, 0), + LPSC(47, 0, vpss_master, pll1_sysclk5, vpss_master_clkdev, 0), + LPSC(50, 0, mjcp, pll1_sysclk3, NULL, 0), + { } +}; + +static int dm365_psc_init(struct device *dev, void __iomem *base) +{ + return davinci_psc_register_clocks(dev, dm365_psc_info, 52, base); +} + +static struct clk_bulk_data dm365_psc_parent_clks[] = { + { .id = "pll1_sysclk1" }, + { .id = "pll1_sysclk3" }, + { .id = "pll1_sysclk4" }, + { .id = "pll1_sysclk5" }, + { .id = "pll1_sysclk8" }, + { .id = "pll2_sysclk2" }, + { .id = "pll2_sysclk4" }, + { .id = "pll1_auxclk" }, +}; + +const struct davinci_psc_init_data dm365_psc_init_data = { + .parent_clks = dm365_psc_parent_clks, + .num_parent_clks = ARRAY_SIZE(dm365_psc_parent_clks), + .psc_init = &dm365_psc_init, +}; diff --git a/drivers/clk/davinci/psc.c b/drivers/clk/davinci/psc.c index 0825b62c1f3d..7bcf31622706 100644 --- a/drivers/clk/davinci/psc.c +++ b/drivers/clk/davinci/psc.c @@ -493,6 +493,7 @@ static const struct platform_device_id davinci_psc_id_table[] = { { .name = "da850-psc0", .driver_data = (kernel_ulong_t)&da850_psc0_init_data }, { .name = "da850-psc1", .driver_data = (kernel_ulong_t)&da850_psc1_init_data }, { .name = "dm355-psc", .driver_data = (kernel_ulong_t)&dm355_psc_init_data }, + { .name = "dm365-psc", .driver_data = (kernel_ulong_t)&dm365_psc_init_data }, { } }; diff --git a/drivers/clk/davinci/psc.h b/drivers/clk/davinci/psc.h index d672e72ec227..4f6210e8606f 100644 --- a/drivers/clk/davinci/psc.h +++ b/drivers/clk/davinci/psc.h @@ -101,5 +101,6 @@ extern const struct davinci_psc_init_data da850_psc1_init_data; extern const struct davinci_psc_init_data of_da850_psc0_init_data; extern const struct davinci_psc_init_data of_da850_psc1_init_data; extern const struct davinci_psc_init_data dm355_psc_init_data; +extern const struct davinci_psc_init_data dm365_psc_init_data; #endif /* __CLK_DAVINCI_PSC_H__ */ -- cgit From f41e5275757ed2516153b2dea616ef9e4afbfbcf Mon Sep 17 00:00:00 2001 From: David Lechner Date: Thu, 15 Mar 2018 21:52:31 -0500 Subject: clk: davinci: Add platform information for TI DM644x PSC This adds platform-specific declarations for the PSC clocks on TI DM644x based systems. Signed-off-by: David Lechner Signed-off-by: Stephen Boyd --- drivers/clk/davinci/Makefile | 1 + drivers/clk/davinci/psc-dm644x.c | 83 ++++++++++++++++++++++++++++++++++++++++ drivers/clk/davinci/psc.c | 1 + drivers/clk/davinci/psc.h | 1 + 4 files changed, 86 insertions(+) create mode 100644 drivers/clk/davinci/psc-dm644x.c diff --git a/drivers/clk/davinci/Makefile b/drivers/clk/davinci/Makefile index 78dc1eba4058..a20e3795eaf9 100644 --- a/drivers/clk/davinci/Makefile +++ b/drivers/clk/davinci/Makefile @@ -14,4 +14,5 @@ obj-$(CONFIG_ARCH_DAVINCI_DA830) += psc-da830.o obj-$(CONFIG_ARCH_DAVINCI_DA850) += psc-da850.o obj-$(CONFIG_ARCH_DAVINCI_DM355) += psc-dm355.o obj-$(CONFIG_ARCH_DAVINCI_DM365) += psc-dm365.o +obj-$(CONFIG_ARCH_DAVINCI_DM644x) += psc-dm644x.o endif diff --git a/drivers/clk/davinci/psc-dm644x.c b/drivers/clk/davinci/psc-dm644x.c new file mode 100644 index 000000000000..c22367baa46f --- /dev/null +++ b/drivers/clk/davinci/psc-dm644x.c @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * PSC clock descriptions for TI DaVinci DM644x + * + * Copyright (C) 2018 David Lechner + */ + +#include +#include +#include +#include +#include +#include + +#include "psc.h" + +LPSC_CLKDEV1(vpss_master_clkdev, "master", "vpss"); +LPSC_CLKDEV1(vpss_slave_clkdev, "slave", "vpss"); +LPSC_CLKDEV2(emac_clkdev, NULL, "davinci_emac.1", + "fck", "davinci_mdio.0"); +LPSC_CLKDEV1(usb_clkdev, "usb", NULL); +LPSC_CLKDEV1(ide_clkdev, NULL, "palm_bk3710"); +LPSC_CLKDEV1(aemif_clkdev, "aemif", NULL); +LPSC_CLKDEV1(mmcsd_clkdev, NULL, "dm6441-mmc.0"); +LPSC_CLKDEV1(asp0_clkdev, NULL, "davinci-mcbsp"); +LPSC_CLKDEV1(i2c_clkdev, NULL, "i2c_davinci.1"); +LPSC_CLKDEV1(uart0_clkdev, NULL, "serial8250.0"); +LPSC_CLKDEV1(uart1_clkdev, NULL, "serial8250.1"); +LPSC_CLKDEV1(uart2_clkdev, NULL, "serial8250.2"); +/* REVISIT: gpio-davinci.c should be modified to drop con_id */ +LPSC_CLKDEV1(gpio_clkdev, "gpio", NULL); +LPSC_CLKDEV1(timer0_clkdev, "timer0", NULL); +LPSC_CLKDEV1(timer2_clkdev, NULL, "davinci-wdt"); + +static const struct davinci_lpsc_clk_info dm644x_psc_info[] = { + LPSC(0, 0, vpss_master, pll1_sysclk3, vpss_master_clkdev, 0), + LPSC(1, 0, vpss_slave, pll1_sysclk3, vpss_slave_clkdev, 0), + LPSC(6, 0, emac, pll1_sysclk5, emac_clkdev, 0), + LPSC(9, 0, usb, pll1_sysclk5, usb_clkdev, 0), + LPSC(10, 0, ide, pll1_sysclk5, ide_clkdev, 0), + LPSC(11, 0, vlynq, pll1_sysclk5, NULL, 0), + LPSC(14, 0, aemif, pll1_sysclk5, aemif_clkdev, 0), + LPSC(15, 0, mmcsd, pll1_sysclk5, mmcsd_clkdev, 0), + LPSC(17, 0, asp0, pll1_sysclk5, asp0_clkdev, 0), + LPSC(18, 0, i2c, pll1_auxclk, i2c_clkdev, 0), + LPSC(19, 0, uart0, pll1_auxclk, uart0_clkdev, 0), + LPSC(20, 0, uart1, pll1_auxclk, uart1_clkdev, 0), + LPSC(21, 0, uart2, pll1_auxclk, uart2_clkdev, 0), + LPSC(22, 0, spi, pll1_sysclk5, NULL, 0), + LPSC(23, 0, pwm0, pll1_auxclk, NULL, 0), + LPSC(24, 0, pwm1, pll1_auxclk, NULL, 0), + LPSC(25, 0, pwm2, pll1_auxclk, NULL, 0), + LPSC(26, 0, gpio, pll1_sysclk5, gpio_clkdev, 0), + LPSC(27, 0, timer0, pll1_auxclk, timer0_clkdev, LPSC_ALWAYS_ENABLED), + LPSC(28, 0, timer1, pll1_auxclk, NULL, 0), + /* REVISIT: why can't this be disabled? */ + LPSC(29, 0, timer2, pll1_auxclk, timer2_clkdev, LPSC_ALWAYS_ENABLED), + LPSC(31, 0, arm, pll1_sysclk2, NULL, LPSC_ALWAYS_ENABLED), + /* REVISIT how to disable? */ + LPSC(39, 1, dsp, pll1_sysclk1, NULL, LPSC_ALWAYS_ENABLED), + /* REVISIT how to disable? */ + LPSC(40, 1, vicp, pll1_sysclk2, NULL, LPSC_ALWAYS_ENABLED), + { } +}; + +static int dm644x_psc_init(struct device *dev, void __iomem *base) +{ + return davinci_psc_register_clocks(dev, dm644x_psc_info, 41, base); +} + +static struct clk_bulk_data dm644x_psc_parent_clks[] = { + { .id = "pll1_sysclk1" }, + { .id = "pll1_sysclk2" }, + { .id = "pll1_sysclk3" }, + { .id = "pll1_sysclk5" }, + { .id = "pll1_auxclk" }, +}; + +const struct davinci_psc_init_data dm644x_psc_init_data = { + .parent_clks = dm644x_psc_parent_clks, + .num_parent_clks = ARRAY_SIZE(dm644x_psc_parent_clks), + .psc_init = &dm644x_psc_init, +}; diff --git a/drivers/clk/davinci/psc.c b/drivers/clk/davinci/psc.c index 7bcf31622706..65209382a3a6 100644 --- a/drivers/clk/davinci/psc.c +++ b/drivers/clk/davinci/psc.c @@ -494,6 +494,7 @@ static const struct platform_device_id davinci_psc_id_table[] = { { .name = "da850-psc1", .driver_data = (kernel_ulong_t)&da850_psc1_init_data }, { .name = "dm355-psc", .driver_data = (kernel_ulong_t)&dm355_psc_init_data }, { .name = "dm365-psc", .driver_data = (kernel_ulong_t)&dm365_psc_init_data }, + { .name = "dm644x-psc", .driver_data = (kernel_ulong_t)&dm644x_psc_init_data }, { } }; diff --git a/drivers/clk/davinci/psc.h b/drivers/clk/davinci/psc.h index 4f6210e8606f..d665cb005099 100644 --- a/drivers/clk/davinci/psc.h +++ b/drivers/clk/davinci/psc.h @@ -102,5 +102,6 @@ extern const struct davinci_psc_init_data of_da850_psc0_init_data; extern const struct davinci_psc_init_data of_da850_psc1_init_data; extern const struct davinci_psc_init_data dm355_psc_init_data; extern const struct davinci_psc_init_data dm365_psc_init_data; +extern const struct davinci_psc_init_data dm644x_psc_init_data; #endif /* __CLK_DAVINCI_PSC_H__ */ -- cgit From aad739f946a86c5dd07c3d8fc66c2795a256cfbb Mon Sep 17 00:00:00 2001 From: David Lechner Date: Thu, 15 Mar 2018 21:52:32 -0500 Subject: clk: davinci: Add platform information for TI DM646x PSC This adds platform-specific declarations for the PSC clocks on TI DM646x based systems. Signed-off-by: David Lechner Signed-off-by: Stephen Boyd --- drivers/clk/davinci/Makefile | 1 + drivers/clk/davinci/psc-dm646x.c | 80 ++++++++++++++++++++++++++++++++++++++++ drivers/clk/davinci/psc.c | 1 + drivers/clk/davinci/psc.h | 1 + 4 files changed, 83 insertions(+) create mode 100644 drivers/clk/davinci/psc-dm646x.c diff --git a/drivers/clk/davinci/Makefile b/drivers/clk/davinci/Makefile index a20e3795eaf9..6c388d44162d 100644 --- a/drivers/clk/davinci/Makefile +++ b/drivers/clk/davinci/Makefile @@ -15,4 +15,5 @@ obj-$(CONFIG_ARCH_DAVINCI_DA850) += psc-da850.o obj-$(CONFIG_ARCH_DAVINCI_DM355) += psc-dm355.o obj-$(CONFIG_ARCH_DAVINCI_DM365) += psc-dm365.o obj-$(CONFIG_ARCH_DAVINCI_DM644x) += psc-dm644x.o +obj-$(CONFIG_ARCH_DAVINCI_DM646x) += psc-dm646x.o endif diff --git a/drivers/clk/davinci/psc-dm646x.c b/drivers/clk/davinci/psc-dm646x.c new file mode 100644 index 000000000000..468ef86ea40b --- /dev/null +++ b/drivers/clk/davinci/psc-dm646x.c @@ -0,0 +1,80 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * PSC clock descriptions for TI DaVinci DM646x + * + * Copyright (C) 2018 David Lechner + */ + +#include +#include +#include +#include +#include +#include + +#include "psc.h" + +LPSC_CLKDEV1(ide_clkdev, NULL, "palm_bk3710"); +LPSC_CLKDEV2(emac_clkdev, NULL, "davinci_emac.1", + "fck", "davinci_mdio.0"); +LPSC_CLKDEV1(aemif_clkdev, "aemif", NULL); +LPSC_CLKDEV1(mcasp0_clkdev, NULL, "davinci-mcasp.0"); +LPSC_CLKDEV1(mcasp1_clkdev, NULL, "davinci-mcasp.1"); +LPSC_CLKDEV1(uart0_clkdev, NULL, "serial8250.0"); +LPSC_CLKDEV1(uart1_clkdev, NULL, "serial8250.1"); +LPSC_CLKDEV1(uart2_clkdev, NULL, "serial8250.2"); +LPSC_CLKDEV1(i2c_clkdev, NULL, "i2c_davinci.1"); +/* REVISIT: gpio-davinci.c should be modified to drop con_id */ +LPSC_CLKDEV1(gpio_clkdev, "gpio", NULL); +LPSC_CLKDEV1(timer0_clkdev, "timer0", NULL); + +static const struct davinci_lpsc_clk_info dm646x_psc_info[] = { + LPSC(0, 0, arm, pll1_sysclk2, NULL, LPSC_ALWAYS_ENABLED), + /* REVISIT how to disable? */ + LPSC(1, 0, dsp, pll1_sysclk1, NULL, LPSC_ALWAYS_ENABLED), + LPSC(4, 0, edma_cc, pll1_sysclk2, NULL, LPSC_ALWAYS_ENABLED), + LPSC(5, 0, edma_tc0, pll1_sysclk2, NULL, LPSC_ALWAYS_ENABLED), + LPSC(6, 0, edma_tc1, pll1_sysclk2, NULL, LPSC_ALWAYS_ENABLED), + LPSC(7, 0, edma_tc2, pll1_sysclk2, NULL, LPSC_ALWAYS_ENABLED), + LPSC(8, 0, edma_tc3, pll1_sysclk2, NULL, LPSC_ALWAYS_ENABLED), + LPSC(10, 0, ide, pll1_sysclk4, ide_clkdev, 0), + LPSC(14, 0, emac, pll1_sysclk3, emac_clkdev, 0), + LPSC(16, 0, vpif0, ref_clk, NULL, LPSC_ALWAYS_ENABLED), + LPSC(17, 0, vpif1, ref_clk, NULL, LPSC_ALWAYS_ENABLED), + LPSC(21, 0, aemif, pll1_sysclk3, aemif_clkdev, LPSC_ALWAYS_ENABLED), + LPSC(22, 0, mcasp0, pll1_sysclk3, mcasp0_clkdev, 0), + LPSC(23, 0, mcasp1, pll1_sysclk3, mcasp1_clkdev, 0), + LPSC(26, 0, uart0, aux_clkin, uart0_clkdev, 0), + LPSC(27, 0, uart1, aux_clkin, uart1_clkdev, 0), + LPSC(28, 0, uart2, aux_clkin, uart2_clkdev, 0), + /* REVIST: disabling hangs system */ + LPSC(29, 0, pwm0, pll1_sysclk3, NULL, LPSC_ALWAYS_ENABLED), + /* REVIST: disabling hangs system */ + LPSC(30, 0, pwm1, pll1_sysclk3, NULL, LPSC_ALWAYS_ENABLED), + LPSC(31, 0, i2c, pll1_sysclk3, i2c_clkdev, 0), + LPSC(33, 0, gpio, pll1_sysclk3, gpio_clkdev, 0), + LPSC(34, 0, timer0, pll1_sysclk3, timer0_clkdev, LPSC_ALWAYS_ENABLED), + LPSC(35, 0, timer1, pll1_sysclk3, NULL, 0), + { } +}; + +static int dm646x_psc_init(struct device *dev, void __iomem *base) +{ + return davinci_psc_register_clocks(dev, dm646x_psc_info, 46, base); +} + +static struct clk_bulk_data dm646x_psc_parent_clks[] = { + { .id = "ref_clk" }, + { .id = "aux_clkin" }, + { .id = "pll1_sysclk1" }, + { .id = "pll1_sysclk2" }, + { .id = "pll1_sysclk3" }, + { .id = "pll1_sysclk4" }, + { .id = "pll1_sysclk5" }, +}; + +const struct davinci_psc_init_data dm646x_psc_init_data = { + .parent_clks = dm646x_psc_parent_clks, + .num_parent_clks = ARRAY_SIZE(dm646x_psc_parent_clks), + .psc_init = &dm646x_psc_init, +}; diff --git a/drivers/clk/davinci/psc.c b/drivers/clk/davinci/psc.c index 65209382a3a6..3b0e59dfbdd7 100644 --- a/drivers/clk/davinci/psc.c +++ b/drivers/clk/davinci/psc.c @@ -495,6 +495,7 @@ static const struct platform_device_id davinci_psc_id_table[] = { { .name = "dm355-psc", .driver_data = (kernel_ulong_t)&dm355_psc_init_data }, { .name = "dm365-psc", .driver_data = (kernel_ulong_t)&dm365_psc_init_data }, { .name = "dm644x-psc", .driver_data = (kernel_ulong_t)&dm644x_psc_init_data }, + { .name = "dm646x-psc", .driver_data = (kernel_ulong_t)&dm646x_psc_init_data }, { } }; diff --git a/drivers/clk/davinci/psc.h b/drivers/clk/davinci/psc.h index d665cb005099..c2a7df6413fe 100644 --- a/drivers/clk/davinci/psc.h +++ b/drivers/clk/davinci/psc.h @@ -103,5 +103,6 @@ extern const struct davinci_psc_init_data of_da850_psc1_init_data; extern const struct davinci_psc_init_data dm355_psc_init_data; extern const struct davinci_psc_init_data dm365_psc_init_data; extern const struct davinci_psc_init_data dm644x_psc_init_data; +extern const struct davinci_psc_init_data dm646x_psc_init_data; #endif /* __CLK_DAVINCI_PSC_H__ */ -- cgit From 0c92c71770457df9c5459190ba72350459785f37 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Thu, 15 Mar 2018 21:52:33 -0500 Subject: dt-bindings: clock: Add bindings for DA8XX CFGCHIP clocks This adds a new binding for the clocks present in the CFGCHIP syscon registers in TI DA8XX SoCs. Signed-off-by: David Lechner Reviewed-by: Rob Herring Signed-off-by: Stephen Boyd --- .../bindings/clock/ti/davinci/da8xx-cfgchip.txt | 93 ++++++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/ti/davinci/da8xx-cfgchip.txt diff --git a/Documentation/devicetree/bindings/clock/ti/davinci/da8xx-cfgchip.txt b/Documentation/devicetree/bindings/clock/ti/davinci/da8xx-cfgchip.txt new file mode 100644 index 000000000000..1e03dce99a8f --- /dev/null +++ b/Documentation/devicetree/bindings/clock/ti/davinci/da8xx-cfgchip.txt @@ -0,0 +1,93 @@ +Binding for TI DA8XX/OMAP-L13X/AM17XX/AM18XX CFGCHIP clocks + +TI DA8XX/OMAP-L13X/AM17XX/AM18XX SoCs contain a general purpose set of +registers call CFGCHIPn. Some of these registers function as clock +gates. This document describes the bindings for those clocks. + +All of the clock nodes described below must be child nodes of a CFGCHIP node +(compatible = "ti,da830-cfgchip"). + +USB PHY clocks +-------------- +Required properties: +- compatible: shall be "ti,da830-usb-phy-clocks". +- #clock-cells: from common clock binding; shall be set to 1. +- clocks: phandles to the parent clocks corresponding to clock-names +- clock-names: shall be "fck", "usb_refclkin", "auxclk" + +This node provides two clocks. The clock at index 0 is the USB 2.0 PHY 48MHz +clock and the clock at index 1 is the USB 1.1 PHY 48MHz clock. + +eHRPWM Time Base Clock (TBCLK) +------------------------------ +Required properties: +- compatible: shall be "ti,da830-tbclksync". +- #clock-cells: from common clock binding; shall be set to 0. +- clocks: phandle to the parent clock +- clock-names: shall be "fck" + +PLL DIV4.5 divider +------------------ +Required properties: +- compatible: shall be "ti,da830-div4p5ena". +- #clock-cells: from common clock binding; shall be set to 0. +- clocks: phandle to the parent clock +- clock-names: shall be "pll0_pllout" + +EMIFA clock source (ASYNC1) +--------------------------- +Required properties: +- compatible: shall be "ti,da850-async1-clksrc". +- #clock-cells: from common clock binding; shall be set to 0. +- clocks: phandles to the parent clocks corresponding to clock-names +- clock-names: shall be "pll0_sysclk3", "div4.5" + +ASYNC3 clock source +------------------- +Required properties: +- compatible: shall be "ti,da850-async3-clksrc". +- #clock-cells: from common clock binding; shall be set to 0. +- clocks: phandles to the parent clocks corresponding to clock-names +- clock-names: shall be "pll0_sysclk2", "pll1_sysclk2" + +Examples: + + cfgchip: syscon@1417c { + compatible = "ti,da830-cfgchip", "syscon", "simple-mfd"; + reg = <0x1417c 0x14>; + + usb_phy_clk: usb-phy-clocks { + compatible = "ti,da830-usb-phy-clocks"; + #clock-cells = <1>; + clocks = <&psc1 1>, <&usb_refclkin>, <&pll0_auxclk>; + clock-names = "fck", "usb_refclkin", "auxclk"; + }; + ehrpwm_tbclk: ehrpwm_tbclk { + compatible = "ti,da830-tbclksync"; + #clock-cells = <0>; + clocks = <&psc1 17>; + clock-names = "fck"; + }; + div4p5_clk: div4.5 { + compatible = "ti,da830-div4p5ena"; + #clock-cells = <0>; + clocks = <&pll0_pllout>; + clock-names = "pll0_pllout"; + }; + async1_clk: async1 { + compatible = "ti,da850-async1-clksrc"; + #clock-cells = <0>; + clocks = <&pll0_sysclk 3>, <&div4p5_clk>; + clock-names = "pll0_sysclk3", "div4.5"; + }; + async3_clk: async3 { + compatible = "ti,da850-async3-clksrc"; + #clock-cells = <0>; + clocks = <&pll0_sysclk 2>, <&pll1_sysclk 2>; + clock-names = "pll0_sysclk2", "pll1_sysclk2"; + }; + }; + +Also see: +- Documentation/devicetree/bindings/clock/clock-bindings.txt + -- cgit From 1e88a8d64f221208801bb279ee7452df0b6d609f Mon Sep 17 00:00:00 2001 From: David Lechner Date: Thu, 15 Mar 2018 21:52:34 -0500 Subject: clk: davinci: New driver for TI DA8XX CFGCHIP clocks This adds a new driver for the gate and multiplexer clocks in the CFGCHIPn syscon registers on TI DA8XX-type SoCs. Signed-off-by: David Lechner Signed-off-by: Stephen Boyd --- drivers/clk/davinci/Makefile | 2 + drivers/clk/davinci/da8xx-cfgchip.c | 439 ++++++++++++++++++++++++ include/linux/platform_data/clk-da8xx-cfgchip.h | 21 ++ 3 files changed, 462 insertions(+) create mode 100644 drivers/clk/davinci/da8xx-cfgchip.c create mode 100644 include/linux/platform_data/clk-da8xx-cfgchip.h diff --git a/drivers/clk/davinci/Makefile b/drivers/clk/davinci/Makefile index 6c388d44162d..11178b79b483 100644 --- a/drivers/clk/davinci/Makefile +++ b/drivers/clk/davinci/Makefile @@ -1,6 +1,8 @@ # SPDX-License-Identifier: GPL-2.0 ifeq ($(CONFIG_COMMON_CLK), y) +obj-$(CONFIG_ARCH_DAVINCI_DA8XX) += da8xx-cfgchip.o + obj-y += pll.o obj-$(CONFIG_ARCH_DAVINCI_DA830) += pll-da830.o obj-$(CONFIG_ARCH_DAVINCI_DA850) += pll-da850.o diff --git a/drivers/clk/davinci/da8xx-cfgchip.c b/drivers/clk/davinci/da8xx-cfgchip.c new file mode 100644 index 000000000000..880a77ace273 --- /dev/null +++ b/drivers/clk/davinci/da8xx-cfgchip.c @@ -0,0 +1,439 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Clock driver for DA8xx/AM17xx/AM18xx/OMAP-L13x CFGCHIP + * + * Copyright (C) 2018 David Lechner + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* --- Gate clocks --- */ + +#define DA8XX_GATE_CLOCK_IS_DIV4P5 BIT(1) + +struct da8xx_cfgchip_gate_clk_info { + const char *name; + u32 cfgchip; + u32 bit; + u32 flags; +}; + +struct da8xx_cfgchip_gate_clk { + struct clk_hw hw; + struct regmap *regmap; + u32 reg; + u32 mask; +}; + +#define to_da8xx_cfgchip_gate_clk(_hw) \ + container_of((_hw), struct da8xx_cfgchip_gate_clk, hw) + +static int da8xx_cfgchip_gate_clk_enable(struct clk_hw *hw) +{ + struct da8xx_cfgchip_gate_clk *clk = to_da8xx_cfgchip_gate_clk(hw); + + return regmap_write_bits(clk->regmap, clk->reg, clk->mask, clk->mask); +} + +static void da8xx_cfgchip_gate_clk_disable(struct clk_hw *hw) +{ + struct da8xx_cfgchip_gate_clk *clk = to_da8xx_cfgchip_gate_clk(hw); + + regmap_write_bits(clk->regmap, clk->reg, clk->mask, 0); +} + +static int da8xx_cfgchip_gate_clk_is_enabled(struct clk_hw *hw) +{ + struct da8xx_cfgchip_gate_clk *clk = to_da8xx_cfgchip_gate_clk(hw); + unsigned int val; + + regmap_read(clk->regmap, clk->reg, &val); + + return !!(val & clk->mask); +} + +static unsigned long da8xx_cfgchip_div4p5_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + /* this clock divides by 4.5 */ + return parent_rate * 2 / 9; +} + +static const struct clk_ops da8xx_cfgchip_gate_clk_ops = { + .enable = da8xx_cfgchip_gate_clk_enable, + .disable = da8xx_cfgchip_gate_clk_disable, + .is_enabled = da8xx_cfgchip_gate_clk_is_enabled, +}; + +static const struct clk_ops da8xx_cfgchip_div4p5_clk_ops = { + .enable = da8xx_cfgchip_gate_clk_enable, + .disable = da8xx_cfgchip_gate_clk_disable, + .is_enabled = da8xx_cfgchip_gate_clk_is_enabled, + .recalc_rate = da8xx_cfgchip_div4p5_recalc_rate, +}; + +static struct da8xx_cfgchip_gate_clk * __init +da8xx_cfgchip_gate_clk_register(struct device *dev, + const struct da8xx_cfgchip_gate_clk_info *info, + struct regmap *regmap) +{ + struct clk *parent; + const char *parent_name; + struct da8xx_cfgchip_gate_clk *gate; + struct clk_init_data init; + int ret; + + parent = devm_clk_get(dev, NULL); + if (IS_ERR(parent)) + return ERR_CAST(parent); + + parent_name = __clk_get_name(parent); + + gate = devm_kzalloc(dev, sizeof(*gate), GFP_KERNEL); + if (!gate) + return ERR_PTR(-ENOMEM); + + init.name = info->name; + if (info->flags & DA8XX_GATE_CLOCK_IS_DIV4P5) + init.ops = &da8xx_cfgchip_div4p5_clk_ops; + else + init.ops = &da8xx_cfgchip_gate_clk_ops; + init.parent_names = &parent_name; + init.num_parents = 1; + init.flags = 0; + + gate->hw.init = &init; + gate->regmap = regmap; + gate->reg = info->cfgchip; + gate->mask = info->bit; + + ret = devm_clk_hw_register(dev, &gate->hw); + if (ret < 0) + return ERR_PTR(ret); + + return gate; +} + +static const struct da8xx_cfgchip_gate_clk_info da8xx_tbclksync_info __initconst = { + .name = "ehrpwm_tbclk", + .cfgchip = CFGCHIP(1), + .bit = CFGCHIP1_TBCLKSYNC, +}; + +static int __init da8xx_cfgchip_register_tbclk(struct device *dev, + struct regmap *regmap) +{ + struct da8xx_cfgchip_gate_clk *gate; + + gate = da8xx_cfgchip_gate_clk_register(dev, &da8xx_tbclksync_info, + regmap); + if (IS_ERR(gate)) + return PTR_ERR(gate); + + clk_hw_register_clkdev(&gate->hw, "tbclk", "ehrpwm.0"); + clk_hw_register_clkdev(&gate->hw, "tbclk", "ehrpwm.1"); + + return 0; +} + +static const struct da8xx_cfgchip_gate_clk_info da8xx_div4p5ena_info __initconst = { + .name = "div4.5", + .cfgchip = CFGCHIP(3), + .bit = CFGCHIP3_DIV45PENA, + .flags = DA8XX_GATE_CLOCK_IS_DIV4P5, +}; + +static int __init da8xx_cfgchip_register_div4p5(struct device *dev, + struct regmap *regmap) +{ + struct da8xx_cfgchip_gate_clk *gate; + + gate = da8xx_cfgchip_gate_clk_register(dev, &da8xx_div4p5ena_info, regmap); + if (IS_ERR(gate)) + return PTR_ERR(gate); + + return 0; +} + +static int __init +of_da8xx_cfgchip_gate_clk_init(struct device *dev, + const struct da8xx_cfgchip_gate_clk_info *info, + struct regmap *regmap) +{ + struct da8xx_cfgchip_gate_clk *gate; + + gate = da8xx_cfgchip_gate_clk_register(dev, info, regmap); + if (IS_ERR(gate)) + return PTR_ERR(gate); + + return devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, gate); +} + +static int __init of_da8xx_tbclksync_init(struct device *dev, + struct regmap *regmap) +{ + return of_da8xx_cfgchip_gate_clk_init(dev, &da8xx_tbclksync_info, regmap); +} + +static int __init of_da8xx_div4p5ena_init(struct device *dev, + struct regmap *regmap) +{ + return of_da8xx_cfgchip_gate_clk_init(dev, &da8xx_div4p5ena_info, regmap); +} + +/* --- MUX clocks --- */ + +struct da8xx_cfgchip_mux_clk_info { + const char *name; + const char *parent0; + const char *parent1; + u32 cfgchip; + u32 bit; +}; + +struct da8xx_cfgchip_mux_clk { + struct clk_hw hw; + struct regmap *regmap; + u32 reg; + u32 mask; +}; + +#define to_da8xx_cfgchip_mux_clk(_hw) \ + container_of((_hw), struct da8xx_cfgchip_mux_clk, hw) + +static int da8xx_cfgchip_mux_clk_set_parent(struct clk_hw *hw, u8 index) +{ + struct da8xx_cfgchip_mux_clk *clk = to_da8xx_cfgchip_mux_clk(hw); + unsigned int val = index ? clk->mask : 0; + + return regmap_write_bits(clk->regmap, clk->reg, clk->mask, val); +} + +static u8 da8xx_cfgchip_mux_clk_get_parent(struct clk_hw *hw) +{ + struct da8xx_cfgchip_mux_clk *clk = to_da8xx_cfgchip_mux_clk(hw); + unsigned int val; + + regmap_read(clk->regmap, clk->reg, &val); + + return (val & clk->mask) ? 1 : 0; +} + +static const struct clk_ops da8xx_cfgchip_mux_clk_ops = { + .set_parent = da8xx_cfgchip_mux_clk_set_parent, + .get_parent = da8xx_cfgchip_mux_clk_get_parent, +}; + +static struct da8xx_cfgchip_mux_clk * __init +da8xx_cfgchip_mux_clk_register(struct device *dev, + const struct da8xx_cfgchip_mux_clk_info *info, + struct regmap *regmap) +{ + const char * const parent_names[] = { info->parent0, info->parent1 }; + struct da8xx_cfgchip_mux_clk *mux; + struct clk_init_data init; + int ret; + + mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL); + if (!mux) + return ERR_PTR(-ENOMEM); + + init.name = info->name; + init.ops = &da8xx_cfgchip_mux_clk_ops; + init.parent_names = parent_names; + init.num_parents = 2; + init.flags = 0; + + mux->hw.init = &init; + mux->regmap = regmap; + mux->reg = info->cfgchip; + mux->mask = info->bit; + + ret = devm_clk_hw_register(dev, &mux->hw); + if (ret < 0) + return ERR_PTR(ret); + + return mux; +} + +static const struct da8xx_cfgchip_mux_clk_info da850_async1_info __initconst = { + .name = "async1", + .parent0 = "pll0_sysclk3", + .parent1 = "div4.5", + .cfgchip = CFGCHIP(3), + .bit = CFGCHIP3_EMA_CLKSRC, +}; + +static int __init da8xx_cfgchip_register_async1(struct device *dev, + struct regmap *regmap) +{ + struct da8xx_cfgchip_mux_clk *mux; + + mux = da8xx_cfgchip_mux_clk_register(dev, &da850_async1_info, regmap); + if (IS_ERR(mux)) + return PTR_ERR(mux); + + clk_hw_register_clkdev(&mux->hw, "async1", "da850-psc0"); + + return 0; +} + +static const struct da8xx_cfgchip_mux_clk_info da850_async3_info __initconst = { + .name = "async3", + .parent0 = "pll0_sysclk2", + .parent1 = "pll1_sysclk2", + .cfgchip = CFGCHIP(3), + .bit = CFGCHIP3_ASYNC3_CLKSRC, +}; + +static int __init da850_cfgchip_register_async3(struct device *dev, + struct regmap *regmap) +{ + struct da8xx_cfgchip_mux_clk *mux; + struct clk_hw *parent; + + mux = da8xx_cfgchip_mux_clk_register(dev, &da850_async3_info, regmap); + if (IS_ERR(mux)) + return PTR_ERR(mux); + + clk_hw_register_clkdev(&mux->hw, "async3", "da850-psc1"); + + /* pll1_sysclk2 is not affected by CPU scaling, so use it for async3 */ + parent = clk_hw_get_parent_by_index(&mux->hw, 1); + if (parent) + clk_set_parent(mux->hw.clk, parent->clk); + else + dev_warn(dev, "Failed to find async3 parent clock\n"); + + return 0; +} + +static int __init +of_da8xx_cfgchip_init_mux_clock(struct device *dev, + const struct da8xx_cfgchip_mux_clk_info *info, + struct regmap *regmap) +{ + struct da8xx_cfgchip_mux_clk *mux; + + mux = da8xx_cfgchip_mux_clk_register(dev, info, regmap); + if (IS_ERR(mux)) + return PTR_ERR(mux); + + return devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, &mux->hw); +} + +static int __init of_da850_async1_init(struct device *dev, struct regmap *regmap) +{ + return of_da8xx_cfgchip_init_mux_clock(dev, &da850_async1_info, regmap); +} + +static int __init of_da850_async3_init(struct device *dev, struct regmap *regmap) +{ + return of_da8xx_cfgchip_init_mux_clock(dev, &da850_async3_info, regmap); +} + +/* --- platform device --- */ + +static const struct of_device_id da8xx_cfgchip_of_match[] = { + { + .compatible = "ti,da830-tbclksync", + .data = of_da8xx_tbclksync_init, + }, + { + .compatible = "ti,da830-div4p5ena", + .data = of_da8xx_div4p5ena_init, + }, + { + .compatible = "ti,da850-async1-clksrc", + .data = of_da850_async1_init, + }, + { + .compatible = "ti,da850-async3-clksrc", + .data = of_da850_async3_init, + }, + { } +}; + +static const struct platform_device_id da8xx_cfgchip_id_table[] = { + { + .name = "da830-tbclksync", + .driver_data = (kernel_ulong_t)da8xx_cfgchip_register_tbclk, + }, + { + .name = "da830-div4p5ena", + .driver_data = (kernel_ulong_t)da8xx_cfgchip_register_div4p5, + }, + { + .name = "da850-async1-clksrc", + .driver_data = (kernel_ulong_t)da8xx_cfgchip_register_async1, + }, + { + .name = "da850-async3-clksrc", + .driver_data = (kernel_ulong_t)da850_cfgchip_register_async3, + }, + { } +}; + +typedef int (*da8xx_cfgchip_init)(struct device *dev, struct regmap *regmap); + +static int da8xx_cfgchip_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct da8xx_cfgchip_clk_platform_data *pdata = dev->platform_data; + const struct of_device_id *of_id; + da8xx_cfgchip_init clk_init = NULL; + struct regmap *regmap = NULL; + + of_id = of_match_device(da8xx_cfgchip_of_match, dev); + if (of_id) { + struct device_node *parent; + + clk_init = of_id->data; + parent = of_get_parent(dev->of_node); + regmap = syscon_node_to_regmap(parent); + of_node_put(parent); + } else if (pdev->id_entry && pdata) { + clk_init = (void *)pdev->id_entry->driver_data; + regmap = pdata->cfgchip; + } + + if (!clk_init) { + dev_err(dev, "unable to find driver data\n"); + return -EINVAL; + } + + if (IS_ERR_OR_NULL(regmap)) { + dev_err(dev, "no regmap for CFGCHIP syscon\n"); + return regmap ? PTR_ERR(regmap) : -ENOENT; + } + + return clk_init(dev, regmap); +} + +static struct platform_driver da8xx_cfgchip_driver = { + .probe = da8xx_cfgchip_probe, + .driver = { + .name = "da8xx-cfgchip-clk", + .of_match_table = da8xx_cfgchip_of_match, + }, + .id_table = da8xx_cfgchip_id_table, +}; + +static int __init da8xx_cfgchip_driver_init(void) +{ + return platform_driver_register(&da8xx_cfgchip_driver); +} + +/* has to be postcore_initcall because PSC devices depend on the async3 clock */ +postcore_initcall(da8xx_cfgchip_driver_init); diff --git a/include/linux/platform_data/clk-da8xx-cfgchip.h b/include/linux/platform_data/clk-da8xx-cfgchip.h new file mode 100644 index 000000000000..de0f77d38669 --- /dev/null +++ b/include/linux/platform_data/clk-da8xx-cfgchip.h @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * clk-da8xx-cfgchip - TI DaVinci DA8xx CFGCHIP clock driver + * + * Copyright (C) 2018 David Lechner + */ + +#ifndef __LINUX_PLATFORM_DATA_CLK_DA8XX_CFGCHIP_H__ +#define __LINUX_PLATFORM_DATA_CLK_DA8XX_CFGCHIP_H__ + +#include + +/** + * da8xx_cfgchip_clk_platform_data + * @cfgchip: CFGCHIP syscon regmap + */ +struct da8xx_cfgchip_clk_platform_data { + struct regmap *cfgchip; +}; + +#endif /* __LINUX_PLATFORM_DATA_CLK_DA8XX_CFGCHIP_H__ */ -- cgit From 58e1e2d2cd89a4aa77212eae64dd4824374e83f4 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Thu, 15 Mar 2018 21:52:35 -0500 Subject: clk: davinci: cfgchip: Add TI DA8XX USB PHY clocks This adds a new driver for the USB PHY clocks in the CFGCHIP2 syscon register on TI DA8XX-type SoCs. The USB0 (USB 2.0) PHY clock is an interesting case because it calls clk_enable() in a reentrant way. The USB 2.0 PSC only has to be enabled temporarily while we are locking the PLL, which takes place during the clk_enable() callback. Signed-off-by: David Lechner Signed-off-by: Stephen Boyd --- drivers/clk/davinci/da8xx-cfgchip.c | 351 ++++++++++++++++++++++++++++++++++++ 1 file changed, 351 insertions(+) diff --git a/drivers/clk/davinci/da8xx-cfgchip.c b/drivers/clk/davinci/da8xx-cfgchip.c index 880a77ace273..c971111d2601 100644 --- a/drivers/clk/davinci/da8xx-cfgchip.c +++ b/drivers/clk/davinci/da8xx-cfgchip.c @@ -343,6 +343,349 @@ static int __init of_da850_async3_init(struct device *dev, struct regmap *regmap return of_da8xx_cfgchip_init_mux_clock(dev, &da850_async3_info, regmap); } +/* --- USB 2.0 PHY clock --- */ + +struct da8xx_usb0_clk48 { + struct clk_hw hw; + struct clk *fck; + struct regmap *regmap; +}; + +#define to_da8xx_usb0_clk48(_hw) \ + container_of((_hw), struct da8xx_usb0_clk48, hw) + +static int da8xx_usb0_clk48_prepare(struct clk_hw *hw) +{ + struct da8xx_usb0_clk48 *usb0 = to_da8xx_usb0_clk48(hw); + + /* The USB 2.0 PSC clock is only needed temporarily during the USB 2.0 + * PHY clock enable, but since clk_prepare() can't be called in an + * atomic context (i.e. in clk_enable()), we have to prepare it here. + */ + return clk_prepare(usb0->fck); +} + +static void da8xx_usb0_clk48_unprepare(struct clk_hw *hw) +{ + struct da8xx_usb0_clk48 *usb0 = to_da8xx_usb0_clk48(hw); + + clk_unprepare(usb0->fck); +} + +static int da8xx_usb0_clk48_enable(struct clk_hw *hw) +{ + struct da8xx_usb0_clk48 *usb0 = to_da8xx_usb0_clk48(hw); + unsigned int mask, val; + int ret; + + /* Locking the USB 2.O PLL requires that the USB 2.O PSC is enabled + * temporaily. It can be turned back off once the PLL is locked. + */ + clk_enable(usb0->fck); + + /* Turn on the USB 2.0 PHY, but just the PLL, and not OTG. The USB 1.1 + * PHY may use the USB 2.0 PLL clock without USB 2.0 OTG being used. + */ + mask = CFGCHIP2_RESET | CFGCHIP2_PHYPWRDN | CFGCHIP2_PHY_PLLON; + val = CFGCHIP2_PHY_PLLON; + + regmap_write_bits(usb0->regmap, CFGCHIP(2), mask, val); + ret = regmap_read_poll_timeout(usb0->regmap, CFGCHIP(2), val, + val & CFGCHIP2_PHYCLKGD, 0, 500000); + + clk_disable(usb0->fck); + + return ret; +} + +static void da8xx_usb0_clk48_disable(struct clk_hw *hw) +{ + struct da8xx_usb0_clk48 *usb0 = to_da8xx_usb0_clk48(hw); + unsigned int val; + + val = CFGCHIP2_PHYPWRDN; + regmap_write_bits(usb0->regmap, CFGCHIP(2), val, val); +} + +static int da8xx_usb0_clk48_is_enabled(struct clk_hw *hw) +{ + struct da8xx_usb0_clk48 *usb0 = to_da8xx_usb0_clk48(hw); + unsigned int val; + + regmap_read(usb0->regmap, CFGCHIP(2), &val); + + return !!(val & CFGCHIP2_PHYCLKGD); +} + +static unsigned long da8xx_usb0_clk48_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct da8xx_usb0_clk48 *usb0 = to_da8xx_usb0_clk48(hw); + unsigned int mask, val; + + /* The parent clock rate must be one of the following */ + mask = CFGCHIP2_REFFREQ_MASK; + switch (parent_rate) { + case 12000000: + val = CFGCHIP2_REFFREQ_12MHZ; + break; + case 13000000: + val = CFGCHIP2_REFFREQ_13MHZ; + break; + case 19200000: + val = CFGCHIP2_REFFREQ_19_2MHZ; + break; + case 20000000: + val = CFGCHIP2_REFFREQ_20MHZ; + break; + case 24000000: + val = CFGCHIP2_REFFREQ_24MHZ; + break; + case 26000000: + val = CFGCHIP2_REFFREQ_26MHZ; + break; + case 38400000: + val = CFGCHIP2_REFFREQ_38_4MHZ; + break; + case 40000000: + val = CFGCHIP2_REFFREQ_40MHZ; + break; + case 48000000: + val = CFGCHIP2_REFFREQ_48MHZ; + break; + default: + return 0; + } + + regmap_write_bits(usb0->regmap, CFGCHIP(2), mask, val); + + /* USB 2.0 PLL always supplies 48MHz */ + return 48000000; +} + +static long da8xx_usb0_clk48_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + return 48000000; +} + +static int da8xx_usb0_clk48_set_parent(struct clk_hw *hw, u8 index) +{ + struct da8xx_usb0_clk48 *usb0 = to_da8xx_usb0_clk48(hw); + + return regmap_write_bits(usb0->regmap, CFGCHIP(2), + CFGCHIP2_USB2PHYCLKMUX, + index ? CFGCHIP2_USB2PHYCLKMUX : 0); +} + +static u8 da8xx_usb0_clk48_get_parent(struct clk_hw *hw) +{ + struct da8xx_usb0_clk48 *usb0 = to_da8xx_usb0_clk48(hw); + unsigned int val; + + regmap_read(usb0->regmap, CFGCHIP(2), &val); + + return (val & CFGCHIP2_USB2PHYCLKMUX) ? 1 : 0; +} + +static const struct clk_ops da8xx_usb0_clk48_ops = { + .prepare = da8xx_usb0_clk48_prepare, + .unprepare = da8xx_usb0_clk48_unprepare, + .enable = da8xx_usb0_clk48_enable, + .disable = da8xx_usb0_clk48_disable, + .is_enabled = da8xx_usb0_clk48_is_enabled, + .recalc_rate = da8xx_usb0_clk48_recalc_rate, + .round_rate = da8xx_usb0_clk48_round_rate, + .set_parent = da8xx_usb0_clk48_set_parent, + .get_parent = da8xx_usb0_clk48_get_parent, +}; + +static struct da8xx_usb0_clk48 * +da8xx_cfgchip_register_usb0_clk48(struct device *dev, + struct regmap *regmap) +{ + const char * const parent_names[] = { "usb_refclkin", "pll0_auxclk" }; + struct clk *fck_clk; + struct da8xx_usb0_clk48 *usb0; + struct clk_init_data init; + int ret; + + fck_clk = devm_clk_get(dev, "fck"); + if (IS_ERR(fck_clk)) { + if (PTR_ERR(fck_clk) != -EPROBE_DEFER) + dev_err(dev, "Missing fck clock\n"); + return ERR_CAST(fck_clk); + } + + usb0 = devm_kzalloc(dev, sizeof(*usb0), GFP_KERNEL); + if (!usb0) + return ERR_PTR(-ENOMEM); + + init.name = "usb0_clk48"; + init.ops = &da8xx_usb0_clk48_ops; + init.parent_names = parent_names; + init.num_parents = 2; + + usb0->hw.init = &init; + usb0->fck = fck_clk; + usb0->regmap = regmap; + + ret = devm_clk_hw_register(dev, &usb0->hw); + if (ret < 0) + return ERR_PTR(ret); + + return usb0; +} + +/* --- USB 1.1 PHY clock --- */ + +struct da8xx_usb1_clk48 { + struct clk_hw hw; + struct regmap *regmap; +}; + +#define to_da8xx_usb1_clk48(_hw) \ + container_of((_hw), struct da8xx_usb1_clk48, hw) + +static int da8xx_usb1_clk48_set_parent(struct clk_hw *hw, u8 index) +{ + struct da8xx_usb1_clk48 *usb1 = to_da8xx_usb1_clk48(hw); + + return regmap_write_bits(usb1->regmap, CFGCHIP(2), + CFGCHIP2_USB1PHYCLKMUX, + index ? CFGCHIP2_USB1PHYCLKMUX : 0); +} + +static u8 da8xx_usb1_clk48_get_parent(struct clk_hw *hw) +{ + struct da8xx_usb1_clk48 *usb1 = to_da8xx_usb1_clk48(hw); + unsigned int val; + + regmap_read(usb1->regmap, CFGCHIP(2), &val); + + return (val & CFGCHIP2_USB1PHYCLKMUX) ? 1 : 0; +} + +static const struct clk_ops da8xx_usb1_clk48_ops = { + .set_parent = da8xx_usb1_clk48_set_parent, + .get_parent = da8xx_usb1_clk48_get_parent, +}; + +/** + * da8xx_cfgchip_register_usb1_clk48 - Register a new USB 1.1 PHY clock + * @regmap: The CFGCHIP regmap + */ +static struct da8xx_usb1_clk48 * +da8xx_cfgchip_register_usb1_clk48(struct device *dev, + struct regmap *regmap) +{ + const char * const parent_names[] = { "usb0_clk48", "usb_refclkin" }; + struct da8xx_usb1_clk48 *usb1; + struct clk_init_data init; + int ret; + + usb1 = devm_kzalloc(dev, sizeof(*usb1), GFP_KERNEL); + if (!usb1) + return ERR_PTR(-ENOMEM); + + init.name = "usb1_clk48"; + init.ops = &da8xx_usb1_clk48_ops; + init.parent_names = parent_names; + init.num_parents = 2; + + usb1->hw.init = &init; + usb1->regmap = regmap; + + ret = devm_clk_hw_register(dev, &usb1->hw); + if (ret < 0) + return ERR_PTR(ret); + + return usb1; +} + +static int da8xx_cfgchip_register_usb_phy_clk(struct device *dev, + struct regmap *regmap) +{ + struct da8xx_usb0_clk48 *usb0; + struct da8xx_usb1_clk48 *usb1; + struct clk_hw *parent; + + usb0 = da8xx_cfgchip_register_usb0_clk48(dev, regmap); + if (IS_ERR(usb0)) + return PTR_ERR(usb0); + + /* + * All existing boards use pll0_auxclk as the parent and new boards + * should use device tree, so hard-coding the value (1) here. + */ + parent = clk_hw_get_parent_by_index(&usb0->hw, 1); + if (parent) + clk_set_parent(usb0->hw.clk, parent->clk); + else + dev_warn(dev, "Failed to find usb0 parent clock\n"); + + usb1 = da8xx_cfgchip_register_usb1_clk48(dev, regmap); + if (IS_ERR(usb1)) + return PTR_ERR(usb1); + + /* + * All existing boards use usb0_clk48 as the parent and new boards + * should use device tree, so hard-coding the value (0) here. + */ + parent = clk_hw_get_parent_by_index(&usb1->hw, 0); + if (parent) + clk_set_parent(usb1->hw.clk, parent->clk); + else + dev_warn(dev, "Failed to find usb1 parent clock\n"); + + clk_hw_register_clkdev(&usb0->hw, "usb0_clk48", "da8xx-usb-phy"); + clk_hw_register_clkdev(&usb1->hw, "usb1_clk48", "da8xx-usb-phy"); + + return 0; +} + +static int of_da8xx_usb_phy_clk_init(struct device *dev, struct regmap *regmap) +{ + struct clk_hw_onecell_data *clk_data; + struct da8xx_usb0_clk48 *usb0; + struct da8xx_usb1_clk48 *usb1; + + clk_data = devm_kzalloc(dev, sizeof(*clk_data) + 2 * + sizeof(*clk_data->hws), GFP_KERNEL); + if (!clk_data) + return -ENOMEM; + + clk_data->num = 2; + + usb0 = da8xx_cfgchip_register_usb0_clk48(dev, regmap); + if (IS_ERR(usb0)) { + if (PTR_ERR(usb0) == -EPROBE_DEFER) + return -EPROBE_DEFER; + + dev_warn(dev, "Failed to register usb0_clk48 (%ld)\n", + PTR_ERR(usb0)); + + clk_data->hws[0] = ERR_PTR(-ENOENT); + } else { + clk_data->hws[0] = &usb0->hw; + } + + usb1 = da8xx_cfgchip_register_usb1_clk48(dev, regmap); + if (IS_ERR(usb1)) { + if (PTR_ERR(usb0) == -EPROBE_DEFER) + return -EPROBE_DEFER; + + dev_warn(dev, "Failed to register usb1_clk48 (%ld)\n", + PTR_ERR(usb1)); + + clk_data->hws[1] = ERR_PTR(-ENOENT); + } else { + clk_data->hws[1] = &usb1->hw; + } + + return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, clk_data); +} + /* --- platform device --- */ static const struct of_device_id da8xx_cfgchip_of_match[] = { @@ -362,6 +705,10 @@ static const struct of_device_id da8xx_cfgchip_of_match[] = { .compatible = "ti,da850-async3-clksrc", .data = of_da850_async3_init, }, + { + .compatible = "ti,da830-usb-phy-clocks", + .data = of_da8xx_usb_phy_clk_init, + }, { } }; @@ -382,6 +729,10 @@ static const struct platform_device_id da8xx_cfgchip_id_table[] = { .name = "da850-async3-clksrc", .driver_data = (kernel_ulong_t)da850_cfgchip_register_async3, }, + { + .name = "da830-usb-phy-clks", + .driver_data = (kernel_ulong_t)da8xx_cfgchip_register_usb_phy_clk, + }, { } }; -- cgit From c744b63b6c422776293cc526ef7887623926f33e Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Tue, 20 Mar 2018 14:19:34 +0000 Subject: clk: hisilicon: fix potential NULL dereference in hisi_clk_alloc() platform_get_resource() may fail and return NULL, so we should better check it's return value to avoid a NULL pointer dereference a bit later in the code. This is detected by Coccinelle semantic patch. @@ expression pdev, res, n, t, e, e1, e2; @@ res = platform_get_resource(pdev, t, n); + if (!res) + return -EINVAL; ... when != res == NULL e = devm_ioremap(e1, res->start, e2); Signed-off-by: Wei Yongjun Fixes: 322269163a36 ("clk: hisilicon: add hisi_clk_alloc function.") Signed-off-by: Stephen Boyd --- drivers/clk/hisilicon/clk.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/clk/hisilicon/clk.c b/drivers/clk/hisilicon/clk.c index 29046b8334c2..953c8dacef8b 100644 --- a/drivers/clk/hisilicon/clk.c +++ b/drivers/clk/hisilicon/clk.c @@ -49,6 +49,8 @@ struct hisi_clock_data *hisi_clk_alloc(struct platform_device *pdev, return NULL; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return NULL; clk_data->base = devm_ioremap(&pdev->dev, res->start, resource_size(res)); if (!clk_data->base) -- cgit From f422fa558aada511406432bc5974d3a5bf728227 Mon Sep 17 00:00:00 2001 From: Icenowy Zheng Date: Wed, 21 Mar 2018 10:46:25 +0800 Subject: clk: sunxi-ng: add missing hdmi-slow clock for H6 CCU The Allwinner H6 CCU has a "HDMI Slow Clock", which is currently missing in the ccu-sun50i-h6 driver. Add this missing clock to the driver. Fixes: 542353ea ("clk: sunxi-ng: add support for the Allwinner H6 CCU") Signed-off-by: Icenowy Zheng Signed-off-by: Maxime Ripard --- drivers/clk/sunxi-ng/ccu-sun50i-h6.c | 4 ++++ drivers/clk/sunxi-ng/ccu-sun50i-h6.h | 2 +- include/dt-bindings/clock/sun50i-h6-ccu.h | 27 ++++++++++++++------------- 3 files changed, 19 insertions(+), 14 deletions(-) diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-h6.c b/drivers/clk/sunxi-ng/ccu-sun50i-h6.c index d5eab49e6350..bdbfe78fe133 100644 --- a/drivers/clk/sunxi-ng/ccu-sun50i-h6.c +++ b/drivers/clk/sunxi-ng/ccu-sun50i-h6.c @@ -643,6 +643,8 @@ static SUNXI_CCU_M_WITH_MUX_GATE(hdmi_clk, "hdmi", hdmi_parents, 0xb00, BIT(31), /* gate */ 0); +static SUNXI_CCU_GATE(hdmi_slow_clk, "hdmi-slow", "osc24M", 0xb04, BIT(31), 0); + static const char * const hdmi_cec_parents[] = { "osc32k", "pll-periph0-2x" }; static const struct ccu_mux_fixed_prediv hdmi_cec_predivs[] = { { .index = 1, .div = 36621 }, @@ -876,6 +878,7 @@ static struct ccu_common *sun50i_h6_ccu_clks[] = { &pcie_aux_clk.common, &bus_pcie_clk.common, &hdmi_clk.common, + &hdmi_slow_clk.common, &hdmi_cec_clk.common, &bus_hdmi_clk.common, &bus_tcon_top_clk.common, @@ -1017,6 +1020,7 @@ static struct clk_hw_onecell_data sun50i_h6_hw_clks = { [CLK_PCIE_AUX] = &pcie_aux_clk.common.hw, [CLK_BUS_PCIE] = &bus_pcie_clk.common.hw, [CLK_HDMI] = &hdmi_clk.common.hw, + [CLK_HDMI_SLOW] = &hdmi_slow_clk.common.hw, [CLK_HDMI_CEC] = &hdmi_cec_clk.common.hw, [CLK_BUS_HDMI] = &bus_hdmi_clk.common.hw, [CLK_BUS_TCON_TOP] = &bus_tcon_top_clk.common.hw, diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-h6.h b/drivers/clk/sunxi-ng/ccu-sun50i-h6.h index ad6da4aa733c..2ccfe4428260 100644 --- a/drivers/clk/sunxi-ng/ccu-sun50i-h6.h +++ b/drivers/clk/sunxi-ng/ccu-sun50i-h6.h @@ -51,6 +51,6 @@ #define CLK_BUS_DRAM 60 -#define CLK_NUMBER 137 +#define CLK_NUMBER (CLK_BUS_HDCP + 1) #endif /* _CCU_SUN50I_H6_H_ */ diff --git a/include/dt-bindings/clock/sun50i-h6-ccu.h b/include/dt-bindings/clock/sun50i-h6-ccu.h index 6045735a2821..a1545cd60e75 100644 --- a/include/dt-bindings/clock/sun50i-h6-ccu.h +++ b/include/dt-bindings/clock/sun50i-h6-ccu.h @@ -107,18 +107,19 @@ #define CLK_PCIE_AUX 121 #define CLK_BUS_PCIE 122 #define CLK_HDMI 123 -#define CLK_HDMI_CEC 124 -#define CLK_BUS_HDMI 125 -#define CLK_BUS_TCON_TOP 126 -#define CLK_TCON_LCD0 127 -#define CLK_BUS_TCON_LCD0 128 -#define CLK_TCON_TV0 129 -#define CLK_BUS_TCON_TV0 130 -#define CLK_CSI_CCI 131 -#define CLK_CSI_TOP 132 -#define CLK_CSI_MCLK 133 -#define CLK_BUS_CSI 134 -#define CLK_HDCP 135 -#define CLK_BUS_HDCP 136 +#define CLK_HDMI_SLOW 124 +#define CLK_HDMI_CEC 125 +#define CLK_BUS_HDMI 126 +#define CLK_BUS_TCON_TOP 127 +#define CLK_TCON_LCD0 128 +#define CLK_BUS_TCON_LCD0 129 +#define CLK_TCON_TV0 130 +#define CLK_BUS_TCON_TV0 131 +#define CLK_CSI_CCI 132 +#define CLK_CSI_TOP 133 +#define CLK_CSI_MCLK 134 +#define CLK_BUS_CSI 135 +#define CLK_HDCP 136 +#define CLK_BUS_HDCP 137 #endif /* _DT_BINDINGS_CLK_SUN50I_H6_H_ */ -- cgit From c733c7d9374191cac6668ce6ea074909d036d8f4 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 15 Mar 2018 10:43:12 +0100 Subject: clk: renesas: div6: Always use readl()/writel() On arm32/arm64, there is no reason to use the (soon deprecated) clk_readl()/clk_writel(). Hence use the generic readl()/writel() instead. Signed-off-by: Geert Uytterhoeven Reviewed-by: Simon Horman --- drivers/clk/renesas/clk-div6.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/clk/renesas/clk-div6.c b/drivers/clk/renesas/clk-div6.c index 151336d2ba59..9febbf42c3df 100644 --- a/drivers/clk/renesas/clk-div6.c +++ b/drivers/clk/renesas/clk-div6.c @@ -53,9 +53,9 @@ static int cpg_div6_clock_enable(struct clk_hw *hw) struct div6_clock *clock = to_div6_clock(hw); u32 val; - val = (clk_readl(clock->reg) & ~(CPG_DIV6_DIV_MASK | CPG_DIV6_CKSTP)) + val = (readl(clock->reg) & ~(CPG_DIV6_DIV_MASK | CPG_DIV6_CKSTP)) | CPG_DIV6_DIV(clock->div - 1); - clk_writel(val, clock->reg); + writel(val, clock->reg); return 0; } @@ -65,7 +65,7 @@ static void cpg_div6_clock_disable(struct clk_hw *hw) struct div6_clock *clock = to_div6_clock(hw); u32 val; - val = clk_readl(clock->reg); + val = readl(clock->reg); val |= CPG_DIV6_CKSTP; /* * DIV6 clocks require the divisor field to be non-zero when stopping @@ -75,14 +75,14 @@ static void cpg_div6_clock_disable(struct clk_hw *hw) */ if (!(val & CPG_DIV6_DIV_MASK)) val |= CPG_DIV6_DIV_MASK; - clk_writel(val, clock->reg); + writel(val, clock->reg); } static int cpg_div6_clock_is_enabled(struct clk_hw *hw) { struct div6_clock *clock = to_div6_clock(hw); - return !(clk_readl(clock->reg) & CPG_DIV6_CKSTP); + return !(readl(clock->reg) & CPG_DIV6_CKSTP); } static unsigned long cpg_div6_clock_recalc_rate(struct clk_hw *hw, @@ -122,10 +122,10 @@ static int cpg_div6_clock_set_rate(struct clk_hw *hw, unsigned long rate, clock->div = div; - val = clk_readl(clock->reg) & ~CPG_DIV6_DIV_MASK; + val = readl(clock->reg) & ~CPG_DIV6_DIV_MASK; /* Only program the new divisor if the clock isn't stopped. */ if (!(val & CPG_DIV6_CKSTP)) - clk_writel(val | CPG_DIV6_DIV(clock->div - 1), clock->reg); + writel(val | CPG_DIV6_DIV(clock->div - 1), clock->reg); return 0; } @@ -139,7 +139,7 @@ static u8 cpg_div6_clock_get_parent(struct clk_hw *hw) if (clock->src_width == 0) return 0; - hw_index = (clk_readl(clock->reg) >> clock->src_shift) & + hw_index = (readl(clock->reg) >> clock->src_shift) & (BIT(clock->src_width) - 1); for (i = 0; i < clk_hw_get_num_parents(hw); i++) { if (clock->parents[i] == hw_index) @@ -163,8 +163,8 @@ static int cpg_div6_clock_set_parent(struct clk_hw *hw, u8 index) mask = ~((BIT(clock->src_width) - 1) << clock->src_shift); hw_index = clock->parents[index]; - clk_writel((clk_readl(clock->reg) & mask) | - (hw_index << clock->src_shift), clock->reg); + writel((readl(clock->reg) & mask) | (hw_index << clock->src_shift), + clock->reg); return 0; } @@ -241,7 +241,7 @@ struct clk * __init cpg_div6_register(const char *name, * Read the divisor. Disabling the clock overwrites the divisor, so we * need to cache its value for the enable operation. */ - clock->div = (clk_readl(clock->reg) & CPG_DIV6_DIV_MASK) + 1; + clock->div = (readl(clock->reg) & CPG_DIV6_DIV_MASK) + 1; switch (num_parents) { case 1: -- cgit From 8027519840653520c256cb5e7768b60af3bc895e Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 15 Mar 2018 10:43:37 +0100 Subject: clk: renesas: mstp: Always use readl()/writel() On arm32, there is no reason to use the (soon deprecated) clk_readl()/clk_writel(). Hence use the generic readl()/writel() instead. Signed-off-by: Geert Uytterhoeven Reviewed-by: Simon Horman --- drivers/clk/renesas/clk-mstp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/clk/renesas/clk-mstp.c b/drivers/clk/renesas/clk-mstp.c index 858c24d4da8f..e82adcb16a52 100644 --- a/drivers/clk/renesas/clk-mstp.c +++ b/drivers/clk/renesas/clk-mstp.c @@ -64,13 +64,13 @@ struct mstp_clock { static inline u32 cpg_mstp_read(struct mstp_clock_group *group, u32 __iomem *reg) { - return group->width_8bit ? readb(reg) : clk_readl(reg); + return group->width_8bit ? readb(reg) : readl(reg); } static inline void cpg_mstp_write(struct mstp_clock_group *group, u32 val, u32 __iomem *reg) { - group->width_8bit ? writeb(val, reg) : clk_writel(val, reg); + group->width_8bit ? writeb(val, reg) : writel(val, reg); } static int cpg_mstp_clock_endisable(struct clk_hw *hw, bool enable) -- cgit From b86b493eb29120b82ba919e2653c863c0b3804d6 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 15 Mar 2018 10:43:47 +0100 Subject: clk: renesas: r8a73a4: Always use readl()/writel() On arm32, there is no reason to use the (soon deprecated) clk_readl()/clk_writel(). Hence use the generic readl()/writel() instead. Signed-off-by: Geert Uytterhoeven Reviewed-by: Simon Horman --- drivers/clk/renesas/clk-r8a73a4.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/clk/renesas/clk-r8a73a4.c b/drivers/clk/renesas/clk-r8a73a4.c index 28d204bb659e..7b903ce4c901 100644 --- a/drivers/clk/renesas/clk-r8a73a4.c +++ b/drivers/clk/renesas/clk-r8a73a4.c @@ -71,7 +71,7 @@ r8a73a4_cpg_register_clock(struct device_node *np, struct r8a73a4_cpg *cpg, if (!strcmp(name, "main")) { - u32 ckscr = clk_readl(cpg->reg + CPG_CKSCR); + u32 ckscr = readl(cpg->reg + CPG_CKSCR); switch ((ckscr >> 28) & 3) { case 0: /* extal1 */ @@ -95,14 +95,14 @@ r8a73a4_cpg_register_clock(struct device_node *np, struct r8a73a4_cpg *cpg, * clock implementation and we currently have no need to change * the multiplier value. */ - u32 value = clk_readl(cpg->reg + CPG_PLL0CR); + u32 value = readl(cpg->reg + CPG_PLL0CR); parent_name = "main"; mult = ((value >> 24) & 0x7f) + 1; if (value & BIT(20)) div = 2; } else if (!strcmp(name, "pll1")) { - u32 value = clk_readl(cpg->reg + CPG_PLL1CR); + u32 value = readl(cpg->reg + CPG_PLL1CR); parent_name = "main"; /* XXX: enable bit? */ @@ -125,7 +125,7 @@ r8a73a4_cpg_register_clock(struct device_node *np, struct r8a73a4_cpg *cpg, default: return ERR_PTR(-EINVAL); } - value = clk_readl(cpg->reg + cr); + value = readl(cpg->reg + cr); switch ((value >> 5) & 7) { case 0: parent_name = "main"; @@ -161,8 +161,7 @@ r8a73a4_cpg_register_clock(struct device_node *np, struct r8a73a4_cpg *cpg, shift = 0; } div *= 32; - mult = 0x20 - ((clk_readl(cpg->reg + CPG_FRQCRC) >> shift) - & 0x1f); + mult = 0x20 - ((readl(cpg->reg + CPG_FRQCRC) >> shift) & 0x1f); } else { struct div4_clk *c; -- cgit From f32b0696eabd7a9dc6efd6a97448742d5f2a7db0 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 15 Mar 2018 10:43:57 +0100 Subject: clk: renesas: r8a7740: Always use readl()/writel() On arm32, there is no reason to use the (soon deprecated) clk_readl()/clk_writel(). Hence use the generic readl()/writel() instead. Signed-off-by: Geert Uytterhoeven Reviewed-by: Simon Horman --- drivers/clk/renesas/clk-r8a7740.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/clk/renesas/clk-r8a7740.c b/drivers/clk/renesas/clk-r8a7740.c index 2f7ce6696b6c..d074f8e982d0 100644 --- a/drivers/clk/renesas/clk-r8a7740.c +++ b/drivers/clk/renesas/clk-r8a7740.c @@ -98,20 +98,20 @@ r8a7740_cpg_register_clock(struct device_node *np, struct r8a7740_cpg *cpg, * clock implementation and we currently have no need to change * the multiplier value. */ - u32 value = clk_readl(cpg->reg + CPG_FRQCRC); + u32 value = readl(cpg->reg + CPG_FRQCRC); parent_name = "system"; mult = ((value >> 24) & 0x7f) + 1; } else if (!strcmp(name, "pllc1")) { - u32 value = clk_readl(cpg->reg + CPG_FRQCRA); + u32 value = readl(cpg->reg + CPG_FRQCRA); parent_name = "system"; mult = ((value >> 24) & 0x7f) + 1; div = 2; } else if (!strcmp(name, "pllc2")) { - u32 value = clk_readl(cpg->reg + CPG_PLLC2CR); + u32 value = readl(cpg->reg + CPG_PLLC2CR); parent_name = "system"; mult = ((value >> 24) & 0x3f) + 1; } else if (!strcmp(name, "usb24s")) { - u32 value = clk_readl(cpg->reg + CPG_USBCKCR); + u32 value = readl(cpg->reg + CPG_USBCKCR); if (value & BIT(7)) /* extal2 */ parent_name = of_clk_get_parent_name(np, 1); -- cgit From 6c669e504a62641fd7189df13ef57d182373e36f Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 15 Mar 2018 10:44:09 +0100 Subject: clk: renesas: rcar-gen2: Always use readl()/writel() On arm32, there is no reason to use the (soon deprecated) clk_readl()/clk_writel(). Hence use the generic readl()/writel() instead. Signed-off-by: Geert Uytterhoeven Reviewed-by: Simon Horman --- drivers/clk/renesas/clk-rcar-gen2.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/drivers/clk/renesas/clk-rcar-gen2.c b/drivers/clk/renesas/clk-rcar-gen2.c index d14cbe1ca29a..ee32a022e6da 100644 --- a/drivers/clk/renesas/clk-rcar-gen2.c +++ b/drivers/clk/renesas/clk-rcar-gen2.c @@ -62,8 +62,7 @@ static unsigned long cpg_z_clk_recalc_rate(struct clk_hw *hw, unsigned int mult; unsigned int val; - val = (clk_readl(zclk->reg) & CPG_FRQCRC_ZFC_MASK) - >> CPG_FRQCRC_ZFC_SHIFT; + val = (readl(zclk->reg) & CPG_FRQCRC_ZFC_MASK) >> CPG_FRQCRC_ZFC_SHIFT; mult = 32 - val; return div_u64((u64)parent_rate * mult, 32); @@ -95,21 +94,21 @@ static int cpg_z_clk_set_rate(struct clk_hw *hw, unsigned long rate, mult = div_u64((u64)rate * 32, parent_rate); mult = clamp(mult, 1U, 32U); - if (clk_readl(zclk->kick_reg) & CPG_FRQCRB_KICK) + if (readl(zclk->kick_reg) & CPG_FRQCRB_KICK) return -EBUSY; - val = clk_readl(zclk->reg); + val = readl(zclk->reg); val &= ~CPG_FRQCRC_ZFC_MASK; val |= (32 - mult) << CPG_FRQCRC_ZFC_SHIFT; - clk_writel(val, zclk->reg); + writel(val, zclk->reg); /* * Set KICK bit in FRQCRB to update hardware setting and wait for * clock change completion. */ - kick = clk_readl(zclk->kick_reg); + kick = readl(zclk->kick_reg); kick |= CPG_FRQCRB_KICK; - clk_writel(kick, zclk->kick_reg); + writel(kick, zclk->kick_reg); /* * Note: There is no HW information about the worst case latency. @@ -121,7 +120,7 @@ static int cpg_z_clk_set_rate(struct clk_hw *hw, unsigned long rate, * "super" safe value. */ for (i = 1000; i; i--) { - if (!(clk_readl(zclk->kick_reg) & CPG_FRQCRB_KICK)) + if (!(readl(zclk->kick_reg) & CPG_FRQCRB_KICK)) return 0; cpu_relax(); @@ -332,7 +331,7 @@ rcar_gen2_cpg_register_clock(struct device_node *np, struct rcar_gen2_cpg *cpg, mult = config->pll0_mult; div = 3; } else { - u32 value = clk_readl(cpg->reg + CPG_PLL0CR); + u32 value = readl(cpg->reg + CPG_PLL0CR); mult = ((value >> 24) & ((1 << 7) - 1)) + 1; } parent_name = "main"; -- cgit From fcf371b3517771589819ffefe2aa16b31f0b0a63 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 15 Mar 2018 10:44:19 +0100 Subject: clk: renesas: rza1: Always use readl()/writel() On arm32, there is no reason to use the (soon deprecated) clk_readl()/clk_writel(). Hence use the generic readl()/writel() instead. Signed-off-by: Geert Uytterhoeven Reviewed-by: Simon Horman --- drivers/clk/renesas/clk-rz.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/clk/renesas/clk-rz.c b/drivers/clk/renesas/clk-rz.c index 127c58135c8f..67dd712aa723 100644 --- a/drivers/clk/renesas/clk-rz.c +++ b/drivers/clk/renesas/clk-rz.c @@ -75,9 +75,9 @@ rz_cpg_register_clock(struct device_node *np, struct rz_cpg *cpg, const char *na * let them run at fixed current speed and implement the details later. */ if (strcmp(name, "i") == 0) - val = (clk_readl(cpg->reg + CPG_FRQCR) >> 8) & 3; + val = (readl(cpg->reg + CPG_FRQCR) >> 8) & 3; else if (strcmp(name, "g") == 0) - val = clk_readl(cpg->reg + CPG_FRQCR2) & 3; + val = readl(cpg->reg + CPG_FRQCR2) & 3; else return ERR_PTR(-EINVAL); -- cgit From f046d6a6bf2a1f0db5e2f61b5236efb1b6bebfde Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 15 Mar 2018 10:44:30 +0100 Subject: clk: renesas: sh73a0: Always use readl()/writel() On arm32, there is no reason to use the (soon deprecated) clk_readl()/clk_writel(). Hence use the generic readl()/writel() instead. Signed-off-by: Geert Uytterhoeven Reviewed-by: Simon Horman --- drivers/clk/renesas/clk-sh73a0.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/clk/renesas/clk-sh73a0.c b/drivers/clk/renesas/clk-sh73a0.c index eea38f6ea77e..6cfa6b519041 100644 --- a/drivers/clk/renesas/clk-sh73a0.c +++ b/drivers/clk/renesas/clk-sh73a0.c @@ -85,7 +85,7 @@ sh73a0_cpg_register_clock(struct device_node *np, struct sh73a0_cpg *cpg, if (!strcmp(name, "main")) { /* extal1, extal1_div2, extal2, extal2_div2 */ - u32 parent_idx = (clk_readl(cpg->reg + CPG_CKSCR) >> 28) & 3; + u32 parent_idx = (readl(cpg->reg + CPG_CKSCR) >> 28) & 3; parent_name = of_clk_get_parent_name(np, parent_idx >> 1); div = (parent_idx & 1) + 1; @@ -110,11 +110,11 @@ sh73a0_cpg_register_clock(struct device_node *np, struct sh73a0_cpg *cpg, default: return ERR_PTR(-EINVAL); } - if (clk_readl(cpg->reg + CPG_PLLECR) & BIT(enable_bit)) { - mult = ((clk_readl(enable_reg) >> 24) & 0x3f) + 1; + if (readl(cpg->reg + CPG_PLLECR) & BIT(enable_bit)) { + mult = ((readl(enable_reg) >> 24) & 0x3f) + 1; /* handle CFG bit for PLL1 and PLL2 */ if (enable_bit == 1 || enable_bit == 2) - if (clk_readl(enable_reg) & BIT(20)) + if (readl(enable_reg) & BIT(20)) mult *= 2; } } else if (!strcmp(name, "dsi0phy") || !strcmp(name, "dsi1phy")) { @@ -193,9 +193,9 @@ static void __init sh73a0_cpg_clocks_init(struct device_node *np) return; /* Set SDHI clocks to a known state */ - clk_writel(0x108, cpg->reg + CPG_SD0CKCR); - clk_writel(0x108, cpg->reg + CPG_SD1CKCR); - clk_writel(0x108, cpg->reg + CPG_SD2CKCR); + writel(0x108, cpg->reg + CPG_SD0CKCR); + writel(0x108, cpg->reg + CPG_SD1CKCR); + writel(0x108, cpg->reg + CPG_SD2CKCR); for (i = 0; i < num_clks; ++i) { const char *name; -- cgit From 2b935d524d851830b68dd8c58d3098d775d6047a Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 15 Mar 2018 10:44:37 +0100 Subject: clk: renesas: rcar-gen3: Always use readl()/writel() The R-Car Gen3 CPG/MSSR driver (again) uses a mix of clk_readl()/clk_writel() and readl()/writel() to access the clock registers. Settle on the generic readl()/writel(). Cfr. commit 30ad3cf00e94f4a7 ("clk: renesas: rcar-gen3-cpg: Always use readl()/writel()"). Signed-off-by: Geert Uytterhoeven Reviewed-by: Simon Horman --- drivers/clk/renesas/rcar-gen3-cpg.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/clk/renesas/rcar-gen3-cpg.c b/drivers/clk/renesas/rcar-gen3-cpg.c index 0c8fe10d57fe..628b63b85d3f 100644 --- a/drivers/clk/renesas/rcar-gen3-cpg.c +++ b/drivers/clk/renesas/rcar-gen3-cpg.c @@ -93,7 +93,7 @@ static unsigned long cpg_z_clk_recalc_rate(struct clk_hw *hw, unsigned int mult; u32 val; - val = clk_readl(zclk->reg) & zclk->mask; + val = readl(zclk->reg) & zclk->mask; mult = 32 - (val >> __ffs(zclk->mask)); /* Factor of 2 is for fixed divider */ @@ -125,20 +125,20 @@ static int cpg_z_clk_set_rate(struct clk_hw *hw, unsigned long rate, mult = DIV_ROUND_CLOSEST_ULL(rate * 32ULL * 2, parent_rate); mult = clamp(mult, 1U, 32U); - if (clk_readl(zclk->kick_reg) & CPG_FRQCRB_KICK) + if (readl(zclk->kick_reg) & CPG_FRQCRB_KICK) return -EBUSY; - val = clk_readl(zclk->reg) & ~zclk->mask; + val = readl(zclk->reg) & ~zclk->mask; val |= ((32 - mult) << __ffs(zclk->mask)) & zclk->mask; - clk_writel(val, zclk->reg); + writel(val, zclk->reg); /* * Set KICK bit in FRQCRB to update hardware setting and wait for * clock change completion. */ - kick = clk_readl(zclk->kick_reg); + kick = readl(zclk->kick_reg); kick |= CPG_FRQCRB_KICK; - clk_writel(kick, zclk->kick_reg); + writel(kick, zclk->kick_reg); /* * Note: There is no HW information about the worst case latency. @@ -150,7 +150,7 @@ static int cpg_z_clk_set_rate(struct clk_hw *hw, unsigned long rate, * "super" safe value. */ for (i = 1000; i; i--) { - if (!(clk_readl(zclk->kick_reg) & CPG_FRQCRB_KICK)) + if (!(readl(zclk->kick_reg) & CPG_FRQCRB_KICK)) return 0; cpu_relax(); -- cgit From 472f5f391819b4b22ec040f227aea26f515b6ae2 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Tue, 20 Mar 2018 16:40:16 +0900 Subject: clk: renesas: cpg-mssr: Adjust r8a77980 ifdef Adjust the R8A77980-specific #ifdefs to use CLK instead of ARCH to follow same style as other SoCs. Fixes: ce15783c510a9905 ("clk: renesas: cpg-mssr: add R8A77980 support") Signed-off-by: Magnus Damm Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/renesas-cpg-mssr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/renesas/renesas-cpg-mssr.c b/drivers/clk/renesas/renesas-cpg-mssr.c index 96c678799623..4e88e980fb76 100644 --- a/drivers/clk/renesas/renesas-cpg-mssr.c +++ b/drivers/clk/renesas/renesas-cpg-mssr.c @@ -705,7 +705,7 @@ static const struct of_device_id cpg_mssr_match[] = { .data = &r8a77970_cpg_mssr_info, }, #endif -#ifdef CONFIG_ARCH_R8A77980 +#ifdef CONFIG_CLK_R8A77980 { .compatible = "renesas,r8a77980-cpg-mssr", .data = &r8a77980_cpg_mssr_info, -- cgit From 4b0556a441dd37e598887215bc89b49a6ef525b3 Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Wed, 21 Mar 2018 10:39:19 +0800 Subject: clk: rockchip: Fix wrong parent for SDMMC phase clock for rk3228 commit c420c1e4db22 ("clk: rockchip: Prevent calculating mmc phase if clock rate is zero") catches one gremlin again for clk-rk3228.c that the parent of SDMMC phase clock should be sclk_sdmmc0, but not sclk_sdmmc. However, the naming of the sdmmc clocks varies in the manual with the card clock having the 0 while the hclk is named without appended 0. So standardize one one format to prevent confusion, as there also is only one (non-sdio) mmc controller on the soc. Signed-off-by: Shawn Lin Signed-off-by: Heiko Stuebner --- drivers/clk/rockchip/clk-rk3228.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/rockchip/clk-rk3228.c b/drivers/clk/rockchip/clk-rk3228.c index 11e7f2d1c054..7af48184b022 100644 --- a/drivers/clk/rockchip/clk-rk3228.c +++ b/drivers/clk/rockchip/clk-rk3228.c @@ -387,7 +387,7 @@ static struct rockchip_clk_branch rk3228_clk_branches[] __initdata = { RK2928_CLKSEL_CON(23), 5, 2, MFLAGS, 0, 6, DFLAGS, RK2928_CLKGATE_CON(2), 15, GFLAGS), - COMPOSITE(SCLK_SDMMC, "sclk_sdmmc0", mux_mmc_src_p, 0, + COMPOSITE(SCLK_SDMMC, "sclk_sdmmc", mux_mmc_src_p, 0, RK2928_CLKSEL_CON(11), 8, 2, MFLAGS, 0, 8, DFLAGS, RK2928_CLKGATE_CON(2), 11, GFLAGS), -- cgit From ce84eca927af24ca27897ba5fee4fbeed443d5fc Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Wed, 21 Mar 2018 10:39:18 +0800 Subject: clk: rockchip: Fix wrong parents for MMC phase clock for rk3328 commit c420c1e4db22 ("clk: rockchip: Prevent calculating mmc phase if clock rate is zero") catches some gremlins for clk-rk3328.c that the parents of MMC phase clock should be clk_{sdmmc, sdio, emmc}, but not sclk_{sdmmc, sdio, emmc}. Signed-off-by: Shawn Lin Signed-off-by: Heiko Stuebner --- drivers/clk/rockchip/clk-rk3328.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/clk/rockchip/clk-rk3328.c b/drivers/clk/rockchip/clk-rk3328.c index f680b421b6d5..252366a5231f 100644 --- a/drivers/clk/rockchip/clk-rk3328.c +++ b/drivers/clk/rockchip/clk-rk3328.c @@ -810,24 +810,24 @@ static struct rockchip_clk_branch rk3328_clk_branches[] __initdata = { GATE(0, "pclk_phy_niu", "pclk_phy_pre", 0, RK3328_CLKGATE_CON(15), 15, GFLAGS), /* PD_MMC */ - MMC(SCLK_SDMMC_DRV, "sdmmc_drv", "sclk_sdmmc", + MMC(SCLK_SDMMC_DRV, "sdmmc_drv", "clk_sdmmc", RK3328_SDMMC_CON0, 1), - MMC(SCLK_SDMMC_SAMPLE, "sdmmc_sample", "sclk_sdmmc", + MMC(SCLK_SDMMC_SAMPLE, "sdmmc_sample", "clk_sdmmc", RK3328_SDMMC_CON1, 1), - MMC(SCLK_SDIO_DRV, "sdio_drv", "sclk_sdio", + MMC(SCLK_SDIO_DRV, "sdio_drv", "clk_sdio", RK3328_SDIO_CON0, 1), - MMC(SCLK_SDIO_SAMPLE, "sdio_sample", "sclk_sdio", + MMC(SCLK_SDIO_SAMPLE, "sdio_sample", "clk_sdio", RK3328_SDIO_CON1, 1), - MMC(SCLK_EMMC_DRV, "emmc_drv", "sclk_emmc", + MMC(SCLK_EMMC_DRV, "emmc_drv", "clk_emmc", RK3328_EMMC_CON0, 1), - MMC(SCLK_EMMC_SAMPLE, "emmc_sample", "sclk_emmc", + MMC(SCLK_EMMC_SAMPLE, "emmc_sample", "clk_emmc", RK3328_EMMC_CON1, 1), - MMC(SCLK_SDMMC_EXT_DRV, "sdmmc_ext_drv", "sclk_sdmmc_ext", + MMC(SCLK_SDMMC_EXT_DRV, "sdmmc_ext_drv", "clk_sdmmc_ext", RK3328_SDMMC_EXT_CON0, 1), - MMC(SCLK_SDMMC_EXT_SAMPLE, "sdmmc_ext_sample", "sclk_sdmmc_ext", + MMC(SCLK_SDMMC_EXT_SAMPLE, "sdmmc_ext_sample", "clk_sdmmc_ext", RK3328_SDMMC_EXT_CON1, 1), }; -- cgit From 570fda972b3178f9a981d1b7ac18e05245a52eab Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Wed, 21 Mar 2018 10:39:20 +0800 Subject: clk: rockchip: Correct the behaviour of restoring cached phase We can't restore every phase, for instance the invalid phase and the phase for coming rate which is out of the scope of boards' ability. And this patch also corrects the error path to return invalid pointer to clk if clk_notifier_register failed introduced by the same offending commit. Fixes: 60cf09e45fbc ("clk: rockchip: Restore the clock phase after the rate was changed") Reported-by: wlq Signed-off-by: Shawn Lin Tested-by: wlq Signed-off-by: Heiko Stuebner --- drivers/clk/rockchip/clk-mmc-phase.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/drivers/clk/rockchip/clk-mmc-phase.c b/drivers/clk/rockchip/clk-mmc-phase.c index dc4c227732bd..b7b9f2e7d64b 100644 --- a/drivers/clk/rockchip/clk-mmc-phase.c +++ b/drivers/clk/rockchip/clk-mmc-phase.c @@ -170,18 +170,30 @@ static int rockchip_mmc_clk_rate_notify(struct notifier_block *nb, unsigned long event, void *data) { struct rockchip_mmc_clock *mmc_clock = to_rockchip_mmc_clock(nb); + struct clk_notifier_data *ndata = data; /* * rockchip_mmc_clk is mostly used by mmc controllers to sample * the intput data, which expects the fixed phase after the tuning * process. However if the clock rate is changed, the phase is stale * and may break the data sampling. So here we try to restore the phase - * for that case. + * for that case, except that + * (1) cached_phase is invaild since we inevitably cached it when the + * clock provider be reparented from orphan to its real parent in the + * first place. Otherwise we may mess up the initialization of MMC cards + * since we only set the default sample phase and drive phase later on. + * (2) the new coming rate is higher than the older one since mmc driver + * set the max-frequency to match the boards' ability but we can't go + * over the heads of that, otherwise the tests smoke out the issue. */ + if (ndata->old_rate <= ndata->new_rate) + return NOTIFY_DONE; + if (event == PRE_RATE_CHANGE) mmc_clock->cached_phase = rockchip_mmc_get_phase(&mmc_clock->hw); - else if (event == POST_RATE_CHANGE) + else if (mmc_clock->cached_phase != -EINVAL && + event == POST_RATE_CHANGE) rockchip_mmc_set_phase(&mmc_clock->hw, mmc_clock->cached_phase); return NOTIFY_DONE; -- cgit From 0d92d1802ced45dab0cbb1d130ace7410bcaec99 Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Wed, 21 Mar 2018 10:39:20 +0800 Subject: clk: rockchip: Fix error return in phase clock registration The newly added clock notifier may return an error code but so far the error output in the function would only return an error pointer from registering the clock. So when the clock notifier fails the clock would be unregistered but the return would still be the clock pointer which could then not be dereferenced correctly. So fix the error handling to prevent that. Fixes: 60cf09e45fbc ("clk: rockchip: Restore the clock phase after the rate was changed") Signed-off-by: Shawn Lin Signed-off-by: Heiko Stuebner --- drivers/clk/rockchip/clk-mmc-phase.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/clk/rockchip/clk-mmc-phase.c b/drivers/clk/rockchip/clk-mmc-phase.c index b7b9f2e7d64b..026a26bb702d 100644 --- a/drivers/clk/rockchip/clk-mmc-phase.c +++ b/drivers/clk/rockchip/clk-mmc-phase.c @@ -223,8 +223,10 @@ struct clk *rockchip_clk_register_mmc(const char *name, mmc_clock->shift = shift; clk = clk_register(NULL, &mmc_clock->hw); - if (IS_ERR(clk)) + if (IS_ERR(clk)) { + ret = PTR_ERR(clk); goto err_register; + } mmc_clock->clk_rate_change_nb.notifier_call = &rockchip_mmc_clk_rate_notify; @@ -237,5 +239,5 @@ err_notifier: clk_unregister(clk); err_register: kfree(mmc_clock); - return clk; + return ERR_PTR(ret); } -- cgit From 9dc486fdf6cc0d7f635954810ab119c5db2cbb60 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Tue, 20 Mar 2018 10:06:28 +0800 Subject: clk: rockchip: assign correct id for pclk_ddr and hclk_sd in rk3399 Since hclk_sd and pclk_ddr source clock from CPLL or GPLL, and these two PLL may change their frequency. If we do not assign right id to pclk_ddr and hclk_sd, they will alway use default cur register value, and may get the frequency exceed their signed off frequency. So assign correct Id for them, then we can assign frequency for them in dts. Signed-off-by: Lin Huang Reviewed-by: Douglas Anderson Reviewed-by: Shawn Lin Signed-off-by: Heiko Stuebner --- drivers/clk/rockchip/clk-rk3399.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/clk/rockchip/clk-rk3399.c b/drivers/clk/rockchip/clk-rk3399.c index 3e57c6eef93d..bca10d618f0a 100644 --- a/drivers/clk/rockchip/clk-rk3399.c +++ b/drivers/clk/rockchip/clk-rk3399.c @@ -671,7 +671,7 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = { RK3399_CLKGATE_CON(9), 7, GFLAGS, &rk3399_uart3_fracmux), - COMPOSITE(0, "pclk_ddr", mux_pll_src_cpll_gpll_p, CLK_IGNORE_UNUSED, + COMPOSITE(PCLK_DDR, "pclk_ddr", mux_pll_src_cpll_gpll_p, CLK_IGNORE_UNUSED, RK3399_CLKSEL_CON(6), 15, 1, MFLAGS, 8, 5, DFLAGS, RK3399_CLKGATE_CON(3), 4, GFLAGS), @@ -887,7 +887,7 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = { RK3399_CLKGATE_CON(31), 8, GFLAGS), /* sdio & sdmmc */ - COMPOSITE(0, "hclk_sd", mux_pll_src_cpll_gpll_p, 0, + COMPOSITE(HCLK_SD, "hclk_sd", mux_pll_src_cpll_gpll_p, 0, RK3399_CLKSEL_CON(13), 15, 1, MFLAGS, 8, 5, DFLAGS, RK3399_CLKGATE_CON(12), 13, GFLAGS), GATE(HCLK_SDMMC, "hclk_sdmmc", "hclk_sd", 0, -- cgit From 726fef09b8018e58f1930fc7bc0a46e8d12ed8c1 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 22 Mar 2018 11:16:18 +0100 Subject: clk: ux500: Drop AB8540/9540 support The AB8540 was an evolved version of the AB8500, but it was never mass produced or put into products, only reference designs exist. The upstream support was never completed and it is unlikely that this will happen so drop the support for now to simplify maintenance of the AB8500. Cc: Loic Pallardy Signed-off-by: Linus Walleij Acked-by: Ulf Hansson Signed-off-by: Stephen Boyd --- drivers/clk/ux500/Makefile | 2 - drivers/clk/ux500/abx500-clk.c | 16 -- drivers/clk/ux500/u8540_clk.c | 597 ----------------------------------------- drivers/clk/ux500/u9540_clk.c | 18 -- 4 files changed, 633 deletions(-) delete mode 100644 drivers/clk/ux500/u8540_clk.c delete mode 100644 drivers/clk/ux500/u9540_clk.c diff --git a/drivers/clk/ux500/Makefile b/drivers/clk/ux500/Makefile index fedc083dc8be..53fd29002401 100644 --- a/drivers/clk/ux500/Makefile +++ b/drivers/clk/ux500/Makefile @@ -10,8 +10,6 @@ obj-y += clk-sysctrl.o # Clock definitions obj-y += u8500_of_clk.o -obj-y += u9540_clk.o -obj-y += u8540_clk.o # ABX500 clock driver obj-y += abx500-clk.o diff --git a/drivers/clk/ux500/abx500-clk.c b/drivers/clk/ux500/abx500-clk.c index 2257d12ba988..5a86cd8fe5de 100644 --- a/drivers/clk/ux500/abx500-clk.c +++ b/drivers/clk/ux500/abx500-clk.c @@ -88,18 +88,6 @@ static int ab8500_reg_clks(struct device *dev) return 0; } -/* Clock definitions for ab8540 */ -static int ab8540_reg_clks(struct device *dev) -{ - return 0; -} - -/* Clock definitions for ab9540 */ -static int ab9540_reg_clks(struct device *dev) -{ - return 0; -} - static int abx500_clk_probe(struct platform_device *pdev) { struct ab8500 *parent = dev_get_drvdata(pdev->dev.parent); @@ -107,10 +95,6 @@ static int abx500_clk_probe(struct platform_device *pdev) if (is_ab8500(parent) || is_ab8505(parent)) { ret = ab8500_reg_clks(&pdev->dev); - } else if (is_ab8540(parent)) { - ret = ab8540_reg_clks(&pdev->dev); - } else if (is_ab9540(parent)) { - ret = ab9540_reg_clks(&pdev->dev); } else { dev_err(&pdev->dev, "non supported plf id\n"); return -ENODEV; diff --git a/drivers/clk/ux500/u8540_clk.c b/drivers/clk/ux500/u8540_clk.c deleted file mode 100644 index 133859f0e2bf..000000000000 --- a/drivers/clk/ux500/u8540_clk.c +++ /dev/null @@ -1,597 +0,0 @@ -/* - * Clock definitions for u8540 platform. - * - * Copyright (C) 2012 ST-Ericsson SA - * Author: Ulf Hansson - * - * License terms: GNU General Public License (GPL) version 2 - */ - -#include -#include -#include -#include -#include -#include "clk.h" - -/* CLKRST4 is missing making it hard to index things */ -enum clkrst_index { - CLKRST1_INDEX = 0, - CLKRST2_INDEX, - CLKRST3_INDEX, - CLKRST5_INDEX, - CLKRST6_INDEX, - CLKRST_MAX, -}; - -static void u8540_clk_init(struct device_node *np) -{ - struct clk *clk; - u32 bases[CLKRST_MAX]; - int i; - - for (i = 0; i < ARRAY_SIZE(bases); i++) { - struct resource r; - - if (of_address_to_resource(np, i, &r)) - /* Not much choice but to continue */ - pr_err("failed to get CLKRST %d base address\n", - i + 1); - bases[i] = r.start; - } - - /* Clock sources. */ - /* Fixed ClockGen */ - clk = clk_reg_prcmu_gate("soc0_pll", NULL, PRCMU_PLLSOC0, - CLK_IGNORE_UNUSED); - clk_register_clkdev(clk, "soc0_pll", NULL); - - clk = clk_reg_prcmu_gate("soc1_pll", NULL, PRCMU_PLLSOC1, - CLK_IGNORE_UNUSED); - clk_register_clkdev(clk, "soc1_pll", NULL); - - clk = clk_reg_prcmu_gate("ddr_pll", NULL, PRCMU_PLLDDR, - CLK_IGNORE_UNUSED); - clk_register_clkdev(clk, "ddr_pll", NULL); - - clk = clk_register_fixed_rate(NULL, "rtc32k", NULL, - CLK_IGNORE_UNUSED, - 32768); - clk_register_clkdev(clk, "clk32k", NULL); - clk_register_clkdev(clk, "apb_pclk", "rtc-pl031"); - - clk = clk_register_fixed_rate(NULL, "ulp38m4", NULL, - CLK_IGNORE_UNUSED, - 38400000); - - clk = clk_reg_prcmu_gate("uartclk", NULL, PRCMU_UARTCLK, 0); - clk_register_clkdev(clk, NULL, "UART"); - - /* msp02clk needs a abx500 clk as parent. Handle by abx500 clk driver */ - clk = clk_reg_prcmu_gate("msp02clk", "ab9540_sysclk12_b1", - PRCMU_MSP02CLK, 0); - clk_register_clkdev(clk, NULL, "MSP02"); - - clk = clk_reg_prcmu_gate("msp1clk", NULL, PRCMU_MSP1CLK, 0); - clk_register_clkdev(clk, NULL, "MSP1"); - - clk = clk_reg_prcmu_gate("i2cclk", NULL, PRCMU_I2CCLK, 0); - clk_register_clkdev(clk, NULL, "I2C"); - - clk = clk_reg_prcmu_gate("slimclk", NULL, PRCMU_SLIMCLK, 0); - clk_register_clkdev(clk, NULL, "slim"); - - clk = clk_reg_prcmu_gate("per1clk", NULL, PRCMU_PER1CLK, 0); - clk_register_clkdev(clk, NULL, "PERIPH1"); - - clk = clk_reg_prcmu_gate("per2clk", NULL, PRCMU_PER2CLK, 0); - clk_register_clkdev(clk, NULL, "PERIPH2"); - - clk = clk_reg_prcmu_gate("per3clk", NULL, PRCMU_PER3CLK, 0); - clk_register_clkdev(clk, NULL, "PERIPH3"); - - clk = clk_reg_prcmu_gate("per5clk", NULL, PRCMU_PER5CLK, 0); - clk_register_clkdev(clk, NULL, "PERIPH5"); - - clk = clk_reg_prcmu_gate("per6clk", NULL, PRCMU_PER6CLK, 0); - clk_register_clkdev(clk, NULL, "PERIPH6"); - - clk = clk_reg_prcmu_gate("per7clk", NULL, PRCMU_PER7CLK, 0); - clk_register_clkdev(clk, NULL, "PERIPH7"); - - clk = clk_reg_prcmu_scalable("lcdclk", NULL, PRCMU_LCDCLK, 0, - CLK_SET_RATE_GATE); - clk_register_clkdev(clk, NULL, "lcd"); - clk_register_clkdev(clk, "lcd", "mcde"); - - clk = clk_reg_prcmu_opp_gate("bmlclk", NULL, PRCMU_BMLCLK, 0); - clk_register_clkdev(clk, NULL, "bml"); - - clk = clk_reg_prcmu_scalable("hsitxclk", NULL, PRCMU_HSITXCLK, 0, - CLK_SET_RATE_GATE); - - clk = clk_reg_prcmu_scalable("hsirxclk", NULL, PRCMU_HSIRXCLK, 0, - CLK_SET_RATE_GATE); - - clk = clk_reg_prcmu_scalable("hdmiclk", NULL, PRCMU_HDMICLK, 0, - CLK_SET_RATE_GATE); - clk_register_clkdev(clk, NULL, "hdmi"); - clk_register_clkdev(clk, "hdmi", "mcde"); - - clk = clk_reg_prcmu_gate("apeatclk", NULL, PRCMU_APEATCLK, 0); - clk_register_clkdev(clk, NULL, "apeat"); - - clk = clk_reg_prcmu_gate("apetraceclk", NULL, PRCMU_APETRACECLK, 0); - clk_register_clkdev(clk, NULL, "apetrace"); - - clk = clk_reg_prcmu_gate("mcdeclk", NULL, PRCMU_MCDECLK, 0); - clk_register_clkdev(clk, NULL, "mcde"); - clk_register_clkdev(clk, "mcde", "mcde"); - clk_register_clkdev(clk, NULL, "dsilink.0"); - clk_register_clkdev(clk, NULL, "dsilink.1"); - clk_register_clkdev(clk, NULL, "dsilink.2"); - - clk = clk_reg_prcmu_opp_gate("ipi2cclk", NULL, PRCMU_IPI2CCLK, 0); - clk_register_clkdev(clk, NULL, "ipi2"); - - clk = clk_reg_prcmu_gate("dsialtclk", NULL, PRCMU_DSIALTCLK, 0); - clk_register_clkdev(clk, NULL, "dsialt"); - - clk = clk_reg_prcmu_gate("dmaclk", NULL, PRCMU_DMACLK, 0); - clk_register_clkdev(clk, NULL, "dma40.0"); - - clk = clk_reg_prcmu_gate("b2r2clk", NULL, PRCMU_B2R2CLK, 0); - clk_register_clkdev(clk, NULL, "b2r2"); - clk_register_clkdev(clk, NULL, "b2r2_core"); - clk_register_clkdev(clk, NULL, "U8500-B2R2.0"); - clk_register_clkdev(clk, NULL, "b2r2_1_core"); - - clk = clk_reg_prcmu_scalable("tvclk", NULL, PRCMU_TVCLK, 0, - CLK_SET_RATE_GATE); - clk_register_clkdev(clk, NULL, "tv"); - clk_register_clkdev(clk, "tv", "mcde"); - - clk = clk_reg_prcmu_gate("sspclk", NULL, PRCMU_SSPCLK, 0); - clk_register_clkdev(clk, NULL, "SSP"); - - clk = clk_reg_prcmu_gate("rngclk", NULL, PRCMU_RNGCLK, 0); - clk_register_clkdev(clk, NULL, "rngclk"); - - clk = clk_reg_prcmu_gate("uiccclk", NULL, PRCMU_UICCCLK, 0); - clk_register_clkdev(clk, NULL, "uicc"); - - clk = clk_reg_prcmu_gate("timclk", NULL, PRCMU_TIMCLK, 0); - clk_register_clkdev(clk, NULL, "mtu0"); - clk_register_clkdev(clk, NULL, "mtu1"); - - clk = clk_reg_prcmu_opp_volt_scalable("sdmmcclk", NULL, - PRCMU_SDMMCCLK, 100000000, - CLK_SET_RATE_GATE); - clk_register_clkdev(clk, NULL, "sdmmc"); - - clk = clk_reg_prcmu_opp_volt_scalable("sdmmchclk", NULL, - PRCMU_SDMMCHCLK, 400000000, - CLK_SET_RATE_GATE); - clk_register_clkdev(clk, NULL, "sdmmchclk"); - - clk = clk_reg_prcmu_gate("hvaclk", NULL, PRCMU_HVACLK, 0); - clk_register_clkdev(clk, NULL, "hva"); - - clk = clk_reg_prcmu_gate("g1clk", NULL, PRCMU_G1CLK, 0); - clk_register_clkdev(clk, NULL, "g1"); - - clk = clk_reg_prcmu_scalable("spare1clk", NULL, PRCMU_SPARE1CLK, 0, - CLK_SET_RATE_GATE); - clk_register_clkdev(clk, "dsilcd", "mcde"); - - clk = clk_reg_prcmu_scalable("dsi_pll", "hdmiclk", - PRCMU_PLLDSI, 0, CLK_SET_RATE_GATE); - clk_register_clkdev(clk, "dsihs2", "mcde"); - clk_register_clkdev(clk, "hs_clk", "dsilink.2"); - - clk = clk_reg_prcmu_scalable("dsilcd_pll", "spare1clk", - PRCMU_PLLDSI_LCD, 0, CLK_SET_RATE_GATE); - clk_register_clkdev(clk, "dsilcd_pll", "mcde"); - - clk = clk_reg_prcmu_scalable("dsi0clk", "dsi_pll", - PRCMU_DSI0CLK, 0, CLK_SET_RATE_GATE); - clk_register_clkdev(clk, "dsihs0", "mcde"); - - clk = clk_reg_prcmu_scalable("dsi0lcdclk", "dsilcd_pll", - PRCMU_DSI0CLK_LCD, 0, CLK_SET_RATE_GATE); - clk_register_clkdev(clk, "dsihs0", "mcde"); - clk_register_clkdev(clk, "hs_clk", "dsilink.0"); - - clk = clk_reg_prcmu_scalable("dsi1clk", "dsi_pll", - PRCMU_DSI1CLK, 0, CLK_SET_RATE_GATE); - clk_register_clkdev(clk, "dsihs1", "mcde"); - - clk = clk_reg_prcmu_scalable("dsi1lcdclk", "dsilcd_pll", - PRCMU_DSI1CLK_LCD, 0, CLK_SET_RATE_GATE); - clk_register_clkdev(clk, "dsihs1", "mcde"); - clk_register_clkdev(clk, "hs_clk", "dsilink.1"); - - clk = clk_reg_prcmu_scalable("dsi0escclk", "tvclk", - PRCMU_DSI0ESCCLK, 0, CLK_SET_RATE_GATE); - clk_register_clkdev(clk, "lp_clk", "dsilink.0"); - clk_register_clkdev(clk, "dsilp0", "mcde"); - - clk = clk_reg_prcmu_scalable("dsi1escclk", "tvclk", - PRCMU_DSI1ESCCLK, 0, CLK_SET_RATE_GATE); - clk_register_clkdev(clk, "lp_clk", "dsilink.1"); - clk_register_clkdev(clk, "dsilp1", "mcde"); - - clk = clk_reg_prcmu_scalable("dsi2escclk", "tvclk", - PRCMU_DSI2ESCCLK, 0, CLK_SET_RATE_GATE); - clk_register_clkdev(clk, "lp_clk", "dsilink.2"); - clk_register_clkdev(clk, "dsilp2", "mcde"); - - clk = clk_reg_prcmu_scalable_rate("armss", NULL, - PRCMU_ARMSS, 0, CLK_IGNORE_UNUSED); - clk_register_clkdev(clk, "armss", NULL); - - clk = clk_register_fixed_factor(NULL, "smp_twd", "armss", - CLK_IGNORE_UNUSED, 1, 2); - clk_register_clkdev(clk, NULL, "smp_twd"); - - /* PRCC P-clocks */ - /* Peripheral 1 : PRCC P-clocks */ - clk = clk_reg_prcc_pclk("p1_pclk0", "per1clk", bases[CLKRST1_INDEX], - BIT(0), 0); - clk_register_clkdev(clk, "apb_pclk", "uart0"); - - clk = clk_reg_prcc_pclk("p1_pclk1", "per1clk", bases[CLKRST1_INDEX], - BIT(1), 0); - clk_register_clkdev(clk, "apb_pclk", "uart1"); - - clk = clk_reg_prcc_pclk("p1_pclk2", "per1clk", bases[CLKRST1_INDEX], - BIT(2), 0); - clk_register_clkdev(clk, "apb_pclk", "nmk-i2c.1"); - - clk = clk_reg_prcc_pclk("p1_pclk3", "per1clk", bases[CLKRST1_INDEX], - BIT(3), 0); - clk_register_clkdev(clk, "apb_pclk", "msp0"); - clk_register_clkdev(clk, "apb_pclk", "dbx5x0-msp-i2s.0"); - - clk = clk_reg_prcc_pclk("p1_pclk4", "per1clk", bases[CLKRST1_INDEX], - BIT(4), 0); - clk_register_clkdev(clk, "apb_pclk", "msp1"); - clk_register_clkdev(clk, "apb_pclk", "dbx5x0-msp-i2s.1"); - - clk = clk_reg_prcc_pclk("p1_pclk5", "per1clk", bases[CLKRST1_INDEX], - BIT(5), 0); - clk_register_clkdev(clk, "apb_pclk", "sdi0"); - - clk = clk_reg_prcc_pclk("p1_pclk6", "per1clk", bases[CLKRST1_INDEX], - BIT(6), 0); - clk_register_clkdev(clk, "apb_pclk", "nmk-i2c.2"); - - clk = clk_reg_prcc_pclk("p1_pclk7", "per1clk", bases[CLKRST1_INDEX], - BIT(7), 0); - clk_register_clkdev(clk, NULL, "spi3"); - - clk = clk_reg_prcc_pclk("p1_pclk8", "per1clk", bases[CLKRST1_INDEX], - BIT(8), 0); - clk_register_clkdev(clk, "apb_pclk", "slimbus0"); - - clk = clk_reg_prcc_pclk("p1_pclk9", "per1clk", bases[CLKRST1_INDEX], - BIT(9), 0); - clk_register_clkdev(clk, NULL, "gpio.0"); - clk_register_clkdev(clk, NULL, "gpio.1"); - clk_register_clkdev(clk, NULL, "gpioblock0"); - clk_register_clkdev(clk, "apb_pclk", "ab85xx-codec.0"); - - clk = clk_reg_prcc_pclk("p1_pclk10", "per1clk", bases[CLKRST1_INDEX], - BIT(10), 0); - clk_register_clkdev(clk, "apb_pclk", "nmk-i2c.4"); - - clk = clk_reg_prcc_pclk("p1_pclk11", "per1clk", bases[CLKRST1_INDEX], - BIT(11), 0); - clk_register_clkdev(clk, "apb_pclk", "msp3"); - clk_register_clkdev(clk, "apb_pclk", "dbx5x0-msp-i2s.3"); - - /* Peripheral 2 : PRCC P-clocks */ - clk = clk_reg_prcc_pclk("p2_pclk0", "per2clk", bases[CLKRST2_INDEX], - BIT(0), 0); - clk_register_clkdev(clk, "apb_pclk", "nmk-i2c.3"); - - clk = clk_reg_prcc_pclk("p2_pclk1", "per2clk", bases[CLKRST2_INDEX], - BIT(1), 0); - clk_register_clkdev(clk, NULL, "spi2"); - - clk = clk_reg_prcc_pclk("p2_pclk2", "per2clk", bases[CLKRST2_INDEX], - BIT(2), 0); - clk_register_clkdev(clk, NULL, "spi1"); - - clk = clk_reg_prcc_pclk("p2_pclk3", "per2clk", bases[CLKRST2_INDEX], - BIT(3), 0); - clk_register_clkdev(clk, NULL, "pwl"); - - clk = clk_reg_prcc_pclk("p2_pclk4", "per2clk", bases[CLKRST2_INDEX], - BIT(4), 0); - clk_register_clkdev(clk, "apb_pclk", "sdi4"); - - clk = clk_reg_prcc_pclk("p2_pclk5", "per2clk", bases[CLKRST2_INDEX], - BIT(5), 0); - clk_register_clkdev(clk, "apb_pclk", "msp2"); - clk_register_clkdev(clk, "apb_pclk", "dbx5x0-msp-i2s.2"); - - clk = clk_reg_prcc_pclk("p2_pclk6", "per2clk", bases[CLKRST2_INDEX], - BIT(6), 0); - clk_register_clkdev(clk, "apb_pclk", "sdi1"); - - clk = clk_reg_prcc_pclk("p2_pclk7", "per2clk", bases[CLKRST2_INDEX], - BIT(7), 0); - clk_register_clkdev(clk, "apb_pclk", "sdi3"); - - clk = clk_reg_prcc_pclk("p2_pclk8", "per2clk", bases[CLKRST2_INDEX], - BIT(8), 0); - clk_register_clkdev(clk, NULL, "spi0"); - - clk = clk_reg_prcc_pclk("p2_pclk9", "per2clk", bases[CLKRST2_INDEX], - BIT(9), 0); - clk_register_clkdev(clk, "hsir_hclk", "ste_hsi.0"); - - clk = clk_reg_prcc_pclk("p2_pclk10", "per2clk", bases[CLKRST2_INDEX], - BIT(10), 0); - clk_register_clkdev(clk, "hsit_hclk", "ste_hsi.0"); - - clk = clk_reg_prcc_pclk("p2_pclk11", "per2clk", bases[CLKRST2_INDEX], - BIT(11), 0); - clk_register_clkdev(clk, NULL, "gpio.6"); - clk_register_clkdev(clk, NULL, "gpio.7"); - clk_register_clkdev(clk, NULL, "gpioblock1"); - - clk = clk_reg_prcc_pclk("p2_pclk12", "per2clk", bases[CLKRST2_INDEX], - BIT(12), 0); - clk_register_clkdev(clk, "msp4-pclk", "ab85xx-codec.0"); - - /* Peripheral 3 : PRCC P-clocks */ - clk = clk_reg_prcc_pclk("p3_pclk0", "per3clk", bases[CLKRST3_INDEX], - BIT(0), 0); - clk_register_clkdev(clk, NULL, "fsmc"); - - clk = clk_reg_prcc_pclk("p3_pclk1", "per3clk", bases[CLKRST3_INDEX], - BIT(1), 0); - clk_register_clkdev(clk, "apb_pclk", "ssp0"); - - clk = clk_reg_prcc_pclk("p3_pclk2", "per3clk", bases[CLKRST3_INDEX], - BIT(2), 0); - clk_register_clkdev(clk, "apb_pclk", "ssp1"); - - clk = clk_reg_prcc_pclk("p3_pclk3", "per3clk", bases[CLKRST3_INDEX], - BIT(3), 0); - clk_register_clkdev(clk, "apb_pclk", "nmk-i2c.0"); - - clk = clk_reg_prcc_pclk("p3_pclk4", "per3clk", bases[CLKRST3_INDEX], - BIT(4), 0); - clk_register_clkdev(clk, "apb_pclk", "sdi2"); - - clk = clk_reg_prcc_pclk("p3_pclk5", "per3clk", bases[CLKRST3_INDEX], - BIT(5), 0); - clk_register_clkdev(clk, "apb_pclk", "ske"); - clk_register_clkdev(clk, "apb_pclk", "nmk-ske-keypad"); - - clk = clk_reg_prcc_pclk("p3_pclk6", "per3clk", bases[CLKRST3_INDEX], - BIT(6), 0); - clk_register_clkdev(clk, "apb_pclk", "uart2"); - - clk = clk_reg_prcc_pclk("p3_pclk7", "per3clk", bases[CLKRST3_INDEX], - BIT(7), 0); - clk_register_clkdev(clk, "apb_pclk", "sdi5"); - - clk = clk_reg_prcc_pclk("p3_pclk8", "per3clk", bases[CLKRST3_INDEX], - BIT(8), 0); - clk_register_clkdev(clk, NULL, "gpio.2"); - clk_register_clkdev(clk, NULL, "gpio.3"); - clk_register_clkdev(clk, NULL, "gpio.4"); - clk_register_clkdev(clk, NULL, "gpio.5"); - clk_register_clkdev(clk, NULL, "gpioblock2"); - - clk = clk_reg_prcc_pclk("p3_pclk9", "per3clk", bases[CLKRST3_INDEX], - BIT(9), 0); - clk_register_clkdev(clk, "apb_pclk", "nmk-i2c.5"); - - clk = clk_reg_prcc_pclk("p3_pclk10", "per3clk", bases[CLKRST3_INDEX], - BIT(10), 0); - clk_register_clkdev(clk, "apb_pclk", "nmk-i2c.6"); - - clk = clk_reg_prcc_pclk("p3_pclk11", "per3clk", bases[CLKRST3_INDEX], - BIT(11), 0); - clk_register_clkdev(clk, "apb_pclk", "uart3"); - - clk = clk_reg_prcc_pclk("p3_pclk12", "per3clk", bases[CLKRST3_INDEX], - BIT(12), 0); - clk_register_clkdev(clk, "apb_pclk", "uart4"); - - /* Peripheral 5 : PRCC P-clocks */ - clk = clk_reg_prcc_pclk("p5_pclk0", "per5clk", bases[CLKRST5_INDEX], - BIT(0), 0); - clk_register_clkdev(clk, "usb", "musb-ux500.0"); - clk_register_clkdev(clk, "usbclk", "ab-iddet.0"); - - clk = clk_reg_prcc_pclk("p5_pclk1", "per5clk", bases[CLKRST5_INDEX], - BIT(1), 0); - clk_register_clkdev(clk, NULL, "gpio.8"); - clk_register_clkdev(clk, NULL, "gpioblock3"); - - /* Peripheral 6 : PRCC P-clocks */ - clk = clk_reg_prcc_pclk("p6_pclk0", "per6clk", bases[CLKRST6_INDEX], - BIT(0), 0); - clk_register_clkdev(clk, "apb_pclk", "rng"); - - clk = clk_reg_prcc_pclk("p6_pclk1", "per6clk", bases[CLKRST6_INDEX], - BIT(1), 0); - clk_register_clkdev(clk, NULL, "cryp0"); - clk_register_clkdev(clk, NULL, "cryp1"); - - clk = clk_reg_prcc_pclk("p6_pclk2", "per6clk", bases[CLKRST6_INDEX], - BIT(2), 0); - clk_register_clkdev(clk, NULL, "hash0"); - - clk = clk_reg_prcc_pclk("p6_pclk3", "per6clk", bases[CLKRST6_INDEX], - BIT(3), 0); - clk_register_clkdev(clk, NULL, "pka"); - - clk = clk_reg_prcc_pclk("p6_pclk4", "per6clk", bases[CLKRST6_INDEX], - BIT(4), 0); - clk_register_clkdev(clk, NULL, "db8540-hash1"); - - clk = clk_reg_prcc_pclk("p6_pclk5", "per6clk", bases[CLKRST6_INDEX], - BIT(5), 0); - clk_register_clkdev(clk, NULL, "cfgreg"); - - clk = clk_reg_prcc_pclk("p6_pclk6", "per6clk", bases[CLKRST6_INDEX], - BIT(6), 0); - clk_register_clkdev(clk, "apb_pclk", "mtu0"); - - clk = clk_reg_prcc_pclk("p6_pclk7", "per6clk", bases[CLKRST6_INDEX], - BIT(7), 0); - clk_register_clkdev(clk, "apb_pclk", "mtu1"); - - /* - * PRCC K-clocks ==> see table PRCC_PCKEN/PRCC_KCKEN - * This differs from the internal implementation: - * We don't use the PERPIH[n| clock as parent, since those _should_ - * only be used as parents for the P-clocks. - * TODO: "parentjoin" with corresponding P-clocks for all K-clocks. - */ - - /* Peripheral 1 : PRCC K-clocks */ - clk = clk_reg_prcc_kclk("p1_uart0_kclk", "uartclk", - bases[CLKRST1_INDEX], BIT(0), CLK_SET_RATE_GATE); - clk_register_clkdev(clk, NULL, "uart0"); - - clk = clk_reg_prcc_kclk("p1_uart1_kclk", "uartclk", - bases[CLKRST1_INDEX], BIT(1), CLK_SET_RATE_GATE); - clk_register_clkdev(clk, NULL, "uart1"); - - clk = clk_reg_prcc_kclk("p1_i2c1_kclk", "i2cclk", - bases[CLKRST1_INDEX], BIT(2), CLK_SET_RATE_GATE); - clk_register_clkdev(clk, NULL, "nmk-i2c.1"); - - clk = clk_reg_prcc_kclk("p1_msp0_kclk", "msp02clk", - bases[CLKRST1_INDEX], BIT(3), CLK_SET_RATE_GATE); - clk_register_clkdev(clk, NULL, "msp0"); - clk_register_clkdev(clk, NULL, "dbx5x0-msp-i2s.0"); - - clk = clk_reg_prcc_kclk("p1_msp1_kclk", "msp1clk", - bases[CLKRST1_INDEX], BIT(4), CLK_SET_RATE_GATE); - clk_register_clkdev(clk, NULL, "msp1"); - clk_register_clkdev(clk, NULL, "dbx5x0-msp-i2s.1"); - - clk = clk_reg_prcc_kclk("p1_sdi0_kclk", "sdmmchclk", - bases[CLKRST1_INDEX], BIT(5), CLK_SET_RATE_GATE); - clk_register_clkdev(clk, NULL, "sdi0"); - - clk = clk_reg_prcc_kclk("p1_i2c2_kclk", "i2cclk", - bases[CLKRST1_INDEX], BIT(6), CLK_SET_RATE_GATE); - clk_register_clkdev(clk, NULL, "nmk-i2c.2"); - - clk = clk_reg_prcc_kclk("p1_slimbus0_kclk", "slimclk", - bases[CLKRST1_INDEX], BIT(8), CLK_SET_RATE_GATE); - clk_register_clkdev(clk, NULL, "slimbus0"); - - clk = clk_reg_prcc_kclk("p1_i2c4_kclk", "i2cclk", - bases[CLKRST1_INDEX], BIT(9), CLK_SET_RATE_GATE); - clk_register_clkdev(clk, NULL, "nmk-i2c.4"); - - clk = clk_reg_prcc_kclk("p1_msp3_kclk", "msp1clk", - bases[CLKRST1_INDEX], BIT(10), CLK_SET_RATE_GATE); - clk_register_clkdev(clk, NULL, "msp3"); - clk_register_clkdev(clk, NULL, "dbx5x0-msp-i2s.3"); - - /* Peripheral 2 : PRCC K-clocks */ - clk = clk_reg_prcc_kclk("p2_i2c3_kclk", "i2cclk", - bases[CLKRST2_INDEX], BIT(0), CLK_SET_RATE_GATE); - clk_register_clkdev(clk, NULL, "nmk-i2c.3"); - - clk = clk_reg_prcc_kclk("p2_pwl_kclk", "rtc32k", - bases[CLKRST2_INDEX], BIT(1), CLK_SET_RATE_GATE); - clk_register_clkdev(clk, NULL, "pwl"); - - clk = clk_reg_prcc_kclk("p2_sdi4_kclk", "sdmmchclk", - bases[CLKRST2_INDEX], BIT(2), CLK_SET_RATE_GATE); - clk_register_clkdev(clk, NULL, "sdi4"); - - clk = clk_reg_prcc_kclk("p2_msp2_kclk", "msp02clk", - bases[CLKRST2_INDEX], BIT(3), CLK_SET_RATE_GATE); - clk_register_clkdev(clk, NULL, "msp2"); - clk_register_clkdev(clk, NULL, "dbx5x0-msp-i2s.2"); - - clk = clk_reg_prcc_kclk("p2_sdi1_kclk", "sdmmchclk", - bases[CLKRST2_INDEX], BIT(4), CLK_SET_RATE_GATE); - clk_register_clkdev(clk, NULL, "sdi1"); - - clk = clk_reg_prcc_kclk("p2_sdi3_kclk", "sdmmcclk", - bases[CLKRST2_INDEX], BIT(5), CLK_SET_RATE_GATE); - clk_register_clkdev(clk, NULL, "sdi3"); - - clk = clk_reg_prcc_kclk("p2_ssirx_kclk", "hsirxclk", - bases[CLKRST2_INDEX], BIT(6), - CLK_SET_RATE_GATE|CLK_SET_RATE_PARENT); - clk_register_clkdev(clk, "hsir_hsirxclk", "ste_hsi.0"); - - clk = clk_reg_prcc_kclk("p2_ssitx_kclk", "hsitxclk", - bases[CLKRST2_INDEX], BIT(7), - CLK_SET_RATE_GATE|CLK_SET_RATE_PARENT); - clk_register_clkdev(clk, "hsit_hsitxclk", "ste_hsi.0"); - - /* Should only be 9540, but might be added for 85xx as well */ - clk = clk_reg_prcc_kclk("p2_msp4_kclk", "msp02clk", - bases[CLKRST2_INDEX], BIT(9), CLK_SET_RATE_GATE); - clk_register_clkdev(clk, NULL, "msp4"); - clk_register_clkdev(clk, "msp4", "ab85xx-codec.0"); - - /* Peripheral 3 : PRCC K-clocks */ - clk = clk_reg_prcc_kclk("p3_ssp0_kclk", "sspclk", - bases[CLKRST3_INDEX], BIT(1), CLK_SET_RATE_GATE); - clk_register_clkdev(clk, NULL, "ssp0"); - - clk = clk_reg_prcc_kclk("p3_ssp1_kclk", "sspclk", - bases[CLKRST3_INDEX], BIT(2), CLK_SET_RATE_GATE); - clk_register_clkdev(clk, NULL, "ssp1"); - - clk = clk_reg_prcc_kclk("p3_i2c0_kclk", "i2cclk", - bases[CLKRST3_INDEX], BIT(3), CLK_SET_RATE_GATE); - clk_register_clkdev(clk, NULL, "nmk-i2c.0"); - - clk = clk_reg_prcc_kclk("p3_sdi2_kclk", "sdmmchclk", - bases[CLKRST3_INDEX], BIT(4), CLK_SET_RATE_GATE); - clk_register_clkdev(clk, NULL, "sdi2"); - - clk = clk_reg_prcc_kclk("p3_ske_kclk", "rtc32k", - bases[CLKRST3_INDEX], BIT(5), CLK_SET_RATE_GATE); - clk_register_clkdev(clk, NULL, "ske"); - clk_register_clkdev(clk, NULL, "nmk-ske-keypad"); - - clk = clk_reg_prcc_kclk("p3_uart2_kclk", "uartclk", - bases[CLKRST3_INDEX], BIT(6), CLK_SET_RATE_GATE); - clk_register_clkdev(clk, NULL, "uart2"); - - clk = clk_reg_prcc_kclk("p3_sdi5_kclk", "sdmmcclk", - bases[CLKRST3_INDEX], BIT(7), CLK_SET_RATE_GATE); - clk_register_clkdev(clk, NULL, "sdi5"); - - clk = clk_reg_prcc_kclk("p3_i2c5_kclk", "i2cclk", - bases[CLKRST3_INDEX], BIT(8), CLK_SET_RATE_GATE); - clk_register_clkdev(clk, NULL, "nmk-i2c.5"); - - clk = clk_reg_prcc_kclk("p3_i2c6_kclk", "i2cclk", - bases[CLKRST3_INDEX], BIT(9), CLK_SET_RATE_GATE); - clk_register_clkdev(clk, NULL, "nmk-i2c.6"); - - clk = clk_reg_prcc_kclk("p3_uart3_kclk", "uartclk", - bases[CLKRST3_INDEX], BIT(10), CLK_SET_RATE_GATE); - clk_register_clkdev(clk, NULL, "uart3"); - - clk = clk_reg_prcc_kclk("p3_uart4_kclk", "uartclk", - bases[CLKRST3_INDEX], BIT(11), CLK_SET_RATE_GATE); - clk_register_clkdev(clk, NULL, "uart4"); - - /* Peripheral 6 : PRCC K-clocks */ - clk = clk_reg_prcc_kclk("p6_rng_kclk", "rngclk", - bases[CLKRST6_INDEX], BIT(0), CLK_SET_RATE_GATE); - clk_register_clkdev(clk, NULL, "rng"); -} -CLK_OF_DECLARE(u8540_clks, "stericsson,u8540-clks", u8540_clk_init); diff --git a/drivers/clk/ux500/u9540_clk.c b/drivers/clk/ux500/u9540_clk.c deleted file mode 100644 index 7b6bca49ce42..000000000000 --- a/drivers/clk/ux500/u9540_clk.c +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Clock definitions for u9540 platform. - * - * Copyright (C) 2012 ST-Ericsson SA - * Author: Ulf Hansson - * - * License terms: GNU General Public License (GPL) version 2 - */ - -#include -#include -#include "clk.h" - -static void u9540_clk_init(struct device_node *np) -{ - /* register clocks here */ -} -CLK_OF_DECLARE(u9540_clks, "stericsson,u9540-clks", u9540_clk_init); -- cgit From c2fd8756c5c3a3187094a4e7d7a6c87aa8033901 Mon Sep 17 00:00:00 2001 From: Kunihiko Hayashi Date: Fri, 23 Mar 2018 14:11:41 +0900 Subject: clk: uniphier: add ethernet clock control support for PXs3 Add clock control for ethernet controller on PXs3 SoC. Signed-off-by: Kunihiko Hayashi Acked-by: Masahiro Yamada Signed-off-by: Stephen Boyd --- drivers/clk/uniphier/clk-uniphier-sys.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/clk/uniphier/clk-uniphier-sys.c b/drivers/clk/uniphier/clk-uniphier-sys.c index 06c5269f63f5..fa7f2f3f8e36 100644 --- a/drivers/clk/uniphier/clk-uniphier-sys.c +++ b/drivers/clk/uniphier/clk-uniphier-sys.c @@ -244,6 +244,8 @@ const struct uniphier_clk_data uniphier_pxs3_sys_clk_data[] = { UNIPHIER_LD20_SYS_CLK_SD, UNIPHIER_LD11_SYS_CLK_NAND(2), UNIPHIER_LD11_SYS_CLK_EMMC(4), + UNIPHIER_CLK_GATE("ether0", 6, NULL, 0x210c, 9), + UNIPHIER_CLK_GATE("ether1", 7, NULL, 0x210c, 10), UNIPHIER_CLK_GATE("usb30", 12, NULL, 0x210c, 4), /* =GIO0 */ UNIPHIER_CLK_GATE("usb31-0", 13, NULL, 0x210c, 5), /* =GIO1 */ UNIPHIER_CLK_GATE("usb31-1", 14, NULL, 0x210c, 6), /* =GIO1-1 */ -- cgit From fc3fcb4ff1960e9f0b72b1d4855f7e0bcf18b7f2 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Thu, 22 Mar 2018 02:11:48 +0000 Subject: clk: davinci: Remove redundant dev_err calls There is a error message within devm_ioremap_resource already, so remove the dev_err call to avoid redundant error message. Signed-off-by: Wei Yongjun Reviewed-by: David Lechner Signed-off-by: Stephen Boyd --- drivers/clk/davinci/pll.c | 4 +--- drivers/clk/davinci/psc.c | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/clk/davinci/pll.c b/drivers/clk/davinci/pll.c index 89d30bf95102..23a24c944f1d 100644 --- a/drivers/clk/davinci/pll.c +++ b/drivers/clk/davinci/pll.c @@ -814,10 +814,8 @@ static int davinci_pll_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); base = devm_ioremap_resource(dev, res); - if (IS_ERR(base)) { - dev_err(dev, "ioremap failed\n"); + if (IS_ERR(base)) return PTR_ERR(base); - } return pll_init(dev, base); } diff --git a/drivers/clk/davinci/psc.c b/drivers/clk/davinci/psc.c index 3b0e59dfbdd7..ff6f4a038e04 100644 --- a/drivers/clk/davinci/psc.c +++ b/drivers/clk/davinci/psc.c @@ -521,10 +521,8 @@ static int davinci_psc_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); base = devm_ioremap_resource(dev, res); - if (IS_ERR(base)) { - dev_err(dev, "ioremap failed\n"); + if (IS_ERR(base)) return PTR_ERR(base); - } ret = devm_clk_bulk_get(dev, init_data->num_parent_clks, init_data->parent_clks); -- cgit From 953cc3e8117013bd39a3b94e28361ce94ad63075 Mon Sep 17 00:00:00 2001 From: Mike Looijmans Date: Tue, 20 Mar 2018 09:15:41 +0100 Subject: clk: Add driver for the si544 clock generator chip This patch adds the driver and devicetree documentation for the Silicon Labs SI544 clock generator chip. This is an I2C controlled oscillator capable of generating clock signals ranging from 200kHz to 1500MHz. Signed-off-by: Mike Looijmans [sboyd: assign max_freq to 0 in is_valid_frequency() to squelch warning] Signed-off-by: Stephen Boyd --- .../devicetree/bindings/clock/silabs,si544.txt | 25 ++ drivers/clk/Kconfig | 9 + drivers/clk/Makefile | 1 + drivers/clk/clk-si544.c | 411 +++++++++++++++++++++ 4 files changed, 446 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/silabs,si544.txt create mode 100644 drivers/clk/clk-si544.c diff --git a/Documentation/devicetree/bindings/clock/silabs,si544.txt b/Documentation/devicetree/bindings/clock/silabs,si544.txt new file mode 100644 index 000000000000..b86535b80920 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/silabs,si544.txt @@ -0,0 +1,25 @@ +Binding for Silicon Labs 544 programmable I2C clock generator. + +Reference +This binding uses the common clock binding[1]. Details about the device can be +found in the datasheet[2]. + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt +[2] Si544 datasheet + https://www.silabs.com/documents/public/data-sheets/si544-datasheet.pdf + +Required properties: + - compatible: One of "silabs,si514a", "silabs,si514b" "silabs,si514c" according + to the speed grade of the chip. + - reg: I2C device address. + - #clock-cells: From common clock bindings: Shall be 0. + +Optional properties: + - clock-output-names: From common clock bindings. Recommended to be "si544". + +Example: + si544: clock-controller@55 { + reg = <0x55>; + #clock-cells = <0>; + compatible = "silabs,si544b"; + }; diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index 98ce9fc6e6c0..580fc04a96c4 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -91,6 +91,15 @@ config COMMON_CLK_SI514 This driver supports the Silicon Labs 514 programmable clock generator. +config COMMON_CLK_SI544 + tristate "Clock driver for SiLabs 544 devices" + depends on I2C + select REGMAP_I2C + help + ---help--- + This driver supports the Silicon Labs 544 programmable clock + generator. + config COMMON_CLK_SI570 tristate "Clock driver for SiLabs 570 and compatible devices" depends on I2C diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 71ec41e6364f..bde614ab82e0 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -44,6 +44,7 @@ obj-$(CONFIG_COMMON_CLK_S2MPS11) += clk-s2mps11.o obj-$(CONFIG_COMMON_CLK_SCPI) += clk-scpi.o obj-$(CONFIG_COMMON_CLK_SI5351) += clk-si5351.o obj-$(CONFIG_COMMON_CLK_SI514) += clk-si514.o +obj-$(CONFIG_COMMON_CLK_SI544) += clk-si544.o obj-$(CONFIG_COMMON_CLK_SI570) += clk-si570.o obj-$(CONFIG_ARCH_STM32) += clk-stm32f4.o obj-$(CONFIG_ARCH_STM32) += clk-stm32h7.o diff --git a/drivers/clk/clk-si544.c b/drivers/clk/clk-si544.c new file mode 100644 index 000000000000..1c96a9f6c022 --- /dev/null +++ b/drivers/clk/clk-si544.c @@ -0,0 +1,411 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Driver for Silicon Labs Si544 Programmable Oscillator + * Copyright (C) 2018 Topic Embedded Products + * Author: Mike Looijmans + */ + +#include +#include +#include +#include +#include +#include + +/* I2C registers (decimal as in datasheet) */ +#define SI544_REG_CONTROL 7 +#define SI544_REG_OE_STATE 17 +#define SI544_REG_HS_DIV 23 +#define SI544_REG_LS_HS_DIV 24 +#define SI544_REG_FBDIV0 26 +#define SI544_REG_FBDIV8 27 +#define SI544_REG_FBDIV16 28 +#define SI544_REG_FBDIV24 29 +#define SI544_REG_FBDIV32 30 +#define SI544_REG_FBDIV40 31 +#define SI544_REG_FCAL_OVR 69 +#define SI544_REG_ADPLL_DELTA_M0 231 +#define SI544_REG_ADPLL_DELTA_M8 232 +#define SI544_REG_ADPLL_DELTA_M16 233 +#define SI544_REG_PAGE_SELECT 255 + +/* Register values */ +#define SI544_CONTROL_RESET BIT(7) +#define SI544_CONTROL_MS_ICAL2 BIT(3) + +#define SI544_OE_STATE_ODC_OE BIT(0) + +/* Max freq depends on speed grade */ +#define SI544_MIN_FREQ 200000U + +/* Si544 Internal oscilator runs at 55.05 MHz */ +#define FXO 55050000U + +/* VCO range is 10.8 .. 12.1 GHz, max depends on speed grade */ +#define FVCO_MIN 10800000000ULL + +#define HS_DIV_MAX 2046 +#define HS_DIV_MAX_ODD 33 + +/* Lowest frequency synthesizeable using only the HS divider */ +#define MIN_HSDIV_FREQ (FVCO_MIN / HS_DIV_MAX) + +enum si544_speed_grade { + si544a, + si544b, + si544c, +}; + +struct clk_si544 { + struct clk_hw hw; + struct regmap *regmap; + struct i2c_client *i2c_client; + enum si544_speed_grade speed_grade; +}; +#define to_clk_si544(_hw) container_of(_hw, struct clk_si544, hw) + +/** + * struct clk_si544_muldiv - Multiplier/divider settings + * @fb_div_frac: integer part of feedback divider (32 bits) + * @fb_div_int: fractional part of feedback divider (11 bits) + * @hs_div: 1st divider, 5..2046, must be even when >33 + * @ls_div_bits: 2nd divider, as 2^x, range 0..5 + * If ls_div_bits is non-zero, hs_div must be even + */ +struct clk_si544_muldiv { + u32 fb_div_frac; + u16 fb_div_int; + u16 hs_div; + u8 ls_div_bits; +}; + +/* Enables or disables the output driver */ +static int si544_enable_output(struct clk_si544 *data, bool enable) +{ + return regmap_update_bits(data->regmap, SI544_REG_OE_STATE, + SI544_OE_STATE_ODC_OE, enable ? SI544_OE_STATE_ODC_OE : 0); +} + +/* Retrieve clock multiplier and dividers from hardware */ +static int si544_get_muldiv(struct clk_si544 *data, + struct clk_si544_muldiv *settings) +{ + int err; + u8 reg[6]; + + err = regmap_bulk_read(data->regmap, SI544_REG_HS_DIV, reg, 2); + if (err) + return err; + + settings->ls_div_bits = (reg[1] >> 4) & 0x07; + settings->hs_div = (reg[1] & 0x07) << 8 | reg[0]; + + err = regmap_bulk_read(data->regmap, SI544_REG_FBDIV0, reg, 6); + if (err) + return err; + + settings->fb_div_int = reg[4] | (reg[5] & 0x07) << 8; + settings->fb_div_frac = reg[0] | reg[1] << 8 | reg[2] << 16 | + reg[3] << 24; + return 0; +} + +static int si544_set_muldiv(struct clk_si544 *data, + struct clk_si544_muldiv *settings) +{ + int err; + u8 reg[6]; + + reg[0] = settings->hs_div; + reg[1] = settings->hs_div >> 8 | settings->ls_div_bits << 4; + + err = regmap_bulk_write(data->regmap, SI544_REG_HS_DIV, reg, 2); + if (err < 0) + return err; + + reg[0] = settings->fb_div_frac; + reg[1] = settings->fb_div_frac >> 8; + reg[2] = settings->fb_div_frac >> 16; + reg[3] = settings->fb_div_frac >> 24; + reg[4] = settings->fb_div_int; + reg[5] = settings->fb_div_int >> 8; + + /* + * Writing to SI544_REG_FBDIV40 triggers the clock change, so that + * must be written last + */ + return regmap_bulk_write(data->regmap, SI544_REG_FBDIV0, reg, 6); +} + +static bool is_valid_frequency(const struct clk_si544 *data, + unsigned long frequency) +{ + unsigned long max_freq = 0; + + if (frequency < SI544_MIN_FREQ) + return false; + + switch (data->speed_grade) { + case si544a: + max_freq = 1500000000; + break; + case si544b: + max_freq = 800000000; + break; + case si544c: + max_freq = 350000000; + break; + } + + return frequency <= max_freq; +} + +/* Calculate divider settings for a given frequency */ +static int si544_calc_muldiv(struct clk_si544_muldiv *settings, + unsigned long frequency) +{ + u64 vco; + u32 ls_freq; + u32 tmp; + u8 res; + + /* Determine the minimum value of LS_DIV and resulting target freq. */ + ls_freq = frequency; + settings->ls_div_bits = 0; + + if (frequency >= MIN_HSDIV_FREQ) { + settings->ls_div_bits = 0; + } else { + res = 1; + tmp = 2 * HS_DIV_MAX; + while (tmp <= (HS_DIV_MAX * 32)) { + if (((u64)frequency * tmp) >= FVCO_MIN) + break; + ++res; + tmp <<= 1; + } + settings->ls_div_bits = res; + ls_freq = frequency << res; + } + + /* Determine minimum HS_DIV by rounding up */ + vco = FVCO_MIN + ls_freq - 1; + do_div(vco, ls_freq); + settings->hs_div = vco; + + /* round up to even number when required */ + if ((settings->hs_div & 1) && + (settings->hs_div > HS_DIV_MAX_ODD || settings->ls_div_bits)) + ++settings->hs_div; + + /* Calculate VCO frequency (in 10..12GHz range) */ + vco = (u64)ls_freq * settings->hs_div; + + /* Calculate the integer part of the feedback divider */ + tmp = do_div(vco, FXO); + settings->fb_div_int = vco; + + /* And the fractional bits using the remainder */ + vco = (u64)tmp << 32; + do_div(vco, FXO); + settings->fb_div_frac = vco; + + return 0; +} + +/* Calculate resulting frequency given the register settings */ +static unsigned long si544_calc_rate(struct clk_si544_muldiv *settings) +{ + u32 d = settings->hs_div * BIT(settings->ls_div_bits); + u64 vco; + + /* Calculate VCO from the fractional part */ + vco = (u64)settings->fb_div_frac * FXO; + vco += (FXO / 2); + vco >>= 32; + + /* Add the integer part of the VCO frequency */ + vco += (u64)settings->fb_div_int * FXO; + + /* Apply divider to obtain the generated frequency */ + do_div(vco, d); + + return vco; +} + +static unsigned long si544_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_si544 *data = to_clk_si544(hw); + struct clk_si544_muldiv settings; + int err; + + err = si544_get_muldiv(data, &settings); + if (err) + return 0; + + return si544_calc_rate(&settings); +} + +static long si544_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + struct clk_si544 *data = to_clk_si544(hw); + struct clk_si544_muldiv settings; + int err; + + if (!is_valid_frequency(data, rate)) + return -EINVAL; + + err = si544_calc_muldiv(&settings, rate); + if (err) + return err; + + return si544_calc_rate(&settings); +} + +/* + * Update output frequency for "big" frequency changes + */ +static int si544_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_si544 *data = to_clk_si544(hw); + struct clk_si544_muldiv settings; + int err; + + if (!is_valid_frequency(data, rate)) + return -EINVAL; + + err = si544_calc_muldiv(&settings, rate); + if (err) + return err; + + si544_enable_output(data, false); + + /* Allow FCAL for this frequency update */ + err = regmap_write(data->regmap, SI544_REG_FCAL_OVR, 0); + if (err < 0) + return err; + + + err = si544_set_muldiv(data, &settings); + if (err < 0) + return err; /* Undefined state now, best to leave disabled */ + + /* Trigger calibration */ + err = regmap_write(data->regmap, SI544_REG_CONTROL, + SI544_CONTROL_MS_ICAL2); + if (err < 0) + return err; + + /* Applying a new frequency can take up to 10ms */ + usleep_range(10000, 12000); + + si544_enable_output(data, true); + + return err; +} + +static const struct clk_ops si544_clk_ops = { + .recalc_rate = si544_recalc_rate, + .round_rate = si544_round_rate, + .set_rate = si544_set_rate, +}; + +static bool si544_regmap_is_volatile(struct device *dev, unsigned int reg) +{ + switch (reg) { + case SI544_REG_CONTROL: + case SI544_REG_FCAL_OVR: + return true; + default: + return false; + } +} + +static const struct regmap_config si544_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .cache_type = REGCACHE_RBTREE, + .max_register = SI544_REG_PAGE_SELECT, + .volatile_reg = si544_regmap_is_volatile, +}; + +static int si544_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct clk_si544 *data; + struct clk_init_data init; + int err; + + data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + init.ops = &si544_clk_ops; + init.flags = 0; + init.num_parents = 0; + data->hw.init = &init; + data->i2c_client = client; + data->speed_grade = id->driver_data; + + if (of_property_read_string(client->dev.of_node, "clock-output-names", + &init.name)) + init.name = client->dev.of_node->name; + + data->regmap = devm_regmap_init_i2c(client, &si544_regmap_config); + if (IS_ERR(data->regmap)) + return PTR_ERR(data->regmap); + + i2c_set_clientdata(client, data); + + /* Select page 0, just to be sure, there appear to be no more */ + err = regmap_write(data->regmap, SI544_REG_PAGE_SELECT, 0); + if (err < 0) + return err; + + err = devm_clk_hw_register(&client->dev, &data->hw); + if (err) { + dev_err(&client->dev, "clock registration failed\n"); + return err; + } + err = devm_of_clk_add_hw_provider(&client->dev, of_clk_hw_simple_get, + &data->hw); + if (err) { + dev_err(&client->dev, "unable to add clk provider\n"); + return err; + } + + return 0; +} + +static const struct i2c_device_id si544_id[] = { + { "si544a", si544a }, + { "si544b", si544b }, + { "si544c", si544c }, + { } +}; +MODULE_DEVICE_TABLE(i2c, si544_id); + +static const struct of_device_id clk_si544_of_match[] = { + { .compatible = "silabs,si544a" }, + { .compatible = "silabs,si544b" }, + { .compatible = "silabs,si544c" }, + { }, +}; +MODULE_DEVICE_TABLE(of, clk_si544_of_match); + +static struct i2c_driver si544_driver = { + .driver = { + .name = "si544", + .of_match_table = clk_si544_of_match, + }, + .probe = si544_probe, + .id_table = si544_id, +}; +module_i2c_driver(si544_driver); + +MODULE_AUTHOR("Mike Looijmans "); +MODULE_DESCRIPTION("Si544 driver"); +MODULE_LICENSE("GPL"); -- cgit From 2e277efb82c1ddacd9afed172098602a44dc5671 Mon Sep 17 00:00:00 2001 From: Kunihiko Hayashi Date: Fri, 30 Mar 2018 18:44:12 +0900 Subject: clk: uniphier: add PCIe clock control support Add clock control for PCIe controller on UniPhier SoCs. This adds support for Pro5, LD20 and PXs3. Signed-off-by: Kunihiko Hayashi Acked-by: Masahiro Yamada Signed-off-by: Stephen Boyd --- drivers/clk/uniphier/clk-uniphier-sys.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/clk/uniphier/clk-uniphier-sys.c b/drivers/clk/uniphier/clk-uniphier-sys.c index fa7f2f3f8e36..d539c82c8217 100644 --- a/drivers/clk/uniphier/clk-uniphier-sys.c +++ b/drivers/clk/uniphier/clk-uniphier-sys.c @@ -141,6 +141,7 @@ const struct uniphier_clk_data uniphier_pro5_sys_clk_data[] = { UNIPHIER_PRO4_SYS_CLK_GIO(12), /* PCIe, USB3 */ UNIPHIER_PRO4_SYS_CLK_USB3(14, 0), UNIPHIER_PRO4_SYS_CLK_USB3(15, 1), + UNIPHIER_CLK_GATE("pcie", 24, NULL, 0x2108, 2), UNIPHIER_PRO5_SYS_CLK_AIO(40), { /* sentinel */ } }; @@ -216,6 +217,7 @@ const struct uniphier_clk_data uniphier_ld20_sys_clk_data[] = { UNIPHIER_CLK_GATE("usb30", 14, NULL, 0x210c, 14), UNIPHIER_CLK_GATE("usb30-phy0", 16, NULL, 0x210c, 12), UNIPHIER_CLK_GATE("usb30-phy1", 17, NULL, 0x210c, 13), + UNIPHIER_CLK_GATE("pcie", 24, NULL, 0x210c, 4), UNIPHIER_LD11_SYS_CLK_AIO(40), UNIPHIER_LD11_SYS_CLK_EVEA(41), UNIPHIER_LD11_SYS_CLK_EXIV(42), @@ -254,6 +256,7 @@ const struct uniphier_clk_data uniphier_pxs3_sys_clk_data[] = { UNIPHIER_CLK_GATE("usb30-phy2", 18, NULL, 0x210c, 20), UNIPHIER_CLK_GATE("usb31-phy0", 20, NULL, 0x210c, 17), UNIPHIER_CLK_GATE("usb31-phy1", 21, NULL, 0x210c, 19), + UNIPHIER_CLK_GATE("pcie", 24, NULL, 0x210c, 3), /* CPU gears */ UNIPHIER_CLK_DIV4("cpll", 2, 3, 4, 8), UNIPHIER_CLK_DIV4("spll", 2, 3, 4, 8), -- cgit From 54e1f7ee1f5e8ec8b56e89fc431b3d07f84e9cbd Mon Sep 17 00:00:00 2001 From: Kunihiko Hayashi Date: Fri, 30 Mar 2018 18:44:13 +0900 Subject: clk: uniphier: add SATA clock control support Add clock control for SATA controller on UniPhier SoCs. This adds support for PXs2, LD20 and PXs3. Signed-off-by: Kunihiko Hayashi Acked-by: Masahiro Yamada Signed-off-by: Stephen Boyd --- drivers/clk/uniphier/clk-uniphier-sys.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/clk/uniphier/clk-uniphier-sys.c b/drivers/clk/uniphier/clk-uniphier-sys.c index d539c82c8217..7d66dfb34af7 100644 --- a/drivers/clk/uniphier/clk-uniphier-sys.c +++ b/drivers/clk/uniphier/clk-uniphier-sys.c @@ -112,6 +112,8 @@ const struct uniphier_clk_data uniphier_pro4_sys_clk_data[] = { UNIPHIER_PRO4_SYS_CLK_GIO(12), /* Ether, SATA, USB3 */ UNIPHIER_PRO4_SYS_CLK_USB3(14, 0), UNIPHIER_PRO4_SYS_CLK_USB3(15, 1), + UNIPHIER_CLK_GATE("sata0", 28, NULL, 0x2104, 18), + UNIPHIER_CLK_GATE("sata1", 29, NULL, 0x2104, 19), UNIPHIER_PRO4_SYS_CLK_AIO(40), { /* sentinel */ } }; @@ -160,6 +162,7 @@ const struct uniphier_clk_data uniphier_pxs2_sys_clk_data[] = { /* The document mentions 0x2104 bit 18, but not functional */ UNIPHIER_CLK_GATE("usb30-phy", 16, NULL, 0x2104, 19), UNIPHIER_CLK_GATE("usb31-phy", 20, NULL, 0x2104, 20), + UNIPHIER_CLK_GATE("sata0", 28, NULL, 0x2104, 22), UNIPHIER_PRO5_SYS_CLK_AIO(40), { /* sentinel */ } }; @@ -257,6 +260,9 @@ const struct uniphier_clk_data uniphier_pxs3_sys_clk_data[] = { UNIPHIER_CLK_GATE("usb31-phy0", 20, NULL, 0x210c, 17), UNIPHIER_CLK_GATE("usb31-phy1", 21, NULL, 0x210c, 19), UNIPHIER_CLK_GATE("pcie", 24, NULL, 0x210c, 3), + UNIPHIER_CLK_GATE("sata0", 28, NULL, 0x210c, 7), + UNIPHIER_CLK_GATE("sata1", 29, NULL, 0x210c, 8), + UNIPHIER_CLK_GATE("sata-phy", 30, NULL, 0x210c, 21), /* CPU gears */ UNIPHIER_CLK_DIV4("cpll", 2, 3, 4, 8), UNIPHIER_CLK_DIV4("spll", 2, 3, 4, 8), -- cgit From 6f1aa4ef3f78cc0b42aa1b4c61e356523d88e680 Mon Sep 17 00:00:00 2001 From: Kunihiko Hayashi Date: Fri, 30 Mar 2018 18:44:14 +0900 Subject: clk: uniphier: add additional ethernet clock lines for Pro4 Pro4 SoC has clock lines for Giga-bit feature and ethernet phy, and these are mandatory to activate the ethernet controller. This adds support for the clock lines. Signed-off-by: Kunihiko Hayashi Acked-by: Masahiro Yamada Signed-off-by: Stephen Boyd --- drivers/clk/uniphier/clk-uniphier-sys.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/clk/uniphier/clk-uniphier-sys.c b/drivers/clk/uniphier/clk-uniphier-sys.c index 7d66dfb34af7..ebc78ab2df05 100644 --- a/drivers/clk/uniphier/clk-uniphier-sys.c +++ b/drivers/clk/uniphier/clk-uniphier-sys.c @@ -102,13 +102,16 @@ const struct uniphier_clk_data uniphier_pro4_sys_clk_data[] = { UNIPHIER_CLK_FACTOR("upll", -1, "ref", 288, 25), /* 288 MHz */ UNIPHIER_CLK_FACTOR("a2pll", -1, "upll", 256, 125), /* 589.824 MHz */ UNIPHIER_CLK_FACTOR("vpll27a", -1, "ref", 270, 25), /* 270 MHz */ + UNIPHIER_CLK_FACTOR("gpll", -1, "ref", 10, 1), /* 250 MHz */ UNIPHIER_CLK_FACTOR("uart", 0, "a2pll", 1, 8), UNIPHIER_CLK_FACTOR("i2c", 1, "spll", 1, 32), UNIPHIER_LD4_SYS_CLK_NAND(2), UNIPHIER_LD4_SYS_CLK_SD, UNIPHIER_CLK_FACTOR("usb2", -1, "upll", 1, 12), UNIPHIER_PRO4_SYS_CLK_ETHER(6), + UNIPHIER_CLK_GATE("ether-gb", 7, "gpll", 0x2104, 5), UNIPHIER_LD4_SYS_CLK_STDMAC(8), /* HSC, MIO, RLE */ + UNIPHIER_CLK_GATE("ether-phy", 10, "ref", 0x2260, 0), UNIPHIER_PRO4_SYS_CLK_GIO(12), /* Ether, SATA, USB3 */ UNIPHIER_PRO4_SYS_CLK_USB3(14, 0), UNIPHIER_PRO4_SYS_CLK_USB3(15, 1), -- cgit From 269bd202bc0fd04e841cb123867fd3f49e04ace9 Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Tue, 27 Mar 2018 20:47:04 +0300 Subject: clk: ti: fix flag space conflict with clkctrl clocks The introduction of support for CLK_SET_RATE_PARENT flag for clkctrl clocks used a generic clock flag, which causes a conflict with the rest of the clkctrl flags, namely the NO_IDLEST flag. This can cause boot failures on certain platforms where this flag is introduced, by omitting the wait for the clockctrl module to be fully enabled before proceeding with rest of the code. Fix this by moving all the clkctrl specific flags to their own bit-range. Signed-off-by: Tero Kristo Fixes: 49159a9dc3da ("clk: ti: add support for CLK_SET_RATE_PARENT flag") Reported-by: Christophe Lyon Tested-by: Tony Lindgren --- drivers/clk/ti/clock.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/clk/ti/clock.h b/drivers/clk/ti/clock.h index d9b43bfc2532..b799a21463d9 100644 --- a/drivers/clk/ti/clock.h +++ b/drivers/clk/ti/clock.h @@ -74,6 +74,11 @@ enum { #define CLKF_CORE (1 << 9) #define CLKF_J_TYPE (1 << 10) +/* CLKCTRL flags */ +#define CLKF_SW_SUP BIT(5) +#define CLKF_HW_SUP BIT(6) +#define CLKF_NO_IDLEST BIT(7) + #define CLK(dev, con, ck) \ { \ .lk = { \ @@ -183,10 +188,6 @@ extern const struct omap_clkctrl_data am438x_clkctrl_data[]; extern const struct omap_clkctrl_data dm814_clkctrl_data[]; extern const struct omap_clkctrl_data dm816_clkctrl_data[]; -#define CLKF_SW_SUP BIT(0) -#define CLKF_HW_SUP BIT(1) -#define CLKF_NO_IDLEST BIT(2) - typedef void (*ti_of_clk_init_cb_t)(void *, struct device_node *); struct clk *ti_clk_register(struct device *dev, struct clk_hw *hw, -- cgit From 89727949ea1e5f8ec481cba4d5c71c32d8bff3bc Mon Sep 17 00:00:00 2001 From: Dinh Nguyen Date: Wed, 21 Mar 2018 09:20:10 -0500 Subject: dt-bindings: documentation: add clock bindings information for Stratix10 Document that Stratix10 clock bindings, and add the clock header file. The clock header is an enumeration of all the different clocks on the Stratix10 platform. Signed-off-by: Dinh Nguyen Reviewed-by: Rob Herring Signed-off-by: Stephen Boyd --- .../devicetree/bindings/clock/intc_stratix10.txt | 20 ++++++ include/dt-bindings/clock/stratix10-clock.h | 84 ++++++++++++++++++++++ 2 files changed, 104 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/intc_stratix10.txt create mode 100644 include/dt-bindings/clock/stratix10-clock.h diff --git a/Documentation/devicetree/bindings/clock/intc_stratix10.txt b/Documentation/devicetree/bindings/clock/intc_stratix10.txt new file mode 100644 index 000000000000..9f4ec5cb5c6b --- /dev/null +++ b/Documentation/devicetree/bindings/clock/intc_stratix10.txt @@ -0,0 +1,20 @@ +Device Tree Clock bindings for Intel's SoCFPGA Stratix10 platform + +This binding uses the common clock binding[1]. + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt + +Required properties: +- compatible : shall be + "intel,stratix10-clkmgr" + +- reg : shall be the control register offset from CLOCK_MANAGER's base for the clock. + +- #clock-cells : from common clock binding, shall be set to 1. + +Example: + clkmgr: clock-controller@ffd10000 { + compatible = "intel,stratix10-clkmgr"; + reg = <0xffd10000 0x1000>; + #clock-cells = <1>; + }; diff --git a/include/dt-bindings/clock/stratix10-clock.h b/include/dt-bindings/clock/stratix10-clock.h new file mode 100644 index 000000000000..0ac1c90a18bf --- /dev/null +++ b/include/dt-bindings/clock/stratix10-clock.h @@ -0,0 +1,84 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2017, Intel Corporation + */ + +#ifndef __STRATIX10_CLOCK_H +#define __STRATIX10_CLOCK_H + +/* fixed rate clocks */ +#define STRATIX10_OSC1 0 +#define STRATIX10_CB_INTOSC_HS_DIV2_CLK 1 +#define STRATIX10_CB_INTOSC_LS_CLK 2 +#define STRATIX10_F2S_FREE_CLK 3 + +/* fixed factor clocks */ +#define STRATIX10_L4_SYS_FREE_CLK 4 +#define STRATIX10_MPU_PERIPH_CLK 5 +#define STRATIX10_MPU_L2RAM_CLK 6 +#define STRATIX10_SDMMC_CIU_CLK 7 + +/* PLL clocks */ +#define STRATIX10_MAIN_PLL_CLK 8 +#define STRATIX10_PERIPH_PLL_CLK 9 +#define STRATIX10_BOOT_CLK 10 + +/* Periph clocks */ +#define STRATIX10_MAIN_MPU_BASE_CLK 11 +#define STRATIX10_MAIN_NOC_BASE_CLK 12 +#define STRATIX10_MAIN_EMACA_CLK 13 +#define STRATIX10_MAIN_EMACB_CLK 14 +#define STRATIX10_MAIN_EMAC_PTP_CLK 15 +#define STRATIX10_MAIN_GPIO_DB_CLK 16 +#define STRATIX10_MAIN_SDMMC_CLK 17 +#define STRATIX10_MAIN_S2F_USR0_CLK 18 +#define STRATIX10_MAIN_S2F_USR1_CLK 19 +#define STRATIX10_MAIN_PSI_REF_CLK 20 + +#define STRATIX10_PERI_MPU_BASE_CLK 21 +#define STRATIX10_PERI_NOC_BASE_CLK 22 +#define STRATIX10_PERI_EMACA_CLK 23 +#define STRATIX10_PERI_EMACB_CLK 24 +#define STRATIX10_PERI_EMAC_PTP_CLK 25 +#define STRATIX10_PERI_GPIO_DB_CLK 26 +#define STRATIX10_PERI_SDMMC_CLK 27 +#define STRATIX10_PERI_S2F_USR0_CLK 28 +#define STRATIX10_PERI_S2F_USR1_CLK 29 +#define STRATIX10_PERI_PSI_REF_CLK 30 + +#define STRATIX10_MPU_FREE_CLK 31 +#define STRATIX10_NOC_FREE_CLK 32 +#define STRATIX10_S2F_USR0_CLK 33 +#define STRATIX10_NOC_CLK 34 +#define STRATIX10_EMAC_A_FREE_CLK 35 +#define STRATIX10_EMAC_B_FREE_CLK 36 +#define STRATIX10_EMAC_PTP_FREE_CLK 37 +#define STRATIX10_GPIO_DB_FREE_CLK 38 +#define STRATIX10_SDMMC_FREE_CLK 39 +#define STRATIX10_S2F_USER1_FREE_CLK 40 +#define STRATIX10_PSI_REF_FREE_CLK 41 + +/* Gate clocks */ +#define STRATIX10_MPU_CLK 42 +#define STRATIX10_L4_MAIN_CLK 43 +#define STRATIX10_L4_MP_CLK 44 +#define STRATIX10_L4_SP_CLK 45 +#define STRATIX10_CS_AT_CLK 46 +#define STRATIX10_CS_TRACE_CLK 47 +#define STRATIX10_CS_PDBG_CLK 48 +#define STRATIX10_CS_TIMER_CLK 49 +#define STRATIX10_S2F_USER0_CLK 50 +#define STRATIX10_S2F_USER1_CLK 51 +#define STRATIX10_EMAC0_CLK 52 +#define STRATIX10_EMAC1_CLK 53 +#define STRATIX10_EMAC2_CLK 54 +#define STRATIX10_EMAC_PTP_CLK 55 +#define STRATIX10_GPIO_DB_CLK 56 +#define STRATIX10_SDMMC_CLK 57 +#define STRATIX10_PSI_REF_CLK 58 +#define STRATIX10_USB_CLK 59 +#define STRATIX10_SPI_M_CLK 60 +#define STRATIX10_NAND_CLK 61 +#define STRATIX10_NUM_CLKS 62 + +#endif /* __STRATIX10_CLOCK_H */ -- cgit From 07afb8db7340f9b6051a26c5c28f2ce74148f6b5 Mon Sep 17 00:00:00 2001 From: Dinh Nguyen Date: Wed, 21 Mar 2018 09:20:12 -0500 Subject: clk: socfpga: stratix10: add clock driver for Stratix10 platform Add a clock driver for the Stratix10 SoC. The driver is similar to the Cyclone5/Arria10 platforms, with the exception that this driver only uses one single clock binding. Signed-off-by: Dinh Nguyen Signed-off-by: Stephen Boyd --- drivers/clk/Makefile | 1 + drivers/clk/socfpga/Makefile | 9 +- drivers/clk/socfpga/clk-gate-s10.c | 125 +++++++++++++ drivers/clk/socfpga/clk-periph-s10.c | 149 +++++++++++++++ drivers/clk/socfpga/clk-pll-s10.c | 146 +++++++++++++++ drivers/clk/socfpga/clk-s10.c | 345 +++++++++++++++++++++++++++++++++++ drivers/clk/socfpga/clk.h | 4 + drivers/clk/socfpga/stratix10-clk.h | 80 ++++++++ 8 files changed, 854 insertions(+), 5 deletions(-) create mode 100644 drivers/clk/socfpga/clk-gate-s10.c create mode 100644 drivers/clk/socfpga/clk-periph-s10.c create mode 100644 drivers/clk/socfpga/clk-pll-s10.c create mode 100644 drivers/clk/socfpga/clk-s10.c create mode 100644 drivers/clk/socfpga/stratix10-clk.h diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 71ec41e6364f..80ab422438ee 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -88,6 +88,7 @@ obj-$(CONFIG_ARCH_SOCFPGA) += socfpga/ obj-$(CONFIG_PLAT_SPEAR) += spear/ obj-$(CONFIG_ARCH_SPRD) += sprd/ obj-$(CONFIG_ARCH_STI) += st/ +obj-$(CONFIG_ARCH_STRATIX10) += socfpga/ obj-$(CONFIG_ARCH_SUNXI) += sunxi/ obj-$(CONFIG_ARCH_SUNXI) += sunxi-ng/ obj-$(CONFIG_ARCH_TEGRA) += tegra/ diff --git a/drivers/clk/socfpga/Makefile b/drivers/clk/socfpga/Makefile index 9146c20fe21f..ce5aa7802eb8 100644 --- a/drivers/clk/socfpga/Makefile +++ b/drivers/clk/socfpga/Makefile @@ -1,6 +1,5 @@ # SPDX-License-Identifier: GPL-2.0 -obj-y += clk.o -obj-y += clk-gate.o -obj-y += clk-pll.o -obj-y += clk-periph.o -obj-y += clk-pll-a10.o clk-periph-a10.o clk-gate-a10.o +obj-$(CONFIG_ARCH_SOCFPGA) += clk.o clk-gate.o clk-pll.o clk-periph.o +obj-$(CONFIG_ARCH_SOCFPGA) += clk-pll-a10.o clk-periph-a10.o clk-gate-a10.o +obj-$(CONFIG_ARCH_STRATIX10) += clk-s10.o +obj-$(CONFIG_ARCH_STRATIX10) += clk-pll-s10.o clk-periph-s10.o clk-gate-s10.o diff --git a/drivers/clk/socfpga/clk-gate-s10.c b/drivers/clk/socfpga/clk-gate-s10.c new file mode 100644 index 000000000000..eee2d48ab656 --- /dev/null +++ b/drivers/clk/socfpga/clk-gate-s10.c @@ -0,0 +1,125 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2017, Intel Corporation + */ +#include +#include +#include "stratix10-clk.h" +#include "clk.h" + +#define SOCFPGA_CS_PDBG_CLK "cs_pdbg_clk" +#define to_socfpga_gate_clk(p) container_of(p, struct socfpga_gate_clk, hw.hw) + +static unsigned long socfpga_gate_clk_recalc_rate(struct clk_hw *hwclk, + unsigned long parent_rate) +{ + struct socfpga_gate_clk *socfpgaclk = to_socfpga_gate_clk(hwclk); + u32 div = 1, val; + + if (socfpgaclk->fixed_div) { + div = socfpgaclk->fixed_div; + } else if (socfpgaclk->div_reg) { + val = readl(socfpgaclk->div_reg) >> socfpgaclk->shift; + val &= GENMASK(socfpgaclk->width - 1, 0); + div = (1 << val); + } + return parent_rate / div; +} + +static unsigned long socfpga_dbg_clk_recalc_rate(struct clk_hw *hwclk, + unsigned long parent_rate) +{ + struct socfpga_gate_clk *socfpgaclk = to_socfpga_gate_clk(hwclk); + u32 div = 1, val; + + val = readl(socfpgaclk->div_reg) >> socfpgaclk->shift; + val &= GENMASK(socfpgaclk->width - 1, 0); + div = (1 << val); + div = div ? 4 : 1; + + return parent_rate / div; +} + +static u8 socfpga_gate_get_parent(struct clk_hw *hwclk) +{ + struct socfpga_gate_clk *socfpgaclk = to_socfpga_gate_clk(hwclk); + u32 mask; + u8 parent = 0; + + if (socfpgaclk->bypass_reg) { + mask = (0x1 << socfpgaclk->bypass_shift); + parent = ((readl(socfpgaclk->bypass_reg) & mask) >> + socfpgaclk->bypass_shift); + } + return parent; +} + +static struct clk_ops gateclk_ops = { + .recalc_rate = socfpga_gate_clk_recalc_rate, + .get_parent = socfpga_gate_get_parent, +}; + +static const struct clk_ops dbgclk_ops = { + .recalc_rate = socfpga_dbg_clk_recalc_rate, + .get_parent = socfpga_gate_get_parent, +}; + +struct clk *s10_register_gate(const char *name, const char *parent_name, + const char * const *parent_names, + u8 num_parents, unsigned long flags, + void __iomem *regbase, unsigned long gate_reg, + unsigned long gate_idx, unsigned long div_reg, + unsigned long div_offset, u8 div_width, + unsigned long bypass_reg, u8 bypass_shift, + u8 fixed_div) +{ + struct clk *clk; + struct socfpga_gate_clk *socfpga_clk; + struct clk_init_data init; + + socfpga_clk = kzalloc(sizeof(*socfpga_clk), GFP_KERNEL); + if (!socfpga_clk) + return NULL; + + socfpga_clk->hw.reg = regbase + gate_reg; + socfpga_clk->hw.bit_idx = gate_idx; + + gateclk_ops.enable = clk_gate_ops.enable; + gateclk_ops.disable = clk_gate_ops.disable; + + socfpga_clk->fixed_div = fixed_div; + + if (div_reg) + socfpga_clk->div_reg = regbase + div_reg; + else + socfpga_clk->div_reg = NULL; + + socfpga_clk->width = div_width; + socfpga_clk->shift = div_offset; + + if (bypass_reg) + socfpga_clk->bypass_reg = regbase + bypass_reg; + else + socfpga_clk->bypass_reg = NULL; + socfpga_clk->bypass_shift = bypass_shift; + + if (streq(name, "cs_pdbg_clk")) + init.ops = &dbgclk_ops; + else + init.ops = &gateclk_ops; + + init.name = name; + init.flags = flags; + + init.num_parents = num_parents; + init.parent_names = parent_names ? parent_names : &parent_name; + socfpga_clk->hw.hw.init = &init; + + clk = clk_register(NULL, &socfpga_clk->hw.hw); + if (WARN_ON(IS_ERR(clk))) { + kfree(socfpga_clk); + return NULL; + } + + return clk; +} diff --git a/drivers/clk/socfpga/clk-periph-s10.c b/drivers/clk/socfpga/clk-periph-s10.c new file mode 100644 index 000000000000..568f59b58ddf --- /dev/null +++ b/drivers/clk/socfpga/clk-periph-s10.c @@ -0,0 +1,149 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2017, Intel Corporation + */ +#include +#include + +#include "stratix10-clk.h" +#include "clk.h" + +#define CLK_MGR_FREE_SHIFT 16 +#define CLK_MGR_FREE_MASK 0x7 +#define SWCTRLBTCLKSEN_SHIFT 8 + +#define to_periph_clk(p) container_of(p, struct socfpga_periph_clk, hw.hw) + +static unsigned long clk_peri_c_clk_recalc_rate(struct clk_hw *hwclk, + unsigned long parent_rate) +{ + struct socfpga_periph_clk *socfpgaclk = to_periph_clk(hwclk); + unsigned long div = 1; + u32 val; + + val = readl(socfpgaclk->hw.reg); + val &= GENMASK(SWCTRLBTCLKSEN_SHIFT - 1, 0); + parent_rate /= val; + + return parent_rate / div; +} + +static unsigned long clk_peri_cnt_clk_recalc_rate(struct clk_hw *hwclk, + unsigned long parent_rate) +{ + struct socfpga_periph_clk *socfpgaclk = to_periph_clk(hwclk); + unsigned long div = 1; + + if (socfpgaclk->fixed_div) { + div = socfpgaclk->fixed_div; + } else { + if (!socfpgaclk->bypass_reg) + div = ((readl(socfpgaclk->hw.reg) & 0x7ff) + 1); + } + + return parent_rate / div; +} + +static u8 clk_periclk_get_parent(struct clk_hw *hwclk) +{ + struct socfpga_periph_clk *socfpgaclk = to_periph_clk(hwclk); + u32 clk_src, mask; + u8 parent; + + if (socfpgaclk->bypass_reg) { + mask = (0x1 << socfpgaclk->bypass_shift); + parent = ((readl(socfpgaclk->bypass_reg) & mask) >> + socfpgaclk->bypass_shift); + } else { + clk_src = readl(socfpgaclk->hw.reg); + parent = (clk_src >> CLK_MGR_FREE_SHIFT) & + CLK_MGR_FREE_MASK; + } + return parent; +} + +static const struct clk_ops peri_c_clk_ops = { + .recalc_rate = clk_peri_c_clk_recalc_rate, + .get_parent = clk_periclk_get_parent, +}; + +static const struct clk_ops peri_cnt_clk_ops = { + .recalc_rate = clk_peri_cnt_clk_recalc_rate, + .get_parent = clk_periclk_get_parent, +}; + +struct clk *s10_register_periph(const char *name, const char *parent_name, + const char * const *parent_names, + u8 num_parents, unsigned long flags, + void __iomem *reg, unsigned long offset) +{ + struct clk *clk; + struct socfpga_periph_clk *periph_clk; + struct clk_init_data init; + + periph_clk = kzalloc(sizeof(*periph_clk), GFP_KERNEL); + if (WARN_ON(!periph_clk)) + return NULL; + + periph_clk->hw.reg = reg + offset; + + init.name = name; + init.ops = &peri_c_clk_ops; + init.flags = flags; + + init.num_parents = num_parents; + init.parent_names = parent_names ? parent_names : &parent_name; + + periph_clk->hw.hw.init = &init; + + clk = clk_register(NULL, &periph_clk->hw.hw); + if (WARN_ON(IS_ERR(clk))) { + kfree(periph_clk); + return NULL; + } + return clk; +} + +struct clk *s10_register_cnt_periph(const char *name, const char *parent_name, + const char * const *parent_names, + u8 num_parents, unsigned long flags, + void __iomem *regbase, unsigned long offset, + u8 fixed_divider, unsigned long bypass_reg, + unsigned long bypass_shift) +{ + struct clk *clk; + struct socfpga_periph_clk *periph_clk; + struct clk_init_data init; + + periph_clk = kzalloc(sizeof(*periph_clk), GFP_KERNEL); + if (WARN_ON(!periph_clk)) + return NULL; + + if (offset) + periph_clk->hw.reg = regbase + offset; + else + periph_clk->hw.reg = NULL; + + if (bypass_reg) + periph_clk->bypass_reg = regbase + bypass_reg; + else + periph_clk->bypass_reg = NULL; + periph_clk->bypass_shift = bypass_shift; + periph_clk->fixed_div = fixed_divider; + + init.name = name; + init.ops = &peri_cnt_clk_ops; + init.flags = flags; + + init.num_parents = num_parents; + init.parent_names = parent_names ? parent_names : &parent_name; + + periph_clk->hw.hw.init = &init; + + clk = clk_register(NULL, &periph_clk->hw.hw); + if (WARN_ON(IS_ERR(clk))) { + kfree(periph_clk); + return NULL; + } + return clk; +} diff --git a/drivers/clk/socfpga/clk-pll-s10.c b/drivers/clk/socfpga/clk-pll-s10.c new file mode 100644 index 000000000000..2d5d8b43727e --- /dev/null +++ b/drivers/clk/socfpga/clk-pll-s10.c @@ -0,0 +1,146 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2017, Intel Corporation + */ +#include +#include + +#include "stratix10-clk.h" +#include "clk.h" + +/* Clock Manager offsets */ +#define CLK_MGR_PLL_CLK_SRC_SHIFT 16 +#define CLK_MGR_PLL_CLK_SRC_MASK 0x3 + +/* PLL Clock enable bits */ +#define SOCFPGA_PLL_POWER 0 +#define SOCFPGA_PLL_RESET_MASK 0x2 +#define SOCFPGA_PLL_REFDIV_MASK 0x00003F00 +#define SOCFPGA_PLL_REFDIV_SHIFT 8 +#define SOCFPGA_PLL_MDIV_MASK 0xFF000000 +#define SOCFPGA_PLL_MDIV_SHIFT 24 +#define SWCTRLBTCLKSEL_MASK 0x200 +#define SWCTRLBTCLKSEL_SHIFT 9 + +#define SOCFPGA_BOOT_CLK "boot_clk" + +#define to_socfpga_clk(p) container_of(p, struct socfpga_pll, hw.hw) + +static unsigned long clk_pll_recalc_rate(struct clk_hw *hwclk, + unsigned long parent_rate) +{ + struct socfpga_pll *socfpgaclk = to_socfpga_clk(hwclk); + unsigned long mdiv; + unsigned long refdiv; + unsigned long reg; + unsigned long long vco_freq; + + /* read VCO1 reg for numerator and denominator */ + reg = readl(socfpgaclk->hw.reg); + refdiv = (reg & SOCFPGA_PLL_REFDIV_MASK) >> SOCFPGA_PLL_REFDIV_SHIFT; + vco_freq = (unsigned long long)parent_rate / refdiv; + + /* Read mdiv and fdiv from the fdbck register */ + reg = readl(socfpgaclk->hw.reg + 0x4); + mdiv = (reg & SOCFPGA_PLL_MDIV_MASK) >> SOCFPGA_PLL_MDIV_SHIFT; + vco_freq = (unsigned long long)parent_rate * (mdiv + 6); + + return (unsigned long)vco_freq; +} + +static unsigned long clk_boot_clk_recalc_rate(struct clk_hw *hwclk, + unsigned long parent_rate) +{ + struct socfpga_pll *socfpgaclk = to_socfpga_clk(hwclk); + u32 div = 1; + + div = ((readl(socfpgaclk->hw.reg) & + SWCTRLBTCLKSEL_MASK) >> + SWCTRLBTCLKSEL_SHIFT); + div += 1; + return parent_rate /= div; +} + + +static u8 clk_pll_get_parent(struct clk_hw *hwclk) +{ + struct socfpga_pll *socfpgaclk = to_socfpga_clk(hwclk); + u32 pll_src; + + pll_src = readl(socfpgaclk->hw.reg); + return (pll_src >> CLK_MGR_PLL_CLK_SRC_SHIFT) & + CLK_MGR_PLL_CLK_SRC_MASK; +} + +static u8 clk_boot_get_parent(struct clk_hw *hwclk) +{ + struct socfpga_pll *socfpgaclk = to_socfpga_clk(hwclk); + u32 pll_src; + + pll_src = readl(socfpgaclk->hw.reg); + return (pll_src >> SWCTRLBTCLKSEL_SHIFT) & + SWCTRLBTCLKSEL_MASK; +} + +static int clk_pll_prepare(struct clk_hw *hwclk) +{ + struct socfpga_pll *socfpgaclk = to_socfpga_clk(hwclk); + u32 reg; + + /* Bring PLL out of reset */ + reg = readl(socfpgaclk->hw.reg); + reg |= SOCFPGA_PLL_RESET_MASK; + writel(reg, socfpgaclk->hw.reg); + + return 0; +} + +static struct clk_ops clk_pll_ops = { + .recalc_rate = clk_pll_recalc_rate, + .get_parent = clk_pll_get_parent, + .prepare = clk_pll_prepare, +}; + +static struct clk_ops clk_boot_ops = { + .recalc_rate = clk_boot_clk_recalc_rate, + .get_parent = clk_boot_get_parent, + .prepare = clk_pll_prepare, +}; + +struct clk *s10_register_pll(const char *name, const char * const *parent_names, + u8 num_parents, unsigned long flags, + void __iomem *reg, unsigned long offset) +{ + struct clk *clk; + struct socfpga_pll *pll_clk; + struct clk_init_data init; + + pll_clk = kzalloc(sizeof(*pll_clk), GFP_KERNEL); + if (WARN_ON(!pll_clk)) + return NULL; + + pll_clk->hw.reg = reg + offset; + + if (streq(name, SOCFPGA_BOOT_CLK)) + init.ops = &clk_boot_ops; + else + init.ops = &clk_pll_ops; + + init.name = name; + init.flags = flags; + + init.num_parents = num_parents; + init.parent_names = parent_names; + pll_clk->hw.hw.init = &init; + + pll_clk->hw.bit_idx = SOCFPGA_PLL_POWER; + clk_pll_ops.enable = clk_gate_ops.enable; + clk_pll_ops.disable = clk_gate_ops.disable; + + clk = clk_register(NULL, &pll_clk->hw.hw); + if (WARN_ON(IS_ERR(clk))) { + kfree(pll_clk); + return NULL; + } + return clk; +} diff --git a/drivers/clk/socfpga/clk-s10.c b/drivers/clk/socfpga/clk-s10.c new file mode 100644 index 000000000000..3a11c382a663 --- /dev/null +++ b/drivers/clk/socfpga/clk-s10.c @@ -0,0 +1,345 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2017, Intel Corporation + */ +#include +#include +#include +#include +#include + +#include + +#include "stratix10-clk.h" + +static const char * const pll_mux[] = { "osc1", "cb_intosc_hs_div2_clk", + "f2s_free_clk",}; +static const char * const cntr_mux[] = { "main_pll", "periph_pll", + "osc1", "cb_intosc_hs_div2_clk", + "f2s_free_clk"}; +static const char * const boot_mux[] = { "osc1", "cb_intosc_hs_div2_clk",}; + +static const char * const noc_free_mux[] = {"main_noc_base_clk", + "peri_noc_base_clk", + "osc1", "cb_intosc_hs_div2_clk", + "f2s_free_clk"}; + +static const char * const emaca_free_mux[] = {"peri_emaca_clk", "boot_clk"}; +static const char * const emacb_free_mux[] = {"peri_emacb_clk", "boot_clk"}; +static const char * const emac_ptp_free_mux[] = {"peri_emac_ptp_clk", "boot_clk"}; +static const char * const gpio_db_free_mux[] = {"peri_gpio_db_clk", "boot_clk"}; +static const char * const sdmmc_free_mux[] = {"peri_sdmmc_clk", "boot_clk"}; +static const char * const s2f_usr1_free_mux[] = {"peri_s2f_usr1_clk", "boot_clk"}; +static const char * const psi_ref_free_mux[] = {"peri_psi_ref_clk", "boot_clk"}; +static const char * const mpu_mux[] = { "mpu_free_clk", "boot_clk",}; + +static const char * const s2f_usr0_mux[] = {"f2s_free_clk", "boot_clk"}; +static const char * const emac_mux[] = {"emaca_free_clk", "emacb_free_clk"}; +static const char * const noc_mux[] = {"noc_free_clk", "boot_clk"}; + +/* clocks in AO (always on) controller */ +static const struct stratix10_pll_clock s10_pll_clks[] = { + { STRATIX10_BOOT_CLK, "boot_clk", boot_mux, ARRAY_SIZE(boot_mux), 0, + 0x0}, + { STRATIX10_MAIN_PLL_CLK, "main_pll", pll_mux, ARRAY_SIZE(pll_mux), + 0, 0x74}, + { STRATIX10_PERIPH_PLL_CLK, "periph_pll", pll_mux, ARRAY_SIZE(pll_mux), + 0, 0xe4}, +}; + +static const struct stratix10_perip_c_clock s10_main_perip_c_clks[] = { + { STRATIX10_MAIN_MPU_BASE_CLK, "main_mpu_base_clk", "main_pll", NULL, 1, 0, 0x84}, + { STRATIX10_MAIN_NOC_BASE_CLK, "main_noc_base_clk", "main_pll", NULL, 1, 0, 0x88}, + { STRATIX10_PERI_MPU_BASE_CLK, "peri_mpu_base_clk", "periph_pll", NULL, 1, 0, + 0xF4}, + { STRATIX10_PERI_NOC_BASE_CLK, "peri_noc_base_clk", "periph_pll", NULL, 1, 0, + 0xF8}, +}; + +static const struct stratix10_perip_cnt_clock s10_main_perip_cnt_clks[] = { + { STRATIX10_MPU_FREE_CLK, "mpu_free_clk", NULL, cntr_mux, ARRAY_SIZE(cntr_mux), + 0, 0x48, 0, 0, 0}, + { STRATIX10_NOC_FREE_CLK, "noc_free_clk", NULL, noc_free_mux, ARRAY_SIZE(noc_free_mux), + 0, 0x4C, 0, 0, 0}, + { STRATIX10_MAIN_EMACA_CLK, "main_emaca_clk", "main_noc_base_clk", NULL, 1, 0, + 0x50, 0, 0, 0}, + { STRATIX10_MAIN_EMACB_CLK, "main_emacb_clk", "main_noc_base_clk", NULL, 1, 0, + 0x54, 0, 0, 0}, + { STRATIX10_MAIN_EMAC_PTP_CLK, "main_emac_ptp_clk", "main_noc_base_clk", NULL, 1, 0, + 0x58, 0, 0, 0}, + { STRATIX10_MAIN_GPIO_DB_CLK, "main_gpio_db_clk", "main_noc_base_clk", NULL, 1, 0, + 0x5C, 0, 0, 0}, + { STRATIX10_MAIN_SDMMC_CLK, "main_sdmmc_clk", "main_noc_base_clk", NULL, 1, 0, + 0x60, 0, 0, 0}, + { STRATIX10_MAIN_S2F_USR0_CLK, "main_s2f_usr0_clk", NULL, cntr_mux, ARRAY_SIZE(cntr_mux), + 0, 0x64, 0, 0, 0}, + { STRATIX10_MAIN_S2F_USR1_CLK, "main_s2f_usr1_clk", "main_noc_base_clk", NULL, 1, 0, + 0x68, 0, 0, 0}, + { STRATIX10_MAIN_PSI_REF_CLK, "main_psi_ref_clk", "main_noc_base_clk", NULL, 1, 0, + 0x6C, 0, 0, 0}, + { STRATIX10_PERI_EMACA_CLK, "peri_emaca_clk", NULL, cntr_mux, ARRAY_SIZE(cntr_mux), + 0, 0xBC, 0, 0, 0}, + { STRATIX10_PERI_EMACB_CLK, "peri_emacb_clk", NULL, cntr_mux, ARRAY_SIZE(cntr_mux), + 0, 0xC0, 0, 0, 0}, + { STRATIX10_PERI_EMAC_PTP_CLK, "peri_emac_ptp_clk", NULL, cntr_mux, ARRAY_SIZE(cntr_mux), + 0, 0xC4, 0, 0, 0}, + { STRATIX10_PERI_GPIO_DB_CLK, "peri_gpio_db_clk", NULL, cntr_mux, ARRAY_SIZE(cntr_mux), + 0, 0xC8, 0, 0, 0}, + { STRATIX10_PERI_SDMMC_CLK, "peri_sdmmc_clk", NULL, cntr_mux, ARRAY_SIZE(cntr_mux), + 0, 0xCC, 0, 0, 0}, + { STRATIX10_PERI_S2F_USR0_CLK, "peri_s2f_usr0_clk", "peri_noc_base_clk", NULL, 1, 0, + 0xD0, 0, 0, 0}, + { STRATIX10_PERI_S2F_USR1_CLK, "peri_s2f_usr1_clk", NULL, cntr_mux, ARRAY_SIZE(cntr_mux), + 0, 0xD4, 0, 0, 0}, + { STRATIX10_PERI_PSI_REF_CLK, "peri_psi_ref_clk", "peri_noc_base_clk", NULL, 1, 0, + 0xD8, 0, 0, 0}, + { STRATIX10_L4_SYS_FREE_CLK, "l4_sys_free_clk", "noc_free_clk", NULL, 1, 0, + 0, 4, 0, 0}, + { STRATIX10_NOC_CLK, "noc_clk", NULL, noc_mux, ARRAY_SIZE(noc_mux), + 0, 0, 0, 0x3C, 1}, + { STRATIX10_EMAC_A_FREE_CLK, "emaca_free_clk", NULL, emaca_free_mux, ARRAY_SIZE(emaca_free_mux), + 0, 0, 4, 0xB0, 0}, + { STRATIX10_EMAC_B_FREE_CLK, "emacb_free_clk", NULL, emacb_free_mux, ARRAY_SIZE(emacb_free_mux), + 0, 0, 4, 0xB0, 1}, + { STRATIX10_EMAC_PTP_FREE_CLK, "emac_ptp_free_clk", NULL, emac_ptp_free_mux, + ARRAY_SIZE(emac_ptp_free_mux), 0, 0, 4, 0xB0, 2}, + { STRATIX10_GPIO_DB_FREE_CLK, "gpio_db_free_clk", NULL, gpio_db_free_mux, + ARRAY_SIZE(gpio_db_free_mux), 0, 0, 0, 0xB0, 3}, + { STRATIX10_SDMMC_FREE_CLK, "sdmmc_free_clk", NULL, sdmmc_free_mux, + ARRAY_SIZE(sdmmc_free_mux), 0, 0, 0, 0xB0, 4}, + { STRATIX10_S2F_USER1_FREE_CLK, "s2f_user1_free_clk", NULL, s2f_usr1_free_mux, + ARRAY_SIZE(s2f_usr1_free_mux), 0, 0, 0, 0xB0, 5}, + { STRATIX10_PSI_REF_FREE_CLK, "psi_ref_free_clk", NULL, psi_ref_free_mux, + ARRAY_SIZE(psi_ref_free_mux), 0, 0, 0, 0xB0, 6}, +}; + +static const struct stratix10_gate_clock s10_gate_clks[] = { + { STRATIX10_MPU_CLK, "mpu_clk", NULL, mpu_mux, ARRAY_SIZE(mpu_mux), 0, 0x30, + 0, 0, 0, 0, 0x3C, 0, 0}, + { STRATIX10_MPU_PERIPH_CLK, "mpu_periph_clk", "mpu_clk", NULL, 1, 0, 0x30, + 0, 0, 0, 0, 0, 0, 4}, + { STRATIX10_MPU_L2RAM_CLK, "mpu_l2ram_clk", "mpu_clk", NULL, 1, 0, 0x30, + 0, 0, 0, 0, 0, 0, 2}, + { STRATIX10_L4_MAIN_CLK, "l4_main_clk", "noc_clk", NULL, 1, 0, 0x30, + 1, 0x70, 0, 2, 0, 0, 0}, + { STRATIX10_L4_MP_CLK, "l4_mp_clk", "noc_clk", NULL, 1, 0, 0x30, + 2, 0x70, 8, 2, 0, 0, 0}, + { STRATIX10_L4_SP_CLK, "l4_sp_clk", "noc_clk", NULL, 1, CLK_IS_CRITICAL, 0x30, + 3, 0x70, 16, 2, 0, 0, 0}, + { STRATIX10_CS_AT_CLK, "cs_at_clk", "noc_clk", NULL, 1, 0, 0x30, + 4, 0x70, 24, 2, 0, 0, 0}, + { STRATIX10_CS_TRACE_CLK, "cs_trace_clk", "noc_clk", NULL, 1, 0, 0x30, + 4, 0x70, 26, 2, 0, 0, 0}, + { STRATIX10_CS_PDBG_CLK, "cs_pdbg_clk", "cs_at_clk", NULL, 1, 0, 0x30, + 4, 0x70, 28, 1, 0, 0, 0}, + { STRATIX10_CS_TIMER_CLK, "cs_timer_clk", "noc_clk", NULL, 1, 0, 0x30, + 5, 0, 0, 0, 0, 0, 0}, + { STRATIX10_S2F_USER0_CLK, "s2f_user0_clk", NULL, s2f_usr0_mux, ARRAY_SIZE(s2f_usr0_mux), 0, 0x30, + 6, 0, 0, 0, 0, 0, 0}, + { STRATIX10_EMAC0_CLK, "emac0_clk", NULL, emac_mux, ARRAY_SIZE(emac_mux), 0, 0xA4, + 0, 0, 0, 0, 0xDC, 26, 0}, + { STRATIX10_EMAC1_CLK, "emac1_clk", NULL, emac_mux, ARRAY_SIZE(emac_mux), 0, 0xA4, + 1, 0, 0, 0, 0xDC, 27, 0}, + { STRATIX10_EMAC2_CLK, "emac2_clk", NULL, emac_mux, ARRAY_SIZE(emac_mux), 0, 0xA4, + 2, 0, 0, 0, 0xDC, 28, 0}, + { STRATIX10_EMAC_PTP_CLK, "emac_ptp_clk", "emac_ptp_free_clk", NULL, 1, 0, 0xA4, + 3, 0, 0, 0, 0, 0, 0}, + { STRATIX10_GPIO_DB_CLK, "gpio_db_clk", "gpio_db_free_clk", NULL, 1, 0, 0xA4, + 4, 0xE0, 0, 16, 0, 0, 0}, + { STRATIX10_SDMMC_CLK, "sdmmc_clk", "sdmmc_free_clk", NULL, 1, 0, 0xA4, + 5, 0, 0, 0, 0, 0, 4}, + { STRATIX10_S2F_USER1_CLK, "s2f_user1_clk", "s2f_user1_free_clk", NULL, 1, 0, 0xA4, + 6, 0, 0, 0, 0, 0, 0}, + { STRATIX10_PSI_REF_CLK, "psi_ref_clk", "psi_ref_free_clk", NULL, 1, 0, 0xA4, + 7, 0, 0, 0, 0, 0, 0}, + { STRATIX10_USB_CLK, "usb_clk", "l4_mp_clk", NULL, 1, 0, 0xA4, + 8, 0, 0, 0, 0, 0, 0}, + { STRATIX10_SPI_M_CLK, "spi_m_clk", "l4_mp_clk", NULL, 1, 0, 0xA4, + 9, 0, 0, 0, 0, 0, 0}, + { STRATIX10_NAND_CLK, "nand_clk", "l4_main_clk", NULL, 1, 0, 0xA4, + 10, 0, 0, 0, 0, 0, 0}, +}; + +static int s10_clk_register_c_perip(const struct stratix10_perip_c_clock *clks, + int nums, struct stratix10_clock_data *data) +{ + struct clk *clk; + void __iomem *base = data->base; + int i; + + for (i = 0; i < nums; i++) { + clk = s10_register_periph(clks[i].name, clks[i].parent_name, + clks[i].parent_names, clks[i].num_parents, + clks[i].flags, base, clks[i].offset); + if (IS_ERR(clk)) { + pr_err("%s: failed to register clock %s\n", + __func__, clks[i].name); + continue; + } + data->clk_data.clks[clks[i].id] = clk; + } + return 0; +} + +static int s10_clk_register_cnt_perip(const struct stratix10_perip_cnt_clock *clks, + int nums, struct stratix10_clock_data *data) +{ + struct clk *clk; + void __iomem *base = data->base; + int i; + + for (i = 0; i < nums; i++) { + clk = s10_register_cnt_periph(clks[i].name, clks[i].parent_name, + clks[i].parent_names, + clks[i].num_parents, + clks[i].flags, base, + clks[i].offset, + clks[i].fixed_divider, + clks[i].bypass_reg, + clks[i].bypass_shift); + if (IS_ERR(clk)) { + pr_err("%s: failed to register clock %s\n", + __func__, clks[i].name); + continue; + } + data->clk_data.clks[clks[i].id] = clk; + } + + return 0; +} + +static int s10_clk_register_gate(const struct stratix10_gate_clock *clks, + int nums, struct stratix10_clock_data *data) +{ + struct clk *clk; + void __iomem *base = data->base; + int i; + + for (i = 0; i < nums; i++) { + clk = s10_register_gate(clks[i].name, clks[i].parent_name, + clks[i].parent_names, + clks[i].num_parents, + clks[i].flags, base, + clks[i].gate_reg, + clks[i].gate_idx, clks[i].div_reg, + clks[i].div_offset, clks[i].div_width, + clks[i].bypass_reg, + clks[i].bypass_shift, + clks[i].fixed_div); + if (IS_ERR(clk)) { + pr_err("%s: failed to register clock %s\n", + __func__, clks[i].name); + continue; + } + data->clk_data.clks[clks[i].id] = clk; + } + + return 0; +} + +static int s10_clk_register_pll(const struct stratix10_pll_clock *clks, + int nums, struct stratix10_clock_data *data) +{ + struct clk *clk; + void __iomem *base = data->base; + int i; + + for (i = 0; i < nums; i++) { + clk = s10_register_pll(clks[i].name, clks[i].parent_names, + clks[i].num_parents, + clks[i].flags, base, + clks[i].offset); + if (IS_ERR(clk)) { + pr_err("%s: failed to register clock %s\n", + __func__, clks[i].name); + continue; + } + data->clk_data.clks[clks[i].id] = clk; + } + + return 0; +} + +static struct stratix10_clock_data *__socfpga_s10_clk_init(struct device_node *np, + int nr_clks) +{ + struct stratix10_clock_data *clk_data; + struct clk **clk_table; + void __iomem *base; + + base = of_iomap(np, 0); + if (!base) { + pr_err("%s: failed to map clock registers\n", __func__); + goto err; + } + + clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL); + if (!clk_data) + goto err; + + clk_data->base = base; + clk_table = kcalloc(nr_clks, sizeof(*clk_table), GFP_KERNEL); + if (!clk_table) + goto err_data; + + clk_data->clk_data.clks = clk_table; + clk_data->clk_data.clk_num = nr_clks; + of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data->clk_data); + return clk_data; + +err_data: + kfree(clk_data); +err: + return NULL; +} + +static int s10_clkmgr_init(struct device_node *np) +{ + struct stratix10_clock_data *clk_data; + + clk_data = __socfpga_s10_clk_init(np, STRATIX10_NUM_CLKS); + if (!clk_data) + return -ENOMEM; + + s10_clk_register_pll(s10_pll_clks, ARRAY_SIZE(s10_pll_clks), clk_data); + + s10_clk_register_c_perip(s10_main_perip_c_clks, + ARRAY_SIZE(s10_main_perip_c_clks), clk_data); + + s10_clk_register_cnt_perip(s10_main_perip_cnt_clks, + ARRAY_SIZE(s10_main_perip_cnt_clks), + clk_data); + + s10_clk_register_gate(s10_gate_clks, ARRAY_SIZE(s10_gate_clks), + clk_data); + return 0; +} + +static int s10_clkmgr_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + + s10_clkmgr_init(np); + + return 0; +} + +static const struct of_device_id stratix10_clkmgr_match_table[] = { + { .compatible = "intel,stratix10-clkmgr", + .data = s10_clkmgr_init }, + { } +}; + +static struct platform_driver stratix10_clkmgr_driver = { + .probe = s10_clkmgr_probe, + .driver = { + .name = "stratix10-clkmgr", + .of_match_table = stratix10_clkmgr_match_table, + }, +}; + +static int __init s10_clk_init(void) +{ + return platform_driver_register(&stratix10_clkmgr_driver); +} +core_initcall(s10_clk_init); diff --git a/drivers/clk/socfpga/clk.h b/drivers/clk/socfpga/clk.h index 9cf1230115b1..26c3a265cf78 100644 --- a/drivers/clk/socfpga/clk.h +++ b/drivers/clk/socfpga/clk.h @@ -54,9 +54,11 @@ struct socfpga_gate_clk { char *parent_name; u32 fixed_div; void __iomem *div_reg; + void __iomem *bypass_reg; struct regmap *sys_mgr_base_addr; u32 width; /* only valid if div_reg != 0 */ u32 shift; /* only valid if div_reg != 0 */ + u32 bypass_shift; /* only valid if bypass_reg != 0 */ u32 clk_phase[2]; }; @@ -65,8 +67,10 @@ struct socfpga_periph_clk { char *parent_name; u32 fixed_div; void __iomem *div_reg; + void __iomem *bypass_reg; u32 width; /* only valid if div_reg != 0 */ u32 shift; /* only valid if div_reg != 0 */ + u32 bypass_shift; /* only valid if bypass_reg != 0 */ }; #endif /* SOCFPGA_CLK_H */ diff --git a/drivers/clk/socfpga/stratix10-clk.h b/drivers/clk/socfpga/stratix10-clk.h new file mode 100644 index 000000000000..e8e121907952 --- /dev/null +++ b/drivers/clk/socfpga/stratix10-clk.h @@ -0,0 +1,80 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2017, Intel Corporation + */ + +#ifndef __STRATIX10_CLK_H +#define __STRATIX10_CLK_H + +struct stratix10_clock_data { + struct clk_onecell_data clk_data; + void __iomem *base; +}; + +struct stratix10_pll_clock { + unsigned int id; + const char *name; + const char *const *parent_names; + u8 num_parents; + unsigned long flags; + unsigned long offset; +}; + +struct stratix10_perip_c_clock { + unsigned int id; + const char *name; + const char *parent_name; + const char *const *parent_names; + u8 num_parents; + unsigned long flags; + unsigned long offset; +}; + +struct stratix10_perip_cnt_clock { + unsigned int id; + const char *name; + const char *parent_name; + const char *const *parent_names; + u8 num_parents; + unsigned long flags; + unsigned long offset; + u8 fixed_divider; + unsigned long bypass_reg; + unsigned long bypass_shift; +}; + +struct stratix10_gate_clock { + unsigned int id; + const char *name; + const char *parent_name; + const char *const *parent_names; + u8 num_parents; + unsigned long flags; + unsigned long gate_reg; + u8 gate_idx; + unsigned long div_reg; + u8 div_offset; + u8 div_width; + unsigned long bypass_reg; + u8 bypass_shift; + u8 fixed_div; +}; + +struct clk *s10_register_pll(const char *, const char *const *, u8, + unsigned long, void __iomem *, unsigned long); + +struct clk *s10_register_periph(const char *, const char *, + const char * const *, u8, unsigned long, + void __iomem *, unsigned long); +struct clk *s10_register_cnt_periph(const char *, const char *, + const char * const *, u8, + unsigned long, void __iomem *, + unsigned long, u8, unsigned long, + unsigned long); +struct clk *s10_register_gate(const char *, const char *, + const char * const *, u8, + unsigned long, void __iomem *, + unsigned long, unsigned long, + unsigned long, unsigned long, u8, + unsigned long, u8, u8); +#endif /* __STRATIX10_CLK_H */ -- cgit From 5fcb4c76bbf4dd0b9371f1b84b5baf7315e942a9 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Wed, 28 Mar 2018 09:46:35 +0300 Subject: clk: imx7d: Add USB clock information Add USB clock information, the pll_usb_main_clk is USB_PLL at CCM which is the output of USBOTG2 PHY. Signed-off-by: Peter Chen Signed-off-by: Irina Tirdea Signed-off-by: Abel Vesa Signed-off-by: Stephen Boyd --- drivers/clk/imx/clk-imx7d.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/clk/imx/clk-imx7d.c b/drivers/clk/imx/clk-imx7d.c index 89bfa75e46bd..39d110bbf5f6 100644 --- a/drivers/clk/imx/clk-imx7d.c +++ b/drivers/clk/imx/clk-imx7d.c @@ -801,7 +801,7 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node) clks[IMX7D_OCOTP_CLK] = imx_clk_gate4("ocotp_clk", "ipg_root_clk", base + 0x4230, 0); clks[IMX7D_SNVS_CLK] = imx_clk_gate4("snvs_clk", "ipg_root_clk", base + 0x4250, 0); clks[IMX7D_CAAM_CLK] = imx_clk_gate4("caam_clk", "ipg_root_clk", base + 0x4240, 0); - clks[IMX7D_USB_HSIC_ROOT_CLK] = imx_clk_gate4("usb_hsic_root_clk", "usb_hsic_post_div", base + 0x4420, 0); + clks[IMX7D_USB_HSIC_ROOT_CLK] = imx_clk_gate4("usb_hsic_root_clk", "usb_hsic_post_div", base + 0x4690, 0); clks[IMX7D_SDMA_CORE_CLK] = imx_clk_gate4("sdma_root_clk", "ahb_root_clk", base + 0x4480, 0); clks[IMX7D_PCIE_CTRL_ROOT_CLK] = imx_clk_gate4("pcie_ctrl_root_clk", "pcie_ctrl_post_div", base + 0x4600, 0); clks[IMX7D_PCIE_PHY_ROOT_CLK] = imx_clk_gate4("pcie_phy_root_clk", "pcie_phy_post_div", base + 0x4600, 0); @@ -867,6 +867,9 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node) clks[IMX7D_CSI_MCLK_ROOT_CLK] = imx_clk_gate4("csi_mclk_root_clk", "csi_mclk_post_div", base + 0x4490, 0); clks[IMX7D_AUDIO_MCLK_ROOT_CLK] = imx_clk_gate4("audio_mclk_root_clk", "audio_mclk_post_div", base + 0x4790, 0); clks[IMX7D_WRCLK_ROOT_CLK] = imx_clk_gate4("wrclk_root_clk", "wrclk_post_div", base + 0x47a0, 0); + clks[IMX7D_USB_CTRL_CLK] = imx_clk_gate4("usb_ctrl_clk", "ahb_root_clk", base + 0x4680, 0); + clks[IMX7D_USB_PHY1_CLK] = imx_clk_gate4("usb_phy1_clk", "pll_usb1_main_clk", base + 0x46a0, 0); + clks[IMX7D_USB_PHY2_CLK] = imx_clk_gate4("usb_phy2_clk", "pll_usb_main_clk", base + 0x46b0, 0); clks[IMX7D_ADC_ROOT_CLK] = imx_clk_gate4("adc_root_clk", "ipg_root_clk", base + 0x4200, 0); clks[IMX7D_GPT_3M_CLK] = imx_clk_fixed_factor("gpt_3m", "osc", 1, 8); @@ -892,6 +895,10 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node) /* set uart module clock's parent clock source that must be great then 80MHz */ clk_set_parent(clks[IMX7D_UART1_ROOT_SRC], clks[IMX7D_OSC_24M_CLK]); + /* Set clock rate for USBPHY, the USB_PLL at CCM is from USBOTG2 */ + clks[IMX7D_USB1_MAIN_480M_CLK] = imx_clk_fixed_factor("pll_usb1_main_clk", "osc", 20, 1); + clks[IMX7D_USB_MAIN_480M_CLK] = imx_clk_fixed_factor("pll_usb_main_clk", "osc", 20, 1); + imx_register_uart_clocks(uart_clks); } -- cgit From afe7c08a03a47732fa32ef12b26fb8fe4f9a00b9 Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Wed, 28 Mar 2018 09:46:37 +0300 Subject: clk: imx7d: Correct dram pll type DRAM PLL is a audio/video type PLL, need to correct it to get correct ops of PLL. There is a test_div placed before DRAM PLL's gate, so add this test div clk. Signed-off-by: Anson Huang Signed-off-by: Irina Tirdea Signed-off-by: Abel Vesa Signed-off-by: Stephen Boyd --- drivers/clk/imx/clk-imx7d.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/clk/imx/clk-imx7d.c b/drivers/clk/imx/clk-imx7d.c index 39d110bbf5f6..1cc485f6c621 100644 --- a/drivers/clk/imx/clk-imx7d.c +++ b/drivers/clk/imx/clk-imx7d.c @@ -441,11 +441,13 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node) clk_set_parent(clks[IMX7D_PLL_VIDEO_MAIN_BYPASS], clks[IMX7D_PLL_VIDEO_MAIN]); clks[IMX7D_PLL_ARM_MAIN_CLK] = imx_clk_gate("pll_arm_main_clk", "pll_arm_main_bypass", base + 0x60, 13); - clks[IMX7D_PLL_DRAM_MAIN_CLK] = imx_clk_gate("pll_dram_main_clk", "pll_dram_main_bypass", base + 0x70, 13); + clks[IMX7D_PLL_DRAM_MAIN_CLK] = imx_clk_gate("pll_dram_main_clk", "pll_dram_test_div", base + 0x70, 13); clks[IMX7D_PLL_SYS_MAIN_CLK] = imx_clk_gate("pll_sys_main_clk", "pll_sys_main_bypass", base + 0xb0, 13); clks[IMX7D_PLL_AUDIO_MAIN_CLK] = imx_clk_gate("pll_audio_main_clk", "pll_audio_main_bypass", base + 0xf0, 13); clks[IMX7D_PLL_VIDEO_MAIN_CLK] = imx_clk_gate("pll_video_main_clk", "pll_video_main_bypass", base + 0x130, 13); + clks[IMX7D_PLL_DRAM_TEST_DIV] = clk_register_divider_table(NULL, "pll_dram_test_div", "pll_dram_main_bypass", + CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0x70, 21, 2, 0, test_div_table, &imx_ccm_lock); clks[IMX7D_PLL_AUDIO_TEST_DIV] = clk_register_divider_table(NULL, "pll_audio_test_div", "pll_audio_main_clk", CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0xf0, 19, 2, 0, test_div_table, &imx_ccm_lock); clks[IMX7D_PLL_AUDIO_POST_DIV] = clk_register_divider_table(NULL, "pll_audio_post_div", "pll_audio_test_div", -- cgit From a12ec8b6536b9eb484627f252d2a460f6b74c585 Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Wed, 28 Mar 2018 09:46:38 +0300 Subject: clk: imx7d: Correct ahb clk parent select Design team change the ahb's clk parent options but did NOT update the DOC accordingly in time, so the AHB/IPG's clk rate in clk tree is incorrect, AHB is 67.5MHz and IPG is 33.75MHz, but using scope to monitor them, they are actually 135MHz and 67.5MHz, update the clk parent option to make clk tree info correct. Signed-off-by: Anson Huang Signed-off-by: Irina Tirdea Signed-off-by: Abel Vesa Signed-off-by: Stephen Boyd --- drivers/clk/imx/clk-imx7d.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/imx/clk-imx7d.c b/drivers/clk/imx/clk-imx7d.c index 1cc485f6c621..50da4cb00912 100644 --- a/drivers/clk/imx/clk-imx7d.c +++ b/drivers/clk/imx/clk-imx7d.c @@ -74,7 +74,7 @@ static const char *nand_usdhc_bus_sel[] = { "osc", "pll_sys_pfd2_270m_clk", static const char *ahb_channel_sel[] = { "osc", "pll_sys_pfd2_270m_clk", "pll_dram_533m_clk", "pll_sys_pfd0_392m_clk", - "pll_enet_125m_clk", "pll_usb_main_clk", "pll_audio_post_div", + "pll_enet_250m_clk", "pll_usb_main_clk", "pll_audio_post_div", "pll_video_post_div", }; static const char *dram_phym_sel[] = { "pll_dram_main_clk", -- cgit From 8d41e6538c1a4d034cd1f4cc5efec699dd83ca5d Mon Sep 17 00:00:00 2001 From: Dong Aisheng Date: Wed, 28 Mar 2018 09:46:39 +0300 Subject: clk: imx7d: Move clks_init_on before any clock operations For init on clocks we should move it at the first place in imx7d_clocks_init() before any clock operations, else the clock operation may fail in case the clock is still not on. Acked-by: Ranjani Vaidyanathan Signed-off-by: Dong Aisheng Signed-off-by: Irina Tirdea Signed-off-by: Abel Vesa Signed-off-by: Stephen Boyd --- drivers/clk/imx/clk-imx7d.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/clk/imx/clk-imx7d.c b/drivers/clk/imx/clk-imx7d.c index 50da4cb00912..975a20d3cc94 100644 --- a/drivers/clk/imx/clk-imx7d.c +++ b/drivers/clk/imx/clk-imx7d.c @@ -433,13 +433,6 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node) clks[IMX7D_PLL_AUDIO_MAIN_BYPASS] = imx_clk_mux_flags("pll_audio_main_bypass", base + 0xf0, 16, 1, pll_audio_bypass_sel, ARRAY_SIZE(pll_audio_bypass_sel), CLK_SET_RATE_PARENT); clks[IMX7D_PLL_VIDEO_MAIN_BYPASS] = imx_clk_mux_flags("pll_video_main_bypass", base + 0x130, 16, 1, pll_video_bypass_sel, ARRAY_SIZE(pll_video_bypass_sel), CLK_SET_RATE_PARENT); - clk_set_parent(clks[IMX7D_PLL_ARM_MAIN_BYPASS], clks[IMX7D_PLL_ARM_MAIN]); - clk_set_parent(clks[IMX7D_PLL_DRAM_MAIN_BYPASS], clks[IMX7D_PLL_DRAM_MAIN]); - clk_set_parent(clks[IMX7D_PLL_SYS_MAIN_BYPASS], clks[IMX7D_PLL_SYS_MAIN]); - clk_set_parent(clks[IMX7D_PLL_ENET_MAIN_BYPASS], clks[IMX7D_PLL_ENET_MAIN]); - clk_set_parent(clks[IMX7D_PLL_AUDIO_MAIN_BYPASS], clks[IMX7D_PLL_AUDIO_MAIN]); - clk_set_parent(clks[IMX7D_PLL_VIDEO_MAIN_BYPASS], clks[IMX7D_PLL_VIDEO_MAIN]); - clks[IMX7D_PLL_ARM_MAIN_CLK] = imx_clk_gate("pll_arm_main_clk", "pll_arm_main_bypass", base + 0x60, 13); clks[IMX7D_PLL_DRAM_MAIN_CLK] = imx_clk_gate("pll_dram_main_clk", "pll_dram_test_div", base + 0x70, 13); clks[IMX7D_PLL_SYS_MAIN_CLK] = imx_clk_gate("pll_sys_main_clk", "pll_sys_main_bypass", base + 0xb0, 13); @@ -891,6 +884,13 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node) for (i = 0; i < ARRAY_SIZE(clks_init_on); i++) clk_prepare_enable(clks[clks_init_on[i]]); + clk_set_parent(clks[IMX7D_PLL_ARM_MAIN_BYPASS], clks[IMX7D_PLL_ARM_MAIN]); + clk_set_parent(clks[IMX7D_PLL_DRAM_MAIN_BYPASS], clks[IMX7D_PLL_DRAM_MAIN]); + clk_set_parent(clks[IMX7D_PLL_SYS_MAIN_BYPASS], clks[IMX7D_PLL_SYS_MAIN]); + clk_set_parent(clks[IMX7D_PLL_ENET_MAIN_BYPASS], clks[IMX7D_PLL_ENET_MAIN]); + clk_set_parent(clks[IMX7D_PLL_AUDIO_MAIN_BYPASS], clks[IMX7D_PLL_AUDIO_MAIN]); + clk_set_parent(clks[IMX7D_PLL_VIDEO_MAIN_BYPASS], clks[IMX7D_PLL_VIDEO_MAIN]); + /* use old gpt clk setting, gpt1 root clk must be twice as gpt counter freq */ clk_set_parent(clks[IMX7D_GPT1_ROOT_SRC], clks[IMX7D_OSC_24M_CLK]); -- cgit From 753872373b599384ac7df809aa61ea12d1c4d5d1 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Thu, 22 Mar 2018 10:11:30 +0100 Subject: clk: bcm2835: De-assert/assert PLL reset signal when appropriate In order to enable a PLL, not only the PLL has to be powered up and locked, but you also have to de-assert the reset signal. The last part was missing. Add it so PLLs that were not enabled by the FW/bootloader can be enabled from Linux. Fixes: 41691b8862e2 ("clk: bcm2835: Add support for programming the audio domain clocks") Cc: Signed-off-by: Boris Brezillon Reviewed-by: Eric Anholt Signed-off-by: Stephen Boyd --- drivers/clk/bcm/clk-bcm2835.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c index 44301a3d9963..40acb8ebfb42 100644 --- a/drivers/clk/bcm/clk-bcm2835.c +++ b/drivers/clk/bcm/clk-bcm2835.c @@ -602,9 +602,7 @@ static void bcm2835_pll_off(struct clk_hw *hw) const struct bcm2835_pll_data *data = pll->data; spin_lock(&cprman->regs_lock); - cprman_write(cprman, data->cm_ctrl_reg, - cprman_read(cprman, data->cm_ctrl_reg) | - CM_PLL_ANARST); + cprman_write(cprman, data->cm_ctrl_reg, CM_PLL_ANARST); cprman_write(cprman, data->a2w_ctrl_reg, cprman_read(cprman, data->a2w_ctrl_reg) | A2W_PLL_CTRL_PWRDN); @@ -638,6 +636,10 @@ static int bcm2835_pll_on(struct clk_hw *hw) cpu_relax(); } + cprman_write(cprman, data->a2w_ctrl_reg, + cprman_read(cprman, data->a2w_ctrl_reg) | + A2W_PLL_CTRL_PRST_DISABLE); + return 0; } -- cgit From eade4ccdb087ae6238bcce78e64587d543374ca4 Mon Sep 17 00:00:00 2001 From: Nikita Yushchenko Date: Tue, 20 Mar 2018 11:33:23 +0300 Subject: clk: cs2000: set pm_ops in hibernate-compatible way Use SET_LATE_SYSTEM_SLEEP_PM_OPS() macro instead of direct assignment to .resume_early field. This fixes initialization of CS2000 in restore from hibernation in case of kernel used to load image did not initialize CS2000 while kernel being restored had CS2000 initialized. Signed-off-by: Nikita Yushchenko Signed-off-by: Stephen Boyd --- drivers/clk/clk-cs2000-cp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/clk-cs2000-cp.c b/drivers/clk/clk-cs2000-cp.c index e8ea81c30f0c..c58019750b7e 100644 --- a/drivers/clk/clk-cs2000-cp.c +++ b/drivers/clk/clk-cs2000-cp.c @@ -549,7 +549,7 @@ static int cs2000_resume(struct device *dev) } static const struct dev_pm_ops cs2000_pm_ops = { - .resume_early = cs2000_resume, + SET_LATE_SYSTEM_SLEEP_PM_OPS(NULL, cs2000_resume) }; static struct i2c_driver cs2000_driver = { -- cgit From 6f9575e55632b2a060c8c158949ec712d39db0be Mon Sep 17 00:00:00 2001 From: Bai Ping Date: Tue, 20 Mar 2018 10:24:01 +0800 Subject: clk: imx: Add CLK_IS_CRITICAL flag for busy divider and busy mux The busy divider and busy mux is actually used by the system critical clocks, so add 'CLK_IS_CRITICAL' to clocks registered with these two type. Signed-off-by: Bai Ping Acked-by: Dong Aisheng Signed-off-by: Stephen Boyd --- drivers/clk/imx/clk-busy.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/clk/imx/clk-busy.c b/drivers/clk/imx/clk-busy.c index 6df3389687bc..99036527eb0d 100644 --- a/drivers/clk/imx/clk-busy.c +++ b/drivers/clk/imx/clk-busy.c @@ -101,7 +101,7 @@ struct clk *imx_clk_busy_divider(const char *name, const char *parent_name, init.name = name; init.ops = &clk_busy_divider_ops; - init.flags = CLK_SET_RATE_PARENT; + init.flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL; init.parent_names = &parent_name; init.num_parents = 1; @@ -175,7 +175,7 @@ struct clk *imx_clk_busy_mux(const char *name, void __iomem *reg, u8 shift, init.name = name; init.ops = &clk_busy_mux_ops; - init.flags = 0; + init.flags = CLK_IS_CRITICAL; init.parent_names = parent_names; init.num_parents = num_parents; -- cgit From 2b18cc1f12f4f751b984f6493db0f25a69b2f860 Mon Sep 17 00:00:00 2001 From: Bai Ping Date: Tue, 20 Mar 2018 10:24:02 +0800 Subject: clk: imx: add new gate/gate2 wrapper funtion Add new gate/gate2 wrapper function to register clocks with optional flags. Signed-off-by: Bai Ping Acked-by: Dong Aisheng Signed-off-by: Stephen Boyd --- drivers/clk/imx/clk.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/clk/imx/clk.h b/drivers/clk/imx/clk.h index d69c4bbf3597..8076ec040f37 100644 --- a/drivers/clk/imx/clk.h +++ b/drivers/clk/imx/clk.h @@ -123,6 +123,13 @@ static inline struct clk *imx_clk_gate(const char *name, const char *parent, shift, 0, &imx_ccm_lock); } +static inline struct clk *imx_clk_gate_flags(const char *name, const char *parent, + void __iomem *reg, u8 shift, unsigned long flags) +{ + return clk_register_gate(NULL, name, parent, flags | CLK_SET_RATE_PARENT, reg, + shift, 0, &imx_ccm_lock); +} + static inline struct clk *imx_clk_gate_dis(const char *name, const char *parent, void __iomem *reg, u8 shift) { @@ -137,6 +144,13 @@ static inline struct clk *imx_clk_gate2(const char *name, const char *parent, shift, 0x3, 0, &imx_ccm_lock, NULL); } +static inline struct clk *imx_clk_gate2_flags(const char *name, const char *parent, + void __iomem *reg, u8 shift, unsigned long flags) +{ + return clk_register_gate2(NULL, name, parent, flags | CLK_SET_RATE_PARENT, reg, + shift, 0x3, 0, &imx_ccm_lock, NULL); +} + static inline struct clk *imx_clk_gate2_shared(const char *name, const char *parent, void __iomem *reg, u8 shift, unsigned int *share_count) -- cgit From 0c123a4fbbf4672fb8c357158eb9368f3d3660f2 Mon Sep 17 00:00:00 2001 From: Bai Ping Date: Tue, 20 Mar 2018 10:24:03 +0800 Subject: dt-bindings: imx: update clock doc for imx6sll Add clock binding doc update for imx6sll. Signed-off-by: Bai Ping Acked-by: Dong Aisheng Signed-off-by: Stephen Boyd --- .../devicetree/bindings/clock/imx6sll-clock.txt | 36 ++++ include/dt-bindings/clock/imx6sll-clock.h | 202 +++++++++++++++++++++ 2 files changed, 238 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/imx6sll-clock.txt create mode 100644 include/dt-bindings/clock/imx6sll-clock.h diff --git a/Documentation/devicetree/bindings/clock/imx6sll-clock.txt b/Documentation/devicetree/bindings/clock/imx6sll-clock.txt new file mode 100644 index 000000000000..fee849d5fdd1 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/imx6sll-clock.txt @@ -0,0 +1,36 @@ +* Clock bindings for Freescale i.MX6 SLL + +Required properties: +- compatible: Should be "fsl,imx6sll-ccm" +- reg: Address and length of the register set +- #clock-cells: Should be <1> +- clocks: list of clock specifiers, must contain an entry for each required + entry in clock-names +- clock-names: should include entries "ckil", "osc", "ipp_di0" and "ipp_di1" + +The clock consumer should specify the desired clock by having the clock +ID in its "clocks" phandle cell. See include/dt-bindings/clock/imx6sll-clock.h +for the full list of i.MX6 SLL clock IDs. + +Examples: + +#include + +clks: clock-controller@20c4000 { + compatible = "fsl,imx6sll-ccm"; + reg = <0x020c4000 0x4000>; + interrupts = , + ; + #clock-cells = <1>; + clocks = <&ckil>, <&osc>, <&ipp_di0>, <&ipp_di1>; + clock-names = "ckil", "osc", "ipp_di0", "ipp_di1"; +}; + +uart1: serial@2020000 { + compatible = "fsl,imx6sl-uart", "fsl,imx6q-uart", "fsl,imx21-uart"; + reg = <0x02020000 0x4000>; + interrupts = ; + clocks = <&clks IMX6SLL_CLK_UART1_IPG>, + <&clks IMX6SLL_CLK_UART1_SERIAL>; + clock-names = "ipg", "per"; +}; diff --git a/include/dt-bindings/clock/imx6sll-clock.h b/include/dt-bindings/clock/imx6sll-clock.h new file mode 100644 index 000000000000..151111e68f4f --- /dev/null +++ b/include/dt-bindings/clock/imx6sll-clock.h @@ -0,0 +1,202 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2016 Freescale Semiconductor, Inc. + * Copyright 2017-2018 NXP. + * + */ + +#ifndef __DT_BINDINGS_CLOCK_IMX6SLL_H +#define __DT_BINDINGS_CLOCK_IMX6SLL_H + +#define IMX6SLL_CLK_DUMMY 0 +#define IMX6SLL_CLK_CKIL 1 +#define IMX6SLL_CLK_OSC 2 +#define IMX6SLL_PLL1_BYPASS_SRC 3 +#define IMX6SLL_PLL2_BYPASS_SRC 4 +#define IMX6SLL_PLL3_BYPASS_SRC 5 +#define IMX6SLL_PLL4_BYPASS_SRC 6 +#define IMX6SLL_PLL5_BYPASS_SRC 7 +#define IMX6SLL_PLL6_BYPASS_SRC 8 +#define IMX6SLL_PLL7_BYPASS_SRC 9 +#define IMX6SLL_CLK_PLL1 10 +#define IMX6SLL_CLK_PLL2 11 +#define IMX6SLL_CLK_PLL3 12 +#define IMX6SLL_CLK_PLL4 13 +#define IMX6SLL_CLK_PLL5 14 +#define IMX6SLL_CLK_PLL6 15 +#define IMX6SLL_CLK_PLL7 16 +#define IMX6SLL_PLL1_BYPASS 17 +#define IMX6SLL_PLL2_BYPASS 18 +#define IMX6SLL_PLL3_BYPASS 19 +#define IMX6SLL_PLL4_BYPASS 20 +#define IMX6SLL_PLL5_BYPASS 21 +#define IMX6SLL_PLL6_BYPASS 22 +#define IMX6SLL_PLL7_BYPASS 23 +#define IMX6SLL_CLK_PLL1_SYS 24 +#define IMX6SLL_CLK_PLL2_BUS 25 +#define IMX6SLL_CLK_PLL3_USB_OTG 26 +#define IMX6SLL_CLK_PLL4_AUDIO 27 +#define IMX6SLL_CLK_PLL5_VIDEO 28 +#define IMX6SLL_CLK_PLL6_ENET 29 +#define IMX6SLL_CLK_PLL7_USB_HOST 30 +#define IMX6SLL_CLK_USBPHY1 31 +#define IMX6SLL_CLK_USBPHY2 32 +#define IMX6SLL_CLK_USBPHY1_GATE 33 +#define IMX6SLL_CLK_USBPHY2_GATE 34 +#define IMX6SLL_CLK_PLL2_PFD0 35 +#define IMX6SLL_CLK_PLL2_PFD1 36 +#define IMX6SLL_CLK_PLL2_PFD2 37 +#define IMX6SLL_CLK_PLL2_PFD3 38 +#define IMX6SLL_CLK_PLL3_PFD0 39 +#define IMX6SLL_CLK_PLL3_PFD1 40 +#define IMX6SLL_CLK_PLL3_PFD2 41 +#define IMX6SLL_CLK_PLL3_PFD3 42 +#define IMX6SLL_CLK_PLL4_POST_DIV 43 +#define IMX6SLL_CLK_PLL4_AUDIO_DIV 44 +#define IMX6SLL_CLK_PLL5_POST_DIV 45 +#define IMX6SLL_CLK_PLL5_VIDEO_DIV 46 +#define IMX6SLL_CLK_PLL2_198M 47 +#define IMX6SLL_CLK_PLL3_120M 48 +#define IMX6SLL_CLK_PLL3_80M 49 +#define IMX6SLL_CLK_PLL3_60M 50 +#define IMX6SLL_CLK_STEP 51 +#define IMX6SLL_CLK_PLL1_SW 52 +#define IMX6SLL_CLK_AXI_ALT_SEL 53 +#define IMX6SLL_CLK_AXI_SEL 54 +#define IMX6SLL_CLK_PERIPH_PRE 55 +#define IMX6SLL_CLK_PERIPH2_PRE 56 +#define IMX6SLL_CLK_PERIPH_CLK2_SEL 57 +#define IMX6SLL_CLK_PERIPH2_CLK2_SEL 58 +#define IMX6SLL_CLK_PERCLK_SEL 59 +#define IMX6SLL_CLK_USDHC1_SEL 60 +#define IMX6SLL_CLK_USDHC2_SEL 61 +#define IMX6SLL_CLK_USDHC3_SEL 62 +#define IMX6SLL_CLK_SSI1_SEL 63 +#define IMX6SLL_CLK_SSI2_SEL 64 +#define IMX6SLL_CLK_SSI3_SEL 65 +#define IMX6SLL_CLK_PXP_SEL 66 +#define IMX6SLL_CLK_LCDIF_PRE_SEL 67 +#define IMX6SLL_CLK_LCDIF_SEL 68 +#define IMX6SLL_CLK_EPDC_PRE_SEL 69 +#define IMX6SLL_CLK_SPDIF_SEL 70 +#define IMX6SLL_CLK_ECSPI_SEL 71 +#define IMX6SLL_CLK_UART_SEL 72 +#define IMX6SLL_CLK_ARM 73 +#define IMX6SLL_CLK_PERIPH 74 +#define IMX6SLL_CLK_PERIPH2 75 +#define IMX6SLL_CLK_PERIPH2_CLK2 76 +#define IMX6SLL_CLK_PERIPH_CLK2 77 +#define IMX6SLL_CLK_MMDC_PODF 78 +#define IMX6SLL_CLK_AXI_PODF 79 +#define IMX6SLL_CLK_AHB 80 +#define IMX6SLL_CLK_IPG 81 +#define IMX6SLL_CLK_PERCLK 82 +#define IMX6SLL_CLK_USDHC1_PODF 83 +#define IMX6SLL_CLK_USDHC2_PODF 84 +#define IMX6SLL_CLK_USDHC3_PODF 85 +#define IMX6SLL_CLK_SSI1_PRED 86 +#define IMX6SLL_CLK_SSI2_PRED 87 +#define IMX6SLL_CLK_SSI3_PRED 88 +#define IMX6SLL_CLK_SSI1_PODF 89 +#define IMX6SLL_CLK_SSI2_PODF 90 +#define IMX6SLL_CLK_SSI3_PODF 91 +#define IMX6SLL_CLK_PXP_PODF 92 +#define IMX6SLL_CLK_LCDIF_PRED 93 +#define IMX6SLL_CLK_LCDIF_PODF 94 +#define IMX6SLL_CLK_EPDC_SEL 95 +#define IMX6SLL_CLK_EPDC_PODF 96 +#define IMX6SLL_CLK_SPDIF_PRED 97 +#define IMX6SLL_CLK_SPDIF_PODF 98 +#define IMX6SLL_CLK_ECSPI_PODF 99 +#define IMX6SLL_CLK_UART_PODF 100 + +/* CCGR 0 */ +#define IMX6SLL_CLK_AIPSTZ1 101 +#define IMX6SLL_CLK_AIPSTZ2 102 +#define IMX6SLL_CLK_DCP 103 +#define IMX6SLL_CLK_UART2_IPG 104 +#define IMX6SLL_CLK_UART2_SERIAL 105 + +/* CCGR 1 */ +#define IMX6SLL_CLK_ECSPI1 106 +#define IMX6SLL_CLK_ECSPI2 107 +#define IMX6SLL_CLK_ECSPI3 108 +#define IMX6SLL_CLK_ECSPI4 109 +#define IMX6SLL_CLK_UART3_IPG 110 +#define IMX6SLL_CLK_UART3_SERIAL 111 +#define IMX6SLL_CLK_UART4_IPG 112 +#define IMX6SLL_CLK_UART4_SERIAL 113 +#define IMX6SLL_CLK_EPIT1 114 +#define IMX6SLL_CLK_EPIT2 115 +#define IMX6SLL_CLK_GPT_BUS 116 +#define IMX6SLL_CLK_GPT_SERIAL 117 + +/* CCGR2 */ +#define IMX6SLL_CLK_CSI 118 +#define IMX6SLL_CLK_I2C1 119 +#define IMX6SLL_CLK_I2C2 120 +#define IMX6SLL_CLK_I2C3 121 +#define IMX6SLL_CLK_OCOTP 122 +#define IMX6SLL_CLK_LCDIF_APB 123 +#define IMX6SLL_CLK_PXP 124 + +/* CCGR3 */ +#define IMX6SLL_CLK_UART5_IPG 125 +#define IMX6SLL_CLK_UART5_SERIAL 126 +#define IMX6SLL_CLK_EPDC_AXI 127 +#define IMX6SLL_CLK_EPDC_PIX 128 +#define IMX6SLL_CLK_LCDIF_PIX 129 +#define IMX6SLL_CLK_WDOG1 130 +#define IMX6SLL_CLK_MMDC_P0_FAST 131 +#define IMX6SLL_CLK_MMDC_P0_IPG 132 +#define IMX6SLL_CLK_OCRAM 133 + +/* CCGR4 */ +#define IMX6SLL_CLK_PWM1 134 +#define IMX6SLL_CLK_PWM2 135 +#define IMX6SLL_CLK_PWM3 136 +#define IMX6SLL_CLK_PWM4 137 + +/* CCGR 5 */ +#define IMX6SLL_CLK_ROM 138 +#define IMX6SLL_CLK_SDMA 139 +#define IMX6SLL_CLK_KPP 140 +#define IMX6SLL_CLK_WDOG2 141 +#define IMX6SLL_CLK_SPBA 142 +#define IMX6SLL_CLK_SPDIF 143 +#define IMX6SLL_CLK_SPDIF_GCLK 144 +#define IMX6SLL_CLK_SSI1 145 +#define IMX6SLL_CLK_SSI1_IPG 146 +#define IMX6SLL_CLK_SSI2 147 +#define IMX6SLL_CLK_SSI2_IPG 148 +#define IMX6SLL_CLK_SSI3 149 +#define IMX6SLL_CLK_SSI3_IPG 150 +#define IMX6SLL_CLK_UART1_IPG 151 +#define IMX6SLL_CLK_UART1_SERIAL 152 + +/* CCGR 6 */ +#define IMX6SLL_CLK_USBOH3 153 +#define IMX6SLL_CLK_USDHC1 154 +#define IMX6SLL_CLK_USDHC2 155 +#define IMX6SLL_CLK_USDHC3 156 + +#define IMX6SLL_CLK_IPP_DI0 157 +#define IMX6SLL_CLK_IPP_DI1 158 +#define IMX6SLL_CLK_LDB_DI0_SEL 159 +#define IMX6SLL_CLK_LDB_DI0_DIV_3_5 160 +#define IMX6SLL_CLK_LDB_DI0_DIV_7 161 +#define IMX6SLL_CLK_LDB_DI0_DIV_SEL 162 +#define IMX6SLL_CLK_LDB_DI0 163 +#define IMX6SLL_CLK_LDB_DI1_SEL 164 +#define IMX6SLL_CLK_LDB_DI1_DIV_3_5 165 +#define IMX6SLL_CLK_LDB_DI1_DIV_7 166 +#define IMX6SLL_CLK_LDB_DI1_DIV_SEL 167 +#define IMX6SLL_CLK_LDB_DI1 168 +#define IMX6SLL_CLK_EXTERN_AUDIO_SEL 169 +#define IMX6SLL_CLK_EXTERN_AUDIO_PRED 170 +#define IMX6SLL_CLK_EXTERN_AUDIO_PODF 171 +#define IMX6SLL_CLK_EXTERN_AUDIO 172 + +#define IMX6SLL_CLK_END 173 + +#endif /* __DT_BINDINGS_CLOCK_IMX6SLL_H */ -- cgit From 4a5f720b65422e168139826c0dae675336bdd706 Mon Sep 17 00:00:00 2001 From: Bai Ping Date: Tue, 20 Mar 2018 10:24:04 +0800 Subject: clk: imx: add clock driver for imx6sll Add clk driver support for imx6sll. Signed-off-by: Bai Ping Acked-by: Dong Aisheng Signed-off-by: Stephen Boyd --- drivers/clk/imx/Makefile | 1 + drivers/clk/imx/clk-imx6sll.c | 340 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 341 insertions(+) create mode 100644 drivers/clk/imx/clk-imx6sll.c diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index f91f2b2e11cd..8c3baa7e6496 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -22,6 +22,7 @@ obj-$(CONFIG_SOC_IMX35) += clk-imx35.o obj-$(CONFIG_SOC_IMX5) += clk-imx51-imx53.o obj-$(CONFIG_SOC_IMX6Q) += clk-imx6q.o obj-$(CONFIG_SOC_IMX6SL) += clk-imx6sl.o +obj-$(CONFIG_SOC_IMX6SLL) += clk-imx6sll.o obj-$(CONFIG_SOC_IMX6SX) += clk-imx6sx.o obj-$(CONFIG_SOC_IMX6UL) += clk-imx6ul.o obj-$(CONFIG_SOC_IMX7D) += clk-imx7d.o diff --git a/drivers/clk/imx/clk-imx6sll.c b/drivers/clk/imx/clk-imx6sll.c new file mode 100644 index 000000000000..3651c77fbabe --- /dev/null +++ b/drivers/clk/imx/clk-imx6sll.c @@ -0,0 +1,340 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2016 Freescale Semiconductor, Inc. + * Copyright 2017-2018 NXP. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "clk.h" + +#define CCM_ANALOG_PLL_BYPASS (0x1 << 16) +#define BM_CCM_CCDR_MMDC_CH0_MASK (0x2 << 16) +#define xPLL_CLR(offset) (offset + 0x8) + +static const char *pll_bypass_src_sels[] = { "osc", "dummy", }; +static const char *pll1_bypass_sels[] = { "pll1", "pll1_bypass_src", }; +static const char *pll2_bypass_sels[] = { "pll2", "pll2_bypass_src", }; +static const char *pll3_bypass_sels[] = { "pll3", "pll3_bypass_src", }; +static const char *pll4_bypass_sels[] = { "pll4", "pll4_bypass_src", }; +static const char *pll5_bypass_sels[] = { "pll5", "pll5_bypass_src", }; +static const char *pll6_bypass_sels[] = { "pll6", "pll6_bypass_src", }; +static const char *pll7_bypass_sels[] = { "pll7", "pll7_bypass_src", }; +static const char *step_sels[] = { "osc", "pll2_pfd2_396m", }; +static const char *pll1_sw_sels[] = { "pll1_sys", "step", }; +static const char *axi_alt_sels[] = { "pll2_pfd2_396m", "pll3_pfd1_540m", }; +static const char *axi_sels[] = {"periph", "axi_alt_sel", }; +static const char *periph_pre_sels[] = { "pll2_bus", "pll2_pfd2_396m", "pll2_pfd0_352m", "pll2_198m", }; +static const char *periph2_pre_sels[] = { "pll2_bus", "pll2_pfd2_396m", "pll2_pfd0_352m", "pll4_audio_div", }; +static const char *periph_clk2_sels[] = { "pll3_usb_otg", "osc", "osc", }; +static const char *periph2_clk2_sels[] = { "pll3_usb_otg", "osc", }; +static const char *periph_sels[] = { "periph_pre", "periph_clk2", }; +static const char *periph2_sels[] = { "periph2_pre", "periph2_clk2", }; +static const char *usdhc_sels[] = { "pll2_pfd2_396m", "pll2_pfd0_352m", }; +static const char *ssi_sels[] = {"pll3_pfd2_508m", "pll3_pfd3_454m", "pll4_audio_div", "dummy",}; +static const char *spdif_sels[] = { "pll4_audio_div", "pll3_pfd2_508m", "pll5_video_div", "pll3_usb_otg", }; +static const char *ldb_di0_div_sels[] = { "ldb_di0_div_3_5", "ldb_di0_div_7", }; +static const char *ldb_di1_div_sels[] = { "ldb_di1_div_3_5", "ldb_di1_div_7", }; +static const char *ldb_di0_sels[] = { "pll5_video_div", "pll2_pfd0_352m", "pll2_pfd2_396m", "pll2_pfd3_594m", "pll2_pfd1_594m", "pll3_pfd3_454m", }; +static const char *ldb_di1_sels[] = { "pll3_usb_otg", "pll2_pfd0_352m", "pll2_pfd2_396m", "pll2_bus", "pll3_pfd3_454m", "pll3_pfd2_508m", }; +static const char *lcdif_pre_sels[] = { "pll2_bus", "pll3_pfd3_454m", "pll5_video_div", "pll2_pfd0_352m", "pll2_pfd1_594m", "pll3_pfd1_540m", }; +static const char *ecspi_sels[] = { "pll3_60m", "osc", }; +static const char *uart_sels[] = { "pll3_80m", "osc", }; +static const char *perclk_sels[] = { "ipg", "osc", }; +static const char *lcdif_sels[] = { "lcdif_podf", "ipp_di0", "ipp_di1", "ldb_di0", "ldb_di1", }; + +static const char *epdc_pre_sels[] = { "pll2_bus", "pll3_usb_otg", "pll5_video_div", "pll2_pfd0_352m", "pll2_pfd2_396m", "pll3_pfd2_508m", }; +static const char *epdc_sels[] = { "epdc_podf", "ipp_di0", "ipp_di1", "ldb_di0", "ldb_di1", }; + +static struct clk *clks[IMX6SLL_CLK_END]; +static struct clk_onecell_data clk_data; + +static const struct clk_div_table post_div_table[] = { + { .val = 2, .div = 1, }, + { .val = 1, .div = 2, }, + { .val = 0, .div = 4, }, + { } +}; + +static const struct clk_div_table video_div_table[] = { + { .val = 0, .div = 1, }, + { .val = 1, .div = 2, }, + { .val = 2, .div = 1, }, + { .val = 3, .div = 4, }, + { } +}; + +static u32 share_count_audio; +static u32 share_count_ssi1; +static u32 share_count_ssi2; +static u32 share_count_ssi3; + +static void __init imx6sll_clocks_init(struct device_node *ccm_node) +{ + struct device_node *np; + void __iomem *base; + + clks[IMX6SLL_CLK_DUMMY] = imx_clk_fixed("dummy", 0); + + clks[IMX6SLL_CLK_CKIL] = of_clk_get_by_name(ccm_node, "ckil"); + clks[IMX6SLL_CLK_OSC] = of_clk_get_by_name(ccm_node, "osc"); + + /* ipp_di clock is external input */ + clks[IMX6SLL_CLK_IPP_DI0] = of_clk_get_by_name(ccm_node, "ipp_di0"); + clks[IMX6SLL_CLK_IPP_DI1] = of_clk_get_by_name(ccm_node, "ipp_di1"); + + np = of_find_compatible_node(NULL, NULL, "fsl,imx6sll-anatop"); + base = of_iomap(np, 0); + WARN_ON(!base); + + /* Do not bypass PLLs initially */ + writel_relaxed(CCM_ANALOG_PLL_BYPASS, base + xPLL_CLR(0x0)); + writel_relaxed(CCM_ANALOG_PLL_BYPASS, base + xPLL_CLR(0x10)); + writel_relaxed(CCM_ANALOG_PLL_BYPASS, base + xPLL_CLR(0x20)); + writel_relaxed(CCM_ANALOG_PLL_BYPASS, base + xPLL_CLR(0x30)); + writel_relaxed(CCM_ANALOG_PLL_BYPASS, base + xPLL_CLR(0x70)); + writel_relaxed(CCM_ANALOG_PLL_BYPASS, base + xPLL_CLR(0xa0)); + writel_relaxed(CCM_ANALOG_PLL_BYPASS, base + xPLL_CLR(0xe0)); + + clks[IMX6SLL_PLL1_BYPASS_SRC] = imx_clk_mux("pll1_bypass_src", base + 0x00, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); + clks[IMX6SLL_PLL2_BYPASS_SRC] = imx_clk_mux("pll2_bypass_src", base + 0x30, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); + clks[IMX6SLL_PLL3_BYPASS_SRC] = imx_clk_mux("pll3_bypass_src", base + 0x10, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); + clks[IMX6SLL_PLL4_BYPASS_SRC] = imx_clk_mux("pll4_bypass_src", base + 0x70, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); + clks[IMX6SLL_PLL5_BYPASS_SRC] = imx_clk_mux("pll5_bypass_src", base + 0xa0, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); + clks[IMX6SLL_PLL6_BYPASS_SRC] = imx_clk_mux("pll6_bypass_src", base + 0xe0, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); + clks[IMX6SLL_PLL7_BYPASS_SRC] = imx_clk_mux("pll7_bypass_src", base + 0x20, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); + + clks[IMX6SLL_CLK_PLL1] = imx_clk_pllv3(IMX_PLLV3_SYS, "pll1", "pll1_bypass_src", base + 0x00, 0x7f); + clks[IMX6SLL_CLK_PLL2] = imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll2", "pll2_bypass_src", base + 0x30, 0x1); + clks[IMX6SLL_CLK_PLL3] = imx_clk_pllv3(IMX_PLLV3_USB, "pll3", "pll3_bypass_src", base + 0x10, 0x3); + clks[IMX6SLL_CLK_PLL4] = imx_clk_pllv3(IMX_PLLV3_AV, "pll4", "pll4_bypass_src", base + 0x70, 0x7f); + clks[IMX6SLL_CLK_PLL5] = imx_clk_pllv3(IMX_PLLV3_AV, "pll5", "pll5_bypass_src", base + 0xa0, 0x7f); + clks[IMX6SLL_CLK_PLL6] = imx_clk_pllv3(IMX_PLLV3_ENET, "pll6", "pll6_bypass_src", base + 0xe0, 0x3); + clks[IMX6SLL_CLK_PLL7] = imx_clk_pllv3(IMX_PLLV3_USB, "pll7", "pll7_bypass_src", base + 0x20, 0x3); + + clks[IMX6SLL_PLL1_BYPASS] = imx_clk_mux_flags("pll1_bypass", base + 0x00, 16, 1, pll1_bypass_sels, ARRAY_SIZE(pll1_bypass_sels), CLK_SET_RATE_PARENT); + clks[IMX6SLL_PLL2_BYPASS] = imx_clk_mux_flags("pll2_bypass", base + 0x30, 16, 1, pll2_bypass_sels, ARRAY_SIZE(pll2_bypass_sels), CLK_SET_RATE_PARENT); + clks[IMX6SLL_PLL3_BYPASS] = imx_clk_mux_flags("pll3_bypass", base + 0x10, 16, 1, pll3_bypass_sels, ARRAY_SIZE(pll3_bypass_sels), CLK_SET_RATE_PARENT); + clks[IMX6SLL_PLL4_BYPASS] = imx_clk_mux_flags("pll4_bypass", base + 0x70, 16, 1, pll4_bypass_sels, ARRAY_SIZE(pll4_bypass_sels), CLK_SET_RATE_PARENT); + clks[IMX6SLL_PLL5_BYPASS] = imx_clk_mux_flags("pll5_bypass", base + 0xa0, 16, 1, pll5_bypass_sels, ARRAY_SIZE(pll5_bypass_sels), CLK_SET_RATE_PARENT); + clks[IMX6SLL_PLL6_BYPASS] = imx_clk_mux_flags("pll6_bypass", base + 0xe0, 16, 1, pll6_bypass_sels, ARRAY_SIZE(pll6_bypass_sels), CLK_SET_RATE_PARENT); + clks[IMX6SLL_PLL7_BYPASS] = imx_clk_mux_flags("pll7_bypass", base + 0x20, 16, 1, pll7_bypass_sels, ARRAY_SIZE(pll7_bypass_sels), CLK_SET_RATE_PARENT); + + clks[IMX6SLL_CLK_PLL1_SYS] = imx_clk_fixed_factor("pll1_sys", "pll1_bypass", 1, 1); + clks[IMX6SLL_CLK_PLL2_BUS] = imx_clk_gate("pll2_bus", "pll2_bypass", base + 0x30, 13); + clks[IMX6SLL_CLK_PLL3_USB_OTG] = imx_clk_gate("pll3_usb_otg", "pll3_bypass", base + 0x10, 13); + clks[IMX6SLL_CLK_PLL4_AUDIO] = imx_clk_gate("pll4_audio", "pll4_bypass", base + 0x70, 13); + clks[IMX6SLL_CLK_PLL5_VIDEO] = imx_clk_gate("pll5_video", "pll5_bypass", base + 0xa0, 13); + clks[IMX6SLL_CLK_PLL6_ENET] = imx_clk_gate("pll6_enet", "pll6_bypass", base + 0xe0, 13); + clks[IMX6SLL_CLK_PLL7_USB_HOST] = imx_clk_gate("pll7_usb_host", "pll7_bypass", base + 0x20, 13); + + /* + * Bit 20 is the reserved and read-only bit, we do this only for: + * - Do nothing for usbphy clk_enable/disable + * - Keep refcount when do usbphy clk_enable/disable, in that case, + * the clk framework many need to enable/disable usbphy's parent + */ + clks[IMX6SLL_CLK_USBPHY1] = imx_clk_gate("usbphy1", "pll3_usb_otg", base + 0x10, 20); + clks[IMX6SLL_CLK_USBPHY2] = imx_clk_gate("usbphy2", "pll7_usb_host", base + 0x20, 20); + + /* + * usbphy*_gate needs to be on after system boots up, and software + * never needs to control it anymore. + */ + if (IS_ENABLED(CONFIG_USB_MXS_PHY)) { + clks[IMX6SLL_CLK_USBPHY1_GATE] = imx_clk_gate_flags("usbphy1_gate", "dummy", base + 0x10, 6, CLK_IS_CRITICAL); + clks[IMX6SLL_CLK_USBPHY2_GATE] = imx_clk_gate_flags("usbphy2_gate", "dummy", base + 0x20, 6, CLK_IS_CRITICAL); + } + + /* name parent_name reg idx */ + clks[IMX6SLL_CLK_PLL2_PFD0] = imx_clk_pfd("pll2_pfd0_352m", "pll2_bus", base + 0x100, 0); + clks[IMX6SLL_CLK_PLL2_PFD1] = imx_clk_pfd("pll2_pfd1_594m", "pll2_bus", base + 0x100, 1); + clks[IMX6SLL_CLK_PLL2_PFD2] = imx_clk_pfd("pll2_pfd2_396m", "pll2_bus", base + 0x100, 2); + clks[IMX6SLL_CLK_PLL2_PFD3] = imx_clk_pfd("pll2_pfd3_594m", "pll2_bus", base + 0x100, 3); + clks[IMX6SLL_CLK_PLL3_PFD0] = imx_clk_pfd("pll3_pfd0_720m", "pll3_usb_otg", base + 0xf0, 0); + clks[IMX6SLL_CLK_PLL3_PFD1] = imx_clk_pfd("pll3_pfd1_540m", "pll3_usb_otg", base + 0xf0, 1); + clks[IMX6SLL_CLK_PLL3_PFD2] = imx_clk_pfd("pll3_pfd2_508m", "pll3_usb_otg", base + 0xf0, 2); + clks[IMX6SLL_CLK_PLL3_PFD3] = imx_clk_pfd("pll3_pfd3_454m", "pll3_usb_otg", base + 0xf0, 3); + + clks[IMX6SLL_CLK_PLL4_POST_DIV] = clk_register_divider_table(NULL, "pll4_post_div", "pll4_audio", + CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0x70, 19, 2, 0, post_div_table, &imx_ccm_lock); + clks[IMX6SLL_CLK_PLL4_AUDIO_DIV] = clk_register_divider(NULL, "pll4_audio_div", "pll4_post_div", + CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0x170, 15, 1, 0, &imx_ccm_lock); + clks[IMX6SLL_CLK_PLL5_POST_DIV] = clk_register_divider_table(NULL, "pll5_post_div", "pll5_video", + CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0xa0, 19, 2, 0, post_div_table, &imx_ccm_lock); + clks[IMX6SLL_CLK_PLL5_VIDEO_DIV] = clk_register_divider_table(NULL, "pll5_video_div", "pll5_post_div", + CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0x170, 30, 2, 0, video_div_table, &imx_ccm_lock); + + /* name parent_name mult div */ + clks[IMX6SLL_CLK_PLL2_198M] = imx_clk_fixed_factor("pll2_198m", "pll2_pfd2_396m", 1, 2); + clks[IMX6SLL_CLK_PLL3_120M] = imx_clk_fixed_factor("pll3_120m", "pll3_usb_otg", 1, 4); + clks[IMX6SLL_CLK_PLL3_80M] = imx_clk_fixed_factor("pll3_80m", "pll3_usb_otg", 1, 6); + clks[IMX6SLL_CLK_PLL3_60M] = imx_clk_fixed_factor("pll3_60m", "pll3_usb_otg", 1, 8); + + np = ccm_node; + base = of_iomap(np, 0); + WARN_ON(!base); + + clks[IMX6SLL_CLK_STEP] = imx_clk_mux("step", base + 0x0c, 8, 1, step_sels, ARRAY_SIZE(step_sels)); + clks[IMX6SLL_CLK_PLL1_SW] = imx_clk_mux_flags("pll1_sw", base + 0x0c, 2, 1, pll1_sw_sels, ARRAY_SIZE(pll1_sw_sels), 0); + clks[IMX6SLL_CLK_AXI_ALT_SEL] = imx_clk_mux("axi_alt_sel", base + 0x14, 7, 1, axi_alt_sels, ARRAY_SIZE(axi_alt_sels)); + clks[IMX6SLL_CLK_AXI_SEL] = imx_clk_mux_flags("axi_sel", base + 0x14, 6, 1, axi_sels, ARRAY_SIZE(axi_sels), 0); + clks[IMX6SLL_CLK_PERIPH_PRE] = imx_clk_mux("periph_pre", base + 0x18, 18, 2, periph_pre_sels, ARRAY_SIZE(periph_pre_sels)); + clks[IMX6SLL_CLK_PERIPH2_PRE] = imx_clk_mux("periph2_pre", base + 0x18, 21, 2, periph2_pre_sels, ARRAY_SIZE(periph2_pre_sels)); + clks[IMX6SLL_CLK_PERIPH_CLK2_SEL] = imx_clk_mux("periph_clk2_sel", base + 0x18, 12, 2, periph_clk2_sels, ARRAY_SIZE(periph_clk2_sels)); + clks[IMX6SLL_CLK_PERIPH2_CLK2_SEL] = imx_clk_mux("periph2_clk2_sel", base + 0x18, 20, 1, periph2_clk2_sels, ARRAY_SIZE(periph2_clk2_sels)); + clks[IMX6SLL_CLK_USDHC1_SEL] = imx_clk_mux("usdhc1_sel", base + 0x1c, 16, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels)); + clks[IMX6SLL_CLK_USDHC2_SEL] = imx_clk_mux("usdhc2_sel", base + 0x1c, 17, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels)); + clks[IMX6SLL_CLK_USDHC3_SEL] = imx_clk_mux("usdhc3_sel", base + 0x1c, 18, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels)); + clks[IMX6SLL_CLK_SSI1_SEL] = imx_clk_mux("ssi1_sel", base + 0x1c, 10, 2, ssi_sels, ARRAY_SIZE(ssi_sels)); + clks[IMX6SLL_CLK_SSI2_SEL] = imx_clk_mux("ssi2_sel", base + 0x1c, 12, 2, ssi_sels, ARRAY_SIZE(ssi_sels)); + clks[IMX6SLL_CLK_SSI3_SEL] = imx_clk_mux("ssi3_sel", base + 0x1c, 14, 2, ssi_sels, ARRAY_SIZE(ssi_sels)); + clks[IMX6SLL_CLK_PERCLK_SEL] = imx_clk_mux("perclk_sel", base + 0x1c, 6, 1, perclk_sels, ARRAY_SIZE(perclk_sels)); + clks[IMX6SLL_CLK_UART_SEL] = imx_clk_mux("uart_sel", base + 0x24, 6, 1, uart_sels, ARRAY_SIZE(uart_sels)); + clks[IMX6SLL_CLK_SPDIF_SEL] = imx_clk_mux("spdif_sel", base + 0x30, 20, 2, spdif_sels, ARRAY_SIZE(spdif_sels)); + clks[IMX6SLL_CLK_EXTERN_AUDIO_SEL] = imx_clk_mux("extern_audio_sel", base + 0x30, 7, 2, spdif_sels, ARRAY_SIZE(spdif_sels)); + clks[IMX6SLL_CLK_EPDC_PRE_SEL] = imx_clk_mux("epdc_pre_sel", base + 0x34, 15, 3, epdc_pre_sels, ARRAY_SIZE(epdc_pre_sels)); + clks[IMX6SLL_CLK_EPDC_SEL] = imx_clk_mux("epdc_sel", base + 0x34, 9, 3, epdc_sels, ARRAY_SIZE(epdc_sels)); + clks[IMX6SLL_CLK_ECSPI_SEL] = imx_clk_mux("ecspi_sel", base + 0x38, 18, 1, ecspi_sels, ARRAY_SIZE(ecspi_sels)); + clks[IMX6SLL_CLK_LCDIF_PRE_SEL] = imx_clk_mux("lcdif_pre_sel", base + 0x38, 15, 3, lcdif_pre_sels, ARRAY_SIZE(lcdif_pre_sels)); + clks[IMX6SLL_CLK_LCDIF_SEL] = imx_clk_mux("lcdif_sel", base + 0x38, 9, 3, lcdif_sels, ARRAY_SIZE(lcdif_sels)); + + clks[IMX6SLL_CLK_PERIPH] = imx_clk_busy_mux("periph", base + 0x14, 25, 1, base + 0x48, 5, periph_sels, ARRAY_SIZE(periph_sels)); + clks[IMX6SLL_CLK_PERIPH2] = imx_clk_busy_mux("periph2", base + 0x14, 26, 1, base + 0x48, 3, periph2_sels, ARRAY_SIZE(periph2_sels)); + + clks[IMX6SLL_CLK_PERIPH_CLK2] = imx_clk_divider("periph_clk2", "periph_clk2_sel", base + 0x14, 27, 3); + clks[IMX6SLL_CLK_PERIPH2_CLK2] = imx_clk_divider("periph2_clk2", "periph2_clk2_sel", base + 0x14, 0, 3); + clks[IMX6SLL_CLK_IPG] = imx_clk_divider("ipg", "ahb", base + 0x14, 8, 2); + clks[IMX6SLL_CLK_LCDIF_PODF] = imx_clk_divider("lcdif_podf", "lcdif_pred", base + 0x18, 23, 3); + clks[IMX6SLL_CLK_PERCLK] = imx_clk_divider("perclk", "perclk_sel", base + 0x1c, 0, 6); + clks[IMX6SLL_CLK_USDHC3_PODF] = imx_clk_divider("usdhc3_podf", "usdhc3_sel", base + 0x24, 19, 3); + clks[IMX6SLL_CLK_USDHC2_PODF] = imx_clk_divider("usdhc2_podf", "usdhc2_sel", base + 0x24, 16, 3); + clks[IMX6SLL_CLK_USDHC1_PODF] = imx_clk_divider("usdhc1_podf", "usdhc1_sel", base + 0x24, 11, 3); + clks[IMX6SLL_CLK_UART_PODF] = imx_clk_divider("uart_podf", "uart_sel", base + 0x24, 0, 6); + clks[IMX6SLL_CLK_SSI3_PRED] = imx_clk_divider("ssi3_pred", "ssi3_sel", base + 0x28, 22, 3); + clks[IMX6SLL_CLK_SSI3_PODF] = imx_clk_divider("ssi3_podf", "ssi3_pred", base + 0x28, 16, 6); + clks[IMX6SLL_CLK_SSI1_PRED] = imx_clk_divider("ssi1_pred", "ssi1_sel", base + 0x28, 6, 3); + clks[IMX6SLL_CLK_SSI1_PODF] = imx_clk_divider("ssi1_podf", "ssi1_pred", base + 0x28, 0, 6); + clks[IMX6SLL_CLK_SSI2_PRED] = imx_clk_divider("ssi2_pred", "ssi2_sel", base + 0x2c, 6, 3); + clks[IMX6SLL_CLK_SSI2_PODF] = imx_clk_divider("ssi2_podf", "ssi2_pred", base + 0x2c, 0, 6); + clks[IMX6SLL_CLK_SPDIF_PRED] = imx_clk_divider("spdif_pred", "spdif_sel", base + 0x30, 25, 3); + clks[IMX6SLL_CLK_SPDIF_PODF] = imx_clk_divider("spdif_podf", "spdif_pred", base + 0x30, 22, 3); + clks[IMX6SLL_CLK_EXTERN_AUDIO_PRED] = imx_clk_divider("extern_audio_pred", "extern_audio_sel", base + 0x30, 12, 3); + clks[IMX6SLL_CLK_EXTERN_AUDIO_PODF] = imx_clk_divider("extern_audio_podf", "extern_audio_pred", base + 0x30, 9, 3); + clks[IMX6SLL_CLK_EPDC_PODF] = imx_clk_divider("epdc_podf", "epdc_pre_sel", base + 0x34, 12, 3); + clks[IMX6SLL_CLK_ECSPI_PODF] = imx_clk_divider("ecspi_podf", "ecspi_sel", base + 0x38, 19, 6); + clks[IMX6SLL_CLK_LCDIF_PRED] = imx_clk_divider("lcdif_pred", "lcdif_pre_sel", base + 0x38, 12, 3); + + clks[IMX6SLL_CLK_ARM] = imx_clk_busy_divider("arm", "pll1_sw", base + 0x10, 0, 3, base + 0x48, 16); + clks[IMX6SLL_CLK_MMDC_PODF] = imx_clk_busy_divider("mmdc_podf", "periph2", base + 0x14, 3, 3, base + 0x48, 2); + clks[IMX6SLL_CLK_AXI_PODF] = imx_clk_busy_divider("axi", "axi_sel", base + 0x14, 16, 3, base + 0x48, 0); + clks[IMX6SLL_CLK_AHB] = imx_clk_busy_divider("ahb", "periph", base + 0x14, 10, 3, base + 0x48, 1); + + clks[IMX6SLL_CLK_LDB_DI0_DIV_3_5] = imx_clk_fixed_factor("ldb_di0_div_3_5", "ldb_di0_sel", 2, 7); + clks[IMX6SLL_CLK_LDB_DI0_DIV_7] = imx_clk_fixed_factor("ldb_di0_div_7", "ldb_di0_sel", 1, 7); + clks[IMX6SLL_CLK_LDB_DI1_DIV_3_5] = imx_clk_fixed_factor("ldb_di1_div_3_5", "ldb_di1_sel", 2, 7); + clks[IMX6SLL_CLK_LDB_DI1_DIV_7] = imx_clk_fixed_factor("ldb_di1_div_7", "ldb_di1_sel", 1, 7); + + clks[IMX6SLL_CLK_LDB_DI0_SEL] = imx_clk_mux("ldb_di0_sel", base + 0x2c, 9, 3, ldb_di0_sels, ARRAY_SIZE(ldb_di0_sels)); + clks[IMX6SLL_CLK_LDB_DI1_SEL] = imx_clk_mux("ldb_di1_sel", base + 0x1c, 7, 3, ldb_di1_sels, ARRAY_SIZE(ldb_di1_sels)); + clks[IMX6SLL_CLK_LDB_DI0_DIV_SEL] = imx_clk_mux("ldb_di0_div_sel", base + 0x20, 10, 1, ldb_di0_div_sels, ARRAY_SIZE(ldb_di0_div_sels)); + clks[IMX6SLL_CLK_LDB_DI1_DIV_SEL] = imx_clk_mux("ldb_di1_div_sel", base + 0x20, 10, 1, ldb_di1_div_sels, ARRAY_SIZE(ldb_di1_div_sels)); + + /* CCGR0 */ + clks[IMX6SLL_CLK_AIPSTZ1] = imx_clk_gate2_flags("aips_tz1", "ahb", base + 0x68, 0, CLK_IS_CRITICAL); + clks[IMX6SLL_CLK_AIPSTZ2] = imx_clk_gate2_flags("aips_tz2", "ahb", base + 0x68, 2, CLK_IS_CRITICAL); + clks[IMX6SLL_CLK_DCP] = imx_clk_gate2("dcp", "ahb", base + 0x68, 10); + clks[IMX6SLL_CLK_UART2_IPG] = imx_clk_gate2("uart2_ipg", "ipg", base + 0x68, 28); + clks[IMX6SLL_CLK_UART2_SERIAL] = imx_clk_gate2("uart2_serial", "uart_podf", base + 0x68, 28); + + /* CCGR1 */ + clks[IMX6SLL_CLK_ECSPI1] = imx_clk_gate2("ecspi1", "ecspi_podf", base + 0x6c, 0); + clks[IMX6SLL_CLK_ECSPI2] = imx_clk_gate2("ecspi2", "ecspi_podf", base + 0x6c, 2); + clks[IMX6SLL_CLK_ECSPI3] = imx_clk_gate2("ecspi3", "ecspi_podf", base + 0x6c, 4); + clks[IMX6SLL_CLK_ECSPI4] = imx_clk_gate2("ecspi4", "ecspi_podf", base + 0x6c, 6); + clks[IMX6SLL_CLK_UART3_IPG] = imx_clk_gate2("uart3_ipg", "ipg", base + 0x6c, 10); + clks[IMX6SLL_CLK_UART3_SERIAL] = imx_clk_gate2("uart3_serial", "uart_podf", base + 0x6c, 10); + clks[IMX6SLL_CLK_EPIT1] = imx_clk_gate2("epit1", "perclk", base + 0x6c, 12); + clks[IMX6SLL_CLK_EPIT2] = imx_clk_gate2("epit2", "perclk", base + 0x6c, 14); + clks[IMX6SLL_CLK_GPT_BUS] = imx_clk_gate2("gpt1_bus", "perclk", base + 0x6c, 20); + clks[IMX6SLL_CLK_GPT_SERIAL] = imx_clk_gate2("gpt1_serial", "perclk", base + 0x6c, 22); + clks[IMX6SLL_CLK_UART4_IPG] = imx_clk_gate2("uart4_ipg", "ipg", base + 0x6c, 24); + clks[IMX6SLL_CLK_UART4_SERIAL] = imx_clk_gate2("uart4_serail", "uart_podf", base + 0x6c, 24); + + /* CCGR2 */ + clks[IMX6SLL_CLK_CSI] = imx_clk_gate2("csi", "axi", base + 0x70, 2); + clks[IMX6SLL_CLK_I2C1] = imx_clk_gate2("i2c1", "perclk", base + 0x70, 6); + clks[IMX6SLL_CLK_I2C2] = imx_clk_gate2("i2c2", "perclk", base + 0x70, 8); + clks[IMX6SLL_CLK_I2C3] = imx_clk_gate2("i2c3", "perclk", base + 0x70, 10); + clks[IMX6SLL_CLK_OCOTP] = imx_clk_gate2("ocotp", "ipg", base + 0x70, 12); + clks[IMX6SLL_CLK_LCDIF_APB] = imx_clk_gate2("lcdif_apb", "axi", base + 0x70, 28); + clks[IMX6SLL_CLK_PXP] = imx_clk_gate2("pxp", "axi", base + 0x70, 30); + + /* CCGR3 */ + clks[IMX6SLL_CLK_UART5_IPG] = imx_clk_gate2("uart5_ipg", "ipg", base + 0x74, 2); + clks[IMX6SLL_CLK_UART5_SERIAL] = imx_clk_gate2("uart5_serial", "uart_podf", base + 0x74, 2); + clks[IMX6SLL_CLK_EPDC_AXI] = imx_clk_gate2("epdc_aclk", "axi", base + 0x74, 4); + clks[IMX6SLL_CLK_EPDC_PIX] = imx_clk_gate2("epdc_pix", "epdc_podf", base + 0x74, 4); + clks[IMX6SLL_CLK_LCDIF_PIX] = imx_clk_gate2("lcdif_pix", "lcdif_podf", base + 0x74, 10); + clks[IMX6SLL_CLK_WDOG1] = imx_clk_gate2("wdog1", "ipg", base + 0x74, 16); + clks[IMX6SLL_CLK_MMDC_P0_FAST] = imx_clk_gate_flags("mmdc_p0_fast", "mmdc_podf", base + 0x74, 20, CLK_IS_CRITICAL); + clks[IMX6SLL_CLK_MMDC_P0_IPG] = imx_clk_gate2_flags("mmdc_p0_ipg", "ipg", base + 0x74, 24, CLK_IS_CRITICAL); + clks[IMX6SLL_CLK_OCRAM] = imx_clk_gate_flags("ocram","ahb", base + 0x74, 28, CLK_IS_CRITICAL); + + /* CCGR4 */ + clks[IMX6SLL_CLK_PWM1] = imx_clk_gate2("pwm1", "perclk", base + 0x78, 16); + clks[IMX6SLL_CLK_PWM2] = imx_clk_gate2("pwm2", "perclk", base + 0x78, 18); + clks[IMX6SLL_CLK_PWM3] = imx_clk_gate2("pwm3", "perclk", base + 0x78, 20); + clks[IMX6SLL_CLK_PWM4] = imx_clk_gate2("pwm4", "perclk", base + 0x78, 22); + + /* CCGR5 */ + clks[IMX6SLL_CLK_ROM] = imx_clk_gate2_flags("rom", "ahb", base + 0x7c, 0, CLK_IS_CRITICAL); + clks[IMX6SLL_CLK_SDMA] = imx_clk_gate2("sdma", "ahb", base + 0x7c, 6); + clks[IMX6SLL_CLK_WDOG2] = imx_clk_gate2("wdog2", "ipg", base + 0x7c, 10); + clks[IMX6SLL_CLK_SPBA] = imx_clk_gate2("spba", "ipg", base + 0x7c, 12); + clks[IMX6SLL_CLK_EXTERN_AUDIO] = imx_clk_gate2_shared("extern_audio", "extern_audio_podf", base + 0x7c, 14, &share_count_audio); + clks[IMX6SLL_CLK_SPDIF] = imx_clk_gate2_shared("spdif", "spdif_podf", base + 0x7c, 14, &share_count_audio); + clks[IMX6SLL_CLK_SPDIF_GCLK] = imx_clk_gate2_shared("spdif_gclk", "ipg", base + 0x7c, 14, &share_count_audio); + clks[IMX6SLL_CLK_SSI1] = imx_clk_gate2_shared("ssi1", "ssi1_podf", base + 0x7c, 18, &share_count_ssi1); + clks[IMX6SLL_CLK_SSI1_IPG] = imx_clk_gate2_shared("ssi1_ipg", "ipg", base + 0x7c, 18, &share_count_ssi1); + clks[IMX6SLL_CLK_SSI2] = imx_clk_gate2_shared("ssi2", "ssi2_podf", base + 0x7c, 20, &share_count_ssi2); + clks[IMX6SLL_CLK_SSI2_IPG] = imx_clk_gate2_shared("ssi2_ipg", "ipg", base + 0x7c, 20, &share_count_ssi2); + clks[IMX6SLL_CLK_SSI3] = imx_clk_gate2_shared("ssi3", "ssi3_podf", base + 0x7c, 22, &share_count_ssi3); + clks[IMX6SLL_CLK_SSI3_IPG] = imx_clk_gate2_shared("ssi3_ipg", "ipg", base + 0x7c, 22, &share_count_ssi3); + clks[IMX6SLL_CLK_UART1_IPG] = imx_clk_gate2("uart1_ipg", "ipg", base + 0x7c, 24); + clks[IMX6SLL_CLK_UART1_SERIAL] = imx_clk_gate2("uart1_serial", "uart_podf", base + 0x7c, 24); + + /* CCGR6 */ + clks[IMX6SLL_CLK_USBOH3] = imx_clk_gate2("usboh3", "ipg", base + 0x80, 0); + clks[IMX6SLL_CLK_USDHC1] = imx_clk_gate2("usdhc1", "usdhc1_podf", base + 0x80, 2); + clks[IMX6SLL_CLK_USDHC2] = imx_clk_gate2("usdhc2", "usdhc2_podf", base + 0x80, 4); + clks[IMX6SLL_CLK_USDHC3] = imx_clk_gate2("usdhc3", "usdhc3_podf", base + 0x80, 6); + + /* mask handshake of mmdc */ + writel_relaxed(BM_CCM_CCDR_MMDC_CH0_MASK, base + 0x4); + + imx_check_clocks(clks, ARRAY_SIZE(clks)); + + clk_data.clks = clks; + clk_data.clk_num = ARRAY_SIZE(clks); + of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); + + /* Lower the AHB clock rate before changing the clock source. */ + clk_set_rate(clks[IMX6SLL_CLK_AHB], 99000000); + + /* Change periph_pre clock to pll2_bus to adjust AXI rate to 264MHz */ + clk_set_parent(clks[IMX6SLL_CLK_PERIPH_CLK2_SEL], clks[IMX6SLL_CLK_PLL3_USB_OTG]); + clk_set_parent(clks[IMX6SLL_CLK_PERIPH], clks[IMX6SLL_CLK_PERIPH_CLK2]); + clk_set_parent(clks[IMX6SLL_CLK_PERIPH_PRE], clks[IMX6SLL_CLK_PLL2_BUS]); + clk_set_parent(clks[IMX6SLL_CLK_PERIPH], clks[IMX6SLL_CLK_PERIPH_PRE]); + + clk_set_rate(clks[IMX6SLL_CLK_AHB], 132000000); +} +CLK_OF_DECLARE_DRIVER(imx6sll, "fsl,imx6sll-ccm", imx6sll_clocks_init); -- cgit From 5ced1923128470bda20d454cc6b07a8aa2f2e64d Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Fri, 30 Mar 2018 17:28:51 +0200 Subject: clk: davinci: add a reset lookup table for psc0 In order to be able to use the reset framework in legacy boot mode as well, add the reset lookup table to the psc driver for da850 variant. Signed-off-by: Bartosz Golaszewski Reviewed-by: David Lechner Signed-off-by: Stephen Boyd --- drivers/clk/davinci/psc-da850.c | 7 +++++++ drivers/clk/davinci/psc.c | 1 + 2 files changed, 8 insertions(+) diff --git a/drivers/clk/davinci/psc-da850.c b/drivers/clk/davinci/psc-da850.c index ccc7eb17bf3a..d196dcbed560 100644 --- a/drivers/clk/davinci/psc-da850.c +++ b/drivers/clk/davinci/psc-da850.c @@ -6,6 +6,7 @@ */ #include +#include #include #include #include @@ -66,8 +67,14 @@ LPSC_CLKDEV3(ecap_clkdev, "fck", "ecap.0", "fck", "ecap.1", "fck", "ecap.2"); +static struct reset_control_lookup da850_psc0_reset_lookup_table[] = { + RESET_LOOKUP("da850-psc0", 15, "davinci-rproc.0", NULL), +}; + static int da850_psc0_init(struct device *dev, void __iomem *base) { + reset_controller_add_lookup(da850_psc0_reset_lookup_table, + ARRAY_SIZE(da850_psc0_reset_lookup_table)); return davinci_psc_register_clocks(dev, da850_psc0_info, 16, base); } diff --git a/drivers/clk/davinci/psc.c b/drivers/clk/davinci/psc.c index ff6f4a038e04..ce170e600f09 100644 --- a/drivers/clk/davinci/psc.c +++ b/drivers/clk/davinci/psc.c @@ -425,6 +425,7 @@ __davinci_psc_register_clocks(struct device *dev, psc->rcdev.ops = &davinci_psc_reset_ops; psc->rcdev.owner = THIS_MODULE; + psc->rcdev.dev = dev; psc->rcdev.of_node = dev->of_node; psc->rcdev.of_reset_n_cells = 1; psc->rcdev.of_xlate = davinci_psc_reset_of_xlate; -- cgit