Kernel Panic with Shipped IMX185 Driver

I’m trying to bring up a MIPI camera on the Xavier, and keep running into issues where the kernel panics in tegra_channel_get_sensor_type

To make things as simple as possible, I tried to use the IMX185 driver as a starting point, then will change it over to our sensor. I’ve made the following changes in the DTSI files:

diff --git a/common/tegra194-p2822-camera-modules.dtsi b/common/tegra194-p2822-camera-modules.dtsi
index 358ea6b..a363180 100644
--- a/common/tegra194-p2822-camera-modules.dtsi
+++ b/common/tegra194-p2822-camera-modules.dtsi
@@ -59,10 +59,10 @@
                vi_base: vi@15c10000 {
                        ports {
                                vi_port0: port@0 {
-                                       status = "disabled";
+                                       status = "okay";
                                        vi_in0: endpoint {
                                                vc-id = <0>;
-                                               status = "disabled";
+                                               status = "okay";
                                        };
                                };
                                vi_port1: port@1 {
@@ -105,18 +105,18 @@
                csi_base: nvcsi@15a00000 {
                        num-tpg-channels = <36>;
                        csi_chan0: channel@0 {
-                               status = "disabled";
+                               status = "okay";
                                ports {
                                        csi_chan0_port0: port@0 {
-                                               status = "disabled";
+                                               status = "okay";
                                                csi_in0: endpoint@0 {
-                                                       status = "disabled";
+                                                       status = "okay";
                                                };
                                        };
                                        csi_chan0_port1: port@1 {
-                                               status = "disabled";
+                                               status = "okay";
                                                csi_out0: endpoint@1 {
-                                                       status = "disabled";
+                                                       status = "okay";
                                                };
                                        };
                                };
@@ -272,7 +272,7 @@
                        };
                };
                tca9546_70: tca9546@70 {
-                       status = "disabled";
+                       status = "okay";
                        i2c@0 {
                                pca9570_a_24: pca9570_a@24 {
                                        status = "disabled";
@@ -281,7 +281,7 @@
                                        status = "disabled";
                                };
                                imx185_cam0: imx185_a@1a {
-                                       status = "disabled";
+                                       status = "okay";
                                };
                                e3331_cam0: imx318_a@10 {
                                        status = "disable";
diff --git a/tegra194-p2888-0001-p2822-0000.dts b/tegra194-p2888-0001-p2822-0000.dts
index f4073db..be037e1 100644
--- a/tegra194-p2888-0001-p2822-0000.dts
+++ b/tegra194-p2888-0001-p2822-0000.dts
@@ -14,4 +14,4 @@
  */
 #include "common/tegra194-p2888-0001-p2822-0000-common.dtsi"
 #include "common/tegra194-p2822-camera-modules.dtsi"
-#include "t19x-common-modules/tegra194-camera-plugin-manager.dtsi"
+/* #include "t19x-common-modules/tegra194-camera-plugin-manager.dtsi" */

And in the IMX185 driver to skip the I2C probe:

diff --git a/drivers/media/i2c/imx185.c b/drivers/media/i2c/imx185.c
index a69f558ea..18af37910 100644
--- a/drivers/media/i2c/imx185.c
+++ b/drivers/media/i2c/imx185.c
@@ -691,23 +691,6 @@ static struct camera_common_sensor_ops imx185_common_ops = {

 static int imx185_fuse_id_setup(struct imx185 *priv)
 {
-       int err;
-       int i;
-       struct camera_common_data *s_data = priv->s_data;
-       struct device *dev = s_data->dev;
-       u8 bak = 0;
-
-       for (i = 0; i < IMX185_FUSE_ID_SIZE; i++) {
-               err |= imx185_read_reg(s_data,
-                       IMX185_FUSE_ID_ADDR + i, &bak);
-               if (!err)
-                       priv->fuse_id[i] = bak;
-               else {

-                       dev_err(dev, "%s: can not read fuse id\n", __func__);
-                       return -EINVAL;
-               }
-       }
-
        return 0;
 }

The kernel then panics inside tegra_channel_get_sensor_type (full stack)

[    7.940527] [<ffffff8008b09424>] tegra_channel_populate_dev_info+0xbc/0x188
[    7.940529] [<ffffff8008b0a990>] tegra_channel_init_subdevices+0x2c0/0x738
[    7.940532] [<ffffff8008b0bb50>] tegra_vi_graph_notify_complete+0x500/0x688
[    7.940537] [<ffffff8008aefd98>] v4l2_async_test_notify+0x108/0x120
[    7.940539] [<ffffff8008aefedc>] v4l2_async_notifier_register+0x12c/0x1a0
[    7.940542] [<ffffff8008b0c808>] tegra_vi_graph_init+0x210/0x290
[    7.940544] [<ffffff8008b06958>] tegra_vi_media_controller_init+0x1a0/0x1d8
[    7.940549] [<ffffff80085507c8>] vi5_priv_late_probe+0x118/0x130
[    7.940551] [<ffffff80085508ac>] vi5_probe+0xcc/0xd0
[    7.940554] [<ffffff8008759780>] platform_drv_probe+0x60/0xc8
[    7.940556] [<ffffff8008756d48>] driver_probe_device+0xd0/0x3f8
[    7.940559] [<ffffff800875724c>] __device_attach_driver+0xb4/0x160
[    7.940561] [<ffffff8008754964>] bus_for_each_drv+0x6c/0xa8
[    7.940563] [<ffffff8008756abc>] __device_attach+0xcc/0x160
[    7.940565] [<ffffff8008757374>] device_initial_probe+0x24/0x30
[    7.940567] [<ffffff8008755c38>] bus_probe_device+0xa0/0xa8
[    7.940569] [<ffffff8008756268>] deferred_probe_work_func+0x90/0xe0
[    7.940575] [<ffffff80080d4e58>] process_one_work+0x1e8/0x490
[    7.940578] [<ffffff80080d533c>] worker_thread+0x23c/0x4c0
[    7.940581] [<ffffff80080dbb28>] kthread+0xd8/0xf0
[    7.940585] [<ffffff8008083850>] ret_from_fork+0x10/0x40

In particular, to_camera_common_data returns NULL when called on sd->dev. It looks like the subdevice node is actually host1x/nvcsi@15a00000, so when it’s trying to look for mode0, it fails since it isn’t on the i2c device host1x/i2c@3180000/tca9546@70/imx185_a@1a

Am I doing something wrong in my DTSI configuration?

hello thorntonc,

this due to there’s no camera devices registered.
suggest you could check Sensor Driver Programming Guide and also the [V4L2 Sensor Driver Development Tutorial] in the Tutorials page for reference,
thanks

Thanks, eventually figured it out. My “tegra-camera-platform” node was getting clobbered from all the versions from the camera specific files that were being included from tegra194-p2822-camera-modules.dtsi. I’d suggest that the “Sensor Driver Programming Guide: Using Main Platform Device” section be updated to mention that the other devices should be commented out (or a mention to double check that the tegra-camera-platform node isn’t being overwritten by some other file).

(Also, the file mentioned in step 3 has a typo, it’s missing the tegra194 instead of t194)

Separately, I think there is still a slight logic bug in tegra_vi_get_port_info. If your config files specify more than one port (but have the last one disabled), the return value of this function will indicate an error, even though it successfully matched the index at an earlier iteration of the loop. I think the attached patch fixes it, or maybe there is a note somewhere in the programming guide that I missed that mentions how you should configure your vi node to only have the ports/endpoints you need.)

diff --git a/drivers/media/platform/tegra/camera/vi/graph.c b/drivers/media/platform/tegra/camera/vi/graph.c
index 896c58103..70b63ba25 100644
--- a/drivers/media/platform/tegra/camera/vi/graph.c
+++ b/drivers/media/platform/tegra/camera/vi/graph.c
@@ -524,10 +524,11 @@ int tegra_vi_get_port_info(struct tegra_channel *chan,
                                next_port = (next_port % (NVCSI_PORT_H + 1));
                                chan->port[i] = next_port;
                        }
+                       return 0;
                }
        }

-       return ret;
+       return -ENOENT;
 }

hello thorntonc,

thanks for the review comments,
I will check what’s we can do to improve the documentation.
thanks