From 7f95beea36089918335eb1810ddd7ba8cf9d09cc Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Thu, 8 Mar 2018 14:49:41 +0800 Subject: clk: update cached phase to respect the fact when setting phase It's found that the final phase set by driver doesn't match that of the output from clk_summary: dwmmc_rockchip fe310000.dwmmc: Successfully tuned phase to 346 mmc0: new ultra high speed SDR104 SDIO card at address 0001 cat /sys/kernel/debug/clk/clk_summary | grep sdio_sample sdio_sample 0 1 0 50000000 0 0 It seems the cached core->phase isn't updated after the clk was registered. So fix this issue by updating the core->phase if setting phase successfully. Fixes: 9e4d04adeb1a ("clk: add clk_core_set_phase_nolock function") Cc: Stable Cc: Jerome Brunet Signed-off-by: Shawn Lin Reviewed-by: Jerome Brunet Tested-by: Jerome Brunet Signed-off-by: Michael Turquette --- drivers/clk/clk.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 0f686a9dac3e..617e56268b18 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -2309,8 +2309,11 @@ static int clk_core_set_phase_nolock(struct clk_core *core, int degrees) trace_clk_set_phase(core, degrees); - if (core->ops->set_phase) + if (core->ops->set_phase) { ret = core->ops->set_phase(core->hw, degrees); + if (!ret) + core->phase = degrees; + } trace_clk_set_phase_complete(core, degrees); -- cgit v1.2.3 From c7e92def1ef4dad7a45f0fcca283da1afd003966 Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Wed, 28 Feb 2018 15:07:51 +0100 Subject: clk: mvebu: cp110: Fix clock tree representation Thanks to new documentation, we have a better view of the clock tree. There were few mistakes in the first version of this driver, the main one being the parental link between the clocks. Actually the tree is more flat that we though. Most of the IP blocks require two clocks: one for the IP itself and one for accessing the registers, and unlike what we wrote there is no link between these two clocks. The other mistakes were about the name of the clocks: the root clock is not the Audio PLL but the PLL0, and what we called the EIP clock is named the x2 Core clock and is used by other IP block than the EIP ones. Signed-off-by: Gregory CLEMENT Signed-off-by: Stephen Boyd --- drivers/clk/mvebu/cp110-system-controller.c | 94 ++++++++++++----------------- 1 file changed, 39 insertions(+), 55 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/mvebu/cp110-system-controller.c b/drivers/clk/mvebu/cp110-system-controller.c index ca9a0a536174..75bf7b8f282f 100644 --- a/drivers/clk/mvebu/cp110-system-controller.c +++ b/drivers/clk/mvebu/cp110-system-controller.c @@ -13,18 +13,17 @@ /* * CP110 has 6 core clocks: * - * - APLL (1 Ghz) - * - PPv2 core (1/3 APLL) - * - EIP (1/2 APLL) - * - Core (1/2 EIP) - * - SDIO (2/5 APLL) + * - PLL0 (1 Ghz) + * - PPv2 core (1/3 PLL0) + * - x2 Core (1/2 PLL0) + * - Core (1/2 x2 Core) + * - SDIO (2/5 PLL0) * * - NAND clock, which is either: * - Equal to SDIO clock - * - 2/5 APLL + * - 2/5 PLL0 * - * CP110 has 32 gatable clocks, for the various peripherals in the - * IP. They have fairly complicated parent/child relationships. + * CP110 has 32 gatable clocks, for the various peripherals in the IP. */ #define pr_fmt(fmt) "cp110-system-controller: " fmt @@ -53,9 +52,9 @@ enum { #define CP110_CLK_NUM \ (CP110_MAX_CORE_CLOCKS + CP110_MAX_GATABLE_CLOCKS) -#define CP110_CORE_APLL 0 +#define CP110_CORE_PLL0 0 #define CP110_CORE_PPV2 1 -#define CP110_CORE_EIP 2 +#define CP110_CORE_X2CORE 2 #define CP110_CORE_CORE 3 #define CP110_CORE_NAND 4 #define CP110_CORE_SDIO 5 @@ -237,7 +236,7 @@ static int cp110_syscon_common_probe(struct platform_device *pdev, struct regmap *regmap; struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; - const char *ppv2_name, *apll_name, *core_name, *eip_name, *nand_name, + const char *ppv2_name, *pll0_name, *core_name, *x2core_name, *nand_name, *sdio_name; struct clk_hw_onecell_data *cp110_clk_data; struct clk_hw *hw, **cp110_clks; @@ -263,20 +262,20 @@ static int cp110_syscon_common_probe(struct platform_device *pdev, cp110_clks = cp110_clk_data->hws; cp110_clk_data->num = CP110_CLK_NUM; - /* Register the APLL which is the root of the hw tree */ - apll_name = cp110_unique_name(dev, syscon_node, "apll"); - hw = clk_hw_register_fixed_rate(NULL, apll_name, NULL, 0, + /* Register the PLL0 which is the root of the hw tree */ + pll0_name = cp110_unique_name(dev, syscon_node, "pll0"); + hw = clk_hw_register_fixed_rate(NULL, pll0_name, NULL, 0, 1000 * 1000 * 1000); if (IS_ERR(hw)) { ret = PTR_ERR(hw); - goto fail_apll; + goto fail_pll0; } - cp110_clks[CP110_CORE_APLL] = hw; + cp110_clks[CP110_CORE_PLL0] = hw; - /* PPv2 is APLL/3 */ + /* PPv2 is PLL0/3 */ ppv2_name = cp110_unique_name(dev, syscon_node, "ppv2-core"); - hw = clk_hw_register_fixed_factor(NULL, ppv2_name, apll_name, 0, 1, 3); + hw = clk_hw_register_fixed_factor(NULL, ppv2_name, pll0_name, 0, 1, 3); if (IS_ERR(hw)) { ret = PTR_ERR(hw); goto fail_ppv2; @@ -284,30 +283,32 @@ static int cp110_syscon_common_probe(struct platform_device *pdev, cp110_clks[CP110_CORE_PPV2] = hw; - /* EIP clock is APLL/2 */ - eip_name = cp110_unique_name(dev, syscon_node, "eip"); - hw = clk_hw_register_fixed_factor(NULL, eip_name, apll_name, 0, 1, 2); + /* X2CORE clock is PLL0/2 */ + x2core_name = cp110_unique_name(dev, syscon_node, "x2core"); + hw = clk_hw_register_fixed_factor(NULL, x2core_name, pll0_name, + 0, 1, 2); if (IS_ERR(hw)) { ret = PTR_ERR(hw); goto fail_eip; } - cp110_clks[CP110_CORE_EIP] = hw; + cp110_clks[CP110_CORE_X2CORE] = hw; - /* Core clock is EIP/2 */ + /* Core clock is X2CORE/2 */ core_name = cp110_unique_name(dev, syscon_node, "core"); - hw = clk_hw_register_fixed_factor(NULL, core_name, eip_name, 0, 1, 2); + hw = clk_hw_register_fixed_factor(NULL, core_name, x2core_name, + 0, 1, 2); if (IS_ERR(hw)) { ret = PTR_ERR(hw); goto fail_core; } cp110_clks[CP110_CORE_CORE] = hw; - /* NAND can be either APLL/2.5 or core clock */ + /* NAND can be either PLL0/2.5 or core clock */ nand_name = cp110_unique_name(dev, syscon_node, "nand-core"); if (nand_clk_ctrl & NF_CLOCK_SEL_400_MASK) hw = clk_hw_register_fixed_factor(NULL, nand_name, - apll_name, 0, 2, 5); + pll0_name, 0, 2, 5); else hw = clk_hw_register_fixed_factor(NULL, nand_name, core_name, 0, 1, 1); @@ -318,10 +319,10 @@ static int cp110_syscon_common_probe(struct platform_device *pdev, cp110_clks[CP110_CORE_NAND] = hw; - /* SDIO clock is APLL/2.5 */ + /* SDIO clock is PLL0/2.5 */ sdio_name = cp110_unique_name(dev, syscon_node, "sdio-core"); hw = clk_hw_register_fixed_factor(NULL, sdio_name, - apll_name, 0, 2, 5); + pll0_name, 0, 2, 5); if (IS_ERR(hw)) { ret = PTR_ERR(hw); goto fail_sdio; @@ -341,40 +342,23 @@ static int cp110_syscon_common_probe(struct platform_device *pdev, continue; switch (i) { - case CP110_GATE_AUDIO: - case CP110_GATE_COMM_UNIT: - case CP110_GATE_EIP150: - case CP110_GATE_EIP197: - case CP110_GATE_SLOW_IO: - parent = gate_name[CP110_GATE_MAIN]; - break; - case CP110_GATE_MG: - parent = gate_name[CP110_GATE_MG_CORE]; - break; case CP110_GATE_NAND: parent = nand_name; break; + case CP110_GATE_MG: + case CP110_GATE_GOP_DP: case CP110_GATE_PPV2: parent = ppv2_name; break; case CP110_GATE_SDIO: parent = sdio_name; break; - case CP110_GATE_GOP_DP: - parent = gate_name[CP110_GATE_SDMMC_GOP]; - break; - case CP110_GATE_XOR1: - case CP110_GATE_XOR0: - case CP110_GATE_PCIE_X1_0: - case CP110_GATE_PCIE_X1_1: + case CP110_GATE_MAIN: + case CP110_GATE_PCIE_XOR: case CP110_GATE_PCIE_X4: - parent = gate_name[CP110_GATE_PCIE_XOR]; - break; - case CP110_GATE_SATA: - case CP110_GATE_USB3H0: - case CP110_GATE_USB3H1: - case CP110_GATE_USB3DEV: - parent = gate_name[CP110_GATE_SATA_USB]; + case CP110_GATE_EIP150: + case CP110_GATE_EIP197: + parent = x2core_name; break; default: parent = core_name; @@ -413,12 +397,12 @@ fail_sdio: fail_nand: clk_hw_unregister_fixed_factor(cp110_clks[CP110_CORE_CORE]); fail_core: - clk_hw_unregister_fixed_factor(cp110_clks[CP110_CORE_EIP]); + clk_hw_unregister_fixed_factor(cp110_clks[CP110_CORE_X2CORE]); fail_eip: clk_hw_unregister_fixed_factor(cp110_clks[CP110_CORE_PPV2]); fail_ppv2: - clk_hw_unregister_fixed_rate(cp110_clks[CP110_CORE_APLL]); -fail_apll: + clk_hw_unregister_fixed_rate(cp110_clks[CP110_CORE_PLL0]); +fail_pll0: return ret; } -- cgit v1.2.3 From 6a4a4595804548e173f0763a0e7274a3521c59a9 Mon Sep 17 00:00:00 2001 From: Richard Genoud Date: Tue, 13 Mar 2018 16:27:02 +0100 Subject: clk: mvebu: armada-38x: add support for missing clocks Clearfog boards can come with a CPU clocked at 1600MHz (commercial) or 1333MHz (industrial). They have also some dip-switches to select a different clock (666, 800, 1066, 1200). The funny thing is that the recovery button is on the MPP34 fq selector. So, when booting an industrial board with this button down, the frequency 666MHz is selected (and the kernel didn't boot). This patch add all the missing clocks. The only mode I didn't test is 2GHz (uboot found 4294MHz instead :/ ). Fixes: 0e85aeced4d6 ("clk: mvebu: add clock support for Armada 380/385") Cc: # 3.16.x: 9593f4f56cf5: clk: mvebu: armada-38x: add support for 1866MHz variants Cc: # 3.16.x Signed-off-by: Richard Genoud Acked-by: Gregory CLEMENT Signed-off-by: Stephen Boyd --- drivers/clk/mvebu/armada-38x.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/mvebu/armada-38x.c b/drivers/clk/mvebu/armada-38x.c index 394aa6f03f01..9ff4ea63932d 100644 --- a/drivers/clk/mvebu/armada-38x.c +++ b/drivers/clk/mvebu/armada-38x.c @@ -46,11 +46,11 @@ static u32 __init armada_38x_get_tclk_freq(void __iomem *sar) } static const u32 armada_38x_cpu_frequencies[] __initconst = { - 0, 0, 0, 0, - 1066 * 1000 * 1000, 0, 0, 0, + 666 * 1000 * 1000, 0, 800 * 1000 * 1000, 0, + 1066 * 1000 * 1000, 0, 1200 * 1000 * 1000, 0, 1332 * 1000 * 1000, 0, 0, 0, 1600 * 1000 * 1000, 0, 0, 0, - 1866 * 1000 * 1000, + 1866 * 1000 * 1000, 0, 0, 2000 * 1000 * 1000, }; static u32 __init armada_38x_get_cpu_freq(void __iomem *sar) @@ -76,11 +76,11 @@ static const struct coreclk_ratio armada_38x_coreclk_ratios[] __initconst = { }; static const int armada_38x_cpu_l2_ratios[32][2] __initconst = { - {0, 1}, {0, 1}, {0, 1}, {0, 1}, - {1, 2}, {0, 1}, {0, 1}, {0, 1}, - {1, 2}, {0, 1}, {0, 1}, {0, 1}, + {1, 2}, {0, 1}, {1, 2}, {0, 1}, + {1, 2}, {0, 1}, {1, 2}, {0, 1}, {1, 2}, {0, 1}, {0, 1}, {0, 1}, {1, 2}, {0, 1}, {0, 1}, {0, 1}, + {1, 2}, {0, 1}, {0, 1}, {1, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, @@ -91,7 +91,7 @@ static const int armada_38x_cpu_ddr_ratios[32][2] __initconst = { {1, 2}, {0, 1}, {0, 1}, {0, 1}, {1, 2}, {0, 1}, {0, 1}, {0, 1}, {1, 2}, {0, 1}, {0, 1}, {0, 1}, - {1, 2}, {0, 1}, {0, 1}, {0, 1}, + {1, 2}, {0, 1}, {0, 1}, {7, 15}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, -- cgit v1.2.3 From 1f9c63e8de3d7b377c9d74e4a17524cfb60e6384 Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Wed, 14 Mar 2018 08:28:31 +0800 Subject: clk: Don't show the incorrect clock phase It's found that the clock phase output from clk_summary is wrong compared to the actual phase reading from the register. cat /sys/kernel/debug/clk/clk_summary | grep sdio_sample sdio_sample 0 1 0 50000000 0 -22 It exposes an issue that clk core, clk_core_get_phase, always returns the cached core->phase which should be either updated by calling clk_set_phase or directly from the first place the clk was registered. When registering the clk, the core->phase geting from ->get_phase() may return negative value indicating error. This is quite common since the clk's phase may be highly related to its parent chain, but it was temporarily orphan when registered, since its parent chains hadn't be ready at that time, so the clk drivers decide to return error in this case. However, if no clk_set_phase is called or maybe the ->set_phase() isn't even implemented, the core->phase would never be updated. This is wrong, and we should try to update it when all its parent chains are settled down, like the way of updating clock rate for that. But it's not deserved to complicate the code now and just update it anyway when calling clk_core_get_phase, which would be much simple and enough. Signed-off-by: Shawn Lin Acked-by: Jerome Brunet Signed-off-by: Stephen Boyd --- drivers/clk/clk.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 617e56268b18..d5c477c7bcf1 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -2373,6 +2373,9 @@ static int clk_core_get_phase(struct clk_core *core) int ret; clk_prepare_lock(); + /* Always try to update cached phase if possible */ + if (core->ops->get_phase) + core->phase = core->ops->get_phase(core->hw); ret = core->phase; clk_prepare_unlock(); -- cgit v1.2.3 From cef7b18c3e8bd709b6b4b7bb67ceca662aa5f60e Mon Sep 17 00:00:00 2001 From: Jeffy Chen Date: Mon, 19 Mar 2018 11:58:54 +0800 Subject: clk: lpc32xx: Set name of regmap_config We are now allowing to register debugfs without a valid device, and not having a valid name will end up using "dummy*" to create debugfs dir. Signed-off-by: Jeffy Chen Acked-by: Vladimir Zapolskiy Signed-off-by: Stephen Boyd --- drivers/clk/nxp/clk-lpc32xx.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/clk/nxp/clk-lpc32xx.c b/drivers/clk/nxp/clk-lpc32xx.c index f5d815f577e0..5eeecee17b69 100644 --- a/drivers/clk/nxp/clk-lpc32xx.c +++ b/drivers/clk/nxp/clk-lpc32xx.c @@ -67,6 +67,7 @@ #define LPC32XX_USB_CLK_STS 0xF8 static struct regmap_config lpc32xx_scb_regmap_config = { + .name = "scb", .reg_bits = 32, .val_bits = 32, .reg_stride = 4, -- cgit v1.2.3 From f72595cf441bb534e601c609b687451cc9143f13 Mon Sep 17 00:00:00 2001 From: Weiyi Lu Date: Mon, 12 Mar 2018 15:03:42 +0800 Subject: clk: mediatek: update clock driver of MT2712 According to ECO design change, 1. add new clock mux data and change some 2. add new clock gate data and clock factor data 3. change status register offset of infra subsystem Signed-off-by: Weiyi Lu Signed-off-by: Stephen Boyd --- drivers/clk/mediatek/clk-mt2712.c | 69 +++++++++++++++++++++++++++++++-------- 1 file changed, 55 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/mediatek/clk-mt2712.c b/drivers/clk/mediatek/clk-mt2712.c index 498d13799388..991d4093726e 100644 --- a/drivers/clk/mediatek/clk-mt2712.c +++ b/drivers/clk/mediatek/clk-mt2712.c @@ -221,6 +221,8 @@ static const struct mtk_fixed_factor top_divs[] = { 4), FACTOR(CLK_TOP_D2A_ULCLK_6P5M, "d2a_ulclk_6p5m", "clk26m", 1, 4), + FACTOR(CLK_TOP_APLL1_D3, "apll1_d3", "apll1_ck", 1, + 3), }; static const char * const axi_parents[] = { @@ -625,7 +627,7 @@ static const char * const ether_125m_parents[] = { static const char * const ether_50m_parents[] = { "clk26m", "etherpll_50m", - "univpll_d26", + "apll1_d3", "univpll3_d4" }; @@ -686,7 +688,7 @@ static const char * const i2c_parents[] = { static const char * const msdc0p_aes_parents[] = { "clk26m", - "msdcpll_ck", + "syspll_d2", "univpll_d3", "vcodecpll_ck" }; @@ -719,6 +721,17 @@ static const char * const aud_apll2_parents[] = { "clkaud_ext_i_2" }; +static const char * const apll1_ref_parents[] = { + "clkaud_ext_i_2", + "clkaud_ext_i_1", + "clki2si0_mck_i", + "clki2si1_mck_i", + "clki2si2_mck_i", + "clktdmin_mclk_i", + "clki2si2_mck_i", + "clktdmin_mclk_i" +}; + static const char * const audull_vtx_parents[] = { "d2a_ulclk_6p5m", "clkaud_ext_i_0" @@ -886,6 +899,10 @@ static struct mtk_composite top_muxes[] = { aud_apll2_parents, 0x134, 1, 1), MUX(CLK_TOP_DA_AUDULL_VTX_6P5M_SEL, "audull_vtx_sel", audull_vtx_parents, 0x134, 31, 1), + MUX(CLK_TOP_APLL1_REF_SEL, "apll1_ref_sel", + apll1_ref_parents, 0x134, 4, 3), + MUX(CLK_TOP_APLL2_REF_SEL, "apll2_ref_sel", + apll1_ref_parents, 0x134, 7, 3), }; static const char * const mcu_mp0_parents[] = { @@ -932,36 +949,56 @@ static const struct mtk_clk_divider top_adj_divs[] = { DIV_ADJ(CLK_TOP_APLL_DIV7, "apll_div7", "i2si3_sel", 0x128, 24, 8), }; -static const struct mtk_gate_regs top_cg_regs = { +static const struct mtk_gate_regs top0_cg_regs = { .set_ofs = 0x120, .clr_ofs = 0x120, .sta_ofs = 0x120, }; -#define GATE_TOP(_id, _name, _parent, _shift) { \ +static const struct mtk_gate_regs top1_cg_regs = { + .set_ofs = 0x424, + .clr_ofs = 0x424, + .sta_ofs = 0x424, +}; + +#define GATE_TOP0(_id, _name, _parent, _shift) { \ .id = _id, \ .name = _name, \ .parent_name = _parent, \ - .regs = &top_cg_regs, \ + .regs = &top0_cg_regs, \ .shift = _shift, \ .ops = &mtk_clk_gate_ops_no_setclr, \ } +#define GATE_TOP1(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &top1_cg_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_ops_no_setclr_inv, \ + } + static const struct mtk_gate top_clks[] = { - GATE_TOP(CLK_TOP_APLL_DIV_PDN0, "apll_div_pdn0", "i2so1_sel", 0), - GATE_TOP(CLK_TOP_APLL_DIV_PDN1, "apll_div_pdn1", "i2so2_sel", 1), - GATE_TOP(CLK_TOP_APLL_DIV_PDN2, "apll_div_pdn2", "i2so3_sel", 2), - GATE_TOP(CLK_TOP_APLL_DIV_PDN3, "apll_div_pdn3", "tdmo0_sel", 3), - GATE_TOP(CLK_TOP_APLL_DIV_PDN4, "apll_div_pdn4", "tdmo1_sel", 4), - GATE_TOP(CLK_TOP_APLL_DIV_PDN5, "apll_div_pdn5", "i2si1_sel", 5), - GATE_TOP(CLK_TOP_APLL_DIV_PDN6, "apll_div_pdn6", "i2si2_sel", 6), - GATE_TOP(CLK_TOP_APLL_DIV_PDN7, "apll_div_pdn7", "i2si3_sel", 7), + /* TOP0 */ + GATE_TOP0(CLK_TOP_APLL_DIV_PDN0, "apll_div_pdn0", "i2so1_sel", 0), + GATE_TOP0(CLK_TOP_APLL_DIV_PDN1, "apll_div_pdn1", "i2so2_sel", 1), + GATE_TOP0(CLK_TOP_APLL_DIV_PDN2, "apll_div_pdn2", "i2so3_sel", 2), + GATE_TOP0(CLK_TOP_APLL_DIV_PDN3, "apll_div_pdn3", "tdmo0_sel", 3), + GATE_TOP0(CLK_TOP_APLL_DIV_PDN4, "apll_div_pdn4", "tdmo1_sel", 4), + GATE_TOP0(CLK_TOP_APLL_DIV_PDN5, "apll_div_pdn5", "i2si1_sel", 5), + GATE_TOP0(CLK_TOP_APLL_DIV_PDN6, "apll_div_pdn6", "i2si2_sel", 6), + GATE_TOP0(CLK_TOP_APLL_DIV_PDN7, "apll_div_pdn7", "i2si3_sel", 7), + /* TOP1 */ + GATE_TOP1(CLK_TOP_NFI2X_EN, "nfi2x_en", "nfi2x_sel", 0), + GATE_TOP1(CLK_TOP_NFIECC_EN, "nfiecc_en", "nfiecc_sel", 1), + GATE_TOP1(CLK_TOP_NFI1X_CK_EN, "nfi1x_ck_en", "nfi2x_sel", 2), }; static const struct mtk_gate_regs infra_cg_regs = { .set_ofs = 0x40, .clr_ofs = 0x44, - .sta_ofs = 0x40, + .sta_ofs = 0x48, }; #define GATE_INFRA(_id, _name, _parent, _shift) { \ @@ -1120,6 +1157,10 @@ static const struct mtk_gate peri_clks[] = { "msdc50_0_h_sel", 4), GATE_PERI2(CLK_PERI_MSDC50_3_HCLK_EN, "per_msdc50_3_h", "msdc50_3_h_sel", 5), + GATE_PERI2(CLK_PERI_MSDC30_0_QTR_EN, "per_msdc30_0_q", + "axi_sel", 6), + GATE_PERI2(CLK_PERI_MSDC30_3_QTR_EN, "per_msdc30_3_q", + "mem_sel", 7), }; #define MT2712_PLL_FMAX (3000UL * MHZ) -- cgit v1.2.3 From 8bcde6582c908bc6567c9d38f7b000d199f7f009 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Sun, 18 Mar 2018 14:44:01 +0000 Subject: clk: qcom: rpmcc: Add support to XO buffered clocks XO is onchip buffer clock to generate 19.2MHz. This patch adds support to 5 XO buffer clocks found on PMIC8921, these buffer clocks can be controlled from external pin or in manual mode. Signed-off-by: Srinivas Kandagatla Signed-off-by: Stephen Boyd --- drivers/clk/qcom/clk-rpm.c | 79 +++++++++++++++++++++++++++++++++- include/dt-bindings/clock/qcom,rpmcc.h | 5 +++ 2 files changed, 83 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/clk/qcom/clk-rpm.c b/drivers/clk/qcom/clk-rpm.c index c60f61b10c7f..b94981447664 100644 --- a/drivers/clk/qcom/clk-rpm.c +++ b/drivers/clk/qcom/clk-rpm.c @@ -29,6 +29,7 @@ #define QCOM_RPM_MISC_CLK_TYPE 0x306b6c63 #define QCOM_RPM_SCALING_ENABLE_ID 0x2 +#define QCOM_RPM_XO_MODE_ON 0x2 #define DEFINE_CLK_RPM(_platform, _name, _active, r_id) \ static struct clk_rpm _platform##_##_active; \ @@ -56,6 +57,18 @@ }, \ } +#define DEFINE_CLK_RPM_XO_BUFFER(_platform, _name, _active, offset) \ + static struct clk_rpm _platform##_##_name = { \ + .rpm_clk_id = QCOM_RPM_CXO_BUFFERS, \ + .xo_offset = (offset), \ + .hw.init = &(struct clk_init_data){ \ + .ops = &clk_rpm_xo_ops, \ + .name = #_name, \ + .parent_names = (const char *[]){ "cxo_board" }, \ + .num_parents = 1, \ + }, \ + } + #define DEFINE_CLK_RPM_FIXED(_platform, _name, _active, r_id, r) \ static struct clk_rpm _platform##_##_name = { \ .rpm_clk_id = (r_id), \ @@ -126,8 +139,11 @@ #define to_clk_rpm(_hw) container_of(_hw, struct clk_rpm, hw) +struct rpm_cc; + struct clk_rpm { const int rpm_clk_id; + const int xo_offset; const bool active_only; unsigned long rate; bool enabled; @@ -135,12 +151,15 @@ struct clk_rpm { struct clk_rpm *peer; struct clk_hw hw; struct qcom_rpm *rpm; + struct rpm_cc *rpm_cc; }; struct rpm_cc { struct qcom_rpm *rpm; struct clk_rpm **clks; size_t num_clks; + u32 xo_buffer_value; + struct mutex xo_lock; }; struct rpm_clk_desc { @@ -159,7 +178,8 @@ static int clk_rpm_handoff(struct clk_rpm *r) * The vendor tree simply reads the status for this * RPM clock. */ - if (r->rpm_clk_id == QCOM_RPM_PLL_4) + if (r->rpm_clk_id == QCOM_RPM_PLL_4 || + r->rpm_clk_id == QCOM_RPM_CXO_BUFFERS) return 0; ret = qcom_rpm_write(r->rpm, QCOM_RPM_ACTIVE_STATE, @@ -288,6 +308,46 @@ out: mutex_unlock(&rpm_clk_lock); } +static int clk_rpm_xo_prepare(struct clk_hw *hw) +{ + struct clk_rpm *r = to_clk_rpm(hw); + struct rpm_cc *rcc = r->rpm_cc; + int ret, clk_id = r->rpm_clk_id; + u32 value; + + mutex_lock(&rcc->xo_lock); + + value = rcc->xo_buffer_value | (QCOM_RPM_XO_MODE_ON << r->xo_offset); + ret = qcom_rpm_write(r->rpm, QCOM_RPM_ACTIVE_STATE, clk_id, &value, 1); + if (!ret) { + r->enabled = true; + rcc->xo_buffer_value = value; + } + + mutex_unlock(&rcc->xo_lock); + + return ret; +} + +static void clk_rpm_xo_unprepare(struct clk_hw *hw) +{ + struct clk_rpm *r = to_clk_rpm(hw); + struct rpm_cc *rcc = r->rpm_cc; + int ret, clk_id = r->rpm_clk_id; + u32 value; + + mutex_lock(&rcc->xo_lock); + + value = rcc->xo_buffer_value & ~(QCOM_RPM_XO_MODE_ON << r->xo_offset); + ret = qcom_rpm_write(r->rpm, QCOM_RPM_ACTIVE_STATE, clk_id, &value, 1); + if (!ret) { + r->enabled = false; + rcc->xo_buffer_value = value; + } + + mutex_unlock(&rcc->xo_lock); +} + static int clk_rpm_fixed_prepare(struct clk_hw *hw) { struct clk_rpm *r = to_clk_rpm(hw); @@ -378,6 +438,11 @@ static unsigned long clk_rpm_recalc_rate(struct clk_hw *hw, return r->rate; } +static const struct clk_ops clk_rpm_xo_ops = { + .prepare = clk_rpm_xo_prepare, + .unprepare = clk_rpm_xo_unprepare, +}; + static const struct clk_ops clk_rpm_fixed_ops = { .prepare = clk_rpm_fixed_prepare, .unprepare = clk_rpm_fixed_unprepare, @@ -449,6 +514,11 @@ DEFINE_CLK_RPM(apq8064, mmfpb_clk, mmfpb_a_clk, QCOM_RPM_MMFPB_CLK); DEFINE_CLK_RPM(apq8064, sfab_clk, sfab_a_clk, QCOM_RPM_SYS_FABRIC_CLK); DEFINE_CLK_RPM(apq8064, sfpb_clk, sfpb_a_clk, QCOM_RPM_SFPB_CLK); DEFINE_CLK_RPM(apq8064, qdss_clk, qdss_a_clk, QCOM_RPM_QDSS_CLK); +DEFINE_CLK_RPM_XO_BUFFER(apq8064, xo_d0_clk, xo_d0_a_clk, 0); +DEFINE_CLK_RPM_XO_BUFFER(apq8064, xo_d1_clk, xo_d1_a_clk, 8); +DEFINE_CLK_RPM_XO_BUFFER(apq8064, xo_a0_clk, xo_a0_a_clk, 16); +DEFINE_CLK_RPM_XO_BUFFER(apq8064, xo_a1_clk, xo_a1_a_clk, 24); +DEFINE_CLK_RPM_XO_BUFFER(apq8064, xo_a2_clk, xo_a2_a_clk, 28); static struct clk_rpm *apq8064_clks[] = { [RPM_APPS_FABRIC_CLK] = &apq8064_afab_clk, @@ -469,6 +539,11 @@ static struct clk_rpm *apq8064_clks[] = { [RPM_SFPB_A_CLK] = &apq8064_sfpb_a_clk, [RPM_QDSS_CLK] = &apq8064_qdss_clk, [RPM_QDSS_A_CLK] = &apq8064_qdss_a_clk, + [RPM_XO_D0] = &apq8064_xo_d0_clk, + [RPM_XO_D1] = &apq8064_xo_d1_clk, + [RPM_XO_A0] = &apq8064_xo_a0_clk, + [RPM_XO_A1] = &apq8064_xo_a1_clk, + [RPM_XO_A2] = &apq8064_xo_a2_clk, }; static const struct rpm_clk_desc rpm_clk_apq8064 = { @@ -526,12 +601,14 @@ static int rpm_clk_probe(struct platform_device *pdev) rcc->clks = rpm_clks; rcc->num_clks = num_clks; + mutex_init(&rcc->xo_lock); for (i = 0; i < num_clks; i++) { if (!rpm_clks[i]) continue; rpm_clks[i]->rpm = rpm; + rpm_clks[i]->rpm_cc = rcc; ret = clk_rpm_handoff(rpm_clks[i]); if (ret) diff --git a/include/dt-bindings/clock/qcom,rpmcc.h b/include/dt-bindings/clock/qcom,rpmcc.h index b8337a5fa347..c585b82b9c05 100644 --- a/include/dt-bindings/clock/qcom,rpmcc.h +++ b/include/dt-bindings/clock/qcom,rpmcc.h @@ -40,6 +40,11 @@ #define RPM_SMI_CLK 22 #define RPM_SMI_A_CLK 23 #define RPM_PLL4_CLK 24 +#define RPM_XO_D0 25 +#define RPM_XO_D1 26 +#define RPM_XO_A0 27 +#define RPM_XO_A1 28 +#define RPM_XO_A2 29 /* SMD RPM clocks */ #define RPM_SMD_XO_CLK_SRC 0 -- cgit v1.2.3