diff mbox series

[v2,43/55] media: rkisp1: Support the ISP parallel input

Message ID 20220630230713.10580-44-laurent.pinchart@ideasonboard.com (mailing list archive)
State New, archived
Headers show
Series media: rkisp1: Cleanups and add support for i.MX8MP | expand

Commit Message

Laurent Pinchart June 30, 2022, 11:07 p.m. UTC
From: Paul Elder <paul.elder@ideasonboard.com>

The ISP has a parallel input, exposed through port 1 in the device tree
node. While the driver supports configuring the ISP for the parallel and
BT.656 input modes, the DT parsing code, the subdev bound handler and
the ISP stream start handler only support the CSI input. Extend them to
support the parallel input.

Signed-off-by: Paul Elder <paul.elder@ideasonboard.com>
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 .../platform/rockchip/rkisp1/rkisp1-common.h  |  2 +
 .../platform/rockchip/rkisp1/rkisp1-dev.c     | 68 ++++++++++++++++---
 .../platform/rockchip/rkisp1/rkisp1-isp.c     | 18 ++++-
 3 files changed, 77 insertions(+), 11 deletions(-)

Comments

Dafna Hirschfeld July 11, 2022, 2:12 a.m. UTC | #1
On 01.07.2022 02:07, Laurent Pinchart wrote:
>From: Paul Elder <paul.elder@ideasonboard.com>
>
>The ISP has a parallel input, exposed through port 1 in the device tree
>node. While the driver supports configuring the ISP for the parallel and
>BT.656 input modes, the DT parsing code, the subdev bound handler and
>the ISP stream start handler only support the CSI input. Extend them to
>support the parallel input.
>
>Signed-off-by: Paul Elder <paul.elder@ideasonboard.com>
>Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

Reviewed-by: Dafna Hirschfeld <dafna@fastmail.com>

