X-Git-Url: https://git.kernelconcepts.de/?p=karo-tx-uboot.git;a=blobdiff_plain;f=drivers%2Fvideo%2Fipu_common.c;h=355c697ef418e462e85d0d673e42141aad4b2117;hp=5873531953316a25799c020206328bd84280b97d;hb=e1be59fc1a959a917749ecf24834acdc6e2d70e7;hpb=625509ab0edbb7d943ad9028de3c21ca48aa58be diff --git a/drivers/video/ipu_common.c b/drivers/video/ipu_common.c index 5873531953..355c697ef4 100644 --- a/drivers/video/ipu_common.c +++ b/drivers/video/ipu_common.c @@ -4,26 +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. * * SPDX-License-Identifier: GPL-2.0+ */ /* #define DEBUG */ #include +#include +#include #include #include #include #include #include #include -#include "ipu.h" +#include + #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]; @@ -37,202 +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) -{ - if (clk && 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; -} +#define IPU_SW_RST_TOUT_USEC 10000 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 defined(CONFIG_MX51) || defined(CONFIG_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 + ipu_clk_enable(); 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 defined(CONFIG_MX51) || defined(CONFIG_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 + ipu_clk_disable(); } - static struct clk ipu_clk = { .name = "ipu_clk", .rate = CONFIG_IPUV3_CLK, -#if defined(CONFIG_MX51) || defined(CONFIG_MX53) - .enable_reg = (u32 *)(CCM_BASE_ADDR + - offsetof(struct mxc_ccm_reg, CCGR5)), - .enable_shift = MXC_CCM_CCGR5_IPU_OFFSET, -#else - .enable_reg = (u32 *)(CCM_BASE_ADDR + - offsetof(struct mxc_ccm_reg, CCGR3)), - .enable_shift = MXC_CCM_CCGR3_IPU1_IPU_DI0_OFFSET, -#endif .enable = clk_ipu_enable, .disable = clk_ipu_disable, - .usecount = 0, }; +static int clk_ldb_enable(struct clk *clk) +{ + ldb_clk_enable(0); + ldb_clk_enable(1); + return 0; +} + +static void clk_ldb_disable(struct clk *clk) +{ + ldb_clk_disable(0); + ldb_clk_disable(1); +} + +#if !defined CONFIG_SYS_LDB_CLOCK +#define CONFIG_SYS_LDB_CLOCK 65000000 +#endif + static struct clk ldb_clk = { .name = "ldb_clk", - .rate = 65000000, - .usecount = 0, + .rate = CONFIG_SYS_LDB_CLOCK, + .enable = clk_ldb_enable, + .disable = clk_ldb_disable, }; /* Globals */ -struct clk *g_ipu_clk; -struct clk *g_ldb_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 */ @@ -272,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; } @@ -332,47 +257,84 @@ 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_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, }, }; @@ -408,48 +370,66 @@ static 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; -#if defined CONFIG_MX51 + 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); #endif - - 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); + 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)); - g_ldb_clk = &ldb_clk; debug("ldb_clk = %u\n", clk_get_rate(g_ldb_clk)); - 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); + ret = clk_enable(g_ipu_clk); + if (ret) + return ret; + ipu_reset(); - 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(); @@ -474,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)); } @@ -578,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 */ @@ -591,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); @@ -628,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; } @@ -675,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) @@ -763,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(¶ms, 0, sizeof(params)); - ipu_ch_param_set_field(¶ms, 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(¶ms, 0, 138, 12, (height / 2) - 1); - ipu_ch_param_set_field(¶ms, 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(¶ms, 0, 138, 12, height - 1); - ipu_ch_param_set_field(¶ms, 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(¶ms, 1, 0, 29, addr0 >> 3); - ipu_ch_param_set_field(¶ms, 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(¶ms, 0, 107, 3, 5); /* bits/pixel */ - ipu_ch_param_set_field(¶ms, 1, 85, 4, 6); /* pix format */ - ipu_ch_param_set_field(¶ms, 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(¶ms, 0, 107, 3, 3); /* bits/pixel */ - ipu_ch_param_set_field(¶ms, 1, 85, 4, 7); /* pix format */ - ipu_ch_param_set_field(¶ms, 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(¶ms, 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(¶ms, 0, 107, 3, 1); /* bits/pixel */ - ipu_ch_param_set_field(¶ms, 1, 85, 4, 7); /* pix format */ - ipu_ch_param_set_field(¶ms, 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(¶ms, 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(¶ms, 0, 107, 3, 1); /* bits/pixel */ - ipu_ch_param_set_field(¶ms, 1, 85, 4, 7); /* pix format */ - ipu_ch_param_set_field(¶ms, 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(¶ms, 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(¶ms, 0, 107, 3, 0); /* bits/pixel */ - ipu_ch_param_set_field(¶ms, 1, 85, 4, 7); /* pix format */ - ipu_ch_param_set_field(¶ms, 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(¶ms, 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(¶ms, 0, 107, 3, 0); /* bits/pixel */ - ipu_ch_param_set_field(¶ms, 1, 85, 4, 7); /* pix format */ - ipu_ch_param_set_field(¶ms, 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(¶ms, 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(¶ms, 0, 107, 3, 0); /* bits/pixel */ - ipu_ch_param_set_field(¶ms, 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(¶ms, 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(¶ms, 0, 107, 3, 3); /* bits/pixel */ - ipu_ch_param_set_field(¶ms, 1, 85, 4, 0xA); /* pix format */ - ipu_ch_param_set_field(¶ms, 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(¶ms, 0, 107, 3, 3); /* bits/pixel */ - ipu_ch_param_set_field(¶ms, 1, 85, 4, 0x8); /* pix format */ - ipu_ch_param_set_field(¶ms, 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(¶ms, 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; @@ -856,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(¶ms, 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(¶ms, 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(¶ms, 1, 85, 4, 1); /* pix format */ - ipu_ch_param_set_field(¶ms, 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; @@ -875,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(¶ms, 1, 85, 4, 1); /* pix format */ - ipu_ch_param_set_field(¶ms, 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; @@ -886,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(¶ms, 1, 85, 4, 4); /* pix format */ - ipu_ch_param_set_field(¶ms, 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(¶ms, 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) { @@ -912,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(¶ms, 0, 46, 22, u_offset / 8); - ipu_ch_param_set_field(¶ms, 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), ¶ms, sizeof(params)); }; /* @@ -968,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 */ @@ -1031,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); @@ -1141,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; } @@ -1186,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; +}