AnsweredAssumed Answered

How to start the parallel CSI0 interface on iMX6Q in CSI0 --> SMFC --> MEM  mode using  IDMAC_CH_0

Question asked by Henk Fijnvandraat on Jul 10, 2014
Latest reply on Oct 14, 2015 by Henk Fijnvandraat
Branched to a new discussion

Hi All,

 

We currently have a sensor that interfaces fully operational to an i.MX27 processor over its parallel CSI interface.

 

We are now trying to get this sensor to interface to an iMX6Q.

The sensor is not a video device or picture camera but a specialized line scanner that only has to transfer its data to the processor memory for analyzing.

Hence we don't want to use v4l2 e.a. Instead we try to write a dedicated driver - for which we naturally borrow freely from existing drivers.

Access to IPU1 is made possible by removing the first of the mxc-ipu platform devices, so the interrupt vectors can be claimed.

To our best knowledge we setup all needed parts of the IPU, but no flow is starting: that is no start/end of frame interrupts are generated by the DMA.

 

Hopefully someone can point us out which bit - lurking somewhere in the 5827 pages of the manual - we missed.

 

regards,

 

Henk

 

 

(page remarks refer to document : IMX6DQRM Rev. 1, 04/2013)

(ioremaps for the IPU registers are done but not shown here except when setting the IDMAC CPMEM parameters)

 

These are the relevant setup code snippets:

 

static iomux_v3_cfg_t mx6q_ipu1_csi0_par_pads[] = {

 

        MX6Q_PAD_CSI0_DATA_EN__IPU1_CSI0_DATA_EN, // if not used should float internally and enable inputs

        MX6Q_PAD_CSI0_DAT12__IPU1_CSI0_D_12,

        MX6Q_PAD_CSI0_DAT13__IPU1_CSI0_D_13,

        MX6Q_PAD_CSI0_DAT14__IPU1_CSI0_D_14,

        MX6Q_PAD_CSI0_DAT15__IPU1_CSI0_D_15,

        MX6Q_PAD_CSI0_DAT16__IPU1_CSI0_D_16,

        MX6Q_PAD_CSI0_DAT17__IPU1_CSI0_D_17,

        MX6Q_PAD_CSI0_DAT18__IPU1_CSI0_D_18,

        MX6Q_PAD_CSI0_DAT19__IPU1_CSI0_D_19,

        MX6Q_PAD_CSI0_VSYNC__IPU1_CSI0_VSYNC,

        MX6Q_PAD_CSI0_MCLK__IPU1_CSI0_HSYNC,

        MX6Q_PAD_CSI0_PIXCLK__IPU1_CSI0_PIXCLK

};

 

  // set the uP physical pins to their CSI0 parallel input state

  // page 1928: bit 19 MIPI_IPU1_MUX = 1 Enable parallel interface to IPU1 CSI0

  mxc_iomux_set_gpr_register(1, 19, 1, 1);

  // set the CSI parallel inputs (starting at page 2082)

  mxc_iomux_v3_setup_multiple_pads(mx6q_ipu1_csi0_par_pads, ARRAY_SIZE(mx6q_ipu1_csi0_par_pads));

 

  writel(readl(ccm_ccgr3) | BM_CCM_CCGR3_CG0, ccm_ccgr3); // turn on IPU1 clock

 

static void testsetup(void)

{

/*

* We try to set up the IPU to the flow described in Table 37-27 on page 2851 of the manual:

*

* Capturing image from sensor and storing it in the memory without processing

*

* CSI0 or CSI1 --> SMFC --> MEM  which uses  IDMAC_CH_0

*

*/

 

  uint32_t height = 800;  // testframe size

  uint32_t width  = 1752;

  uint32_t stride = 1752;

  CPMEM_CHANNEL_PARAMS cpmem_entry; // 160 bit mega word to setup the Image DMA Controller

 

  // enable all possible error interrupts

  HW_IPU_INT_CTRL_5_WR(1, 0xffffffff);

  HW_IPU_INT_CTRL_6_WR(1, 0xffffffff);

  HW_IPU_INT_CTRL_9_WR(1, 0xffffffff);

  HW_IPU_INT_CTRL_10_WR(1, 0xffffffff);

 

  // Set up the Camera Sensor Interface (CSI)

  // (page 3245)

  BW_IPU_CSI0_SENS_CONF_CSI0_DATA_DEST(1, 4); // CSI0_DATA_DEST[2] - destination is IDMAC via SMFC

 

#ifndef CSI_TEST_MODE

  BW_IPU_CSI0_SENS_CONF_CSI0_VSYNC_POL(1, 0);

  BW_IPU_CSI0_SENS_CONF_CSI0_HSYNC_POL(1, 0);

  BW_IPU_CSI0_SENS_CONF_CSI0_DATA_POL(1, 0);

  BW_IPU_CSI0_SENS_CONF_CSI0_SENS_PIX_CLK_POL(1, 0);

  BW_IPU_CSI0_SENS_CONF_CSI0_SENS_PRTCL(1, 0);       // Gated clock mode

  BW_IPU_CSI0_SENS_CONF_CSI0_SENS_DATA_FORMAT(1, 3); // Bayer or Generic data

  BW_IPU_CSI0_SENS_CONF_CSI0_DATA_WIDTH(1, 1);       // interface is 8 bits wide

  BW_IPU_CSI0_SENS_CONF_CSI0_EXT_VSYNC(1, 1);        // External VSYNC mode

  // pixel clock from sensor interface is 24MHz, hsync and vsync are high active

#else

  BW_IPU_CSI0_SENS_CONF_CSI0_VSYNC_POL(1, 0);

  BW_IPU_CSI0_SENS_CONF_CSI0_HSYNC_POL(1, 0);

  BW_IPU_CSI0_SENS_CONF_CSI0_DATA_POL(1, 0);

  BW_IPU_CSI0_SENS_CONF_CSI0_SENS_PIX_CLK_POL(1, 1);

  BW_IPU_CSI0_SENS_CONF_CSI0_SENS_PRTCL(1, 1);       // Non-gated clock sensor timing/data mode

  BW_IPU_CSI0_SENS_CONF_CSI0_SENS_DATA_FORMAT(1, 0); // Full RGB or YUV444

  BW_IPU_CSI0_SENS_CONF_CSI0_DATA_WIDTH(1, 1);       // interface is 8 bits wide

  BW_IPU_CSI0_SENS_CONF_CSI0_EXT_VSYNC(1, 1);        // External VSYNC mode

#endif

 

// DIV Ratio Clock division ratio minus 1.

// This field defines the division ratio of HSP_CLK into

// SENSB_MCLK: SENSB_MCLK rate = HSP_CLK rate /(DIV_RATIO+1)

// HSP_CLK = 264MHz

  BW_IPU_CSI0_SENS_CONF_CSI0_DIV_RATIO(1, 3); // used to synchronize incomming data only so 66Mhz against 24MHz should do

 

  // Set up the sensor dimensions

  printk(KERN_INFO "CSI0 Sensor Form Register: %x\n", HW_IPU_CSI0_SENS_FRM_SIZE_RD(1));

  // (page 3211) set the sensor dimensions

  {

    hw_ipu_csi0_sens_frm_size_t v;

    v.B.CSI0_SENS_FRM_WIDTH = width - 1;

    v.B.RESERVED0 = 0;

    v.B.CSI0_SENS_FRM_HEIGHT = height - 1;

    v.B.RESERVED1 = 0;

    HW_IPU_CSI0_SENS_FRM_SIZE_WR(1, v.U);

    HW_IPU_CSI0_ACT_FRM_SIZE_WR(1, v.U);

  }

 

#ifdef CSI_TEST_MODE

  BW_IPU_CSI0_TST_CTRL_PG_R_VALUE(1, 128);

  BW_IPU_CSI0_TST_CTRL_PG_G_VALUE(1, 128);

  BW_IPU_CSI0_TST_CTRL_PG_B_VALUE(1, 128);

  BW_IPU_CSI0_TST_CTRL_TEST_GEN_MODE(1, 1); // test generator on

#endif

  // just in case

  BW_IPU_SRM_PRI1_CSI0_SRM_MODE(1, 3); // (page 3016) Shadow register handling: have CSI0 settings written

  // Update now. The SRM is controlled by the ARM Platform. The Register will be update now

 

  // set up the IDMAC CPMEM parameters

  memset(&cpmem_entry, 0, sizeof(CPMEM_CHANNEL_PARAMS)); // clean it out

 

  // We are using: Interleaved mode where the Y:U:V data is organized

  // in a single buffer in the system's memory (page 2735 of manual)

 

  CPMEM_SET_FIELD(&cpmem_entry, 0, 125, 13, width - 1);  // Frame Width (page 2743)

  CPMEM_SET_FIELD(&cpmem_entry, 0, 138, 12, height - 1); // Frame Heigth

  CPMEM_SET_FIELD(&cpmem_entry, 1, 102, 14, stride - 1);

  // Transport 8-bit Generic data

  CPMEM_SET_FIELD(&cpmem_entry, 0, 107, 3, 5);  // bits/pixel BPP  5 == 8 bits per pixel (page 2742)

  CPMEM_SET_FIELD(&cpmem_entry, 1, 85, 4, 6);   // Pixel Format Select PFS (page 2745)

  CPMEM_SET_FIELD(&cpmem_entry, 1, 78, 7, 63);  // Number of Pixels in Whole Burst Access NPB (page 2745)

 

  // this does not seem to be documented anywhere

  //CPMEM_SET_FIELD(&cpmem_entry, 1, 93, 2, 0);   // AXI protocol id (page 2746) ???????

 

  // EBA is 8-byte aligned

  // Do we need double buffering ??

  dma1order = get_order(height * width);

  dmabuf1 = __get_free_pages(ZONE_DMA, dma1order);

  if(dmabuf1 == 0L)

  {

    printk(KERN_ERR "Could not allocate dmabuf1\n");

  }

/*

  dma2order = get_order(height * width);

  dmabuf2 = __get_free_pages(ZONE_DMA, dma1order);

  if(dmabuf2 == 0L)

  {

    printk(KERN_ERR "Could not allocate dmabuf2\n");

  }

*/

  CPMEM_SET_FIELD(&cpmem_entry, 1, 0, 29, dmabuf1 >> 3); // Ext Mem Buffer 0 Address EBA0

//  CPMEM_SET_FIELD(&cpmem_entry, 1, 29, 29, dmabuf2 >> 3); // Ext Mem Buffer 1 Address EBA1

  if(dmabuf1 % 8)

    printk(KERN_INFO "IDMAC EBA0 is not 8-byte aligned\n");

//  if(dmabuf2 % 8)

//    printk(KERN_INFO "IDMAC EBA1 is not 8-byte aligned\n");

  printk(KERN_INFO "dmabuf1 %lx\n", dmabuf1);

//  printk(KERN_INFO "dmabuf2 %lx\n", dmabuf2);

 

  // to write the data remap the physical cpmem area

  ipu1cpmem = ioremap(REGS_IPU1_CPMEM, sizeof(CPMEM_CHANNEL_PARAMS));

  if(ipu1cpmem == NULL)

  {

    printk(KERN_ERR "CIS driver: cannot grab ipu1cpmem\n");

    internal_deinit();

    return ;

  }

  memcpy(ipu1cpmem, &cpmem_entry, sizeof(CPMEM_CHANNEL_PARAMS));

  iounmap(ipu1cpmem);

  ipu1cpmem = NULL;

  // end IDMAC CPMEM parameters

 

  // Set up the Sensor Multi Fifo Controller (SMFC)

  BW_IPU_SMFC_BS_BURST0_SIZE(1, 63); // Burst size 64 (page 3383)

 

  // Set up the IPU configuration

  // page 2936: configure IPU

  BW_IPU_CONF_CSI0_DATA_SOURCE(1, 0); // CSI0_DATA_SOURCE is parallel input

  BW_IPU_CONF_CSI_SEL(1, 0);          // CSI_SEL set to CSI0

  BW_IPU_CONF_CSI0_EN(1, 1);          // Camera Sensor Interface 0 Enable bit

  BW_IPU_CONF_SMFC_EN(1, 1);          // Sensor's Multi FIFO Controller Sub-block (SMFC) Enable bit

 

  // our flow goes through DMA channel 0 (page 2851)

  BW_IPU_INT_CTRL_1_IDMAC_EOF_EN_0(1, 1);     // enable DMA channel 0 EOF interrupt

  BW_IPU_INT_CTRL_3_IDMAC_NFACK_EN_0(1, 1);   // enable DMA channel 0 new frame ack interrupt

  BW_IPU_INT_CTRL_5_IDMAC_NFB4EOF_EN_0(1, 1); // enable DMA channel 0 new frame before EOF interrupt

  BW_IPU_IDMAC_CH_EN_1_IDMAC_CH_EN_0(1, 1);   // DMA channel 0 enable

 

  // enable IPU task, preprocessor seems the only relevant one ??

  BW_IPU_FS_PROC_FLOW1_PRP_SRC_SEL(1, 1); // source select for preprocessor task is capture 0

 

  BW_IPU_CH_BUF0_RDY0_DMA_CH_BUF0_RDY_0(1, 1);

 

What more needs to be done ?????

}

Outcomes