@@ -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;
};
/*
@@ -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", ®);
+ 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) {
@@ -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;