Commit 3e52419e authored by Niklas Söderlund's avatar Niklas Söderlund Committed by Hans Verkuil

media: rcar-{csi2,vin}: Move to full Virtual Channel routing per CSI-2 IP

When Gen3 support was first added to this R-Car VIN and CSI-2 driver the
routing was centred around the CHSEL register which multiplexes the
different parallel buses that sit between the CSI-2 receivers source
side and the VIN dma engines. This was a bad design as the multiplexing
do allow for only a few combinations and do not play nice with many
video streams in the system.

For example it's only possible for CSI-2 Virtual Channels 0 and 1 of any
given CSI-2 receiver to be used together with the scaler.

Later datasheets have expanded the documentation and it is now possible
to improve on this design by allowing any Virtual Channel to be routed
to any R-Car VIN instance, provided that there exists a parallel bus
between them. This increases the flexibility as all Virtual Channels can
now be used together with the scaler for example.

The redesign is not however perfect. While the new design allows for
many more routes, two constrains limit a small portion of routes that
was possible in the old design but are no more.

- It is no longer possible to route the same CSI-2 and VC to more then
  one VIN at a time. This was theoretically possible before if the
  specific SoC allowed for the same CSI-2 and VC to be routed to two
  different VIN capture groups.

- It is no longer possible to simultaneously mix links from two CSI-2 IP
  blocks to the same VIN capture group.

  For example if VIN2 is capturing from CSI40 then VIN{0,1,3} must also
  capture from CSI40. While VIN{4,5,6,7} is still free to capture from
  any other CSI-2 IP in the system. Once all VIN{0,1,2,3} links to CSI40
  are disabled that VIN capture group is free again to capture from any
  other CSI-2 IP it is connected to.

At the core of the redesign is greater cooperator of the R-Car VIN and
CSI-2 drivers in configuring the routing. The VIN driver is after this
change only responsible to configure the full VIN capture groups
parallel buses to be to a particular CSI-2 IP. While the configuration
of which CSI-2 Virtual Channel is outputted on which of the R-Car CSI-2
IP output ports is handled by the CSI-2 driver.

Before this change the CSI-2 Virtual Channel to output port was static
in the CSI-2 driver and the different links only manipulated the VIN
capture groups CHSEL register. With this change both the CHSEl register
and the CSI-2 routing VCDT registers are modified for greater
flexibility.

