Dual 1-lane MIPI CSI Cameras

We’re trying to get two identical MIPI cameras working simultaneously. Our board is configured with two physical camera ports, providing four lanes each. One uses CSI A/B, the other CSI C/D. The Jetson documentation has an example using CSI A/B for one four-lane camera alongside another on the one-lane CSI E bus, but the driver seems to be prepared for our scenario.

Currently our driver can enable either camera, and both work well independently. However, once we enable both cameras at the same time, we get a CSI bus stall, as follows.

I’m including some snippets from our set up, in hopes that someone may notice something obvious. We’re hoping someone out there might have had a similar experience, and can provide us with some tips.

//
// This is a cleaned-up copy of what we get on the syslog.  Most of this comes from our driver,
// except the last part where the syncpt timeout is reported.  At this point the kernel is locked up.
//

eniac$ tail -f /var/log/syslog
Jan 29 19:48:24 eniac dbus[275]: [system] Successfully activated service 'org.freedesktop.nm_dispatcher'
Jan 29 19:52:54 eniac kernel: [ 5419.860802] ov7251_v4l2 2-0061: ov7251_power_on
Jan 29 19:52:54 eniac kernel: [ 5419.860814] ov7251_v4l2 2-0061: enabling MCLK with 24000000 Hz
Jan 29 19:52:55 eniac kernel: [ 5420.265256] tegra-i2c tegra12-i2c.2: no acknowledge from address 0x61
Jan 29 19:52:55 eniac kernel: [ 5420.268404] ov7251_v4l2 2-0061: setting I2C addr to 0x61
Jan 29 19:52:55 eniac kernel: [ 5420.274545] vi vi.0: 640x480 is supported
Jan 29 19:52:55 eniac kernel: [ 5420.274596] vi vi.0: 640x480 is supported
Jan 29 19:52:55 eniac kernel: [ 5420.275077] vi vi.0: 640x480 is supported
Jan 29 19:52:55 eniac kernel: [ 5420.275119] vi vi.0: 640x480 is supported
Jan 29 19:52:55 eniac kernel: [ 5420.286071] ov7251_v4l2 2-0061: ov7251_s_stream(enable=1)
Jan 29 19:53:17 eniac kernel: [ 5442.259624] ov7251_v4l2 2-0062: ov7251_power_on
Jan 29 19:53:17 eniac kernel: [ 5442.259632] ov7251_v4l2 2-0062: enabling MCLK with 24000000 Hz
Jan 29 19:53:17 eniac kernel: [ 5442.663825] tegra-i2c tegra12-i2c.2: no acknowledge from address 0x62
Jan 29 19:53:17 eniac kernel: [ 5442.666608] ov7251_v4l2 2-0062: setting I2C addr to 0x62
Jan 29 19:53:17 eniac kernel: [ 5442.670827] vi vi.0: 640x480 is supported
Jan 29 19:53:17 eniac kernel: [ 5442.670837] vi vi.0: 640x480 is supported
Jan 29 19:53:17 eniac kernel: [ 5442.670983] vi vi.0: 640x480 is supported
Jan 29 19:53:17 eniac kernel: [ 5442.670991] vi vi.0: 640x480 is supported
Jan 29 19:53:17 eniac kernel: [ 5442.678156] ov7251_v4l2 2-0062: ov7251_s_stream(enable=1)
Jan 29 19:53:17 eniac kernel: [ 5442.877770] vi vi.0: CSI_B/CSI_C syncpt timeout, syncpt = 498, err = -11
Jan 29 19:53:17 eniac kernel: [ 5442.886743] TEGRA_CSI_CSI_CIL_A_STATUS 0x00000000
Jan 29 19:53:17 eniac kernel: [ 5442.894701] TEGRA_CSI_CSI_CILA_STATUS 0x00000000
Jan 29 19:53:17 eniac kernel: [ 5442.902562] TEGRA_CSI_CSI_CIL_B_STATUS 0x00000000
Jan 29 19:53:17 eniac kernel: [ 5442.910861] TEGRA_CSI_CSI_CIL_C_STATUS 0x00000000
Jan 29 19:53:17 eniac kernel: [ 5442.918972] TEGRA_CSI_CSI_CIL_D_STATUS 0x00000000
Jan 29 19:53:17 eniac kernel: [ 5442.927338] TEGRA_CSI_CSI_CIL_E_STATUS 0x00000000
Jan 29 19:53:17 eniac kernel: [ 5442.935583] TEGRA_CSI_CSI_PIXEL_PARSER_A_STATUS 0x00000000
Jan 29 19:53:17 eniac kernel: [ 5442.944190] TEGRA_CSI_CSI_PIXEL_PARSER_B_STATUS 0x00000080
Jan 29 19:53:17 eniac kernel: [ 5442.953316] TEGRA_VI_CSI_0_ERROR_STATUS 0x00000000
Jan 29 19:53:17 eniac kernel: [ 5442.961584] TEGRA_VI_CSI_1_ERROR_STATUS 0x00000004
Jan 29 19:53:18 eniac kernel: [ 5443.169730] vi vi.0: CSI_B/CSI_C syncpt timeout, syncpt = 499, err = -11
Jan 29 19:53:18 eniac kernel: [ 5443.179176] TEGRA_CSI_CSI_CIL_A_STATUS 0x00000000
Jan 29 19:53:18 eniac kernel: [ 5443.187719] TEGRA_CSI_CSI_CILA_STATUS 0x00000000
Jan 29 19:53:18 eniac kernel: [ 5443.196022] TEGRA_CSI_CSI_CIL_B_STATUS 0x00000000
Jan 29 19:53:18 eniac kernel: [ 5443.203968] TEGRA_CSI_CSI_CIL_C_STATUS 0x00000000
Jan 29 19:53:18 eniac kernel: [ 5443.212804] TEGRA_CSI_CSI_CIL_D_STATUS 0x00000000
Jan 29 19:53:18 eniac kernel: [ 5443.220304] TEGRA_CSI_CSI_CIL_E_STATUS 0x00000000
Jan 29 19:53:18 eniac kernel: [ 5443.228621] TEGRA_CSI_CSI_PIXEL_PARSER_A_STATUS 0x00000000
Jan 29 19:53:18 eniac kernel: [ 5443.237751] TEGRA_CSI_CSI_PIXEL_PARSER_B_STATUS 0x00000080
Jan 29 19:53:18 eniac kernel: [ 5443.246563] TEGRA_VI_CSI_0_ERROR_STATUS 0x00000000
Jan 29 19:53:18 eniac kernel: [ 5443.254712] TEGRA_VI_CSI_1_ERROR_STATUS 0x00000004
Jan 29 19:53:18 eniac kernel: [ 5443.463255] vi vi.0: CSI_B/CSI_C syncpt timeout, syncpt = 500, err = -11
Jan 29 19:53:18 eniac kernel: [ 5443.470379] TEGRA_CSI_CSI_CIL_A_STATUS 0x00000000
Jan 29 19:53:18 eniac kernel: [ 5443.478253] TEGRA_CSI_CSI_CILA_STATUS 0x00000000
Jan 29 19:53:18 eniac kernel: [ 5443.486846] TEGRA_CSI_CSI_CIL_B_STATUS 0x00000000
Jan 29 19:53:18 eniac kernel: [ 5443.495036] TEGRA_CSI_CSI_CIL_C_STATUS 0x00000000
Jan 29 19:53:18 eniac kernel: [ 5443.503348] TEGRA_CSI_CSI_CIL_D_STATUS 0x00000000
Jan 29 19:53:18 eniac kernel: [ 5443.511518] TEGRA_CSI_CSI_CIL_E_STATUS 0x00000000
Jan 29 19:53:18 eniac kernel: [ 5443.519587] TEGRA_CSI_CSI_PIXEL_PARSER_A_STATUS 0x00000000
Jan 29 19:53:18 eniac kernel: [ 5443.528474] TEGRA_CSI_CSI_PIXEL_PARSER_B_STATUS 0x00000080
Jan 29 19:53:18 eniac kernel: [ 5443.537811] TEGRA_VI_CSI_0_ERROR_STATUS 0x00000000
Jan 29 19:53:18 eniac kernel: [ 5443.546449] TEGRA_VI_CSI_1_ERROR_STATUS 0x00000004
[ 5468.031278] BUG: soft lockup - CPU#0 stuck for 22s! [kworker/0:2:2186]
...

//
// This is the left-side camera.  [board-ardbeg-sensors.c]
//

static struct i2c_board_info ardbeg_ov7251a_camera_i2c_device = {
        I2C_BOARD_INFO("ov7251_v4l2", 0x61),
};

static struct tegra_camera_platform_data ardbeg_ov7251a_camera_platform_data = {
        .port                   = TEGRA_CAMERA_PORT_CSI_A,
        .lanes                  = 1,
};

static struct soc_camera_link ov7251a_iclink = {
        .bus_id         = 0, /* This must match the .id of tegra_vi01_device */
        .board_info     = &ardbeg_ov7251a_camera_i2c_device,
        .module_name    = "ov7251_v4l2",
        .i2c_adapter_id = 2,
        .priv           = &ardbeg_ov7251a_camera_platform_data,
};

static struct platform_device ardbeg_ov7251a_soc_camera_device = {
        .name   = "soc-camera-pdrv",
        .id     = 0,
        .dev    = {
                .platform_data = &ov7251a_iclink,
        },
};

//
// This is the right-side camera.  [board-ardbeg-sensors.c]
//

static struct i2c_board_info ardbeg_ov7251b_camera_i2c_device = {
        I2C_BOARD_INFO("ov7251_v4l2", 0x62),
};

static struct tegra_camera_platform_data ardbeg_ov7251b_camera_platform_data = {
        .port                   = TEGRA_CAMERA_PORT_CSI_B,
        .lanes                  = 1,
};

static struct soc_camera_link ov7251b_iclink = {
        .bus_id         = 0, /* This must match the .id of tegra_vi01_device */
        .board_info     = &ardbeg_ov7251b_camera_i2c_device,
        .module_name    = "ov7251_v4l2",
        .i2c_adapter_id = 2,
        .priv           = &ardbeg_ov7251b_camera_platform_data,
};

static struct platform_device ardbeg_ov7251b_soc_camera_device = {
        .name   = "soc-camera-pdrv",
        .id     = 1,
        .dev    = {
                .platform_data = &ov7251b_iclink,
        },
};

//
// These are used to exit/enter low-power mode.  [ov7251_v4l2.c]
//
// The cameras also also work when CSIA is enabled for camera A,
// and CSIB is enabled for camera B, instead of two for each.  I
// suspect that CSIB and DSIC are twinned somehow.  Both cameras
// use only a single CSI lane.
//

static struct tegra_io_dpd csia_io[] = {
        {
                .name                   = "CSIA",
                .io_dpd_reg_index       = 0,
                .io_dpd_bit             = 0,
        }, {
                .name                   = "CSIB",
                .io_dpd_reg_index       = 0,
                .io_dpd_bit             = 1,
        },
        { NULL }
};

static struct tegra_io_dpd csib_io[] = {
        {
                .name                   = "DSIC",
                .io_dpd_reg_index       = 1,
                .io_dpd_bit             = 8,
        }, {
                .name                   = "DSID",
                .io_dpd_reg_index       = 1,
                .io_dpd_bit             = 9,
        },
        { NULL }
};

//
// These are selected later, depending on which camera is used.
//

static struct ov7251_platform_data *
ov7251_pdata_from_soc(struct i2c_client *client)
{
        struct soc_camera_link *link = client->dev.platform_data;
        struct tegra_camera_platform_data *camera = link->priv;

	// ...

        switch (camera->port) {
        case TEGRA_CAMERA_PORT_CSI_A:
                pdata->mclk_name   = "vi_sensor";
                pdata->pwr_en_gpio = 22*8 + 2;  /* W2  */
                pdata->pwdn_gpio   = 27*8 + 5;  /* BB5 */
                pdata->csi_io      = csia_io;
                break;
        case TEGRA_CAMERA_PORT_CSI_B:
                pdata->mclk_name   = "mclk2";
                pdata->pwr_en_gpio = 23*8 + 6;  /* X6  */
                pdata->pwdn_gpio   = 27*8 + 6;  /* BB6 */
                pdata->csi_io      = csib_io;
                break;
        default:
                dev_err(&client->dev, "unknown CSI port: %d", camera->port);
                return NULL;
        }

	return pdata;
}

Hi actuated-man,

Both camera A and camera B are 1 lane CSI caemra, right?

Would you please help to do the experiment?
Please remove the “CSIB” from camera A csia_io and update whether the camera B still can work well or not.

Thanks

Hi kayccc,

Yes, the first camera only needs CSIA, I’ve verified that. The second camera needs either CSIB or DSIC. I’m fuzzy as to why either work, but the hardware guys just shrugged, so it probably doesn’t matter. :-)

Originally the code used CSIA and CSIB for the cameras, respectively, but before I tried to operate them simultaneously. I expanded it out to power all four busses, but that didn’t solve my problem. Each camera works, but not at the same time.

Thanks for responding. If you’ve got any other experiments in mind, please let me know.

Hi actuated-man,

Due to both camera A and camera B are 1 lane CSI camera, by referring the design guide doc, you could use CSIA for camera A csia_io and CSIE for camera B csib_io

Thanks

Hi kayccc,

We actually have a custom board, with the second camera connector using CSI C/D, not the 1-lane CSI E. We considered hot-wiring over the CSI E to make it closer to nVidia’s example, but as it turns out, I GOT IT WORKING!

First, you might have noticed above that the second camera was set to use vi.0, “.bus_id = 0”. This was a mistake. I had been tinkering and noticed that it worked on both, but only in isolation. I forgot to change it back to vi.1, as is necessary to power all the correct clocks (I’m pretty sure).

Second, the device tree had to be tweaked to configure the “mipi_pad_ctrl_dsi_b” pin for CSI, not DSI.

pinmux {
  common {
    mipi_pad_ctrl_dsi_b {
      nvidia,pins = "mipi_pad_ctrl_dsi_b";
      nvidia,function = "csi";
    };
  };
};

And finally, I removed the extra CSI power-up bits. Camera one only needs CSIA, and camera two only needs DSIC (well, might have worked with CSIB, but I never tried it).

Thanks for all your suggestions, kayccc! :-)