diff options
Diffstat (limited to 'drivers/video/imx/ipu_common.c')
| -rw-r--r-- | drivers/video/imx/ipu_common.c | 371 |
1 files changed, 59 insertions, 312 deletions
diff --git a/drivers/video/imx/ipu_common.c b/drivers/video/imx/ipu_common.c index e9897ee79d2..8630374a055 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,19 @@ 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; +#if CONFIG_IS_ENABLED(IPU_CLK_LEGACY) + return ipu_clk_init_legacy(ctx); #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 + struct clk *clk; - ipu_clk->enable = clk_ipu_enable; - ipu_clk->disable = clk_ipu_disable; - ipu_clk->usecount = 0; + clk = devm_clk_get(ctx->dev, "bus"); + if (IS_ERR(clk)) + return PTR_ERR(clk); -#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; + ctx->ipu_clk = clk; return 0; -}; - -#if !defined CFG_SYS_LDB_CLOCK -#define CFG_SYS_LDB_CLOCK 65000000 #endif +} /* * Function to initialize the ldb dummy clock @@ -268,23 +124,14 @@ 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; +#if CONFIG_IS_ENABLED(IPU_CLK_LEGACY) + return ipu_ldb_clk_init_legacy(ctx); +#else + /* Set this in the FB driver where we know the display id */ + ctx->ldb_clk = NULL; return 0; -}; - -u32 *ipu_cpmem_base; -u32 *ipu_dc_tmpl_reg; +#endif +} /* Static functions */ @@ -320,124 +167,29 @@ 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) +/* + * Function to initialize the display clocks + * + * @param ctx The ipu context for which the function is called + * + * Return: Returns 0 on success or negative error code on error + */ +static int ipu_di_clk_init(struct ipu_ctx *ctx, int id) { - 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); - +#if CONFIG_IS_ENABLED(IPU_CLK_LEGACY) + ctx->di_clk[id] = NULL; 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; +#else + struct clk *clk; - 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; + clk = devm_clk_get(ctx->dev, id ? "di1" : "di0"); + if (IS_ERR(clk)) + return PTR_ERR(clk); - __raw_writel(di_gen, DI_GENERAL(clk->id)); - ipu_pixel_clk_recalc(clk); + ctx->di_clk[id] = clk; return 0; +#endif } - /* * Function to initialize the pixel clock * @@ -447,26 +199,13 @@ 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; +#if CONFIG_IS_ENABLED(IPU_CLK_LEGACY) + return ipu_pixel_clk_init_legacy(ctx, id); +#else + ctx->pixel_clk[id] = ctx->ipu_clk; return 0; -}; +#endif +} /* * This function resets IPU @@ -536,33 +275,39 @@ struct ipu_ctx *ipu_probe(struct udevice *dev) ipu_cpmem_base = (u32 *)(ipu_base + IPU_CPMEM_REG_BASE); ipu_dc_tmpl_reg = (u32 *)(ipu_base + IPU_DC_TMPL_REG_BASE); - ret = ipu_pixel_clk_init(ctx, 0); - if (ret) - goto err; - - ret = ipu_pixel_clk_init(ctx, 1); - if (ret) - goto err; + for (int i = 0; i <= 1; i++) { + ret = ipu_pixel_clk_init(ctx, i); + if (ret) + goto err; + } ret = ipu_clk_init(ctx); if (ret) goto err; - debug("ipu_clk = %u\n", clk_get_rate(ctx->ipu_clk)); + debug("ipu_clk = %lu\n", (ulong)clk_get_rate(ctx->ipu_clk)); ret = ipu_ldb_clk_init(ctx); if (ret) goto err; - debug("ldb_clk = %u\n", clk_get_rate(ctx->ldb_clk)); + if (ctx->ldb_clk) + debug("ldb_clk = %lu\n", (ulong)clk_get_rate(ctx->ldb_clk)); + ipu_reset(); +#if CONFIG_IS_ENABLED(IPU_CLK_LEGACY) clk_set_parent(ctx->pixel_clk[0], ctx->ipu_clk); clk_set_parent(ctx->pixel_clk[1], ctx->ipu_clk); + clk_enable(ctx->ipu_clk); +#endif - ctx->di_clk[0] = NULL; - ctx->di_clk[1] = NULL; + for (int i = 0; i <= 1; i++) { + ret = ipu_di_clk_init(ctx, i); + if (ret) + goto err; + } __raw_writel(0x807FFFFF, IPU_MEM_RST); while (__raw_readl(IPU_MEM_RST) & 0x80000000) @@ -584,7 +329,9 @@ struct ipu_ctx *ipu_probe(struct udevice *dev) /* Set MCU_T to divide MCU access window into 2 */ __raw_writel(0x00400000L | (IPU_MCU_T_DEFAULT << 18), IPU_DISP_GEN); +#if CONFIG_IS_ENABLED(IPU_CLK_LEGACY) clk_disable(ctx->ipu_clk); +#endif return ctx; err: |
