About IPU CSI->VDI->MEM channel question on Imx53 Platform

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

About IPU CSI->VDI->MEM channel question on Imx53 Platform

2,932 Views
JianqingChen
Contributor II

Now,I am working at using the channel CSI->VDI->MEM in order to de-interlace video.However,there is no source about IPU's capture flows CSI->VDI->MEM channel in kernel_imx/drivers/media/video/mxc/capture file,only something about CSI0->SMFC->MEM channel.From the IMX53RM(2,12/2011) Manual page 2782 table 45-28,there has a tasks chain CSIO->VDIC->MEM,other input is IDMAC_CH_9 and IDMAC_CH_10, output is IDMAC_CH_5 and IDMAC_CH_13.But I don't know how to use it.I programed about this channel,but it doesn't work.Please give me something advices or reference resources for how to use the channel.Then please send to my email"568075896@qq.com".

this is my source ,but it doesn't working,and printf "ERROR: v4l2 capture: mxc_v4l_dqueue timeout enc_counter 0".


/*!
 * @file ipu_vdi_enc.c
 *
 * @brief IPU Use case for VDI-ENC
 *
 * @ingroup IPU
 */

#include <linux/dma-mapping.h>
#include <linux/ipu.h>
#include "mxc_v4l2_capture.h"
#include "ipu_prp_sw.h"

#ifdef CAMERA_DBG
 #define CAMERA_TRACE(x) (printk)x
#else
 #define CAMERA_TRACE(x)
#endif

static ipu_rotate_mode_t grotation = IPU_ROTATE_NONE;

/*
 * Function definitions
 */

/*!
 * IPU ENC callback function.
 *
 * @param irq       int irq line
 * @param dev_id    void * device id
 *
 * @return status   IRQ_HANDLED for handled
 */
static irqreturn_t vdi_enc_callback(int irq, void *dev_id)
{
 cam_data *cam = (cam_data *) dev_id;

 if (cam->enc_callback == NULL)
  return IRQ_HANDLED;

 cam->enc_callback(irq, dev_id);

 return IRQ_HANDLED;
}

 

/*!
 * PrpENC enable channel setup function
 *
 * @param cam       struct cam_data * mxc capture instance
 *
 * @return  status
 */
 #if 1
static int vdi_enc_setup(cam_data *cam)
{     printk("===aa============0529 %s\n",__FUNCTION__);
 ipu_channel_params_t enc;
 int err = 0;
 dma_addr_t dummy = 0xdeadbeaf;

 CAMERA_TRACE("In prp_enc_setup\n");
 if (!cam) {
  printk(KERN_ERR "cam private is NULL\n");
  return -ENXIO;
 }
 memset(&enc, 0, sizeof(ipu_channel_params_t));

 ipu_csi_get_window_size(&enc.csi_prp_enc_mem.in_width,
    &enc.csi_prp_enc_mem.in_height, cam->csi);

 enc.csi_prp_enc_mem.in_pixel_fmt = IPU_PIX_FMT_UYVY;
 enc.csi_prp_enc_mem.out_width = cam->v2f.fmt.pix.width;
 enc.csi_prp_enc_mem.out_height =cam->v2f.fmt.pix.height;
 enc.csi_prp_enc_mem.csi = cam->csi;
/* if (cam->rotation >= IPU_ROTATE_90_RIGHT) {
  enc.csi_prp_enc_mem.out_width = cam->v2f.fmt.pix.height;
  enc.csi_prp_enc_mem.out_height = cam->v2f.fmt.pix.width;
 }*/

 if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUV420) {
  enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_YUV420P;
  pr_info("YUV420\n");
 } else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUV422P) {
  enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_YUV422P;
  pr_info("YUV422P\n");
 } else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV) {
  enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_YUYV;
  pr_info("YUYV\n");
 } else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_UYVY) {
  enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_UYVY;
  pr_info("UYVY\n");
 } else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_NV12) {
  enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_NV12;
  pr_info("NV12\n");
 } else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_BGR24) {
  enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_BGR24;
  pr_info("BGR24\n");
 } else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_RGB24) {
  enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_RGB24;
  pr_info("RGB24\n");
 } else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_RGB565) {
  enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_RGB565;
  pr_info("RGB565\n");
 } else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_BGR32) {
  enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_BGR32;
  pr_info("BGR32\n");
 } else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_RGB32) {
  enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_RGB32;
  pr_info("RGB32\n");
 } else {
  printk(KERN_ERR "format not supported\n");
  return -EINVAL;
 }

 if (ipu_init_channel(MEM_VDI_PRP_VF_MEM, &enc) != 0) {
  printk( "Error initializing VDI current channel\n");
  return -EINVAL;
 }

  if (ipu_init_channel(MEM_VDI_PRP_VF_MEM_N, &enc) != 0) {
   printk("Error initializing VDI next channel\n");
   return -EINVAL;
  }


    /*
 err = ipu_init_channel(CSI_PRP_ENC_MEM, &enc);
 if (err != 0) {
  printk(KERN_ERR "ipu_init_channel %d\n", err);
  return err;
 }*/

 ipu_csi_enable_mclk_if(CSI_MCLK_ENC, cam->csi, true, true);

 grotation = cam->rotation;

