From nobody Tue Dec 16 05:43:03 2025 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 D8D9C34029C; Fri, 14 Nov 2025 15:20:20 +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=1763133621; cv=none; b=jreu8TuMvIxFJt62184wHXyk3Ozq+kdylgEEVzeKYoQW5ZYZLNypTmN0aEIhBOU1bKbRbYp1Eghsn7JZqSr/mkNLb1nTB728dRaxyRJNRkWycHFacdA/OkQ6PgnXlZPlQMhrPgvSng8spVLj6bKerjI0qFGIqZ944kEbTaPXUM8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1763133621; c=relaxed/simple; bh=uI2gmuk6W6jKS5lvrE6qYjVwf9T0D5Cwegzz088e3Fs=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=WlRhAIxHS8C0U4s+dgTqcFcdeeKbkXHI8i94YG2G4mvxSY6+jx3fvAl4RdXfoVr2z+jU3kK5RCyvUCfLsKO7hHVTDinGuvg4+YUQOjclDWeFrvYVJdajNhryfht2HbHCclpJPCfJUYMf3e3fx3eiT0MjuPfVKAHPj0b5allK5Dg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=nFvTACBG; 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="nFvTACBG" Received: by smtp.kernel.org (Postfix) with ESMTPS id ABD63C4CEF8; Fri, 14 Nov 2025 15:20:20 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1763133620; bh=uI2gmuk6W6jKS5lvrE6qYjVwf9T0D5Cwegzz088e3Fs=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=nFvTACBGuIIt6LbXnadIqjxufFd4vJSwL4BRbNyydkBCehpvTDbjH32ONj1tuD2yg n1BSIfhA5ppbTEkzRZjNngSotsK3ngg/VB7jQ5SPFMUwpV/ltUc9pxLpyn2BkwXsnN 7DnB+IjcMck1QjN94P0COnuJxO+WRzyeKjR18zSomdft+cjPoCiGPorDhkYA1P4DCr esDlaB7nCbNKBFstEcseSkYNXxfW/Zlsx3I1XuuQ79ozoxP7VMUzAxd1vAsb3I4tYL XEhyYuHZJ1s30qE5D1EsHNiiH6T6zRfavBoneX3WU5UQ4PFx0GESk1DpYT3I1Uk+B3 r/wxVNabYxDdQ== 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 9E3BBCE7B1E; Fri, 14 Nov 2025 15:20:20 +0000 (UTC) From: Michael Riesch via B4 Relay Date: Fri, 14 Nov 2025 16:20:21 +0100 Subject: [PATCH v15 10/14] media: rockchip: rkcif: add support for rk3568 vicap mipi capture 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-v15-10-8f4915ee365d@collabora.com> References: <20240220-rk3568-vicap-v15-0-8f4915ee365d@collabora.com> In-Reply-To: <20240220-rk3568-vicap-v15-0-8f4915ee365d@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=1763133617; l=27198; i=michael.riesch@collabora.com; s=20250410; h=from:subject:message-id; bh=V/SSFlqvsbMLOMKOYqjTmzEpKtCu2afX7wqm/Jhnx5Q=; b=MlXsSkuCk/263/z2OWV1KsA5tgsOPc179gSXSZ8h4E2uPh9uUjXG33qYBaEBlpUMupf3axuiQ ZLXBgGyYvFhB7bg80h0mIFEgyL5FNA34fPX3bdHUnUmnU0e5SeB+J8e 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 The RK3568 Video Capture (VICAP) unit features a MIPI CSI-2 capture interface. Add support for the MIPI capture interface in general and for the RK3568 VICAP MIPI capture in particular. Signed-off-by: Michael Riesch Reviewed-by: Bryan O'Donoghue Reviewed-by: Mehdi Djait Signed-off-by: Michael Riesch --- drivers/media/platform/rockchip/rkcif/Makefile | 1 + .../platform/rockchip/rkcif/rkcif-capture-mipi.c | 777 +++++++++++++++++= ++++ .../platform/rockchip/rkcif/rkcif-capture-mipi.h | 23 + .../media/platform/rockchip/rkcif/rkcif-common.h | 29 + drivers/media/platform/rockchip/rkcif/rkcif-dev.c | 12 + drivers/media/platform/rockchip/rkcif/rkcif-regs.h | 22 + 6 files changed, 864 insertions(+) diff --git a/drivers/media/platform/rockchip/rkcif/Makefile b/drivers/media= /platform/rockchip/rkcif/Makefile index a36e294d569d..dca2bf45159f 100644 --- a/drivers/media/platform/rockchip/rkcif/Makefile +++ b/drivers/media/platform/rockchip/rkcif/Makefile @@ -2,6 +2,7 @@ obj-$(CONFIG_VIDEO_ROCKCHIP_CIF) +=3D rockchip-cif.o =20 rockchip-cif-objs +=3D rkcif-capture-dvp.o +rockchip-cif-objs +=3D rkcif-capture-mipi.o rockchip-cif-objs +=3D rkcif-dev.o rockchip-cif-objs +=3D rkcif-interface.o rockchip-cif-objs +=3D rkcif-stream.o diff --git a/drivers/media/platform/rockchip/rkcif/rkcif-capture-mipi.c b/d= rivers/media/platform/rockchip/rkcif/rkcif-capture-mipi.c new file mode 100644 index 000000000000..1b81bcc067ef --- /dev/null +++ b/drivers/media/platform/rockchip/rkcif/rkcif-capture-mipi.c @@ -0,0 +1,777 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Rockchip Camera Interface (CIF) Driver + * + * Copyright (C) 2018 Rockchip Electronics Co., Ltd. + * Copyright (C) 2025 Michael Riesch + * Copyright (C) 2025 Collabora, Ltd. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rkcif-capture-mipi.h" +#include "rkcif-common.h" +#include "rkcif-interface.h" +#include "rkcif-regs.h" +#include "rkcif-stream.h" + +#define RK3568_MIPI_CTRL0_HIGH_ALIGN BIT(31) +#define RK3568_MIPI_CTRL0_UV_SWAP_EN BIT(7) +#define RK3568_MIPI_CTRL0_COMPACT_EN BIT(6) +#define RK3568_MIPI_CTRL0_CROP_EN BIT(5) +#define RK3568_MIPI_CTRL0_WRDDR(type) ((type) << 1) + +#define RKCIF_MIPI_CTRL0_DT_ID(id) ((id) << 10) +#define RKCIF_MIPI_CTRL0_VC_ID(id) ((id) << 8) +#define RKCIF_MIPI_CTRL0_CAP_EN BIT(0) + +#define RKCIF_MIPI_INT_FRAME0_END(id) BIT(8 + (id) * 2 + 0) +#define RKCIF_MIPI_INT_FRAME1_END(id) BIT(8 + (id) * 2 + 1) + +static const struct rkcif_output_fmt mipi_out_fmts[] =3D { + /* YUV formats */ + { + .fourcc =3D V4L2_PIX_FMT_YUYV, + .mbus_code =3D MEDIA_BUS_FMT_YUYV8_1X16, + .depth =3D 16, + .cplanes =3D 1, + .mipi =3D { + .dt =3D MIPI_CSI2_DT_YUV422_8B, + .type =3D RKCIF_MIPI_TYPE_RAW8, + }, + }, + { + .fourcc =3D V4L2_PIX_FMT_UYVY, + .mbus_code =3D MEDIA_BUS_FMT_UYVY8_1X16, + .depth =3D 16, + .cplanes =3D 1, + .mipi =3D { + .dt =3D MIPI_CSI2_DT_YUV422_8B, + .type =3D RKCIF_MIPI_TYPE_RAW8, + }, + }, + { + .fourcc =3D V4L2_PIX_FMT_YVYU, + .mbus_code =3D MEDIA_BUS_FMT_YVYU8_1X16, + .depth =3D 16, + .cplanes =3D 1, + .mipi =3D { + .dt =3D MIPI_CSI2_DT_YUV422_8B, + .type =3D RKCIF_MIPI_TYPE_RAW8, + }, + }, + { + .fourcc =3D V4L2_PIX_FMT_VYUY, + .mbus_code =3D MEDIA_BUS_FMT_VYUY8_1X16, + .depth =3D 16, + .cplanes =3D 1, + .mipi =3D { + .dt =3D MIPI_CSI2_DT_YUV422_8B, + .type =3D RKCIF_MIPI_TYPE_RAW8, + }, + }, + /* RGB formats */ + { + .fourcc =3D V4L2_PIX_FMT_RGB24, + .mbus_code =3D MEDIA_BUS_FMT_RGB888_1X24, + .depth =3D 24, + .cplanes =3D 1, + .mipi =3D { + .dt =3D MIPI_CSI2_DT_RGB888, + .type =3D RKCIF_MIPI_TYPE_RGB888, + }, + }, + { + .fourcc =3D V4L2_PIX_FMT_BGR24, + .mbus_code =3D MEDIA_BUS_FMT_BGR888_1X24, + .depth =3D 24, + .cplanes =3D 1, + .mipi =3D { + .dt =3D MIPI_CSI2_DT_RGB888, + .type =3D RKCIF_MIPI_TYPE_RGB888, + }, + }, + /* Bayer formats */ + { + .fourcc =3D V4L2_PIX_FMT_SBGGR8, + .mbus_code =3D MEDIA_BUS_FMT_SBGGR8_1X8, + .depth =3D 8, + .cplanes =3D 1, + .mipi =3D { + .dt =3D MIPI_CSI2_DT_RAW8, + .type =3D RKCIF_MIPI_TYPE_RAW8, + }, + }, + { + .fourcc =3D V4L2_PIX_FMT_SGBRG8, + .mbus_code =3D MEDIA_BUS_FMT_SGBRG8_1X8, + .depth =3D 8, + .cplanes =3D 1, + .mipi =3D { + .dt =3D MIPI_CSI2_DT_RAW8, + .type =3D RKCIF_MIPI_TYPE_RAW8, + }, + }, + { + .fourcc =3D V4L2_PIX_FMT_SGRBG8, + .mbus_code =3D MEDIA_BUS_FMT_SGRBG8_1X8, + .depth =3D 8, + .cplanes =3D 1, + .mipi =3D { + .dt =3D MIPI_CSI2_DT_RAW8, + .type =3D RKCIF_MIPI_TYPE_RAW8, + }, + }, + { + .fourcc =3D V4L2_PIX_FMT_SRGGB8, + .mbus_code =3D MEDIA_BUS_FMT_SRGGB8_1X8, + .depth =3D 8, + .cplanes =3D 1, + .mipi =3D { + .dt =3D MIPI_CSI2_DT_RAW8, + .type =3D RKCIF_MIPI_TYPE_RAW8, + }, + }, + { + .fourcc =3D V4L2_PIX_FMT_SBGGR10, + .mbus_code =3D MEDIA_BUS_FMT_SBGGR10_1X10, + .depth =3D 10, + .cplanes =3D 1, + .mipi =3D { + .dt =3D MIPI_CSI2_DT_RAW10, + .type =3D RKCIF_MIPI_TYPE_RAW10, + }, + }, + { + .fourcc =3D V4L2_PIX_FMT_SBGGR10P, + .mbus_code =3D MEDIA_BUS_FMT_SBGGR10_1X10, + .depth =3D 10, + .cplanes =3D 1, + .mipi =3D { + .dt =3D MIPI_CSI2_DT_RAW10, + .compact =3D true, + .type =3D RKCIF_MIPI_TYPE_RAW10, + }, + }, + { + .fourcc =3D V4L2_PIX_FMT_SGBRG10, + .mbus_code =3D MEDIA_BUS_FMT_SGBRG10_1X10, + .depth =3D 10, + .cplanes =3D 1, + .mipi =3D { + .dt =3D MIPI_CSI2_DT_RAW10, + .type =3D RKCIF_MIPI_TYPE_RAW10, + }, + }, + { + .fourcc =3D V4L2_PIX_FMT_SGBRG10P, + .mbus_code =3D MEDIA_BUS_FMT_SGBRG10_1X10, + .depth =3D 10, + .cplanes =3D 1, + .mipi =3D { + .dt =3D MIPI_CSI2_DT_RAW10, + .compact =3D true, + .type =3D RKCIF_MIPI_TYPE_RAW10, + }, + }, + { + .fourcc =3D V4L2_PIX_FMT_SGRBG10, + .mbus_code =3D MEDIA_BUS_FMT_SGRBG10_1X10, + .depth =3D 10, + .cplanes =3D 1, + .mipi =3D { + .dt =3D MIPI_CSI2_DT_RAW10, + .type =3D RKCIF_MIPI_TYPE_RAW10, + }, + }, + { + .fourcc =3D V4L2_PIX_FMT_SGRBG10P, + .mbus_code =3D MEDIA_BUS_FMT_SGRBG10_1X10, + .depth =3D 10, + .cplanes =3D 1, + .mipi =3D { + .dt =3D MIPI_CSI2_DT_RAW10, + .compact =3D true, + .type =3D RKCIF_MIPI_TYPE_RAW10, + }, + }, + { + .fourcc =3D V4L2_PIX_FMT_SRGGB10, + .mbus_code =3D MEDIA_BUS_FMT_SRGGB10_1X10, + .depth =3D 10, + .cplanes =3D 1, + .mipi =3D { + .dt =3D MIPI_CSI2_DT_RAW10, + .type =3D RKCIF_MIPI_TYPE_RAW10, + }, + }, + { + .fourcc =3D V4L2_PIX_FMT_SRGGB10P, + .mbus_code =3D MEDIA_BUS_FMT_SRGGB10_1X10, + .depth =3D 10, + .cplanes =3D 1, + .mipi =3D { + .dt =3D MIPI_CSI2_DT_RAW10, + .compact =3D true, + .type =3D RKCIF_MIPI_TYPE_RAW10, + }, + }, + { + .fourcc =3D V4L2_PIX_FMT_SBGGR12, + .mbus_code =3D MEDIA_BUS_FMT_SBGGR12_1X12, + .depth =3D 12, + .cplanes =3D 1, + .mipi =3D { + .dt =3D MIPI_CSI2_DT_RAW12, + .type =3D RKCIF_MIPI_TYPE_RAW12, + }, + }, + { + .fourcc =3D V4L2_PIX_FMT_SBGGR12P, + .mbus_code =3D MEDIA_BUS_FMT_SBGGR12_1X12, + .depth =3D 12, + .cplanes =3D 1, + .mipi =3D { + .dt =3D MIPI_CSI2_DT_RAW12, + .compact =3D true, + .type =3D RKCIF_MIPI_TYPE_RAW12, + }, + }, + { + .fourcc =3D V4L2_PIX_FMT_SGBRG12, + .mbus_code =3D MEDIA_BUS_FMT_SGBRG12_1X12, + .depth =3D 12, + .cplanes =3D 1, + .mipi =3D { + .dt =3D MIPI_CSI2_DT_RAW12, + .type =3D RKCIF_MIPI_TYPE_RAW12, + }, + }, + { + .fourcc =3D V4L2_PIX_FMT_SGBRG12P, + .mbus_code =3D MEDIA_BUS_FMT_SGBRG12_1X12, + .depth =3D 12, + .cplanes =3D 1, + .mipi =3D { + .dt =3D MIPI_CSI2_DT_RAW12, + .compact =3D true, + .type =3D RKCIF_MIPI_TYPE_RAW12, + }, + }, + { + .fourcc =3D V4L2_PIX_FMT_SGRBG12, + .mbus_code =3D MEDIA_BUS_FMT_SGRBG12_1X12, + .depth =3D 12, + .cplanes =3D 1, + .mipi =3D { + .dt =3D MIPI_CSI2_DT_RAW12, + .type =3D RKCIF_MIPI_TYPE_RAW12, + }, + }, + { + .fourcc =3D V4L2_PIX_FMT_SGRBG12P, + .mbus_code =3D MEDIA_BUS_FMT_SGRBG12_1X12, + .depth =3D 12, + .cplanes =3D 1, + .mipi =3D { + .dt =3D MIPI_CSI2_DT_RAW12, + .compact =3D true, + .type =3D RKCIF_MIPI_TYPE_RAW12, + }, + }, + { + .fourcc =3D V4L2_PIX_FMT_SRGGB12, + .mbus_code =3D MEDIA_BUS_FMT_SRGGB12_1X12, + .depth =3D 12, + .cplanes =3D 1, + .mipi =3D { + .dt =3D MIPI_CSI2_DT_RAW12, + .type =3D RKCIF_MIPI_TYPE_RAW12, + }, + }, + { + .fourcc =3D V4L2_PIX_FMT_SRGGB12P, + .mbus_code =3D MEDIA_BUS_FMT_SRGGB12_1X12, + .depth =3D 12, + .cplanes =3D 1, + .mipi =3D { + .dt =3D MIPI_CSI2_DT_RAW12, + .compact =3D true, + .type =3D RKCIF_MIPI_TYPE_RAW12, + }, + }, +}; + +static const struct rkcif_input_fmt mipi_in_fmts[] =3D { + /* YUV formats */ + { + .mbus_code =3D MEDIA_BUS_FMT_YUYV8_1X16, + }, + { + .mbus_code =3D MEDIA_BUS_FMT_UYVY8_1X16, + }, + { + .mbus_code =3D MEDIA_BUS_FMT_YVYU8_1X16, + }, + { + .mbus_code =3D MEDIA_BUS_FMT_VYUY8_1X16, + }, + /* RGB formats */ + { + .mbus_code =3D MEDIA_BUS_FMT_RGB888_1X24, + }, + { + .mbus_code =3D MEDIA_BUS_FMT_BGR888_1X24, + }, + /* Bayer formats */ + { + .mbus_code =3D MEDIA_BUS_FMT_SBGGR8_1X8, + }, + { + .mbus_code =3D MEDIA_BUS_FMT_SGBRG8_1X8, + }, + { + .mbus_code =3D MEDIA_BUS_FMT_SGRBG8_1X8, + }, + { + .mbus_code =3D MEDIA_BUS_FMT_SRGGB8_1X8, + }, + { + .mbus_code =3D MEDIA_BUS_FMT_SBGGR10_1X10, + }, + { + .mbus_code =3D MEDIA_BUS_FMT_SGBRG10_1X10, + }, + { + .mbus_code =3D MEDIA_BUS_FMT_SGRBG10_1X10, + }, + { + .mbus_code =3D MEDIA_BUS_FMT_SRGGB10_1X10, + }, + { + .mbus_code =3D MEDIA_BUS_FMT_SBGGR12_1X12, + }, + { + .mbus_code =3D MEDIA_BUS_FMT_SGBRG12_1X12, + }, + { + .mbus_code =3D MEDIA_BUS_FMT_SGRBG12_1X12, + }, + { + .mbus_code =3D MEDIA_BUS_FMT_SRGGB12_1X12, + }, +}; + +static u32 +rkcif_rk3568_mipi_ctrl0(struct rkcif_stream *stream, + const struct rkcif_output_fmt *active_out_fmt) +{ + u32 ctrl0 =3D 0; + + ctrl0 |=3D RKCIF_MIPI_CTRL0_DT_ID(active_out_fmt->mipi.dt); + ctrl0 |=3D RKCIF_MIPI_CTRL0_CAP_EN; + ctrl0 |=3D RK3568_MIPI_CTRL0_CROP_EN; + + if (active_out_fmt->mipi.compact) + ctrl0 |=3D RK3568_MIPI_CTRL0_COMPACT_EN; + + switch (active_out_fmt->mipi.type) { + case RKCIF_MIPI_TYPE_RAW8: + break; + case RKCIF_MIPI_TYPE_RAW10: + ctrl0 |=3D RK3568_MIPI_CTRL0_WRDDR(0x1); + break; + case RKCIF_MIPI_TYPE_RAW12: + ctrl0 |=3D RK3568_MIPI_CTRL0_WRDDR(0x2); + break; + case RKCIF_MIPI_TYPE_RGB888: + ctrl0 |=3D RK3568_MIPI_CTRL0_WRDDR(0x3); + break; + case RKCIF_MIPI_TYPE_YUV422SP: + ctrl0 |=3D RK3568_MIPI_CTRL0_WRDDR(0x4); + break; + case RKCIF_MIPI_TYPE_YUV420SP: + ctrl0 |=3D RK3568_MIPI_CTRL0_WRDDR(0x5); + break; + case RKCIF_MIPI_TYPE_YUV400: + ctrl0 |=3D RK3568_MIPI_CTRL0_WRDDR(0x6); + break; + default: + break; + } + + return ctrl0; +} + +const struct rkcif_mipi_match_data rkcif_rk3568_vicap_mipi_match_data =3D { + .mipi_num =3D 1, + .mipi_ctrl0 =3D rkcif_rk3568_mipi_ctrl0, + .regs =3D { + [RKCIF_MIPI_CTRL] =3D 0x20, + [RKCIF_MIPI_INTEN] =3D 0xa4, + [RKCIF_MIPI_INTSTAT] =3D 0xa8, + }, + .regs_id =3D { + [RKCIF_ID0] =3D { + [RKCIF_MIPI_CTRL0] =3D 0x00, + [RKCIF_MIPI_CTRL1] =3D 0x04, + [RKCIF_MIPI_FRAME0_ADDR_Y] =3D 0x24, + [RKCIF_MIPI_FRAME0_ADDR_UV] =3D 0x2c, + [RKCIF_MIPI_FRAME0_VLW_Y] =3D 0x34, + [RKCIF_MIPI_FRAME0_VLW_UV] =3D 0x3c, + [RKCIF_MIPI_FRAME1_ADDR_Y] =3D 0x28, + [RKCIF_MIPI_FRAME1_ADDR_UV] =3D 0x30, + [RKCIF_MIPI_FRAME1_VLW_Y] =3D 0x38, + [RKCIF_MIPI_FRAME1_VLW_UV] =3D 0x40, + [RKCIF_MIPI_CROP_START] =3D 0xbc, + }, + [RKCIF_ID1] =3D { + [RKCIF_MIPI_CTRL0] =3D 0x08, + [RKCIF_MIPI_CTRL1] =3D 0x0c, + [RKCIF_MIPI_FRAME0_ADDR_Y] =3D 0x44, + [RKCIF_MIPI_FRAME0_ADDR_UV] =3D 0x4c, + [RKCIF_MIPI_FRAME0_VLW_Y] =3D 0x54, + [RKCIF_MIPI_FRAME0_VLW_UV] =3D 0x5c, + [RKCIF_MIPI_FRAME1_ADDR_Y] =3D 0x48, + [RKCIF_MIPI_FRAME1_ADDR_UV] =3D 0x50, + [RKCIF_MIPI_FRAME1_VLW_Y] =3D 0x58, + [RKCIF_MIPI_FRAME1_VLW_UV] =3D 0x60, + [RKCIF_MIPI_CROP_START] =3D 0xc0, + }, + [RKCIF_ID2] =3D { + [RKCIF_MIPI_CTRL0] =3D 0x10, + [RKCIF_MIPI_CTRL1] =3D 0x14, + [RKCIF_MIPI_FRAME0_ADDR_Y] =3D 0x64, + [RKCIF_MIPI_FRAME0_ADDR_UV] =3D 0x6c, + [RKCIF_MIPI_FRAME0_VLW_Y] =3D 0x74, + [RKCIF_MIPI_FRAME0_VLW_UV] =3D 0x7c, + [RKCIF_MIPI_FRAME1_ADDR_Y] =3D 0x68, + [RKCIF_MIPI_FRAME1_ADDR_UV] =3D 0x70, + [RKCIF_MIPI_FRAME1_VLW_Y] =3D 0x78, + [RKCIF_MIPI_FRAME1_VLW_UV] =3D 0x80, + [RKCIF_MIPI_CROP_START] =3D 0xc4, + }, + [RKCIF_ID3] =3D { + [RKCIF_MIPI_CTRL0] =3D 0x18, + [RKCIF_MIPI_CTRL1] =3D 0x1c, + [RKCIF_MIPI_FRAME0_ADDR_Y] =3D 0x84, + [RKCIF_MIPI_FRAME0_ADDR_UV] =3D 0x8c, + [RKCIF_MIPI_FRAME0_VLW_Y] =3D 0x94, + [RKCIF_MIPI_FRAME0_VLW_UV] =3D 0x9c, + [RKCIF_MIPI_FRAME1_ADDR_Y] =3D 0x88, + [RKCIF_MIPI_FRAME1_ADDR_UV] =3D 0x90, + [RKCIF_MIPI_FRAME1_VLW_Y] =3D 0x98, + [RKCIF_MIPI_FRAME1_VLW_UV] =3D 0xa0, + [RKCIF_MIPI_CROP_START] =3D 0xc8, + }, + }, + .blocks =3D { + { + .offset =3D 0x80, + }, + }, +}; + +static inline unsigned int rkcif_mipi_get_reg(struct rkcif_interface *inte= rface, + unsigned int index) +{ + struct rkcif_device *rkcif =3D interface->rkcif; + unsigned int block, offset, reg; + + block =3D interface->index - RKCIF_MIPI_BASE; + + if (WARN_ON_ONCE(block > RKCIF_MIPI_MAX - RKCIF_MIPI_BASE) || + WARN_ON_ONCE(index > RKCIF_MIPI_REGISTER_MAX)) + return RKCIF_REGISTER_NOTSUPPORTED; + + offset =3D rkcif->match_data->mipi->blocks[block].offset; + reg =3D rkcif->match_data->mipi->regs[index]; + if (reg =3D=3D RKCIF_REGISTER_NOTSUPPORTED) + return reg; + + return offset + reg; +} + +static inline unsigned int rkcif_mipi_id_get_reg(struct rkcif_stream *stre= am, + unsigned int index) +{ + struct rkcif_device *rkcif =3D stream->rkcif; + unsigned int block, id, offset, reg; + + block =3D stream->interface->index - RKCIF_MIPI_BASE; + id =3D stream->id; + + if (WARN_ON_ONCE(block > RKCIF_MIPI_MAX - RKCIF_MIPI_BASE) || + WARN_ON_ONCE(id > RKCIF_ID_MAX) || + WARN_ON_ONCE(index > RKCIF_MIPI_ID_REGISTER_MAX)) + return RKCIF_REGISTER_NOTSUPPORTED; + + offset =3D rkcif->match_data->mipi->blocks[block].offset; + reg =3D rkcif->match_data->mipi->regs_id[id][index]; + if (reg =3D=3D RKCIF_REGISTER_NOTSUPPORTED) + return reg; + + return offset + reg; +} + +static inline __maybe_unused void +rkcif_mipi_write(struct rkcif_interface *interface, unsigned int index, u3= 2 val) +{ + unsigned int addr =3D rkcif_mipi_get_reg(interface, index); + + if (addr =3D=3D RKCIF_REGISTER_NOTSUPPORTED) + return; + + writel(val, interface->rkcif->base_addr + addr); +} + +static inline __maybe_unused void +rkcif_mipi_stream_write(struct rkcif_stream *stream, unsigned int index, + u32 val) +{ + unsigned int addr =3D rkcif_mipi_id_get_reg(stream, index); + + if (addr =3D=3D RKCIF_REGISTER_NOTSUPPORTED) + return; + + writel(val, stream->rkcif->base_addr + addr); +} + +static inline __maybe_unused u32 +rkcif_mipi_read(struct rkcif_interface *interface, unsigned int index) +{ + unsigned int addr =3D rkcif_mipi_get_reg(interface, index); + + if (addr =3D=3D RKCIF_REGISTER_NOTSUPPORTED) + return 0; + + return readl(interface->rkcif->base_addr + addr); +} + +static inline __maybe_unused u32 +rkcif_mipi_stream_read(struct rkcif_stream *stream, unsigned int index) +{ + unsigned int addr =3D rkcif_mipi_id_get_reg(stream, index); + + if (addr =3D=3D RKCIF_REGISTER_NOTSUPPORTED) + return 0; + + return readl(stream->rkcif->base_addr + addr); +} + +static void rkcif_mipi_queue_buffer(struct rkcif_stream *stream, + unsigned int index) +{ + struct rkcif_buffer *buffer =3D stream->buffers[index]; + u32 frm_addr_y, frm_addr_uv; + + frm_addr_y =3D index ? RKCIF_MIPI_FRAME1_ADDR_Y : + RKCIF_MIPI_FRAME0_ADDR_Y; + frm_addr_uv =3D index ? RKCIF_MIPI_FRAME1_ADDR_UV : + RKCIF_MIPI_FRAME0_ADDR_UV; + + rkcif_mipi_stream_write(stream, frm_addr_y, + buffer->buff_addr[RKCIF_PLANE_Y]); + rkcif_mipi_stream_write(stream, frm_addr_uv, + buffer->buff_addr[RKCIF_PLANE_UV]); +} + +static int rkcif_mipi_start_streaming(struct rkcif_stream *stream) +{ + struct rkcif_interface *interface =3D stream->interface; + const struct rkcif_output_fmt *active_out_fmt; + const struct rkcif_mipi_match_data *match_data; + struct v4l2_subdev_state *state; + u32 ctrl0 =3D 0, ctrl1 =3D 0, int_temp =3D 0, int_mask =3D 0, vlw =3D 0; + u16 height, width; + int ret =3D -EINVAL; + + state =3D v4l2_subdev_lock_and_get_active_state(&interface->sd); + + active_out_fmt =3D rkcif_stream_find_output_fmt(stream, false, + stream->pix.pixelformat); + if (!active_out_fmt) + goto out; + + height =3D stream->pix.height; + width =3D stream->pix.width; + vlw =3D stream->pix.plane_fmt[0].bytesperline; + + match_data =3D stream->rkcif->match_data->mipi; + if (match_data->mipi_ctrl0) + ctrl0 =3D match_data->mipi_ctrl0(stream, active_out_fmt); + + ctrl1 =3D RKCIF_XY_COORD(width, height); + + int_mask |=3D RKCIF_MIPI_INT_FRAME0_END(stream->id); + int_mask |=3D RKCIF_MIPI_INT_FRAME1_END(stream->id); + + int_temp =3D rkcif_mipi_read(interface, RKCIF_MIPI_INTEN); + int_temp |=3D int_mask; + rkcif_mipi_write(interface, RKCIF_MIPI_INTEN, int_temp); + + int_temp =3D rkcif_mipi_read(interface, RKCIF_MIPI_INTSTAT); + int_temp &=3D ~int_mask; + rkcif_mipi_write(interface, RKCIF_MIPI_INTSTAT, int_temp); + + rkcif_mipi_stream_write(stream, RKCIF_MIPI_FRAME0_VLW_Y, vlw); + rkcif_mipi_stream_write(stream, RKCIF_MIPI_FRAME1_VLW_Y, vlw); + rkcif_mipi_stream_write(stream, RKCIF_MIPI_FRAME0_VLW_UV, vlw); + rkcif_mipi_stream_write(stream, RKCIF_MIPI_FRAME1_VLW_UV, vlw); + rkcif_mipi_stream_write(stream, RKCIF_MIPI_CROP_START, 0x0); + rkcif_mipi_stream_write(stream, RKCIF_MIPI_CTRL1, ctrl1); + rkcif_mipi_stream_write(stream, RKCIF_MIPI_CTRL0, ctrl0); + + ret =3D 0; + +out: + v4l2_subdev_unlock_state(state); + return ret; +} + +static void rkcif_mipi_stop_streaming(struct rkcif_stream *stream) +{ + struct rkcif_interface *interface =3D stream->interface; + struct v4l2_subdev_state *state; + u32 int_temp =3D 0, int_mask =3D 0; + + state =3D v4l2_subdev_lock_and_get_active_state(&interface->sd); + + rkcif_mipi_stream_write(stream, RKCIF_MIPI_CTRL0, 0); + + int_mask |=3D RKCIF_MIPI_INT_FRAME0_END(stream->id); + int_mask |=3D RKCIF_MIPI_INT_FRAME1_END(stream->id); + + int_temp =3D rkcif_mipi_read(interface, RKCIF_MIPI_INTEN); + int_temp &=3D ~int_mask; + rkcif_mipi_write(interface, RKCIF_MIPI_INTEN, int_temp); + + int_temp =3D rkcif_mipi_read(interface, RKCIF_MIPI_INTSTAT); + int_temp &=3D ~int_mask; + rkcif_mipi_write(interface, RKCIF_MIPI_INTSTAT, int_temp); + + stream->stopping =3D false; + + v4l2_subdev_unlock_state(state); +} + +static void rkcif_mipi_set_crop(struct rkcif_stream *stream, u16 left, u16= top) +{ + u32 val; + + val =3D RKCIF_XY_COORD(left, top); + rkcif_mipi_stream_write(stream, RKCIF_MIPI_CROP_START, val); +} + +irqreturn_t rkcif_mipi_isr(int irq, void *ctx) +{ + struct device *dev =3D ctx; + struct rkcif_device *rkcif =3D dev_get_drvdata(dev); + irqreturn_t ret =3D IRQ_NONE; + u32 intstat; + + for (unsigned int i =3D 0; i < rkcif->match_data->mipi->mipi_num; i++) { + enum rkcif_interface_index index =3D RKCIF_MIPI_BASE + i; + struct rkcif_interface *interface =3D &rkcif->interfaces[index]; + + intstat =3D rkcif_mipi_read(interface, RKCIF_MIPI_INTSTAT); + rkcif_mipi_write(interface, RKCIF_MIPI_INTSTAT, intstat); + + for (unsigned int j =3D 0; j < interface->streams_num; j++) { + struct rkcif_stream *stream =3D &interface->streams[j]; + + if (intstat & RKCIF_MIPI_INT_FRAME0_END(stream->id) || + intstat & RKCIF_MIPI_INT_FRAME1_END(stream->id)) { + ret =3D IRQ_HANDLED; + + if (stream->stopping) { + rkcif_mipi_stop_streaming(stream); + wake_up(&stream->wq_stopped); + continue; + } + + rkcif_stream_pingpong(stream); + } + } + } + + return ret; +} + +int rkcif_mipi_register(struct rkcif_device *rkcif) +{ + int ret; + + if (!rkcif->match_data->mipi) + return 0; + + for (unsigned int i =3D 0; i < rkcif->match_data->mipi->mipi_num; i++) { + enum rkcif_interface_index index =3D RKCIF_MIPI_BASE + i; + struct rkcif_interface *interface =3D &rkcif->interfaces[index]; + + interface->index =3D index; + interface->type =3D RKCIF_IF_MIPI; + interface->in_fmts =3D mipi_in_fmts; + interface->in_fmts_num =3D ARRAY_SIZE(mipi_in_fmts); + interface->set_crop =3D rkcif_mipi_set_crop; + interface->streams_num =3D 0; + ret =3D rkcif_interface_register(rkcif, interface); + if (ret) + continue; + + for (unsigned int j =3D 0; j < RKCIF_ID_MAX; j++) { + struct rkcif_stream *stream =3D &interface->streams[j]; + + stream->id =3D j; + stream->interface =3D interface; + stream->out_fmts =3D mipi_out_fmts; + stream->out_fmts_num =3D ARRAY_SIZE(mipi_out_fmts); + stream->queue_buffer =3D rkcif_mipi_queue_buffer; + stream->start_streaming =3D rkcif_mipi_start_streaming; + stream->stop_streaming =3D rkcif_mipi_stop_streaming; + ret =3D rkcif_stream_register(rkcif, stream); + if (ret) + goto err; + interface->streams_num++; + } + } + + return 0; + +err: + for (unsigned int i =3D 0; i < rkcif->match_data->mipi->mipi_num; i++) { + enum rkcif_interface_index index =3D RKCIF_MIPI_BASE + i; + struct rkcif_interface *interface =3D &rkcif->interfaces[index]; + + for (unsigned int j =3D 0; j < interface->streams_num; j++) + rkcif_stream_unregister(&interface->streams[j]); + + rkcif_interface_unregister(interface); + } + return ret; +} + +void rkcif_mipi_unregister(struct rkcif_device *rkcif) +{ + if (!rkcif->match_data->mipi) + return; + + for (unsigned int i =3D 0; i < rkcif->match_data->mipi->mipi_num; i++) { + enum rkcif_interface_index index =3D RKCIF_MIPI_BASE + i; + struct rkcif_interface *interface =3D &rkcif->interfaces[index]; + + for (unsigned int j =3D 0; j < interface->streams_num; j++) + rkcif_stream_unregister(&interface->streams[j]); + + rkcif_interface_unregister(interface); + } +} diff --git a/drivers/media/platform/rockchip/rkcif/rkcif-capture-mipi.h b/d= rivers/media/platform/rockchip/rkcif/rkcif-capture-mipi.h new file mode 100644 index 000000000000..7f16eadc474c --- /dev/null +++ b/drivers/media/platform/rockchip/rkcif/rkcif-capture-mipi.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Rockchip Camera Interface (CIF) Driver + * + * Copyright (C) 2018 Rockchip Electronics Co., Ltd. + * Copyright (C) 2025 Michael Riesch + * Copyright (C) 2025 Collabora, Ltd. + */ + +#ifndef _RKCIF_CAPTURE_MIPI_H +#define _RKCIF_CAPTURE_MIPI_H + +#include "rkcif-common.h" + +extern const struct rkcif_mipi_match_data rkcif_rk3568_vicap_mipi_match_da= ta; + +int rkcif_mipi_register(struct rkcif_device *rkcif); + +void rkcif_mipi_unregister(struct rkcif_device *rkcif); + +irqreturn_t rkcif_mipi_isr(int irq, void *ctx); + +#endif diff --git a/drivers/media/platform/rockchip/rkcif/rkcif-common.h b/drivers= /media/platform/rockchip/rkcif/rkcif-common.h index c6ec578e1049..dd92cfbc879f 100644 --- a/drivers/media/platform/rockchip/rkcif/rkcif-common.h +++ b/drivers/media/platform/rockchip/rkcif/rkcif-common.h @@ -73,6 +73,17 @@ enum rkcif_interface_type { RKCIF_IF_MIPI, }; =20 +enum rkcif_mipi_format_type { + RKCIF_MIPI_TYPE_INVALID, + RKCIF_MIPI_TYPE_RAW8, + RKCIF_MIPI_TYPE_RAW10, + RKCIF_MIPI_TYPE_RAW12, + RKCIF_MIPI_TYPE_RGB888, + RKCIF_MIPI_TYPE_YUV422SP, + RKCIF_MIPI_TYPE_YUV420SP, + RKCIF_MIPI_TYPE_YUV400, +}; + struct rkcif_buffer { struct vb2_v4l2_buffer vb; struct list_head queue; @@ -107,9 +118,15 @@ struct rkcif_output_fmt { u32 fourcc; u32 mbus_code; u8 cplanes; + u8 depth; =20 union { u32 dvp_fmt_val; + struct { + u8 dt; + bool compact; + enum rkcif_mipi_format_type type; + } mipi; }; }; =20 @@ -184,6 +201,17 @@ struct rkcif_interface { void (*set_crop)(struct rkcif_stream *stream, u16 left, u16 top); }; =20 +struct rkcif_mipi_match_data { + unsigned int mipi_num; + unsigned int regs[RKCIF_MIPI_REGISTER_MAX]; + unsigned int regs_id[RKCIF_ID_MAX][RKCIF_MIPI_ID_REGISTER_MAX]; + u32 (*mipi_ctrl0)(struct rkcif_stream *stream, + const struct rkcif_output_fmt *active_out_fmt); + struct { + unsigned int offset; + } blocks[RKCIF_MIPI_MAX - RKCIF_MIPI_BASE]; +}; + struct rkcif_dvp_match_data { const struct rkcif_input_fmt *in_fmts; unsigned int in_fmts_num; @@ -199,6 +227,7 @@ struct rkcif_match_data { const char *const *clks; unsigned int clks_num; const struct rkcif_dvp_match_data *dvp; + const struct rkcif_mipi_match_data *mipi; }; =20 struct rkcif_device { diff --git a/drivers/media/platform/rockchip/rkcif/rkcif-dev.c b/drivers/me= dia/platform/rockchip/rkcif/rkcif-dev.c index addc118ff8bf..b4cf1146f131 100644 --- a/drivers/media/platform/rockchip/rkcif/rkcif-dev.c +++ b/drivers/media/platform/rockchip/rkcif/rkcif-dev.c @@ -24,6 +24,7 @@ #include =20 #include "rkcif-capture-dvp.h" +#include "rkcif-capture-mipi.h" #include "rkcif-common.h" =20 static const char *const px30_vip_clks[] =3D { @@ -49,6 +50,7 @@ static const struct rkcif_match_data rk3568_vicap_match_d= ata =3D { .clks =3D rk3568_vicap_clks, .clks_num =3D ARRAY_SIZE(rk3568_vicap_clks), .dvp =3D &rkcif_rk3568_vicap_dvp_match_data, + .mipi =3D &rkcif_rk3568_vicap_mipi_match_data, }; =20 static const struct of_device_id rkcif_plat_of_match[] =3D { @@ -72,14 +74,21 @@ static int rkcif_register(struct rkcif_device *rkcif) if (ret && ret !=3D -ENODEV) goto err; =20 + ret =3D rkcif_mipi_register(rkcif); + if (ret && ret !=3D -ENODEV) + goto err_dvp_unregister; + return 0; =20 +err_dvp_unregister: + rkcif_dvp_unregister(rkcif); err: return ret; } =20 static void rkcif_unregister(struct rkcif_device *rkcif) { + rkcif_mipi_unregister(rkcif); rkcif_dvp_unregister(rkcif); } =20 @@ -128,6 +137,9 @@ static irqreturn_t rkcif_isr(int irq, void *ctx) if (rkcif_dvp_isr(irq, ctx) =3D=3D IRQ_HANDLED) ret =3D IRQ_HANDLED; =20 + if (rkcif_mipi_isr(irq, ctx) =3D=3D IRQ_HANDLED) + ret =3D IRQ_HANDLED; + return ret; } =20 diff --git a/drivers/media/platform/rockchip/rkcif/rkcif-regs.h b/drivers/m= edia/platform/rockchip/rkcif/rkcif-regs.h index 91d42d31fd10..3cf7ee19de30 100644 --- a/drivers/media/platform/rockchip/rkcif/rkcif-regs.h +++ b/drivers/media/platform/rockchip/rkcif/rkcif-regs.h @@ -128,4 +128,26 @@ enum rkcif_dvp_register_index { RKCIF_DVP_REGISTER_MAX }; =20 +enum rkcif_mipi_register_index { + RKCIF_MIPI_CTRL, + RKCIF_MIPI_INTEN, + RKCIF_MIPI_INTSTAT, + RKCIF_MIPI_REGISTER_MAX +}; + +enum rkcif_mipi_id_register_index { + RKCIF_MIPI_CTRL0, + RKCIF_MIPI_CTRL1, + RKCIF_MIPI_FRAME0_ADDR_Y, + RKCIF_MIPI_FRAME0_ADDR_UV, + RKCIF_MIPI_FRAME0_VLW_Y, + RKCIF_MIPI_FRAME0_VLW_UV, + RKCIF_MIPI_FRAME1_ADDR_Y, + RKCIF_MIPI_FRAME1_ADDR_UV, + RKCIF_MIPI_FRAME1_VLW_Y, + RKCIF_MIPI_FRAME1_VLW_UV, + RKCIF_MIPI_CROP_START, + RKCIF_MIPI_ID_REGISTER_MAX +}; + #endif --=20 2.39.5