From 2852bfbf4f168fec27049ad9ed20941fc9e84b95 Mon Sep 17 00:00:00 2001 From: Icenowy Zheng Date: Thu, 9 Aug 2018 01:19:52 +0800 Subject: [PATCH 01/23] clk: sunxi-ng: h6: fix bus clocks' divider position The bus clocks (AHB/APB) on Allwinner H6 have their second divider start at bit 8, according to the user manual and the BSP code. However, currently the divider offset is incorrectly set to 16, thus the divider is not correctly read and the clock frequency is not correctly calculated. Fix this bit offset on all affected bus clocks in ccu-sun50i-h6. Cc: stable@vger.kernel.org # v4.17.y Signed-off-by: Icenowy Zheng Signed-off-by: Chen-Yu Tsai --- drivers/clk/sunxi-ng/ccu-sun50i-h6.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-h6.c b/drivers/clk/sunxi-ng/ccu-sun50i-h6.c index bdbfe78fe133..0f7a0ffd3f70 100644 --- a/drivers/clk/sunxi-ng/ccu-sun50i-h6.c +++ b/drivers/clk/sunxi-ng/ccu-sun50i-h6.c @@ -224,7 +224,7 @@ static SUNXI_CCU_MP_WITH_MUX(psi_ahb1_ahb2_clk, "psi-ahb1-ahb2", psi_ahb1_ahb2_parents, 0x510, 0, 5, /* M */ - 16, 2, /* P */ + 8, 2, /* P */ 24, 2, /* mux */ 0); @@ -233,19 +233,19 @@ static const char * const ahb3_apb1_apb2_parents[] = { "osc24M", "osc32k", "pll-periph0" }; static SUNXI_CCU_MP_WITH_MUX(ahb3_clk, "ahb3", ahb3_apb1_apb2_parents, 0x51c, 0, 5, /* M */ - 16, 2, /* P */ + 8, 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 */ + 8, 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 */ + 8, 2, /* P */ 24, 2, /* mux */ 0); From 58c0f79887d5e425fe6a9fd542778e50df69e9c6 Mon Sep 17 00:00:00 2001 From: Rongyi Chen Date: Fri, 10 Aug 2018 23:16:38 +0800 Subject: [PATCH 02/23] clk: sunxi-ng: h6: fix PWM gate/reset offset Currently the register offset of the PWM bus gate in Allwinner H6 clock driver is wrong. Fix this issue. Fixes: 542353ea ("clk: sunxi-ng: add support for the Allwinner H6 CCU") Signed-off-by: Rongyi Chen [Icenowy: refactor commit message] Signed-off-by: Icenowy Zheng Signed-off-by: Chen-Yu Tsai --- drivers/clk/sunxi-ng/ccu-sun50i-h6.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-h6.c b/drivers/clk/sunxi-ng/ccu-sun50i-h6.c index 0f7a0ffd3f70..d425b47cef17 100644 --- a/drivers/clk/sunxi-ng/ccu-sun50i-h6.c +++ b/drivers/clk/sunxi-ng/ccu-sun50i-h6.c @@ -352,7 +352,7 @@ static SUNXI_CCU_GATE(bus_dbg_clk, "bus-dbg", "psi-ahb1-ahb2", 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_pwm_clk, "bus-pwm", "apb1", 0x7ac, BIT(0), 0); static SUNXI_CCU_GATE(bus_iommu_clk, "bus-iommu", "apb1", 0x7bc, BIT(0), 0); From cb54fbd21a8fd97c2a82a069e8c80abdedbeb530 Mon Sep 17 00:00:00 2001 From: Jernej Skrabec Date: Thu, 9 Aug 2018 18:52:13 +0200 Subject: [PATCH 03/23] clk: sunxi-ng: Add maximum rate constraint to NM PLLs On some NM PLLs, frequency can be set above PLL working range. Add a constraint for maximum supported rate. This way, drivers can specify which is maximum allowed rate for PLL. 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 | 30 ++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/drivers/clk/sunxi-ng/ccu_nm.c b/drivers/clk/sunxi-ng/ccu_nm.c index 4e2073307f34..6fe3c14f7b2d 100644 --- a/drivers/clk/sunxi-ng/ccu_nm.c +++ b/drivers/clk/sunxi-ng/ccu_nm.c @@ -124,6 +124,13 @@ static long ccu_nm_round_rate(struct clk_hw *hw, unsigned long rate, return rate; } + if (nm->max_rate && rate > nm->max_rate) { + rate = nm->max_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 1d8b459c50b7..de232f2199a6 100644 --- a/drivers/clk/sunxi-ng/ccu_nm.h +++ b/drivers/clk/sunxi-ng/ccu_nm.h @@ -38,6 +38,7 @@ struct ccu_nm { unsigned int fixed_post_div; unsigned int min_rate; + unsigned int max_rate; struct ccu_common common; }; @@ -115,6 +116,35 @@ struct ccu_nm { }, \ } +#define SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN_MAX(_struct, _name, \ + _parent, _reg, \ + _min_rate, _max_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, \ + .max_rate = _max_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, \ From 02d7901695afd1dcbec7182d878927893c07174e Mon Sep 17 00:00:00 2001 From: Jernej Skrabec Date: Thu, 9 Aug 2018 18:52:14 +0200 Subject: [PATCH 04/23] clk: sunxi-ng: h3/h5: Add max. rate constraint to pll-video As it turns out, pll-video can be set to higher rate that it is really supported by HW. For example, one monitor requested 185.58 MHz pixel clock. Clock framework calculated that minimum rate error would be when pll-video is set to 2040 MHz. This is clearly out of specs. Both H3 and H5 user manuals specify 600 MHz as maximum supported rate. However, BSP clock drivers allow up to 912 MHz and 1008 MHz respectively. Here 912 MHz is chosen because user manuals were already proven wrong once for lower limits. Signed-off-by: Jernej Skrabec Signed-off-by: Maxime Ripard --- drivers/clk/sunxi-ng/ccu-sun8i-h3.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-h3.c b/drivers/clk/sunxi-ng/ccu-sun8i-h3.c index 77ed0b0ba681..eb5c608428fa 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-h3.c +++ b/drivers/clk/sunxi-ng/ccu-sun8i-h3.c @@ -69,18 +69,19 @@ 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_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_MIN_MAX(pll_video_clk, "pll-video", + "osc24M", 0x0010, + 192000000, /* Minimum rate */ + 912000000, /* Maximum 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, From b16fb66915fcfc6b1a7eb48225b6b30b69bb721b Mon Sep 17 00:00:00 2001 From: Jernej Skrabec Date: Thu, 9 Aug 2018 18:52:15 +0200 Subject: [PATCH 05/23] clk: sunxi-ng: r40: Add max. rate constraint to video PLLs Video PLLs on R40 can be set to higher rate that it is actually supported by HW. Limit maximum rate to 1008 MHz. This is the maximum allowed rate by BSP clock driver. Interestengly, user manual specifies maximum frequency to be 600 MHz. Historically, this data was wrong in some user manuals for other SoCs, so more faith is put in BSP clock driver. Signed-off-by: Jernej Skrabec Signed-off-by: Maxime Ripard --- drivers/clk/sunxi-ng/ccu-sun8i-r40.c | 52 ++++++++++++++-------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-r40.c b/drivers/clk/sunxi-ng/ccu-sun8i-r40.c index 0f388f6944d5..582ebd41d20d 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-r40.c +++ b/drivers/clk/sunxi-ng/ccu-sun8i-r40.c @@ -65,19 +65,19 @@ static SUNXI_CCU_NM_WITH_GATE_LOCK(pll_audio_base_clk, "pll-audio-base", BIT(28), /* lock */ CLK_SET_RATE_UNGATE); -/* TODO: The result of N/M is required to be in [8, 25] range. */ -static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN(pll_video0_clk, "pll-video0", - "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_MIN_MAX(pll_video0_clk, "pll-video0", + "osc24M", 0x0010, + 192000000, /* Minimum rate */ + 1008000000, /* Maximum 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); /* TODO: The result of N/M is required to be in [8, 25] range. */ static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_ve_clk, "pll-ve", @@ -152,19 +152,19 @@ static struct ccu_nk pll_periph1_clk = { }, }; -/* TODO: The result of N/M is required to be in [8, 25] range. */ -static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN(pll_video1_clk, "pll-video1", - "osc24M", 0x030, - 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_MIN_MAX(pll_video1_clk, "pll-video1", + "osc24M", 0x030, + 192000000, /* Minimum rate */ + 1008000000, /* Maximum 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 struct ccu_nkm pll_sata_clk = { .enable = BIT(31), From a8e5433cdc500290b52d26a05056e02c448a413c Mon Sep 17 00:00:00 2001 From: Jernej Skrabec Date: Thu, 9 Aug 2018 18:52:16 +0200 Subject: [PATCH 06/23] clk: sunxi-ng: nkmp: Add constraint for maximum rate Some, if not most, NKMP PLLs can be set to higher rate that is really supported by HW. Implement support for maximum frequency constrain for NKMP PLLs. Signed-off-by: Jernej Skrabec Signed-off-by: Maxime Ripard --- drivers/clk/sunxi-ng/ccu_nkmp.c | 7 +++++++ drivers/clk/sunxi-ng/ccu_nkmp.h | 1 + 2 files changed, 8 insertions(+) diff --git a/drivers/clk/sunxi-ng/ccu_nkmp.c b/drivers/clk/sunxi-ng/ccu_nkmp.c index ebd9436d2c7c..9b49adb20d07 100644 --- a/drivers/clk/sunxi-ng/ccu_nkmp.c +++ b/drivers/clk/sunxi-ng/ccu_nkmp.c @@ -137,6 +137,13 @@ static long ccu_nkmp_round_rate(struct clk_hw *hw, unsigned long rate, if (nkmp->common.features & CCU_FEATURE_FIXED_POSTDIV) rate *= nkmp->fixed_post_div; + if (nkmp->max_rate && rate > nkmp->max_rate) { + rate = nkmp->max_rate; + if (nkmp->common.features & CCU_FEATURE_FIXED_POSTDIV) + rate /= nkmp->fixed_post_div; + return rate; + } + _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 6940503e7fc4..a9f8c116a745 100644 --- a/drivers/clk/sunxi-ng/ccu_nkmp.h +++ b/drivers/clk/sunxi-ng/ccu_nkmp.h @@ -35,6 +35,7 @@ struct ccu_nkmp { struct ccu_div_internal p; unsigned int fixed_post_div; + unsigned int max_rate; struct ccu_common common; }; From a528872dbb87faefda3056023eaaf83f14fdafdf Mon Sep 17 00:00:00 2001 From: Jernej Skrabec Date: Thu, 9 Aug 2018 18:52:17 +0200 Subject: [PATCH 07/23] clk: sunxi-ng: a83t: Add max. rate constraint to video PLLs It may happen that clock framework finds optimal video PLL rate above that which is really supported by HW. User manual doesn't really say what is upper limit for video PLLs on A83T. Because of that, use the maximum rate defined in BSP clk driver which is 3 GHz. Signed-off-by: Jernej Skrabec Signed-off-by: Maxime Ripard --- drivers/clk/sunxi-ng/ccu-sun8i-a83t.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-a83t.c b/drivers/clk/sunxi-ng/ccu-sun8i-a83t.c index 7d08015b980d..2d6555d73170 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-a83t.c +++ b/drivers/clk/sunxi-ng/ccu-sun8i-a83t.c @@ -108,6 +108,7 @@ static struct ccu_nkmp pll_video0_clk = { .n = _SUNXI_CCU_MULT_OFFSET_MIN_MAX(8, 8, 0, 12, 0), .m = _SUNXI_CCU_DIV(16, 1), /* input divider */ .p = _SUNXI_CCU_DIV(0, 2), /* output divider */ + .max_rate = 3000000000UL, .common = { .reg = 0x010, .lock_reg = CCU_SUN8I_A83T_LOCK_REG, @@ -220,6 +221,7 @@ static struct ccu_nkmp pll_video1_clk = { .n = _SUNXI_CCU_MULT_OFFSET_MIN_MAX(8, 8, 0, 12, 0), .m = _SUNXI_CCU_DIV(16, 1), /* input divider */ .p = _SUNXI_CCU_DIV(0, 2), /* external divider p */ + .max_rate = 3000000000UL, .common = { .reg = 0x04c, .lock_reg = CCU_SUN8I_A83T_LOCK_REG, From d9d95e78cff80c3fe43e757ba90644cd766302ac Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Fri, 13 Jul 2018 15:44:45 +0200 Subject: [PATCH 08/23] clk: mvebu: armada-37xx-periph: save the IP base address in the driver data Prepare the introduction of suspend/resume hooks by having an easy way to access all the registers in one go just from a device: add the IP base address in the driver data. Signed-off-by: Miquel Raynal Signed-off-by: Stephen Boyd --- drivers/clk/mvebu/armada-37xx-periph.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/drivers/clk/mvebu/armada-37xx-periph.c b/drivers/clk/mvebu/armada-37xx-periph.c index 499f5962c8b0..78048c2e3774 100644 --- a/drivers/clk/mvebu/armada-37xx-periph.c +++ b/drivers/clk/mvebu/armada-37xx-periph.c @@ -56,6 +56,7 @@ struct clk_periph_driver_data { struct clk_hw_onecell_data *hw_data; spinlock_t lock; + void __iomem *reg; }; struct clk_double_div { @@ -680,7 +681,6 @@ static int armada_3700_periph_clock_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; int num_periph = 0, i, ret; struct resource *res; - void __iomem *reg; data = of_device_get_match_data(dev); if (!data) @@ -689,11 +689,6 @@ static int armada_3700_periph_clock_probe(struct platform_device *pdev) while (data[num_periph].name) num_periph++; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - reg = devm_ioremap_resource(dev, res); - if (IS_ERR(reg)) - return PTR_ERR(reg); - driver_data = devm_kzalloc(dev, sizeof(*driver_data), GFP_KERNEL); if (!driver_data) return -ENOMEM; @@ -706,12 +701,16 @@ static int armada_3700_periph_clock_probe(struct platform_device *pdev) return -ENOMEM; driver_data->hw_data->num = num_periph; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + driver_data->reg = devm_ioremap_resource(dev, res); + if (IS_ERR(driver_data->reg)) + return PTR_ERR(driver_data->reg); + spin_lock_init(&driver_data->lock); for (i = 0; i < num_periph; i++) { struct clk_hw **hw = &driver_data->hw_data->hws[i]; - - if (armada_3700_add_composite_clk(&data[i], reg, + if (armada_3700_add_composite_clk(&data[i], driver_data->reg, &driver_data->lock, dev, hw)) dev_err(dev, "Can't register periph clock %s\n", data[i].name); From 5beb1e60dba973e0b9cfb54d9735d5d4385b9d90 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Fri, 13 Jul 2018 15:44:46 +0200 Subject: [PATCH 09/23] clk: mvebu: armada-37xx-periph: add suspend/resume support Add suspend/resume hooks in Armada 37xx peripheral clocks driver to handle S2RAM operations. One can think that these hooks are useless by comparing the register values before and after a suspend/resume cycle: they will look the same anyway. This is because of some scripts executed by the Cortex-M3 core during ATF operations to init both the clocks and the DDR. These values could be modified by the BL33 stage or by Linux itself and should be preserved. Signed-off-by: Miquel Raynal Signed-off-by: Stephen Boyd --- drivers/clk/mvebu/armada-37xx-periph.c | 43 ++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/drivers/clk/mvebu/armada-37xx-periph.c b/drivers/clk/mvebu/armada-37xx-periph.c index 78048c2e3774..1f1cff428d78 100644 --- a/drivers/clk/mvebu/armada-37xx-periph.c +++ b/drivers/clk/mvebu/armada-37xx-periph.c @@ -57,6 +57,14 @@ struct clk_periph_driver_data { struct clk_hw_onecell_data *hw_data; spinlock_t lock; void __iomem *reg; + + /* Storage registers for suspend/resume operations */ + u32 tbg_sel; + u32 div_sel0; + u32 div_sel1; + u32 div_sel2; + u32 clk_sel; + u32 clk_dis; }; struct clk_double_div { @@ -673,6 +681,40 @@ static int armada_3700_add_composite_clk(const struct clk_periph_data *data, return PTR_ERR_OR_ZERO(*hw); } +static int __maybe_unused armada_3700_periph_clock_suspend(struct device *dev) +{ + struct clk_periph_driver_data *data = dev_get_drvdata(dev); + + data->tbg_sel = readl(data->reg + TBG_SEL); + data->div_sel0 = readl(data->reg + DIV_SEL0); + data->div_sel1 = readl(data->reg + DIV_SEL1); + data->div_sel2 = readl(data->reg + DIV_SEL2); + data->clk_sel = readl(data->reg + CLK_SEL); + data->clk_dis = readl(data->reg + CLK_DIS); + + return 0; +} + +static int __maybe_unused armada_3700_periph_clock_resume(struct device *dev) +{ + struct clk_periph_driver_data *data = dev_get_drvdata(dev); + + /* Follow the same order than what the Cortex-M3 does (ATF code) */ + writel(data->clk_dis, data->reg + CLK_DIS); + writel(data->div_sel0, data->reg + DIV_SEL0); + writel(data->div_sel1, data->reg + DIV_SEL1); + writel(data->div_sel2, data->reg + DIV_SEL2); + writel(data->tbg_sel, data->reg + TBG_SEL); + writel(data->clk_sel, data->reg + CLK_SEL); + + return 0; +} + +static const struct dev_pm_ops armada_3700_periph_clock_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(armada_3700_periph_clock_suspend, + armada_3700_periph_clock_resume) +}; + static int armada_3700_periph_clock_probe(struct platform_device *pdev) { struct clk_periph_driver_data *driver_data; @@ -748,6 +790,7 @@ static struct platform_driver armada_3700_periph_clock_driver = { .driver = { .name = "marvell-armada-3700-periph-clock", .of_match_table = armada_3700_periph_clock_of_match, + .pm = &armada_3700_periph_clock_pm_ops, }, }; From c2ff8383cc33c2d9c169e4daf1e37a434c3bb420 Mon Sep 17 00:00:00 2001 From: Icenowy Zheng Date: Mon, 20 Aug 2018 21:40:13 +0800 Subject: [PATCH 10/23] clk: sunxi-ng: sun50i: h6: Add 2x fixed post-divider to MMC module clocks On the H6, the MMC module clocks are fixed in the new timing mode, i.e. they do not have a bit to select the mode. These clocks have a 2x divider somewhere between the clock and the MMC module. To be consistent with other SoCs supporting the new timing mode, we model the 2x divider as a fixed post-divider on the MMC module clocks. This patch adds the post-dividers to the MMC clocks, following the approach on A64. Fixes: 524353ea480b ("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 | 39 +++++++++++++++------------- 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-h6.c b/drivers/clk/sunxi-ng/ccu-sun50i-h6.c index d425b47cef17..2193e1495086 100644 --- a/drivers/clk/sunxi-ng/ccu-sun50i-h6.c +++ b/drivers/clk/sunxi-ng/ccu-sun50i-h6.c @@ -408,26 +408,29 @@ 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_POSTDIV(mmc0_clk, "mmc0", mmc_parents, 0x830, + 0, 4, /* M */ + 8, 2, /* N */ + 24, 3, /* mux */ + BIT(31), /* gate */ + 2, /* post-div */ + 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_POSTDIV(mmc1_clk, "mmc1", mmc_parents, 0x834, + 0, 4, /* M */ + 8, 2, /* N */ + 24, 3, /* mux */ + BIT(31), /* gate */ + 2, /* post-div */ + 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_MP_WITH_MUX_GATE_POSTDIV(mmc2_clk, "mmc2", mmc_parents, 0x838, + 0, 4, /* M */ + 8, 2, /* N */ + 24, 3, /* mux */ + BIT(31), /* gate */ + 2, /* post-div */ + 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); From 65b1e8a6ca5f5305962daee6af730bd2d210bb0b Mon Sep 17 00:00:00 2001 From: Jagan Teki Date: Tue, 4 Sep 2018 12:40:43 +0800 Subject: [PATCH 11/23] clk: sunxi-ng: a64: Add minimal rate for video PLLs According to documentation and experience with other similar SoCs, video PLLs don't work stable if their output frequency is set below 192 MHz. Because of that, set minimal rate to both A64 video PLLs to 192 MHz. Signed-off-by: Jagan Teki Signed-off-by: Icenowy Zheng Reviewed-by: Jernej Skrabec Signed-off-by: Maxime Ripard --- drivers/clk/sunxi-ng/ccu-sun50i-a64.c | 46 ++++++++++++++------------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-a64.c b/drivers/clk/sunxi-ng/ccu-sun50i-a64.c index ee9c12cf3f08..d0e30192f0cf 100644 --- a/drivers/clk/sunxi-ng/ccu-sun50i-a64.c +++ b/drivers/clk/sunxi-ng/ccu-sun50i-a64.c @@ -64,17 +64,18 @@ static SUNXI_CCU_NM_WITH_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_video0_clk, "pll-video0", - "osc24M", 0x010, - 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_video0_clk, "pll-video0", + "osc24M", 0x010, + 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", 0x018, @@ -125,17 +126,18 @@ static struct ccu_nk pll_periph1_clk = { }, }; -static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_video1_clk, "pll-video1", - "osc24M", 0x030, - 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_video1_clk, "pll-video1", + "osc24M", 0x030, + 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_gpu_clk, "pll-gpu", "osc24M", 0x038, From 5de39acaf34604bd04834f092479cf4dcc946dd4 Mon Sep 17 00:00:00 2001 From: Icenowy Zheng Date: Tue, 4 Sep 2018 12:40:44 +0800 Subject: [PATCH 12/23] clk: sunxi-ng: a64: Add max. rate constraint to video PLLs Video PLLs on A64 can be set to higher rate that it is actually supported by HW. Limit maximum rate to 1008 MHz. This is the maximum allowed rate by BSP clock driver. Interestengly, user manual specifies maximum frequency to be 600 MHz. Historically, this data was wrong in some user manuals for other SoCs, so more faith is put in BSP clock driver. Signed-off-by: Icenowy Zheng Signed-off-by: Maxime Ripard --- drivers/clk/sunxi-ng/ccu-sun50i-a64.c | 50 ++++++++++++++------------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-a64.c b/drivers/clk/sunxi-ng/ccu-sun50i-a64.c index d0e30192f0cf..5f80eb018014 100644 --- a/drivers/clk/sunxi-ng/ccu-sun50i-a64.c +++ b/drivers/clk/sunxi-ng/ccu-sun50i-a64.c @@ -64,18 +64,19 @@ static SUNXI_CCU_NM_WITH_GATE_LOCK(pll_audio_base_clk, "pll-audio-base", BIT(28), /* lock */ CLK_SET_RATE_UNGATE); -static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN(pll_video0_clk, "pll-video0", - "osc24M", 0x010, - 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_MIN_MAX(pll_video0_clk, "pll-video0", + "osc24M", 0x010, + 192000000, /* Minimum rate */ + 1008000000, /* Maximum 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", 0x018, @@ -126,18 +127,19 @@ static struct ccu_nk pll_periph1_clk = { }, }; -static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN(pll_video1_clk, "pll-video1", - "osc24M", 0x030, - 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_MIN_MAX(pll_video1_clk, "pll-video1", + "osc24M", 0x030, + 192000000, /* Minimum rate */ + 1008000000, /* Maximum 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_gpu_clk, "pll-gpu", "osc24M", 0x038, From 8b2a37870419f4aa6e6f837aa8ec627eae984010 Mon Sep 17 00:00:00 2001 From: Jagan Teki Date: Tue, 4 Sep 2018 12:40:49 +0800 Subject: [PATCH 13/23] dt-bindings: clock: sun50i-a64-ccu: Add PLL_VIDEO0 macro Allwinner A64 HDMI PHY clock has PLL_VIDEO0 as a parent. Include the macro on dt-bindings so-that the same can be used while defining CCU clock phandles. Signed-off-by: Jagan Teki Reviewed-by: Rob Herring Signed-off-by: Icenowy Zheng Signed-off-by: Maxime Ripard --- drivers/clk/sunxi-ng/ccu-sun50i-a64.h | 4 +++- include/dt-bindings/clock/sun50i-a64-ccu.h | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-a64.h b/drivers/clk/sunxi-ng/ccu-sun50i-a64.h index 061b6fbb4f95..cd415b968e8c 100644 --- a/drivers/clk/sunxi-ng/ccu-sun50i-a64.h +++ b/drivers/clk/sunxi-ng/ccu-sun50i-a64.h @@ -27,7 +27,9 @@ #define CLK_PLL_AUDIO_2X 4 #define CLK_PLL_AUDIO_4X 5 #define CLK_PLL_AUDIO_8X 6 -#define CLK_PLL_VIDEO0 7 + +/* PLL_VIDEO0 exported for HDMI PHY */ + #define CLK_PLL_VIDEO0_2X 8 #define CLK_PLL_VE 9 #define CLK_PLL_DDR0 10 diff --git a/include/dt-bindings/clock/sun50i-a64-ccu.h b/include/dt-bindings/clock/sun50i-a64-ccu.h index d66432c6e675..a8ac4cfcdcbc 100644 --- a/include/dt-bindings/clock/sun50i-a64-ccu.h +++ b/include/dt-bindings/clock/sun50i-a64-ccu.h @@ -43,6 +43,7 @@ #ifndef _DT_BINDINGS_CLK_SUN50I_A64_H_ #define _DT_BINDINGS_CLK_SUN50I_A64_H_ +#define CLK_PLL_VIDEO0 7 #define CLK_PLL_PERIPH0 11 #define CLK_BUS_MIPI_DSI 28 From e40c7e3cda07099a92ea68d022f3304c14f9659f Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Wed, 1 Aug 2018 16:00:50 +0200 Subject: [PATCH 14/23] clk: meson: clk-pll: add enable bit Add the enable the bit of the pll clocks. These pll clocks may be disabled but we can't model this as an external gate since the pll needs to lock when enabled. Adding this bit allows to drop the poke of the first register of PLL. This will be useful to model the different components of the pll using generic clocks elements Acked-by: Neil Armstrong Reviewed-by: Martin Blumenstingl Tested-by: Martin Blumenstingl Signed-off-by: Jerome Brunet --- drivers/clk/meson/axg.c | 28 +++++++++++++++++++--- drivers/clk/meson/clk-pll.c | 47 +++++++++++++++++++++++++++++++++---- drivers/clk/meson/clkc.h | 1 + drivers/clk/meson/gxbb.c | 32 +++++++++++++++++++++++-- drivers/clk/meson/meson8b.c | 15 ++++++++++++ 5 files changed, 113 insertions(+), 10 deletions(-) diff --git a/drivers/clk/meson/axg.c b/drivers/clk/meson/axg.c index 00ce62ad6416..6d8976554656 100644 --- a/drivers/clk/meson/axg.c +++ b/drivers/clk/meson/axg.c @@ -24,6 +24,11 @@ static DEFINE_SPINLOCK(meson_clk_lock); static struct clk_regmap axg_fixed_pll = { .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = HHI_MPLL_CNTL, + .shift = 30, + .width = 1, + }, .m = { .reg_off = HHI_MPLL_CNTL, .shift = 0, @@ -65,6 +70,11 @@ static struct clk_regmap axg_fixed_pll = { static struct clk_regmap axg_sys_pll = { .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = HHI_SYS_PLL_CNTL, + .shift = 30, + .width = 1, + }, .m = { .reg_off = HHI_SYS_PLL_CNTL, .shift = 0, @@ -197,11 +207,15 @@ static const struct reg_sequence axg_gp0_init_regs[] = { { .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 = { .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = HHI_GP0_PLL_CNTL, + .shift = 30, + .width = 1, + }, .m = { .reg_off = HHI_GP0_PLL_CNTL, .shift = 0, @@ -250,11 +264,15 @@ static const struct reg_sequence axg_hifi_init_regs[] = { { .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){ + .en = { + .reg_off = HHI_HIFI_PLL_CNTL, + .shift = 30, + .width = 1, + }, .m = { .reg_off = HHI_HIFI_PLL_CNTL, .shift = 0, @@ -637,7 +655,6 @@ static const struct pll_rate_table axg_pcie_pll_rate_table[] = { }; static const struct reg_sequence axg_pcie_init_regs[] = { - { .reg = HHI_PCIE_PLL_CNTL, .def = 0x400106c8 }, { .reg = HHI_PCIE_PLL_CNTL1, .def = 0x0084a2aa }, { .reg = HHI_PCIE_PLL_CNTL2, .def = 0xb75020be }, { .reg = HHI_PCIE_PLL_CNTL3, .def = 0x0a47488e }, @@ -648,6 +665,11 @@ static const struct reg_sequence axg_pcie_init_regs[] = { static struct clk_regmap axg_pcie_pll = { .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = HHI_PCIE_PLL_CNTL, + .shift = 30, + .width = 1, + }, .m = { .reg_off = HHI_PCIE_PLL_CNTL, .shift = 0, diff --git a/drivers/clk/meson/clk-pll.c b/drivers/clk/meson/clk-pll.c index 3e04617ac47f..8aaefe67025f 100644 --- a/drivers/clk/meson/clk-pll.c +++ b/drivers/clk/meson/clk-pll.c @@ -185,12 +185,45 @@ static void meson_clk_pll_init(struct clk_hw *hw) } } +static int meson_clk_pll_enable(struct clk_hw *hw) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_clk_pll_data *pll = meson_clk_pll_data(clk); + + /* Make sure the pll is in reset */ + meson_parm_write(clk->map, &pll->rst, 1); + + /* Enable the pll */ + meson_parm_write(clk->map, &pll->en, 1); + + /* Take the pll out reset */ + meson_parm_write(clk->map, &pll->rst, 0); + + if (meson_clk_pll_wait_lock(hw)) + return -EIO; + + return 0; +} + +static void meson_clk_pll_disable(struct clk_hw *hw) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_clk_pll_data *pll = meson_clk_pll_data(clk); + + /* Put the pll is in reset */ + meson_parm_write(clk->map, &pll->rst, 1); + + /* Disable the pll */ + meson_parm_write(clk->map, &pll->en, 0); +} + static int meson_clk_pll_set_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; + unsigned int enabled; unsigned long old_rate; u16 frac = 0; @@ -203,8 +236,9 @@ static int meson_clk_pll_set_rate(struct clk_hw *hw, unsigned long rate, if (!pllt) return -EINVAL; - /* Put the pll in reset to write the params */ - meson_parm_write(clk->map, &pll->rst, 1); + enabled = meson_parm_read(clk->map, &pll->en); + if (enabled) + meson_clk_pll_disable(hw); meson_parm_write(clk->map, &pll->n, pllt->n); meson_parm_write(clk->map, &pll->m, pllt->m); @@ -221,10 +255,11 @@ static int meson_clk_pll_set_rate(struct clk_hw *hw, unsigned long rate, 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); + /* If the pll is stopped, bail out now */ + if (!enabled) + return 0; - if (meson_clk_pll_wait_lock(hw)) { + if (meson_clk_pll_enable(hw)) { pr_warn("%s: pll did not lock, trying to restore old rate %lu\n", __func__, old_rate); /* @@ -244,6 +279,8 @@ const struct clk_ops meson_clk_pll_ops = { .recalc_rate = meson_clk_pll_recalc_rate, .round_rate = meson_clk_pll_round_rate, .set_rate = meson_clk_pll_set_rate, + .enable = meson_clk_pll_enable, + .disable = meson_clk_pll_disable }; const struct clk_ops meson_clk_pll_ro_ops = { diff --git a/drivers/clk/meson/clkc.h b/drivers/clk/meson/clkc.h index 24cec16b6038..c2ee37a78ceb 100644 --- a/drivers/clk/meson/clkc.h +++ b/drivers/clk/meson/clkc.h @@ -63,6 +63,7 @@ struct pll_rate_table { #define CLK_MESON_PLL_ROUND_CLOSEST BIT(0) struct meson_clk_pll_data { + struct parm en; struct parm m; struct parm n; struct parm frac; diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c index 86d3ae58e84c..5ed34566917c 100644 --- a/drivers/clk/meson/gxbb.c +++ b/drivers/clk/meson/gxbb.c @@ -177,6 +177,11 @@ static const struct pll_rate_table gxl_gp0_pll_rate_table[] = { static struct clk_regmap gxbb_fixed_pll = { .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = HHI_MPLL_CNTL, + .shift = 30, + .width = 1, + }, .m = { .reg_off = HHI_MPLL_CNTL, .shift = 0, @@ -230,6 +235,11 @@ static struct clk_fixed_factor gxbb_hdmi_pll_pre_mult = { static struct clk_regmap gxbb_hdmi_pll = { .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = HHI_HDMI_PLL_CNTL, + .shift = 30, + .width = 1, + }, .m = { .reg_off = HHI_HDMI_PLL_CNTL, .shift = 0, @@ -282,6 +292,11 @@ static struct clk_regmap gxbb_hdmi_pll = { static struct clk_regmap gxl_hdmi_pll = { .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = HHI_HDMI_PLL_CNTL, + .shift = 30, + .width = 1, + }, .m = { .reg_off = HHI_HDMI_PLL_CNTL, .shift = 0, @@ -340,6 +355,11 @@ static struct clk_regmap gxl_hdmi_pll = { static struct clk_regmap gxbb_sys_pll = { .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = HHI_SYS_PLL_CNTL, + .shift = 30, + .width = 1, + }, .m = { .reg_off = HHI_SYS_PLL_CNTL, .shift = 0, @@ -379,11 +399,15 @@ 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 }, - { .reg = HHI_GP0_PLL_CNTL, .def = 0x4a000228 }, }; static struct clk_regmap gxbb_gp0_pll = { .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = HHI_GP0_PLL_CNTL, + .shift = 30, + .width = 1, + }, .m = { .reg_off = HHI_GP0_PLL_CNTL, .shift = 0, @@ -428,11 +452,15 @@ static const struct reg_sequence gxl_gp0_init_regs[] = { { .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 = { .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = HHI_GP0_PLL_CNTL, + .shift = 30, + .width = 1, + }, .m = { .reg_off = HHI_GP0_PLL_CNTL, .shift = 0, diff --git a/drivers/clk/meson/meson8b.c b/drivers/clk/meson/meson8b.c index 7447d96a265f..fd4c414893f5 100644 --- a/drivers/clk/meson/meson8b.c +++ b/drivers/clk/meson/meson8b.c @@ -96,6 +96,11 @@ static struct clk_fixed_rate meson8b_xtal = { static struct clk_regmap meson8b_fixed_pll = { .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = HHI_MPLL_CNTL, + .shift = 30, + .width = 1, + }, .m = { .reg_off = HHI_MPLL_CNTL, .shift = 0, @@ -138,6 +143,11 @@ static struct clk_regmap meson8b_fixed_pll = { static struct clk_regmap meson8b_vid_pll = { .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = HHI_VID_PLL_CNTL, + .shift = 30, + .width = 1, + }, .m = { .reg_off = HHI_VID_PLL_CNTL, .shift = 0, @@ -175,6 +185,11 @@ static struct clk_regmap meson8b_vid_pll = { static struct clk_regmap meson8b_sys_pll = { .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = HHI_SYS_PLL_CNTL, + .shift = 30, + .width = 1, + }, .m = { .reg_off = HHI_SYS_PLL_CNTL, .shift = 0, From 2303a9ca693e585a558497ad737728fec97e2b8a Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Wed, 1 Aug 2018 16:00:51 +0200 Subject: [PATCH 15/23] clk: meson: clk-pll: drop CLK_GET_RATE_NOCACHE where unnecessary CLK_GET_RATE_NOCACHE should only be necessary when the registers controlling the rate of clock may change outside of CCF. On Amlogic, it should only be the case for the hdmi pll which is directly controlled by the display driver (WIP to fix this). The other plls should not require this flag. Reviewed-by: Martin Blumenstingl Tested-by: Martin Blumenstingl Signed-off-by: Jerome Brunet --- drivers/clk/meson/axg.c | 1 - drivers/clk/meson/gxbb.c | 12 ++++++++---- drivers/clk/meson/meson8b.c | 3 --- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/clk/meson/axg.c b/drivers/clk/meson/axg.c index 6d8976554656..991fa511c05a 100644 --- a/drivers/clk/meson/axg.c +++ b/drivers/clk/meson/axg.c @@ -106,7 +106,6 @@ static struct clk_regmap axg_sys_pll = { .ops = &meson_clk_pll_ro_ops, .parent_names = (const char *[]){ "xtal" }, .num_parents = 1, - .flags = CLK_GET_RATE_NOCACHE, }, }; diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c index 5ed34566917c..01e3f80e88cc 100644 --- a/drivers/clk/meson/gxbb.c +++ b/drivers/clk/meson/gxbb.c @@ -218,7 +218,6 @@ static struct clk_regmap gxbb_fixed_pll = { .ops = &meson_clk_pll_ro_ops, .parent_names = (const char *[]){ "xtal" }, .num_parents = 1, - .flags = CLK_GET_RATE_NOCACHE, }, }; @@ -286,6 +285,10 @@ static struct clk_regmap gxbb_hdmi_pll = { .ops = &meson_clk_pll_ro_ops, .parent_names = (const char *[]){ "hdmi_pll_pre_mult" }, .num_parents = 1, + /* + * Display directly handle hdmi pll registers ATM, we need + * NOCACHE to keep our view of the clock as accurate as possible + */ .flags = CLK_GET_RATE_NOCACHE, }, }; @@ -349,6 +352,10 @@ static struct clk_regmap gxl_hdmi_pll = { .ops = &meson_clk_pll_ro_ops, .parent_names = (const char *[]){ "xtal" }, .num_parents = 1, + /* + * Display directly handle hdmi pll registers ATM, we need + * NOCACHE to keep our view of the clock as accurate as possible + */ .flags = CLK_GET_RATE_NOCACHE, }, }; @@ -391,7 +398,6 @@ static struct clk_regmap gxbb_sys_pll = { .ops = &meson_clk_pll_ro_ops, .parent_names = (const char *[]){ "xtal" }, .num_parents = 1, - .flags = CLK_GET_RATE_NOCACHE, }, }; @@ -442,7 +448,6 @@ static struct clk_regmap gxbb_gp0_pll = { .ops = &meson_clk_pll_ops, .parent_names = (const char *[]){ "xtal" }, .num_parents = 1, - .flags = CLK_GET_RATE_NOCACHE, }, }; @@ -500,7 +505,6 @@ static struct clk_regmap gxl_gp0_pll = { .ops = &meson_clk_pll_ops, .parent_names = (const char *[]){ "xtal" }, .num_parents = 1, - .flags = CLK_GET_RATE_NOCACHE, }, }; diff --git a/drivers/clk/meson/meson8b.c b/drivers/clk/meson/meson8b.c index fd4c414893f5..ec1f97725b9f 100644 --- a/drivers/clk/meson/meson8b.c +++ b/drivers/clk/meson/meson8b.c @@ -137,7 +137,6 @@ static struct clk_regmap meson8b_fixed_pll = { .ops = &meson_clk_pll_ro_ops, .parent_names = (const char *[]){ "xtal" }, .num_parents = 1, - .flags = CLK_GET_RATE_NOCACHE, }, }; @@ -179,7 +178,6 @@ static struct clk_regmap meson8b_vid_pll = { .ops = &meson_clk_pll_ro_ops, .parent_names = (const char *[]){ "xtal" }, .num_parents = 1, - .flags = CLK_GET_RATE_NOCACHE, }, }; @@ -222,7 +220,6 @@ static struct clk_regmap meson8b_sys_pll = { .ops = &meson_clk_pll_ro_ops, .parent_names = (const char *[]){ "xtal" }, .num_parents = 1, - .flags = CLK_GET_RATE_NOCACHE, }, }; From 87173557d2f6d28ba6e19f8aaf6b7f3d45d51511 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Wed, 1 Aug 2018 16:00:52 +0200 Subject: [PATCH 16/23] clk: meson: clk-pll: remove od parameters Remove od parameters from pll clocks and add post dividers clocks instead. Some clock, especially the one which feature several ods, may provide output between those ods. Also, some drivers, such as the hdmi driver, may require a more detailed control of the clock dividers, compared to what CCF would perform automatically. One added benefit of removing ods is that it also greatly reduce the size of the rate parameter tables. In the future, we could possibly take the predivider 'n' out of this driver as well. To do so, we will need to understand the constraints for the PLL to lock and whether or not it depends on the input clock rate. Acked-by: Neil Armstrong Reviewed-by: Martin Blumenstingl Tested-by: Martin Blumenstingl Signed-off-by: Jerome Brunet --- drivers/clk/meson/axg.c | 284 +++++++++++---------- drivers/clk/meson/axg.h | 8 +- drivers/clk/meson/clk-pll.c | 40 +-- drivers/clk/meson/clkc.h | 9 +- drivers/clk/meson/gxbb.c | 492 +++++++++++++++++------------------- drivers/clk/meson/gxbb.h | 8 +- drivers/clk/meson/meson8b.c | 151 +++++------ drivers/clk/meson/meson8b.h | 5 +- 8 files changed, 496 insertions(+), 501 deletions(-) diff --git a/drivers/clk/meson/axg.c b/drivers/clk/meson/axg.c index 991fa511c05a..a5e4f7b22f39 100644 --- a/drivers/clk/meson/axg.c +++ b/drivers/clk/meson/axg.c @@ -22,7 +22,7 @@ static DEFINE_SPINLOCK(meson_clk_lock); -static struct clk_regmap axg_fixed_pll = { +static struct clk_regmap axg_fixed_pll_dco = { .data = &(struct meson_clk_pll_data){ .en = { .reg_off = HHI_MPLL_CNTL, @@ -39,11 +39,6 @@ static struct clk_regmap axg_fixed_pll = { .shift = 9, .width = 5, }, - .od = { - .reg_off = HHI_MPLL_CNTL, - .shift = 16, - .width = 2, - }, .frac = { .reg_off = HHI_MPLL_CNTL2, .shift = 0, @@ -61,14 +56,33 @@ static struct clk_regmap axg_fixed_pll = { }, }, .hw.init = &(struct clk_init_data){ - .name = "fixed_pll", + .name = "fixed_pll_dco", .ops = &meson_clk_pll_ro_ops, .parent_names = (const char *[]){ "xtal" }, .num_parents = 1, }, }; -static struct clk_regmap axg_sys_pll = { +static struct clk_regmap axg_fixed_pll = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_MPLL_CNTL, + .shift = 16, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "fixed_pll", + .ops = &clk_regmap_divider_ro_ops, + .parent_names = (const char *[]){ "fixed_pll_dco" }, + .num_parents = 1, + /* + * This clock won't ever change at runtime so + * CLK_SET_RATE_PARENT is not required + */ + }, +}; + +static struct clk_regmap axg_sys_pll_dco = { .data = &(struct meson_clk_pll_data){ .en = { .reg_off = HHI_SYS_PLL_CNTL, @@ -85,11 +99,6 @@ static struct clk_regmap axg_sys_pll = { .shift = 9, .width = 5, }, - .od = { - .reg_off = HHI_SYS_PLL_CNTL, - .shift = 16, - .width = 2, - }, .l = { .reg_off = HHI_SYS_PLL_CNTL, .shift = 31, @@ -102,101 +111,59 @@ static struct clk_regmap axg_sys_pll = { }, }, .hw.init = &(struct clk_init_data){ - .name = "sys_pll", + .name = "sys_pll_dco", .ops = &meson_clk_pll_ro_ops, .parent_names = (const char *[]){ "xtal" }, .num_parents = 1, }, }; +static struct clk_regmap axg_sys_pll = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_SYS_PLL_CNTL, + .shift = 16, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "sys_pll", + .ops = &clk_regmap_divider_ro_ops, + .parent_names = (const char *[]){ "sys_pll_dco" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + static const struct pll_rate_table axg_gp0_pll_rate_table[] = { - PLL_RATE(240000000, 40, 1, 2), - PLL_RATE(246000000, 41, 1, 2), - PLL_RATE(252000000, 42, 1, 2), - PLL_RATE(258000000, 43, 1, 2), - PLL_RATE(264000000, 44, 1, 2), - PLL_RATE(270000000, 45, 1, 2), - PLL_RATE(276000000, 46, 1, 2), - PLL_RATE(282000000, 47, 1, 2), - PLL_RATE(288000000, 48, 1, 2), - PLL_RATE(294000000, 49, 1, 2), - PLL_RATE(300000000, 50, 1, 2), - PLL_RATE(306000000, 51, 1, 2), - PLL_RATE(312000000, 52, 1, 2), - PLL_RATE(318000000, 53, 1, 2), - PLL_RATE(324000000, 54, 1, 2), - PLL_RATE(330000000, 55, 1, 2), - PLL_RATE(336000000, 56, 1, 2), - PLL_RATE(342000000, 57, 1, 2), - PLL_RATE(348000000, 58, 1, 2), - PLL_RATE(354000000, 59, 1, 2), - PLL_RATE(360000000, 60, 1, 2), - PLL_RATE(366000000, 61, 1, 2), - PLL_RATE(372000000, 62, 1, 2), - PLL_RATE(378000000, 63, 1, 2), - PLL_RATE(384000000, 64, 1, 2), - PLL_RATE(390000000, 65, 1, 3), - PLL_RATE(396000000, 66, 1, 3), - PLL_RATE(402000000, 67, 1, 3), - PLL_RATE(408000000, 68, 1, 3), - PLL_RATE(480000000, 40, 1, 1), - PLL_RATE(492000000, 41, 1, 1), - PLL_RATE(504000000, 42, 1, 1), - PLL_RATE(516000000, 43, 1, 1), - PLL_RATE(528000000, 44, 1, 1), - PLL_RATE(540000000, 45, 1, 1), - PLL_RATE(552000000, 46, 1, 1), - PLL_RATE(564000000, 47, 1, 1), - PLL_RATE(576000000, 48, 1, 1), - PLL_RATE(588000000, 49, 1, 1), - PLL_RATE(600000000, 50, 1, 1), - PLL_RATE(612000000, 51, 1, 1), - PLL_RATE(624000000, 52, 1, 1), - PLL_RATE(636000000, 53, 1, 1), - PLL_RATE(648000000, 54, 1, 1), - PLL_RATE(660000000, 55, 1, 1), - PLL_RATE(672000000, 56, 1, 1), - PLL_RATE(684000000, 57, 1, 1), - PLL_RATE(696000000, 58, 1, 1), - PLL_RATE(708000000, 59, 1, 1), - PLL_RATE(720000000, 60, 1, 1), - PLL_RATE(732000000, 61, 1, 1), - PLL_RATE(744000000, 62, 1, 1), - PLL_RATE(756000000, 63, 1, 1), - PLL_RATE(768000000, 64, 1, 1), - PLL_RATE(780000000, 65, 1, 1), - PLL_RATE(792000000, 66, 1, 1), - PLL_RATE(804000000, 67, 1, 1), - PLL_RATE(816000000, 68, 1, 1), - PLL_RATE(960000000, 40, 1, 0), - PLL_RATE(984000000, 41, 1, 0), - PLL_RATE(1008000000, 42, 1, 0), - PLL_RATE(1032000000, 43, 1, 0), - PLL_RATE(1056000000, 44, 1, 0), - PLL_RATE(1080000000, 45, 1, 0), - PLL_RATE(1104000000, 46, 1, 0), - PLL_RATE(1128000000, 47, 1, 0), - PLL_RATE(1152000000, 48, 1, 0), - PLL_RATE(1176000000, 49, 1, 0), - 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(960000000, 40, 1), + PLL_RATE(984000000, 41, 1), + PLL_RATE(1008000000, 42, 1), + PLL_RATE(1032000000, 43, 1), + PLL_RATE(1056000000, 44, 1), + PLL_RATE(1080000000, 45, 1), + PLL_RATE(1104000000, 46, 1), + PLL_RATE(1128000000, 47, 1), + PLL_RATE(1152000000, 48, 1), + PLL_RATE(1176000000, 49, 1), + PLL_RATE(1200000000, 50, 1), + PLL_RATE(1224000000, 51, 1), + PLL_RATE(1248000000, 52, 1), + PLL_RATE(1272000000, 53, 1), + PLL_RATE(1296000000, 54, 1), + PLL_RATE(1320000000, 55, 1), + PLL_RATE(1344000000, 56, 1), + PLL_RATE(1368000000, 57, 1), + PLL_RATE(1392000000, 58, 1), + PLL_RATE(1416000000, 59, 1), + PLL_RATE(1440000000, 60, 1), + PLL_RATE(1464000000, 61, 1), + PLL_RATE(1488000000, 62, 1), + PLL_RATE(1512000000, 63, 1), + PLL_RATE(1536000000, 64, 1), + PLL_RATE(1560000000, 65, 1), + PLL_RATE(1584000000, 66, 1), + PLL_RATE(1608000000, 67, 1), + PLL_RATE(1632000000, 68, 1), { /* sentinel */ }, }; @@ -208,7 +175,7 @@ static const struct reg_sequence axg_gp0_init_regs[] = { { .reg = HHI_GP0_PLL_CNTL5, .def = 0x00078000 }, }; -static struct clk_regmap axg_gp0_pll = { +static struct clk_regmap axg_gp0_pll_dco = { .data = &(struct meson_clk_pll_data){ .en = { .reg_off = HHI_GP0_PLL_CNTL, @@ -225,11 +192,6 @@ static struct clk_regmap axg_gp0_pll = { .shift = 9, .width = 5, }, - .od = { - .reg_off = HHI_GP0_PLL_CNTL, - .shift = 16, - .width = 2, - }, .frac = { .reg_off = HHI_GP0_PLL_CNTL1, .shift = 0, @@ -250,13 +212,29 @@ static struct clk_regmap axg_gp0_pll = { .init_count = ARRAY_SIZE(axg_gp0_init_regs), }, .hw.init = &(struct clk_init_data){ - .name = "gp0_pll", + .name = "gp0_pll_dco", .ops = &meson_clk_pll_ops, .parent_names = (const char *[]){ "xtal" }, .num_parents = 1, }, }; +static struct clk_regmap axg_gp0_pll = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_GP0_PLL_CNTL, + .shift = 16, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "gp0_pll", + .ops = &clk_regmap_divider_ops, + .parent_names = (const char *[]){ "gp0_pll_dco" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + static const struct reg_sequence axg_hifi_init_regs[] = { { .reg = HHI_HIFI_PLL_CNTL1, .def = 0xc084b000 }, { .reg = HHI_HIFI_PLL_CNTL2, .def = 0xb75020be }, @@ -265,7 +243,7 @@ static const struct reg_sequence axg_hifi_init_regs[] = { { .reg = HHI_HIFI_PLL_CNTL5, .def = 0x00058000 }, }; -static struct clk_regmap axg_hifi_pll = { +static struct clk_regmap axg_hifi_pll_dco = { .data = &(struct meson_clk_pll_data){ .en = { .reg_off = HHI_HIFI_PLL_CNTL, @@ -282,11 +260,6 @@ static struct clk_regmap axg_hifi_pll = { .shift = 9, .width = 5, }, - .od = { - .reg_off = HHI_HIFI_PLL_CNTL, - .shift = 16, - .width = 2, - }, .frac = { .reg_off = HHI_HIFI_PLL_CNTL5, .shift = 0, @@ -308,13 +281,29 @@ static struct clk_regmap axg_hifi_pll = { .flags = CLK_MESON_PLL_ROUND_CLOSEST, }, .hw.init = &(struct clk_init_data){ - .name = "hifi_pll", + .name = "hifi_pll_dco", .ops = &meson_clk_pll_ops, .parent_names = (const char *[]){ "xtal" }, .num_parents = 1, }, }; +static struct clk_regmap axg_hifi_pll = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_HIFI_PLL_CNTL, + .shift = 16, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "hifi_pll", + .ops = &clk_regmap_divider_ops, + .parent_names = (const char *[]){ "hifi_pll_dco" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + static struct clk_fixed_factor axg_fclk_div2_div = { .mult = 1, .div = 2, @@ -644,11 +633,9 @@ static struct clk_regmap axg_mpll3 = { static const struct pll_rate_table axg_pcie_pll_rate_table[] = { { - .rate = 100000000, + .rate = 1600000000, .m = 200, .n = 3, - .od = 1, - .od2 = 3, }, { /* sentinel */ }, }; @@ -660,9 +647,10 @@ static const struct reg_sequence axg_pcie_init_regs[] = { { .reg = HHI_PCIE_PLL_CNTL4, .def = 0xc000004d }, { .reg = HHI_PCIE_PLL_CNTL5, .def = 0x00078000 }, { .reg = HHI_PCIE_PLL_CNTL6, .def = 0x002323c6 }, + { .reg = HHI_PCIE_PLL_CNTL, .def = 0x400106c8 }, }; -static struct clk_regmap axg_pcie_pll = { +static struct clk_regmap axg_pcie_pll_dco = { .data = &(struct meson_clk_pll_data){ .en = { .reg_off = HHI_PCIE_PLL_CNTL, @@ -679,16 +667,6 @@ static struct clk_regmap axg_pcie_pll = { .shift = 9, .width = 5, }, - .od = { - .reg_off = HHI_PCIE_PLL_CNTL, - .shift = 16, - .width = 2, - }, - .od2 = { - .reg_off = HHI_PCIE_PLL_CNTL6, - .shift = 6, - .width = 2, - }, .frac = { .reg_off = HHI_PCIE_PLL_CNTL1, .shift = 0, @@ -709,13 +687,45 @@ static struct clk_regmap axg_pcie_pll = { .init_count = ARRAY_SIZE(axg_pcie_init_regs), }, .hw.init = &(struct clk_init_data){ - .name = "pcie_pll", + .name = "pcie_pll_dco", .ops = &meson_clk_pll_ops, .parent_names = (const char *[]){ "xtal" }, .num_parents = 1, }, }; +static struct clk_regmap axg_pcie_pll_od = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_PCIE_PLL_CNTL, + .shift = 16, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "pcie_pll_od", + .ops = &clk_regmap_divider_ops, + .parent_names = (const char *[]){ "pcie_pll_dco" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap axg_pcie_pll = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_PCIE_PLL_CNTL6, + .shift = 6, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "pcie_pll", + .ops = &clk_regmap_divider_ops, + .parent_names = (const char *[]){ "pcie_pll_od" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + static struct clk_regmap axg_pcie_mux = { .data = &(struct clk_regmap_mux_data){ .offset = HHI_PCIE_PLL_CNTL6, @@ -1128,6 +1138,12 @@ static struct clk_hw_onecell_data axg_hw_onecell_data = { [CLKID_GEN_CLK_SEL] = &axg_gen_clk_sel.hw, [CLKID_GEN_CLK_DIV] = &axg_gen_clk_div.hw, [CLKID_GEN_CLK] = &axg_gen_clk.hw, + [CLKID_SYS_PLL_DCO] = &axg_sys_pll_dco.hw, + [CLKID_FIXED_PLL_DCO] = &axg_fixed_pll_dco.hw, + [CLKID_GP0_PLL_DCO] = &axg_gp0_pll_dco.hw, + [CLKID_HIFI_PLL_DCO] = &axg_hifi_pll_dco.hw, + [CLKID_PCIE_PLL_DCO] = &axg_pcie_pll_dco.hw, + [CLKID_PCIE_PLL_OD] = &axg_pcie_pll_od.hw, [NR_CLKS] = NULL, }, .num = NR_CLKS, @@ -1206,6 +1222,8 @@ static struct clk_regmap *const axg_clk_regmaps[] = { &axg_fclk_div4, &axg_fclk_div5, &axg_fclk_div7, + &axg_pcie_pll_dco, + &axg_pcie_pll_od, &axg_pcie_pll, &axg_pcie_mux, &axg_pcie_ref, @@ -1215,6 +1233,12 @@ static struct clk_regmap *const axg_clk_regmaps[] = { &axg_gen_clk_sel, &axg_gen_clk_div, &axg_gen_clk, + &axg_fixed_pll_dco, + &axg_sys_pll_dco, + &axg_gp0_pll_dco, + &axg_hifi_pll_dco, + &axg_pcie_pll_dco, + &axg_pcie_pll_od, }; static const struct of_device_id clkc_match_table[] = { diff --git a/drivers/clk/meson/axg.h b/drivers/clk/meson/axg.h index 1d04144a1b2c..0431dabac629 100644 --- a/drivers/clk/meson/axg.h +++ b/drivers/clk/meson/axg.h @@ -133,8 +133,14 @@ #define CLKID_PCIE_REF 78 #define CLKID_GEN_CLK_SEL 82 #define CLKID_GEN_CLK_DIV 83 +#define CLKID_SYS_PLL_DCO 85 +#define CLKID_FIXED_PLL_DCO 86 +#define CLKID_GP0_PLL_DCO 87 +#define CLKID_HIFI_PLL_DCO 88 +#define CLKID_PCIE_PLL_DCO 89 +#define CLKID_PCIE_PLL_OD 90 -#define NR_CLKS 85 +#define NR_CLKS 91 /* include the CLKIDs that have been made part of the DT binding */ #include diff --git a/drivers/clk/meson/clk-pll.c b/drivers/clk/meson/clk-pll.c index 8aaefe67025f..348a866f09eb 100644 --- a/drivers/clk/meson/clk-pll.c +++ b/drivers/clk/meson/clk-pll.c @@ -11,15 +11,19 @@ * In the most basic form, a Meson PLL is composed as follows: * * PLL - * +------------------------------+ - * | | - * in -----[ /N ]---[ *M ]---[ >>OD ]----->> out - * | ^ ^ | - * +------------------------------+ - * | | - * FREF VCO + * +--------------------------------+ + * | | + * | +--+ | + * in >>-----[ /N ]--->| | +-----+ | + * | | |------| DCO |---->> out + * | +--------->| | +--v--+ | + * | | +--+ | | + * | | | | + * | +--[ *(M + (F/Fmax) ]<--+ | + * | | + * +--------------------------------+ * - * out = in * (m + frac / frac_max) / (n << sum(ods)) + * out = in * (m + frac / frac_max) / n */ #include @@ -46,7 +50,6 @@ static unsigned long __pll_params_to_rate(unsigned long parent_rate, 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; @@ -55,7 +58,7 @@ static unsigned long __pll_params_to_rate(unsigned long parent_rate, (1 << pll->frac.width)); } - return DIV_ROUND_UP_ULL(rate, pllt->n << od); + return DIV_ROUND_UP_ULL(rate, pllt->n); } static unsigned long meson_clk_pll_recalc_rate(struct clk_hw *hw, @@ -68,15 +71,6 @@ static unsigned long meson_clk_pll_recalc_rate(struct clk_hw *hw, 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); - - pllt.od2 = MESON_PARM_APPLICABLE(&pll->od2) ? - meson_parm_read(clk->map, &pll->od2) : - 0; - - pllt.od3 = MESON_PARM_APPLICABLE(&pll->od3) ? - meson_parm_read(clk->map, &pll->od3) : - 0; frac = MESON_PARM_APPLICABLE(&pll->frac) ? meson_parm_read(clk->map, &pll->frac) : @@ -93,8 +87,6 @@ static u16 __pll_params_with_frac(unsigned long rate, u16 frac_max = (1 << pll->frac.width); u64 val = (u64)rate * pllt->n; - val <<= pllt->od + pllt->od2 + pllt->od3; - if (pll->flags & CLK_MESON_PLL_ROUND_CLOSEST) val = DIV_ROUND_CLOSEST_ULL(val * frac_max, parent_rate); else @@ -242,13 +234,7 @@ static int meson_clk_pll_set_rate(struct clk_hw *hw, unsigned long rate, 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); - if (MESON_PARM_APPLICABLE(&pll->od2)) - meson_parm_write(clk->map, &pll->od2, pllt->od2); - - if (MESON_PARM_APPLICABLE(&pll->od3)) - meson_parm_write(clk->map, &pll->od3, pllt->od3); if (MESON_PARM_APPLICABLE(&pll->frac)) { frac = __pll_params_with_frac(rate, parent_rate, pllt, pll); diff --git a/drivers/clk/meson/clkc.h b/drivers/clk/meson/clkc.h index c2ee37a78ceb..a2245e857f70 100644 --- a/drivers/clk/meson/clkc.h +++ b/drivers/clk/meson/clkc.h @@ -47,17 +47,13 @@ struct pll_rate_table { unsigned long rate; u16 m; u16 n; - u16 od; - u16 od2; - u16 od3; }; -#define PLL_RATE(_r, _m, _n, _od) \ +#define PLL_RATE(_r, _m, _n) \ { \ .rate = (_r), \ .m = (_m), \ .n = (_n), \ - .od = (_od), \ } #define CLK_MESON_PLL_ROUND_CLOSEST BIT(0) @@ -67,9 +63,6 @@ struct meson_clk_pll_data { struct parm m; struct parm n; struct parm frac; - struct parm od; - struct parm od2; - struct parm od3; struct parm l; struct parm rst; const struct reg_sequence *init_regs; diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c index 01e3f80e88cc..af59f2607dc1 100644 --- a/drivers/clk/meson/gxbb.c +++ b/drivers/clk/meson/gxbb.c @@ -19,163 +19,70 @@ static DEFINE_SPINLOCK(meson_clk_lock); static const struct pll_rate_table gxbb_gp0_pll_rate_table[] = { - PLL_RATE(96000000, 32, 1, 3), - PLL_RATE(99000000, 33, 1, 3), - PLL_RATE(102000000, 34, 1, 3), - PLL_RATE(105000000, 35, 1, 3), - PLL_RATE(108000000, 36, 1, 3), - PLL_RATE(111000000, 37, 1, 3), - PLL_RATE(114000000, 38, 1, 3), - PLL_RATE(117000000, 39, 1, 3), - PLL_RATE(120000000, 40, 1, 3), - PLL_RATE(123000000, 41, 1, 3), - PLL_RATE(126000000, 42, 1, 3), - PLL_RATE(129000000, 43, 1, 3), - PLL_RATE(132000000, 44, 1, 3), - PLL_RATE(135000000, 45, 1, 3), - PLL_RATE(138000000, 46, 1, 3), - PLL_RATE(141000000, 47, 1, 3), - PLL_RATE(144000000, 48, 1, 3), - PLL_RATE(147000000, 49, 1, 3), - PLL_RATE(150000000, 50, 1, 3), - PLL_RATE(153000000, 51, 1, 3), - PLL_RATE(156000000, 52, 1, 3), - PLL_RATE(159000000, 53, 1, 3), - PLL_RATE(162000000, 54, 1, 3), - PLL_RATE(165000000, 55, 1, 3), - PLL_RATE(168000000, 56, 1, 3), - PLL_RATE(171000000, 57, 1, 3), - PLL_RATE(174000000, 58, 1, 3), - PLL_RATE(177000000, 59, 1, 3), - PLL_RATE(180000000, 60, 1, 3), - PLL_RATE(183000000, 61, 1, 3), - PLL_RATE(186000000, 62, 1, 3), - PLL_RATE(192000000, 32, 1, 2), - PLL_RATE(198000000, 33, 1, 2), - PLL_RATE(204000000, 34, 1, 2), - PLL_RATE(210000000, 35, 1, 2), - PLL_RATE(216000000, 36, 1, 2), - PLL_RATE(222000000, 37, 1, 2), - PLL_RATE(228000000, 38, 1, 2), - PLL_RATE(234000000, 39, 1, 2), - PLL_RATE(240000000, 40, 1, 2), - PLL_RATE(246000000, 41, 1, 2), - PLL_RATE(252000000, 42, 1, 2), - PLL_RATE(258000000, 43, 1, 2), - PLL_RATE(264000000, 44, 1, 2), - PLL_RATE(270000000, 45, 1, 2), - PLL_RATE(276000000, 46, 1, 2), - PLL_RATE(282000000, 47, 1, 2), - PLL_RATE(288000000, 48, 1, 2), - PLL_RATE(294000000, 49, 1, 2), - PLL_RATE(300000000, 50, 1, 2), - PLL_RATE(306000000, 51, 1, 2), - PLL_RATE(312000000, 52, 1, 2), - PLL_RATE(318000000, 53, 1, 2), - PLL_RATE(324000000, 54, 1, 2), - PLL_RATE(330000000, 55, 1, 2), - PLL_RATE(336000000, 56, 1, 2), - PLL_RATE(342000000, 57, 1, 2), - PLL_RATE(348000000, 58, 1, 2), - PLL_RATE(354000000, 59, 1, 2), - PLL_RATE(360000000, 60, 1, 2), - PLL_RATE(366000000, 61, 1, 2), - PLL_RATE(372000000, 62, 1, 2), - PLL_RATE(384000000, 32, 1, 1), - PLL_RATE(396000000, 33, 1, 1), - PLL_RATE(408000000, 34, 1, 1), - PLL_RATE(420000000, 35, 1, 1), - PLL_RATE(432000000, 36, 1, 1), - PLL_RATE(444000000, 37, 1, 1), - PLL_RATE(456000000, 38, 1, 1), - PLL_RATE(468000000, 39, 1, 1), - PLL_RATE(480000000, 40, 1, 1), - PLL_RATE(492000000, 41, 1, 1), - PLL_RATE(504000000, 42, 1, 1), - PLL_RATE(516000000, 43, 1, 1), - PLL_RATE(528000000, 44, 1, 1), - PLL_RATE(540000000, 45, 1, 1), - PLL_RATE(552000000, 46, 1, 1), - PLL_RATE(564000000, 47, 1, 1), - PLL_RATE(576000000, 48, 1, 1), - PLL_RATE(588000000, 49, 1, 1), - PLL_RATE(600000000, 50, 1, 1), - PLL_RATE(612000000, 51, 1, 1), - PLL_RATE(624000000, 52, 1, 1), - PLL_RATE(636000000, 53, 1, 1), - PLL_RATE(648000000, 54, 1, 1), - PLL_RATE(660000000, 55, 1, 1), - PLL_RATE(672000000, 56, 1, 1), - PLL_RATE(684000000, 57, 1, 1), - PLL_RATE(696000000, 58, 1, 1), - PLL_RATE(708000000, 59, 1, 1), - PLL_RATE(720000000, 60, 1, 1), - PLL_RATE(732000000, 61, 1, 1), - PLL_RATE(744000000, 62, 1, 1), - PLL_RATE(768000000, 32, 1, 0), - PLL_RATE(792000000, 33, 1, 0), - PLL_RATE(816000000, 34, 1, 0), - PLL_RATE(840000000, 35, 1, 0), - PLL_RATE(864000000, 36, 1, 0), - PLL_RATE(888000000, 37, 1, 0), - PLL_RATE(912000000, 38, 1, 0), - PLL_RATE(936000000, 39, 1, 0), - PLL_RATE(960000000, 40, 1, 0), - PLL_RATE(984000000, 41, 1, 0), - PLL_RATE(1008000000, 42, 1, 0), - PLL_RATE(1032000000, 43, 1, 0), - PLL_RATE(1056000000, 44, 1, 0), - PLL_RATE(1080000000, 45, 1, 0), - PLL_RATE(1104000000, 46, 1, 0), - PLL_RATE(1128000000, 47, 1, 0), - PLL_RATE(1152000000, 48, 1, 0), - PLL_RATE(1176000000, 49, 1, 0), - 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(768000000, 32, 1), + PLL_RATE(792000000, 33, 1), + PLL_RATE(816000000, 34, 1), + PLL_RATE(840000000, 35, 1), + PLL_RATE(864000000, 36, 1), + PLL_RATE(888000000, 37, 1), + PLL_RATE(912000000, 38, 1), + PLL_RATE(936000000, 39, 1), + PLL_RATE(960000000, 40, 1), + PLL_RATE(984000000, 41, 1), + PLL_RATE(1008000000, 42, 1), + PLL_RATE(1032000000, 43, 1), + PLL_RATE(1056000000, 44, 1), + PLL_RATE(1080000000, 45, 1), + PLL_RATE(1104000000, 46, 1), + PLL_RATE(1128000000, 47, 1), + PLL_RATE(1152000000, 48, 1), + PLL_RATE(1176000000, 49, 1), + PLL_RATE(1200000000, 50, 1), + PLL_RATE(1224000000, 51, 1), + PLL_RATE(1248000000, 52, 1), + PLL_RATE(1272000000, 53, 1), + PLL_RATE(1296000000, 54, 1), + PLL_RATE(1320000000, 55, 1), + PLL_RATE(1344000000, 56, 1), + PLL_RATE(1368000000, 57, 1), + PLL_RATE(1392000000, 58, 1), + PLL_RATE(1416000000, 59, 1), + PLL_RATE(1440000000, 60, 1), + PLL_RATE(1464000000, 61, 1), + PLL_RATE(1488000000, 62, 1), { /* sentinel */ }, }; static const struct pll_rate_table gxl_gp0_pll_rate_table[] = { - PLL_RATE(504000000, 42, 1, 1), - PLL_RATE(516000000, 43, 1, 1), - PLL_RATE(528000000, 44, 1, 1), - PLL_RATE(540000000, 45, 1, 1), - PLL_RATE(552000000, 46, 1, 1), - PLL_RATE(564000000, 47, 1, 1), - PLL_RATE(576000000, 48, 1, 1), - PLL_RATE(588000000, 49, 1, 1), - PLL_RATE(600000000, 50, 1, 1), - PLL_RATE(612000000, 51, 1, 1), - PLL_RATE(624000000, 52, 1, 1), - PLL_RATE(636000000, 53, 1, 1), - PLL_RATE(648000000, 54, 1, 1), - PLL_RATE(660000000, 55, 1, 1), - PLL_RATE(672000000, 56, 1, 1), - PLL_RATE(684000000, 57, 1, 1), - PLL_RATE(696000000, 58, 1, 1), - PLL_RATE(708000000, 59, 1, 1), - PLL_RATE(720000000, 60, 1, 1), - PLL_RATE(732000000, 61, 1, 1), - PLL_RATE(744000000, 62, 1, 1), - PLL_RATE(756000000, 63, 1, 1), - PLL_RATE(768000000, 64, 1, 1), - PLL_RATE(780000000, 65, 1, 1), - PLL_RATE(792000000, 66, 1, 1), + PLL_RATE(1008000000, 42, 1), + PLL_RATE(1032000000, 43, 1), + PLL_RATE(1056000000, 44, 1), + PLL_RATE(1080000000, 45, 1), + PLL_RATE(1104000000, 46, 1), + PLL_RATE(1128000000, 47, 1), + PLL_RATE(1152000000, 48, 1), + PLL_RATE(1176000000, 49, 1), + PLL_RATE(1200000000, 50, 1), + PLL_RATE(1224000000, 51, 1), + PLL_RATE(1248000000, 52, 1), + PLL_RATE(1272000000, 53, 1), + PLL_RATE(1296000000, 54, 1), + PLL_RATE(1320000000, 55, 1), + PLL_RATE(1344000000, 56, 1), + PLL_RATE(1368000000, 57, 1), + PLL_RATE(1392000000, 58, 1), + PLL_RATE(1416000000, 59, 1), + PLL_RATE(1440000000, 60, 1), + PLL_RATE(1464000000, 61, 1), + PLL_RATE(1488000000, 62, 1), + PLL_RATE(1512000000, 63, 1), + PLL_RATE(1536000000, 64, 1), + PLL_RATE(1560000000, 65, 1), + PLL_RATE(1584000000, 66, 1), { /* sentinel */ }, }; -static struct clk_regmap gxbb_fixed_pll = { +static struct clk_regmap gxbb_fixed_pll_dco = { .data = &(struct meson_clk_pll_data){ .en = { .reg_off = HHI_MPLL_CNTL, @@ -192,11 +99,6 @@ static struct clk_regmap gxbb_fixed_pll = { .shift = 9, .width = 5, }, - .od = { - .reg_off = HHI_MPLL_CNTL, - .shift = 16, - .width = 2, - }, .frac = { .reg_off = HHI_MPLL_CNTL2, .shift = 0, @@ -214,13 +116,32 @@ static struct clk_regmap gxbb_fixed_pll = { }, }, .hw.init = &(struct clk_init_data){ - .name = "fixed_pll", + .name = "fixed_pll_dco", .ops = &meson_clk_pll_ro_ops, .parent_names = (const char *[]){ "xtal" }, .num_parents = 1, }, }; +static struct clk_regmap gxbb_fixed_pll = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_MPLL_CNTL, + .shift = 16, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "fixed_pll", + .ops = &clk_regmap_divider_ro_ops, + .parent_names = (const char *[]){ "fixed_pll_dco" }, + .num_parents = 1, + /* + * This clock won't ever change at runtime so + * CLK_SET_RATE_PARENT is not required + */ + }, +}; + static struct clk_fixed_factor gxbb_hdmi_pll_pre_mult = { .mult = 2, .div = 1, @@ -232,7 +153,7 @@ static struct clk_fixed_factor gxbb_hdmi_pll_pre_mult = { }, }; -static struct clk_regmap gxbb_hdmi_pll = { +static struct clk_regmap gxbb_hdmi_pll_dco = { .data = &(struct meson_clk_pll_data){ .en = { .reg_off = HHI_HDMI_PLL_CNTL, @@ -254,21 +175,6 @@ static struct clk_regmap gxbb_hdmi_pll = { .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, @@ -281,7 +187,7 @@ static struct clk_regmap gxbb_hdmi_pll = { }, }, .hw.init = &(struct clk_init_data){ - .name = "hdmi_pll", + .name = "hdmi_pll_dco", .ops = &meson_clk_pll_ro_ops, .parent_names = (const char *[]){ "hdmi_pll_pre_mult" }, .num_parents = 1, @@ -293,111 +199,151 @@ static struct clk_regmap gxbb_hdmi_pll = { }, }; +static struct clk_regmap gxbb_hdmi_pll_od = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_HDMI_PLL_CNTL2, + .shift = 16, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll_od", + .ops = &clk_regmap_divider_ro_ops, + .parent_names = (const char *[]){ "hdmi_pll_dco" }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap gxbb_hdmi_pll_od2 = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_HDMI_PLL_CNTL2, + .shift = 22, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll_od2", + .ops = &clk_regmap_divider_ro_ops, + .parent_names = (const char *[]){ "hdmi_pll_od" }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap gxbb_hdmi_pll = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_HDMI_PLL_CNTL2, + .shift = 18, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll", + .ops = &clk_regmap_divider_ro_ops, + .parent_names = (const char *[]){ "hdmi_pll_od2" }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap gxl_hdmi_pll_od = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_HDMI_PLL_CNTL + 8, + .shift = 21, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll_od", + .ops = &clk_regmap_divider_ro_ops, + .parent_names = (const char *[]){ "hdmi_pll_dco" }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap gxl_hdmi_pll_od2 = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_HDMI_PLL_CNTL + 8, + .shift = 23, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll_od2", + .ops = &clk_regmap_divider_ro_ops, + .parent_names = (const char *[]){ "hdmi_pll_od" }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT, + }, +}; + static struct clk_regmap gxl_hdmi_pll = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_HDMI_PLL_CNTL + 8, + .shift = 19, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll", + .ops = &clk_regmap_divider_ro_ops, + .parent_names = (const char *[]){ "hdmi_pll_od2" }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap gxbb_sys_pll_dco = { .data = &(struct meson_clk_pll_data){ .en = { - .reg_off = HHI_HDMI_PLL_CNTL, + .reg_off = HHI_SYS_PLL_CNTL, .shift = 30, .width = 1, }, .m = { - .reg_off = HHI_HDMI_PLL_CNTL, + .reg_off = HHI_SYS_PLL_CNTL, .shift = 0, .width = 9, }, .n = { - .reg_off = HHI_HDMI_PLL_CNTL, + .reg_off = HHI_SYS_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, + .reg_off = HHI_SYS_PLL_CNTL, .shift = 31, .width = 1, }, .rst = { - .reg_off = HHI_HDMI_PLL_CNTL, + .reg_off = HHI_SYS_PLL_CNTL, .shift = 29, .width = 1, }, }, .hw.init = &(struct clk_init_data){ - .name = "hdmi_pll", + .name = "sys_pll_dco", .ops = &meson_clk_pll_ro_ops, .parent_names = (const char *[]){ "xtal" }, .num_parents = 1, - /* - * Display directly handle hdmi pll registers ATM, we need - * NOCACHE to keep our view of the clock as accurate as possible - */ - .flags = CLK_GET_RATE_NOCACHE, }, }; static struct clk_regmap gxbb_sys_pll = { - .data = &(struct meson_clk_pll_data){ - .en = { - .reg_off = HHI_SYS_PLL_CNTL, - .shift = 30, - .width = 1, - }, - .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, - }, + .data = &(struct clk_regmap_div_data){ + .offset = HHI_SYS_PLL_CNTL, + .shift = 10, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, }, .hw.init = &(struct clk_init_data){ .name = "sys_pll", - .ops = &meson_clk_pll_ro_ops, - .parent_names = (const char *[]){ "xtal" }, + .ops = &clk_regmap_divider_ro_ops, + .parent_names = (const char *[]){ "sys_pll_dco" }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, }, }; @@ -407,7 +353,7 @@ static const struct reg_sequence gxbb_gp0_init_regs[] = { { .reg = HHI_GP0_PLL_CNTL4, .def = 0x0000500d }, }; -static struct clk_regmap gxbb_gp0_pll = { +static struct clk_regmap gxbb_gp0_pll_dco = { .data = &(struct meson_clk_pll_data){ .en = { .reg_off = HHI_GP0_PLL_CNTL, @@ -424,11 +370,6 @@ static struct clk_regmap gxbb_gp0_pll = { .shift = 9, .width = 5, }, - .od = { - .reg_off = HHI_GP0_PLL_CNTL, - .shift = 16, - .width = 2, - }, .l = { .reg_off = HHI_GP0_PLL_CNTL, .shift = 31, @@ -444,7 +385,7 @@ static struct clk_regmap gxbb_gp0_pll = { .init_count = ARRAY_SIZE(gxbb_gp0_init_regs), }, .hw.init = &(struct clk_init_data){ - .name = "gp0_pll", + .name = "gp0_pll_dco", .ops = &meson_clk_pll_ops, .parent_names = (const char *[]){ "xtal" }, .num_parents = 1, @@ -459,7 +400,7 @@ static const struct reg_sequence gxl_gp0_init_regs[] = { { .reg = HHI_GP0_PLL_CNTL5, .def = 0x00078000 }, }; -static struct clk_regmap gxl_gp0_pll = { +static struct clk_regmap gxl_gp0_pll_dco = { .data = &(struct meson_clk_pll_data){ .en = { .reg_off = HHI_GP0_PLL_CNTL, @@ -476,11 +417,6 @@ static struct clk_regmap gxl_gp0_pll = { .shift = 9, .width = 5, }, - .od = { - .reg_off = HHI_GP0_PLL_CNTL, - .shift = 16, - .width = 2, - }, .frac = { .reg_off = HHI_GP0_PLL_CNTL1, .shift = 0, @@ -501,13 +437,29 @@ static struct clk_regmap gxl_gp0_pll = { .init_count = ARRAY_SIZE(gxl_gp0_init_regs), }, .hw.init = &(struct clk_init_data){ - .name = "gp0_pll", + .name = "gp0_pll_dco", .ops = &meson_clk_pll_ops, .parent_names = (const char *[]){ "xtal" }, .num_parents = 1, }, }; +static struct clk_regmap gxbb_gp0_pll = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_GP0_PLL_CNTL, + .shift = 16, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "gp0_pll", + .ops = &clk_regmap_divider_ops, + .parent_names = (const char *[]){ "gp0_pll_dco" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + static struct clk_fixed_factor gxbb_fclk_div2_div = { .mult = 1, .div = 2, @@ -1965,6 +1917,12 @@ static struct clk_hw_onecell_data gxbb_hw_onecell_data = { [CLKID_GEN_CLK_SEL] = &gxbb_gen_clk_sel.hw, [CLKID_GEN_CLK_DIV] = &gxbb_gen_clk_div.hw, [CLKID_GEN_CLK] = &gxbb_gen_clk.hw, + [CLKID_FIXED_PLL_DCO] = &gxbb_fixed_pll_dco.hw, + [CLKID_HDMI_PLL_DCO] = &gxbb_hdmi_pll_dco.hw, + [CLKID_HDMI_PLL_OD] = &gxbb_hdmi_pll_od.hw, + [CLKID_HDMI_PLL_OD2] = &gxbb_hdmi_pll_od2.hw, + [CLKID_SYS_PLL_DCO] = &gxbb_sys_pll_dco.hw, + [CLKID_GP0_PLL_DCO] = &gxbb_gp0_pll_dco.hw, [NR_CLKS] = NULL, }, .num = NR_CLKS, @@ -1980,7 +1938,7 @@ static struct clk_hw_onecell_data gxl_hw_onecell_data = { [CLKID_FCLK_DIV4] = &gxbb_fclk_div4.hw, [CLKID_FCLK_DIV5] = &gxbb_fclk_div5.hw, [CLKID_FCLK_DIV7] = &gxbb_fclk_div7.hw, - [CLKID_GP0_PLL] = &gxl_gp0_pll.hw, + [CLKID_GP0_PLL] = &gxbb_gp0_pll.hw, [CLKID_MPEG_SEL] = &gxbb_mpeg_clk_sel.hw, [CLKID_MPEG_DIV] = &gxbb_mpeg_clk_div.hw, [CLKID_CLK81] = &gxbb_clk81.hw, @@ -2130,19 +2088,29 @@ static struct clk_hw_onecell_data gxl_hw_onecell_data = { [CLKID_GEN_CLK_SEL] = &gxbb_gen_clk_sel.hw, [CLKID_GEN_CLK_DIV] = &gxbb_gen_clk_div.hw, [CLKID_GEN_CLK] = &gxbb_gen_clk.hw, + [CLKID_FIXED_PLL_DCO] = &gxbb_fixed_pll_dco.hw, + [CLKID_HDMI_PLL_DCO] = &gxbb_hdmi_pll_dco.hw, + [CLKID_HDMI_PLL_OD] = &gxl_hdmi_pll_od.hw, + [CLKID_HDMI_PLL_OD2] = &gxl_hdmi_pll_od2.hw, + [CLKID_SYS_PLL_DCO] = &gxbb_sys_pll_dco.hw, + [CLKID_GP0_PLL_DCO] = &gxl_gp0_pll_dco.hw, [NR_CLKS] = NULL, }, .num = NR_CLKS, }; static struct clk_regmap *const gxbb_clk_regmaps[] = { - &gxbb_gp0_pll, + &gxbb_gp0_pll_dco, &gxbb_hdmi_pll, + &gxbb_hdmi_pll_od, + &gxbb_hdmi_pll_od2, }; static struct clk_regmap *const gxl_clk_regmaps[] = { - &gxl_gp0_pll, + &gxl_gp0_pll_dco, &gxl_hdmi_pll, + &gxl_hdmi_pll_od, + &gxl_hdmi_pll_od2, }; static struct clk_regmap *const gx_clk_regmaps[] = { @@ -2297,6 +2265,10 @@ static struct clk_regmap *const gx_clk_regmaps[] = { &gxbb_gen_clk_sel, &gxbb_gen_clk_div, &gxbb_gen_clk, + &gxbb_fixed_pll_dco, + &gxbb_hdmi_pll_dco, + &gxbb_sys_pll_dco, + &gxbb_gp0_pll, }; struct clkc_data { diff --git a/drivers/clk/meson/gxbb.h b/drivers/clk/meson/gxbb.h index 20dfb1daf5b8..72bc077d9663 100644 --- a/drivers/clk/meson/gxbb.h +++ b/drivers/clk/meson/gxbb.h @@ -159,8 +159,14 @@ #define CLKID_VDEC_HEVC_DIV 155 #define CLKID_GEN_CLK_SEL 157 #define CLKID_GEN_CLK_DIV 158 +#define CLKID_FIXED_PLL_DCO 160 +#define CLKID_HDMI_PLL_DCO 161 +#define CLKID_HDMI_PLL_OD 162 +#define CLKID_HDMI_PLL_OD2 163 +#define CLKID_SYS_PLL_DCO 164 +#define CLKID_GP0_PLL_DCO 165 -#define NR_CLKS 160 +#define NR_CLKS 166 /* 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 ec1f97725b9f..4c061c1d3683 100644 --- a/drivers/clk/meson/meson8b.c +++ b/drivers/clk/meson/meson8b.c @@ -30,58 +30,21 @@ struct meson8b_clk_reset { }; static const struct pll_rate_table sys_pll_rate_table[] = { - 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(1200000000, 50, 1), + PLL_RATE(1224000000, 51, 1), + PLL_RATE(1248000000, 52, 1), + PLL_RATE(1272000000, 53, 1), + PLL_RATE(1296000000, 54, 1), + PLL_RATE(1320000000, 55, 1), + PLL_RATE(1344000000, 56, 1), + PLL_RATE(1368000000, 57, 1), + PLL_RATE(1392000000, 58, 1), + PLL_RATE(1416000000, 59, 1), + PLL_RATE(1440000000, 60, 1), + PLL_RATE(1464000000, 61, 1), + PLL_RATE(1488000000, 62, 1), + PLL_RATE(1512000000, 63, 1), + PLL_RATE(1536000000, 64, 1), { /* sentinel */ }, }; @@ -94,7 +57,7 @@ static struct clk_fixed_rate meson8b_xtal = { }, }; -static struct clk_regmap meson8b_fixed_pll = { +static struct clk_regmap meson8b_fixed_pll_dco = { .data = &(struct meson_clk_pll_data){ .en = { .reg_off = HHI_MPLL_CNTL, @@ -111,11 +74,6 @@ static struct clk_regmap meson8b_fixed_pll = { .shift = 9, .width = 5, }, - .od = { - .reg_off = HHI_MPLL_CNTL, - .shift = 16, - .width = 2, - }, .frac = { .reg_off = HHI_MPLL_CNTL2, .shift = 0, @@ -133,14 +91,33 @@ static struct clk_regmap meson8b_fixed_pll = { }, }, .hw.init = &(struct clk_init_data){ - .name = "fixed_pll", + .name = "fixed_pll_dco", .ops = &meson_clk_pll_ro_ops, .parent_names = (const char *[]){ "xtal" }, .num_parents = 1, }, }; -static struct clk_regmap meson8b_vid_pll = { +static struct clk_regmap meson8b_fixed_pll = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_MPLL_CNTL, + .shift = 16, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "fixed_pll", + .ops = &clk_regmap_divider_ro_ops, + .parent_names = (const char *[]){ "fixed_pll_dco" }, + .num_parents = 1, + /* + * This clock won't ever change at runtime so + * CLK_SET_RATE_PARENT is not required + */ + }, +}; + +static struct clk_regmap meson8b_vid_pll_dco = { .data = &(struct meson_clk_pll_data){ .en = { .reg_off = HHI_VID_PLL_CNTL, @@ -157,11 +134,6 @@ static struct clk_regmap meson8b_vid_pll = { .shift = 9, .width = 5, }, - .od = { - .reg_off = HHI_VID_PLL_CNTL, - .shift = 16, - .width = 2, - }, .l = { .reg_off = HHI_VID_PLL_CNTL, .shift = 31, @@ -174,14 +146,30 @@ static struct clk_regmap meson8b_vid_pll = { }, }, .hw.init = &(struct clk_init_data){ - .name = "vid_pll", + .name = "vid_pll_dco", .ops = &meson_clk_pll_ro_ops, .parent_names = (const char *[]){ "xtal" }, .num_parents = 1, }, }; -static struct clk_regmap meson8b_sys_pll = { +static struct clk_regmap meson8b_vid_pll = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_VID_PLL_CNTL, + .shift = 16, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "vid_pll", + .ops = &clk_regmap_divider_ro_ops, + .parent_names = (const char *[]){ "vid_pll_dco" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_sys_pll_dco = { .data = &(struct meson_clk_pll_data){ .en = { .reg_off = HHI_SYS_PLL_CNTL, @@ -198,11 +186,6 @@ static struct clk_regmap meson8b_sys_pll = { .shift = 9, .width = 5, }, - .od = { - .reg_off = HHI_SYS_PLL_CNTL, - .shift = 16, - .width = 2, - }, .l = { .reg_off = HHI_SYS_PLL_CNTL, .shift = 31, @@ -216,13 +199,29 @@ static struct clk_regmap meson8b_sys_pll = { .table = sys_pll_rate_table, }, .hw.init = &(struct clk_init_data){ - .name = "sys_pll", + .name = "sys_pll_dco", .ops = &meson_clk_pll_ro_ops, .parent_names = (const char *[]){ "xtal" }, .num_parents = 1, }, }; +static struct clk_regmap meson8b_sys_pll = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_SYS_PLL_CNTL, + .shift = 16, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "sys_pll", + .ops = &clk_regmap_divider_ro_ops, + .parent_names = (const char *[]){ "sys_pll_dco" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + static struct clk_fixed_factor meson8b_fclk_div2_div = { .mult = 1, .div = 2, @@ -891,6 +890,9 @@ static struct clk_hw_onecell_data meson8b_hw_onecell_data = { [CLKID_NAND_SEL] = &meson8b_nand_clk_sel.hw, [CLKID_NAND_DIV] = &meson8b_nand_clk_div.hw, [CLKID_NAND_CLK] = &meson8b_nand_clk_gate.hw, + [CLKID_PLL_FIXED_DCO] = &meson8b_fixed_pll_dco.hw, + [CLKID_PLL_VID_DCO] = &meson8b_vid_pll_dco.hw, + [CLKID_PLL_SYS_DCO] = &meson8b_sys_pll_dco.hw, [CLK_NR_CLKS] = NULL, }, .num = CLK_NR_CLKS, @@ -999,6 +1001,9 @@ static struct clk_regmap *const meson8b_clk_regmaps[] = { &meson8b_nand_clk_sel, &meson8b_nand_clk_div, &meson8b_nand_clk_gate, + &meson8b_fixed_pll_dco, + &meson8b_vid_pll_dco, + &meson8b_sys_pll_dco, }; static const struct meson8b_clk_reset_line { diff --git a/drivers/clk/meson/meson8b.h b/drivers/clk/meson/meson8b.h index 5d09412b5084..1c6fb180e6a2 100644 --- a/drivers/clk/meson/meson8b.h +++ b/drivers/clk/meson/meson8b.h @@ -75,8 +75,11 @@ #define CLKID_FCLK_DIV7_DIV 109 #define CLKID_NAND_SEL 110 #define CLKID_NAND_DIV 111 +#define CLKID_PLL_FIXED_DCO 113 +#define CLKID_PLL_VID_DCO 114 +#define CLKID_PLL_SYS_DCO 115 -#define CLK_NR_CLKS 113 +#define CLK_NR_CLKS 116 /* * include the CLKID and RESETID that have From dd601dbc011e4eeda9e4c8c19ffe5b2fb33223dc Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Wed, 1 Aug 2018 16:00:53 +0200 Subject: [PATCH 17/23] clk: meson: clk-pll: drop hard-coded rates from pll tables Putting hard-coded rates inside the parameter tables assumes that the parent is known and will never change. That's a big assumption we should not make. We have everything we need to recalculate the output rate using the parent rate and the rest of the parameters. Let's do so and drop the rates from the tables. Acked-by: Neil Armstrong Reviewed-by: Martin Blumenstingl Tested-by: Martin Blumenstingl Signed-off-by: Jerome Brunet --- drivers/clk/meson/axg.c | 73 +++++++++++----------- drivers/clk/meson/clk-pll.c | 69 ++++++++++++++------- drivers/clk/meson/clkc.h | 8 +-- drivers/clk/meson/gxbb.c | 120 ++++++++++++++++++------------------ drivers/clk/meson/meson8b.c | 34 +++++----- 5 files changed, 162 insertions(+), 142 deletions(-) diff --git a/drivers/clk/meson/axg.c b/drivers/clk/meson/axg.c index a5e4f7b22f39..7511b3e26d40 100644 --- a/drivers/clk/meson/axg.c +++ b/drivers/clk/meson/axg.c @@ -134,36 +134,36 @@ static struct clk_regmap axg_sys_pll = { }, }; -static const struct pll_rate_table axg_gp0_pll_rate_table[] = { - PLL_RATE(960000000, 40, 1), - PLL_RATE(984000000, 41, 1), - PLL_RATE(1008000000, 42, 1), - PLL_RATE(1032000000, 43, 1), - PLL_RATE(1056000000, 44, 1), - PLL_RATE(1080000000, 45, 1), - PLL_RATE(1104000000, 46, 1), - PLL_RATE(1128000000, 47, 1), - PLL_RATE(1152000000, 48, 1), - PLL_RATE(1176000000, 49, 1), - PLL_RATE(1200000000, 50, 1), - PLL_RATE(1224000000, 51, 1), - PLL_RATE(1248000000, 52, 1), - PLL_RATE(1272000000, 53, 1), - PLL_RATE(1296000000, 54, 1), - PLL_RATE(1320000000, 55, 1), - PLL_RATE(1344000000, 56, 1), - PLL_RATE(1368000000, 57, 1), - PLL_RATE(1392000000, 58, 1), - PLL_RATE(1416000000, 59, 1), - PLL_RATE(1440000000, 60, 1), - PLL_RATE(1464000000, 61, 1), - PLL_RATE(1488000000, 62, 1), - PLL_RATE(1512000000, 63, 1), - PLL_RATE(1536000000, 64, 1), - PLL_RATE(1560000000, 65, 1), - PLL_RATE(1584000000, 66, 1), - PLL_RATE(1608000000, 67, 1), - PLL_RATE(1632000000, 68, 1), +static const struct pll_params_table axg_gp0_pll_params_table[] = { + PLL_PARAMS(40, 1), + PLL_PARAMS(41, 1), + PLL_PARAMS(42, 1), + PLL_PARAMS(43, 1), + PLL_PARAMS(44, 1), + PLL_PARAMS(45, 1), + PLL_PARAMS(46, 1), + PLL_PARAMS(47, 1), + PLL_PARAMS(48, 1), + PLL_PARAMS(49, 1), + PLL_PARAMS(50, 1), + PLL_PARAMS(51, 1), + PLL_PARAMS(52, 1), + PLL_PARAMS(53, 1), + PLL_PARAMS(54, 1), + PLL_PARAMS(55, 1), + PLL_PARAMS(56, 1), + PLL_PARAMS(57, 1), + PLL_PARAMS(58, 1), + PLL_PARAMS(59, 1), + PLL_PARAMS(60, 1), + PLL_PARAMS(61, 1), + PLL_PARAMS(62, 1), + PLL_PARAMS(63, 1), + PLL_PARAMS(64, 1), + PLL_PARAMS(65, 1), + PLL_PARAMS(66, 1), + PLL_PARAMS(67, 1), + PLL_PARAMS(68, 1), { /* sentinel */ }, }; @@ -207,7 +207,7 @@ static struct clk_regmap axg_gp0_pll_dco = { .shift = 29, .width = 1, }, - .table = axg_gp0_pll_rate_table, + .table = axg_gp0_pll_params_table, .init_regs = axg_gp0_init_regs, .init_count = ARRAY_SIZE(axg_gp0_init_regs), }, @@ -275,7 +275,7 @@ static struct clk_regmap axg_hifi_pll_dco = { .shift = 29, .width = 1, }, - .table = axg_gp0_pll_rate_table, + .table = axg_gp0_pll_params_table, .init_regs = axg_hifi_init_regs, .init_count = ARRAY_SIZE(axg_hifi_init_regs), .flags = CLK_MESON_PLL_ROUND_CLOSEST, @@ -631,11 +631,10 @@ static struct clk_regmap axg_mpll3 = { }, }; -static const struct pll_rate_table axg_pcie_pll_rate_table[] = { +static const struct pll_params_table axg_pcie_pll_params_table[] = { { - .rate = 1600000000, - .m = 200, - .n = 3, + .m = 200, + .n = 3, }, { /* sentinel */ }, }; @@ -682,7 +681,7 @@ static struct clk_regmap axg_pcie_pll_dco = { .shift = 29, .width = 1, }, - .table = axg_pcie_pll_rate_table, + .table = axg_pcie_pll_params_table, .init_regs = axg_pcie_init_regs, .init_count = ARRAY_SIZE(axg_pcie_init_regs), }, diff --git a/drivers/clk/meson/clk-pll.c b/drivers/clk/meson/clk-pll.c index 348a866f09eb..f5b5b3fabe3c 100644 --- a/drivers/clk/meson/clk-pll.c +++ b/drivers/clk/meson/clk-pll.c @@ -45,7 +45,7 @@ meson_clk_pll_data(struct clk_regmap *clk) } static unsigned long __pll_params_to_rate(unsigned long parent_rate, - const struct pll_rate_table *pllt, + const struct pll_params_table *pllt, u16 frac, struct meson_clk_pll_data *pll) { @@ -66,7 +66,7 @@ static unsigned long meson_clk_pll_recalc_rate(struct clk_hw *hw, { struct clk_regmap *clk = to_clk_regmap(hw); struct meson_clk_pll_data *pll = meson_clk_pll_data(clk); - struct pll_rate_table pllt; + struct pll_params_table pllt; u16 frac; pllt.n = meson_parm_read(clk->map, &pll->n); @@ -81,7 +81,7 @@ static unsigned long meson_clk_pll_recalc_rate(struct clk_hw *hw, static u16 __pll_params_with_frac(unsigned long rate, unsigned long parent_rate, - const struct pll_rate_table *pllt, + const struct pll_params_table *pllt, struct meson_clk_pll_data *pll) { u16 frac_max = (1 << pll->frac.width); @@ -97,29 +97,50 @@ static u16 __pll_params_with_frac(unsigned long rate, return min((u16)val, (u16)(frac_max - 1)); } -static const struct pll_rate_table * +static bool meson_clk_pll_is_better(unsigned long rate, + unsigned long best, + unsigned long now, + struct meson_clk_pll_data *pll) +{ + if (!(pll->flags & CLK_MESON_PLL_ROUND_CLOSEST) || + MESON_PARM_APPLICABLE(&pll->frac)) { + /* Round down */ + if (now < rate && best < now) + return true; + } else { + /* Round Closest */ + if (abs(now - rate) < abs(best - rate)) + return true; + } + + return false; +} + +static const struct pll_params_table * meson_clk_get_pll_settings(unsigned long rate, + unsigned long parent_rate, struct meson_clk_pll_data *pll) { - const struct pll_rate_table *table = pll->table; - unsigned int i = 0; + const struct pll_params_table *table = pll->table; + unsigned long best = 0, now = 0; + unsigned int i, best_i = 0; if (!table) return NULL; - /* Find the first table element exceeding rate */ - while (table[i].rate && table[i].rate <= rate) - i++; + for (i = 0; table[i].n; i++) { + now = __pll_params_to_rate(parent_rate, &table[i], 0, pll); - 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--; + /* If we get an exact match, don't bother any further */ + if (now == rate) { + return &table[i]; + } else if (meson_clk_pll_is_better(rate, best, now, pll)) { + best = now; + best_i = i; + } } - return (struct pll_rate_table *)&table[i]; + return (struct pll_params_table *)&table[best_i]; } static long meson_clk_pll_round_rate(struct clk_hw *hw, unsigned long rate, @@ -127,16 +148,18 @@ static long meson_clk_pll_round_rate(struct clk_hw *hw, unsigned long 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); + const struct pll_params_table *pllt = + meson_clk_get_pll_settings(rate, *parent_rate, pll); + unsigned long round; 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; + round = __pll_params_to_rate(*parent_rate, pllt, 0, pll); + + if (!MESON_PARM_APPLICABLE(&pll->frac) || rate == round) + return round; /* * The rate provided by the setting is not an exact match, let's @@ -214,7 +237,7 @@ static int meson_clk_pll_set_rate(struct clk_hw *hw, unsigned long 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; + const struct pll_params_table *pllt; unsigned int enabled; unsigned long old_rate; u16 frac = 0; @@ -224,7 +247,7 @@ static int meson_clk_pll_set_rate(struct clk_hw *hw, unsigned long rate, old_rate = rate; - pllt = meson_clk_get_pll_settings(rate, pll); + pllt = meson_clk_get_pll_settings(rate, parent_rate, pll); if (!pllt) return -EINVAL; diff --git a/drivers/clk/meson/clkc.h b/drivers/clk/meson/clkc.h index a2245e857f70..6b96d55c047d 100644 --- a/drivers/clk/meson/clkc.h +++ b/drivers/clk/meson/clkc.h @@ -43,15 +43,13 @@ static inline void meson_parm_write(struct regmap *map, struct parm *p, } -struct pll_rate_table { - unsigned long rate; +struct pll_params_table { u16 m; u16 n; }; -#define PLL_RATE(_r, _m, _n) \ +#define PLL_PARAMS(_m, _n) \ { \ - .rate = (_r), \ .m = (_m), \ .n = (_n), \ } @@ -67,7 +65,7 @@ struct meson_clk_pll_data { struct parm rst; const struct reg_sequence *init_regs; unsigned int init_count; - const struct pll_rate_table *table; + const struct pll_params_table *table; u8 flags; }; diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c index af59f2607dc1..9309cfaaa464 100644 --- a/drivers/clk/meson/gxbb.c +++ b/drivers/clk/meson/gxbb.c @@ -18,67 +18,67 @@ static DEFINE_SPINLOCK(meson_clk_lock); -static const struct pll_rate_table gxbb_gp0_pll_rate_table[] = { - PLL_RATE(768000000, 32, 1), - PLL_RATE(792000000, 33, 1), - PLL_RATE(816000000, 34, 1), - PLL_RATE(840000000, 35, 1), - PLL_RATE(864000000, 36, 1), - PLL_RATE(888000000, 37, 1), - PLL_RATE(912000000, 38, 1), - PLL_RATE(936000000, 39, 1), - PLL_RATE(960000000, 40, 1), - PLL_RATE(984000000, 41, 1), - PLL_RATE(1008000000, 42, 1), - PLL_RATE(1032000000, 43, 1), - PLL_RATE(1056000000, 44, 1), - PLL_RATE(1080000000, 45, 1), - PLL_RATE(1104000000, 46, 1), - PLL_RATE(1128000000, 47, 1), - PLL_RATE(1152000000, 48, 1), - PLL_RATE(1176000000, 49, 1), - PLL_RATE(1200000000, 50, 1), - PLL_RATE(1224000000, 51, 1), - PLL_RATE(1248000000, 52, 1), - PLL_RATE(1272000000, 53, 1), - PLL_RATE(1296000000, 54, 1), - PLL_RATE(1320000000, 55, 1), - PLL_RATE(1344000000, 56, 1), - PLL_RATE(1368000000, 57, 1), - PLL_RATE(1392000000, 58, 1), - PLL_RATE(1416000000, 59, 1), - PLL_RATE(1440000000, 60, 1), - PLL_RATE(1464000000, 61, 1), - PLL_RATE(1488000000, 62, 1), +static const struct pll_params_table gxbb_gp0_pll_params_table[] = { + PLL_PARAMS(32, 1), + PLL_PARAMS(33, 1), + PLL_PARAMS(34, 1), + PLL_PARAMS(35, 1), + PLL_PARAMS(36, 1), + PLL_PARAMS(37, 1), + PLL_PARAMS(38, 1), + PLL_PARAMS(39, 1), + PLL_PARAMS(40, 1), + PLL_PARAMS(41, 1), + PLL_PARAMS(42, 1), + PLL_PARAMS(43, 1), + PLL_PARAMS(44, 1), + PLL_PARAMS(45, 1), + PLL_PARAMS(46, 1), + PLL_PARAMS(47, 1), + PLL_PARAMS(48, 1), + PLL_PARAMS(49, 1), + PLL_PARAMS(50, 1), + PLL_PARAMS(51, 1), + PLL_PARAMS(52, 1), + PLL_PARAMS(53, 1), + PLL_PARAMS(54, 1), + PLL_PARAMS(55, 1), + PLL_PARAMS(56, 1), + PLL_PARAMS(57, 1), + PLL_PARAMS(58, 1), + PLL_PARAMS(59, 1), + PLL_PARAMS(60, 1), + PLL_PARAMS(61, 1), + PLL_PARAMS(62, 1), { /* sentinel */ }, }; -static const struct pll_rate_table gxl_gp0_pll_rate_table[] = { - PLL_RATE(1008000000, 42, 1), - PLL_RATE(1032000000, 43, 1), - PLL_RATE(1056000000, 44, 1), - PLL_RATE(1080000000, 45, 1), - PLL_RATE(1104000000, 46, 1), - PLL_RATE(1128000000, 47, 1), - PLL_RATE(1152000000, 48, 1), - PLL_RATE(1176000000, 49, 1), - PLL_RATE(1200000000, 50, 1), - PLL_RATE(1224000000, 51, 1), - PLL_RATE(1248000000, 52, 1), - PLL_RATE(1272000000, 53, 1), - PLL_RATE(1296000000, 54, 1), - PLL_RATE(1320000000, 55, 1), - PLL_RATE(1344000000, 56, 1), - PLL_RATE(1368000000, 57, 1), - PLL_RATE(1392000000, 58, 1), - PLL_RATE(1416000000, 59, 1), - PLL_RATE(1440000000, 60, 1), - PLL_RATE(1464000000, 61, 1), - PLL_RATE(1488000000, 62, 1), - PLL_RATE(1512000000, 63, 1), - PLL_RATE(1536000000, 64, 1), - PLL_RATE(1560000000, 65, 1), - PLL_RATE(1584000000, 66, 1), +static const struct pll_params_table gxl_gp0_pll_params_table[] = { + PLL_PARAMS(42, 1), + PLL_PARAMS(43, 1), + PLL_PARAMS(44, 1), + PLL_PARAMS(45, 1), + PLL_PARAMS(46, 1), + PLL_PARAMS(47, 1), + PLL_PARAMS(48, 1), + PLL_PARAMS(49, 1), + PLL_PARAMS(50, 1), + PLL_PARAMS(51, 1), + PLL_PARAMS(52, 1), + PLL_PARAMS(53, 1), + PLL_PARAMS(54, 1), + PLL_PARAMS(55, 1), + PLL_PARAMS(56, 1), + PLL_PARAMS(57, 1), + PLL_PARAMS(58, 1), + PLL_PARAMS(59, 1), + PLL_PARAMS(60, 1), + PLL_PARAMS(61, 1), + PLL_PARAMS(62, 1), + PLL_PARAMS(63, 1), + PLL_PARAMS(64, 1), + PLL_PARAMS(65, 1), + PLL_PARAMS(66, 1), { /* sentinel */ }, }; @@ -380,7 +380,7 @@ static struct clk_regmap gxbb_gp0_pll_dco = { .shift = 29, .width = 1, }, - .table = gxbb_gp0_pll_rate_table, + .table = gxbb_gp0_pll_params_table, .init_regs = gxbb_gp0_init_regs, .init_count = ARRAY_SIZE(gxbb_gp0_init_regs), }, @@ -432,7 +432,7 @@ static struct clk_regmap gxl_gp0_pll_dco = { .shift = 29, .width = 1, }, - .table = gxl_gp0_pll_rate_table, + .table = gxl_gp0_pll_params_table, .init_regs = gxl_gp0_init_regs, .init_count = ARRAY_SIZE(gxl_gp0_init_regs), }, diff --git a/drivers/clk/meson/meson8b.c b/drivers/clk/meson/meson8b.c index 4c061c1d3683..978485146ec3 100644 --- a/drivers/clk/meson/meson8b.c +++ b/drivers/clk/meson/meson8b.c @@ -29,22 +29,22 @@ struct meson8b_clk_reset { void __iomem *base; }; -static const struct pll_rate_table sys_pll_rate_table[] = { - PLL_RATE(1200000000, 50, 1), - PLL_RATE(1224000000, 51, 1), - PLL_RATE(1248000000, 52, 1), - PLL_RATE(1272000000, 53, 1), - PLL_RATE(1296000000, 54, 1), - PLL_RATE(1320000000, 55, 1), - PLL_RATE(1344000000, 56, 1), - PLL_RATE(1368000000, 57, 1), - PLL_RATE(1392000000, 58, 1), - PLL_RATE(1416000000, 59, 1), - PLL_RATE(1440000000, 60, 1), - PLL_RATE(1464000000, 61, 1), - PLL_RATE(1488000000, 62, 1), - PLL_RATE(1512000000, 63, 1), - PLL_RATE(1536000000, 64, 1), +static const struct pll_params_table sys_pll_params_table[] = { + PLL_PARAMS(50, 1), + PLL_PARAMS(51, 1), + PLL_PARAMS(52, 1), + PLL_PARAMS(53, 1), + PLL_PARAMS(54, 1), + PLL_PARAMS(55, 1), + PLL_PARAMS(56, 1), + PLL_PARAMS(57, 1), + PLL_PARAMS(58, 1), + PLL_PARAMS(59, 1), + PLL_PARAMS(60, 1), + PLL_PARAMS(61, 1), + PLL_PARAMS(62, 1), + PLL_PARAMS(63, 1), + PLL_PARAMS(64, 1), { /* sentinel */ }, }; @@ -196,7 +196,7 @@ static struct clk_regmap meson8b_sys_pll_dco = { .shift = 29, .width = 1, }, - .table = sys_pll_rate_table, + .table = sys_pll_params_table, }, .hw.init = &(struct clk_init_data){ .name = "sys_pll_dco", From 56dbabc0ff733ab0828e9567c886933fe77fa087 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Wed, 1 Aug 2018 16:07:32 +0200 Subject: [PATCH 18/23] clk: meson: axg: round audio system master clocks down Some of the master clocks provided by the axg audio clock controller are system clock (spdifin and pdm sysclk). They are used to clock an internal DSP of the related devices. Having them constantly rounded down instead of closest is preferable. Signed-off-by: Jerome Brunet --- drivers/clk/meson/axg-audio.c | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/drivers/clk/meson/axg-audio.c b/drivers/clk/meson/axg-audio.c index a0ed41e73bde..5f6c860aa122 100644 --- a/drivers/clk/meson/axg-audio.c +++ b/drivers/clk/meson/axg-audio.c @@ -101,10 +101,16 @@ static const char * const mst_mux_parent_names[] = { "axg_mst_in4", "axg_mst_in5", "axg_mst_in6", "axg_mst_in7", }; -#define AXG_MST_MCLK_MUX(_name, _reg) \ - AXG_AUD_MUX(_name##_sel, _reg, 0x7, 24, CLK_MUX_ROUND_CLOSEST, \ +#define AXG_MST_MUX(_name, _reg, _flag) \ + AXG_AUD_MUX(_name##_sel, _reg, 0x7, 24, _flag, \ mst_mux_parent_names, CLK_SET_RATE_PARENT) +#define AXG_MST_MCLK_MUX(_name, _reg) \ + AXG_MST_MUX(_name, _reg, CLK_MUX_ROUND_CLOSEST) + +#define AXG_MST_SYS_MUX(_name, _reg) \ + AXG_MST_MUX(_name, _reg, 0) + static AXG_MST_MCLK_MUX(mst_a_mclk, AUDIO_MCLK_A_CTRL); static AXG_MST_MCLK_MUX(mst_b_mclk, AUDIO_MCLK_B_CTRL); static AXG_MST_MCLK_MUX(mst_c_mclk, AUDIO_MCLK_C_CTRL); @@ -112,13 +118,19 @@ static AXG_MST_MCLK_MUX(mst_d_mclk, AUDIO_MCLK_D_CTRL); static AXG_MST_MCLK_MUX(mst_e_mclk, AUDIO_MCLK_E_CTRL); static AXG_MST_MCLK_MUX(mst_f_mclk, AUDIO_MCLK_F_CTRL); static AXG_MST_MCLK_MUX(spdifout_clk, AUDIO_CLK_SPDIFOUT_CTRL); -static AXG_MST_MCLK_MUX(spdifin_clk, AUDIO_CLK_SPDIFIN_CTRL); static AXG_MST_MCLK_MUX(pdm_dclk, AUDIO_CLK_PDMIN_CTRL0); -static AXG_MST_MCLK_MUX(pdm_sysclk, AUDIO_CLK_PDMIN_CTRL1); +static AXG_MST_SYS_MUX(spdifin_clk, AUDIO_CLK_SPDIFIN_CTRL); +static AXG_MST_SYS_MUX(pdm_sysclk, AUDIO_CLK_PDMIN_CTRL1); -#define AXG_MST_MCLK_DIV(_name, _reg) \ - AXG_AUD_DIV(_name##_div, _reg, 0, 16, CLK_DIVIDER_ROUND_CLOSEST, \ - "axg_"#_name"_sel", CLK_SET_RATE_PARENT) \ +#define AXG_MST_DIV(_name, _reg, _flag) \ + AXG_AUD_DIV(_name##_div, _reg, 0, 16, _flag, \ + "axg_"#_name"_sel", CLK_SET_RATE_PARENT) \ + +#define AXG_MST_MCLK_DIV(_name, _reg) \ + AXG_MST_DIV(_name, _reg, CLK_DIVIDER_ROUND_CLOSEST) + +#define AXG_MST_SYS_DIV(_name, _reg) \ + AXG_MST_DIV(_name, _reg, 0) static AXG_MST_MCLK_DIV(mst_a_mclk, AUDIO_MCLK_A_CTRL); static AXG_MST_MCLK_DIV(mst_b_mclk, AUDIO_MCLK_B_CTRL); @@ -127,12 +139,12 @@ static AXG_MST_MCLK_DIV(mst_d_mclk, AUDIO_MCLK_D_CTRL); static AXG_MST_MCLK_DIV(mst_e_mclk, AUDIO_MCLK_E_CTRL); static AXG_MST_MCLK_DIV(mst_f_mclk, AUDIO_MCLK_F_CTRL); static AXG_MST_MCLK_DIV(spdifout_clk, AUDIO_CLK_SPDIFOUT_CTRL); -static AXG_MST_MCLK_DIV(spdifin_clk, AUDIO_CLK_SPDIFIN_CTRL); static AXG_MST_MCLK_DIV(pdm_dclk, AUDIO_CLK_PDMIN_CTRL0); -static AXG_MST_MCLK_DIV(pdm_sysclk, AUDIO_CLK_PDMIN_CTRL1); +static AXG_MST_SYS_DIV(spdifin_clk, AUDIO_CLK_SPDIFIN_CTRL); +static AXG_MST_SYS_DIV(pdm_sysclk, AUDIO_CLK_PDMIN_CTRL1); -#define AXG_MST_MCLK_GATE(_name, _reg) \ - AXG_AUD_GATE(_name, _reg, 31, "axg_"#_name"_div", \ +#define AXG_MST_MCLK_GATE(_name, _reg) \ + AXG_AUD_GATE(_name, _reg, 31, "axg_"#_name"_div", \ CLK_SET_RATE_PARENT) static AXG_MST_MCLK_GATE(mst_a_mclk, AUDIO_MCLK_A_CTRL); From 69b93104c7ec5668019caf5d2dbfd0e182df06db Mon Sep 17 00:00:00 2001 From: Yixun Lan Date: Wed, 1 Aug 2018 12:16:24 +0000 Subject: [PATCH 19/23] clk: meson-axg: pcie: drop the mpll3 clock parent We found the PCIe driver doesn't really work with the mpll3 clock which is actually reserved for debug, So drop it from the mux list. Fixes: 33b89db68236 ("clk: meson-axg: add clocks required by pcie driver") Tested-by: Jianxin Qin Signed-off-by: Yixun Lan Signed-off-by: Jerome Brunet --- drivers/clk/meson/axg.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/clk/meson/axg.c b/drivers/clk/meson/axg.c index 7511b3e26d40..c981159b02c0 100644 --- a/drivers/clk/meson/axg.c +++ b/drivers/clk/meson/axg.c @@ -730,12 +730,14 @@ static struct clk_regmap axg_pcie_mux = { .offset = HHI_PCIE_PLL_CNTL6, .mask = 0x1, .shift = 2, + /* skip the parent mpll3, reserved for debug */ + .table = (u32[]){ 1 }, }, .hw.init = &(struct clk_init_data){ .name = "pcie_mux", .ops = &clk_regmap_mux_ops, - .parent_names = (const char *[]){ "mpll3", "pcie_pll" }, - .num_parents = 2, + .parent_names = (const char *[]){ "pcie_pll" }, + .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; From 6291b8c5ac67d0f1121d8dfd83a82c83272e3499 Mon Sep 17 00:00:00 2001 From: Martin Blumenstingl Date: Sat, 21 Jul 2018 21:13:59 +0200 Subject: [PATCH 20/23] clk: meson: meson8b: register the clock controller early Until now only the reset controller (part of the clock controller register space) was registered early in the boot process, while the clock controller itself was registered later on. However, some parts of the SoC are initialized early in the boot process, such as the SRAM and the TWD timer. The bootloader already enables these clocks so we didn't see any issues so far. Register the clock controller early so other drivers (such as the SRAM and TWD timer) can use the clocks early in the boot process. Signed-off-by: Martin Blumenstingl Signed-off-by: Jerome Brunet --- drivers/clk/meson/meson8b.c | 94 ++++++++++++++----------------------- 1 file changed, 34 insertions(+), 60 deletions(-) diff --git a/drivers/clk/meson/meson8b.c b/drivers/clk/meson/meson8b.c index 978485146ec3..2a31d6eeef37 100644 --- a/drivers/clk/meson/meson8b.c +++ b/drivers/clk/meson/meson8b.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include @@ -22,8 +21,6 @@ static DEFINE_SPINLOCK(meson_clk_lock); -static void __iomem *clk_base; - struct meson8b_clk_reset { struct reset_controller_dev reset; void __iomem *base; @@ -1111,62 +1108,12 @@ static const struct regmap_config clkc_regmap_config = { .reg_stride = 4, }; -static int meson8b_clkc_probe(struct platform_device *pdev) -{ - int ret, i; - 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 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 - */ - for (i = CLKID_XTAL; i < CLK_NR_CLKS; i++) { - /* array might be sparse */ - if (!meson8b_hw_onecell_data.hws[i]) - continue; - - ret = devm_clk_hw_register(dev, meson8b_hw_onecell_data.hws[i]); - if (ret) - return ret; - } - - 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[] = { - { .compatible = "amlogic,meson8-clkc" }, - { .compatible = "amlogic,meson8b-clkc" }, - { .compatible = "amlogic,meson8m2-clkc" }, - { } -}; - -static struct platform_driver meson8b_driver = { - .probe = meson8b_clkc_probe, - .driver = { - .name = "meson8b-clkc", - .of_match_table = meson8b_clkc_match_table, - }, -}; - -builtin_platform_driver(meson8b_driver); - -static void __init meson8b_clkc_reset_init(struct device_node *np) +static void __init meson8b_clkc_init(struct device_node *np) { struct meson8b_clk_reset *rstc; - int ret; + void __iomem *clk_base; + struct regmap *map; + int i, ret; /* Generic clocks, PLLs and some of the reset-bits */ clk_base = of_iomap(np, 1); @@ -1175,6 +1122,10 @@ static void __init meson8b_clkc_reset_init(struct device_node *np) return; } + map = regmap_init_mmio(NULL, clk_base, &clkc_regmap_config); + if (IS_ERR(map)) + return; + rstc = kzalloc(sizeof(*rstc), GFP_KERNEL); if (!rstc) return; @@ -1190,11 +1141,34 @@ static void __init meson8b_clkc_reset_init(struct device_node *np) __func__, ret); return; } + + /* 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 + */ + for (i = CLKID_XTAL; i < CLK_NR_CLKS; i++) { + /* array might be sparse */ + if (!meson8b_hw_onecell_data.hws[i]) + continue; + + ret = clk_hw_register(NULL, meson8b_hw_onecell_data.hws[i]); + if (ret) + return; + } + + ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, + &meson8b_hw_onecell_data); + if (ret) + pr_err("%s: failed to register clock provider\n", __func__); } CLK_OF_DECLARE_DRIVER(meson8_clkc, "amlogic,meson8-clkc", - meson8b_clkc_reset_init); + meson8b_clkc_init); CLK_OF_DECLARE_DRIVER(meson8b_clkc, "amlogic,meson8b-clkc", - meson8b_clkc_reset_init); + meson8b_clkc_init); CLK_OF_DECLARE_DRIVER(meson8m2_clkc, "amlogic,meson8m2-clkc", - meson8b_clkc_reset_init); + meson8b_clkc_init); From 93c873d686461652921fe18b137ac28002dfe166 Mon Sep 17 00:00:00 2001 From: Martin Blumenstingl Date: Sat, 21 Jul 2018 21:14:00 +0200 Subject: [PATCH 21/23] clk: meson: meson8b: use the regmap in the internal reset controller For now the reset controller was using raw register access because the early init did not initialize the regmap. However, now that clocks are initialized early we can simply use the regmap also for the reset controller. No functional changes. Signed-off-by: Martin Blumenstingl Signed-off-by: Jerome Brunet --- drivers/clk/meson/meson8b.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/clk/meson/meson8b.c b/drivers/clk/meson/meson8b.c index 2a31d6eeef37..346b9e165b7a 100644 --- a/drivers/clk/meson/meson8b.c +++ b/drivers/clk/meson/meson8b.c @@ -23,7 +23,7 @@ static DEFINE_SPINLOCK(meson_clk_lock); struct meson8b_clk_reset { struct reset_controller_dev reset; - void __iomem *base; + struct regmap *regmap; }; static const struct pll_params_table sys_pll_params_table[] = { @@ -1064,7 +1064,6 @@ static int meson8b_clk_reset_update(struct reset_controller_dev *rcdev, container_of(rcdev, struct meson8b_clk_reset, reset); unsigned long flags; const struct meson8b_clk_reset_line *reset; - u32 val; if (id >= ARRAY_SIZE(meson8b_clk_reset_bits)) return -EINVAL; @@ -1073,12 +1072,12 @@ static int meson8b_clk_reset_update(struct reset_controller_dev *rcdev, spin_lock_irqsave(&meson_clk_lock, flags); - val = readl(meson8b_clk_reset->base + reset->reg); if (assert) - val |= BIT(reset->bit_idx); + regmap_update_bits(meson8b_clk_reset->regmap, reset->reg, + BIT(reset->bit_idx), BIT(reset->bit_idx)); else - val &= ~BIT(reset->bit_idx); - writel(val, meson8b_clk_reset->base + reset->reg); + regmap_update_bits(meson8b_clk_reset->regmap, reset->reg, + BIT(reset->bit_idx), 0); spin_unlock_irqrestore(&meson_clk_lock, flags); @@ -1131,7 +1130,7 @@ static void __init meson8b_clkc_init(struct device_node *np) return; /* Reset Controller */ - rstc->base = clk_base; + rstc->regmap = map; rstc->reset.ops = &meson8b_clk_reset_ops; rstc->reset.nr_resets = ARRAY_SIZE(meson8b_clk_reset_bits); rstc->reset.of_node = np; From 6ffeddd6bca4cb838623d0bf4134c0eb06ad7485 Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Wed, 12 Sep 2018 17:35:49 +0200 Subject: [PATCH 22/23] clk: mvebu: ap806: Remove superfluous of_clk_add_provider While applying the commit a8309cedcdce ("clk: apn806: Add eMMC clock to system controller driver"), of_clk_add_provider was added wheres it was already present in the probe function. This extraneous call is harmless but not useful so remove it. Signed-off-by: Gregory CLEMENT Signed-off-by: Stephen Boyd --- drivers/clk/mvebu/ap806-system-controller.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/clk/mvebu/ap806-system-controller.c b/drivers/clk/mvebu/ap806-system-controller.c index fa2fbd2cef4a..cfc6b82d2448 100644 --- a/drivers/clk/mvebu/ap806-system-controller.c +++ b/drivers/clk/mvebu/ap806-system-controller.c @@ -155,7 +155,6 @@ static int ap806_syscon_common_probe(struct platform_device *pdev, goto fail4; } - of_clk_add_provider(np, of_clk_src_onecell_get, &ap806_clk_data); ret = of_clk_add_provider(np, of_clk_src_onecell_get, &ap806_clk_data); if (ret) goto fail_clk_add; From e3aaadb0f0d64153674b9f81e3c12f95fa420e6d Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Thu, 21 Jun 2018 09:37:04 +0200 Subject: [PATCH 23/23] clk: davinci: kill davinci_clk_reset_assert/deassert() This code is no longer used. Remove it. Signed-off-by: Bartosz Golaszewski Reviewed-by: David Lechner Signed-off-by: Stephen Boyd --- arch/arm/mach-davinci/include/mach/clock.h | 21 --------------------- drivers/clk/davinci/psc.c | 18 ------------------ 2 files changed, 39 deletions(-) delete mode 100644 arch/arm/mach-davinci/include/mach/clock.h diff --git a/arch/arm/mach-davinci/include/mach/clock.h b/arch/arm/mach-davinci/include/mach/clock.h deleted file mode 100644 index 42ed4f2f5ce4..000000000000 --- a/arch/arm/mach-davinci/include/mach/clock.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * arch/arm/mach-davinci/include/mach/clock.h - * - * Clock control driver for DaVinci - header file - * - * Authors: Vladimir Barinov - * - * 2007 (c) MontaVista Software, Inc. This file is licensed under - * the terms of the GNU General Public License version 2. This program - * is licensed "as is" without any warranty of any kind, whether express - * or implied. - */ -#ifndef __ASM_ARCH_DAVINCI_CLOCK_H -#define __ASM_ARCH_DAVINCI_CLOCK_H - -struct clk; - -int davinci_clk_reset_assert(struct clk *c); -int davinci_clk_reset_deassert(struct clk *c); - -#endif diff --git a/drivers/clk/davinci/psc.c b/drivers/clk/davinci/psc.c index fffbed5e263b..5b69e24a224f 100644 --- a/drivers/clk/davinci/psc.c +++ b/drivers/clk/davinci/psc.c @@ -303,24 +303,6 @@ static int davinci_lpsc_clk_reset(struct clk *clk, bool reset) 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) {