[PATCH 4/6] v4l: ti-vpe: Add de-interlacer support in VPE

2013-08-02 Thread Archit Taneja
Add support for the de-interlacer block in VPE.

For de-interlacer to work, we need to enable 2 more sets of VPE input ports
which fetch data from the 'last' and 'last to last' fields of the interlaced
video. Apart from that, we need to enable the Motion vector output and input
ports, and also allocate DMA buffers for them.

We need to make sure that two most recent fields in the source queue are
available and in the 'READY' state. Once a mem2mem context gets access to the
VPE HW(in device_run), it extracts the addresses of the 3 buffers, and provides
it to the data descriptors for the 3 sets of input ports((LUMA1, CHROMA1),
(LUMA2, CHROMA2), and (LUMA3, CHROMA3)) respectively for the 3 consecutive
fields. The motion vector and output port descriptors are configured and the
list is submitted to VPDMA.

Once the transaction is done, the v4l2 buffer corresponding to the oldest
field(the 3rd one) is changed to the state 'DONE', and the buffers corresponding
to 1st and 2nd fields become the 2nd and 3rd field for the next de-interlace
operation. This way, for each deinterlace operation, we have the 3 most recent
fields. After each transaction, we also swap the motion vector buffers, the new
input motion vector buffer contains the resultant motion information of all the
previous frames, and the new output motion vector buffer will be used to hold
the updated motion vector to capture the motion changes in the next field.

The de-interlacer is removed from bypass mode, it requires some extra default
configurations which are now added. The chrominance upsampler coefficients are
added for interlaced frames. Some VPDMA parameters like frame start event and
line mode are configured for the 2 extra sets of input ports.

Signed-off-by: Archit Taneja arc...@ti.com
---
 drivers/media/platform/ti-vpe/vpe.c | 372 
 1 file changed, 337 insertions(+), 35 deletions(-)

diff --git a/drivers/media/platform/ti-vpe/vpe.c 
b/drivers/media/platform/ti-vpe/vpe.c
index 14a292b..5b1410c 100644
--- a/drivers/media/platform/ti-vpe/vpe.c
+++ b/drivers/media/platform/ti-vpe/vpe.c
@@ -69,6 +69,8 @@
 #define VPE_CHROMA 1
 
 /* per m2m context info */
+#define VPE_MAX_SRC_BUFS   3   /* need 3 src fields to de-interlace */
+
 #define VPE_DEF_BUFS_PER_JOB   1   /* default one buffer per batch job */
 
 /*
@@ -104,12 +106,44 @@ struct vpe_us_coeffs {
 /*
  * Default upsampler coefficients
  */
