File Index
Files and directories
Sign in
FILE

rkcif-interface.c

File preview with syntax highlighting.

linux-6.19.14/drivers/media/platform/rockchip/rkcif/rkcif-interface.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Rockchip Camera Interface (CIF) Driver
  4 *
  5 * Copyright (C) 2025 Michael Riesch <michael.riesch@wolfvision.net>
  6 * Copyright (C) 2025 Collabora, Ltd.
  7 */
  8
  9#include <media/v4l2-common.h>
 10#include <media/v4l2-fwnode.h>
 11#include <media/v4l2-mc.h>
 12#include <media/v4l2-subdev.h>
 13
 14#include "rkcif-common.h"
 15#include "rkcif-interface.h"
 16
 17static inline struct rkcif_interface *to_rkcif_interface(struct v4l2_subdev *sd)
 18{
 19	return container_of(sd, struct rkcif_interface, sd);
 20}
 21
 22static const struct media_entity_operations rkcif_interface_media_ops = {
 23	.link_validate = v4l2_subdev_link_validate,
 24	.has_pad_interdep = v4l2_subdev_has_pad_interdep,
 25};
 26
 27static int rkcif_interface_set_fmt(struct v4l2_subdev *sd,
 28				   struct v4l2_subdev_state *state,
 29				   struct v4l2_subdev_format *format)
 30{
 31	struct rkcif_interface *interface = to_rkcif_interface(sd);
 32	const struct rkcif_input_fmt *input;
 33	struct v4l2_mbus_framefmt *sink, *src;
 34	struct v4l2_rect *crop;
 35	u32 other_pad, other_stream;
 36	int ret;
 37
 38	/* the format on the source pad always matches the sink pad */
 39	if (format->pad == RKCIF_IF_PAD_SRC)
 40		return v4l2_subdev_get_fmt(sd, state, format);
 41
 42	input = rkcif_interface_find_input_fmt(interface, true,
 43					       format->format.code);
 44	format->format.code = input->mbus_code;
 45
 46	sink = v4l2_subdev_state_get_format(state, format->pad, format->stream);
 47	if (!sink)
 48		return -EINVAL;
 49
 50	*sink = format->format;
 51
 52	/* propagate the format to the source pad */
 53	src = v4l2_subdev_state_get_opposite_stream_format(state, format->pad,
 54							   format->stream);
 55	if (!src)
 56		return -EINVAL;
 57
 58	*src = *sink;
 59
 60	ret = v4l2_subdev_routing_find_opposite_end(&state->routing,
 61						    format->pad, format->stream,
 62						    &other_pad, &other_stream);
 63	if (ret)
 64		return -EINVAL;
 65
 66	crop = v4l2_subdev_state_get_crop(state, other_pad, other_stream);
 67	if (!crop)
 68		return -EINVAL;
 69
 70	/* reset crop */
 71	crop->left = 0;
 72	crop->top = 0;
 73	crop->width = sink->width;
 74	crop->height = sink->height;
 75
 76	return 0;
 77}
 78
 79static int rkcif_interface_get_sel(struct v4l2_subdev *sd,
 80				   struct v4l2_subdev_state *state,
 81				   struct v4l2_subdev_selection *sel)
 82{
 83	struct v4l2_mbus_framefmt *sink;
 84	struct v4l2_rect *crop;
 85	int ret = 0;
 86
 87	if (sel->pad != RKCIF_IF_PAD_SRC)
 88		return -EINVAL;
 89
 90	sink = v4l2_subdev_state_get_opposite_stream_format(state, sel->pad,
 91							    sel->stream);
 92	if (!sink)
 93		return -EINVAL;
 94
 95	crop = v4l2_subdev_state_get_crop(state, sel->pad, sel->stream);
 96	if (!crop)
 97		return -EINVAL;
 98
 99	switch (sel->target) {
100	case V4L2_SEL_TGT_CROP_DEFAULT:
101	case V4L2_SEL_TGT_CROP_BOUNDS:
102		sel->r.left = 0;
103		sel->r.top = 0;
104		sel->r.width = sink->width;
105		sel->r.height = sink->height;
106		break;
107	case V4L2_SEL_TGT_CROP:
108		sel->r = *crop;
109		break;
110	default:
111		ret = -EINVAL;
112	}
113
114	return ret;
115}
116
117static int rkcif_interface_set_sel(struct v4l2_subdev *sd,
118				   struct v4l2_subdev_state *state,
119				   struct v4l2_subdev_selection *sel)
120{
121	struct v4l2_mbus_framefmt *sink, *src;
122	struct v4l2_rect *crop;
123
124	if (sel->pad != RKCIF_IF_PAD_SRC || sel->target != V4L2_SEL_TGT_CROP)
125		return -EINVAL;
126
127	sink = v4l2_subdev_state_get_opposite_stream_format(state, sel->pad,
128							    sel->stream);
129	if (!sink)
130		return -EINVAL;
131
132	src = v4l2_subdev_state_get_format(state, sel->pad, sel->stream);
133	if (!src)
134		return -EINVAL;
135
136	crop = v4l2_subdev_state_get_crop(state, sel->pad, sel->stream);
137	if (!crop)
138		return -EINVAL;
139
140	*crop = sel->r;
141
142	src->height = sel->r.height;
143	src->width = sel->r.width;
144
145	return 0;
146}
147
148static int rkcif_interface_set_routing(struct v4l2_subdev *sd,
149				       struct v4l2_subdev_state *state,
150				       enum v4l2_subdev_format_whence which,
151				       struct v4l2_subdev_krouting *routing)
152{
153	int ret;
154
155	ret = v4l2_subdev_routing_validate(sd, routing,
156					   V4L2_SUBDEV_ROUTING_ONLY_1_TO_1);
157	if (ret)
158		return ret;
159
160	for (unsigned int i = 0; i < routing->num_routes; i++) {
161		const struct v4l2_subdev_route *route = &routing->routes[i];
162
163		if (route->source_stream >= RKCIF_ID_MAX)
164			return -EINVAL;
165	}
166
167	ret = v4l2_subdev_set_routing(sd, state, routing);
168
169	return ret;
170}
171
172static int rkcif_interface_apply_crop(struct rkcif_stream *stream,
173				      struct v4l2_subdev_state *state)
174{
175	struct rkcif_interface *interface = stream->interface;
176	struct v4l2_rect *crop;
177
178	crop = v4l2_subdev_state_get_crop(state, RKCIF_IF_PAD_SRC, stream->id);
179	if (!crop)
180		return -EINVAL;
181
182	if (interface->set_crop)
183		interface->set_crop(stream, crop->left, crop->top);
184
185	return 0;
186}
187
188static int rkcif_interface_enable_streams(struct v4l2_subdev *sd,
189					  struct v4l2_subdev_state *state,
190					  u32 pad, u64 streams_mask)
191{
192	struct rkcif_interface *interface = to_rkcif_interface(sd);
193	struct rkcif_stream *stream;
194	struct v4l2_subdev_route *route;
195	struct v4l2_subdev *remote_sd;
196	struct media_pad *remote_pad;
197	u64 mask;
198
199	remote_pad =
200		media_pad_remote_pad_first(&sd->entity.pads[RKCIF_IF_PAD_SINK]);
201	remote_sd = media_entity_to_v4l2_subdev(remote_pad->entity);
202
203	/* DVP has one crop setting for all IDs */
204	if (interface->type == RKCIF_IF_DVP) {
205		stream = &interface->streams[RKCIF_ID0];
206		rkcif_interface_apply_crop(stream, state);
207	} else {
208		for_each_active_route(&state->routing, route) {
209			stream = &interface->streams[route->sink_stream];
210			rkcif_interface_apply_crop(stream, state);
211		}
212	}
213
214	mask = v4l2_subdev_state_xlate_streams(state, RKCIF_IF_PAD_SINK,
215					       RKCIF_IF_PAD_SRC, &streams_mask);
216
217	return v4l2_subdev_enable_streams(remote_sd, remote_pad->index, mask);
218}
219
220static int rkcif_interface_disable_streams(struct v4l2_subdev *sd,
221					   struct v4l2_subdev_state *state,
222					   u32 pad, u64 streams_mask)
223{
224	struct v4l2_subdev *remote_sd;
225	struct media_pad *remote_pad;
226	u64 mask;
227
228	remote_pad =
229		media_pad_remote_pad_first(&sd->entity.pads[RKCIF_IF_PAD_SINK]);
230	remote_sd = media_entity_to_v4l2_subdev(remote_pad->entity);
231
232	mask = v4l2_subdev_state_xlate_streams(state, RKCIF_IF_PAD_SINK,
233					       RKCIF_IF_PAD_SRC, &streams_mask);
234
235	return v4l2_subdev_disable_streams(remote_sd, remote_pad->index, mask);
236}
237
238static const struct v4l2_subdev_pad_ops rkcif_interface_pad_ops = {
239	.get_fmt = v4l2_subdev_get_fmt,
240	.set_fmt = rkcif_interface_set_fmt,
241	.get_selection = rkcif_interface_get_sel,
242	.set_selection = rkcif_interface_set_sel,
243	.set_routing = rkcif_interface_set_routing,
244	.enable_streams = rkcif_interface_enable_streams,
245	.disable_streams = rkcif_interface_disable_streams,
246};
247
248static const struct v4l2_subdev_ops rkcif_interface_ops = {
249	.pad = &rkcif_interface_pad_ops,
250};
251
252static int rkcif_interface_init_state(struct v4l2_subdev *sd,
253				      struct v4l2_subdev_state *state)
254{
255	struct rkcif_interface *interface = to_rkcif_interface(sd);
256	struct v4l2_subdev_route routes[] = {
257		{
258			.sink_pad = RKCIF_IF_PAD_SINK,
259			.sink_stream = 0,
260			.source_pad = RKCIF_IF_PAD_SRC,
261			.source_stream = 0,
262			.flags = V4L2_SUBDEV_ROUTE_FL_ACTIVE,
263		},
264	};
265	struct v4l2_subdev_krouting routing = {
266		.len_routes = ARRAY_SIZE(routes),
267		.num_routes = ARRAY_SIZE(routes),
268		.routes = routes,
269	};
270	const struct v4l2_mbus_framefmt dvp_default_format = {
271		.width = 3840,
272		.height = 2160,
273		.code = MEDIA_BUS_FMT_YUYV8_1X16,
274		.field = V4L2_FIELD_NONE,
275		.colorspace = V4L2_COLORSPACE_REC709,
276		.ycbcr_enc = V4L2_YCBCR_ENC_709,
277		.quantization = V4L2_QUANTIZATION_LIM_RANGE,
278		.xfer_func = V4L2_XFER_FUNC_NONE,
279	};
280	const struct v4l2_mbus_framefmt mipi_default_format = {
281		.width = 3840,
282		.height = 2160,
283		.code = MEDIA_BUS_FMT_SRGGB10_1X10,
284		.field = V4L2_FIELD_NONE,
285		.colorspace = V4L2_COLORSPACE_RAW,
286		.ycbcr_enc = V4L2_YCBCR_ENC_601,
287		.quantization = V4L2_QUANTIZATION_FULL_RANGE,
288		.xfer_func = V4L2_XFER_FUNC_NONE,
289	};
290	const struct v4l2_mbus_framefmt *default_format;
291	int ret;
292
293	default_format = (interface->type == RKCIF_IF_DVP) ?
294				 &dvp_default_format :
295				 &mipi_default_format;
296
297	ret = v4l2_subdev_set_routing_with_fmt(sd, state, &routing,
298					       default_format);
299
300	return ret;
301}
302
303static const struct v4l2_subdev_internal_ops rkcif_interface_internal_ops = {
304	.init_state = rkcif_interface_init_state,
305};
306
307static int rkcif_interface_add(struct rkcif_interface *interface)
308{
309	struct rkcif_device *rkcif = interface->rkcif;
310	struct rkcif_remote *remote;
311	struct v4l2_async_notifier *ntf = &rkcif->notifier;
312	struct v4l2_fwnode_endpoint *vep = &interface->vep;
313	struct device *dev = rkcif->dev;
314	struct fwnode_handle *ep;
315	u32 dvp_clk_delay = 0;
316	int ret;
317
318	ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), interface->index,
319					     0, 0);
320	if (!ep)
321		return -ENODEV;
322
323	vep->bus_type = V4L2_MBUS_UNKNOWN;
324	ret = v4l2_fwnode_endpoint_parse(ep, vep);
325	if (ret)
326		goto complete;
327
328	if (interface->type == RKCIF_IF_DVP) {
329		if (vep->bus_type != V4L2_MBUS_BT656 &&
330		    vep->bus_type != V4L2_MBUS_PARALLEL) {
331			ret = dev_err_probe(dev, -EINVAL,
332					    "unsupported bus type\n");
333			goto complete;
334		}
335
336		fwnode_property_read_u32(ep, "rockchip,dvp-clk-delay",
337					 &dvp_clk_delay);
338		interface->dvp.dvp_clk_delay = dvp_clk_delay;
339	}
340
341	remote = v4l2_async_nf_add_fwnode_remote(ntf, ep, struct rkcif_remote);
342	if (IS_ERR(remote)) {
343		ret = PTR_ERR(remote);
344		goto complete;
345	}
346
347	remote->interface = interface;
348	interface->remote = remote;
349	interface->status = RKCIF_IF_ACTIVE;
350	ret = 0;
351
352complete:
353	fwnode_handle_put(ep);
354
355	return ret;
356}
357
358int rkcif_interface_register(struct rkcif_device *rkcif,
359			     struct rkcif_interface *interface)
360{
361	struct media_pad *pads = interface->pads;
362	struct v4l2_subdev *sd = &interface->sd;
363	int ret;
364
365	interface->rkcif = rkcif;
366
367	v4l2_subdev_init(sd, &rkcif_interface_ops);
368	sd->dev = rkcif->dev;
369	sd->entity.ops = &rkcif_interface_media_ops;
370	sd->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;
371	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_STREAMS;
372	sd->internal_ops = &rkcif_interface_internal_ops;
373	sd->owner = THIS_MODULE;
374
375	if (interface->type == RKCIF_IF_DVP)
376		snprintf(sd->name, sizeof(sd->name), "rkcif-dvp0");
377	else if (interface->type == RKCIF_IF_MIPI)
378		snprintf(sd->name, sizeof(sd->name), "rkcif-mipi%d",
379			 interface->index - RKCIF_MIPI_BASE);
380
381	pads[RKCIF_IF_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
382	pads[RKCIF_IF_PAD_SRC].flags = MEDIA_PAD_FL_SOURCE;
383	ret = media_entity_pads_init(&sd->entity, RKCIF_IF_PAD_MAX, pads);
384	if (ret)
385		goto err;
386
387	ret = v4l2_subdev_init_finalize(sd);
388	if (ret)
389		goto err_entity_cleanup;
390
391	ret = v4l2_device_register_subdev(&rkcif->v4l2_dev, sd);
392	if (ret) {
393		dev_err(sd->dev, "failed to register subdev\n");
394		goto err_subdev_cleanup;
395	}
396
397	ret = rkcif_interface_add(interface);
398	if (ret)
399		goto err_subdev_unregister;
400
401	return 0;
402
403err_subdev_unregister:
404	v4l2_device_unregister_subdev(sd);
405err_subdev_cleanup:
406	v4l2_subdev_cleanup(sd);
407err_entity_cleanup:
408	media_entity_cleanup(&sd->entity);
409err:
410	return ret;
411}
412
413void rkcif_interface_unregister(struct rkcif_interface *interface)
414{
415	struct v4l2_subdev *sd = &interface->sd;
416
417	if (interface->status != RKCIF_IF_ACTIVE)
418		return;
419
420	v4l2_device_unregister_subdev(sd);
421	v4l2_subdev_cleanup(sd);
422	media_entity_cleanup(&sd->entity);
423}
424
425const struct rkcif_input_fmt *
426rkcif_interface_find_input_fmt(struct rkcif_interface *interface, bool ret_def,
427			       u32 mbus_code)
428{
429	const struct rkcif_input_fmt *fmt;
430
431	WARN_ON(interface->in_fmts_num == 0);
432
433	for (unsigned int i = 0; i < interface->in_fmts_num; i++) {
434		fmt = &interface->in_fmts[i];
435		if (fmt->mbus_code == mbus_code)
436			return fmt;
437	}
438	if (ret_def)
439		return &interface->in_fmts[0];
440	else
441		return NULL;
442}
~/ Read-only file preview.