mirror of
https://github.com/openwrt/openwrt.git
synced 2024-12-23 15:32:33 +00:00
160 lines
4.5 KiB
Diff
160 lines
4.5 KiB
Diff
|
From 15221304a23fd99c84a6da4b68dc0e887150d1ee Mon Sep 17 00:00:00 2001
|
||
|
From: Jacopo Mondi <jacopo+renesas@jmondi.org>
|
||
|
Date: Tue, 16 Jun 2020 16:12:44 +0200
|
||
|
Subject: [PATCH] media: rcar-csi2: Negotiate data lanes number
|
||
|
|
||
|
Upstream https://patchwork.linuxtv.org/patch/64675/
|
||
|
|
||
|
Use the newly introduced get_mbus_config() subdevice pad operation to
|
||
|
retrieve the remote subdevice MIPI CSI-2 bus configuration and configure
|
||
|
the number of active data lanes accordingly.
|
||
|
|
||
|
In order to be able to call the remote subdevice operation cache the
|
||
|
index of the remote pad connected to the single CSI-2 input port.
|
||
|
|
||
|
Signed-off-by: Jacopo Mondi <jacopo+renesas@jmondi.org>
|
||
|
---
|
||
|
drivers/media/platform/rcar-vin/rcar-csi2.c | 74 +++++++++++++++++++--
|
||
|
1 file changed, 67 insertions(+), 7 deletions(-)
|
||
|
|
||
|
--- a/drivers/media/platform/rcar-vin/rcar-csi2.c
|
||
|
+++ b/drivers/media/platform/rcar-vin/rcar-csi2.c
|
||
|
@@ -362,6 +362,7 @@ struct rcar_csi2 {
|
||
|
|
||
|
struct v4l2_async_notifier notifier;
|
||
|
struct v4l2_subdev *remote;
|
||
|
+ unsigned int remote_pad;
|
||
|
|
||
|
struct v4l2_mbus_framefmt mf;
|
||
|
|
||
|
@@ -407,13 +408,14 @@ static void rcsi2_exit_standby(struct rc
|
||
|
reset_control_deassert(priv->rstc);
|
||
|
}
|
||
|
|
||
|
-static int rcsi2_wait_phy_start(struct rcar_csi2 *priv)
|
||
|
+static int rcsi2_wait_phy_start(struct rcar_csi2 *priv,
|
||
|
+ unsigned int active_lanes)
|
||
|
{
|
||
|
unsigned int timeout;
|
||
|
|
||
|
/* Wait for the clock and data lanes to enter LP-11 state. */
|
||
|
for (timeout = 0; timeout <= 20; timeout++) {
|
||
|
- const u32 lane_mask = (1 << priv->lanes) - 1;
|
||
|
+ const u32 lane_mask = (1 << active_lanes) - 1;
|
||
|
|
||
|
if ((rcsi2_read(priv, PHCLM_REG) & PHCLM_STOPSTATECKL) &&
|
||
|
(rcsi2_read(priv, PHDLM_REG) & lane_mask) == lane_mask)
|
||
|
@@ -445,7 +447,8 @@ static int rcsi2_set_phypll(struct rcar_
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
-static int rcsi2_calc_mbps(struct rcar_csi2 *priv, unsigned int bpp)
|
||
|
+static int rcsi2_calc_mbps(struct rcar_csi2 *priv, unsigned int bpp,
|
||
|
+ unsigned int active_lanes)
|
||
|
{
|
||
|
struct v4l2_subdev *source;
|
||
|
struct v4l2_ctrl *ctrl;
|
||
|
@@ -470,15 +473,63 @@ static int rcsi2_calc_mbps(struct rcar_c
|
||
|
* bps = link_freq * 2
|
||
|
*/
|
||
|
mbps = v4l2_ctrl_g_ctrl_int64(ctrl) * bpp;
|
||
|
- do_div(mbps, priv->lanes * 1000000);
|
||
|
+ do_div(mbps, active_lanes * 1000000);
|
||
|
|
||
|
return mbps;
|
||
|
}
|
||
|
|
||
|
+static int rcsi2_config_active_lanes(struct rcar_csi2 *priv,
|
||
|
+ unsigned int *active_lanes)
|
||
|
+{
|
||
|
+ struct v4l2_mbus_config mbus_config = { 0 };
|
||
|
+ unsigned int num_lanes = (-1U);
|
||
|
+ int ret;
|
||
|
+
|
||
|
+ *active_lanes = priv->lanes;
|
||
|
+ ret = v4l2_subdev_call(priv->remote, pad, get_mbus_config,
|
||
|
+ priv->remote_pad, &mbus_config);
|
||
|
+ if (ret == -ENOIOCTLCMD) {
|
||
|
+ dev_dbg(priv->dev, "No remote mbus configuration available\n");
|
||
|
+ return 0;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (ret) {
|
||
|
+ dev_err(priv->dev, "Failed to get remote mbus configuration\n");
|
||
|
+ return ret;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (mbus_config.type != V4L2_MBUS_CSI2_DPHY) {
|
||
|
+ dev_err(priv->dev, "Unsupported media bus type %u\n",
|
||
|
+ mbus_config.type);
|
||
|
+ return -EINVAL;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (mbus_config.flags & V4L2_MBUS_CSI2_1_LANE)
|
||
|
+ num_lanes = 1;
|
||
|
+ else if (mbus_config.flags & V4L2_MBUS_CSI2_2_LANE)
|
||
|
+ num_lanes = 2;
|
||
|
+ else if (mbus_config.flags & V4L2_MBUS_CSI2_3_LANE)
|
||
|
+ num_lanes = 3;
|
||
|
+ else if (mbus_config.flags & V4L2_MBUS_CSI2_4_LANE)
|
||
|
+ num_lanes = 4;
|
||
|
+
|
||
|
+ if (num_lanes > priv->lanes) {
|
||
|
+ dev_err(priv->dev,
|
||
|
+ "Unsupported mbus config: too many data lanes %u\n",
|
||
|
+ num_lanes);
|
||
|
+ return -EINVAL;
|
||
|
+ }
|
||
|
+
|
||
|
+ *active_lanes = num_lanes;
|
||
|
+
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
static int rcsi2_start_receiver(struct rcar_csi2 *priv)
|
||
|
{
|
||
|
const struct rcar_csi2_format *format;
|
||
|
u32 phycnt, vcdt = 0, vcdt2 = 0, fld = 0;
|
||
|
+ unsigned int active_lanes;
|
||
|
unsigned int i;
|
||
|
int mbps, ret;
|
||
|
|
||
|
@@ -520,10 +571,18 @@ static int rcsi2_start_receiver(struct r
|
||
|
fld |= FLD_FLD_NUM(1);
|
||
|
}
|
||
|
|
||
|
+ /*
|
||
|
+ * Get the number of active data lanes inspecting the remote mbus
|
||
|
+ * configuration.
|
||
|
+ */
|
||
|
+ ret = rcsi2_config_active_lanes(priv, &active_lanes);
|
||
|
+ if (ret)
|
||
|
+ return ret;
|
||
|
+
|
||
|
phycnt = PHYCNT_ENABLECLK;
|
||
|
- phycnt |= (1 << priv->lanes) - 1;
|
||
|
+ phycnt |= (1 << active_lanes) - 1;
|
||
|
|
||
|
- mbps = rcsi2_calc_mbps(priv, format->bpp);
|
||
|
+ mbps = rcsi2_calc_mbps(priv, format->bpp, active_lanes);
|
||
|
if (mbps < 0)
|
||
|
return mbps;
|
||
|
|
||
|
@@ -570,7 +629,7 @@ static int rcsi2_start_receiver(struct r
|
||
|
rcsi2_write(priv, PHYCNT_REG, phycnt | PHYCNT_SHUTDOWNZ);
|
||
|
rcsi2_write(priv, PHYCNT_REG, phycnt | PHYCNT_SHUTDOWNZ | PHYCNT_RSTZ);
|
||
|
|
||
|
- ret = rcsi2_wait_phy_start(priv);
|
||
|
+ ret = rcsi2_wait_phy_start(priv, active_lanes);
|
||
|
if (ret)
|
||
|
return ret;
|
||
|
|
||
|
@@ -747,6 +806,7 @@ static int rcsi2_notify_bound(struct v4l
|
||
|
}
|
||
|
|
||
|
priv->remote = subdev;
|
||
|
+ priv->remote_pad = pad;
|
||
|
|
||
|
dev_dbg(priv->dev, "Bound %s pad: %d\n", subdev->name, pad);
|
||
|
|