Tx1 CSI without I2c

Hello all. What I try to do is, we have a camera that outputs LVDS (Tamron MP1010M-VC), and we convert it to CSI-2 MIPI with an FPGA-Bridge. And we also configure the camera with this FPGA.

So we have such a block diagram. CAMERA --(LVDS)–> FPGA —(CSI)—> Jetson TX1

Since this camera doesn’t have an included driver with the Jetpack3.3, we try to modify the ov5693 driver accordingly. (We are using L4T-28.2.1)

Since we won’t configure the Camera with i2c, and with an external FPGA, we don’t need the i2c driven. But since people here said that I need an i2c, even if “dummy” I tried to create one that always return 0 with ov5693_write_reg and ov5693_read_reg, basically and’ed with 0 the returns.

The problem is that we’re unable to get video, nor register the /dev/video0.
/dev/video0 will be sufficient enough for us.

I’m also missing the /dev/video/ file, is that because there is no Camera CSI connected, or should I have had it available from the beginning, therefore I made a mistake in my driver/devicetree?

Thank you all for your replies and support.
Have a nice day! :)

Edit: I’m trying now the probe source code Dalt has suggested here; https://devtalk.nvidia.com/default/topic/1025863/jetson-tx2/how-to-grab-pre-configured-csi-video-stream-without-i2c-/post/5218418/#5218418

Will write back here. (He couldn’t get /dev/video0 with this one as well)

Edit2: Dalt’s suggestion didnt even compile… Had to change

common_data->i2c_client		= client;
...
err = camera_common_parse_ports(client, common_data);

to

common_data->dev		= &client->dev;
...
err = camera_common_parse_ports(&client->dev, common_data);

Still getting the same errors;

We mostly skipped the errors, but now it says;

my_in 6-0036: could not read otp bank
my_in 6-0036: Error -121 reading otp data

1)As far as I know, OTP means One-Time Programmable. Are those important? Or can I just skip configuring them?

(Commented them out, and got to the end)

Now It comes down until

[OV5693]: Detected OV5693 sensor.

2)But it doesn’t still register the device, /dev/video0. What can I do?

(I commented a lot of code, so I want you to please check it out)

https://devtalk.nvidia.com/default/topic/1025863/jetson-tx2/how-to-grab-pre-configured-csi-video-stream-without-i2c-/2

Comment #18 (number is written in the right bottom corner)

The mod proposed a function, and Dalt’s problem is solved somehow.

3)Did you also modify this function to see video0 in /dev/ ? Thank you! :))

I try to use the command;

v4l2-ctl -d /dev/video0 --set-ctrl bypass_mode=0 --stream-mmap --stream-count=1 --stream-to=test.raw

but it says that v4l2-ctl: command not found

4)When I debugged the channel.c;

vi 54080000.vi : initialized
vi 54080000.vi : ep of_device is not enabled /host1x/vi/port@0/endpoint.
vi 54080000.vi : ep of_device is not enabled /host1x/vi/port@1/endpoint.
vi 54080000.vi : ep of_device is not enabled /host1x/vi/port@2/endpoint.
vi 54080000.vi : ep of_device is not enabled /host1x/vi/port@3/endpoint.
vi 54080000.vi : all channel register failed

Is this because of device-tree?

Please have a check the sensor programing guide to use Main Platform Device Tree File instead of plugin manager.

file:///C:/JEP%20Forum/document/l4t-documentation-28.2/nvl4t_docs/Tegra%20Linux%20Driver%20Package%20Development%20Guide/camera_sensor_prog.html#wwpID0E0XE0HA

I’ve already checked it, but I have some problems regarding the guide.

To register a device using main-platform device tree files

  1. Locate and edit the following file:
    • TX1:
    /hardware/nvidia/platform/t210/jetson/kernel-dts/tegra210-jetson-cv-base-p25970-2180-a00.dts
    • TX2:
    /hardware/nvidia/platform/t18x/quill/kernel-dts/tegra186-quill-p3310-1000-a00-00-base.dtsi
  2. In the DTSI, remove the following line:
    • TX1:
    #include “jetson-plugin-manager/tegra210-jetson-cv-camera-plugin-manager.dtsi”
    • TX2:
    #include <t18x-common-plugin-manager/tegra186-quill-camera-plugin-manager.dtsi"
  3. Locate and edit the following file:
    • TX1:
    /hardware/nvidia/platform/t210/jetson/kernel-dts/tegra210-jetson-cv-base-p2597-2180-a00.dts
    • TX2:
    /hardware/nvidia/platform/t18x/quill/kernel-dts/tegra186-quill-p3310-1000-a00-00-base.dts
  4. In the DTS file, replace the following line:
    • TX1:
    #include “jetson-platforms/tegra210-jetson-cv-camera-modules.dtsi”
    • TX2:
    #include <t18x-common-platforms/tegra186-quill-camera-modules.dtsi>
    With an #include statement specifying the DTSI file for your new device.
    Note:
    Use tegra210-jetson-cv-camera-modules.dtsi or tegra18x-quill-cv-camera-modules.dtsi as a model for generating your DTSI. In your file, change status = disable to status = okay.