printk(" enc.csi_prp_enc_mem.out_pixel_fmt = %d,\
 enc.csi_prp_enc_mem.out_width = %d,\
  enc.csi_prp_enc_mem.out_height = %d,\
 cam->v2f.fmt.pix.bytesperline / bytes_per_pixel(enc.csi_prp_enc_mem.out_pixel_fmt)= %d,\
cam->rotation = %d,\
cam->offset.u_offset = %d,\
cam->offset.v_offset = %d\n ",enc.csi_prp_enc_mem.out_pixel_fmt, enc.csi_prp_enc_mem.out_width,  enc.csi_prp_enc_mem.out_height,\
 cam->v2f.fmt.pix.bytesperline / bytes_per_pixel(enc.csi_prp_enc_mem.out_pixel_fmt),\
 cam->rotation,cam->offset.u_offset,cam->offset.v_offset);

   /*     err = ipu_init_channel_buffer(CSI_PRP_ENC_MEM, IPU_OUTPUT_BUFFER,
         enc.csi_prp_enc_mem.out_pixel_fmt,
         enc.csi_prp_enc_mem.out_width,
         enc.csi_prp_enc_mem.out_height,
         cam->v2f.fmt.pix.bytesperline /
         bytes_per_pixel(enc.csi_prp_enc_mem.
           out_pixel_fmt),
         cam->rotation,
         dummy, dummy, 0,
         cam->offset.u_offset,
         cam->offset.v_offset);
  if (err != 0) {
   printk(KERN_ERR "CSI_PRP_ENC_MEM output buffer\n");
   return err;
  }*/


   if (ipu_init_channel_buffer(MEM_VDI_PRP_VF_MEM, IPU_INPUT_BUFFER,
         enc.csi_prp_enc_mem.out_pixel_fmt,
         enc.csi_prp_enc_mem.out_width,
         enc.csi_prp_enc_mem.out_height,
         cam->v2f.fmt.pix.bytesperline /
         bytes_per_pixel(enc.csi_prp_enc_mem.
           out_pixel_fmt),
         cam->rotation,
         dummy, dummy, 0,
         cam->offset.u_offset,
         cam->offset.v_offset)!= 0) {
  printk( "Error initializing VDI current input buffer\n");
  return -EINVAL;
 }
 
  if (ipu_init_channel_buffer(MEM_VDI_PRP_VF_MEM_N,
         IPU_INPUT_BUFFER,
         enc.csi_prp_enc_mem.out_pixel_fmt,
         enc.csi_prp_enc_mem.out_width,
         enc.csi_prp_enc_mem.out_height,
         cam->v2f.fmt.pix.bytesperline /
         bytes_per_pixel(enc.csi_prp_enc_mem.
           out_pixel_fmt),
         cam->rotation,
         dummy, dummy, 0,
         cam->offset.u_offset,
         cam->offset.v_offset)!= 0) {
   printk("Error initializing VDI next input buffer\n");
   return -EINVAL;
  }


  if (ipu_init_channel_buffer(MEM_VDI_PRP_VF_MEM,
         IPU_OUTPUT_BUFFER,
         enc.csi_prp_enc_mem.out_pixel_fmt,
         enc.csi_prp_enc_mem.out_width,
         enc.csi_prp_enc_mem.out_height,
         cam->v2f.fmt.pix.bytesperline /
         bytes_per_pixel(enc.csi_prp_enc_mem.
           out_pixel_fmt),
         cam->rotation,
         dummy, dummy, 0,
         cam->offset.u_offset,
         cam->offset.v_offset)!= 0) {
   printk("Error initializing PP-VDI output buffer\n");
   return -EINVAL;
  }
     err =ipu_enable_channel(MEM_VDI_PRP_VF_MEM);
        if (err < 0) {
   printk(KERN_ERR "ipu_enable_channel MEM_VDI_PRP_VF_MEM\n");
   return err;
  }
  err =ipu_enable_channel(MEM_VDI_PRP_VF_MEM_N);
  if (err < 0) {
   printk(KERN_ERR "ipu_enable_channel MEM_VDI_PRP_VF_MEM_N\n");
   return err;
  }
  ipu_select_buffer(MEM_VDI_PRP_VF_MEM, IPU_OUTPUT_BUFFER, 0);
  ipu_select_buffer(MEM_VDI_PRP_VF_MEM, IPU_OUTPUT_BUFFER, 1);

 return err;
}
 #endif

