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.

https://hastebin.com/muwotujezi.md

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