>---
> .../platform/rockchip/rkisp1/rkisp1-common.h  |  2 +
> .../platform/rockchip/rkisp1/rkisp1-dev.c     | 68 ++++++++++++++++---
> .../platform/rockchip/rkisp1/rkisp1-isp.c     | 18 ++++-
> 3 files changed, 77 insertions(+), 11 deletions(-)
>
>diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h b/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h
>index 84832e1367ff..e436f1572566 100644
>--- a/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h
>+++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h
>@@ -130,6 +130,7 @@ struct rkisp1_info {
>  * @mbus_flags:		media bus (V4L2_MBUS_*) flags
>  * @sd:			a pointer to v4l2_subdev struct of the sensor
>  * @pixel_rate_ctrl:	pixel rate of the sensor, used to initialize the phy
>+ * @port:		port number (0: MIPI, 1: Parallel)
>  */
> struct rkisp1_sensor_async {
> 	struct v4l2_async_subdev asd;
>@@ -140,6 +141,7 @@ struct rkisp1_sensor_async {
> 	unsigned int mbus_flags;
> 	struct v4l2_subdev *sd;
> 	struct v4l2_ctrl *pixel_rate_ctrl;
>+	unsigned int port;
> };
>
> /*
>diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c
>index 0eb37ba557ce..1dcade2fd2a7 100644
>--- a/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c
>+++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c
>@@ -129,6 +129,7 @@ static int rkisp1_subdev_notifier_bound(struct v4l2_async_notifier *notifier,
> 	struct rkisp1_sensor_async *s_asd =
> 		container_of(asd, struct rkisp1_sensor_async, asd);
> 	int source_pad;
>+	int ret;
>
> 	s_asd->sd = sd;
>
>@@ -140,7 +141,20 @@ static int rkisp1_subdev_notifier_bound(struct v4l2_async_notifier *notifier,
> 		return source_pad;
> 	}
>
>-	return rkisp1_csi_link_sensor(rkisp1, sd, s_asd, source_pad);
>+	if (s_asd->port == 0)
>+		return rkisp1_csi_link_sensor(rkisp1, sd, s_asd, source_pad);
>+
>+	ret = media_create_pad_link(&sd->entity, source_pad,
>+				    &rkisp1->isp.sd.entity,
>+				    RKISP1_ISP_PAD_SINK_VIDEO,
>+				    !s_asd->index ? MEDIA_LNK_FL_ENABLED : 0);
>+	if (ret) {
>+		dev_err(rkisp1->dev, "failed to link source pad of %s\n",
>+			sd->name);
>+		return ret;
>+	}
>+
>+	return 0;
> }
>
> static int rkisp1_subdev_notifier_complete(struct v4l2_async_notifier *notifier)
>@@ -178,12 +192,33 @@ static int rkisp1_subdev_notifier_register(struct rkisp1_device *rkisp1)
> 	ntf->ops = &rkisp1_subdev_notifier_ops;
>
> 	fwnode_graph_for_each_endpoint(fwnode, ep) {
>-		struct v4l2_fwnode_endpoint vep = {
>-			.bus_type = V4L2_MBUS_CSI2_DPHY
>-		};
>+		struct fwnode_handle *port;
>+		struct v4l2_fwnode_endpoint vep = { };
> 		struct rkisp1_sensor_async *rk_asd;
> 		struct fwnode_handle *source;
>+		u32 reg = 0;
>
>+		/* Select the bus type based on the port. */
>+		port = fwnode_get_parent(ep);
>+		fwnode_property_read_u32(port, "reg", &reg);
>+		fwnode_handle_put(port);
>+
>+		switch (reg) {
>+		case 0:
>+			vep.bus_type = V4L2_MBUS_CSI2_DPHY;
>+			break;
>+
>+		case 1:
>+			/*
>+			 * Parallel port. The bus-type property in DT is
>+			 * mandatory for port 1, it will be used to determine if
>+			 * it's PARALLEL or BT656.
>+			 */
>+			vep.bus_type = V4L2_MBUS_UNKNOWN;
>+			break;
>+		}
>+
>+		/* Parse the endpoint and validate the bus type. */
> 		ret = v4l2_fwnode_endpoint_parse(ep, &vep);
> 		if (ret) {
> 			dev_err(rkisp1->dev, "failed to parse endpoint %pfw\n",
>@@ -191,6 +226,17 @@ static int rkisp1_subdev_notifier_register(struct rkisp1_device *rkisp1)
> 			break;
> 		}
>
>+		if (vep.base.port == 1) {
>+			if (vep.bus_type != V4L2_MBUS_PARALLEL &&
>+			    vep.bus_type != V4L2_MBUS_BT656) {
>+				dev_err(rkisp1->dev,
>+					"port 1 must be parallel or BT656\n");
>+				ret = -EINVAL;
>+				break;
>+			}
>+		}
>+
>+		/* Add the async subdev to the notifier. */
> 		source = fwnode_graph_get_remote_endpoint(ep);
> 		if (!source) {
> 			dev_err(rkisp1->dev,
>@@ -211,11 +257,17 @@ static int rkisp1_subdev_notifier_register(struct rkisp1_device *rkisp1)
> 		rk_asd->index = index++;
> 		rk_asd->source_ep = source;
> 		rk_asd->mbus_type = vep.bus_type;
>-		rk_asd->mbus_flags = vep.bus.mipi_csi2.flags;
>-		rk_asd->lanes = vep.bus.mipi_csi2.num_data_lanes;
>+		rk_asd->port = vep.base.port;
>
>-		dev_dbg(rkisp1->dev, "registered ep id %d with %d lanes\n",
>-			vep.base.id, rk_asd->lanes);
>+		if (vep.bus_type == V4L2_MBUS_CSI2_DPHY) {
>+			rk_asd->mbus_flags = vep.bus.mipi_csi2.flags;
>+			rk_asd->lanes = vep.bus.mipi_csi2.num_data_lanes;
>+		} else {
>+			rk_asd->mbus_flags = vep.bus.parallel.flags;
>+		}
>+
>+		dev_dbg(rkisp1->dev, "registered ep id %d, bus type %u, %u lanes\n",
>+			vep.base.id, rk_asd->mbus_type, rk_asd->lanes);
> 	}
>
> 	if (ret) {
>diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c
>index ea0bbccb5aee..383a3ec83ca9 100644
>--- a/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c
>+++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c
>@@ -729,6 +729,8 @@ static int rkisp1_isp_s_stream(struct v4l2_subdev *sd, int enable)
> 	struct rkisp1_device *rkisp1 = isp->rkisp1;
> 	struct media_pad *source_pad;
> 	struct media_pad *sink_pad;
>+	enum v4l2_mbus_type mbus_type;
>+	u32 mbus_flags;
> 	int ret;
>
> 	if (!enable) {
>@@ -751,12 +753,22 @@ static int rkisp1_isp_s_stream(struct v4l2_subdev *sd, int enable)
> 		return -EPIPE;
> 	}
>
>-	if (rkisp1->source != &rkisp1->csi.sd)
>-		return -EPIPE;
>+	if (rkisp1->source == &rkisp1->csi.sd) {
>+		mbus_type = V4L2_MBUS_CSI2_DPHY;
>+		mbus_flags = 0;
>+	} else {
>+		const struct rkisp1_sensor_async *asd;
>+
>+		asd = container_of(rkisp1->source->asd,
>+				   struct rkisp1_sensor_async, asd);
>+
>+		mbus_type = asd->mbus_type;
>+		mbus_flags = asd->mbus_flags;
>+	}
>
> 	isp->frame_sequence = -1;
> 	mutex_lock(&isp->ops_lock);
>-	ret = rkisp1_config_cif(isp, V4L2_MBUS_CSI2_DPHY, 0);
>+	ret = rkisp1_config_cif(isp, mbus_type, mbus_flags);
> 	if (ret)
> 		goto mutex_unlock;
>
>-- 
>Regards,
>
>Laurent Pinchart
>
>
>_______________________________________________
>Linux-rockchip mailing list
>Linux-rockchip@lists.infradead.org
>http://lists.infradead.org/mailman/listinfo/linux-rockchip
diff mbox series

Patch

diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h b/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h
index 84832e1367ff..e436f1572566 100644
--- a/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h
+++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h
@@ -130,6 +130,7 @@  struct rkisp1_info {
  * @mbus_flags:		media bus (V4L2_MBUS_*) flags
  * @sd:			a pointer to v4l2_subdev struct of the sensor
  * @pixel_rate_ctrl:	pixel rate of the sensor, used to initialize the phy
+ * @port:		port number (0: MIPI, 1: Parallel)
  */
 struct rkisp1_sensor_async {
 	struct v4l2_async_subdev asd;
@@ -140,6 +141,7 @@  struct rkisp1_sensor_async {
 	unsigned int mbus_flags;
 	struct v4l2_subdev *sd;
 	struct v4l2_ctrl *pixel_rate_ctrl;
+	unsigned int port;
 };
 
 /*
diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c
index 0eb37ba557ce..1dcade2fd2a7 100644
--- a/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c
+++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c
@@ -129,6 +129,7 @@  static int rkisp1_subdev_notifier_bound(struct v4l2_async_notifier *notifier,
 	struct rkisp1_sensor_async *s_asd =
 		container_of(asd, struct rkisp1_sensor_async, asd);
 	int source_pad;
+	int ret;
 
 	s_asd->sd = sd;
 
@@ -140,7 +141,20 @@  static int rkisp1_subdev_notifier_bound(struct v4l2_async_notifier *notifier,
 		return source_pad;
 	}
 
-	return rkisp1_csi_link_sensor(rkisp1, sd, s_asd, source_pad);
+	if (s_asd->port == 0)
+		return rkisp1_csi_link_sensor(rkisp1, sd, s_asd, source_pad);
+
+	ret = media_create_pad_link(&sd->entity, source_pad,
+				    &rkisp1->isp.sd.entity,
+				    RKISP1_ISP_PAD_SINK_VIDEO,
+				    !s_asd->index ? MEDIA_LNK_FL_ENABLED : 0);
+	if (ret) {
+		dev_err(rkisp1->dev, "failed to link source pad of %s\n",
+			sd->name);
+		return ret;
+	}
+
+	return 0;
 }
 
 static int rkisp1_subdev_notifier_complete(struct v4l2_async_notifier *notifier)
@@ -178,12 +192,33 @@  static int rkisp1_subdev_notifier_register(struct rkisp1_device *rkisp1)
 	ntf->ops = &rkisp1_subdev_notifier_ops;
 
 	fwnode_graph_for_each_endpoint(fwnode, ep) {
-		struct v4l2_fwnode_endpoint vep = {
-			.bus_type = V4L2_MBUS_CSI2_DPHY
-		};
+		struct fwnode_handle *port;
+		struct v4l2_fwnode_endpoint vep = { };
 		struct rkisp1_sensor_async *rk_asd;
 		struct fwnode_handle *source;
+		u32 reg = 0;
 
+		/* Select the bus type based on the port. */
+		port = fwnode_get_parent(ep);
+		fwnode_property_read_u32(port, "reg", &reg);
+		fwnode_handle_put(port);
+
+		switch (reg) {
+		case 0:
+			vep.bus_type = V4L2_MBUS_CSI2_DPHY;
+			break;
+
+		case 1:
+			/*
+			 * Parallel port. The bus-type property in DT is
+			 * mandatory for port 1, it will be used to determine if
+			 * it's PARALLEL or BT656.
+			 */
+			vep.bus_type = V4L2_MBUS_UNKNOWN;
+			break;
+		}
+
+		/* Parse the endpoint and validate the bus type. */
 		ret = v4l2_fwnode_endpoint_parse(ep, &vep);
 		if (ret) {
 			dev_err(rkisp1->dev, "failed to parse endpoint %pfw\n",
@@ -191,6 +226,17 @@  static int rkisp1_subdev_notifier_register(struct rkisp1_device *rkisp1)
 			break;
 		}
 
+		if (vep.base.port == 1) {
+			if (vep.bus_type != V4L2_MBUS_PARALLEL &&
+			    vep.bus_type != V4L2_MBUS_BT656) {
+				dev_err(rkisp1->dev,
+					"port 1 must be parallel or BT656\n");
+				ret = -EINVAL;
+				break;
+			}
+		}
+
+		/* Add the async subdev to the notifier. */
 		source = fwnode_graph_get_remote_endpoint(ep);
 		if (!source) {
 			dev_err(rkisp1->dev,
@@ -211,11 +257,17 @@  static int rkisp1_subdev_notifier_register(struct rkisp1_device *rkisp1)
 		rk_asd->index = index++;
 		rk_asd->source_ep = source;
 		rk_asd->mbus_type = vep.bus_type;
-		rk_asd->mbus_flags = vep.bus.mipi_csi2.flags;
-		rk_asd->lanes = vep.bus.mipi_csi2.num_data_lanes;
+		rk_asd->port = vep.base.port;
 
-		dev_dbg(rkisp1->dev, "registered ep id %d with %d lanes\n",
-			vep.base.id, rk_asd->lanes);
+		if (vep.bus_type == V4L2_MBUS_CSI2_DPHY) {
+			rk_asd->mbus_flags = vep.bus.mipi_csi2.flags;
+			rk_asd->lanes = vep.bus.mipi_csi2.num_data_lanes;
+		} else {
+			rk_asd->mbus_flags = vep.bus.parallel.flags;
+		}
+
+		dev_dbg(rkisp1->dev, "registered ep id %d, bus type %u, %u lanes\n",
+			vep.base.id, rk_asd->mbus_type, rk_asd->lanes);
 	}
 
 	if (ret) {
diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c
index ea0bbccb5aee..383a3ec83ca9 100644
--- a/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c
+++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c
@@ -729,6 +729,8 @@  static int rkisp1_isp_s_stream(struct v4l2_subdev *sd, int enable)
 	struct rkisp1_device *rkisp1 = isp->rkisp1;
 	struct media_pad *source_pad;
 	struct media_pad *sink_pad;
+	enum v4l2_mbus_type mbus_type;
+	u32 mbus_flags;
 	int ret;
 
 	if (!enable) {
@@ -751,12 +753,22 @@  static int rkisp1_isp_s_stream(struct v4l2_subdev *sd, int enable)
 		return -EPIPE;
 	}
 
-	if (rkisp1->source != &rkisp1->csi.sd)
-		return -EPIPE;
+	if (rkisp1->source == &rkisp1->csi.sd) {
+		mbus_type = V4L2_MBUS_CSI2_DPHY;
+		mbus_flags = 0;
+	} else {
+		const struct rkisp1_sensor_async *asd;
+
+		asd = container_of(rkisp1->source->asd,
+				   struct rkisp1_sensor_async, asd);
+
+		mbus_type = asd->mbus_type;
+		mbus_flags = asd->mbus_flags;
+	}
 
 	isp->frame_sequence = -1;
 	mutex_lock(&isp->ops_lock);
-	ret = rkisp1_config_cif(isp, V4L2_MBUS_CSI2_DPHY, 0);
+	ret = rkisp1_config_cif(isp, mbus_type, mbus_flags);
 	if (ret)
 		goto mutex_unlock;