/*!
 * function to update physical buffer address for encorder IDMA channel
 *
 * @param eba         physical buffer address for encorder IDMA channel
 * @param buffer_num  int buffer 0 or buffer 1
 *
 * @return  status
 */
static int vdi_enc_eba_update(dma_addr_t eba, int *buffer_num)
{
 int err = 0;

 pr_debug("eba %x\n", eba);

 err = ipu_update_channel_buffer(MEM_VDI_PRP_VF_MEM,
      IPU_OUTPUT_BUFFER, *buffer_num,
      eba);
 err = ipu_update_channel_buffer(MEM_VDI_PRP_VF_MEM_N,
      IPU_OUTPUT_BUFFER, *buffer_num,
      eba);
 if (err != 0) {
 
   ipu_clear_buffer_ready(MEM_VDI_PRP_VF_MEM,
            IPU_OUTPUT_BUFFER,
            *buffer_num);
              ipu_clear_buffer_ready(MEM_VDI_PRP_VF_MEM_N,
            IPU_OUTPUT_BUFFER,
            *buffer_num);
   err = ipu_update_channel_buffer(MEM_VDI_PRP_VF_MEM,
       IPU_OUTPUT_BUFFER,
       *buffer_num,
       eba);
  
   err = ipu_update_channel_buffer(MEM_VDI_PRP_VF_MEM_N,
       IPU_OUTPUT_BUFFER,
       *buffer_num,
       eba);
  if (err != 0) {
   pr_err("ERROR: v4l2 capture: fail to update "
          "buf%d\n", *buffer_num);
   return err;
  }
 }

    ipu_select_buffer(MEM_VDI_PRP_VF_MEM, IPU_OUTPUT_BUFFER, *buffer_num);
 ipu_select_buffer(MEM_VDI_PRP_VF_MEM, IPU_OUTPUT_BUFFER, *buffer_num);
 

 *buffer_num = (*buffer_num == 0) ? 1 : 0;
 return 0;
}

/*!
 * Enable encoder task
 * @param private       struct cam_data * mxc capture instance
 *
 * @return  status
 */
static int vdi_enc_enabling_tasks(void *private)
{
 cam_data *cam = (cam_data *) private;
 int err = 0;
 CAMERA_TRACE("IPU:In vdi_enc_enabling_tasks\n");

 cam->dummy_frame.vaddress = dma_alloc_coherent(0,
          PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage),
          &cam->dummy_frame.paddress,
          GFP_DMA | GFP_KERNEL);
 if (cam->dummy_frame.vaddress == 0) {
  pr_err("ERROR: v4l2 capture: Allocate dummy frame "
         "failed.\n");
  return -ENOBUFS;
 }
 cam->dummy_frame.buffer.type = V4L2_BUF_TYPE_PRIVATE;
 cam->dummy_frame.buffer.length =
     PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage);
 cam->dummy_frame.buffer.m.offset = cam->dummy_frame.paddress;

 err = ipu_request_irq(IPU_IRQ_VDI_C_IN_EOF,//IPU_IRQ_PRP_VF_OUT_EOF
          vdi_enc_callback, 0, "Mxc Camera", cam);
        err = ipu_request_irq(IPU_IRQ_VDI_N_IN_EOF,//IPU_IRQ_PRP_VF_OUT_EOF
          vdi_enc_callback, 0, "Mxc Camera", cam);

 if (err != 0) {
  printk(KERN_ERR "Error registering rot irq\n");
  return err;
 }

 err = vdi_enc_setup(cam);
 if (err != 0) {
  printk(KERN_ERR "prp_enc_setup %d\n", err);
  return err;
 }

 return err;
}

/*!
 * Disable encoder task
 * @param private       struct cam_data * mxc capture instance
 *
 * @return  int
 */
static int vdi_enc_disabling_tasks(void *private)
{
 cam_data *cam = (cam_data *) private;
 int err = 0;


 ipu_free_irq(IPU_IRQ_PRP_VF_OUT_EOF, cam);
 


 ipu_disable_channel(MEM_VDI_PRP_VF_MEM, true);
    ipu_disable_channel(MEM_VDI_PRP_VF_MEM_N, true);

 ipu_uninit_channel(MEM_VDI_PRP_VF_MEM);

 if (cam->dummy_frame.vaddress != 0) {
  dma_free_coherent(0, cam->dummy_frame.buffer.length,
      cam->dummy_frame.vaddress,
      cam->dummy_frame.paddress);
  cam->dummy_frame.vaddress = 0;
 }
 ipu_csi_enable_mclk_if(CSI_MCLK_ENC, cam->csi, false, false);

 return err;
}

/*!
 * Enable csi
 * @param private       struct cam_data * mxc capture instance
 *
 * @return  status
 */
static int vdi_enc_enable_csi(void *private)
{
 cam_data *cam = (cam_data *) private;

 return ipu_enable_csi(cam->csi);
}

/*!
 * Disable csi
 * @param private       struct cam_data * mxc capture instance
 *
 * @return  status
 */
static int vdi_enc_disable_csi(void *private)
{
 cam_data *cam = (cam_data *) private;

 return ipu_disable_csi(cam->csi);
}

/*!
 * function to select VDI-ENC as the working path
 *
 * @param private       struct cam_data * mxc capture instance
 *
 * @return  int
 */
int vdi_enc_select(void *private)
{
 cam_data *cam = (cam_data *) private;
 int err = 0;

 if (cam) {
  cam->enc_update_eba = vdi_enc_eba_update;
  cam->enc_enable = vdi_enc_enabling_tasks;
  cam->enc_disable = vdi_enc_disabling_tasks;
  cam->enc_enable_csi = vdi_enc_enable_csi;
  cam->enc_disable_csi = vdi_enc_disable_csi;
 } else {
  err = -EIO;
 }

 return err;
}

/*!
 * function to de-select VDI-ENC as the working path
 *
 * @param private       struct cam_data * mxc capture instance
 *
 * @return  int
 */
int vdi_enc_deselect(void *private)
{
 cam_data *cam = (cam_data *) private;
 int err = 0;

 if (cam) {
  cam->enc_update_eba = NULL;
  cam->enc_enable = NULL;
  cam->enc_disable = NULL;
  cam->enc_enable_csi = NULL;
  cam->enc_disable_csi = NULL;
 /* if (cam->rot_enc_bufs_vaddr[0]) {
   dma_free_coherent(0, cam->rot_enc_buf_size[0],
       cam->rot_enc_bufs_vaddr[0],
       cam->rot_enc_bufs[0]);
   cam->rot_enc_bufs_vaddr[0] = NULL;
   cam->rot_enc_bufs[0] = 0;
  }
  if (cam->rot_enc_bufs_vaddr[1]) {
   dma_free_coherent(0, cam->rot_enc_buf_size[1],
       cam->rot_enc_bufs_vaddr[1],
       cam->rot_enc_bufs[1]);
   cam->rot_enc_bufs_vaddr[1] = NULL;
   cam->rot_enc_bufs[1] = 0;
  }*/
 }

 return err;
}

/*!
 * Init the Encorder channels
 *
 * @return  Error code indicating success or failure
 */
__init int vdi_enc_init(void)
{
 return 0;
}

/*!
 * Deinit the Encorder channels
 *
 */
void __exit vdi_enc_exit(void)
{
}

module_init(vdi_enc_init);
module_exit(vdi_enc_exit);

EXPORT_SYMBOL(vdi_enc_select);
EXPORT_SYMBOL(vdi_enc_deselect);

MODULE_AUTHOR("Freescale Semiconductor, Inc.");
MODULE_DESCRIPTION("IPU PRP ENC Driver");
MODULE_LICENSE("GPL");

0 Kudos
1 Reply

645 Views
Yanfei_Sun
Contributor IV

No any input channel needed for you flow. CSI will capture the data and store them in internal buffer, with deinterlacing it will output the data to memory with PRP output channel(that is channel # 21).

Besides, you need to set the data path in Flow Proc registers of IPU, to trigger the flow automatically by FSU.

Regards,

Ray

0 Kudos