İ.MX8 Dual Camera Under Single MIPI CSI

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

İ.MX8 Dual Camera Under Single MIPI CSI

Jump to solution
1,644 Views
kayakaantuna
Contributor III

Hi all,

 

I want to get stream from two of my cameras in single MIPI CSI. Currently I have the setup below:

kayakaantuna_0-1729161764913.png


I did find some useful information on the below forum post:

bring up dual Camera under single mipi csi 

however, those modifications didn't work for me, but it was a good head start.

I change the device tree like below:

 

	fragment@9 {
		target = <&irqsteer_csi0>;
		__overlay__ {
			status = "okay";
		};
	};

	fragment@10 {
		target = <&irqsteer_csi1>;
		__overlay__ {
			status = "okay";
		};
	};

	fragment@11 {
		target = <&mipi_csi_0>;
		__overlay__  {
			#address-cells = <1>;
			#size-cells = <0>;
			status = "okay";

			/* Camera 0 MIPI CSI-2 (CSIS0) */
            port@0 {
                reg = <0>;
                mipi_csi0_ep_0: endpoint {
                    remote-endpoint = <&as0149_serdes_ep_0>;
                    data-lanes = <1 2>;
					csis-hs-settle = <10>;
                };
            };
			port@2 {
                reg = <2>;
                mipi_csi0_ep_1: endpoint {
                    remote-endpoint = <&as0149_serdes_ep_1>;
                    data-lanes = <1 2>;
					csis-hs-settle = <10>;
                };
            };
		};
	};

	fragment@12 {
		target = <&isi_0>;
		__overlay__ {
			status = "okay";

			cap_device {
				status = "okay";
			};

			m2m_device {
				status = "okay";
			};
		};
	};
	fragment@12 {
		target = <&isi_1>;
		__overlay__ {
			status = "okay";

			cap_device {
				status = "okay";
			};

			m2m_device {
				status = "okay";
			};
		};
	};

	fragment@13 {
		target = <&mipi_csi_1>;
		__overlay__  {
			#address-cells = <1>;
			#size-cells = <0>;
			status = "okay";

			/* Camera 2 MIPI CSI-2 (CSIS2) */
            port@1 {
                reg = <1>;
                mipi_csi1_ep_0: endpoint {
                    remote-endpoint = <&as0149_serdes_ep_2>;
                    data-lanes = <1 2>;
                };
            };
			port@3 {
                reg = <3>;
                mipi_csi1_ep_1: endpoint {
                    remote-endpoint = <&as0149_serdes_ep_3>;
                    data-lanes = <1 2>;
                };
            };

            /* Camera 3 MIPI CSI-2 (CSIS3) */
		};
	};

	fragment@14 {
		target = <&isi_4>;
		__overlay__ {
			status = "okay";

			cap_device {
				status = "okay";
			};

			m2m_device {
				status = "okay";
			};
		};
	};
	fragment@14 {
		target = <&isi_5>;
		__overlay__ {
			status = "okay";

			cap_device {
				status = "okay";
			};

			m2m_device {
				status = "okay";
			};
		};
	};
};

 

 
and here is the changes I made on the `imx8-mipi-csi2-sam.c` and `imx8-media-dev.c`. 

 

diff --git a/drivers/staging/media/imx/imx8-media-dev.c b/drivers/staging/media/imx/imx8-media-dev.c
index 0d0355844eab..c18a1b15265f 100644
--- a/drivers/staging/media/imx/imx8-media-dev.c
+++ b/drivers/staging/media/imx/imx8-media-dev.c
@@ -35,8 +35,8 @@
 #define ISI_OF_NODE_NAME	"isi"
 #define MIPI_CSI2_OF_NODE_NAME  "csi"
 
-#define MXC_MAX_SENSORS		3
-#define MXC_MIPI_CSI2_MAX_DEVS	2
+#define MXC_MAX_SENSORS		4
+#define MXC_MIPI_CSI2_MAX_DEVS	4
 
 #define MXC_NAME_LENS		32
 
