]> git.kernelconcepts.de Git - karo-tx-uboot.git/blobdiff - drivers/video/ipu_common.c
video: ipu: initialize g_ipu_clk, g_ldb_clk statically
[karo-tx-uboot.git] / drivers / video / ipu_common.c
index 9d20c864bac8adc70cd1acb1dcf2538d71bcaebd..355c697ef418e462e85d0d673e42141aad4b2117 100644 (file)
@@ -4,42 +4,28 @@
  * (C) Copyright 2010
  * Stefano Babic, DENX Software Engineering, sbabic@denx.de
  *
- * Linux IPU driver for MX51:
+ * Linux IPU driver
  *
- * (C) Copyright 2005-2010 Freescale Semiconductor, Inc.
+ * (C) Copyright 2005-2011 Freescale Semiconductor, Inc.
  *
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
+ * SPDX-License-Identifier:    GPL-2.0+
  */
 
 /* #define DEBUG */
 #include <common.h>
+#include <div64.h>
+#include <ipu.h>
 #include <linux/types.h>
 #include <linux/err.h>
 #include <asm/io.h>
 #include <asm/errno.h>
 #include <asm/arch/imx-regs.h>
 #include <asm/arch/crm_regs.h>
-#include "ipu.h"
+#include <asm/arch/clock.h>
+
 #include "ipu_regs.h"
 
-extern struct mxc_ccm_reg *mxc_ccm;
-extern u32 *ipu_cpmem_base;
+static struct mxc_ccm_reg __maybe_unused *mxc_ccm = (void *)CCM_BASE_ADDR;
 
 struct ipu_ch_param_word {
        uint32_t data[5];
@@ -53,185 +39,108 @@ struct ipu_ch_param {
 #define ipu_ch_param_addr(ch) (((struct ipu_ch_param *)ipu_cpmem_base) + (ch))
 
 #define _param_word(base, w) \
-       (((struct ipu_ch_param *)(base))->word[(w)].data)
+       (((struct ipu_ch_param *)(base))->word[w].data)
 
-#define ipu_ch_param_set_field(base, w, bit, size, v) { \
-       int i = (bit) / 32; \
-       int off = (bit) % 32; \
-       _param_word(base, w)[i] |= (v) << off; \
-       if (((bit) + (size) - 1) / 32 > i) { \
+#define ipu_ch_param_set_field(base, w, bit, size, v) {                        \
+       int i = (bit) / 32;                                             \
+       int off = (bit) % 32;                                           \
+       _param_word(base, w)[i] |= (v) << off;                          \
+       if (((bit) + (size) - 1) / 32 > i) {                            \
                _param_word(base, w)[i + 1] |= (v) >> (off ? (32 - off) : 0); \
-       } \
+       }                                                               \
 }
 
-#define ipu_ch_param_mod_field(base, w, bit, size, v) { \
-       int i = (bit) / 32; \
-       int off = (bit) % 32; \
-       u32 mask = (1UL << size) - 1; \
-       u32 temp = _param_word(base, w)[i]; \
-       temp &= ~(mask << off); \
-       _param_word(base, w)[i] = temp | (v) << off; \
-       if (((bit) + (size) - 1) / 32 > i) { \
-               temp = _param_word(base, w)[i + 1]; \
-               temp &= ~(mask >> (32 - off)); \
-               _param_word(base, w)[i + 1] = \
+#define ipu_ch_param_mod_field(base, w, bit, size, v) {                \
+       int i = (bit) / 32;                                     \
+       int off = (bit) % 32;                                   \
+       u32 mask = (1UL << size) - 1;                           \
+       u32 temp = _param_word(base, w)[i];                     \
+       temp &= ~(mask << off);                                 \
+       _param_word(base, w)[i] = temp | (v) << off;            \
+       if (((bit) + (size) - 1) / 32 > i) {                    \
+               temp = _param_word(base, w)[i + 1];             \
+               temp &= ~(mask >> (32 - off));                  \
+               _param_word(base, w)[i + 1] =                   \
                        temp | ((v) >> (off ? (32 - off) : 0)); \
-       } \
+       }                                                       \
 }
 
-#define ipu_ch_param_read_field(base, w, bit, size) ({ \
-       u32 temp2; \
-       int i = (bit) / 32; \
-       int off = (bit) % 32; \
-       u32 mask = (1UL << size) - 1; \
-       u32 temp1 = _param_word(base, w)[i]; \
-       temp1 = mask & (temp1 >> off); \
-       if (((bit)+(size) - 1) / 32 > i) { \
-               temp2 = _param_word(base, w)[i + 1]; \
-               temp2 &= mask >> (off ? (32 - off) : 0); \
-               temp1 |= temp2 << (off ? (32 - off) : 0); \
-       } \
-       temp1; \
+#define ipu_ch_param_read_field(base, w, bit, size) ({         \
+       u32 temp2;                                              \
+       int i = (bit) / 32;                                     \
+       int off = (bit) % 32;                                   \
+       u32 mask = (1UL << size) - 1;                           \
+       u32 temp1 = _param_word(base, w)[i];                    \
+       temp1 = mask & (temp1 >> off);                          \
+       if (((bit)+(size) - 1) / 32 > i) {                      \
+               temp2 = _param_word(base, w)[i + 1];            \
+               temp2 &= mask >> (off ? (32 - off) : 0);        \
+               temp1 |= temp2 << (off ? (32 - off) : 0);       \
+       }                                                       \
+       temp1;                                                  \
 })
 
+#define IPU_SW_RST_TOUT_USEC   10000
 
-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)
+static int clk_ipu_enable(struct clk *clk)
 {
-       if (clk && clk->set_rate)
-               clk->set_rate(clk, rate);
-       return clk->rate;
+       ipu_clk_enable();
+       return 0;
 }
 
-long clk_round_rate(struct clk *clk, unsigned long rate)
+static void clk_ipu_disable(struct clk *clk)
 {
-       if (clk == NULL || !clk->round_rate)
-               return 0;
-
-       return clk->round_rate(clk, rate);
+       ipu_clk_disable();
 }
 
-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 struct clk ipu_clk = {
+       .name = "ipu_clk",
+       .rate = CONFIG_IPUV3_CLK,
+       .enable = clk_ipu_enable,
+       .disable = clk_ipu_disable,
+};
 
-static int clk_ipu_enable(struct clk *clk)
+static int clk_ldb_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);
-
-       /* 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);
-
+       ldb_clk_enable(0);
+       ldb_clk_enable(1);
        return 0;
 }
 
-static void clk_ipu_disable(struct clk *clk)
+static void clk_ldb_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);
-
-       /*
-        * 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);
+       ldb_clk_disable(0);
+       ldb_clk_disable(1);
 }
 
+#if !defined CONFIG_SYS_LDB_CLOCK
+#define CONFIG_SYS_LDB_CLOCK 65000000
+#endif
 
-static struct clk ipu_clk = {
-       .name = "ipu_clk",
-       .rate = 133000000,
-       .enable_reg = (u32 *)(MXC_CCM_BASE +
-               offsetof(struct mxc_ccm_reg, CCGR5)),
-       .enable_shift = MXC_CCM_CCGR5_CG5_OFFSET,
-       .enable = clk_ipu_enable,
-       .disable = clk_ipu_disable,
-       .usecount = 0,
+static struct clk ldb_clk = {
+       .name = "ldb_clk",
+       .rate = CONFIG_SYS_LDB_CLOCK,
+       .enable = clk_ldb_enable,
+       .disable = clk_ldb_disable,
 };
 
 /* Globals */
-struct clk *g_ipu_clk;
-unsigned char g_ipu_clk_enabled;
+struct clk *g_ipu_clk = &ipu_clk;
+struct clk *g_ldb_clk = &ldb_clk;
 struct clk *g_di_clk[2];
 struct clk *g_pixel_clk[2];
 unsigned char g_dc_di_assignment[10];
-uint32_t g_channel_init_mask;
-uint32_t g_channel_enable_mask;
+int g_ipu_clk_enabled;
+u32 *ipu_dc_tmpl_reg;
 
+static uint32_t g_channel_init_mask;
+static uint32_t g_channel_enable_mask;
 static int ipu_dc_use_count;
 static int ipu_dp_use_count;
 static int ipu_dmfc_use_count;
 static int ipu_di_use_count[2];
 
-u32 *ipu_cpmem_base;
-u32 *ipu_dc_tmpl_reg;
+static u32 *ipu_cpmem_base;
 
 /* Static functions */
 
