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

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

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

Jump to solution
3,128 Views
henkfijnvandraa
Contributor II

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 ?????

}

Labels (3)
Tags (1)
0 Kudos
1 Solution
1,082 Views
henkfijnvandraa
Contributor II

"i.MX 6Series Platform SDK"

contains a file called: regsipu.h

which contains the following:

#define HW_IPU_IDMAC_CH_EN_1_ADDR(x)  (REGS_IPU_BASE(x) + 0x1f44)
#define HW_IPU_IDMAC_CH_EN_2_ADDR(x)  (REGS_IPU_BASE(x) + 0x1f48)

Freescale, think about your quality of support!

View solution in original post

0 Kudos
4 Replies
1,082 Views
qiang_li-mpu_se
NXP Employee
NXP Employee

Hi Henk Fijnvandraat, the non OS CSI capture code can be found in the "i.MX 6Series Platform SDK":

http://www.freescale.com/webapp/sps/site/prod_summary.jsp?code=i.MX6Q&fpsp=1&tab=Design_Tools_Tab

Software Development Tools (33) -> Software Development Kits

Just quickly go through your code, I found the burst size setting in SMFC is wrong, you had set both NPB and SMFC burst size to 64,

CPMEM_SET_FIELD(&cpmem_entry, 1, 78, 7, 63);

BW_IPU_SMFC_BS_BURST0_SIZE(1, 63);

The above setting is wrong, for SMFC burst size, in 8 bpp mode, its value should be set to NPB[6:4], not the NPB value directly. (Table 37-727. SMFC Burst Size, page 3382)

BW_IPU_SMFC_BS_BURST0_SIZE(1, (64 >> 4) - 1);

By the way, since you are used such code in Linux, you shoudl also pay attention to the interrupt. I think you can make your driver working in V4l2 mode, then dump all registers setting and IDMAC setting, then these dumped setting can be referenced for your not-v4l2 case.

0 Kudos
1,082 Views
henkfijnvandraa
Contributor II

Hi,

Even after correcting the burst size we get no data transfer at all. Not when using the test mode and not when using the parallel interface

And with all respect for the suggestion, dumping the v4l2 settings is an extreme reverse engineering method that should not be needed.

I expect to be able to program the chip by means of its documentation.

We program the:

CSI

SMFC

IDMAC

CM (control module) to set a flow

And we then expect to see data transported.

In essence this is the simplest task the IPU can perform, so why is it so hard to make it work?

Are there some border conditions - other parts of the IPU not needed for this data stream that must be enabled too?

There must be a Freescale expert somewhere who can tell us how to do this

Regards,

Henk

0 Kudos
1,082 Views
qiang_li-mpu_se
NXP Employee
NXP Employee

Hi Henk, I think you can go back to the v4l2 driver, for your case, it can also use v4l2 capture to capture your data (CSI -> MEM mode), Since the IPU code will be used for display too, in Linux, it is hard to use another driver to handle the IPU.

By the way, you should also make sure the CSI_DATA_EN is high, only when it is high, the CSI will capture data from data line. And for test mode, it must use internal VSYNC mode, the clock mode should be non-gated clock mode, data format should be RGB888.

0 Kudos
1,083 Views
henkfijnvandraa
Contributor II

"i.MX 6Series Platform SDK"

contains a file called: regsipu.h

which contains the following:

#define HW_IPU_IDMAC_CH_EN_1_ADDR(x)  (REGS_IPU_BASE(x) + 0x1f44)
#define HW_IPU_IDMAC_CH_EN_2_ADDR(x)  (REGS_IPU_BASE(x) + 0x1f48)

Freescale, think about your quality of support!

0 Kudos