From 4d1369cae0165227048c420cf089668335084151 Mon Sep 17 00:00:00 2001 From: Vasyl Gomonovych Date: Wed, 29 Nov 2017 17:15:43 +0100 Subject: clk: sunxi: Use PTR_ERR_OR_ZERO() Fix ptr_ret.cocci warnings: drivers/clk/sunxi/clk-sun8i-apb0.c:101:1-3: WARNING: PTR_ERR_OR_ZERO can be used Use PTR_ERR_OR_ZERO rather than if(IS_ERR(...)) + PTR_ERR Generated by: scripts/coccinelle/api/ptr_ret.cocci Signed-off-by: Vasyl Gomonovych Signed-off-by: Maxime Ripard --- drivers/clk/sunxi/clk-sun8i-apb0.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/clk/sunxi/clk-sun8i-apb0.c b/drivers/clk/sunxi/clk-sun8i-apb0.c index ea1eed24778c..d5c31804ee54 100644 --- a/drivers/clk/sunxi/clk-sun8i-apb0.c +++ b/drivers/clk/sunxi/clk-sun8i-apb0.c @@ -98,10 +98,7 @@ static int sun8i_a23_apb0_clk_probe(struct platform_device *pdev) return PTR_ERR(reg); clk = sun8i_a23_apb0_register(np, reg); - if (IS_ERR(clk)) - return PTR_ERR(clk); - - return 0; + return PTR_ERR_OR_ZERO(clk); } static const struct of_device_id sun8i_a23_apb0_clk_dt_ids[] = { -- cgit v1.2.3-58-ga151 From 946797aa3f08e2f6f5992f3ec2be44791e9b9260 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Mon, 4 Dec 2017 13:19:11 +0800 Subject: clk: sunxi-ng: Support fixed post-dividers on MP style clocks On the A64, 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. To do this, we first add fixed post-divider to the MP style clocks, which the MMC module clocks are. Signed-off-by: Chen-Yu Tsai Tested-by: Andre Przywara Signed-off-by: Maxime Ripard --- drivers/clk/sunxi-ng/ccu_mp.c | 20 ++++++++++++++++++-- drivers/clk/sunxi-ng/ccu_mp.h | 24 ++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/drivers/clk/sunxi-ng/ccu_mp.c b/drivers/clk/sunxi-ng/ccu_mp.c index 688855e7dc8c..5d0af4051737 100644 --- a/drivers/clk/sunxi-ng/ccu_mp.c +++ b/drivers/clk/sunxi-ng/ccu_mp.c @@ -50,12 +50,19 @@ static unsigned long ccu_mp_round_rate(struct ccu_mux_internal *mux, unsigned int max_m, max_p; unsigned int m, p; + if (cmp->common.features & CCU_FEATURE_FIXED_POSTDIV) + rate *= cmp->fixed_post_div; + max_m = cmp->m.max ?: 1 << cmp->m.width; max_p = cmp->p.max ?: 1 << ((1 << cmp->p.width) - 1); ccu_mp_find_best(*parent_rate, rate, max_m, max_p, &m, &p); + rate = *parent_rate / p / m; + + if (cmp->common.features & CCU_FEATURE_FIXED_POSTDIV) + rate /= cmp->fixed_post_div; - return *parent_rate / p / m; + return rate; } static void ccu_mp_disable(struct clk_hw *hw) @@ -83,6 +90,7 @@ static unsigned long ccu_mp_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { struct ccu_mp *cmp = hw_to_ccu_mp(hw); + unsigned long rate; unsigned int m, p; u32 reg; @@ -101,7 +109,11 @@ static unsigned long ccu_mp_recalc_rate(struct clk_hw *hw, p = reg >> cmp->p.shift; p &= (1 << cmp->p.width) - 1; - return (parent_rate >> p) / m; + rate = (parent_rate >> p) / m; + if (cmp->common.features & CCU_FEATURE_FIXED_POSTDIV) + rate /= cmp->fixed_post_div; + + return rate; } static int ccu_mp_determine_rate(struct clk_hw *hw, @@ -129,6 +141,10 @@ static int ccu_mp_set_rate(struct clk_hw *hw, unsigned long rate, max_m = cmp->m.max ?: 1 << cmp->m.width; max_p = cmp->p.max ?: 1 << ((1 << cmp->p.width) - 1); + /* Adjust target rate according to post-dividers */ + if (cmp->common.features & CCU_FEATURE_FIXED_POSTDIV) + rate = rate * cmp->fixed_post_div; + ccu_mp_find_best(parent_rate, rate, max_m, max_p, &m, &p); spin_lock_irqsave(cmp->common.lock, flags); diff --git a/drivers/clk/sunxi-ng/ccu_mp.h b/drivers/clk/sunxi-ng/ccu_mp.h index aaef11d747ea..5107635e61de 100644 --- a/drivers/clk/sunxi-ng/ccu_mp.h +++ b/drivers/clk/sunxi-ng/ccu_mp.h @@ -33,9 +33,33 @@ struct ccu_mp { struct ccu_div_internal m; struct ccu_div_internal p; struct ccu_mux_internal mux; + + unsigned int fixed_post_div; + struct ccu_common common; }; +#define SUNXI_CCU_MP_WITH_MUX_GATE_POSTDIV(_struct, _name, _parents, _reg, \ + _mshift, _mwidth, \ + _pshift, _pwidth, \ + _muxshift, _muxwidth, \ + _gate, _postdiv, _flags) \ + struct ccu_mp _struct = { \ + .enable = _gate, \ + .m = _SUNXI_CCU_DIV(_mshift, _mwidth), \ + .p = _SUNXI_CCU_DIV(_pshift, _pwidth), \ + .mux = _SUNXI_CCU_MUX(_muxshift, _muxwidth), \ + .fixed_post_div = _postdiv, \ + .common = { \ + .reg = _reg, \ + .features = CCU_FEATURE_FIXED_POSTDIV, \ + .hw.init = CLK_HW_INIT_PARENTS(_name, \ + _parents, \ + &ccu_mp_ops, \ + _flags), \ + } \ + } + #define SUNXI_CCU_MP_WITH_MUX_GATE(_struct, _name, _parents, _reg, \ _mshift, _mwidth, \ _pshift, _pwidth, \ -- cgit v1.2.3-58-ga151 From 83fe3be4d1974f5f50c5e2039a1609f4960e8579 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Mon, 4 Dec 2017 13:19:12 +0800 Subject: clk: sunxi-ng: sun50i: a64: Add 2x fixed post-divider to MMC module clocks On the A64, 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. Signed-off-by: Chen-Yu Tsai Reviewed-by: Andre Przywara Tested-by: Andre Przywara Signed-off-by: Maxime Ripard --- drivers/clk/sunxi-ng/ccu-sun50i-a64.c | 57 +++++++++++++++++++++++------------ 1 file changed, 37 insertions(+), 20 deletions(-) diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-a64.c b/drivers/clk/sunxi-ng/ccu-sun50i-a64.c index 2bb4cabf802f..ee9c12cf3f08 100644 --- a/drivers/clk/sunxi-ng/ccu-sun50i-a64.c +++ b/drivers/clk/sunxi-ng/ccu-sun50i-a64.c @@ -400,28 +400,45 @@ static SUNXI_CCU_MP_WITH_MUX_GATE(nand_clk, "nand", mod0_default_parents, 0x080, BIT(31), /* gate */ 0); +/* + * MMC clocks are the new timing mode (see A83T & H3) variety, but without + * the mode switch. This means they have a 2x post divider between the clock + * and the MMC module. This is not documented in the manual, but is taken + * into consideration when setting the mmc module clocks in the BSP kernel. + * Without it, MMC performance is degraded. + * + * We model it here to be consistent with other SoCs supporting this mode. + * The alternative would be to add the 2x multiplier when setting the MMC + * module clock in the MMC driver, just for the A64. + */ static const char * const mmc_default_parents[] = { "osc24M", "pll-periph0-2x", "pll-periph1-2x" }; -static SUNXI_CCU_MP_WITH_MUX_GATE(mmc0_clk, "mmc0", mmc_default_parents, 0x088, - 0, 4, /* M */ - 16, 2, /* P */ - 24, 2, /* mux */ - BIT(31), /* gate */ - 0); - -static SUNXI_CCU_MP_WITH_MUX_GATE(mmc1_clk, "mmc1", mmc_default_parents, 0x08c, - 0, 4, /* M */ - 16, 2, /* P */ - 24, 2, /* mux */ - BIT(31), /* gate */ - 0); - -static SUNXI_CCU_MP_WITH_MUX_GATE(mmc2_clk, "mmc2", mmc_default_parents, 0x090, - 0, 4, /* M */ - 16, 2, /* P */ - 24, 2, /* mux */ - BIT(31), /* gate */ - 0); +static SUNXI_CCU_MP_WITH_MUX_GATE_POSTDIV(mmc0_clk, "mmc0", + mmc_default_parents, 0x088, + 0, 4, /* M */ + 16, 2, /* P */ + 24, 2, /* mux */ + BIT(31), /* gate */ + 2, /* post-div */ + 0); + +static SUNXI_CCU_MP_WITH_MUX_GATE_POSTDIV(mmc1_clk, "mmc1", + mmc_default_parents, 0x08c, + 0, 4, /* M */ + 16, 2, /* P */ + 24, 2, /* mux */ + BIT(31), /* gate */ + 2, /* post-div */ + 0); + +static SUNXI_CCU_MP_WITH_MUX_GATE_POSTDIV(mmc2_clk, "mmc2", + mmc_default_parents, 0x090, + 0, 4, /* M */ + 16, 2, /* P */ + 24, 2, /* mux */ + BIT(31), /* gate */ + 2, /* post-div */ + 0); static const char * const ts_parents[] = { "osc24M", "pll-periph0", }; static SUNXI_CCU_MP_WITH_MUX_GATE(ts_clk, "ts", ts_parents, 0x098, -- cgit v1.2.3-58-ga151 From 7d333ef1cc1b8c8951f3a2c41f6406e2295d8be9 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Fri, 8 Dec 2017 16:35:10 +0800 Subject: clk: sunxi-ng: Support fixed post-dividers on NM style clocks On the A83T, the audio PLL should have its div1 set to 0, or /1, and div2 set to 1, or /2. This setting is the default, and is required to match the sigma-delta modulation parameters from the BSP kernel. To do this, we first add fixed post-divider to the NM style clocks, which is the type of clock the audio PLL clock is modeled into. Signed-off-by: Chen-Yu Tsai Signed-off-by: Maxime Ripard --- drivers/clk/sunxi-ng/ccu_nm.c | 50 ++++++++++++++++++++++++++++++++----------- drivers/clk/sunxi-ng/ccu_nm.h | 2 ++ 2 files changed, 39 insertions(+), 13 deletions(-) diff --git a/drivers/clk/sunxi-ng/ccu_nm.c b/drivers/clk/sunxi-ng/ccu_nm.c index 7620aa973a6e..a16de092bf94 100644 --- a/drivers/clk/sunxi-ng/ccu_nm.c +++ b/drivers/clk/sunxi-ng/ccu_nm.c @@ -70,11 +70,18 @@ static unsigned long ccu_nm_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { struct ccu_nm *nm = hw_to_ccu_nm(hw); + unsigned long rate; unsigned long n, m; u32 reg; - if (ccu_frac_helper_is_enabled(&nm->common, &nm->frac)) - return ccu_frac_helper_read_rate(&nm->common, &nm->frac); + if (ccu_frac_helper_is_enabled(&nm->common, &nm->frac)) { + rate = ccu_frac_helper_read_rate(&nm->common, &nm->frac); + + if (nm->common.features & CCU_FEATURE_FIXED_POSTDIV) + rate /= nm->fixed_post_div; + + return rate; + } reg = readl(nm->common.base + nm->common.reg); @@ -90,15 +97,15 @@ static unsigned long ccu_nm_recalc_rate(struct clk_hw *hw, if (!m) m++; - if (ccu_sdm_helper_is_enabled(&nm->common, &nm->sdm)) { - unsigned long rate = - ccu_sdm_helper_read_rate(&nm->common, &nm->sdm, - m, n); - if (rate) - return rate; - } + if (ccu_sdm_helper_is_enabled(&nm->common, &nm->sdm)) + rate = ccu_sdm_helper_read_rate(&nm->common, &nm->sdm, m, n); + else + rate = parent_rate * n / m; + + if (nm->common.features & CCU_FEATURE_FIXED_POSTDIV) + rate /= nm->fixed_post_div; - return parent_rate * n / m; + return rate; } static long ccu_nm_round_rate(struct clk_hw *hw, unsigned long rate, @@ -107,11 +114,20 @@ static long ccu_nm_round_rate(struct clk_hw *hw, unsigned long rate, struct ccu_nm *nm = hw_to_ccu_nm(hw); struct _ccu_nm _nm; - if (ccu_frac_helper_has_rate(&nm->common, &nm->frac, rate)) + if (nm->common.features & CCU_FEATURE_FIXED_POSTDIV) + rate *= nm->fixed_post_div; + + if (ccu_frac_helper_has_rate(&nm->common, &nm->frac, rate)) { + if (nm->common.features & CCU_FEATURE_FIXED_POSTDIV) + rate /= nm->fixed_post_div; return rate; + } - if (ccu_sdm_helper_has_rate(&nm->common, &nm->sdm, rate)) + if (ccu_sdm_helper_has_rate(&nm->common, &nm->sdm, rate)) { + if (nm->common.features & CCU_FEATURE_FIXED_POSTDIV) + rate /= nm->fixed_post_div; return rate; + } _nm.min_n = nm->n.min ?: 1; _nm.max_n = nm->n.max ?: 1 << nm->n.width; @@ -119,8 +135,12 @@ static long ccu_nm_round_rate(struct clk_hw *hw, unsigned long rate, _nm.max_m = nm->m.max ?: 1 << nm->m.width; ccu_nm_find_best(*parent_rate, rate, &_nm); + rate = *parent_rate * _nm.n / _nm.m; + + if (nm->common.features & CCU_FEATURE_FIXED_POSTDIV) + rate /= nm->fixed_post_div; - return *parent_rate * _nm.n / _nm.m; + return rate; } static int ccu_nm_set_rate(struct clk_hw *hw, unsigned long rate, @@ -131,6 +151,10 @@ static int ccu_nm_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long flags; u32 reg; + /* Adjust target rate according to post-dividers */ + if (nm->common.features & CCU_FEATURE_FIXED_POSTDIV) + rate = rate * nm->fixed_post_div; + if (ccu_frac_helper_has_rate(&nm->common, &nm->frac, rate)) { spin_lock_irqsave(nm->common.lock, flags); diff --git a/drivers/clk/sunxi-ng/ccu_nm.h b/drivers/clk/sunxi-ng/ccu_nm.h index c623b0c7a23c..eba586b4c7d0 100644 --- a/drivers/clk/sunxi-ng/ccu_nm.h +++ b/drivers/clk/sunxi-ng/ccu_nm.h @@ -36,6 +36,8 @@ struct ccu_nm { struct ccu_frac_internal frac; struct ccu_sdm_internal sdm; + unsigned int fixed_post_div; + struct ccu_common common; }; -- cgit v1.2.3-58-ga151 From 10e6eb4f2c5b35ae71c9bc0db83d74238719b453 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Fri, 8 Dec 2017 16:35:11 +0800 Subject: clk: sunxi-ng: sun8i: a83t: Add /2 fixed post divider to audio PLL On the A83T, the audio PLL should have its div1 set to 0, or /1, and div2 set to 1, or /2. This setting is the default, and is required to match the sigma-delta modulation parameters from the BSP kernel. This patch adds a /2 fixed post divider to the audio PLL, and fixes the enforced d1 & d2 values. This also resolves the mismatch between the values mentioned in the comment for the audio PLL, and the actual enforced values. Signed-off-by: Chen-Yu Tsai Signed-off-by: Maxime Ripard --- drivers/clk/sunxi-ng/ccu-sun8i-a83t.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-a83t.c b/drivers/clk/sunxi-ng/ccu-sun8i-a83t.c index 5cedcd0d8be8..06b69e433d0f 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-a83t.c +++ b/drivers/clk/sunxi-ng/ccu-sun8i-a83t.c @@ -81,10 +81,12 @@ static struct ccu_nm pll_audio_clk = { .lock = BIT(2), .n = _SUNXI_CCU_MULT_OFFSET_MIN_MAX(8, 8, 0, 12, 0), .m = _SUNXI_CCU_DIV(0, 6), + .fixed_post_div = 2, .common = { .reg = SUN8I_A83T_PLL_AUDIO_REG, .lock_reg = CCU_SUN8I_A83T_LOCK_REG, - .features = CCU_FEATURE_LOCK_REG, + .features = CCU_FEATURE_LOCK_REG | + CCU_FEATURE_FIXED_POSTDIV, .hw.init = CLK_HW_INIT("pll-audio", "osc24M", &ccu_nm_ops, CLK_SET_RATE_UNGATE), }, @@ -889,9 +891,10 @@ static int sun8i_a83t_ccu_probe(struct platform_device *pdev) if (IS_ERR(reg)) return PTR_ERR(reg); - /* Enforce d1 = 0, d2 = 0 for Audio PLL */ + /* Enforce d1 = 0, d2 = 1 for Audio PLL */ val = readl(reg + SUN8I_A83T_PLL_AUDIO_REG); - val &= ~(BIT(16) | BIT(18)); + val &= ~BIT(16); + val |= BIT(18); writel(val, reg + SUN8I_A83T_PLL_AUDIO_REG); /* Enforce P = 1 for both CPU cluster PLLs */ -- cgit v1.2.3-58-ga151 From e952ca3c6b2ffdfbf9618e4bd3e9aad1ff3f5eb4 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Fri, 8 Dec 2017 16:35:12 +0800 Subject: clk: sunxi-ng: sun8i: a83t: Use sigma-delta modulation for audio PLL The audio blocks require specific clock rates. Until now we were using the closest clock rate possible with integer N-M factors. This resulted in audio playback being slightly slower than it should be. The vendor kernel gets around this (for newer SoCs) by using sigma-delta modulation to generate a fractional-N factor. This patch copies the parameters for the A83T. Signed-off-by: Chen-Yu Tsai Signed-off-by: Maxime Ripard --- drivers/clk/sunxi-ng/ccu-sun8i-a83t.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-a83t.c b/drivers/clk/sunxi-ng/ccu-sun8i-a83t.c index 06b69e433d0f..04a9c33f53f0 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-a83t.c +++ b/drivers/clk/sunxi-ng/ccu-sun8i-a83t.c @@ -76,17 +76,26 @@ static struct ccu_mult pll_c1cpux_clk = { */ #define SUN8I_A83T_PLL_AUDIO_REG 0x008 +/* clock rates doubled for post divider */ +static struct ccu_sdm_setting pll_audio_sdm_table[] = { + { .rate = 45158400, .pattern = 0xc00121ff, .m = 29, .n = 54 }, + { .rate = 49152000, .pattern = 0xc000e147, .m = 30, .n = 61 }, +}; + static struct ccu_nm pll_audio_clk = { .enable = BIT(31), .lock = BIT(2), .n = _SUNXI_CCU_MULT_OFFSET_MIN_MAX(8, 8, 0, 12, 0), .m = _SUNXI_CCU_DIV(0, 6), .fixed_post_div = 2, + .sdm = _SUNXI_CCU_SDM(pll_audio_sdm_table, BIT(24), + 0x284, BIT(31)), .common = { .reg = SUN8I_A83T_PLL_AUDIO_REG, .lock_reg = CCU_SUN8I_A83T_LOCK_REG, .features = CCU_FEATURE_LOCK_REG | - CCU_FEATURE_FIXED_POSTDIV, + CCU_FEATURE_FIXED_POSTDIV | + CCU_FEATURE_SIGMA_DELTA_MOD, .hw.init = CLK_HW_INIT("pll-audio", "osc24M", &ccu_nm_ops, CLK_SET_RATE_UNGATE), }, -- cgit v1.2.3-58-ga151 From 70dad67ab1af7766ed046281eaed26d48a26916e Mon Sep 17 00:00:00 2001 From: Joel Stanley Date: Mon, 11 Dec 2017 15:24:37 +1030 Subject: dt-bindings: clock: Add ASPEED constants These will be used by the clock driver and device trees. Reviewed-by: Rob Herring Signed-off-by: Joel Stanley --- include/dt-bindings/clock/aspeed-clock.h | 52 ++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 include/dt-bindings/clock/aspeed-clock.h diff --git a/include/dt-bindings/clock/aspeed-clock.h b/include/dt-bindings/clock/aspeed-clock.h new file mode 100644 index 000000000000..d3558d897a4d --- /dev/null +++ b/include/dt-bindings/clock/aspeed-clock.h @@ -0,0 +1,52 @@ +/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */ + +#ifndef DT_BINDINGS_ASPEED_CLOCK_H +#define DT_BINDINGS_ASPEED_CLOCK_H + +#define ASPEED_CLK_GATE_ECLK 0 +#define ASPEED_CLK_GATE_GCLK 1 +#define ASPEED_CLK_GATE_MCLK 2 +#define ASPEED_CLK_GATE_VCLK 3 +#define ASPEED_CLK_GATE_BCLK 4 +#define ASPEED_CLK_GATE_DCLK 5 +#define ASPEED_CLK_GATE_REFCLK 6 +#define ASPEED_CLK_GATE_USBPORT2CLK 7 +#define ASPEED_CLK_GATE_LCLK 8 +#define ASPEED_CLK_GATE_USBUHCICLK 9 +#define ASPEED_CLK_GATE_D1CLK 10 +#define ASPEED_CLK_GATE_YCLK 11 +#define ASPEED_CLK_GATE_USBPORT1CLK 12 +#define ASPEED_CLK_GATE_UART1CLK 13 +#define ASPEED_CLK_GATE_UART2CLK 14 +#define ASPEED_CLK_GATE_UART5CLK 15 +#define ASPEED_CLK_GATE_ESPICLK 16 +#define ASPEED_CLK_GATE_MAC1CLK 17 +#define ASPEED_CLK_GATE_MAC2CLK 18 +#define ASPEED_CLK_GATE_RSACLK 19 +#define ASPEED_CLK_GATE_UART3CLK 20 +#define ASPEED_CLK_GATE_UART4CLK 21 +#define ASPEED_CLK_GATE_SDCLKCLK 22 +#define ASPEED_CLK_GATE_LHCCLK 23 +#define ASPEED_CLK_HPLL 24 +#define ASPEED_CLK_AHB 25 +#define ASPEED_CLK_APB 26 +#define ASPEED_CLK_UART 27 +#define ASPEED_CLK_SDIO 28 +#define ASPEED_CLK_ECLK 29 +#define ASPEED_CLK_ECLK_MUX 30 +#define ASPEED_CLK_LHCLK 31 +#define ASPEED_CLK_MAC 32 +#define ASPEED_CLK_BCLK 33 +#define ASPEED_CLK_MPLL 34 + +#define ASPEED_RESET_XDMA 0 +#define ASPEED_RESET_MCTP 1 +#define ASPEED_RESET_ADC 2 +#define ASPEED_RESET_JTAG_MASTER 3 +#define ASPEED_RESET_MIC 4 +#define ASPEED_RESET_PWM 5 +#define ASPEED_RESET_PCIVGA 6 +#define ASPEED_RESET_I2C 7 +#define ASPEED_RESET_AHB 8 + +#endif -- cgit v1.2.3-58-ga151 From 16a1ac19a0f00b1606bcac736145f497a1009707 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Wed, 20 Dec 2017 14:42:58 +0800 Subject: clk: mediatek: group drivers under indpendent menu Getting much MediaTek clock driver have been added to CCF, so it's better adding the cleanup for grouping drivers under the independent menu to simplify configuration selection. In addition, really trivial fixups for typos are added in the same patch. Signed-off-by: Sean Wang Signed-off-by: Stephen Boyd --- drivers/clk/mediatek/Kconfig | 96 +++++++++++++++++++++++--------------------- 1 file changed, 50 insertions(+), 46 deletions(-) diff --git a/drivers/clk/mediatek/Kconfig b/drivers/clk/mediatek/Kconfig index 59dc0aad553c..7338f816c603 100644 --- a/drivers/clk/mediatek/Kconfig +++ b/drivers/clk/mediatek/Kconfig @@ -1,136 +1,139 @@ # -# MediaTek SoC drivers +# MediaTek Clock Drivers # +menu "Clock driver for MediaTek SoC" + depends on ARCH_MEDIATEK || COMPILE_TEST + config COMMON_CLK_MEDIATEK bool ---help--- - Mediatek SoCs' clock support. + MediaTek SoCs' clock support. config COMMON_CLK_MT2701 - bool "Clock driver for Mediatek MT2701" + bool "Clock driver for MediaTek MT2701" depends on (ARCH_MEDIATEK && ARM) || COMPILE_TEST select COMMON_CLK_MEDIATEK default ARCH_MEDIATEK && ARM ---help--- - This driver supports Mediatek MT2701 basic clocks. + This driver supports MediaTek MT2701 basic clocks. config COMMON_CLK_MT2701_MMSYS - bool "Clock driver for Mediatek MT2701 mmsys" + bool "Clock driver for MediaTek MT2701 mmsys" depends on COMMON_CLK_MT2701 ---help--- - This driver supports Mediatek MT2701 mmsys clocks. + This driver supports MediaTek MT2701 mmsys clocks. config COMMON_CLK_MT2701_IMGSYS - bool "Clock driver for Mediatek MT2701 imgsys" + bool "Clock driver for MediaTek MT2701 imgsys" depends on COMMON_CLK_MT2701 ---help--- - This driver supports Mediatek MT2701 imgsys clocks. + This driver supports MediaTek MT2701 imgsys clocks. config COMMON_CLK_MT2701_VDECSYS - bool "Clock driver for Mediatek MT2701 vdecsys" + bool "Clock driver for MediaTek MT2701 vdecsys" depends on COMMON_CLK_MT2701 ---help--- - This driver supports Mediatek MT2701 vdecsys clocks. + This driver supports MediaTek MT2701 vdecsys clocks. config COMMON_CLK_MT2701_HIFSYS - bool "Clock driver for Mediatek MT2701 hifsys" + bool "Clock driver for MediaTek MT2701 hifsys" depends on COMMON_CLK_MT2701 ---help--- - This driver supports Mediatek MT2701 hifsys clocks. + This driver supports MediaTek MT2701 hifsys clocks. config COMMON_CLK_MT2701_ETHSYS - bool "Clock driver for Mediatek MT2701 ethsys" + bool "Clock driver for MediaTek MT2701 ethsys" depends on COMMON_CLK_MT2701 ---help--- - This driver supports Mediatek MT2701 ethsys clocks. + This driver supports MediaTek MT2701 ethsys clocks. config COMMON_CLK_MT2701_BDPSYS - bool "Clock driver for Mediatek MT2701 bdpsys" + bool "Clock driver for MediaTek MT2701 bdpsys" depends on COMMON_CLK_MT2701 ---help--- - This driver supports Mediatek MT2701 bdpsys clocks. + This driver supports MediaTek MT2701 bdpsys clocks. config COMMON_CLK_MT2712 - bool "Clock driver for Mediatek MT2712" + bool "Clock driver for MediaTek MT2712" depends on (ARCH_MEDIATEK && ARM64) || COMPILE_TEST select COMMON_CLK_MEDIATEK default ARCH_MEDIATEK && ARM64 ---help--- - This driver supports Mediatek MT2712 basic clocks. + This driver supports MediaTek MT2712 basic clocks. config COMMON_CLK_MT2712_BDPSYS - bool "Clock driver for Mediatek MT2712 bdpsys" + bool "Clock driver for MediaTek MT2712 bdpsys" depends on COMMON_CLK_MT2712 ---help--- - This driver supports Mediatek MT2712 bdpsys clocks. + This driver supports MediaTek MT2712 bdpsys clocks. config COMMON_CLK_MT2712_IMGSYS - bool "Clock driver for Mediatek MT2712 imgsys" + bool "Clock driver for MediaTek MT2712 imgsys" depends on COMMON_CLK_MT2712 ---help--- - This driver supports Mediatek MT2712 imgsys clocks. + This driver supports MediaTek MT2712 imgsys clocks. config COMMON_CLK_MT2712_JPGDECSYS - bool "Clock driver for Mediatek MT2712 jpgdecsys" + bool "Clock driver for MediaTek MT2712 jpgdecsys" depends on COMMON_CLK_MT2712 ---help--- - This driver supports Mediatek MT2712 jpgdecsys clocks. + This driver supports MediaTek MT2712 jpgdecsys clocks. config COMMON_CLK_MT2712_MFGCFG - bool "Clock driver for Mediatek MT2712 mfgcfg" + bool "Clock driver for MediaTek MT2712 mfgcfg" depends on COMMON_CLK_MT2712 ---help--- - This driver supports Mediatek MT2712 mfgcfg clocks. + This driver supports MediaTek MT2712 mfgcfg clocks. config COMMON_CLK_MT2712_MMSYS - bool "Clock driver for Mediatek MT2712 mmsys" + bool "Clock driver for MediaTek MT2712 mmsys" depends on COMMON_CLK_MT2712 ---help--- - This driver supports Mediatek MT2712 mmsys clocks. + This driver supports MediaTek MT2712 mmsys clocks. config COMMON_CLK_MT2712_VDECSYS - bool "Clock driver for Mediatek MT2712 vdecsys" + bool "Clock driver for MediaTek MT2712 vdecsys" depends on COMMON_CLK_MT2712 ---help--- - This driver supports Mediatek MT2712 vdecsys clocks. + This driver supports MediaTek MT2712 vdecsys clocks. config COMMON_CLK_MT2712_VENCSYS - bool "Clock driver for Mediatek MT2712 vencsys" + bool "Clock driver for MediaTek MT2712 vencsys" depends on COMMON_CLK_MT2712 ---help--- - This driver supports Mediatek MT2712 vencsys clocks. + This driver supports MediaTek MT2712 vencsys clocks. config COMMON_CLK_MT6797 - bool "Clock driver for Mediatek MT6797" + bool "Clock driver for MediaTek MT6797" depends on (ARCH_MEDIATEK && ARM64) || COMPILE_TEST select COMMON_CLK_MEDIATEK default ARCH_MEDIATEK && ARM64 ---help--- - This driver supports Mediatek MT6797 basic clocks. + This driver supports MediaTek MT6797 basic clocks. config COMMON_CLK_MT6797_MMSYS - bool "Clock driver for Mediatek MT6797 mmsys" + bool "Clock driver for MediaTek MT6797 mmsys" depends on COMMON_CLK_MT6797 ---help--- - This driver supports Mediatek MT6797 mmsys clocks. + This driver supports MediaTek MT6797 mmsys clocks. config COMMON_CLK_MT6797_IMGSYS - bool "Clock driver for Mediatek MT6797 imgsys" + bool "Clock driver for MediaTek MT6797 imgsys" depends on COMMON_CLK_MT6797 ---help--- - This driver supports Mediatek MT6797 imgsys clocks. + This driver supports MediaTek MT6797 imgsys clocks. config COMMON_CLK_MT6797_VDECSYS - bool "Clock driver for Mediatek MT6797 vdecsys" + bool "Clock driver for MediaTek MT6797 vdecsys" depends on COMMON_CLK_MT6797 ---help--- - This driver supports Mediatek MT6797 vdecsys clocks. + This driver supports MediaTek MT6797 vdecsys clocks. config COMMON_CLK_MT6797_VENCSYS - bool "Clock driver for Mediatek MT6797 vencsys" + bool "Clock driver for MediaTek MT6797 vencsys" depends on COMMON_CLK_MT6797 ---help--- - This driver supports Mediatek MT6797 vencsys clocks. + This driver supports MediaTek MT6797 vencsys clocks. config COMMON_CLK_MT7622 bool "Clock driver for MediaTek MT7622" @@ -163,17 +166,18 @@ config COMMON_CLK_MT7622_AUDSYS to audio consumers such as I2S and TDM. config COMMON_CLK_MT8135 - bool "Clock driver for Mediatek MT8135" + bool "Clock driver for MediaTek MT8135" depends on (ARCH_MEDIATEK && ARM) || COMPILE_TEST select COMMON_CLK_MEDIATEK default ARCH_MEDIATEK && ARM ---help--- - This driver supports Mediatek MT8135 clocks. + This driver supports MediaTek MT8135 clocks. config COMMON_CLK_MT8173 - bool "Clock driver for Mediatek MT8173" + bool "Clock driver for MediaTek MT8173" depends on ARCH_MEDIATEK || COMPILE_TEST select COMMON_CLK_MEDIATEK default ARCH_MEDIATEK ---help--- - This driver supports Mediatek MT8173 clocks. + This driver supports MediaTek MT8173 clocks. +endmenu -- cgit v1.2.3-58-ga151 From 74cb0d6dde85fef197aca3b2976487e99934309d Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Wed, 20 Dec 2017 14:42:59 +0800 Subject: clk: mediatek: fixup test-building of MediaTek clock drivers Let the build system looking into the directiory where the clock drivers resides for the COMPILE_TEST alternative dependency allows test-building the drivers. Signed-off-by: Sean Wang Signed-off-by: Stephen Boyd --- drivers/clk/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index f7f761b02bed..2e3fb08352a7 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -67,7 +67,7 @@ obj-$(CONFIG_ARCH_MXC) += imx/ obj-$(CONFIG_MACH_INGENIC) += ingenic/ obj-$(CONFIG_ARCH_KEYSTONE) += keystone/ obj-$(CONFIG_MACH_LOONGSON32) += loongson1/ -obj-$(CONFIG_ARCH_MEDIATEK) += mediatek/ +obj-y += mediatek/ obj-$(CONFIG_COMMON_CLK_AMLOGIC) += meson/ obj-$(CONFIG_MACH_PIC32) += microchip/ ifeq ($(CONFIG_COMMON_CLK), y) -- cgit v1.2.3-58-ga151 From 5589818b2fab09c4b7250865a6163c3e2f81a9d6 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Mon, 25 Dec 2017 16:03:57 +0800 Subject: clk: mediatek: Fix all warnings for missing struct clk_onecell_data Even though the header file linux/clk-provider.h is already being properly included in clk-mtk.h, the definition of struct clk_onecell_data still must depend on CONFIG_COMMON_CLK defined and thus it's possible that below build warnings occur when CONFIG_COMMON_CLK is not being selected. Therefore, these functions which need struct clk_onecell_data without declaring that structure first requires simply declaring that this struct exists prior to referencing it in clk-mtk.h Changes from v1->v2: enhance v1 based on two useful solutions Jean Delvare kindly suggested. All warnings (new ones prefixed by >>): In file included from drivers/clk/mediatek/reset.c:22:0: >>drivers/clk/mediatek/clk-mtk.h:44:19: warning: 'struct clk_onecell_data' declared inside parameter list will not be visible outside of this definition or declaration int num, struct clk_onecell_data *clk_data); ^~~~~~~~~~~~~~~~ drivers/clk/mediatek/clk-mtk.h:63:19: warning: 'struct clk_onecell_data' declared inside parameter list will not be visible outside of this definition or declaration int num, struct clk_onecell_data *clk_data); ^~~~~~~~~~~~~~~~ drivers/clk/mediatek/clk-mtk.h:145:10: warning: 'struct clk_onecell_data' declared inside parameter list will not be visible outside of this definition or declaration struct clk_onecell_data *clk_data); ^~~~~~~~~~~~~~~~ drivers/clk/mediatek/clk-mtk.h:164:11: warning: 'struct clk_onecell_data' declared inside parameter list will not be visible outside of this definition or declaration struct clk_onecell_data *clk_data); ^~~~~~~~~~~~~~~~ drivers/clk/mediatek/clk-mtk.h:190:12: warning: 'struct clk_onecell_data' declared inside parameter list will not be visible outside of this definition or declaration struct clk_onecell_data *clk_data); ^~~~~~~~~~~~~~~~ Reported-by: kbuild test robot Signed-off-by: Sean Wang Cc: kbuild-all@01.org Cc: Stephen Boyd Cc: Jean Delvare Cc: linux-clk@vger.kernel.org Signed-off-by: Stephen Boyd --- drivers/clk/mediatek/clk-mtk.h | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/mediatek/clk-mtk.h b/drivers/clk/mediatek/clk-mtk.h index f10250dcece4..bf8006d41861 100644 --- a/drivers/clk/mediatek/clk-mtk.h +++ b/drivers/clk/mediatek/clk-mtk.h @@ -20,6 +20,7 @@ #include struct clk; +struct clk_onecell_data; #define MAX_MUX_GATE_BIT 31 #define INVALID_MUX_GATE_BIT (MAX_MUX_GATE_BIT + 1) -- cgit v1.2.3-58-ga151 From 3525c7c3bd2b7b0b77bdb0ab46a7c5338e188a5a Mon Sep 17 00:00:00 2001 From: Icenowy Zheng Date: Fri, 22 Dec 2017 20:22:33 +0800 Subject: dt-bindings: fix the binding of Allwinner DE2 CCU of A83T and H3 The DE2 CCU is different on A83T and H3 -- the parent of the clocks on A83T is PLL_DE but on H3 it's the DE module clock. This is not noticed when I develop the DE2 CCU driver. Fix the binding by using different compatibles for A83T and H3, adding notes for the PLL_DE usage on A83T, and change the binding example's compatible from A83T to H3 (as it specifies the DE module clock). Fixes: ed74f8a8a679 ("dt-bindings: add binding for the Allwinner DE2 CCU") Signed-off-by: Icenowy Zheng Acked-by: Rob Herring Signed-off-by: Chen-Yu Tsai --- Documentation/devicetree/bindings/clock/sun8i-de2.txt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/clock/sun8i-de2.txt b/Documentation/devicetree/bindings/clock/sun8i-de2.txt index 631d27cd89d6..f2fa87c4765c 100644 --- a/Documentation/devicetree/bindings/clock/sun8i-de2.txt +++ b/Documentation/devicetree/bindings/clock/sun8i-de2.txt @@ -4,13 +4,14 @@ Allwinner Display Engine 2.0 Clock Control Binding Required properties : - compatible: must contain one of the following compatibles: - "allwinner,sun8i-a83t-de2-clk" + - "allwinner,sun8i-h3-de2-clk" - "allwinner,sun8i-v3s-de2-clk" - "allwinner,sun50i-h5-de2-clk" - reg: Must contain the registers base address and length - clocks: phandle to the clocks feeding the display engine subsystem. Three are needed: - - "mod": the display engine module clock + - "mod": the display engine module clock (on A83T it's the DE PLL) - "bus": the bus clock for the whole display engine subsystem - clock-names: Must contain the clock names described just above - resets: phandle to the reset control for the display engine subsystem. @@ -19,7 +20,7 @@ Required properties : Example: de2_clocks: clock@1000000 { - compatible = "allwinner,sun8i-a83t-de2-clk"; + compatible = "allwinner,sun8i-h3-de2-clk"; reg = <0x01000000 0x100000>; clocks = <&ccu CLK_BUS_DE>, <&ccu CLK_DE>; -- cgit v1.2.3-58-ga151 From 19368d99746e9fda90ab4a7decb148a9f65e3915 Mon Sep 17 00:00:00 2001 From: Icenowy Zheng Date: Fri, 22 Dec 2017 20:22:34 +0800 Subject: clk: sunxi-ng: add support for Allwinner H3 DE2 CCU Allwinner H3 features a DE2 CCU like the one on A83T, however the parent of the clocks is the DE module clock, not the PLL_DE clock. Add support for it. Signed-off-by: Icenowy Zheng Signed-off-by: Chen-Yu Tsai --- drivers/clk/sunxi-ng/ccu-sun8i-de2.c | 47 ++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-de2.c b/drivers/clk/sunxi-ng/ccu-sun8i-de2.c index 5cc9d9952121..2db5d4e00ea7 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-de2.c +++ b/drivers/clk/sunxi-ng/ccu-sun8i-de2.c @@ -41,6 +41,8 @@ static SUNXI_CCU_GATE(wb_clk, "wb", "wb-div", static SUNXI_CCU_M(mixer0_div_clk, "mixer0-div", "de", 0x0c, 0, 4, CLK_SET_RATE_PARENT); +static SUNXI_CCU_M(mixer1_div_clk, "mixer1-div", "de", 0x0c, 4, 4, + CLK_SET_RATE_PARENT); static SUNXI_CCU_M(wb_div_clk, "wb-div", "de", 0x0c, 8, 4, CLK_SET_RATE_PARENT); @@ -65,6 +67,20 @@ static struct ccu_common *sun8i_a83t_de2_clks[] = { &wb_div_a83_clk.common, }; +static struct ccu_common *sun8i_h3_de2_clks[] = { + &mixer0_clk.common, + &mixer1_clk.common, + &wb_clk.common, + + &bus_mixer0_clk.common, + &bus_mixer1_clk.common, + &bus_wb_clk.common, + + &mixer0_div_clk.common, + &mixer1_div_clk.common, + &wb_div_clk.common, +}; + static struct ccu_common *sun8i_v3s_de2_clks[] = { &mixer0_clk.common, &wb_clk.common, @@ -93,6 +109,23 @@ static struct clk_hw_onecell_data sun8i_a83t_de2_hw_clks = { .num = CLK_NUMBER, }; +static struct clk_hw_onecell_data sun8i_h3_de2_hw_clks = { + .hws = { + [CLK_MIXER0] = &mixer0_clk.common.hw, + [CLK_MIXER1] = &mixer1_clk.common.hw, + [CLK_WB] = &wb_clk.common.hw, + + [CLK_BUS_MIXER0] = &bus_mixer0_clk.common.hw, + [CLK_BUS_MIXER1] = &bus_mixer1_clk.common.hw, + [CLK_BUS_WB] = &bus_wb_clk.common.hw, + + [CLK_MIXER0_DIV] = &mixer0_div_clk.common.hw, + [CLK_MIXER1_DIV] = &mixer1_div_clk.common.hw, + [CLK_WB_DIV] = &wb_div_clk.common.hw, + }, + .num = CLK_NUMBER, +}; + static struct clk_hw_onecell_data sun8i_v3s_de2_hw_clks = { .hws = { [CLK_MIXER0] = &mixer0_clk.common.hw, @@ -133,6 +166,16 @@ static const struct sunxi_ccu_desc sun8i_a83t_de2_clk_desc = { .num_resets = ARRAY_SIZE(sun8i_a83t_de2_resets), }; +static const struct sunxi_ccu_desc sun8i_h3_de2_clk_desc = { + .ccu_clks = sun8i_h3_de2_clks, + .num_ccu_clks = ARRAY_SIZE(sun8i_h3_de2_clks), + + .hw_clks = &sun8i_h3_de2_hw_clks, + + .resets = sun8i_a83t_de2_resets, + .num_resets = ARRAY_SIZE(sun8i_a83t_de2_resets), +}; + static const struct sunxi_ccu_desc sun50i_a64_de2_clk_desc = { .ccu_clks = sun8i_a83t_de2_clks, .num_ccu_clks = ARRAY_SIZE(sun8i_a83t_de2_clks), @@ -237,6 +280,10 @@ static const struct of_device_id sunxi_de2_clk_ids[] = { .compatible = "allwinner,sun8i-a83t-de2-clk", .data = &sun8i_a83t_de2_clk_desc, }, + { + .compatible = "allwinner,sun8i-h3-de2-clk", + .data = &sun8i_h3_de2_clk_desc, + }, { .compatible = "allwinner,sun8i-v3s-de2-clk", .data = &sun8i_v3s_de2_clk_desc, -- cgit v1.2.3-58-ga151 From cf4881c1293516c1975606e8f2af7948789168b8 Mon Sep 17 00:00:00 2001 From: Icenowy Zheng Date: Fri, 22 Dec 2017 20:22:35 +0800 Subject: clk: sunxi-ng: fix the A64/H5 clock description of DE2 CCU The clocks of A64/H5 SoCs in the DE2 CCU is the same as the clocks in H3 DE2 CCU rather than the A83T DE2 CCU (the parent of them is the DE module clock). Fix this by change the clock descriptions to use the clocks of H3. Fixes: 763c5bd045b1 ("clk: sunxi-ng: add support for DE2 CCU") Signed-off-by: Icenowy Zheng Signed-off-by: Chen-Yu Tsai --- drivers/clk/sunxi-ng/ccu-sun8i-de2.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-de2.c b/drivers/clk/sunxi-ng/ccu-sun8i-de2.c index 2db5d4e00ea7..468d1abaf0ee 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-de2.c +++ b/drivers/clk/sunxi-ng/ccu-sun8i-de2.c @@ -177,10 +177,10 @@ static const struct sunxi_ccu_desc sun8i_h3_de2_clk_desc = { }; static const struct sunxi_ccu_desc sun50i_a64_de2_clk_desc = { - .ccu_clks = sun8i_a83t_de2_clks, - .num_ccu_clks = ARRAY_SIZE(sun8i_a83t_de2_clks), + .ccu_clks = sun8i_h3_de2_clks, + .num_ccu_clks = ARRAY_SIZE(sun8i_h3_de2_clks), - .hw_clks = &sun8i_a83t_de2_hw_clks, + .hw_clks = &sun8i_h3_de2_hw_clks, .resets = sun50i_a64_de2_resets, .num_resets = ARRAY_SIZE(sun50i_a64_de2_resets), -- cgit v1.2.3-58-ga151 From 7dbc7f5f4904cfddc199af171ea095490a434f15 Mon Sep 17 00:00:00 2001 From: Jernej Škrabec Date: Sat, 30 Dec 2017 22:01:54 +0100 Subject: clk: sunxi-ng: a83t: Add M divider to TCON1 clock TCON1 also has M divider, contrary to TCON0. And the mux is only 2 bits wide, instead of 3. Fixes: 05359be1176b ("clk: sunxi-ng: Add driver for A83T CCU") Signed-off-by: Jernej Skrabec [wens@csie.org: Add description about mux width difference] Signed-off-by: Chen-Yu Tsai --- drivers/clk/sunxi-ng/ccu-sun8i-a83t.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-a83t.c b/drivers/clk/sunxi-ng/ccu-sun8i-a83t.c index 04a9c33f53f0..7d08015b980d 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-a83t.c +++ b/drivers/clk/sunxi-ng/ccu-sun8i-a83t.c @@ -504,8 +504,8 @@ static SUNXI_CCU_MUX_WITH_GATE(tcon0_clk, "tcon0", tcon0_parents, 0x118, 24, 3, BIT(31), CLK_SET_RATE_PARENT); static const char * const tcon1_parents[] = { "pll-video1" }; -static SUNXI_CCU_MUX_WITH_GATE(tcon1_clk, "tcon1", tcon1_parents, - 0x11c, 24, 3, BIT(31), CLK_SET_RATE_PARENT); +static SUNXI_CCU_M_WITH_MUX_GATE(tcon1_clk, "tcon1", tcon1_parents, + 0x11c, 0, 4, 24, 2, BIT(31), CLK_SET_RATE_PARENT); static SUNXI_CCU_GATE(csi_misc_clk, "csi-misc", "osc24M", 0x130, BIT(16), 0); -- cgit v1.2.3-58-ga151 From a12aa8a68dfef5de181f2e555aa950a0ab05411f Mon Sep 17 00:00:00 2001 From: David Lechner Date: Thu, 4 Jan 2018 19:46:08 -0600 Subject: clk: fix reentrancy of clk_enable() on UP systems Reentrant calls to clk_enable() are not working on UP systems. This is caused by the fact spin_trylock_irqsave() always returns true when CONFIG_SMP=n (and CONFIG_DEBUG_SPINLOCK=n) which causes the reference counting to not work correctly when clk_enable_lock() is called twice before clk_enable_unlock() is called (this happens when clk_enable() is called from within another clk_enable()). This fixes the problem by skipping the call to spin_trylock_irqsave() on UP systems and relying solely on reference counting. We also make sure to set flags in this case so that we are not returning an uninitialized value. Suggested-by: Stephen Boyd Signed-off-by: David Lechner Signed-off-by: Stephen Boyd --- drivers/clk/clk.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 647d056df88c..b221d80cc7ba 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -141,10 +141,18 @@ static unsigned long clk_enable_lock(void) { unsigned long flags; - if (!spin_trylock_irqsave(&enable_lock, flags)) { + /* + * On UP systems, spin_trylock_irqsave() always returns true, even if + * we already hold the lock. So, in that case, we rely only on + * reference counting. + */ + if (!IS_ENABLED(CONFIG_SMP) || + !spin_trylock_irqsave(&enable_lock, flags)) { if (enable_owner == current) { enable_refcnt++; __acquire(enable_lock); + if (!IS_ENABLED(CONFIG_SMP)) + local_save_flags(flags); return flags; } spin_lock_irqsave(&enable_lock, flags); -- cgit v1.2.3-58-ga151 From bc27360b3c7aedfc385f7fc0527a42918bdeba51 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Fri, 5 Jan 2018 16:14:06 +0800 Subject: clk: mediatek: adjust dependency of reset.c to avoid unexpectedly being built Changes from v1->v2: Add 'select RESET_CONTROLLER' under COMMON_CLK_MEDIATEK and enable reset.c to be built when COMMON_CLK_MEDIATEK is selected. That should be quite reasonable because the reset controller is tightly embedded inside and exported from these clock subsystems. At least it can be found on infracfg and pericfg subsystem that both are really fundamental block lots of devices must depend on. commit 74cb0d6dde8 ("clk: mediatek: fixup test-building of MediaTek clock drivers") can let the build system looking into the directory where the clock drivers resides and then allow test-building the drivers. But the change also gives rise to certain incorrect behavior which is reset.c being built even not depending on either COMPILE_TEST or ARCH_MEDIATEK alternative dependency. To get rid of reset.c being built unexpectedly on the other platforms, it would be a good change that the file should be built depending on its own specific configuration rather than just on generic RESET_CONTROLLER one. Signed-off-by: Sean Wang Cc: Jean Delvare Signed-off-by: Stephen Boyd --- drivers/clk/mediatek/Kconfig | 1 + drivers/clk/mediatek/Makefile | 3 +-- drivers/clk/mediatek/clk-mtk.h | 7 ------- 3 files changed, 2 insertions(+), 9 deletions(-) diff --git a/drivers/clk/mediatek/Kconfig b/drivers/clk/mediatek/Kconfig index 7338f816c603..1f9ea0f21df1 100644 --- a/drivers/clk/mediatek/Kconfig +++ b/drivers/clk/mediatek/Kconfig @@ -6,6 +6,7 @@ menu "Clock driver for MediaTek SoC" config COMMON_CLK_MEDIATEK bool + select RESET_CONTROLLER ---help--- MediaTek SoCs' clock support. diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile index c421ffcd49ff..5160fdc4bbb8 100644 --- a/drivers/clk/mediatek/Makefile +++ b/drivers/clk/mediatek/Makefile @@ -1,6 +1,5 @@ # SPDX-License-Identifier: GPL-2.0 -obj-$(CONFIG_COMMON_CLK_MEDIATEK) += clk-mtk.o clk-pll.o clk-gate.o clk-apmixed.o clk-cpumux.o -obj-$(CONFIG_RESET_CONTROLLER) += reset.o +obj-$(CONFIG_COMMON_CLK_MEDIATEK) += clk-mtk.o clk-pll.o clk-gate.o clk-apmixed.o clk-cpumux.o reset.o obj-$(CONFIG_COMMON_CLK_MT6797) += clk-mt6797.o obj-$(CONFIG_COMMON_CLK_MT6797_IMGSYS) += clk-mt6797-img.o obj-$(CONFIG_COMMON_CLK_MT6797_MMSYS) += clk-mt6797-mm.o diff --git a/drivers/clk/mediatek/clk-mtk.h b/drivers/clk/mediatek/clk-mtk.h index bf8006d41861..f83c2bbb677e 100644 --- a/drivers/clk/mediatek/clk-mtk.h +++ b/drivers/clk/mediatek/clk-mtk.h @@ -229,14 +229,7 @@ void mtk_clk_register_plls(struct device_node *node, struct clk *mtk_clk_register_ref2usb_tx(const char *name, const char *parent_name, void __iomem *reg); -#ifdef CONFIG_RESET_CONTROLLER void mtk_register_reset_controller(struct device_node *np, unsigned int num_regs, int regofs); -#else -static inline void mtk_register_reset_controller(struct device_node *np, - unsigned int num_regs, int regofs) -{ -} -#endif #endif /* __DRV_CLK_MTK_H */ -- cgit v1.2.3-58-ga151 From 5eda5d79e4be347758df5d502df2f4ddcfc2a701 Mon Sep 17 00:00:00 2001 From: Joel Stanley Date: Fri, 22 Dec 2017 13:15:18 +1030 Subject: clk: Add clock driver for ASPEED BMC SoCs This adds the stub of a driver for the ASPEED SoCs. The clocks are defined and the static registration is set up. Reviewed-by: Andrew Jeffery Signed-off-by: Joel Stanley Reviewed-by: Benjamin Herrenschmidt Signed-off-by: Stephen Boyd --- drivers/clk/Kconfig | 12 ++++ drivers/clk/Makefile | 1 + drivers/clk/clk-aspeed.c | 141 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 154 insertions(+) create mode 100644 drivers/clk/clk-aspeed.c diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index 1c4e1aa6767e..9abe063ef8d2 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -142,6 +142,18 @@ config COMMON_CLK_GEMINI This driver supports the SoC clocks on the Cortina Systems Gemini platform, also known as SL3516 or CS3516. +config COMMON_CLK_ASPEED + bool "Clock driver for Aspeed BMC SoCs" + depends on ARCH_ASPEED || COMPILE_TEST + default ARCH_ASPEED + select MFD_SYSCON + select RESET_CONTROLLER + ---help--- + This driver supports the SoC clocks on the Aspeed BMC platforms. + + The G4 and G5 series, including the ast2400 and ast2500, are supported + by this driver. + config COMMON_CLK_S2MPS11 tristate "Clock driver for S2MPS1X/S5M8767 MFD" depends on MFD_SEC_CORE || COMPILE_TEST diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index f7f761b02bed..d260da4809f8 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -27,6 +27,7 @@ obj-$(CONFIG_ARCH_CLPS711X) += clk-clps711x.o obj-$(CONFIG_COMMON_CLK_CS2000_CP) += clk-cs2000-cp.o obj-$(CONFIG_ARCH_EFM32) += clk-efm32gg.o obj-$(CONFIG_COMMON_CLK_GEMINI) += clk-gemini.o +obj-$(CONFIG_COMMON_CLK_ASPEED) += clk-aspeed.o obj-$(CONFIG_ARCH_HIGHBANK) += clk-highbank.o obj-$(CONFIG_CLK_HSDK) += clk-hsdk-pll.o obj-$(CONFIG_COMMON_CLK_MAX77686) += clk-max77686.o diff --git a/drivers/clk/clk-aspeed.c b/drivers/clk/clk-aspeed.c new file mode 100644 index 000000000000..7a86ee08ea4f --- /dev/null +++ b/drivers/clk/clk-aspeed.c @@ -0,0 +1,141 @@ +// SPDX-License-Identifier: GPL-2.0+ + +#define pr_fmt(fmt) "clk-aspeed: " fmt + +#include +#include +#include +#include +#include +#include + +#include + +#define ASPEED_NUM_CLKS 35 + +#define ASPEED_STRAP 0x70 + +/* Keeps track of all clocks */ +static struct clk_hw_onecell_data *aspeed_clk_data; + +static void __iomem *scu_base; + +/** + * struct aspeed_gate_data - Aspeed gated clocks + * @clock_idx: bit used to gate this clock in the clock register + * @reset_idx: bit used to reset this IP in the reset register. -1 if no + * reset is required when enabling the clock + * @name: the clock name + * @parent_name: the name of the parent clock + * @flags: standard clock framework flags + */ +struct aspeed_gate_data { + u8 clock_idx; + s8 reset_idx; + const char *name; + const char *parent_name; + unsigned long flags; +}; + +/** + * struct aspeed_clk_gate - Aspeed specific clk_gate structure + * @hw: handle between common and hardware-specific interfaces + * @reg: register controlling gate + * @clock_idx: bit used to gate this clock in the clock register + * @reset_idx: bit used to reset this IP in the reset register. -1 if no + * reset is required when enabling the clock + * @flags: hardware-specific flags + * @lock: register lock + * + * Some of the clocks in the Aspeed SoC must be put in reset before enabling. + * This modified version of clk_gate allows an optional reset bit to be + * specified. + */ +struct aspeed_clk_gate { + struct clk_hw hw; + struct regmap *map; + u8 clock_idx; + s8 reset_idx; + u8 flags; + spinlock_t *lock; +}; + +#define to_aspeed_clk_gate(_hw) container_of(_hw, struct aspeed_clk_gate, hw) + +/* TODO: ask Aspeed about the actual parent data */ +static const struct aspeed_gate_data aspeed_gates[] = { + /* clk rst name parent flags */ + [ASPEED_CLK_GATE_ECLK] = { 0, -1, "eclk-gate", "eclk", 0 }, /* Video Engine */ + [ASPEED_CLK_GATE_GCLK] = { 1, 7, "gclk-gate", NULL, 0 }, /* 2D engine */ + [ASPEED_CLK_GATE_MCLK] = { 2, -1, "mclk-gate", "mpll", CLK_IS_CRITICAL }, /* SDRAM */ + [ASPEED_CLK_GATE_VCLK] = { 3, 6, "vclk-gate", NULL, 0 }, /* Video Capture */ + [ASPEED_CLK_GATE_BCLK] = { 4, 10, "bclk-gate", "bclk", 0 }, /* PCIe/PCI */ + [ASPEED_CLK_GATE_DCLK] = { 5, -1, "dclk-gate", NULL, 0 }, /* DAC */ + [ASPEED_CLK_GATE_REFCLK] = { 6, -1, "refclk-gate", "clkin", CLK_IS_CRITICAL }, + [ASPEED_CLK_GATE_USBPORT2CLK] = { 7, 3, "usb-port2-gate", NULL, 0 }, /* USB2.0 Host port 2 */ + [ASPEED_CLK_GATE_LCLK] = { 8, 5, "lclk-gate", NULL, 0 }, /* LPC */ + [ASPEED_CLK_GATE_USBUHCICLK] = { 9, 15, "usb-uhci-gate", NULL, 0 }, /* USB1.1 (requires port 2 enabled) */ + [ASPEED_CLK_GATE_D1CLK] = { 10, 13, "d1clk-gate", NULL, 0 }, /* GFX CRT */ + [ASPEED_CLK_GATE_YCLK] = { 13, 4, "yclk-gate", NULL, 0 }, /* HAC */ + [ASPEED_CLK_GATE_USBPORT1CLK] = { 14, 14, "usb-port1-gate", NULL, 0 }, /* USB2 hub/USB2 host port 1/USB1.1 dev */ + [ASPEED_CLK_GATE_UART1CLK] = { 15, -1, "uart1clk-gate", "uart", 0 }, /* UART1 */ + [ASPEED_CLK_GATE_UART2CLK] = { 16, -1, "uart2clk-gate", "uart", 0 }, /* UART2 */ + [ASPEED_CLK_GATE_UART5CLK] = { 17, -1, "uart5clk-gate", "uart", 0 }, /* UART5 */ + [ASPEED_CLK_GATE_ESPICLK] = { 19, -1, "espiclk-gate", NULL, 0 }, /* eSPI */ + [ASPEED_CLK_GATE_MAC1CLK] = { 20, 11, "mac1clk-gate", "mac", 0 }, /* MAC1 */ + [ASPEED_CLK_GATE_MAC2CLK] = { 21, 12, "mac2clk-gate", "mac", 0 }, /* MAC2 */ + [ASPEED_CLK_GATE_RSACLK] = { 24, -1, "rsaclk-gate", NULL, 0 }, /* RSA */ + [ASPEED_CLK_GATE_UART3CLK] = { 25, -1, "uart3clk-gate", "uart", 0 }, /* UART3 */ + [ASPEED_CLK_GATE_UART4CLK] = { 26, -1, "uart4clk-gate", "uart", 0 }, /* UART4 */ + [ASPEED_CLK_GATE_SDCLKCLK] = { 27, 16, "sdclk-gate", NULL, 0 }, /* SDIO/SD */ + [ASPEED_CLK_GATE_LHCCLK] = { 28, -1, "lhclk-gate", "lhclk", 0 }, /* LPC master/LPC+ */ +}; + +static void __init aspeed_cc_init(struct device_node *np) +{ + struct regmap *map; + u32 val; + int ret; + int i; + + scu_base = of_iomap(np, 0); + if (IS_ERR(scu_base)) + return; + + aspeed_clk_data = kzalloc(sizeof(*aspeed_clk_data) + + sizeof(*aspeed_clk_data->hws) * ASPEED_NUM_CLKS, + GFP_KERNEL); + if (!aspeed_clk_data) + return; + + /* + * This way all clocks fetched before the platform device probes, + * except those we assign here for early use, will be deferred. + */ + for (i = 0; i < ASPEED_NUM_CLKS; i++) + aspeed_clk_data->hws[i] = ERR_PTR(-EPROBE_DEFER); + + map = syscon_node_to_regmap(np); + if (IS_ERR(map)) { + pr_err("no syscon regmap\n"); + return; + } + /* + * We check that the regmap works on this very first access, + * but as this is an MMIO-backed regmap, subsequent regmap + * access is not going to fail and we skip error checks from + * this point. + */ + ret = regmap_read(map, ASPEED_STRAP, &val); + if (ret) { + pr_err("failed to read strapping register\n"); + return; + } + + aspeed_clk_data->num = ASPEED_NUM_CLKS; + ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, aspeed_clk_data); + if (ret) + pr_err("failed to add DT provider: %d\n", ret); +}; +CLK_OF_DECLARE_DRIVER(aspeed_cc_g5, "aspeed,ast2500-scu", aspeed_cc_init); +CLK_OF_DECLARE_DRIVER(aspeed_cc_g4, "aspeed,ast2400-scu", aspeed_cc_init); -- cgit v1.2.3-58-ga151 From 99d01e0ec3415424210fcd345ebb0c516e4b7fa9 Mon Sep 17 00:00:00 2001 From: Joel Stanley Date: Fri, 22 Dec 2017 13:15:19 +1030 Subject: clk: aspeed: Register core clocks This registers the core clocks; those which are required to calculate the rate of the timer peripheral so the system can load a clocksource driver. Reviewed-by: Andrew Jeffery Signed-off-by: Joel Stanley Reviewed-by: Benjamin Herrenschmidt Signed-off-by: Stephen Boyd --- drivers/clk/clk-aspeed.c | 177 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 177 insertions(+) diff --git a/drivers/clk/clk-aspeed.c b/drivers/clk/clk-aspeed.c index 7a86ee08ea4f..5adedda82d26 100644 --- a/drivers/clk/clk-aspeed.c +++ b/drivers/clk/clk-aspeed.c @@ -13,7 +13,23 @@ #define ASPEED_NUM_CLKS 35 +#define ASPEED_RESET_CTRL 0x04 +#define ASPEED_CLK_SELECTION 0x08 +#define ASPEED_CLK_STOP_CTRL 0x0c +#define ASPEED_MPLL_PARAM 0x20 +#define ASPEED_HPLL_PARAM 0x24 +#define AST2500_HPLL_BYPASS_EN BIT(20) +#define AST2400_HPLL_STRAPPED BIT(18) +#define AST2400_HPLL_BYPASS_EN BIT(17) +#define ASPEED_MISC_CTRL 0x2c +#define UART_DIV13_EN BIT(12) #define ASPEED_STRAP 0x70 +#define CLKIN_25MHZ_EN BIT(23) +#define AST2400_CLK_SOURCE_SEL BIT(18) +#define ASPEED_CLK_SELECTION_2 0xd8 + +/* Globally visible clocks */ +static DEFINE_SPINLOCK(aspeed_clk_lock); /* Keeps track of all clocks */ static struct clk_hw_onecell_data *aspeed_clk_data; @@ -91,6 +107,160 @@ static const struct aspeed_gate_data aspeed_gates[] = { [ASPEED_CLK_GATE_LHCCLK] = { 28, -1, "lhclk-gate", "lhclk", 0 }, /* LPC master/LPC+ */ }; +static const struct clk_div_table ast2400_div_table[] = { + { 0x0, 2 }, + { 0x1, 4 }, + { 0x2, 6 }, + { 0x3, 8 }, + { 0x4, 10 }, + { 0x5, 12 }, + { 0x6, 14 }, + { 0x7, 16 }, + { 0 } +}; + +static const struct clk_div_table ast2500_div_table[] = { + { 0x0, 4 }, + { 0x1, 8 }, + { 0x2, 12 }, + { 0x3, 16 }, + { 0x4, 20 }, + { 0x5, 24 }, + { 0x6, 28 }, + { 0x7, 32 }, + { 0 } +}; + +static struct clk_hw *aspeed_ast2400_calc_pll(const char *name, u32 val) +{ + unsigned int mult, div; + + if (val & AST2400_HPLL_BYPASS_EN) { + /* Pass through mode */ + mult = div = 1; + } else { + /* F = 24Mhz * (2-OD) * [(N + 2) / (D + 1)] */ + u32 n = (val >> 5) & 0x3f; + u32 od = (val >> 4) & 0x1; + u32 d = val & 0xf; + + mult = (2 - od) * (n + 2); + div = d + 1; + } + return clk_hw_register_fixed_factor(NULL, name, "clkin", 0, + mult, div); +}; + +static struct clk_hw *aspeed_ast2500_calc_pll(const char *name, u32 val) +{ + unsigned int mult, div; + + if (val & AST2500_HPLL_BYPASS_EN) { + /* Pass through mode */ + mult = div = 1; + } else { + /* F = clkin * [(M+1) / (N+1)] / (P + 1) */ + u32 p = (val >> 13) & 0x3f; + u32 m = (val >> 5) & 0xff; + u32 n = val & 0x1f; + + mult = (m + 1) / (n + 1); + div = p + 1; + } + + return clk_hw_register_fixed_factor(NULL, name, "clkin", 0, + mult, div); +} + +static void __init aspeed_ast2400_cc(struct regmap *map) +{ + struct clk_hw *hw; + u32 val, freq, div; + + /* + * CLKIN is the crystal oscillator, 24, 48 or 25MHz selected by + * strapping + */ + regmap_read(map, ASPEED_STRAP, &val); + if (val & CLKIN_25MHZ_EN) + freq = 25000000; + else if (val & AST2400_CLK_SOURCE_SEL) + freq = 48000000; + else + freq = 24000000; + hw = clk_hw_register_fixed_rate(NULL, "clkin", NULL, 0, freq); + pr_debug("clkin @%u MHz\n", freq / 1000000); + + /* + * High-speed PLL clock derived from the crystal. This the CPU clock, + * and we assume that it is enabled + */ + regmap_read(map, ASPEED_HPLL_PARAM, &val); + WARN(val & AST2400_HPLL_STRAPPED, "hpll is strapped not configured"); + aspeed_clk_data->hws[ASPEED_CLK_HPLL] = aspeed_ast2400_calc_pll("hpll", val); + + /* + * Strap bits 11:10 define the CPU/AHB clock frequency ratio (aka HCLK) + * 00: Select CPU:AHB = 1:1 + * 01: Select CPU:AHB = 2:1 + * 10: Select CPU:AHB = 4:1 + * 11: Select CPU:AHB = 3:1 + */ + regmap_read(map, ASPEED_STRAP, &val); + val = (val >> 10) & 0x3; + div = val + 1; + if (div == 3) + div = 4; + else if (div == 4) + div = 3; + hw = clk_hw_register_fixed_factor(NULL, "ahb", "hpll", 0, 1, div); + aspeed_clk_data->hws[ASPEED_CLK_AHB] = hw; + + /* APB clock clock selection register SCU08 (aka PCLK) */ + hw = clk_hw_register_divider_table(NULL, "apb", "hpll", 0, + scu_base + ASPEED_CLK_SELECTION, 23, 3, 0, + ast2400_div_table, + &aspeed_clk_lock); + aspeed_clk_data->hws[ASPEED_CLK_APB] = hw; +} + +static void __init aspeed_ast2500_cc(struct regmap *map) +{ + struct clk_hw *hw; + u32 val, freq, div; + + /* CLKIN is the crystal oscillator, 24 or 25MHz selected by strapping */ + regmap_read(map, ASPEED_STRAP, &val); + if (val & CLKIN_25MHZ_EN) + freq = 25000000; + else + freq = 24000000; + hw = clk_hw_register_fixed_rate(NULL, "clkin", NULL, 0, freq); + pr_debug("clkin @%u MHz\n", freq / 1000000); + + /* + * High-speed PLL clock derived from the crystal. This the CPU clock, + * and we assume that it is enabled + */ + regmap_read(map, ASPEED_HPLL_PARAM, &val); + aspeed_clk_data->hws[ASPEED_CLK_HPLL] = aspeed_ast2500_calc_pll("hpll", val); + + /* Strap bits 11:9 define the AXI/AHB clock frequency ratio (aka HCLK)*/ + regmap_read(map, ASPEED_STRAP, &val); + val = (val >> 9) & 0x7; + WARN(val == 0, "strapping is zero: cannot determine ahb clock"); + div = 2 * (val + 1); + hw = clk_hw_register_fixed_factor(NULL, "ahb", "hpll", 0, 1, div); + aspeed_clk_data->hws[ASPEED_CLK_AHB] = hw; + + /* APB clock clock selection register SCU08 (aka PCLK) */ + regmap_read(map, ASPEED_CLK_SELECTION, &val); + val = (val >> 23) & 0x7; + div = 4 * (val + 1); + hw = clk_hw_register_fixed_factor(NULL, "apb", "hpll", 0, 1, div); + aspeed_clk_data->hws[ASPEED_CLK_APB] = hw; +}; + static void __init aspeed_cc_init(struct device_node *np) { struct regmap *map; @@ -132,6 +302,13 @@ static void __init aspeed_cc_init(struct device_node *np) return; } + if (of_device_is_compatible(np, "aspeed,ast2400-scu")) + aspeed_ast2400_cc(map); + else if (of_device_is_compatible(np, "aspeed,ast2500-scu")) + aspeed_ast2500_cc(map); + else + pr_err("unknown platform, failed to add clocks\n"); + aspeed_clk_data->num = ASPEED_NUM_CLKS; ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, aspeed_clk_data); if (ret) -- cgit v1.2.3-58-ga151 From 98f3118debb3876399a8da59d72b4908431f1027 Mon Sep 17 00:00:00 2001 From: Joel Stanley Date: Fri, 22 Dec 2017 13:15:20 +1030 Subject: clk: aspeed: Add platform driver and register PLLs This registers a platform driver to set up all of the non-core clocks. The clocks that have configurable rates are now registered. Reviewed-by: Andrew Jeffery Signed-off-by: Joel Stanley Reviewed-by: Benjamin Herrenschmidt Signed-off-by: Stephen Boyd --- drivers/clk/clk-aspeed.c | 130 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 130 insertions(+) diff --git a/drivers/clk/clk-aspeed.c b/drivers/clk/clk-aspeed.c index 5adedda82d26..cf5ea63feb31 100644 --- a/drivers/clk/clk-aspeed.c +++ b/drivers/clk/clk-aspeed.c @@ -5,6 +5,8 @@ #include #include #include +#include +#include #include #include #include @@ -107,6 +109,18 @@ static const struct aspeed_gate_data aspeed_gates[] = { [ASPEED_CLK_GATE_LHCCLK] = { 28, -1, "lhclk-gate", "lhclk", 0 }, /* LPC master/LPC+ */ }; +static const struct clk_div_table ast2500_mac_div_table[] = { + { 0x0, 4 }, /* Yep, really. Aspeed confirmed this is correct */ + { 0x1, 4 }, + { 0x2, 6 }, + { 0x3, 8 }, + { 0x4, 10 }, + { 0x5, 12 }, + { 0x6, 14 }, + { 0x7, 16 }, + { 0 } +}; + static const struct clk_div_table ast2400_div_table[] = { { 0x0, 2 }, { 0x1, 4 }, @@ -172,6 +186,122 @@ static struct clk_hw *aspeed_ast2500_calc_pll(const char *name, u32 val) mult, div); } +struct aspeed_clk_soc_data { + const struct clk_div_table *div_table; + const struct clk_div_table *mac_div_table; + struct clk_hw *(*calc_pll)(const char *name, u32 val); +}; + +static const struct aspeed_clk_soc_data ast2500_data = { + .div_table = ast2500_div_table, + .mac_div_table = ast2500_mac_div_table, + .calc_pll = aspeed_ast2500_calc_pll, +}; + +static const struct aspeed_clk_soc_data ast2400_data = { + .div_table = ast2400_div_table, + .mac_div_table = ast2400_div_table, + .calc_pll = aspeed_ast2400_calc_pll, +}; + +static int aspeed_clk_probe(struct platform_device *pdev) +{ + const struct aspeed_clk_soc_data *soc_data; + struct device *dev = &pdev->dev; + struct regmap *map; + struct clk_hw *hw; + u32 val, rate; + + map = syscon_node_to_regmap(dev->of_node); + if (IS_ERR(map)) { + dev_err(dev, "no syscon regmap\n"); + return PTR_ERR(map); + } + + /* SoC generations share common layouts but have different divisors */ + soc_data = of_device_get_match_data(dev); + if (!soc_data) { + dev_err(dev, "no match data for platform\n"); + return -EINVAL; + } + + /* UART clock div13 setting */ + regmap_read(map, ASPEED_MISC_CTRL, &val); + if (val & UART_DIV13_EN) + rate = 24000000 / 13; + else + rate = 24000000; + /* TODO: Find the parent data for the uart clock */ + hw = clk_hw_register_fixed_rate(dev, "uart", NULL, 0, rate); + if (IS_ERR(hw)) + return PTR_ERR(hw); + aspeed_clk_data->hws[ASPEED_CLK_UART] = hw; + + /* + * Memory controller (M-PLL) PLL. This clock is configured by the + * bootloader, and is exposed to Linux as a read-only clock rate. + */ + regmap_read(map, ASPEED_MPLL_PARAM, &val); + hw = soc_data->calc_pll("mpll", val); + if (IS_ERR(hw)) + return PTR_ERR(hw); + aspeed_clk_data->hws[ASPEED_CLK_MPLL] = hw; + + /* SD/SDIO clock divider (TODO: There's a gate too) */ + hw = clk_hw_register_divider_table(dev, "sdio", "hpll", 0, + scu_base + ASPEED_CLK_SELECTION, 12, 3, 0, + soc_data->div_table, + &aspeed_clk_lock); + if (IS_ERR(hw)) + return PTR_ERR(hw); + aspeed_clk_data->hws[ASPEED_CLK_SDIO] = hw; + + /* MAC AHB bus clock divider */ + hw = clk_hw_register_divider_table(dev, "mac", "hpll", 0, + scu_base + ASPEED_CLK_SELECTION, 16, 3, 0, + soc_data->mac_div_table, + &aspeed_clk_lock); + if (IS_ERR(hw)) + return PTR_ERR(hw); + aspeed_clk_data->hws[ASPEED_CLK_MAC] = hw; + + /* LPC Host (LHCLK) clock divider */ + hw = clk_hw_register_divider_table(dev, "lhclk", "hpll", 0, + scu_base + ASPEED_CLK_SELECTION, 20, 3, 0, + soc_data->div_table, + &aspeed_clk_lock); + if (IS_ERR(hw)) + return PTR_ERR(hw); + aspeed_clk_data->hws[ASPEED_CLK_LHCLK] = hw; + + /* P-Bus (BCLK) clock divider */ + hw = clk_hw_register_divider_table(dev, "bclk", "hpll", 0, + scu_base + ASPEED_CLK_SELECTION_2, 0, 2, 0, + soc_data->div_table, + &aspeed_clk_lock); + if (IS_ERR(hw)) + return PTR_ERR(hw); + aspeed_clk_data->hws[ASPEED_CLK_BCLK] = hw; + + return 0; +}; + +static const struct of_device_id aspeed_clk_dt_ids[] = { + { .compatible = "aspeed,ast2400-scu", .data = &ast2400_data }, + { .compatible = "aspeed,ast2500-scu", .data = &ast2500_data }, + { } +}; + +static struct platform_driver aspeed_clk_driver = { + .probe = aspeed_clk_probe, + .driver = { + .name = "aspeed-clk", + .of_match_table = aspeed_clk_dt_ids, + .suppress_bind_attrs = true, + }, +}; +builtin_platform_driver(aspeed_clk_driver); + static void __init aspeed_ast2400_cc(struct regmap *map) { struct clk_hw *hw; -- cgit v1.2.3-58-ga151 From 15ed8ce5f84e2b3718690915dbee12ebd497dc0f Mon Sep 17 00:00:00 2001 From: Joel Stanley Date: Fri, 22 Dec 2017 13:15:21 +1030 Subject: clk: aspeed: Register gated clocks The majority of the clocks in the system are gates paired with a reset controller that holds the IP in reset. This borrows from clk_hw_register_gate, but registers two 'gates', one to control the clock enable register and the other to control the reset IP. This allows us to enforce the ordering: 1. Place IP in reset 2. Enable clock 3. Delay 4. Release reset There are some gates that do not have an associated reset; these are handled by using -1 as the index for the reset. Reviewed-by: Andrew Jeffery Signed-off-by: Joel Stanley Reviewed-by: Benjamin Herrenschmidt Signed-off-by: Stephen Boyd --- drivers/clk/clk-aspeed.c | 130 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 130 insertions(+) diff --git a/drivers/clk/clk-aspeed.c b/drivers/clk/clk-aspeed.c index cf5ea63feb31..dbd3c7774831 100644 --- a/drivers/clk/clk-aspeed.c +++ b/drivers/clk/clk-aspeed.c @@ -204,6 +204,106 @@ static const struct aspeed_clk_soc_data ast2400_data = { .calc_pll = aspeed_ast2400_calc_pll, }; +static int aspeed_clk_enable(struct clk_hw *hw) +{ + struct aspeed_clk_gate *gate = to_aspeed_clk_gate(hw); + unsigned long flags; + u32 clk = BIT(gate->clock_idx); + u32 rst = BIT(gate->reset_idx); + + spin_lock_irqsave(gate->lock, flags); + + if (gate->reset_idx >= 0) { + /* Put IP in reset */ + regmap_update_bits(gate->map, ASPEED_RESET_CTRL, rst, rst); + + /* Delay 100us */ + udelay(100); + } + + /* Enable clock */ + regmap_update_bits(gate->map, ASPEED_CLK_STOP_CTRL, clk, 0); + + if (gate->reset_idx >= 0) { + /* A delay of 10ms is specified by the ASPEED docs */ + mdelay(10); + + /* Take IP out of reset */ + regmap_update_bits(gate->map, ASPEED_RESET_CTRL, rst, 0); + } + + spin_unlock_irqrestore(gate->lock, flags); + + return 0; +} + +static void aspeed_clk_disable(struct clk_hw *hw) +{ + struct aspeed_clk_gate *gate = to_aspeed_clk_gate(hw); + unsigned long flags; + u32 clk = BIT(gate->clock_idx); + + spin_lock_irqsave(gate->lock, flags); + + regmap_update_bits(gate->map, ASPEED_CLK_STOP_CTRL, clk, clk); + + spin_unlock_irqrestore(gate->lock, flags); +} + +static int aspeed_clk_is_enabled(struct clk_hw *hw) +{ + struct aspeed_clk_gate *gate = to_aspeed_clk_gate(hw); + u32 clk = BIT(gate->clock_idx); + u32 reg; + + regmap_read(gate->map, ASPEED_CLK_STOP_CTRL, ®); + + return (reg & clk) ? 0 : 1; +} + +static const struct clk_ops aspeed_clk_gate_ops = { + .enable = aspeed_clk_enable, + .disable = aspeed_clk_disable, + .is_enabled = aspeed_clk_is_enabled, +}; + +static struct clk_hw *aspeed_clk_hw_register_gate(struct device *dev, + const char *name, const char *parent_name, unsigned long flags, + struct regmap *map, u8 clock_idx, u8 reset_idx, + u8 clk_gate_flags, spinlock_t *lock) +{ + struct aspeed_clk_gate *gate; + struct clk_init_data init; + struct clk_hw *hw; + int ret; + + gate = kzalloc(sizeof(*gate), GFP_KERNEL); + if (!gate) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.ops = &aspeed_clk_gate_ops; + init.flags = flags; + init.parent_names = parent_name ? &parent_name : NULL; + init.num_parents = parent_name ? 1 : 0; + + gate->map = map; + gate->clock_idx = clock_idx; + gate->reset_idx = reset_idx; + gate->flags = clk_gate_flags; + gate->lock = lock; + gate->hw.init = &init; + + hw = &gate->hw; + ret = clk_hw_register(dev, hw); + if (ret) { + kfree(gate); + hw = ERR_PTR(ret); + } + + return hw; +} + static int aspeed_clk_probe(struct platform_device *pdev) { const struct aspeed_clk_soc_data *soc_data; @@ -211,6 +311,7 @@ static int aspeed_clk_probe(struct platform_device *pdev) struct regmap *map; struct clk_hw *hw; u32 val, rate; + int i; map = syscon_node_to_regmap(dev->of_node); if (IS_ERR(map)) { @@ -283,6 +384,35 @@ static int aspeed_clk_probe(struct platform_device *pdev) return PTR_ERR(hw); aspeed_clk_data->hws[ASPEED_CLK_BCLK] = hw; + /* + * TODO: There are a number of clocks that not included in this driver + * as more information is required: + * D2-PLL + * D-PLL + * YCLK + * RGMII + * RMII + * UART[1..5] clock source mux + * Video Engine (ECLK) mux and clock divider + */ + + for (i = 0; i < ARRAY_SIZE(aspeed_gates); i++) { + const struct aspeed_gate_data *gd = &aspeed_gates[i]; + + hw = aspeed_clk_hw_register_gate(dev, + gd->name, + gd->parent_name, + gd->flags, + map, + gd->clock_idx, + gd->reset_idx, + CLK_GATE_SET_TO_DISABLE, + &aspeed_clk_lock); + if (IS_ERR(hw)) + return PTR_ERR(hw); + aspeed_clk_data->hws[i] = hw; + } + return 0; }; -- cgit v1.2.3-58-ga151 From f798983982386a3f36ecc4bbdad2657d38bad3e3 Mon Sep 17 00:00:00 2001 From: Joel Stanley Date: Fri, 22 Dec 2017 13:15:22 +1030 Subject: clk: aspeed: Add reset controller There are some resets that are not associated with gates. These are represented by a reset controller. Reviewed-by: Andrew Jeffery Signed-off-by: Joel Stanley Reviewed-by: Benjamin Herrenschmidt Signed-off-by: Stephen Boyd --- drivers/clk/clk-aspeed.c | 82 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 81 insertions(+), 1 deletion(-) diff --git a/drivers/clk/clk-aspeed.c b/drivers/clk/clk-aspeed.c index dbd3c7774831..6fb344730cea 100644 --- a/drivers/clk/clk-aspeed.c +++ b/drivers/clk/clk-aspeed.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -267,6 +268,68 @@ static const struct clk_ops aspeed_clk_gate_ops = { .is_enabled = aspeed_clk_is_enabled, }; +/** + * struct aspeed_reset - Aspeed reset controller + * @map: regmap to access the containing system controller + * @rcdev: reset controller device + */ +struct aspeed_reset { + struct regmap *map; + struct reset_controller_dev rcdev; +}; + +#define to_aspeed_reset(p) container_of((p), struct aspeed_reset, rcdev) + +static const u8 aspeed_resets[] = { + [ASPEED_RESET_XDMA] = 25, + [ASPEED_RESET_MCTP] = 24, + [ASPEED_RESET_ADC] = 23, + [ASPEED_RESET_JTAG_MASTER] = 22, + [ASPEED_RESET_MIC] = 18, + [ASPEED_RESET_PWM] = 9, + [ASPEED_RESET_PCIVGA] = 8, + [ASPEED_RESET_I2C] = 2, + [ASPEED_RESET_AHB] = 1, +}; + +static int aspeed_reset_deassert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct aspeed_reset *ar = to_aspeed_reset(rcdev); + u32 rst = BIT(aspeed_resets[id]); + + return regmap_update_bits(ar->map, ASPEED_RESET_CTRL, rst, 0); +} + +static int aspeed_reset_assert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct aspeed_reset *ar = to_aspeed_reset(rcdev); + u32 rst = BIT(aspeed_resets[id]); + + return regmap_update_bits(ar->map, ASPEED_RESET_CTRL, rst, rst); +} + +static int aspeed_reset_status(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct aspeed_reset *ar = to_aspeed_reset(rcdev); + u32 val, rst = BIT(aspeed_resets[id]); + int ret; + + ret = regmap_read(ar->map, ASPEED_RESET_CTRL, &val); + if (ret) + return ret; + + return !!(val & rst); +} + +static const struct reset_control_ops aspeed_reset_ops = { + .assert = aspeed_reset_assert, + .deassert = aspeed_reset_deassert, + .status = aspeed_reset_status, +}; + static struct clk_hw *aspeed_clk_hw_register_gate(struct device *dev, const char *name, const char *parent_name, unsigned long flags, struct regmap *map, u8 clock_idx, u8 reset_idx, @@ -308,10 +371,11 @@ static int aspeed_clk_probe(struct platform_device *pdev) { const struct aspeed_clk_soc_data *soc_data; struct device *dev = &pdev->dev; + struct aspeed_reset *ar; struct regmap *map; struct clk_hw *hw; u32 val, rate; - int i; + int i, ret; map = syscon_node_to_regmap(dev->of_node); if (IS_ERR(map)) { @@ -319,6 +383,22 @@ static int aspeed_clk_probe(struct platform_device *pdev) return PTR_ERR(map); } + ar = devm_kzalloc(dev, sizeof(*ar), GFP_KERNEL); + if (!ar) + return -ENOMEM; + + ar->map = map; + ar->rcdev.owner = THIS_MODULE; + ar->rcdev.nr_resets = ARRAY_SIZE(aspeed_resets); + ar->rcdev.ops = &aspeed_reset_ops; + ar->rcdev.of_node = dev->of_node; + + ret = devm_reset_controller_register(dev, &ar->rcdev); + if (ret) { + dev_err(dev, "could not register reset controller\n"); + return ret; + } + /* SoC generations share common layouts but have different divisors */ soc_data = of_device_get_match_data(dev); if (!soc_data) { -- cgit v1.2.3-58-ga151 From accf475a5ece972af58c81e0742035ed90ad41d2 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Fri, 5 Jan 2018 01:41:01 +0000 Subject: clk: aspeed: Fix return value check in aspeed_cc_init() In case of error, the function of_iomap() returns NULL pointer not ERR_PTR(). The IS_ERR() test in the return value check should be replaced with NULL test. Fixes: a2e230c7b2ea ("clk: Add clock driver for ASPEED BMC SoCs") Signed-off-by: Wei Yongjun Signed-off-by: Stephen Boyd --- drivers/clk/clk-aspeed.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/clk-aspeed.c b/drivers/clk/clk-aspeed.c index 6fb344730cea..f9b9688cbd1f 100644 --- a/drivers/clk/clk-aspeed.c +++ b/drivers/clk/clk-aspeed.c @@ -609,7 +609,7 @@ static void __init aspeed_cc_init(struct device_node *np) int i; scu_base = of_iomap(np, 0); - if (IS_ERR(scu_base)) + if (!scu_base) return; aspeed_clk_data = kzalloc(sizeof(*aspeed_clk_data) + -- cgit v1.2.3-58-ga151 From 6671507f0fbd582b4003f837ab791d03ade8e0f4 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Fri, 12 Jan 2018 16:48:01 +1100 Subject: clk: aspeed: Handle inverse polarity of USB port 1 clock gate The USB port 1 clock gate control has an inversed polarity from all the other clock gates in the chip. This makes the aspeed_clk_{enable,disable} functions honor the flag CLK_GATE_SET_TO_DISABLE and set that flag appropriately so it's set for all clocks except USB port 1. Signed-off-by: Benjamin Herrenschmidt Reviewed-by: Joel Stanley Signed-off-by: Stephen Boyd --- drivers/clk/clk-aspeed.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/drivers/clk/clk-aspeed.c b/drivers/clk/clk-aspeed.c index f9b9688cbd1f..9f7f931d6b2f 100644 --- a/drivers/clk/clk-aspeed.c +++ b/drivers/clk/clk-aspeed.c @@ -211,6 +211,7 @@ static int aspeed_clk_enable(struct clk_hw *hw) unsigned long flags; u32 clk = BIT(gate->clock_idx); u32 rst = BIT(gate->reset_idx); + u32 enval; spin_lock_irqsave(gate->lock, flags); @@ -223,7 +224,8 @@ static int aspeed_clk_enable(struct clk_hw *hw) } /* Enable clock */ - regmap_update_bits(gate->map, ASPEED_CLK_STOP_CTRL, clk, 0); + enval = (gate->flags & CLK_GATE_SET_TO_DISABLE) ? 0 : clk; + regmap_update_bits(gate->map, ASPEED_CLK_STOP_CTRL, clk, enval); if (gate->reset_idx >= 0) { /* A delay of 10ms is specified by the ASPEED docs */ @@ -243,10 +245,12 @@ static void aspeed_clk_disable(struct clk_hw *hw) struct aspeed_clk_gate *gate = to_aspeed_clk_gate(hw); unsigned long flags; u32 clk = BIT(gate->clock_idx); + u32 enval; spin_lock_irqsave(gate->lock, flags); - regmap_update_bits(gate->map, ASPEED_CLK_STOP_CTRL, clk, clk); + enval = (gate->flags & CLK_GATE_SET_TO_DISABLE) ? clk : 0; + regmap_update_bits(gate->map, ASPEED_CLK_STOP_CTRL, clk, enval); spin_unlock_irqrestore(gate->lock, flags); } @@ -478,7 +482,12 @@ static int aspeed_clk_probe(struct platform_device *pdev) for (i = 0; i < ARRAY_SIZE(aspeed_gates); i++) { const struct aspeed_gate_data *gd = &aspeed_gates[i]; + u32 gate_flags; + /* Special case: the USB port 1 clock (bit 14) is always + * working the opposite way from the other ones. + */ + gate_flags = (gd->clock_idx == 14) ? 0 : CLK_GATE_SET_TO_DISABLE; hw = aspeed_clk_hw_register_gate(dev, gd->name, gd->parent_name, @@ -486,7 +495,7 @@ static int aspeed_clk_probe(struct platform_device *pdev) map, gd->clock_idx, gd->reset_idx, - CLK_GATE_SET_TO_DISABLE, + gate_flags, &aspeed_clk_lock); if (IS_ERR(hw)) return PTR_ERR(hw); -- cgit v1.2.3-58-ga151