f057e78f1ffef1cac1d220ce9ee4e3a92729934e
[openwrt/staging/neocturne.git] /
1 From 49c4d625a8477689891d68509d9f2b3ede3ed3f9 Mon Sep 17 00:00:00 2001
2 From: Dave Stevenson <dave.stevenson@raspberrypi.com>
3 Date: Fri, 29 Jul 2022 17:46:49 +0100
4 Subject: [PATCH] media: video-mux: Read CSI2 config from FW, and pass
5 to receiver
6
7 There is no obligation for all source devices on a video-mux to
8 require the same bus configuration, so read the configuration
9 from the sink ports, and relay via get_mbus_config on the source
10 port.
11 If the sources support get_mbus_config, then call that first.
12
13 Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
14 ---
15 drivers/media/platform/video-mux.c | 68 +++++++++++++++++++++++++++++-
16 1 file changed, 66 insertions(+), 2 deletions(-)
17
18 --- a/drivers/media/platform/video-mux.c
19 +++ b/drivers/media/platform/video-mux.c
20 @@ -20,11 +20,28 @@
21 #include <media/v4l2-mc.h>
22 #include <media/v4l2-subdev.h>
23
24 +struct video_mux_asd {
25 + struct v4l2_async_subdev base;
26 + unsigned int port;
27 +};
28 +
29 +static inline struct video_mux_asd *to_video_mux_asd(struct v4l2_async_subdev *asd)
30 +{
31 + return container_of(asd, struct video_mux_asd, base);
32 +}
33 +
34 +struct video_mux_pad_cfg {
35 + unsigned int num_lanes;
36 + bool non_continuous;
37 + struct v4l2_subdev *source;
38 +};
39 +
40 struct video_mux {
41 struct v4l2_subdev subdev;
42 struct v4l2_async_notifier notifier;
43 struct media_pad *pads;
44 struct v4l2_mbus_framefmt *format_mbus;
45 + struct video_mux_pad_cfg *cfg;
46 struct mux_control *mux;
47 struct mutex lock;
48 int active;
49 @@ -330,10 +347,34 @@ static int video_mux_init_cfg(struct v4l
50 return 0;
51 }
52
53 +static int video_mux_get_mbus_config(struct v4l2_subdev *sd,
54 + unsigned int pad,
55 + struct v4l2_mbus_config *cfg)
56 +{
57 + struct video_mux *vmux = v4l2_subdev_to_video_mux(sd);
58 + int ret;
59 +
60 + ret = v4l2_subdev_call(vmux->cfg[vmux->active].source, pad, get_mbus_config,
61 + 0, cfg);
62 +
63 + if (ret != -ENOIOCTLCMD)
64 + return ret;
65 +
66 + cfg->type = V4L2_MBUS_CSI2_DPHY;
67 + cfg->bus.mipi_csi2.num_data_lanes = vmux->cfg[vmux->active].num_lanes;
68 +
69 + /* Support for non-continuous CSI-2 clock is missing in pdate mode */
70 + if (vmux->cfg[vmux->active].non_continuous)
71 + cfg->bus.mipi_csi2.flags |= V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK;
72 +
73 + return 0;
74 +};
75 +
76 static const struct v4l2_subdev_pad_ops video_mux_pad_ops = {
77 .init_cfg = video_mux_init_cfg,
78 .get_fmt = video_mux_get_format,
79 .set_fmt = video_mux_set_format,
80 + .get_mbus_config = video_mux_get_mbus_config,
81 };
82
83 static const struct v4l2_subdev_ops video_mux_subdev_ops = {
84 @@ -346,6 +387,9 @@ static int video_mux_notify_bound(struct
85 struct v4l2_async_subdev *asd)
86 {
87 struct video_mux *vmux = notifier_to_video_mux(notifier);
88 + unsigned int port = to_video_mux_asd(asd)->port;
89 +
90 + vmux->cfg[port].source = sd;
91
92 return v4l2_create_fwnode_links(sd, &vmux->subdev);
93 }
94 @@ -363,7 +407,7 @@ static int video_mux_async_register(stru
95 v4l2_async_nf_init(&vmux->notifier);
96
97 for (i = 0; i < num_input_pads; i++) {
98 - struct v4l2_async_subdev *asd;
99 + struct video_mux_asd *asd;
100 struct fwnode_handle *ep, *remote_ep;
101
102 ep = fwnode_graph_get_endpoint_by_id(
103 @@ -381,7 +425,8 @@ static int video_mux_async_register(stru
104 fwnode_handle_put(remote_ep);
105
106 asd = v4l2_async_nf_add_fwnode_remote(&vmux->notifier, ep,
107 - struct v4l2_async_subdev);
108 + struct video_mux_asd);
109 + asd->port = i;
110
111 fwnode_handle_put(ep);
112
113 @@ -406,6 +451,9 @@ static int video_mux_probe(struct platfo
114 {
115 struct device_node *np = pdev->dev.of_node;
116 struct device *dev = &pdev->dev;
117 + struct v4l2_fwnode_endpoint fwnode_ep = {
118 + .bus_type = V4L2_MBUS_CSI2_DPHY
119 + };
120 struct device_node *ep;
121 struct video_mux *vmux;
122 unsigned int num_pads = 0;
123 @@ -458,10 +506,26 @@ static int video_mux_probe(struct platfo
124 if (!vmux->format_mbus)
125 return -ENOMEM;
126
127 + vmux->cfg = devm_kcalloc(dev, num_pads, sizeof(*vmux->cfg), GFP_KERNEL);
128 + if (!vmux->cfg)
129 + return -ENOMEM;
130 +
131 for (i = 0; i < num_pads; i++) {
132 vmux->pads[i].flags = (i < num_pads - 1) ? MEDIA_PAD_FL_SINK
133 : MEDIA_PAD_FL_SOURCE;
134 vmux->format_mbus[i] = video_mux_format_mbus_default;
135 +
136 + ep = of_graph_get_endpoint_by_regs(pdev->dev.of_node, i, 0);
137 + if (ep) {
138 + ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep), &fwnode_ep);
139 + if (!ret) {
140 + /* Get number of data lanes */
141 + vmux->cfg[i].num_lanes = fwnode_ep.bus.mipi_csi2.num_data_lanes;
142 + vmux->cfg[i].non_continuous = fwnode_ep.bus.mipi_csi2.flags &
143 + V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK;
144 + }
145 + of_node_put(ep);
146 + }
147 }
148
149 vmux->subdev.entity.function = MEDIA_ENT_F_VID_MUX;