aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/bcm27xx/patches-5.15/950-0542-media-bcm2835-unicam-Parse-pad-numbers-correctly.patch
blob: ba0d4fe4f47cb549ec629aa6d213c2d866d39705 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
From 38c605af2dce528db71bd349ad9ecd41389a52b1 Mon Sep 17 00:00:00 2001
From: Dave Stevenson <dave.stevenson@raspberrypi.com>
Date: Wed, 23 Sep 2020 15:16:18 +0100
Subject: [PATCH] media/bcm2835-unicam: Parse pad numbers correctly

The driver was making big assumptions about the source device
using pad 0 and 1, which doesn't follow for more complex
devices where Unicam's source device may be a sink device for
something else.

Read the pad numbers through media controller, and reference
them appropriately.

Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
---
 .../media/platform/bcm2835/bcm2835-unicam.c   | 89 ++++++++++++-------
 1 file changed, 58 insertions(+), 31 deletions(-)

--- a/drivers/media/platform/bcm2835/bcm2835-unicam.c
+++ b/drivers/media/platform/bcm2835/bcm2835-unicam.c
@@ -383,6 +383,8 @@ struct unicam_node {
 	int open;
 	bool streaming;
 	unsigned int pad_id;
+	/* Source pad id on the sensor for this node */
+	unsigned int src_pad_id;
 	/* Pointer pointing to current v4l2_buffer */
 	struct unicam_buffer *cur_frm;
 	/* Pointer pointing to next v4l2_buffer */
@@ -591,7 +593,7 @@ static int __subdev_get_format(struct un
 {
 	struct v4l2_subdev_format sd_fmt = {
 		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
-		.pad = pad_id
+		.pad = dev->node[pad_id].src_pad_id,
 	};
 	int ret;
 
@@ -613,7 +615,7 @@ static int __subdev_set_format(struct un
 {
 	struct v4l2_subdev_format sd_fmt = {
 		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
-		.pad = pad_id
+		.pad = dev->node[pad_id].src_pad_id,
 	};
 	int ret;
 
@@ -1981,7 +1983,7 @@ static int unicam_enum_framesizes(struct
 
 	fse.which = V4L2_SUBDEV_FORMAT_ACTIVE;
 	fse.index = fsize->index;
-	fse.pad = node->pad_id;
+	fse.pad = node->src_pad_id;
 
 	ret = v4l2_subdev_call(dev->sensor, pad, enum_frame_size, NULL, &fse);
 	if (ret)
@@ -2006,6 +2008,7 @@ static int unicam_enum_frameintervals(st
 	const struct unicam_fmt *fmt;
 	struct v4l2_subdev_frame_interval_enum fie = {
 		.index = fival->index,
+		.pad = node->src_pad_id,
 		.width = fival->width,
 		.height = fival->height,
 		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
@@ -2097,8 +2100,13 @@ static int unicam_enum_dv_timings(struct
 {
 	struct unicam_node *node = video_drvdata(file);
 	struct unicam_device *dev = node->dev;
+	int ret;
+
+	timings->pad = node->src_pad_id;
+	ret = v4l2_subdev_call(dev->sensor, pad, enum_dv_timings, timings);
+	timings->pad = node->pad_id;
 
-	return v4l2_subdev_call(dev->sensor, pad, enum_dv_timings, timings);
+	return ret;
 }
 
 static int unicam_dv_timings_cap(struct file *file, void *priv,
@@ -2106,8 +2114,13 @@ static int unicam_dv_timings_cap(struct
 {
 	struct unicam_node *node = video_drvdata(file);
 	struct unicam_device *dev = node->dev;
+	int ret;
+
+	cap->pad = node->src_pad_id;
+	ret = v4l2_subdev_call(dev->sensor, pad, dv_timings_cap, cap);
+	cap->pad = node->pad_id;
 
-	return v4l2_subdev_call(dev->sensor, pad, dv_timings_cap, cap);
+	return ret;
 }
 
 static int unicam_subscribe_event(struct v4l2_fh *fh,
@@ -2378,14 +2391,12 @@ static int register_node(struct unicam_d
 			 */
 			fmt = get_first_supported_format(unicam);
 
-			if (!fmt)
-				/* No compatible formats */
-				return -EINVAL;
-
-			mbus_fmt.code = fmt->code;
-			ret = __subdev_set_format(unicam, &mbus_fmt, pad_id);
-			if (ret)
-				return -EINVAL;
+			if (fmt) {
+				mbus_fmt.code = fmt->code;
+				ret = __subdev_set_format(unicam, &mbus_fmt, pad_id);
+				if (ret)
+					return -EINVAL;
+			}
 		}
 		if (mbus_fmt.field != V4L2_FIELD_NONE) {
 			/* Interlaced not supported - disable it now. */
@@ -2395,7 +2406,8 @@ static int register_node(struct unicam_d
 				return -EINVAL;
 		}
 
-		node->v_fmt.fmt.pix.pixelformat = fmt->fourcc ? fmt->fourcc
+		if (fmt)
+			node->v_fmt.fmt.pix.pixelformat = fmt->fourcc ? fmt->fourcc
 						: fmt->repacked_fourcc;
 	} else {
 		/* Fix this node format as embedded data. */
@@ -2408,7 +2420,8 @@ static int register_node(struct unicam_d
 	node->fmt = fmt;
 
 	/* Read current subdev format */
-	unicam_reset_format(node);
+	if (fmt)
+		unicam_reset_format(node);
 
 	if (v4l2_subdev_has_op(unicam->sensor, video, s_std)) {
 		v4l2_std_id tvnorms;
@@ -2497,6 +2510,7 @@ static int register_node(struct unicam_d
 		unicam_err(unicam, "Unable to allocate dummy buffer.\n");
 		return -ENOMEM;
 	}
+
 	if (pad_id == METADATA_PAD ||
 	    !v4l2_subdev_has_op(unicam->sensor, video, s_std)) {
 		v4l2_disable_ioctl(&node->video_dev, VIDIOC_S_STD);
@@ -2555,7 +2569,8 @@ static int register_node(struct unicam_d
 	node->registered = true;
 
 	if (pad_id != METADATA_PAD || unicam->sensor_embedded_data) {
-		ret = media_create_pad_link(&unicam->sensor->entity, pad_id,
+		ret = media_create_pad_link(&unicam->sensor->entity,
+					    node->src_pad_id,
 					    &node->video_dev.entity, 0,
 					    MEDIA_LNK_FL_ENABLED |
 					    MEDIA_LNK_FL_IMMUTABLE);
@@ -2587,8 +2602,10 @@ static void unregister_nodes(struct unic
 	}
 }
 
-static int unicam_probe_complete(struct unicam_device *unicam)
+static int unicam_async_complete(struct v4l2_async_notifier *notifier)
 {
+	struct unicam_device *unicam = to_unicam_device(notifier->v4l2_dev);
+	unsigned int i, source_pads = 0;
 	int ret;
 
 	unicam->v4l2_dev.notify = unicam_notify;
@@ -2597,7 +2614,20 @@ static int unicam_probe_complete(struct
 	if (!unicam->sensor_state)
 		return -ENOMEM;
 
-	unicam->sensor_embedded_data = (unicam->sensor->entity.num_pads >= 2);
+	for (i = 0; i < unicam->sensor->entity.num_pads; i++) {
+		if (unicam->sensor->entity.pads[i].flags & MEDIA_PAD_FL_SOURCE) {
+			if (source_pads < MAX_NODES) {
+				unicam->node[source_pads].src_pad_id = i;
+				unicam_err(unicam, "source pad %u is index %u\n",
+					   source_pads, i);
+			}
+			source_pads++;
+		}
+	}
+	if (!source_pads) {
+		unicam_err(unicam, "No source pads on sensor.\n");
+		goto unregister;
+	}
 
 	ret = register_node(unicam, &unicam->node[IMAGE_PAD],
 			    V4L2_BUF_TYPE_VIDEO_CAPTURE, IMAGE_PAD);
@@ -2606,11 +2636,15 @@ static int unicam_probe_complete(struct
 		goto unregister;
 	}
 
-	ret = register_node(unicam, &unicam->node[METADATA_PAD],
-			    V4L2_BUF_TYPE_META_CAPTURE, METADATA_PAD);
-	if (ret) {
-		unicam_err(unicam, "Unable to register metadata video device.\n");
-		goto unregister;
+	if (source_pads >= 2) {
+		unicam->sensor_embedded_data = true;
+
+		ret = register_node(unicam, &unicam->node[METADATA_PAD],
+				    V4L2_BUF_TYPE_META_CAPTURE, METADATA_PAD);
+		if (ret) {
+			unicam_err(unicam, "Unable to register metadata video device.\n");
+			goto unregister;
+		}
 	}
 
 	ret = v4l2_device_register_ro_subdev_nodes(&unicam->v4l2_dev);
@@ -2633,13 +2667,6 @@ unregister:
 	return ret;
 }
 
-static int unicam_async_complete(struct v4l2_async_notifier *notifier)
-{
-	struct unicam_device *unicam = to_unicam_device(notifier->v4l2_dev);
-
-	return unicam_probe_complete(unicam);
-}
-
 static const struct v4l2_async_notifier_operations unicam_async_ops = {
 	.bound = unicam_async_bound,
 	.complete = unicam_async_complete,
@@ -2748,7 +2775,7 @@ static int of_unicam_connect_subdevs(str
 	dev->notifier.ops = &unicam_async_ops;
 
 	dev->asd.match_type = V4L2_ASYNC_MATCH_FWNODE;
-	dev->asd.match.fwnode = of_fwnode_handle(sensor_node);
+	dev->asd.match.fwnode = fwnode_graph_get_remote_endpoint(of_fwnode_handle(ep_node));
 	ret = v4l2_async_notifier_add_subdev(&dev->notifier, &dev->asd);
 	if (ret) {
 		unicam_err(dev, "Error adding subdevice: %d\n", ret);