TX2 VI / ISP causing timeouts

We have a dual sensor system with IMX290 which worked fine with a TX1 SOM.

We’ve now tried to use a TX2 SOM. The DTB needs some adjustments, but when it comes to describing the camera module for nvcamera-daemon, everything looks the same. The V4L2 devices /dev/video0 and /dev/video1 are present and nvcamera-daemon is able to parse the module configuration.

But we cannot get the capture running. See the attached logfiles for further information. From the trace information I have gathered, I see that the VI block generates error notifications (but the reported error conditions are not explained in the Parker TRM). The kernel log indicates that the ISP is causing timeouts in the host1x, but that seems to be “normal” considering that the ISP is a slave of the VI.

I don’t know how to continue from here. Does anyone know what the problem might be?
kernel.log (27.3 KB)
trace.log (8.67 KB)
nvcamera-daemon.log (387 KB)

When comparing the nvcamera-daemon output of the (working) TX1 and (non-working) TX2 cases, I noticed the following:

TX1:

NvPclSettingsApply: Reading PCL settings
PowerServiceUtils:calculateReqClock: entered
PowerServiceHw:addRequest: table size: before: 0, after:1
        request table for VI 0:
        req[0]: guID=1, stageID=SensorCapture
        req[0]: inW=1948, inH=1108, inBpp = 12, fps=30
        req[0]: outW=1948, outH=1108, outBpp=12
        req[0]: out1W=0, out1H=0, out1Bpp=0
        req[0]: out2W=0, out2H=0, out2Bpp=0
        req[0]: clock=81675000, pixelRate=74250000, timeout=900
        req[0]: isoBw=122512, timeout=900
        req[0]: non_isoBw=0, timeout=900
PowerServiceHw:addRequest: table size: before: 0, after:1
        request table for CSI 0:
        req[0]: guID=1, stageID=SensorCapture
        req[0]: inW=1948, inH=1108, inBpp = 12, fps=30
        req[0]: outW=1948, outH=1108, outBpp=12
        req[0]: out1W=0, out1H=0, out1Bpp=0
        req[0]: out2W=0, out2H=0, out2Bpp=0
        req[0]: clock=0, pixelRate=74250000, timeout=900
        req[0]: isoBw=0, timeout=900
        req[0]: non_isoBw=0, timeout=900
PowerServiceHwVi:setIso: m_bwVal_Iso=122512
PowerServiceHw:setClock: PowerServiceHw[1]: requested_clock_Hz=81675000
PowerServiceCore:setCameraBw: totalIsoBw=122512
NvPclSettingsUpdate: Sending Updated Settings through PCL
NvPclSettingsApply: Applying last settings through PCL

TX2:

NvPclSettingsApply: Reading PCL settings
PowerServiceUtils:calculateReqClock: entered
PowerServiceHw:addRequest: table size: before: 0, after:1
	request table for VI 0:
	req[0]: guID=0, stageID=SensorCapture
	req[0]: inW=1948, inH=1108, inBpp = 12, fps=30
	req[0]: outW=1948, outH=1108, outBpp=12
	req[0]: out1W=0, out1H=0, out1Bpp=0
	req[0]: out2W=0, out2H=0, out2Bpp=0
	req[0]: clock=12993750, pixelRate=74250000, timeout=900
	req[0]: isoBw=155916, timeout=900
	req[0]: non_isoBw=0, timeout=900
PowerServiceUtils:calculateReqClock: entered
PowerServiceHw:addRequest: table size: before: 0, after:1
	request table for CSI 0:
	req[0]: guID=0, stageID=SensorCapture
	req[0]: inW=1948, inH=1108, inBpp = 12, fps=30
	req[0]: outW=1948, outH=1108, outBpp=12
	req[0]: out1W=0, out1H=0, out1Bpp=0
	req[0]: out2W=0, out2H=0, out2Bpp=0
	req[0]: clock=18098436, pixelRate=74250000, timeout=900
	req[0]: isoBw=0, timeout=900
	req[0]: non_isoBw=0, timeout=900
PowerServiceHwVi:setIso: m_bwVal_Iso=155916
PowerServiceHw:setClock: PowerServiceHw[1]: requested_clock_Hz=12993750
PowerServiceHw:setClock: PowerServiceHw[0]: requested_clock_Hz=18098436
PowerServiceCore:setCameraBw: totalIsoBw=155916
NvPclSettingsUpdate: Sending Updated Settings through PCL
NvPclSettingsApply: Applying last settings through PCL

It is obvious that on TX2 the requested clock is totally different from TX1 and, likely, totally wrong. There’s also a difference in the ISO bandwidth.

Where does that clock frequency come from, how is it calculated and which parameters do enter that calculation?

TX2 driver will check the frame size more than the TX1.
I attached a setting is working form me for you to try. Please use the v4l2-ctl check first.

