[PATCH v2 5/6] video: imx: ipuv3: move clock code to legacy
Brian Ruley
brian.ruley at gehealthcare.com
Tue Feb 10 10:00:27 CET 2026
In preparation for CCF migration for IPUv3 separate existing clock code
to legacy files. These will be used by i.MX5 that currently does not
support the CCF. No functional change.
Signed-off-by: Brian Ruley <brian.ruley at gehealthcare.com>
---
(no changes since v1)
drivers/video/imx/Kconfig | 7 +
drivers/video/imx/Makefile | 1 +
drivers/video/imx/ipu.h | 60 +++++-
drivers/video/imx/ipu_clk_legacy.c | 310 +++++++++++++++++++++++++++
drivers/video/imx/ipu_common.c | 322 +----------------------------
5 files changed, 376 insertions(+), 324 deletions(-)
create mode 100644 drivers/video/imx/ipu_clk_legacy.c
diff --git a/drivers/video/imx/Kconfig b/drivers/video/imx/Kconfig
index b35ba965efc..c25f209629e 100644
--- a/drivers/video/imx/Kconfig
+++ b/drivers/video/imx/Kconfig
@@ -15,6 +15,13 @@ config IMX_HDMI
bool "Enable HDMI support in IPUv3"
depends on VIDEO_IPUV3
+config IPU_CLK_LEGACY
+ bool "Use legacy clock management for IPU"
+ depends on VIDEO_IPUV3 && !CLK
+ default y
+ help
+ Use legacy clock management instead of Common Clock Framework.
+
config IMX_LDB
bool "Freescale i.MX8MP LDB bridge"
depends on VIDEO_BRIDGE
diff --git a/drivers/video/imx/Makefile b/drivers/video/imx/Makefile
index 1edf5a6bdf0..0e7f71a9f93 100644
--- a/drivers/video/imx/Makefile
+++ b/drivers/video/imx/Makefile
@@ -4,5 +4,6 @@
# Wolfgang Denk, DENX Software Engineering, wd at denx.de.
obj-$(CONFIG_VIDEO_IPUV3) += mxc_ipuv3_fb.o ipu_common.o ipu_disp.o
+obj-$(CONFIG_IPU_CLK_LEGACY) += ipu_clk_legacy.o
obj-$(CONFIG_IMX_LDB) += ldb.o
obj-$(CONFIG_IMX_LCDIF) += lcdif.o
diff --git a/drivers/video/imx/ipu.h b/drivers/video/imx/ipu.h
index 62827dc480d..ae40e20bc28 100644
--- a/drivers/video/imx/ipu.h
+++ b/drivers/video/imx/ipu.h
@@ -18,14 +18,23 @@
#ifndef __ASM_ARCH_IPU_H__
#define __ASM_ARCH_IPU_H__
+#if !CONFIG_IS_ENABLED(IPU_CLK_LEGACY)
+#include <clk.h>
+#endif
#include <ipu_pixfmt.h>
#include <linux/types.h>
+#define IPUV3_CLK_MX51 133000000
+#define IPUV3_CLK_MX53 200000000
+#define IPUV3_CLK_MX6Q 264000000
+#define IPUV3_CLK_MX6DL 198000000
+
#define IDMA_CHAN_INVALID 0xFF
#define HIGH_RESOLUTION_WIDTH 1024
struct ipu_ctx;
-struct ipu_di_config;
+
+#if CONFIG_IS_ENABLED(IPU_CLK_LEGACY)
struct clk {
const char *name;
@@ -75,6 +84,46 @@ struct clk {
int (*set_parent)(struct clk *clk, struct clk *parent);
};
+/* Legacy clock API functions */
+void clk_enable(struct clk *clk);
+void clk_disable(struct clk *clk);
+int clk_get_usecount(struct clk *clk);
+u32 clk_get_rate(struct clk *clk);
+struct clk *clk_get_parent(struct clk *clk);
+int clk_set_rate(struct clk *clk, unsigned long rate);
+long clk_round_rate(struct clk *clk, unsigned long rate);
+int clk_set_parent(struct clk *clk, struct clk *parent);
+
+/* IPU clock initialization */
+int ipu_clk_init_legacy(struct ipu_ctx *ctx);
+int ipu_ldb_clk_init_legacy(struct ipu_ctx *ctx);
+int ipu_pixel_clk_init_legacy(struct ipu_ctx *ctx, int id);
+
+#else
+
+static inline int clk_get_usecount(struct clk *clk)
+{
+ return clk->enable_count;
+}
+
+/* Stub functions for non-legacy builds */
+static inline int ipu_clk_init_legacy(struct ipu_ctx *ctx)
+{
+ return -ENOSYS;
+}
+
+static inline int ipu_ldb_clk_init_legacy(struct ipu_ctx *ctx)
+{
+ return -ENOSYS;
+}
+
+static inline int ipu_pixel_clk_init_legacy(struct ipu_ctx *ctx, int id)
+{
+ return -ENOSYS;
+}
+
+#endif /* CONFIG_IS_ENABLED(IPU_CLK_LEGACY) */
+
struct udevice;
/*
@@ -298,15 +347,6 @@ int32_t ipu_disp_set_color_key(ipu_channel_t channel, unsigned char enable,
u32 bytes_per_pixel(u32 fmt);
-void clk_enable(struct clk *clk);
-void clk_disable(struct clk *clk);
-u32 clk_get_rate(struct clk *clk);
-int clk_set_rate(struct clk *clk, unsigned long rate);
-long clk_round_rate(struct clk *clk, unsigned long rate);
-int clk_set_parent(struct clk *clk, struct clk *parent);
-int clk_get_usecount(struct clk *clk);
-struct clk *clk_get_parent(struct clk *clk);
-
void ipu_dump_registers(void);
struct ipu_ctx *ipu_probe(struct udevice *dev);
bool ipu_clk_enabled(struct ipu_ctx *ctx);
diff --git a/drivers/video/imx/ipu_clk_legacy.c b/drivers/video/imx/ipu_clk_legacy.c
new file mode 100644
index 00000000000..8aaafa2a080
--- /dev/null
+++ b/drivers/video/imx/ipu_clk_legacy.c
@@ -0,0 +1,310 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Legacy IPU clock management for i.MX5/6 without Common Clock Framework
+ *
+ * (C) Copyright 2026
+ * Brian Ruley, GE HealthCare, brian.ruley at gehealthcare.com
+ */
+
+#include "ipu.h"
+#include "ipu_regs.h"
+#include <asm/arch/crm_regs.h>
+#include <asm/arch/sys_proto.h>
+#include <asm/io.h>
+#include <div64.h>
+#include <dm/devres.h>
+#include <linux/err.h>
+#include <log.h>
+
+extern struct mxc_ccm_reg *mxc_ccm;
+
+void clk_enable(struct clk *clk)
+{
+ if (clk) {
+ if (clk->usecount++ == 0)
+ clk->enable(clk);
+ }
+}
+
+void clk_disable(struct clk *clk)
+{
+ if (clk) {
+ if (!(--clk->usecount)) {
+ if (clk->disable)
+ clk->disable(clk);
+ }
+ }
+}
+
+int clk_get_usecount(struct clk *clk)
+{
+ if (clk == NULL)
+ return 0;
+
+ return clk->usecount;
+}
+
+u32 clk_get_rate(struct clk *clk)
+{
+ if (!clk)
+ return 0;
+
+ return clk->rate;
+}
+
+struct clk *clk_get_parent(struct clk *clk)
+{
+ if (!clk)
+ return 0;
+
+ return clk->parent;
+}
+
+int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+ if (!clk)
+ return 0;
+
+ if (clk->set_rate)
+ clk->set_rate(clk, rate);
+
+ return clk->rate;
+}
+
+long clk_round_rate(struct clk *clk, unsigned long rate)
+{
+ if (clk == NULL || !clk->round_rate)
+ return 0;
+
+ return clk->round_rate(clk, rate);
+}
+
+int clk_set_parent(struct clk *clk, struct clk *parent)
+{
+ clk->parent = parent;
+ if (clk->set_parent)
+ return clk->set_parent(clk, parent);
+ return 0;
+}
+
+static int clk_ipu_enable(struct clk *clk)
+{
+ u32 reg;
+
+ reg = __raw_readl(clk->enable_reg);
+ reg |= MXC_CCM_CCGR_CG_MASK << clk->enable_shift;
+ __raw_writel(reg, clk->enable_reg);
+
+#if CONFIG_IS_ENABLED(MX51) || CONFIG_IS_ENABLED(MX53)
+ reg = __raw_readl(&mxc_ccm->ccdr);
+ reg &= ~MXC_CCM_CCDR_IPU_HS_MASK;
+ __raw_writel(reg, &mxc_ccm->ccdr);
+
+ reg = __raw_readl(&mxc_ccm->clpcr);
+ reg &= ~MXC_CCM_CLPCR_BYPASS_IPU_LPM_HS;
+ __raw_writel(reg, &mxc_ccm->clpcr);
+#endif
+ return 0;
+}
+
+static void clk_ipu_disable(struct clk *clk)
+{
+ u32 reg;
+
+ reg = __raw_readl(clk->enable_reg);
+ reg &= ~(MXC_CCM_CCGR_CG_MASK << clk->enable_shift);
+ __raw_writel(reg, clk->enable_reg);
+
+#if CONFIG_IS_ENABLED(MX51) || CONFIG_IS_ENABLED(MX53)
+ reg = __raw_readl(&mxc_ccm->ccdr);
+ reg |= MXC_CCM_CCDR_IPU_HS_MASK;
+ __raw_writel(reg, &mxc_ccm->ccdr);
+
+ reg = __raw_readl(&mxc_ccm->clpcr);
+ reg |= MXC_CCM_CLPCR_BYPASS_IPU_LPM_HS;
+ __raw_writel(reg, &mxc_ccm->clpcr);
+#endif
+}
+
+static void ipu_pixel_clk_recalc(struct clk *clk)
+{
+ u32 div;
+ u64 final_rate = (unsigned long long)clk->parent->rate * 16;
+
+ div = __raw_readl(DI_BS_CLKGEN0(clk->id));
+ debug("read BS_CLKGEN0 div:%d, final_rate:%lld, prate:%ld\n", div,
+ final_rate, clk->parent->rate);
+
+ clk->rate = 0;
+ if (div != 0) {
+ do_div(final_rate, div);
+ clk->rate = final_rate;
+ }
+}
+
+static unsigned long ipu_pixel_clk_round_rate(struct clk *clk,
+ unsigned long rate)
+{
+ u64 div, final_rate;
+ u32 remainder;
+ u64 parent_rate = (unsigned long long)clk->parent->rate * 16;
+
+ div = parent_rate;
+ remainder = do_div(div, rate);
+ if (remainder > (rate / 2))
+ div++;
+ if (div < 0x10)
+ div = 0x10;
+ if (div & ~0xFEF)
+ div &= 0xFF8;
+ else {
+ if ((div & 0xC) == 0xC) {
+ div += 0x10;
+ div &= ~0xF;
+ }
+ }
+ final_rate = parent_rate;
+ do_div(final_rate, div);
+
+ return final_rate;
+}
+
+static int ipu_pixel_clk_set_rate(struct clk *clk, unsigned long rate)
+{
+ u64 div, parent_rate;
+ u32 remainder;
+
+ parent_rate = (unsigned long long)clk->parent->rate * 16;
+ div = parent_rate;
+ remainder = do_div(div, rate);
+ if (remainder > (rate / 2))
+ div++;
+
+ if ((div & 0xC) == 0xC) {
+ div += 0x10;
+ div &= ~0xF;
+ }
+ if (div > 0x1000)
+ debug("Overflow, DI_BS_CLKGEN0 div:0x%x\n", (u32)div);
+
+ __raw_writel(div, DI_BS_CLKGEN0(clk->id));
+ __raw_writel((div / 16) << 16, DI_BS_CLKGEN1(clk->id));
+
+ do_div(parent_rate, div);
+ clk->rate = parent_rate;
+
+ return 0;
+}
+
+static int ipu_pixel_clk_enable(struct clk *clk)
+{
+ u32 disp_gen = __raw_readl(IPU_DISP_GEN);
+ disp_gen |= clk->id ? DI1_COUNTER_RELEASE : DI0_COUNTER_RELEASE;
+ __raw_writel(disp_gen, IPU_DISP_GEN);
+
+ return 0;
+}
+
+static void ipu_pixel_clk_disable(struct clk *clk)
+{
+ u32 disp_gen = __raw_readl(IPU_DISP_GEN);
+ disp_gen &= clk->id ? ~DI1_COUNTER_RELEASE : ~DI0_COUNTER_RELEASE;
+ __raw_writel(disp_gen, IPU_DISP_GEN);
+}
+
+static int ipu_pixel_clk_set_parent(struct clk *clk, struct clk *parent)
+{
+ u32 di_gen = __raw_readl(DI_GENERAL(clk->id));
+ struct ipu_ctx *ctx = clk->ctx;
+
+ if (parent == ctx->ipu_clk)
+ di_gen &= ~DI_GEN_DI_CLK_EXT;
+ else if (!IS_ERR(ctx->di_clk[clk->id]) && parent == ctx->ldb_clk)
+ di_gen |= DI_GEN_DI_CLK_EXT;
+ else
+ return -EINVAL;
+
+ __raw_writel(di_gen, DI_GENERAL(clk->id));
+ ipu_pixel_clk_recalc(clk);
+ return 0;
+}
+
+int ipu_pixel_clk_init_legacy(struct ipu_ctx *ctx, int id)
+{
+ struct clk *pixel_clk;
+
+ pixel_clk = devm_kzalloc(ctx->dev, sizeof(*pixel_clk), GFP_KERNEL);
+ if (!pixel_clk)
+ return -ENOMEM;
+
+ pixel_clk->name = "pixel_clk";
+ pixel_clk->id = id;
+ pixel_clk->ctx = ctx;
+ pixel_clk->recalc = ipu_pixel_clk_recalc;
+ pixel_clk->set_rate = ipu_pixel_clk_set_rate;
+ pixel_clk->round_rate = ipu_pixel_clk_round_rate;
+ pixel_clk->set_parent = ipu_pixel_clk_set_parent;
+ pixel_clk->enable = ipu_pixel_clk_enable;
+ pixel_clk->disable = ipu_pixel_clk_disable;
+ pixel_clk->usecount = 0;
+
+ ctx->pixel_clk[id] = pixel_clk;
+ return 0;
+}
+
+int ipu_clk_init_legacy(struct ipu_ctx *ctx)
+{
+ struct clk *ipu_clk;
+
+ ipu_clk = devm_kzalloc(ctx->dev, sizeof(*ipu_clk), GFP_KERNEL);
+ if (!ipu_clk)
+ return -ENOMEM;
+
+ ipu_clk->name = "ipu_clk";
+ ipu_clk->ctx = ctx;
+#if CONFIG_IS_ENABLED(MX51) || CONFIG_IS_ENABLED(MX53)
+ ipu_clk->enable_reg =
+ (u32 *)(CCM_BASE_ADDR + offsetof(struct mxc_ccm_reg, CCGR5));
+ ipu_clk->enable_shift = MXC_CCM_CCGR5_IPU_OFFSET;
+#else
+ ipu_clk->enable_reg =
+ (u32 *)(CCM_BASE_ADDR + offsetof(struct mxc_ccm_reg, CCGR3));
+ ipu_clk->enable_shift = MXC_CCM_CCGR3_IPU1_IPU_DI0_OFFSET;
+#endif
+
+ ipu_clk->enable = clk_ipu_enable;
+ ipu_clk->disable = clk_ipu_disable;
+ ipu_clk->usecount = 0;
+
+#if CONFIG_IS_ENABLED(MX51)
+ ipu_clk->rate = IPUV3_CLK_MX51;
+#elif CONFIG_IS_ENABLED(MX53)
+ ipu_clk->rate = IPUV3_CLK_MX53;
+#else
+ ipu_clk->rate = is_mx6sdl() ? IPUV3_CLK_MX6DL : IPUV3_CLK_MX6Q;
+#endif
+
+ ctx->ipu_clk = ipu_clk;
+ return 0;
+}
+
+#if !defined CFG_SYS_LDB_CLOCK
+#define CFG_SYS_LDB_CLOCK 65000000
+#endif
+
+int ipu_ldb_clk_init_legacy(struct ipu_ctx *ctx)
+{
+ struct clk *ldb_clk;
+
+ ldb_clk = devm_kzalloc(ctx->dev, sizeof(*ldb_clk), GFP_KERNEL);
+ if (!ldb_clk)
+ return -ENOMEM;
+
+ ldb_clk->name = "ldb_clk";
+ ldb_clk->ctx = ctx;
+ ldb_clk->rate = CFG_SYS_LDB_CLOCK;
+ ldb_clk->usecount = 0;
+
+ ctx->ldb_clk = ldb_clk;
+ return 0;
+}
diff --git a/drivers/video/imx/ipu_common.c b/drivers/video/imx/ipu_common.c
index e9897ee79d2..d994053394f 100644
--- a/drivers/video/imx/ipu_common.c
+++ b/drivers/video/imx/ipu_common.c
@@ -31,8 +31,8 @@
#include <linux/types.h>
#include <log.h>
-extern struct mxc_ccm_reg *mxc_ccm;
-extern u32 *ipu_cpmem_base;
+u32 *ipu_cpmem_base;
+u32 *ipu_dc_tmpl_reg;
struct ipu_ch_param_word {
u32 data[5];
@@ -92,126 +92,6 @@ struct ipu_ch_param {
#define IPU_SW_RST_TOUT_USEC (10000)
-#define IPUV3_CLK_MX51 133000000
-#define IPUV3_CLK_MX53 200000000
-#define IPUV3_CLK_MX6Q 264000000
-#define IPUV3_CLK_MX6DL 198000000
-
-void clk_enable(struct clk *clk)
-{
- if (clk) {
- if (clk->usecount++ == 0)
- clk->enable(clk);
- }
-}
-
-void clk_disable(struct clk *clk)
-{
- if (clk) {
- if (!(--clk->usecount)) {
- if (clk->disable)
- clk->disable(clk);
- }
- }
-}
-
-int clk_get_usecount(struct clk *clk)
-{
- if (clk == NULL)
- return 0;
-
- return clk->usecount;
-}
-
-u32 clk_get_rate(struct clk *clk)
-{
- if (!clk)
- return 0;
-
- return clk->rate;
-}
-
-struct clk *clk_get_parent(struct clk *clk)
-{
- if (!clk)
- return 0;
-
- return clk->parent;
-}
-
-int clk_set_rate(struct clk *clk, unsigned long rate)
-{
- if (!clk)
- return 0;
-
- if (clk->set_rate)
- clk->set_rate(clk, rate);
-
- return clk->rate;
-}
-
-long clk_round_rate(struct clk *clk, unsigned long rate)
-{
- if (clk == NULL || !clk->round_rate)
- return 0;
-
- return clk->round_rate(clk, rate);
-}
-
-int clk_set_parent(struct clk *clk, struct clk *parent)
-{
- clk->parent = parent;
- if (clk->set_parent)
- return clk->set_parent(clk, parent);
- return 0;
-}
-
-static int clk_ipu_enable(struct clk *clk)
-{
- u32 reg;
-
- reg = __raw_readl(clk->enable_reg);
- reg |= MXC_CCM_CCGR_CG_MASK << clk->enable_shift;
- __raw_writel(reg, clk->enable_reg);
-
-#if CONFIG_IS_ENABLED(MX51) || CONFIG_IS_ENABLED(MX53)
- /* Handshake with IPU when certain clock rates are changed. */
- reg = __raw_readl(&mxc_ccm->ccdr);
- reg &= ~MXC_CCM_CCDR_IPU_HS_MASK;
- __raw_writel(reg, &mxc_ccm->ccdr);
-
- /* Handshake with IPU when LPM is entered as its enabled. */
- reg = __raw_readl(&mxc_ccm->clpcr);
- reg &= ~MXC_CCM_CLPCR_BYPASS_IPU_LPM_HS;
- __raw_writel(reg, &mxc_ccm->clpcr);
-#endif
- return 0;
-}
-
-static void clk_ipu_disable(struct clk *clk)
-{
- u32 reg;
-
- reg = __raw_readl(clk->enable_reg);
- reg &= ~(MXC_CCM_CCGR_CG_MASK << clk->enable_shift);
- __raw_writel(reg, clk->enable_reg);
-
-#if CONFIG_IS_ENABLED(MX51) || CONFIG_IS_ENABLED(MX53)
- /*
- * No handshake with IPU whe dividers are changed
- * as its not enabled.
- */
- reg = __raw_readl(&mxc_ccm->ccdr);
- reg |= MXC_CCM_CCDR_IPU_HS_MASK;
- __raw_writel(reg, &mxc_ccm->ccdr);
-
- /* No handshake with IPU when LPM is entered as its not enabled. */
- reg = __raw_readl(&mxc_ccm->clpcr);
- reg |= MXC_CCM_CLPCR_BYPASS_IPU_LPM_HS;
- __raw_writel(reg, &mxc_ccm->clpcr);
-#endif
-}
-
/*
* Function to initialize the ipu clock
*
@@ -221,43 +101,8 @@ static void clk_ipu_disable(struct clk *clk)
*/
static int ipu_clk_init(struct ipu_ctx *ctx)
{
- struct clk *ipu_clk;
-
- ipu_clk = devm_kzalloc(ctx->dev, sizeof(*ipu_clk), GFP_KERNEL);
- if (!ipu_clk)
- return -ENOMEM;
-
- ipu_clk->name = "ipu_clk";
- ipu_clk->ctx = ctx;
-#if CONFIG_IS_ENABLED(MX51) || CONFIG_IS_ENABLED(MX53)
- ipu_clk->enable_reg =
- (u32 *)(CCM_BASE_ADDR + offsetof(struct mxc_ccm_reg, CCGR5));
- ipu_clk->enable_shift = MXC_CCM_CCGR5_IPU_OFFSET;
-#else
- ipu_clk->enable_reg =
- (u32 *)(CCM_BASE_ADDR + offsetof(struct mxc_ccm_reg, CCGR3));
- ipu_clk->enable_shift = MXC_CCM_CCGR3_IPU1_IPU_DI0_OFFSET;
-#endif
-
- ipu_clk->enable = clk_ipu_enable;
- ipu_clk->disable = clk_ipu_disable;
- ipu_clk->usecount = 0;
-
-#if CONFIG_IS_ENABLED(MX51)
- ipu_clk->rate = IPUV3_CLK_MX51;
-#elif CONFIG_IS_ENABLED(MX53)
- ipu_clk->rate = IPUV3_CLK_MX53;
-#else
- ipu_clk->rate = is_mx6sdl() ? IPUV3_CLK_MX6DL : IPUV3_CLK_MX6Q;
-#endif
-
- ctx->ipu_clk = ipu_clk;
- return 0;
-};
-
-#if !defined CFG_SYS_LDB_CLOCK
-#define CFG_SYS_LDB_CLOCK 65000000
-#endif
+ return ipu_clk_init_legacy(ctx);
+}
/*
* Function to initialize the ldb dummy clock
@@ -268,23 +113,8 @@ static int ipu_clk_init(struct ipu_ctx *ctx)
*/
static int ipu_ldb_clk_init(struct ipu_ctx *ctx)
{
- struct clk *ldb_clk;
-
- ldb_clk = devm_kzalloc(ctx->dev, sizeof(*ldb_clk), GFP_KERNEL);
- if (!ldb_clk)
- return -ENOMEM;
-
- ldb_clk->name = "ldb_clk";
- ldb_clk->ctx = ctx;
- ldb_clk->rate = CFG_SYS_LDB_CLOCK;
- ldb_clk->usecount = 0;
-
- ctx->ldb_clk = ldb_clk;
- return 0;
-};
-
-u32 *ipu_cpmem_base;
-u32 *ipu_dc_tmpl_reg;
+ return ipu_ldb_clk_init_legacy(ctx);
+}
/* Static functions */
@@ -320,124 +150,6 @@ static inline void ipu_ch_param_set_buffer(u32 ch, int buf_num,
#define idma_mask(ch) (idma_is_valid(ch) ? (1UL << (ch & 0x1F)) : 0)
#define idma_is_set(reg, dma) (__raw_readl(reg(dma)) & idma_mask(dma))
-static void ipu_pixel_clk_recalc(struct clk *clk)
-{
- u32 div;
- u64 final_rate = (unsigned long long)clk->parent->rate * 16;
-
- div = __raw_readl(DI_BS_CLKGEN0(clk->id));
- debug("read BS_CLKGEN0 div:%d, final_rate:%lld, prate:%ld\n", div,
- final_rate, clk->parent->rate);
-
- clk->rate = 0;
- if (div != 0) {
- do_div(final_rate, div);
- clk->rate = final_rate;
- }
-}
-
-static unsigned long ipu_pixel_clk_round_rate(struct clk *clk,
- unsigned long rate)
-{
- u64 div, final_rate;
- u32 remainder;
- u64 parent_rate = (unsigned long long)clk->parent->rate * 16;
-
- /*
- * Calculate divider
- * Fractional part is 4 bits,
- * so simply multiply by 2^4 to get fractional part.
- */
- div = parent_rate;
- remainder = do_div(div, rate);
- /* Round the divider value */
- if (remainder > (rate / 2))
- div++;
- if (div < 0x10) /* Min DI disp clock divider is 1 */
- div = 0x10;
- if (div & ~0xFEF)
- div &= 0xFF8;
- else {
- /* Round up divider if it gets us closer to desired pix clk */
- if ((div & 0xC) == 0xC) {
- div += 0x10;
- div &= ~0xF;
- }
- }
- final_rate = parent_rate;
- do_div(final_rate, div);
-
- return final_rate;
-}
-
-static int ipu_pixel_clk_set_rate(struct clk *clk, unsigned long rate)
-{
- u64 div, parent_rate;
- u32 remainder;
-
- parent_rate = (unsigned long long)clk->parent->rate * 16;
- div = parent_rate;
- remainder = do_div(div, rate);
- /* Round the divider value */
- if (remainder > (rate / 2))
- div++;
-
- /* Round up divider if it gets us closer to desired pix clk */
- if ((div & 0xC) == 0xC) {
- div += 0x10;
- div &= ~0xF;
- }
- if (div > 0x1000)
- debug("Overflow, DI_BS_CLKGEN0 div:0x%x\n", (u32)div);
-
- __raw_writel(div, DI_BS_CLKGEN0(clk->id));
-
- /*
- * Setup pixel clock timing
- * Down time is half of period
- */
- __raw_writel((div / 16) << 16, DI_BS_CLKGEN1(clk->id));
-
- do_div(parent_rate, div);
-
- clk->rate = parent_rate;
-
- return 0;
-}
-
-static int ipu_pixel_clk_enable(struct clk *clk)
-{
- u32 disp_gen = __raw_readl(IPU_DISP_GEN);
- disp_gen |= clk->id ? DI1_COUNTER_RELEASE : DI0_COUNTER_RELEASE;
- __raw_writel(disp_gen, IPU_DISP_GEN);
-
- return 0;
-}
-
-static void ipu_pixel_clk_disable(struct clk *clk)
-{
- u32 disp_gen = __raw_readl(IPU_DISP_GEN);
- disp_gen &= clk->id ? ~DI1_COUNTER_RELEASE : ~DI0_COUNTER_RELEASE;
- __raw_writel(disp_gen, IPU_DISP_GEN);
-}
-
-static int ipu_pixel_clk_set_parent(struct clk *clk, struct clk *parent)
-{
- u32 di_gen = __raw_readl(DI_GENERAL(clk->id));
- struct ipu_ctx *ctx = clk->ctx;
-
- if (parent == ctx->ipu_clk)
- di_gen &= ~DI_GEN_DI_CLK_EXT;
- else if (!IS_ERR(ctx->di_clk[clk->id]) && parent == ctx->ldb_clk)
- di_gen |= DI_GEN_DI_CLK_EXT;
- else
- return -EINVAL;
-
- __raw_writel(di_gen, DI_GENERAL(clk->id));
- ipu_pixel_clk_recalc(clk);
- return 0;
-}
-
/*
* Function to initialize the pixel clock
*
@@ -447,26 +159,8 @@ static int ipu_pixel_clk_set_parent(struct clk *clk, struct clk *parent)
*/
static int ipu_pixel_clk_init(struct ipu_ctx *ctx, int id)
{
- struct clk *pixel_clk;
-
- pixel_clk = devm_kzalloc(ctx->dev, sizeof(*pixel_clk), GFP_KERNEL);
- if (!pixel_clk)
- return -ENOMEM;
-
- pixel_clk->name = "pixel_clk";
- pixel_clk->id = id;
- pixel_clk->ctx = ctx;
- pixel_clk->recalc = ipu_pixel_clk_recalc;
- pixel_clk->set_rate = ipu_pixel_clk_set_rate;
- pixel_clk->round_rate = ipu_pixel_clk_round_rate;
- pixel_clk->set_parent = ipu_pixel_clk_set_parent;
- pixel_clk->enable = ipu_pixel_clk_enable;
- pixel_clk->disable = ipu_pixel_clk_disable;
- pixel_clk->usecount = 0;
-
- ctx->pixel_clk[id] = pixel_clk;
- return 0;
-};
+ return ipu_pixel_clk_init_legacy(ctx, id);
+}
/*
* This function resets IPU
--
2.39.5
More information about the U-Boot
mailing list