@@ -271,49 +180,66 @@ static inline void ipu_ch_param_set_buffer(uint32_t ch, int bufNum,
 static void ipu_pixel_clk_recalc(struct clk *clk)
 {
        u32 div = __raw_readl(DI_BS_CLKGEN0(clk->id));
+       u64 parent_rate = (u64)clk->parent->rate * 16;
+
        if (div == 0)
                clk->rate = 0;
        else
-               clk->rate = (clk->parent->rate * 16) / div;
+               clk->rate = lldiv(parent_rate, div);
 }
 
 static unsigned long ipu_pixel_clk_round_rate(struct clk *clk,
        unsigned long rate)
 {
        u32 div, div1;
-       u32 tmp;
+       u64 tmp;
+
        /*
         * Calculate divider
         * Fractional part is 4 bits,
         * so simply multiply by 2^4 to get fractional part.
         */
-       tmp = (clk->parent->rate * 16);
-       div = tmp / rate;
+       tmp = (u64)clk->parent->rate * 16;
+       div = lldiv(tmp, rate);
 
        if (div < 0x10)            /* Min DI disp clock divider is 1 */
                div = 0x10;
-       if (div & ~0xFEF)
+       if (div & ~0xFEF) {
                div &= 0xFF8;
-       else {
+       else {
                div1 = div & 0xFE0;
-               if ((tmp/div1 - tmp/div) < rate / 4)
+
+               if ((lldiv(tmp, div1) - lldiv(tmp, div)) < rate / 4)
                        div = div1;
                else
                        div &= 0xFF8;
        }
-       return (clk->parent->rate * 16) / div;
+       do_div(tmp, div);
+#if 1
+       debug("%s: requested rate: %lu.%03luMHz parent_rate: %lu.%03luMHz actual rate: %llu.%03lluMHz div: %u.%u\n", __func__,
+               rate / 1000000, rate / 1000 % 1000,
+               clk->parent->rate / 1000000, clk->parent->rate / 1000 % 1000,
+               lldiv(tmp, 1000000), lldiv(tmp, 1000) % 1000, div / 16, div % 16);
+#endif
+       return tmp;
 }
 
 static int ipu_pixel_clk_set_rate(struct clk *clk, unsigned long rate)
 {
-       u32 div = (clk->parent->rate * 16) / rate;
+       u64 parent_rate = (u64)clk->parent->rate * 16;
+       u32 div = lldiv(parent_rate, rate);
+
+       debug("%s: parent_rate: %lu.%03luMHz actual rate: %lu.%03luMHz div: %u.%u\n", __func__,
+               clk->parent->rate / 1000000, clk->parent->rate / 1000 % 1000,
+               rate / 1000000, rate / 1000 % 1000, div / 16, div % 16);
 
        __raw_writel(div, DI_BS_CLKGEN0(clk->id));
 
        /* Setup pixel clock timing */
        __raw_writel((div / 16) << 16, DI_BS_CLKGEN1(clk->id));
-
-       clk->rate = (clk->parent->rate * 16) / div;
+       clk->rate = lldiv(parent_rate, div);
+       debug("%s: pix_clk=%lu.%03luMHz\n", __func__,
+               clk->rate / 1000000, clk->rate / 1000 % 1000);
        return 0;
 }
 
@@ -331,62 +257,108 @@ 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));
+       int ret;
+       u32 di_gen;
+
+       ret = clk_enable(clk);
+       if (ret)
+               return ret;
+
+       di_gen = __raw_readl(DI_GENERAL(clk->id));
 
        if (parent == g_ipu_clk)
                di_gen &= ~DI_GEN_DI_CLK_EXT;
-       else if (!IS_ERR(g_di_clk[clk->id]) && parent == g_di_clk[clk->id])
+       else if (!IS_ERR(g_di_clk[clk->id]) && parent == g_ldb_clk)
                di_gen |= DI_GEN_DI_CLK_EXT;
        else
-               return -EINVAL;
+               goto err;
 
+       ret = clk_enable(parent);
+       if (ret)
+               goto err;
        __raw_writel(di_gen, DI_GENERAL(clk->id));
        ipu_pixel_clk_recalc(clk);
-       return 0;
+       clk->disable(clk->parent);
+       clk->parent = parent;
+err:
+       clk_disable(clk);
+       return ret;
 }
 
 static struct clk pixel_clk[] = {
        {
-       .name = "pixel_clk",
-       .id = 0,
-       .recalc = ipu_pixel_clk_recalc,
-       .set_rate = ipu_pixel_clk_set_rate,
-       .round_rate = ipu_pixel_clk_round_rate,
-       .set_parent = ipu_pixel_clk_set_parent,
-       .enable = ipu_pixel_clk_enable,
-       .disable = ipu_pixel_clk_disable,
-       .usecount = 0,
+               .name = "pixel_clk",
+               .id = 0,
+               .recalc = ipu_pixel_clk_recalc,
+               .set_rate = ipu_pixel_clk_set_rate,
+               .round_rate = ipu_pixel_clk_round_rate,
+               .set_parent = ipu_pixel_clk_set_parent,
+               .enable = ipu_pixel_clk_enable,
+               .disable = ipu_pixel_clk_disable,
+       },
+       {
+               .name = "pixel_clk",
+               .id = 1,
+               .recalc = ipu_pixel_clk_recalc,
+               .set_rate = ipu_pixel_clk_set_rate,
+               .round_rate = ipu_pixel_clk_round_rate,
+               .set_parent = ipu_pixel_clk_set_parent,
+               .enable = ipu_pixel_clk_enable,
+               .disable = ipu_pixel_clk_disable,
+       },
+};
+
+static int clk_ipu_di_enable(struct clk *clk)
+{
+       ipu_di_clk_enable(clk->id);
+       return 0;
+}
+
+static void clk_ipu_di_disable(struct clk *clk)
+{
+       ipu_di_clk_disable(clk->id);
+}
+
+static struct clk di_clk[] = {
+       {
+               .name = "ipu_di_clk",
+               .id = 0,
+               .enable = clk_ipu_di_enable,
+               .disable = clk_ipu_di_disable,
        },
        {
-       .name = "pixel_clk",
-       .id = 1,
-       .recalc = ipu_pixel_clk_recalc,
-       .set_rate = ipu_pixel_clk_set_rate,
-       .round_rate = ipu_pixel_clk_round_rate,
-       .set_parent = ipu_pixel_clk_set_parent,
-       .enable = ipu_pixel_clk_enable,
-       .disable = ipu_pixel_clk_disable,
-       .usecount = 0,
+               .name = "ipu_di_clk",
+               .id = 1,
+               .enable = clk_ipu_di_enable,
+               .disable = clk_ipu_di_disable,
        },
 };
 
 /*
  * This function resets IPU
  */
-void ipu_reset(void)
+static void ipu_reset(void)
 {
        u32 *reg;
        u32 value;
+       int timeout = IPU_SW_RST_TOUT_USEC;
 
        reg = (u32 *)SRC_BASE_ADDR;
        value = __raw_readl(reg);
        value = value | SW_IPU_RST;
        __raw_writel(value, reg);
+
+       while (__raw_readl(reg) & SW_IPU_RST) {
+               udelay(1);
+               if (!(timeout--)) {
+                       printf("ipu software reset timeout\n");
+                       break;
+               }
+       };
 }
 
 /*
@@ -398,45 +370,66 @@ void ipu_reset(void)
  *
  * @return      Returns 0 on success or negative error code on error
  */