/*
 * imx290_tables.h - sensor mode tables for imx290 HDR sensor.
 *
 * Copyright (c) 2015-2016, NVIDIA CORPORATION, All Rights Reserved.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms and conditions of the GNU General Public License,
 * version 2, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef IMX290_I2C_TABLES
#define IMX290_I2C_TABLES

#define IMX290_TABLE_WAIT_MS 0
#define IMX290_TABLE_END 1
#define IMX290_MAX_RETRIES 3
#define IMX290_WAIT_MS 3

static struct reg_8 mode_1920x1080[] = {
	{IMX290_TABLE_WAIT_MS, 10},
	/* software reset */
	{0x3003, 0x01},
	{IMX290_TABLE_WAIT_MS, 50},
	{0x3000, 0x01},
	{0x3002, 0x00},
	{0x3002, 0x01},
	{IMX290_TABLE_WAIT_MS, 50},

	/* global settings */
	//ID2 
    {0x3004,0x10},// FIXED
    {0x3005,0x01},// AD 12BIT, NO SHIFT
    {0x3006,0x00},// DRIVE MODE = ALL PIXEL SCAN MODE
    {0x3007,0x00},// NO H,V REVERSE , WIN MODE =FULL 1080p mode
    {0x3008,0xA0},// FIXED
    {0x3009,0x02},// Middle Speed FRAME RATE = 30 FPS
    {0x300A,0xF0},// 12BIT BLACK LEVEL[0:7]
    {0x300B,0x00},// 12BIT BLACK LEVEL[8]

    {0x300C,0x00},// FIXED
    {0x300D,0x00},// FIXED
    {0x300E,0x01},// FIXED
    {0x300F,0x00},// FIXED
    {0x3010,0x21},// FIXED
    {0x3011,0x00},// FIXED
    {0x3012,0x64},// FIXED
    {0x3013,0x00},// FIXED

    {0x3014,0x00},// GAIN = 0 DB

    {0x3015,0x00},// FIXED
    {0x3016,0x09},// FIXED
    {0x3017,0x00},// FIXED

    {0x3018,0x65},// VMAX[0:7]
    {0x3019,0x04},// VMAX[8:15] ==>1125
    {0x301A,0x00},// VMAX[16]

    {0x301B,0x00},
    {0x301C,0x98},// HMAX[0:7]
    {0x301D,0x08},// HMAX[8:15] ==>4400
    {0x301E,0xB2},// FIXED
    {0x301F,0x01},// FIXED

    {0x3020,0x00},// SUB CONTROL [0:7]
    {0x3021,0x00},// SUB CONTROL [8:15]
    {0x3022,0x00},// SUB CONTROL [16]

    {0x303E,0x48},// WINWH[0:7] , H CROPPING SIZE
    {0x303F,0x04},// WINWH[8:10]

    {0x3040,0x00},// FIXED
    {0x3041,0x00},// FIXED


    {0x3046,0x01},// CSI-2 fixed 0x1
    {0x3047,0x01},

	{0x3070, 0x02},
	{0x3071, 0x11},
	{0x309B, 0x10},
	{0x309C, 0x22},
	{0x30A2, 0x02},
	{0x30A6, 0x20},
	{0x30A8, 0x20},
	{0x30AA, 0x20},
	{0x30AC, 0x20},
	{0x30b0, 0x43},

	//ID3 
	{0x3119, 0x9E},
	{0x311C, 0x1E},
	{0x311E, 0x08},
	{0x3128, 0x05},
	{0x3129, 0x1D},
	{0x313D, 0x83},
	{0x3150, 0x03},
	{0x315E, 0x1A},
	{0x3164, 0x1A},
	{0x317C, 0x00},
	{0x317E, 0x00},
	{0x317F,0x50},

	//ID4
	{0x32B8,0x50},
	{0x32B9,0x10},
	{0x32BA,0x00},
	{0x32BB,0x04},
	{0x32C8,0x50},
	{0x32C9,0x10},
	{0x32CA,0x00},
	{0x32CB,0x04},
	
	//ID5
	{0x332C,0xD3},
    {0x332D,0x10},
    {0x332E,0x0D},
    {0x3358,0x06},
    {0x3359,0xE1},
    {0x335A,0x11},
    {0x3360,0x1E},
    {0x3361,0x61},
    {0x3362,0x10},
    {0x33B0,0x50},
    {0x33B1,0x1A},
    {0x33B3,0x04},
	//ID6
	{0x3405,0x10}, // frame rate 30
	{0x3407,0x03}, // 4 Lane
	{0x3414,0x0A}, // OB size
	{0x3418,0x48}, // Y OUT SIZE
	{0x3419,0x04},
	{0x3441,0x0C}, // RAW12
	{0x3442,0x0C},
	{0x3443,0x03}, // CSI LANE MODE
	{0x3444,0x20}, // EXTCLK 37.125M
	{0x3445,0x25},
	{0x3446,0x57},
	{0x3447,0x00},

	{0x3448,0x37},
	{0x3449,0x00},
	{0x344a,0x1F},
	{0x344b,0x00},
	{0x344c,0x1F},
	{0x344d,0x00},
	{0x344e,0x1F},
	{0x344f,0x00},
	{0x3450,0x77},
	{0x3451,0x00},
	{0x3452,0x1F},
	{0x3453,0x00},
	{0x3454,0x17},
	{0x3455,0x00},
	{0x3472,0x9C}, // X OUT SIZE
	{0x3473,0x07},

	

	//MISC
	// LVDS 4CH CSI2  , 1080p Mode
	{0x305C,0x18},// INCKSEL1
	{0x305D,0x03},// INCKSEL2
	{0x305E,0x20},// INCKSEL3
	{0x305F,0x01},// INCKSEL4
	{0x315E,0x1A},// INCKSEL5
	{0x3164,0x1A},// INCKSEL6
	{0x3480,0x49},// INCKSEL7

	{0x3048,0x00},// XVS PULSE WIDTH=8H
	{0x3049,0x00},// XHS PULSE max
	{0x3005,0x01},// AD bit 12

	/* stream on */
	{0x3000, 0x00},// STANDBY CANCEL
	{IMX290_TABLE_WAIT_MS, 30},
	{0x3002, 0x00},// Master mode start
	{0x304B, 0x0A},// XVS Abd XHS O/P
	{IMX290_TABLE_WAIT_MS, 240},
	{IMX290_TABLE_END, 0x00}
};

enum {
	IMX290_MODE_1920x1080,
};

static struct reg_8 *mode_table[] = {
	[IMX290_MODE_1920x1080] = mode_1920x1080,

};

static const int imx290_30fps[] = {
	30,
};

static const struct camera_common_frmfmt imx290_frmfmt[] = {
	{{1948, 1096},	imx290_30fps, 1, 0, IMX290_MODE_1920x1080},
};