@@ -516,6 +516,7 @@ static int mxc_md_create_links(struct mxc_md *mxc_md)
 				  source->name, sink->name);
 		} else if (mxc_md->mipi_csi2[sensor->id].sd) {
 			mipi_csi2 = &mxc_md->mipi_csi2[sensor->id];
+			v4l2_info(&mxc_md->v4l2_dev, "sensor->id is (%d)\n", sensor->id);//joan
 
 			source = &sensor->sd->entity;
 			sink = find_entity_by_name(mxc_md, mipi_csi2->sd_name);
@@ -523,7 +524,9 @@ static int mxc_md_create_links(struct mxc_md *mxc_md)
 			sink_pad = source_pad;
 
 			mipi_vc = (mipi_csi2->vchannel) ? 4 : 1;
+			v4l2_info(&mxc_md->v4l2_dev, "mipi_vc is (%d)\n", mipi_vc);
 			for (j = 0; j < mipi_vc; j++) {
+				v4l2_info(&mxc_md->v4l2_dev, "j is (%d)\n", j);
 				ret = media_create_pad_link(source,
 							    source_pad + j,
 							    sink,
@@ -958,8 +961,8 @@ static int mxc_md_register_platform_entities(struct mxc_md *mxc_md,
 static int register_sensor_entities(struct mxc_md *mxc_md)
 {
 	struct device_node *parent = mxc_md->pdev->dev.of_node;
-	struct device_node *node, *ep, *rem;
-	struct v4l2_fwnode_endpoint endpoint;
+	struct device_node *node, *ep, *ep1, *rem, *rem1;
+	struct v4l2_fwnode_endpoint endpoint, endpoint1;
 	struct i2c_client *client;
 	struct v4l2_async_subdev *asd;
 	int index = 0;
@@ -967,9 +970,12 @@ static int register_sensor_entities(struct mxc_md *mxc_md)
 
 	mxc_md->num_sensors = 0;
 
+	v4l2_info(&mxc_md->v4l2_dev, "port full name is %s\n", mxc_md->pdev->dev.of_node->name);//joan
+
 	/* Attach sensors linked to MIPI CSI2 / paralle csi / HDMI Rx */
 	for_each_available_child_of_node(parent, node) {
 		struct device_node *port;
+		struct device_node *port1;
 
 		if (!of_node_cmp(node->name, HDMI_RX_OF_NODE_NAME)) {
 			mxc_md->sensor[index].fwnode = of_fwnode_handle(node);
@@ -990,16 +996,25 @@ static int register_sensor_entities(struct mxc_md *mxc_md)
 			continue;
 
 		/* csi2 node have only port */
-		port = of_get_next_child(node, NULL);
+		//port = of_get_next_child(node, NULL);//joan
+		port1 = of_get_next_child(node, NULL);//joan
+		port = of_get_next_child(node, port1);//joan
+		v4l2_info(&mxc_md->v4l2_dev, "port full name is %s\n", port->full_name);//joan
+		v4l2_info(&mxc_md->v4l2_dev, "port name is %s\n", port->name);//joan
 		if (!port)
 			continue;
 
 		/* port can have only endpoint */
 		ep = of_get_next_child(port, NULL);
+		ep1 = of_get_next_child(port1, NULL);
+		v4l2_info(&mxc_md->v4l2_dev, "ep full name is %s and ep name is %s\n", ep->full_name, ep->name);//joan
+
 		if (!ep)
 			return -EINVAL;
 
 		memset(&endpoint, 0, sizeof(endpoint));
+		memset(&endpoint1, 0, sizeof(endpoint1));
+		ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep1), &endpoint1);
 		ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep), &endpoint);
 		if (WARN_ON(endpoint.base.port >= MXC_MAX_SENSORS || ret)) {
 			v4l2_err(&mxc_md->v4l2_dev,
@@ -1007,14 +1022,21 @@ static int register_sensor_entities(struct mxc_md *mxc_md)
 			return -EINVAL;
 		}
 
+		if (endpoint1.base.port ==2)//joan
+			endpoint1.base.port=0; //joan
+		if (endpoint1.base.port ==3)//joan
+			endpoint1.base.port=1; //joan
 		mxc_md->sensor[index].id = endpoint.base.port;
+		mxc_md->sensor[index+1].id = endpoint1.base.port;
 
 		if (!of_node_cmp(node->name, MIPI_CSI2_OF_NODE_NAME))
 			mxc_md->sensor[index].mipi_mode = true;
 
 		/* remote port---sensor node */
+		rem1 = of_graph_get_remote_port_parent(ep1);
 		rem = of_graph_get_remote_port_parent(ep);
 		of_node_put(ep);
+		of_node_put(ep1);
 		if (!rem) {
 			v4l2_info(&mxc_md->v4l2_dev,
 				  "Remote device at %s not found\n",
@@ -1025,6 +1047,7 @@ static int register_sensor_entities(struct mxc_md *mxc_md)
 		/*
 		 * Need to wait sensor driver probed for the first time
 		 */
+		client = of_find_i2c_device_by_node(rem1);
 		client = of_find_i2c_device_by_node(rem);
 		if (!client) {
 			v4l2_info(&mxc_md->v4l2_dev,
@@ -1033,7 +1056,12 @@ static int register_sensor_entities(struct mxc_md *mxc_md)
 			return -EPROBE_DEFER;
 		}
 
+		mxc_md->sensor[index+1].fwnode = of_fwnode_handle(rem1);
 		mxc_md->sensor[index].fwnode = of_fwnode_handle(rem);
+		asd = v4l2_async_notifier_add_fwnode_subdev(
+						&mxc_md->subdev_notifier,
+						mxc_md->sensor[index+1].fwnode,
+						struct v4l2_async_subdev);
 		asd = v4l2_async_notifier_add_fwnode_subdev(
 						&mxc_md->subdev_notifier,
 						mxc_md->sensor[index].fwnode,
@@ -1043,9 +1071,9 @@ static int register_sensor_entities(struct mxc_md *mxc_md)
 			return PTR_ERR(asd);
 		}
 
-		mxc_md->num_sensors++;
+		mxc_md->num_sensors += 2;
 
-		index++;
+		index += 2;
 	}
 
 	return 0;
@@ -1118,8 +1146,8 @@ static int mxc_md_probe(struct platform_device *pdev)
 				mxc_md_clean_unlink_channels(mxc_md);
 			} else {
 				/* no sensors connected */
-				mxc_md_unregister_all(mxc_md);
-				v4l2_async_notifier_unregister(&mxc_md->subdev_notifier);
+				//mxc_md_unregister_all(mxc_md);
+				//v4l2_async_notifier_unregister(&mxc_md->subdev_notifier);
 			}
 		}
 	}
@@ -1168,7 +1196,19 @@ static struct platform_driver mxc_md_driver = {
 	.remove = mxc_md_remove,
 };
 
-module_platform_driver(mxc_md_driver);
+
+static int __init mxc_md_driver_init(void)
+{
+	return platform_driver_register(&mxc_md_driver);
+}
+
+static void __exit mxc_md_driver_exit(void)
+{
+	platform_driver_unregister(&mxc_md_driver);
+}
+
+late_initcall(mxc_md_driver_init);
+module_exit(mxc_md_driver_exit);
 
 MODULE_AUTHOR("Freescale Semiconductor, Inc.");
 MODULE_DESCRIPTION("MXC Media Device driver");
diff --git a/drivers/staging/media/imx/imx8-mipi-csi2-sam.c b/drivers/staging/media/imx/imx8-mipi-csi2-sam.c
index 1d12365520a6..c94dd8ee721d 100644
--- a/drivers/staging/media/imx/imx8-mipi-csi2-sam.c
+++ b/drivers/staging/media/imx/imx8-mipi-csi2-sam.c
@@ -46,7 +46,7 @@
 
 #define CSIS_DRIVER_NAME		"mxc-mipi-csi2-sam"
 #define CSIS_SUBDEV_NAME		"mxc-mipi-csi2"
-#define CSIS_MAX_ENTITIES		2
+#define CSIS_MAX_ENTITIES		4
 #define CSIS0_MAX_LANES			4
 #define CSIS1_MAX_LANES			2
 
@@ -1486,6 +1486,7 @@ static int mipi_csis_parse_dt(struct platform_device *pdev,
 			    struct csi_state *state)
 {
 	struct device_node *node = pdev->dev.of_node;
+	struct device_node *node1;
 
 	state->index = of_alias_get_id(node, "csi");
 
@@ -1495,7 +1496,9 @@ static int mipi_csis_parse_dt(struct platform_device *pdev,
 	if (of_property_read_u32(node, "bus-width", &state->max_num_lanes))
 		return -EINVAL;
 
-	node = of_graph_get_next_endpoint(node, NULL);
+	//node = of_graph_get_next_endpoint(node, NULL);
+	node1 = of_graph_get_next_endpoint(node, NULL);
+	node = of_graph_get_next_endpoint(node, node1);
 	if (!node) {
 		dev_err(&pdev->dev, "No port node\n");
 		return -EINVAL;
@@ -1505,10 +1508,14 @@ static int mipi_csis_parse_dt(struct platform_device *pdev,
 	of_property_read_u32(node, "csis-hs-settle", &state->hs_settle);
 	of_property_read_u32(node, "csis-clk-settle", &state->clk_settle);
 	of_property_read_u32(node, "data-lanes", &state->num_lanes);
+	of_property_read_u32(node1, "csis-hs-settle", &state->hs_settle);
+	of_property_read_u32(node1, "csis-clk-settle", &state->clk_settle);
+	of_property_read_u32(node1, "data-lanes", &state->num_lanes);
 
 	state->wclk_ext = of_property_read_bool(node, "csis-wclk");
 
 	of_node_put(node);
+	of_node_put(node1);
 	return 0;
 }
 

 


with the above changes I manage to get this log from the dmesg:

 

[   13.882103] mxc-mipi-csi2 58227000.csi: lanes: 2, name: mxc-mipi-csi2.0
[   13.910417] mxc-mipi-csi2 58247000.csi: lanes: 2, name: mxc-mipi-csi2.1
[   13.925936] mxc-isi 58110000.isi: mxc_isi.1 registered successfully
[   13.933616] mxc-isi 58150000.isi: mxc_isi.5 registered successfully
[   13.945677] mx8-img-md: Registered mxc_isi.1.capture as /dev/video2
[   13.952694] mx8-img-md: Registered mxc_isi.5.capture as /dev/video3
[   13.959160] mx8-img-md: port full name is camera
[   13.963813] mx8-img-md: port full name is port@0
[   13.968440] mx8-img-md: port name is port
[   13.972455] mx8-img-md: ep full name is endpoint and ep name is endpoint
[   13.979270] mx8-img-md: port full name is port@1
[   13.983896] mx8-img-md: port name is port
[   13.987913] mx8-img-md: ep full name is endpoint and ep name is endpoint
[   13.994738] mx8-img-md: Registered sensor subdevice: as0149 3-005f (1)
[   14.002070] mx8-img-md: Registered sensor subdevice: as0149 3-005e (2)
[   14.009413] mx8-img-md: created link [mxc_isi.1] => [mxc_isi.1.capture]
[   14.016050] mx8-img-md: created link [mxc-mipi-csi2.0] => [mxc_isi.1]
[   14.022527] mx8-img-md: created link [mxc_isi.5] => [mxc_isi.5.capture]
[   14.029150] mx8-img-md: created link [mxc-mipi-csi2.1] => [mxc_isi.5]
[   14.035616] mx8-img-md: sensor->id is (1)
[   14.039634] mx8-img-md: mipi_vc is (1)
[   14.043386] mx8-img-md: j is (0)
[   14.046632] mx8-img-md: created link [as0149 3-005f] => [mxc-mipi-csi2.1]
[   14.054212] mx8-img-md: sensor->id is (1)
[   14.058238] mx8-img-md: mipi_vc is (1)
[   14.061997] mx8-img-md: j is (0)
[   14.065228] mx8-img-md: created link [as0149 3-005e] => [mxc-mipi-csi2.1]
[   14.072817] mxc-md bus@58000000:camera: mxc_md_create_links
[   14.078833] mxc-md bus@58000000:camera: mxc_md_do_clean get remote pad fail
[   14.085829] mxc_md_clean_unlink_channels: clean channel fail(0)

 


however as you can see I have a remote pad fail error, and also below error:

 

[   18.034390] mxc-mipi-csi2.0: is_entity_link_setup, No remote pad found!

 



I can see that it links on the media-ctl:

 

root@sm2s-imx8:~/test-suite/camera# media-ctl -p -d 1
Media controller API version 5.15.71

Media device information
------------------------
driver          mxc-md
model           FSL Capture Media Device
serial          
bus info        
hw revision     0x0
driver version  5.15.71

Device topology
- entity 1: mxc_isi.1 (16 pads, 2 links)
            type V4L2 subdev subtype Unknown flags 0
	pad0: Sink
	pad1: Sink
		<- "mxc-mipi-csi2.0":5 [ENABLED]
	pad2: Sink
	pad3: Sink
	pad4: Sink
	pad5: Sink
	pad6: Sink
	pad7: Sink
	pad8: Sink
	pad9: Sink
	pad10: Sink
	pad11: Sink
	pad12: Source
		-> "mxc_isi.1.capture":0 [ENABLED]
	pad13: Source
	pad14: Source
	pad15: Sink

- entity 18: mxc_isi.1.capture (1 pad, 1 link)
             type Node subtype V4L flags 0
             device node name /dev/video2
	pad0: Sink
		<- "mxc_isi.1":12 [ENABLED]

- entity 22: mxc_isi.5 (16 pads, 2 links)
             type V4L2 subdev subtype Unknown flags 0
	pad0: Sink
	pad1: Sink
	pad2: Sink
	pad3: Sink
	pad4: Sink
	pad5: Sink
		<- "mxc-mipi-csi2.1":5 [ENABLED]
	pad6: Sink
	pad7: Sink
	pad8: Sink
	pad9: Sink
	pad10: Sink
	pad11: Sink
	pad12: Source
		-> "mxc_isi.5.capture":0 [ENABLED]
	pad13: Source
	pad14: Source
	pad15: Sink

- entity 39: mxc_isi.5.capture (1 pad, 1 link)
             type Node subtype V4L flags 0
             device node name /dev/video3
	pad0: Sink
		<- "mxc_isi.5":12 [ENABLED]

- entity 43: mxc-mipi-csi2.0 (8 pads, 1 link)
             type Node subtype V4L flags 0
             device node name /dev/v4l-subdev0
	pad0: Sink
	pad1: Sink
	pad2: Sink
	pad3: Sink
	pad4: Source
	pad5: Source
		-> "mxc_isi.1":1 [ENABLED]
	pad6: Source
	pad7: Source

- entity 52: mxc-mipi-csi2.1 (8 pads, 3 links)
             type Node subtype V4L flags 0
             device node name /dev/v4l-subdev1
	pad0: Sink
		<- "as0149 3-005f":0 [ENABLED,IMMUTABLE]
		<- "as0149 3-005e":0 [ENABLED,IMMUTABLE]
	pad1: Sink
	pad2: Sink
	pad3: Sink
	pad4: Source
	pad5: Source
		-> "mxc_isi.5":5 [ENABLED]
	pad6: Source
	pad7: Source

- entity 61: as0149 3-005f (1 pad, 1 link)
             type V4L2 subdev subtype Sensor flags 0
	pad0: Source
		-> "mxc-mipi-csi2.1":0 [ENABLED,IMMUTABLE]

- entity 63: as0149 3-005e (1 pad, 1 link)
             type V4L2 subdev subtype Sensor flags 0
	pad0: Source
		-> "mxc-mipi-csi2.1":0 [ENABLED,IMMUTABLE]

 

 

however when I try to stream I get the following error:

 

[ 1271.639925] subdev->entity.num_pads = 16
[ 1271.639952] subdev->entity.num_pads = 8
[ 1271.644613] mxc-mipi-csi2.0: is_entity_link_setup, No remote pad found!
[ 1271.655623] subdev->entity.num_pads = 16
[ 1271.655638] subdev->entity.num_pads = 8
[ 1271.659931] subdev->entity.num_pads = 16
[ 1271.685547] subdev->entity.num_pads = 16
[ 1271.689520] subdev->entity.num_pads = 8
[ 1271.693488] mxc-mipi-csi2.0: is_entity_link_setup, No remote pad found!
[ 1271.706157] subdev->entity.num_pads = 16
[ 1271.706178] mxc-mipi-csi2.0: mipi_csi2_enum_framesizes, No remote pad found!
[ 1271.717394] subdev->entity.num_pads = 16
[ 1271.717408] mxc-mipi-csi2.0: mipi_csi2_enum_framesizes, No remote pad found!
[ 1271.728498] subdev->entity.num_pads = 16
[ 1271.728509] mxc-mipi-csi2.0: mipi_csi2_enum_framesizes, No remote pad found!
[ 1271.739767] subdev->entity.num_pads = 16
[ 1271.739788] mxc-mipi-csi2.0: mipi_csi2_enum_framesizes, No remote pad found!
[ 1271.754653] subdev->entity.num_pads = 16
[ 1271.754669] mxc-mipi-csi2.0: mipi_csi2_enum_framesizes, No remote pad found!
[ 1271.768329] subdev->entity.num_pads = 16
[ 1271.768344] mxc-mipi-csi2.0: mipi_csi2_enum_framesizes, No remote pad found!
[ 1271.779549] subdev->entity.num_pads = 16
[ 1271.779561] mxc-mipi-csi2.0: mipi_csi2_enum_framesizes, No remote pad found!
[ 1271.790708] subdev->entity.num_pads = 16
[ 1271.790727] mxc-mipi-csi2.0: mipi_csi2_enum_framesizes, No remote pad found!
[ 1271.803980] subdev->entity.num_pads = 16
[ 1271.803996] mxc-mipi-csi2.0: mipi_csi2_g_frame_interval, No remote pad found!
[ 1271.837543] subdev->entity.num_pads = 16
[ 1271.837568] mxc-mipi-csi2.0: mipi_csi2_s_power, No remote pad found!
[ 1271.847946] mxc_isi.1: Call subdev s_power fail!

 

 

maybe if I solve the padding error I might able to get a stream ? hopefully :). Can you help me on this ? I kind of stuck at this. 

Thanks!

Tags (1)
0 Kudos
Reply
1 Solution
1,181 Views
kayakaantuna
Contributor III

Hi all,

Below you can find how you can create virtual channels in i.mx8 board. I manage to create 4 virtual channels and get a stream from all 4 of them:

diff --git a/drivers/staging/media/imx/imx8-media-dev.c b/drivers/staging/media/imx/imx8-media-dev.c
index 0d0355844..4d86eadc0 100644
--- a/drivers/staging/media/imx/imx8-media-dev.c
+++ b/drivers/staging/media/imx/imx8-media-dev.c
@@ -35,8 +35,8 @@
 #define ISI_OF_NODE_NAME	"isi"
 #define MIPI_CSI2_OF_NODE_NAME  "csi"
 
-#define MXC_MAX_SENSORS		3
-#define MXC_MIPI_CSI2_MAX_DEVS	2
+#define MXC_MAX_SENSORS		4
+#define MXC_MIPI_CSI2_MAX_DEVS	4
 
 #define MXC_NAME_LENS		32
@@ -515,7 +517,11 @@ static int mxc_md_create_links(struct mxc_md *mxc_md)
 				  "created link [%s] => [%s]\n",
 				  source->name, sink->name);
 		} else if (mxc_md->mipi_csi2[sensor->id].sd) {
-			mipi_csi2 = &mxc_md->mipi_csi2[sensor->id];
+			if(mxc_md->mipi_csi2[i].sd == 0)
+				mipi_csi2 = &mxc_md->mipi_csi2[1];
+			else
+				mipi_csi2 = &mxc_md->mipi_csi2[0];
+			v4l2_info(&mxc_md->v4l2_dev, "sensor->id is (%d)\n", sensor->id);
 
 			source = &sensor->sd->entity;
 			sink = find_entity_by_name(mxc_md, mipi_csi2->sd_name);
@@ -523,7 +529,12 @@ static int mxc_md_create_links(struct mxc_md *mxc_md)
 			sink_pad = source_pad;
 
 			mipi_vc = (mipi_csi2->vchannel) ? 4 : 1;
+			v4l2_info(&mxc_md->v4l2_dev, "mipi_vc is (%d)\n", mipi_vc);
 			for (j = 0; j < mipi_vc; j++) {
+				v4l2_info(&mxc_md->v4l2_dev, "j is (%d), sink pad is (%d), source_pad is (%d)\n", j, sink_pad, source_pad);
+				if(sensor->id == 1)
+					sink_pad++;
+				
 				ret = media_create_pad_link(source,
 							    source_pad + j,
 							    sink,
@@ -958,8 +969,8 @@ static int mxc_md_register_platform_entities(struct mxc_md *mxc_md,
 static int register_sensor_entities(struct mxc_md *mxc_md)
 {
 	struct device_node *parent = mxc_md->pdev->dev.of_node;
-	struct device_node *node, *ep, *rem;
-	struct v4l2_fwnode_endpoint endpoint;
+	struct device_node *node, *ep, *ep1, *rem, *rem1;
+	struct v4l2_fwnode_endpoint endpoint, endpoint1;
 	struct i2c_client *client;
 	struct v4l2_async_subdev *asd;
 	int index = 0;
@@ -967,9 +978,12 @@ static int register_sensor_entities(struct mxc_md *mxc_md)
 
 	mxc_md->num_sensors = 0;
 
+	v4l2_info(&mxc_md->v4l2_dev, "port full name is %s\n", mxc_md->pdev->dev.of_node->name);
+
 	/* Attach sensors linked to MIPI CSI2 / paralle csi / HDMI Rx */
 	for_each_available_child_of_node(parent, node) {
 		struct device_node *port;
+		struct device_node *port1;
 
 		if (!of_node_cmp(node->name, HDMI_RX_OF_NODE_NAME)) {
 			mxc_md->sensor[index].fwnode = of_fwnode_handle(node);
@@ -990,16 +1004,25 @@ static int register_sensor_entities(struct mxc_md *mxc_md)
 			continue;
 
 		/* csi2 node have only port */
-		port = of_get_next_child(node, NULL);
+		//port = of_get_next_child(node, NULL);
+		port1 = of_get_next_child(node, NULL);
+		port = of_get_next_child(node, port1);
+		v4l2_info(&mxc_md->v4l2_dev, "port full name is %s\n", port->full_name);
+		v4l2_info(&mxc_md->v4l2_dev, "port name is %s\n", port->name);
 		if (!port)
 			continue;
 
 		/* port can have only endpoint */
 		ep = of_get_next_child(port, NULL);
+		ep1 = of_get_next_child(port1, NULL);
+		v4l2_info(&mxc_md->v4l2_dev, "ep full name is %s and ep name is %s\n", ep->full_name, ep->name);
+
 		if (!ep)
 			return -EINVAL;
 
 		memset(&endpoint, 0, sizeof(endpoint));
+		memset(&endpoint1, 0, sizeof(endpoint1));
+		ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep1), &endpoint1);
 		ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep), &endpoint);
 		if (WARN_ON(endpoint.base.port >= MXC_MAX_SENSORS || ret)) {
 			v4l2_err(&mxc_md->v4l2_dev,
@@ -1007,14 +1030,21 @@ static int register_sensor_entities(struct mxc_md *mxc_md)
 			return -EINVAL;
 		}
 
+		if (endpoint1.base.port ==2)
+			endpoint1.base.port=1;
 		mxc_md->sensor[index].id = endpoint.base.port;
+		mxc_md->sensor[index+1].id = endpoint1.base.port;
 
 		if (!of_node_cmp(node->name, MIPI_CSI2_OF_NODE_NAME))
 			mxc_md->sensor[index].mipi_mode = true;
 
 		/* remote port---sensor node */
+		rem1 = of_graph_get_remote_port_parent(ep1);
 		rem = of_graph_get_remote_port_parent(ep);
 		of_node_put(ep);
+		of_node_put(ep1);
 		if (!rem) {
 			v4l2_info(&mxc_md->v4l2_dev,
 				  "Remote device at %s not found\n",
@@ -1025,6 +1055,7 @@ static int register_sensor_entities(struct mxc_md *mxc_md)
 		/*
 		 * Need to wait sensor driver probed for the first time
 		 */
+		client = of_find_i2c_device_by_node(rem1);
 		client = of_find_i2c_device_by_node(rem);
 		if (!client) {
 			v4l2_info(&mxc_md->v4l2_dev,
@@ -1033,7 +1064,12 @@ static int register_sensor_entities(struct mxc_md *mxc_md)
 			return -EPROBE_DEFER;
 		}
 
+		mxc_md->sensor[index+1].fwnode = of_fwnode_handle(rem1);
 		mxc_md->sensor[index].fwnode = of_fwnode_handle(rem);
+		asd = v4l2_async_notifier_add_fwnode_subdev(
+						&mxc_md->subdev_notifier,
+						mxc_md->sensor[index+1].fwnode,
+						struct v4l2_async_subdev);
 		asd = v4l2_async_notifier_add_fwnode_subdev(
 						&mxc_md->subdev_notifier,
 						mxc_md->sensor[index].fwnode,
@@ -1043,9 +1079,9 @@ static int register_sensor_entities(struct mxc_md *mxc_md)
 			return PTR_ERR(asd);
 		}
 
-		mxc_md->num_sensors++;
+		mxc_md->num_sensors += 2;
 
-		index++;
+		index += 2;
 	}
 
 	return 0;

diff --git a/drivers/staging/media/imx/imx8-mipi-csi2-sam.c b/drivers/staging/media/imx/imx8-mipi-csi2-sam.c
index 1d1236552..d2ba5c890 100644
--- a/drivers/staging/media/imx/imx8-mipi-csi2-sam.c
+++ b/drivers/staging/media/imx/imx8-mipi-csi2-sam.c
@@ -46,7 +46,7 @@
 
 #define CSIS_DRIVER_NAME		"mxc-mipi-csi2-sam"
 #define CSIS_SUBDEV_NAME		"mxc-mipi-csi2"
-#define CSIS_MAX_ENTITIES		2
+#define CSIS_MAX_ENTITIES		4
 #define CSIS0_MAX_LANES			4
 #define CSIS1_MAX_LANES			2
 
@@ -1486,6 +1486,7 @@ static int mipi_csis_parse_dt(struct platform_device *pdev,
 			    struct csi_state *state)
 {
 	struct device_node *node = pdev->dev.of_node;
+	struct device_node *node1;
 
 	state->index = of_alias_get_id(node, "csi");
 
@@ -1495,7 +1496,9 @@ static int mipi_csis_parse_dt(struct platform_device *pdev,
 	if (of_property_read_u32(node, "bus-width", &state->max_num_lanes))
 		return -EINVAL;
 
-	node = of_graph_get_next_endpoint(node, NULL);
+	//node = of_graph_get_next_endpoint(node, NULL);
+	node1 = of_graph_get_next_endpoint(node, NULL);
+	node = of_graph_get_next_endpoint(node, node1);
 	if (!node) {
 		dev_err(&pdev->dev, "No port node\n");
 		return -EINVAL;
 


its very messy way to do such thing but for now, it works without an issue. 

The above code basically parses device tree and connects two cameras into csi2.0 and other two to csi2.1. And since we have isi subdevices you can get a stream from all 4 of them.

Hopefully this will help someone in future.  

View solution in original post

0 Kudos
Reply
6 Replies
1,617 Views
Bio_TICFSL
NXP TechSupport
NXP TechSupport

Hello,

Have you connected the MIPI port? since it looks like you are not attached nothing on it, please try the latest BSP it include support for dual camera, but check your hardware camera firts.

Regards

0 Kudos
Reply
1,607 Views
kayakaantuna
Contributor III

Hello Bio_TICFSL,

Yes I connect my camera into mipi_csi_1. Where can I find the `latest BSP` ? 

 

thanks

0 Kudos
Reply
1,529 Views
kayakaantuna
Contributor III

Hello @Bio_TICFSL,

 

I check out the latest BSP, if I understood it correctly, the approach is basically didn't changed.

 

I can get some output from video3 and video4, which is both connected to csi2.0.

[   14.313983] mx8-img-md: num_sensors is (4)
[   14.318097] mx8-img-md: sensor is (as0149 2-005f), sd (69904512)
[   14.324920] mx8-img-md: sensor->id is (0)
[   14.328947] mx8-img-md: mipi_vc is (1)
[   14.332708] mx8-img-md: j is (0)
[   14.335973] mx8-img-md: created link [as0149 2-005f] => [mxc-mipi-csi2.0]
[   14.343561] mx8-img-md: sensor is (as0149 2-005e), sd (70127744)
[   14.350392] mx8-img-md: sensor->id is (1)
[   14.354419] mx8-img-md: mipi_vc is (1)
[   14.358179] mx8-img-md: j is (0)
[   14.361413] mx8-img-md: created link [as0149 2-005e] => [mxc-mipi-csi2.0]
[   14.369019] mx8-img-md: sensor is ((efault)), sd (0)
[   14.374009] mx8-img-md: sensor is ((efault)), sd (0)
[   14.378987] mxc-md bus@58000000:camera: mxc_md_create_links

 

but the output is green, and at the top of the screen there are statics. Like below:

kayakaantuna_0-1729490439884.jpeg


How can I possibly solve this ? Also from media-ctl -p -d 1:

- entity 85: mxc-mipi-csi2.0 (8 pads, 4 links)
             type Node subtype V4L flags 0
             device node name /dev/v4l-subdev0
	pad0: Sink
		<- "as0149 2-005f":0 [ENABLED,IMMUTABLE]
		<- "as0149 2-005e":0 [ENABLED,IMMUTABLE]
	pad1: Sink
	pad2: Sink
	pad3: Sink
	pad4: Source
		-> "mxc_isi.0":0 [ENABLED]
	pad5: Source
		-> "mxc_isi.1":1 [ENABLED]
	pad6: Source
	pad7: Source


I see both of my cameras connected to port0, which basically means when I try to stream from video3 or video4 both of my cameras tries to go into stream. May be this is the problem why I'm getting the green screen output from the MIPI CSI ?

I appreciate any help I can get on this. 

Thanks.

0 Kudos
Reply
1,600 Views
kayakaantuna
Contributor III

Hi,

My kernel version is 5.15.71_2.2.0, the one you linked is Linux 6.6.36_2.1.0. Is it possible to compare the changes and apply it on my own and work it that way ?

Thanks.

0 Kudos
Reply
1,182 Views
kayakaantuna
Contributor III

Hi all,

Below you can find how you can create virtual channels in i.mx8 board. I manage to create 4 virtual channels and get a stream from all 4 of them:

diff --git a/drivers/staging/media/imx/imx8-media-dev.c b/drivers/staging/media/imx/imx8-media-dev.c
index 0d0355844..4d86eadc0 100644
--- a/drivers/staging/media/imx/imx8-media-dev.c
+++ b/drivers/staging/media/imx/imx8-media-dev.c
@@ -35,8 +35,8 @@
 #define ISI_OF_NODE_NAME	"isi"
 #define MIPI_CSI2_OF_NODE_NAME  "csi"
 
-#define MXC_MAX_SENSORS		3
-#define MXC_MIPI_CSI2_MAX_DEVS	2
+#define MXC_MAX_SENSORS		4
+#define MXC_MIPI_CSI2_MAX_DEVS	4
 
 #define MXC_NAME_LENS		32
@@ -515,7 +517,11 @@ static int mxc_md_create_links(struct mxc_md *mxc_md)
 				  "created link [%s] => [%s]\n",
 				  source->name, sink->name);
 		} else if (mxc_md->mipi_csi2[sensor->id].sd) {
-			mipi_csi2 = &mxc_md->mipi_csi2[sensor->id];
+			if(mxc_md->mipi_csi2[i].sd == 0)
+				mipi_csi2 = &mxc_md->mipi_csi2[1];
+			else
+				mipi_csi2 = &mxc_md->mipi_csi2[0];
+			v4l2_info(&mxc_md->v4l2_dev, "sensor->id is (%d)\n", sensor->id);
 
 			source = &sensor->sd->entity;
 			sink = find_entity_by_name(mxc_md, mipi_csi2->sd_name);
@@ -523,7 +529,12 @@ static int mxc_md_create_links(struct mxc_md *mxc_md)
 			sink_pad = source_pad;
 
 			mipi_vc = (mipi_csi2->vchannel) ? 4 : 1;
+			v4l2_info(&mxc_md->v4l2_dev, "mipi_vc is (%d)\n", mipi_vc);
 			for (j = 0; j < mipi_vc; j++) {
+				v4l2_info(&mxc_md->v4l2_dev, "j is (%d), sink pad is (%d), source_pad is (%d)\n", j, sink_pad, source_pad);
+				if(sensor->id == 1)
+					sink_pad++;
+				
 				ret = media_create_pad_link(source,
 							    source_pad + j,
 							    sink,
@@ -958,8 +969,8 @@ static int mxc_md_register_platform_entities(struct mxc_md *mxc_md,
 static int register_sensor_entities(struct mxc_md *mxc_md)
 {
 	struct device_node *parent = mxc_md->pdev->dev.of_node;
-	struct device_node *node, *ep, *rem;
-	struct v4l2_fwnode_endpoint endpoint;
+	struct device_node *node, *ep, *ep1, *rem, *rem1;
+	struct v4l2_fwnode_endpoint endpoint, endpoint1;
 	struct i2c_client *client;
 	struct v4l2_async_subdev *asd;
 	int index = 0;
@@ -967,9 +978,12 @@ static int register_sensor_entities(struct mxc_md *mxc_md)
 
 	mxc_md->num_sensors = 0;
 
+	v4l2_info(&mxc_md->v4l2_dev, "port full name is %s\n", mxc_md->pdev->dev.of_node->name);
+
 	/* Attach sensors linked to MIPI CSI2 / paralle csi / HDMI Rx */
 	for_each_available_child_of_node(parent, node) {
 		struct device_node *port;
+		struct device_node *port1;
 
 		if (!of_node_cmp(node->name, HDMI_RX_OF_NODE_NAME)) {
 			mxc_md->sensor[index].fwnode = of_fwnode_handle(node);
@@ -990,16 +1004,25 @@ static int register_sensor_entities(struct mxc_md *mxc_md)
 			continue;
 
 		/* csi2 node have only port */
-		port = of_get_next_child(node, NULL);
+		//port = of_get_next_child(node, NULL);
+		port1 = of_get_next_child(node, NULL);
+		port = of_get_next_child(node, port1);
+		v4l2_info(&mxc_md->v4l2_dev, "port full name is %s\n", port->full_name);
+		v4l2_info(&mxc_md->v4l2_dev, "port name is %s\n", port->name);
 		if (!port)
 			continue;
 
 		/* port can have only endpoint */
 		ep = of_get_next_child(port, NULL);
+		ep1 = of_get_next_child(port1, NULL);
+		v4l2_info(&mxc_md->v4l2_dev, "ep full name is %s and ep name is %s\n", ep->full_name, ep->name);
+
 		if (!ep)
 			return -EINVAL;
 
 		memset(&endpoint, 0, sizeof(endpoint));
+		memset(&endpoint1, 0, sizeof(endpoint1));
+		ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep1), &endpoint1);
 		ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep), &endpoint);
 		if (WARN_ON(endpoint.base.port >= MXC_MAX_SENSORS || ret)) {
 			v4l2_err(&mxc_md->v4l2_dev,
@@ -1007,14 +1030,21 @@ static int register_sensor_entities(struct mxc_md *mxc_md)
 			return -EINVAL;
 		}
 
+		if (endpoint1.base.port ==2)
+			endpoint1.base.port=1;
 		mxc_md->sensor[index].id = endpoint.base.port;
+		mxc_md->sensor[index+1].id = endpoint1.base.port;
 
 		if (!of_node_cmp(node->name, MIPI_CSI2_OF_NODE_NAME))
 			mxc_md->sensor[index].mipi_mode = true;
 
 		/* remote port---sensor node */
+		rem1 = of_graph_get_remote_port_parent(ep1);
 		rem = of_graph_get_remote_port_parent(ep);
 		of_node_put(ep);
+		of_node_put(ep1);
 		if (!rem) {
 			v4l2_info(&mxc_md->v4l2_dev,
 				  "Remote device at %s not found\n",
@@ -1025,6 +1055,7 @@ static int register_sensor_entities(struct mxc_md *mxc_md)
 		/*
 		 * Need to wait sensor driver probed for the first time
 		 */
+		client = of_find_i2c_device_by_node(rem1);
 		client = of_find_i2c_device_by_node(rem);
 		if (!client) {
 			v4l2_info(&mxc_md->v4l2_dev,
@@ -1033,7 +1064,12 @@ static int register_sensor_entities(struct mxc_md *mxc_md)
 			return -EPROBE_DEFER;
 		}
 
+		mxc_md->sensor[index+1].fwnode = of_fwnode_handle(rem1);
 		mxc_md->sensor[index].fwnode = of_fwnode_handle(rem);
+		asd = v4l2_async_notifier_add_fwnode_subdev(
+						&mxc_md->subdev_notifier,
+						mxc_md->sensor[index+1].fwnode,
+						struct v4l2_async_subdev);
 		asd = v4l2_async_notifier_add_fwnode_subdev(
 						&mxc_md->subdev_notifier,
 						mxc_md->sensor[index].fwnode,
@@ -1043,9 +1079,9 @@ static int register_sensor_entities(struct mxc_md *mxc_md)
 			return PTR_ERR(asd);
 		}
 
-		mxc_md->num_sensors++;
+		mxc_md->num_sensors += 2;
 
-		index++;
+		index += 2;
 	}
 
 	return 0;

diff --git a/drivers/staging/media/imx/imx8-mipi-csi2-sam.c b/drivers/staging/media/imx/imx8-mipi-csi2-sam.c
index 1d1236552..d2ba5c890 100644
--- a/drivers/staging/media/imx/imx8-mipi-csi2-sam.c
+++ b/drivers/staging/media/imx/imx8-mipi-csi2-sam.c
@@ -46,7 +46,7 @@
 
 #define CSIS_DRIVER_NAME		"mxc-mipi-csi2-sam"
 #define CSIS_SUBDEV_NAME		"mxc-mipi-csi2"
-#define CSIS_MAX_ENTITIES		2
+#define CSIS_MAX_ENTITIES		4
 #define CSIS0_MAX_LANES			4
 #define CSIS1_MAX_LANES			2
 
@@ -1486,6 +1486,7 @@ static int mipi_csis_parse_dt(struct platform_device *pdev,
 			    struct csi_state *state)
 {
 	struct device_node *node = pdev->dev.of_node;
+	struct device_node *node1;
 
 	state->index = of_alias_get_id(node, "csi");
 
@@ -1495,7 +1496,9 @@ static int mipi_csis_parse_dt(struct platform_device *pdev,
 	if (of_property_read_u32(node, "bus-width", &state->max_num_lanes))
 		return -EINVAL;
 
-	node = of_graph_get_next_endpoint(node, NULL);
+	//node = of_graph_get_next_endpoint(node, NULL);
+	node1 = of_graph_get_next_endpoint(node, NULL);
+	node = of_graph_get_next_endpoint(node, node1);
 	if (!node) {
 		dev_err(&pdev->dev, "No port node\n");
 		return -EINVAL;
 


its very messy way to do such thing but for now, it works without an issue. 

The above code basically parses device tree and connects two cameras into csi2.0 and other two to csi2.1. And since we have isi subdevices you can get a stream from all 4 of them.

Hopefully this will help someone in future.  

0 Kudos
Reply