-int ipu_probe(void)
+int ipu_probe(int di, ipu_di_clk_parent_t di_clk_parent, int di_clk_val)
 {
-       unsigned long ipu_base;
+       int ret;
+       void *ipu_base;
+       unsigned long start;
+#if defined CONFIG_SOC_MX51
        u32 temp;
-
        u32 *reg_hsc_mcd = (u32 *)MIPI_HSC_BASE_ADDR;
        u32 *reg_hsc_mxt_conf = (u32 *)(MIPI_HSC_BASE_ADDR + 0x800);
 
         __raw_writel(0xF00, reg_hsc_mcd);
 
-       /* CSI mode reserved*/
+       /* CSI mode reserved */
        temp = __raw_readl(reg_hsc_mxt_conf);
         __raw_writel(temp | 0x0FF, reg_hsc_mxt_conf);
 
        temp = __raw_readl(reg_hsc_mxt_conf);
        __raw_writel(temp | 0x10000, reg_hsc_mxt_conf);
-
-       ipu_base = IPU_CTRL_BASE_ADDR;
-       ipu_cpmem_base = (u32 *)(ipu_base + IPU_CPMEM_REG_BASE);
-       ipu_dc_tmpl_reg = (u32 *)(ipu_base + IPU_DC_TMPL_REG_BASE);
+#endif
+       ipu_base = (void *)IPU_SOC_BASE_ADDR;
+       /* base fixup */
+       if (gd->arch.ipu_hw_rev == IPUV3_HW_REV_IPUV3H) /* IPUv3H */
+               ipu_base += IPUV3H_REG_BASE;
+       else if (gd->arch.ipu_hw_rev == IPUV3_HW_REV_IPUV3M)    /* IPUv3M */
+               ipu_base += IPUV3M_REG_BASE;
+       else                    /* IPUv3D, v3E, v3EX */
+               ipu_base += IPUV3DEX_REG_BASE;
+       ipu_cpmem_base = ipu_base + IPU_CPMEM_REG_BASE;
+       ipu_dc_tmpl_reg = ipu_base + IPU_DC_TMPL_REG_BASE;
+
+       printf("IPU HW Rev: %d\n", gd->arch.ipu_hw_rev);
 
        g_pixel_clk[0] = &pixel_clk[0];
        g_pixel_clk[1] = &pixel_clk[1];
 
-       g_ipu_clk = &ipu_clk;
+       g_di_clk[0] = &di_clk[0];
+       g_di_clk[1] = &di_clk[1];
+       g_di_clk[di]->rate = di_clk_val;
+
        debug("ipu_clk = %u\n", clk_get_rate(g_ipu_clk));
+       debug("ldb_clk = %u\n", clk_get_rate(g_ldb_clk));
 
+       ret = clk_enable(g_ipu_clk);
+       if (ret)
+               return ret;
        ipu_reset();
 
-       clk_set_parent(g_pixel_clk[0], g_ipu_clk);
-       clk_set_parent(g_pixel_clk[1], g_ipu_clk);
-       clk_enable(g_ipu_clk);
-
-       g_di_clk[0] = NULL;
-       g_di_clk[1] = NULL;
+       if (di_clk_parent == DI_PCLK_LDB) {
+               clk_set_parent(g_pixel_clk[di], g_ldb_clk);
+       } else {
+               clk_set_parent(g_pixel_clk[0], g_ipu_clk);
+               clk_set_parent(g_pixel_clk[1], g_ipu_clk);
+       }
 
        __raw_writel(0x807FFFFF, IPU_MEM_RST);
-       while (__raw_readl(IPU_MEM_RST) & 0x80000000)
-               ;
+       start = get_timer_masked();
+       while (__raw_readl(IPU_MEM_RST) & 0x80000000) {
+               if (get_timer(start) > CONFIG_SYS_HZ)
+                       return -ETIME;
+       }
 
        ipu_init_dc_mappings();
 
@@ -461,37 +454,37 @@ int ipu_probe(void)
 
 void ipu_dump_registers(void)
 {
-       debug("IPU_CONF = \t0x%08X\n", __raw_readl(IPU_CONF));
-       debug("IDMAC_CONF = \t0x%08X\n", __raw_readl(IDMAC_CONF));
-       debug("IDMAC_CHA_EN1 = \t0x%08X\n",
+       debug("IPU_CONF             0x%08X\n", __raw_readl(IPU_CONF));
+       debug("IDMAC_CONF           0x%08X\n", __raw_readl(IDMAC_CONF));
+       debug("IDMAC_CHA_EN1        0x%08X\n",
               __raw_readl(IDMAC_CHA_EN(0)));
-       debug("IDMAC_CHA_EN2 = \t0x%08X\n",
+       debug("IDMAC_CHA_EN2        0x%08X\n",
               __raw_readl(IDMAC_CHA_EN(32)));
-       debug("IDMAC_CHA_PRI1 = \t0x%08X\n",
+       debug("IDMAC_CHA_PRI1       0x%08X\n",
               __raw_readl(IDMAC_CHA_PRI(0)));
-       debug("IDMAC_CHA_PRI2 = \t0x%08X\n",
+       debug("IDMAC_CHA_PRI2       0x%08X\n",
               __raw_readl(IDMAC_CHA_PRI(32)));
-       debug("IPU_CHA_DB_MODE_SEL0 = \t0x%08X\n",
+       debug("IPU_CHA_DB_MODE_SEL0 0x%08X\n",
               __raw_readl(IPU_CHA_DB_MODE_SEL(0)));
-       debug("IPU_CHA_DB_MODE_SEL1 = \t0x%08X\n",
+       debug("IPU_CHA_DB_MODE_SEL1 0x%08X\n",
               __raw_readl(IPU_CHA_DB_MODE_SEL(32)));
-       debug("DMFC_WR_CHAN = \t0x%08X\n",
+       debug("DMFC_WR_CHAN         0x%08X\n",
               __raw_readl(DMFC_WR_CHAN));
-       debug("DMFC_WR_CHAN_DEF = \t0x%08X\n",
+       debug("DMFC_WR_CHAN_DEF     0x%08X\n",
               __raw_readl(DMFC_WR_CHAN_DEF));
-       debug("DMFC_DP_CHAN = \t0x%08X\n",
+       debug("DMFC_DP_CHAN         0x%08X\n",
               __raw_readl(DMFC_DP_CHAN));
-       debug("DMFC_DP_CHAN_DEF = \t0x%08X\n",
+       debug("DMFC_DP_CHAN_DEF     0x%08X\n",
               __raw_readl(DMFC_DP_CHAN_DEF));
-       debug("DMFC_IC_CTRL = \t0x%08X\n",
+       debug("DMFC_IC_CTRL         0x%08X\n",
               __raw_readl(DMFC_IC_CTRL));
-       debug("IPU_FS_PROC_FLOW1 = \t0x%08X\n",
+       debug("IPU_FS_PROC_FLOW1    0x%08X\n",
               __raw_readl(IPU_FS_PROC_FLOW1));
-       debug("IPU_FS_PROC_FLOW2 = \t0x%08X\n",
+       debug("IPU_FS_PROC_FLOW2    0x%08X\n",
               __raw_readl(IPU_FS_PROC_FLOW2));
-       debug("IPU_FS_PROC_FLOW3 = \t0x%08X\n",
+       debug("IPU_FS_PROC_FLOW3    0x%08X\n",
               __raw_readl(IPU_FS_PROC_FLOW3));
-       debug("IPU_FS_DISP_FLOW1 = \t0x%08X\n",
+       debug("IPU_FS_DISP_FLOW1    0x%08X\n",
               __raw_readl(IPU_FS_DISP_FLOW1));
 }
 
@@ -565,7 +558,6 @@ int32_t ipu_init_channel(ipu_channel_t channel, ipu_channel_params_t *params)
                break;
        default:
                printf("Missing channel initialization\n");
-               break;
        }
 
        /* Enable IPU sub module */
@@ -578,9 +570,11 @@ int32_t ipu_init_channel(ipu_channel_t channel, ipu_channel_params_t *params)
                ipu_conf |= IPU_CONF_DMFC_EN;
        if (ipu_di_use_count[0] == 1) {
                ipu_conf |= IPU_CONF_DI0_EN;
+               clk_enable(g_di_clk[0]);
        }
        if (ipu_di_use_count[1] == 1) {
                ipu_conf |= IPU_CONF_DI1_EN;
+               clk_enable(g_di_clk[1]);
        }
 
        __raw_writel(ipu_conf, IPU_CONF);
@@ -615,8 +609,7 @@ void ipu_uninit_channel(ipu_channel_t channel)
 
        if (idma_is_set(IDMAC_CHA_EN, in_dma) ||
            idma_is_set(IDMAC_CHA_EN, out_dma)) {
-               printf(
-                       "Channel %d is not disabled, disable first\n",
+               printf("Channel %d is not disabled, disable first\n",
                        IPU_CHAN_ID(channel));
                return;
        }
@@ -662,20 +655,24 @@ void ipu_uninit_channel(ipu_channel_t channel)
                ipu_conf &= ~IPU_CONF_DP_EN;
        if (ipu_dmfc_use_count == 0)
                ipu_conf &= ~IPU_CONF_DMFC_EN;
-       if (ipu_di_use_count[0] == 0) {
+       if (ipu_di_use_count[0] == 0 && ipu_conf & IPU_CONF_DI0_EN) {
                ipu_conf &= ~IPU_CONF_DI0_EN;
+               clk_disable(g_di_clk[0]);
        }
-       if (ipu_di_use_count[1] == 0) {
+       if (ipu_di_use_count[1] == 0 && ipu_conf & IPU_CONF_DI1_EN) {
                ipu_conf &= ~IPU_CONF_DI1_EN;
+               clk_disable(g_di_clk[1]);
        }
 
        __raw_writel(ipu_conf, IPU_CONF);
 
+       /* clear interrupt status */
+       __raw_writel(__raw_readl(IPU_STAT), IPU_STAT);
+
        if (ipu_conf == 0) {
                clk_disable(g_ipu_clk);
                g_ipu_clk_enabled = 0;
        }
-
 }
 
 static inline void ipu_ch_param_dump(int ch)
@@ -750,91 +747,88 @@ static void ipu_ch_param_init(int ch,
 {
        uint32_t u_offset = 0;
        uint32_t v_offset = 0;
-       struct ipu_ch_param params;
-
-       memset(&params, 0, sizeof(params));
 
-       ipu_ch_param_set_field(&params, 0, 125, 13, width - 1);
+       ipu_ch_param_set_field(ipu_ch_param_addr(ch), 0, 125, 13, width - 1);
 
        if ((ch == 8) || (ch == 9) || (ch == 10)) {
-               ipu_ch_param_set_field(&params, 0, 138, 12, (height / 2) - 1);
-               ipu_ch_param_set_field(&params, 1, 102, 14, (stride * 2) - 1);
+               ipu_ch_param_set_field(ipu_ch_param_addr(ch), 0, 138, 12, (height / 2) - 1);
+               ipu_ch_param_set_field(ipu_ch_param_addr(ch), 1, 102, 14, (stride * 2) - 1);
        } else {
-               ipu_ch_param_set_field(&params, 0, 138, 12, height - 1);
-               ipu_ch_param_set_field(&params, 1, 102, 14, stride - 1);
+               ipu_ch_param_set_field(ipu_ch_param_addr(ch), 0, 138, 12, height - 1);
+               ipu_ch_param_set_field(ipu_ch_param_addr(ch), 1, 102, 14, stride - 1);
        }
 
-       ipu_ch_param_set_field(&params, 1, 0, 29, addr0 >> 3);
-       ipu_ch_param_set_field(&params, 1, 29, 29, addr1 >> 3);
+       ipu_ch_param_set_field(ipu_ch_param_addr(ch), 1, 0, 29, addr0 >> 3);
+       ipu_ch_param_set_field(ipu_ch_param_addr(ch), 1, 29, 29, addr1 >> 3);
 
        switch (pixel_fmt) {
        case IPU_PIX_FMT_GENERIC:
                /*Represents 8-bit Generic data */
-               ipu_ch_param_set_field(&params, 0, 107, 3, 5);  /* bits/pixel */
-               ipu_ch_param_set_field(&params, 1, 85, 4, 6);   /* pix format */
-               ipu_ch_param_set_field(&params, 1, 78, 7, 63);  /* burst size */
+               ipu_ch_param_set_field(ipu_ch_param_addr(ch), 0, 107, 3, 5);    /* bits/pixel */
+               ipu_ch_param_set_field(ipu_ch_param_addr(ch), 1, 85, 4, 6);     /* pix format */
+               ipu_ch_param_set_field(ipu_ch_param_addr(ch), 1, 78, 7, 63);    /* burst size */
 
                break;
        case IPU_PIX_FMT_GENERIC_32:
                /*Represents 32-bit Generic data */
                break;
        case IPU_PIX_FMT_RGB565:
-               ipu_ch_param_set_field(&params, 0, 107, 3, 3);  /* bits/pixel */
-               ipu_ch_param_set_field(&params, 1, 85, 4, 7);   /* pix format */
-               ipu_ch_param_set_field(&params, 1, 78, 7, 15);  /* burst size */
+               ipu_ch_param_set_field(ipu_ch_param_addr(ch), 0, 107, 3, 3);    /* bits/pixel */
+               ipu_ch_param_set_field(ipu_ch_param_addr(ch), 1, 85, 4, 7);     /* pix format */
+               ipu_ch_param_set_field(ipu_ch_param_addr(ch), 1, 78, 7, 15);    /* burst size */
 
-               ipu_ch_params_set_packing(&params, 5, 0, 6, 5, 5, 11, 8, 16);
+               ipu_ch_params_set_packing(ipu_ch_param_addr(ch), 5, 0, 6, 5, 5, 11, 8, 16);
                break;
        case IPU_PIX_FMT_BGR24:
-               ipu_ch_param_set_field(&params, 0, 107, 3, 1);  /* bits/pixel */
-               ipu_ch_param_set_field(&params, 1, 85, 4, 7);   /* pix format */
-               ipu_ch_param_set_field(&params, 1, 78, 7, 19);  /* burst size */
+               ipu_ch_param_set_field(ipu_ch_param_addr(ch), 0, 107, 3, 1);    /* bits/pixel */
+               ipu_ch_param_set_field(ipu_ch_param_addr(ch), 1, 85, 4, 7);     /* pix format */
+               ipu_ch_param_set_field(ipu_ch_param_addr(ch), 1, 78, 7, 19);    /* burst size */
 
-               ipu_ch_params_set_packing(&params, 8, 0, 8, 8, 8, 16, 8, 24);
+               ipu_ch_params_set_packing(ipu_ch_param_addr(ch), 8, 0, 8, 8, 8, 16, 8, 24);
                break;
        case IPU_PIX_FMT_RGB24:
        case IPU_PIX_FMT_YUV444:
-               ipu_ch_param_set_field(&params, 0, 107, 3, 1);  /* bits/pixel */
-               ipu_ch_param_set_field(&params, 1, 85, 4, 7);   /* pix format */
-               ipu_ch_param_set_field(&params, 1, 78, 7, 19);  /* burst size */
+               ipu_ch_param_set_field(ipu_ch_param_addr(ch), 0, 107, 3, 1);    /* bits/pixel */
+               ipu_ch_param_set_field(ipu_ch_param_addr(ch), 1, 85, 4, 7);     /* pix format */
+               ipu_ch_param_set_field(ipu_ch_param_addr(ch), 1, 78, 7, 19);    /* burst size */
 
-               ipu_ch_params_set_packing(&params, 8, 16, 8, 8, 8, 0, 8, 24);
+               ipu_ch_params_set_packing(ipu_ch_param_addr(ch), 8, 16, 8, 8, 8, 0, 8, 24);
                break;
        case IPU_PIX_FMT_BGRA32:
        case IPU_PIX_FMT_BGR32:
-               ipu_ch_param_set_field(&params, 0, 107, 3, 0);  /* bits/pixel */
-               ipu_ch_param_set_field(&params, 1, 85, 4, 7);   /* pix format */
-               ipu_ch_param_set_field(&params, 1, 78, 7, 15);  /* burst size */
+               ipu_ch_param_set_field(ipu_ch_param_addr(ch), 0, 107, 3, 0);    /* bits/pixel */
+               ipu_ch_param_set_field(ipu_ch_param_addr(ch), 1, 85, 4, 7);     /* pix format */
+               ipu_ch_param_set_field(ipu_ch_param_addr(ch), 1, 78, 7, 15);    /* burst size */
 
-               ipu_ch_params_set_packing(&params, 8, 8, 8, 16, 8, 24, 8, 0);
+               ipu_ch_params_set_packing(ipu_ch_param_addr(ch), 8, 8, 8, 16, 8, 24, 8, 0);
                break;
        case IPU_PIX_FMT_RGBA32:
        case IPU_PIX_FMT_RGB32:
-               ipu_ch_param_set_field(&params, 0, 107, 3, 0);  /* bits/pixel */
-               ipu_ch_param_set_field(&params, 1, 85, 4, 7);   /* pix format */
-               ipu_ch_param_set_field(&params, 1, 78, 7, 15);  /* burst size */
+               ipu_ch_param_set_field(ipu_ch_param_addr(ch), 0, 107, 3, 0);    /* bits/pixel */
+               ipu_ch_param_set_field(ipu_ch_param_addr(ch), 1, 85, 4, 7);     /* pix format */
+               ipu_ch_param_set_field(ipu_ch_param_addr(ch), 1, 78, 7, 15);    /* burst size */
 
-               ipu_ch_params_set_packing(&params, 8, 24, 8, 16, 8, 8, 8, 0);
+               ipu_ch_params_set_packing(ipu_ch_param_addr(ch), 8, 24, 8, 16, 8, 8, 8, 0);
                break;
        case IPU_PIX_FMT_ABGR32:
-               ipu_ch_param_set_field(&params, 0, 107, 3, 0);  /* bits/pixel */
-               ipu_ch_param_set_field(&params, 1, 85, 4, 7);   /* pix format */
+               ipu_ch_param_set_field(ipu_ch_param_addr(ch), 0, 107, 3, 0);    /* bits/pixel */
+               ipu_ch_param_set_field(ipu_ch_param_addr(ch), 1, 85, 4, 7);     /* pix format */
 
-               ipu_ch_params_set_packing(&params, 8, 0, 8, 8, 8, 16, 8, 24);
+               ipu_ch_params_set_packing(ipu_ch_param_addr(ch), 8, 0, 8, 8, 8, 16, 8, 24);
                break;
        case IPU_PIX_FMT_UYVY:
-               ipu_ch_param_set_field(&params, 0, 107, 3, 3);  /* bits/pixel */
-               ipu_ch_param_set_field(&params, 1, 85, 4, 0xA); /* pix format */
-               ipu_ch_param_set_field(&params, 1, 78, 7, 15);  /* burst size */
+               ipu_ch_param_set_field(ipu_ch_param_addr(ch), 0, 107, 3, 3);    /* bits/pixel */
+               ipu_ch_param_set_field(ipu_ch_param_addr(ch), 1, 85, 4, 0xA);   /* pix format */
+               ipu_ch_param_set_field(ipu_ch_param_addr(ch), 1, 78, 7, 15);    /* burst size */
                break;
        case IPU_PIX_FMT_YUYV:
-               ipu_ch_param_set_field(&params, 0, 107, 3, 3);  /* bits/pixel */
-               ipu_ch_param_set_field(&params, 1, 85, 4, 0x8); /* pix format */
-               ipu_ch_param_set_field(&params, 1, 78, 7, 31);  /* burst size */
+               ipu_ch_param_set_field(ipu_ch_param_addr(ch), 0, 107, 3, 3);    /* bits/pixel */
+               ipu_ch_param_set_field(ipu_ch_param_addr(ch), 1, 85, 4, 0x8);   /* pix format */
+               ipu_ch_param_set_field(ipu_ch_param_addr(ch), 1, 78, 7, 31);    /* burst size */
                break;
        case IPU_PIX_FMT_YUV420P2:
        case IPU_PIX_FMT_YUV420P:
-               ipu_ch_param_set_field(&params, 1, 85, 4, 2);   /* pix format */
+               ipu_ch_param_set_field(ipu_ch_param_addr(ch), 1, 85, 4, 2);     /* pix format */
 
                if (uv_stride < stride / 2)
                        uv_stride = stride / 2;
@@ -843,16 +837,16 @@ static void ipu_ch_param_init(int ch,
                v_offset = u_offset + (uv_stride * height / 2);
                /* burst size */
                if ((ch == 8) || (ch == 9) || (ch == 10)) {
-                       ipu_ch_param_set_field(&params, 1, 78, 7, 15);
+                       ipu_ch_param_set_field(ipu_ch_param_addr(ch), 1, 78, 7, 15);
                        uv_stride = uv_stride*2;
                } else {
-                       ipu_ch_param_set_field(&params, 1, 78, 7, 31);
+                       ipu_ch_param_set_field(ipu_ch_param_addr(ch), 1, 78, 7, 31);
                }
                break;
        case IPU_PIX_FMT_YVU422P:
                /* BPP & pixel format */
-               ipu_ch_param_set_field(&params, 1, 85, 4, 1);   /* pix format */
-               ipu_ch_param_set_field(&params, 1, 78, 7, 31);  /* burst size */
+               ipu_ch_param_set_field(ipu_ch_param_addr(ch), 1, 85, 4, 1);     /* pix format */
+               ipu_ch_param_set_field(ipu_ch_param_addr(ch), 1, 78, 7, 31);    /* burst size */
 
                if (uv_stride < stride / 2)
                        uv_stride = stride / 2;
@@ -862,8 +856,8 @@ static void ipu_ch_param_init(int ch,
                break;
        case IPU_PIX_FMT_YUV422P:
                /* BPP & pixel format */
-               ipu_ch_param_set_field(&params, 1, 85, 4, 1);   /* pix format */
-               ipu_ch_param_set_field(&params, 1, 78, 7, 31);  /* burst size */
+               ipu_ch_param_set_field(ipu_ch_param_addr(ch), 1, 85, 4, 1);     /* pix format */
+               ipu_ch_param_set_field(ipu_ch_param_addr(ch), 1, 78, 7, 31);    /* burst size */
 
                if (uv_stride < stride / 2)
                        uv_stride = stride / 2;
@@ -873,19 +867,19 @@ static void ipu_ch_param_init(int ch,
                break;
        case IPU_PIX_FMT_NV12:
                /* BPP & pixel format */
-               ipu_ch_param_set_field(&params, 1, 85, 4, 4);   /* pix format */
-               ipu_ch_param_set_field(&params, 1, 78, 7, 31);  /* burst size */
+               ipu_ch_param_set_field(ipu_ch_param_addr(ch), 1, 85, 4, 4);     /* pix format */
+               ipu_ch_param_set_field(ipu_ch_param_addr(ch), 1, 78, 7, 31);    /* burst size */
                uv_stride = stride;
                u_offset = (u == 0) ? stride * height : u;
                break;
        default:
-               puts("mxc ipu: unimplemented pixel format\n");
-               break;
+               printf("mxc ipu: unimplemented pixel format: %08x\n",
+                       pixel_fmt);
        }
 
 
        if (uv_stride)
-               ipu_ch_param_set_field(&params, 1, 128, 14, uv_stride - 1);
+               ipu_ch_param_set_field(ipu_ch_param_addr(ch), 1, 128, 14, uv_stride - 1);
 
        /* Get the uv offset from user when need cropping */
        if (u || v) {
@@ -899,11 +893,10 @@ static void ipu_ch_param_init(int ch,
        if (v_offset/8 > 0x3fffff)
                puts("The value of V offset exceeds IPU limitation\n");
 
-       ipu_ch_param_set_field(&params, 0, 46, 22, u_offset / 8);
-       ipu_ch_param_set_field(&params, 0, 68, 22, v_offset / 8);
+       ipu_ch_param_set_field(ipu_ch_param_addr(ch), 0, 46, 22, u_offset / 8);
+       ipu_ch_param_set_field(ipu_ch_param_addr(ch), 0, 68, 22, v_offset / 8);
 
        debug("initializing idma ch %d @ %p\n", ch, ipu_ch_param_addr(ch));
-       memcpy(ipu_ch_param_addr(ch), &params, sizeof(params));
 };
 
 /*
@@ -955,8 +948,7 @@ int32_t ipu_init_channel_buffer(ipu_channel_t channel, ipu_buffer_t type,
                stride = width * bytes_per_pixel(pixel_fmt);
 
        if (stride % 4) {
-               printf(
-                       "Stride not 32-bit aligned, stride = %d\n", stride);
+               printf("Stride %d not 32-bit aligned\n", stride);
                return -EINVAL;
        }
        /* Build parameter memory data for DMA channel */
@@ -1018,8 +1010,12 @@ int32_t ipu_enable_channel(ipu_channel_t channel)
        }
 
        if ((channel == MEM_DC_SYNC) || (channel == MEM_BG_SYNC) ||
-           (channel == MEM_FG_SYNC))
+           (channel == MEM_FG_SYNC)) {
+               reg = __raw_readl(IDMAC_WM_EN(in_dma));
+               __raw_writel(reg | idma_mask(in_dma), IDMAC_WM_EN(in_dma));
+
                ipu_dp_dc_enable(channel);
+       }
 
        g_channel_enable_mask |= 1L << IPU_CHAN_ID(channel);
 
@@ -1128,32 +1124,27 @@ int32_t ipu_disable_channel(ipu_channel_t channel)
 uint32_t bytes_per_pixel(uint32_t fmt)
 {
        switch (fmt) {
-       case IPU_PIX_FMT_GENERIC:       /*generic data */
+       case IPU_PIX_FMT_GENERIC:       /* generic data */
        case IPU_PIX_FMT_RGB332:
        case IPU_PIX_FMT_YUV420P:
        case IPU_PIX_FMT_YUV422P:
                return 1;
-               break;
        case IPU_PIX_FMT_RGB565:
        case IPU_PIX_FMT_YUYV:
        case IPU_PIX_FMT_UYVY:
                return 2;
-               break;
        case IPU_PIX_FMT_BGR24:
        case IPU_PIX_FMT_RGB24:
                return 3;
-               break;
-       case IPU_PIX_FMT_GENERIC_32:    /*generic data */
+       case IPU_PIX_FMT_GENERIC_32:    /* generic data */
        case IPU_PIX_FMT_BGR32:
        case IPU_PIX_FMT_BGRA32:
        case IPU_PIX_FMT_RGB32:
        case IPU_PIX_FMT_RGBA32:
        case IPU_PIX_FMT_ABGR32:
                return 4;
-               break;
        default:
                return 1;
-               break;
        }
        return 0;
 }
@@ -1173,11 +1164,17 @@ ipu_color_space_t format_to_colorspace(uint32_t fmt)
        case IPU_PIX_FMT_LVDS666:
        case IPU_PIX_FMT_LVDS888:
                return RGB;
-               break;
 
        default:
                return YCbCr;
-               break;
        }
        return RGB;
 }
+
+/* should be removed when clk framework is availiable */
+int ipu_set_ldb_clock(int rate)
+{
+       ldb_clk.rate = rate;
+
+       return 0;
+}