I’ll explain the steps I’ve taken according to this.

1) /hardware/nvidia/platform/t210/jetson/kernel-dts/tegra210-jetson-cv-base-p25970-2180-a00.dts, there is no such file.

There only is tegra210-jetson-cv-base-p2597-2180-a00.dts in my kernel source. Are they the same and is the extra “0” is just a typo?

So I moved on edited the dts file without a “0”. (tegra210-jetson-cv-base-p2597-2180-a00.dts)

deleted the line

#include "jetson-plugin-manager/tegra210-jetson-cv-camera-plugin-manager.dtsi"

and replaced the line

#include "jetson-platforms/tegra210-jetson-cv-camera-modules.dtsi"

with the line

#include "jetson-platforms/tegra210-camera-e3326-a00.dtsi"

Didn’t under stand what it means by

Note:
Use tegra210-jetson-cv-camera-modules.dtsi or tegra18x-quill-cv-camera-modules.dtsi as a model for generating your DTSI. In your file, change status = disable to status = okay.

Havent we just removed this file? Didnt do anything about Note*, skipped that part.

now when I dmesg after flashing to TX1,

vi 54080000.vi: initialized
vi 54080000.vi: subdev nvcsi-2 bound
vi 54080000.vi: subdev my_in 6-0036 bound
vi 54080000.vi: all channel register failed

but the modification added

v4l-subdev0
v4l-subdev1

devices to /dev
What should be my next moves? Still I can’t seem to register /dev/video0

Please enable the dev_debug() in ov5693.c to check the message.

Just add below at most top of the file to build the kernel image.
#define DEBUG

Did what you say;

the result of the dmesg is now this; (Not sure if #define DEBUG really worked, but here it goes)

There are some of my personal print debugs, you can just ignore them.

This function (just so you know the numeration)

int tegra_vi_channels_register(struct tegra_mc_vi *vi)
{
	int ret = 0;
	struct tegra_channel *it;
	int count = 0;

	pr_info("[OV5693]: channel.c tegra_vi_channels_register 1.\n");
	list_for_each_entry(it, &vi->vi_chans, list) {
		struct v4l2_subdev *sd = it->subdev_on_csi;
		bool is_csi = false;

		pr_info("[OV5693]: channel.c tegra_vi_channels_register 2.\n");
		if (sd) {
			/*
			 * If subdevice on csi is csi itself,
			 * then sensor subdevice is not connected
			 */
			pr_info("[OV5693]: channel.c tegra_vi_channels_register 3.\n");
			is_csi = strstr(sd->name, "nvcsi") != NULL;
			pr_info("[OV5693]: channel.c tegra_vi_channels_register 4.\n");

			if (is_csi)
			pr_info("[OV5693]: channel.c tegra_vi_channels_register 5.\n");
				continue;
		} else
		pr_info("[OV5693]: channel.c tegra_vi_channels_register 6.\n");
			continue;

		if (!it->init_done)
			continue;
		pr_info("[OV5693]: channel.c tegra_vi_channels_register 7.\n");	
		ret = video_register_device(&it->video, VFL_TYPE_GRABBER, -1);
		pr_info("[OV5693]: channel.c tegra_vi_channels_register 8.\n");
		if (ret < 0) {
			pr_info("[OV5693]: channel.c tegra_vi_channels_register 9.\n");
			dev_err(&it->video.dev, "failed to register %s\n",
				it->video.name);
			continue;
		}
		count++;
	}

	if (count == 0) {
		dev_err(vi->dev, "all channel register failed\n");
		return ret;
	}

	return 0;
}

prints;

[    4.111678] vi 54080000.vi: subdev nvcsi-2 bound
[    4.111682] vi 54080000.vi: subdev my_in 6-0036 bound
[    4.111932] [OV5693]: channel.c tegra_vi_channels_register 1.
[    4.111933] [OV5693]: channel.c tegra_vi_channels_register 2.
[    4.111934] [OV5693]: channel.c tegra_vi_channels_register 3.
[    4.111935] [OV5693]: channel.c tegra_vi_channels_register 4.
[    4.111937] vi 54080000.vi: all channel register failed

What’s my_in for? driver name?

Yes.

static const struct i2c_device_id my_in_id[] = {
	{ "my_in", 0 },
	{ }
};

MODULE_DEVICE_TABLE(i2c, my_in_id);

static struct i2c_driver my_i2c_driver = {
    .driver =
    {
	.name = "my_in",
	.owner = THIS_MODULE,
	.of_match_table = of_match_ptr(my_hd_in_of_match),
    },
    .probe = ov5693_probe,
    .remove = ov5693_remove,
    .id_table = my_in_id,
};

OK, then did you change the devname in the DT?

devname = “ov5693 6-0036”;

Didn’t change it, is it necessary? Saw people make it work even without a devname

Yes, and below need to match with kernel driver.

	compatible = "my_video_in";

Compatible is already there.

So I need to add;

devname = “my_video_in”;

?

No, you need modify both of them to below.

devname = “my_in”;
compatible = “my_in”;

Are you sure? Because the driver’s being called right now. Otherwise these errors wouldnt even be there…

in ov5693.c file, I also have

static struct of_device_id my_hd_in_of_match[] = {
	{ .compatible = "my_video_in", },
	{ },
};

Which I believe connects the DT with this kernel driver.

Cant get past the line 30 of this function, if (!it->init_done)
I can comment it out, but I believe there will be more problems later on, when we try to capture the video.

Check line 30 here;

int tegra_vi_channels_register(struct tegra_mc_vi *vi)
{
	int ret = 0;
	struct tegra_channel *it;
	int count = 0;

	pr_info("[OV5693]: channel.c tegra_vi_channels_register 1.\n");
	list_for_each_entry(it, &vi->vi_chans, list) {
		struct v4l2_subdev *sd = it->subdev_on_csi;
		bool is_csi = false;

		pr_info("[OV5693]: channel.c tegra_vi_channels_register 2.\n");
		if (sd) {
			/*
			 * If subdevice on csi is csi itself,
			 * then sensor subdevice is not connected
			 */
			pr_info("[OV5693]: channel.c tegra_vi_channels_register 3.\n");
			is_csi = strstr(sd->name, "nvcsi") != NULL;
			pr_info("[OV5693]: channel.c tegra_vi_channels_register 4.\n");

			if (is_csi)
			pr_info("[OV5693]: channel.c tegra_vi_channels_register 5.\n");
				continue;
		} else
			continue;
		pr_info("[OV5693]: channel.c tegra_vi_channels_register 6.\n");
	

		<b>if (!it->init_done)</b>
			continue;
		pr_info("[OV5693]: channel.c tegra_vi_channels_register 7.\n");	
		ret = video_register_device(&it->video, VFL_TYPE_GRABBER, -1);
		pr_info("[OV5693]: channel.c tegra_vi_channels_register 8.\n");
		if (ret < 0) {
			pr_info("[OV5693]: channel.c tegra_vi_channels_register 9.\n");
			dev_err(&it->video.dev, "failed to register %s\n",
				it->video.name);
			continue;
		}
		count++;
	}

	if (count == 0) {
		dev_err(vi->dev, "all channel register failed\n");
		return ret;
	}

	return 0;
});
		return ret;
	}

	return 0;
}

Error is still;

vi 54080000.vi: initialized
vi 54080000.vi: subdev nvcsi-2 bound
vi 54080000.vi: subdev my_in 6-0036 bound
vi 54080000.vi: all channel register failed

I guess my biggest mistake is that I commented out ov5693_read_otp_bank, ov5693_otp_setup, ov5693_fuse_id_setup. They just return 0 in my code.

Are they usefull in capturing video or just configuring the camera? Thank you.

@hburaksaruhan
No, the opt and fuse does matter for the video register.

opt ?= otp
When I uncomment them, I get the error,

my_in 6-0036: could not read otp bank
my_in 6-0036: Error -121 reading otp data

If you could tell me which function’s DO NOT matter for the operation, that could be faster for dummying out an i2c. :)) (We configure the camera with an outer FPGA)

Both of them fuse otp function can remove.

I didn’t understand it correctly, I can remove “ov5693_read_otp_bank, ov5693_otp_setup, ov5693_fuse_id_setup” ?