aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Chen <b02280@freescale.com>2011-11-23 14:42:24 +0800
committerEric Miao <eric.miao@linaro.org>2011-12-02 14:41:50 +0800
commit5a5a3b462dfad82dfb4a9b86d3fe37e12842893e (patch)
treeb867a04d4551768cce9431973e9db05578c5c867
parent2a842a14fc361cc45d187214f0ef8e4fd511126a (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/Kconfig10
-rw-r--r--arch/arm/plat-mxc/devices/platform-imx_ipuv3.c1
-rw-r--r--arch/arm/plat-mxc/include/mach/ipu-v3.h61
-rw-r--r--drivers/mxc/Kconfig5
-rw-r--r--drivers/mxc/ipu3/ipu_calc_stripes_sizes.c14
-rw-r--r--drivers/mxc/ipu3/ipu_capture.c13
-rw-r--r--drivers/mxc/ipu3/ipu_common.c78
-rw-r--r--drivers/mxc/ipu3/ipu_device.c381
-rw-r--r--drivers/mxc/ipu3/ipu_disp.c30
-rw-r--r--drivers/mxc/ipu3/ipu_ic.c1
-rw-r--r--drivers/mxc/ipu3/ipu_param_mem.h17
-rw-r--r--drivers/mxc/ipu3/ipu_prv.h6
-rw-r--r--include/linux/ipu.h17
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