This change touches both the R-Car VIN and R-Car CSI-2 drivers in the
same commit as both drivers cooperate closely and one change without the
other would more or less break video capture.
Signed-off-by: default avatarNiklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
Tested-by: default avatarJacopo Mondi <jacopo+renesas@jmondi.org>
Signed-off-by: default avatarHans Verkuil <hverkuil-cisco@xs4all.nl>
[hverkuil: fix two trivial checkpatch whitespace issues]
parent 624e8b62
This diff is collapsed.
...@@ -503,6 +503,8 @@ struct rcar_csi2 { ...@@ -503,6 +503,8 @@ struct rcar_csi2 {
struct v4l2_subdev *remote; struct v4l2_subdev *remote;
unsigned int remote_pad; unsigned int remote_pad;
int channel_vc[4];
struct mutex lock; /* Protects mf and stream_count. */ struct mutex lock; /* Protects mf and stream_count. */
struct v4l2_mbus_framefmt mf; struct v4l2_mbus_framefmt mf;
int stream_count; int stream_count;
...@@ -700,8 +702,11 @@ static int rcsi2_start_receiver(struct rcar_csi2 *priv) ...@@ -700,8 +702,11 @@ static int rcsi2_start_receiver(struct rcar_csi2 *priv)
for (i = 0; i < priv->info->num_channels; i++) { for (i = 0; i < priv->info->num_channels; i++) {
u32 vcdt_part; u32 vcdt_part;
vcdt_part = VCDT_SEL_VC(i) | VCDT_VCDTN_EN | VCDT_SEL_DTN_ON | if (priv->channel_vc[i] < 0)
VCDT_SEL_DT(format->datatype); continue;
vcdt_part = VCDT_SEL_VC(priv->channel_vc[i]) | VCDT_VCDTN_EN |
VCDT_SEL_DTN_ON | VCDT_SEL_DT(format->datatype);
/* Store in correct reg and offset. */ /* Store in correct reg and offset. */
if (i < 2) if (i < 2)
...@@ -1283,7 +1288,52 @@ static int rcsi2_init_phtw_v3u(struct rcar_csi2 *priv, ...@@ -1283,7 +1288,52 @@ static int rcsi2_init_phtw_v3u(struct rcar_csi2 *priv,
* Platform Device Driver. * Platform Device Driver.
*/ */
static int rcsi2_link_setup(struct media_entity *entity,
const struct media_pad *local,
const struct media_pad *remote, u32 flags)
{
struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
struct rcar_csi2 *priv = sd_to_csi2(sd);
struct video_device *vdev;
int channel, vc;
u32 id;
if (!is_media_entity_v4l2_video_device(remote->entity)) {
dev_err(priv->dev, "Remote is not a video device\n");
return -EINVAL;
}
vdev = media_entity_to_video_device(remote->entity);
if (of_property_read_u32(vdev->dev_parent->of_node, "renesas,id", &id)) {
dev_err(priv->dev, "No renesas,id, can't configure routing\n");
return -EINVAL;
}
channel = id % 4;
if (flags & MEDIA_LNK_FL_ENABLED) {
if (media_entity_remote_pad(local)) {
dev_dbg(priv->dev,
"Each VC can only be routed to one output channel\n");
return -EINVAL;
}
vc = local->index - 1;
dev_dbg(priv->dev, "Route VC%d to VIN%u on output channel %d\n",
vc, id, channel);
} else {
vc = -1;
}
priv->channel_vc[channel] = vc;
return 0;
}
static const struct media_entity_operations rcar_csi2_entity_ops = { static const struct media_entity_operations rcar_csi2_entity_ops = {
.link_setup = rcsi2_link_setup,
.link_validate = v4l2_subdev_link_validate, .link_validate = v4l2_subdev_link_validate,
}; };
...@@ -1502,6 +1552,9 @@ static int rcsi2_probe(struct platform_device *pdev) ...@@ -1502,6 +1552,9 @@ static int rcsi2_probe(struct platform_device *pdev)
if (ret) if (ret)
goto error_async; goto error_async;
for (i = 0; i < ARRAY_SIZE(priv->channel_vc); i++)
priv->channel_vc[i] = -1;
pm_runtime_enable(&pdev->dev); pm_runtime_enable(&pdev->dev);
ret = v4l2_async_register_subdev(&priv->subdev); ret = v4l2_async_register_subdev(&priv->subdev);
......
...@@ -1507,7 +1507,7 @@ int rvin_set_channel_routing(struct rvin_dev *vin, u8 chsel) ...@@ -1507,7 +1507,7 @@ int rvin_set_channel_routing(struct rvin_dev *vin, u8 chsel)
* register. IFMD_DES1 controls data expansion mode for CSI20/21, * register. IFMD_DES1 controls data expansion mode for CSI20/21,
* IFMD_DES0 controls data expansion mode for CSI40/41. * IFMD_DES0 controls data expansion mode for CSI40/41.
*/ */
for (route = vin->info->routes; route->mask; route++) { for (route = vin->info->routes; route->chsel; route++) {
if (route->csi == RVIN_CSI20 || route->csi == RVIN_CSI21) if (route->csi == RVIN_CSI20 || route->csi == RVIN_CSI21)
ifmd |= VNCSI_IFMD_DES1; ifmd |= VNCSI_IFMD_DES1;
else else
......
...@@ -128,11 +128,9 @@ struct rvin_parallel_entity { ...@@ -128,11 +128,9 @@ struct rvin_parallel_entity {
* struct rvin_group_route - describes a route from a channel of a * struct rvin_group_route - describes a route from a channel of a
* CSI-2 receiver to a VIN * CSI-2 receiver to a VIN
* *
* @master: VIN group master ID.
* @csi: CSI-2 receiver ID. * @csi: CSI-2 receiver ID.
* @channel: Output channel of the CSI-2 receiver. * @chsel: CHSEL register values that connects VIN group to CSI-2.
* @vin: VIN ID.
* @mask: Bitmask of the different CHSEL register values that
* allow for a route from @csi + @chan to @vin.
* *
* .. note:: * .. note::
* Each R-Car CSI-2 receiver has four output channels facing the VIN * Each R-Car CSI-2 receiver has four output channels facing the VIN
...@@ -140,19 +138,11 @@ struct rvin_parallel_entity { ...@@ -140,19 +138,11 @@ struct rvin_parallel_entity {
* There is no correlation between channel number and CSI-2 VC. It's * There is no correlation between channel number and CSI-2 VC. It's
* up to the CSI-2 receiver driver to configure which VC is output * up to the CSI-2 receiver driver to configure which VC is output
* on which channel, the VIN devices only care about output channels. * on which channel, the VIN devices only care about output channels.
*
* There are in some cases multiple CHSEL register settings which would
* allow for the same route from @csi + @channel to @vin. For example
* on R-Car H3 both the CHSEL values 0 and 3 allow for a route from
* CSI40/VC0 to VIN0. All possible CHSEL values for a route need to be
* recorded as a bitmask in @mask, in this example bit 0 and 3 should
* be set.
*/ */
struct rvin_group_route { struct rvin_group_route {
unsigned int master;
enum rvin_csi_id csi; enum rvin_csi_id csi;
unsigned int channel; unsigned int chsel;
unsigned int vin;
unsigned int mask;
}; };
/** /**
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment