Jetpack-5.0.2 migration : tegra camera subdev registration failed

Hi All,

I am migrating a camera driver (without using I2C) for Jetpack-4.5.1 to Jetpack-5.0.2 and facing following error :
[ 15.525536] toto 8-0010: probing v4l2 sensor without i2c.
[ 15.525658] toto 8-0010: tegra camera driver registration failed

Below is the probing function :

static int toto_probe(struct i2c_client *client,
                        const struct i2c_device_id *id)
{
        struct device *dev = &client->dev;
        struct device_node *node = client->dev.of_node;
        struct tegracam_device *tc_dev;
        struct toto *priv;
        int err;
        const struct of_device_id *match;

        dev_info(dev, "probing v4l2 sensor without i2c.\n");

        match = of_match_device(toto_of_match, dev);
        if (!match) {
                dev_err(dev, "No device match found\n");
                return -ENODEV;
        }

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

        priv = devm_kzalloc(dev,
                            sizeof(struct toto), GFP_KERNEL);
        if (!priv)
                return -ENOMEM;

        tc_dev = devm_kzalloc(dev,
                            sizeof(struct tegracam_device), GFP_KERNEL);
        if (!tc_dev)
                return -ENOMEM;

        priv->i2c_client = tc_dev->client = client;
        tc_dev->dev = dev;
        strncpy(tc_dev->name, "toto", sizeof(tc_dev->name));
        tc_dev->dev_regmap_config = &toto_regmap_config;
        tc_dev->sensor_ops = &toto_common_ops;
        tc_dev->v4l2sd_internal_ops = &toto_subdev_internal_ops;
        tc_dev->tcctrl_ops = &toto_ctrl_ops;

        err = tegracam_device_register(tc_dev);
        if (err) {
                dev_err(dev, "tegra camera driver registration failed\n");
                return err;
        }

        priv->tc_dev = tc_dev;
        priv->s_data = tc_dev->s_data;
        priv->subdev = &tc_dev->s_data->subdev;
        tegracam_set_privdata(tc_dev, (void *)priv);
        mutex_init(&priv->streaming_lock);

        err = tegracam_v4l2subdev_register(tc_dev, true);
        if (err) {
                dev_err(dev, "tegra camera subdev registration failed\n");
                return err;
        }

        dev_dbg(dev, "Detected TOTO sensor\n");

        return 0;
}

and device-tree node:

        i2c@31e0000 {
                status = "okay";
                #address-cells = <1>;
                #size-cells = <0>;

                toto_a@10 {
                        compatible = "sony,toto";

                        /* I2C device address */
                        reg = <0x10>;

                        /* V4L2 device node location */
                        devnode = "video0";

                        /* Physical dimensions of sensor */
                        physical_w = "1.944";
                        physical_h = "1.097";

                        sensor_model = "toto";
                        use_sensor_mode_id = "false";

                        /* Define any required hw resources needed by driver */
                        /* ie. clocks, io pins, power sources */
                        avdd-reg = "vana";
                        iovdd-reg = "vif";
                        dvdd-reg = "vdig";

                        /* Define any required hw resources needed by driver */
                        /* ie. clocks, io pins, power sources */
                        /* mclk-index indicates the index of the */
                        /* mclk-name with in the clock-names array */

                        clocks = <&bpmp_clks TEGRA194_CLK_EXTPERIPH1>,
                                 <&bpmp_clks TEGRA194_CLK_PLLP_OUT0>;
                        clock-names = "extperiph1", "pllp_grtba";

                        status = "okay";
                        mclk = "extperiph1";
                        clock-frequency = <24000000>;

                        vana-supply = <&p3509_vdd_3v3_cvb>;
                        vdig-supply = <&p3509_vdd_sys_en>;

                        mode0 {
                                mclk_khz = "24000";
                                num_lanes = "4";
                                tegra_sinterface = "serial_a";
                                phy_mode = "DPHY";
                                discontinuous_clk = "no";
                                dpcm_enable = "false";
                                cil_settletime = "0";

                                active_w = "1920";
                                active_h = "1080";
                                mode_type = "yuv";
                                pixel_phase = "uyvy";
                                pixel_t = "yuv_uyvy16";

                                dynamic_pixel_bit_depth = "16";
                                csi_pixel_bit_depth = "16";
                                readout_orientation = "0";
                                line_length = "1920";
                                inherent_gain = "1";
                                mclk_multiplier = "30";
                                pix_clk_hz = "742500000";

                                gain_factor = "10";
                                min_gain_val = "10";/* 1DB*/
                                max_gain_val = "160";/* 16DB*/
                                step_gain_val = "1";
                                default_gain = "10";
                                min_hdr_ratio = "1";
                                max_hdr_ratio = "1";
                                framerate_factor = "1000000";
                                min_framerate = "1816577";/*1.816577 */
                                max_framerate = "60000000";/*60fps*/
                                step_framerate = "1";
                                default_framerate = "60000000";/*60fps*/
                                exposure_factor = "1000000";
                                min_exp_time = "34";/* us */
                                max_exp_time = "550385";/* us */
                                step_exp_time = "1";
                                default_exp_time = "33334";/* us */
                                embedded_metadata_height = "0";
                        };

                        ports {
                                #address-cells = <1>;
                                #size-cells = <0>;
                                port@0 {
                                        reg = <0>;
                                        toto_out0: endpoint {
                                                status = "okay";
                                                port-index = <0>; /* CSI A */
                                                bus-width = <4>;
                                                remote-endpoint = <&toto_csi_in0>;
                                        };
                                };
                        };
                };
        };

I also updated the vi@xxx{} to tegra-capture-vi {} as per the following comment : Xavier NX MIPI CSI-2 without I2C from FPGA - #10 by ShaneCCC

I compared existing drivers btw the aforementioned Jetpacks such as kernel/nvidia/drivers/media/i2c/ov5693.c vs kernel/nvidia/drivers/media/i2c/nv_ov5693.c, kernel/nvidia/drivers/media/i2c/imx219.c vs kernel/nvidia/drivers/media/i2c/nv_imx219.c and kernel/nvidia/drivers/media/i2c/imx477.c vs kernel/nvidia/drivers/media/i2c/nv_imx477.c but did not see big evolution in probing function, except for :

static const struct regmap_config sensor_regmap_config = {
	.reg_bits = 16,
	.val_bits = 8,
	.cache_type = REGCACHE_RBTREE,
#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 4, 0)
	.use_single_rw = true,
#else
	.use_single_read = true,
	.use_single_write = true,
#endif
};

Could you help to point-out the potential issue, please ? Could it be related to enabling/disabling camera plugin that I haven’t touched ?

Best Regards,
K.

Suppose it could be some parameter for tegracam_device_register() cause the register failed.
Please trace into the tegracam_device_register() to figure out the root cause.

Thanks

For tegracam_v4l2subdev_register() in kernel/nvidia/drivers/media/platform/tegra/camera/tegracam_v4l2.c:

int tegracam_v4l2subdev_register(struct tegracam_device *tc_dev,
                                bool is_sensor)
{
        struct camera_common_data *s_data = tc_dev->s_data;
        struct tegracam_ctrl_handler *ctrl_hdl;
        struct v4l2_subdev *sd = NULL;
        struct device *dev = tc_dev->dev;
        int err = 0;

        if (!s_data) 
                return -EINVAL;

        ctrl_hdl = s_data->tegracam_ctrl_hdl;

        /* init v4l2 subdevice for registration */
        sd = &s_data->subdev;
        if (!sd || !tc_dev->client) {
                dev_err(dev, "Invalid subdev context\n");
                return -ENODEV;
        }

        v4l2_i2c_subdev_init(sd, tc_dev->client, &v4l2sd_ops);

        ctrl_hdl->ctrl_ops = tc_dev->tcctrl_ops;
        err = tegracam_ctrl_handler_init(ctrl_hdl);
        if (err) {
                dev_err(dev, "Failed to init ctrls %s\n", tc_dev->name);
                return err;
        }
        if (ctrl_hdl->ctrl_ops != NULL)
                tc_dev->numctrls = ctrl_hdl->ctrl_ops->numctrls;
        else
                tc_dev->numctrls = 0;
        s_data->numctrls = tc_dev->numctrls;
        sd->ctrl_handler = s_data->ctrl_handler = &ctrl_hdl->ctrl_handler;
        s_data->ctrls = ctrl_hdl->ctrls;
        sd->internal_ops = tc_dev->v4l2sd_internal_ops;
        sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
                        V4L2_SUBDEV_FL_HAS_EVENTS;
        s_data->owner = sd->owner;
        /* Set owner to NULL so we can unload the driver module */
        sd->owner = NULL;

#if defined(CONFIG_MEDIA_CONTROLLER)
        tc_dev->pad.flags = MEDIA_PAD_FL_SOURCE;
        sd->entity.ops = &media_ops;
        err = tegra_media_entity_init(&sd->entity,
                        1, &tc_dev->pad, true, is_sensor);
        if (err < 0) {
                dev_err(dev, "unable to init media entity\n");
                return err;
        }
#endif

        return v4l2_async_register_subdev(sd);
}
EXPORT_SYMBOL_GPL(tegracam_v4l2subdev_register);

I added more debug messages to trap the returns where there was not :

git diff kernel/nvidia/drivers/media/platform/tegra/camera/tegracam_v4l2.c
diff --git a/kernel/nvidia/drivers/media/platform/tegra/camera/tegracam_v4l2.c b/kernel/nvidia/drivers/media/platform/tegra/camera/tegracam_v4l2.c
index 8d0d16ca5..a0be9fcae 100644
--- a/kernel/nvidia/drivers/media/platform/tegra/camera/tegracam_v4l2.c
+++ b/kernel/nvidia/drivers/media/platform/tegra/camera/tegracam_v4l2.c
@@ -202,8 +202,10 @@ int tegracam_v4l2subdev_register(struct tegracam_device *tc_dev,
        struct device *dev = tc_dev->dev;
        int err = 0;
 
-       if (!s_data)
+       if (!s_data) {
+               dev_err(dev, "L4ES: Invalid data\n");
                return -EINVAL;
+       }
 
        ctrl_hdl = s_data->tegracam_ctrl_hdl;

And for v4l2_async_register_subdev() in kernel/kernel-5.10/drivers/media/v4l2-core/v4l2-async.c that is called by above tegracam_v4l2subdev_register():

int v4l2_async_register_subdev(struct v4l2_subdev *sd)
{
        struct v4l2_async_notifier *subdev_notifier;
        struct v4l2_async_notifier *notifier;
        int ret;

        /*
         * No reference taken. The reference is held by the device
         * (struct v4l2_subdev.dev), and async sub-device does not
         * exist independently of the device at any point of time.
         */
        if (!sd->fwnode && sd->dev)
                sd->fwnode = dev_fwnode(sd->dev);

        mutex_lock(&list_lock);

        INIT_LIST_HEAD(&sd->async_list);

        list_for_each_entry(notifier, &notifier_list, list) {
                struct v4l2_device *v4l2_dev =
                        v4l2_async_notifier_find_v4l2_dev(notifier);
                struct v4l2_async_subdev *asd;

                if (!v4l2_dev)
                        continue;

                asd = v4l2_async_find_match(notifier, sd);
                if (!asd)
                        continue;

                ret = v4l2_async_match_notify(notifier, v4l2_dev, sd, asd);
                if (ret)
                        goto err_unbind;

                ret = v4l2_async_notifier_try_complete(notifier);
                if (ret)
                        goto err_unbind;

                goto out_unlock;
        }

        /* None matched, wait for hot-plugging */
        list_add(&sd->async_list, &subdev_list);

out_unlock:
        mutex_unlock(&list_lock);

        return 0;

err_unbind:
        /*
         * Complete failed. Unbind the sub-devices bound through registering
         * this async sub-device.
         */
        subdev_notifier = v4l2_async_find_subdev_notifier(sd);
        if (subdev_notifier)
                v4l2_async_notifier_unbind_all_subdevs(subdev_notifier);

        if (sd->asd)
                v4l2_async_notifier_call_unbind(notifier, sd, sd->asd);
        v4l2_async_cleanup(sd);

        mutex_unlock(&list_lock);

        return ret;
}
EXPORT_SYMBOL(v4l2_async_register_subdev);

I applied following patch :

diff --git a/kernel/kernel-5.10/drivers/media/v4l2-core/v4l2-async.c b/kernel/kernel-5.10/drivers/media/v4l2-core/v4l2-async.c
index 33babe6e8..aad730369 100644
--- a/kernel/kernel-5.10/drivers/media/v4l2-core/v4l2-async.c
+++ b/kernel/kernel-5.10/drivers/media/v4l2-core/v4l2-async.c
@@ -770,20 +770,28 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd)
                        v4l2_async_notifier_find_v4l2_dev(notifier);
                struct v4l2_async_subdev *asd;
 
-               if (!v4l2_dev)
+               if (!v4l2_dev) {
+                       dev_warn(sd->dev, "L4ES: Invalid v4l2_dev\n");
                        continue;
+               }
 
                asd = v4l2_async_find_match(notifier, sd);
-               if (!asd)
+               if (!asd) {
+                       dev_warn(sd->dev, "L4ES: Invalid asd\n");
                        continue;
+               }
 
                ret = v4l2_async_match_notify(notifier, v4l2_dev, sd, asd);
-               if (ret)
+               if (ret) {
+                       dev_err(sd->dev, "L4ES: Error, v4l2_async_match_notify() returned %d\n", ret);
                        goto err_unbind;
+               }
 
                ret = v4l2_async_notifier_try_complete(notifier);
-               if (ret)
+               if (ret) {
+                       dev_err(sd->dev, "L4ES: Error, v4l2_async_notifier_try_complete() returned %d\n", ret);
                        goto err_unbind;
+               }
 
                goto out_unlock;
        }

But strangely, there seems no relevant message in to dmesg.

Hi @ShaneCCC ,

It seems that I was able to resolve this as it was my error still keeping vi@xxxxx{} within tegra-capture-vi{} . Now I have it probed :

rtr@ubuntu:~$ sudo dmesg | grep toto
[   11.085300] toto 8-0010: probing v4l2 sensor without i2c.
[   11.094084] toto 8-0010: tegracam sensor driver:toto_v2.0.6
[   11.103658] toto 8-0010: L4ES: Invalid asd
[   11.120714] tegra-camrtc-capture-vi tegra-capture-vi: subdev toto 8-0010 bound
[   11.123455] toto 8-0010: Detected TOTO sensor
[   12.309754] toto 8-0010: toto_open:
[   27.551952] toto 8-0010: toto_open:
[   35.899998] toto 8-0010: toto_open:

Thanks again for your support.

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.