diff options
author | Jason Chen <b02280@freescale.com> | 2011-11-23 14:42:24 +0800 |
---|---|---|
committer | Eric Miao <eric.miao@linaro.org> | 2011-12-02 14:41:50 +0800 |
commit | 5a5a3b462dfad82dfb4a9b86d3fe37e12842893e (patch) | |
tree | b867a04d4551768cce9431973e9db05578c5c867 | |
parent | 2a842a14fc361cc45d187214f0ef8e4fd511126a (diff) |
IPU3: porting to fsl imx_2.6.38 branch base
porting to commit 433c6306fe9455163cff3591b4cf8e2f22bc6cc8
add basic ipu drivers.
Signed-off-by: Jason Chen <jason.chen@linaro.org>
-rw-r--r-- | arch/arm/mach-imx/Kconfig | 10 | ||||
-rw-r--r-- | arch/arm/plat-mxc/devices/platform-imx_ipuv3.c | 1 | ||||
-rw-r--r-- | arch/arm/plat-mxc/include/mach/ipu-v3.h | 61 | ||||
-rw-r--r-- | drivers/mxc/Kconfig | 5 | ||||
-rw-r--r-- | drivers/mxc/ipu3/ipu_calc_stripes_sizes.c | 14 | ||||
-rw-r--r-- | drivers/mxc/ipu3/ipu_capture.c | 13 | ||||
-rw-r--r-- | drivers/mxc/ipu3/ipu_common.c | 78 | ||||
-rw-r--r-- | drivers/mxc/ipu3/ipu_device.c | 381 | ||||
-rw-r--r-- | drivers/mxc/ipu3/ipu_disp.c | 30 | ||||
-rw-r--r-- | drivers/mxc/ipu3/ipu_ic.c | 1 | ||||
-rw-r--r-- | drivers/mxc/ipu3/ipu_param_mem.h | 17 | ||||
-rw-r--r-- | drivers/mxc/ipu3/ipu_prv.h | 6 | ||||
-rw-r--r-- | include/linux/ipu.h | 17 |
13 files changed, 440 insertions, 194 deletions
diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig index c44aa974e79..30199fc4b8c 100644 --- a/arch/arm/mach-imx/Kconfig +++ b/arch/arm/mach-imx/Kconfig @@ -22,6 +22,15 @@ config ARCH_MX25 config MACH_MX27 bool +config ARCH_MX31 + bool + +config ARCH_MX35 + bool + +config ARCH_MX6Q + bool + config SOC_IMX1 bool select ARCH_MX1 @@ -595,6 +604,7 @@ comment "i.MX6 family:" config SOC_IMX6Q bool "i.MX6 Quad support" + select ARCH_MX6Q select ARM_GIC select CACHE_L2X0 select CPU_V7 diff --git a/arch/arm/plat-mxc/devices/platform-imx_ipuv3.c b/arch/arm/plat-mxc/devices/platform-imx_ipuv3.c index a353060bc95..4c3ebaf327d 100644 --- a/arch/arm/plat-mxc/devices/platform-imx_ipuv3.c +++ b/arch/arm/plat-mxc/devices/platform-imx_ipuv3.c @@ -20,7 +20,6 @@ #include <mach/hardware.h> #include <mach/devices-common.h> -#include <linux/dma-mapping.h> #include <linux/clk.h> #define imx5_ipuv3_data_entry_single(soc, size, ipu_init, ipu_pg) \ diff --git a/arch/arm/plat-mxc/include/mach/ipu-v3.h b/arch/arm/plat-mxc/include/mach/ipu-v3.h index 713ee9f62d5..480b4ea338e 100644 --- a/arch/arm/plat-mxc/include/mach/ipu-v3.h +++ b/arch/arm/plat-mxc/include/mach/ipu-v3.h @@ -18,66 +18,6 @@ #include <linux/ipu.h> -/* IPU Pixel format definitions */ -/* Four-character-code (FOURCC) */ -#define fourcc(a, b, c, d)\ - (((__u32)(a)<<0)|((__u32)(b)<<8)|((__u32)(c)<<16)|((__u32)(d)<<24)) - -/*! - * @name IPU Pixel Formats - * - * Pixel formats are defined with ASCII FOURCC code. The pixel format codes are - * the same used by V4L2 API. - */ - -/*! @{ */ -/*! @name Generic or Raw Data Formats */ -/*! @{ */ -#define IPU_PIX_FMT_GENERIC fourcc('I', 'P', 'U', '0') /*!< IPU Generic Data */ -#define IPU_PIX_FMT_GENERIC_32 fourcc('I', 'P', 'U', '1') /*!< IPU Generic Data */ -#define IPU_PIX_FMT_LVDS666 fourcc('L', 'V', 'D', '6') /*!< IPU Generic Data */ -#define IPU_PIX_FMT_LVDS888 fourcc('L', 'V', 'D', '8') /*!< IPU Generic Data */ -/*! @} */ -/*! @name RGB Formats */ -/*! @{ */ -#define IPU_PIX_FMT_RGB332 fourcc('R', 'G', 'B', '1') /*!< 8 RGB-3-3-2 */ -#define IPU_PIX_FMT_RGB555 fourcc('R', 'G', 'B', 'O') /*!< 16 RGB-5-5-5 */ -#define IPU_PIX_FMT_RGB565 fourcc('R', 'G', 'B', 'P') /*!< 1 6 RGB-5-6-5 */ -#define IPU_PIX_FMT_RGB666 fourcc('R', 'G', 'B', '6') /*!< 18 RGB-6-6-6 */ -#define IPU_PIX_FMT_BGR666 fourcc('B', 'G', 'R', '6') /*!< 18 BGR-6-6-6 */ -#define IPU_PIX_FMT_BGR24 fourcc('B', 'G', 'R', '3') /*!< 24 BGR-8-8-8 */ -#define IPU_PIX_FMT_RGB24 fourcc('R', 'G', 'B', '3') /*!< 24 RGB-8-8-8 */ -#define IPU_PIX_FMT_GBR24 fourcc('G', 'B', 'R', '3') /*!< 24 GBR-8-8-8 */ -#define IPU_PIX_FMT_BGR32 fourcc('B', 'G', 'R', '4') /*!< 32 BGR-8-8-8-8 */ -#define IPU_PIX_FMT_BGRA32 fourcc('B', 'G', 'R', 'A') /*!< 32 BGR-8-8-8-8 */ -#define IPU_PIX_FMT_RGB32 fourcc('R', 'G', 'B', '4') /*!< 32 RGB-8-8-8-8 */ -#define IPU_PIX_FMT_RGBA32 fourcc('R', 'G', 'B', 'A') /*!< 32 RGB-8-8-8-8 */ -#define IPU_PIX_FMT_ABGR32 fourcc('A', 'B', 'G', 'R') /*!< 32 ABGR-8-8-8-8 */ -/*! @} */ -/*! @name YUV Interleaved Formats */ -/*! @{ */ -#define IPU_PIX_FMT_YUYV fourcc('Y', 'U', 'Y', 'V') /*!< 16 YUV 4:2:2 */ -#define IPU_PIX_FMT_UYVY fourcc('U', 'Y', 'V', 'Y') /*!< 16 YUV 4:2:2 */ -#define IPU_PIX_FMT_YVYU fourcc('Y', 'V', 'Y', 'U') /*!< 16 YVYU 4:2:2 */ -#define IPU_PIX_FMT_VYUY fourcc('V', 'Y', 'U', 'Y') /*!< 16 VYYU 4:2:2 */ -#define IPU_PIX_FMT_Y41P fourcc('Y', '4', '1', 'P') /*!< 12 YUV 4:1:1 */ -#define IPU_PIX_FMT_YUV444 fourcc('Y', '4', '4', '4') /*!< 24 YUV 4:4:4 */ -#define IPU_PIX_FMT_VYU444 fourcc('V', '4', '4', '4') /*!< 24 VYU 4:4:4 */ -/* two planes -- one Y, one Cb + Cr interleaved */ -#define IPU_PIX_FMT_NV12 fourcc('N', 'V', '1', '2') /* 12 Y/CbCr 4:2:0 */ -/*! @} */ -/*! @name YUV Planar Formats */ -/*! @{ */ -#define IPU_PIX_FMT_GREY fourcc('G', 'R', 'E', 'Y') /*!< 8 Greyscale */ -#define IPU_PIX_FMT_YVU410P fourcc('Y', 'V', 'U', '9') /*!< 9 YVU 4:1:0 */ -#define IPU_PIX_FMT_YUV410P fourcc('Y', 'U', 'V', '9') /*!< 9 YUV 4:1:0 */ -#define IPU_PIX_FMT_YVU420P fourcc('Y', 'V', '1', '2') /*!< 12 YVU 4:2:0 */ -#define IPU_PIX_FMT_YUV420P fourcc('I', '4', '2', '0') /*!< 12 YUV 4:2:0 */ -#define IPU_PIX_FMT_YUV420P2 fourcc('Y', 'U', '1', '2') /*!< 12 YUV 4:2:0 */ -#define IPU_PIX_FMT_YVU422P fourcc('Y', 'V', '1', '6') /*!< 16 YVU 4:2:2 */ -#define IPU_PIX_FMT_YUV422P fourcc('4', '2', '2', 'P') /*!< 16 YUV 4:2:2 */ -/*! @} */ - /* IPU Driver channels definitions. */ /* Note these are different from IDMA channels */ #define IPU_MAX_CH 32 @@ -185,6 +125,7 @@ typedef union { struct { uint32_t csi; uint32_t mipi_id; + uint32_t mipi_vc; bool mipi_en; bool interlaced; } csi_mem; diff --git a/drivers/mxc/Kconfig b/drivers/mxc/Kconfig index d2b05814832..5316e4c8325 100644 --- a/drivers/mxc/Kconfig +++ b/drivers/mxc/Kconfig @@ -9,10 +9,11 @@ config MXC_IPU depends on !ARCH_MX21 depends on !ARCH_MX27 depends on !ARCH_MX25 - select MXC_IPU_V1 if !ARCH_MX37 && !ARCH_MX5 - select MXC_IPU_V3 if ARCH_MX37 || ARCH_MX5 + select MXC_IPU_V1 if !ARCH_MX37 && !ARCH_MX5 && !ARCH_MX6Q + select MXC_IPU_V3 if ARCH_MX37 || ARCH_MX5 || ARCH_MX6Q select MXC_IPU_V3D if ARCH_MX37 select MXC_IPU_V3EX if ARCH_MX5 + select MXC_IPU_V3H if ARCH_MX6Q help If you plan to use the Image Processing unit, say Y here. IPU is needed by Framebuffer and V4L2 drivers. diff --git a/drivers/mxc/ipu3/ipu_calc_stripes_sizes.c b/drivers/mxc/ipu3/ipu_calc_stripes_sizes.c index 1e05cc5808b..0a135995fe7 100644 --- a/drivers/mxc/ipu3/ipu_calc_stripes_sizes.c +++ b/drivers/mxc/ipu3/ipu_calc_stripes_sizes.c @@ -20,6 +20,7 @@ */ #include <linux/module.h> +#include <linux/export.h> #include <mach/ipu-v3.h> #include <asm/div64.h> @@ -52,8 +53,8 @@ static u32 truncate(u32 up, /* 0: down; else: up */ return d; } -/*static unsigned int f_calc(unsigned int pfs, unsigned int bpp, unsigned int *write) -{[> return input_f <] +static unsigned int f_calc(unsigned int pfs, unsigned int bpp, unsigned int *write) +{/* return input_f */ unsigned int f_calculated = 0; switch (pfs) { case IPU_PIX_FMT_YVU422P: @@ -129,7 +130,7 @@ static unsigned int m_calc(unsigned int pfs) } return m_calculated; -}*/ +} /* Stripe parameters calculator */ @@ -214,14 +215,14 @@ int ipu_calc_stripes_sizes(const unsigned int input_frame_width, /* M, F calculations */ /* read back pfs from params */ - input_f = 16; + input_f = f_calc(input_pixelformat, 0, NULL); input_m = 16; /* BPP should be used in the out_F calc */ /* Temporarily not used */ /* out_F = F_calc(idmac->pfs, idmac->bpp, NULL); */ output_f = 16; - output_m = 16; + output_m = m_calc(output_pixelformat); if ((input_frame_width < 4) || (output_frame_width < 4)) @@ -370,7 +371,6 @@ int ipu_calc_stripes_sizes(const unsigned int input_frame_width, left->output_column = 0; right->output_column = onw; } - return status; } -EXPORT_SYMBOL(ipu_calc_stripes_sizes); +EXPORT_SYMBOL_GPL(ipu_calc_stripes_sizes); diff --git a/drivers/mxc/ipu3/ipu_capture.c b/drivers/mxc/ipu3/ipu_capture.c index ff738453004..faed8887aab 100644 --- a/drivers/mxc/ipu3/ipu_capture.c +++ b/drivers/mxc/ipu3/ipu_capture.c @@ -25,6 +25,7 @@ #include <linux/spinlock.h> #include <linux/delay.h> #include <linux/clk.h> +#include <linux/export.h> #include <mach/ipu-v3.h> #include "ipu_prv.h" @@ -168,7 +169,7 @@ ipu_csi_init_interface(struct ipu_soc *ipu, uint16_t width, uint16_t height, return 0; } -EXPORT_SYMBOL(ipu_csi_init_interface); +EXPORT_SYMBOL_GPL(ipu_csi_init_interface); /*! * ipu_csi_get_sensor_protocol @@ -184,7 +185,7 @@ int32_t ipu_csi_get_sensor_protocol(struct ipu_soc *ipu, uint32_t csi) CSI_SENS_CONF_SENS_PRTCL_MASK) >> CSI_SENS_CONF_SENS_PRTCL_SHIFT; } -EXPORT_SYMBOL(ipu_csi_get_sensor_protocol); +EXPORT_SYMBOL_GPL(ipu_csi_get_sensor_protocol); /*! * _ipu_csi_mclk_set @@ -237,7 +238,7 @@ int ipu_csi_enable_mclk(struct ipu_soc *ipu, int csi, bool flag, bool wait) return 0; } -EXPORT_SYMBOL(ipu_csi_enable_mclk); +EXPORT_SYMBOL_GPL(ipu_csi_enable_mclk); /*! * ipu_csi_get_window_size @@ -263,7 +264,7 @@ void ipu_csi_get_window_size(struct ipu_soc *ipu, uint32_t *width, uint32_t *hei _ipu_put(ipu); } -EXPORT_SYMBOL(ipu_csi_get_window_size); +EXPORT_SYMBOL_GPL(ipu_csi_get_window_size); /*! * ipu_csi_set_window_size @@ -285,7 +286,7 @@ void ipu_csi_set_window_size(struct ipu_soc *ipu, uint32_t width, uint32_t heigh _ipu_put(ipu); } -EXPORT_SYMBOL(ipu_csi_set_window_size); +EXPORT_SYMBOL_GPL(ipu_csi_set_window_size); /*! * ipu_csi_set_window_pos @@ -312,7 +313,7 @@ void ipu_csi_set_window_pos(struct ipu_soc *ipu, uint32_t left, uint32_t top, ui _ipu_put(ipu); } -EXPORT_SYMBOL(ipu_csi_set_window_pos); +EXPORT_SYMBOL_GPL(ipu_csi_set_window_pos); /*! * _ipu_csi_horizontal_downsize_enable diff --git a/drivers/mxc/ipu3/ipu_common.c b/drivers/mxc/ipu3/ipu_common.c index 0911a15f480..388bf537541 100644 --- a/drivers/mxc/ipu3/ipu_common.c +++ b/drivers/mxc/ipu3/ipu_common.c @@ -29,6 +29,7 @@ #include <linux/irq.h> #include <linux/irqdesc.h> #include <linux/clk.h> +#include <linux/export.h> #include <mach/clock.h> #include <mach/hardware.h> #include <mach/ipu-v3.h> @@ -661,8 +662,10 @@ int32_t ipu_init_channel(struct ipu_soc *ipu, ipu_channel_t channel, ipu_channel if (params->csi_mem.mipi_en) { ipu_conf |= (1 << (IPU_CONF_CSI0_DATA_SOURCE_OFFSET + params->csi_mem.csi)); - _ipu_smfc_init(ipu, channel, params->csi_mem.mipi_id, + _ipu_smfc_init(ipu, channel, params->csi_mem.mipi_vc, params->csi_mem.csi); + _ipu_csi_set_mipi_di(ipu, params->csi_mem.mipi_vc, + params->csi_mem.mipi_id, params->csi_mem.csi); } else { ipu_conf &= ~(1 << (IPU_CONF_CSI0_DATA_SOURCE_OFFSET + params->csi_mem.csi)); @@ -883,7 +886,7 @@ err: _ipu_unlock(ipu); return ret; } -EXPORT_SYMBOL(ipu_init_channel); +EXPORT_SYMBOL_GPL(ipu_init_channel); /*! * This function is called to uninitialize a logical IPU channel. @@ -1091,7 +1094,7 @@ void ipu_uninit_channel(struct ipu_soc *ipu, ipu_channel_t channel) WARN_ON(ipu->dmfc_use_count < 0); WARN_ON(ipu->smfc_use_count < 0); } -EXPORT_SYMBOL(ipu_uninit_channel); +EXPORT_SYMBOL_GPL(ipu_uninit_channel); /*! * This function is called to initialize buffer(s) for logical IPU channel. @@ -1357,7 +1360,7 @@ int32_t ipu_init_channel_buffer(struct ipu_soc *ipu, ipu_channel_t channel, return 0; } -EXPORT_SYMBOL(ipu_init_channel_buffer); +EXPORT_SYMBOL_GPL(ipu_init_channel_buffer); /*! * This function is called to update the physical address of a buffer for @@ -1404,7 +1407,7 @@ int32_t ipu_update_channel_buffer(struct ipu_soc *ipu, ipu_channel_t channel, return ret; } -EXPORT_SYMBOL(ipu_update_channel_buffer); +EXPORT_SYMBOL_GPL(ipu_update_channel_buffer); /*! @@ -1472,7 +1475,7 @@ int32_t ipu_update_channel_offset(struct ipu_soc *ipu, _ipu_unlock(ipu); return ret; } -EXPORT_SYMBOL(ipu_update_channel_offset); +EXPORT_SYMBOL_GPL(ipu_update_channel_offset); /*! @@ -1510,7 +1513,7 @@ int32_t ipu_select_buffer(struct ipu_soc *ipu, ipu_channel_t channel, _ipu_unlock(ipu); return 0; } -EXPORT_SYMBOL(ipu_select_buffer); +EXPORT_SYMBOL_GPL(ipu_select_buffer); /*! * This function is called to set a channel's buffer as ready. @@ -1539,7 +1542,7 @@ int32_t ipu_select_multi_vdi_buffer(struct ipu_soc *ipu, uint32_t bufNum) _ipu_unlock(ipu); return 0; } -EXPORT_SYMBOL(ipu_select_multi_vdi_buffer); +EXPORT_SYMBOL_GPL(ipu_select_multi_vdi_buffer); #define NA -1 static int proc_dest_sel[] = { @@ -1752,7 +1755,7 @@ err: _ipu_unlock(ipu); return retval; } -EXPORT_SYMBOL(ipu_link_channels); +EXPORT_SYMBOL_GPL(ipu_link_channels); /*! * This function unlinks 2 channels and disables automatic frame @@ -1882,7 +1885,7 @@ err: _ipu_unlock(ipu); return retval; } -EXPORT_SYMBOL(ipu_unlink_channels); +EXPORT_SYMBOL_GPL(ipu_unlink_channels); /*! * This function check whether a logical channel was enabled. @@ -1910,7 +1913,7 @@ int32_t ipu_is_channel_busy(struct ipu_soc *ipu, ipu_channel_t channel) return 1; return 0; } -EXPORT_SYMBOL(ipu_is_channel_busy); +EXPORT_SYMBOL_GPL(ipu_is_channel_busy); /*! * This function enables a logical channel. @@ -2021,7 +2024,7 @@ int32_t ipu_enable_channel(struct ipu_soc *ipu, ipu_channel_t channel) return 0; } -EXPORT_SYMBOL(ipu_enable_channel); +EXPORT_SYMBOL_GPL(ipu_enable_channel); /*! * This function check buffer ready for a logical channel. @@ -2056,7 +2059,7 @@ int32_t ipu_check_buffer_ready(struct ipu_soc *ipu, ipu_channel_t channel, ipu_b else return 0; } -EXPORT_SYMBOL(ipu_check_buffer_ready); +EXPORT_SYMBOL_GPL(ipu_check_buffer_ready); /*! * This function clear buffer ready for a logical channel. @@ -2098,7 +2101,7 @@ void ipu_clear_buffer_ready(struct ipu_soc *ipu, ipu_channel_t channel, ipu_buff _ipu_clear_buffer_ready(ipu, channel, type, bufNum); _ipu_unlock(ipu); } -EXPORT_SYMBOL(ipu_clear_buffer_ready); +EXPORT_SYMBOL_GPL(ipu_clear_buffer_ready); /*! * This function disables a logical channel. @@ -2295,7 +2298,7 @@ int32_t ipu_disable_channel(struct ipu_soc *ipu, ipu_channel_t channel, bool wai return 0; } -EXPORT_SYMBOL(ipu_disable_channel); +EXPORT_SYMBOL_GPL(ipu_disable_channel); /*! * This function enables CSI. @@ -2315,6 +2318,7 @@ int32_t ipu_enable_csi(struct ipu_soc *ipu, uint32_t csi) return -EINVAL; } + _ipu_get(ipu); _ipu_lock(ipu); ipu->csi_use_count[csi]++; @@ -2326,9 +2330,10 @@ int32_t ipu_enable_csi(struct ipu_soc *ipu, uint32_t csi) ipu_cm_write(ipu, reg | IPU_CONF_CSI1_EN, IPU_CONF); } _ipu_unlock(ipu); + _ipu_put(ipu); return 0; } -EXPORT_SYMBOL(ipu_enable_csi); +EXPORT_SYMBOL_GPL(ipu_enable_csi); /*! * This function disables CSI. @@ -2347,7 +2352,7 @@ int32_t ipu_disable_csi(struct ipu_soc *ipu, uint32_t csi) dev_err(ipu->dev, "Wrong csi num_%d\n", csi); return -EINVAL; } - + _ipu_get(ipu); _ipu_lock(ipu); ipu->csi_use_count[csi]--; if (ipu->csi_use_count[csi] == 0) { @@ -2358,9 +2363,10 @@ int32_t ipu_disable_csi(struct ipu_soc *ipu, uint32_t csi) ipu_cm_write(ipu, reg & ~IPU_CONF_CSI1_EN, IPU_CONF); } _ipu_unlock(ipu); + _ipu_put(ipu); return 0; } -EXPORT_SYMBOL(ipu_disable_csi); +EXPORT_SYMBOL_GPL(ipu_disable_csi); static irqreturn_t ipu_irq_handler(int irq, void *desc) { @@ -2442,7 +2448,7 @@ void ipu_enable_irq(struct ipu_soc *ipu, uint32_t irq) _ipu_put(ipu); } -EXPORT_SYMBOL(ipu_enable_irq); +EXPORT_SYMBOL_GPL(ipu_enable_irq); /*! * This function disables the interrupt for the specified interrupt line. @@ -2469,7 +2475,7 @@ void ipu_disable_irq(struct ipu_soc *ipu, uint32_t irq) _ipu_put(ipu); } -EXPORT_SYMBOL(ipu_disable_irq); +EXPORT_SYMBOL_GPL(ipu_disable_irq); /*! * This function clears the interrupt for the specified interrupt line. @@ -2493,7 +2499,7 @@ void ipu_clear_irq(struct ipu_soc *ipu, uint32_t irq) _ipu_put(ipu); } -EXPORT_SYMBOL(ipu_clear_irq); +EXPORT_SYMBOL_GPL(ipu_clear_irq); /*! * This function returns the current interrupt status for the specified @@ -2520,7 +2526,7 @@ bool ipu_get_irq_status(struct ipu_soc *ipu, uint32_t irq) else return false; } -EXPORT_SYMBOL(ipu_get_irq_status); +EXPORT_SYMBOL_GPL(ipu_get_irq_status); /*! * This function registers an interrupt handler function for the specified @@ -2578,7 +2584,7 @@ int ipu_request_irq(struct ipu_soc *ipu, uint32_t irq, return 0; } -EXPORT_SYMBOL(ipu_request_irq); +EXPORT_SYMBOL_GPL(ipu_request_irq); /*! * This function unregisters an interrupt handler for the specified interrupt @@ -2603,7 +2609,7 @@ void ipu_free_irq(struct ipu_soc *ipu, uint32_t irq, void *dev_id) ipu->irq_list[irq].handler = NULL; spin_unlock_irqrestore(&ipu->spin_lock, lock_flags); } -EXPORT_SYMBOL(ipu_free_irq); +EXPORT_SYMBOL_GPL(ipu_free_irq); uint32_t ipu_get_cur_buffer_idx(struct ipu_soc *ipu, ipu_channel_t channel, ipu_buffer_t type) { @@ -2626,7 +2632,7 @@ uint32_t ipu_get_cur_buffer_idx(struct ipu_soc *ipu, ipu_channel_t channel, ipu_ return 0; } } -EXPORT_SYMBOL(ipu_get_cur_buffer_idx); +EXPORT_SYMBOL_GPL(ipu_get_cur_buffer_idx); uint32_t _ipu_channel_status(struct ipu_soc *ipu, ipu_channel_t channel) { @@ -2702,7 +2708,7 @@ int32_t ipu_swap_channel(struct ipu_soc *ipu, ipu_channel_t from_ch, ipu_channel return 0; } -EXPORT_SYMBOL(ipu_swap_channel); +EXPORT_SYMBOL_GPL(ipu_swap_channel); uint32_t bytes_per_pixel(uint32_t fmt) { @@ -2737,7 +2743,7 @@ uint32_t bytes_per_pixel(uint32_t fmt) } return 0; } -EXPORT_SYMBOL(bytes_per_pixel); +EXPORT_SYMBOL_GPL(bytes_per_pixel); ipu_color_space_t format_to_colorspace(uint32_t fmt) { @@ -2779,8 +2785,9 @@ bool ipu_pixel_format_has_alpha(uint32_t fmt) return false; } -static int ipu_suspend(struct platform_device *pdev, pm_message_t state) +static int ipu_suspend_noirq(struct device *dev) { + struct platform_device *pdev = to_platform_device(dev); struct imx_ipuv3_platform_data *plat_data = pdev->dev.platform_data; struct ipu_soc *ipu = platform_get_drvdata(pdev); @@ -2849,6 +2856,8 @@ static int ipu_suspend(struct platform_device *pdev, pm_message_t state) ipu->buf_ready_reg[7] = ipu_cm_read(ipu, IPU_ALT_CHA_BUF1_RDY(32)); ipu->buf_ready_reg[8] = ipu_cm_read(ipu, IPU_CHA_BUF2_RDY(0)); ipu->buf_ready_reg[9] = ipu_cm_read(ipu, IPU_CHA_BUF2_RDY(32)); + + clk_disable(ipu->ipu_clk); } if (plat_data->pg) @@ -2857,8 +2866,9 @@ static int ipu_suspend(struct platform_device *pdev, pm_message_t state) return 0; } -static int ipu_resume(struct platform_device *pdev) +static int ipu_resume_noirq(struct device *dev) { + struct platform_device *pdev = to_platform_device(dev); struct imx_ipuv3_platform_data *plat_data = pdev->dev.platform_data; struct ipu_soc *ipu = platform_get_drvdata(pdev); @@ -2866,6 +2876,8 @@ static int ipu_resume(struct platform_device *pdev) plat_data->pg(0); if (atomic_read(&ipu->ipu_use_count)) { + clk_enable(ipu->ipu_clk); + /* restore buf ready regs */ ipu_cm_write(ipu, ipu->buf_ready_reg[0], IPU_CHA_BUF0_RDY(0)); ipu_cm_write(ipu, ipu->buf_ready_reg[1], IPU_CHA_BUF0_RDY(32)); @@ -2916,17 +2928,21 @@ static int ipu_resume(struct platform_device *pdev) return 0; } +static const struct dev_pm_ops mxcipu_pm_ops = { + .suspend_noirq = ipu_suspend_noirq, + .resume_noirq = ipu_resume_noirq, +}; + /*! * This structure contains pointers to the power management callback functions. */ static struct platform_driver mxcipu_driver = { .driver = { .name = "imx-ipuv3", + .pm = &mxcipu_pm_ops, }, .probe = ipu_probe, .remove = ipu_remove, - .suspend = ipu_suspend, - .resume = ipu_resume, }; int32_t __init ipu_gen_init(void) diff --git a/drivers/mxc/ipu3/ipu_device.c b/drivers/mxc/ipu3/ipu_device.c index 5f908be66df..1f0eba46713 100644 --- a/drivers/mxc/ipu3/ipu_device.c +++ b/drivers/mxc/ipu3/ipu_device.c @@ -33,8 +33,11 @@ #include <linux/dma-mapping.h> #include <linux/io.h> #include <linux/kthread.h> -#include <asm/cacheflush.h> +#include <linux/vmalloc.h> +#include <linux/export.h> #include <mach/ipu-v3.h> +#include <asm/outercache.h> +#include <asm/cacheflush.h> #include "ipu_prv.h" #include "ipu_regs.h" @@ -42,12 +45,6 @@ /* Strucutures and variables for exporting MXC IPU as device*/ typedef enum { - RGB_CS, - YUV_CS, - NULL_CS -} cs_t; - -typedef enum { STATE_OK = 0, STATE_NO_IPU, STATE_NO_IRQ, @@ -87,6 +84,8 @@ struct stripe_setting { u32 o_right_pos; u32 o_top_pos; u32 o_bottom_pos; + u32 rl_split_line; + u32 ud_split_line; }; struct task_set { @@ -146,9 +145,11 @@ struct ipu_split_task { struct ipu_task task; struct ipu_task_entry *parent_task; struct task_struct *thread; - bool could_finish; + volatile bool could_finish; wait_queue_head_t waitq; int ret; + + u32 task_no; }; struct ipu_task_entry { @@ -168,8 +169,9 @@ struct ipu_task_entry { struct task_set set; struct completion comp; ipu_state_t state; -}; + u32 task_no; +}; struct ipu_alloc_list { struct list_head list; dma_addr_t phy_addr; @@ -179,9 +181,12 @@ struct ipu_alloc_list { LIST_HEAD(ipu_alloc_list); static int major; +static u32 frame_no; static struct class *ipu_class; static struct device *ipu_dev; - +static char *vditmpbuf[2]; +static bool buf1filled, buf0filled; +static u32 old_save_lines, old_size; int ipu_queue_sp_task(struct ipu_split_task *sp_task); static bool deinterlace_3_field(struct ipu_task_entry *t) @@ -190,7 +195,7 @@ static bool deinterlace_3_field(struct ipu_task_entry *t) (t->input.deinterlace.motion != HIGH_MOTION)); } -static u32 fmt_to_bpp(u32 pixelformat) +unsigned int fmt_to_bpp(unsigned int pixelformat) { u32 bpp; @@ -229,8 +234,9 @@ static u32 fmt_to_bpp(u32 pixelformat) } return bpp; } +EXPORT_SYMBOL_GPL(fmt_to_bpp); -static cs_t colorspaceofpixel(int fmt) +cs_t colorspaceofpixel(int fmt) { switch (fmt) { case IPU_PIX_FMT_RGB565: @@ -258,8 +264,9 @@ static cs_t colorspaceofpixel(int fmt) return NULL_CS; } } +EXPORT_SYMBOL_GPL(colorspaceofpixel); -static int need_csc(int ifmt, int ofmt) +int need_csc(int ifmt, int ofmt) { cs_t ics, ocs; @@ -273,6 +280,7 @@ static int need_csc(int ifmt, int ofmt) return 0; } +EXPORT_SYMBOL_GPL(need_csc); static int soc_max_in_width(void) { @@ -481,6 +489,7 @@ static void dump_task_info(struct ipu_task_entry *t) dev_dbg(t->dev, "[0x%p]\tIC_MODE = 0x%x\n", (void *)t, IC_MODE); dev_dbg(t->dev, "[0x%p]\tROT_MODE = 0x%x\n", (void *)t, ROT_MODE); dev_dbg(t->dev, "[0x%p]\tVDI_MODE = 0x%x\n", (void *)t, VDI_MODE); + dev_dbg(t->dev, "[0x%p]\tTask_no = 0x%x\n\n\n", (void *)t, t->task_no); } static void dump_check_err(struct device *dev, int err) @@ -520,6 +529,9 @@ static void dump_check_err(struct device *dev, int err) case IPU_CHECK_ERR_SPLIT_OUTPUTH_OVER: dev_err(dev, "split mode output height overflow\n"); break; + case IPU_CHECK_ERR_SPLIT_WITH_ROT: + dev_err(dev, "not support split mode with rotation\n"); + break; default: break; } @@ -605,15 +617,14 @@ static int update_split_setting(struct ipu_task_entry *t) struct stripe_param down_stripe; u32 iw, ih, ow, oh; + if (t->output.rotate >= IPU_ROTATE_90_RIGHT) + return IPU_CHECK_ERR_SPLIT_WITH_ROT; + iw = t->input.crop.w; ih = t->input.crop.h; - if (t->output.rotate >= IPU_ROTATE_90_RIGHT) { - ow = t->output.crop.h; - oh = t->output.crop.w; - } else { - ow = t->output.crop.w; - oh = t->output.crop.h; - } + + ow = t->output.crop.w; + oh = t->output.crop.h; if (t->set.split_mode & RL_SPLIT) { ipu_calc_stripes_sizes(iw, @@ -796,9 +807,11 @@ static int check_task(struct ipu_task_entry *t) t->set.split_mode |= RL_SPLIT; if (t->output.crop.h > soc_max_out_height()) t->set.split_mode |= UD_SPLIT; - ret = update_split_setting(t); - if (ret > IPU_CHECK_ERR_MIN) - goto done; + if (t->set.split_mode) { + ret = update_split_setting(t); + if (ret > IPU_CHECK_ERR_MIN) + goto done; + } } if (t->output.rotate >= IPU_ROTATE_90_RIGHT) { @@ -928,10 +941,11 @@ static int split_task_thread(void *data) t->ret = ipu_queue_sp_task(t); - while (!kthread_should_stop()) - wait_event_interruptible(t->waitq, t->could_finish); + t->could_finish = true; - return 0; + wake_up_interruptible(&t->waitq); + + do_exit(0); } static int create_split_task( @@ -941,6 +955,8 @@ static int create_split_task( struct ipu_task *task = &(sp_task->task); struct ipu_task_entry *t = sp_task->parent_task; + sp_task->task_no |= stripe; + task->input = t->input; task->output = t->output; task->overlay_en = t->overlay_en; @@ -959,9 +975,14 @@ static int create_split_task( if (t->output.rotate >= IPU_ROTATE_90_RIGHT) { task->output.crop.w = t->set.sp_setting.oh; task->output.crop.h = t->set.sp_setting.ow; + t->set.sp_setting.rl_split_line = t->set.sp_setting.o_bottom_pos; + t->set.sp_setting.ud_split_line = t->set.sp_setting.o_right_pos; + } else { task->output.crop.w = t->set.sp_setting.ow; task->output.crop.h = t->set.sp_setting.oh; + t->set.sp_setting.rl_split_line = t->set.sp_setting.o_right_pos; + t->set.sp_setting.ud_split_line = t->set.sp_setting.o_bottom_pos; } if (stripe & LEFT_STRIPE) @@ -1102,11 +1123,16 @@ static int create_split_task( break; } - sp_task->thread = kthread_run(split_task_thread, sp_task, + /*check split task deinterlace enable*/ + if (t->input.deinterlace.enable) { + sp_task->ret = ipu_queue_sp_task(sp_task); + } else { + sp_task->thread = kthread_run(split_task_thread, sp_task, "ipu_split_task"); - if (IS_ERR(sp_task->thread)) { - dev_err(t->dev, "split thread can not create\n"); - return PTR_ERR(sp_task->thread); + if (IS_ERR(sp_task->thread)) { + dev_err(t->dev, "split thread can not create\n"); + return PTR_ERR(sp_task->thread); + } } return 0; @@ -1129,6 +1155,7 @@ static int queue_split_task(struct ipu_task_entry *t) init_waitqueue_head(&(sp_task[i].waitq)); sp_task[i].could_finish = false; sp_task[i].parent_task = t; + sp_task[i].task_no = t->task_no; } if (t->set.split_mode == RL_SPLIT) { @@ -1139,24 +1166,26 @@ static int queue_split_task(struct ipu_task_entry *t) create_split_task(DOWN_STRIPE, &sp_task[1]); } else { create_split_task(LEFT_STRIPE | UP_STRIPE, &sp_task[0]); - create_split_task(RIGHT_STRIPE | UP_STRIPE, &sp_task[1]); - create_split_task(LEFT_STRIPE | DOWN_STRIPE, &sp_task[2]); + create_split_task(LEFT_STRIPE | DOWN_STRIPE, &sp_task[1]); + create_split_task(RIGHT_STRIPE | UP_STRIPE, &sp_task[2]); create_split_task(RIGHT_STRIPE | DOWN_STRIPE, &sp_task[3]); } - for (i = 0; i < size; i++) { - sp_task[i].could_finish = true; - wake_up_interruptible(&sp_task[i].waitq); - kthread_stop(sp_task[i].thread); - if (sp_task[i].ret < 0) { - ret = sp_task[i].ret; - dev_err(t->dev, - "split task %d fail with ret %d\n", - i, ret); + /*check split task deinterlace enable*/ + if (t->input.deinterlace.enable) { + return ret; + } else { + for (i = 0; i < size; i++) { + wait_event_interruptible(sp_task[i].waitq, sp_task[i].could_finish); + if (sp_task[i].ret < 0) { + ret = sp_task[i].ret; + dev_err(t->dev, + "split task %d fail with ret %d\n", + i, ret); + } } + return ret; } - - return ret; } static struct ipu_task_entry *create_task_entry(struct ipu_task *task) @@ -1198,6 +1227,8 @@ int ipu_check_task(struct ipu_task *task) task->output = tsk->output; task->overlay = tsk->overlay; + dump_task_info(tsk); + kfree(tsk); return ret; @@ -1213,12 +1244,13 @@ int ipu_queue_sp_task(struct ipu_split_task *sp_task) if (IS_ERR(tsk)) return PTR_ERR(tsk); + tsk->task_no = sp_task->task_no; + ret = prepare_task(tsk); if (ret < 0) goto done; tsk->set.sp_setting = sp_task->parent_task->set.sp_setting; - tsk->set.sp_setting = sp_task->parent_task->set.sp_setting; ret = queue_task(tsk); done: @@ -1230,6 +1262,7 @@ int ipu_queue_task(struct ipu_task *task) { struct ipu_task_entry *tsk; int ret; + u32 tmp_task_no; tsk = create_task_entry(task); if (IS_ERR(tsk)) @@ -1239,6 +1272,10 @@ int ipu_queue_task(struct ipu_task *task) if (ret < 0) goto done; + /* task_no last for bits for split task type*/ + tmp_task_no = frame_no++ % 1024; + tsk->task_no = tmp_task_no << 4; + if (need_split(tsk)) ret = queue_split_task(tsk); else @@ -1529,7 +1566,7 @@ static int init_rot(struct ipu_soc *ipu, struct ipu_task_entry *t) in_fmt, in_width, in_height, - t->set.istride, + in_stride, t->output.rotate, inbuf, 0, @@ -1606,10 +1643,184 @@ static irqreturn_t task_irq_handler(int irq, void *dev_id) return IRQ_HANDLED; } +/* Fix deinterlace up&down split mode medium line */ +static void vdi_split_process(struct ipu_soc *ipu, struct ipu_task_entry *t) +{ + u32 vdi_size; + u32 vdi_save_lines; + u32 stripe_mode; + u32 task_no; + u32 i, offset_addr; + unsigned char *base_off; + + stripe_mode = t->task_no & 0xf; + task_no = t->task_no >> 4; + + base_off = (char *) __va(t->output.paddr); + if (base_off == NULL) { + dev_err(t->dev, "[0x%p]Falied get vitual address\n", (void *)t); + return; + } + + vdi_save_lines = (t->output.crop.h - t->set.sp_setting.ud_split_line)/2 ; + vdi_size = vdi_save_lines * t->output.crop.w * 2; + + if (vdi_save_lines <= 0) { + dev_err(t->dev, "[0x%p] vdi_save_line error\n", (void *)t); + return; + } + + /*check vditmpbuf buffer have alloced or buffer size is changed */ + if ((vdi_save_lines != old_save_lines) || (vdi_size != old_size)) { + if (vditmpbuf[0] != NULL) + kfree(vditmpbuf[0]); + if (vditmpbuf[1] != NULL) + kfree(vditmpbuf[1]); + + vditmpbuf[0] = (char *)kmalloc(vdi_size, GFP_KERNEL); + if (vditmpbuf[0] == NULL) { + dev_err(t->dev, + "[0x%p]Falied Alloc vditmpbuf[0]\n", (void *)t); + return; + } + memset(vditmpbuf[0], 0, vdi_size); + + vditmpbuf[1] = (char *)kmalloc(vdi_size, GFP_KERNEL); + if (vditmpbuf[1] == NULL) { + dev_err(t->dev, + "[0x%p]Falied Alloc vditmpbuf[1]\n", (void *)t); + return; + } + memset(vditmpbuf[1], 0, vdi_size); + + old_save_lines = vdi_save_lines; + old_size = vdi_size; + } + + /* UP stripe or UP&LEFT stripe */ + if ((stripe_mode == UP_STRIPE) || + (stripe_mode == (UP_STRIPE | LEFT_STRIPE))) { + if (!buf0filled) { + + offset_addr = t->set.o_off + + t->set.sp_setting.ud_split_line*t->set.ostride; + dmac_flush_range(base_off + offset_addr, + base_off + offset_addr + vdi_size); + outer_flush_range(t->output.paddr + offset_addr, + t->output.paddr + offset_addr + vdi_size); + + for (i = 0; i < vdi_save_lines; i++) + memcpy(vditmpbuf[0] + i*t->output.crop.w*2, + base_off + offset_addr + i*t->set.ostride, + t->output.crop.w*2); + buf0filled = true; + } else { + offset_addr = t->set.o_off + + (t->output.crop.h - vdi_save_lines)*t->set.ostride; + for (i = 0; i < vdi_save_lines; i++) + memcpy(base_off + offset_addr + i*t->set.ostride, + vditmpbuf[0] + i*t->output.crop.w*2, + t->output.crop.w*2); + + dmac_flush_range(base_off + offset_addr, + base_off + offset_addr + i*t->set.ostride); + outer_flush_range(t->output.paddr + offset_addr, + t->output.paddr + offset_addr + i*t->set.ostride); + buf0filled = false; + } + } + /*Down stripe or Down&Left stripe*/ + else if ((stripe_mode == DOWN_STRIPE) || + (stripe_mode == (DOWN_STRIPE | LEFT_STRIPE))) { + if (!buf0filled) { + offset_addr = t->set.o_off + vdi_save_lines*t->set.ostride; + dmac_flush_range(base_off + offset_addr, + base_off + offset_addr + vdi_size); + outer_flush_range(t->output.paddr + offset_addr, + t->output.paddr + offset_addr + vdi_size); + + for (i = 0; i < vdi_save_lines; i++) + memcpy(vditmpbuf[0] + i*t->output.crop.w*2, + base_off + offset_addr + i*t->set.ostride, + t->output.crop.w*2); + buf0filled = true; + } else { + offset_addr = t->set.o_off; + for (i = 0; i < vdi_save_lines; i++) + memcpy(base_off + offset_addr + i*t->set.ostride, + vditmpbuf[0] + i*t->output.crop.w*2, + t->output.crop.w*2); + + dmac_flush_range(base_off + offset_addr, + base_off + offset_addr + i*t->set.ostride); + outer_flush_range(t->output.paddr + offset_addr, + t->output.paddr + offset_addr + i*t->set.ostride); + buf0filled = false; + } + } + /*Up&Right stripe*/ + else if (stripe_mode == (UP_STRIPE | RIGHT_STRIPE)) { + if (!buf1filled) { + offset_addr = t->set.o_off + + t->set.sp_setting.ud_split_line*t->set.ostride; + dmac_flush_range(base_off + offset_addr, + base_off + offset_addr + vdi_size); + outer_flush_range(t->output.paddr + offset_addr, + t->output.paddr + offset_addr + vdi_size); + + for (i = 0; i < vdi_save_lines; i++) + memcpy(vditmpbuf[1] + i*t->output.crop.w*2, + base_off + offset_addr + i*t->set.ostride, + t->output.crop.w*2); + buf1filled = true; + } else { + offset_addr = t->set.o_off + + (t->output.crop.h - vdi_save_lines)*t->set.ostride; + for (i = 0; i < vdi_save_lines; i++) + memcpy(base_off + offset_addr + i*t->set.ostride, + vditmpbuf[1] + i*t->output.crop.w*2, + t->output.crop.w*2); + + dmac_flush_range(base_off + offset_addr, + base_off + offset_addr + i*t->set.ostride); + outer_flush_range(t->output.paddr + offset_addr, + t->output.paddr + offset_addr + i*t->set.ostride); + buf1filled = false; + } + } + /*Down stripe or Down&Right stript*/ + else if (stripe_mode == (DOWN_STRIPE | RIGHT_STRIPE)) { + if (!buf1filled) { + offset_addr = t->set.o_off + vdi_save_lines*t->set.ostride; + dmac_flush_range(base_off + offset_addr, + base_off + offset_addr + vdi_save_lines*t->set.ostride); + outer_flush_range(t->output.paddr + offset_addr, + t->output.paddr + offset_addr + vdi_save_lines*t->set.ostride); + + for (i = 0; i < vdi_save_lines; i++) + memcpy(vditmpbuf[1] + i*t->output.crop.w*2, + base_off + offset_addr + i*t->set.ostride, + t->output.crop.w*2); + buf1filled = true; + } else { + offset_addr = t->set.o_off; + for (i = 0; i < vdi_save_lines; i++) + memcpy(base_off + offset_addr + i*t->set.ostride, + vditmpbuf[1] + i*t->output.crop.w*2, + t->output.crop.w*2); + + dmac_flush_range(base_off + offset_addr, + base_off + offset_addr + vdi_save_lines*t->set.ostride); + outer_flush_range(t->output.paddr + offset_addr, + t->output.paddr + offset_addr + vdi_save_lines*t->set.ostride); + buf1filled = false; + } + } +} + static void do_task(struct ipu_soc *ipu, struct ipu_task_entry *t) { struct completion comp; - void *r_vaddr; int r_size; int irq; int ret; @@ -1657,6 +1868,8 @@ static void do_task(struct ipu_soc *ipu, struct ipu_task_entry *t) if (ret < 0) goto chan_done; } else if (ic_and_rot(t->set.mode)) { + int rot_idx = (t->task_id == IPU_TASK_ID_VF) ? 0 : 1; + dev_dbg(t->dev, "[0x%p]ic + rot mode\n", (void *)t); t->set.r_fmt = t->output.format; if (t->output.rotate >= IPU_ROTATE_90_RIGHT) { @@ -1668,16 +1881,29 @@ static void do_task(struct ipu_soc *ipu, struct ipu_task_entry *t) } t->set.r_stride = t->set.r_width * bytes_per_pixel(t->set.r_fmt); - r_size = t->set.r_width * t->set.r_height - * fmt_to_bpp(t->set.r_fmt)/8; - r_vaddr = dma_alloc_coherent(t->dev, - r_size, - &t->set.r_paddr, - GFP_DMA | GFP_KERNEL); - if (r_vaddr == NULL) { - ret = -ENOMEM; - goto chan_done; + r_size = PAGE_ALIGN(t->set.r_width * t->set.r_height + * fmt_to_bpp(t->set.r_fmt)/8); + + if (r_size > ipu->rot_dma[rot_idx].size) { + dev_dbg(t->dev, "[0x%p]realloc rot buffer\n", (void *)t); + + if (ipu->rot_dma[rot_idx].vaddr) + dma_free_coherent(t->dev, + ipu->rot_dma[rot_idx].size, + ipu->rot_dma[rot_idx].vaddr, + ipu->rot_dma[rot_idx].paddr); + + ipu->rot_dma[rot_idx].size = r_size; + ipu->rot_dma[rot_idx].vaddr = dma_alloc_coherent(t->dev, + r_size, + &ipu->rot_dma[rot_idx].paddr, + GFP_DMA | GFP_KERNEL); + if (ipu->rot_dma[rot_idx].vaddr == NULL) { + ret = -ENOMEM; + goto chan_done; + } } + t->set.r_paddr = ipu->rot_dma[rot_idx].paddr; dev_dbg(t->dev, "[0x%p]rotation:\n", (void *)t); dev_dbg(t->dev, "[0x%p]\tformat = 0x%x\n", (void *)t, t->set.r_fmt); @@ -1703,6 +1929,7 @@ static void do_task(struct ipu_soc *ipu, struct ipu_task_entry *t) return; } + /* channel setup */ /* irq setup */ irq = get_irq(t); if (irq < 0) { @@ -1755,17 +1982,22 @@ static void do_task(struct ipu_soc *ipu, struct ipu_task_entry *t) if (t->overlay.alpha.mode == IPU_ALPHA_MODE_LOCAL) ipu_select_buffer(ipu, t->set.ic_chan, IPU_ALPHA_IN_BUFFER, 0); } + ipu_select_buffer(ipu, t->set.ic_chan, IPU_OUTPUT_BUFFER, 0); if (deinterlace_3_field(t)) ipu_select_multi_vdi_buffer(ipu, 0); else ipu_select_buffer(ipu, t->set.ic_chan, IPU_INPUT_BUFFER, 0); - ipu_select_buffer(ipu, t->set.ic_chan, IPU_OUTPUT_BUFFER, 0); } ret = wait_for_completion_timeout(&comp, msecs_to_jiffies(t->timeout)); if (ret == 0) t->state = STATE_IRQ_TIMEOUT; + /* split mode and VDI mode */ + if (t->input.deinterlace.enable && + (t->task_no & (UP_STRIPE | DOWN_STRIPE))) + vdi_split_process(ipu, t); + ipu_free_irq(ipu, irq, &comp); if (only_ic(t->set.mode)) { @@ -1777,12 +2009,13 @@ static void do_task(struct ipu_soc *ipu, struct ipu_task_entry *t) } else if (only_rot(t->set.mode)) ipu_disable_channel(ipu, t->set.rot_chan, true); else if (ic_and_rot(t->set.mode)) { + ipu_unlink_channels(ipu, t->set.ic_chan, t->set.rot_chan); + ipu_disable_channel(ipu, t->set.rot_chan, true); ipu_disable_channel(ipu, t->set.ic_chan, true); if (deinterlace_3_field(t)) { ipu_disable_channel(ipu, t->set.vdi_ic_p_chan, true); ipu_disable_channel(ipu, t->set.vdi_ic_n_chan, true); } - ipu_disable_channel(ipu, t->set.rot_chan, true); } chan_done: @@ -1791,15 +2024,8 @@ chan_done: else if (only_rot(t->set.mode)) uninit_rot(ipu, t); else if (ic_and_rot(t->set.mode)) { - ipu_unlink_channels(ipu, t->set.ic_chan, - t->set.rot_chan); uninit_ic(ipu, t); uninit_rot(ipu, t); - if (r_vaddr) - dma_free_coherent(t->dev, - r_size, - r_vaddr, - t->set.r_paddr); } return; } @@ -2008,7 +2234,7 @@ static struct file_operations mxc_ipu_fops = { int register_ipu_device(struct ipu_soc *ipu, int id) { - int ret = 0; + int i, ret = 0; if (!major) { major = register_chrdev(0, "mxc_ipu", &mxc_ipu_fops); @@ -2035,12 +2261,14 @@ int register_ipu_device(struct ipu_soc *ipu, int id) ipu_dev->coherent_dma_mask = DMA_BIT_MASK(32); } - INIT_LIST_HEAD(&ipu->task_list[0]); - INIT_LIST_HEAD(&ipu->task_list[1]); - init_waitqueue_head(&ipu->waitq[0]); - init_waitqueue_head(&ipu->waitq[1]); - mutex_init(&ipu->task_lock[0]); - mutex_init(&ipu->task_lock[1]); + for (i = 0; i < 2; i++) { + INIT_LIST_HEAD(&ipu->task_list[i]); + init_waitqueue_head(&ipu->waitq[i]); + mutex_init(&ipu->task_lock[i]); + + ipu->rot_dma[i].size = 0; + } + ipu->thread[0] = kthread_run(task_vf_thread, ipu, "ipu%d_process-vf", id); if (IS_ERR(ipu->thread[0])) { @@ -2076,8 +2304,19 @@ register_cdev_fail: void unregister_ipu_device(struct ipu_soc *ipu, int id) { + int i; + kthread_stop(ipu->thread[0]); kthread_stop(ipu->thread[1]); + + for (i = 0; i < 2; i++) { + if (ipu->rot_dma[i].vaddr) + dma_free_coherent(ipu_dev, + ipu->rot_dma[i].size, + ipu->rot_dma[i].vaddr, + ipu->rot_dma[i].paddr); + } + if (major) { device_destroy(ipu_class, MKDEV(major, 0)); class_destroy(ipu_class); diff --git a/drivers/mxc/ipu3/ipu_disp.c b/drivers/mxc/ipu3/ipu_disp.c index 9094fc64f10..e9585e0e1a7 100644 --- a/drivers/mxc/ipu3/ipu_disp.c +++ b/drivers/mxc/ipu3/ipu_disp.c @@ -26,6 +26,7 @@ #include <linux/io.h> #include <linux/clk.h> #include <linux/err.h> +#include <linux/export.h> #include <asm/atomic.h> #include <mach/clock.h> #include <mach/ipu-v3.h> @@ -59,7 +60,12 @@ static inline struct ipu_soc *pixelclk2ipu(struct clk *clk) static unsigned long _ipu_pixel_clk_get_rate(struct clk *clk) { struct ipu_soc *ipu = pixelclk2ipu(clk); - u32 div = ipu_di_read(ipu, clk->id, DI_BS_CLKGEN0); + u32 div; + + _ipu_get(ipu); + div = ipu_di_read(ipu, clk->id, DI_BS_CLKGEN0); + _ipu_put(ipu); + if (div == 0) return 0; return (clk_get_rate(clk->parent) * 16) / div; @@ -1119,7 +1125,7 @@ void ipu_set_csc_coefficients(struct ipu_soc *ipu, ipu_channel_t channel, int32_ { _ipu_dp_set_csc_coefficients(ipu, channel, param); } -EXPORT_SYMBOL(ipu_set_csc_coefficients); +EXPORT_SYMBOL_GPL(ipu_set_csc_coefficients); /*! * This function is called to adapt synchronous LCD panel to IPU restriction. @@ -1656,7 +1662,7 @@ int32_t ipu_init_sync_panel(struct ipu_soc *ipu, int disp, uint32_t pixel_clk, return 0; } -EXPORT_SYMBOL(ipu_init_sync_panel); +EXPORT_SYMBOL_GPL(ipu_init_sync_panel); void ipu_uninit_sync_panel(struct ipu_soc *ipu, int disp) { @@ -1678,7 +1684,7 @@ void ipu_uninit_sync_panel(struct ipu_soc *ipu, int disp) _ipu_unlock(ipu); } -EXPORT_SYMBOL(ipu_uninit_sync_panel); +EXPORT_SYMBOL_GPL(ipu_uninit_sync_panel); int ipu_init_async_panel(struct ipu_soc *ipu, int disp, int type, uint32_t cycle_time, uint32_t pixel_fmt, ipu_adc_sig_cfg_t sig) @@ -1728,7 +1734,7 @@ int ipu_init_async_panel(struct ipu_soc *ipu, int disp, int type, uint32_t cycle _ipu_unlock(ipu); return 0; } -EXPORT_SYMBOL(ipu_init_async_panel); +EXPORT_SYMBOL_GPL(ipu_init_async_panel); /*! * This function sets the foreground and background plane global alpha blending @@ -1800,7 +1806,7 @@ int32_t ipu_disp_set_global_alpha(struct ipu_soc *ipu, ipu_channel_t channel, return 0; } -EXPORT_SYMBOL(ipu_disp_set_global_alpha); +EXPORT_SYMBOL_GPL(ipu_disp_set_global_alpha); /*! * This function sets the transparent color key for SDC graphic plane. @@ -1877,7 +1883,7 @@ int32_t ipu_disp_set_color_key(struct ipu_soc *ipu, ipu_channel_t channel, return 0; } -EXPORT_SYMBOL(ipu_disp_set_color_key); +EXPORT_SYMBOL_GPL(ipu_disp_set_color_key); /*! * This function sets the gamma correction for DP output. @@ -1935,7 +1941,7 @@ int32_t ipu_disp_set_gamma_correction(struct ipu_soc *ipu, ipu_channel_t channel return 0; } -EXPORT_SYMBOL(ipu_disp_set_gamma_correction); +EXPORT_SYMBOL_GPL(ipu_disp_set_gamma_correction); /*! * This function sets the window position of the foreground or background plane. @@ -1999,7 +2005,7 @@ int32_t ipu_disp_set_window_pos(struct ipu_soc *ipu, ipu_channel_t channel, _ipu_put(ipu); return ret; } -EXPORT_SYMBOL(ipu_disp_set_window_pos); +EXPORT_SYMBOL_GPL(ipu_disp_set_window_pos); int32_t _ipu_disp_get_window_pos(struct ipu_soc *ipu, ipu_channel_t channel, int16_t *x_pos, int16_t *y_pos) @@ -2035,7 +2041,7 @@ int32_t ipu_disp_get_window_pos(struct ipu_soc *ipu, ipu_channel_t channel, _ipu_put(ipu); return ret; } -EXPORT_SYMBOL(ipu_disp_get_window_pos); +EXPORT_SYMBOL_GPL(ipu_disp_get_window_pos); void ipu_disp_direct_write(struct ipu_soc *ipu, ipu_channel_t channel, u32 value, u32 offset) { @@ -2044,7 +2050,7 @@ void ipu_disp_direct_write(struct ipu_soc *ipu, ipu_channel_t channel, u32 value else if (channel == DIRECT_ASYNC1) writel(value, ipu->disp_base[1] + offset); } -EXPORT_SYMBOL(ipu_disp_direct_write); +EXPORT_SYMBOL_GPL(ipu_disp_direct_write); void ipu_reset_disp_panel(struct ipu_soc *ipu) { @@ -2059,7 +2065,7 @@ void ipu_reset_disp_panel(struct ipu_soc *ipu) return; } -EXPORT_SYMBOL(ipu_reset_disp_panel); +EXPORT_SYMBOL_GPL(ipu_reset_disp_panel); void __devinit ipu_disp_init(struct ipu_soc *ipu) { diff --git a/drivers/mxc/ipu3/ipu_ic.c b/drivers/mxc/ipu3/ipu_ic.c index 7387e518deb..7712bc5c659 100644 --- a/drivers/mxc/ipu3/ipu_ic.c +++ b/drivers/mxc/ipu3/ipu_ic.c @@ -24,6 +24,7 @@ #include <linux/spinlock.h> #include <linux/videodev2.h> #include <linux/io.h> +#include <linux/export.h> #include <mach/ipu-v3.h> #include "ipu_prv.h" diff --git a/drivers/mxc/ipu3/ipu_param_mem.h b/drivers/mxc/ipu3/ipu_param_mem.h index 7fbd4e12d0f..223a1cdf5fa 100644 --- a/drivers/mxc/ipu3/ipu_param_mem.h +++ b/drivers/mxc/ipu3/ipu_param_mem.h @@ -653,6 +653,7 @@ static inline void _ipu_ch_offset_update(struct ipu_soc *ipu, { uint32_t u_offset = 0; uint32_t v_offset = 0; + uint32_t old_offset = 0; uint32_t u_fix = 0; uint32_t v_fix = 0; int32_t sub_ch = 0; @@ -788,14 +789,22 @@ static inline void _ipu_ch_offset_update(struct ipu_soc *ipu, dev_warn(ipu->dev, "IDMAC%d's V offset is not 8-byte aligned\n", ch); - ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 0, 46, 22, u_offset / 8); - ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 0, 68, 22, v_offset / 8); + old_offset = ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 0, 46, 22); + if (old_offset != u_offset / 8) + ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 0, 46, 22, u_offset / 8); + old_offset = ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 0, 68, 22); + if (old_offset != v_offset / 8) + ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 0, 68, 22, v_offset / 8); sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch); if (sub_ch <= 0) return; - ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 0, 46, 22, u_offset / 8); - ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 0, 68, 22, v_offset / 8); + old_offset = ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, sub_ch), 0, 46, 22); + if (old_offset != u_offset / 8) + ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 0, 46, 22, u_offset / 8); + old_offset = ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, sub_ch), 0, 68, 22); + if (old_offset != v_offset / 8) + ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 0, 68, 22, v_offset / 8); }; static inline void _ipu_ch_params_set_alpha_width(struct ipu_soc *ipu, uint32_t ch, int alpha_width) diff --git a/drivers/mxc/ipu3/ipu_prv.h b/drivers/mxc/ipu3/ipu_prv.h index 7a17a0ea4d0..42060c954a1 100644 --- a/drivers/mxc/ipu3/ipu_prv.h +++ b/drivers/mxc/ipu3/ipu_prv.h @@ -132,6 +132,11 @@ struct ipu_soc { struct mutex task_lock[2]; wait_queue_head_t waitq[2]; struct task_struct *thread[2]; + struct rot_mem { + void *vaddr; + dma_addr_t paddr; + int size; + } rot_dma[2]; }; struct ipu_channel { @@ -314,6 +319,7 @@ int _ipu_ic_idma_init(struct ipu_soc *ipu, int dma_chan, uint16_t width, uint16_ int burst_size, ipu_rotate_mode_t rot); void _ipu_vdi_toggle_top_field_man(struct ipu_soc *ipu); int _ipu_csi_init(struct ipu_soc *ipu, ipu_channel_t channel, uint32_t csi); +int _ipu_csi_set_mipi_di(struct ipu_soc *ipu, uint32_t num, uint32_t di_val, uint32_t csi); void ipu_csi_set_test_generator(struct ipu_soc *ipu, bool active, uint32_t r_value, uint32_t g_value, uint32_t b_value, uint32_t pix_clk, uint32_t csi); diff --git a/include/linux/ipu.h b/include/linux/ipu.h index d6c1588b82c..05162485455 100644 --- a/include/linux/ipu.h +++ b/include/linux/ipu.h @@ -138,6 +138,12 @@ typedef enum { /*! @} */ /* IPU device */ +typedef enum { + RGB_CS, + YUV_CS, + NULL_CS +} cs_t; + struct ipu_pos { u32 x; u32 y; @@ -237,6 +243,7 @@ enum { IPU_CHECK_ERR_SPLIT_INPUTH_OVER, IPU_CHECK_ERR_SPLIT_OUTPUTW_OVER, IPU_CHECK_ERR_SPLIT_OUTPUTH_OVER, + IPU_CHECK_ERR_SPLIT_WITH_ROT, }; /* IOCTL commands */ @@ -245,4 +252,14 @@ enum { #define IPU_ALLOC _IOWR('I', 0x3, int) #define IPU_FREE _IOW('I', 0x4, int) +/* export functions */ +#ifdef __KERNEL__ +unsigned int fmt_to_bpp(unsigned int pixelformat); +cs_t colorspaceofpixel(int fmt); +int need_csc(int ifmt, int ofmt); + +int ipu_queue_task(struct ipu_task *task); +int ipu_check_task(struct ipu_task *task); +#endif + #endif |