#endif
/*
 * imx290.c - imx290 sensor driver
 *
 * Copyright (c) 2015-2016, NVIDIA CORPORATION.  All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms and conditions of the GNU General Public License,
 * version 2, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <dt-bindings/gpio/tegra-gpio.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/gpio.h>
#include <linux/module.h>

#include <linux/seq_file.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>


#include <media/camera_common.h>
#include <media/soc_camera.h>
#include <media/imx290.h>

#include "imx290_mode_tbls.h"

#define IMX290_MAX_COARSE_DIFF		1

//#define IMX290_GAIN_SHIFT		8
#define IMX290_MIN_GAIN		(0)//(0 * FIXED_POINT_SCALING_FACTOR)
#define IMX290_MAX_GAIN		(72 * FIXED_POINT_SCALING_FACTOR)
#define IMX290_MIN_FRAME_LENGTH	(0x465)
#define IMX290_MAX_FRAME_LENGTH	(0xFFFF)
#define IMX290_MIN_EXPOSURE_COARSE	(0x0001)
#define IMX290_MAX_EXPOSURE_COARSE	\
	(IMX290_MAX_FRAME_LENGTH-IMX290_MAX_COARSE_DIFF)

#define IMX290_DEFAULT_GAIN		(6 * FIXED_POINT_SCALING_FACTOR)
#define IMX290_DEFAULT_FRAME_LENGTH	(0x0465)
#define IMX290_DEFAULT_EXPOSURE_COARSE	\
	(IMX290_DEFAULT_FRAME_LENGTH-IMX290_MAX_COARSE_DIFF)

#define IMX290_DEFAULT_MODE	IMX290_MODE_1920x1080
#define IMX290_DEFAULT_WIDTH	1948
#define IMX290_DEFAULT_HEIGHT	1096
//#define IMX290_DEFAULT_DATAFMT	V4L2_MBUS_FMT_SRGGB12_1X12
#define IMX290_DEFAULT_DATAFMT	MEDIA_BUS_FMT_SRGGB12_1X12
#define IMX290_DEFAULT_CLK_FREQ	74250000

struct imx290 {
	struct mutex			imx290_camera_lock;
	struct camera_common_power_rail	power;
	int				num_ctrls;
	struct v4l2_ctrl_handler	ctrl_handler;
	struct i2c_client		*i2c_client;
	struct v4l2_subdev		*subdev;
	struct media_pad		pad;
	struct regmap			*regmap;
	struct camera_common_data	*s_data;
	struct camera_common_pdata	*pdata;
	struct v4l2_ctrl		*ctrls[];
};

static const struct regmap_config sensor_regmap_config = {
	.reg_bits = 16,
	.val_bits = 8,
	.cache_type = REGCACHE_RBTREE,
	.use_single_rw = true,
};

static int imx290_g_volatile_ctrl(struct v4l2_ctrl *ctrl);
static int imx290_s_ctrl(struct v4l2_ctrl *ctrl);

static const struct v4l2_ctrl_ops imx290_ctrl_ops = {
	.g_volatile_ctrl = imx290_g_volatile_ctrl,
	.s_ctrl	= imx290_s_ctrl,
};

static struct v4l2_ctrl_config ctrl_config_list[] = {
/* Do not change the name field for the controls! */
	{
		.ops = &imx290_ctrl_ops,
		.id = V4L2_CID_GAIN,
		.name = "Gain",
		.type = V4L2_CTRL_TYPE_INTEGER64,
		.flags = V4L2_CTRL_FLAG_SLIDER,
		.min = IMX290_MIN_GAIN,
		.max = IMX290_MAX_GAIN,
		.def = IMX290_DEFAULT_GAIN,
		.step = 1,
	},
	{
		.ops = &imx290_ctrl_ops,
		.id = V4L2_CID_FRAME_LENGTH,
		.name = "Frame Length",
		.type = V4L2_CTRL_TYPE_INTEGER,
		.flags = V4L2_CTRL_FLAG_SLIDER,
		.min = IMX290_MIN_FRAME_LENGTH,
		.max = IMX290_MAX_FRAME_LENGTH,
		.def = IMX290_DEFAULT_FRAME_LENGTH,
		.step = 1,
	},
	{
		.ops = &imx290_ctrl_ops,
		.id = V4L2_CID_COARSE_TIME,
		.name = "Coarse Time",
		.type = V4L2_CTRL_TYPE_INTEGER,
		.flags = V4L2_CTRL_FLAG_SLIDER,
		.min = IMX290_MIN_EXPOSURE_COARSE,
		.max = IMX290_MAX_EXPOSURE_COARSE,
		.def = IMX290_DEFAULT_EXPOSURE_COARSE,
		.step = 1,
	},
	{
		.ops = &imx290_ctrl_ops,
		.id = V4L2_CID_GROUP_HOLD,
		.name = "Group Hold",
		.type = V4L2_CTRL_TYPE_INTEGER_MENU,
		.min = 0,
		.max = ARRAY_SIZE(switch_ctrl_qmenu) - 1,
		.menu_skip_mask = 0,
		.def = 0,
		.qmenu_int = switch_ctrl_qmenu,
	},
	{
		.ops = &imx290_ctrl_ops,
		.id = V4L2_CID_HDR_EN,
		.name = "HDR enable",
		.type = V4L2_CTRL_TYPE_INTEGER_MENU,
		.min = 0,
		.max = ARRAY_SIZE(switch_ctrl_qmenu) - 1,
		.menu_skip_mask = 0,
		.def = 0,
		.qmenu_int = switch_ctrl_qmenu,
	},
	{
		.ops = &imx290_ctrl_ops,
		.id = V4L2_CID_FUSE_ID,
		.name = "Fuse ID",
		.type = V4L2_CTRL_TYPE_STRING,
		.flags = V4L2_CTRL_FLAG_READ_ONLY,
		.min = 0,
		.max = IMX290_FUSE_ID_STR_SIZE,
		.step = 2,
	},
};

static inline void imx290_get_frame_length_regs(struct reg_8 *regs,
				u16 frame_length)
{
	regs->addr = IMX290_FRAME_LENGTH_ADDR_MSB;
	regs->val = (frame_length >> 8) & 0xff;
	(regs + 1)->addr = IMX290_FRAME_LENGTH_ADDR_LSB;
	(regs + 1)->val = (frame_length) & 0xff;
}

static inline void imx290_get_coarse_time_regs(struct reg_8 *regs,
				u16 coarse_time)
{
	regs->addr = IMX290_COARSE_TIME_ADDR_MSB;
	regs->val = (coarse_time >> 8) & 0xff;
	(regs + 1)->addr = IMX290_COARSE_TIME_ADDR_LSB;
	(regs + 1)->val = (coarse_time) & 0xff;
}

static inline void imx290_get_gain_reg(struct reg_8 *regs,
				u16 gain)
{
	regs->addr = IMX290_GAIN_ADDR;
	regs->val = gain & 0xff;
}

static inline void imx290_get_hold_reg(struct reg_8 *regs,
				u16 hold)
{
	regs->addr = IMX290_REGHOLD_ADDR;
	regs->val = hold & 0xff;
}


static int test_mode;
module_param(test_mode, int, 0644);

static inline int imx290_read_reg(struct camera_common_data *s_data,
				u16 addr, u8 *val)
{
	struct imx290 *priv = (struct imx290 *)s_data->priv;
	return regmap_read(priv->regmap, addr, (unsigned int *) val);
}

static int imx290_write_reg(struct camera_common_data *s_data, u16 addr, u8 val)
{
	int err;
	struct imx290 *priv = (struct imx290 *)s_data->priv;

	err = regmap_write(priv->regmap, addr, val);
	if (err)
		pr_err("%s:i2c write failed, %x = %x\n",
			__func__, addr, val);

	return err;
}

static int imx290_write_table(struct imx290 *priv,
			      const struct reg_8 table[])
{
	return regmap_util_write_table_8(priv->regmap,
					 table,
					 NULL, 0,
					 IMX290_TABLE_WAIT_MS,
					 IMX290_TABLE_END);
}

static void imx290_mclk_disable(struct camera_common_power_rail *pw)
{
	clk_disable_unprepare(pw->mclk);
}

static void imx290_mclk_enable(struct camera_common_power_rail *pw)
{
	clk_set_rate(pw->mclk, IMX290_DEFAULT_CLK_FREQ);
	clk_prepare_enable(pw->mclk);
}

static int imx290_power_on(struct camera_common_data *s_data)
{
	int err = 0;
	struct imx290 *priv = (struct imx290 *)s_data->priv;
	struct camera_common_power_rail *pw = &priv->power;

	//dev_err(&priv->i2c_client->dev, "%s: power on\n", __func__);

	if (gpio_cansleep(pw->reset_gpio))
		gpio_set_value_cansleep(pw->reset_gpio, 0);
	else
		gpio_set_value(pw->reset_gpio, 0);
	usleep_range(10, 20);

	if (pw->avdd)
		err = regulator_enable(pw->avdd);
	if (err)
		goto imx290_avdd_fail;

	if (pw->iovdd)
		err = regulator_enable(pw->iovdd);
	if (err)
		goto imx290_iovdd_fail;

	if (pw->dvdd)
		err = regulator_enable(pw->dvdd);
	if (err)
		goto imx290_dvdd_fail;

	usleep_range(1, 2);
	if (gpio_cansleep(pw->reset_gpio))
		gpio_set_value_cansleep(pw->reset_gpio, 1);
	else
		gpio_set_value(pw->reset_gpio, 1);

	usleep_range(1, 2);
	imx290_mclk_enable(pw);

	/* Need to wait for t4 + t5 + t9 time as per the data sheet */
	/* t4 - 200us, t5 - 6ms, t9 - 1.2ms */
	usleep_range(7400, 7410);

	pw->state = SWITCH_ON;
	return 0;

imx290_dvdd_fail:
	regulator_disable(pw->iovdd);

imx290_iovdd_fail:
	regulator_disable(pw->avdd);

imx290_avdd_fail:
	return -ENODEV;
}

static int imx290_power_off(struct camera_common_data *s_data)
{
	struct imx290 *priv = (struct imx290 *)s_data->priv;
	struct camera_common_power_rail *pw = &priv->power;

	//dev_err(&priv->i2c_client->dev, "%s: power off\n", __func__);

	usleep_range(1, 2);
	if (gpio_cansleep(pw->reset_gpio))
		gpio_set_value_cansleep(pw->reset_gpio, 0);
	else
		gpio_set_value(pw->reset_gpio, 0);
	usleep_range(1, 2);

	if (pw->dvdd)
		regulator_disable(pw->dvdd);
	if (pw->iovdd)
		regulator_disable(pw->iovdd);
	if (pw->avdd)
		regulator_disable(pw->avdd);

	imx290_mclk_disable(pw);
	pw->state = SWITCH_OFF;
	return 0;
}

static int imx290_power_put(struct imx290 *priv)
{
	struct camera_common_power_rail *pw = &priv->power;
	if (unlikely(!pw))
		return -EFAULT;

	if (likely(pw->avdd))
		regulator_put(pw->avdd);

	if (likely(pw->iovdd))
		regulator_put(pw->iovdd);

	if (likely(pw->dvdd))
		regulator_put(pw->dvdd);

	pw->avdd = NULL;
	pw->iovdd = NULL;
	pw->dvdd = NULL;

	return 0;
}

static int imx290_power_get(struct imx290 *priv)
{
	struct camera_common_power_rail *pw = &priv->power;
	struct camera_common_pdata *pdata = priv->pdata;
	const char *mclk_name;
	int err = 0;

	mclk_name = priv->pdata->mclk_name ?
		    priv->pdata->mclk_name : "cam_mclk1";
	pw->mclk = devm_clk_get(&priv->i2c_client->dev, mclk_name);
	if (IS_ERR(pw->mclk)) {
		dev_err(&priv->i2c_client->dev,
			"unable to get clock %s\n", mclk_name);
		return PTR_ERR(pw->mclk);
	}

	/* ananlog 2.7v */
	err |= camera_common_regulator_get(priv->i2c_client,
			&pw->avdd, pdata->regulators.avdd);
	/* digital 1.2v */
	err |= camera_common_regulator_get(priv->i2c_client,
			&pw->dvdd, pdata->regulators.dvdd);
	/* IO 1.8v */
	err |= camera_common_regulator_get(priv->i2c_client,
			&pw->iovdd, pdata->regulators.iovdd);

	if (!err)
		pw->reset_gpio = pdata->reset_gpio;

	



	pw->state = SWITCH_OFF;
	return err;
}

static int imx290_set_gain(struct imx290 *priv, s64 val);
static int imx290_set_frame_length(struct imx290 *priv, s32 val);
static int imx290_set_coarse_time(struct imx290 *priv, s32 val);

static int imx290_s_stream(struct v4l2_subdev *sd, int enable)
{
	struct i2c_client *client = v4l2_get_subdevdata(sd);
	struct camera_common_data *s_data = to_camera_common_data(client);
	struct imx290 *priv = (struct imx290 *)s_data->priv;
	int err;
	struct v4l2_control control;

	dev_dbg(&client->dev, "%s\n", __func__);

	if (!enable)
		return 0;
#if 1
	err = imx290_write_table(priv, mode_table[s_data->mode]);
	if (err)
		goto exit;

		/* write list of override regs for the asking frame length,
		 * coarse integration time, and gain. Failures to write
		 * overrides are non-fatal */
		printk(KERN_DEBUG "\n Start set V4L2_CID_GAIN \n");
		control.id = V4L2_CID_GAIN;
		err = v4l2_g_ctrl(&priv->ctrl_handler, &control);
		control.value = IMX290_MIN_GAIN;
			
		printk(KERN_DEBUG "\n Start set V4L2_CID_FRAME_LENGTH \n"); 
		control.id = V4L2_CID_FRAME_LENGTH;
		err = v4l2_g_ctrl(&priv->ctrl_handler, &control);
		control.value = IMX290_DEFAULT_FRAME_LENGTH;
		
		printk(KERN_DEBUG "\n Start set V4L2_CID_COARSE_TIME \n");
		control.id = V4L2_CID_COARSE_TIME;
		err = v4l2_g_ctrl(&priv->ctrl_handler, &control);
		control.value = IMX290_DEFAULT_EXPOSURE_COARSE;
			
#endif

	return 0;
exit:
	dev_dbg(&client->dev, "%s: error setting stream\n", __func__);
	return err;
}

