diff options
Diffstat (limited to 'drivers/mxc/ipu3')
-rw-r--r-- | drivers/mxc/ipu3/ipu_calc_stripes_sizes.c | 2 | ||||
-rw-r--r-- | drivers/mxc/ipu3/ipu_capture.c | 130 | ||||
-rw-r--r-- | drivers/mxc/ipu3/ipu_common.c | 184 | ||||
-rw-r--r-- | drivers/mxc/ipu3/ipu_device.c | 25 | ||||
-rw-r--r-- | drivers/mxc/ipu3/ipu_disp.c | 364 | ||||
-rw-r--r-- | drivers/mxc/ipu3/ipu_ic.c | 39 | ||||
-rw-r--r-- | drivers/mxc/ipu3/ipu_param_mem.h | 55 | ||||
-rw-r--r-- | drivers/mxc/ipu3/ipu_prv.h | 4 | ||||
-rw-r--r-- | drivers/mxc/ipu3/ipu_regs.h | 11 |
9 files changed, 597 insertions, 217 deletions
diff --git a/drivers/mxc/ipu3/ipu_calc_stripes_sizes.c b/drivers/mxc/ipu3/ipu_calc_stripes_sizes.c index 6a29c90fe095..5d5e0b9155a0 100644 --- a/drivers/mxc/ipu3/ipu_calc_stripes_sizes.c +++ b/drivers/mxc/ipu3/ipu_calc_stripes_sizes.c @@ -260,7 +260,7 @@ int ipu_calc_stripes_sizes(const unsigned int input_frame_width, input_frame_width >> 1; left->output_width = right->output_width = right->output_column = output_frame_width >> 1; - left->input_column = right->input_column = 0; + left->input_column = 0; div = _do_div(((((u64)irr_steps) << 32) * (right->input_width - 1)), (right->output_width - 1)); left->irr = right->irr = truncate(0, div, 1); diff --git a/drivers/mxc/ipu3/ipu_capture.c b/drivers/mxc/ipu3/ipu_capture.c index 5d084ab37b0b..b9967135eac1 100644 --- a/drivers/mxc/ipu3/ipu_capture.c +++ b/drivers/mxc/ipu3/ipu_capture.c @@ -26,6 +26,7 @@ #include <linux/delay.h> #include <linux/ipu.h> #include <linux/clk.h> +#include <mach/mxc_dvfs.h> #include "ipu_prv.h" #include "ipu_regs.h" @@ -93,6 +94,12 @@ ipu_csi_init_interface(uint16_t width, uint16_t height, uint32_t pixel_fmt, cfg_param.force_eof << CSI_SENS_CONF_FORCE_EOF_SHIFT | cfg_param.data_en_pol << CSI_SENS_CONF_DATA_EN_POL_SHIFT; + if (g_ipu_clk_enabled == false) { + stop_dvfs_per(); + g_ipu_clk_enabled = true; + clk_enable(g_ipu_clk); + } + spin_lock_irqsave(&ipu_lock, lock_flags); __raw_writel(data, CSI_SENS_CONF(csi)); @@ -101,11 +108,18 @@ ipu_csi_init_interface(uint16_t width, uint16_t height, uint32_t pixel_fmt, __raw_writel((width - 1) | (height - 1) << 16, CSI_SENS_FRM_SIZE(csi)); /* Set CCIR registers */ - if ((cfg_param.clk_mode == IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE) || - (cfg_param.clk_mode == IPU_CSI_CLK_MODE_CCIR656_INTERLACED)) { - _ipu_csi_ccir_err_detection_enable(csi); + if (cfg_param.clk_mode == IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE) { __raw_writel(0x40030, CSI_CCIR_CODE_1(csi)); __raw_writel(0xFF0000, CSI_CCIR_CODE_3(csi)); + } else if (cfg_param.clk_mode == IPU_CSI_CLK_MODE_CCIR656_INTERLACED) { + _ipu_csi_ccir_err_detection_enable(csi); + /* Field0BlankEnd = 0x7, Field0BlankStart = 0x3, + Field0ActiveEnd = 0x5, Field0ActiveStart = 0x1 */ + __raw_writel(0xD07DF, CSI_CCIR_CODE_1(csi)); + /* Field1BlankEnd = 0x6, Field1BlankStart = 0x2, + Field1ActiveEnd = 0x4, Field1ActiveStart = 0 */ + __raw_writel(0x40596, CSI_CCIR_CODE_2(csi)); + __raw_writel(0xFF0000, CSI_CCIR_CODE_3(csi)); } else if ((cfg_param.clk_mode == IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_DDR) || (cfg_param.clk_mode == @@ -171,34 +185,13 @@ int _ipu_csi_mclk_set(uint32_t pixel_clk, uint32_t csi) */ int ipu_csi_enable_mclk(int csi, bool flag, bool wait) { - struct clk *clk; if (flag) { - if (cpu_is_mx53()) { - if (csi == 0) { - clk = clk_get(NULL, "ssi_ext1_clk"); - clk_enable(clk); - clk_put(clk); - } else { - pr_err("invalid csi num %d\n", csi); - return -EINVAL; - } - } else - clk_enable(g_csi_clk[csi]); + clk_enable(g_csi_clk[csi]); if (wait == true) msleep(10); } else { - if (cpu_is_mx53()) { - if (csi == 0) { - clk = clk_get(NULL, "ssi_ext1_clk"); - clk_disable(clk); - clk_put(clk); - } else { - pr_err("invalid csi num %d\n", csi); - return -EINVAL; - } - } else - clk_disable(g_csi_clk[csi]); + clk_disable(g_csi_clk[csi]); } return 0; @@ -217,6 +210,12 @@ void ipu_csi_get_window_size(uint32_t *width, uint32_t *height, uint32_t csi) uint32_t reg; unsigned long lock_flags; + if (g_ipu_clk_enabled == false) { + stop_dvfs_per(); + g_ipu_clk_enabled = true; + clk_enable(g_ipu_clk); + } + spin_lock_irqsave(&ipu_lock, lock_flags); reg = __raw_readl(CSI_ACT_FRM_SIZE(csi)); @@ -238,6 +237,12 @@ void ipu_csi_set_window_size(uint32_t width, uint32_t height, uint32_t csi) { unsigned long lock_flags; + if (g_ipu_clk_enabled == false) { + stop_dvfs_per(); + g_ipu_clk_enabled = true; + clk_enable(g_ipu_clk); + } + spin_lock_irqsave(&ipu_lock, lock_flags); __raw_writel((width - 1) | (height - 1) << 16, CSI_ACT_FRM_SIZE(csi)); @@ -258,6 +263,12 @@ void ipu_csi_set_window_pos(uint32_t left, uint32_t top, uint32_t csi) uint32_t temp; unsigned long lock_flags; + if (g_ipu_clk_enabled == false) { + stop_dvfs_per(); + g_ipu_clk_enabled = true; + clk_enable(g_ipu_clk); + } + spin_lock_irqsave(&ipu_lock, lock_flags); temp = __raw_readl(CSI_OUT_FRM_CTRL(csi)); @@ -280,6 +291,12 @@ void _ipu_csi_horizontal_downsize_enable(uint32_t csi) uint32_t temp; unsigned long lock_flags; + if (g_ipu_clk_enabled == false) { + stop_dvfs_per(); + g_ipu_clk_enabled = true; + clk_enable(g_ipu_clk); + } + spin_lock_irqsave(&ipu_lock, lock_flags); temp = __raw_readl(CSI_OUT_FRM_CTRL(csi)); @@ -300,6 +317,12 @@ void _ipu_csi_horizontal_downsize_disable(uint32_t csi) uint32_t temp; unsigned long lock_flags; + if (g_ipu_clk_enabled == false) { + stop_dvfs_per(); + g_ipu_clk_enabled = true; + clk_enable(g_ipu_clk); + } + spin_lock_irqsave(&ipu_lock, lock_flags); temp = __raw_readl(CSI_OUT_FRM_CTRL(csi)); @@ -320,6 +343,12 @@ void _ipu_csi_vertical_downsize_enable(uint32_t csi) uint32_t temp; unsigned long lock_flags; + if (g_ipu_clk_enabled == false) { + stop_dvfs_per(); + g_ipu_clk_enabled = true; + clk_enable(g_ipu_clk); + } + spin_lock_irqsave(&ipu_lock, lock_flags); temp = __raw_readl(CSI_OUT_FRM_CTRL(csi)); @@ -340,6 +369,12 @@ void _ipu_csi_vertical_downsize_disable(uint32_t csi) uint32_t temp; unsigned long lock_flags; + if (g_ipu_clk_enabled == false) { + stop_dvfs_per(); + g_ipu_clk_enabled = true; + clk_enable(g_ipu_clk); + } + spin_lock_irqsave(&ipu_lock, lock_flags); temp = __raw_readl(CSI_OUT_FRM_CTRL(csi)); @@ -366,6 +401,12 @@ void ipu_csi_set_test_generator(bool active, uint32_t r_value, uint32_t temp; unsigned long lock_flags; + if (g_ipu_clk_enabled == false) { + stop_dvfs_per(); + g_ipu_clk_enabled = true; + clk_enable(g_ipu_clk); + } + spin_lock_irqsave(&ipu_lock, lock_flags); temp = __raw_readl(CSI_TST_CTRL(csi)); @@ -401,6 +442,12 @@ void _ipu_csi_ccir_err_detection_enable(uint32_t csi) { uint32_t temp; + if (g_ipu_clk_enabled == false) { + stop_dvfs_per(); + g_ipu_clk_enabled = true; + clk_enable(g_ipu_clk); + } + temp = __raw_readl(CSI_CCIR_CODE_1(csi)); temp |= CSI_CCIR_ERR_DET_EN; __raw_writel(temp, CSI_CCIR_CODE_1(csi)); @@ -417,6 +464,12 @@ void _ipu_csi_ccir_err_detection_disable(uint32_t csi) { uint32_t temp; + if (g_ipu_clk_enabled == false) { + stop_dvfs_per(); + g_ipu_clk_enabled = true; + clk_enable(g_ipu_clk); + } + temp = __raw_readl(CSI_CCIR_CODE_1(csi)); temp &= ~CSI_CCIR_ERR_DET_EN; __raw_writel(temp, CSI_CCIR_CODE_1(csi)); @@ -442,6 +495,12 @@ int _ipu_csi_set_mipi_di(uint32_t num, uint32_t di_val, uint32_t csi) goto err; } + if (g_ipu_clk_enabled == false) { + stop_dvfs_per(); + g_ipu_clk_enabled = true; + clk_enable(g_ipu_clk); + } + spin_lock_irqsave(&ipu_lock, lock_flags); temp = __raw_readl(CSI_MIPI_DI(csi)); @@ -499,6 +558,12 @@ int _ipu_csi_set_skip_isp(uint32_t skip, uint32_t max_ratio, uint32_t csi) goto err; } + if (g_ipu_clk_enabled == false) { + stop_dvfs_per(); + g_ipu_clk_enabled = true; + clk_enable(g_ipu_clk); + } + spin_lock_irqsave(&ipu_lock, lock_flags); temp = __raw_readl(CSI_SKIP(csi)); @@ -536,6 +601,12 @@ int _ipu_csi_set_skip_smfc(uint32_t skip, uint32_t max_ratio, goto err; } + if (g_ipu_clk_enabled == false) { + stop_dvfs_per(); + g_ipu_clk_enabled = true; + clk_enable(g_ipu_clk); + } + spin_lock_irqsave(&ipu_lock, lock_flags); temp = __raw_readl(CSI_SKIP(csi)); @@ -585,7 +656,6 @@ void _ipu_smfc_init(ipu_channel_t channel, uint32_t mipi_id, uint32_t csi) default: return; } - __raw_writel(temp, SMFC_MAP); } @@ -604,6 +674,12 @@ void _ipu_smfc_set_wmc(ipu_channel_t channel, bool set, uint32_t level) uint32_t temp; unsigned long lock_flags; + if (g_ipu_clk_enabled == false) { + stop_dvfs_per(); + g_ipu_clk_enabled = true; + clk_enable(g_ipu_clk); + } + spin_lock_irqsave(&ipu_lock, lock_flags); temp = __raw_readl(SMFC_WMC); diff --git a/drivers/mxc/ipu3/ipu_common.c b/drivers/mxc/ipu3/ipu_common.c index 68be542e8370..b1b8a8b39ae1 100644 --- a/drivers/mxc/ipu3/ipu_common.c +++ b/drivers/mxc/ipu3/ipu_common.c @@ -52,8 +52,8 @@ unsigned char g_dc_di_assignment[10]; ipu_channel_t g_ipu_csi_channel[2]; int g_ipu_irq[2]; int g_ipu_hw_rev; -bool g_sec_chan_en[22]; -bool g_thrd_chan_en[21]; +bool g_sec_chan_en[24]; +bool g_thrd_chan_en[24]; uint32_t g_channel_init_mask; uint32_t g_channel_enable_mask; DEFINE_SPINLOCK(ipu_lock); @@ -354,8 +354,8 @@ static int ipu_probe(struct platform_device *pdev) g_di_clk[0] = plat_data->di_clk[0]; g_di_clk[1] = plat_data->di_clk[1]; - g_csi_clk[0] = clk_get(&pdev->dev, "csi_mclk1"); - g_csi_clk[1] = clk_get(&pdev->dev, "csi_mclk2"); + g_csi_clk[0] = plat_data->csi_clk[0]; + g_csi_clk[1] = plat_data->csi_clk[1]; __raw_writel(0x807FFFFF, IPU_MEM_RST); while (__raw_readl(IPU_MEM_RST) & 0x80000000) ; @@ -372,7 +372,7 @@ static int ipu_probe(struct platform_device *pdev) _ipu_dmfc_init(DMFC_NORMAL, 1); /* Set sync refresh channels and CSI->mem channel as high priority */ - __raw_writel(0x18800001L, IDMAC_CHA_PRI(0)); + __raw_writel(0x18800003L, IDMAC_CHA_PRI(0)); /* Set MCU_T to divide MCU access window into 2 */ __raw_writel(0x00400000L | (IPU_MCU_T_DEFAULT << 18), IPU_DISP_GEN); @@ -415,7 +415,10 @@ int ipu_remove(struct platform_device *pdev) void ipu_dump_registers(void) { + printk(KERN_DEBUG "--------------------------------------------\n"); printk(KERN_DEBUG "IPU_CONF = \t0x%08X\n", __raw_readl(IPU_CONF)); + printk(KERN_DEBUG "SMFC_MAP = \t0x%08X\n", __raw_readl(SMFC_MAP)); + printk(KERN_DEBUG "SMFC_WMC = \t0x%08X\n", __raw_readl(SMFC_WMC)); printk(KERN_DEBUG "IDMAC_CONF = \t0x%08X\n", __raw_readl(IDMAC_CONF)); printk(KERN_DEBUG "IDMAC_CHA_EN1 = \t0x%08X\n", __raw_readl(IDMAC_CHA_EN(0))); @@ -451,6 +454,25 @@ void ipu_dump_registers(void) __raw_readl(IPU_FS_PROC_FLOW3)); printk(KERN_DEBUG "IPU_FS_DISP_FLOW1 = \t0x%08X\n", __raw_readl(IPU_FS_DISP_FLOW1)); + + printk(KERN_DEBUG "IPU_INT_CTRL_1 = \t0x%08X\n", __raw_readl(IPU_INT_CTRL (1))); + printk(KERN_DEBUG "IPU_INT_STAT_1 = \t0x%08X\n", __raw_readl(IPU_INT_STAT (1))); + printk(KERN_DEBUG "IPU_INT_STAT_2 = \t0x%08X\n", __raw_readl(IPU_INT_STAT (2))); + printk(KERN_DEBUG "IPU_INT_STAT_3 = \t0x%08X\n", __raw_readl(IPU_INT_STAT (3))); + printk(KERN_DEBUG "IPU_INT_STAT_4 = \t0x%08X\n", __raw_readl(IPU_INT_STAT (4))); + printk(KERN_DEBUG "IPU_INT_STAT_5 = \t0x%08X\n", __raw_readl(IPU_INT_STAT (5))); + printk(KERN_DEBUG "IPU_INT_STAT_6 = \t0x%08X\n", __raw_readl(IPU_INT_STAT (6))); + + printk(KERN_DEBUG "CSI0_SENS_CONF = \t0x%08X\n", __raw_readl(CSI_SENS_CONF (0))); + printk(KERN_DEBUG "CSI0_SENS_FRM_SIZE = \t0x%08X\n", __raw_readl(CSI_SENS_FRM_SIZE(0))); + printk(KERN_DEBUG "CSI0_ACT_FRM_SIZE = \t0x%08X\n", __raw_readl(CSI_ACT_FRM_SIZE(0))); + printk(KERN_DEBUG "CSI0_SKIP = \t0x%08X\n", __raw_readl(CSI_SKIP(0))); + + printk(KERN_DEBUG "CSI1_SENS_CONF = \t0x%08X\n", __raw_readl(CSI_SENS_CONF (1))); + printk(KERN_DEBUG "CSI1_SENS_FRM_SIZE = \t0x%08X\n", __raw_readl(CSI_SENS_FRM_SIZE(1))); + printk(KERN_DEBUG "CSI1_ACT_FRM_SIZE = \t0x%08X\n", __raw_readl(CSI_ACT_FRM_SIZE(1))); + printk(KERN_DEBUG "CSI1_SKIP = \t0x%08X\n", __raw_readl(CSI_SKIP(1))); + printk(KERN_DEBUG "--------------------------------------------\n"); } /*! @@ -660,7 +682,8 @@ int32_t ipu_init_channel(ipu_channel_t channel, ipu_channel_params_t *params) g_dc_di_assignment[1] = params->mem_dc_sync.di; _ipu_dc_init(1, params->mem_dc_sync.di, - params->mem_dc_sync.interlaced); + params->mem_dc_sync.interlaced, + params->mem_dc_sync.out_pixel_fmt); ipu_di_use_count[params->mem_dc_sync.di]++; ipu_dc_use_count++; ipu_dmfc_use_count++; @@ -678,7 +701,8 @@ int32_t ipu_init_channel(ipu_channel_t channel, ipu_channel_params_t *params) _ipu_dp_init(channel, params->mem_dp_bg_sync.in_pixel_fmt, params->mem_dp_bg_sync.out_pixel_fmt); _ipu_dc_init(5, params->mem_dp_bg_sync.di, - params->mem_dp_bg_sync.interlaced); + params->mem_dp_bg_sync.interlaced, + params->mem_dp_bg_sync.out_pixel_fmt); ipu_di_use_count[params->mem_dp_bg_sync.di]++; ipu_dc_use_count++; ipu_dp_use_count++; @@ -702,7 +726,7 @@ int32_t ipu_init_channel(ipu_channel_t channel, ipu_channel_params_t *params) } g_dc_di_assignment[8] = params->direct_async.di; - _ipu_dc_init(8, params->direct_async.di, false); + _ipu_dc_init(8, params->direct_async.di, false, IPU_PIX_FMT_GENERIC); ipu_di_use_count[params->direct_async.di]++; ipu_dc_use_count++; break; @@ -713,7 +737,7 @@ int32_t ipu_init_channel(ipu_channel_t channel, ipu_channel_params_t *params) } g_dc_di_assignment[9] = params->direct_async.di; - _ipu_dc_init(9, params->direct_async.di, false); + _ipu_dc_init(9, params->direct_async.di, false, IPU_PIX_FMT_GENERIC); ipu_di_use_count[params->direct_async.di]++; ipu_dc_use_count++; break; @@ -724,31 +748,8 @@ int32_t ipu_init_channel(ipu_channel_t channel, ipu_channel_params_t *params) /* Enable IPU sub module */ g_channel_init_mask |= 1L << IPU_CHAN_ID(channel); - if (ipu_ic_use_count == 1) - ipu_conf |= IPU_CONF_IC_EN; - if (ipu_vdi_use_count == 1) { - ipu_conf |= IPU_CONF_VDI_EN; - ipu_conf |= IPU_CONF_IC_INPUT; - } - if (ipu_rot_use_count == 1) - ipu_conf |= IPU_CONF_ROT_EN; - if (ipu_dc_use_count == 1) - ipu_conf |= IPU_CONF_DC_EN; - if (ipu_dp_use_count == 1) - ipu_conf |= IPU_CONF_DP_EN; - if (ipu_dmfc_use_count == 1) - ipu_conf |= IPU_CONF_DMFC_EN; - if (ipu_di_use_count[0] == 1) { - ipu_conf |= IPU_CONF_DI0_EN; - } - if (ipu_di_use_count[1] == 1) { - ipu_conf |= IPU_CONF_DI1_EN; - } - if (ipu_smfc_use_count == 1) - ipu_conf |= IPU_CONF_SMFC_EN; __raw_writel(ipu_conf, IPU_CONF); - err: spin_unlock_irqrestore(&ipu_lock, lock_flags); return ret; @@ -775,8 +776,8 @@ void ipu_uninit_channel(ipu_channel_t channel) /* Make sure channel is disabled */ /* Get input and output dma channels */ - in_dma = channel_2_dma(channel, IPU_OUTPUT_BUFFER); - out_dma = channel_2_dma(channel, IPU_VIDEO_IN_BUFFER); + in_dma = channel_2_dma(channel, IPU_VIDEO_IN_BUFFER); + out_dma = channel_2_dma(channel, IPU_OUTPUT_BUFFER); if (idma_is_set(IDMAC_CHA_EN, in_dma) || idma_is_set(IDMAC_CHA_EN, out_dma)) { @@ -796,8 +797,10 @@ void ipu_uninit_channel(ipu_channel_t channel) reg = __raw_readl(IPU_CHA_DB_MODE_SEL(out_dma)); __raw_writel(reg & ~idma_mask(out_dma), IPU_CHA_DB_MODE_SEL(out_dma)); - g_sec_chan_en[IPU_CHAN_ID(channel)] = false; - g_thrd_chan_en[IPU_CHAN_ID(channel)] = false; + if (_ipu_is_ic_chan(in_dma) || _ipu_is_dp_graphic_chan(in_dma)) { + g_sec_chan_en[IPU_CHAN_ID(channel)] = false; + g_thrd_chan_en[IPU_CHAN_ID(channel)] = false; + } switch (channel) { case CSI_MEM0: @@ -849,6 +852,9 @@ void ipu_uninit_channel(ipu_channel_t channel) reg = __raw_readl(IPU_FS_PROC_FLOW1); __raw_writel(reg & ~FS_VF_IN_VALID, IPU_FS_PROC_FLOW1); break; + case MEM_VDI_PRP_VF_MEM_P: + case MEM_VDI_PRP_VF_MEM_N: + break; case MEM_ROT_VF_MEM: ipu_rot_use_count--; ipu_ic_use_count--; @@ -913,6 +919,7 @@ void ipu_uninit_channel(ipu_channel_t channel) if (ipu_ic_use_count == 0) ipu_conf &= ~IPU_CONF_IC_EN; if (ipu_vdi_use_count == 0) { + ipu_conf &= ~IPU_CONF_ISP_EN; ipu_conf &= ~IPU_CONF_VDI_EN; ipu_conf &= ~IPU_CONF_IC_INPUT; } @@ -1239,8 +1246,6 @@ int32_t ipu_select_buffer(ipu_channel_t channel, ipu_buffer_t type, __raw_writel(idma_mask(dma_chan) | reg, IPU_CHA_BUF1_RDY(dma_chan)); } - if (channel == MEM_VDI_PRP_VF_MEM) - _ipu_vdi_toggle_top_field_man(); return 0; } EXPORT_SYMBOL(ipu_select_buffer); @@ -1269,10 +1274,9 @@ int32_t ipu_select_multi_vdi_buffer(uint32_t bufNum) __raw_writel(mask_bit | reg, IPU_CHA_BUF0_RDY(dma_chan)); } else { /*Mark buffer 1 as ready. */ - reg = __raw_readl(IPU_CHA_BUF0_RDY(dma_chan)); + reg = __raw_readl(IPU_CHA_BUF1_RDY(dma_chan)); __raw_writel(mask_bit | reg, IPU_CHA_BUF1_RDY(dma_chan)); } - _ipu_vdi_toggle_top_field_man(); return 0; } EXPORT_SYMBOL(ipu_select_multi_vdi_buffer); @@ -1282,7 +1286,7 @@ static int proc_dest_sel[] = { 0, 1, 1, 3, 5, 5, 4, 7, 8, 9, 10, 11, 12, 14, 15, 16, 0, 1, 1, 5, 5, 5, 5, 5, 7, 8, 9, 10, 11, 12, 14, 31 }; static int proc_src_sel[] = { 0, 6, 7, 6, 7, 8, 5, NA, NA, NA, - NA, NA, NA, NA, NA, 1, 2, 3, 4, 7, 8, NA, NA, NA }; + NA, NA, NA, NA, NA, 1, 2, 3, 4, 7, 8, NA, 8, NA }; static int disp_src_sel[] = { 0, 6, 7, 8, 3, 4, 5, NA, NA, NA, NA, NA, NA, NA, NA, 1, NA, 2, NA, 3, 4, 4, 4, 4 }; @@ -1659,6 +1663,7 @@ int32_t ipu_enable_channel(ipu_channel_t channel) { uint32_t reg; unsigned long lock_flags; + uint32_t ipu_conf; uint32_t in_dma; uint32_t out_dma; uint32_t sec_dma; @@ -1675,6 +1680,32 @@ int32_t ipu_enable_channel(ipu_channel_t channel) spin_lock_irqsave(&ipu_lock, lock_flags); + ipu_conf = __raw_readl(IPU_CONF); + if (ipu_di_use_count[0] > 0) { + ipu_conf |= IPU_CONF_DI0_EN; + } + if (ipu_di_use_count[1] > 0) { + ipu_conf |= IPU_CONF_DI1_EN; + } + if (ipu_dp_use_count > 0) + ipu_conf |= IPU_CONF_DP_EN; + if (ipu_dc_use_count > 0) + ipu_conf |= IPU_CONF_DC_EN; + if (ipu_dmfc_use_count > 0) + ipu_conf |= IPU_CONF_DMFC_EN; + if (ipu_ic_use_count > 0) + ipu_conf |= IPU_CONF_IC_EN; + if (ipu_vdi_use_count > 0) { + ipu_conf |= IPU_CONF_ISP_EN; + ipu_conf |= IPU_CONF_VDI_EN; + ipu_conf |= IPU_CONF_IC_INPUT; + } + if (ipu_rot_use_count > 0) + ipu_conf |= IPU_CONF_ROT_EN; + if (ipu_smfc_use_count > 0) + ipu_conf |= IPU_CONF_SMFC_EN; + __raw_writel(ipu_conf, IPU_CONF); + if (idma_is_valid(in_dma)) { reg = __raw_readl(IDMAC_CHA_EN(in_dma)); __raw_writel(reg | idma_mask(in_dma), IDMAC_CHA_EN(in_dma)); @@ -1710,8 +1741,11 @@ 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); + } if (_ipu_is_ic_chan(in_dma) || _ipu_is_ic_chan(out_dma) || _ipu_is_irt_chan(in_dma) || _ipu_is_irt_chan(out_dma)) @@ -1726,6 +1760,38 @@ int32_t ipu_enable_channel(ipu_channel_t channel) EXPORT_SYMBOL(ipu_enable_channel); /*! + * This function check buffer ready for a logical channel. + * + * @param channel Input parameter for the logical channel ID. + * + * @param type Input parameter which buffer to clear. + * + * @param bufNum Input parameter for which buffer number clear + * ready state. + * + */ +int32_t ipu_check_buffer_busy(ipu_channel_t channel, ipu_buffer_t type, + uint32_t bufNum) +{ + uint32_t dma_chan = channel_2_dma(channel, type); + uint32_t reg; + + if (dma_chan == IDMA_CHAN_INVALID) + return -EINVAL; + + if (bufNum == 0) + reg = __raw_readl(IPU_CHA_BUF0_RDY(dma_chan)); + else + reg = __raw_readl(IPU_CHA_BUF1_RDY(dma_chan)); + + if (reg & idma_mask(dma_chan)) + return 1; + else + return 0; +} +EXPORT_SYMBOL(ipu_check_buffer_busy); + +/*! * This function clear buffer ready for a logical channel. * * @param channel Input parameter for the logical channel ID. @@ -1817,7 +1883,30 @@ int32_t ipu_disable_channel(ipu_channel_t channel, bool wait_for_stop) if ((channel == MEM_BG_SYNC) || (channel == MEM_FG_SYNC) || (channel == MEM_DC_SYNC)) { + if (channel == MEM_FG_SYNC) + ipu_disp_set_window_pos(channel, 0, 0); + _ipu_dp_dc_disable(channel, false); + + /* + * wait for BG channel EOF then disable FG-IDMAC, + * it avoid FG NFB4EOF error. + */ + if (channel == MEM_FG_SYNC) { + int timeout = 50; + + __raw_writel(IPUIRQ_2_MASK(IPU_IRQ_BG_SYNC_EOF), + IPUIRQ_2_STATREG(IPU_IRQ_BG_SYNC_EOF)); + while ((__raw_readl(IPUIRQ_2_STATREG(IPU_IRQ_BG_SYNC_EOF)) & + IPUIRQ_2_MASK(IPU_IRQ_BG_SYNC_EOF)) == 0) { + msleep(10); + timeout -= 10; + if (timeout <= 0) { + dev_err(g_ipu_dev, "warning: wait for bg sync eof timeout\n"); + break; + } + } + } } else if (wait_for_stop) { while (idma_is_set(IDMAC_CHA_BUSY, in_dma) || idma_is_set(IDMAC_CHA_BUSY, out_dma) || @@ -1861,6 +1950,12 @@ int32_t ipu_disable_channel(ipu_channel_t channel, bool wait_for_stop) spin_lock_irqsave(&ipu_lock, lock_flags); + if ((channel == MEM_BG_SYNC) || (channel == MEM_FG_SYNC) || + (channel == MEM_DC_SYNC)) { + reg = __raw_readl(IDMAC_WM_EN(in_dma)); + __raw_writel(reg & ~idma_mask(in_dma), IDMAC_WM_EN(in_dma)); + } + /* Disable IC task */ if (_ipu_is_ic_chan(in_dma) || _ipu_is_ic_chan(out_dma) || _ipu_is_irt_chan(in_dma) || _ipu_is_irt_chan(out_dma)) @@ -1897,8 +1992,6 @@ int32_t ipu_disable_channel(ipu_channel_t channel, bool wait_for_stop) g_channel_enable_mask &= ~(1L << IPU_CHAN_ID(channel)); - spin_unlock_irqrestore(&ipu_lock, lock_flags); - /* Set channel buffers NOT to be ready */ if (idma_is_valid(in_dma)) { ipu_clear_buffer_ready(channel, IPU_VIDEO_IN_BUFFER, 0); @@ -1917,6 +2010,8 @@ int32_t ipu_disable_channel(ipu_channel_t channel, bool wait_for_stop) ipu_clear_buffer_ready(channel, IPU_ALPHA_IN_BUFFER, 1); } + spin_unlock_irqrestore(&ipu_lock, lock_flags); + return 0; } EXPORT_SYMBOL(ipu_disable_channel); @@ -2029,7 +2124,6 @@ static irqreturn_t ipu_irq_handler(int irq, void *desc) dev_id); } } - return result; } diff --git a/drivers/mxc/ipu3/ipu_device.c b/drivers/mxc/ipu3/ipu_device.c index 27455fe26ab6..bf71ea833f58 100644 --- a/drivers/mxc/ipu3/ipu_device.c +++ b/drivers/mxc/ipu3/ipu_device.c @@ -124,7 +124,6 @@ static int mxc_ipu_ioctl(struct inode *inode, struct file *file, (&parm, (ipu_channel_buf_parm *) arg, sizeof(ipu_channel_buf_parm))) return -EFAULT; - ret = ipu_init_channel_buffer( parm.channel, parm.type, @@ -183,6 +182,17 @@ static int mxc_ipu_ioctl(struct inode *inode, struct file *file, } break; + case IPU_SELECT_MULTI_VDI_BUFFER: + { + uint32_t parm; + if (copy_from_user + (&parm, (uint32_t *) arg, + sizeof(uint32_t))) + return -EFAULT; + + ret = ipu_select_multi_vdi_buffer(parm); + } + break; case IPU_LINK_CHANNELS: { ipu_channel_link link; @@ -225,7 +235,6 @@ static int mxc_ipu_ioctl(struct inode *inode, struct file *file, (&info, (ipu_channel_info *) arg, sizeof(ipu_channel_info))) return -EFAULT; - ret = ipu_disable_channel(info.channel, info.stop); } @@ -435,7 +444,7 @@ static int mxc_ipu_ioctl(struct inode *inode, struct file *file, static int mxc_ipu_mmap(struct file *file, struct vm_area_struct *vma) { -// vma->vm_page_prot = pgprot_writethru(vma->vm_page_prot); + vma->vm_page_prot = pgprot_writethru(vma->vm_page_prot); if (remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff, vma->vm_end - vma->vm_start, @@ -452,12 +461,20 @@ static int mxc_ipu_release(struct inode *inode, struct file *file) return 0; } +int mxc_ipu_fsync(struct file *filp, struct dentry *dentry, int datasync) +{ + flush_cache_all(); + outer_flush_all(); + return 0; +} + static struct file_operations mxc_ipu_fops = { .owner = THIS_MODULE, .open = mxc_ipu_open, .mmap = mxc_ipu_mmap, .release = mxc_ipu_release, - .ioctl = mxc_ipu_ioctl + .ioctl = mxc_ipu_ioctl, + .fsync = mxc_ipu_fsync }; int register_ipu_device() diff --git a/drivers/mxc/ipu3/ipu_disp.c b/drivers/mxc/ipu3/ipu_disp.c index 00c5008d149f..14dde404990b 100644 --- a/drivers/mxc/ipu3/ipu_disp.c +++ b/drivers/mxc/ipu3/ipu_disp.c @@ -147,6 +147,37 @@ static int __init dmfc_setup(char *options) } __setup("dmfc=", dmfc_setup); +static bool _ipu_update_dmfc_used_size(int dma_chan, int width, int dmfc_size) +{ + u32 fifo_size_5f = 1; + u32 dmfc_dp_chan = __raw_readl(DMFC_DP_CHAN); + + if ((width > 352) && (dmfc_size == (256 * 4))) + fifo_size_5f = 1; + else if (width > 176) + fifo_size_5f = 2; + else if (width > 88) + fifo_size_5f = 3; + else if (width > 44) + fifo_size_5f = 4; + else if (width > 22) + fifo_size_5f = 5; + else if (width > 11) + fifo_size_5f = 6; + else if (width > 6) + fifo_size_5f = 7; + else + return false; + + if (dma_chan == 27) { + dmfc_dp_chan &= ~DMFC_FIFO_SIZE_5F; + dmfc_dp_chan |= fifo_size_5f << 11; + __raw_writel(dmfc_dp_chan, DMFC_DP_CHAN); + } + + return true; +} + void _ipu_dmfc_set_wait4eot(int dma_chan, int width) { u32 dmfc_gen1 = __raw_readl(DMFC_GENERAL1); @@ -169,7 +200,7 @@ void _ipu_dmfc_set_wait4eot(int dma_chan, int width) else dmfc_gen1 &= ~(1UL << 22); } else if (dma_chan == 27) { /*5F*/ - if (dmfc_size_27/width > 2) + if (!_ipu_update_dmfc_used_size(dma_chan, width, dmfc_size_27)) dmfc_gen1 |= 1UL << 21; else dmfc_gen1 &= ~(1UL << 21); @@ -245,6 +276,24 @@ static void _ipu_di_sync_config(int di, int wave_gen, __raw_writel(reg, DI_STP_REP(di, wave_gen)); } +static void _ipu_dc_map_link(int current_map, + int base_map_0, int buf_num_0, + int base_map_1, int buf_num_1, + int base_map_2, int buf_num_2) +{ + int ptr_0 = base_map_0 * 3 + buf_num_0; + int ptr_1 = base_map_1 * 3 + buf_num_1; + int ptr_2 = base_map_2 * 3 + buf_num_2; + int ptr; + u32 reg; + ptr = (ptr_2 << 10) + (ptr_1 << 5) + ptr_0; + + reg = __raw_readl(DC_MAP_CONF_PTR(current_map)); + reg &= ~(0x1F << ((16 * (current_map & 0x1)))); + reg |= ptr << ((16 * (current_map & 0x1))); + __raw_writel(reg, DC_MAP_CONF_PTR(current_map)); +} + static void _ipu_dc_map_config(int map, int byte_num, int offset, int mask) { int ptr = map * 3 + byte_num; @@ -269,32 +318,63 @@ static void _ipu_dc_map_clear(int map) } static void _ipu_dc_write_tmpl(int word, u32 opcode, u32 operand, int map, - int wave, int glue, int sync) + int wave, int glue, int sync, int stop) { u32 reg; - int stop = 1; - - reg = sync; - reg |= (glue << 4); - reg |= (++wave << 11); - reg |= (++map << 15); - reg |= (operand << 20) & 0xFFF00000; - __raw_writel(reg, ipu_dc_tmpl_reg + word * 2); - - reg = (operand >> 12); - reg |= opcode << 4; - reg |= (stop << 9); - __raw_writel(reg, ipu_dc_tmpl_reg + word * 2 + 1); + + if (opcode == WRG) { + reg = sync; + reg |= (glue << 4); + reg |= (++wave << 11); + reg |= ((operand & 0x1FFFF) << 15); + __raw_writel(reg, ipu_dc_tmpl_reg + word * 2); + + reg = (operand >> 17); + reg |= opcode << 7; + reg |= (stop << 9); + __raw_writel(reg, ipu_dc_tmpl_reg + word * 2 + 1); + } else { + reg = sync; + reg |= (glue << 4); + reg |= (++wave << 11); + reg |= (++map << 15); + reg |= (operand << 20) & 0xFFF00000; + __raw_writel(reg, ipu_dc_tmpl_reg + word * 2); + + reg = (operand >> 12); + reg |= opcode << 4; + reg |= (stop << 9); + __raw_writel(reg, ipu_dc_tmpl_reg + word * 2 + 1); + } } static void _ipu_dc_link_event(int chan, int event, int addr, int priority) { u32 reg; - - reg = __raw_readl(DC_RL_CH(chan, event)); - reg &= ~(0xFFFF << (16 * (event & 0x1))); - reg |= ((addr << 8) | priority) << (16 * (event & 0x1)); - __raw_writel(reg, DC_RL_CH(chan, event)); + u32 address_shift; + if (event < DC_EVEN_UGDE0) { + reg = __raw_readl(DC_RL_CH(chan, event)); + reg &= ~(0xFFFF << (16 * (event & 0x1))); + reg |= ((addr << 8) | priority) << (16 * (event & 0x1)); + __raw_writel(reg, DC_RL_CH(chan, event)); + } else { + reg = __raw_readl(DC_UGDE_0((event - DC_EVEN_UGDE0) / 2)); + if ((event - DC_EVEN_UGDE0) & 0x1) { + reg &= ~(0x2FF << 16); + reg |= (addr << 16); + reg |= priority ? (2 << 24) : 0x0; + } else { + reg &= ~0xFC00FFFF; + if (priority) + chan = (chan >> 1) + + ((((chan & 0x1) + ((chan & 0x2) >> 1))) | (chan >> 3)); + else + chan = 0x7; + address_shift = ((event - DC_EVEN_UGDE0) >> 1) ? 7 : 8; + reg |= (addr << address_shift) | (priority << 3) | chan; + } + __raw_writel(reg, DC_UGDE_0((event - DC_EVEN_UGDE0) / 2)); + } } /* Y = R * 1.200 + G * 2.343 + B * .453 + 0.250; @@ -503,7 +583,7 @@ void _ipu_dp_uninit(ipu_channel_t channel) __ipu_dp_csc_setup(dp, dp_csc_array[bg_csc_type][fg_csc_type], false); } -void _ipu_dc_init(int dc_chan, int di, bool interlaced) +void _ipu_dc_init(int dc_chan, int di, bool interlaced, uint32_t pixel_fmt) { u32 reg = 0; @@ -517,10 +597,24 @@ void _ipu_dc_init(int dc_chan, int di, bool interlaced) _ipu_dc_link_event(dc_chan, DC_EVT_NL, 2, 3); _ipu_dc_link_event(dc_chan, DC_EVT_EOL, 3, 2); _ipu_dc_link_event(dc_chan, DC_EVT_NEW_DATA, 4, 1); + if ((pixel_fmt == IPU_PIX_FMT_YUYV) || + (pixel_fmt == IPU_PIX_FMT_UYVY) || + (pixel_fmt == IPU_PIX_FMT_YVYU) || + (pixel_fmt == IPU_PIX_FMT_VYUY)) { + _ipu_dc_link_event(dc_chan, DC_ODD_UGDE1, 9, 5); + _ipu_dc_link_event(dc_chan, DC_EVEN_UGDE1, 8, 5); + } } else { _ipu_dc_link_event(dc_chan, DC_EVT_NL, 5, 3); _ipu_dc_link_event(dc_chan, DC_EVT_EOL, 6, 2); _ipu_dc_link_event(dc_chan, DC_EVT_NEW_DATA, 7, 1); + if ((pixel_fmt == IPU_PIX_FMT_YUYV) || + (pixel_fmt == IPU_PIX_FMT_UYVY) || + (pixel_fmt == IPU_PIX_FMT_YVYU) || + (pixel_fmt == IPU_PIX_FMT_VYUY)) { + _ipu_dc_link_event(dc_chan, DC_ODD_UGDE0, 10, 5); + _ipu_dc_link_event(dc_chan, DC_EVEN_UGDE0, 11, 5); + } } } _ipu_dc_link_event(dc_chan, DC_EVT_NF, 0, 0); @@ -562,6 +656,10 @@ void _ipu_dc_uninit(int dc_chan) _ipu_dc_link_event(dc_chan, DC_EVT_EOFIELD, 0, 0); _ipu_dc_link_event(dc_chan, DC_EVT_NEW_CHAN, 0, 0); _ipu_dc_link_event(dc_chan, DC_EVT_NEW_ADDR, 0, 0); + _ipu_dc_link_event(dc_chan, DC_ODD_UGDE0, 0, 0); + _ipu_dc_link_event(dc_chan, DC_EVEN_UGDE0, 0, 0); + _ipu_dc_link_event(dc_chan, DC_ODD_UGDE1, 0, 0); + _ipu_dc_link_event(dc_chan, DC_EVEN_UGDE1, 0, 0); } else if ((dc_chan == 8) || (dc_chan == 9)) { _ipu_dc_link_event(dc_chan, DC_EVT_NEW_ADDR_W_0, 0, 0); _ipu_dc_link_event(dc_chan, DC_EVT_NEW_ADDR_W_1, 0, 0); @@ -637,6 +735,26 @@ static bool dc_swap; static irqreturn_t dc_irq_handler(int irq, void *dev_id) { struct completion *comp = dev_id; + uint32_t reg; + uint32_t dc_chan; + + if (irq == IPU_IRQ_DC_FC_1) + dc_chan = 1; + else + dc_chan = 5; + + if (!dc_swap) { + reg = __raw_readl(DC_WR_CH_CONF(dc_chan)); + reg &= ~DC_WR_CH_CONF_PROG_TYPE_MASK; + __raw_writel(reg, DC_WR_CH_CONF(dc_chan)); + + reg = __raw_readl(IPU_DISP_GEN); + if (g_dc_di_assignment[dc_chan]) + reg &= ~DI1_COUNTER_RELEASE; + else + reg &= ~DI0_COUNTER_RELEASE; + __raw_writel(reg, IPU_DISP_GEN); + } complete(comp); return IRQ_HANDLED; @@ -689,29 +807,6 @@ void _ipu_dp_dc_disable(ipu_channel_t channel, bool swap) if (timeout <= 0) break; } - - timeout = 50; - - /* - * Wait for DC triple buffer to empty, - * this check is useful for tv overlay. - */ - if (g_dc_di_assignment[dc_chan] == 0) - while ((__raw_readl(DC_STAT) & 0x00000002) - != 0x00000002) { - msleep(2); - timeout -= 2; - if (timeout <= 0) - break; - } - else if (g_dc_di_assignment[dc_chan] == 1) - while ((__raw_readl(DC_STAT) & 0x00000020) - != 0x00000020) { - msleep(2); - timeout -= 2; - if (timeout <= 0) - break; - } return; } else { return; @@ -743,39 +838,6 @@ void _ipu_dp_dc_disable(ipu_channel_t channel, bool swap) __raw_writel(reg, DC_WR_CH_CONF(dc_chan)); spin_unlock_irqrestore(&ipu_lock, lock_flags); } else { - timeout = 50; - - /* Wait for DC triple buffer to empty */ - if (g_dc_di_assignment[dc_chan] == 0) - while ((__raw_readl(DC_STAT) & 0x00000002) - != 0x00000002) { - msleep(2); - timeout -= 2; - if (timeout <= 0) - break; - } - else if (g_dc_di_assignment[dc_chan] == 1) - while ((__raw_readl(DC_STAT) & 0x00000020) - != 0x00000020) { - msleep(2); - timeout -= 2; - if (timeout <= 0) - break; - } - - spin_lock_irqsave(&ipu_lock, lock_flags); - reg = __raw_readl(DC_WR_CH_CONF(dc_chan)); - reg &= ~DC_WR_CH_CONF_PROG_TYPE_MASK; - __raw_writel(reg, DC_WR_CH_CONF(dc_chan)); - - reg = __raw_readl(IPU_DISP_GEN); - if (g_dc_di_assignment[dc_chan]) - reg &= ~DI1_COUNTER_RELEASE; - else - reg &= ~DI0_COUNTER_RELEASE; - __raw_writel(reg, IPU_DISP_GEN); - - spin_unlock_irqrestore(&ipu_lock, lock_flags); /* Clock is already off because it must be done quickly, but we need to fix the ref count */ clk_disable(g_pixel_clk[g_dc_di_assignment[dc_chan]]); @@ -821,6 +883,34 @@ void _ipu_init_dc_mappings(void) _ipu_dc_map_config(4, 0, 5, 0xFC); _ipu_dc_map_config(4, 1, 13, 0xFC); _ipu_dc_map_config(4, 2, 21, 0xFC); + + /* IPU_PIX_FMT_VYUY 16bit width */ + _ipu_dc_map_clear(5); + _ipu_dc_map_config(5, 0, 7, 0xFF); + _ipu_dc_map_config(5, 1, 0, 0x0); + _ipu_dc_map_config(5, 2, 15, 0xFF); + _ipu_dc_map_clear(6); + _ipu_dc_map_config(6, 0, 0, 0x0); + _ipu_dc_map_config(6, 1, 7, 0xFF); + _ipu_dc_map_config(6, 2, 15, 0xFF); + + /* IPU_PIX_FMT_UYUV 16bit width */ + _ipu_dc_map_clear(7); + _ipu_dc_map_link(7, 6, 0, 6, 1, 6, 2); + _ipu_dc_map_clear(8); + _ipu_dc_map_link(8, 5, 0, 5, 1, 5, 2); + + /* IPU_PIX_FMT_YUYV 16bit width */ + _ipu_dc_map_clear(9); + _ipu_dc_map_link(9, 5, 2, 5, 1, 5, 0); + _ipu_dc_map_clear(10); + _ipu_dc_map_link(10, 5, 1, 5, 2, 5, 0); + + /* IPU_PIX_FMT_YVYU 16bit width */ + _ipu_dc_map_clear(11); + _ipu_dc_map_link(11, 5, 1, 5, 2, 5, 0); + _ipu_dc_map_clear(12); + _ipu_dc_map_link(12, 5, 2, 5, 1, 5, 0); } int _ipu_pixfmt_to_map(uint32_t fmt) @@ -837,6 +927,14 @@ int _ipu_pixfmt_to_map(uint32_t fmt) return 3; case IPU_PIX_FMT_LVDS666: return 4; + case IPU_PIX_FMT_VYUY: + return 6; + case IPU_PIX_FMT_UYVY: + return 8; + case IPU_PIX_FMT_YUYV: + return 10; + case IPU_PIX_FMT_YVYU: + return 12; } return -1; @@ -964,22 +1062,22 @@ int32_t ipu_init_sync_panel(int disp, uint32_t pixel_clk, dev_dbg(g_ipu_dev, "pixel clk = %d\n", pixel_clk); if (sig.ext_clk) { - /* Set the PLL to be an even multiple of the pixel clock. not round div for tvout*/ - if ((clk_get_usecount(g_pixel_clk[0]) == 0) && - (clk_get_usecount(g_pixel_clk[1]) == 0)) { + /* + * Set the PLL to be an even multiple of the pixel clock. + * Not round div for tvout and ldb. + * Did not consider both DI come from the same ext clk, if + * meet such case, ext clk rate should be set specially. + */ + if (clk_get_usecount(g_pixel_clk[disp]) == 0) { di_parent = clk_get_parent(g_di_clk[disp]); - if (strcmp(di_parent->name, "tve_clk") != 0) { - rounded_pixel_clk = - clk_round_rate(g_pixel_clk[disp], pixel_clk); - div = clk_get_rate(di_parent) / rounded_pixel_clk; - if (div % 2) - div++; - - if (clk_get_rate(di_parent) != div * rounded_pixel_clk) - clk_set_rate(di_parent, div * rounded_pixel_clk); - msleep(10); - clk_set_rate(g_di_clk[disp], 2 * rounded_pixel_clk); - msleep(10); + if (strcmp(di_parent->name, "tve_clk") != 0 && + strcmp(di_parent->name, "ldb_di0_clk") != 0 && + strcmp(di_parent->name, "ldb_di1_clk") != 0) { + rounded_pixel_clk = pixel_clk * 2; + while (rounded_pixel_clk < 150000000) + rounded_pixel_clk += pixel_clk * 2; + clk_set_rate(di_parent, rounded_pixel_clk); + clk_set_rate(g_di_clk[disp], pixel_clk); } } clk_set_parent(g_pixel_clk[disp], g_di_clk[disp]); @@ -1019,7 +1117,7 @@ int32_t ipu_init_sync_panel(int disp, uint32_t pixel_clk, di_gen = __raw_readl(DI_GENERAL(disp)); if (sig.interlaced) { - if (cpu_is_mx51_rev(CHIP_REV_2_0)) { + if (g_ipu_hw_rev >= 2) { /* Setup internal HSYNC waveform */ _ipu_di_sync_config( disp, /* display */ @@ -1259,7 +1357,7 @@ int32_t ipu_init_sync_panel(int disp, uint32_t pixel_clk, } /* Init template microcode */ - _ipu_dc_write_tmpl(0, WROD(0), 0, map, SYNC_WAVE, 0, 8); + _ipu_dc_write_tmpl(0, WROD(0), 0, map, SYNC_WAVE, 0, 8, 1); if (sig.Hsync_pol) di_gen |= DI_GEN_POLARITY_3; @@ -1322,13 +1420,31 @@ int32_t ipu_init_sync_panel(int disp, uint32_t pixel_clk, /* Init template microcode */ if (disp) { - _ipu_dc_write_tmpl(2, WROD(0), 0, map, SYNC_WAVE, 8, 5); - _ipu_dc_write_tmpl(3, WROD(0), 0, map, SYNC_WAVE, 4, 5); - _ipu_dc_write_tmpl(4, WROD(0), 0, map, SYNC_WAVE, 0, 5); + if ((pixel_fmt == IPU_PIX_FMT_YUYV) || + (pixel_fmt == IPU_PIX_FMT_UYVY) || + (pixel_fmt == IPU_PIX_FMT_YVYU) || + (pixel_fmt == IPU_PIX_FMT_VYUY)) { + _ipu_dc_write_tmpl(8, WROD(0), 0, (map - 1), SYNC_WAVE, 0, 5, 1); + _ipu_dc_write_tmpl(9, WROD(0), 0, map, SYNC_WAVE, 0, 5, 1); + /* configure user events according to DISP NUM */ + __raw_writel((width - 1), DC_UGDE_3(disp)); + } + _ipu_dc_write_tmpl(2, WROD(0), 0, map, SYNC_WAVE, 8, 5, 1); + _ipu_dc_write_tmpl(3, WRG, 0, map, SYNC_WAVE, 4, 5, 1); + _ipu_dc_write_tmpl(4, WROD(0), 0, map, SYNC_WAVE, 0, 5, 1); } else { - _ipu_dc_write_tmpl(5, WROD(0), 0, map, SYNC_WAVE, 8, 5); - _ipu_dc_write_tmpl(6, WROD(0), 0, map, SYNC_WAVE, 4, 5); - _ipu_dc_write_tmpl(7, WROD(0), 0, map, SYNC_WAVE, 0, 5); + if ((pixel_fmt == IPU_PIX_FMT_YUYV) || + (pixel_fmt == IPU_PIX_FMT_UYVY) || + (pixel_fmt == IPU_PIX_FMT_YVYU) || + (pixel_fmt == IPU_PIX_FMT_VYUY)) { + _ipu_dc_write_tmpl(10, WROD(0), 0, (map - 1), SYNC_WAVE, 0, 5, 1); + _ipu_dc_write_tmpl(11, WROD(0), 0, map, SYNC_WAVE, 0, 5, 1); + /* configure user events according to DISP NUM */ + __raw_writel(width - 1, DC_UGDE_3(disp)); + } + _ipu_dc_write_tmpl(5, WROD(0), 0, map, SYNC_WAVE, 8, 5, 1); + _ipu_dc_write_tmpl(6, WRG, 0, map, SYNC_WAVE, 4, 5, 1); + _ipu_dc_write_tmpl(7, WROD(0), 0, map, SYNC_WAVE, 0, 5, 1); } if (sig.Hsync_pol) @@ -1340,6 +1456,19 @@ int32_t ipu_init_sync_panel(int disp, uint32_t pixel_clk, /* Set the clock to stop at counter 6. */ di_gen |= 0x6000000; } + /* changinc DISP_CLK polarity: it can be wrong for some applications */ + if ((pixel_fmt == IPU_PIX_FMT_YUYV) || + (pixel_fmt == IPU_PIX_FMT_UYVY) || + (pixel_fmt == IPU_PIX_FMT_YVYU) || + (pixel_fmt == IPU_PIX_FMT_VYUY)) + di_gen |= 0x00020000; + else { + /* Configure accordingly to the received configuration */ + if (sig.clk_pol) + di_gen |= 0x00020000; + else + di_gen &= ~0x00020000; + } __raw_writel(di_gen, DI_GENERAL(disp)); @@ -1402,7 +1531,7 @@ int ipu_init_async_panel(int disp, int type, uint32_t cycle_time, _ipu_di_data_pin_config(disp, ASYNC_SER_WAVE, DI_PIN_SER_RS, 2, 0, 0); - _ipu_dc_write_tmpl(0x64, WROD(0), 0, map, ASYNC_SER_WAVE, 0, 0); + _ipu_dc_write_tmpl(0x64, WROD(0), 0, map, ASYNC_SER_WAVE, 0, 0, 1); /* Configure DC for serial panel */ __raw_writel(0x14, DC_DISP_CONF1(DC_DISP_ID_SERIAL)); @@ -1679,6 +1808,39 @@ int32_t ipu_disp_set_window_pos(ipu_channel_t channel, int16_t x_pos, } EXPORT_SYMBOL(ipu_disp_set_window_pos); +int32_t ipu_disp_get_window_pos(ipu_channel_t channel, int16_t *x_pos, + int16_t *y_pos) +{ + u32 reg; + unsigned long lock_flags; + uint32_t flow = 0; + + if (channel == MEM_FG_SYNC) + flow = DP_SYNC; + else if (channel == MEM_FG_ASYNC0) + flow = DP_ASYNC0; + else if (channel == MEM_FG_ASYNC1) + flow = DP_ASYNC1; + else + return -EINVAL; + + if (!g_ipu_clk_enabled) + clk_enable(g_ipu_clk); + spin_lock_irqsave(&ipu_lock, lock_flags); + + reg = __raw_readl(DP_FG_POS(flow)); + + *x_pos = (reg >> 16) & 0x7FF; + *y_pos = reg & 0x7FF; + + spin_unlock_irqrestore(&ipu_lock, lock_flags); + if (!g_ipu_clk_enabled) + clk_disable(g_ipu_clk); + + return 0; +} +EXPORT_SYMBOL(ipu_disp_get_window_pos); + void ipu_disp_direct_write(ipu_channel_t channel, u32 value, u32 offset) { if (channel == DIRECT_ASYNC0) diff --git a/drivers/mxc/ipu3/ipu_ic.c b/drivers/mxc/ipu3/ipu_ic.c index 564fab0b699a..78c3a9228941 100644 --- a/drivers/mxc/ipu3/ipu_ic.c +++ b/drivers/mxc/ipu3/ipu_ic.c @@ -1,5 +1,5 @@ /* - * Copyright 2005-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2005-2010 Freescale Semiconductor, Inc. All Rights Reserved. */ /* @@ -157,7 +157,6 @@ void _ipu_vdi_init(ipu_channel_t channel, ipu_channel_params_t *params) { uint32_t reg; uint32_t pixel_fmt; - bool top_field_0; reg = ((params->mem_prp_vf_mem.in_height-1) << 16) | (params->mem_prp_vf_mem.in_width-1); @@ -186,19 +185,7 @@ void _ipu_vdi_init(ipu_channel_t channel, ipu_channel_params_t *params) } __raw_writel(reg, VDI_C); - /* MED_MOTION and LOW_MOTION algorithm that are using 3 fields - * should start presenting using the 2nd field. - */ - if (((params->mem_prp_vf_mem.field_fmt == V4L2_FIELD_INTERLACED_TB) && - (params->mem_prp_vf_mem.motion_sel != HIGH_MOTION)) || - ((params->mem_prp_vf_mem.field_fmt == V4L2_FIELD_INTERLACED_BT) && - (params->mem_prp_vf_mem.motion_sel == HIGH_MOTION))) - top_field_0 = false; - else - top_field_0 = true; - - /* Buffer selection toggle the value therefore init val is inverted. */ - _ipu_vdi_set_top_field_man(!top_field_0); + _ipu_vdi_set_top_field_man(false); _ipu_vdi_set_motion(params->mem_prp_vf_mem.motion_sel); @@ -227,13 +214,13 @@ void _ipu_ic_init_prpvf(ipu_channel_params_t *params, bool src_is_csi) /* Setup horizontal resizing */ /* Upadeted for IC split case */ - if (!(params->mem_prp_vf_mem.out_resize_ratio)) { + if (!(params->mem_prp_vf_mem.outh_resize_ratio)) { _calc_resize_coeffs(params->mem_prp_vf_mem.in_width, params->mem_prp_vf_mem.out_width, &resizeCoeff, &downsizeCoeff); reg |= (downsizeCoeff << 14) | resizeCoeff; } else - reg |= params->mem_prp_vf_mem.out_resize_ratio; + reg |= params->mem_prp_vf_mem.outh_resize_ratio; __raw_writel(reg, IC_PRP_VF_RSC); @@ -349,13 +336,13 @@ void _ipu_ic_init_prpenc(ipu_channel_params_t *params, bool src_is_csi) /* Setup horizontal resizing */ /* Upadeted for IC split case */ - if (!(params->mem_prp_enc_mem.out_resize_ratio)) { + if (!(params->mem_prp_enc_mem.outh_resize_ratio)) { _calc_resize_coeffs(params->mem_prp_enc_mem.in_width, params->mem_prp_enc_mem.out_width, &resizeCoeff, &downsizeCoeff); reg |= (downsizeCoeff << 14) | resizeCoeff; } else - reg |= params->mem_prp_enc_mem.out_resize_ratio; + reg |= params->mem_prp_enc_mem.outh_resize_ratio; __raw_writel(reg, IC_PRP_ENC_RSC); @@ -387,6 +374,8 @@ void _ipu_ic_init_prpenc(ipu_channel_params_t *params, bool src_is_csi) ic_conf |= IC_CONF_RWS_EN; __raw_writel(ic_conf, IC_CONF); + +// ic_dump_register(); } void _ipu_ic_uninit_prpenc(void) @@ -418,20 +407,24 @@ void _ipu_ic_init_pp(ipu_channel_params_t *params) ipu_color_space_t in_fmt, out_fmt; /* Setup vertical resizing */ - _calc_resize_coeffs(params->mem_pp_mem.in_height, + if (!(params->mem_pp_mem.outv_resize_ratio)) { + _calc_resize_coeffs(params->mem_pp_mem.in_height, params->mem_pp_mem.out_height, &resizeCoeff, &downsizeCoeff); - reg = (downsizeCoeff << 30) | (resizeCoeff << 16); + reg = (downsizeCoeff << 30) | (resizeCoeff << 16); + } else { + reg = (params->mem_pp_mem.outv_resize_ratio) << 16; + } /* Setup horizontal resizing */ /* Upadeted for IC split case */ - if (!(params->mem_pp_mem.out_resize_ratio)) { + if (!(params->mem_pp_mem.outh_resize_ratio)) { _calc_resize_coeffs(params->mem_pp_mem.in_width, params->mem_pp_mem.out_width, &resizeCoeff, &downsizeCoeff); reg |= (downsizeCoeff << 14) | resizeCoeff; } else { - reg |= params->mem_pp_mem.out_resize_ratio; + reg |= params->mem_pp_mem.outh_resize_ratio; } __raw_writel(reg, IC_PP_RSC); diff --git a/drivers/mxc/ipu3/ipu_param_mem.h b/drivers/mxc/ipu3/ipu_param_mem.h index dab3b617db1c..30e6dc1005ba 100644 --- a/drivers/mxc/ipu3/ipu_param_mem.h +++ b/drivers/mxc/ipu3/ipu_param_mem.h @@ -155,8 +155,15 @@ static inline void _ipu_ch_param_init(int ch, ipu_ch_param_set_field(¶ms, 1, 102, 14, stride - 1); } + /* EBA is 8-byte aligned */ ipu_ch_param_set_field(¶ms, 1, 0, 29, addr0 >> 3); ipu_ch_param_set_field(¶ms, 1, 29, 29, addr1 >> 3); + if (addr0%8) + dev_warn(g_ipu_dev, + "IDMAC%d's EBA0 is not 8-byte aligned\n", ch); + if (addr1%8) + dev_warn(g_ipu_dev, + "IDMAC%d's EBA1 is not 8-byte aligned\n", ch); switch (pixel_fmt) { case IPU_PIX_FMT_GENERIC: @@ -210,13 +217,14 @@ static inline void _ipu_ch_param_init(int ch, 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(¶ms, 1, 78, 7, 15); /* burst size */ _ipu_ch_params_set_packing(¶ms, 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(¶ms, 1, 78, 7, 31); /* burst size */ break; case IPU_PIX_FMT_YUYV: ipu_ch_param_set_field(¶ms, 0, 107, 3, 3); /* bits/pixel */ @@ -289,13 +297,19 @@ static inline void _ipu_ch_param_init(int ch, v_offset = v; } - /* UBO and VBO are 22-bit */ + /* UBO and VBO are 22-bit and 8-byte aligned */ if (u_offset/8 > 0x3fffff) - dev_err(g_ipu_dev, - "The value of U offset exceeds IPU limitation\n"); + dev_warn(g_ipu_dev, + "IDMAC%d's U offset exceeds IPU limitation\n", ch); if (v_offset/8 > 0x3fffff) - dev_err(g_ipu_dev, - "The value of V offset exceeds IPU limitation\n"); + dev_warn(g_ipu_dev, + "IDMAC%d's V offset exceeds IPU limitation\n", ch); + if (u_offset%8) + dev_warn(g_ipu_dev, + "IDMAC%d's U offset is not 8-byte aligned\n", ch); + if (v_offset%8) + dev_warn(g_ipu_dev, + "IDMAC%d's V offset is not 8-byte aligned\n", ch); ipu_ch_param_set_field(¶ms, 0, 46, 22, u_offset / 8); ipu_ch_param_set_field(¶ms, 0, 68, 22, v_offset / 8); @@ -386,6 +400,13 @@ static inline void _ipu_ch_param_set_interlaced_scan(uint32_t ch) u32 stride; ipu_ch_param_set_field(ipu_ch_param_addr(ch), 0, 113, 1, 1); stride = ipu_ch_param_read_field(ipu_ch_param_addr(ch), 1, 102, 14) + 1; + /* ILO is 20-bit and 8-byte aligned */ + if (stride/8 > 0xfffff) + dev_warn(g_ipu_dev, + "IDMAC%d's ILO exceeds IPU limitation\n", ch); + if (stride%8) + dev_warn(g_ipu_dev, + "IDMAC%d's ILO is not 8-byte aligned\n", ch); ipu_ch_param_mod_field(ipu_ch_param_addr(ch), 1, 58, 20, stride / 8); stride *= 2; ipu_ch_param_mod_field(ipu_ch_param_addr(ch), 1, 102, 14, stride - 1); @@ -442,7 +463,7 @@ static inline void _ipu_ch_offset_update(int ch, (uv_stride * vertical_offset / 2) + horizontal_offset / 2; v_offset = u_offset + (uv_stride * height / 2); - u_fix = u ? (u + (uv_stride * vertical_offset) + + u_fix = u ? (u + (uv_stride * vertical_offset / 2) + (horizontal_offset / 2) - (stride * vertical_offset) - (horizontal_offset)) : u_offset; @@ -493,9 +514,9 @@ static inline void _ipu_ch_offset_update(int ch, uv_stride = stride; u_offset = stride * (height - vertical_offset - 1) + (stride - horizontal_offset) + - (uv_stride * vertical_offset) + + (uv_stride * vertical_offset / 2) + horizontal_offset; - u_fix = u ? (u + (uv_stride * vertical_offset) + + u_fix = u ? (u + (uv_stride * vertical_offset / 2) + horizontal_offset - (stride * vertical_offset) - (horizontal_offset)) : u_offset; @@ -514,13 +535,19 @@ static inline void _ipu_ch_offset_update(int ch, if (v_fix > v_offset) v_offset = v_fix; - /* UBO and VBO are 22-bit */ + /* UBO and VBO are 22-bit and 8-byte aligned */ if (u_offset/8 > 0x3fffff) - dev_err(g_ipu_dev, - "The value of U offset exceeds IPU limitation\n"); + dev_warn(g_ipu_dev, + "IDMAC%d's U offset exceeds IPU limitation\n", ch); if (v_offset/8 > 0x3fffff) - dev_err(g_ipu_dev, - "The value of V offset exceeds IPU limitation\n"); + dev_warn(g_ipu_dev, + "IDMAC%d's V offset exceeds IPU limitation\n", ch); + if (u_offset%8) + dev_warn(g_ipu_dev, + "IDMAC%d's U offset is not 8-byte aligned\n", ch); + if (v_offset%8) + dev_warn(g_ipu_dev, + "IDMAC%d's V offset is not 8-byte aligned\n", ch); ipu_ch_param_mod_field(ipu_ch_param_addr(ch), 0, 46, 22, u_offset / 8); ipu_ch_param_mod_field(ipu_ch_param_addr(ch), 0, 68, 22, v_offset / 8); diff --git a/drivers/mxc/ipu3/ipu_prv.h b/drivers/mxc/ipu3/ipu_prv.h index 213ded04c87d..4e62b256889f 100644 --- a/drivers/mxc/ipu3/ipu_prv.h +++ b/drivers/mxc/ipu3/ipu_prv.h @@ -1,5 +1,5 @@ /* - * Copyright 2005-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2005-2010 Freescale Semiconductor, Inc. All Rights Reserved. */ /* @@ -60,7 +60,7 @@ void _ipu_init_dc_mappings(void); int _ipu_dp_init(ipu_channel_t channel, uint32_t in_pixel_fmt, uint32_t out_pixel_fmt); void _ipu_dp_uninit(ipu_channel_t channel); -void _ipu_dc_init(int dc_chan, int di, bool interlaced); +void _ipu_dc_init(int dc_chan, int di, bool interlaced, uint32_t pixel_fmt); void _ipu_dc_uninit(int dc_chan); void _ipu_dp_dc_enable(ipu_channel_t channel); void _ipu_dp_dc_disable(ipu_channel_t channel, bool swap); diff --git a/drivers/mxc/ipu3/ipu_regs.h b/drivers/mxc/ipu3/ipu_regs.h index 2438df60a0ce..4a78e14df560 100644 --- a/drivers/mxc/ipu3/ipu_regs.h +++ b/drivers/mxc/ipu3/ipu_regs.h @@ -261,6 +261,14 @@ extern u32 *ipu_vdi_reg; #define DC_EVT_NEW_CHAN_R_1 9 #define DC_EVT_NEW_DATA_R_0 10 #define DC_EVT_NEW_DATA_R_1 11 +#define DC_EVEN_UGDE0 12 +#define DC_ODD_UGDE0 13 +#define DC_EVEN_UGDE1 14 +#define DC_ODD_UGDE1 15 +#define DC_EVEN_UGDE2 16 +#define DC_ODD_UGDE2 17 +#define DC_EVEN_UGDE3 18 +#define DC_ODD_UGDE3 19 #define dc_ch_offset(ch) \ ({ \ @@ -627,6 +635,8 @@ enum { VDI_C_VWM3_CLR_2 = 0x02000000, VDI_C_TOP_FIELD_MAN_1 = 0x40000000, VDI_C_TOP_FIELD_AUTO_1 = 0x80000000, + + DMFC_FIFO_SIZE_5F = 0x00003800, }; enum di_pins { @@ -654,5 +664,6 @@ enum di_sync_wave { /* DC template opcodes */ #define WROD(lf) (0x18 | (lf << 1)) +#define WRG (0x01) #endif |