From a96cbb146a9736f501fe66ebda6a9018735e5e8a Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 18 Jul 2023 08:31:43 -0600 Subject: clk: Explicitly include correct DT includes The DT of_device.h and of_platform.h date back to the separate of_platform_bus_type before it as merged into the regular platform bus. As part of that merge prepping Arm DT support 13 years ago, they "temporarily" include each other. They also include platform_device.h and of.h. As a result, there's a pretty much random mix of those include files used throughout the tree. In order to detangle these headers and replace the implicit includes with struct declarations, users need to explicitly include the correct includes. Acked-by: Dinh Nguyen Acked-by: Krzysztof Kozlowski # samsung Acked-by: Heiko Stuebner #rockchip Acked-by: Chanwoo Choi Acked-by: Geert Uytterhoeven Reviewed-by: AngeloGioacchino Del Regno Reviewed-by: Luca Ceresoli # versaclock5 Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20230718143156.1066339-1-robh@kernel.org Acked-by: Abel Vesa #imx Signed-off-by: Stephen Boyd --- drivers/clk/imx/clk-imx8qxp-lpcg.c | 2 -- drivers/clk/imx/clk-imx8qxp.c | 1 - drivers/clk/imx/clk-imx8ulp.c | 2 +- drivers/clk/imx/clk-scu.c | 2 +- 4 files changed, 2 insertions(+), 5 deletions(-) (limited to 'drivers/clk/imx') diff --git a/drivers/clk/imx/clk-imx8qxp-lpcg.c b/drivers/clk/imx/clk-imx8qxp-lpcg.c index 5e31a6a24b3a..5ce2c34e8f0c 100644 --- a/drivers/clk/imx/clk-imx8qxp-lpcg.c +++ b/drivers/clk/imx/clk-imx8qxp-lpcg.c @@ -9,8 +9,6 @@ #include #include #include -#include -#include #include #include #include diff --git a/drivers/clk/imx/clk-imx8qxp.c b/drivers/clk/imx/clk-imx8qxp.c index 546a3703bfeb..cadcbb318f5c 100644 --- a/drivers/clk/imx/clk-imx8qxp.c +++ b/drivers/clk/imx/clk-imx8qxp.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include diff --git a/drivers/clk/imx/clk-imx8ulp.c b/drivers/clk/imx/clk-imx8ulp.c index e308c88cb801..6636a1921b46 100644 --- a/drivers/clk/imx/clk-imx8ulp.c +++ b/drivers/clk/imx/clk-imx8ulp.c @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/clk/imx/clk-scu.c b/drivers/clk/imx/clk-scu.c index 85041e339515..cd83c52e9952 100644 --- a/drivers/clk/imx/clk-scu.c +++ b/drivers/clk/imx/clk-scu.c @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include #include #include -- cgit v1.2.3 From 3ea570486039a12bb9dcbec977c70390b3d3c902 Mon Sep 17 00:00:00 2001 From: Chancel Liu Date: Wed, 28 Jun 2023 14:17:23 +0800 Subject: clk: imx93: Add PDM IPG clk The IPG clk and MCLK of PDM share the same control gate. Reviewed-by: Shengjiu Wang Signed-off-by: Chancel Liu Signed-off-by: Jacky Bai Reviewed-by: Peng Fan Link: https://lore.kernel.org/r/20230628061724.2056520-2-ping.bai@nxp.com Signed-off-by: Abel Vesa --- drivers/clk/imx/clk-imx93.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/clk/imx') diff --git a/drivers/clk/imx/clk-imx93.c b/drivers/clk/imx/clk-imx93.c index b6c7c2725906..f5dc1ee4990d 100644 --- a/drivers/clk/imx/clk-imx93.c +++ b/drivers/clk/imx/clk-imx93.c @@ -32,6 +32,7 @@ static u32 share_count_sai1; static u32 share_count_sai2; static u32 share_count_sai3; static u32 share_count_mub; +static u32 share_count_pdm; static const char * const a55_core_sels[] = {"a55_alt", "arm_pll"}; static const char *parent_names[MAX_SEL][4] = { @@ -236,7 +237,8 @@ static const struct imx93_clk_ccgr { { IMX93_CLK_USB_CONTROLLER_GATE, "usb_controller", "hsio_root", 0x9a00, }, { IMX93_CLK_USB_TEST_60M_GATE, "usb_test_60m", "hsio_usb_test_60m_root", 0x9a40, }, { IMX93_CLK_HSIO_TROUT_24M_GATE, "hsio_trout_24m", "osc_24m", 0x9a80, }, - { IMX93_CLK_PDM_GATE, "pdm", "pdm_root", 0x9ac0, }, + { IMX93_CLK_PDM_GATE, "pdm", "pdm_root", 0x9ac0, 0, &share_count_pdm}, + { IMX93_CLK_PDM_IPG, "pdm_ipg_clk", "bus_aon_root", 0x9ac0, 0, &share_count_pdm}, { IMX93_CLK_MQS1_GATE, "mqs1", "sai1_root", 0x9b00, }, { IMX93_CLK_MQS2_GATE, "mqs2", "sai3_root", 0x9b40, }, { IMX93_CLK_AUD_XCVR_GATE, "aud_xcvr", "audio_xcvr_root", 0x9b80, }, -- cgit v1.2.3 From 07ba6d1ae524c627ac55bb98d5610d4fc44d3fe7 Mon Sep 17 00:00:00 2001 From: Jacky Bai Date: Wed, 28 Jun 2023 14:17:24 +0800 Subject: clk: imx: Add 519.75MHz frequency support for imx9 pll For video pll, it may need 519.75MHz clock frequency for the LVDS display usage. So add 519.75MHz frequency config support for video pll. Signed-off-by: Jacky Bai Reviewed-by: Peng Fan Link: https://lore.kernel.org/r/20230628061724.2056520-3-ping.bai@nxp.com Signed-off-by: Abel Vesa --- drivers/clk/imx/clk-fracn-gppll.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/clk/imx') diff --git a/drivers/clk/imx/clk-fracn-gppll.c b/drivers/clk/imx/clk-fracn-gppll.c index c54f9999da04..44462ab50e51 100644 --- a/drivers/clk/imx/clk-fracn-gppll.c +++ b/drivers/clk/imx/clk-fracn-gppll.c @@ -81,6 +81,7 @@ static const struct imx_fracn_gppll_rate_table fracn_tbl[] = { PLL_FRACN_GP(650000000U, 162, 50, 100, 0, 6), PLL_FRACN_GP(594000000U, 198, 0, 1, 0, 8), PLL_FRACN_GP(560000000U, 140, 0, 1, 0, 6), + PLL_FRACN_GP(519750000U, 173, 25, 100, 1, 8), PLL_FRACN_GP(498000000U, 166, 0, 1, 0, 8), PLL_FRACN_GP(484000000U, 121, 0, 1, 0, 6), PLL_FRACN_GP(445333333U, 167, 0, 1, 0, 9), -- cgit v1.2.3 From 2deed4cda3b76bcb8be2533f5bd07803b1bfa452 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Fri, 7 Jul 2023 22:02:48 +0200 Subject: clk: imx: clk-gpr-mux: Simplify .determine_rate() imx_clk_gpr_mux_determine_rate() is the same as __clk_mux_determine_rate(), so use the latter to save some LoC. Signed-off-by: Christophe JAILLET Reviewed-by: Peng Fan Link: https://lore.kernel.org/r/ac8bd50c41b84f244bb0ec94e8aed25c513c9037.1688760152.git.christophe.jaillet@wanadoo.fr Signed-off-by: Abel Vesa --- drivers/clk/imx/clk-gpr-mux.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'drivers/clk/imx') diff --git a/drivers/clk/imx/clk-gpr-mux.c b/drivers/clk/imx/clk-gpr-mux.c index 0b5a97698b47..0e14b61cba84 100644 --- a/drivers/clk/imx/clk-gpr-mux.c +++ b/drivers/clk/imx/clk-gpr-mux.c @@ -65,16 +65,10 @@ static int imx_clk_gpr_mux_set_parent(struct clk_hw *hw, u8 index) return regmap_update_bits(priv->regmap, priv->reg, priv->mask, val); } -static int imx_clk_gpr_mux_determine_rate(struct clk_hw *hw, - struct clk_rate_request *req) -{ - return clk_mux_determine_rate_flags(hw, req, 0); -} - static const struct clk_ops imx_clk_gpr_mux_ops = { .get_parent = imx_clk_gpr_mux_get_parent, .set_parent = imx_clk_gpr_mux_set_parent, - .determine_rate = imx_clk_gpr_mux_determine_rate, + .determine_rate = __clk_mux_determine_rate, }; struct clk_hw *imx_clk_gpr_mux(const char *name, const char *compatible, -- cgit v1.2.3 From 94945b23133db0b698ffe764d8a82593906d1e74 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Wed, 5 Jul 2023 14:53:08 +0800 Subject: clk: imx: clk-imx8qxp-lpcg: Convert to devm_platform_ioremap_resource() Use devm_platform_ioremap_resource() to simplify code. Signed-off-by: Yangtao Li Reviewed-by: Abel Vesa Link: https://lore.kernel.org/r/20230705065313.67043-8-frank.li@vivo.com Signed-off-by: Abel Vesa --- drivers/clk/imx/clk-imx8qxp-lpcg.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/clk/imx') diff --git a/drivers/clk/imx/clk-imx8qxp-lpcg.c b/drivers/clk/imx/clk-imx8qxp-lpcg.c index 5e31a6a24b3a..e0ee9a2572d0 100644 --- a/drivers/clk/imx/clk-imx8qxp-lpcg.c +++ b/drivers/clk/imx/clk-imx8qxp-lpcg.c @@ -183,7 +183,6 @@ static int imx_lpcg_parse_clks_from_dt(struct platform_device *pdev, unsigned int bit_offset[IMX_LPCG_MAX_CLKS]; struct clk_hw_onecell_data *clk_data; struct clk_hw **clk_hws; - struct resource *res; void __iomem *base; int count; int idx; @@ -193,8 +192,7 @@ static int imx_lpcg_parse_clks_from_dt(struct platform_device *pdev, if (!of_device_is_compatible(np, "fsl,imx8qxp-lpcg")) return -EINVAL; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(&pdev->dev, res); + base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(base)) return PTR_ERR(base); -- cgit v1.2.3 From d3a0946d7ac9ad844a196f0f2af696fde6b0728d Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Tue, 25 Jul 2023 12:56:24 +0800 Subject: clk: imx: imx8: add audio clock mux driver The Audio Clock Mux (ACM) is a collection of control registers and multiplexers that are used to route the audio source clocks to the audio peripherals. Each audio peripheral has its dedicated audio clock mux (which differ based on usage) and control register. Signed-off-by: Shengjiu Wang Reviewed-by: Peng Fan Reviewed-by: Abel Vesa Link: https://lore.kernel.org/r/1690260984-25744-3-git-send-email-shengjiu.wang@nxp.com Signed-off-by: Abel Vesa --- drivers/clk/imx/Makefile | 3 +- drivers/clk/imx/clk-imx8-acm.c | 476 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 478 insertions(+), 1 deletion(-) create mode 100644 drivers/clk/imx/clk-imx8-acm.c (limited to 'drivers/clk/imx') diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index ae9d84ef046b..d4b8e10b1970 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -32,11 +32,12 @@ obj-$(CONFIG_CLK_IMX8MQ) += clk-imx8mq.o obj-$(CONFIG_CLK_IMX93) += clk-imx93.o -obj-$(CONFIG_MXC_CLK_SCU) += clk-imx-scu.o clk-imx-lpcg-scu.o +obj-$(CONFIG_MXC_CLK_SCU) += clk-imx-scu.o clk-imx-lpcg-scu.o clk-imx-acm.o clk-imx-scu-$(CONFIG_CLK_IMX8QXP) += clk-scu.o clk-imx8qxp.o \ clk-imx8qxp-rsrc.o clk-imx8qm-rsrc.o \ clk-imx8dxl-rsrc.o clk-imx-lpcg-scu-$(CONFIG_CLK_IMX8QXP) += clk-lpcg-scu.o clk-imx8qxp-lpcg.o +clk-imx-acm-$(CONFIG_CLK_IMX8QXP) = clk-imx8-acm.o obj-$(CONFIG_CLK_IMX8ULP) += clk-imx8ulp.o diff --git a/drivers/clk/imx/clk-imx8-acm.c b/drivers/clk/imx/clk-imx8-acm.c new file mode 100644 index 000000000000..1e82f72b75c6 --- /dev/null +++ b/drivers/clk/imx/clk-imx8-acm.c @@ -0,0 +1,476 @@ +// SPDX-License-Identifier: GPL-2.0+ +// +// Copyright 2023 NXP +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "clk.h" + +/** + * struct clk_imx_acm_pm_domains - structure for multi power domain + * @pd_dev: power domain device + * @pd_dev_link: power domain device link + * @num_domains: power domain nummber + */ +struct clk_imx_acm_pm_domains { + struct device **pd_dev; + struct device_link **pd_dev_link; + int num_domains; +}; + +/** + * struct clk_imx8_acm_sel - for clock mux + * @name: clock name + * @clkid: clock id + * @parents: clock parents + * @num_parents: clock parents number + * @reg: register offset + * @shift: bit shift in register + * @width: bits width + */ +struct clk_imx8_acm_sel { + const char *name; + int clkid; + const struct clk_parent_data *parents; /* For mux */ + int num_parents; + u32 reg; + u8 shift; + u8 width; +}; + +/** + * struct imx8_acm_soc_data - soc specific data + * @sels: pointer to struct clk_imx8_acm_sel + * @num_sels: numbers of items + */ +struct imx8_acm_soc_data { + struct clk_imx8_acm_sel *sels; + unsigned int num_sels; +}; + +/** + * struct imx8_acm_priv - private structure + * @dev_pm: multi power domain + * @soc_data: pointer to soc data + * @reg: base address of registers + * @regs: save registers for suspend + */ +struct imx8_acm_priv { + struct clk_imx_acm_pm_domains dev_pm; + const struct imx8_acm_soc_data *soc_data; + void __iomem *reg; + u32 regs[IMX_ADMA_ACM_CLK_END]; +}; + +static const struct clk_parent_data imx8qm_aud_clk_sels[] = { + { .fw_name = "aud_rec_clk0_lpcg_clk" }, + { .fw_name = "aud_rec_clk1_lpcg_clk" }, + { .fw_name = "mlb_clk" }, + { .fw_name = "hdmi_rx_mclk" }, + { .fw_name = "ext_aud_mclk0" }, + { .fw_name = "ext_aud_mclk1" }, + { .fw_name = "esai0_rx_clk" }, + { .fw_name = "esai0_rx_hf_clk" }, + { .fw_name = "esai0_tx_clk" }, + { .fw_name = "esai0_tx_hf_clk" }, + { .fw_name = "esai1_rx_clk" }, + { .fw_name = "esai1_rx_hf_clk" }, + { .fw_name = "esai1_tx_clk" }, + { .fw_name = "esai1_tx_hf_clk" }, + { .fw_name = "spdif0_rx" }, + { .fw_name = "spdif1_rx" }, + { .fw_name = "sai0_rx_bclk" }, + { .fw_name = "sai0_tx_bclk" }, + { .fw_name = "sai1_rx_bclk" }, + { .fw_name = "sai1_tx_bclk" }, + { .fw_name = "sai2_rx_bclk" }, + { .fw_name = "sai3_rx_bclk" }, + { .fw_name = "sai4_rx_bclk" }, +}; + +static const struct clk_parent_data imx8qm_mclk_out_sels[] = { + { .fw_name = "aud_rec_clk0_lpcg_clk" }, + { .fw_name = "aud_rec_clk1_lpcg_clk" }, + { .fw_name = "mlb_clk" }, + { .fw_name = "hdmi_rx_mclk" }, + { .fw_name = "spdif0_rx" }, + { .fw_name = "spdif1_rx" }, + { .fw_name = "sai4_rx_bclk" }, + { .fw_name = "sai6_rx_bclk" }, +}; + +static const struct clk_parent_data imx8qm_mclk_sels[] = { + { .fw_name = "aud_pll_div_clk0_lpcg_clk" }, + { .fw_name = "aud_pll_div_clk1_lpcg_clk" }, + { .fw_name = "acm_aud_clk0_sel" }, + { .fw_name = "acm_aud_clk1_sel" }, +}; + +static const struct clk_parent_data imx8qm_asrc_mux_clk_sels[] = { + { .fw_name = "sai4_rx_bclk" }, + { .fw_name = "sai5_tx_bclk" }, + { .index = -1 }, + { .fw_name = "mlb_clk" }, + +}; + +static struct clk_imx8_acm_sel imx8qm_sels[] = { + { "acm_aud_clk0_sel", IMX_ADMA_ACM_AUD_CLK0_SEL, imx8qm_aud_clk_sels, ARRAY_SIZE(imx8qm_aud_clk_sels), 0x000000, 0, 5 }, + { "acm_aud_clk1_sel", IMX_ADMA_ACM_AUD_CLK1_SEL, imx8qm_aud_clk_sels, ARRAY_SIZE(imx8qm_aud_clk_sels), 0x010000, 0, 5 }, + { "acm_mclkout0_sel", IMX_ADMA_ACM_MCLKOUT0_SEL, imx8qm_mclk_out_sels, ARRAY_SIZE(imx8qm_mclk_out_sels), 0x020000, 0, 3 }, + { "acm_mclkout1_sel", IMX_ADMA_ACM_MCLKOUT1_SEL, imx8qm_mclk_out_sels, ARRAY_SIZE(imx8qm_mclk_out_sels), 0x030000, 0, 3 }, + { "acm_asrc0_mclk_sel", IMX_ADMA_ACM_ASRC0_MUX_CLK_SEL, imx8qm_asrc_mux_clk_sels, ARRAY_SIZE(imx8qm_asrc_mux_clk_sels), 0x040000, 0, 2 }, + { "acm_esai0_mclk_sel", IMX_ADMA_ACM_ESAI0_MCLK_SEL, imx8qm_mclk_sels, ARRAY_SIZE(imx8qm_mclk_sels), 0x060000, 0, 2 }, + { "acm_esai1_mclk_sel", IMX_ADMA_ACM_ESAI1_MCLK_SEL, imx8qm_mclk_sels, ARRAY_SIZE(imx8qm_mclk_sels), 0x070000, 0, 2 }, + { "acm_sai0_mclk_sel", IMX_ADMA_ACM_SAI0_MCLK_SEL, imx8qm_mclk_sels, ARRAY_SIZE(imx8qm_mclk_sels), 0x0E0000, 0, 2 }, + { "acm_sai1_mclk_sel", IMX_ADMA_ACM_SAI1_MCLK_SEL, imx8qm_mclk_sels, ARRAY_SIZE(imx8qm_mclk_sels), 0x0F0000, 0, 2 }, + { "acm_sai2_mclk_sel", IMX_ADMA_ACM_SAI2_MCLK_SEL, imx8qm_mclk_sels, ARRAY_SIZE(imx8qm_mclk_sels), 0x100000, 0, 2 }, + { "acm_sai3_mclk_sel", IMX_ADMA_ACM_SAI3_MCLK_SEL, imx8qm_mclk_sels, ARRAY_SIZE(imx8qm_mclk_sels), 0x110000, 0, 2 }, + { "acm_sai4_mclk_sel", IMX_ADMA_ACM_SAI4_MCLK_SEL, imx8qm_mclk_sels, ARRAY_SIZE(imx8qm_mclk_sels), 0x120000, 0, 2 }, + { "acm_sai5_mclk_sel", IMX_ADMA_ACM_SAI5_MCLK_SEL, imx8qm_mclk_sels, ARRAY_SIZE(imx8qm_mclk_sels), 0x130000, 0, 2 }, + { "acm_sai6_mclk_sel", IMX_ADMA_ACM_SAI6_MCLK_SEL, imx8qm_mclk_sels, ARRAY_SIZE(imx8qm_mclk_sels), 0x140000, 0, 2 }, + { "acm_sai7_mclk_sel", IMX_ADMA_ACM_SAI7_MCLK_SEL, imx8qm_mclk_sels, ARRAY_SIZE(imx8qm_mclk_sels), 0x150000, 0, 2 }, + { "acm_spdif0_mclk_sel", IMX_ADMA_ACM_SPDIF0_TX_CLK_SEL, imx8qm_mclk_sels, ARRAY_SIZE(imx8qm_mclk_sels), 0x1A0000, 0, 2 }, + { "acm_spdif1_mclk_sel", IMX_ADMA_ACM_SPDIF1_TX_CLK_SEL, imx8qm_mclk_sels, ARRAY_SIZE(imx8qm_mclk_sels), 0x1B0000, 0, 2 }, + { "acm_mqs_mclk_sel", IMX_ADMA_ACM_MQS_TX_CLK_SEL, imx8qm_mclk_sels, ARRAY_SIZE(imx8qm_mclk_sels), 0x1C0000, 0, 2 }, +}; + +static const struct clk_parent_data imx8qxp_aud_clk_sels[] = { + { .fw_name = "aud_rec_clk0_lpcg_clk" }, + { .fw_name = "aud_rec_clk1_lpcg_clk" }, + { .fw_name = "ext_aud_mclk0" }, + { .fw_name = "ext_aud_mclk1" }, + { .fw_name = "esai0_rx_clk" }, + { .fw_name = "esai0_rx_hf_clk" }, + { .fw_name = "esai0_tx_clk" }, + { .fw_name = "esai0_tx_hf_clk" }, + { .fw_name = "spdif0_rx" }, + { .fw_name = "sai0_rx_bclk" }, + { .fw_name = "sai0_tx_bclk" }, + { .fw_name = "sai1_rx_bclk" }, + { .fw_name = "sai1_tx_bclk" }, + { .fw_name = "sai2_rx_bclk" }, + { .fw_name = "sai3_rx_bclk" }, +}; + +static const struct clk_parent_data imx8qxp_mclk_out_sels[] = { + { .fw_name = "aud_rec_clk0_lpcg_clk" }, + { .fw_name = "aud_rec_clk1_lpcg_clk" }, + { .index = -1 }, + { .index = -1 }, + { .fw_name = "spdif0_rx" }, + { .index = -1 }, + { .index = -1 }, + { .fw_name = "sai4_rx_bclk" }, +}; + +static const struct clk_parent_data imx8qxp_mclk_sels[] = { + { .fw_name = "aud_pll_div_clk0_lpcg_clk" }, + { .fw_name = "aud_pll_div_clk1_lpcg_clk" }, + { .fw_name = "acm_aud_clk0_sel" }, + { .fw_name = "acm_aud_clk1_sel" }, +}; + +static struct clk_imx8_acm_sel imx8qxp_sels[] = { + { "acm_aud_clk0_sel", IMX_ADMA_ACM_AUD_CLK0_SEL, imx8qxp_aud_clk_sels, ARRAY_SIZE(imx8qxp_aud_clk_sels), 0x000000, 0, 5 }, + { "acm_aud_clk1_sel", IMX_ADMA_ACM_AUD_CLK1_SEL, imx8qxp_aud_clk_sels, ARRAY_SIZE(imx8qxp_aud_clk_sels), 0x010000, 0, 5 }, + { "acm_mclkout0_sel", IMX_ADMA_ACM_MCLKOUT0_SEL, imx8qxp_mclk_out_sels, ARRAY_SIZE(imx8qxp_mclk_out_sels), 0x020000, 0, 3 }, + { "acm_mclkout1_sel", IMX_ADMA_ACM_MCLKOUT1_SEL, imx8qxp_mclk_out_sels, ARRAY_SIZE(imx8qxp_mclk_out_sels), 0x030000, 0, 3 }, + { "acm_esai0_mclk_sel", IMX_ADMA_ACM_ESAI0_MCLK_SEL, imx8qxp_mclk_sels, ARRAY_SIZE(imx8qxp_mclk_sels), 0x060000, 0, 2 }, + { "acm_sai0_mclk_sel", IMX_ADMA_ACM_SAI0_MCLK_SEL, imx8qxp_mclk_sels, ARRAY_SIZE(imx8qxp_mclk_sels), 0x0E0000, 0, 2 }, + { "acm_sai1_mclk_sel", IMX_ADMA_ACM_SAI1_MCLK_SEL, imx8qxp_mclk_sels, ARRAY_SIZE(imx8qxp_mclk_sels), 0x0F0000, 0, 2 }, + { "acm_sai2_mclk_sel", IMX_ADMA_ACM_SAI2_MCLK_SEL, imx8qxp_mclk_sels, ARRAY_SIZE(imx8qxp_mclk_sels), 0x100000, 0, 2 }, + { "acm_sai3_mclk_sel", IMX_ADMA_ACM_SAI3_MCLK_SEL, imx8qxp_mclk_sels, ARRAY_SIZE(imx8qxp_mclk_sels), 0x110000, 0, 2 }, + { "acm_sai4_mclk_sel", IMX_ADMA_ACM_SAI4_MCLK_SEL, imx8qxp_mclk_sels, ARRAY_SIZE(imx8qxp_mclk_sels), 0x140000, 0, 2 }, + { "acm_sai5_mclk_sel", IMX_ADMA_ACM_SAI5_MCLK_SEL, imx8qxp_mclk_sels, ARRAY_SIZE(imx8qxp_mclk_sels), 0x150000, 0, 2 }, + { "acm_spdif0_mclk_sel", IMX_ADMA_ACM_SPDIF0_TX_CLK_SEL, imx8qxp_mclk_sels, ARRAY_SIZE(imx8qxp_mclk_sels), 0x1A0000, 0, 2 }, + { "acm_mqs_mclk_sel", IMX_ADMA_ACM_MQS_TX_CLK_SEL, imx8qxp_mclk_sels, ARRAY_SIZE(imx8qxp_mclk_sels), 0x1C0000, 0, 2 }, +}; + +static const struct clk_parent_data imx8dxl_aud_clk_sels[] = { + { .fw_name = "aud_rec_clk0_lpcg_clk" }, + { .fw_name = "aud_rec_clk1_lpcg_clk" }, + { .fw_name = "ext_aud_mclk0" }, + { .fw_name = "ext_aud_mclk1" }, + { .index = -1 }, + { .index = -1 }, + { .index = -1 }, + { .index = -1 }, + { .fw_name = "spdif0_rx" }, + { .fw_name = "sai0_rx_bclk" }, + { .fw_name = "sai0_tx_bclk" }, + { .fw_name = "sai1_rx_bclk" }, + { .fw_name = "sai1_tx_bclk" }, + { .fw_name = "sai2_rx_bclk" }, + { .fw_name = "sai3_rx_bclk" }, +}; + +static const struct clk_parent_data imx8dxl_mclk_out_sels[] = { + { .fw_name = "aud_rec_clk0_lpcg_clk" }, + { .fw_name = "aud_rec_clk1_lpcg_clk" }, + { .index = -1 }, + { .index = -1 }, + { .fw_name = "spdif0_rx" }, + { .index = -1 }, + { .index = -1 }, + { .index = -1 }, +}; + +static const struct clk_parent_data imx8dxl_mclk_sels[] = { + { .fw_name = "aud_pll_div_clk0_lpcg_clk" }, + { .fw_name = "aud_pll_div_clk1_lpcg_clk" }, + { .fw_name = "acm_aud_clk0_sel" }, + { .fw_name = "acm_aud_clk1_sel" }, +}; + +static struct clk_imx8_acm_sel imx8dxl_sels[] = { + { "acm_aud_clk0_sel", IMX_ADMA_ACM_AUD_CLK0_SEL, imx8dxl_aud_clk_sels, ARRAY_SIZE(imx8dxl_aud_clk_sels), 0x000000, 0, 5 }, + { "acm_aud_clk1_sel", IMX_ADMA_ACM_AUD_CLK1_SEL, imx8dxl_aud_clk_sels, ARRAY_SIZE(imx8dxl_aud_clk_sels), 0x010000, 0, 5 }, + { "acm_mclkout0_sel", IMX_ADMA_ACM_MCLKOUT0_SEL, imx8dxl_mclk_out_sels, ARRAY_SIZE(imx8dxl_mclk_out_sels), 0x020000, 0, 3 }, + { "acm_mclkout1_sel", IMX_ADMA_ACM_MCLKOUT1_SEL, imx8dxl_mclk_out_sels, ARRAY_SIZE(imx8dxl_mclk_out_sels), 0x030000, 0, 3 }, + { "acm_sai0_mclk_sel", IMX_ADMA_ACM_SAI0_MCLK_SEL, imx8dxl_mclk_sels, ARRAY_SIZE(imx8dxl_mclk_sels), 0x0E0000, 0, 2 }, + { "acm_sai1_mclk_sel", IMX_ADMA_ACM_SAI1_MCLK_SEL, imx8dxl_mclk_sels, ARRAY_SIZE(imx8dxl_mclk_sels), 0x0F0000, 0, 2 }, + { "acm_sai2_mclk_sel", IMX_ADMA_ACM_SAI2_MCLK_SEL, imx8dxl_mclk_sels, ARRAY_SIZE(imx8dxl_mclk_sels), 0x100000, 0, 2 }, + { "acm_sai3_mclk_sel", IMX_ADMA_ACM_SAI3_MCLK_SEL, imx8dxl_mclk_sels, ARRAY_SIZE(imx8dxl_mclk_sels), 0x110000, 0, 2 }, + { "acm_spdif0_mclk_sel", IMX_ADMA_ACM_SPDIF0_TX_CLK_SEL, imx8dxl_mclk_sels, ARRAY_SIZE(imx8dxl_mclk_sels), 0x1A0000, 0, 2 }, + { "acm_mqs_mclk_sel", IMX_ADMA_ACM_MQS_TX_CLK_SEL, imx8dxl_mclk_sels, ARRAY_SIZE(imx8dxl_mclk_sels), 0x1C0000, 0, 2 }, +}; + +/** + * clk_imx_acm_attach_pm_domains: attach multi power domains + * @dev: device pointer + * @dev_pm: power domains for device + */ +static int clk_imx_acm_attach_pm_domains(struct device *dev, + struct clk_imx_acm_pm_domains *dev_pm) +{ + int ret; + int i; + + dev_pm->num_domains = of_count_phandle_with_args(dev->of_node, "power-domains", + "#power-domain-cells"); + if (dev_pm->num_domains <= 1) + return 0; + + dev_pm->pd_dev = devm_kmalloc_array(dev, dev_pm->num_domains, + sizeof(*dev_pm->pd_dev), + GFP_KERNEL); + if (!dev_pm->pd_dev) + return -ENOMEM; + + dev_pm->pd_dev_link = devm_kmalloc_array(dev, + dev_pm->num_domains, + sizeof(*dev_pm->pd_dev_link), + GFP_KERNEL); + if (!dev_pm->pd_dev_link) + return -ENOMEM; + + for (i = 0; i < dev_pm->num_domains; i++) { + dev_pm->pd_dev[i] = dev_pm_domain_attach_by_id(dev, i); + if (IS_ERR(dev_pm->pd_dev[i])) + return PTR_ERR(dev_pm->pd_dev[i]); + + dev_pm->pd_dev_link[i] = device_link_add(dev, + dev_pm->pd_dev[i], + DL_FLAG_STATELESS | + DL_FLAG_PM_RUNTIME | + DL_FLAG_RPM_ACTIVE); + if (IS_ERR(dev_pm->pd_dev_link[i])) { + dev_pm_domain_detach(dev_pm->pd_dev[i], false); + ret = PTR_ERR(dev_pm->pd_dev_link[i]); + goto detach_pm; + } + } + return 0; + +detach_pm: + while (--i >= 0) { + device_link_del(dev_pm->pd_dev_link[i]); + dev_pm_domain_detach(dev_pm->pd_dev[i], false); + } + return ret; +} + +/** + * clk_imx_acm_detach_pm_domains: detach multi power domains + * @dev: deivice pointer + * @dev_pm: multi power domain for device + */ +static int clk_imx_acm_detach_pm_domains(struct device *dev, + struct clk_imx_acm_pm_domains *dev_pm) +{ + int i; + + if (dev_pm->num_domains <= 1) + return 0; + + for (i = 0; i < dev_pm->num_domains; i++) { + device_link_del(dev_pm->pd_dev_link[i]); + dev_pm_domain_detach(dev_pm->pd_dev[i], false); + } + + return 0; +} + +static int imx8_acm_clk_probe(struct platform_device *pdev) +{ + struct clk_hw_onecell_data *clk_hw_data; + struct device *dev = &pdev->dev; + struct clk_imx8_acm_sel *sels; + struct imx8_acm_priv *priv; + struct clk_hw **hws; + void __iomem *base; + int ret; + int i; + + base = devm_of_iomap(dev, dev->of_node, 0, NULL); + if (WARN_ON(IS_ERR(base))) + return PTR_ERR(base); + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->reg = base; + priv->soc_data = of_device_get_match_data(dev); + platform_set_drvdata(pdev, priv); + + clk_hw_data = devm_kzalloc(&pdev->dev, struct_size(clk_hw_data, hws, IMX_ADMA_ACM_CLK_END), + GFP_KERNEL); + if (!clk_hw_data) + return -ENOMEM; + + clk_hw_data->num = IMX_ADMA_ACM_CLK_END; + hws = clk_hw_data->hws; + + ret = clk_imx_acm_attach_pm_domains(&pdev->dev, &priv->dev_pm); + if (ret) + return ret; + + pm_runtime_enable(&pdev->dev); + pm_runtime_get_sync(&pdev->dev); + + sels = priv->soc_data->sels; + for (i = 0; i < priv->soc_data->num_sels; i++) { + hws[sels[i].clkid] = devm_clk_hw_register_mux_parent_data_table(dev, + sels[i].name, sels[i].parents, + sels[i].num_parents, 0, + base + sels[i].reg, + sels[i].shift, sels[i].width, + 0, NULL, NULL); + if (IS_ERR(hws[sels[i].clkid])) { + pm_runtime_disable(&pdev->dev); + goto err_clk_register; + } + } + + imx_check_clk_hws(hws, IMX_ADMA_ACM_CLK_END); + + ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, clk_hw_data); + if (ret < 0) { + dev_err(dev, "failed to register hws for ACM\n"); + pm_runtime_disable(&pdev->dev); + } + +err_clk_register: + + pm_runtime_put_sync(&pdev->dev); + + return ret; +} + +static int imx8_acm_clk_remove(struct platform_device *pdev) +{ + struct imx8_acm_priv *priv = dev_get_drvdata(&pdev->dev); + + pm_runtime_disable(&pdev->dev); + + clk_imx_acm_detach_pm_domains(&pdev->dev, &priv->dev_pm); + + return 0; +} + +static const struct imx8_acm_soc_data imx8qm_acm_data = { + .sels = imx8qm_sels, + .num_sels = ARRAY_SIZE(imx8qm_sels), +}; + +static const struct imx8_acm_soc_data imx8qxp_acm_data = { + .sels = imx8qxp_sels, + .num_sels = ARRAY_SIZE(imx8qxp_sels), +}; + +static const struct imx8_acm_soc_data imx8dxl_acm_data = { + .sels = imx8dxl_sels, + .num_sels = ARRAY_SIZE(imx8dxl_sels), +}; + +static const struct of_device_id imx8_acm_match[] = { + { .compatible = "fsl,imx8qm-acm", .data = &imx8qm_acm_data }, + { .compatible = "fsl,imx8qxp-acm", .data = &imx8qxp_acm_data }, + { .compatible = "fsl,imx8dxl-acm", .data = &imx8dxl_acm_data }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, imx8_acm_match); + +static int __maybe_unused imx8_acm_runtime_suspend(struct device *dev) +{ + struct imx8_acm_priv *priv = dev_get_drvdata(dev); + struct clk_imx8_acm_sel *sels; + int i; + + sels = priv->soc_data->sels; + + for (i = 0; i < priv->soc_data->num_sels; i++) + priv->regs[i] = readl_relaxed(priv->reg + sels[i].reg); + + return 0; +} + +static int __maybe_unused imx8_acm_runtime_resume(struct device *dev) +{ + struct imx8_acm_priv *priv = dev_get_drvdata(dev); + struct clk_imx8_acm_sel *sels; + int i; + + sels = priv->soc_data->sels; + + for (i = 0; i < priv->soc_data->num_sels; i++) + writel_relaxed(priv->regs[i], priv->reg + sels[i].reg); + + return 0; +} + +static const struct dev_pm_ops imx8_acm_pm_ops = { + SET_RUNTIME_PM_OPS(imx8_acm_runtime_suspend, + imx8_acm_runtime_resume, NULL) + SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) +}; + +static struct platform_driver imx8_acm_clk_driver = { + .driver = { + .name = "imx8-acm", + .of_match_table = imx8_acm_match, + .pm = &imx8_acm_pm_ops, + }, + .probe = imx8_acm_clk_probe, + .remove = imx8_acm_clk_remove, +}; +module_platform_driver(imx8_acm_clk_driver); + +MODULE_AUTHOR("Shengjiu Wang "); +MODULE_DESCRIPTION("Freescale i.MX8 Audio Clock Mux driver"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 3f0cdb945471f1abd1cf4d172190e9c489c5052a Mon Sep 17 00:00:00 2001 From: Ye Li Date: Sun, 25 Jun 2023 20:33:39 +0800 Subject: clk: imx: pllv4: Fix SPLL2 MULT range The SPLL2 on iMX8ULP is different with other frac PLLs, it can support VCO from 650Mhz to 1Ghz. According to RM, the MULT is using a range from 27 to 54, not some fixed values. If using current PLL implementation, some clock rate can't be supported. Fix the issue by adding new type for the SPLL2 and use MULT range to replace MULT table Fixes: 5f0601c47c33 ("clk: imx: Update the pllv4 to support imx8ulp") Reviewed-by: Peng Fan Reviewed-by: Jacky Bai Signed-off-by: Ye Li Signed-off-by: Peng Fan Reviewed-by: Abel Vesa Link: https://lore.kernel.org/r/20230625123340.4067536-1-peng.fan@oss.nxp.com Signed-off-by: Abel Vesa --- drivers/clk/imx/clk-pllv4.c | 46 +++++++++++++++++++++++++++++++++++---------- drivers/clk/imx/clk.h | 1 + 2 files changed, 37 insertions(+), 10 deletions(-) (limited to 'drivers/clk/imx') diff --git a/drivers/clk/imx/clk-pllv4.c b/drivers/clk/imx/clk-pllv4.c index 6e7e34571fc8..9b136c951762 100644 --- a/drivers/clk/imx/clk-pllv4.c +++ b/drivers/clk/imx/clk-pllv4.c @@ -44,11 +44,15 @@ struct clk_pllv4 { u32 cfg_offset; u32 num_offset; u32 denom_offset; + bool use_mult_range; }; /* Valid PLL MULT Table */ static const int pllv4_mult_table[] = {33, 27, 22, 20, 17, 16}; +/* Valid PLL MULT range, (max, min) */ +static const int pllv4_mult_range[] = {54, 27}; + #define to_clk_pllv4(__hw) container_of(__hw, struct clk_pllv4, hw) #define LOCK_TIMEOUT_US USEC_PER_MSEC @@ -94,17 +98,30 @@ static unsigned long clk_pllv4_recalc_rate(struct clk_hw *hw, static long clk_pllv4_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *prate) { + struct clk_pllv4 *pll = to_clk_pllv4(hw); unsigned long parent_rate = *prate; unsigned long round_rate, i; u32 mfn, mfd = DEFAULT_MFD; bool found = false; u64 temp64; - - for (i = 0; i < ARRAY_SIZE(pllv4_mult_table); i++) { - round_rate = parent_rate * pllv4_mult_table[i]; - if (rate >= round_rate) { + u32 mult; + + if (pll->use_mult_range) { + temp64 = (u64)rate; + do_div(temp64, parent_rate); + mult = temp64; + if (mult >= pllv4_mult_range[1] && + mult <= pllv4_mult_range[0]) { + round_rate = parent_rate * mult; found = true; - break; + } + } else { + for (i = 0; i < ARRAY_SIZE(pllv4_mult_table); i++) { + round_rate = parent_rate * pllv4_mult_table[i]; + if (rate >= round_rate) { + found = true; + break; + } } } @@ -138,14 +155,20 @@ static long clk_pllv4_round_rate(struct clk_hw *hw, unsigned long rate, return round_rate + (u32)temp64; } -static bool clk_pllv4_is_valid_mult(unsigned int mult) +static bool clk_pllv4_is_valid_mult(struct clk_pllv4 *pll, unsigned int mult) { int i; /* check if mult is in valid MULT table */ - for (i = 0; i < ARRAY_SIZE(pllv4_mult_table); i++) { - if (pllv4_mult_table[i] == mult) + if (pll->use_mult_range) { + if (mult >= pllv4_mult_range[1] && + mult <= pllv4_mult_range[0]) return true; + } else { + for (i = 0; i < ARRAY_SIZE(pllv4_mult_table); i++) { + if (pllv4_mult_table[i] == mult) + return true; + } } return false; @@ -160,7 +183,7 @@ static int clk_pllv4_set_rate(struct clk_hw *hw, unsigned long rate, mult = rate / parent_rate; - if (!clk_pllv4_is_valid_mult(mult)) + if (!clk_pllv4_is_valid_mult(pll, mult)) return -EINVAL; if (parent_rate <= MAX_MFD) @@ -227,10 +250,13 @@ struct clk_hw *imx_clk_hw_pllv4(enum imx_pllv4_type type, const char *name, pll->base = base; - if (type == IMX_PLLV4_IMX8ULP) { + if (type == IMX_PLLV4_IMX8ULP || + type == IMX_PLLV4_IMX8ULP_1GHZ) { pll->cfg_offset = IMX8ULP_PLL_CFG_OFFSET; pll->num_offset = IMX8ULP_PLL_NUM_OFFSET; pll->denom_offset = IMX8ULP_PLL_DENOM_OFFSET; + if (type == IMX_PLLV4_IMX8ULP_1GHZ) + pll->use_mult_range = true; } else { pll->cfg_offset = PLL_CFG_OFFSET; pll->num_offset = PLL_NUM_OFFSET; diff --git a/drivers/clk/imx/clk.h b/drivers/clk/imx/clk.h index af19d9f6aed0..adb7ad649a0d 100644 --- a/drivers/clk/imx/clk.h +++ b/drivers/clk/imx/clk.h @@ -45,6 +45,7 @@ enum imx_pll14xx_type { enum imx_pllv4_type { IMX_PLLV4_IMX7ULP, IMX_PLLV4_IMX8ULP, + IMX_PLLV4_IMX8ULP_1GHZ, }; enum imx_pfdv2_type { -- cgit v1.2.3 From 7653a59be8af043adc4c09473975a860e6055ff9 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Sun, 25 Jun 2023 20:33:40 +0800 Subject: clk: imx: imx8ulp: update SPLL2 type The SPLL2 on iMX8ULP is different with other frac PLLs, it can support VCO from 650Mhz to 1Ghz. Following the changes to pllv4, use the new type IMX_PLLV4_IMX8ULP_1GHZ. Fixes: c43a801a5789 ("clk: imx: Add clock driver for imx8ulp") Signed-off-by: Peng Fan Reviewed-by: Abel Vesa Link: https://lore.kernel.org/r/20230625123340.4067536-2-peng.fan@oss.nxp.com Signed-off-by: Abel Vesa --- drivers/clk/imx/clk-imx8ulp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/clk/imx') diff --git a/drivers/clk/imx/clk-imx8ulp.c b/drivers/clk/imx/clk-imx8ulp.c index e308c88cb801..1b04e2fc78ad 100644 --- a/drivers/clk/imx/clk-imx8ulp.c +++ b/drivers/clk/imx/clk-imx8ulp.c @@ -167,7 +167,7 @@ static int imx8ulp_clk_cgc1_init(struct platform_device *pdev) clks[IMX8ULP_CLK_SPLL2_PRE_SEL] = imx_clk_hw_mux_flags("spll2_pre_sel", base + 0x510, 0, 1, pll_pre_sels, ARRAY_SIZE(pll_pre_sels), CLK_SET_PARENT_GATE); clks[IMX8ULP_CLK_SPLL3_PRE_SEL] = imx_clk_hw_mux_flags("spll3_pre_sel", base + 0x610, 0, 1, pll_pre_sels, ARRAY_SIZE(pll_pre_sels), CLK_SET_PARENT_GATE); - clks[IMX8ULP_CLK_SPLL2] = imx_clk_hw_pllv4(IMX_PLLV4_IMX8ULP, "spll2", "spll2_pre_sel", base + 0x500); + clks[IMX8ULP_CLK_SPLL2] = imx_clk_hw_pllv4(IMX_PLLV4_IMX8ULP_1GHZ, "spll2", "spll2_pre_sel", base + 0x500); clks[IMX8ULP_CLK_SPLL3] = imx_clk_hw_pllv4(IMX_PLLV4_IMX8ULP, "spll3", "spll3_pre_sel", base + 0x600); clks[IMX8ULP_CLK_SPLL3_VCODIV] = imx_clk_hw_divider("spll3_vcodiv", "spll3", base + 0x604, 0, 6); -- cgit v1.2.3 From c30f600f1f41dcf5ef0fb02e9a201f9b2e8f31bd Mon Sep 17 00:00:00 2001 From: Marco Felsch Date: Mon, 31 Jul 2023 16:21:49 +0200 Subject: clk: imx8mp: fix sai4 clock The reference manual don't mention a SAI4 hardware block. This would be clock slice 78 which is skipped (TRM, page 237). Remove any reference to this clock to align the driver with the reality. Fixes: 9c140d992676 ("clk: imx: Add support for i.MX8MP clock driver") Acked-by: Stephen Boyd Signed-off-by: Marco Felsch Link: https://lore.kernel.org/r/20230731142150.3186650-1-m.felsch@pengutronix.de Signed-off-by: Abel Vesa --- drivers/clk/imx/clk-imx8mp.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers/clk/imx') diff --git a/drivers/clk/imx/clk-imx8mp.c b/drivers/clk/imx/clk-imx8mp.c index 1469249386dd..670aa2bab301 100644 --- a/drivers/clk/imx/clk-imx8mp.c +++ b/drivers/clk/imx/clk-imx8mp.c @@ -178,10 +178,6 @@ static const char * const imx8mp_sai3_sels[] = {"osc_24m", "audio_pll1_out", "au "video_pll1_out", "sys_pll1_133m", "osc_hdmi", "clk_ext3", "clk_ext4", }; -static const char * const imx8mp_sai4_sels[] = {"osc_24m", "audio_pll1_out", "audio_pll2_out", - "video_pll1_out", "sys_pll1_133m", "osc_hdmi", - "clk_ext1", "clk_ext2", }; - static const char * const imx8mp_sai5_sels[] = {"osc_24m", "audio_pll1_out", "audio_pll2_out", "video_pll1_out", "sys_pll1_133m", "osc_hdmi", "clk_ext2", "clk_ext3", }; @@ -567,7 +563,6 @@ static int imx8mp_clocks_probe(struct platform_device *pdev) hws[IMX8MP_CLK_SAI1] = imx8m_clk_hw_composite("sai1", imx8mp_sai1_sels, ccm_base + 0xa580); hws[IMX8MP_CLK_SAI2] = imx8m_clk_hw_composite("sai2", imx8mp_sai2_sels, ccm_base + 0xa600); hws[IMX8MP_CLK_SAI3] = imx8m_clk_hw_composite("sai3", imx8mp_sai3_sels, ccm_base + 0xa680); - hws[IMX8MP_CLK_SAI4] = imx8m_clk_hw_composite("sai4", imx8mp_sai4_sels, ccm_base + 0xa700); hws[IMX8MP_CLK_SAI5] = imx8m_clk_hw_composite("sai5", imx8mp_sai5_sels, ccm_base + 0xa780); hws[IMX8MP_CLK_SAI6] = imx8m_clk_hw_composite("sai6", imx8mp_sai6_sels, ccm_base + 0xa800); hws[IMX8MP_CLK_ENET_QOS] = imx8m_clk_hw_composite("enet_qos", imx8mp_enet_qos_sels, ccm_base + 0xa880); -- cgit v1.2.3 From b8a06b125c245eb946d88847e052294a85b206c3 Mon Sep 17 00:00:00 2001 From: Martin Kaiser Date: Wed, 2 Aug 2023 20:40:45 +0200 Subject: clk: imx25: print silicon revision during init Print the imx25 silicon revision when the clocks are initialised. Use the same mechanism as for imx27, i.e. call mx25_revision. This function is unused at the moment. Signed-off-by: Martin Kaiser Reviewed-by: Fabio Estevam Acked-by: Arnd Bergmann Acked-by: Stephen Boyd Link: https://lore.kernel.org/r/20230802184046.153394-2-martin@kaiser.cx Signed-off-by: Abel Vesa --- drivers/clk/imx/clk-imx25.c | 3 +++ include/soc/imx/revision.h | 1 + 2 files changed, 4 insertions(+) (limited to 'drivers/clk/imx') diff --git a/drivers/clk/imx/clk-imx25.c b/drivers/clk/imx/clk-imx25.c index cc013b343e62..bee3da2e21e1 100644 --- a/drivers/clk/imx/clk-imx25.c +++ b/drivers/clk/imx/clk-imx25.c @@ -13,6 +13,7 @@ #include #include #include +#include #include "clk.h" @@ -220,6 +221,8 @@ static int __init __mx25_clocks_init(void __iomem *ccm_base) imx_register_uart_clocks(); + imx_print_silicon_rev("i.MX25", mx25_revision()); + return 0; } diff --git a/include/soc/imx/revision.h b/include/soc/imx/revision.h index b2a55dafaf0a..b122d2fc8881 100644 --- a/include/soc/imx/revision.h +++ b/include/soc/imx/revision.h @@ -22,6 +22,7 @@ #define IMX_CHIP_REVISION_3_3 0x33 #define IMX_CHIP_REVISION_UNKNOWN 0xff +int mx25_revision(void); int mx27_revision(void); int mx31_revision(void); int mx35_revision(void); -- cgit v1.2.3 From 5dc176079b7a8ba7ff89db10e0c9784856c79d7f Mon Sep 17 00:00:00 2001 From: Martin Kaiser Date: Wed, 2 Aug 2023 20:40:46 +0200 Subject: clk: imx25: make __mx25_clocks_init return void The __mx25_clocks_init function always returns 0 and its only caller does not check the return value. Let's remove it. Signed-off-by: Martin Kaiser Reviewed-by: Fabio Estevam Acked-by: Arnd Bergmann Acked-by: Stephen Boyd Link: https://lore.kernel.org/r/20230802184046.153394-3-martin@kaiser.cx Signed-off-by: Abel Vesa --- drivers/clk/imx/clk-imx25.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/clk/imx') diff --git a/drivers/clk/imx/clk-imx25.c b/drivers/clk/imx/clk-imx25.c index bee3da2e21e1..c566be848c2d 100644 --- a/drivers/clk/imx/clk-imx25.c +++ b/drivers/clk/imx/clk-imx25.c @@ -74,7 +74,7 @@ enum mx25_clks { static struct clk *clk[clk_max]; -static int __init __mx25_clocks_init(void __iomem *ccm_base) +static void __init __mx25_clocks_init(void __iomem *ccm_base) { BUG_ON(!ccm_base); @@ -222,8 +222,6 @@ static int __init __mx25_clocks_init(void __iomem *ccm_base) imx_register_uart_clocks(); imx_print_silicon_rev("i.MX25", mx25_revision()); - - return 0; } static void __init mx25_clocks_init_dt(struct device_node *np) -- cgit v1.2.3 From 4dd432d985ef258e3bc436e568fba4b987b59171 Mon Sep 17 00:00:00 2001 From: Ahmad Fatoum Date: Mon, 7 Aug 2023 10:22:00 +0200 Subject: clk: imx: composite-8m: fix clock pauses when set_rate would be a no-op Reconfiguring the clock divider to the exact same value is observed on an i.MX8MN to often cause a longer than usual clock pause, probably because the divider restarts counting whenever the register is rewritten. This issue doesn't show up normally, because the clock framework will take care to not call set_rate when the clock rate is the same. However, when we reconfigure an upstream clock, the common code will call set_rate with the newly calculated rate on all children, e.g.: - sai5 is running normally and divides Audio PLL out by 16. - Audio PLL rate is increased by 32Hz (glitch-free kdiv change) - rates for children are recalculated and rates are set recursively - imx8m_clk_composite_divider_set_rate(sai5) is called with 32/16 = 2Hz more - imx8m_clk_composite_divider_set_rate computes same divider as before - divider register is written, so it restarts counting from zero and MCLK is briefly paused, so instead of e.g. 40ns, MCLK is low for 120ns. Some external clock consumers can be upset by such unexpected clock pauses, so let's make sure we only rewrite the divider value when the value to be written is actually different. Fixes: d3ff9728134e ("clk: imx: Add imx composite clock") Signed-off-by: Ahmad Fatoum Reviewed-by: Peng Fan Link: https://lore.kernel.org/r/20230807082201.2332746-1-a.fatoum@pengutronix.de Signed-off-by: Abel Vesa --- drivers/clk/imx/clk-composite-8m.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'drivers/clk/imx') diff --git a/drivers/clk/imx/clk-composite-8m.c b/drivers/clk/imx/clk-composite-8m.c index 7a6e3ce97133..27a08c50ac1d 100644 --- a/drivers/clk/imx/clk-composite-8m.c +++ b/drivers/clk/imx/clk-composite-8m.c @@ -97,7 +97,7 @@ static int imx8m_clk_composite_divider_set_rate(struct clk_hw *hw, int prediv_value; int div_value; int ret; - u32 val; + u32 orig, val; ret = imx8m_clk_composite_compute_dividers(rate, parent_rate, &prediv_value, &div_value); @@ -106,13 +106,15 @@ static int imx8m_clk_composite_divider_set_rate(struct clk_hw *hw, spin_lock_irqsave(divider->lock, flags); - val = readl(divider->reg); - val &= ~((clk_div_mask(divider->width) << divider->shift) | - (clk_div_mask(PCG_DIV_WIDTH) << PCG_DIV_SHIFT)); + orig = readl(divider->reg); + val = orig & ~((clk_div_mask(divider->width) << divider->shift) | + (clk_div_mask(PCG_DIV_WIDTH) << PCG_DIV_SHIFT)); val |= (u32)(prediv_value - 1) << divider->shift; val |= (u32)(div_value - 1) << PCG_DIV_SHIFT; - writel(val, divider->reg); + + if (val != orig) + writel(val, divider->reg); spin_unlock_irqrestore(divider->lock, flags); -- cgit v1.2.3 From 37cfd5e457cbdcd030f378127ff2d62776f641e7 Mon Sep 17 00:00:00 2001 From: Marco Felsch Date: Mon, 7 Aug 2023 10:47:43 +0200 Subject: clk: imx: pll14xx: align pdiv with reference manual The PLL14xx hardware can be found on i.MX8M{M,N,P} SoCs and always come with a 6-bit pre-divider. Neither the reference manuals nor the datasheets of these SoCs do mention any restrictions. Furthermore the current code doesn't respect the restrictions from the comment too. Therefore drop the restriction and align the max pre-divider (pdiv) value to 63 to get more accurate frequencies. Fixes: b09c68dc57c9 ("clk: imx: pll14xx: Support dynamic rates") Cc: stable@vger.kernel.org Signed-off-by: Marco Felsch Reviewed-by: Abel Vesa Reviewed-by: Adam Ford Signed-off-by: Philipp Zabel Acked-by: Sascha Hauer Tested-by: Ahmad Fatoum Link: https://lore.kernel.org/r/20230807084744.1184791-1-m.felsch@pengutronix.de Signed-off-by: Abel Vesa --- drivers/clk/imx/clk-pll14xx.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'drivers/clk/imx') diff --git a/drivers/clk/imx/clk-pll14xx.c b/drivers/clk/imx/clk-pll14xx.c index 7150c59bbfc9..dc6bc21dff41 100644 --- a/drivers/clk/imx/clk-pll14xx.c +++ b/drivers/clk/imx/clk-pll14xx.c @@ -139,11 +139,10 @@ static void imx_pll14xx_calc_settings(struct clk_pll14xx *pll, unsigned long rat /* * Fractional PLL constrains: * - * a) 6MHz <= prate <= 25MHz - * b) 1 <= p <= 63 (1 <= p <= 4 prate = 24MHz) - * c) 64 <= m <= 1023 - * d) 0 <= s <= 6 - * e) -32768 <= k <= 32767 + * a) 1 <= p <= 63 + * b) 64 <= m <= 1023 + * c) 0 <= s <= 6 + * d) -32768 <= k <= 32767 * * fvco = (m * 65536 + k) * prate / (p * 65536) */ @@ -186,7 +185,7 @@ static void imx_pll14xx_calc_settings(struct clk_pll14xx *pll, unsigned long rat } /* Finally calculate best values */ - for (pdiv = 1; pdiv <= 7; pdiv++) { + for (pdiv = 1; pdiv <= 63; pdiv++) { for (sdiv = 0; sdiv <= 6; sdiv++) { /* calc mdiv = round(rate * pdiv * 2^sdiv) / prate) */ mdiv = DIV_ROUND_CLOSEST(rate * (pdiv << sdiv), prate); -- cgit v1.2.3 From 72d00e560d10665e6139c9431956a87ded6e9880 Mon Sep 17 00:00:00 2001 From: Ahmad Fatoum Date: Mon, 7 Aug 2023 10:47:44 +0200 Subject: clk: imx: pll14xx: dynamically configure PLL for 393216000/361267200Hz Since commit b09c68dc57c9 ("clk: imx: pll14xx: Support dynamic rates"), the driver has the ability to dynamically compute PLL parameters to approximate the requested rates. This is not always used, because the logic is as follows: - Check if the target rate is hardcoded in the frequency table - Check if varying only kdiv is possible, so switch over is glitch free - Compute rate dynamically by iterating over pdiv range If we skip the frequency table for the 1443x PLL, we find that the computed values differ to the hardcoded ones. This can be valid if the hardcoded values guarantee for example an earlier lock-in or if the divisors are chosen, so that other important rates are more likely to be reached glitch-free. For rates (393216000 and 361267200, this doesn't seem to be the case: They are only approximated by existing parameters (393215995 and 361267196 Hz, respectively) and they aren't reachable glitch-free from other hardcoded frequencies. Dropping them from the table allows us to lock-in to these frequencies exactly. This is immediately noticeable because they are the assigned-clock-rates for IMX8MN_AUDIO_PLL1 and IMX8MN_AUDIO_PLL2, respectively and a look into clk_summary so far showed that they were a few Hz short of the target: imx8mn-board:~# grep audio_pll[12]_out /sys/kernel/debug/clk/clk_summary audio_pll2_out 0 0 0 361267196 0 0 50000 N audio_pll1_out 1 1 0 393215995 0 0 50000 Y and afterwards: imx8mn-board:~# grep audio_pll[12]_out /sys/kernel/debug/clk/clk_summary audio_pll2_out 0 0 0 361267200 0 0 50000 N audio_pll1_out 1 1 0 393216000 0 0 50000 Y This change is equivalent to adding following hardcoded values: /* rate mdiv pdiv sdiv kdiv */ PLL_1443X_RATE(393216000, 655, 5, 3, 23593), PLL_1443X_RATE(361267200, 497, 33, 0, -16882), Fixes: 053a4ffe2988 ("clk: imx: imx8mm: fix audio pll setting") Cc: stable@vger.kernel.org # v5.18+ Signed-off-by: Ahmad Fatoum Signed-off-by: Marco Felsch Link: https://lore.kernel.org/r/20230807084744.1184791-2-m.felsch@pengutronix.de Signed-off-by: Abel Vesa --- drivers/clk/imx/clk-pll14xx.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/clk/imx') diff --git a/drivers/clk/imx/clk-pll14xx.c b/drivers/clk/imx/clk-pll14xx.c index dc6bc21dff41..0d58d85c375e 100644 --- a/drivers/clk/imx/clk-pll14xx.c +++ b/drivers/clk/imx/clk-pll14xx.c @@ -64,8 +64,6 @@ static const struct imx_pll14xx_rate_table imx_pll1443x_tbl[] = { PLL_1443X_RATE(650000000U, 325, 3, 2, 0), PLL_1443X_RATE(594000000U, 198, 2, 2, 0), PLL_1443X_RATE(519750000U, 173, 2, 2, 16384), - PLL_1443X_RATE(393216000U, 262, 2, 3, 9437), - PLL_1443X_RATE(361267200U, 361, 3, 3, 17511), }; struct imx_pll14xx_clk imx_1443x_pll = { -- cgit v1.2.3