static int imx290_g_input_status(struct v4l2_subdev *sd, u32 *status)
{
	struct i2c_client *client = v4l2_get_subdevdata(sd);
	struct camera_common_data *s_data = to_camera_common_data(client);
	struct imx290 *priv = (struct imx290 *)s_data->priv;
	struct camera_common_power_rail *pw = &priv->power;

	*status = pw->state == SWITCH_ON;
	return 0;
}

static int imx290_get_fmt(struct v4l2_subdev *sd,
		struct v4l2_subdev_pad_config *cfg,
		struct v4l2_subdev_format *format)
{
	return camera_common_g_fmt(sd, &format->format);
}

static int imx290_set_fmt(struct v4l2_subdev *sd,
	struct v4l2_subdev_pad_config *cfg,
	struct v4l2_subdev_format *format)
{
	int ret;

	if (format->which == V4L2_SUBDEV_FORMAT_TRY)
		ret = camera_common_try_fmt(sd, &format->format);
	else
		ret = camera_common_s_fmt(sd, &format->format);

	return ret;
}

static struct v4l2_subdev_video_ops imx290_subdev_video_ops = {
	.s_stream	= imx290_s_stream,
	//.s_mbus_fmt	= camera_common_s_fmt,
	//.g_mbus_fmt	= camera_common_g_fmt,
	//.try_mbus_fmt	= camera_common_try_fmt,
	//.enum_mbus_fmt	= camera_common_enum_fmt,
	.g_mbus_config	= camera_common_g_mbus_config,
	.g_input_status	= imx290_g_input_status,
	//.enum_framesizes	= camera_common_enum_framesizes,
	//.enum_frameintervals	= camera_common_enum_frameintervals,
};

static struct v4l2_subdev_core_ops imx290_subdev_core_ops = {
	.s_power	= camera_common_s_power,
};

static struct v4l2_subdev_pad_ops imx290_subdev_pad_ops = {
	//.enum_mbus_code = camera_common_enum_mbus_code,
	.set_fmt = imx290_set_fmt,
	.get_fmt = imx290_get_fmt,
	.enum_mbus_code = camera_common_enum_mbus_code,
	.enum_frame_size	= camera_common_enum_framesizes,
	.enum_frame_interval	= camera_common_enum_frameintervals,	
};

static struct v4l2_subdev_ops imx290_subdev_ops = {
	.core	= &imx290_subdev_core_ops,
	.video	= &imx290_subdev_video_ops,
	.pad	= &imx290_subdev_pad_ops,
};

static struct of_device_id imx290_of_match[] = {
	{ .compatible = "nvidia,imx290", },
	{ },
};

static struct camera_common_sensor_ops imx290_common_ops = {
	.power_on = imx290_power_on,
	.power_off = imx290_power_off,
	.write_reg = imx290_write_reg,
	.read_reg = imx290_read_reg,
};

static int imx290_set_group_hold(struct imx290 *priv, s32 val)
{
	struct reg_8 reg_list[1];
	int err;
	int i = 0;

	imx290_get_hold_reg(reg_list, val);
		
	err = imx290_write_reg(priv->s_data, reg_list[i].addr,
		 reg_list[i].val);
	if (err)
		goto fail;

	return 0;

fail:
	dev_dbg(&priv->i2c_client->dev,
		 "%s: REGHOLD error\n", __func__);
	return err;

}

static int imx290_set_gain(struct imx290 *priv, s64 val)
{
	struct reg_8 reg_list[2];
	int err;
	u32 gain;
	s64 gain64;
	int i = 0;

	/* translate value */
	gain64 = (s64)(val / FIXED_POINT_SCALING_FACTOR);
	//gain = (u8)(gain64 * 240 / 72);
	gain = (u8)((val * 240) / (72*FIXED_POINT_SCALING_FACTOR));
	//dev_err(&priv->i2c_client->dev,
		//"%s:  gain reg: %d, db: %lld\n",  __func__, gain, gain64);


	imx290_get_gain_reg(reg_list, gain);

	err = imx290_write_reg(priv->s_data, reg_list[i].addr,
		 reg_list[i].val);
	if (err)
		goto fail;

	return 0;

fail:
	dev_dbg(&priv->i2c_client->dev,
		 "%s: GAIN control error\n", __func__);
	return err;
}

static int imx290_set_frame_length(struct imx290 *priv, s32 val)
{
	struct reg_8 reg_list[2];
	int err;
	u16 frame_length = (u16) val;
	int i = 0;

	frame_length = val;

	//dev_err(&priv->i2c_client->dev,
		// "%s: val: %d\n", __func__, frame_length);

	imx290_get_frame_length_regs(reg_list, frame_length);

	for (i = 0; i < 2; i++) {
		err = imx290_write_reg(priv->s_data, reg_list[i].addr,
			 reg_list[i].val);
		if (err)
			goto fail;
	}

	return 0;

fail:
	dev_dbg(&priv->i2c_client->dev,
		 "%s: FRAME_LENGTH control error\n", __func__);
	return err;
}

static int imx290_set_coarse_time(struct imx290 *priv, s32 val)
{
	struct reg_8 reg_list[2];
	int err;
	u16 coarse_time = (u16) val;
	int i = 0;


	if(val < IMX290_DEFAULT_FRAME_LENGTH )
	{
		coarse_time = IMX290_DEFAULT_FRAME_LENGTH - val - 1;
	}else{
		coarse_time = 0;
	}

	if(coarse_time < IMX290_MIN_EXPOSURE_COARSE)
	{
		coarse_time = IMX290_MIN_EXPOSURE_COARSE;
	}
	

	//dev_err(&priv->i2c_client->dev,
		// "%s: val: %d ,%d\n", __func__, coarse_time,val);

	imx290_get_coarse_time_regs(reg_list, coarse_time);

	for (i = 0; i < 2; i++) {
		err = imx290_write_reg(priv->s_data, reg_list[i].addr,
			 reg_list[i].val);
		if (err)
			goto fail;
	}

	return 0;

fail:
	dev_dbg(&priv->i2c_client->dev,
		 "%s: COARSE_TIME control error\n", __func__);
	return err;
}