-static struct vpe_us_coeffs us_coeffs[] = {
+static struct vpe_us_coeffs us_coeffs[2] = {
{
/* Coefficients for progressive input */
0x00C8, 0x0348, 0x0018, 0x3FD8, 0x3FB8, 0x0378, 0x00E8, 0x3FE8,
0x00C8, 0x0348, 0x0018, 0x3FD8, 0x3FB8, 0x0378, 0x00E8, 0x3FE8,
},
+   {
+   /* Coefficients for Top Field Interlaced input */
+   0x0051, 0x03D5, 0x3FE3, 0x3FF7, 0x3FB5, 0x02E9, 0x018F, 0x3FD3,
+   /* Coefficients for Bottom Field Interlaced input */
+   0x016B, 0x0247, 0x00B1, 0x3F9D, 0x3FCF, 0x03DB, 0x005D, 0x3FF9,
+   },
+};
+
+/*
+ * the following registers are for configuring some of the parameters of the
+ * motion and edge detection blocks inside DEI, these generally remain the 
same,
+ * these could be passed later via userspace if some one needs to tweak these.
+ */
+struct vpe_dei_regs {
+   unsigned long mdt_spacial_freq_thr_reg; /* VPE_DEI_REG2 */
+   unsigned long edi_config_reg;   /* VPE_DEI_REG3 */
+   unsigned long edi_lut_reg0; /* VPE_DEI_REG4 */
+   unsigned long edi_lut_reg1; /* VPE_DEI_REG5 */
+   unsigned long edi_lut_reg2; /* VPE_DEI_REG6 */
+   unsigned long edi_lut_reg3; /* VPE_DEI_REG7 */
+};
+
+/*
+ * default expert DEI register values, unlikely to be modified.
+ */
+static struct vpe_dei_regs dei_regs = {
+   0x020C0804u,
+   0x0118100Fu,
+   0x08040200u,
+   0x1010100Cu,
+   0x10101010u,
+   0x10101010u,
 };
 
 /*
@@ -117,6 +151,7 @@ static struct vpe_us_coeffs us_coeffs[] = {
  */
 struct vpe_port_data {
enum vpdma_channel channel; /* VPDMA channel */
+   u8  vb_index;   /* input frame f, f-1, f-2 index */
u8  vb_part;/* plane index for co-panar formats */
 };
 
@@ -125,6 +160,12 @@ struct vpe_port_data {
  */
 #define VPE_PORT_LUMA1_IN  0
 #define VPE_PORT_CHROMA1_IN1
+#define VPE_PORT_LUMA2_IN  2
+#define VPE_PORT_CHROMA2_IN3
+#define VPE_PORT_LUMA3_IN  4
+#define VPE_PORT_CHROMA3_IN5
+#define VPE_PORT_MV_IN 6
+#define VPE_PORT_MV_OUT7
 #define VPE_PORT_LUMA_OUT  8
 #define VPE_PORT_CHROMA_OUT9
 #define VPE_PORT_RGB_OUT   10
@@ -132,12 +173,40 @@ struct vpe_port_data {
 static struct vpe_port_data port_data[11] = {
[VPE_PORT_LUMA1_IN] = {
.channel= 

Re: [PATCH 4/6] v4l: ti-vpe: Add de-interlacer support in VPE

2013-08-02 Thread Hans Verkuil
More comments...

On 08/02/2013 04:03 PM, Archit Taneja wrote:
 Add support for the de-interlacer block in VPE.
 
 For de-interlacer to work, we need to enable 2 more sets of VPE input ports
 which fetch data from the 'last' and 'last to last' fields of the interlaced
 video. Apart from that, we need to enable the Motion vector output and input
 ports, and also allocate DMA buffers for them.
 
 We need to make sure that two most recent fields in the source queue are
 available and in the 'READY' state. Once a mem2mem context gets access to the
 VPE HW(in device_run), it extracts the addresses of the 3 buffers, and 
 provides
 it to the data descriptors for the 3 sets of input ports((LUMA1, CHROMA1),
 (LUMA2, CHROMA2), and (LUMA3, CHROMA3)) respectively for the 3 consecutive
 fields. The motion vector and output port descriptors are configured and the
 list is submitted to VPDMA.
 
 Once the transaction is done, the v4l2 buffer corresponding to the oldest
 field(the 3rd one) is changed to the state 'DONE', and the buffers 
 corresponding
 to 1st and 2nd fields become the 2nd and 3rd field for the next de-interlace
 operation. This way, for each deinterlace operation, we have the 3 most recent
 fields. After each transaction, we also swap the motion vector buffers, the 
 new
 input motion vector buffer contains the resultant motion information of all 
 the
 previous frames, and the new output motion vector buffer will be used to hold
 the updated motion vector to capture the motion changes in the next field.
 
 The de-interlacer is removed from bypass mode, it requires some extra default
 configurations which are now added. The chrominance upsampler coefficients are
 added for interlaced frames. Some VPDMA parameters like frame start event and
 line mode are configured for the 2 extra sets of input ports.
 
 Signed-off-by: Archit Taneja arc...@ti.com
 ---
  drivers/media/platform/ti-vpe/vpe.c | 372 
 
  1 file changed, 337 insertions(+), 35 deletions(-)
 
 diff --git a/drivers/media/platform/ti-vpe/vpe.c 
 b/drivers/media/platform/ti-vpe/vpe.c
 index 14a292b..5b1410c 100644
 --- a/drivers/media/platform/ti-vpe/vpe.c
 +++ b/drivers/media/platform/ti-vpe/vpe.c

...

 @@ -1035,7 +1310,8 @@ static int __vpe_try_fmt(struct vpe_ctx *ctx, struct 
 v4l2_format *f,
  
   if (pix-field == V4L2_FIELD_ANY)
   pix-field = V4L2_FIELD_NONE;
 - else if (V4L2_FIELD_NONE != pix-field)
 + else if (V4L2_FIELD_NONE != pix-field 
 + V4L2_FIELD_ALTERNATE != pix-field)
   return -EINVAL;

As mentioned before, this shouldn't result in an error, but map to a valid
field format.

For a deinterlacer I would expect NONE for the output of the deinterlacer (or
capture buffer type) and ALTERNATE for the input of the deinterlacer (or output
buffer type).

  
   v4l_bound_align_image(pix-width, MIN_W, MAX_W, W_ALIGN,
 @@ -1104,6 +1380,7 @@ static int __vpe_s_fmt(struct vpe_ctx *ctx, struct 
 v4l2_format *f)
   q_data-width   = pix-width;
   q_data-height  = pix-height;
   q_data-colorspace  = pix-colorspace;
 + q_data-field   = pix-field;
  
   for (i = 0; i  pix-num_planes; i++) {
   plane_fmt = pix-plane_fmt[i];
 @@ -1117,6 +1394,11 @@ static int __vpe_s_fmt(struct vpe_ctx *ctx, struct 
 v4l2_format *f)
   q_data-c_rect.width= q_data-width;
   q_data-c_rect.height   = q_data-height;
  
 + if (q_data-field == V4L2_FIELD_ALTERNATE)
 + q_data-flags |= Q_DATA_INTERLACED;
 + else
 + q_data-flags = ~Q_DATA_INTERLACED;
 +
   vpe_dbg(ctx-dev, Setting format for type %d, wxh: %dx%d, fmt: %d 
 bpl_y %d,
   f-type, q_data-width, q_data-height, q_data-fmt-fourcc,
   q_data-bytesperline[VPE_LUMA]);
 @@ -1194,6 +1476,22 @@ static int vpe_streamoff(struct file *file, void 
 *priv, enum v4l2_buf_type type)
   return v4l2_m2m_streamoff(file, ctx-m2m_ctx, type);
  }
  
 +static void set_dei_shadow_registers(struct vpe_ctx *ctx)
 +{
 + struct vpe_mmr_adb *mmr_adb = ctx-mmr_adb.addr;
 + u32 *dei_mmr = mmr_adb-dei_regs[0];
 + struct vpe_dei_regs *cur = dei_regs;
 +
 + dei_mmr[2]  = cur-mdt_spacial_freq_thr_reg;
 + dei_mmr[3]  = cur-edi_config_reg;
 + dei_mmr[4]  = cur-edi_lut_reg0;
 + dei_mmr[5]  = cur-edi_lut_reg1;
 + dei_mmr[6]  = cur-edi_lut_reg2;
 + dei_mmr[7]  = cur-edi_lut_reg3;
 +
 + ctx-load_mmrs = true;
 +}
 +
  #define V4L2_CID_TRANS_NUM_BUFS  (V4L2_CID_USER_BASE)
  
  static int vpe_s_ctrl(struct v4l2_ctrl *ctrl)
 @@ -1425,6 +1723,7 @@ static int vpe_open(struct file *file)
   s_q_data-sizeimage[VPE_LUMA] = (s_q_data-width * s_q_data-height *
   s_q_data-fmt-vpdma_fmt[VPE_LUMA]-depth)  3;
   s_q_data-colorspace = V4L2_COLORSPACE_SMPTE240M;
 + s_q_data-field = V4L2_FIELD_NONE;
   s_q_data-c_rect.left = 0;
   s_q_data-c_rect.top =