From nobody Mon Feb 9 16:38:32 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 42E9E2D7DD4; Wed, 15 Oct 2025 14:56:28 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1760540188; cv=none; b=uGR0VXIEplLoj7R2oQ1xffU6SO/Ezi2/9MQlPu2RJjBgu5hq6G2UudtjlsTS4QdkYvtkrdrgNUZmdezmxYDsTijPoUSjbxtL6L7YrGxjZk6XM73aSoJm/uN4tfk66bMiMMjLmDiYClpFfiy8YxxljVi+TwEh3lNvdbSrC3N+QB4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1760540188; c=relaxed/simple; bh=f920Zl64SHfjpPVnmieHnCw8gH1sbYcEkdt6qA0T92A=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=ZvYhiWJ0SMBU6xPrIDmmldcijmQahUUbMx378QLJ+6G4C0OS75Z4MIxSOGctNCpckzJ6DXl9TCZQo5ToWWXQKrkxx1sNOyxwhyUyvUUTRRydeQW7ZogY5hn14X6qR1DEHdR1m/w+5s1M0t4tgK7B5lkEtRQ+2O/8FVEEJe12uP0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=p5jDJlcK; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="p5jDJlcK" Received: by smtp.kernel.org (Postfix) with ESMTPS id DE18DC2BCF4; Wed, 15 Oct 2025 14:56:27 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1760540187; bh=f920Zl64SHfjpPVnmieHnCw8gH1sbYcEkdt6qA0T92A=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=p5jDJlcKf9T9MRqH3zmMZsO/3WJr0gBc0wvsNaBQB8l0dg7TV2OrYnASu8PHl17sL bOEzajDRH/1IYXzfVgcq1osnhcQaeBDm2KhUc1vQvWNGRcpE4xfBf5MXwuX+bmdA35 mXSbQ24jcZSxGpY+LgKlRUWE/5/kXbFJw/TfzgaGDSCRtkB+r4Mi+WzATxOIBgV4ZU opxAKIBt7eQbetWJGB7ZYIkbG9HIuY4Q4PSWfi1xHxmsx51JJwp6s9Mawwdsakj3FZ j4mPrPD7FBCAAFCpBz4IMjaRWCAWza3GtcXBQGP0idfhxsWeoHloPTX4SMl/ZfVker cFob5QB+UjbfQ== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id D3E39CCD194; Wed, 15 Oct 2025 14:56:27 +0000 (UTC) From: Michael Riesch via B4 Relay Date: Wed, 15 Oct 2025 16:56:31 +0200 Subject: [PATCH v13 08/18] media: rockchip: rkcif: add abstraction for interface and crop blocks Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20240220-rk3568-vicap-v13-8-da164b4918fe@collabora.com> References: <20240220-rk3568-vicap-v13-0-da164b4918fe@collabora.com> In-Reply-To: <20240220-rk3568-vicap-v13-0-da164b4918fe@collabora.com> To: Mehdi Djait , Maxime Chevallier , =?utf-8?q?Th=C3=A9o_Lebrun?= , Thomas Petazzoni , Gerald Loacker , Bryan O'Donoghue , Markus Elfring , Laurent Pinchart , Mauro Carvalho Chehab , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Heiko Stuebner , Kever Yang , Nicolas Dufresne , Sebastian Reichel , Collabora Kernel Team , Paul Kocialkowski , Alexander Shiyan , Val Packett , Rob Herring , Philipp Zabel , Sakari Ailus Cc: linux-media@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-rockchip@lists.infradead.org, Michael Riesch , Michael Riesch X-Mailer: b4 0.12.0 X-Developer-Signature: v=1; a=ed25519-sha256; t=1760540185; l=17229; i=michael.riesch@collabora.com; s=20250410; h=from:subject:message-id; bh=FzRmmqtIMIBhOXHIuJprbzKa/+zK1isBj+MF4VCktl4=; b=qS/BqmHIZcMFNbuu8MweZ7rne1tb8SLVgT+t+8K5qAWLwM0aTdbEbONElxmIQxMa1PISlFDus plqmOs8MAQ2DyIZlasFKgjXvEAR9oNmv2rXIZUMcTWpKWrAIBSSNMjp X-Developer-Key: i=michael.riesch@collabora.com; a=ed25519; pk=+MWX1fffLFZtTPG/I6XdYm/+OSvpRE8D9evQaWbiN04= X-Endpoint-Received: by B4 Relay for michael.riesch@collabora.com/20250410 with auth_id=371 X-Original-From: Michael Riesch Reply-To: michael.riesch@collabora.com From: Michael Riesch Add an abstraction for the INTERFACE and CROP parts of the different Rockchip Camera Interface (CIF) variants. These parts are represented as V4L2 subdevice with one sink pad and one source pad. The sink pad is connected to a subdevice: either the subdevice provided by the driver of the companion chip connected to the DVP, or the subdevice provided by the MIPI CSI-2 receiver. The source pad is connected to V4l2 device(s) provided by one or many instance(s) of the DMA abstraction. Tested-by: Gerald Loacker Reviewed-by: Gerald Loacker Reviewed-by: Bryan O'Donoghue Reviewed-by: Mehdi Djait Signed-off-by: Michael Riesch --- drivers/media/platform/rockchip/rkcif/Makefile | 1 + .../media/platform/rockchip/rkcif/rkcif-common.h | 71 ++++ drivers/media/platform/rockchip/rkcif/rkcif-dev.c | 13 + .../platform/rockchip/rkcif/rkcif-interface.c | 389 +++++++++++++++++= ++++ .../platform/rockchip/rkcif/rkcif-interface.h | 31 ++ 5 files changed, 505 insertions(+) diff --git a/drivers/media/platform/rockchip/rkcif/Makefile b/drivers/media= /platform/rockchip/rkcif/Makefile index c6837ed2f65c..9d535fc27e51 100644 --- a/drivers/media/platform/rockchip/rkcif/Makefile +++ b/drivers/media/platform/rockchip/rkcif/Makefile @@ -2,3 +2,4 @@ obj-$(CONFIG_VIDEO_ROCKCHIP_CIF) +=3D rockchip-cif.o =20 rockchip-cif-objs +=3D rkcif-dev.o +rockchip-cif-objs +=3D rkcif-interface.o diff --git a/drivers/media/platform/rockchip/rkcif/rkcif-common.h b/drivers= /media/platform/rockchip/rkcif/rkcif-common.h index b456a56b5ac4..f01536727a5d 100644 --- a/drivers/media/platform/rockchip/rkcif/rkcif-common.h +++ b/drivers/media/platform/rockchip/rkcif/rkcif-common.h @@ -27,9 +27,78 @@ #define RKCIF_DRIVER_NAME "rockchip-cif" #define RKCIF_CLK_MAX 4 =20 +enum rkcif_format_type { + RKCIF_FMT_TYPE_INVALID, + RKCIF_FMT_TYPE_YUV, + RKCIF_FMT_TYPE_RAW, +}; + +enum rkcif_interface_index { + RKCIF_DVP, + RKCIF_MIPI_BASE, + RKCIF_MIPI1 =3D RKCIF_MIPI_BASE, + RKCIF_MIPI2, + RKCIF_MIPI3, + RKCIF_MIPI4, + RKCIF_MIPI5, + RKCIF_MIPI6, + RKCIF_MIPI_MAX, + RKCIF_IF_MAX =3D RKCIF_MIPI_MAX +}; + +enum rkcif_interface_pad_index { + RKCIF_IF_PAD_SINK, + RKCIF_IF_PAD_SRC, + RKCIF_IF_PAD_MAX +}; + +enum rkcif_interface_status { + RKCIF_IF_INACTIVE, + RKCIF_IF_ACTIVE, +}; + +enum rkcif_interface_type { + RKCIF_IF_INVALID, + RKCIF_IF_DVP, + RKCIF_IF_MIPI, +}; + +struct rkcif_input_fmt { + u32 mbus_code; + + enum rkcif_format_type fmt_type; + enum v4l2_field field; +}; + +struct rkcif_interface; + struct rkcif_remote { struct v4l2_async_connection async_conn; struct v4l2_subdev *sd; + + struct rkcif_interface *interface; +}; + +struct rkcif_dvp { + u32 dvp_clk_delay; +}; + +struct rkcif_interface { + enum rkcif_interface_type type; + enum rkcif_interface_status status; + enum rkcif_interface_index index; + struct rkcif_device *rkcif; + struct rkcif_remote *remote; + const struct rkcif_input_fmt *in_fmts; + unsigned int in_fmts_num; + + struct media_pad pads[RKCIF_IF_PAD_MAX]; + struct v4l2_fwnode_endpoint vep; + struct v4l2_subdev sd; + + union { + struct rkcif_dvp dvp; + }; }; =20 struct rkcif_match_data { @@ -47,6 +116,8 @@ struct rkcif_device { struct reset_control *reset; void __iomem *base_addr; =20 + struct rkcif_interface interfaces[RKCIF_IF_MAX]; + struct media_device media_dev; struct v4l2_device v4l2_dev; struct v4l2_async_notifier notifier; diff --git a/drivers/media/platform/rockchip/rkcif/rkcif-dev.c b/drivers/me= dia/platform/rockchip/rkcif/rkcif-dev.c index 9215dbe90353..49e53f70715c 100644 --- a/drivers/media/platform/rockchip/rkcif/rkcif-dev.c +++ b/drivers/media/platform/rockchip/rkcif/rkcif-dev.c @@ -74,8 +74,21 @@ static int rkcif_notifier_bound(struct v4l2_async_notifi= er *notifier, struct v4l2_subdev *sd, struct v4l2_async_connection *asd) { + struct rkcif_device *rkcif =3D + container_of(notifier, struct rkcif_device, notifier); struct rkcif_remote *remote =3D container_of(asd, struct rkcif_remote, async_conn); + struct media_pad *sink_pad =3D + &remote->interface->pads[RKCIF_IF_PAD_SINK]; + int ret; + + ret =3D v4l2_create_fwnode_links_to_pad(sd, sink_pad, + MEDIA_LNK_FL_ENABLED); + if (ret) { + dev_err(rkcif->dev, "failed to link source pad of %s\n", + sd->name); + return ret; + } =20 remote->sd =3D sd; =20 diff --git a/drivers/media/platform/rockchip/rkcif/rkcif-interface.c b/driv= ers/media/platform/rockchip/rkcif/rkcif-interface.c new file mode 100644 index 000000000000..9cea9060ce02 --- /dev/null +++ b/drivers/media/platform/rockchip/rkcif/rkcif-interface.c @@ -0,0 +1,389 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Rockchip Camera Interface (CIF) Driver + * + * Copyright (C) 2025 Michael Riesch + * Copyright (C) 2025 Collabora, Ltd. + */ + +#include +#include +#include +#include + +#include "rkcif-common.h" +#include "rkcif-interface.h" + +static inline struct rkcif_interface *to_rkcif_interface(struct v4l2_subde= v *sd) +{ + return container_of(sd, struct rkcif_interface, sd); +} + +static const struct media_entity_operations rkcif_interface_media_ops =3D { + .link_validate =3D v4l2_subdev_link_validate, + .has_pad_interdep =3D v4l2_subdev_has_pad_interdep, +}; + +static int rkcif_interface_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_format *format) +{ + struct rkcif_interface *interface =3D to_rkcif_interface(sd); + const struct rkcif_input_fmt *input; + struct v4l2_mbus_framefmt *sink, *src; + + /* the format on the source pad always matches the sink pad */ + if (format->pad =3D=3D RKCIF_IF_PAD_SRC) + return v4l2_subdev_get_fmt(sd, state, format); + + input =3D rkcif_interface_find_input_fmt(interface, true, + format->format.code); + format->format.code =3D input->mbus_code; + + sink =3D v4l2_subdev_state_get_format(state, format->pad, format->stream); + if (!sink) + return -EINVAL; + + *sink =3D format->format; + + /* propagate the format to the source pad */ + src =3D v4l2_subdev_state_get_opposite_stream_format(state, format->pad, + format->stream); + if (!src) + return -EINVAL; + + *src =3D *sink; + + return 0; +} + +static int rkcif_interface_get_sel(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_selection *sel) +{ + struct v4l2_mbus_framefmt *sink; + struct v4l2_rect *crop; + int ret =3D 0; + + if (sel->pad !=3D RKCIF_IF_PAD_SRC) + return -EINVAL; + + sink =3D v4l2_subdev_state_get_opposite_stream_format(state, sel->pad, + sel->stream); + if (!sink) + return -EINVAL; + + crop =3D v4l2_subdev_state_get_crop(state, sel->pad, sel->stream); + if (!crop) + return -EINVAL; + + switch (sel->target) { + case V4L2_SEL_TGT_CROP_DEFAULT: + case V4L2_SEL_TGT_CROP_BOUNDS: + sel->r.left =3D 0; + sel->r.top =3D 0; + sel->r.width =3D sink->width; + sel->r.height =3D sink->height; + break; + case V4L2_SEL_TGT_CROP: + sel->r =3D *crop; + break; + default: + ret =3D -EINVAL; + } + + return ret; +} + +static int rkcif_interface_set_sel(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_selection *sel) +{ + struct v4l2_mbus_framefmt *sink, *src; + struct v4l2_rect *crop; + + if (sel->pad !=3D RKCIF_IF_PAD_SRC || sel->target !=3D V4L2_SEL_TGT_CROP) + return -EINVAL; + + sink =3D v4l2_subdev_state_get_opposite_stream_format(state, sel->pad, + sel->stream); + if (!sink) + return -EINVAL; + + src =3D v4l2_subdev_state_get_format(state, sel->pad, sel->stream); + if (!src) + return -EINVAL; + + crop =3D v4l2_subdev_state_get_crop(state, sel->pad, sel->stream); + if (!crop) + return -EINVAL; + + /* only starting point of crop can be specified */ + sel->r.height =3D sink->height - sel->r.top; + sel->r.width =3D sink->width - sel->r.left; + *crop =3D sel->r; + + src->height =3D sel->r.height; + src->width =3D sel->r.width; + + return 0; +} + +static int rkcif_interface_set_routing(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + enum v4l2_subdev_format_whence which, + struct v4l2_subdev_krouting *routing) +{ + int ret; + + ret =3D v4l2_subdev_routing_validate(sd, routing, + V4L2_SUBDEV_ROUTING_ONLY_1_TO_1); + if (ret) + return ret; + + ret =3D v4l2_subdev_set_routing(sd, state, routing); + + return ret; +} + +static int rkcif_interface_enable_streams(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + u32 pad, u64 streams_mask) +{ + struct v4l2_subdev *remote_sd; + struct media_pad *remote_pad; + u64 mask; + + remote_pad =3D + media_pad_remote_pad_first(&sd->entity.pads[RKCIF_IF_PAD_SINK]); + remote_sd =3D media_entity_to_v4l2_subdev(remote_pad->entity); + + mask =3D v4l2_subdev_state_xlate_streams(state, RKCIF_IF_PAD_SINK, + RKCIF_IF_PAD_SRC, &streams_mask); + + return v4l2_subdev_enable_streams(remote_sd, remote_pad->index, mask); +} + +static int rkcif_interface_disable_streams(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + u32 pad, u64 streams_mask) +{ + struct v4l2_subdev *remote_sd; + struct media_pad *remote_pad; + u64 mask; + + remote_pad =3D + media_pad_remote_pad_first(&sd->entity.pads[RKCIF_IF_PAD_SINK]); + remote_sd =3D media_entity_to_v4l2_subdev(remote_pad->entity); + + mask =3D v4l2_subdev_state_xlate_streams(state, RKCIF_IF_PAD_SINK, + RKCIF_IF_PAD_SRC, &streams_mask); + + return v4l2_subdev_disable_streams(remote_sd, remote_pad->index, mask); +} + +static const struct v4l2_subdev_pad_ops rkcif_interface_pad_ops =3D { + .get_fmt =3D v4l2_subdev_get_fmt, + .set_fmt =3D rkcif_interface_set_fmt, + .get_selection =3D rkcif_interface_get_sel, + .set_selection =3D rkcif_interface_set_sel, + .set_routing =3D rkcif_interface_set_routing, + .enable_streams =3D rkcif_interface_enable_streams, + .disable_streams =3D rkcif_interface_disable_streams, +}; + +static const struct v4l2_subdev_ops rkcif_interface_ops =3D { + .pad =3D &rkcif_interface_pad_ops, +}; + +static int rkcif_interface_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state) +{ + struct rkcif_interface *interface =3D to_rkcif_interface(sd); + struct v4l2_subdev_route routes[] =3D { + { + .sink_pad =3D RKCIF_IF_PAD_SINK, + .sink_stream =3D 0, + .source_pad =3D RKCIF_IF_PAD_SRC, + .source_stream =3D 0, + .flags =3D V4L2_SUBDEV_ROUTE_FL_ACTIVE, + }, + }; + struct v4l2_subdev_krouting routing =3D { + .len_routes =3D ARRAY_SIZE(routes), + .num_routes =3D ARRAY_SIZE(routes), + .routes =3D routes, + }; + const struct v4l2_mbus_framefmt dvp_default_format =3D { + .width =3D 3840, + .height =3D 2160, + .code =3D MEDIA_BUS_FMT_YUYV8_1X16, + .field =3D V4L2_FIELD_NONE, + .colorspace =3D V4L2_COLORSPACE_REC709, + .ycbcr_enc =3D V4L2_YCBCR_ENC_709, + .quantization =3D V4L2_QUANTIZATION_LIM_RANGE, + .xfer_func =3D V4L2_XFER_FUNC_NONE, + }; + const struct v4l2_mbus_framefmt mipi_default_format =3D { + .width =3D 3840, + .height =3D 2160, + .code =3D MEDIA_BUS_FMT_SRGGB10_1X10, + .field =3D V4L2_FIELD_NONE, + .colorspace =3D V4L2_COLORSPACE_RAW, + .ycbcr_enc =3D V4L2_YCBCR_ENC_601, + .quantization =3D V4L2_QUANTIZATION_FULL_RANGE, + .xfer_func =3D V4L2_XFER_FUNC_NONE, + }; + const struct v4l2_mbus_framefmt *default_format; + int ret; + + default_format =3D (interface->type =3D=3D RKCIF_IF_DVP) ? + &dvp_default_format : + &mipi_default_format; + + ret =3D v4l2_subdev_set_routing_with_fmt(sd, state, &routing, + default_format); + + return ret; +} + +static const struct v4l2_subdev_internal_ops rkcif_interface_internal_ops = =3D { + .init_state =3D rkcif_interface_init_state, +}; + +static int rkcif_interface_add(struct rkcif_interface *interface) +{ + struct rkcif_device *rkcif =3D interface->rkcif; + struct rkcif_remote *remote; + struct v4l2_async_notifier *ntf =3D &rkcif->notifier; + struct v4l2_fwnode_endpoint *vep =3D &interface->vep; + struct device *dev =3D rkcif->dev; + struct fwnode_handle *ep; + u32 dvp_clk_delay =3D 0; + int ret; + + ep =3D fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), interface->index, + 0, 0); + if (!ep) + return -ENODEV; + + vep->bus_type =3D V4L2_MBUS_UNKNOWN; + ret =3D v4l2_fwnode_endpoint_parse(ep, vep); + if (ret) + goto complete; + + if (interface->type =3D=3D RKCIF_IF_DVP) { + if (vep->bus_type !=3D V4L2_MBUS_BT656 && + vep->bus_type !=3D V4L2_MBUS_PARALLEL) { + ret =3D dev_err_probe(dev, -EINVAL, + "unsupported bus type\n"); + goto complete; + } + + fwnode_property_read_u32(ep, "rockchip,dvp-clk-delay", + &dvp_clk_delay); + interface->dvp.dvp_clk_delay =3D dvp_clk_delay; + } + + remote =3D v4l2_async_nf_add_fwnode_remote(ntf, ep, struct rkcif_remote); + if (IS_ERR(remote)) { + ret =3D PTR_ERR(remote); + goto complete; + } + + remote->interface =3D interface; + interface->remote =3D remote; + interface->status =3D RKCIF_IF_ACTIVE; + ret =3D 0; + +complete: + fwnode_handle_put(ep); + + return ret; +} + +int rkcif_interface_register(struct rkcif_device *rkcif, + struct rkcif_interface *interface) +{ + struct media_pad *pads =3D interface->pads; + struct v4l2_subdev *sd =3D &interface->sd; + int ret; + + interface->rkcif =3D rkcif; + + v4l2_subdev_init(sd, &rkcif_interface_ops); + sd->dev =3D rkcif->dev; + sd->entity.ops =3D &rkcif_interface_media_ops; + sd->entity.function =3D MEDIA_ENT_F_VID_IF_BRIDGE; + sd->flags |=3D V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_STREAMS; + sd->internal_ops =3D &rkcif_interface_internal_ops; + sd->owner =3D THIS_MODULE; + + if (interface->type =3D=3D RKCIF_IF_DVP) + snprintf(sd->name, sizeof(sd->name), "rkcif-dvp0"); + else if (interface->type =3D=3D RKCIF_IF_MIPI) + snprintf(sd->name, sizeof(sd->name), "rkcif-mipi%d", + interface->index - RKCIF_MIPI_BASE); + + pads[RKCIF_IF_PAD_SINK].flags =3D MEDIA_PAD_FL_SINK; + pads[RKCIF_IF_PAD_SRC].flags =3D MEDIA_PAD_FL_SOURCE; + ret =3D media_entity_pads_init(&sd->entity, RKCIF_IF_PAD_MAX, pads); + if (ret) + goto err; + + ret =3D v4l2_subdev_init_finalize(sd); + if (ret) + goto err_entity_cleanup; + + ret =3D v4l2_device_register_subdev(&rkcif->v4l2_dev, sd); + if (ret) { + dev_err(sd->dev, "failed to register subdev\n"); + goto err_subdev_cleanup; + } + + ret =3D rkcif_interface_add(interface); + if (ret) + goto err_subdev_unregister; + + return 0; + +err_subdev_unregister: + v4l2_device_unregister_subdev(sd); +err_subdev_cleanup: + v4l2_subdev_cleanup(sd); +err_entity_cleanup: + media_entity_cleanup(&sd->entity); +err: + return ret; +} + +void rkcif_interface_unregister(struct rkcif_interface *interface) +{ + struct v4l2_subdev *sd =3D &interface->sd; + + if (interface->status !=3D RKCIF_IF_ACTIVE) + return; + + v4l2_device_unregister_subdev(sd); + v4l2_subdev_cleanup(sd); + media_entity_cleanup(&sd->entity); +} + +const struct rkcif_input_fmt * +rkcif_interface_find_input_fmt(struct rkcif_interface *interface, bool ret= _def, + u32 mbus_code) +{ + const struct rkcif_input_fmt *fmt; + + WARN_ON(interface->in_fmts_num =3D=3D 0); + + for (unsigned int i =3D 0; i < interface->in_fmts_num; i++) { + fmt =3D &interface->in_fmts[i]; + if (fmt->mbus_code =3D=3D mbus_code) + return fmt; + } + if (ret_def) + return &interface->in_fmts[0]; + else + return NULL; +} diff --git a/drivers/media/platform/rockchip/rkcif/rkcif-interface.h b/driv= ers/media/platform/rockchip/rkcif/rkcif-interface.h new file mode 100644 index 000000000000..f13aa28b6fa7 --- /dev/null +++ b/drivers/media/platform/rockchip/rkcif/rkcif-interface.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Rockchip Camera Interface (CIF) Driver + * + * Abstraction for the INTERFACE and CROP parts of the different CIF varia= nts. + * They shall be represented as V4L2 subdevice with one sink pad and one + * source pad. The sink pad is connected to a subdevice: either the subdev= ice + * provided by the driver of the companion chip connected to the DVP, or t= he + * subdevice provided by the MIPI CSI-2 receiver driver. The source pad is + * to V4l2 device(s) provided by one or many instance(s) of the DMA + * abstraction. + * + * Copyright (C) 2025 Michael Riesch + * Copyright (C) 2025 Collabora, Ltd. + */ + +#ifndef _RKCIF_INTERFACE_H +#define _RKCIF_INTERFACE_H + +#include "rkcif-common.h" + +int rkcif_interface_register(struct rkcif_device *rkcif, + struct rkcif_interface *interface); + +void rkcif_interface_unregister(struct rkcif_interface *interface); + +const struct rkcif_input_fmt * +rkcif_interface_find_input_fmt(struct rkcif_interface *interface, bool ret= _def, + u32 mbus_code); + +#endif --=20 2.39.5