Porting AR0135 + DS90UB964 driver to Jetson TX2 (Chansel Fault?)

Shortly after getting frames we have discovered that the frames itself are incorrect.
Our 12 bit pixel values are wrong. They are shifted 2 bits to the left and the lower 2 bits are mirrored versions of the two most significant bits of the 12 bit value.

Otherwise explained:
00BB AAAA AAAA AABB
A are the 10 least significat bits of our 12 bit raw value.
B are the 2 most significant bits of our 12 bit raw value.
So essentially the 2 most significant bits are mirroed on the low ones.
I would expect something like:
0000 BBAA AAAA AAAA

So we are kinda not finished here.
14 bits of the 16 bits are set which is impossible considering the CSI data type is RAW12. So I assume a mistake on the side of the TX2.

Well but now to your question. In fact i had it set to bayer_bggr in the first place. But now I’ve altered the kernel to actually have support for raw12 which I didn’t find inside the kernel.
But it still has the same issue

Here is my device tree part of relevance:

mode0 { // AR0135_MODE_1280X960
	mclk_khz = "25000";
	num_lanes = "2";
	tegra_sinterface = "serial_c";
	discontinuous_clk = "no";
	dpcm_enable = "false";
	cil_settletime = "0";

	active_w = "1280";
	//active_w = "1920"; //FIXME
	active_h = "960";
	pixel_t = "raw12";
	readout_orientation = "90";
	line_length = "1388";
	inherent_gain = "1";
	mclk_multiplier = "6.67";
	//pix_clk_hz = "74250000";
	pix_clk_hz = "160000000";

	min_gain_val = "1.0";
	max_gain_val = "16";
	min_hdr_ratio = "1";
	max_hdr_ratio = "64";
	min_framerate = "1.816577";
	max_framerate = "54";
	min_exp_time = "34";
	max_exp_time = "550385";
	embedded_metadata_height = "0";
};

But this is not supported inside the official kernel.
I’ve added to core.c

{
		TEGRA_VF_RAW12,
		12,
		MEDIA_BUS_FMT_SBGGR12_1X12,
		2,
		TEGRA_IMAGE_FORMAT_T_R16_I,
		TEGRA_IMAGE_DT_RAW12,
		V4L2_PIX_FMT_SBGGR12,
		"BGBG.. GRGR..",
	},

        /* RAW12 - This is new */
	{
		TEGRA_VF_RAW12,
		12,
		MEDIA_BUS_FMT_Y12_1X12,
		2,
		TEGRA_IMAGE_FORMAT_T_R16_I,
		TEGRA_IMAGE_DT_RAW12,
		V4L2_PIX_FMT_Y12,
		"RAW 12 Bit Grey",
	},

	/* RGB888 */
	{
		TEGRA_VF_RGB888,
		24,
		MEDIA_BUS_FMT_RGB888_1X24,
		4,
		TEGRA_IMAGE_FORMAT_T_A8R8G8B8,
		TEGRA_IMAGE_DT_RGB888,
		V4L2_PIX_FMT_ABGR32,
		"BGRA-8-8-8-8",
	},

And also in camera_common.c

static const struct camera_common_colorfmt camera_common_color_fmts[] = {
	{
		MEDIA_BUS_FMT_SRGGB12_1X12,
		V4L2_COLORSPACE_SRGB,
		V4L2_PIX_FMT_SRGGB12,
	},
	{
		MEDIA_BUS_FMT_SRGGB10_1X10,
		V4L2_COLORSPACE_SRGB,
		V4L2_PIX_FMT_SRGGB10,
	},
	{
		MEDIA_BUS_FMT_SRGGB8_1X8,
		V4L2_COLORSPACE_SRGB,
		V4L2_PIX_FMT_SRGGB8,
	},
	{ /* This is new */
		MEDIA_BUS_FMT_Y12_1X12,
		V4L2_COLORSPACE_RAW,
		V4L2_PIX_FMT_Y12,
	},
};

It was strange that only SRGGB was supported in the function camera_common_try_fmt(*). So I’ve modded this at the end:

if (mf->code != MEDIA_BUS_FMT_SRGGB8_1X8 &&
		mf->code != MEDIA_BUS_FMT_SRGGB10_1X10 &&
		mf->code != MEDIA_BUS_FMT_SRGGB12_1X12 &&
		mf->code != MEDIA_BUS_FMT_Y12_1X12)
	{
		mf->code = MEDIA_BUS_FMT_SRGGB10_1X10;
		err = -EINVAL;
	}

	mf->field = V4L2_FIELD_NONE;
	mf->colorspace = V4L2_COLORSPACE_SRGB;
	printk("camera_common_try_fmt wants to have SRGB.\n");

	if (mf->code == MEDIA_BUS_FMT_Y12_1X12)
	{
		printk("camera_common_try_fmt - But I will force RAW at this point FIXME\n");
		mf->colorspace = V4L2_COLORSPACE_RAW;
	}

	return err;
}

I’ve also added a type to soc_mediabus.c as only Y10 was supported here. But no Y12.

.code = MEDIA_BUS_FMT_Y10_1X10,
	.fmt = {
		.fourcc			= V4L2_PIX_FMT_Y10,
		.name			= "Grey 10bit",
		.bits_per_sample	= 10,
		.packing		= SOC_MBUS_PACKING_EXTEND16,
		.order			= SOC_MBUS_ORDER_LE,
		.layout			= SOC_MBUS_LAYOUT_PACKED,
	},
}, {
	.code = MEDIA_BUS_FMT_Y12_1X12, /* This is new */
	.fmt = {
		.fourcc			= V4L2_PIX_FMT_Y12,
		.name			= "Grey 12bit",
		.bits_per_sample	= 12,
		.packing		= SOC_MBUS_PACKING_EXTEND16,
		.order			= SOC_MBUS_ORDER_LE,
		.layout			= SOC_MBUS_LAYOUT_PACKED,
	},
}, {
	.code = MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE,
	.fmt = {
		.fourcc			= V4L2_PIX_FMT_SBGGR10,
		.name			= "Bayer 10 BGGR",
		.bits_per_sample	= 8,
		.packing		= SOC_MBUS_PACKING_2X8_PADHI,
		.order			= SOC_MBUS_ORDER_LE,
		.layout			= SOC_MBUS_LAYOUT_PACKED,
	},
}, {

Then I changed the support for the device tree in sensor_common.c:

static int extract_pixel_format(
	const char *pixel_t, u32 *format)
{
	size_t size = strnlen(pixel_t, OF_MAX_STR_LEN);

	if (strncmp(pixel_t, "bayer_bggr10", size) == 0)
		*format = V4L2_PIX_FMT_SBGGR10;
	else if (strncmp(pixel_t, "bayer_rggb10", size) == 0)
		*format = V4L2_PIX_FMT_SRGGB10;
	else if (strncmp(pixel_t, "bayer_bggr12", size) == 0)
		*format = V4L2_PIX_FMT_SBGGR12;
	else if (strncmp(pixel_t, "bayer_rggb12", size) == 0)
		*format = V4L2_PIX_FMT_SRGGB12;
	else if (strncmp(pixel_t, "bayer_wdr_pwl_rggb12", size) == 0)
		*format = V4L2_PIX_FMT_SRGGB12;
	else if (strncmp(pixel_t, "bayer_xbggr10p", size) == 0)
		*format = V4L2_PIX_FMT_XBGGR10P;
	else if (strncmp(pixel_t, "bayer_xrggb10p", size) == 0)
		*format = V4L2_PIX_FMT_XRGGB10P;
	else if (strncmp(pixel_t, "raw12", size) == 0)
	{
		*format = V4L2_PIX_FMT_Y12;
		printk("extract_pixel_format V4L2_PIX_FMT_Y12 *********************\n");
	}
	else {
		pr_err("%s: Need to extend format%s\n", __func__, pixel_t);
		return -EINVAL;
	}

	return 0;
}

Adding the driver to the kernel compile was done like this:

Adding

CONFIG_VIDEO_AR0135=y

to tegra18_defconfig.

Adding this to drivers/media/i2c/Kconfig:

config VIDEO_AR0135
        tristate "AR0135 camera sensor support"
        depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
        ---help---
          This is a Video4Linux2 sensor-level driver for the Aptina
          AR0135 imager.

Adding this to the Makefile next to that Kconfig:

obj-$(CONFIG_VIDEO_AR0135) += ar0135.o