/*static int imx290_verify_streaming(struct imx290 *priv)
{
	int err = 0;

	err = camera_common_s_power(priv->subdev, true);
	if (err)
		return err;

	err = imx290_s_stream(priv->subdev, true);
	if (err)
		goto error;

error:
	imx290_s_stream(priv->subdev, false);
	camera_common_s_power(priv->subdev, false);

	return err;
}
*/
static int imx290_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
{
	struct imx290 *priv =
		container_of(ctrl->handler, struct imx290, ctrl_handler);
	int err = 0;

	if (priv->power.state == SWITCH_OFF)
		return 0;

	switch (ctrl->id) {
	default:
		pr_err("%s: unknown ctrl id.\n", __func__);
		return -EINVAL;
	}

	return err;
}

static int imx290_s_ctrl(struct v4l2_ctrl *ctrl)
{
	struct imx290 *priv =
		container_of(ctrl->handler, struct imx290, ctrl_handler);
	int err = 0;

	if (priv->power.state == SWITCH_OFF)
		return 0;
	//dev_err(&priv->i2c_client->dev,
		//	"%s:  0x%X \n",  __func__, ctrl->id);

	switch (ctrl->id) {
	case V4L2_CID_GAIN:
		err = imx290_set_gain(priv, *ctrl->p_new.p_s64);
		break;
	case V4L2_CID_FRAME_LENGTH:
		err = imx290_set_frame_length(priv, ctrl->val);
		break;
	case V4L2_CID_COARSE_TIME:
		err = imx290_set_coarse_time(priv, ctrl->val);
		break;
	case V4L2_CID_GROUP_HOLD:
		err = imx290_set_group_hold(priv, ctrl->val);
		break;
	case V4L2_CID_HDR_EN:
		break;
	case V4L2_CID_FUSE_ID:
		break;
	default:
		pr_err("%s: unknown ctrl id.\n", __func__);
		return -EINVAL;
	}

	return err;
}

static int imx290_ctrls_init(struct imx290 *priv)
{
	struct i2c_client *client = priv->i2c_client;
	struct v4l2_ctrl *ctrl;
	int num_ctrls;
	int err;
	int i;

	dev_info(&client->dev, "%s++\n", __func__);

	num_ctrls = ARRAY_SIZE(ctrl_config_list);
	v4l2_ctrl_handler_init(&priv->ctrl_handler, num_ctrls);

	for (i = 0; i < num_ctrls; i++) {
		ctrl = v4l2_ctrl_new_custom(&priv->ctrl_handler,
			&ctrl_config_list[i], NULL);
		if (ctrl == NULL) {
			dev_err(&client->dev, "Failed to init %s ctrl\n",
				ctrl_config_list[i].name);
			continue;
		}

		if (ctrl_config_list[i].type == V4L2_CTRL_TYPE_STRING &&
			ctrl_config_list[i].flags & V4L2_CTRL_FLAG_READ_ONLY) {
			ctrl->p_new.p_char = devm_kzalloc(&client->dev,
				ctrl_config_list[i].max + 1, GFP_KERNEL);
			if (!ctrl->p_new.p_char) {
				dev_err(&client->dev,
					"Failed to allocate otp data\n");
				return -ENOMEM;
			}
		}
		priv->ctrls[i] = ctrl;
	}

	priv->num_ctrls = num_ctrls;
	priv->subdev->ctrl_handler = &priv->ctrl_handler;
	if (priv->ctrl_handler.error) {
		dev_err(&client->dev, "Error %d adding controls\n",
			priv->ctrl_handler.error);
		err = priv->ctrl_handler.error;
		goto error;
	}

	err = v4l2_ctrl_handler_setup(&priv->ctrl_handler);
	if (err) {
		dev_err(&client->dev,
			"Error %d setting default controls\n", err);
		goto error;
	}

	return 0;

error:
	v4l2_ctrl_handler_free(&priv->ctrl_handler);
	return err;
}

MODULE_DEVICE_TABLE(of, imx290_of_match);

static struct camera_common_pdata *imx290_parse_dt(struct i2c_client *client)
{
	struct device_node *np = client->dev.of_node;
	struct camera_common_pdata *board_priv_pdata;
	const struct of_device_id *match;
	int gpio, err;
	
	

	match = of_match_device(imx290_of_match, &client->dev);
	if (!match) {
		dev_err(&client->dev, "Failed to find matching dt id\n");
		return NULL;
	}
	


	board_priv_pdata = devm_kzalloc(&client->dev,
			   sizeof(*board_priv_pdata), GFP_KERNEL);
	if (!board_priv_pdata) {
		dev_err(&client->dev, "Failed to allocate pdata\n");
		return NULL;
	}


	err = of_property_read_string(np, "mclk", &board_priv_pdata->mclk_name);
	if (err) {
		dev_err(&client->dev, "mclk not in DT\n");
		goto error;
	}


	gpio = of_get_named_gpio(np, "reset-gpios", 0);
	if (gpio < 0) {
		dev_err(&client->dev, "reset gpios not in DT\n");
		goto error;
	}
	board_priv_pdata->reset_gpio = (unsigned int)gpio;


	err = of_property_read_string(np, "avdd-reg",
			&board_priv_pdata->regulators.avdd);
	if (err) {
		dev_err(&client->dev, "avdd-reg not in DT\n");
		goto error;
	}
	err = of_property_read_string(np, "dvdd-reg",
			&board_priv_pdata->regulators.dvdd);
	if (err) {
		dev_err(&client->dev, "dvdd-reg not in DT\n");
		goto error;
	}
	err = of_property_read_string(np, "iovdd-reg",
			&board_priv_pdata->regulators.iovdd);
	if (err) {
		dev_err(&client->dev, "iovdd-reg not in DT\n");
		goto error;
	}


	return board_priv_pdata;

error:
	devm_kfree(&client->dev, board_priv_pdata);
	return NULL;
}

static int imx290_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
	struct i2c_client *client = v4l2_get_subdevdata(sd);
	dev_dbg(&client->dev, "%s:\n", __func__);

	return 0;
}

static const struct v4l2_subdev_internal_ops imx290_subdev_internal_ops = {
	.open = imx290_open,
};

static const struct media_entity_operations imx290_media_ops = {
	.link_validate = v4l2_subdev_link_validate,
};

static int imx290_probe(struct i2c_client *client,
			const struct i2c_device_id *id)
{
	struct camera_common_data *common_data;
	struct device_node *node = client->dev.of_node;
	//struct soc_camera_link *imx290_iclink;
	struct imx290 *priv;
	char node_name[10];
	int err;




	if (!IS_ENABLED(CONFIG_OF) || !node)
		return -EINVAL;

	common_data = devm_kzalloc(&client->dev,
			    sizeof(struct camera_common_data), GFP_KERNEL);
	if (!common_data) {
		dev_err(&client->dev, "unable to allocate memory!\n");
		return -ENOMEM;
	}


	priv = devm_kzalloc(&client->dev,
			    sizeof(struct imx290) + sizeof(struct v4l2_ctrl *) *
			    ARRAY_SIZE(ctrl_config_list),
			    GFP_KERNEL);
	if (!priv) {
		dev_err(&client->dev, "unable to allocate memory!\n");
		return -ENOMEM;
	}


	priv->regmap = devm_regmap_init_i2c(client, &sensor_regmap_config);
	if (IS_ERR(priv->regmap)) {
		dev_err(&client->dev,
			"regmap init failed: %ld\n", PTR_ERR(priv->regmap));
		return -ENODEV;
	}


	/* HACK: use DT for parsing platform data when we are using */
	sprintf(node_name, "imx290_%c", 'c' + (client->adapter->nr - 30)*2);
	client->dev.of_node = of_find_node_by_name(NULL, node_name);


#if 0
	if (client->dev.of_node)
		priv->pdata = imx290_parse_dt(client);
	else {
		imx290_iclink = client->dev.platform_data;
		priv->pdata = imx290_iclink->dev_priv;
	}
#else
	priv->pdata = imx290_parse_dt(client);
	if (PTR_ERR(priv->pdata) == -EPROBE_DEFER) {
		devm_kfree(&client->dev, priv);
		return -EPROBE_DEFER;
	}
#endif

#if 1

	if (!priv->pdata) {
		dev_err(&client->dev, "unable to get platform data\n");
		return -EFAULT;
	}


	common_data->ops		= &imx290_common_ops;
	common_data->ctrl_handler	= &priv->ctrl_handler;
	common_data->i2c_client		= client;
	common_data->frmfmt		= &imx290_frmfmt[0];
	common_data->colorfmt		= camera_common_find_datafmt(
					  IMX290_DEFAULT_DATAFMT);
	common_data->power		= &priv->power;
	common_data->priv		= (void *)priv;
	//common_data->ident		= V4L2_IDENT_IMX290;
	common_data->numctrls		= ARRAY_SIZE(ctrl_config_list);
	common_data->numfmts		= ARRAY_SIZE(imx290_frmfmt);
	common_data->def_mode		= IMX290_DEFAULT_MODE;
	common_data->def_width		= IMX290_DEFAULT_WIDTH;
	common_data->def_height		= IMX290_DEFAULT_HEIGHT;
	common_data->fmt_width		= common_data->def_width;
	common_data->fmt_height		= common_data->def_height;
	common_data->def_clk_freq	= IMX290_DEFAULT_CLK_FREQ;

	priv->i2c_client		= client;
	priv->s_data			= common_data;
	priv->subdev			= &common_data->subdev;
	priv->subdev->dev		= &client->dev;

	err = imx290_power_get(priv);
	if (err)
		return err;


	camera_common_create_debugfs(common_data, "imx290");


	v4l2_i2c_subdev_init(&common_data->subdev, client, &imx290_subdev_ops);


	err = imx290_ctrls_init(priv);
	if (err)
		return err;


	gpio_request(priv->pdata->reset_gpio, "cam_reset_gpio");
	gpio_direction_output(priv->pdata->reset_gpio,1);

	//err = imx290_verify_streaming(priv);
	//if (err)
		//return err;


	priv->subdev->internal_ops = &imx290_subdev_internal_ops;
	priv->subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
		     V4L2_SUBDEV_FL_HAS_EVENTS;

#if defined(CONFIG_MEDIA_CONTROLLER)
	priv->pad.flags = MEDIA_PAD_FL_SOURCE;
	priv->subdev->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR;
	priv->subdev->entity.ops = &imx290_media_ops;
	err = media_entity_init(&priv->subdev->entity, 1, &priv->pad, 0);
	if (err < 0) {
		dev_err(&client->dev, "unable to init media entity\n");
		return err;
	}
#endif


	err = v4l2_async_register_subdev(priv->subdev);
	if (err)
		return err;
#endif
	dev_info(&client->dev, "Detected IMX290 sensor\n");

	return 0;
}

static int
imx290_remove(struct i2c_client *client)
{
	struct camera_common_data *s_data = to_camera_common_data(client);
	struct imx290 *priv = (struct imx290 *)s_data->priv;

	v4l2_async_unregister_subdev(priv->subdev);
#if defined(CONFIG_MEDIA_CONTROLLER)
	media_entity_cleanup(&priv->subdev->entity);
#endif

	v4l2_ctrl_handler_free(&priv->ctrl_handler);
	imx290_power_put(priv);
	camera_common_remove_debugfs(s_data);

	return 0;
}

static const struct i2c_device_id imx290_id[] = {
	{ "imx290", 0 },
	{ }
};

MODULE_DEVICE_TABLE(i2c, imx290_id);

static struct i2c_driver imx290_i2c_driver = {
	.driver = {
		.name = "imx290",
		.owner = THIS_MODULE,
		.of_match_table = of_match_ptr(imx290_of_match),
	},
	.probe = imx290_probe,
	.remove = imx290_remove,
	.id_table = imx290_id,
};

module_i2c_driver(imx290_i2c_driver);

MODULE_DESCRIPTION("SoC Camera driver for Sony IMX290");
MODULE_AUTHOR("Bryan Wu <pengw@nvidia.com>");
MODULE_LICENSE("GPL v2");

Thanks for the sample driver. After some fiddling I managed to get at least v4l2-ctl to capture something. The following command line seems works:

v4l2-ctl --set-fmt-video=width=<W>,height=<H>,pixelformat=RG12 --stream-mmap --set-ctrl bypass_mode=0 --stream-count=10 -d /dev/video0

If I provide invalid width/height on the command line, I even get the expexted errors like

[30137.267851] tegra-vi4 15700000.vi: Status:  4 channel:01 frame:0000
[30137.274161] tegra-vi4 15700000.vi:          timestamp sof 30143986525248 eof 30143986573024 data 0x00000200
[30137.283924] tegra-vi4 15700000.vi:          capture_id 14913 stream  0 vchan  0
[30138.241847] tegra-vi4 15700000.vi: PXL_SOF syncpt timeout! err = -11
[30139.245857] tegra-vi4 15700000.vi: ATOMP_FE syncpt timeout!

Still nothing using nvcamera-daemon, though. When using v4l2-ctl, I see the following messages in dmesg (after enabling them):

[30136.723433] tegra-vi4 15700000.vi: Create Surface with imgW=1948, imgH=1108, memFmt=32
[30136.724253] nvcsi 150c0000.nvcsi: csi port:0
[30136.724408] nvcsi 150c0000.nvcsi: csi4_start_streaming ports index=0, lanes=4
[30136.724413] nvcsi 150c0000.nvcsi: csi4_stream_init
[30136.724424] nvcsi 150c0000.nvcsi: csi4_stream_config
[30136.724434] nvcsi 150c0000.nvcsi: csi4_stream_config (0) read VC0_DPCM_CTRL = 00000000
[30136.724438] nvcsi 150c0000.nvcsi: csi4_phy_config
[30136.724443] nvcsi 150c0000.nvcsi: NVCSI_CIL_CONFIG = 00000000
[30136.724463] imx290 2-0031: imx290_s_stream++ enable 1

However, with nvcamera-daemon, I can’t see CSI being enabled:

[30328.349127] nvcsi 150c0000.nvcsi: csi port:0
[30328.349280] imx290 2-0031: imx290_s_stream++ enable 1

Can that be a problem??

In the mean time I’ve done more work on debugging the problem and it seems that I’m getting a “PIXEL_SHORT_LINE” in line #0 error from the VI. I had a hard time finding that out!

The interesting thing is that the

  • FPS = 30 Hz
  • mclk_khz = 25000 kHz
  • pix_clk_hz = 37.125 MHz * 4 = 148500000
  • settings in the DTB are all correct. I've tried mclk_multiplier values equal to and larger than pix_clk/mclk. I've set active_w and active_h to what the sensor is configured: 1948 x 1096. v4l2-ctl work with these settings: if I deviate by just a pixel it generates PIXEL_LONG_LINE or PIXEL_SHORT_LINE errors as expected.

    Still, I’m getting this PIXEL_SHORT_LINE error with nvcamera-daemon, mostly with line number < 3. Does nvcamera-daemon add any margins to the specified geometry? Is there a way to see how it does set-up the VI registers?

    @ShaneCCC: I’ve tried the settings you propose: they are for 10bit ADC and 60 FPS.

    They give the following error with v4l2-ctl:

    [   63.204461] tegra-vi4 15700000.vi: Status:  2 channel:00 frame:0010
    [   63.210804] tegra-vi4 15700000.vi:          timestamp sof 69938042368 eof 69954245664 data 0x00400060
    [   63.220068] tegra-vi4 15700000.vi:          capture_id 5 stream  0 vchan  0
    [   64.186779] tegra-vi4 15700000.vi: PXL_SOF syncpt timeout! err = -11
    [   65.190777] tegra-vi4 15700000.vi: ATOMP_FE syncpt timeout!
    [   65.196459] imx290 2-0031: imx290_s_stream++ enable 0
    [   65.197140] nvcsi 150c0000.nvcsi: csi4_stream_check_status (0) ERROR_STATUS2VI_VC0 = 0x00000004
    [   65.205851] nvcsi 150c0000.nvcsi: csi4_stream_check_status (0) INTR_STATUS 0x00000004
    [   65.213680] nvcsi 150c0000.nvcsi: csi4_stream_check_status (0) ERR_INTR_STATUS 0x00000004
    

    where, I think, Status==2 refers to an CSIMUX_FRAME error message and I can’t find the documentation to decode the data argument. But STATUS2VI_VC0 seems to indicate a CSI-2 Payload CRC error.

    Here’s what we get with nvcamera-daemon:

    Error: waitCsiFrameStart timeout guid 0
    VI Stream Id = 0 Virtual Channel = 0
    ************VI Debug Registers**********
    VI_CSIMUX_STAT_FRAME_0	 = 0x0001006a
    VI_CSIMUX_FRAME_STATUS_0	 = 0x00000001
    VI_CFG_INTERRUPT_STATUS_0	 = 0x3f000000
    VI_ISPBUFA_ERROR_0	 = 0x00000000
    VI_FMLITE_ERROR_0	 = 0x00000000
    VI_NOTIFY_ERROR_0	 = 0x00000000
    *****************************************
    CSI Stream Id = 0 Brick Id = 0
    ************CSI Debug Registers**********
    CILA_INTR_STATUS_CILA[0x10400]	 = 0x00000110
    CILB_INTR_STATUS_CILB[0x10c00]	 = 0x00000110
    INTR_STATUS[0x100a4]	 = 0x0000000e
    INTR_STATUS[0x100a4]	 = 0x0000000e
    ERR_INTR_STATUS[0x100ac]	 = 0x0000000e
    ERROR_STATUS2VI_VC0[0x10094]	 = 0x0000000e
    ERROR_STATUS2VI_VC1[0x10098]	 = 0x00000000
    ERROR_STATUS2VI_VC2[0x1009c]	 = 0x00000000
    ERROR_STATUS2VI_VC3[0x100a0]	 = 0x00000000
    *****************************************
    Error: waitCsiFrameStart Something went wrong with waiting on frame start
    

    Here, the STATUS2VI indicates PacketHeader ECC errors and “Word Count different from PacketHeader” as well as Payload Data CRC errors. Looks like it thinks to receive garbage on CSI lane #0.

    Switching back to 12-bit ADC still allows capturing via v4l2-ctl, which makes me think that the hardware is OK.

    I continued this topic in thread #1030505