From 731237359d83bfb4f27eea5b7a8935af5c72a5ac Mon Sep 17 00:00:00 2001 From: Richard Zhu Date: Tue, 15 Oct 2024 15:34:03 +0800 Subject: [PATCH 01/12] dt-bindings: clock: nxp,imx95-blk-ctl: Add compatible string for i.MX95 HSIO BLK CTRL Sort compatible entries by alphabetical order. Then, add compatible string "nxp,imx95-hsio-blk-ctl" for i.MX95. Signed-off-by: Richard Zhu Acked-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/1728977644-8207-2-git-send-email-hongxing.zhu@nxp.com Signed-off-by: Abel Vesa --- .../devicetree/bindings/clock/nxp,imx95-blk-ctl.yaml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/clock/nxp,imx95-blk-ctl.yaml b/Documentation/devicetree/bindings/clock/nxp,imx95-blk-ctl.yaml index 5dc360b2ea4b..d0291bfff23a 100644 --- a/Documentation/devicetree/bindings/clock/nxp,imx95-blk-ctl.yaml +++ b/Documentation/devicetree/bindings/clock/nxp,imx95-blk-ctl.yaml @@ -13,9 +13,10 @@ properties: compatible: items: - enum: - - nxp,imx95-lvds-csr - - nxp,imx95-display-csr - nxp,imx95-camera-csr + - nxp,imx95-display-csr + - nxp,imx95-hsio-blk-ctl + - nxp,imx95-lvds-csr - nxp,imx95-netcmix-blk-ctrl - nxp,imx95-vpu-csr - const: syscon From cf295252f0d88410d5793fa6db56a7192a65d66f Mon Sep 17 00:00:00 2001 From: Richard Zhu Date: Tue, 15 Oct 2024 15:34:04 +0800 Subject: [PATCH 02/12] clk: imx95-blk-ctl: Add one clock gate for HSIO block CREF_EN (Bit6) of LFAST_IO_REG control i.MX95 PCIe REF clock out enable/disable. Add compatible string "nxp,imx95-hsio-blk-ctl" to support PCIe REF clock out gate. Signed-off-by: Richard Zhu Reviewed-by: Frank Li Reviewed-by: Peng Fan Link: https://lore.kernel.org/r/1728977644-8207-3-git-send-email-hongxing.zhu@nxp.com Signed-off-by: Abel Vesa --- drivers/clk/imx/clk-imx95-blk-ctl.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/drivers/clk/imx/clk-imx95-blk-ctl.c b/drivers/clk/imx/clk-imx95-blk-ctl.c index 19a62da74be4..25974947ad0c 100644 --- a/drivers/clk/imx/clk-imx95-blk-ctl.c +++ b/drivers/clk/imx/clk-imx95-blk-ctl.c @@ -277,6 +277,25 @@ static const struct imx95_blk_ctl_dev_data netcmix_dev_data = { .clk_reg_offset = 0, }; +static const struct imx95_blk_ctl_clk_dev_data hsio_blk_ctl_clk_dev_data[] = { + [0] = { + .name = "hsio_blk_ctl_clk", + .parent_names = (const char *[]){ "hsio_pll", }, + .num_parents = 1, + .reg = 0, + .bit_idx = 6, + .bit_width = 1, + .type = CLK_GATE, + .flags = CLK_SET_RATE_PARENT, + } +}; + +static const struct imx95_blk_ctl_dev_data hsio_blk_ctl_dev_data = { + .num_clks = 1, + .clk_dev_data = hsio_blk_ctl_clk_dev_data, + .clk_reg_offset = 0, +}; + static int imx95_bc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -447,6 +466,7 @@ static const struct of_device_id imx95_bc_of_match[] = { { .compatible = "nxp,imx95-display-master-csr", }, { .compatible = "nxp,imx95-lvds-csr", .data = &lvds_csr_dev_data }, { .compatible = "nxp,imx95-display-csr", .data = &dispmix_csr_dev_data }, + { .compatible = "nxp,imx95-hsio-blk-ctl", .data = &hsio_blk_ctl_dev_data }, { .compatible = "nxp,imx95-vpu-csr", .data = &vpublk_dev_data }, { .compatible = "nxp,imx95-netcmix-blk-ctrl", .data = &netcmix_dev_data}, { /* Sentinel */ }, From 0af18ba60752e8a4ba34404c1d9a4a799da690f5 Mon Sep 17 00:00:00 2001 From: Pengfei Li Date: Wed, 23 Oct 2024 11:46:47 -0700 Subject: [PATCH 03/12] clk: imx93: Move IMX93_CLK_END macro to clk driver IMX93_CLK_END was previously defined in imx93-clock.h to indicate the number of clocks. However, it is not part of the ABI. For starters it does no really appear in DTS. But what's more important - new clocks are described later, which contradicts this define in binding header. So move this macro to clock driver. Signed-off-by: Pengfei Li Reviewed-by: Abel Vesa Link: https://lore.kernel.org/r/20241023184651.381265-2-pengfei.li_1@nxp.com Signed-off-by: Abel Vesa --- drivers/clk/imx/clk-imx93.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/clk/imx/clk-imx93.c b/drivers/clk/imx/clk-imx93.c index c6a9bc8ecc1f..c8b65146e76e 100644 --- a/drivers/clk/imx/clk-imx93.c +++ b/drivers/clk/imx/clk-imx93.c @@ -15,6 +15,8 @@ #include "clk.h" +#define IMX93_CLK_END 202 + enum clk_sel { LOW_SPEED_IO_SEL, NON_IO_SEL, From c0813ce2e5b0d1174782aff30d366509377abc7b Mon Sep 17 00:00:00 2001 From: Pengfei Li Date: Wed, 23 Oct 2024 11:46:48 -0700 Subject: [PATCH 04/12] dt-bindings: clock: imx93: Drop IMX93_CLK_END macro definition IMX93_CLK_END should be dropped as it is not part of the ABI. Signed-off-by: Pengfei Li Acked-by: Krzysztof Kozlowski Acked-by: Peng Fan Acked-by: Conor Dooley Link: https://lore.kernel.org/r/20241023184651.381265-3-pengfei.li_1@nxp.com Signed-off-by: Abel Vesa --- include/dt-bindings/clock/imx93-clock.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/dt-bindings/clock/imx93-clock.h b/include/dt-bindings/clock/imx93-clock.h index 787c9e74dc96..a1d0b326bb6b 100644 --- a/include/dt-bindings/clock/imx93-clock.h +++ b/include/dt-bindings/clock/imx93-clock.h @@ -204,6 +204,5 @@ #define IMX93_CLK_A55_SEL 199 #define IMX93_CLK_A55_CORE 200 #define IMX93_CLK_PDM_IPG 201 -#define IMX93_CLK_END 202 #endif From f029d870096fcd8565a2ee8c2d0078b9aaec4fdb Mon Sep 17 00:00:00 2001 From: Pengfei Li Date: Wed, 23 Oct 2024 11:46:49 -0700 Subject: [PATCH 05/12] dt-bindings: clock: Add i.MX91 clock support i.MX91 has similar Clock Control Module(CCM) design as i.MX93, only add few new clock compared to i.MX93. Add a new compatible string and some new clocks for i.MX91. Signed-off-by: Pengfei Li Reviewed-by: Frank Li Acked-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20241023184651.381265-4-pengfei.li_1@nxp.com Signed-off-by: Abel Vesa --- Documentation/devicetree/bindings/clock/imx93-clock.yaml | 1 + include/dt-bindings/clock/imx93-clock.h | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/Documentation/devicetree/bindings/clock/imx93-clock.yaml b/Documentation/devicetree/bindings/clock/imx93-clock.yaml index ccb53c6b96c1..98c0800732ef 100644 --- a/Documentation/devicetree/bindings/clock/imx93-clock.yaml +++ b/Documentation/devicetree/bindings/clock/imx93-clock.yaml @@ -16,6 +16,7 @@ description: | properties: compatible: enum: + - fsl,imx91-ccm - fsl,imx93-ccm reg: diff --git a/include/dt-bindings/clock/imx93-clock.h b/include/dt-bindings/clock/imx93-clock.h index a1d0b326bb6b..6c685067288b 100644 --- a/include/dt-bindings/clock/imx93-clock.h +++ b/include/dt-bindings/clock/imx93-clock.h @@ -204,5 +204,10 @@ #define IMX93_CLK_A55_SEL 199 #define IMX93_CLK_A55_CORE 200 #define IMX93_CLK_PDM_IPG 201 +#define IMX91_CLK_ENET1_QOS_TSN 202 +#define IMX91_CLK_ENET_TIMER 203 +#define IMX91_CLK_ENET2_REGULAR 204 +#define IMX91_CLK_ENET2_REGULAR_GATE 205 +#define IMX91_CLK_ENET1_QOS_TSN_GATE 206 #endif From a27bfff88dd2e1279c858311bc57ce4deb44f684 Mon Sep 17 00:00:00 2001 From: Pengfei Li Date: Wed, 23 Oct 2024 11:46:50 -0700 Subject: [PATCH 06/12] clk: imx: add i.MX91 clk Reuse i.MX93 clk driver for i.MX91, because i.MX91 reuses the Clock Control Module from i.MX93, with only a few clocks removed and a few clocks added. For clocks specific to i.MX93 use PLAT_IMX93 to flag them, for clocks specific to i.MX91, use PLAT_IMX91 to flag them. Others are shared by both. Signed-off-by: Pengfei Li Reviewed-by: Peng Fan Link: https://lore.kernel.org/r/20241023184651.381265-5-pengfei.li_1@nxp.com Signed-off-by: Abel Vesa --- drivers/clk/imx/clk-imx93.c | 63 +++++++++++++++++++++++-------------- 1 file changed, 39 insertions(+), 24 deletions(-) diff --git a/drivers/clk/imx/clk-imx93.c b/drivers/clk/imx/clk-imx93.c index c8b65146e76e..58a516dd385b 100644 --- a/drivers/clk/imx/clk-imx93.c +++ b/drivers/clk/imx/clk-imx93.c @@ -15,7 +15,10 @@ #include "clk.h" -#define IMX93_CLK_END 202 +#define IMX93_CLK_END 207 + +#define PLAT_IMX93 BIT(0) +#define PLAT_IMX91 BIT(1) enum clk_sel { LOW_SPEED_IO_SEL, @@ -55,6 +58,7 @@ static const struct imx93_clk_root { u32 off; enum clk_sel sel; unsigned long flags; + unsigned long plat; } root_array[] = { /* a55/m33/bus critical clk for system run */ { IMX93_CLK_A55_PERIPH, "a55_periph_root", 0x0000, FAST_SEL, CLK_IS_CRITICAL }, @@ -65,7 +69,7 @@ static const struct imx93_clk_root { { IMX93_CLK_BUS_AON, "bus_aon_root", 0x0300, LOW_SPEED_IO_SEL, CLK_IS_CRITICAL }, { IMX93_CLK_WAKEUP_AXI, "wakeup_axi_root", 0x0380, FAST_SEL, CLK_IS_CRITICAL }, { IMX93_CLK_SWO_TRACE, "swo_trace_root", 0x0400, LOW_SPEED_IO_SEL, }, - { IMX93_CLK_M33_SYSTICK, "m33_systick_root", 0x0480, LOW_SPEED_IO_SEL, }, + { IMX93_CLK_M33_SYSTICK, "m33_systick_root", 0x0480, LOW_SPEED_IO_SEL, 0, PLAT_IMX93, }, { IMX93_CLK_FLEXIO1, "flexio1_root", 0x0500, LOW_SPEED_IO_SEL, }, { IMX93_CLK_FLEXIO2, "flexio2_root", 0x0580, LOW_SPEED_IO_SEL, }, { IMX93_CLK_LPTMR1, "lptmr1_root", 0x0700, LOW_SPEED_IO_SEL, }, @@ -122,15 +126,15 @@ static const struct imx93_clk_root { { IMX93_CLK_HSIO_ACSCAN_80M, "hsio_acscan_80m_root", 0x1f80, LOW_SPEED_IO_SEL, }, { IMX93_CLK_HSIO_ACSCAN_480M, "hsio_acscan_480m_root", 0x2000, MISC_SEL, }, { IMX93_CLK_NIC_AXI, "nic_axi_root", 0x2080, FAST_SEL, CLK_IS_CRITICAL, }, - { IMX93_CLK_ML_APB, "ml_apb_root", 0x2180, LOW_SPEED_IO_SEL, }, - { IMX93_CLK_ML, "ml_root", 0x2200, FAST_SEL, }, + { IMX93_CLK_ML_APB, "ml_apb_root", 0x2180, LOW_SPEED_IO_SEL, 0, PLAT_IMX93, }, + { IMX93_CLK_ML, "ml_root", 0x2200, FAST_SEL, 0, PLAT_IMX93, }, { IMX93_CLK_MEDIA_AXI, "media_axi_root", 0x2280, FAST_SEL, }, { IMX93_CLK_MEDIA_APB, "media_apb_root", 0x2300, LOW_SPEED_IO_SEL, }, - { IMX93_CLK_MEDIA_LDB, "media_ldb_root", 0x2380, VIDEO_SEL, }, + { IMX93_CLK_MEDIA_LDB, "media_ldb_root", 0x2380, VIDEO_SEL, 0, PLAT_IMX93, }, { IMX93_CLK_MEDIA_DISP_PIX, "media_disp_pix_root", 0x2400, VIDEO_SEL, }, { IMX93_CLK_CAM_PIX, "cam_pix_root", 0x2480, VIDEO_SEL, }, - { IMX93_CLK_MIPI_TEST_BYTE, "mipi_test_byte_root", 0x2500, VIDEO_SEL, }, - { IMX93_CLK_MIPI_PHY_CFG, "mipi_phy_cfg_root", 0x2580, VIDEO_SEL, }, + { IMX93_CLK_MIPI_TEST_BYTE, "mipi_test_byte_root", 0x2500, VIDEO_SEL, 0, PLAT_IMX93, }, + { IMX93_CLK_MIPI_PHY_CFG, "mipi_phy_cfg_root", 0x2580, VIDEO_SEL, 0, PLAT_IMX93, }, { IMX93_CLK_ADC, "adc_root", 0x2700, LOW_SPEED_IO_SEL, }, { IMX93_CLK_PDM, "pdm_root", 0x2780, AUDIO_SEL, }, { IMX93_CLK_TSTMR1, "tstmr1_root", 0x2800, LOW_SPEED_IO_SEL, }, @@ -139,13 +143,16 @@ static const struct imx93_clk_root { { IMX93_CLK_MQS2, "mqs2_root", 0x2980, AUDIO_SEL, }, { IMX93_CLK_AUDIO_XCVR, "audio_xcvr_root", 0x2a00, NON_IO_SEL, }, { IMX93_CLK_SPDIF, "spdif_root", 0x2a80, AUDIO_SEL, }, - { IMX93_CLK_ENET, "enet_root", 0x2b00, NON_IO_SEL, }, - { IMX93_CLK_ENET_TIMER1, "enet_timer1_root", 0x2b80, LOW_SPEED_IO_SEL, }, - { IMX93_CLK_ENET_TIMER2, "enet_timer2_root", 0x2c00, LOW_SPEED_IO_SEL, }, - { IMX93_CLK_ENET_REF, "enet_ref_root", 0x2c80, NON_IO_SEL, }, - { IMX93_CLK_ENET_REF_PHY, "enet_ref_phy_root", 0x2d00, LOW_SPEED_IO_SEL, }, - { IMX93_CLK_I3C1_SLOW, "i3c1_slow_root", 0x2d80, LOW_SPEED_IO_SEL, }, - { IMX93_CLK_I3C2_SLOW, "i3c2_slow_root", 0x2e00, LOW_SPEED_IO_SEL, }, + { IMX93_CLK_ENET, "enet_root", 0x2b00, NON_IO_SEL, 0, PLAT_IMX93, }, + { IMX93_CLK_ENET_TIMER1, "enet_timer1_root", 0x2b80, LOW_SPEED_IO_SEL, 0, PLAT_IMX93, }, + { IMX93_CLK_ENET_TIMER2, "enet_timer2_root", 0x2c00, LOW_SPEED_IO_SEL, 0, PLAT_IMX93, }, + { IMX93_CLK_ENET_REF, "enet_ref_root", 0x2c80, NON_IO_SEL, 0, PLAT_IMX93, }, + { IMX93_CLK_ENET_REF_PHY, "enet_ref_phy_root", 0x2d00, LOW_SPEED_IO_SEL, 0, PLAT_IMX93, }, + { IMX91_CLK_ENET1_QOS_TSN, "enet1_qos_tsn_root", 0x2b00, NON_IO_SEL, 0, PLAT_IMX91, }, + { IMX91_CLK_ENET_TIMER, "enet_timer_root", 0x2b80, LOW_SPEED_IO_SEL, 0, PLAT_IMX91, }, + { IMX91_CLK_ENET2_REGULAR, "enet2_regular_root", 0x2c80, NON_IO_SEL, 0, PLAT_IMX91, }, + { IMX93_CLK_I3C1_SLOW, "i3c1_slow_root", 0x2d80, LOW_SPEED_IO_SEL, 0, PLAT_IMX93, }, + { IMX93_CLK_I3C2_SLOW, "i3c2_slow_root", 0x2e00, LOW_SPEED_IO_SEL, 0, PLAT_IMX93, }, { IMX93_CLK_USB_PHY_BURUNIN, "usb_phy_root", 0x2e80, LOW_SPEED_IO_SEL, }, { IMX93_CLK_PAL_CAME_SCAN, "pal_came_scan_root", 0x2f00, MISC_SEL, } }; @@ -157,6 +164,7 @@ static const struct imx93_clk_ccgr { u32 off; unsigned long flags; u32 *shared_count; + unsigned long plat; } ccgr_array[] = { { IMX93_CLK_A55_GATE, "a55_alt", "a55_alt_root", 0x8000, }, /* M33 critical clk for system run */ @@ -246,8 +254,10 @@ static const struct imx93_clk_ccgr { { IMX93_CLK_AUD_XCVR_GATE, "aud_xcvr", "audio_xcvr_root", 0x9b80, }, { IMX93_CLK_SPDIF_GATE, "spdif", "spdif_root", 0x9c00, }, { IMX93_CLK_HSIO_32K_GATE, "hsio_32k", "osc_32k", 0x9dc0, }, - { IMX93_CLK_ENET1_GATE, "enet1", "wakeup_axi_root", 0x9e00, }, - { IMX93_CLK_ENET_QOS_GATE, "enet_qos", "wakeup_axi_root", 0x9e40, }, + { IMX93_CLK_ENET1_GATE, "enet1", "wakeup_axi_root", 0x9e00, 0, NULL, PLAT_IMX93, }, + { IMX93_CLK_ENET_QOS_GATE, "enet_qos", "wakeup_axi_root", 0x9e40, 0, NULL, PLAT_IMX93, }, + { IMX91_CLK_ENET2_REGULAR_GATE, "enet2_regular", "wakeup_axi_root", 0x9e00, 0, NULL, PLAT_IMX91, }, + { IMX91_CLK_ENET1_QOS_TSN_GATE, "enet1_qos_tsn", "wakeup_axi_root", 0x9e40, 0, NULL, PLAT_IMX91, }, /* Critical because clk accessed during CPU idle */ { IMX93_CLK_SYS_CNT_GATE, "sys_cnt", "osc_24m", 0x9e80, CLK_IS_CRITICAL}, { IMX93_CLK_TSTMR1_GATE, "tstmr1", "bus_aon_root", 0x9ec0, }, @@ -267,6 +277,7 @@ static int imx93_clocks_probe(struct platform_device *pdev) const struct imx93_clk_ccgr *ccgr; void __iomem *base, *anatop_base; int i, ret; + const unsigned long plat = (unsigned long)device_get_match_data(&pdev->dev); clk_hw_data = devm_kzalloc(dev, struct_size(clk_hw_data, hws, IMX93_CLK_END), GFP_KERNEL); @@ -316,17 +327,20 @@ static int imx93_clocks_probe(struct platform_device *pdev) for (i = 0; i < ARRAY_SIZE(root_array); i++) { root = &root_array[i]; - clks[root->clk] = imx93_clk_composite_flags(root->name, - parent_names[root->sel], - 4, base + root->off, 3, - root->flags); + if (!root->plat || root->plat & plat) + clks[root->clk] = imx93_clk_composite_flags(root->name, + parent_names[root->sel], + 4, base + root->off, 3, + root->flags); } for (i = 0; i < ARRAY_SIZE(ccgr_array); i++) { ccgr = &ccgr_array[i]; - clks[ccgr->clk] = imx93_clk_gate(NULL, ccgr->name, ccgr->parent_name, - ccgr->flags, base + ccgr->off, 0, 1, 1, 3, - ccgr->shared_count); + if (!ccgr->plat || ccgr->plat & plat) + clks[ccgr->clk] = imx93_clk_gate(NULL, + ccgr->name, ccgr->parent_name, + ccgr->flags, base + ccgr->off, 0, 1, 1, 3, + ccgr->shared_count); } clks[IMX93_CLK_A55_SEL] = imx_clk_hw_mux2("a55_sel", base + 0x4820, 0, 1, a55_core_sels, @@ -356,7 +370,8 @@ unregister_hws: } static const struct of_device_id imx93_clk_of_match[] = { - { .compatible = "fsl,imx93-ccm" }, + { .compatible = "fsl,imx93-ccm", .data = (void *)PLAT_IMX93 }, + { .compatible = "fsl,imx91-ccm", .data = (void *)PLAT_IMX91 }, { /* Sentinel */ }, }; MODULE_DEVICE_TABLE(of, imx93_clk_of_match); From 5ee063fac85656bea9cfe3570af147ba1701ba18 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Sun, 27 Oct 2024 20:00:07 +0800 Subject: [PATCH 07/12] clk: imx: lpcg-scu: SW workaround for errata (e10858) Back-to-back LPCG writes can be ignored by the LPCG register due to a HW bug. The writes need to be separated by at least 4 cycles of the gated clock. See https://www.nxp.com.cn/docs/en/errata/IMX8_1N94W.pdf The workaround is implemented as follows: 1. For clocks running greater than or equal to 24MHz, a read followed by the write will provide sufficient delay. 2. For clocks running below 24MHz, add a delay of 4 clock cylces after the write to the LPCG register. Fixes: 2f77296d3df9 ("clk: imx: add lpcg clock support") Signed-off-by: Peng Fan Reviewed-by: Abel Vesa Link: https://lore.kernel.org/r/20241027-imx-clk-v1-v3-1-89152574d1d7@nxp.com Signed-off-by: Abel Vesa --- drivers/clk/imx/clk-lpcg-scu.c | 37 ++++++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/drivers/clk/imx/clk-lpcg-scu.c b/drivers/clk/imx/clk-lpcg-scu.c index dd5abd09f3e2..620afdf8dc03 100644 --- a/drivers/clk/imx/clk-lpcg-scu.c +++ b/drivers/clk/imx/clk-lpcg-scu.c @@ -6,10 +6,12 @@ #include #include +#include #include #include #include #include +#include #include "clk-scu.h" @@ -41,6 +43,29 @@ struct clk_lpcg_scu { #define to_clk_lpcg_scu(_hw) container_of(_hw, struct clk_lpcg_scu, hw) +/* e10858 -LPCG clock gating register synchronization errata */ +static void lpcg_e10858_writel(unsigned long rate, void __iomem *reg, u32 val) +{ + writel(val, reg); + + if (rate >= 24 * HZ_PER_MHZ || rate == 0) { + /* + * The time taken to access the LPCG registers from the AP core + * through the interconnect is longer than the minimum delay + * of 4 clock cycles required by the errata. + * Adding a readl will provide sufficient delay to prevent + * back-to-back writes. + */ + readl(reg); + } else { + /* + * For clocks running below 24MHz, wait a minimum of + * 4 clock cycles. + */ + ndelay(4 * (DIV_ROUND_UP(1000 * HZ_PER_MHZ, rate))); + } +} + static int clk_lpcg_scu_enable(struct clk_hw *hw) { struct clk_lpcg_scu *clk = to_clk_lpcg_scu(hw); @@ -57,7 +82,8 @@ static int clk_lpcg_scu_enable(struct clk_hw *hw) val |= CLK_GATE_SCU_LPCG_HW_SEL; reg |= val << clk->bit_idx; - writel(reg, clk->reg); + + lpcg_e10858_writel(clk_hw_get_rate(hw), clk->reg, reg); spin_unlock_irqrestore(&imx_lpcg_scu_lock, flags); @@ -74,7 +100,7 @@ static void clk_lpcg_scu_disable(struct clk_hw *hw) reg = readl_relaxed(clk->reg); reg &= ~(CLK_GATE_SCU_LPCG_MASK << clk->bit_idx); - writel(reg, clk->reg); + lpcg_e10858_writel(clk_hw_get_rate(hw), clk->reg, reg); spin_unlock_irqrestore(&imx_lpcg_scu_lock, flags); } @@ -145,13 +171,8 @@ static int __maybe_unused imx_clk_lpcg_scu_resume(struct device *dev) { struct clk_lpcg_scu *clk = dev_get_drvdata(dev); - /* - * FIXME: Sometimes writes don't work unless the CPU issues - * them twice - */ - - writel(clk->state, clk->reg); writel(clk->state, clk->reg); + lpcg_e10858_writel(0, clk->reg, clk->state); dev_dbg(dev, "restore lpcg state 0x%x\n", clk->state); return 0; From 557be501c38e1864b948fc6ccdf4b035d610a2ea Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Sun, 27 Oct 2024 20:00:08 +0800 Subject: [PATCH 08/12] clk: imx: fracn-gppll: correct PLL initialization flow MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Per i.MX93 Reference Mannual 22.4 Initialization information 1. Program appropriate value of DIV[ODIV], DIV[RDIV] and DIV[MFI] as per Integer mode. 2. Wait for 5 μs. 3. Program the following field in CTRL register. Set CTRL[POWERUP] to 1'b1 to enable PLL block. 4. Poll PLL_STATUS[PLL_LOCK] register, and wait till PLL_STATUS[PLL_LOCK] is 1'b1 and pll_lock output signal is 1'b1. 5. Set CTRL[CLKMUX_EN] to 1'b1 to enable PLL output clock. So move the CLKMUX_EN operation after PLL locked. Fixes: 1b26cb8a77a4 ("clk: imx: support fracn gppll") Co-developed-by: Jacky Bai Signed-off-by: Jacky Bai Signed-off-by: Peng Fan Reviewed-by: Abel Vesa Link: https://lore.kernel.org/r/20241027-imx-clk-v1-v3-2-89152574d1d7@nxp.com Signed-off-by: Abel Vesa --- drivers/clk/imx/clk-fracn-gppll.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/clk/imx/clk-fracn-gppll.c b/drivers/clk/imx/clk-fracn-gppll.c index 591e0364ee5c..4749c3e0b705 100644 --- a/drivers/clk/imx/clk-fracn-gppll.c +++ b/drivers/clk/imx/clk-fracn-gppll.c @@ -303,13 +303,13 @@ static int clk_fracn_gppll_prepare(struct clk_hw *hw) val |= POWERUP_MASK; writel_relaxed(val, pll->base + PLL_CTRL); - val |= CLKMUX_EN; - writel_relaxed(val, pll->base + PLL_CTRL); - ret = clk_fracn_gppll_wait_lock(pll); if (ret) return ret; + val |= CLKMUX_EN; + writel_relaxed(val, pll->base + PLL_CTRL); + val &= ~CLKMUX_BYPASS; writel_relaxed(val, pll->base + PLL_CTRL); From ff4279618f0aec350b0fb41b2b35841324fbd96e Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Sun, 27 Oct 2024 20:00:09 +0800 Subject: [PATCH 09/12] clk: imx: fracn-gppll: fix pll power up To i.MX93 which features dual Cortex-A55 cores and DSU, when using writel_relaxed to write value to PLL registers, the value might be buffered. To make sure the value has been written into the hardware, using readl to read back the register could achieve the goal. current PLL power up flow can be simplified as below: 1. writel_relaxed to set the PLL POWERUP bit; 2. readl_poll_timeout to check the PLL lock bit: a). timeout = ktime_add_us(ktime_get(), timeout_us); b). readl the pll the lock reg; c). check if the pll lock bit ready d). check if timeout But in some corner cases, both the write in step 1 and read in step 2 will be blocked by other bus transaction in the SoC for a long time, saying the value into real hardware is just before step b). That means the timeout counting has begins for quite sometime since step a), but value still not written into real hardware until bus released just at a point before step b). Then there maybe chances that the pll lock bit is not ready when readl done but the timeout happens. readl_poll_timeout will err return due to timeout. To avoid such unexpected failure, read back the reg to make sure the write has been done in HW reg. So use readl after writel_relaxed to fix the issue. Since we are here, to avoid udelay to run before writel_relaxed, use readl before udelay. Fixes: 1b26cb8a77a4 ("clk: imx: support fracn gppll") Co-developed-by: Jacky Bai Signed-off-by: Jacky Bai Signed-off-by: Peng Fan Reviewed-by: Abel Vesa Link: https://lore.kernel.org/r/20241027-imx-clk-v1-v3-3-89152574d1d7@nxp.com Signed-off-by: Abel Vesa --- drivers/clk/imx/clk-fracn-gppll.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/clk/imx/clk-fracn-gppll.c b/drivers/clk/imx/clk-fracn-gppll.c index 4749c3e0b705..85771afd4698 100644 --- a/drivers/clk/imx/clk-fracn-gppll.c +++ b/drivers/clk/imx/clk-fracn-gppll.c @@ -254,9 +254,11 @@ static int clk_fracn_gppll_set_rate(struct clk_hw *hw, unsigned long drate, pll_div = FIELD_PREP(PLL_RDIV_MASK, rate->rdiv) | rate->odiv | FIELD_PREP(PLL_MFI_MASK, rate->mfi); writel_relaxed(pll_div, pll->base + PLL_DIV); + readl(pll->base + PLL_DIV); if (pll->flags & CLK_FRACN_GPPLL_FRACN) { writel_relaxed(rate->mfd, pll->base + PLL_DENOMINATOR); writel_relaxed(FIELD_PREP(PLL_MFN_MASK, rate->mfn), pll->base + PLL_NUMERATOR); + readl(pll->base + PLL_NUMERATOR); } /* Wait for 5us according to fracn mode pll doc */ @@ -265,6 +267,7 @@ static int clk_fracn_gppll_set_rate(struct clk_hw *hw, unsigned long drate, /* Enable Powerup */ tmp |= POWERUP_MASK; writel_relaxed(tmp, pll->base + PLL_CTRL); + readl(pll->base + PLL_CTRL); /* Wait Lock */ ret = clk_fracn_gppll_wait_lock(pll); @@ -302,6 +305,7 @@ static int clk_fracn_gppll_prepare(struct clk_hw *hw) val |= POWERUP_MASK; writel_relaxed(val, pll->base + PLL_CTRL); + readl(pll->base + PLL_CTRL); ret = clk_fracn_gppll_wait_lock(pll); if (ret) From e81361f6cf9bf4a1848b0813bc4becb2250870b8 Mon Sep 17 00:00:00 2001 From: Dong Aisheng Date: Sun, 27 Oct 2024 20:00:10 +0800 Subject: [PATCH 10/12] clk: imx: clk-scu: fix clk enable state save and restore The scu clk_ops only inplements prepare() and unprepare() callback. Saving the clock state during suspend by checking clk_hw_is_enabled() is not safe as it's possible that some device drivers may only disable the clocks without unprepare. Then the state retention will not work for such clocks. Fixing it by checking clk_hw_is_prepared() which is more reasonable and safe. Fixes: d0409631f466 ("clk: imx: scu: add suspend/resume support") Reviewed-by: Peng Fan Tested-by: Carlos Song Signed-off-by: Dong Aisheng Link: https://lore.kernel.org/r/20241027-imx-clk-v1-v3-4-89152574d1d7@nxp.com Signed-off-by: Abel Vesa --- drivers/clk/imx/clk-scu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/imx/clk-scu.c b/drivers/clk/imx/clk-scu.c index b1dd0c08e091..b27186aaf2a1 100644 --- a/drivers/clk/imx/clk-scu.c +++ b/drivers/clk/imx/clk-scu.c @@ -596,7 +596,7 @@ static int __maybe_unused imx_clk_scu_suspend(struct device *dev) clk->rate = clk_scu_recalc_rate(&clk->hw, 0); else clk->rate = clk_hw_get_rate(&clk->hw); - clk->is_enabled = clk_hw_is_enabled(&clk->hw); + clk->is_enabled = clk_hw_is_prepared(&clk->hw); if (clk->parent) dev_dbg(dev, "save parent %s idx %u\n", clk_hw_get_name(clk->parent), From 92888f39193419c117e282cce7fd762ba78784a4 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Sun, 27 Oct 2024 20:00:11 +0800 Subject: [PATCH 11/12] clk: imx: lpcg-scu: Skip HDMI LPCG clock save/restore On i.MX8QM, HDMI LPCG clocks operation needs SCU clock "hdmi_ipg_clk" to be ON. While during noirq suspend phase, "hdmi_ipg_clk" is disabled by HDMI IRQ STEER driver, so SError will be triggered when accessing the HDMI LPCG registers. Skip all HDMI LPCG clocks save/restore to avoid SError during system suspend/resume, it will NOT introduce additional power consumption as their parent clock is disabled when suspend. Signed-off-by: Peng Fan Link: https://lore.kernel.org/r/20241027-imx-clk-v1-v3-5-89152574d1d7@nxp.com Signed-off-by: Abel Vesa --- drivers/clk/imx/clk-lpcg-scu.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/clk/imx/clk-lpcg-scu.c b/drivers/clk/imx/clk-lpcg-scu.c index 620afdf8dc03..6376557a3c3d 100644 --- a/drivers/clk/imx/clk-lpcg-scu.c +++ b/drivers/clk/imx/clk-lpcg-scu.c @@ -161,6 +161,9 @@ static int __maybe_unused imx_clk_lpcg_scu_suspend(struct device *dev) { struct clk_lpcg_scu *clk = dev_get_drvdata(dev); + if (!strncmp("hdmi_lpcg", clk_hw_get_name(&clk->hw), strlen("hdmi_lpcg"))) + return 0; + clk->state = readl_relaxed(clk->reg); dev_dbg(dev, "save lpcg state 0x%x\n", clk->state); @@ -171,6 +174,9 @@ static int __maybe_unused imx_clk_lpcg_scu_resume(struct device *dev) { struct clk_lpcg_scu *clk = dev_get_drvdata(dev); + if (!strncmp("hdmi_lpcg", clk_hw_get_name(&clk->hw), strlen("hdmi_lpcg"))) + return 0; + writel(clk->state, clk->reg); lpcg_e10858_writel(0, clk->reg, clk->state); dev_dbg(dev, "restore lpcg state 0x%x\n", clk->state); From 81a206d736c19139d3863b79e7174f9e98b45499 Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Sat, 26 Oct 2024 19:24:52 +0800 Subject: [PATCH 12/12] clk: imx: imx8-acm: Fix return value check in clk_imx_acm_attach_pm_domains() If device_link_add() fails, it returns NULL pointer not ERR_PTR(), replace IS_ERR() with NULL pointer check, and return -EINVAL. Fixes: d3a0946d7ac9 ("clk: imx: imx8: add audio clock mux driver") Signed-off-by: Yang Yingliang Reviewed-by: Peng Fan Reviewed-by: Abel Vesa Link: https://lore.kernel.org/r/20241026112452.1523-1-yangyingliang@huaweicloud.com Signed-off-by: Abel Vesa --- drivers/clk/imx/clk-imx8-acm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/clk/imx/clk-imx8-acm.c b/drivers/clk/imx/clk-imx8-acm.c index 6c351050b82a..c169fe53a35f 100644 --- a/drivers/clk/imx/clk-imx8-acm.c +++ b/drivers/clk/imx/clk-imx8-acm.c @@ -294,9 +294,9 @@ static int clk_imx_acm_attach_pm_domains(struct device *dev, DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE); - if (IS_ERR(dev_pm->pd_dev_link[i])) { + if (!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]); + ret = -EINVAL; goto detach_pm; } }