xref: /linux/drivers/media/pci/intel/ipu6/ipu6-isys-subdev.c (revision d30c1683aaecb93d2ab95685dc4300a33d3cea7a)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (C) 2013--2024 Intel Corporation
4  */
5 
6 #include <linux/bug.h>
7 #include <linux/device.h>
8 #include <linux/minmax.h>
9 
10 #include <media/media-entity.h>
11 #include <media/mipi-csi2.h>
12 #include <media/v4l2-ctrls.h>
13 #include <media/v4l2-subdev.h>
14 
15 #include "ipu6-bus.h"
16 #include "ipu6-isys.h"
17 #include "ipu6-isys-subdev.h"
18 
19 unsigned int ipu6_isys_mbus_code_to_bpp(u32 code)
20 {
21 	switch (code) {
22 	case MEDIA_BUS_FMT_RGB888_1X24:
23 	case MEDIA_BUS_FMT_META_24:
24 		return 24;
25 	case MEDIA_BUS_FMT_RGB565_1X16:
26 	case MEDIA_BUS_FMT_UYVY8_1X16:
27 	case MEDIA_BUS_FMT_YUYV8_1X16:
28 	case MEDIA_BUS_FMT_Y16_1X16:
29 	case MEDIA_BUS_FMT_META_16:
30 		return 16;
31 	case MEDIA_BUS_FMT_SBGGR12_1X12:
32 	case MEDIA_BUS_FMT_SGBRG12_1X12:
33 	case MEDIA_BUS_FMT_SGRBG12_1X12:
34 	case MEDIA_BUS_FMT_SRGGB12_1X12:
35 	case MEDIA_BUS_FMT_Y12_1X12:
36 	case MEDIA_BUS_FMT_META_12:
37 		return 12;
38 	case MEDIA_BUS_FMT_SBGGR10_1X10:
39 	case MEDIA_BUS_FMT_SGBRG10_1X10:
40 	case MEDIA_BUS_FMT_SGRBG10_1X10:
41 	case MEDIA_BUS_FMT_SRGGB10_1X10:
42 	case MEDIA_BUS_FMT_Y10_1X10:
43 	case MEDIA_BUS_FMT_META_10:
44 		return 10;
45 	case MEDIA_BUS_FMT_SBGGR8_1X8:
46 	case MEDIA_BUS_FMT_SGBRG8_1X8:
47 	case MEDIA_BUS_FMT_SGRBG8_1X8:
48 	case MEDIA_BUS_FMT_SRGGB8_1X8:
49 	case MEDIA_BUS_FMT_Y8_1X8:
50 	case MEDIA_BUS_FMT_META_8:
51 		return 8;
52 	default:
53 		WARN_ON(1);
54 		return 8;
55 	}
56 }
57 
58 unsigned int ipu6_isys_mbus_code_to_mipi(u32 code)
59 {
60 	switch (code) {
61 	case MEDIA_BUS_FMT_RGB565_1X16:
62 		return MIPI_CSI2_DT_RGB565;
63 	case MEDIA_BUS_FMT_RGB888_1X24:
64 		return MIPI_CSI2_DT_RGB888;
65 	case MEDIA_BUS_FMT_UYVY8_1X16:
66 	case MEDIA_BUS_FMT_YUYV8_1X16:
67 		return MIPI_CSI2_DT_YUV422_8B;
68 	case MEDIA_BUS_FMT_SBGGR16_1X16:
69 	case MEDIA_BUS_FMT_SGBRG16_1X16:
70 	case MEDIA_BUS_FMT_SGRBG16_1X16:
71 	case MEDIA_BUS_FMT_SRGGB16_1X16:
72 	case MEDIA_BUS_FMT_Y16_1X16:
73 		return MIPI_CSI2_DT_RAW16;
74 	case MEDIA_BUS_FMT_SBGGR12_1X12:
75 	case MEDIA_BUS_FMT_SGBRG12_1X12:
76 	case MEDIA_BUS_FMT_SGRBG12_1X12:
77 	case MEDIA_BUS_FMT_SRGGB12_1X12:
78 	case MEDIA_BUS_FMT_Y12_1X12:
79 		return MIPI_CSI2_DT_RAW12;
80 	case MEDIA_BUS_FMT_SBGGR10_1X10:
81 	case MEDIA_BUS_FMT_SGBRG10_1X10:
82 	case MEDIA_BUS_FMT_SGRBG10_1X10:
83 	case MEDIA_BUS_FMT_SRGGB10_1X10:
84 	case MEDIA_BUS_FMT_Y10_1X10:
85 		return MIPI_CSI2_DT_RAW10;
86 	case MEDIA_BUS_FMT_SBGGR8_1X8:
87 	case MEDIA_BUS_FMT_SGBRG8_1X8:
88 	case MEDIA_BUS_FMT_SGRBG8_1X8:
89 	case MEDIA_BUS_FMT_SRGGB8_1X8:
90 	case MEDIA_BUS_FMT_Y8_1X8:
91 		return MIPI_CSI2_DT_RAW8;
92 	case MEDIA_BUS_FMT_META_8:
93 	case MEDIA_BUS_FMT_META_10:
94 	case MEDIA_BUS_FMT_META_12:
95 	case MEDIA_BUS_FMT_META_16:
96 	case MEDIA_BUS_FMT_META_24:
97 		return MIPI_CSI2_DT_EMBEDDED_8B;
98 	default:
99 		/* return unavailable MIPI data type - 0x3f */
100 		WARN_ON(1);
101 		return 0x3f;
102 	}
103 }
104 
105 bool ipu6_isys_is_bayer_format(u32 code)
106 {
107 	switch (code) {
108 	case MEDIA_BUS_FMT_SBGGR8_1X8:
109 	case MEDIA_BUS_FMT_SGBRG8_1X8:
110 	case MEDIA_BUS_FMT_SGRBG8_1X8:
111 	case MEDIA_BUS_FMT_SRGGB8_1X8:
112 	case MEDIA_BUS_FMT_SBGGR10_1X10:
113 	case MEDIA_BUS_FMT_SGBRG10_1X10:
114 	case MEDIA_BUS_FMT_SGRBG10_1X10:
115 	case MEDIA_BUS_FMT_SRGGB10_1X10:
116 	case MEDIA_BUS_FMT_SBGGR12_1X12:
117 	case MEDIA_BUS_FMT_SGBRG12_1X12:
118 	case MEDIA_BUS_FMT_SGRBG12_1X12:
119 	case MEDIA_BUS_FMT_SRGGB12_1X12:
120 	case MEDIA_BUS_FMT_SRGGB16_1X16:
121 	case MEDIA_BUS_FMT_SGRBG16_1X16:
122 	case MEDIA_BUS_FMT_SGBRG16_1X16:
123 	case MEDIA_BUS_FMT_SBGGR16_1X16:
124 		return true;
125 	default:
126 		return false;
127 	}
128 }
129 
130 u32 ipu6_isys_convert_bayer_order(u32 code, int x, int y)
131 {
132 	static const u32 code_map[] = {
133 		MEDIA_BUS_FMT_SRGGB8_1X8,
134 		MEDIA_BUS_FMT_SGRBG8_1X8,
135 		MEDIA_BUS_FMT_SGBRG8_1X8,
136 		MEDIA_BUS_FMT_SBGGR8_1X8,
137 		MEDIA_BUS_FMT_SRGGB10_1X10,
138 		MEDIA_BUS_FMT_SGRBG10_1X10,
139 		MEDIA_BUS_FMT_SGBRG10_1X10,
140 		MEDIA_BUS_FMT_SBGGR10_1X10,
141 		MEDIA_BUS_FMT_SRGGB12_1X12,
142 		MEDIA_BUS_FMT_SGRBG12_1X12,
143 		MEDIA_BUS_FMT_SGBRG12_1X12,
144 		MEDIA_BUS_FMT_SBGGR12_1X12,
145 		MEDIA_BUS_FMT_SRGGB16_1X16,
146 		MEDIA_BUS_FMT_SGRBG16_1X16,
147 		MEDIA_BUS_FMT_SGBRG16_1X16,
148 		MEDIA_BUS_FMT_SBGGR16_1X16,
149 	};
150 	u32 i;
151 
152 	for (i = 0; i < ARRAY_SIZE(code_map); i++)
153 		if (code_map[i] == code)
154 			break;
155 
156 	if (WARN_ON(i == ARRAY_SIZE(code_map)))
157 		return code;
158 
159 	return code_map[i ^ (((y & 1) << 1) | (x & 1))];
160 }
161 
162 int ipu6_isys_subdev_set_fmt(struct v4l2_subdev *sd,
163 			     struct v4l2_subdev_state *state,
164 			     struct v4l2_subdev_format *format)
165 {
166 	struct ipu6_isys_subdev *asd = to_ipu6_isys_subdev(sd);
167 	struct v4l2_mbus_framefmt *fmt;
168 	struct v4l2_rect *crop;
169 	u32 code = asd->supported_codes[0];
170 	u32 other_pad, other_stream;
171 	unsigned int i;
172 	int ret;
173 
174 	/* No transcoding, source and sink formats must match. */
175 	if ((sd->entity.pads[format->pad].flags & MEDIA_PAD_FL_SOURCE) &&
176 	    sd->entity.num_pads > 1)
177 		return v4l2_subdev_get_fmt(sd, state, format);
178 
179 	format->format.width = clamp(format->format.width, IPU6_ISYS_MIN_WIDTH,
180 				     IPU6_ISYS_MAX_WIDTH);
181 	format->format.height = clamp(format->format.height,
182 				      IPU6_ISYS_MIN_HEIGHT,
183 				      IPU6_ISYS_MAX_HEIGHT);
184 
185 	for (i = 0; asd->supported_codes[i]; i++) {
186 		if (asd->supported_codes[i] == format->format.code) {
187 			code = asd->supported_codes[i];
188 			break;
189 		}
190 	}
191 	format->format.code = code;
192 	format->format.field = V4L2_FIELD_NONE;
193 
194 	/* Store the format and propagate it to the source pad. */
195 	fmt = v4l2_subdev_state_get_format(state, format->pad, format->stream);
196 	if (!fmt)
197 		return -EINVAL;
198 
199 	*fmt = format->format;
200 
201 	if (!(sd->entity.pads[format->pad].flags & MEDIA_PAD_FL_SINK))
202 		return 0;
203 
204 	/* propagate format to following source pad */
205 	fmt = v4l2_subdev_state_get_opposite_stream_format(state, format->pad,
206 							   format->stream);
207 	if (!fmt)
208 		return -EINVAL;
209 
210 	*fmt = format->format;
211 
212 	ret = v4l2_subdev_routing_find_opposite_end(&state->routing,
213 						    format->pad,
214 						    format->stream,
215 						    &other_pad,
216 						    &other_stream);
217 	if (ret)
218 		return -EINVAL;
219 
220 	crop = v4l2_subdev_state_get_crop(state, other_pad, other_stream);
221 	/* reset crop */
222 	crop->left = 0;
223 	crop->top = 0;
224 	crop->width = fmt->width;
225 	crop->height = fmt->height;
226 
227 	return 0;
228 }
229 
230 int ipu6_isys_subdev_enum_mbus_code(struct v4l2_subdev *sd,
231 				    struct v4l2_subdev_state *state,
232 				    struct v4l2_subdev_mbus_code_enum *code)
233 {
234 	struct ipu6_isys_subdev *asd = to_ipu6_isys_subdev(sd);
235 	const u32 *supported_codes = asd->supported_codes;
236 	u32 index;
237 
238 	for (index = 0; supported_codes[index]; index++) {
239 		if (index == code->index) {
240 			code->code = supported_codes[index];
241 			return 0;
242 		}
243 	}
244 
245 	return -EINVAL;
246 }
247 
248 static int subdev_set_routing(struct v4l2_subdev *sd,
249 			      struct v4l2_subdev_state *state,
250 			      struct v4l2_subdev_krouting *routing)
251 {
252 	static const struct v4l2_mbus_framefmt format = {
253 		.width = 4096,
254 		.height = 3072,
255 		.code = MEDIA_BUS_FMT_SGRBG10_1X10,
256 		.field = V4L2_FIELD_NONE,
257 	};
258 	int ret;
259 
260 	ret = v4l2_subdev_routing_validate(sd, routing,
261 					   V4L2_SUBDEV_ROUTING_ONLY_1_TO_1);
262 	if (ret)
263 		return ret;
264 
265 	return v4l2_subdev_set_routing_with_fmt(sd, state, routing, &format);
266 }
267 
268 int ipu6_isys_get_stream_pad_fmt(struct v4l2_subdev *sd, u32 pad, u32 stream,
269 				 struct v4l2_mbus_framefmt *format)
270 {
271 	struct v4l2_mbus_framefmt *fmt;
272 	struct v4l2_subdev_state *state;
273 
274 	if (!sd || !format)
275 		return -EINVAL;
276 
277 	state = v4l2_subdev_lock_and_get_active_state(sd);
278 	fmt = v4l2_subdev_state_get_format(state, pad, stream);
279 	if (fmt)
280 		*format = *fmt;
281 	v4l2_subdev_unlock_state(state);
282 
283 	return fmt ? 0 : -EINVAL;
284 }
285 
286 int ipu6_isys_get_stream_pad_crop(struct v4l2_subdev *sd, u32 pad, u32 stream,
287 				  struct v4l2_rect *crop)
288 {
289 	struct v4l2_subdev_state *state;
290 	struct v4l2_rect *rect;
291 
292 	if (!sd || !crop)
293 		return -EINVAL;
294 
295 	state = v4l2_subdev_lock_and_get_active_state(sd);
296 	rect = v4l2_subdev_state_get_crop(state, pad, stream);
297 	if (rect)
298 		*crop = *rect;
299 	v4l2_subdev_unlock_state(state);
300 
301 	return rect ? 0 : -EINVAL;
302 }
303 
304 u32 ipu6_isys_get_src_stream_by_src_pad(struct v4l2_subdev *sd, u32 pad)
305 {
306 	struct v4l2_subdev_state *state;
307 	struct v4l2_subdev_route *routes;
308 	unsigned int i;
309 	u32 source_stream = 0;
310 
311 	state = v4l2_subdev_lock_and_get_active_state(sd);
312 	if (!state)
313 		return 0;
314 
315 	routes = state->routing.routes;
316 	for (i = 0; i < state->routing.num_routes; i++) {
317 		if (routes[i].source_pad == pad) {
318 			source_stream = routes[i].source_stream;
319 			break;
320 		}
321 	}
322 
323 	v4l2_subdev_unlock_state(state);
324 
325 	return source_stream;
326 }
327 
328 static int ipu6_isys_subdev_init_state(struct v4l2_subdev *sd,
329 				       struct v4l2_subdev_state *state)
330 {
331 	struct v4l2_subdev_route route = {
332 		.sink_pad = 0,
333 		.sink_stream = 0,
334 		.source_pad = 1,
335 		.source_stream = 0,
336 		.flags = V4L2_SUBDEV_ROUTE_FL_ACTIVE,
337 	};
338 	struct v4l2_subdev_krouting routing = {
339 		.num_routes = 1,
340 		.routes = &route,
341 	};
342 
343 	return subdev_set_routing(sd, state, &routing);
344 }
345 
346 int ipu6_isys_subdev_set_routing(struct v4l2_subdev *sd,
347 				 struct v4l2_subdev_state *state,
348 				 enum v4l2_subdev_format_whence which,
349 				 struct v4l2_subdev_krouting *routing)
350 {
351 	return subdev_set_routing(sd, state, routing);
352 }
353 
354 static const struct v4l2_subdev_internal_ops ipu6_isys_subdev_internal_ops = {
355 	.init_state = ipu6_isys_subdev_init_state,
356 };
357 
358 int ipu6_isys_subdev_init(struct ipu6_isys_subdev *asd,
359 			  const struct v4l2_subdev_ops *ops,
360 			  unsigned int nr_ctrls,
361 			  unsigned int num_sink_pads,
362 			  unsigned int num_source_pads)
363 {
364 	unsigned int num_pads = num_sink_pads + num_source_pads;
365 	unsigned int i;
366 	int ret;
367 
368 	v4l2_subdev_init(&asd->sd, ops);
369 
370 	asd->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
371 			 V4L2_SUBDEV_FL_HAS_EVENTS |
372 			 V4L2_SUBDEV_FL_STREAMS;
373 	asd->sd.owner = THIS_MODULE;
374 	asd->sd.dev = &asd->isys->adev->auxdev.dev;
375 	asd->sd.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;
376 	asd->sd.internal_ops = &ipu6_isys_subdev_internal_ops;
377 
378 	asd->pad = devm_kcalloc(&asd->isys->adev->auxdev.dev, num_pads,
379 				sizeof(*asd->pad), GFP_KERNEL);
380 	if (!asd->pad)
381 		return -ENOMEM;
382 
383 	for (i = 0; i < num_sink_pads; i++)
384 		asd->pad[i].flags = MEDIA_PAD_FL_SINK |
385 				    MEDIA_PAD_FL_MUST_CONNECT;
386 
387 	for (i = num_sink_pads; i < num_pads; i++)
388 		asd->pad[i].flags = MEDIA_PAD_FL_SOURCE;
389 
390 	ret = media_entity_pads_init(&asd->sd.entity, num_pads, asd->pad);
391 	if (ret)
392 		return ret;
393 
394 	if (asd->ctrl_init) {
395 		ret = v4l2_ctrl_handler_init(&asd->ctrl_handler, nr_ctrls);
396 		if (ret)
397 			goto out_media_entity_cleanup;
398 
399 		asd->ctrl_init(&asd->sd);
400 		if (asd->ctrl_handler.error) {
401 			ret = asd->ctrl_handler.error;
402 			goto out_v4l2_ctrl_handler_free;
403 		}
404 
405 		asd->sd.ctrl_handler = &asd->ctrl_handler;
406 	}
407 
408 	asd->source = -1;
409 
410 	return 0;
411 
412 out_v4l2_ctrl_handler_free:
413 	v4l2_ctrl_handler_free(&asd->ctrl_handler);
414 
415 out_media_entity_cleanup:
416 	media_entity_cleanup(&asd->sd.entity);
417 
418 	return ret;
419 }
420 
421 void ipu6_isys_subdev_cleanup(struct ipu6_isys_subdev *asd)
422 {
423 	media_entity_cleanup(&asd->sd.entity);
424 	v4l2_ctrl_handler_free(&asd->ctrl_handler);
425 }
426