From nobody Thu Oct 2 14:12:03 2025 Received: from fout-b1-smtp.messagingengine.com (fout-b1-smtp.messagingengine.com [202.12.124.144]) (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 A5550283682; Mon, 15 Sep 2025 17:10:28 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=202.12.124.144 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757956233; cv=none; b=TLylKskIcH74BkBhfD9t1lJLlC418zJyv2TUvDMrk+jht0gt31Qf+FPWURHKOXlUwe/8JmkODMdVpGzdFZLJ/hpB3+zxdvpHvL+txFcgNmszRHhvWGVnFR8SYs0GI8sjw6BTdwitdSEh2giozazwePyg10OxTfdykchZfrZ2jP0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757956233; c=relaxed/simple; bh=PEwixX8LGpX429pCRznzR7ZNgr1hL3S4liJ6aLanZn0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=lJor4uDVlZ4LmVnud549fTxC+a+UPdkQNjwdyasgpo151TsLXBW8XhwXBnOreKyIyf3UaUv+CLOboswTzvkpkfN0+3mJzdqxHSJQr0xzhf85OvRuDp1k7FoKl9g1nemMUaakiiKq1KpvMNLEHs6P3fm1gJ7NhVYyUsjd8GtPtH8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=ragnatech.se; spf=pass smtp.mailfrom=ragnatech.se; dkim=pass (2048-bit key) header.d=ragnatech.se header.i=@ragnatech.se header.b=QWBY8WrG; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=Jih83UWE; arc=none smtp.client-ip=202.12.124.144 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=ragnatech.se Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=ragnatech.se Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=ragnatech.se header.i=@ragnatech.se header.b="QWBY8WrG"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="Jih83UWE" Received: from phl-compute-04.internal (phl-compute-04.internal [10.202.2.44]) by mailfout.stl.internal (Postfix) with ESMTP id 8206B1D0019D; Mon, 15 Sep 2025 13:10:27 -0400 (EDT) Received: from phl-mailfrontend-01 ([10.202.2.162]) by phl-compute-04.internal (MEProxy); Mon, 15 Sep 2025 13:10:27 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ragnatech.se; h= cc:cc:content-transfer-encoding:content-type:content-type:date :date:from:from:in-reply-to:in-reply-to:message-id:mime-version :references:reply-to:subject:subject:to:to; s=fm3; t=1757956227; x=1758042627; bh=tQ5PkvvgeMjSfbL230X9aurlwCI/SS65UyUgggi2foU=; b= QWBY8WrGEIRzWvVqYfyhvO5CDYdUMOWI0JCJWRScBcrlpMU2+HDrL6CHq/mTPYNW l/bscBw+kM+K7XWY7cCoqivt8yjw11JzNJlVKrF4z58YK9ipK83f+DDHQZS3M0MR AZmvHQ2RKXsJf1GjKnCWs6M70Q/T2npKgkYWTG9xLaOLdmUcNH31wdgqA3ZrCAWq /z2xUbJD9350hY463/pNCoNK/v71Q8Xkp0CpfN2lw/D05BR69gq5dzuJ7HwnoOsm u9P0ru6vAv08hvpPIXC2wOt0m+dGXlbEyNyhffm7Jv/KY9DC0pv2R+gHZqxs8ZUU QvOcNc2vabhhhJVwm/z5Hw== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:content-type:date:date:feedback-id:feedback-id :from:from:in-reply-to:in-reply-to:message-id:mime-version :references:reply-to:subject:subject:to:to:x-me-proxy :x-me-sender:x-me-sender:x-sasl-enc; s=fm1; t=1757956227; x= 1758042627; bh=tQ5PkvvgeMjSfbL230X9aurlwCI/SS65UyUgggi2foU=; b=J ih83UWE//Fc8dg6KN8qjLbiBgizDKsoykKmgLnWeusPmHOadQ7cQZ3+5uncN6WD0 5JQ2WqI7j8XMkj7TdQIXmwT26TsRLgDo7YdplQxAZP4HcBtXICarfdNFXBMr+kDS HnaWX0PAt+Oaf0CZAUti+3duPrpoZ8AAE2EBeYrUQ//qwrwOdUZeSXB5b/KXq45S bVov37UKihT5tZQIiNAkOm4p2Uwu6bsp+xN46Ao7o5JDBEH4G2UeUrP6/wlcB/jj i3Ll3sqAzR8N2kABF8V6NkEM2OEqBdZyRGQ+WlElBuwJ14cvREprCS5apGl+38HF gkOFy163cNtc3lzfLNNBA== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeeffedrtdeggdefkedvhecutefuodetggdotefrod ftvfcurfhrohhfihhlvgemucfhrghsthforghilhdpuffrtefokffrpgfnqfghnecuuegr ihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmdenucfjug hrpefhvfevufffkffojghfgggtgfesthekredtredtjeenucfhrhhomheppfhikhhlrghs ucfunpguvghrlhhunhguuceonhhikhhlrghsrdhsohguvghrlhhunhguodhrvghnvghsrg hssehrrghgnhgrthgvtghhrdhsvgeqnecuggftrfgrthhtvghrnhepheeigfeuveeutdef hfehgeekvedtleeuueekveefudehhffhjeffgfegffelfeegnecuvehluhhsthgvrhfuih iivgeptdenucfrrghrrghmpehmrghilhhfrhhomhepnhhikhhlrghsrdhsohguvghrlhhu nhgusehrrghgnhgrthgvtghhrdhsvgdpnhgspghrtghpthhtohepjedpmhhouggvpehsmh htphhouhhtpdhrtghpthhtohepmhgthhgvhhgrsgeskhgvrhhnvghlrdhorhhgpdhrtghp thhtohepjhgrtghophhordhmohhnughisehiuggvrghsohhnsghorghrugdrtghomhdprh gtphhtthhopehlrghurhgvnhhtrdhpihhntghhrghrthesihguvggrshhonhgsohgrrhgu rdgtohhmpdhrtghpthhtoheplhhinhhugidqmhgvughirgesvhhgvghrrdhkvghrnhgvlh drohhrghdprhgtphhtthhopehlihhnuhigqdhrvghnvghsrghsqdhsohgtsehvghgvrhdr khgvrhhnvghlrdhorhhgpdhrtghpthhtoheplhhinhhugidqkhgvrhhnvghlsehvghgvrh drkhgvrhhnvghlrdhorhhgpdhrtghpthhtohepnhhikhhlrghsrdhsohguvghrlhhunhgu odhrvghnvghsrghssehrrghgnhgrthgvtghhrdhsvg X-ME-Proxy: Feedback-ID: i80c9496c:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Mon, 15 Sep 2025 13:10:26 -0400 (EDT) From: =?UTF-8?q?Niklas=20S=C3=B6derlund?= To: Mauro Carvalho Chehab , Jacopo Mondi , Laurent Pinchart , linux-media@vger.kernel.org, linux-renesas-soc@vger.kernel.org, linux-kernel@vger.kernel.org Cc: =?UTF-8?q?Niklas=20S=C3=B6derlund?= Subject: [PATCH v2 01/12] media: rppx1: Add framework to support Dreamchip RPPX1 ISP Date: Mon, 15 Sep 2025 19:07:32 +0200 Message-ID: <20250915170743.106249-2-niklas.soderlund+renesas@ragnatech.se> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20250915170743.106249-1-niklas.soderlund+renesas@ragnatech.se> References: <20250915170743.106249-1-niklas.soderlund+renesas@ragnatech.se> 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 Add a framework driver for Dreamchip RPPX1 ISP. The driver aims to provide a framework for other V4L2 based drivers to drive the RPPX1 functionality. The reason for this split is that the RPPX1 IP itself do not provide any DMA engines to drive data to/from the device, instead it depends on other IP blocks to implement these features. While the peripherals around the RPPX1 ISP used in different designs and by different vendors are different the RPPX1 core itself is the same. For this reason the framework solution to be able to split the Dreamchip RPPX1 driver from vendors usage of it have been picked in hope to reduce duplication of the common parts. The functions provided by the RPPX1 is similar to what is exposed by other ISP drivers already in tree (RkISP1 primarily), but the implementation of them are different. It do however open up for the possibility to reuse the RkISP1 parameter and statistics pixel formats in an initial implementation. The design is to try and keep the surface of this framework as small as possible. The intention of this change is to be able to fill all needs of this. * Two functions to create and destroy a RPPX1 instance, rppx1_create() and rppx1_destory(). These are intended to be called in the users probe and remove code paths. * Two functions to start and stop the RPPX1 processing, rppx1_start() and rppx1_stop(). These are intended to be called in the users stream on and stream off code paths. * One function to ask the RPPX1 to process parameters buffer prepared by user space, rppx1_params_rkisp1(). This is intended to translate the parameter buffer (RkISP1 format) to the register writes needed to be preformed on the RPPX1. The intention is to call this function when the parameter buffer is queued to the V4L2 driver and the result stored by the driver until the time it needs to be written to the RPPX1. It's the users responsibility to write it either using MMIO or other means. * One function to fill in a statistic buffer (RkISP1 format) based on the current status of the RPPX1, rppx1_stats_fill_isr(). The intention is that the user call's this in its interrupt handler when it knows the RPPX1 is done processing a frame. * One function to ack and retrieve the interrupts generated by the RPPX1, rppx1_interrupt(). The intention is to call this function when the users interrupt handler detects the RPPX1 have raised and interrupt. There is no need for the user to understand, or act, on the actual RPPX1 interrupt, but it can if it wants too. The initial support in the framework is limited and do not implement any ISP processing algorithms other then configuring the RPPX1 to process any Bayer (8-, 10, or 12-bit) image and produce either a RGB or YUYV output. It do however probe all function blocks of the RPPX1 and provide an interface to interact with both parameter and statistic bufferers. The user of the framework will not change as algorithms for the different function blocks of the ISP are being added. Signed-off-by: Niklas S=C3=B6derlund --- MAINTAINERS | 6 + drivers/media/platform/Kconfig | 1 + drivers/media/platform/Makefile | 1 + drivers/media/platform/dreamchip/Kconfig | 3 + drivers/media/platform/dreamchip/Makefile | 6 + .../media/platform/dreamchip/rppx1/Kconfig | 11 + .../media/platform/dreamchip/rppx1/Makefile | 33 ++ .../platform/dreamchip/rppx1/rpp_module.c | 40 +++ .../platform/dreamchip/rppx1/rpp_module.h | 157 ++++++++ .../platform/dreamchip/rppx1/rpp_params.c | 46 +++ .../platform/dreamchip/rppx1/rpp_stats.c | 15 + .../media/platform/dreamchip/rppx1/rppx1.c | 337 ++++++++++++++++++ .../media/platform/dreamchip/rppx1/rppx1.h | 99 +++++ .../platform/dreamchip/rppx1/rppx1_acq.c | 147 ++++++++ .../platform/dreamchip/rppx1/rppx1_awbg.c | 30 ++ .../media/platform/dreamchip/rppx1/rppx1_bd.c | 52 +++ .../platform/dreamchip/rppx1/rppx1_bdrgb.c | 80 +++++ .../platform/dreamchip/rppx1/rppx1_bls.c | 59 +++ .../platform/dreamchip/rppx1/rppx1_cac.c | 29 ++ .../platform/dreamchip/rppx1/rppx1_ccor.c | 106 ++++++ .../media/platform/dreamchip/rppx1/rppx1_db.c | 44 +++ .../platform/dreamchip/rppx1/rppx1_dpcc.c | 76 ++++ .../platform/dreamchip/rppx1/rppx1_exm.c | 51 +++ .../media/platform/dreamchip/rppx1/rppx1_ga.c | 49 +++ .../platform/dreamchip/rppx1/rppx1_hist.c | 76 ++++ .../platform/dreamchip/rppx1/rppx1_hist256.c | 46 +++ .../media/platform/dreamchip/rppx1/rppx1_is.c | 42 +++ .../platform/dreamchip/rppx1/rppx1_lin.c | 60 ++++ .../platform/dreamchip/rppx1/rppx1_lsc.c | 68 ++++ .../platform/dreamchip/rppx1/rppx1_ltm.c | 48 +++ .../platform/dreamchip/rppx1/rppx1_ltmmeas.c | 41 +++ .../platform/dreamchip/rppx1/rppx1_outif.c | 45 +++ .../platform/dreamchip/rppx1/rppx1_outregs.c | 75 ++++ .../platform/dreamchip/rppx1/rppx1_rmap.c | 64 ++++ .../platform/dreamchip/rppx1/rppx1_rmapmeas.c | 47 +++ .../platform/dreamchip/rppx1/rppx1_shrp.c | 64 ++++ .../platform/dreamchip/rppx1/rppx1_wbmeas.c | 61 ++++ .../platform/dreamchip/rppx1/rppx1_xyz2luv.c | 26 ++ include/media/rppx1.h | 33 ++ 39 files changed, 2274 insertions(+) create mode 100644 drivers/media/platform/dreamchip/Kconfig create mode 100644 drivers/media/platform/dreamchip/Makefile create mode 100644 drivers/media/platform/dreamchip/rppx1/Kconfig create mode 100644 drivers/media/platform/dreamchip/rppx1/Makefile create mode 100644 drivers/media/platform/dreamchip/rppx1/rpp_module.c create mode 100644 drivers/media/platform/dreamchip/rppx1/rpp_module.h create mode 100644 drivers/media/platform/dreamchip/rppx1/rpp_params.c create mode 100644 drivers/media/platform/dreamchip/rppx1/rpp_stats.c create mode 100644 drivers/media/platform/dreamchip/rppx1/rppx1.c create mode 100644 drivers/media/platform/dreamchip/rppx1/rppx1.h create mode 100644 drivers/media/platform/dreamchip/rppx1/rppx1_acq.c create mode 100644 drivers/media/platform/dreamchip/rppx1/rppx1_awbg.c create mode 100644 drivers/media/platform/dreamchip/rppx1/rppx1_bd.c create mode 100644 drivers/media/platform/dreamchip/rppx1/rppx1_bdrgb.c create mode 100644 drivers/media/platform/dreamchip/rppx1/rppx1_bls.c create mode 100644 drivers/media/platform/dreamchip/rppx1/rppx1_cac.c create mode 100644 drivers/media/platform/dreamchip/rppx1/rppx1_ccor.c create mode 100644 drivers/media/platform/dreamchip/rppx1/rppx1_db.c create mode 100644 drivers/media/platform/dreamchip/rppx1/rppx1_dpcc.c create mode 100644 drivers/media/platform/dreamchip/rppx1/rppx1_exm.c create mode 100644 drivers/media/platform/dreamchip/rppx1/rppx1_ga.c create mode 100644 drivers/media/platform/dreamchip/rppx1/rppx1_hist.c create mode 100644 drivers/media/platform/dreamchip/rppx1/rppx1_hist256.c create mode 100644 drivers/media/platform/dreamchip/rppx1/rppx1_is.c create mode 100644 drivers/media/platform/dreamchip/rppx1/rppx1_lin.c create mode 100644 drivers/media/platform/dreamchip/rppx1/rppx1_lsc.c create mode 100644 drivers/media/platform/dreamchip/rppx1/rppx1_ltm.c create mode 100644 drivers/media/platform/dreamchip/rppx1/rppx1_ltmmeas.c create mode 100644 drivers/media/platform/dreamchip/rppx1/rppx1_outif.c create mode 100644 drivers/media/platform/dreamchip/rppx1/rppx1_outregs.c create mode 100644 drivers/media/platform/dreamchip/rppx1/rppx1_rmap.c create mode 100644 drivers/media/platform/dreamchip/rppx1/rppx1_rmapmeas.c create mode 100644 drivers/media/platform/dreamchip/rppx1/rppx1_shrp.c create mode 100644 drivers/media/platform/dreamchip/rppx1/rppx1_wbmeas.c create mode 100644 drivers/media/platform/dreamchip/rppx1/rppx1_xyz2luv.c create mode 100644 include/media/rppx1.h diff --git a/MAINTAINERS b/MAINTAINERS index f3335f0f7c3c..8259af1904a2 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7469,6 +7469,12 @@ F: drivers/block/drbd/ F: include/linux/drbd* F: lib/lru_cache.c =20 +DREAMCHIP RPPX1 ISP +M: Niklas S=C3=B6derlund +L: linux-media@vger.kernel.org +S: Maintained +F: drivers/media/platform/dreamchip/rppx1/ + DRIVER COMPONENT FRAMEWORK L: dri-devel@lists.freedesktop.org F: drivers/base/component.c diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index 9287faafdce5..726309238dd1 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -70,6 +70,7 @@ source "drivers/media/platform/atmel/Kconfig" source "drivers/media/platform/broadcom/Kconfig" source "drivers/media/platform/cadence/Kconfig" source "drivers/media/platform/chips-media/Kconfig" +source "drivers/media/platform/dreamchip/Kconfig" source "drivers/media/platform/imagination/Kconfig" source "drivers/media/platform/intel/Kconfig" source "drivers/media/platform/marvell/Kconfig" diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makef= ile index 6fd7db0541c7..3a34df769759 100644 --- a/drivers/media/platform/Makefile +++ b/drivers/media/platform/Makefile @@ -13,6 +13,7 @@ obj-y +=3D atmel/ obj-y +=3D broadcom/ obj-y +=3D cadence/ obj-y +=3D chips-media/ +obj-y +=3D dreamchip/ obj-y +=3D imagination/ obj-y +=3D intel/ obj-y +=3D marvell/ diff --git a/drivers/media/platform/dreamchip/Kconfig b/drivers/media/platf= orm/dreamchip/Kconfig new file mode 100644 index 000000000000..d177d4ee79ae --- /dev/null +++ b/drivers/media/platform/dreamchip/Kconfig @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0-only + +source "drivers/media/platform/dreamchip/rppx1/Kconfig" diff --git a/drivers/media/platform/dreamchip/Makefile b/drivers/media/plat= form/dreamchip/Makefile new file mode 100644 index 000000000000..ba47ba2d136e --- /dev/null +++ b/drivers/media/platform/dreamchip/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# Makefile for the Dreamchip device drivers. +# + +obj-y +=3D rppx1/ diff --git a/drivers/media/platform/dreamchip/rppx1/Kconfig b/drivers/media= /platform/dreamchip/rppx1/Kconfig new file mode 100644 index 000000000000..8bac9fd8ed24 --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/Kconfig @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: GPL-2.0 +config VIDEO_DCT_RPPX1 + tristate "Dreamchip HDR RPP X1 High Dynamic Range Real-time Pixel Process= or support library" + depends on V4L_PLATFORM_DRIVERS + help + Support library for Dreamchip HDR RPP X1 High Dynamic Range Real-time + Pixel Processor (RPP). The library can be used by other drivers who + utilises the RPP as part of an ISP implementation. + + To compile this driver as a module, choose M here: the + module will be called rppx1. diff --git a/drivers/media/platform/dreamchip/rppx1/Makefile b/drivers/medi= a/platform/dreamchip/rppx1/Makefile new file mode 100644 index 000000000000..b2bd6b5d68bc --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/Makefile @@ -0,0 +1,33 @@ +# SPDX-License-Identifier: GPL-2.0 +dct-rpp-x1-objs =3D \ + rpp_module.o \ + rpp_params.o \ + rpp_stats.o \ + rppx1.o \ + rppx1_acq.o \ + rppx1_awbg.o \ + rppx1_bd.o \ + rppx1_bdrgb.o \ + rppx1_bls.o \ + rppx1_cac.o \ + rppx1_ccor.o \ + rppx1_db.o \ + rppx1_dpcc.o \ + rppx1_exm.o \ + rppx1_ga.o \ + rppx1_hist.o \ + rppx1_hist256.o \ + rppx1_is.o \ + rppx1_lin.o \ + rppx1_lsc.o \ + rppx1_ltm.o \ + rppx1_ltmmeas.o \ + rppx1_outif.o \ + rppx1_outregs.o \ + rppx1_rmap.o \ + rppx1_rmapmeas.o \ + rppx1_shrp.o \ + rppx1_wbmeas.o \ + rppx1_xyz2luv.o + +obj-$(CONFIG_VIDEO_DCT_RPPX1) +=3D dct-rpp-x1.o diff --git a/drivers/media/platform/dreamchip/rppx1/rpp_module.c b/drivers/= media/platform/dreamchip/rppx1/rpp_module.c new file mode 100644 index 000000000000..cd923b7ff5c1 --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rpp_module.c @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2025 Renesas Electronics Corp. + * Copyright 2025 Niklas S=C3=B6derlund + */ + +#include + +#include "rppx1.h" +#include "rpp_module.h" + +int rpp_module_probe(struct rpp_module *mod, struct rppx1 *rpp, + const struct rpp_module_ops *ops, u32 base) +{ + mod->rpp =3D rpp; + mod->base =3D base; + mod->ops =3D ops; + + if (ops->probe) + return ops->probe(mod); + + return 0; +} + +void rpp_module_write(struct rpp_module *mod, u32 offset, u32 value) +{ + rppx1_write(mod->rpp, mod->base + offset, value); +} + +u32 rpp_module_read(struct rpp_module *mod, u32 offset) +{ + return rppx1_read(mod->rpp, mod->base + offset); +} + +void rpp_module_clrset(struct rpp_module *mod, u32 offset, u32 mask, u32 v= alue) +{ + u32 reg =3D rpp_module_read(mod, offset) & ~mask; + + rpp_module_write(mod, offset, reg | value); +} diff --git a/drivers/media/platform/dreamchip/rppx1/rpp_module.h b/drivers/= media/platform/dreamchip/rppx1/rpp_module.h new file mode 100644 index 000000000000..25869990948d --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rpp_module.h @@ -0,0 +1,157 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright 2025 Renesas Electronics Corp. + * Copyright 2025 Niklas S=C3=B6derlund + */ + +#ifndef __RPPX1_MODULE_H__ +#define __RPPX1_MODULE_H__ + +#include +#include + +#include + +#include + +struct rpp_module_ops; + +enum rpp_raw_pattern { + RPP_RGGB =3D 0, + RPP_GRBG, + RPP_GBRG, + RPP_BGGR, +}; + +struct rpp_module { + struct rppx1 *rpp; + u32 base; + + const struct rpp_module_ops *ops; + + union { + struct { + enum rpp_raw_pattern raw_pattern; + } acq; + struct { + unsigned int colorbits; + } bdrgb; + struct { + unsigned int colorbits; + } bls; + struct { + unsigned int colorbits; + unsigned int type; + } ccor; + struct { + unsigned int colorbits; + } dpcc; + struct { + unsigned int resultbits; + } exm; + struct { + unsigned int colorbits; + } ga; + struct { + unsigned int colorbits; + } hist; + struct { + unsigned int colorbits; + } lin; + struct { + unsigned int colorbits_high; + unsigned int colorbits_low; + } rmap; + struct { + unsigned int colorbits_high; + unsigned int colorbits_low; + } rmapmeas; + struct { + unsigned int colorbits; + } shrp; + struct { + unsigned int colorbits; + } wbmeas; + } info; +}; + +int rpp_module_probe(struct rpp_module *mod, struct rppx1 *rpp, + const struct rpp_module_ops *ops, u32 base); + +void rpp_module_write(struct rpp_module *mod, u32 offset, u32 value); +u32 rpp_module_read(struct rpp_module *mod, u32 offset); +void rpp_module_clrset(struct rpp_module *mod, u32 offset, u32 mask, u32 v= alue); + +union rppx1_params_rkisp1_config { + struct rkisp1_ext_params_block_header header; + struct rkisp1_ext_params_bls_config bls; + struct rkisp1_ext_params_dpcc_config dpcc; + struct rkisp1_ext_params_sdg_config sdg; + struct rkisp1_ext_params_lsc_config lsc; + struct rkisp1_ext_params_awb_gain_config awbg; + struct rkisp1_ext_params_flt_config flt; + struct rkisp1_ext_params_bdm_config bdm; + struct rkisp1_ext_params_ctk_config ctk; + struct rkisp1_ext_params_goc_config goc; + struct rkisp1_ext_params_dpf_config dpf; + struct rkisp1_ext_params_dpf_strength_config dpfs; + struct rkisp1_ext_params_cproc_config cproc; + struct rkisp1_ext_params_ie_config ie; + struct rkisp1_ext_params_awb_meas_config awbm; + struct rkisp1_ext_params_hst_config hst; + struct rkisp1_ext_params_aec_config aec; + struct rkisp1_ext_params_afc_config afc; +}; + +struct rpp_module_ops { + int (*probe)(struct rpp_module *mod); + int (*start)(struct rpp_module *mod, const struct v4l2_mbus_framefmt *fmt= ); + + int (*param_rkisp1)(struct rpp_module *mod, + const union rppx1_params_rkisp1_config *block, + rppx1_reg_write write, void *priv); + int (*stats_rkisp1)(struct rpp_module *mod, + struct rkisp1_cif_isp_stat *stats); +}; + +extern const struct rpp_module_ops rppx1_acq_ops; +extern const struct rpp_module_ops rppx1_awbg_ops; +extern const struct rpp_module_ops rppx1_bd_ops; +extern const struct rpp_module_ops rppx1_bdrgb_ops; +extern const struct rpp_module_ops rppx1_bls_ops; +extern const struct rpp_module_ops rppx1_cac_ops; +extern const struct rpp_module_ops rppx1_ccor_ops; +extern const struct rpp_module_ops rppx1_ccor_csm_ops; +extern const struct rpp_module_ops rppx1_db_ops; +extern const struct rpp_module_ops rppx1_dpcc_ops; +extern const struct rpp_module_ops rppx1_exm_ops; +extern const struct rpp_module_ops rppx1_ga_ops; +extern const struct rpp_module_ops rppx1_hist256_ops; +extern const struct rpp_module_ops rppx1_hist_ops; +extern const struct rpp_module_ops rppx1_is_ops; +extern const struct rpp_module_ops rppx1_lin_ops; +extern const struct rpp_module_ops rppx1_lsc_ops; +extern const struct rpp_module_ops rppx1_ltm_ops; +extern const struct rpp_module_ops rppx1_ltmmeas_ops; +extern const struct rpp_module_ops rppx1_outif_ops; +extern const struct rpp_module_ops rppx1_outregs_ops; +extern const struct rpp_module_ops rppx1_rmapmeas_ops; +extern const struct rpp_module_ops rppx1_rmap_ops; +extern const struct rpp_module_ops rppx1_shrp_ops; +extern const struct rpp_module_ops rppx1_wbmeas_ops; +extern const struct rpp_module_ops rppx1_xyz2luv_ops; + +#define rpp_module_call(mod, op, args...) \ + ({ \ + struct rpp_module *__mod =3D (mod); \ + int __result; \ + if (!__mod) \ + __result =3D -ENODEV; \ + else if (!__mod->ops->op) \ + __result =3D 0; \ + else \ + __result =3D __mod->ops->op(__mod, ##args); \ + __result; \ + }) + +#endif /* __RPPX1_MODULE_H__ */ diff --git a/drivers/media/platform/dreamchip/rppx1/rpp_params.c b/drivers/= media/platform/dreamchip/rppx1/rpp_params.c new file mode 100644 index 000000000000..0bed0ee9d6f8 --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rpp_params.c @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2025 Renesas Electronics Corp. + * Copyright 2025 Niklas S=C3=B6derlund + */ + +#include "rppx1.h" + +int rppx1_params_rkisp1(struct rppx1 *rpp, struct rkisp1_ext_params_cfg *c= fg, + rppx1_reg_write write, void *priv) +{ + size_t block_offset =3D 0; + + if (WARN_ON(!cfg)) + return -EINVAL; + + /* Walk the list of parameter blocks and process them. */ + while (block_offset < cfg->data_size) { + const union rppx1_params_rkisp1_config *block =3D + (const union rppx1_params_rkisp1_config *)&cfg->data[block_offset]; + struct rpp_module *module; + int ret; + + block_offset +=3D block->header.size; + + switch (block->header.type) { + default: + module =3D NULL; + break; + } + + if (!module) { + pr_warn("Not handled RPPX1 block type: 0x%04x\n", block->header.type); + continue; + } + + ret =3D rpp_module_call(module, param_rkisp1, block, write, priv); + if (ret) { + pr_err("Error processing RPPX1 block type: 0x%04x\n", block->header.typ= e); + return ret; + } + } + + return 0; +} +EXPORT_SYMBOL_GPL(rppx1_params_rkisp1); diff --git a/drivers/media/platform/dreamchip/rppx1/rpp_stats.c b/drivers/m= edia/platform/dreamchip/rppx1/rpp_stats.c new file mode 100644 index 000000000000..a5daa28e09cf --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rpp_stats.c @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2025 Renesas Electronics Corp. + * Copyright 2025 Niklas S=C3=B6derlund + */ + +#include "rppx1.h" + +void rppx1_stats_fill_isr(struct rppx1 *rpp, u32 isc, void *buf) +{ + struct rkisp1_stat_buffer *stats =3D buf; + + stats->meas_type =3D 0; +} +EXPORT_SYMBOL_GPL(rppx1_stats_fill_isr); diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1.c b/drivers/media= /platform/dreamchip/rppx1/rppx1.c new file mode 100644 index 000000000000..c2a0deb4d253 --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rppx1.c @@ -0,0 +1,337 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2025 Renesas Electronics Corp. + * Copyright 2025 Niklas S=C3=B6derlund + * + * Support library for Dreamchip HDR RPPX1 High Dynamic Range Real-time Pi= xel + * Processor. + */ + +#include +#include + +#include "rppx1.h" + +/* RPP_HDR Base Addresses */ +#define HDRREGS_BASE 0x0000 +#define HDR_IRQ_BASE 0x0200 +#define RPP_OUT_BASE 0x0800 +#define RPP_RMAP_BASE 0x0c00 +#define RPP_RMAP_MEAS_BASE 0x1000 +#define RPP_MAIN_PRE1_BASE 0x2000 +#define RPP_MAIN_PRE2_BASE 0x4000 +#define RPP_MAIN_POST_BASE 0xa000 +#define RPP_MVOUT_BASE 0xc000 +#define RPP_FUSA_BASE 0xf000 + +#define RPP_HDRREGS_VERSION_REG (HDRREGS_BASE + 0x0000) +#define RPP_HDR_UPD_REG (HDRREGS_BASE + 0x0004) +#define RESERVED_3_REG (HDRREGS_BASE + 0x0008) +#define RPP_HDR_INFORM_ENABLE_REG (HDRREGS_BASE + 0x000c) +#define RPP_HDR_OUT_IF_ON_REG (HDRREGS_BASE + 0x0010) +#define RPP_HDR_OUT_IF_OFF_REG (HDRREGS_BASE + 0x0014) +#define RPP_HDR_SAFETY_ACCESS_PROTECTION_REG (HDRREGS_BASE + 0x0018) + +#define RPP_ISM (HDR_IRQ_BASE + 0x00) +#define RPP_RIS (HDR_IRQ_BASE + 0x04) +#define RPP_MIS (HDR_IRQ_BASE + 0x08) +#define RPP_ISC (HDR_IRQ_BASE + 0x0c) + +/* RPP_OUT/MV_OUT Pipelines - Base Addresses */ +#define GAMMA_OUT_BASE 0x0000 /* HV, MV */ +#define IS_BASE 0x00c0 /* HV, MV */ +#define CSM_BASE 0x0100 /* HV, MV */ +#define OUT_IF_BASE 0x0200 /* HV, MV */ +#define RPP_OUTREGS_BASE 0x02c0 /* HV, MV */ +#define LUV_BASE 0x0300 /* MV */ + +/* PRE1/PRE2/POST Pipelines - Base Addresses */ +#define ACQ_BASE 0x0080 /* PRE1, PRE2 */ +#define BLS_BASE 0x0100 /* PRE1, PRE2 */ +#define GAMMA_IN_BASE 0x0200 /* PRE1, PRE2 */ +#define LSC_BASE 0x0400 /* PRE1, PRE2 */ +#define AWB_GAIN_BASE 0x0500 /* PRE1, PRE2, POST */ +#define DPCC_BASE 0x0600 /* PRE1, PRE2 */ +#define DPF_BASE 0x0700 /* PRE1, PRE2 */ +#define FILT_BASE 0x0800 /* POST */ +#define CAC_BASE 0x0880 /* POST */ +#define CCOR_BASE 0x0900 /* POST */ +#define HIST_BASE 0x0a00 /* PRE1, PRE2, POST */ +#define HIST256_BASE 0x0b00 /* PRE1 */ +#define EXM_BASE 0x0c00 /* PRE1, PRE2 */ +#define LTM_BASE 0x1000 /* POST */ +#define LTM_MEAS_BASE 0x1200 /* POST */ +#define WBMEAS_BASE 0x1700 /* POST */ +#define BDRGB_BASE 0x1800 /* POST */ +#define SHRP_BASE 0x1a00 /* POST */ + +/* Functional Safety Module Base Addresses */ +#define FMU_BASE 0x0100 + +#define RPP_HDR_FMU_FSM (RPP_FUSA_BASE + FMU_BASE + 0x00) +#define RPP_HDR_FMU_RFS (RPP_FUSA_BASE + FMU_BASE + 0x04) +#define RPP_HDR_FMU_MFS (RPP_FUSA_BASE + FMU_BASE + 0x08) +#define RPP_HDR_FMU_FSC (RPP_FUSA_BASE + FMU_BASE + 0x0c) + +void rppx1_write(struct rppx1 *rpp, u32 offset, u32 value) +{ + iowrite32(value, rpp->base + offset); +} + +u32 rppx1_read(struct rppx1 *rpp, u32 offset) +{ + u32 ret =3D ioread32(rpp->base + offset); + return ret; +} + +bool rppx1_interrupt(struct rppx1 *rpp, u32 *isc) +{ + u32 status, raw, fault; + + fault =3D rppx1_read(rpp, RPP_HDR_FMU_MFS); + if (fault) { + pr_err("%s: fault 0x%08x\n", __func__, fault); + rppx1_write(rpp, RPP_HDR_FMU_FSC, fault); + } + + /* Read raw interrupt status. */ + raw =3D rppx1_read(rpp, RPP_RIS); + status =3D rppx1_read(rpp, RPP_MIS); + + /* Propagate the isc status. */ + if (isc) + *isc =3D status | raw; + + /* Clear enabled interrupts */ + rppx1_write(rpp, RPP_ISC, status); + + return !!(status & RPPX1_IRQ_ID_OUT_FRAME); +} +EXPORT_SYMBOL_GPL(rppx1_interrupt); + +void rppx1_destroy(struct rppx1 *rpp) +{ + kfree(rpp); +} +EXPORT_SYMBOL_GPL(rppx1_destroy); + +/** + * Allocate the private data structure and verify the hardware is present. + */ +struct rppx1 *rppx1_create(void __iomem *base) +{ + struct rppx1 *rpp; + u32 reg; + + /* Allocate library structure */ + rpp =3D kzalloc(sizeof(*rpp), GFP_KERNEL); + if (!rpp) + return NULL; + + rpp->base =3D base; + + /* Check communication with RPP and verify it truly is a X1. */ + reg =3D rppx1_read(rpp, RPP_HDRREGS_VERSION_REG); + if (reg !=3D 3) { + pr_err("Unsupported HDR version (%u)\n", reg); + rppx1_destroy(rpp); + return NULL; + } + + /* Probe the PRE1 pipeline. */ + if (rpp_module_probe(&rpp->pre1.acq, rpp, &rppx1_acq_ops, + RPP_MAIN_PRE1_BASE + ACQ_BASE) || + rpp_module_probe(&rpp->pre1.bls, rpp, &rppx1_bls_ops, + RPP_MAIN_PRE1_BASE + BLS_BASE) || + rpp_module_probe(&rpp->pre1.lin, rpp, &rppx1_lin_ops, + RPP_MAIN_PRE1_BASE + GAMMA_IN_BASE) || + rpp_module_probe(&rpp->pre1.lsc, rpp, &rppx1_lsc_ops, + RPP_MAIN_PRE1_BASE + LSC_BASE) || + rpp_module_probe(&rpp->pre1.awbg, rpp, &rppx1_awbg_ops, + RPP_MAIN_PRE1_BASE + AWB_GAIN_BASE) || + rpp_module_probe(&rpp->pre1.dpcc, rpp, &rppx1_dpcc_ops, + RPP_MAIN_PRE1_BASE + DPCC_BASE) || + rpp_module_probe(&rpp->pre1.bd, rpp, &rppx1_bd_ops, + RPP_MAIN_PRE1_BASE + DPF_BASE) || + rpp_module_probe(&rpp->pre1.hist, rpp, &rppx1_hist_ops, + RPP_MAIN_PRE1_BASE + HIST_BASE) || + rpp_module_probe(&rpp->pre1.hist256, rpp, &rppx1_hist256_ops, + RPP_MAIN_PRE1_BASE + HIST256_BASE) || + rpp_module_probe(&rpp->pre1.exm, rpp, &rppx1_exm_ops, + RPP_MAIN_PRE1_BASE + EXM_BASE)) + goto err; + + /* Probe the PRE2 pipeline. */ + if (rpp_module_probe(&rpp->pre2.acq, rpp, &rppx1_acq_ops, + RPP_MAIN_PRE2_BASE + ACQ_BASE) || + rpp_module_probe(&rpp->pre2.bls, rpp, &rppx1_bls_ops, + RPP_MAIN_PRE2_BASE + BLS_BASE) || + rpp_module_probe(&rpp->pre2.lin, rpp, &rppx1_lin_ops, + RPP_MAIN_PRE2_BASE + GAMMA_IN_BASE) || + rpp_module_probe(&rpp->pre2.lsc, rpp, &rppx1_lsc_ops, + RPP_MAIN_PRE2_BASE + LSC_BASE) || + rpp_module_probe(&rpp->pre2.awbg, rpp, &rppx1_awbg_ops, + RPP_MAIN_PRE2_BASE + AWB_GAIN_BASE) || + rpp_module_probe(&rpp->pre2.dpcc, rpp, &rppx1_dpcc_ops, + RPP_MAIN_PRE2_BASE + DPCC_BASE) || + rpp_module_probe(&rpp->pre2.bd, rpp, &rppx1_bd_ops, + RPP_MAIN_PRE2_BASE + DPF_BASE) || + rpp_module_probe(&rpp->pre2.hist, rpp, &rppx1_hist_ops, + RPP_MAIN_PRE2_BASE + HIST_BASE) || + rpp_module_probe(&rpp->pre2.exm, rpp, &rppx1_exm_ops, + RPP_MAIN_PRE2_BASE + EXM_BASE)) + goto err; + + /* Probe the POST pipeline. */ + if (rpp_module_probe(&rpp->post.awbg, rpp, &rppx1_awbg_ops, + RPP_MAIN_POST_BASE + AWB_GAIN_BASE) || + rpp_module_probe(&rpp->post.ccor, rpp, &rppx1_ccor_ops, + RPP_MAIN_POST_BASE + CCOR_BASE) || + rpp_module_probe(&rpp->post.hist, rpp, &rppx1_hist_ops, + RPP_MAIN_POST_BASE + HIST_BASE) || + rpp_module_probe(&rpp->post.db, rpp, &rppx1_db_ops, + RPP_MAIN_POST_BASE + FILT_BASE) || + rpp_module_probe(&rpp->post.cac, rpp, &rppx1_cac_ops, + RPP_MAIN_POST_BASE + CAC_BASE) || + rpp_module_probe(&rpp->post.ltm, rpp, &rppx1_ltm_ops, + RPP_MAIN_POST_BASE + LTM_BASE) || + rpp_module_probe(&rpp->post.ltmmeas, rpp, &rppx1_ltmmeas_ops, + RPP_MAIN_POST_BASE + LTM_MEAS_BASE) || + rpp_module_probe(&rpp->post.wbmeas, rpp, &rppx1_wbmeas_ops, + RPP_MAIN_POST_BASE + WBMEAS_BASE) || + rpp_module_probe(&rpp->post.bdrgb, rpp, &rppx1_bdrgb_ops, + RPP_MAIN_POST_BASE + BDRGB_BASE) || + rpp_module_probe(&rpp->post.shrp, rpp, &rppx1_shrp_ops, + RPP_MAIN_POST_BASE + SHRP_BASE)) + goto err; + + /* Probe the Human Vision pipeline. */ + if (rpp_module_probe(&rpp->hv.ga, rpp, &rppx1_ga_ops, + RPP_OUT_BASE + GAMMA_OUT_BASE) || + rpp_module_probe(&rpp->hv.is, rpp, &rppx1_is_ops, + RPP_OUT_BASE + IS_BASE) || + rpp_module_probe(&rpp->hv.ccor, rpp, &rppx1_ccor_csm_ops, + RPP_OUT_BASE + CSM_BASE) || + rpp_module_probe(&rpp->hv.outif, rpp, &rppx1_outif_ops, + RPP_OUT_BASE + OUT_IF_BASE) || + rpp_module_probe(&rpp->hv.outregs, rpp, &rppx1_outregs_ops, + RPP_OUT_BASE + RPP_OUTREGS_BASE)) + goto err; + + /* Probe the Machine Vision pipeline. */ + if (rpp_module_probe(&rpp->mv.ga, rpp, &rppx1_ga_ops, + RPP_MVOUT_BASE + GAMMA_OUT_BASE) || + rpp_module_probe(&rpp->mv.is, rpp, &rppx1_is_ops, + RPP_MVOUT_BASE + IS_BASE) || + rpp_module_probe(&rpp->mv.ccor, rpp, &rppx1_ccor_csm_ops, + RPP_MVOUT_BASE + CSM_BASE) || + rpp_module_probe(&rpp->mv.outif, rpp, &rppx1_outif_ops, + RPP_MVOUT_BASE + OUT_IF_BASE) || + rpp_module_probe(&rpp->mv.outregs, rpp, &rppx1_outregs_ops, + RPP_MVOUT_BASE + RPP_OUTREGS_BASE) || + rpp_module_probe(&rpp->mv.xyz2luv, rpp, &rppx1_xyz2luv_ops, + RPP_MVOUT_BASE + LUV_BASE)) + goto err; + + /* Probe the standalone Radiance Mapping modules. */ + if (rpp_module_probe(&rpp->rmap, rpp, &rppx1_rmap_ops, + RPP_RMAP_BASE) || + rpp_module_probe(&rpp->rmapmeas, rpp, &rppx1_rmapmeas_ops, + RPP_RMAP_MEAS_BASE)) + goto err; + + return rpp; +err: + rppx1_destroy(rpp); + + return NULL; +} +EXPORT_SYMBOL_GPL(rppx1_create); + +int rppx1_start(struct rppx1 *rpp, + const struct v4l2_mbus_framefmt *input, + const struct v4l2_mbus_framefmt *hv, + const struct v4l2_mbus_framefmt *mv) +{ + if (rpp_module_call(&rpp->pre1.acq, start, input) || + rpp_module_call(&rpp->pre1.bls, start, input) || + rpp_module_call(&rpp->pre1.lin, start, input) || + rpp_module_call(&rpp->pre1.lsc, start, input) || + rpp_module_call(&rpp->pre1.awbg, start, input) || + rpp_module_call(&rpp->pre1.dpcc, start, input) || + rpp_module_call(&rpp->pre1.bd, start, input) || + rpp_module_call(&rpp->pre1.hist, start, input) || + rpp_module_call(&rpp->pre1.exm, start, input) || + rpp_module_call(&rpp->pre1.hist256, start, input)) + return -EINVAL; + + if (rpp_module_call(&rpp->rmap, start, NULL) || + rpp_module_call(&rpp->rmapmeas, start, NULL)) + return -EINVAL; + + if (rpp_module_call(&rpp->post.awbg, start, input) || + rpp_module_call(&rpp->post.db, start, input) || + rpp_module_call(&rpp->post.cac, start, input) || + rpp_module_call(&rpp->post.ccor, start, input) || + rpp_module_call(&rpp->post.ltm, start, input) || + rpp_module_call(&rpp->post.bdrgb, start, input) || + rpp_module_call(&rpp->post.shrp, start, input) || + rpp_module_call(&rpp->post.ltmmeas, start, input) || + rpp_module_call(&rpp->post.wbmeas, start, input) || + rpp_module_call(&rpp->post.hist, start, input)) + return -EINVAL; + + if (hv && (rpp_module_call(&rpp->hv.ga, start, hv) || + rpp_module_call(&rpp->hv.ccor, start, hv) || + rpp_module_call(&rpp->hv.outregs, start, hv) || + rpp_module_call(&rpp->hv.is, start, hv) || + rpp_module_call(&rpp->hv.outif, start, hv))) + return -EINVAL; + + if (mv && (rpp_module_call(&rpp->mv.ga, start, mv) || + rpp_module_call(&rpp->mv.ccor, start, mv) || + rpp_module_call(&rpp->mv.xyz2luv, start, mv) || + rpp_module_call(&rpp->mv.outregs, start, mv) || + rpp_module_call(&rpp->mv.is, start, mv) || + rpp_module_call(&rpp->mv.outif, start, mv))) + return -EINVAL; + + rppx1_write(rpp, RPP_HDR_UPD_REG, 0x00000001); + + /* Clear fault interrupts. */ + rppx1_write(rpp, RPP_HDR_SAFETY_ACCESS_PROTECTION_REG, 0x00000001); + rppx1_write(rpp, RPP_HDR_FMU_FSM, 0x000001c0); + rppx1_write(rpp, RPP_HDR_FMU_FSC, rppx1_read(rpp, RPP_HDR_FMU_MFS)); + rppx1_write(rpp, RPP_HDR_SAFETY_ACCESS_PROTECTION_REG, 0x00000000); + + /* Set interrupt mask. */ + rppx1_write(rpp, RPP_ISM, RPPX1_IRQ_ID_OUT_FRAME); + + rppx1_write(rpp, RPP_HDR_UPD_REG, 0x00000001); + rppx1_write(rpp, RPP_HDR_UPD_REG, 0x00000002); + + /* Clear any pending interrupts. */ + rppx1_interrupt(rpp, NULL); + + /* Enable input formatters. */ + rppx1_write(rpp, RPP_HDR_INFORM_ENABLE_REG, 1); + + return 0; +} +EXPORT_SYMBOL_GPL(rppx1_start); + +int rppx1_stop(struct rppx1 *rpp) +{ + /* Disable input formatters. */ + rppx1_write(rpp, RPP_HDR_INFORM_ENABLE_REG, 0); + + /* Clear any pending interrupts. */ + rppx1_interrupt(rpp, NULL); + + return 0; +} +EXPORT_SYMBOL_GPL(rppx1_stop); + +MODULE_AUTHOR("Niklas S=C3=B6derlund "); +MODULE_DESCRIPTION("Dreamchip HDR RPPX1 support library"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1.h b/drivers/media= /platform/dreamchip/rppx1/rppx1.h new file mode 100644 index 000000000000..dcf43826d308 --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rppx1.h @@ -0,0 +1,99 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef __MEDIA_RPPX1_H__ +#define __MEDIA_RPPX1_H__ + +#include + +#include "rpp_module.h" + +#define RPPX1_IRQ_ID_256HIST BIT(27) +#define RPPX1_IRQ_ID_PRE2_DPCC BIT(25) +#define RPPX1_IRQ_ID_PRE1_DPCC BIT(24) +#define RPPX1_IRQ_ID_MV_OUT_FRAME_OUT BIT(23) +#define RPPX1_IRQ_ID_MV_OUT_OFF BIT(22) +#define RPPX1_IRQ_ID_POST_AWB_MEAS BIT(21) +#define RPPX1_IRQ_ID_POST_HIST_MEAS BIT(20) +#define RPPX1_IRQ_ID_POST_TM BIT(19) +#define RPPX1_IRQ_ID_PRE1_EXM BIT(18) +#define RPPX1_IRQ_ID_PRE1_HIST BIT(17) +#define RPPX1_IRQ_ID_PRE1_FRAME_IN BIT(16) +#define RPPX1_IRQ_ID_PRE1_HSTART BIT(15) +#define RPPX1_IRQ_ID_PRE1_VSTART BIT(14) +#define RPPX1_IRQ_ID_PRE2_EXM BIT(13) +#define RPPX1_IRQ_ID_PRE2_HIST BIT(12) +#define RPPX1_IRQ_ID_PRE2_FRAME_IN BIT(11) +#define RPPX1_IRQ_ID_PRE2_HSTART BIT(10) +#define RPPX1_IRQ_ID_PRE2_VSTART BIT(9) +#define RPPX1_IRQ_ID_OUT_FRAME BIT(3) +#define RPPX1_IRQ_ID_OUT_OFF BIT(2) +#define RPPX1_IRQ_ID_RMAP_MEAS BIT(1) +#define RPPX1_IRQ_ID_RMAP_DONE BIT(0) + +struct rppx1 { + struct device *dev; + void __iomem *base; + + struct { + struct rpp_module acq; + struct rpp_module bls; + struct rpp_module lin; + struct rpp_module lsc; + struct rpp_module awbg; + struct rpp_module dpcc; + struct rpp_module bd; + struct rpp_module hist; + struct rpp_module hist256; + struct rpp_module exm; + } pre1; + + struct { + struct rpp_module acq; + struct rpp_module bls; + struct rpp_module lin; + struct rpp_module lsc; + struct rpp_module awbg; + struct rpp_module dpcc; + struct rpp_module bd; + struct rpp_module hist; + struct rpp_module exm; + } pre2; + + struct { + struct rpp_module awbg; + struct rpp_module ccor; + struct rpp_module hist; + struct rpp_module db; + struct rpp_module cac; + struct rpp_module ltm; + struct rpp_module ltmmeas; + struct rpp_module wbmeas; + struct rpp_module bdrgb; + struct rpp_module shrp; + } post; + + struct { + struct rpp_module ga; + struct rpp_module is; + struct rpp_module ccor; + struct rpp_module outif; + struct rpp_module outregs; + } hv; + + struct { + struct rpp_module ga; + struct rpp_module is; + struct rpp_module ccor; + struct rpp_module outif; + struct rpp_module outregs; + struct rpp_module xyz2luv; + } mv; + + struct rpp_module rmap; + struct rpp_module rmapmeas; +}; + +void rppx1_write(struct rppx1 *rpp, u32 offset, u32 value); +u32 rppx1_read(struct rppx1 *rpp, u32 offset); + +#endif /* __MEDIA_RPPX1_H__ */ diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_acq.c b/drivers/m= edia/platform/dreamchip/rppx1/rppx1_acq.c new file mode 100644 index 000000000000..45f619ccb684 --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_acq.c @@ -0,0 +1,147 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2025 Renesas Electronics Corp. + * Copyright 2025 Niklas S=C3=B6derlund + */ + +#include "rpp_module.h" + +#define ACQ_VERSION_REG 0x0000 + +#define ACQ_CTRL_REG 0x0004 +#define ACQ_CTRL_ALTERNATIVE_CFG_MODE_ENABLE BIT(8) +#define ACQ_CTRL_RPP_MODE_MASK GENMASK(3, 1) +#define ACQ_CTRL_RPP_MODE_RAWBT601 (0 << 1) +#define ACQ_CTRL_RPP_MODE_BT656 (1 << 1) +#define ACQ_CTRL_RPP_MODE_BT601 (2 << 1) +#define ACQ_CTRL_RPP_MODE_BAYER (3 << 1) +#define ACQ_CTRL_RPP_MODE_DATA (4 << 1) +#define ACQ_CTRL_RPP_MODE_BAYERRGB (5 << 1) +#define ACQ_CTRL_RPP_MODE_RAWBT656 (6 << 1) +#define ACQ_CTRL_INFORM_EN_ENABLE BIT(0) + +#define ACQ_PROP_REG 0x0008 + +#define ACQ_PROP_SENSOR_IN_LSB_ALIGNED_IN_LSB BIT(30) +#define ACQ_PROP_YUV_OUT_SEL BIT(25) +#define ACQ_PROP_MUX_DMA_SEL BIT(24) +#define ACQ_PROP_SECOND_INPUT_TYPE BIT(18) +#define ACQ_PROP_LATENCY_FIFO_INPUT_SELECTION BIT(15) +#define ACQ_PROP_INPUT_SELECTION_MASK GENMASK(14, 12) +#define ACQ_PROP_INPUT_SELECTION_8BIT (0 << 12) +#define ACQ_PROP_INPUT_SELECTION_10BIT (1 << 12) +#define ACQ_PROP_INPUT_SELECTION_12BIT (2 << 12) +#define ACQ_PROP_BAYER_PAT_MASK GENMASK(4, 3) +#define ACQ_PROP_BAYER_PAT_RGRG (0 << 3) +#define ACQ_PROP_BAYER_PAT_GRGR (1 << 3) +#define ACQ_PROP_BAYER_PAT_GBGB (2 << 3) +#define ACQ_PROP_BAYER_PAT_BGBG (3 << 3) +#define ACQ_PROP_VSYNC_POL BIT(2) +#define ACQ_PROP_HSYNC_POL BIT(1) +#define ACQ_PROP_SAMPLE_EDGE BIT(0) + +#define ACQ_H_OFFS_REG 0x000c +#define ACQ_V_OFFS_REG 0x0010 +#define ACQ_H_SIZE_REG 0x0014 +#define ACQ_V_SIZE_REG 0x0018 +#define ACQ_OUT_H_OFFS_REG 0x001c +#define ACQ_OUT_V_OFFS_REG 0x0020 +#define ACQ_OUT_H_SIZE_REG 0x0024 +#define ACQ_OUT_V_SIZE_REG 0x0028 +#define FLAGS_SHD_REG 0x002c +#define ACQ_OUT_H_OFFS_SHD_REG 0x0030 +#define ACQ_OUT_V_OFFS_SHD_REG 0x0034 +#define ACQ_OUT_H_SIZE_SHD_REG 0x0038 +#define ACQ_OUT_V_SIZE_SHD_REG 0x003c + +static int rppx1_acq_probe(struct rpp_module *mod) +{ + /* Version check. */ + if (rpp_module_read(mod, ACQ_VERSION_REG) !=3D 0x0b) + return -EINVAL; + + return 0; +} + +static int rppx1_acq_start(struct rpp_module *mod, + const struct v4l2_mbus_framefmt *fmt) +{ + u32 bayerpat, selection; + + rpp_module_clrset(mod, ACQ_CTRL_REG, ACQ_CTRL_RPP_MODE_MASK, + ACQ_CTRL_RPP_MODE_BAYER); + + rpp_module_write(mod, ACQ_H_OFFS_REG, 0); + rpp_module_write(mod, ACQ_V_OFFS_REG, 0); + rpp_module_write(mod, ACQ_H_SIZE_REG, fmt->width); + rpp_module_write(mod, ACQ_V_SIZE_REG, fmt->height); + rpp_module_write(mod, ACQ_OUT_H_OFFS_REG, 0); + rpp_module_write(mod, ACQ_OUT_V_OFFS_REG, 0); + rpp_module_write(mod, ACQ_OUT_H_SIZE_REG, fmt->width); + rpp_module_write(mod, ACQ_OUT_V_SIZE_REG, fmt->height); + + switch (fmt->code) { + case MEDIA_BUS_FMT_SBGGR8_1X8: + case MEDIA_BUS_FMT_SBGGR10_1X10: + case MEDIA_BUS_FMT_SBGGR12_1X12: + mod->info.acq.raw_pattern =3D RPP_BGGR; + bayerpat =3D ACQ_PROP_BAYER_PAT_BGBG; + break; + case MEDIA_BUS_FMT_SGBRG8_1X8: + case MEDIA_BUS_FMT_SGBRG10_1X10: + case MEDIA_BUS_FMT_SGBRG12_1X12: + mod->info.acq.raw_pattern =3D RPP_GBRG; + bayerpat =3D ACQ_PROP_BAYER_PAT_GBGB; + break; + case MEDIA_BUS_FMT_SGRBG8_1X8: + case MEDIA_BUS_FMT_SGRBG10_1X10: + case MEDIA_BUS_FMT_SGRBG12_1X12: + mod->info.acq.raw_pattern =3D RPP_GRBG; + bayerpat =3D ACQ_PROP_BAYER_PAT_GRGR; + break; + case MEDIA_BUS_FMT_SRGGB8_1X8: + case MEDIA_BUS_FMT_SRGGB10_1X10: + case MEDIA_BUS_FMT_SRGGB12_1X12: + mod->info.acq.raw_pattern =3D RPP_RGGB; + bayerpat =3D ACQ_PROP_BAYER_PAT_RGRG; + break; + default: + return -EINVAL; + } + + switch (fmt->code) { + case MEDIA_BUS_FMT_SBGGR8_1X8: + case MEDIA_BUS_FMT_SGBRG8_1X8: + case MEDIA_BUS_FMT_SGRBG8_1X8: + case MEDIA_BUS_FMT_SRGGB8_1X8: + selection =3D ACQ_PROP_INPUT_SELECTION_8BIT; + break; + case MEDIA_BUS_FMT_SBGGR10_1X10: + case MEDIA_BUS_FMT_SGBRG10_1X10: + case MEDIA_BUS_FMT_SGRBG10_1X10: + case MEDIA_BUS_FMT_SRGGB10_1X10: + selection =3D ACQ_PROP_INPUT_SELECTION_10BIT; + break; + case MEDIA_BUS_FMT_SBGGR12_1X12: + case MEDIA_BUS_FMT_SGBRG12_1X12: + case MEDIA_BUS_FMT_SGRBG12_1X12: + case MEDIA_BUS_FMT_SRGGB12_1X12: + selection =3D ACQ_PROP_INPUT_SELECTION_12BIT; + break; + default: + return -EINVAL; + } + + rpp_module_write(mod, ACQ_PROP_REG, bayerpat | selection | + ACQ_PROP_SENSOR_IN_LSB_ALIGNED_IN_LSB); + + rpp_module_clrset(mod, ACQ_CTRL_REG, ACQ_CTRL_INFORM_EN_ENABLE, + ACQ_CTRL_INFORM_EN_ENABLE); + + return 0; +} + +const struct rpp_module_ops rppx1_acq_ops =3D { + .probe =3D rppx1_acq_probe, + .start =3D rppx1_acq_start, +}; diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_awbg.c b/drivers/= media/platform/dreamchip/rppx1/rppx1_awbg.c new file mode 100644 index 000000000000..e20bc369ca8c --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_awbg.c @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2025 Renesas Electronics Corp. + * Copyright 2025 Niklas S=C3=B6derlund + */ + +#include "rpp_module.h" + +#define AWB_GAIN_VERSION_REG 0x0000 + +#define AWB_ENABLE_REG 0x0004 +#define AWB_ENABLE_AWB_GAIN_EN BIT(0) + +#define AWB_GAIN_GR_REG 0x0008 +#define AWB_GAIN_GB_REG 0x000c +#define AWB_GAIN_R_REG 0x0010 +#define AWB_GAIN_B_REG 0x0014 + +static int rppx1_awbg_probe(struct rpp_module *mod) +{ + /* Version check. */ + if (rpp_module_read(mod, AWB_GAIN_VERSION_REG) !=3D 3) + return -EINVAL; + + return 0; +} + +const struct rpp_module_ops rppx1_awbg_ops =3D { + .probe =3D rppx1_awbg_probe, +}; diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_bd.c b/drivers/me= dia/platform/dreamchip/rppx1/rppx1_bd.c new file mode 100644 index 000000000000..acbfbcd59591 --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_bd.c @@ -0,0 +1,52 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2025 Renesas Electronics Corp. + * Copyright 2025 Niklas S=C3=B6derlund + */ + +#include "rpp_module.h" + +#define DPF_VERSION_REG 0x0000 + +#define DPF_MODE_REG 0x0004 +#define DPF_MODE_USE_NF_GAIN BIT(9) +#define DPF_MODE_LSC_GAIN_COMP BIT(8) +#define DPF_MODE_NLL_SEGMENTATION BIT(6) +#define DPF_MODE_RB_FILTER_SIZE BIT(5) +#define DPF_MODE_R_FILTER_OFF BIT(4) +#define DPF_MODE_GR_FILTER_OFF BIT(3) +#define DPF_MODE_GB_FILTER_OFF BIT(2) +#define DPF_MODE_B_FILTER_OFF BIT(1) +#define DPF_MODE_DPF_ENABLE BIT(0) + +#define DPF_STRENGTH_R_REG 0x0008 +#define DPF_STRENGTH_G_REG 0x000c +#define DPF_STRENGTH_B_REG 0x0010 +#define DPF_S_WEIGHT_G_1_4_REG 0x0014 +#define DPF_S_WEIGHT_G_5_6_REG 0x0018 +#define DPF_S_WEIGHT_RB_1_4_REG 0x001c +#define DPF_S_WEIGHT_RB_5_6_REG 0x0020 + +#define DPF_NLL_G_COEFF_REG_NUM 17 +#define DPF_NLL_G_COEFF_REG(n) (0x0024 + (4 * (n))) + +#define DPF_NLL_RB_COEFF_REG_NUM 17 +#define DPF_NLL_RB_COEFF_REG(n) (0x0068 + (4 * (n))) + +#define DPF_NF_GAIN_R_REG 0x00ac +#define DPF_NF_GAIN_GR_REG 0x00b0 +#define DPF_NF_GAIN_GB_REG 0x00b4 +#define DPF_NF_GAIN_B_REG 0x00b8 + +static int rppx1_bd_probe(struct rpp_module *mod) +{ + /* Version check. */ + if (rpp_module_read(mod, DPF_VERSION_REG) !=3D 5) + return -EINVAL; + + return 0; +} + +const struct rpp_module_ops rppx1_bd_ops =3D { + .probe =3D rppx1_bd_probe, +}; diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_bdrgb.c b/drivers= /media/platform/dreamchip/rppx1/rppx1_bdrgb.c new file mode 100644 index 000000000000..292f0b7bfd3f --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_bdrgb.c @@ -0,0 +1,80 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2025 Renesas Electronics Corp. + * Copyright 2025 Niklas S=C3=B6derlund + */ + +#include "rpp_module.h" + +#define RGBDENOISE_VERSION_REG 0x0000 + +#define RGBDENOISE_HW_BYPASS_REG 0x0004 +#define RGBDENOISE_HW_BYPASS_BYPASS_EN BIT(0) + +#define RGBDENOISE_SPNR_CTRL_REG 0x0008 +#define RGBDENOISE_SPNR_CTRL_C2NR_INTENSITY_SHIFT_C_MASK GENMASK(11, 8) +#define RGBDENOISE_SPNR_CTRL_C2NR_INTENSITY_SHIFT_Y_MASK GENMASK(7, 4) +#define RGBDENOISE_SPNR_CTRL_C2NR_EN BIT(0) + +#define RGBDENOISE_SPNR_LUMA_IF_COEF_00_07_REG 0x000c +#define RGBDENOISE_SPNR_LUMA_IF_COEF_08_15_REG 0x0010 +#define RGBDENOISE_SPNR_LUMA_IF_COEF_16_23_REG 0x0014 +#define RGBDENOISE_SPNR_LUMA_IF_COEF_24_31_REG 0x0018 +#define RGBDENOISE_SPNR_CHROMA_IF_COEF_00_07_REG 0x001c +#define RGBDENOISE_SPNR_CHROMA_IF_COEF_08_15_REG 0x0020 +#define RGBDENOISE_SPNR_CHROMA_IF_COEF_16_23_REG 0x0024 +#define RGBDENOISE_SPNR_CHROMA_IF_COEF_24_31_REG 0x0028 +#define RGBDENOISE_SPNR_SPATIAL_COEF_0_3_REG 0x002c +#define RGBDENOISE_RGB2YUV_CCOR_COEFF_0_REG 0x0030 +#define RGBDENOISE_RGB2YUV_CCOR_COEFF_1_REG 0x0034 +#define RGBDENOISE_RGB2YUV_CCOR_COEFF_2_REG 0x0038 +#define RGBDENOISE_RGB2YUV_CCOR_COEFF_3_REG 0x003c +#define RGBDENOISE_RGB2YUV_CCOR_COEFF_4_REG 0x0040 +#define RGBDENOISE_RGB2YUV_CCOR_COEFF_5_REG 0x0044 +#define RGBDENOISE_RGB2YUV_CCOR_COEFF_6_REG 0x0048 +#define RGBDENOISE_RGB2YUV_CCOR_COEFF_7_REG 0x004c +#define RGBDENOISE_RGB2YUV_CCOR_COEFF_8_REG 0x0050 +#define RGBDENOISE_RGB2YUV_CCOR_OFFSET_R_REG 0x0054 +#define RGBDENOISE_RGB2YUV_CCOR_OFFSET_G_REG 0x0058 +#define RGBDENOISE_RGB2YUV_CCOR_OFFSET_B_REG 0x005c +#define RGBDENOISE_HW_BYPASS_SDW_REG 0x0060 +#define RGBDENOISE_SPNR_CTRL_SDW_REG 0x0064 +#define RGBDENOISE_SPNR_LUMA_IF_COEF_00_07_SDW_REG 0x0068 +#define RGBDENOISE_SPNR_LUMA_IF_COEF_08_15_SDW_REG 0x006c +#define RGBDENOISE_SPNR_LUMA_IF_COEF_16_23_SDW_REG 0x0070 +#define RGBDENOISE_SPNR_LUMA_IF_COEF_24_31_SDW_REG 0x0074 +#define RGBDENOISE_SPNR_CHROMA_IF_COEF_00_07_SDW_REG 0x0078 +#define RGBDENOISE_SPNR_CHROMA_IF_COEF_08_15_SDW_REG 0x007c +#define RGBDENOISE_SPNR_CHROMA_IF_COEF_16_23_SDW_REG 0x0080 +#define RGBDENOISE_SPNR_CHROMA_IF_COEF_24_31_SDW_REG 0x0084 +#define RGBDENOISE_SPNR_SPATIAL_COEFF_0_3_SDW_REG 0x0088 +#define RGBDENOISE_RGB2YUV_CCOR_COEFF_0_SDW_REG 0x008c +#define RGBDENOISE_RGB2YUV_CCOR_COEFF_1_SDW_REG 0x0090 +#define RGBDENOISE_RGB2YUV_CCOR_COEFF_2_SDW_REG 0x0094 +#define RGBDENOISE_RGB2YUV_CCOR_COEFF_3_SDW_REG 0x0098 +#define RGBDENOISE_RGB2YUV_CCOR_COEFF_4_SDW_REG 0x009c +#define RGBDENOISE_RGB2YUV_CCOR_COEFF_5_SDW_REG 0x00a0 +#define RGBDENOISE_RGB2YUV_CCOR_COEFF_6_SDW_REG 0x00a4 +#define RGBDENOISE_RGB2YUV_CCOR_COEFF_7_SDW_REG 0x00a8 +#define RGBDENOISE_RGB2YUV_CCOR_COEFF_8_SDW_REG 0x00ac +#define RGBDENOISE_RGB2YUV_CCOR_OFFSET_R_SDW_REG 0x00b0 +#define RGBDENOISE_RGB2YUV_CCOR_OFFSET_G_SDW_REG 0x00b4 +#define RGBDENOISE_RGB2YUV_CCOR_OFFSET_B_SDW_REG 0x00b8 + +static int rppx1_bdrgb_probe(struct rpp_module *mod) +{ + /* Version check. */ + switch (rpp_module_read(mod, RGBDENOISE_VERSION_REG)) { + case 6: + mod->info.bdrgb.colorbits =3D 12; + break; + default: + return -EINVAL; + } + + return 0; +} + +const struct rpp_module_ops rppx1_bdrgb_ops =3D { + .probe =3D rppx1_bdrgb_probe, +}; diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_bls.c b/drivers/m= edia/platform/dreamchip/rppx1/rppx1_bls.c new file mode 100644 index 000000000000..de7008befd8e --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_bls.c @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2025 Renesas Electronics Corp. + * Copyright 2025 Niklas S=C3=B6derlund + */ + +#include "rpp_module.h" + +#define BLS_VERSION_REG 0x0000 + +#define BLS_CTRL_REG 0x0004 +#define BLS_CTRL_BLS_WIN2 BIT(3) +#define BLS_CTRL_BLS_WIN1 BIT(2) +#define BLS_CTRL_BLS_MODE_MEASURED BIT(1) +#define BLS_CTRL_BLS_EN BIT(0) + +#define BLS_SAMPLES_REG 0x0008 +#define BLS_H1_START_REG 0x000c +#define BLS_H1_STOP_REG 0x0010 +#define BLS_V1_START_REG 0x0014 +#define BLS_V1_STOP_REG 0x0018 +#define BLS_H2_START_REG 0x001c +#define BLS_H2_STOP_REG 0x0020 +#define BLS_V2_START_REG 0x0024 +#define BLS_V2_STOP_REG 0x0028 +#define BLS_A_FIXED_REG 0x002c +#define BLS_B_FIXED_REG 0x0030 +#define BLS_C_FIXED_REG 0x0034 +#define BLS_D_FIXED_REG 0x0038 +#define BLS_A_MEASURED_REG 0x003c +#define BLS_B_MEASURED_REG 0x0040 +#define BLS_C_MEASURED_REG 0x0044 +#define BLS_D_MEASURED_REG 0x0048 + +static int rppx1_bls_probe(struct rpp_module *mod) +{ + /* Version check. */ + switch (rpp_module_read(mod, BLS_VERSION_REG)) { + case 3: + case 5: + mod->info.bls.colorbits =3D 12; + break; + case 2: + case 4: + mod->info.bls.colorbits =3D 20; + break; + case 6: + mod->info.bls.colorbits =3D 24; + break; + default: + return -EINVAL; + } + + return 0; +} + +const struct rpp_module_ops rppx1_bls_ops =3D { + .probe =3D rppx1_bls_probe, +}; diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_cac.c b/drivers/m= edia/platform/dreamchip/rppx1/rppx1_cac.c new file mode 100644 index 000000000000..5ed8c60982ba --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_cac.c @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2025 Renesas Electronics Corp. + * Copyright 2025 Niklas S=C3=B6derlund + */ + +#include "rpp_module.h" + +#define CAC_VERSION_REG 0x0000 +#define CAC_CTRL_REG 0x0004 +#define CAC_COUNT_START_REG 0x0008 +#define CAC_A_REG 0x000c +#define CAC_B_REG 0x0010 +#define CAC_C_REG 0x0014 +#define CAC_X_NORM_REG 0x0018 +#define CAC_Y_NORM_REG 0x001c + +static int rppx1_cac_probe(struct rpp_module *mod) +{ + /* Version check. */ + if (rpp_module_read(mod, CAC_VERSION_REG) !=3D 3) + return -EINVAL; + + return 0; +} + +const struct rpp_module_ops rppx1_cac_ops =3D { + .probe =3D rppx1_cac_probe, +}; diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_ccor.c b/drivers/= media/platform/dreamchip/rppx1/rppx1_ccor.c new file mode 100644 index 000000000000..4754b0bbce0a --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_ccor.c @@ -0,0 +1,106 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2025 Renesas Electronics Corp. + * Copyright 2025 Niklas S=C3=B6derlund + */ + +#include "rpp_module.h" + +#define CCOR_VERSION_REG 0x0000 + +#define CCOR_COEFF_REG_NUM 9 +#define CCOR_COEFF_REG(n) (0x0004 + (4 * (n))) + +#define CCOR_OFFSET_R_REG 0x0028 +#define CCOR_OFFSET_G_REG 0x002c +#define CCOR_OFFSET_B_REG 0x0030 + +#define CCOR_CONFIG_TYPE_REG 0x0034 +#define CCOR_CONFIG_TYPE_USE_OFFSETS_AS_PRE_OFFSETS BIT(1) +#define CCOR_CONFIG_TYPE_CCOR_RANGE_AVAILABLE BIT(0) + +#define CCOR_RANGE_REG 0x0038 +#define CCOR_RANGE_CCOR_C_RANGE BIT(1) +#define CCOR_RANGE_CCOR_Y_RANGE BIT(0) + +static int rppx1_ccor_probe(struct rpp_module *mod) +{ + /* Version check. */ + switch (rpp_module_read(mod, CCOR_VERSION_REG)) { + case 3: + mod->info.ccor.colorbits =3D 12; + break; + case 4: + mod->info.ccor.colorbits =3D 20; + break; + case 5: + mod->info.ccor.colorbits =3D 24; + break; + default: + return -EINVAL; + } + + mod->info.ccor.type =3D rpp_module_read(mod, CCOR_CONFIG_TYPE_REG); + + return 0; +} + +static int rppx1_ccor_start(struct rpp_module *mod, + const struct v4l2_mbus_framefmt *fmt) +{ + /* Configure matrix in bypass mode. */ + rpp_module_write(mod, CCOR_COEFF_REG(0), 0x1000); + rpp_module_write(mod, CCOR_COEFF_REG(1), 0x0000); + rpp_module_write(mod, CCOR_COEFF_REG(2), 0x0000); + + rpp_module_write(mod, CCOR_COEFF_REG(3), 0x0000); + rpp_module_write(mod, CCOR_COEFF_REG(4), 0x1000); + rpp_module_write(mod, CCOR_COEFF_REG(5), 0x0000); + + rpp_module_write(mod, CCOR_COEFF_REG(6), 0x0000); + rpp_module_write(mod, CCOR_COEFF_REG(7), 0x0000); + rpp_module_write(mod, CCOR_COEFF_REG(8), 0x1000); + + rpp_module_write(mod, CCOR_OFFSET_R_REG, 0x00000000); + rpp_module_write(mod, CCOR_OFFSET_G_REG, 0x00000000); + rpp_module_write(mod, CCOR_OFFSET_B_REG, 0x00000000); + + return 0; +} + +const struct rpp_module_ops rppx1_ccor_ops =3D { + .probe =3D rppx1_ccor_probe, + .start =3D rppx1_ccor_start, +}; + +static int rppx1_ccor_csm_start(struct rpp_module *mod, + const struct v4l2_mbus_framefmt *fmt) +{ + /* Reuse bypass matrix setup. */ + if (fmt->code =3D=3D MEDIA_BUS_FMT_RGB888_1X24) + return rppx1_ccor_start(mod, fmt); + + /* Color Transformation RGB to YUV according to ITU-R BT.709. */ + rpp_module_write(mod, CCOR_COEFF_REG(0), 0x0367); + rpp_module_write(mod, CCOR_COEFF_REG(1), 0x0b71); + rpp_module_write(mod, CCOR_COEFF_REG(2), 0x0128); + + rpp_module_write(mod, CCOR_COEFF_REG(3), 0xfe2b); + rpp_module_write(mod, CCOR_COEFF_REG(4), 0xf9d5); + rpp_module_write(mod, CCOR_COEFF_REG(5), 0x0800); + + rpp_module_write(mod, CCOR_COEFF_REG(6), 0x0800); + rpp_module_write(mod, CCOR_COEFF_REG(7), 0xf8bc); + rpp_module_write(mod, CCOR_COEFF_REG(8), 0xff44); + + rpp_module_write(mod, CCOR_OFFSET_R_REG, 0x00000000); + rpp_module_write(mod, CCOR_OFFSET_G_REG, 0x00000800); + rpp_module_write(mod, CCOR_OFFSET_B_REG, 0x00000800); + + return 0; +} + +const struct rpp_module_ops rppx1_ccor_csm_ops =3D { + .probe =3D rppx1_ccor_probe, + .start =3D rppx1_ccor_csm_start, +}; diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_db.c b/drivers/me= dia/platform/dreamchip/rppx1/rppx1_db.c new file mode 100644 index 000000000000..5e233896cfc8 --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_db.c @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2025 Renesas Electronics Corp. + * Copyright 2025 Niklas S=C3=B6derlund + */ + +#include "rpp_module.h" + +#define FILT_VERSION_REG 0x0000 + +#define DEMOSAIC_REG 0x0004 +#define DEMOSAIC_DEMOSAIC_BYPASS BIT(16) +#define DEMOSAIC_DEMOSAIC_TH_MASK GENMASK(15, 0) + +#define FILT_MODE_REG 0x0008 +#define FILT_MODE_FILT_LP_SELECT_MASK GENMASK(11, 8) +#define FILT_MODE_FILT_CHR_H_MODE_MASK GENMASK(7, 6) +#define FILT_MODE_FILT_CHR_V_MODE_MASK GENMASK(5, 4) +#define FILT_MODE_FILT_MODE BIT(1) +#define FILT_MODE_FILT_ENABLE BIT(0) + +#define FILT_THRESH_BL0_REG 0x000c +#define FILT_THRESH_BL1_REG 0x0010 +#define FILT_THRESH_SH0_REG 0x0014 +#define FILT_THRESH_SH1_REG 0x0018 +#define FILT_LUM_WEIGHT_REG 0x001c +#define FILT_FAC_SH1_REG 0x0020 +#define FILT_FAC_SH0_REG 0x0024 +#define FILT_FAC_MID_REG 0x0028 +#define FILT_FAC_BL0_REG 0x002c +#define FILT_FAC_BL1_REG 0x0030 + +static int rppx1_db_probe(struct rpp_module *mod) +{ + /* Version check. */ + if (rpp_module_read(mod, FILT_VERSION_REG) !=3D 5) + return -EINVAL; + + return 0; +} + +const struct rpp_module_ops rppx1_db_ops =3D { + .probe =3D rppx1_db_probe, +}; diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_dpcc.c b/drivers/= media/platform/dreamchip/rppx1/rppx1_dpcc.c new file mode 100644 index 000000000000..ae0b65976452 --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_dpcc.c @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2025 Renesas Electronics Corp. + * Copyright 2025 Niklas S=C3=B6derlund + */ + +#include "rpp_module.h" + +#define DPCC_VERSION_REG 0x0000 + +#define DPCC_MODE_REG 0x0004 +#define DPCC_MODE_STAGE1_ENABLE BIT(2) +#define DPCC_MODE_GRAYSCALE_MODE BIT(1) +#define DPCC_MODE_DPCC_ENABLE BIT(0) + +#define DPCC_OUTPUT_MODE_REG 0x0008 +#define DPCC_SET_USE_REG 0x000c +#define DPCC_METHODS_SET_1_REG 0x0010 +#define DPCC_METHODS_SET_2_REG 0x0014 +#define DPCC_METHODS_SET_3_REG 0x0018 +#define DPCC_LINE_THRESH_1_REG 0x001c +#define DPCC_LINE_MAD_FAC_1_REG 0x0020 +#define DPCC_PG_FAC_1_REG 0x0024 +#define DPCC_RND_THRESH_1_REG 0x0028 +#define DPCC_RG_FAC_1_REG 0x002c +#define DPCC_LINE_THRESH_2_REG 0x0030 +#define DPCC_LINE_MAD_FAC_2_REG 0x0034 +#define DPCC_PG_FAC_2_REG 0x0038 +#define DPCC_RND_THRESH_2_REG 0x003c +#define DPCC_RG_FAC_2_REG 0x0040 +#define DPCC_LINE_THRESH_3_REG 0x0044 +#define DPCC_LINE_MAD_FAC_3_REG 0x0048 +#define DPCC_PG_FAC_3_REG 0x004c +#define DPCC_RND_THRESH_3_REG 0x0050 +#define DPCC_RG_FAC_3_REG 0x0054 +#define DPCC_RO_LIMITS_REG 0x0058 +#define DPCC_RND_OFFS_REG 0x005c +#define DPCC_BPT_CTRL_REG 0x0060 +#define DPCC_BP_NUMBER_REG 0x0064 +#define DPCC_BP_TADDR_REG 0x0068 +#define DPCC_BP_POSITION_REG 0x006c + +static int rppx1_dpcc_probe(struct rpp_module *mod) +{ + /* Version check. */ + switch (rpp_module_read(mod, DPCC_VERSION_REG)) { + case 2: + case 4: + case 6: + mod->info.dpcc.colorbits =3D 12; + break; + case 3: + case 5: + case 7: + mod->info.dpcc.colorbits =3D 24; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int rppx1_dpcc_start(struct rpp_module *mod, + const struct v4l2_mbus_framefmt *fmt) +{ + /* Bypass stage1 and DPCC. */ + rpp_module_write(mod, DPCC_MODE_REG, 0); + + return 0; +} + +const struct rpp_module_ops rppx1_dpcc_ops =3D { + .probe =3D rppx1_dpcc_probe, + .start =3D rppx1_dpcc_start, +}; diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_exm.c b/drivers/m= edia/platform/dreamchip/rppx1/rppx1_exm.c new file mode 100644 index 000000000000..0c40300e13ad --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_exm.c @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2025 Renesas Electronics Corp. + * Copyright 2025 Niklas S=C3=B6derlund + */ + +#include "rpp_module.h" + +#define EXM_VERSION_REG 0x0000 +#define EXM_START_REG 0x0004 + +#define EXM_CTRL_REG 0x0008 +#define EXM_CTRL_EXM_UPDATE_ENABLE BIT(0) + +#define EXM_MODE_REG 0x000c +#define EXM_CHANNEL_SEL_REG 0x0010 +#define EXM_LAST_MEAS_LINE_REG 0x0014 +#define EXM_COEFF_R_REG 0x0018 +#define EXM_COEFF_G_GR_REG 0x001c +#define EXM_COEFF_B_REG 0x0020 +#define EXM_COEFF_GB_REG 0x0024 +#define EXM_H_OFFS_REG 0x0028 +#define EXM_V_OFFS_REG 0x002c +#define EXM_H_SIZE_REG 0x0030 +#define EXM_V_SIZE_REG 0x0034 +#define EXM_FORCED_UPD_START_LINE_REG 0x0038 +#define EXM_VSTART_STATUS_REG 0x003c + +#define EXM_MEAN_REG_NUM 25 +#define EXM_MEAN_REG(n) (0x0040 + (4 * (n))) + +static int rppx1_exm_probe(struct rpp_module *mod) +{ + /* Version check. */ + switch (rpp_module_read(mod, EXM_VERSION_REG)) { + case 1: + mod->info.exm.resultbits =3D 8; + break; + case 3: + mod->info.exm.resultbits =3D 20; + break; + default: + return -EINVAL; + } + + return 0; +} + +const struct rpp_module_ops rppx1_exm_ops =3D { + .probe =3D rppx1_exm_probe, +}; diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_ga.c b/drivers/me= dia/platform/dreamchip/rppx1/rppx1_ga.c new file mode 100644 index 000000000000..d6c7f951cf29 --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_ga.c @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2025 Renesas Electronics Corp. + * Copyright 2025 Niklas S=C3=B6derlund + */ + +#include "rpp_module.h" + +#define GAMMA_OUT_VERSION_REG 0x0000 + +#define GAMMA_OUT_ENABLE_REG 0x0004 +#define GAMMA_OUT_ENABLE_GAMMA_OUT_EN BIT(0) + +#define GAMMA_OUT_MODE_REG 0x0008 +#define GAMMA_OUT_MODE_GAMMA_OUT_EQU_SEGM BIT(0) + +#define GAMMA_OUT_Y_REG_NUM 17 +#define GAMMA_OUT_Y_REG(n) (0x000c + (4 * (n))) + +static int rppx1_ga_probe(struct rpp_module *mod) +{ + /* Version check. */ + switch (rpp_module_read(mod, GAMMA_OUT_VERSION_REG)) { + case 1: + mod->info.ga.colorbits =3D 12; + break; + case 2: + mod->info.ga.colorbits =3D 24; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int rppx1_ga_start(struct rpp_module *mod, + const struct v4l2_mbus_framefmt *fmt) +{ + /* Disable stage. */ + rpp_module_write(mod, GAMMA_OUT_ENABLE_REG, 0); + + return 0; +} + +const struct rpp_module_ops rppx1_ga_ops =3D { + .probe =3D rppx1_ga_probe, + .start =3D rppx1_ga_start, +}; diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_hist.c b/drivers/= media/platform/dreamchip/rppx1/rppx1_hist.c new file mode 100644 index 000000000000..cab498ece5a8 --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_hist.c @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2025 Renesas Electronics Corp. + * Copyright 2025 Niklas S=C3=B6derlund + */ + +#include "rpp_module.h" + +#define HIST_VERSION_REG 0x0000 + +#define HIST_CTRL_REG 0x0004 +#define HIST_CTRL_HIST_UPDATE_ENABLE BIT(0) + +#define HIST_MODE_REG 0x0008 +#define HIST_MODE_HIST_MODE_MASK GENMASK(2, 0) +#define HIST_MODE_HIST_MODE_DISABLE 0 +#define HIST_MODE_HIST_MODE_YRGB 1 +#define HIST_MODE_HIST_MODE_R 2 +#define HIST_MODE_HIST_MODE_GR 3 +#define HIST_MODE_HIST_MODE_B 4 +#define HIST_MODE_HIST_MODE_GB 5 + +#define HIST_CHANNEL_SEL_REG 0x000c +#define HIST_CHANNEL_SEL_CHANNEL_SELECT_MASK GENMASK(2, 0) + +#define HIST_LAST_MEAS_LINE_REG 0x0010 +#define HIST_SUBSAMPLING_REG 0x0014 +#define HIST_COEFF_R_REG 0x0018 +#define HIST_COEFF_G_REG 0x001c +#define HIST_COEFF_B_REG 0x0020 +#define HIST_H_OFFS_REG 0x0024 +#define HIST_V_OFFS_REG 0x0028 +#define HIST_H_SIZE_REG 0x002c +#define HIST_V_SIZE_REG 0x0030 + +#define HIST_SAMPLE_RANGE_REG 0x0034 +#define HIST_SAMPLE_RANGE_SAMPLE_SHIFT_MASK GENMASK(28, 24) +#define HIST_SAMPLE_RANGE_SAMPLE_OFFSET_MASK GENMASK(23, 0) + +#define HIST_WEIGHT_00TO30_REG 0x0038 +#define HIST_WEIGHT_40TO21_REG 0x003c +#define HIST_WEIGHT_31TO12_REG 0x0040 +#define HIST_WEIGHT_22TO03_REG 0x0044 +#define HIST_WEIGHT_13TO43_REG 0x0048 +#define HIST_WEIGHT_04TO34_REG 0x004c +#define HIST_WEIGHT_44_REG 0x0050 +#define HIST_FORCED_UPD_START_LINE_REG 0x0054 +#define HIST_FORCED_UPDATE_REG 0x0058 +#define HIST_VSTART_STATUS_REG 0x005c + +#define HIST_BIN_REG_NUM 32 +#define HIST_BIN_REG(n) (0x0060 + (4 * (n))) + +static int rppx1_hist_probe(struct rpp_module *mod) +{ + /* Version check. */ + switch (rpp_module_read(mod, HIST_VERSION_REG)) { + case 3: + mod->info.hist.colorbits =3D 12; + break; + case 4: + mod->info.hist.colorbits =3D 20; + break; + case 5: + mod->info.hist.colorbits =3D 24; + break; + default: + return -EINVAL; + } + + return 0; +} + +const struct rpp_module_ops rppx1_hist_ops =3D { + .probe =3D rppx1_hist_probe, +}; diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_hist256.c b/drive= rs/media/platform/dreamchip/rppx1/rppx1_hist256.c new file mode 100644 index 000000000000..5b846b415a49 --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_hist256.c @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2025 Renesas Electronics Corp. + * Copyright 2025 Niklas S=C3=B6derlund + */ + +#include "rpp_module.h" + +#define HIST256_VERSION_REG 0x0000 +#define HIST256_MODE_REG 0x0004 +#define HIST256_MODE_HIST256_MODE BIT(0) + +#define HIST256_CHANNEL_SEL_REG 0x0008 +#define HIST256_CHANNEL_SEL_CHANNEL_SELECT GENMASK(2, 0) + +#define HIST256_H_OFFS_REG 0x000c +#define HIST256_V_OFFS_REG 0x0010 +#define HIST256_H_SIZE_REG 0x0014 +#define HIST256_V_SIZE_REG 0x0018 +#define HIST256_SAMPLE_OFFSET_REG 0x001c +#define HIST256_SAMPLE_SCALE_REG 0x0020 +#define HIST256_MEAS_RESULT_ADDR_AUTOINCR_REG 0x0024 +#define HIST256_MEAS_RESULT_ADDR_REG 0x0028 +#define HIST256_MEAS_RESULT_DATA_REG 0x002c + +#define HIST256_LOG_ENABLE_REG 0x0030 +#define HIST256_LOG_ENABLE_HIST256_LOG_EN BIT(0) + +#define HIST256_LOG_DX_LO_REG 0x0034 +#define HIST256_LOG_DX_HI_REG 0x0038 + +#define HIST256_Y_REG_NUM 17 +#define HIST256_Y_REG(n) (0x0040 + (4 * (n))) + +static int rppx1_hist256_probe(struct rpp_module *mod) +{ + /* Version check. */ + if (rpp_module_read(mod, HIST256_VERSION_REG) !=3D 2) + return -EINVAL; + + return 0; +} + +const struct rpp_module_ops rppx1_hist256_ops =3D { + .probe =3D rppx1_hist256_probe, +}; diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_is.c b/drivers/me= dia/platform/dreamchip/rppx1/rppx1_is.c new file mode 100644 index 000000000000..3637a2e677ca --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_is.c @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2025 Renesas Electronics Corp. + * Copyright 2025 Niklas S=C3=B6derlund + */ + +#include "rpp_module.h" + +#define IS_VERSION 0x0000 +#define IS_H_OFFS 0x0008 +#define IS_V_OFFS 0x000c +#define IS_H_SIZE 0x0010 +#define IS_V_SIZE 0x0014 +#define IS_H_OFFS_SHD 0x0024 +#define IS_V_OFFS_SHD 0x0028 +#define IS_H_SIZE_SHD 0x002c +#define IS_V_SIZE_SHD 0x0030 + +static int rppx1_is_probe(struct rpp_module *mod) +{ + /* Version check. */ + if (rpp_module_read(mod, IS_VERSION) !=3D 1) + return -EINVAL; + + return 0; +} + +static int rppx1_is_start(struct rpp_module *mod, + const struct v4l2_mbus_framefmt *fmt) +{ + rpp_module_write(mod, IS_H_OFFS, 0); + rpp_module_write(mod, IS_V_OFFS, 0); + rpp_module_write(mod, IS_H_SIZE, fmt->width); + rpp_module_write(mod, IS_V_SIZE, fmt->height); + + return 0; +} + +const struct rpp_module_ops rppx1_is_ops =3D { + .probe =3D rppx1_is_probe, + .start =3D rppx1_is_start, +}; diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_lin.c b/drivers/m= edia/platform/dreamchip/rppx1/rppx1_lin.c new file mode 100644 index 000000000000..e4b0a7be7665 --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_lin.c @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2025 Renesas Electronics Corp. + * Copyright 2025 Niklas S=C3=B6derlund + */ + +#include "rpp_module.h" + +/* NOTE: The module is called LIN the registers GAMMA_IN. */ +#define LIN_VERSION_REG 0x0000 + +#define LIN_ENABLE_REG 0x0004 +#define LIN_ENABLE_GAMMA_IN_EN BIT(0) + +#define LIN_DX_LO_REG 0x0008 +#define LIN_DX_HI_REG 0x000c + +#define LIN_R_Y_REG_NUM 17 +#define LIN_R_Y_REG(n) (0x0010 + (4 * (n))) + +#define LIN_G_Y_REG_NUM 17 +#define LIN_G_Y_REG(n) (0x0054 + (4 * (n))) + +#define LIN_B_Y_REG_NUM 17 +#define LIN_B_Y_REG(n) (0x0098 + (4 * (n))) + +#define LIN_SAMPLES_NUM 17 + +static int rppx1_lin_probe(struct rpp_module *mod) +{ + /* Version check. */ + switch (rpp_module_read(mod, LIN_VERSION_REG)) { + case 7: + mod->info.lin.colorbits =3D 12; + break; + case 8: + mod->info.lin.colorbits =3D 20; + break; + case 9: + mod->info.lin.colorbits =3D 24; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int rppx1_lin_start(struct rpp_module *mod, + const struct v4l2_mbus_framefmt *fmt) +{ + rpp_module_clrset(mod, LIN_ENABLE_REG, LIN_ENABLE_GAMMA_IN_EN, 0); + + return 0; +} + +const struct rpp_module_ops rppx1_lin_ops =3D { + .probe =3D rppx1_lin_probe, + .start =3D rppx1_lin_start, +}; diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_lsc.c b/drivers/m= edia/platform/dreamchip/rppx1/rppx1_lsc.c new file mode 100644 index 000000000000..e8acdf744956 --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_lsc.c @@ -0,0 +1,68 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2025 Renesas Electronics Corp. + * Copyright 2025 Niklas S=C3=B6derlund + */ + +#include "rpp_module.h" + +#define LSC_VERSION_REG 0x0000 + +#define LSC_CTRL_REG 0x0004 +#define LSC_CTRL_LSC_EN BIT(0) + +#define LSC_R_TABLE_ADDR_REG 0x0008 +#define LSC_GR_TABLE_ADDR_REG 0x000c +#define LSC_B_TABLE_ADDR_REG 0x0010 +#define LSC_GB_TABLE_ADDR_REG 0x0014 +#define LSC_R_TABLE_DATA_REG 0x0018 +#define LSC_GR_TABLE_DATA_REG 0x001c +#define LSC_B_TABLE_DATA_REG 0x0020 +#define LSC_GB_TABLE_DATA_REG 0x0024 +#define LSC_XGRAD_01_REG 0x0028 +#define LSC_XGRAD_23_REG 0x002c +#define LSC_XGRAD_45_REG 0x0030 +#define LSC_XGRAD_67_REG 0x0034 +#define LSC_XGRAD_89_REG 0x0038 +#define LSC_XGRAD_1011_REG 0x003c +#define LSC_XGRAD_1213_REG 0x0040 +#define LSC_XGRAD_1415_REG 0x0044 +#define LSC_YGRAD_01_REG 0x0048 +#define LSC_YGRAD_23_REG 0x004c +#define LSC_YGRAD_45_REG 0x0050 +#define LSC_YGRAD_67_REG 0x0054 +#define LSC_YGRAD_89_REG 0x0058 +#define LSC_YGRAD_1011_REG 0x005c +#define LSC_YGRAD_1213_REG 0x0060 +#define LSC_YGRAD_1415_REG 0x0064 +#define LSC_XSIZE_01_REG 0x0068 +#define LSC_XSIZE_23_REG 0x006c +#define LSC_XSIZE_45_REG 0x0070 +#define LSC_XSIZE_67_REG 0x0074 +#define LSC_XSIZE_89_REG 0x0078 +#define LSC_XSIZE_1011_REG 0x007c +#define LSC_XSIZE_1213_REG 0x0080 +#define LSC_XSIZE_1415_REG 0x0084 +#define LSC_YSIZE_01_REG 0x0088 +#define LSC_YSIZE_23_REG 0x008c +#define LSC_YSIZE_45_REG 0x0090 +#define LSC_YSIZE_67_REG 0x0094 +#define LSC_YSIZE_89_REG 0x0098 +#define LSC_YSIZE_1011_REG 0x009c +#define LSC_YSIZE_1213_REG 0x00a0 +#define LSC_YSIZE_1415_REG 0x00a4 +#define LSC_TABLE_SEL_REG 0x00a8 +#define LSC_STATUS_REG 0x00ac + +static int rppx1_lsc_probe(struct rpp_module *mod) +{ + /* Version check. */ + if (rpp_module_read(mod, LSC_VERSION_REG) !=3D 0x04) + return -EINVAL; + + return 0; +} + +const struct rpp_module_ops rppx1_lsc_ops =3D { + .probe =3D rppx1_lsc_probe, +}; diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_ltm.c b/drivers/m= edia/platform/dreamchip/rppx1/rppx1_ltm.c new file mode 100644 index 000000000000..693cf5ed1689 --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_ltm.c @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2025 Renesas Electronics Corp. + * Copyright 2025 Niklas S=C3=B6derlund + */ + +#include "rpp_module.h" + +#define LTM_VERSION_REG 0x0000 + +#define LTM_CTRL_REG 0x0004 +#define LTM_CTRL_LTM_ENABLE BIT(0) + +#define LTM_RGB_WEIGHTS_REG 0x0008 +#define LTM_CLB_LINESIZE_REG 0x000c +#define LTM_TONECURVE_1_REG 0x0010 +#define LTM_TONECURVE_2_REG 0x0014 +#define LTM_TONECURVE_3_REG 0x0018 +#define LTM_TONECURVE_4_REG 0x001c +#define LTM_TONECURVE_5_REG 0x0020 +#define LTM_TONECURVE_6_REG 0x0024 +#define LTM_TONECURVE_YM_REG(n) (0x0028 + (4 * (n))) +#define LTM_L0W_REG 0x00ec +#define LTM_L0W_R_REG 0x00f0 +#define LTM_L0D_REG 0x00f4 +#define LTM_L0D_R_REG 0x00f8 +#define LTM_KMIND_REG 0x00fc +#define LTM_KMAXD_REG 0x0100 +#define LTM_KDIFFD_REG 0x0104 +#define LTM_KDIFFD_R_REG 0x0108 +#define LTM_KW_REG 0x010c +#define LTM_KW_R_REG 0x0110 +#define LTM_CGAIN_REG 0x0114 +#define LTM_LPRCH_R_HIGH_REG 0x0118 +#define LTM_LPRCH_R_LOW_REG 0x011c + +static int rppx1_ltm_probe(struct rpp_module *mod) +{ + /* Version check. */ + if (rpp_module_read(mod, LTM_VERSION_REG) !=3D 8) + return -EINVAL; + + return 0; +} + +const struct rpp_module_ops rppx1_ltm_ops =3D { + .probe =3D rppx1_ltm_probe, +}; diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_ltmmeas.c b/drive= rs/media/platform/dreamchip/rppx1/rppx1_ltmmeas.c new file mode 100644 index 000000000000..efc3d09db5eb --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_ltmmeas.c @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2025 Renesas Electronics Corp. + * Copyright 2025 Niklas S=C3=B6derlund + */ + +#include "rpp_module.h" + +#define LTM_MEAS_VERSION_REG 0x0000 + +#define LTM_MEAS_CTRL_REG 0x0004 +#define LTM_MEAS_CTRL_LTM_MEAS_ENABLE BIT(0) + +#define LTM_MEAS_RGB_WEIGHTS_REG 0x0008 +#define LTM_MEAS_H_OFFS_REG 0x000c +#define LTM_MEAS_V_OFFS_REG 0x0010 +#define LTM_MEAS_H_SIZE_REG 0x0014 +#define LTM_MEAS_V_SIZE_REG 0x0018 + +#define LTM_MEAS_PRC_THRESH_NUM 8 +#define LTM_MEAS_PRC_THRESH_REG(n) (0x001c + (4 * (n))) + +#define LTM_MEAS_PRC_REG_NUM 8 +#define LTM_MEAS_PRC_REG(n) (0x003c + (4 * (n))) + +#define LTM_MEAS_L_MIN_REG 0x005c +#define LTM_MEAS_L_MAX_REG 0x0060 +#define LTM_MEAS_L_GMEAN_REG 0x0064 + +static int rppx1_ltmmeas_probe(struct rpp_module *mod) +{ + /* Version check. */ + if (rpp_module_read(mod, LTM_MEAS_VERSION_REG) !=3D 1) + return -EINVAL; + + return 0; +} + +const struct rpp_module_ops rppx1_ltmmeas_ops =3D { + .probe =3D rppx1_ltmmeas_probe, +}; diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_outif.c b/drivers= /media/platform/dreamchip/rppx1/rppx1_outif.c new file mode 100644 index 000000000000..742c81844912 --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_outif.c @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2025 Renesas Electronics Corp. + * Copyright 2025 Niklas S=C3=B6derlund + */ + +#include "rpp_module.h" + +#define OUT_IF_VERSION_REG 0x0000 + +#define OUT_IF_ON_REG 0x0004 +#define OUT_IF_ON_RPP_ON BIT(0) + +#define OUT_IF_OFF_REG 0x0008 + +#define OUT_IF_NR_FRAMES_REG 0x000c +#define OUT_IF_NR_FRAMES_NR_FRAMES GENMASK(9, 0) + +#define OUT_IF_NR_FRAMES_CNT_REG 0x0010 +#define FLAGS_SHD_REG 0x0018 + +static int rppx1_outif_probe(struct rpp_module *mod) +{ + /* Version check. */ + if (rpp_module_read(mod, OUT_IF_VERSION_REG) !=3D 1) + return -EINVAL; + + return 0; +} + +static int rppx1_outif_start(struct rpp_module *mod, + const struct v4l2_mbus_framefmt *fmt) +{ + rpp_module_clrset(mod, OUT_IF_NR_FRAMES_REG, + OUT_IF_NR_FRAMES_NR_FRAMES, 0); + + rpp_module_write(mod, OUT_IF_ON_REG, OUT_IF_ON_RPP_ON); + + return 0; +} + +const struct rpp_module_ops rppx1_outif_ops =3D { + .probe =3D rppx1_outif_probe, + .start =3D rppx1_outif_start, +}; diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_outregs.c b/drive= rs/media/platform/dreamchip/rppx1/rppx1_outregs.c new file mode 100644 index 000000000000..63d61e1dc447 --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_outregs.c @@ -0,0 +1,75 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2025 Renesas Electronics Corp. + * Copyright 2025 Niklas S=C3=B6derlund + */ + +#include "rpp_module.h" + +#define OUTREGS_VERSION_REG 0x0000 + +#define OUT_MODE_REG 0x0004 +#define OUT_MODE_UNSELECTED_MODE_MASK GENMASK(11, 8) +#define OUT_MODE_UNSELECTED_MODE_MAIN (0x1 << 8) +#define OUT_MODE_UNSELECTED_MODE_PRE1 (0x2 << 8) +#define OUT_MODE_UNSELECTED_MODE_PRE2 (0x4 << 8) +#define OUT_MODE_IN_SEL_MASK GENMASK(3, 0) +#define OUT_MODE_IN_SEL_MAIN 1 +#define OUT_MODE_IN_SEL_PRE1 2 +#define OUT_MODE_IN_SEL_PRE2 4 + +#define OUT_CONV_422_METHOD_REG 0x0008 +#define OUT_CONV_422_METHOD_CONV_422_METHOD_MASK GENMASK(1, 0) +#define OUT_CONV_422_METHOD_CONV_422_METHOD_CO_SITED1 0 +#define OUT_CONV_422_METHOD_CONV_422_METHOD_CO_SITED2 1 +#define OUT_CONV_422_METHOD_CONV_422_METHOD_NON_CO_SITED 2 + +#define OUTREGS_FORMAT_REG 0x000c +#define OUTREGS_FORMAT_OUTPUT_FORMAT_MASK GENMASK(1, 0) +#define OUTREGS_FORMAT_OUTPUT_FORMAT_RGB 0 +#define OUTREGS_FORMAT_OUTPUT_FORMAT_YUV422 1 +#define OUTREGS_FORMAT_OUTPUT_FORMAT_YUV420 2 + +static int rppx1_outregs_probe(struct rpp_module *mod) +{ + /* Version check. */ + if (rpp_module_read(mod, OUTREGS_VERSION_REG) !=3D 2) + return -EINVAL; + + return 0; +} + +static int rppx1_outregs_start(struct rpp_module *mod, + const struct v4l2_mbus_framefmt *fmt) +{ + u32 format; + + switch (fmt->code) { + case MEDIA_BUS_FMT_YUYV12_1X24: + format =3D OUTREGS_FORMAT_OUTPUT_FORMAT_YUV422; + break; + case MEDIA_BUS_FMT_RGB888_1X24: + format =3D OUTREGS_FORMAT_OUTPUT_FORMAT_RGB; + break; + default: + return -EINVAL; + } + + rpp_module_clrset(mod, OUT_MODE_REG, + OUT_MODE_UNSELECTED_MODE_MASK | OUT_MODE_IN_SEL_MASK, + OUT_MODE_UNSELECTED_MODE_MASK | OUT_MODE_IN_SEL_MAIN); + + rpp_module_clrset(mod, OUT_CONV_422_METHOD_REG, + OUT_CONV_422_METHOD_CONV_422_METHOD_MASK, + OUT_CONV_422_METHOD_CONV_422_METHOD_CO_SITED1); + + rpp_module_clrset(mod, OUTREGS_FORMAT_REG, + OUTREGS_FORMAT_OUTPUT_FORMAT_MASK, format); + + return 0; +} + +const struct rpp_module_ops rppx1_outregs_ops =3D { + .probe =3D rppx1_outregs_probe, + .start =3D rppx1_outregs_start, +}; diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_rmap.c b/drivers/= media/platform/dreamchip/rppx1/rppx1_rmap.c new file mode 100644 index 000000000000..f6773a452bd1 --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_rmap.c @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2025 Renesas Electronics Corp. + * Copyright 2025 Niklas S=C3=B6derlund + */ + +#include "rpp_module.h" + +#define RMAP_DATA_VERSION_REG 0x0000 + +#define RMAP_CTRL_REG 0x0004 +#define RMAP_CTRL_BYPASS_LONG BIT(2) + +#define RMAP_WBTHRESHOLD_LONG_REG 0x0008 +#define RMAP_WBTHRESHOLD_SHORT_REG 0x000c +#define RMAP_RESERVED_1_REG 0x0010 +#define RMAP_WBGAIN_LONG_RED_REG 0x0014 +#define RMAP_WBGAIN_LONG_BLUE_REG 0x0018 +#define RMAP_WBGAIN_SHORT_RED_REG 0x001c +#define RMAP_WBGAIN_SHORT_BLUE_REG 0x0020 +#define RMAP_RESERVED_2_REG 0x0024 +#define RMAP_RESERVED_3_REG 0x0028 +#define RMAP_MAP_FAC_SHORT_REG 0x002c +#define RMAP_RESERVED_4_REG 0x0030 +#define RMAP_MIN_THRES_SHORT_REG 0x0034 +#define RMAP_MAX_THRES_SHORT_REG 0x0038 +#define RMAP_STEPSIZE_SHORT_REG 0x003c +#define RMAP_MIN_THRES_LONG_REG 0x0040 +#define RMAP_MAX_THRES_LONG_REG 0x0044 +#define RMAP_STEPSIZE_LONG_REG 0x0048 +#define RMAP_CLB_LINESIZE_REG 0x004c + +static int rppx1_rmap_probe(struct rpp_module *mod) +{ + /* Version check. */ + switch (rpp_module_read(mod, RMAP_DATA_VERSION_REG)) { + case 8: + mod->info.rmap.colorbits_high =3D 20; + mod->info.rmap.colorbits_low =3D 12; + break; + case 9: + mod->info.rmap.colorbits_high =3D 24; + mod->info.rmap.colorbits_low =3D 12; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int rppx1_rmap_start(struct rpp_module *mod, + const struct v4l2_mbus_framefmt *fmt) +{ + /* Bypass radiance mapping and use the long exposure channel (PRE1). */ + rpp_module_write(mod, RMAP_CTRL_REG, RMAP_CTRL_BYPASS_LONG); + + return 0; +} + +const struct rpp_module_ops rppx1_rmap_ops =3D { + .probe =3D rppx1_rmap_probe, + .start =3D rppx1_rmap_start, +}; diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_rmapmeas.c b/driv= ers/media/platform/dreamchip/rppx1/rppx1_rmapmeas.c new file mode 100644 index 000000000000..c04f92508f6d --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_rmapmeas.c @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2025 Renesas Electronics Corp. + * Copyright 2025 Niklas S=C3=B6derlund + */ + +#include "rpp_module.h" + +#define RMAP_MEAS_VERSION_REG 0x0000 +#define RMAP_MEAS_MODE_REG 0x0004 +#define RMAP_MEAS_SUBSAMPLING_REG 0x0008 +#define RMAP_MEAS_RESERVED_1_REG 0x000c +#define RMAP_MEAS_MIN_THRES_SHORT_REG 0x0010 +#define RMAP_MEAS_MAX_THRES_SHORT_REG 0x0014 +#define RMAP_MEAS_MAX_THRES_LONG_REG 0x0018 +#define RMAP_MEAS_H_OFFS_REG 0x001c +#define RMAP_MEAS_V_OFFS_REG 0x0020 +#define RMAP_MEAS_H_SIZE_REG 0x0024 +#define RMAP_MEAS_V_SIZE_REG 0x0028 +#define RMAP_MEAS_LAST_MEAS_LINE_REG 0x002c +#define RMAP_MEAS_LS_RESULTSHORT0_REG 0x0030 +#define RMAP_MEAS_LS_RESULTLONG0_REG 0x0034 +#define RMAP_MEAS_RESERVED_2_REG 0x0038 +#define RMAP_MEAS_RESERVED_3_REG 0x003c +#define RMAP_MEAS_LS_RESULTSHORT1_REG 0x0040 +#define RMAP_MEAS_LS_RESULTLONG1_REG 0x0044 +#define RMAP_MEAS_RESERVED_4_REG 0x0048 +#define RMAP_MEAS_RESERVED_5_REG 0x004c + +static int rppx1_rmapmeas_probe(struct rpp_module *mod) +{ + /* Version check. */ + switch (rpp_module_read(mod, RMAP_MEAS_VERSION_REG)) { + case 3: + mod->info.rmapmeas.colorbits_high =3D 24; + mod->info.rmapmeas.colorbits_low =3D 12; + break; + default: + return -EINVAL; + } + + return 0; +} + +const struct rpp_module_ops rppx1_rmapmeas_ops =3D { + .probe =3D rppx1_rmapmeas_probe, +}; diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_shrp.c b/drivers/= media/platform/dreamchip/rppx1/rppx1_shrp.c new file mode 100644 index 000000000000..5bec022e8f05 --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_shrp.c @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2025 Renesas Electronics Corp. + * Copyright 2025 Niklas S=C3=B6derlund + */ + +#include "rpp_module.h" + +#define SHRPCNR_VERSION_REG 0x0000 + +#define SHRPCNR_CTRL_REG 0x0004 +#define SHRPCNR_CTRL_CAD_EN BIT(3) +#define SHRPCNR_CTRL_DESAT_EN BIT(2) +#define SHRPCNR_CTRL_CNR_EN BIT(1) +#define SHRPCNR_CTRL_SHARPEN_EN BIT(0) + +#define SHRPCNR_PARAM_REG 0x0008 +#define SHRPCNR_PARAM_SHARP_FACTOR_MASK GENMASK(19, 12) +#define SHRPCNR_PARAM_CORING_THR_MASK GENMASK(11, 0) + +#define SHRPCNR_MAT_1_REG 0x000c +#define SHRPCNR_MAT_2_REG 0x0010 +#define SHRPCNR_CLB_LINESIZE_REG 0x0014 +#define SHRPCNR_YUV2RGB_CCOR_COEFF_0_REG 0x0018 +#define SHRPCNR_YUV2RGB_CCOR_COEFF_1_REG 0x001c +#define SHRPCNR_YUV2RGB_CCOR_COEFF_2_REG 0x0020 +#define SHRPCNR_YUV2RGB_CCOR_COEFF_3_REG 0x0024 +#define SHRPCNR_YUV2RGB_CCOR_COEFF_4_REG 0x0028 +#define SHRPCNR_YUV2RGB_CCOR_COEFF_5_REG 0x002c +#define SHRPCNR_YUV2RGB_CCOR_COEFF_6_REG 0x0030 +#define SHRPCNR_YUV2RGB_CCOR_COEFF_7_REG 0x0034 +#define SHRPCNR_YUV2RGB_CCOR_COEFF_8_REG 0x0038 +#define SHRPCNR_YUV2RGB_CCOR_OFFSET_R_REG 0x003c +#define SHRPCNR_YUV2RGB_CCOR_OFFSET_G_REG 0x0040 +#define SHRPCNR_YUV2RGB_CCOR_OFFSET_B_REG 0x0044 + +#define SHRPCNR_CNR_THRES_REG 0x0048 +#define SHRPCNR_CNR_THRES_CNR_THRES_CR_MASK GENMASK(27, 16) +#define SHRPCNR_CNR_THRES_CNR_THRES_CB_MASK GENMASK(11, 0) + +#define SHRPCNR_CRED_THRES_REG 0x004c +#define SHRPCNR_CRED_SLOPE_REG 0x0050 +#define SHRPCNR_CAD_RESTORE_LVL_REG 0x0054 +#define SHRPCNR_CAD_THRESH_V_UNEG_REG 0x0058 +#define SHRPCNR_CAD_THRESH_V_UPOS_REG 0x005c +#define SHRPCNR_CAD_THRESH_U_REG 0x0060 + +static int rppx1_shrp_probe(struct rpp_module *mod) +{ + /* Version check. */ + switch (rpp_module_read(mod, SHRPCNR_VERSION_REG)) { + case 2: + mod->info.shrp.colorbits =3D 12; + break; + default: + return -EINVAL; + } + + return 0; +} + +const struct rpp_module_ops rppx1_shrp_ops =3D { + .probe =3D rppx1_shrp_probe, +}; diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_wbmeas.c b/driver= s/media/platform/dreamchip/rppx1/rppx1_wbmeas.c new file mode 100644 index 000000000000..3d197d914d07 --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_wbmeas.c @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2025 Renesas Electronics Corp. + * Copyright 2025 Niklas S=C3=B6derlund + */ + +#include "rpp_module.h" + +#define AWB_MEAS_VERSION_REG 0x0000 + +#define AWB_MEAS_PROP_REG 0x0004 +#define AWB_MEAS_PROP_MEAS_MODE_RGB BIT(16) /* 0: YCbCr 1: RGB */ +#define AWB_MEAS_PROP_YMAX BIT(2) +#define AWB_MEAS_PROP_AWB_MODE_ON BIT(1) + +#define AWB_MEAS_H_OFFS_REG 0x0008 +#define AWB_MEAS_V_OFFS_REG 0x000c +#define AWB_MEAS_H_SIZE_REG 0x0010 +#define AWB_MEAS_V_SIZE_REG 0x0014 +#define AWB_MEAS_FRAMES_REG 0x0018 +#define AWB_MEAS_REF_CB_MAX_B_REG 0x001c +#define AWB_MEAS_REF_CR_MAX_R_REG 0x0020 +#define AWB_MEAS_MAX_Y_REG 0x0024 +#define AWB_MEAS_MIN_Y_MAX_G_REG 0x0028 +#define AWB_MEAS_MAX_CSUM_REG 0x002c +#define AWB_MEAS_MIN_C_REG 0x0030 +#define AWB_MEAS_WHITE_CNT_REG 0x0034 +#define AWB_MEAS_MEAN_Y_G_REG 0x0038 +#define AWB_MEAS_MEAN_CB_B_REG 0x003c +#define AWB_MEAS_MEAN_CR_R_REG 0x0040 + +#define AWB_MEAS_CCOR_COEFF_NUM 9 +#define AWB_MEAS_CCOR_COEFF_REG(n) (0x0044 + (4 * (n))) + +#define AWB_MEAS_CCOR_OFFSET_R_REG 0x0068 +#define AWB_MEAS_CCOR_OFFSET_G_REG 0x006c +#define AWB_MEAS_CCOR_OFFSET_B_REG 0x0070 + +static int rppx1_wbmeas_probe(struct rpp_module *mod) +{ + /* Version check. */ + switch (rpp_module_read(mod, AWB_MEAS_VERSION_REG)) { + case 1: + mod->info.wbmeas.colorbits =3D 8; + break; + case 2: + mod->info.wbmeas.colorbits =3D 20; + break; + case 3: + mod->info.wbmeas.colorbits =3D 24; + break; + default: + return -EINVAL; + } + + return 0; +} + +const struct rpp_module_ops rppx1_wbmeas_ops =3D { + .probe =3D rppx1_wbmeas_probe, +}; diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_xyz2luv.c b/drive= rs/media/platform/dreamchip/rppx1/rppx1_xyz2luv.c new file mode 100644 index 000000000000..73789c48c057 --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_xyz2luv.c @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2025 Renesas Electronics Corp. + * Copyright 2025 Niklas S=C3=B6derlund + */ + +#include "rpp_module.h" + +#define XYZ2LUV_VERSION_REG 0x0000 +#define XYZ2LUV_U_REF_REG 0x0004 +#define XYZ2LUV_V_REF_REG 0x0008 +#define XYZ2LUV_LUMA_OUT_FAC_REG 0x000c +#define XYZ2LUV_CHROMA_OUT_FAC_REG 0x0010 + +static int rppx1_xyz2luv_probe(struct rpp_module *mod) +{ + /* Version check. */ + if (rpp_module_read(mod, XYZ2LUV_VERSION_REG) !=3D 4) + return -EINVAL; + + return 0; +} + +const struct rpp_module_ops rppx1_xyz2luv_ops =3D { + .probe =3D rppx1_xyz2luv_probe, +}; diff --git a/include/media/rppx1.h b/include/media/rppx1.h new file mode 100644 index 000000000000..111e0218846e --- /dev/null +++ b/include/media/rppx1.h @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright 2025 Renesas Electronics Corp. + * Copyright 2025 Niklas S=C3=B6derlund + */ +#ifndef __MEDIA_DCT_RPPX1_H__ +#define __MEDIA_DCT_RPPX1_H__ + +#include + +#include + +struct rppx1; + +struct rppx1 *rppx1_create(void __iomem *base); + +void rppx1_destroy(struct rppx1 *rpp); + +int rppx1_start(struct rppx1 *rpp, const struct v4l2_mbus_framefmt *input, + const struct v4l2_mbus_framefmt *hv, + const struct v4l2_mbus_framefmt *mv); + +int rppx1_stop(struct rppx1 *rpp); + +bool rppx1_interrupt(struct rppx1 *rpp, u32 *isc); + +typedef int (*rppx1_reg_write)(void *priv, u32 offset, u32 value); +int rppx1_params_rkisp1(struct rppx1 *rpp, struct rkisp1_ext_params_cfg *c= fg, + rppx1_reg_write write, void *priv); + +void rppx1_stats_fill_isr(struct rppx1 *rpp, u32 isc, void *buf); + +#endif /* __MEDIA_DCT_RPPX1_H__ */ --=20 2.51.0 From nobody Thu Oct 2 14:12:03 2025 Received: from fhigh-b2-smtp.messagingengine.com (fhigh-b2-smtp.messagingengine.com [202.12.124.153]) (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 919B828314A; Mon, 15 Sep 2025 17:10:31 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=202.12.124.153 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757956236; cv=none; b=lJFJNpGmVxcXCKLa9D8sMhs5x6QTEkaZ4c+MIF/6Ri2t2w7Iiv4NBHP9BTzL/QgoamZ/faU7CDkqhwItus6JPWw1szsYbEyYBy4TUSiuHWDMncjC9Rn2Lm760O1QgT4I+3swG2KmYlMFbrzuMkEiPW20yv9xFkc9DKgAjag4bIU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757956236; c=relaxed/simple; bh=BpYx3VfijGsukxCibG55P5zh1uNRvjTOiHS9qVEZHbA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=YX35/q/0L44CFASOp876d1G0FrDcqL5QVU3nf85nxEZTceoofSCERXFTvEdsXGW5Dgptk0HTLyJUUWjX+fmTKlL95gNDITZl0oxKtDnPOOCh//bdxWDlVQlVRyPGnSiYN0dUv28/ml9YjNT+p9b/BRIyM6B0a/Qrsfp6QGr4uKM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=ragnatech.se; spf=pass smtp.mailfrom=ragnatech.se; dkim=pass (2048-bit key) header.d=ragnatech.se header.i=@ragnatech.se header.b=Qgubt4uD; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=HM7X/dyU; arc=none smtp.client-ip=202.12.124.153 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=ragnatech.se Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=ragnatech.se Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=ragnatech.se header.i=@ragnatech.se header.b="Qgubt4uD"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="HM7X/dyU" Received: from phl-compute-01.internal (phl-compute-01.internal [10.202.2.41]) by mailfhigh.stl.internal (Postfix) with ESMTP id 6EB6B7A016C; Mon, 15 Sep 2025 13:10:30 -0400 (EDT) Received: from phl-mailfrontend-02 ([10.202.2.163]) by phl-compute-01.internal (MEProxy); Mon, 15 Sep 2025 13:10:30 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ragnatech.se; h= cc:cc:content-transfer-encoding:content-type:content-type:date :date:from:from:in-reply-to:in-reply-to:message-id:mime-version :references:reply-to:subject:subject:to:to; s=fm3; t=1757956230; x=1758042630; bh=tfP2yRgWUYI6u47/XNr3sNYz9H6t9Fypa6/OKiHOPMU=; b= Qgubt4uDxvxPNjdPpVZM0FnnNQQ9yYExNNF7xEWGgKIdz09ay2kiUWqUlv2ykV9x xm3F4qyFke1EvIYqQly6wtrkYAWGeFkn8ZMCf5D/1MRJ6MwoeBp4nWDR7dT+YvZb iK7P+qX6u7IPT3m2k7IjCdfO4QNISvUT4tuTxpVNMlwKyN/e2ld55RLwCdHnLXlh LaNjCMaiz0yi39LmfUAPnau329WgHStAiylqE1fIRJXV69gm7ZNFoW6BiSbRMyAd OYWEmXkSEYA/kAOZh5G3erEEMzUg6TEyH2wett1J6RTKQLE8qAm5MYmDAeeyucdj iWgfRUeqA5okR93K/8qugg== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:content-type:date:date:feedback-id:feedback-id :from:from:in-reply-to:in-reply-to:message-id:mime-version :references:reply-to:subject:subject:to:to:x-me-proxy :x-me-sender:x-me-sender:x-sasl-enc; s=fm1; t=1757956230; x= 1758042630; bh=tfP2yRgWUYI6u47/XNr3sNYz9H6t9Fypa6/OKiHOPMU=; b=H M7X/dyUESKgkeNIWyZKH33gm0glL02UI0p9NsGzH8X9npfSVaZ9Wk85o/uLX5JU0 xFGjD9fGOJfuKd8cx4OrbUbRz8qmcHk8tbzNYej79z9hcbVj5QoZFC6rFlJt9sKd MXsG56I4h3bQtDo+DZZPRG8UJQkF/wcX2Xesl9JOCRni0AbbnCNirnU33sSXBf5F GiXE9DKDP0STyZQ8PEpguUQerEUH72HqD1ucew8bJq0C7bNAFKxFFYe/Kz4xWtAV 5UDGQEtdiGCmA2+ynbeQzLjuyVEqxU7BTPLMUhnr08j6TY2UUMyTwGA60WhuTYDN 5Jsp5Llx5dkQl3+2y8GAg== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeeffedrtdeggdefkedvhecutefuodetggdotefrod ftvfcurfhrohhfihhlvgemucfhrghsthforghilhdpuffrtefokffrpgfnqfghnecuuegr ihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmdenucfjug hrpefhvfevufffkffojghfgggtgfesthekredtredtjeenucfhrhhomheppfhikhhlrghs ucfunpguvghrlhhunhguuceonhhikhhlrghsrdhsohguvghrlhhunhguodhrvghnvghsrg hssehrrghgnhgrthgvtghhrdhsvgeqnecuggftrfgrthhtvghrnhepheeigfeuveeutdef hfehgeekvedtleeuueekveefudehhffhjeffgfegffelfeegnecuvehluhhsthgvrhfuih iivgeptdenucfrrghrrghmpehmrghilhhfrhhomhepnhhikhhlrghsrdhsohguvghrlhhu nhgusehrrghgnhgrthgvtghhrdhsvgdpnhgspghrtghpthhtohepjedpmhhouggvpehsmh htphhouhhtpdhrtghpthhtohepmhgthhgvhhgrsgeskhgvrhhnvghlrdhorhhgpdhrtghp thhtohepjhgrtghophhordhmohhnughisehiuggvrghsohhnsghorghrugdrtghomhdprh gtphhtthhopehlrghurhgvnhhtrdhpihhntghhrghrthesihguvggrshhonhgsohgrrhgu rdgtohhmpdhrtghpthhtoheplhhinhhugidqmhgvughirgesvhhgvghrrdhkvghrnhgvlh drohhrghdprhgtphhtthhopehlihhnuhigqdhrvghnvghsrghsqdhsohgtsehvghgvrhdr khgvrhhnvghlrdhorhhgpdhrtghpthhtoheplhhinhhugidqkhgvrhhnvghlsehvghgvrh drkhgvrhhnvghlrdhorhhgpdhrtghpthhtohepnhhikhhlrghsrdhsohguvghrlhhunhgu odhrvghnvghsrghssehrrghgnhgrthgvtghhrdhsvg X-ME-Proxy: Feedback-ID: i80c9496c:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Mon, 15 Sep 2025 13:10:29 -0400 (EDT) From: =?UTF-8?q?Niklas=20S=C3=B6derlund?= To: Mauro Carvalho Chehab , Jacopo Mondi , Laurent Pinchart , linux-media@vger.kernel.org, linux-renesas-soc@vger.kernel.org, linux-kernel@vger.kernel.org Cc: =?UTF-8?q?Niklas=20S=C3=B6derlund?= Subject: [PATCH v2 02/12] media: rcar-isp: Add support for ISPCORE Date: Mon, 15 Sep 2025 19:07:33 +0200 Message-ID: <20250915170743.106249-3-niklas.soderlund+renesas@ragnatech.se> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20250915170743.106249-1-niklas.soderlund+renesas@ragnatech.se> References: <20250915170743.106249-1-niklas.soderlund+renesas@ragnatech.se> 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 The Renesas R-Car ISP block consists of two different IP blocks, one CSI-2 Channel Selector (CSISP) and one traditional ISP for image operation (ISPCORE). The R-Car ISP driver currently supports the CSISP functionality as part of the video capture pipeline, this change adds support for the ISPCORE functionality. The ISPCORE functionality is further split in two parts, a Renesas specific part and a Dream Chip Real-time Pixel Processor IP part (RPPX1). The Renesas part deals with I/O to/from the block while the RPPX1 part deals with the actual ISP functions. The RPPX1 functionality is implemented in a support framework (DCT RPPX1) as this block can be used by different vendors or setups. This change deals with the Renesas part of exposing the V4L2 elements needed for a user-space interface to the RPPX1 and deals with the DMA to/from the RPP block. It also facilitates the user-space V4L2 API to allow configuring the RPPX1 using the DCT RPPX1 support framework. The functionality exposed are one input video device where RAW bayer frames can be queued for processing, one output video device where the debayerd image can be read as either ABGR32 or NV16M format. Further more a video device to queue the image processing parameters to configure the RPPX1 IPS as well as a video device to read statistics about the processed image is available. The parameters and statistics puffer formats piggy back on the Rockchip RkISP1 format's as the capabilities of the two devices are similar and this is what the DCT RPPX1 support framework expects. There is no change in the operation of the CSISP functionality. Signed-off-by: Niklas S=C3=B6derlund --- .../media/platform/renesas/rcar-isp/Kconfig | 1 + .../media/platform/renesas/rcar-isp/Makefile | 2 +- .../media/platform/renesas/rcar-isp/core-io.c | 1053 +++++++++++++++++ .../media/platform/renesas/rcar-isp/core.c | 790 +++++++++++++ .../media/platform/renesas/rcar-isp/csisp.c | 48 +- .../platform/renesas/rcar-isp/risp-core.h | 163 +++ 6 files changed, 2049 insertions(+), 8 deletions(-) create mode 100644 drivers/media/platform/renesas/rcar-isp/core-io.c create mode 100644 drivers/media/platform/renesas/rcar-isp/core.c create mode 100644 drivers/media/platform/renesas/rcar-isp/risp-core.h diff --git a/drivers/media/platform/renesas/rcar-isp/Kconfig b/drivers/medi= a/platform/renesas/rcar-isp/Kconfig index 242f6a23851f..1621971547e6 100644 --- a/drivers/media/platform/renesas/rcar-isp/Kconfig +++ b/drivers/media/platform/renesas/rcar-isp/Kconfig @@ -9,6 +9,7 @@ config VIDEO_RCAR_ISP select VIDEO_V4L2_SUBDEV_API select RESET_CONTROLLER select V4L2_FWNODE + select VIDEO_DCT_RPPX1 help Support for Renesas R-Car Image Signal Processor (ISP). Enable this to support the Renesas R-Car Image Signal diff --git a/drivers/media/platform/renesas/rcar-isp/Makefile b/drivers/med= ia/platform/renesas/rcar-isp/Makefile index b542118c831e..c0c80303682c 100644 --- a/drivers/media/platform/renesas/rcar-isp/Makefile +++ b/drivers/media/platform/renesas/rcar-isp/Makefile @@ -1,4 +1,4 @@ # SPDX-License-Identifier: GPL-2.0 -rcar-isp-objs =3D csisp.o +rcar-isp-objs =3D csisp.o core.o core-io.o =20 obj-$(CONFIG_VIDEO_RCAR_ISP) +=3D rcar-isp.o diff --git a/drivers/media/platform/renesas/rcar-isp/core-io.c b/drivers/me= dia/platform/renesas/rcar-isp/core-io.c new file mode 100644 index 000000000000..e5bae626e134 --- /dev/null +++ b/drivers/media/platform/renesas/rcar-isp/core-io.c @@ -0,0 +1,1053 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include + +#include +#include +#include +#include + +#include + +#include "risp-core.h" + +#define risp_io_err(d, fmt, arg...) dev_err((d)->core->dev, fmt, #= #arg) + +static struct risp_buffer *risp_io_vb2buf(struct vb2_v4l2_buffer *vb) +{ + return container_of(vb, struct risp_buffer, vb); +} + +static int risp_io_open(struct file *file) +{ + struct rcar_isp_core_io *io =3D video_drvdata(file); + struct rcar_isp_core *core =3D io->core; + int ret; + + ret =3D pm_runtime_resume_and_get(core->dev); + if (ret < 0) + return ret; + + ret =3D reset_control_deassert(core->csrstc); + if (ret) + goto err_csrstc; + + ret =3D clk_prepare_enable(core->clk); + if (ret) + goto err_clk; + + ret =3D mutex_lock_interruptible(&io->lock); + if (ret) + goto err_pm; + + file->private_data =3D io; + + ret =3D v4l2_fh_open(file); + if (ret) + goto err_unlock; + + ret =3D v4l2_pipeline_pm_get(&io->vdev.entity); + if (ret < 0) + goto err_open; + + mutex_unlock(&io->lock); + + return 0; +err_open: + v4l2_fh_release(file); +err_unlock: + mutex_unlock(&io->lock); +err_pm: + pm_runtime_put(core->dev); +err_clk: + clk_disable_unprepare(core->clk); +err_csrstc: + reset_control_assert(core->csrstc); + + return ret; +} + +static int risp_io_release(struct file *file) +{ + struct rcar_isp_core_io *io =3D video_drvdata(file); + struct rcar_isp_core *core =3D io->core; + int ret; + + mutex_lock(&io->lock); + + ret =3D _vb2_fop_release(file, NULL); + + v4l2_pipeline_pm_put(&io->vdev.entity); + + mutex_unlock(&io->lock); + + clk_disable_unprepare(core->clk); + + pm_runtime_put(core->dev); + + reset_control_assert(core->csrstc); + + return ret; +} + +static const struct v4l2_file_operations risp_io_fops =3D { + .owner =3D THIS_MODULE, + .unlocked_ioctl =3D video_ioctl2, + .open =3D risp_io_open, + .release =3D risp_io_release, + .poll =3D vb2_fop_poll, + .mmap =3D vb2_fop_mmap, + .read =3D vb2_fop_read, +}; + +/* -----------------------------------------------------------------------= ------ + * Common queue + */ + +static int risp_io_queue_setup(struct vb2_queue *vq, unsigned int *nbuffer= s, + unsigned int *nplanes, unsigned int sizes[], + struct device *alloc_devs[]) + +{ + struct rcar_isp_core_io *io =3D vb2_get_drv_priv(vq); + + if (V4L2_TYPE_IS_MULTIPLANAR(vq->type)) { + const struct v4l2_pix_format_mplane *pix =3D &io->format.fmt.pix_mp; + + if (*nplanes) { + if (*nplanes > pix->num_planes) + return -EINVAL; + + for (unsigned int i =3D 0; i < pix->num_planes; i++) + if (sizes[i] < pix->plane_fmt[i].sizeimage) + return -EINVAL; + + return 0; + } + + *nplanes =3D pix->num_planes; + for (unsigned int i =3D 0; i < pix->num_planes; i++) + sizes[i] =3D pix->plane_fmt[i].sizeimage; + } else { + if (*nplanes) { + if (sizes[0] < io->format.fmt.meta.buffersize) + return -EINVAL; + + return 0; + } + + *nplanes =3D 1; + sizes[0] =3D io->format.fmt.meta.buffersize; + } + + /* Initialize buffer queue */ + INIT_LIST_HEAD(&io->buffers); + + return 0; +}; + +static int risp_io_buffer_prepare_set(struct rcar_isp_core_io *io, + struct vb2_buffer *vb, unsigned int plane, + unsigned long size) +{ + if (vb2_plane_size(vb, plane) < size) { + risp_io_err(io, "Buffer too small (%lu < %lu)\n", + vb2_plane_size(vb, plane), size); + return -EINVAL; + } + + vb2_set_plane_payload(vb, plane, size); + + return 0; +} + +static int risp_io_buffer_prepare(struct vb2_buffer *vb) +{ + struct rcar_isp_core_io *io =3D vb2_get_drv_priv(vb->vb2_queue); + int ret =3D 0; + + if (V4L2_TYPE_IS_MULTIPLANAR(vb->vb2_queue->type)) { + const struct v4l2_pix_format_mplane *pix =3D &io->format.fmt.pix_mp; + + for (unsigned int i =3D 0; i < pix->num_planes; i++) { + ret =3D risp_io_buffer_prepare_set(io, vb, i, + pix->plane_fmt[i].sizeimage); + if (ret) + break; + } + } else { + ret =3D risp_io_buffer_prepare_set(io, vb, 0, + io->format.fmt.meta.buffersize); + } + + return ret; +} + +static void risp_io_buffer_queue(struct vb2_buffer *vb) +{ + struct rcar_isp_core_io *io =3D vb2_get_drv_priv(vb->vb2_queue); + struct vb2_v4l2_buffer *vbuf =3D to_vb2_v4l2_buffer(vb); + struct risp_buffer *buf =3D risp_io_vb2buf(vbuf); + + guard(mutex)(&io->core->io_lock); + + list_add_tail(&buf->list, &io->buffers); + + if (risp_core_job_prepare(io->core)) + risp_io_err(io, "Failed to prepare job\n"); +} + +static void risp_io_return_buffers(struct rcar_isp_core_io *io, + enum vb2_buffer_state state) +{ + struct risp_buffer *buf, *node; + + lockdep_assert_held(&io->core->io_lock); + + list_for_each_entry_safe(buf, node, &io->buffers, list) { + vb2_buffer_done(&buf->vb.vb2_buf, state); + list_del(&buf->list); + } +} + +static int risp_io_start_streaming(struct vb2_queue *vq, unsigned int coun= t) +{ + struct rcar_isp_core_io *io =3D vb2_get_drv_priv(vq); + int ret; + + scoped_guard(mutex, &io->core->io_lock) { + if (io->core->io[RISP_CORE_INPUT1].format.fmt.pix_mp.width !=3D + io->core->io[RISP_CORE_OUTPUT1].format.fmt.pix_mp.width || + io->core->io[RISP_CORE_INPUT1].format.fmt.pix_mp.height !=3D + io->core->io[RISP_CORE_OUTPUT1].format.fmt.pix_mp.height) { + risp_io_return_buffers(io, VB2_BUF_STATE_QUEUED); + return -EPIPE; + } + + io->streaming =3D true; + } + + ret =3D risp_core_start_streaming(io->core); + if (ret) { + guard(mutex)(&io->core->io_lock); + + risp_io_return_buffers(io, VB2_BUF_STATE_QUEUED); + return ret; + } + + return 0; +} + +static void risp_io_stop_streaming(struct vb2_queue *vq) +{ + struct rcar_isp_core_io *io =3D vb2_get_drv_priv(vq); + + scoped_guard(mutex, &io->core->io_lock) { + io->streaming =3D false; + risp_core_stop_streaming(io->core); + risp_io_return_buffers(io, VB2_BUF_STATE_ERROR); + } + + /* + * Wait for buffers part of the jobs not yet processed. Note that this + * might complete buffers out of order. + */ + vb2_wait_for_all_buffers(&io->queue); +} + +/* -----------------------------------------------------------------------= ------ + * Common V4L2 IOCTLs + */ + +static int risp_io_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct video_device *vdev =3D video_devdata(file); + + strscpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver)); + strscpy(cap->card, vdev->name, sizeof(cap->card)); + + return 0; +} + +/* -----------------------------------------------------------------------= ------ + * Input Exposure + */ + +static int risp_io_input_queue_setup(struct vb2_queue *vq, unsigned int *n= buffers, + unsigned int *nplanes, unsigned int sizes[], + struct device *alloc_devs[]) + +{ + struct rcar_isp_core_io *io =3D vb2_get_drv_priv(vq); + struct rcar_isp_core *core =3D io->core; + struct device *bus_master; + int ret; + + ret =3D risp_io_queue_setup(vq, nbuffers, nplanes, sizes, alloc_devs); + if (ret) + return ret; + + bus_master =3D vsp1_isp_get_bus_master(core->vspx.dev); + if (IS_ERR_OR_NULL(bus_master)) { + risp_io_err(io, "Missing reference to bus-master device\n"); + return -EINVAL; + } + + /* + * Allocate buffers using the bus_master device associated with the + * VSPX associated to this ISP instance. + */ + alloc_devs[0] =3D bus_master; + + return 0; +}; + +static const struct vb2_ops risp_io_input_qops =3D { + .queue_setup =3D risp_io_input_queue_setup, + .buf_prepare =3D risp_io_buffer_prepare, + .buf_queue =3D risp_io_buffer_queue, + .start_streaming =3D risp_io_start_streaming, + .stop_streaming =3D risp_io_stop_streaming, +}; + +static const struct v4l2_pix_format_mplane risp_io_input_default_format = =3D { + .width =3D 1920, + .height =3D 1080, + .field =3D V4L2_FIELD_NONE, + .pixelformat =3D V4L2_PIX_FMT_SGRBG8, + .colorspace =3D V4L2_COLORSPACE_RAW, + .num_planes =3D 1, + .plane_fmt =3D { + [0] =3D { + .sizeimage =3D 1920 * 1080, + .bytesperline =3D 1920, + }, + }, +}; + +static const struct risp_io_input_format { + unsigned int fourcc; + unsigned int bpp; +} risp_io_input_formats[] =3D { + { .fourcc =3D V4L2_PIX_FMT_SBGGR8, .bpp =3D 1 }, + { .fourcc =3D V4L2_PIX_FMT_SGBRG8, .bpp =3D 1 }, + { .fourcc =3D V4L2_PIX_FMT_SGRBG8, .bpp =3D 1 }, + { .fourcc =3D V4L2_PIX_FMT_SRGGB8, .bpp =3D 1 }, + { .fourcc =3D V4L2_PIX_FMT_SBGGR10, .bpp =3D 2 }, + { .fourcc =3D V4L2_PIX_FMT_SGBRG10, .bpp =3D 2 }, + { .fourcc =3D V4L2_PIX_FMT_SGRBG10, .bpp =3D 2 }, + { .fourcc =3D V4L2_PIX_FMT_SRGGB10, .bpp =3D 2 }, + { .fourcc =3D V4L2_PIX_FMT_SBGGR12, .bpp =3D 2 }, + { .fourcc =3D V4L2_PIX_FMT_SGBRG12, .bpp =3D 2 }, + { .fourcc =3D V4L2_PIX_FMT_SGRBG12, .bpp =3D 2 }, + { .fourcc =3D V4L2_PIX_FMT_SRGGB12, .bpp =3D 2 }, +}; + +static void risp_io_input_try_format(struct rcar_isp_core_io *io, + struct v4l2_pix_format_mplane *pix) +{ + unsigned int bpp =3D 0; + + v4l_bound_align_image(&pix->width, 128, 5120, 2, + &pix->height, 128, 4096, 2, 0); + + for (unsigned int i =3D 0; i < ARRAY_SIZE(risp_io_input_formats); i++) { + if (risp_io_input_formats[i].fourcc =3D=3D pix->pixelformat) { + bpp =3D risp_io_input_formats[i].bpp; + break; + } + } + + if (!bpp) { + pix->pixelformat =3D risp_io_input_formats[0].fourcc; + bpp =3D risp_io_input_formats[0].bpp; + } + + pix->field =3D V4L2_FIELD_NONE; + pix->colorspace =3D V4L2_COLORSPACE_RAW; + + pix->num_planes =3D 1; + pix->plane_fmt[0].bytesperline =3D pix->width * bpp; + pix->plane_fmt[0].sizeimage =3D pix->plane_fmt[0].bytesperline * pix->hei= ght; +} + +static int risp_io_input_enum_fmt(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + if (f->index >=3D ARRAY_SIZE(risp_io_input_formats)) + return -EINVAL; + + f->pixelformat =3D risp_io_input_formats[f->index].fourcc; + + return 0; +} + +static int risp_io_input_g_fmt(struct file *file, void *priv, struct v4l2_= format *f) +{ + struct rcar_isp_core_io *io =3D video_drvdata(file); + + if (f->type !=3D V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) + return -EINVAL; + + f->fmt.pix_mp =3D io->format.fmt.pix_mp; + + return 0; +} + +static int risp_io_input_s_fmt(struct file *file, void *priv, struct v4l2_= format *f) +{ + struct rcar_isp_core_io *io =3D video_drvdata(file); + + if (vb2_is_busy(&io->queue)) + return -EBUSY; + + if (f->type !=3D V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) + return -EINVAL; + + risp_io_input_try_format(io, &f->fmt.pix_mp); + + io->format.fmt.pix_mp =3D f->fmt.pix_mp; + + return 0; +} + +static int risp_io_input_try_fmt(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct rcar_isp_core_io *io =3D video_drvdata(file); + + risp_io_input_try_format(io, &f->fmt.pix_mp); + + return 0; +} + +static int risp_io_input_enum_framesizes(struct file *file, void *fh, + struct v4l2_frmsizeenum *fsize) +{ + bool found =3D false; + + if (fsize->index !=3D 0) + return -EINVAL; + + for (unsigned int i =3D 0; i < ARRAY_SIZE(risp_io_input_formats); i++) { + if (risp_io_input_formats[i].fourcc =3D=3D fsize->pixel_format) { + found =3D true; + break; + } + } + + if (!found) + return -EINVAL; + + fsize->type =3D V4L2_FRMSIZE_TYPE_STEPWISE; + + fsize->stepwise.min_width =3D 128; + fsize->stepwise.max_width =3D 5120; + fsize->stepwise.step_width =3D 2; + + fsize->stepwise.min_height =3D 128; + fsize->stepwise.max_height =3D 4096; + fsize->stepwise.step_height =3D 2; + + return 0; +} + +static const struct v4l2_ioctl_ops risp_io_input_ioctl_ops =3D { + .vidioc_querycap =3D risp_io_querycap, + + .vidioc_enum_fmt_vid_out =3D risp_io_input_enum_fmt, + .vidioc_g_fmt_vid_out_mplane =3D risp_io_input_g_fmt, + .vidioc_s_fmt_vid_out_mplane =3D risp_io_input_s_fmt, + .vidioc_try_fmt_vid_out_mplane =3D risp_io_input_try_fmt, + .vidioc_enum_framesizes =3D risp_io_input_enum_framesizes, + + .vidioc_reqbufs =3D vb2_ioctl_reqbufs, + .vidioc_querybuf =3D vb2_ioctl_querybuf, + .vidioc_qbuf =3D vb2_ioctl_qbuf, + .vidioc_expbuf =3D vb2_ioctl_expbuf, + .vidioc_dqbuf =3D vb2_ioctl_dqbuf, + .vidioc_create_bufs =3D vb2_ioctl_create_bufs, + .vidioc_prepare_buf =3D vb2_ioctl_prepare_buf, + .vidioc_streamon =3D vb2_ioctl_streamon, + .vidioc_streamoff =3D vb2_ioctl_streamoff, +}; + +/* -----------------------------------------------------------------------= ------ + * Parameters + * + */ + +/* Max 2048 address + value pairs in one VSPX buffer, increase if needed. = */ +#define RISP_IO_PARAMS_BUF_SIZE 16384 + +static int risp_io_params_buf_init(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf =3D to_vb2_v4l2_buffer(vb); + struct risp_buffer *buf =3D risp_io_vb2buf(vbuf); + struct rcar_isp_core_io *io =3D vb2_get_drv_priv(vb->vb2_queue); + struct rcar_isp_core *core =3D io->core; + size_t size; + int ret; + + memset(&buf->vsp_buffer, 0, sizeof(buf->vsp_buffer)); + + size =3D RISP_IO_PARAMS_BUF_SIZE; + ret =3D vsp1_isp_alloc_buffer(core->vspx.dev, size, &buf->vsp_buffer); + if (ret) + return -EINVAL; + + memset(buf->vsp_buffer.cpu_addr, 0, RISP_IO_PARAMS_BUF_SIZE); + + return 0; +} + +static void risp_io_params_buf_cleanup(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf =3D to_vb2_v4l2_buffer(vb); + struct risp_buffer *buf =3D risp_io_vb2buf(vbuf); + struct rcar_isp_core_io *io =3D vb2_get_drv_priv(vb->vb2_queue); + struct rcar_isp_core *core =3D io->core; + + vsp1_isp_free_buffer(core->vspx.dev, &buf->vsp_buffer); +} + +struct risp_conf_dma_write_desc { + u32 *buf; + u32 base; + unsigned int count; +}; + +static int risp_conf_dma_prepare(void *priv, u32 offset, u32 value) +{ + struct risp_conf_dma_write_desc *desc =3D priv; + + /* Bounds check, 8 bytes =3D address (4)+ value (4). */ + if ((desc->count + 1) * 8 > RISP_IO_PARAMS_BUF_SIZE) + return -ENOMEM; + + (*desc->buf++) =3D desc->base | offset; + (*desc->buf++) =3D value; + + desc->count++; + + return 0; +} + +static int risp_io_params_buffer_prepare(struct vb2_buffer *vb) +{ + struct rcar_isp_core_io *io =3D vb2_get_drv_priv(vb->vb2_queue); + struct vb2_v4l2_buffer *vbuf =3D to_vb2_v4l2_buffer(vb); + struct risp_buffer *buf =3D risp_io_vb2buf(vbuf); + struct risp_conf_dma_write_desc desc; + struct rkisp1_ext_params_cfg *cfg; + size_t header_size, payload_size; + size_t cfg_size; + u32 *cpu_addr; + int ret; + + payload_size =3D vb2_get_plane_payload(vb, 0); + header_size =3D offsetof(struct rkisp1_ext_params_cfg, data); + + /* Validate the buffer payload sizes. */ + if (payload_size > io->format.fmt.meta.buffersize) { + risp_io_err(io, "Too large buffer payload size %zu\n", + payload_size); + return -EINVAL; + } + + if (payload_size < header_size) { + risp_io_err(io, + "Buffer payload %zu smaller than header size %zu\n", + payload_size, header_size); + return -EINVAL; + } + + /* Validate params header. */ + cfg =3D vb2_plane_vaddr(&vbuf->vb2_buf, 0); + + if (cfg->version !=3D RKISP1_EXT_PARAM_BUFFER_V1) { + risp_io_err(io, + "Unsupported extensible format version: %u\n", + cfg->version); + return -EINVAL; + } + + cfg_size =3D header_size + cfg->data_size; + if (cfg_size !=3D payload_size) { + risp_io_err(io, + "Data size %zu different than buffer payload size %zu\n", + cfg_size, payload_size); + return -EINVAL; + } + + /* Prepare params. */ + cpu_addr =3D (u32 *)buf->vsp_buffer.cpu_addr; + + desc.buf =3D cpu_addr + 2; + desc.base =3D io->core->rppaddr; + desc.count =3D 0; + + /* Fill params body. */ + ret =3D rppx1_params_rkisp1(io->core->rpp, cfg, risp_conf_dma_prepare, &d= esc); + if (ret) + return ret; + + /* Fill params header. */ + cpu_addr[0] =3D desc.count; + cpu_addr[1] =3D 0x0; + + return 0; +} + +static const struct vb2_ops risp_io_params_qops =3D { + .queue_setup =3D risp_io_queue_setup, + .buf_init =3D risp_io_params_buf_init, + .buf_cleanup =3D risp_io_params_buf_cleanup, + .buf_prepare =3D risp_io_params_buffer_prepare, + .buf_queue =3D risp_io_buffer_queue, + .start_streaming =3D risp_io_start_streaming, + .stop_streaming =3D risp_io_stop_streaming, +}; + +static const struct v4l2_meta_format risp_io_params_default_format =3D { + .dataformat =3D V4L2_META_FMT_RK_ISP1_EXT_PARAMS, + .buffersize =3D sizeof(struct rkisp1_ext_params_cfg), +}; + +static int risp_io_params_enum_fmt(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + struct rcar_isp_core_io *io =3D video_drvdata(file); + + if (f->type !=3D V4L2_BUF_TYPE_META_OUTPUT || f->index) + return -EINVAL; + + f->pixelformat =3D io->format.fmt.meta.dataformat; + + return 0; +} + +static int risp_io_params_g_fmt(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct rcar_isp_core_io *io =3D video_drvdata(file); + struct v4l2_meta_format *meta =3D &f->fmt.meta; + + if (f->type !=3D V4L2_BUF_TYPE_META_OUTPUT) + return -EINVAL; + + *meta =3D io->format.fmt.meta; + + return 0; +} + +static int risp_io_params_s_fmt(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct rcar_isp_core_io *io =3D video_drvdata(file); + + if (vb2_is_busy(&io->queue)) + return -EBUSY; + + return risp_io_params_g_fmt(file, priv, f); +} + +static const struct v4l2_ioctl_ops risp_io_params_ioctl_ops =3D { + .vidioc_querycap =3D risp_io_querycap, + + .vidioc_enum_fmt_meta_out =3D risp_io_params_enum_fmt, + .vidioc_g_fmt_meta_out =3D risp_io_params_g_fmt, + .vidioc_s_fmt_meta_out =3D risp_io_params_s_fmt, + .vidioc_try_fmt_meta_out =3D risp_io_params_g_fmt, + + .vidioc_reqbufs =3D vb2_ioctl_reqbufs, + .vidioc_querybuf =3D vb2_ioctl_querybuf, + .vidioc_qbuf =3D vb2_ioctl_qbuf, + .vidioc_expbuf =3D vb2_ioctl_expbuf, + .vidioc_dqbuf =3D vb2_ioctl_dqbuf, + .vidioc_create_bufs =3D vb2_ioctl_create_bufs, + .vidioc_prepare_buf =3D vb2_ioctl_prepare_buf, + .vidioc_streamon =3D vb2_ioctl_streamon, + .vidioc_streamoff =3D vb2_ioctl_streamoff, +}; + +/* -----------------------------------------------------------------------= ------ + * Statistics + */ + +static const struct vb2_ops risp_io_stats_qops =3D { + .queue_setup =3D risp_io_queue_setup, + .buf_prepare =3D risp_io_buffer_prepare, + .buf_queue =3D risp_io_buffer_queue, + .start_streaming =3D risp_io_start_streaming, + .stop_streaming =3D risp_io_stop_streaming, +}; + +static const struct v4l2_meta_format risp_io_stats_default_format =3D { + .dataformat =3D V4L2_META_FMT_RK_ISP1_STAT_3A, + .buffersize =3D sizeof(struct rkisp1_stat_buffer), +}; + +static int risp_io_stats_enum_fmt(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + struct rcar_isp_core_io *io =3D video_drvdata(file); + + if (f->type !=3D V4L2_BUF_TYPE_META_CAPTURE || f->index) + return -EINVAL; + + f->pixelformat =3D io->format.fmt.meta.dataformat; + + return 0; +} + +static int risp_io_stats_g_fmt(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct rcar_isp_core_io *io =3D video_drvdata(file); + struct v4l2_meta_format *meta =3D &f->fmt.meta; + + if (f->type !=3D V4L2_BUF_TYPE_META_CAPTURE) + return -EINVAL; + + *meta =3D io->format.fmt.meta; + + return 0; +} + +static int risp_io_stats_s_fmt(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct rcar_isp_core_io *io =3D video_drvdata(file); + + if (vb2_is_busy(&io->queue)) + return -EBUSY; + + return risp_io_stats_g_fmt(file, priv, f); +} + +static const struct v4l2_ioctl_ops risp_io_stats_ioctl_ops =3D { + .vidioc_querycap =3D risp_io_querycap, + + .vidioc_enum_fmt_meta_cap =3D risp_io_stats_enum_fmt, + .vidioc_g_fmt_meta_cap =3D risp_io_stats_g_fmt, + .vidioc_s_fmt_meta_cap =3D risp_io_stats_s_fmt, + .vidioc_try_fmt_meta_cap =3D risp_io_stats_g_fmt, + + .vidioc_reqbufs =3D vb2_ioctl_reqbufs, + .vidioc_querybuf =3D vb2_ioctl_querybuf, + .vidioc_qbuf =3D vb2_ioctl_qbuf, + .vidioc_expbuf =3D vb2_ioctl_expbuf, + .vidioc_dqbuf =3D vb2_ioctl_dqbuf, + .vidioc_create_bufs =3D vb2_ioctl_create_bufs, + .vidioc_prepare_buf =3D vb2_ioctl_prepare_buf, + .vidioc_streamon =3D vb2_ioctl_streamon, + .vidioc_streamoff =3D vb2_ioctl_streamoff, +}; + +/* -----------------------------------------------------------------------= ------ + * Video capture + */ + +static const struct vb2_ops risp_io_capture_qops =3D { + .queue_setup =3D risp_io_queue_setup, + .buf_prepare =3D risp_io_buffer_prepare, + .buf_queue =3D risp_io_buffer_queue, + .start_streaming =3D risp_io_start_streaming, + .stop_streaming =3D risp_io_stop_streaming, +}; + +static const struct v4l2_pix_format_mplane risp_io_capture_default_format = =3D { + .width =3D 1920, + .height =3D 1080, + .pixelformat =3D V4L2_PIX_FMT_XBGR32, + .field =3D V4L2_FIELD_NONE, + .colorspace =3D V4L2_COLORSPACE_DEFAULT, + .ycbcr_enc =3D V4L2_YCBCR_ENC_DEFAULT, + .quantization =3D V4L2_QUANTIZATION_DEFAULT, + .num_planes =3D 1, + .plane_fmt =3D { + [0] =3D { + .bytesperline =3D ALIGN(1920 * 4, 256), + .sizeimage =3D ALIGN(1920 * 4, 256) * 1080, + }, + }, +}; + +static void risp_io_capture_try_format(struct rcar_isp_core_io *io, + struct v4l2_pix_format_mplane *pix) +{ + v4l_bound_align_image(&pix->width, 128, 5120, 2, + &pix->height, 128, 4096, 2, 0); + + pix->field =3D V4L2_FIELD_NONE; + pix->colorspace =3D V4L2_COLORSPACE_DEFAULT; + pix->ycbcr_enc =3D V4L2_YCBCR_ENC_DEFAULT; + pix->quantization =3D V4L2_QUANTIZATION_DEFAULT; + + switch (pix->pixelformat) { + case V4L2_PIX_FMT_NV16M: + pix->num_planes =3D 2; + pix->plane_fmt[0].bytesperline =3D ALIGN(pix->width, 256); + pix->plane_fmt[0].sizeimage =3D pix->plane_fmt[0].bytesperline * pix->he= ight; + pix->plane_fmt[1].bytesperline =3D ALIGN(pix->width, 256); + pix->plane_fmt[1].sizeimage =3D pix->plane_fmt[1].bytesperline * pix->he= ight; + break; + default: + pix->pixelformat =3D V4L2_PIX_FMT_XBGR32; + pix->num_planes =3D 1; + pix->plane_fmt[0].bytesperline =3D ALIGN(pix->width * 4, 256); + pix->plane_fmt[0].sizeimage =3D pix->plane_fmt[0].bytesperline * pix->he= ight; + break; + } +} + +static int risp_io_capture_enum_fmt(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + if (f->type !=3D V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + return -EINVAL; + + switch (f->index) { + case 0: + f->pixelformat =3D V4L2_PIX_FMT_NV16M; + break; + case 1: + f->pixelformat =3D V4L2_PIX_FMT_XBGR32; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int risp_io_capture_g_fmt(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct rcar_isp_core_io *io =3D video_drvdata(file); + + if (f->type !=3D V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + return -EINVAL; + + f->fmt.pix_mp =3D io->format.fmt.pix_mp; + + return 0; +} + +static int risp_io_capture_s_fmt(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct rcar_isp_core_io *io =3D video_drvdata(file); + + if (vb2_is_busy(&io->queue)) + return -EBUSY; + + if (f->type !=3D V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + return -EINVAL; + + risp_io_capture_try_format(io, &f->fmt.pix_mp); + + io->format.fmt.pix_mp =3D f->fmt.pix_mp; + + return 0; +} + +static int risp_io_capture_try_fmt(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct rcar_isp_core_io *io =3D video_drvdata(file); + + risp_io_capture_try_format(io, &f->fmt.pix_mp); + + return 0; +} + +static int risp_io_capture_enum_framesizes(struct file *file, void *fh, + struct v4l2_frmsizeenum *fsize) +{ + if (fsize->index !=3D 0) + return -EINVAL; + + switch (fsize->pixel_format) { + case V4L2_PIX_FMT_NV16M: + case V4L2_PIX_FMT_XBGR32: + break; + default: + return -EINVAL; + } + + fsize->type =3D V4L2_FRMSIZE_TYPE_STEPWISE; + + fsize->stepwise.min_width =3D 128; + fsize->stepwise.max_width =3D 5120; + fsize->stepwise.step_width =3D 2; + + fsize->stepwise.min_height =3D 128; + fsize->stepwise.max_height =3D 4096; + fsize->stepwise.step_height =3D 2; + + return 0; +} + +static const struct v4l2_ioctl_ops risp_io_capture_ioctl_ops =3D { + .vidioc_querycap =3D risp_io_querycap, + + .vidioc_enum_fmt_vid_cap =3D risp_io_capture_enum_fmt, + .vidioc_g_fmt_vid_cap_mplane =3D risp_io_capture_g_fmt, + .vidioc_s_fmt_vid_cap_mplane =3D risp_io_capture_s_fmt, + .vidioc_try_fmt_vid_cap_mplane =3D risp_io_capture_try_fmt, + .vidioc_enum_framesizes =3D risp_io_capture_enum_framesizes, + + .vidioc_reqbufs =3D vb2_ioctl_reqbufs, + .vidioc_querybuf =3D vb2_ioctl_querybuf, + .vidioc_qbuf =3D vb2_ioctl_qbuf, + .vidioc_expbuf =3D vb2_ioctl_expbuf, + .vidioc_dqbuf =3D vb2_ioctl_dqbuf, + .vidioc_create_bufs =3D vb2_ioctl_create_bufs, + .vidioc_prepare_buf =3D vb2_ioctl_prepare_buf, + .vidioc_streamon =3D vb2_ioctl_streamon, + .vidioc_streamoff =3D vb2_ioctl_streamoff, +}; + +/* -----------------------------------------------------------------------= ------ + * Create and remove IO video devices + */ + +int risp_core_io_create(struct device *dev, struct rcar_isp_core *core, + struct rcar_isp_core_io *io, unsigned int pad) +{ + struct video_device *vdev =3D &io->vdev; + struct vb2_queue *q =3D &io->queue; + int ret; + + switch (pad) { + case RISP_CORE_INPUT1: + snprintf(vdev->name, sizeof(vdev->name), "%s %s input1", + KBUILD_MODNAME, dev_name(dev)); + vdev->vfl_dir =3D VFL_DIR_TX; + vdev->device_caps =3D V4L2_CAP_VIDEO_OUTPUT_MPLANE; + vdev->ioctl_ops =3D &risp_io_input_ioctl_ops; + + q->type =3D V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + q->ops =3D &risp_io_input_qops; + + io->pad.flags =3D MEDIA_PAD_FL_SOURCE; + io->format.fmt.pix_mp =3D risp_io_input_default_format; + break; + + case RISP_CORE_PARAMS: + snprintf(vdev->name, sizeof(vdev->name), "%s %s params", + KBUILD_MODNAME, dev_name(dev)); + vdev->vfl_dir =3D VFL_DIR_TX; + vdev->device_caps =3D V4L2_CAP_META_OUTPUT; + vdev->ioctl_ops =3D &risp_io_params_ioctl_ops; + + q->type =3D V4L2_BUF_TYPE_META_OUTPUT; + q->ops =3D &risp_io_params_qops; + + io->pad.flags =3D MEDIA_PAD_FL_SOURCE; + io->format.fmt.meta =3D risp_io_params_default_format; + break; + + case RISP_CORE_STATS: + snprintf(vdev->name, sizeof(vdev->name), "%s %s stats", + KBUILD_MODNAME, dev_name(dev)); + vdev->vfl_dir =3D VFL_DIR_RX; + vdev->device_caps =3D V4L2_CAP_META_CAPTURE; + vdev->ioctl_ops =3D &risp_io_stats_ioctl_ops; + + q->type =3D V4L2_BUF_TYPE_META_CAPTURE; + q->ops =3D &risp_io_stats_qops; + + io->pad.flags =3D MEDIA_PAD_FL_SINK; + io->format.fmt.meta =3D risp_io_stats_default_format; + break; + + case RISP_CORE_OUTPUT1: + snprintf(vdev->name, sizeof(vdev->name), "%s %s output1", + KBUILD_MODNAME, dev_name(dev)); + vdev->vfl_dir =3D VFL_DIR_RX; + vdev->device_caps =3D V4L2_CAP_VIDEO_CAPTURE_MPLANE; + vdev->ioctl_ops =3D &risp_io_capture_ioctl_ops; + + q->type =3D V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + q->ops =3D &risp_io_capture_qops; + + io->pad.flags =3D MEDIA_PAD_FL_SINK; + io->format.fmt.pix_mp =3D risp_io_capture_default_format; + break; + } + + io->core =3D core; + + mutex_init(&io->lock); + INIT_LIST_HEAD(&io->buffers); + + /* Create media graph pad. */ + ret =3D media_entity_pads_init(&io->vdev.entity, 1, &io->pad); + if (ret) + return ret; + + /* Create queue */ + q->io_modes =3D VB2_MMAP | VB2_DMABUF; + q->lock =3D &io->lock; + q->drv_priv =3D io; + q->mem_ops =3D &vb2_dma_contig_memops; + q->buf_struct_size =3D sizeof(struct risp_buffer); + q->timestamp_flags =3D V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->dev =3D dev; + + ret =3D vb2_queue_init(q); + if (ret < 0) { + risp_io_err(io, "Failed to initialize VB2 queue\n"); + return ret; + } + + /* Create video device */ + vdev->v4l2_dev =3D &core->v4l2_dev; + vdev->queue =3D &io->queue; + + vdev->release =3D video_device_release_empty; + vdev->lock =3D &io->lock; + vdev->fops =3D &risp_io_fops; + + vdev->device_caps |=3D V4L2_CAP_STREAMING | V4L2_CAP_IO_MC; + + ret =3D video_register_device(vdev, VFL_TYPE_VIDEO, -1); + if (ret) { + risp_io_err(io, "Failed to register video device\n"); + return ret; + } + + video_set_drvdata(&io->vdev, io); + + v4l2_info(&core->v4l2_dev, "Device registered as %s\n", + video_device_node_name(vdev)); + + switch (pad) { + case RISP_CORE_INPUT1: + case RISP_CORE_PARAMS: + ret =3D media_create_pad_link(&io->vdev.entity, 0, + &core->subdev.entity, pad, + MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE); + break; + case RISP_CORE_STATS: + case RISP_CORE_OUTPUT1: + ret =3D media_create_pad_link(&core->subdev.entity, pad, + &io->vdev.entity, 0, + MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE); + break; + } + + return ret; +} + +void risp_core_io_destory(struct rcar_isp_core_io *io) +{ + if (!video_is_registered(&io->vdev)) + return; + + video_unregister_device(&io->vdev); +} diff --git a/drivers/media/platform/renesas/rcar-isp/core.c b/drivers/media= /platform/renesas/rcar-isp/core.c new file mode 100644 index 000000000000..b63a3234c37b --- /dev/null +++ b/drivers/media/platform/renesas/rcar-isp/core.c @@ -0,0 +1,790 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include + +#include +#include +#include + +#include "risp-core.h" + +#define ISP_CS_STREAMER_MODE_REG 0x7000 +#define ISP_CS_STREAMER_MODE_STREAMER_EN 0xf + +#define ISP_CS_STREAMER_VBLANK_REG 0x7004 +#define ISP_CS_STREAMER_HBLANK_REG 0x7008 + +#define ISP_CS_STREAMER_CONFIG_DMA_CONTROL_REG 0x7100 +#define ISP_CS_STREAMER_CONFIG_DMA_REG_ADDRESS_UPPER_8BIT_MASK GENMASK(31,= 24) +#define ISP_CS_STREAMER_CONFIG_DMA_ENABLE0 BIT(0) + +#define ISP_CS_STREAMER_CONFIG_DMA_CONTROL1_REG 0x2100 +#define ISP_CS_STREAMER_CONFIG_DMA_CONTROL1_ENABLE1 BIT(31) +#define ISP_CS_STREAMER_CONFIG_DMA_CONTROL1_CONFIG_DATA_START_REG_ADDRESS_= MASK GENMASK(15, 0) + +#define ISP_CS_STREAMER_CONFIG_DMA_CONTROL2_REG 0x2104 + +#define ISP_CORE_ISPCORE_INT_STATUS 0x80000 +#define ISP_CORE_ISPCORE_INT_ENABLE 0x80004 +#define ISPCORE_DMA_IMAGE_FRAME_MODE(i, f) (0x84000 + 0x1000 * (i) + = 0x100 * (f)) +#define ISPCORE_DMA_IMAGE_FRAME_PIXEL_POSITION(i, f) (0x84004 + 0x1000= * (i) + 0x100 * (f)) +#define ISPCORE_DMA_IMAGE_FRAME_PIXEL_BITWIDTH_MINUS1(i, f) (0x84008 + 0x1= 000 * (i) + 0x100 * (f)) +#define ISPCORE_DMA_IMAGE_FRAME_PIXEL_BPP(i, f) (0x8400c + 0x1000 * (= i) + 0x100 * (f)) +#define ISPCORE_DMA_IMAGE_FRAME_BASE_ADDRESS_COMP0(i, f) (0x84010 + 0x1= 000 * (i) + 0x100 * (f)) +#define ISPCORE_DMA_IMAGE_FRAME_BASE_ADDRESS_COMP1(i, f) (0x84014 + 0x1= 000 * (i) + 0x100 * (f)) +#define ISPCORE_DMA_IMAGE_FRAME_BASE_ADDRESS_COMP2(i, f) (0x84018 + 0x1= 000 * (i) + 0x100 * (f)) +#define ISPCORE_DMA_IMAGE_FRAME_BASE_ADDRESS_COMP3(i, f) (0x8401c + 0x1= 000 * (i) + 0x100 * (f)) +#define ISPCORE_DMA_IMAGE_FRAME_STRIDE_COMP0(i, f) (0x84020 + 0x1000 *= (i) + 0x100 * (f)) +#define ISPCORE_DMA_IMAGE_FRAME_STRIDE_COMP1(i, f) (0x84024 + 0x1000 *= (i) + 0x100 * (f)) +#define ISPCORE_DMA_IMAGE_FRAME_STRIDE_COMP2(i, f) (0x84028 + 0x1000 *= (i) + 0x100 * (f)) +#define ISPCORE_DMA_IMAGE_FRAME_STRIDE_COMP3(i, f) (0x8402c + 0x1000 *= (i) + 0x100 * (f)) +#define ISPCORE_DMA_IMAGE_FRAME_AXI_ID(i, f) (0x84030 + 0x1000 * (i) = + 0x100 * (f)) + +#define ISPCORE_DMA_IMAGE_FLUSH_OUT_REG(i) (0x84400 + 0x1000 * (i)) +#define ISPCORE_DMA_IMAGE_FLUSH_OUT_PADDING_PIXEL_EOF_MASK GENMASK(31, 16) +#define ISPCORE_DMA_IMAGE_FLUSH_OUT_PADDING_PIXEL_EOF_SHIFT 16 + +#define ISPCORE_DMA_IMAGE_AXI_CONFIG_REG(i) (0x84800 + 0x1000 * (i)) + +static void risp_cs_write(struct rcar_isp_core *core, u32 offset, u32 valu= e) +{ + iowrite32(value, core->csbase + offset); +} + +static u32 risp_cs_read(struct rcar_isp_core *core, u32 offset) +{ + return ioread32(core->csbase + offset); +} + +static void risp_core_write(struct rcar_isp_core *core, u32 offset, u32 va= lue) +{ + iowrite32(value, core->base + offset); +} + +static u32 risp_core_read(struct rcar_isp_core *core, u32 offset) +{ + return ioread32(core->base + offset); +} + +static void risp_core_job_run_params(struct rcar_isp_core *core, + struct vsp1_isp_job_desc *vspx_job, + struct risp_buffer *buf) +{ + u32 *params_buf =3D (u32 *)buf->vsp_buffer.cpu_addr; + bool have_config =3D !!params_buf[0]; + u32 ctrl0, ctrl1, ctrl2; + + /* + * If we have a configuration but not asked the VSPX to programme it, + * use MMIO to write the configuration. This might be needed to work + * around limitations of the VSPX ConfigDMA. + */ + if (have_config && !vspx_job->config.pairs) { + for (unsigned int i =3D 0; i < params_buf[0]; i++) + risp_core_write(core, params_buf[2 + i * 2] & 0xffff, + params_buf[3 + i * 2]); + + /* Disable ConfigDMA. */ + have_config =3D false; + } + + ctrl0 =3D risp_cs_read(core, ISP_CS_STREAMER_CONFIG_DMA_CONTROL_REG) & + ~ISP_CS_STREAMER_CONFIG_DMA_ENABLE0; + ctrl1 =3D risp_cs_read(core, ISP_CS_STREAMER_CONFIG_DMA_CONTROL1_REG) & + ~(ISP_CS_STREAMER_CONFIG_DMA_CONTROL1_ENABLE1 | 0xffff); + ctrl2 =3D 0; + + if (have_config) { + ctrl0 |=3D ISP_CS_STREAMER_CONFIG_DMA_ENABLE0; + ctrl1 |=3D ISP_CS_STREAMER_CONFIG_DMA_CONTROL1_ENABLE1 | + (params_buf[2] & 0xffff); + ctrl2 =3D params_buf[3]; + } + + risp_cs_write(core, ISP_CS_STREAMER_CONFIG_DMA_CONTROL_REG, ctrl0); + risp_cs_write(core, ISP_CS_STREAMER_CONFIG_DMA_CONTROL1_REG, ctrl1); + risp_cs_write(core, ISP_CS_STREAMER_CONFIG_DMA_CONTROL2_REG, ctrl2); +} + +static void risp_core_job_run_output(struct rcar_isp_core *core, + struct risp_buffer *buf) +{ + const struct v4l2_format *fmt =3D &core->io[RISP_CORE_OUTPUT1].format; + dma_addr_t mem; + u32 reg; + + for (unsigned int frame =3D 0; frame < 4; frame++) { + reg =3D ISPCORE_DMA_IMAGE_FRAME_BASE_ADDRESS_COMP0(0, frame); + mem =3D vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0); + risp_core_write(core, reg, mem); + + /* Only NV16 uses 2 planes. */ + if (fmt->fmt.pix_mp.pixelformat !=3D V4L2_PIX_FMT_NV16M) + continue; + + reg =3D ISPCORE_DMA_IMAGE_FRAME_BASE_ADDRESS_COMP1(0, frame); + mem =3D vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 1); + risp_core_write(core, reg, mem); + } +} + +static void risp_core_job_run(struct rcar_isp_core *core) +{ + struct rcar_isp_job *job; + + lockdep_assert_held(&core->lock); + + /* ISP not yet started, nothing to do. */ + if (!core->streaming) + return; + + /* If we have active buffers in the ISP core, nothing to do. */ + if (core->vspx.job) + return; + + job =3D list_first_entry_or_null(&core->risp_jobs, + struct rcar_isp_job, + job_queue); + if (!job) + return; + + list_del(&job->job_queue); + + core->vspx.job =3D job; + + /* Program the ISP register before kicking the VSPX. */ + for (unsigned int i =3D 0; i < RISP_CORE_NUM_PADS; i++) { + struct risp_buffer *buf =3D job->buffers[i]; + + switch (i) { + case RISP_CORE_PARAMS: + risp_core_job_run_params(core, &job->vspx_job, buf); + break; + case RISP_CORE_OUTPUT1: + risp_core_job_run_output(core, buf); + break; + } + } + + if (vsp1_isp_job_run(core->vspx.dev, &job->vspx_job)) { + /* + * Release all buffers in this job if running on the VSPX + * failed. Userspace should recover from this, no new jobs are + * scheduled. + */ + for (unsigned int i =3D 0; i < RISP_CORE_NUM_PADS; i++) { + struct risp_buffer *buf =3D job->buffers[i]; + + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); + } + + vsp1_isp_job_release(core->vspx.dev, &job->vspx_job); + core->vspx.job =3D NULL; + kfree(job); + + dev_err(core->dev, "Failed to run job"); + } +} + +static int risp_core_pixfmt_to_vspx(u32 pixfmt) +{ + switch (pixfmt) { + case V4L2_PIX_FMT_SBGGR8: + case V4L2_PIX_FMT_SGBRG8: + case V4L2_PIX_FMT_SGRBG8: + case V4L2_PIX_FMT_SRGGB8: + return V4L2_PIX_FMT_GREY; + case V4L2_PIX_FMT_SBGGR10: + case V4L2_PIX_FMT_SGBRG10: + case V4L2_PIX_FMT_SGRBG10: + case V4L2_PIX_FMT_SRGGB10: + return V4L2_PIX_FMT_Y10; + case V4L2_PIX_FMT_SBGGR12: + case V4L2_PIX_FMT_SGBRG12: + case V4L2_PIX_FMT_SGRBG12: + case V4L2_PIX_FMT_SRGGB12: + return V4L2_PIX_FMT_Y12; + default: + return -EINVAL; + } +} + +int risp_core_job_prepare(struct rcar_isp_core *core) +{ + struct vsp1_isp_job_desc *vspx_job; + int vspx_pixfmt =3D -EINVAL; + struct rcar_isp_job *job; + int ret; + + lockdep_assert_held(&core->io_lock); + + for (unsigned int i =3D 0; i < RISP_CORE_NUM_PADS; i++) { + if (list_empty(&core->io[i].buffers)) + return 0; + } + + /* Memory is released when the job is consumed. */ + job =3D kzalloc(sizeof(*job), GFP_KERNEL); + if (!job) + return -ENOMEM; + + vspx_job =3D &job->vspx_job; + + for (unsigned int i =3D 0; i < RISP_CORE_NUM_PADS; i++) { + struct risp_buffer *buf; + + /* + * Extract buffer from the IO queue and save a reference in + * the job description. Buffers will be completed when the + * corresponding frame will be completed by the ISP. + */ + buf =3D list_first_entry_or_null(&core->io[i].buffers, + struct risp_buffer, list); + if (!buf) { + ret =3D -EINVAL; + goto error_return_buffers; + } + + switch (i) { + case RISP_CORE_INPUT1: { + u32 isp_pixfmt =3D core->io[i].format.fmt.pix_mp.pixelformat; + + vspx_pixfmt =3D risp_core_pixfmt_to_vspx(isp_pixfmt); + + vspx_job->img.fmt =3D core->io[i].format.fmt.pix_mp; + vspx_job->img.fmt.pixelformat =3D vspx_pixfmt; + vspx_job->img.mem =3D + vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, + 0); + break; + } + case RISP_CORE_PARAMS: { + /* + * Work around undocumented behavior of the ConfigDMA + * interface by using MMIO if 16 or less pairs are to + * be programmed. + * + * Programing 15 or less pairs corrupts the image data + * following the config buffer, programing exactly 16 + * pairs freeze the whole VSPX. + */ + u32 *params_buf =3D (u32 *)buf->vsp_buffer.cpu_addr; + + if (params_buf[0] <=3D 16) { + vspx_job->config.pairs =3D 0; + } else { + vspx_job->config.pairs =3D params_buf[0]; + vspx_job->config.mem =3D buf->vsp_buffer.dma_addr; + } + break; + } + } + + list_del(&buf->list); + job->buffers[i] =3D buf; + } + + if (vspx_pixfmt < 0) { + ret =3D -EINVAL; + goto error_return_buffers; + } + + ret =3D vsp1_isp_job_prepare(core->vspx.dev, &job->vspx_job); + if (ret) + goto error_return_buffers; + + scoped_guard(spinlock_irqsave, &core->lock) { + list_add_tail(&job->job_queue, &core->risp_jobs); + risp_core_job_run(core); + } + + return 0; + +error_return_buffers: + for (unsigned int i =3D 0; i < RISP_CORE_NUM_PADS; i++) { + if (!job->buffers[i]) + continue; + + vb2_buffer_done(&job->buffers[i]->vb.vb2_buf, + VB2_BUF_STATE_ERROR); + } + kfree(job); + return ret; +} + +static int risp_core_config_output(struct rcar_isp_core *core, + unsigned int index, + const struct v4l2_pix_format_mplane *pix) +{ + /* For all frame capture slots. */ + for (unsigned int frame =3D 0; frame < 4; frame++) { + switch (pix->pixelformat) { + case V4L2_PIX_FMT_NV16M: + risp_core_write(core, + ISPCORE_DMA_IMAGE_FRAME_MODE(index, frame), + 1); + risp_core_write(core, + ISPCORE_DMA_IMAGE_FRAME_PIXEL_POSITION(index, frame), + 0 << 24 | 0 << 16 | 4 << 8 | 16 << 0); + risp_core_write(core, + ISPCORE_DMA_IMAGE_FRAME_PIXEL_BITWIDTH_MINUS1(index, frame), + 0 << 24 | 0 << 16 | 7 << 8 | 7 << 0); + risp_core_write(core, + ISPCORE_DMA_IMAGE_FRAME_PIXEL_BPP(index, frame), + 0 << 28 | 0 << 24 | + 0 << 20 | 0 << 16 | + 3 << 12 | 0 << 8 | + 3 << 4 | 0 << 0); + + risp_core_write(core, + ISPCORE_DMA_IMAGE_FRAME_STRIDE_COMP0(index, frame), + pix->plane_fmt[0].bytesperline); + risp_core_write(core, + ISPCORE_DMA_IMAGE_FRAME_STRIDE_COMP1(index, frame), + pix->plane_fmt[0].bytesperline); + break; + case V4L2_PIX_FMT_XBGR32: + risp_core_write(core, + ISPCORE_DMA_IMAGE_FRAME_MODE(index, frame), + 0); + risp_core_write(core, + ISPCORE_DMA_IMAGE_FRAME_PIXEL_POSITION(index, frame), + 0 << 24 | 0 << 16 | 0 << 8 | 0 << 0); + risp_core_write(core, + ISPCORE_DMA_IMAGE_FRAME_PIXEL_BITWIDTH_MINUS1(index, frame), + 0 << 24 | 0 << 16 | 0 << 8 | 23 << 0); + risp_core_write(core, + ISPCORE_DMA_IMAGE_FRAME_PIXEL_BPP(index, frame), + 0 << 28 | 0 << 24 | + 0 << 20 | 0 << 16 | + 0 << 12 | 0 << 8 | + 3 << 4 | 2 << 0); + + risp_core_write(core, + ISPCORE_DMA_IMAGE_FRAME_STRIDE_COMP0(index, frame), + pix->plane_fmt[0].bytesperline); + break; + default: + return -EINVAL; + } + + risp_core_write(core, + ISPCORE_DMA_IMAGE_FRAME_AXI_ID(index, frame), + 0); + } + + /* Set image out flush EOF. */ + risp_core_write(core, ISPCORE_DMA_IMAGE_FLUSH_OUT_REG(index), + pix->plane_fmt[0].bytesperline << + ISPCORE_DMA_IMAGE_FLUSH_OUT_PADDING_PIXEL_EOF_SHIFT); + + /* Enable DMA and set burst length. */ + risp_core_write(core, ISPCORE_DMA_IMAGE_AXI_CONFIG_REG(index), + BIT(31) | 7); + + return 0; +} + +static u32 risp_core_pix2bus(const struct rcar_isp_core_io *io) +{ + switch (io->format.fmt.pix_mp.pixelformat) { + case V4L2_PIX_FMT_SBGGR8: + return MEDIA_BUS_FMT_SBGGR8_1X8; + case V4L2_PIX_FMT_SGBRG8: + return MEDIA_BUS_FMT_SGBRG8_1X8; + case V4L2_PIX_FMT_SGRBG8: + return MEDIA_BUS_FMT_SGRBG8_1X8; + case V4L2_PIX_FMT_SRGGB8: + return MEDIA_BUS_FMT_SRGGB8_1X8; + case V4L2_PIX_FMT_SBGGR10: + return MEDIA_BUS_FMT_SBGGR10_1X10; + case V4L2_PIX_FMT_SGBRG10: + return MEDIA_BUS_FMT_SGBRG10_1X10; + case V4L2_PIX_FMT_SGRBG10: + return MEDIA_BUS_FMT_SGRBG10_1X10; + case V4L2_PIX_FMT_SRGGB10: + return MEDIA_BUS_FMT_SRGGB10_1X10; + case V4L2_PIX_FMT_SBGGR12: + return MEDIA_BUS_FMT_SBGGR12_1X12; + case V4L2_PIX_FMT_SGBRG12: + return MEDIA_BUS_FMT_SGBRG12_1X12; + case V4L2_PIX_FMT_SGRBG12: + return MEDIA_BUS_FMT_SGRBG12_1X12; + case V4L2_PIX_FMT_SRGGB12: + return MEDIA_BUS_FMT_SRGGB12_1X12; + case V4L2_PIX_FMT_XBGR32: + return MEDIA_BUS_FMT_RGB888_1X24; + case V4L2_PIX_FMT_NV16M: + return MEDIA_BUS_FMT_YUYV12_1X24; + default: + return 0; + } +} + +int risp_core_start_streaming(struct rcar_isp_core *core) +{ + struct vsp1_vspx_frame_end vspx_fe =3D {}; + unsigned long flags; + int ret; + + struct v4l2_mbus_framefmt inputfmt =3D { + .width =3D core->io[RISP_CORE_INPUT1].format.fmt.pix_mp.width, + .height =3D core->io[RISP_CORE_INPUT1].format.fmt.pix_mp.height, + .code =3D risp_core_pix2bus(&core->io[RISP_CORE_INPUT1]), + .field =3D V4L2_FIELD_NONE, + .colorspace =3D V4L2_COLORSPACE_RAW, + .ycbcr_enc =3D V4L2_YCBCR_ENC_DEFAULT, + .quantization =3D V4L2_QUANTIZATION_DEFAULT, + .xfer_func =3D V4L2_XFER_FUNC_DEFAULT, + }; + + struct v4l2_mbus_framefmt hvout =3D { + .width =3D core->io[RISP_CORE_OUTPUT1].format.fmt.pix_mp.width, + .height =3D core->io[RISP_CORE_OUTPUT1].format.fmt.pix_mp.height, + .code =3D risp_core_pix2bus(&core->io[RISP_CORE_OUTPUT1]), + .field =3D V4L2_FIELD_NONE, + .colorspace =3D V4L2_COLORSPACE_SRGB, + .ycbcr_enc =3D V4L2_YCBCR_ENC_DEFAULT, + .quantization =3D V4L2_QUANTIZATION_DEFAULT, + .xfer_func =3D V4L2_XFER_FUNC_DEFAULT, + }; + + scoped_guard(mutex, &core->io_lock) { + for (unsigned int i =3D 0; i < RISP_CORE_NUM_PADS; i++) { + if (!core->io[i].streaming) + return false; + } + } + + spin_lock_irqsave(&core->lock, flags); + + if (core->streaming) { + spin_unlock_irqrestore(&core->lock, flags); + return 0; + } + + /* Reset and wait for ISP core to initialize itself. */ + reset_control_reset(core->rstc); + udelay(2000); /* Busy sleep when reset as we hold the spinlock. */ + + risp_core_write(core, ISP_CORE_ISPCORE_INT_ENABLE, 1); + + /* Configure output DMA */ + risp_core_config_output(core, 0, + &core->io[RISP_CORE_OUTPUT1].format.fmt.pix_mp); + + risp_cs_write(core, ISP_CS_STREAMER_VBLANK_REG, inputfmt.width * 25); + risp_cs_write(core, ISP_CS_STREAMER_HBLANK_REG, 64); + + /* Enable ISP Streaming bridge. */ + risp_cs_write(core, ISP_CS_STREAMER_MODE_REG, + ISP_CS_STREAMER_MODE_STREAMER_EN); + + /* Start RPP ISP */ + ret =3D rppx1_start(core->rpp, &inputfmt, &hvout, NULL); + if (ret) { + spin_unlock_irqrestore(&core->lock, flags); + return ret; + } + + core->vspx.job =3D NULL; + core->sequence =3D 0; + core->streaming =3D true; + spin_unlock_irqrestore(&core->lock, flags); + + /* Start VSPX */ + vsp1_isp_start_streaming(core->vspx.dev, &vspx_fe); + + scoped_guard(spinlock_irqsave, &core->lock) { + risp_core_job_run(core); + } + + return 0; +} + +static void risp_core_jobs_release(struct rcar_isp_core *core) +{ + struct rcar_isp_job *job, *tmp; + + job =3D core->vspx.job; + if (job) { + /* + * No need to release the VSPX job has it has been scheduled + * already and it will complete. + * + * Only return buffer and free the job descriptor. + */ + + for (unsigned int i =3D 0; i < RISP_CORE_NUM_PADS; i++) { + struct risp_buffer *buf =3D job->buffers[i]; + + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); + } + + kfree(job); + core->vspx.job =3D NULL; + } + + list_for_each_entry_safe(job, tmp, &core->risp_jobs, job_queue) { + vsp1_isp_job_release(core->vspx.dev, &job->vspx_job); + + for (unsigned int i =3D 0; i < RISP_CORE_NUM_PADS; i++) { + struct risp_buffer *buf =3D job->buffers[i]; + + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); + } + + list_del(&job->job_queue); + kfree(job); + } +} + +void risp_core_stop_streaming(struct rcar_isp_core *core) +{ + /* + * This function releases buffers and jobs: make sure the queues mutex + * is held. + */ + lockdep_assert_held(&core->io_lock); + + scoped_guard(spinlock_irqsave, &core->lock) { + /* + * New jobs might be posted before the ISP is stopped: make sure + * we clear all pending jobs in every call of stop_streaming. + */ + risp_core_jobs_release(core); + + if (!core->streaming) + return; + + rppx1_stop(core->rpp); + risp_cs_write(core, ISP_CS_STREAMER_MODE_REG, 0); + risp_core_write(core, ISP_CORE_ISPCORE_INT_ENABLE, 0); + + core->streaming =3D false; + } + + vsp1_isp_stop_streaming(core->vspx.dev); +} + +static irqreturn_t risp_core_irq(int irq, void *data) +{ + struct rcar_isp_core *core =3D data; + struct rcar_isp_job *job; + u32 status; + + status =3D risp_core_read(core, ISP_CORE_ISPCORE_INT_STATUS); + if (!(status & BIT(0))) + return IRQ_NONE; + + if (!rppx1_interrupt(core->rpp, &status)) + return IRQ_HANDLED; + + guard(spinlock_irqsave)(&core->lock); + + job =3D core->vspx.job; + if (!job) + return IRQ_HANDLED; + + for (unsigned int i =3D 0; i < RISP_CORE_NUM_PADS; i++) { + struct risp_buffer *buf; + + buf =3D job->buffers[i]; + + switch (i) { + case RISP_CORE_STATS: + rppx1_stats_fill_isr(core->rpp, status, + vb2_plane_vaddr(&buf->vb.vb2_buf, 0)); + fallthrough; + case RISP_CORE_OUTPUT1: + case RISP_CORE_INPUT1: + buf->vb.sequence =3D core->sequence; + buf->vb.vb2_buf.timestamp =3D ktime_get_ns(); + fallthrough; + case RISP_CORE_PARAMS: + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE); + break; + } + } + + core->vspx.job =3D NULL; + kfree(job); + + core->sequence++; + + /* Kickoff processing of next frame (if any). */ + risp_core_job_run(core); + + return IRQ_HANDLED; +} + +static const struct v4l2_subdev_ops risp_core_subdev_ops =3D { +}; + +static int risp_core_create_subdev(struct rcar_isp_core *core) +{ + struct v4l2_subdev *subdev =3D &core->subdev; + int ret; + + subdev->owner =3D THIS_MODULE; + subdev->dev =3D core->dev; + v4l2_subdev_init(subdev, &risp_core_subdev_ops); + v4l2_set_subdevdata(subdev, core->dev); + snprintf(subdev->name, sizeof(subdev->name), "%s %s core", + KBUILD_MODNAME, dev_name(core->dev)); + subdev->flags =3D V4L2_SUBDEV_FL_HAS_DEVNODE; + + subdev->entity.function =3D MEDIA_ENT_F_VID_MUX; + + core->pads[RISP_CORE_INPUT1].flags =3D MEDIA_PAD_FL_SINK; + core->pads[RISP_CORE_PARAMS].flags =3D MEDIA_PAD_FL_SINK; + core->pads[RISP_CORE_STATS].flags =3D MEDIA_PAD_FL_SOURCE; + core->pads[RISP_CORE_OUTPUT1].flags =3D MEDIA_PAD_FL_SOURCE; + + ret =3D media_entity_pads_init(&subdev->entity, RISP_CORE_NUM_PADS, + core->pads); + if (ret) + return ret; + + dev_info(core->dev, "Registered ISP core\n"); + + return 0; +} + +int risp_core_registered(struct rcar_isp_core *core, struct v4l2_subdev *s= d) +{ + int ret; + + core->v4l2_dev.mdev =3D sd->v4l2_dev->mdev; + + /* Register ISP Core subdevice. */ + ret =3D v4l2_device_register_subdev(&core->v4l2_dev, &core->subdev); + if (ret) + return ret; + + for (unsigned int i =3D 0; i < RISP_CORE_NUM_PADS; i++) { + ret =3D risp_core_io_create(core->dev, core, &core->io[i], i); + if (ret) + return ret; + } + + return 0; +} + +static int risp_core_probe_resources(struct rcar_isp_core *core, + struct platform_device *pdev) +{ + struct platform_device *vspx; + struct device_node *of_vspx; + struct resource *res; + int ret; + + res =3D platform_get_resource_byname(pdev, IORESOURCE_MEM, "core"); + if (!res) + return -ENODEV; + + core->rppaddr =3D res->start; + core->base =3D devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(core->base)) + return PTR_ERR(core->base); + + ret =3D platform_get_irq_byname(pdev, "core"); + if (ret < 0) + return -ENODEV; + + ret =3D devm_request_irq(&pdev->dev, ret, risp_core_irq, IRQF_SHARED, + KBUILD_MODNAME, core); + if (ret) + return ret; + + core->clk =3D devm_clk_get(&pdev->dev, "core"); + if (IS_ERR(core->clk)) + return -ENODEV; + + core->rstc =3D devm_reset_control_get(&pdev->dev, "core"); + if (IS_ERR(core->rstc)) + return -ENODEV; + + of_vspx =3D of_parse_phandle(pdev->dev.of_node, "renesas,vspx", 0); + if (!of_vspx) + return -ENODEV; + + vspx =3D of_find_device_by_node(of_vspx); + if (!vspx) + return -ENODEV; + + /* Attach to VSP-X */ + core->vspx.dev =3D &vspx->dev; + + ret =3D vsp1_isp_init(&vspx->dev); + if (ret < 0) + return ret; + + /* Attach ro the RPP library + * + * 1. Start and wait for the ISP to startup. + * 2. Attach the RPP library and talk with the RPP ISP. + * 3. Turn off ISP. + * 4. Fail if the RPP is unhappy with the hardware. + */ + ret =3D clk_prepare_enable(core->clk); + if (ret) + return ret; + + usleep_range(2000, 4000); + + core->rpp =3D rppx1_create(core->base); + + clk_disable_unprepare(core->clk); + + if (!core->rpp) + return -ENODEV; + + return 0; +} + +int risp_core_probe(struct rcar_isp_core *core, struct platform_device *pd= ev, + void __iomem *csbase, struct reset_control *csrstc) +{ + int ret; + + core->dev =3D &pdev->dev; + core->csrstc =3D csrstc; + core->csbase =3D csbase; + + ret =3D risp_core_probe_resources(core, pdev); + if (ret) { + core->base =3D 0; + return ret; + } + + ret =3D v4l2_device_register(core->dev, &core->v4l2_dev); + if (ret) + return ret; + + ret =3D risp_core_create_subdev(core); + if (ret) + return ret; + + mutex_init(&core->io_lock); + spin_lock_init(&core->lock); + INIT_LIST_HEAD(&core->risp_jobs); + + return 0; +} + +void risp_core_remove(struct rcar_isp_core *core) +{ + /* If we did not probe the ISP core, nothing to do. */ + if (!core->base) + return; + + dev_info(core->dev, "Remove ISP Core\n"); + + for (unsigned int i =3D 0; i < RISP_CORE_NUM_PADS; i++) + risp_core_io_destory(&core->io[i]); + + mutex_destroy(&core->io_lock); + rppx1_destroy(core->rpp); +} diff --git a/drivers/media/platform/renesas/rcar-isp/csisp.c b/drivers/medi= a/platform/renesas/rcar-isp/csisp.c index 1eb29a0b774a..9d8571916c96 100644 --- a/drivers/media/platform/renesas/rcar-isp/csisp.c +++ b/drivers/media/platform/renesas/rcar-isp/csisp.c @@ -11,14 +11,13 @@ */ =20 #include -#include #include -#include #include -#include =20 #include -#include +#include + +#include "risp-core.h" =20 #define ISPINPUTSEL0_REG 0x0008 #define ISPINPUTSEL0_SEL_CSI0 BIT(31) @@ -161,6 +160,7 @@ struct rcar_isp { struct device *dev; void __iomem *csbase; struct reset_control *rstc; + struct rcar_isp_core core; =20 enum rcar_isp_input csi_input; =20 @@ -454,6 +454,21 @@ static int risp_parse_dt(struct rcar_isp *isp) return ret; } =20 +/* -----------------------------------------------------------------------= ------ + * ISP Core connection + */ + +static int risp_cs_registered(struct v4l2_subdev *sd) +{ + struct rcar_isp *isp =3D sd_to_isp(sd); + + return risp_core_registered(&isp->core, sd); +} + +static const struct v4l2_subdev_internal_ops risp_cs_internal_ops =3D { + .registered =3D risp_cs_registered, +}; + /* -----------------------------------------------------------------------= ------ * Platform Device Driver */ @@ -480,7 +495,7 @@ static int risp_probe_resources(struct rcar_isp *isp, if (IS_ERR(isp->csbase)) return PTR_ERR(isp->csbase); =20 - isp->rstc =3D devm_reset_control_get(&pdev->dev, NULL); + isp->rstc =3D devm_reset_control_get_shared(&pdev->dev, NULL); =20 return PTR_ERR_OR_ZERO(isp->rstc); } @@ -544,14 +559,31 @@ static int risp_probe(struct platform_device *pdev) if (ret) goto error_notifier; =20 - ret =3D v4l2_async_register_subdev(&isp->subdev); - if (ret < 0) + ret =3D risp_core_probe(&isp->core, pdev, isp->csbase, isp->rstc); + switch (ret) { + case 0: + /* The device have an ISP core. */ + isp->subdev.internal_ops =3D &risp_cs_internal_ops; + break; + case -ENODEV: + /* The device don't have an ISP core, that is OK. */ + ret =3D 0; + break; + default: + /* Something went wrong registering the ISP core. */ goto error_subdev; + } + + ret =3D v4l2_async_register_subdev(&isp->subdev); + if (ret < 0) + goto error_core; =20 dev_info(isp->dev, "Using CSI-2 input: %u\n", isp->csi_input); =20 return 0; =20 +error_core: + risp_core_remove(&isp->core); error_subdev: v4l2_subdev_cleanup(&isp->subdev); error_notifier: @@ -567,6 +599,8 @@ static void risp_remove(struct platform_device *pdev) { struct rcar_isp *isp =3D platform_get_drvdata(pdev); =20 + risp_core_remove(&isp->core); + v4l2_async_nf_unregister(&isp->notifier); v4l2_async_nf_cleanup(&isp->notifier); =20 diff --git a/drivers/media/platform/renesas/rcar-isp/risp-core.h b/drivers/= media/platform/renesas/rcar-isp/risp-core.h new file mode 100644 index 000000000000..2bebaf6fbec9 --- /dev/null +++ b/drivers/media/platform/renesas/rcar-isp/risp-core.h @@ -0,0 +1,163 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ + +#ifndef __RCAR_ISP__ +#define __RCAR_ISP__ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +struct rcar_isp_core; + +enum risp_core_pads { + RISP_CORE_INPUT1, + RISP_CORE_PARAMS, + RISP_CORE_STATS, + RISP_CORE_OUTPUT1, + RISP_CORE_NUM_PADS, +}; + +/** + * struct risp_buffer - Describe an IO buffer + * @vb: The VB2 buffer + * @list: List of buffers queued to the IO queue + * @vsp_buffer: Buffer mapped from VSP-X, only used for params IO + */ +struct risp_buffer { + struct vb2_v4l2_buffer vb; + struct list_head list; + struct vsp1_isp_buffer_desc vsp_buffer; +}; + +/** + * struct rcar_isp_core_io - Information for a IO video devices + * @core: Backlink to the common ISP core structure + * + * @lock: Protects @vdev, @pad and @queue + open/close fops + * @vdev: V4L2 video device associated with this IO port + * @pad: Media pad for @vdev + * @queue: VB2 buffers queue for $@vdev + * + * @qlock: Protects @streaming and @buffers + * @streaming: Flag to indicate if device is streaming, or not + * @buffers: List of buffers queued to the device + * + * @format: The active V4L2 format + */ +struct rcar_isp_core_io { + struct rcar_isp_core *core; + + struct mutex lock; + struct video_device vdev; + struct media_pad pad; + struct vb2_queue queue; + + bool streaming; + struct list_head buffers; + + struct v4l2_format format; +}; + +/** + * struct rcar_isp_job - R-Car ISP job description + * + * @buffers: IO buffers that form a job + * @vspx_job: VSPX job description + * @job_queue: list handle + */ +struct rcar_isp_job { + struct risp_buffer *buffers[RISP_CORE_NUM_PADS]; + struct vsp1_isp_job_desc vspx_job; + struct list_head job_queue; +}; + +/** + * struct rcar_isp_job - R-Car ISP job description + * + * @dev: Device reference to VSPX + * @job: Job currently being processed by VSPX + */ +struct rcar_isp_vspx { + struct device *dev; + struct rcar_isp_job *job; +}; + +/** + * struct rcar_isp_core - ISP Core + * @dev: (OF) device + * @rppaddr: Hardware address of the RPP ISP (from OF) + * @clk: The clock for the ISP CORE + * @rstc: The reset for the ISP Core + * @csrstc: The reset for the ISP Channel Selector + * + * @base: MMIO base of the ISP CORE + * @csbase: MMIO base of the ISP CS + * + * @subdev: V4L2 subdevice to represent the ISP CORE + * @pads: Media pad for @subdev + * + * @v4l2_dev: V4L2 device + * @rpp: Handle to the RPP ISP connected to the ISP CORE + * + * @io_lock: Protect io[*].streaming and io[*].buffers + * @io: Array of IO ports to the ISP CORE + * + * @lock: Protects @vspx, @risp_jobs, @sequence and @streaming + * @vspx: Handle to the resources used by VSPX connected to the ISP CORE + * @risp_jobs: Queue of VSPX transfer jobs + * @sequence: V4L2 buffers sequence number + * @streaming: Tracks if the device is streaming + */ +struct rcar_isp_core { + struct device *dev; + + u32 rppaddr; + struct clk *clk; + + struct reset_control *rstc; + struct reset_control *csrstc; + + void __iomem *base; + void __iomem *csbase; + + struct v4l2_subdev subdev; + struct media_pad pads[RISP_CORE_NUM_PADS]; + + struct v4l2_device v4l2_dev; + struct rppx1 *rpp; + + struct mutex io_lock; + struct rcar_isp_core_io io[RISP_CORE_NUM_PADS]; + + spinlock_t lock; + struct rcar_isp_vspx vspx; + struct list_head risp_jobs; + unsigned int sequence; + bool streaming; +}; + +int risp_core_probe(struct rcar_isp_core *core, struct platform_device *pd= ev, + void __iomem *csbase, struct reset_control *csrstc); +void risp_core_remove(struct rcar_isp_core *core); +int risp_core_registered(struct rcar_isp_core *core, struct v4l2_subdev *s= d); + +int risp_core_job_prepare(struct rcar_isp_core *core); + +int risp_core_start_streaming(struct rcar_isp_core *core); +void risp_core_stop_streaming(struct rcar_isp_core *core); + +int risp_core_io_create(struct device *dev, struct rcar_isp_core *core, + struct rcar_isp_core_io *io, unsigned int pad); +void risp_core_io_destory(struct rcar_isp_core_io *io); + +#endif --=20 2.51.0 From nobody Thu Oct 2 14:12:03 2025 Received: from fhigh-b2-smtp.messagingengine.com (fhigh-b2-smtp.messagingengine.com [202.12.124.153]) (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 D242528AB0B; Mon, 15 Sep 2025 17:10:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=202.12.124.153 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757956235; cv=none; b=q4izij3nru9n4pO5SPcQF5spoh8kS0tFRpezpI5+dGgaPGcxGPbqYG25sXTwBFBDMniqQ+Rw6k396bAmgrq5vjNiFoR/gSdR8Jd5wvpkwqLpmE5EGuqsyZliwMYBf62B+C5Jb7AOeIuc3zqxe018slKQVgx5oqf8gDjT3QbSjHQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757956235; c=relaxed/simple; bh=IlvkU3oQXr92gXNs8RTytU0L461IdEPDfJjcijQVydk=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=nHqyD1zMkMEg8Ck6jnt2P2mbKNh4VXnVk5Tqp9UTKQYAhEFh8JWy8/JFOJHIMAzCxlyCuL1EMQSZjT1FOBIMAP0VJ+TYSHdwx6uQl6CmDRTdIxFZTvR6dxF6buozUeJZ5D14K+etb8zaG/MX8NS7/kg3WKIaskgKRaijS68EPMU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=ragnatech.se; spf=pass smtp.mailfrom=ragnatech.se; dkim=pass (2048-bit key) header.d=ragnatech.se header.i=@ragnatech.se header.b=EGEEpYZB; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=CX7UJsJF; arc=none smtp.client-ip=202.12.124.153 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=ragnatech.se Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=ragnatech.se Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=ragnatech.se header.i=@ragnatech.se header.b="EGEEpYZB"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="CX7UJsJF" Received: from phl-compute-05.internal (phl-compute-05.internal [10.202.2.45]) by mailfhigh.stl.internal (Postfix) with ESMTP id BE1357A016F; Mon, 15 Sep 2025 13:10:32 -0400 (EDT) Received: from phl-mailfrontend-01 ([10.202.2.162]) by phl-compute-05.internal (MEProxy); Mon, 15 Sep 2025 13:10:32 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ragnatech.se; h= cc:cc:content-transfer-encoding:content-type:content-type:date :date:from:from:in-reply-to:in-reply-to:message-id:mime-version :references:reply-to:subject:subject:to:to; s=fm3; t=1757956232; x=1758042632; bh=AX1hMc0O9NGrp5fIrm2udEyZxyIIdIT6uKXDroGnSxo=; b= EGEEpYZBDBjV86db07Q1UsfrPclsIc2ZjG/eYdqMT2zYAGddon5gFH5D4GxYJU2L Nfdr16FwDFUGCRKHKwxvpfmfgdl0anJV/YR/IkCzBoipF2iTL3XxDdFk0nH0sOvV kRYw1ffgvGYiV1MSgCvslY5fl63NZzNZ2zTbmSxf9Mm1AJcc9xwSrowZjgcJkIzx hTr80yAaYDYjtSkKlSJMLN1tWsmYZyfKRCtGkVCVHH1DICM6Cu5/gvFhCdcxyBVx T891gxiR9pDKblLZXMdth8b76r93sypDh5ydbzjFEsHTsrgApmGe8Xk+9NaXK8B4 dWiEc5VGrz0uVLHr2XlfwQ== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:content-type:date:date:feedback-id:feedback-id :from:from:in-reply-to:in-reply-to:message-id:mime-version :references:reply-to:subject:subject:to:to:x-me-proxy :x-me-sender:x-me-sender:x-sasl-enc; s=fm1; t=1757956232; x= 1758042632; bh=AX1hMc0O9NGrp5fIrm2udEyZxyIIdIT6uKXDroGnSxo=; b=C X7UJsJFeL4d37Cu6/I7GtoEQ6mJm1U2i1olLOtit+US6uy0evoB/t0nCWdQU/ZFi 3ElDjVNzhARDn3z9jxq3LVZzUshkF7jVL8EX4jfyQoySqEyR5ZaWdvWjNdxNueP1 8ROFWapU8GqOshaCMuoHOBiJC4LCTbVSCVKQeB6kZlcEu7SEPiYyg5T0a10+seGW nLxgj5Rk7ne93u54Uj0pqerwMPuSvoQu9zDJ85F5O+KNm20fqjWOdz9ZZlQp2Bub +Z3S2J3HjslX74sbpKVeQ3VykvQzpgV7096g6tp+aPgzMuFrfxSBT3m10+rrOqn0 gnK5x2FY6xmcFoPNwhb4A== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeeffedrtdeggdefkedvhecutefuodetggdotefrod ftvfcurfhrohhfihhlvgemucfhrghsthforghilhdpuffrtefokffrpgfnqfghnecuuegr ihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmdenucfjug hrpefhvfevufffkffojghfgggtgfesthekredtredtjeenucfhrhhomheppfhikhhlrghs ucfunpguvghrlhhunhguuceonhhikhhlrghsrdhsohguvghrlhhunhguodhrvghnvghsrg hssehrrghgnhgrthgvtghhrdhsvgeqnecuggftrfgrthhtvghrnhepheeigfeuveeutdef hfehgeekvedtleeuueekveefudehhffhjeffgfegffelfeegnecuvehluhhsthgvrhfuih iivgeptdenucfrrghrrghmpehmrghilhhfrhhomhepnhhikhhlrghsrdhsohguvghrlhhu nhgusehrrghgnhgrthgvtghhrdhsvgdpnhgspghrtghpthhtohepjedpmhhouggvpehsmh htphhouhhtpdhrtghpthhtohepmhgthhgvhhgrsgeskhgvrhhnvghlrdhorhhgpdhrtghp thhtohepjhgrtghophhordhmohhnughisehiuggvrghsohhnsghorghrugdrtghomhdprh gtphhtthhopehlrghurhgvnhhtrdhpihhntghhrghrthesihguvggrshhonhgsohgrrhgu rdgtohhmpdhrtghpthhtoheplhhinhhugidqmhgvughirgesvhhgvghrrdhkvghrnhgvlh drohhrghdprhgtphhtthhopehlihhnuhigqdhrvghnvghsrghsqdhsohgtsehvghgvrhdr khgvrhhnvghlrdhorhhgpdhrtghpthhtoheplhhinhhugidqkhgvrhhnvghlsehvghgvrh drkhgvrhhnvghlrdhorhhgpdhrtghpthhtohepnhhikhhlrghsrdhsohguvghrlhhunhgu odhrvghnvghsrghssehrrghgnhgrthgvtghhrdhsvg X-ME-Proxy: Feedback-ID: i80c9496c:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Mon, 15 Sep 2025 13:10:31 -0400 (EDT) From: =?UTF-8?q?Niklas=20S=C3=B6derlund?= To: Mauro Carvalho Chehab , Jacopo Mondi , Laurent Pinchart , linux-media@vger.kernel.org, linux-renesas-soc@vger.kernel.org, linux-kernel@vger.kernel.org Cc: =?UTF-8?q?Niklas=20S=C3=B6derlund?= Subject: [PATCH v2 03/12] media: rppx1: Add support for AWB measurement parameters and statistics Date: Mon, 15 Sep 2025 19:07:34 +0200 Message-ID: <20250915170743.106249-4-niklas.soderlund+renesas@ragnatech.se> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20250915170743.106249-1-niklas.soderlund+renesas@ragnatech.se> References: <20250915170743.106249-1-niklas.soderlund+renesas@ragnatech.se> 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 Extend the RPPX1 driver to parse parameter blocks configuring for the auto white balance measurement window and parameters. As well as producing the measurements as part of a statistics buffer. This is the first ISP algorithm added to the RPPX1 driver and exercises both the parameter and statistics API provided by the base driver. It shows how the RkISP1 parameter and statistics buffer data can be scaled and adopted to fit the RPPX1 hardware. It also uses the parameter writing interface which allows the framework user to specify how (and when) the configuration are applied to the RPPX1. As the RkISP1 parameters and statics buffers have lower precision then the RPPX1 hardware the values needs to be scaled. Signed-off-by: Niklas S=C3=B6derlund --- .../platform/dreamchip/rppx1/rpp_params.c | 3 + .../platform/dreamchip/rppx1/rpp_stats.c | 4 + .../platform/dreamchip/rppx1/rppx1_wbmeas.c | 127 ++++++++++++++++++ 3 files changed, 134 insertions(+) diff --git a/drivers/media/platform/dreamchip/rppx1/rpp_params.c b/drivers/= media/platform/dreamchip/rppx1/rpp_params.c index 0bed0ee9d6f8..eb57f52ed676 100644 --- a/drivers/media/platform/dreamchip/rppx1/rpp_params.c +++ b/drivers/media/platform/dreamchip/rppx1/rpp_params.c @@ -24,6 +24,9 @@ int rppx1_params_rkisp1(struct rppx1 *rpp, struct rkisp1_= ext_params_cfg *cfg, block_offset +=3D block->header.size; =20 switch (block->header.type) { + case RKISP1_EXT_PARAMS_BLOCK_TYPE_AWB_MEAS: + module =3D &rpp->post.wbmeas; + break; default: module =3D NULL; break; diff --git a/drivers/media/platform/dreamchip/rppx1/rpp_stats.c b/drivers/m= edia/platform/dreamchip/rppx1/rpp_stats.c index a5daa28e09cf..a6abb85f0df1 100644 --- a/drivers/media/platform/dreamchip/rppx1/rpp_stats.c +++ b/drivers/media/platform/dreamchip/rppx1/rpp_stats.c @@ -11,5 +11,9 @@ void rppx1_stats_fill_isr(struct rppx1 *rpp, u32 isc, voi= d *buf) struct rkisp1_stat_buffer *stats =3D buf; =20 stats->meas_type =3D 0; + + if (isc & RPPX1_IRQ_ID_POST_AWB_MEAS) + if (!rpp_module_call(&rpp->post.wbmeas, stats_rkisp1, &stats->params)) + stats->meas_type |=3D RKISP1_CIF_ISP_STAT_AWB; } EXPORT_SYMBOL_GPL(rppx1_stats_fill_isr); diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_wbmeas.c b/driver= s/media/platform/dreamchip/rppx1/rppx1_wbmeas.c index 3d197d914d07..126972cfd57a 100644 --- a/drivers/media/platform/dreamchip/rppx1/rppx1_wbmeas.c +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_wbmeas.c @@ -56,6 +56,133 @@ static int rppx1_wbmeas_probe(struct rpp_module *mod) return 0; } =20 +static int +rppx1_wbmeas_param_rkisp1(struct rpp_module *mod, + const union rppx1_params_rkisp1_config *block, + rppx1_reg_write write, void *priv) +{ + const struct rkisp1_ext_params_awb_meas_config *cfg =3D &block->awbm; + /* + * The RkISP params are 8-bit while the RPP can be 8, 20 or 24 bit. + * Figure out how much we need to adjust the input parameters. + */ + const unsigned int shift =3D mod->info.wbmeas.colorbits - 8; + + /* If the modules is disabled, simply bypass it. */ + if (cfg->header.flags & RKISP1_EXT_PARAMS_FL_BLOCK_DISABLE) { + write(priv, mod->base + AWB_MEAS_PROP_REG, 0); + return 0; + } + + /* Program measurement window. */ + write(priv, mod->base + AWB_MEAS_H_OFFS_REG, + cfg->config.awb_wnd.h_offs); + write(priv, mod->base + AWB_MEAS_V_OFFS_REG, + cfg->config.awb_wnd.v_offs); + write(priv, mod->base + AWB_MEAS_H_SIZE_REG, + cfg->config.awb_wnd.h_size); + write(priv, mod->base + AWB_MEAS_V_SIZE_REG, + cfg->config.awb_wnd.v_size); + + /* Set number of frames to sample. */ + write(priv, mod->base + AWB_MEAS_FRAMES_REG, cfg->config.frames); + + if (cfg->config.awb_mode =3D=3D RKISP1_CIF_ISP_AWB_MODE_YCBCR) { + write(priv, mod->base + AWB_MEAS_REF_CB_MAX_B_REG, + cfg->config.awb_ref_cb << shift); + write(priv, mod->base + AWB_MEAS_REF_CR_MAX_R_REG, + cfg->config.awb_ref_cr << shift); + write(priv, mod->base + AWB_MEAS_MAX_Y_REG, + cfg->config.max_y << shift); + write(priv, mod->base + AWB_MEAS_MIN_Y_MAX_G_REG, + cfg->config.min_y << shift); + write(priv, mod->base + AWB_MEAS_MAX_CSUM_REG, + cfg->config.max_csum << shift); + write(priv, mod->base + AWB_MEAS_MIN_C_REG, + cfg->config.min_c << shift); + + /* + * Match RkISP1 conversion, documented as + * Y =3D 16 + 0.2500 R + 0.5000 G + 0.1094 B + * Cb =3D 128 - 0.1406 R - 0.2969 G + 0.4375 B + * Cr =3D 128 + 0.4375 R - 0.3750 G - 0.0625 B + * + * Note map Y to G. Matrix is GBR, not RGB documented for RPPX1. + */ + write(priv, mod->base + AWB_MEAS_CCOR_COEFF_REG(0), 0x0800); + write(priv, mod->base + AWB_MEAS_CCOR_COEFF_REG(1), 0x01c0); + write(priv, mod->base + AWB_MEAS_CCOR_COEFF_REG(2), 0x0400); + write(priv, mod->base + AWB_MEAS_CCOR_COEFF_REG(3), 0xfb40); + write(priv, mod->base + AWB_MEAS_CCOR_COEFF_REG(4), 0x0700); + write(priv, mod->base + AWB_MEAS_CCOR_COEFF_REG(5), 0xfdc0); + write(priv, mod->base + AWB_MEAS_CCOR_COEFF_REG(6), 0xfa00); + write(priv, mod->base + AWB_MEAS_CCOR_COEFF_REG(7), 0xff00); + write(priv, mod->base + AWB_MEAS_CCOR_COEFF_REG(8), 0x0700); + + write(priv, mod->base + AWB_MEAS_CCOR_OFFSET_R_REG, 0x00100000); + write(priv, mod->base + AWB_MEAS_CCOR_OFFSET_G_REG, 0x00800000); + write(priv, mod->base + AWB_MEAS_CCOR_OFFSET_B_REG, 0x00800000); + + write(priv, mod->base + AWB_MEAS_PROP_REG, + cfg->config.enable_ymax_cmp ? AWB_MEAS_PROP_YMAX : 0 | + AWB_MEAS_PROP_AWB_MODE_ON); + } else { + /* The RkISP params are oddly named, but do map to RGB. */ + write(priv, mod->base + AWB_MEAS_REF_CB_MAX_B_REG, + cfg->config.awb_ref_cb << shift); + write(priv, mod->base + AWB_MEAS_REF_CR_MAX_R_REG, + cfg->config.awb_ref_cr << shift); + write(priv, mod->base + AWB_MEAS_MIN_Y_MAX_G_REG, + cfg->config.min_y << shift); + + /* Values from datasheet to map G to Y, B to Cb and R to Cr. */ + write(priv, mod->base + AWB_MEAS_CCOR_COEFF_REG(0), 0x1000); + write(priv, mod->base + AWB_MEAS_CCOR_COEFF_REG(1), 0x0000); + write(priv, mod->base + AWB_MEAS_CCOR_COEFF_REG(2), 0x0000); + write(priv, mod->base + AWB_MEAS_CCOR_COEFF_REG(3), 0x0000); + write(priv, mod->base + AWB_MEAS_CCOR_COEFF_REG(4), 0x1000); + write(priv, mod->base + AWB_MEAS_CCOR_COEFF_REG(5), 0x0000); + write(priv, mod->base + AWB_MEAS_CCOR_COEFF_REG(6), 0x0000); + write(priv, mod->base + AWB_MEAS_CCOR_COEFF_REG(7), 0x0000); + write(priv, mod->base + AWB_MEAS_CCOR_COEFF_REG(8), 0x1000); + + /* Values from datasheet. */ + write(priv, mod->base + AWB_MEAS_CCOR_OFFSET_R_REG, 0x00000000); + write(priv, mod->base + AWB_MEAS_CCOR_OFFSET_G_REG, 0x00000000); + write(priv, mod->base + AWB_MEAS_CCOR_OFFSET_B_REG, 0x00000000); + + write(priv, mod->base + AWB_MEAS_PROP_REG, + AWB_MEAS_PROP_MEAS_MODE_RGB | + AWB_MEAS_PROP_AWB_MODE_ON); + } + + return 0; +} + +static int rppx1_wbmeas_stats_rkisp1(struct rpp_module *mod, + struct rkisp1_cif_isp_stat *stats) +{ + struct rkisp1_cif_isp_awb_meas *meas =3D &stats->awb.awb_mean[0]; + /* + * The RkISP YCbCr/RGB mean stats are 8-bit while the RPP can be 8, 20 + * or 24 bit. Figure out how much we need to adjust the output + * statistics. + */ + const unsigned int shift =3D mod->info.wbmeas.colorbits - 8; + + meas->cnt =3D rpp_module_read(mod, AWB_MEAS_WHITE_CNT_REG); + meas->mean_y_or_g =3D + rpp_module_read(mod, AWB_MEAS_MEAN_Y_G_REG) >> shift; + meas->mean_cb_or_b =3D + rpp_module_read(mod, AWB_MEAS_MEAN_CB_B_REG) >> shift; + meas->mean_cr_or_r =3D + rpp_module_read(mod, AWB_MEAS_MEAN_CR_R_REG) >> shift; + + return 0; +} + const struct rpp_module_ops rppx1_wbmeas_ops =3D { .probe =3D rppx1_wbmeas_probe, + .param_rkisp1 =3D rppx1_wbmeas_param_rkisp1, + .stats_rkisp1 =3D rppx1_wbmeas_stats_rkisp1 }; --=20 2.51.0 From nobody Thu Oct 2 14:12:03 2025 Received: from fhigh-b2-smtp.messagingengine.com (fhigh-b2-smtp.messagingengine.com [202.12.124.153]) (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 2778E298CDE; Mon, 15 Sep 2025 17:10:35 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=202.12.124.153 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757956238; cv=none; b=iNEyLZ1RCFaDvqxSTukvLSq0a1ij/dMmuOaz0eMMIOpe8Oi4i+IEsUxaWE+eqNmhPVOXFWtkM0hIJ6IhhHqZTmWY4b6QRsEtiqTqpmaD8IQZSw3ERVXMm9xSYYzHSzc9DLwlKJ0vAHRPfh1mA5d2Y25IDNLBAEyboyz1CQEAcKw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757956238; c=relaxed/simple; bh=7e8egqOCImb/lkbKUKmWkumHv+x7xMYjt96QOTqzmw8=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=VfkXL50+tvO3MWzP1t0+YFEutbh1PO5YCSEuWR30EAfFHD37soZtx8WvAnEQdw0zWImPDH18LTFe1RZt0Csq1t7/sUKQR6Bb4C0xJz3zq0pBMaGqUUAamG8oa5z+QgNd7YqFd0oXtt6rXUCHc06ZxQ/X5u7vfdjtHnuvOPxfaHA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=ragnatech.se; spf=pass smtp.mailfrom=ragnatech.se; dkim=pass (2048-bit key) header.d=ragnatech.se header.i=@ragnatech.se header.b=EW98RY+X; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=EPb9HwUb; arc=none smtp.client-ip=202.12.124.153 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=ragnatech.se Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=ragnatech.se Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=ragnatech.se header.i=@ragnatech.se header.b="EW98RY+X"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="EPb9HwUb" Received: from phl-compute-02.internal (phl-compute-02.internal [10.202.2.42]) by mailfhigh.stl.internal (Postfix) with ESMTP id 0CD797A0176; Mon, 15 Sep 2025 13:10:35 -0400 (EDT) Received: from phl-mailfrontend-02 ([10.202.2.163]) by phl-compute-02.internal (MEProxy); Mon, 15 Sep 2025 13:10:35 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ragnatech.se; h= cc:cc:content-transfer-encoding:content-type:content-type:date :date:from:from:in-reply-to:in-reply-to:message-id:mime-version :references:reply-to:subject:subject:to:to; s=fm3; t=1757956234; x=1758042634; bh=d90jod6/y/Dq0GiewWRppCVVjIn1oL7yf1PbO8vM+UA=; b= EW98RY+XIFgMgR+9gpTl/0r+4W8fmj6GkxHxgA9wHucji6QNTmO5Z6zxK6x3V3R4 2yALT843LAjdzKtP9uGCAG6a3QVShpDsAdRRZqTIbiSGAV/QE3NlBYu1XKq5Ixm9 lmXPQU37Y0kG/u+FSRsQlkVNR/0c3MiZWLQDPj//CRIVk7nhRXZ5Lk7y3PeZ/aB0 ps42QXhrhMoerJjvD/qDr54bqi9B1jJ7zWPJcb6QbdByykhFsE6b9jij0NZFL0af aVqWqcEmk9ygwd/O6Ijq4yU9NDYJ4BBNk8CFdQ/NTyvC/57KAfQ/tU6YVNEqLCl2 DTsaMXieKHDNlWsA+ho7Fw== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:content-type:date:date:feedback-id:feedback-id :from:from:in-reply-to:in-reply-to:message-id:mime-version :references:reply-to:subject:subject:to:to:x-me-proxy :x-me-sender:x-me-sender:x-sasl-enc; s=fm1; t=1757956234; x= 1758042634; bh=d90jod6/y/Dq0GiewWRppCVVjIn1oL7yf1PbO8vM+UA=; b=E Pb9HwUbJBHm5DgiIECTjjSzpMrxoRq4BK1g48uWesUkUMcrJ5ISrR8yDs/db6c/i kCkQ8NwnnJlZ75V7yHyrIPaG1ShBoNMlxoRIvbe/AFzpk4hpYA8coaDC0m6AqJ21 gxGyX+Kzg+Q6yW4eKdGovFR35fgz9xwIX5iQlNpjGTqv3ceZQLsbZ0ZxSS5L7K3G GidOV49SaXYZ1Cs1hBcOgyVdmCAXQ9lC/f1ZfdIyK4xGNfNnaXksMt66JCRBVacK 8OkWwyCB6a3f4kC7yiz3UAl2hAp+bDcEfY3AB4XqyO+1Gh+RHkNjOMHY2V7W6Lfe fjQhLKr4SPTVetdFA54aA== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeeffedrtdeggdefkedviecutefuodetggdotefrod ftvfcurfhrohhfihhlvgemucfhrghsthforghilhdpuffrtefokffrpgfnqfghnecuuegr ihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmdenucfjug hrpefhvfevufffkffojghfgggtgfesthekredtredtjeenucfhrhhomheppfhikhhlrghs ucfunpguvghrlhhunhguuceonhhikhhlrghsrdhsohguvghrlhhunhguodhrvghnvghsrg hssehrrghgnhgrthgvtghhrdhsvgeqnecuggftrfgrthhtvghrnhepheeigfeuveeutdef hfehgeekvedtleeuueekveefudehhffhjeffgfegffelfeegnecuvehluhhsthgvrhfuih iivgeptdenucfrrghrrghmpehmrghilhhfrhhomhepnhhikhhlrghsrdhsohguvghrlhhu nhgusehrrghgnhgrthgvtghhrdhsvgdpnhgspghrtghpthhtohepjedpmhhouggvpehsmh htphhouhhtpdhrtghpthhtohepmhgthhgvhhgrsgeskhgvrhhnvghlrdhorhhgpdhrtghp thhtohepjhgrtghophhordhmohhnughisehiuggvrghsohhnsghorghrugdrtghomhdprh gtphhtthhopehlrghurhgvnhhtrdhpihhntghhrghrthesihguvggrshhonhgsohgrrhgu rdgtohhmpdhrtghpthhtoheplhhinhhugidqmhgvughirgesvhhgvghrrdhkvghrnhgvlh drohhrghdprhgtphhtthhopehlihhnuhigqdhrvghnvghsrghsqdhsohgtsehvghgvrhdr khgvrhhnvghlrdhorhhgpdhrtghpthhtoheplhhinhhugidqkhgvrhhnvghlsehvghgvrh drkhgvrhhnvghlrdhorhhgpdhrtghpthhtohepnhhikhhlrghsrdhsohguvghrlhhunhgu odhrvghnvghsrghssehrrghgnhgrthgvtghhrdhsvg X-ME-Proxy: Feedback-ID: i80c9496c:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Mon, 15 Sep 2025 13:10:34 -0400 (EDT) From: =?UTF-8?q?Niklas=20S=C3=B6derlund?= To: Mauro Carvalho Chehab , Jacopo Mondi , Laurent Pinchart , linux-media@vger.kernel.org, linux-renesas-soc@vger.kernel.org, linux-kernel@vger.kernel.org Cc: =?UTF-8?q?Niklas=20S=C3=B6derlund?= Subject: [PATCH v2 04/12] media: rppx1: Add support for AWB gain settings Date: Mon, 15 Sep 2025 19:07:35 +0200 Message-ID: <20250915170743.106249-5-niklas.soderlund+renesas@ragnatech.se> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20250915170743.106249-1-niklas.soderlund+renesas@ragnatech.se> References: <20250915170743.106249-1-niklas.soderlund+renesas@ragnatech.se> 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 Extend the RPPX1 driver to allow setting the AWB gains using the RkISP1 parameter buffer format. This is the second function block inside the RPPX1 to be enabled and it uses the RPPX1 framework for parameters and its writer abstraction to allow the user to control how (and when) configuration is applied to the RPPX1. As the RkISP1 parameters buffer have lower precision then the RPPX1 hardware the values needs to be scaled. Signed-off-by: Niklas S=C3=B6derlund --- .../platform/dreamchip/rppx1/rpp_params.c | 3 ++ .../platform/dreamchip/rppx1/rppx1_awbg.c | 37 +++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/drivers/media/platform/dreamchip/rppx1/rpp_params.c b/drivers/= media/platform/dreamchip/rppx1/rpp_params.c index eb57f52ed676..a561c01bda9a 100644 --- a/drivers/media/platform/dreamchip/rppx1/rpp_params.c +++ b/drivers/media/platform/dreamchip/rppx1/rpp_params.c @@ -24,6 +24,9 @@ int rppx1_params_rkisp1(struct rppx1 *rpp, struct rkisp1_= ext_params_cfg *cfg, block_offset +=3D block->header.size; =20 switch (block->header.type) { + case RKISP1_EXT_PARAMS_BLOCK_TYPE_AWB_GAIN: + module =3D &rpp->pre1.awbg; + break; case RKISP1_EXT_PARAMS_BLOCK_TYPE_AWB_MEAS: module =3D &rpp->post.wbmeas; break; diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_awbg.c b/drivers/= media/platform/dreamchip/rppx1/rppx1_awbg.c index e20bc369ca8c..da5ae3cfadb8 100644 --- a/drivers/media/platform/dreamchip/rppx1/rppx1_awbg.c +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_awbg.c @@ -25,6 +25,43 @@ static int rppx1_awbg_probe(struct rpp_module *mod) return 0; } =20 +static int +rppx1_awbg_param_rkisp1(struct rpp_module *mod, + const union rppx1_params_rkisp1_config *block, + rppx1_reg_write write, void *priv) +{ + const struct rkisp1_ext_params_awb_gain_config *cfg =3D &block->awbg; + + /* If the modules is disabled, simply bypass it. */ + if (cfg->header.flags & RKISP1_EXT_PARAMS_FL_BLOCK_DISABLE) { + write(priv, mod->base + AWB_ENABLE_REG, 0); + return 0; + } + + /* + * RkISP1 gains are 10-bit with 8 bit fractional part and 0x100 =3D 1.0, + * giving a possible range of 0.0 to 4.0. + * + * RPP gains are 18-bit with 12 bit fractional part and 0x1000 =3D 1.0, + * giving a possible range of 0.0 to 64.0. NOTE: RPP documentation is + * contradictory this is the register definition, the function + * description states 0x400 =3D 1.0 AND 18-bit with 12 fractional bits, + * which is not possible... + * + * Map the RkISP1 value range (0.0 - 4.0) by left shifting by 4. + */ + + write(priv, mod->base + AWB_GAIN_GR_REG, cfg->config.gain_green_r << 4); + write(priv, mod->base + AWB_GAIN_GB_REG, cfg->config.gain_green_b << 4); + write(priv, mod->base + AWB_GAIN_R_REG, cfg->config.gain_red << 4); + write(priv, mod->base + AWB_GAIN_B_REG, cfg->config.gain_blue << 4); + + write(priv, mod->base + AWB_ENABLE_REG, AWB_ENABLE_AWB_GAIN_EN); + + return 0; +} + const struct rpp_module_ops rppx1_awbg_ops =3D { .probe =3D rppx1_awbg_probe, + .param_rkisp1 =3D rppx1_awbg_param_rkisp1, }; --=20 2.51.0 From nobody Thu Oct 2 14:12:03 2025 Received: from fhigh-b2-smtp.messagingengine.com (fhigh-b2-smtp.messagingengine.com [202.12.124.153]) (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 799102BDC2A; Mon, 15 Sep 2025 17:10:38 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=202.12.124.153 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757956240; cv=none; b=l3xTnIy5ECEUjEYGCW/S3ryfJAKFuvCovDOCYn+9XUDp0/L0zV0JR1R9/SH/8tJm/Dbv8ky411Fq06uN2ptJt8R3/ZdePjHNHDwno6TGDLGi3o4ALgVDA4BieP9n7+FkiwnywJwdvdm/Bw2xvBHmJTisg9GUEe+oZXkXEUXYtNM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757956240; c=relaxed/simple; bh=W23WvG6i/eXMgyq45Wiam5ZNV3mhM9OYpsBzb1xe04U=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=qz5CUjMvy+oJGrJpGoeiuJsnu2OpLdWiDQa26SMjcagEEKXTrrqQEPxzRnuUYcgi5S/omaIW2ljRhTXL9JblDwSBzwt2AVaUgsaEBNClnafxxZaHzSRw0XQ7gz3pW/Gk3fAmqbfkNP/XbyhHUB2xsvVxsE7hd/PQocnwXUuaViY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=ragnatech.se; spf=pass smtp.mailfrom=ragnatech.se; dkim=pass (2048-bit key) header.d=ragnatech.se header.i=@ragnatech.se header.b=llvArw2V; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=aOBWhdI8; arc=none smtp.client-ip=202.12.124.153 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=ragnatech.se Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=ragnatech.se Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=ragnatech.se header.i=@ragnatech.se header.b="llvArw2V"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="aOBWhdI8" Received: from phl-compute-08.internal (phl-compute-08.internal [10.202.2.48]) by mailfhigh.stl.internal (Postfix) with ESMTP id 567437A016C; Mon, 15 Sep 2025 13:10:37 -0400 (EDT) Received: from phl-mailfrontend-01 ([10.202.2.162]) by phl-compute-08.internal (MEProxy); Mon, 15 Sep 2025 13:10:37 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ragnatech.se; h= cc:cc:content-transfer-encoding:content-type:content-type:date :date:from:from:in-reply-to:in-reply-to:message-id:mime-version :references:reply-to:subject:subject:to:to; s=fm3; t=1757956237; x=1758042637; bh=xuDFp1RtM2AFEnQwJl6rEVVX3JlEN/BoW+rZvEASSyY=; b= llvArw2VrN1DGSTrQFB+sVIhUxGQT4XX2zOGEX0lyxJHQkeLRbGS3a48OFjyg+bT ohDuN0gCxJ+57E+dwjMC8SJ/CVsPNo3FTvJijLW/19cPBSsX9OGYeUo7dP661Dt2 mM/bClFA1H+++MeGD3k3Ms4dEIAtrEpx1spi/FxJnf67bq2BebaspVds+FUG1rRl i2HABv6kWhNcuG/xXm7zZtA1PGxn/3zjkuHks9UbPMNwa9afT6a3wtnupd9fyFYk o3VrGiv82Vyr+1CrHBYM3hOMDNOU4BWl1EHC9QbE/5nYTzuIovCS4PSu3JXAfMk/ OOTGvmZD/MLbbho8hGT7MQ== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:content-type:date:date:feedback-id:feedback-id :from:from:in-reply-to:in-reply-to:message-id:mime-version :references:reply-to:subject:subject:to:to:x-me-proxy :x-me-sender:x-me-sender:x-sasl-enc; s=fm1; t=1757956237; x= 1758042637; bh=xuDFp1RtM2AFEnQwJl6rEVVX3JlEN/BoW+rZvEASSyY=; b=a OBWhdI8eQZ8vEmOdU+g2+Tx3HBgbp43IU7KE97zYA9NO9SeBPaJRBoGWFHdEuXke ZjeOSXgcHLTrH4N8Fw9prUcu17H+WlfWO+zvryNUouFUcA0zHH6G1gfRDi0HsJ48 +cYB+JEvZ4XPIUzydpdspaAZrnYKBVXwTX+MQXt3hS+6nn9ThN3FSUDokG4HICMO QFlQk6nqynVDCuDbjSMlw/ZcuzA1wNORkjjHCFxqQMTs1PgPiZVO2Drs1p+rh79f Uum/HrifQN1Kdh+TgkCE09zyuGyvrNL8tqLUOnBGquZoGJnd2BpE1pIrLmPXL/JR zzcm9NohqC8FREX2PmiHw== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeeffedrtdeggdefkedvhecutefuodetggdotefrod ftvfcurfhrohhfihhlvgemucfhrghsthforghilhdpuffrtefokffrpgfnqfghnecuuegr ihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmdenucfjug hrpefhvfevufffkffojghfgggtgfesthekredtredtjeenucfhrhhomheppfhikhhlrghs ucfunpguvghrlhhunhguuceonhhikhhlrghsrdhsohguvghrlhhunhguodhrvghnvghsrg hssehrrghgnhgrthgvtghhrdhsvgeqnecuggftrfgrthhtvghrnhepheeigfeuveeutdef hfehgeekvedtleeuueekveefudehhffhjeffgfegffelfeegnecuvehluhhsthgvrhfuih iivgeptdenucfrrghrrghmpehmrghilhhfrhhomhepnhhikhhlrghsrdhsohguvghrlhhu nhgusehrrghgnhgrthgvtghhrdhsvgdpnhgspghrtghpthhtohepjedpmhhouggvpehsmh htphhouhhtpdhrtghpthhtohepmhgthhgvhhgrsgeskhgvrhhnvghlrdhorhhgpdhrtghp thhtohepjhgrtghophhordhmohhnughisehiuggvrghsohhnsghorghrugdrtghomhdprh gtphhtthhopehlrghurhgvnhhtrdhpihhntghhrghrthesihguvggrshhonhgsohgrrhgu rdgtohhmpdhrtghpthhtoheplhhinhhugidqmhgvughirgesvhhgvghrrdhkvghrnhgvlh drohhrghdprhgtphhtthhopehlihhnuhigqdhrvghnvghsrghsqdhsohgtsehvghgvrhdr khgvrhhnvghlrdhorhhgpdhrtghpthhtoheplhhinhhugidqkhgvrhhnvghlsehvghgvrh drkhgvrhhnvghlrdhorhhgpdhrtghpthhtohepnhhikhhlrghsrdhsohguvghrlhhunhgu odhrvghnvghsrghssehrrghgnhgrthgvtghhrdhsvg X-ME-Proxy: Feedback-ID: i80c9496c:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Mon, 15 Sep 2025 13:10:36 -0400 (EDT) From: =?UTF-8?q?Niklas=20S=C3=B6derlund?= To: Mauro Carvalho Chehab , Jacopo Mondi , Laurent Pinchart , linux-media@vger.kernel.org, linux-renesas-soc@vger.kernel.org, linux-kernel@vger.kernel.org Cc: =?UTF-8?q?Niklas=20S=C3=B6derlund?= Subject: [PATCH v2 05/12] media: rppx1: Add support for Auto Exposure Measurement Date: Mon, 15 Sep 2025 19:07:36 +0200 Message-ID: <20250915170743.106249-6-niklas.soderlund+renesas@ragnatech.se> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20250915170743.106249-1-niklas.soderlund+renesas@ragnatech.se> References: <20250915170743.106249-1-niklas.soderlund+renesas@ragnatech.se> 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 Extend the RPPX1 driver to allow setting the EXM configuration using the RkISP1 parameter buffer format. It uses the RPPX1 framework for parameters and its writer abstraction to allow the user to control how (and when) configuration is applied to the RPPX1. As the RkISP1 parameters buffer have lower precision then the RPPX1 hardware the values needs to be scaled. The behavior matches the RkISP1 hardware. Signed-off-by: Niklas S=C3=B6derlund --- .../platform/dreamchip/rppx1/rpp_params.c | 3 + .../platform/dreamchip/rppx1/rpp_stats.c | 4 + .../platform/dreamchip/rppx1/rppx1_exm.c | 89 +++++++++++++++++++ 3 files changed, 96 insertions(+) diff --git a/drivers/media/platform/dreamchip/rppx1/rpp_params.c b/drivers/= media/platform/dreamchip/rppx1/rpp_params.c index a561c01bda9a..bff525970478 100644 --- a/drivers/media/platform/dreamchip/rppx1/rpp_params.c +++ b/drivers/media/platform/dreamchip/rppx1/rpp_params.c @@ -30,6 +30,9 @@ int rppx1_params_rkisp1(struct rppx1 *rpp, struct rkisp1_= ext_params_cfg *cfg, case RKISP1_EXT_PARAMS_BLOCK_TYPE_AWB_MEAS: module =3D &rpp->post.wbmeas; break; + case RKISP1_EXT_PARAMS_BLOCK_TYPE_AEC_MEAS: + module =3D &rpp->pre1.exm; + break; default: module =3D NULL; break; diff --git a/drivers/media/platform/dreamchip/rppx1/rpp_stats.c b/drivers/m= edia/platform/dreamchip/rppx1/rpp_stats.c index a6abb85f0df1..d62b26e24cb0 100644 --- a/drivers/media/platform/dreamchip/rppx1/rpp_stats.c +++ b/drivers/media/platform/dreamchip/rppx1/rpp_stats.c @@ -15,5 +15,9 @@ void rppx1_stats_fill_isr(struct rppx1 *rpp, u32 isc, voi= d *buf) if (isc & RPPX1_IRQ_ID_POST_AWB_MEAS) if (!rpp_module_call(&rpp->post.wbmeas, stats_rkisp1, &stats->params)) stats->meas_type |=3D RKISP1_CIF_ISP_STAT_AWB; + + if (isc & RPPX1_IRQ_ID_PRE1_EXM) + if (!rpp_module_call(&rpp->pre1.exm, stats_rkisp1, &stats->params)) + stats->meas_type |=3D RKISP1_CIF_ISP_STAT_AUTOEXP; } EXPORT_SYMBOL_GPL(rppx1_stats_fill_isr); diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_exm.c b/drivers/m= edia/platform/dreamchip/rppx1/rppx1_exm.c index 0c40300e13ad..c9478ea5f851 100644 --- a/drivers/media/platform/dreamchip/rppx1/rppx1_exm.c +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_exm.c @@ -10,6 +10,7 @@ #define EXM_START_REG 0x0004 =20 #define EXM_CTRL_REG 0x0008 +#define EXM_CTRL_EXM_AUTOSTOP BIT(1) /* HW doc says not supported. */ #define EXM_CTRL_EXM_UPDATE_ENABLE BIT(0) =20 #define EXM_MODE_REG 0x000c @@ -46,6 +47,94 @@ static int rppx1_exm_probe(struct rpp_module *mod) return 0; } =20 +static int +rppx1_exm_param_rkisp1(struct rpp_module *mod, + const union rppx1_params_rkisp1_config *block, + rppx1_reg_write write, void *priv) +{ + const struct rkisp1_ext_params_aec_config *cfg =3D &block->aec; + const struct rkisp1_cif_isp_aec_config *arg =3D &cfg->config; + u32 h_offs, v_offs, h_size, v_size; + + /* If the modules is disabled, simply bypass it. */ + if (cfg->header.flags & RKISP1_EXT_PARAMS_FL_BLOCK_DISABLE) { + write(priv, mod->base + EXM_MODE_REG, 0); + return 0; + } + + /* RGB bayer exposure measurement */ + write(priv, mod->base + EXM_MODE_REG, 2); + + write(priv, mod->base + EXM_CTRL_REG, EXM_CTRL_EXM_UPDATE_ENABLE | + arg->autostop ? EXM_CTRL_EXM_AUTOSTOP : 0); + + /* + * Select where to sample. + * 0 - after input acquisition + * 1 - after black level subtraction + * 2 - after input linearization + * 3 - after lens shade correction + * 4 - after white balance gain stage + * 5 - after defect pixel correction + * 6 - after denoising + */ + write(priv, mod->base + EXM_CHANNEL_SEL_REG, 6); + + if (arg->mode =3D=3D RKISP1_CIF_ISP_EXP_MEASURING_MODE_0) { + /* Coefficients for a BT.601 BAYER (from datasheet). */ + write(priv, mod->base + EXM_COEFF_R_REG, 38); + write(priv, mod->base + EXM_COEFF_G_GR_REG, 75); + write(priv, mod->base + EXM_COEFF_B_REG, 15); + write(priv, mod->base + EXM_COEFF_GB_REG, 75); + } else { + /* Y =3D (R + Gr + B + Gb) / 4*/ + write(priv, mod->base + EXM_COEFF_R_REG, 128); + write(priv, mod->base + EXM_COEFF_G_GR_REG, 128); + write(priv, mod->base + EXM_COEFF_B_REG, 128); + write(priv, mod->base + EXM_COEFF_GB_REG, 128); + } + + /* + * Adjust and set measurement window to hardware limitations, + * - Offsets must be even. + * - Width and height must be divisible by 10. + */ + h_offs =3D arg->meas_window.h_offs & 0x1ffe; + v_offs =3D arg->meas_window.v_offs & 0x1ffe; + h_size =3D (arg->meas_window.h_size - 1) - ((arg->meas_window.h_size - 1)= % 10); + v_size =3D (arg->meas_window.v_size - 1) - ((arg->meas_window.v_size - 1)= % 10); + + write(priv, mod->base + EXM_H_OFFS_REG, h_offs); + write(priv, mod->base + EXM_V_OFFS_REG, v_offs); + write(priv, mod->base + EXM_H_SIZE_REG, h_size / 5); + write(priv, mod->base + EXM_V_SIZE_REG, v_size / 5); + + /* Set last measurement line for ready interrupt. */ + write(priv, mod->base + EXM_LAST_MEAS_LINE_REG, v_offs + v_size + 1); + + write(priv, mod->base + EXM_START_REG, 1); + + return 0; +} + +static int rppx1_exm_stats_rkisp1(struct rpp_module *mod, + struct rkisp1_cif_isp_stat *stats) +{ + u8 *meas =3D &stats->ae.exp_mean[0]; + /* + * The RkISP mean stats are 8-bit while the RPP can be 8 or 20 bit. + * Figure out how much we need to adjust the output parameters. + */ + const unsigned int shift =3D mod->info.exm.resultbits - 8; + + for (unsigned int i =3D 0; i < EXM_MEAN_REG_NUM; i++) + meas[i] =3D rpp_module_read(mod, EXM_MEAN_REG(i)) >> shift; + + return 0; +} + const struct rpp_module_ops rppx1_exm_ops =3D { .probe =3D rppx1_exm_probe, + .param_rkisp1 =3D rppx1_exm_param_rkisp1, + .stats_rkisp1 =3D rppx1_exm_stats_rkisp1, }; --=20 2.51.0 From nobody Thu Oct 2 14:12:03 2025 Received: from fhigh-b2-smtp.messagingengine.com (fhigh-b2-smtp.messagingengine.com [202.12.124.153]) (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 A29272C08D4; Mon, 15 Sep 2025 17:10:40 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=202.12.124.153 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757956242; cv=none; b=QlOmaVU5A1OidTk6b3gzRCiUi/kUlzG48xPtZLVWSZe5x9LqWaH/7twHWtMdTK/NsccbYcZ2UP7GWmtP2QbAa2bqT5yqwDymVJPKEpuh9MuR7tNWRBBvE3L+nvKRj4ia9M9kzJQXEsIyZiLh02piLyATzWi4ZzDxLawT0HaWE10= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757956242; c=relaxed/simple; bh=SS5LQRIEDoqDDL5IhsqFIlLgwRllsQKu+iYkbcFEqGk=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=Xl8hLWZKsFJCMXB+/FEq74y4UDdOiphpEiXXa16es8Z+PbjNpUFI/OSiHJlGe2wr8kalUcbmNcK68jrlb19W0+doY8GQrkTlE+YMYcdDL+AIVZ7Rv1TEn16N0GTYBHpRwC7NCur1b3kBZ44vBy3ydRip9q4+HPltUIu9BsWig6s= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=ragnatech.se; spf=pass smtp.mailfrom=ragnatech.se; dkim=pass (2048-bit key) header.d=ragnatech.se header.i=@ragnatech.se header.b=lSNzQcwO; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=Hm4E5TqD; arc=none smtp.client-ip=202.12.124.153 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=ragnatech.se Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=ragnatech.se Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=ragnatech.se header.i=@ragnatech.se header.b="lSNzQcwO"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="Hm4E5TqD" Received: from phl-compute-02.internal (phl-compute-02.internal [10.202.2.42]) by mailfhigh.stl.internal (Postfix) with ESMTP id 8E5867A0188; Mon, 15 Sep 2025 13:10:39 -0400 (EDT) Received: from phl-mailfrontend-02 ([10.202.2.163]) by phl-compute-02.internal (MEProxy); Mon, 15 Sep 2025 13:10:39 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ragnatech.se; h= cc:cc:content-transfer-encoding:content-type:content-type:date :date:from:from:in-reply-to:in-reply-to:message-id:mime-version :references:reply-to:subject:subject:to:to; s=fm3; t=1757956239; x=1758042639; bh=6mefLAI9ROKPMRAZVtJzEGzrw1zhU0SiVOplEIuy5WA=; b= lSNzQcwOHrHqwVv1ERl9ZEVabQ0I/IjcptNlkajQer+uRCFrzrTOK0LW3qCLyEc0 T7W/kuWuyd/UivHspu7uXlGNn8ZOp0Bcf6/omt9l3m7W8wi2ijsww5gKVzChHUAX PCQw7OaTcTiaMRLYj4Mfu44B9/cooP0wVq1alsxpEUXPrEFjkzijqI4Nl73hrcZy /L3S/tsNRBdOSa8iYuCKF7rLI65vO8E4k98CTbhXgge4m5b9MpKNAq8WGer8SGX6 BFuOFIpVeBPfdMAg3rOQq0kiQL+dafg7IazqS2nohloVnBguKjxRpHJXc2iAeyTo XBFr5VAxAXnZ2/bnD0LLcA== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:content-type:date:date:feedback-id:feedback-id :from:from:in-reply-to:in-reply-to:message-id:mime-version :references:reply-to:subject:subject:to:to:x-me-proxy :x-me-sender:x-me-sender:x-sasl-enc; s=fm1; t=1757956239; x= 1758042639; bh=6mefLAI9ROKPMRAZVtJzEGzrw1zhU0SiVOplEIuy5WA=; b=H m4E5TqDhj8lkc4r/iV6nO5MTuVQUGZIpq1bZpgbIa+Xzs4jNNBPai9WtFzcDgwid WiMMCiKLavsLKlTaFOF0aSJoBxAtKeQ2rXjqaw78DMaB+CFsxz2tEERezJm1Zhei 9MjNE2a2bHVNqHUlEa5DFiHVLtVskec1KAdLN3GSjxUwLORYyaKFO4nAi85oLjVG KvA86Zq83oav1M0Gs994ZPLbPkbV8M/5q9iIiv3NRNJy9AcofkjmYCl0TYxur6aD YjmhLwv0m3u6lMYcnsis1yXozapMkTCiY88iksBFJteH+t/PkErkW3QaHV5mTUUX b+NCAlWdfW0M78vmWk5pw== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeeffedrtdeggdefkedviecutefuodetggdotefrod ftvfcurfhrohhfihhlvgemucfhrghsthforghilhdpuffrtefokffrpgfnqfghnecuuegr ihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmdenucfjug hrpefhvfevufffkffojghfgggtgfesthekredtredtjeenucfhrhhomheppfhikhhlrghs ucfunpguvghrlhhunhguuceonhhikhhlrghsrdhsohguvghrlhhunhguodhrvghnvghsrg hssehrrghgnhgrthgvtghhrdhsvgeqnecuggftrfgrthhtvghrnhepheeigfeuveeutdef hfehgeekvedtleeuueekveefudehhffhjeffgfegffelfeegnecuvehluhhsthgvrhfuih iivgepudenucfrrghrrghmpehmrghilhhfrhhomhepnhhikhhlrghsrdhsohguvghrlhhu nhgusehrrghgnhgrthgvtghhrdhsvgdpnhgspghrtghpthhtohepjedpmhhouggvpehsmh htphhouhhtpdhrtghpthhtohepmhgthhgvhhgrsgeskhgvrhhnvghlrdhorhhgpdhrtghp thhtohepjhgrtghophhordhmohhnughisehiuggvrghsohhnsghorghrugdrtghomhdprh gtphhtthhopehlrghurhgvnhhtrdhpihhntghhrghrthesihguvggrshhonhgsohgrrhgu rdgtohhmpdhrtghpthhtoheplhhinhhugidqmhgvughirgesvhhgvghrrdhkvghrnhgvlh drohhrghdprhgtphhtthhopehlihhnuhigqdhrvghnvghsrghsqdhsohgtsehvghgvrhdr khgvrhhnvghlrdhorhhgpdhrtghpthhtoheplhhinhhugidqkhgvrhhnvghlsehvghgvrh drkhgvrhhnvghlrdhorhhgpdhrtghpthhtohepnhhikhhlrghsrdhsohguvghrlhhunhgu odhrvghnvghsrghssehrrghgnhgrthgvtghhrdhsvg X-ME-Proxy: Feedback-ID: i80c9496c:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Mon, 15 Sep 2025 13:10:38 -0400 (EDT) From: =?UTF-8?q?Niklas=20S=C3=B6derlund?= To: Mauro Carvalho Chehab , Jacopo Mondi , Laurent Pinchart , linux-media@vger.kernel.org, linux-renesas-soc@vger.kernel.org, linux-kernel@vger.kernel.org Cc: =?UTF-8?q?Niklas=20S=C3=B6derlund?= Subject: [PATCH v2 06/12] media: rppx1: Add support for Histogram Measurement Date: Mon, 15 Sep 2025 19:07:37 +0200 Message-ID: <20250915170743.106249-7-niklas.soderlund+renesas@ragnatech.se> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20250915170743.106249-1-niklas.soderlund+renesas@ragnatech.se> References: <20250915170743.106249-1-niklas.soderlund+renesas@ragnatech.se> 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 Extend the RPPX1 driver to allow setting the Histogram configuration using the RkISP1 parameter buffer format. It uses the RPPX1 framework for parameters and its writer abstraction to allow the user to control how (and when) configuration is applied to the RPPX1. As the RkISP1 parameters buffer have lower precision then the RPPX1 hardware the values needs to be scaled. The behavior matches the RkISP1 hardware. Signed-off-by: Niklas S=C3=B6derlund --- .../platform/dreamchip/rppx1/rpp_params.c | 3 + .../platform/dreamchip/rppx1/rpp_stats.c | 4 + .../platform/dreamchip/rppx1/rppx1_hist.c | 173 ++++++++++++++++++ 3 files changed, 180 insertions(+) diff --git a/drivers/media/platform/dreamchip/rppx1/rpp_params.c b/drivers/= media/platform/dreamchip/rppx1/rpp_params.c index bff525970478..15e476d2fa1c 100644 --- a/drivers/media/platform/dreamchip/rppx1/rpp_params.c +++ b/drivers/media/platform/dreamchip/rppx1/rpp_params.c @@ -30,6 +30,9 @@ int rppx1_params_rkisp1(struct rppx1 *rpp, struct rkisp1_= ext_params_cfg *cfg, case RKISP1_EXT_PARAMS_BLOCK_TYPE_AWB_MEAS: module =3D &rpp->post.wbmeas; break; + case RKISP1_EXT_PARAMS_BLOCK_TYPE_HST_MEAS: + module =3D &rpp->post.hist; + break; case RKISP1_EXT_PARAMS_BLOCK_TYPE_AEC_MEAS: module =3D &rpp->pre1.exm; break; diff --git a/drivers/media/platform/dreamchip/rppx1/rpp_stats.c b/drivers/m= edia/platform/dreamchip/rppx1/rpp_stats.c index d62b26e24cb0..059bd76ecf64 100644 --- a/drivers/media/platform/dreamchip/rppx1/rpp_stats.c +++ b/drivers/media/platform/dreamchip/rppx1/rpp_stats.c @@ -16,6 +16,10 @@ void rppx1_stats_fill_isr(struct rppx1 *rpp, u32 isc, vo= id *buf) if (!rpp_module_call(&rpp->post.wbmeas, stats_rkisp1, &stats->params)) stats->meas_type |=3D RKISP1_CIF_ISP_STAT_AWB; =20 + if (isc & RPPX1_IRQ_ID_POST_HIST_MEAS) + if (!rpp_module_call(&rpp->post.hist, stats_rkisp1, &stats->params)) + stats->meas_type |=3D RKISP1_CIF_ISP_STAT_HIST; + if (isc & RPPX1_IRQ_ID_PRE1_EXM) if (!rpp_module_call(&rpp->pre1.exm, stats_rkisp1, &stats->params)) stats->meas_type |=3D RKISP1_CIF_ISP_STAT_AUTOEXP; diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_hist.c b/drivers/= media/platform/dreamchip/rppx1/rppx1_hist.c index cab498ece5a8..40ae8dc72b90 100644 --- a/drivers/media/platform/dreamchip/rppx1/rppx1_hist.c +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_hist.c @@ -25,6 +25,9 @@ =20 #define HIST_LAST_MEAS_LINE_REG 0x0010 #define HIST_SUBSAMPLING_REG 0x0014 +#define HIST_SUBSAMPLING_V_STEPSIZE(x) (((x) & 0x7f) << 24) +#define HIST_SUBSAMPLING_H_STEP_INC(x) (((x) & 0x1ffff)) + #define HIST_COEFF_R_REG 0x0018 #define HIST_COEFF_G_REG 0x001c #define HIST_COEFF_B_REG 0x0020 @@ -71,6 +74,176 @@ static int rppx1_hist_probe(struct rpp_module *mod) return 0; } =20 +#define RPPX1_HIST_WEIGHT(v0, v1, v2, v3) \ + (((v0) & 0x1f) | (((v1) & 0x1f) << 8) | \ + (((v2) & 0x1f) << 16) | \ + (((v3) & 0x1f) << 24)) + +static int rppx1_hist_param_rkisp1(struct rpp_module *mod, + const union rppx1_params_rkisp1_config *block, + rppx1_reg_write write, void *priv) +{ + const struct rkisp1_ext_params_hst_config *cfg =3D &block->hst; + const struct rkisp1_cif_isp_hst_config *arg =3D &cfg->config; + u32 h_offs, v_offs, h_size, v_size; + u8 mode, coeff[3]; + + /* If the modules is disabled, simply bypass it. */ + if (cfg->header.flags & RKISP1_EXT_PARAMS_FL_BLOCK_DISABLE) { + write(priv, mod->base + HIST_MODE_REG, + HIST_MODE_HIST_MODE_DISABLE); + return 0; + } + + /* Sample after demosaicing. */ + write(priv, mod->base + HIST_CHANNEL_SEL_REG, 7); + + /* + * The RkISP1 histogram_predivider setting controls the pixel spacing + * between each sample. On RPPX1 there is greater control as both line + * and pixel spacing can be controlled. The RkISP1 stepsize register is + * documented as. + * + * 0, 1, 3: not allowed + * 3: process every third input pixel + * 4: process every fourth input pixel + * 127: process every 127th pixel + * + * The output bins are 16 bit (FP16.4) so to not overflow a divider + * calculated as would be needed. + * + * count =3D mode =3D=3D RGB_COMBINED ? 3 : 1 + * factor =3D vsize * hsize * count / 65536 + * + * However the libcamera user of the RkISP documents the setting as + * applying to both h and v direction at the same time and calculates + * the divider as, + * + * count =3D mode =3D=3D RGB_COMBINED ? 3 : 1 + * factor =3D ceil(sqrt(vsize * hsize * count / 65536)) + * + * Real world usage is better then bad documentation, do the same here + * and apply the divider in both directions. + * + * The RPPX1 h-stepping is also configured differently. Internally + * there is a 16-bit counter and for each input pixel h_step_inc is + * added to it. Every time it overflows the input pixel is sampled. + * + * h_step_inc =3D 2**16 =3D> sample every pixel + * h_step_inc =3D 2**15 =3D> sample every other pixel + * + * Gives us the conversion to RkISP1 parameters of. + * + * h_step_inc =3D 65536 / divider + */ + write(priv, mod->base + HIST_SUBSAMPLING_REG, + HIST_SUBSAMPLING_V_STEPSIZE(arg->histogram_predivider) | + HIST_SUBSAMPLING_H_STEP_INC(0x10000 / arg->histogram_predivider)); + + /* + * Adjust and set measurement window to hardware limitations, + * - Offsets must be even. + * - Width and height must be divisible by 10. + */ + h_offs =3D arg->meas_window.h_offs & 0x1ffe; + v_offs =3D arg->meas_window.v_offs & 0x1ffe; + h_size =3D arg->meas_window.h_size - arg->meas_window.h_size % 10; + v_size =3D arg->meas_window.v_size - arg->meas_window.v_size % 10; + + write(priv, mod->base + HIST_H_OFFS_REG, h_offs); + write(priv, mod->base + HIST_V_OFFS_REG, v_offs); + write(priv, mod->base + HIST_H_SIZE_REG, h_size / 5); + write(priv, mod->base + HIST_V_SIZE_REG, v_size / 5); + + /* Set last measurement line for ready interrupt. */ + write(priv, mod->base + HIST_LAST_MEAS_LINE_REG, + v_offs + v_size + 1); + + /* NOTE: Keep the default full sample range. */ + + /* Set measurement window weights. */ + write(priv, mod->base + HIST_WEIGHT_00TO30_REG, + RPPX1_HIST_WEIGHT(arg->hist_weight[0], arg->hist_weight[1], + arg->hist_weight[2], arg->hist_weight[3])); + write(priv, mod->base + HIST_WEIGHT_40TO21_REG, + RPPX1_HIST_WEIGHT(arg->hist_weight[4], arg->hist_weight[5], + arg->hist_weight[6], arg->hist_weight[7])); + write(priv, mod->base + HIST_WEIGHT_31TO12_REG, + RPPX1_HIST_WEIGHT(arg->hist_weight[8], arg->hist_weight[9], + arg->hist_weight[10], arg->hist_weight[11])); + write(priv, mod->base + HIST_WEIGHT_22TO03_REG, + RPPX1_HIST_WEIGHT(arg->hist_weight[12], arg->hist_weight[13], + arg->hist_weight[14], arg->hist_weight[15])); + write(priv, mod->base + HIST_WEIGHT_13TO43_REG, + RPPX1_HIST_WEIGHT(arg->hist_weight[16], arg->hist_weight[17], + arg->hist_weight[18], arg->hist_weight[19])); + write(priv, mod->base + HIST_WEIGHT_04TO34_REG, + RPPX1_HIST_WEIGHT(arg->hist_weight[20], arg->hist_weight[21], + arg->hist_weight[22], arg->hist_weight[23])); + write(priv, mod->base + HIST_WEIGHT_44_REG, + RPPX1_HIST_WEIGHT(arg->hist_weight[24], 0, 0, 0)); + + /* Translate RkISP1 modes. */ + mode =3D HIST_MODE_HIST_MODE_YRGB; + switch (arg->mode) { + case RKISP1_CIF_ISP_HISTOGRAM_MODE_RGB_COMBINED: + /* L =3D R + G + B */ + coeff[0] =3D 0x80; + coeff[1] =3D 0x80; + coeff[2] =3D 0x80; + break; + case RKISP1_CIF_ISP_HISTOGRAM_MODE_R_HISTOGRAM: + /* L =3D R */ + coeff[0] =3D 0x80; + coeff[1] =3D 0x00; + coeff[2] =3D 0x00; + break; + case RKISP1_CIF_ISP_HISTOGRAM_MODE_G_HISTOGRAM: + /* L =3D G */ + coeff[0] =3D 0x00; + coeff[1] =3D 0x80; + coeff[2] =3D 0x00; + break; + case RKISP1_CIF_ISP_HISTOGRAM_MODE_B_HISTOGRAM: + coeff[0] =3D 0x00; + coeff[1] =3D 0x00; + coeff[2] =3D 0x80; + break; + case RKISP1_CIF_ISP_HISTOGRAM_MODE_Y_HISTOGRAM: + /* Coefficients for a BT.601 (from datasheet). */ + coeff[0] =3D 38; + coeff[1] =3D 75; + coeff[2] =3D 15; + break; + default: + mode =3D HIST_MODE_HIST_MODE_DISABLE; + coeff[0] =3D 0x00; + coeff[1] =3D 0x00; + coeff[2] =3D 0x00; + break; + } + + write(priv, mod->base + HIST_MODE_REG, mode); + write(priv, mod->base + HIST_COEFF_R_REG, coeff[0]); + write(priv, mod->base + HIST_COEFF_G_REG, coeff[1]); + write(priv, mod->base + HIST_COEFF_B_REG, coeff[2]); + + write(priv, mod->base + HIST_FORCED_UPDATE_REG, 1); + + return 0; +} + +static int rppx1_hist_stats_rkisp1(struct rpp_module *mod, + struct rkisp1_cif_isp_stat *stats) +{ + for (unsigned int i =3D 0; i < HIST_BIN_REG_NUM; i++) + stats->hist.hist_bins[i] =3D rpp_module_read(mod, HIST_BIN_REG(i)) & 0xf= ffff; + + return 0; +} + const struct rpp_module_ops rppx1_hist_ops =3D { .probe =3D rppx1_hist_probe, + .param_rkisp1 =3D rppx1_hist_param_rkisp1, + .stats_rkisp1 =3D rppx1_hist_stats_rkisp1, }; --=20 2.51.0 From nobody Thu Oct 2 14:12:04 2025 Received: from fhigh-b2-smtp.messagingengine.com (fhigh-b2-smtp.messagingengine.com [202.12.124.153]) (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 D5B892C08BD; Mon, 15 Sep 2025 17:10:42 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=202.12.124.153 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757956244; cv=none; b=qSTdcR0o55WIbl5UyTtCI6IeXeLjW+fB37xW8znFiiMHJd/pJK23BuOxHXfS3D0CQpBRxkJh6elNto6S+ofR8OnvLQtg30Gr4G1uVJgnmM+ekID2u26USDhFWTyAnkSoj0cGYsaQvkm2OQM0NTA/IHq6Kc22AG8oJVwfyqU1fKc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757956244; c=relaxed/simple; bh=mPOPgNID57f+GH1HOa0O4vfR2JBuImkSJRSRhRk48Fc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=Cc2f2dn626TpZK+uliGdKsHcc+4Av7BNDN0F6+XxgNWqARp7KeSyBA0rSGB/QyQhqVuJwZOACPYhQIBtTP6EOj4XcvADVAUlzLmW4hQGS9yAOAlfQ4ObZmEq5D4eXXOI9+HvIkuL6Qh3qtzKgQ/RyDGWSwquaF4kCqWGcBH9SA0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=ragnatech.se; spf=pass smtp.mailfrom=ragnatech.se; dkim=pass (2048-bit key) header.d=ragnatech.se header.i=@ragnatech.se header.b=g7F7yn7j; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=hyTdSzgV; arc=none smtp.client-ip=202.12.124.153 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=ragnatech.se Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=ragnatech.se Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=ragnatech.se header.i=@ragnatech.se header.b="g7F7yn7j"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="hyTdSzgV" Received: from phl-compute-01.internal (phl-compute-01.internal [10.202.2.41]) by mailfhigh.stl.internal (Postfix) with ESMTP id CAD5D7A016C; Mon, 15 Sep 2025 13:10:41 -0400 (EDT) Received: from phl-mailfrontend-01 ([10.202.2.162]) by phl-compute-01.internal (MEProxy); Mon, 15 Sep 2025 13:10:42 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ragnatech.se; h= cc:cc:content-transfer-encoding:content-type:content-type:date :date:from:from:in-reply-to:in-reply-to:message-id:mime-version :references:reply-to:subject:subject:to:to; s=fm3; t=1757956241; x=1758042641; bh=mAJtIlDWRgExlwUw4LeBdysX++mXrqNhzg2vRb4wAn0=; b= g7F7yn7jaEvFVqT0jf8xX6O2BxwARqgX0wkfur3Lxq9bAUNerpBVUTtzzfoKiYOc prkcuw+pR2RYqsWDoPVZbbiFGV+SDBLzvMaRZ2Cmym9jMlWSb3br4zJH18Dakryg UyjRV80oBO2sG4JpRdQBSZltB0I7lTfy9/vpTORC0ivhI9eG5t5mMk6Qd6zqdkdM YFj8qkFpswqoJZBfjt6qDov94Xsy51ZcC5ELgcDXpOLjC8ENNuh1yXFf1k68sNd0 zG0PLfpxOg/c8R2qNVvW6ygfq0zPkVxFUutXsKdZl3RAwiHqaq7volD+arCYpGtF UvDz8TELrxWCwdPX+iL51g== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:content-type:date:date:feedback-id:feedback-id :from:from:in-reply-to:in-reply-to:message-id:mime-version :references:reply-to:subject:subject:to:to:x-me-proxy :x-me-sender:x-me-sender:x-sasl-enc; s=fm1; t=1757956241; x= 1758042641; bh=mAJtIlDWRgExlwUw4LeBdysX++mXrqNhzg2vRb4wAn0=; b=h yTdSzgVyo1svpOF241L7VxQHvd6BIvQYy2Nj+Eyd3oWR3Lk2o8jg0jUYV14JAbLN piPh2e5M/GdHaVtB8BThHTNb0G9Kamns6bqdoRq3kmz/7TxD2yFOP1SNA5TVIRTc yzr1K/V2mOGM4gbcRcLG9nmgtN9A9PoyVMl4qRqnpS+h4NhhnwvS9lZykF5XcRvd 5EcvkARvKEJO48NQCW10BZcdun65SRgY35PsBFb+KezhP9lzj09T2Lb7rusSRkg1 6YOnLyMFdj0JUDChk/d7nOkdZ4JedwiS2ySlgF0iQHug1OrcX1zh4WD/JGy9BzxC UdFXXSVPAQJ6jGrtSqd8g== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeeffedrtdeggdefkedviecutefuodetggdotefrod ftvfcurfhrohhfihhlvgemucfhrghsthforghilhdpuffrtefokffrpgfnqfghnecuuegr ihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmdenucfjug hrpefhvfevufffkffojghfgggtgfesthekredtredtjeenucfhrhhomheppfhikhhlrghs ucfunpguvghrlhhunhguuceonhhikhhlrghsrdhsohguvghrlhhunhguodhrvghnvghsrg hssehrrghgnhgrthgvtghhrdhsvgeqnecuggftrfgrthhtvghrnhepkeehteffudektdek ieejveeiheelgfefkedvjeeuleehkeefudetvdduteeffeeinecuffhomhgrihhnpehfih igvggupghvrghlrdhgrhdpfhhigigvuggpvhgrlhdrghgsnecuvehluhhsthgvrhfuihii vgeptdenucfrrghrrghmpehmrghilhhfrhhomhepnhhikhhlrghsrdhsohguvghrlhhunh gusehrrghgnhgrthgvtghhrdhsvgdpnhgspghrtghpthhtohepjedpmhhouggvpehsmhht phhouhhtpdhrtghpthhtohepmhgthhgvhhgrsgeskhgvrhhnvghlrdhorhhgpdhrtghpth htohepjhgrtghophhordhmohhnughisehiuggvrghsohhnsghorghrugdrtghomhdprhgt phhtthhopehlrghurhgvnhhtrdhpihhntghhrghrthesihguvggrshhonhgsohgrrhgurd gtohhmpdhrtghpthhtoheplhhinhhugidqmhgvughirgesvhhgvghrrdhkvghrnhgvlhdr ohhrghdprhgtphhtthhopehlihhnuhigqdhrvghnvghsrghsqdhsohgtsehvghgvrhdrkh gvrhhnvghlrdhorhhgpdhrtghpthhtoheplhhinhhugidqkhgvrhhnvghlsehvghgvrhdr khgvrhhnvghlrdhorhhgpdhrtghpthhtohepnhhikhhlrghsrdhsohguvghrlhhunhguod hrvghnvghsrghssehrrghgnhgrthgvtghhrdhsvg X-ME-Proxy: Feedback-ID: i80c9496c:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Mon, 15 Sep 2025 13:10:41 -0400 (EDT) From: =?UTF-8?q?Niklas=20S=C3=B6derlund?= To: Mauro Carvalho Chehab , Jacopo Mondi , Laurent Pinchart , linux-media@vger.kernel.org, linux-renesas-soc@vger.kernel.org, linux-kernel@vger.kernel.org Cc: =?UTF-8?q?Niklas=20S=C3=B6derlund?= Subject: [PATCH v2 07/12] media: rppx1: Add support for Black Level Subtraction Date: Mon, 15 Sep 2025 19:07:38 +0200 Message-ID: <20250915170743.106249-8-niklas.soderlund+renesas@ragnatech.se> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20250915170743.106249-1-niklas.soderlund+renesas@ragnatech.se> References: <20250915170743.106249-1-niklas.soderlund+renesas@ragnatech.se> 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 Extend the RPPX1 driver to allow setting the Black Level Subtraction (BLS) configuration using the RkISP1 parameter buffer format. It uses the RPPX1 framework for parameters and its writer abstraction to allow the user to control how (and when) configuration is applied to the RPPX1. As the RkISP1 parameters buffer have lower precision then the RPPX1 hardware the values needs to be scaled. The behavior matches the RkISP1 hardware. Signed-off-by: Niklas S=C3=B6derlund --- .../platform/dreamchip/rppx1/rpp_params.c | 3 + .../platform/dreamchip/rppx1/rpp_stats.c | 5 +- .../platform/dreamchip/rppx1/rppx1_bls.c | 116 ++++++++++++++++++ 3 files changed, 123 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/dreamchip/rppx1/rpp_params.c b/drivers/= media/platform/dreamchip/rppx1/rpp_params.c index 15e476d2fa1c..afc80a480d42 100644 --- a/drivers/media/platform/dreamchip/rppx1/rpp_params.c +++ b/drivers/media/platform/dreamchip/rppx1/rpp_params.c @@ -24,6 +24,9 @@ int rppx1_params_rkisp1(struct rppx1 *rpp, struct rkisp1_= ext_params_cfg *cfg, block_offset +=3D block->header.size; =20 switch (block->header.type) { + case RKISP1_EXT_PARAMS_BLOCK_TYPE_BLS: + module =3D &rpp->pre1.bls; + break; case RKISP1_EXT_PARAMS_BLOCK_TYPE_AWB_GAIN: module =3D &rpp->pre1.awbg; break; diff --git a/drivers/media/platform/dreamchip/rppx1/rpp_stats.c b/drivers/m= edia/platform/dreamchip/rppx1/rpp_stats.c index 059bd76ecf64..1bffa6dd35f8 100644 --- a/drivers/media/platform/dreamchip/rppx1/rpp_stats.c +++ b/drivers/media/platform/dreamchip/rppx1/rpp_stats.c @@ -20,8 +20,11 @@ void rppx1_stats_fill_isr(struct rppx1 *rpp, u32 isc, vo= id *buf) if (!rpp_module_call(&rpp->post.hist, stats_rkisp1, &stats->params)) stats->meas_type |=3D RKISP1_CIF_ISP_STAT_HIST; =20 - if (isc & RPPX1_IRQ_ID_PRE1_EXM) + if (isc & RPPX1_IRQ_ID_PRE1_EXM) { if (!rpp_module_call(&rpp->pre1.exm, stats_rkisp1, &stats->params)) stats->meas_type |=3D RKISP1_CIF_ISP_STAT_AUTOEXP; + + rpp_module_call(&rpp->pre1.bls, stats_rkisp1, &stats->params); + } } EXPORT_SYMBOL_GPL(rppx1_stats_fill_isr); diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_bls.c b/drivers/m= edia/platform/dreamchip/rppx1/rppx1_bls.c index de7008befd8e..164bc4a63c23 100644 --- a/drivers/media/platform/dreamchip/rppx1/rppx1_bls.c +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_bls.c @@ -5,6 +5,7 @@ */ =20 #include "rpp_module.h" +#include "rppx1.h" =20 #define BLS_VERSION_REG 0x0000 =20 @@ -54,6 +55,121 @@ static int rppx1_bls_probe(struct rpp_module *mod) return 0; } =20 +static void +rppx1_bls_swap_regs(struct rpp_module *mod, const u32 input[4], u32 output= [4]) +{ + static const unsigned int swap[4][4] =3D { + [RPP_RGGB] =3D { 0, 1, 2, 3 }, + [RPP_GRBG] =3D { 1, 0, 3, 2 }, + [RPP_GBRG] =3D { 2, 3, 0, 1 }, + [RPP_BGGR] =3D { 3, 2, 1, 0 }, + }; + + /* Swap to pattern used in our path, PRE1 or PRE2. */ + struct rpp_module *acq =3D mod =3D=3D &mod->rpp->pre1.bls ? + &mod->rpp->pre1.acq : &mod->rpp->pre2.bls; + enum rpp_raw_pattern pattern =3D acq->info.acq.raw_pattern; + + for (unsigned int i =3D 0; i < 4; ++i) + output[i] =3D input[swap[pattern][i]]; +} + +static int +rppx1_bls_param_rkisp1(struct rpp_module *mod, + const union rppx1_params_rkisp1_config *block, + rppx1_reg_write write, void *priv) +{ + const struct rkisp1_ext_params_bls_config *cfg =3D &block->bls; + + /* If the modules is disabled, simply bypass it. */ + if (cfg->header.flags & RKISP1_EXT_PARAMS_FL_BLOCK_DISABLE) { + write(priv, mod->base + BLS_CTRL_REG, 0); + return 0; + } + + u32 ctrl =3D BLS_CTRL_BLS_EN; + + if (!cfg->config.enable_auto) { + static const u32 regs[] =3D { + BLS_A_FIXED_REG, + BLS_B_FIXED_REG, + BLS_C_FIXED_REG, + BLS_D_FIXED_REG, + }; + u32 swapped[4]; + + rppx1_bls_swap_regs(mod, regs, swapped); + + /* + * The RkISP params are 12-bit + 1 signed bit, while the RPP can + * be 12, 20 or 24 bit + 1 signed bit. Figure out how much we + * need to adjust the input parameters. + */ + const unsigned int shift =3D mod->info.bls.colorbits - 12; + + write(priv, mod->base + swapped[0], cfg->config.fixed_val.r << shift); + write(priv, mod->base + swapped[1], cfg->config.fixed_val.gr << shift); + write(priv, mod->base + swapped[2], cfg->config.fixed_val.gb << shift); + write(priv, mod->base + swapped[3], cfg->config.fixed_val.b << shift); + } else { + write(priv, mod->base + BLS_SAMPLES_REG, cfg->config.bls_samples); + + if (cfg->config.en_windows & BIT(0)) { + write(priv, mod->base + BLS_H1_START_REG, cfg->config.bls_window1.h_off= s); + write(priv, mod->base + BLS_H1_STOP_REG, cfg->config.bls_window1.h_size= ); + write(priv, mod->base + BLS_V1_START_REG, cfg->config.bls_window1.v_off= s); + write(priv, mod->base + BLS_V1_STOP_REG, cfg->config.bls_window1.v_size= ); + ctrl |=3D BLS_CTRL_BLS_WIN1; + } + + if (cfg->config.en_windows & BIT(1)) { + write(priv, mod->base + BLS_H2_START_REG, cfg->config.bls_window2.h_off= s); + write(priv, mod->base + BLS_H2_STOP_REG, cfg->config.bls_window2.h_size= ); + write(priv, mod->base + BLS_V2_START_REG, cfg->config.bls_window2.v_off= s); + write(priv, mod->base + BLS_V2_STOP_REG, cfg->config.bls_window2.v_size= ); + ctrl |=3D BLS_CTRL_BLS_WIN2; + } + + ctrl |=3D BLS_CTRL_BLS_MODE_MEASURED; + } + + write(priv, mod->base + BLS_CTRL_REG, ctrl); + + return 0; +} + +static int rppx1_bls_stats_rkisp1(struct rpp_module *mod, + struct rkisp1_cif_isp_stat *stats) +{ + struct rkisp1_cif_isp_bls_meas_val *bls =3D &stats->ae.bls_val; + + static const u32 regs[] =3D { + BLS_A_MEASURED_REG, + BLS_B_MEASURED_REG, + BLS_C_MEASURED_REG, + BLS_D_MEASURED_REG, + }; + u32 swapped[4]; + + rppx1_bls_swap_regs(mod, regs, swapped); + + /* + * The RkISP BLS stats are 12-bit while the RPP can be 8, 20 + * or 24 bit. Figure out how much we need to adjust the output + * statistics. + */ + const unsigned int shift =3D mod->info.bls.colorbits - 12; + + bls->meas_r =3D rpp_module_read(mod, swapped[0]) >> shift; + bls->meas_gr =3D rpp_module_read(mod, swapped[1]) >> shift; + bls->meas_gb =3D rpp_module_read(mod, swapped[2]) >> shift; + bls->meas_b =3D rpp_module_read(mod, swapped[3]) >> shift; + + return 0; +} + const struct rpp_module_ops rppx1_bls_ops =3D { .probe =3D rppx1_bls_probe, + .param_rkisp1 =3D rppx1_bls_param_rkisp1, + .stats_rkisp1 =3D rppx1_bls_stats_rkisp1 }; --=20 2.51.0 From nobody Thu Oct 2 14:12:04 2025 Received: from fout-b1-smtp.messagingengine.com (fout-b1-smtp.messagingengine.com [202.12.124.144]) (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 4AA9B2DE6E8; Mon, 15 Sep 2025 17:10:45 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=202.12.124.144 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757956247; cv=none; b=FkWHTLVFU812qBNyQSmwhcCQiqMIMr7G5y/F2m0d69liziEOfUNud5dSWyS+Ir/GDoNcC4ZGfuEnYz19zh1L0etGWYhQzSUFon3vcg5LHnnUNA7TYIQetJ7mssoUPOJL4WShDemE+qJEDTQMjPRpOX+l9icAdKpiiBNo6rd3JQM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757956247; c=relaxed/simple; bh=sJTbXXngzJNFtPf5fBJ8qMT08dQ0ouBCzAJz9Bs/ynA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=NbB/VkYEWaKkW5Utot1E9tPk3htmms3Pcy5k+z0fhU9j3IvuNoywp2L6yiQYuYjmvJnNAAEzjAGhaeUT+Gn90xNrn2wI3ieAnrN1hUKYmR3ECYmCpt0i5tsNoIM7T4fXdsoNcMzih5Naw4So7bXgqCzjglk8uboWTOm6lHNe8Xo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=ragnatech.se; spf=pass smtp.mailfrom=ragnatech.se; dkim=pass (2048-bit key) header.d=ragnatech.se header.i=@ragnatech.se header.b=TdRZXZbb; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=lWxjdzV8; arc=none smtp.client-ip=202.12.124.144 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=ragnatech.se Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=ragnatech.se Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=ragnatech.se header.i=@ragnatech.se header.b="TdRZXZbb"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="lWxjdzV8" Received: from phl-compute-10.internal (phl-compute-10.internal [10.202.2.50]) by mailfout.stl.internal (Postfix) with ESMTP id 300A21D00153; Mon, 15 Sep 2025 13:10:44 -0400 (EDT) Received: from phl-mailfrontend-02 ([10.202.2.163]) by phl-compute-10.internal (MEProxy); Mon, 15 Sep 2025 13:10:44 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ragnatech.se; h= cc:cc:content-transfer-encoding:content-type:content-type:date :date:from:from:in-reply-to:in-reply-to:message-id:mime-version :references:reply-to:subject:subject:to:to; s=fm3; t=1757956244; x=1758042644; bh=LmvZxPwatK4qKPxXge+q3IDINjzHCMSgdKqn29GSQoE=; b= TdRZXZbb+YpwZqG5QFcKebUHFFBAf0XeZUrOr2ery8uMWn+wIB9Fy2c9+uWc61b2 o1mNKJgKw9Euw5t/UEGLi+JZFtgiw4dYDnJLxFNdgfBZB5a7MJVTjSpwCG408A4C iV3PHYfeKQeCOu4ETAomwTvlU2Qy8oUmcFHX1Rux58GLHE+OseULGj1zlBs/5Skl ymejqEaad2AJXw8UpNBh5w1psszVA70CbwJrqENQMjsBLPjz9lDrzd8Gcu5xS6bo Rkv/zf7K31wIhDr6hydCBMl76fVXqXvbbLVFXCc/TveXwhHu98S5iglIJd6A8jIx CSg8lb3/OMH8aCjtPAb4NA== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:content-type:date:date:feedback-id:feedback-id :from:from:in-reply-to:in-reply-to:message-id:mime-version :references:reply-to:subject:subject:to:to:x-me-proxy :x-me-sender:x-me-sender:x-sasl-enc; s=fm1; t=1757956244; x= 1758042644; bh=LmvZxPwatK4qKPxXge+q3IDINjzHCMSgdKqn29GSQoE=; b=l WxjdzV8H6Iv98BgGtTn4zNX8hAyu3c4ro1/hEqpJvv+tPYinPrCvbtmk+c9s0EKk 4cPZti+QToC+4+rRGqkVR8MMXCSgw3uo601XaLDAi25qhNr+1xoYLT0OjVDUIWaC Z49MjC9phsBXT5Thgdl2miUZXlRrvAzj+MyKANZ5F5OSBxCJIbIOwaRb5CB0V1GO hXFdxyRr/vTWxkEQXT+fl4yxNk5fcXph40APcU+p/stNrOkUGoJdCD5DjktS312+ UrfpDaDFnjP90Np8crAeFw9/2x5hBshc/9JNtlv/qSp4vuQcFQEYsU0VmvclU8O2 ZFEwXidm6qqk9vunDDf0w== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeeffedrtdeggdefkedvhecutefuodetggdotefrod ftvfcurfhrohhfihhlvgemucfhrghsthforghilhdpuffrtefokffrpgfnqfghnecuuegr ihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmdenucfjug hrpefhvfevufffkffojghfgggtgfesthekredtredtjeenucfhrhhomheppfhikhhlrghs ucfunpguvghrlhhunhguuceonhhikhhlrghsrdhsohguvghrlhhunhguodhrvghnvghsrg hssehrrghgnhgrthgvtghhrdhsvgeqnecuggftrfgrthhtvghrnhepheeigfeuveeutdef hfehgeekvedtleeuueekveefudehhffhjeffgfegffelfeegnecuvehluhhsthgvrhfuih iivgeptdenucfrrghrrghmpehmrghilhhfrhhomhepnhhikhhlrghsrdhsohguvghrlhhu nhgusehrrghgnhgrthgvtghhrdhsvgdpnhgspghrtghpthhtohepjedpmhhouggvpehsmh htphhouhhtpdhrtghpthhtohepmhgthhgvhhgrsgeskhgvrhhnvghlrdhorhhgpdhrtghp thhtohepjhgrtghophhordhmohhnughisehiuggvrghsohhnsghorghrugdrtghomhdprh gtphhtthhopehlrghurhgvnhhtrdhpihhntghhrghrthesihguvggrshhonhgsohgrrhgu rdgtohhmpdhrtghpthhtoheplhhinhhugidqmhgvughirgesvhhgvghrrdhkvghrnhgvlh drohhrghdprhgtphhtthhopehlihhnuhigqdhrvghnvghsrghsqdhsohgtsehvghgvrhdr khgvrhhnvghlrdhorhhgpdhrtghpthhtoheplhhinhhugidqkhgvrhhnvghlsehvghgvrh drkhgvrhhnvghlrdhorhhgpdhrtghpthhtohepnhhikhhlrghsrdhsohguvghrlhhunhgu odhrvghnvghsrghssehrrghgnhgrthgvtghhrdhsvg X-ME-Proxy: Feedback-ID: i80c9496c:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Mon, 15 Sep 2025 13:10:43 -0400 (EDT) From: =?UTF-8?q?Niklas=20S=C3=B6derlund?= To: Mauro Carvalho Chehab , Jacopo Mondi , Laurent Pinchart , linux-media@vger.kernel.org, linux-renesas-soc@vger.kernel.org, linux-kernel@vger.kernel.org Cc: =?UTF-8?q?Niklas=20S=C3=B6derlund?= Subject: [PATCH v2 08/12] media: rppx1: Add support for Color Correction Matrix Date: Mon, 15 Sep 2025 19:07:39 +0200 Message-ID: <20250915170743.106249-9-niklas.soderlund+renesas@ragnatech.se> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20250915170743.106249-1-niklas.soderlund+renesas@ragnatech.se> References: <20250915170743.106249-1-niklas.soderlund+renesas@ragnatech.se> 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 Extend the RPPX1 driver to allow setting the Color Correction Matrix (BLS) configuration using the RkISP1 parameter buffer format. It uses the RPPX1 framework for parameters and its writer abstraction to allow the user to control how (and when) configuration is applied to the RPPX1. As the RkISP1 parameters buffer have lower precision then the RPPX1 hardware the values needs to be scaled. The behavior matches the RkISP1 hardware. Signed-off-by: Niklas S=C3=B6derlund --- .../platform/dreamchip/rppx1/rpp_params.c | 3 + .../platform/dreamchip/rppx1/rppx1_ccor.c | 74 +++++++++++++++++++ 2 files changed, 77 insertions(+) diff --git a/drivers/media/platform/dreamchip/rppx1/rpp_params.c b/drivers/= media/platform/dreamchip/rppx1/rpp_params.c index afc80a480d42..c2c8349a2837 100644 --- a/drivers/media/platform/dreamchip/rppx1/rpp_params.c +++ b/drivers/media/platform/dreamchip/rppx1/rpp_params.c @@ -30,6 +30,9 @@ int rppx1_params_rkisp1(struct rppx1 *rpp, struct rkisp1_= ext_params_cfg *cfg, case RKISP1_EXT_PARAMS_BLOCK_TYPE_AWB_GAIN: module =3D &rpp->pre1.awbg; break; + case RKISP1_EXT_PARAMS_BLOCK_TYPE_CTK: + module =3D &rpp->post.ccor; + break; case RKISP1_EXT_PARAMS_BLOCK_TYPE_AWB_MEAS: module =3D &rpp->post.wbmeas; break; diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_ccor.c b/drivers/= media/platform/dreamchip/rppx1/rppx1_ccor.c index 4754b0bbce0a..0ccaed8ce55d 100644 --- a/drivers/media/platform/dreamchip/rppx1/rppx1_ccor.c +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_ccor.c @@ -68,9 +68,83 @@ static int rppx1_ccor_start(struct rpp_module *mod, return 0; } =20 +static int +rppx1_ccor_param_rkisp1(struct rpp_module *mod, + const union rppx1_params_rkisp1_config *block, + rppx1_reg_write write, void *priv) +{ + const struct rkisp1_ext_params_ctk_config *cfg =3D &block->ctk; + + /* If the modules is disabled, configure in bypass mode. */ + if (cfg->header.flags & RKISP1_EXT_PARAMS_FL_BLOCK_DISABLE) { + write(priv, mod->base + CCOR_COEFF_REG(0), 0x1000); + write(priv, mod->base + CCOR_COEFF_REG(1), 0x0000); + write(priv, mod->base + CCOR_COEFF_REG(2), 0x0000); + + write(priv, mod->base + CCOR_COEFF_REG(3), 0x0000); + write(priv, mod->base + CCOR_COEFF_REG(4), 0x1000); + write(priv, mod->base + CCOR_COEFF_REG(5), 0x0000); + + write(priv, mod->base + CCOR_COEFF_REG(6), 0x0000); + write(priv, mod->base + CCOR_COEFF_REG(7), 0x0000); + write(priv, mod->base + CCOR_COEFF_REG(8), 0x1000); + + write(priv, mod->base + CCOR_OFFSET_R_REG, 0x00000000); + write(priv, mod->base + CCOR_OFFSET_G_REG, 0x00000000); + write(priv, mod->base + CCOR_OFFSET_B_REG, 0x00000000); + + return 0; + } + + /* + * Coefficient n for color correction matrix. + * + * RkISP1 coefficients are 11-bit signed fixed-point numbers with 4 bit + * integer and 7 bit fractional part, ranging from -8 (0x400) to +7.992 + * (0x3FF). 0 is represented by 0x000 and a coefficient value of 1 as + * 0x080. + * + * RPP gains are 16-bit signed fixed-point numbers with 4 bit integer + * and 12 bit fractional part ranging from -8 (0x8000) to +7.9996 + * (0x7FFF). 0 is represented by 0x0000 and a coefficient value of 1 as + * 0x1000. + * + * Map the RkISP1 value range by left shifting by 5. + */ + write(priv, mod->base + CCOR_COEFF_REG(0), cfg->config.coeff[0][0] << 5); + write(priv, mod->base + CCOR_COEFF_REG(1), cfg->config.coeff[0][1] << 5); + write(priv, mod->base + CCOR_COEFF_REG(2), cfg->config.coeff[0][2] << 5); + + write(priv, mod->base + CCOR_COEFF_REG(3), cfg->config.coeff[1][0] << 5); + write(priv, mod->base + CCOR_COEFF_REG(4), cfg->config.coeff[1][1] << 5); + write(priv, mod->base + CCOR_COEFF_REG(5), cfg->config.coeff[1][2] << 5); + + write(priv, mod->base + CCOR_COEFF_REG(6), cfg->config.coeff[2][0] << 5); + write(priv, mod->base + CCOR_COEFF_REG(7), cfg->config.coeff[2][1] << 5); + write(priv, mod->base + CCOR_COEFF_REG(8), cfg->config.coeff[2][2] << 5); + + /* + * Offset for color components correction matrix. + * + * Values are a two's complement integer with one sign bit. + * + * The RkISP params are 11-bit while the RPP can be 12, 20 or 24 bit, + * all values are excluding the sign bit. Figure out how much we need + * to adjust the input parameters. + */ + const unsigned int shift =3D mod->info.wbmeas.colorbits - 12 + 1; + + write(priv, mod->base + CCOR_OFFSET_R_REG, cfg->config.ct_offset[0] << sh= ift); + write(priv, mod->base + CCOR_OFFSET_G_REG, cfg->config.ct_offset[1] << sh= ift); + write(priv, mod->base + CCOR_OFFSET_B_REG, cfg->config.ct_offset[2] << sh= ift); + + return 0; +} + const struct rpp_module_ops rppx1_ccor_ops =3D { .probe =3D rppx1_ccor_probe, .start =3D rppx1_ccor_start, + .param_rkisp1 =3D rppx1_ccor_param_rkisp1, }; =20 static int rppx1_ccor_csm_start(struct rpp_module *mod, --=20 2.51.0 From nobody Thu Oct 2 14:12:04 2025 Received: from fout-b1-smtp.messagingengine.com (fout-b1-smtp.messagingengine.com [202.12.124.144]) (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 7969F2E0905; Mon, 15 Sep 2025 17:10:47 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=202.12.124.144 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757956249; cv=none; b=RUa2tcvdHAmjTjtUDOHBxyoOLwPJn9s7+2vAtXLd8KY9IomLvIcHl0elT5yTUkSCAgAfQfJuIfcB8ISWsRVOEcc/72a5ga2LSGqAwh4uSbk6zBivDEIcL3h9vfoO/cKETbFo2q0PtjSC7YAlDY0jhHMuWnNMX8uBwegXApatJ9Q= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757956249; c=relaxed/simple; bh=VpUlgm40R2Hku1s5CV/eXDleSE2Fi0x2hIuafjzNNSo=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=GJh3NEB3MRMVddNn1wWXZDwZpwdV9wBI9zOAPUz6O03o4QGxwkv3kceB0QKBBct8nq7XtEPsjCoUYBVPVv+YT7GED5+cIRZT2yd+lalbvQybboDknV+yUlor/DUD+Dsx/lvdZ/vHRQ8jxna37v5Wqv0pNyObSA9u0ZRPOYw32vg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=ragnatech.se; spf=pass smtp.mailfrom=ragnatech.se; dkim=pass (2048-bit key) header.d=ragnatech.se header.i=@ragnatech.se header.b=H9OYoVZn; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=HNPd/zVs; arc=none smtp.client-ip=202.12.124.144 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=ragnatech.se Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=ragnatech.se Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=ragnatech.se header.i=@ragnatech.se header.b="H9OYoVZn"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="HNPd/zVs" Received: from phl-compute-05.internal (phl-compute-05.internal [10.202.2.45]) by mailfout.stl.internal (Postfix) with ESMTP id 70CF41D0019E; Mon, 15 Sep 2025 13:10:46 -0400 (EDT) Received: from phl-mailfrontend-01 ([10.202.2.162]) by phl-compute-05.internal (MEProxy); Mon, 15 Sep 2025 13:10:46 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ragnatech.se; h= cc:cc:content-transfer-encoding:content-type:content-type:date :date:from:from:in-reply-to:in-reply-to:message-id:mime-version :references:reply-to:subject:subject:to:to; s=fm3; t=1757956246; x=1758042646; bh=a9NVSUliwPYYQEYpUBXXaDEsjdNbdV03ITBqz/1pNgE=; b= H9OYoVZn6GAeIgSgfA4YwFfz/77ICC1ESUFlm22saaFtWORc0+5Z9+QtkUWhEppM wGgg7pGwD58HcfPuv6c2jon4GXokFiwoLSYzragvnC6XmjRNihW5XNjdaxa9hmgv l+I73xPubHQXZdf1EUWM/DCHZRcYQU2z21r4V9TUJq2e4qsqZ6mf+dvHEvzmTTzv loDdVXV6Jdgw7K+MQZslSMZHqozWt6IAeBADQHFSFNJ+0c4SWpiqPgKqsC/MEmqP Sy3u9J+9rGnZNgv0qmQxJwwT5lnUKzzlY43lI3N3VKc3uM+SH5mapNWOOt47ncNr tvWdFYcN9iybv74Leq/HTg== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:content-type:date:date:feedback-id:feedback-id :from:from:in-reply-to:in-reply-to:message-id:mime-version :references:reply-to:subject:subject:to:to:x-me-proxy :x-me-sender:x-me-sender:x-sasl-enc; s=fm1; t=1757956246; x= 1758042646; bh=a9NVSUliwPYYQEYpUBXXaDEsjdNbdV03ITBqz/1pNgE=; b=H NPd/zVs8MOk7XSXr8kyPYTKdFlTDAxUp9pkebX6+NFRBbR9h3zgCcq4kGgr6kKx6 6RLMdzVMCjnWOnFGzbZd2G0VRWKh1st6Rnd4lACTyHodjFoREH4sHJtUK+S8ggcq 7lwbfKQvI6P4z/2X1uz9wMRuuHy5SgXSiJTeSxOQQ53e8ZRIZveMh4BIvO9YgBOB P2yjqI+29yuVhiLnp4FQgPSz2HjdGXGLgPWEKb5mB0feBChT0eXuNkTp1aTA0Yva 8iR9INTnvVeYjqNxbvoQuyiNCXzdxjOZANr0kD/OErA40+isgG7gOCTgVDr/6kJK dw4iTJCCt6XhySXvbu6iA== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeeffedrtdeggdefkedvhecutefuodetggdotefrod ftvfcurfhrohhfihhlvgemucfhrghsthforghilhdpuffrtefokffrpgfnqfghnecuuegr ihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmdenucfjug hrpefhvfevufffkffojghfgggtgfesthekredtredtjeenucfhrhhomheppfhikhhlrghs ucfunpguvghrlhhunhguuceonhhikhhlrghsrdhsohguvghrlhhunhguodhrvghnvghsrg hssehrrghgnhgrthgvtghhrdhsvgeqnecuggftrfgrthhtvghrnhepheeigfeuveeutdef hfehgeekvedtleeuueekveefudehhffhjeffgfegffelfeegnecuvehluhhsthgvrhfuih iivgepudenucfrrghrrghmpehmrghilhhfrhhomhepnhhikhhlrghsrdhsohguvghrlhhu nhgusehrrghgnhgrthgvtghhrdhsvgdpnhgspghrtghpthhtohepjedpmhhouggvpehsmh htphhouhhtpdhrtghpthhtohepmhgthhgvhhgrsgeskhgvrhhnvghlrdhorhhgpdhrtghp thhtohepjhgrtghophhordhmohhnughisehiuggvrghsohhnsghorghrugdrtghomhdprh gtphhtthhopehlrghurhgvnhhtrdhpihhntghhrghrthesihguvggrshhonhgsohgrrhgu rdgtohhmpdhrtghpthhtoheplhhinhhugidqmhgvughirgesvhhgvghrrdhkvghrnhgvlh drohhrghdprhgtphhtthhopehlihhnuhigqdhrvghnvghsrghsqdhsohgtsehvghgvrhdr khgvrhhnvghlrdhorhhgpdhrtghpthhtoheplhhinhhugidqkhgvrhhnvghlsehvghgvrh drkhgvrhhnvghlrdhorhhgpdhrtghpthhtohepnhhikhhlrghsrdhsohguvghrlhhunhgu odhrvghnvghsrghssehrrghgnhgrthgvtghhrdhsvg X-ME-Proxy: Feedback-ID: i80c9496c:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Mon, 15 Sep 2025 13:10:45 -0400 (EDT) From: =?UTF-8?q?Niklas=20S=C3=B6derlund?= To: Mauro Carvalho Chehab , Jacopo Mondi , Laurent Pinchart , linux-media@vger.kernel.org, linux-renesas-soc@vger.kernel.org, linux-kernel@vger.kernel.org Cc: =?UTF-8?q?Niklas=20S=C3=B6derlund?= Subject: [PATCH v2 09/12] media: rppx1: Add support for Lens Shade Correction Date: Mon, 15 Sep 2025 19:07:40 +0200 Message-ID: <20250915170743.106249-10-niklas.soderlund+renesas@ragnatech.se> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20250915170743.106249-1-niklas.soderlund+renesas@ragnatech.se> References: <20250915170743.106249-1-niklas.soderlund+renesas@ragnatech.se> 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 Extend the RPPX1 driver to allow setting the Lens Shade Correction (LSC) configuration using the RkISP1 parameter buffer format. It uses the RPPX1 framework for parameters and its writer abstraction to allow the user to control how (and when) configuration is applied to the RPPX1. As the RkISP1 parameters buffer only describes one quadrant of the lens, this is due to the RkISP1 hardware only allowing one quadrant to be programmed to hardware. The hardware then extrapolates this to the other three quadrants of the lens. For RPP all four quadrants are individually programmable. To compensate for the driver need to extrapolate all four quadrants from the RkISP1 parameters buffer information. Signed-off-by: Niklas S=C3=B6derlund --- .../platform/dreamchip/rppx1/rpp_params.c | 3 + .../platform/dreamchip/rppx1/rppx1_lsc.c | 126 ++++++++++++++++++ 2 files changed, 129 insertions(+) diff --git a/drivers/media/platform/dreamchip/rppx1/rpp_params.c b/drivers/= media/platform/dreamchip/rppx1/rpp_params.c index c2c8349a2837..8491ce88ab90 100644 --- a/drivers/media/platform/dreamchip/rppx1/rpp_params.c +++ b/drivers/media/platform/dreamchip/rppx1/rpp_params.c @@ -33,6 +33,9 @@ int rppx1_params_rkisp1(struct rppx1 *rpp, struct rkisp1_= ext_params_cfg *cfg, case RKISP1_EXT_PARAMS_BLOCK_TYPE_CTK: module =3D &rpp->post.ccor; break; + case RKISP1_EXT_PARAMS_BLOCK_TYPE_LSC: + module =3D &rpp->pre1.lsc; + break; case RKISP1_EXT_PARAMS_BLOCK_TYPE_AWB_MEAS: module =3D &rpp->post.wbmeas; break; diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_lsc.c b/drivers/m= edia/platform/dreamchip/rppx1/rppx1_lsc.c index e8acdf744956..00bdcc4aedb3 100644 --- a/drivers/media/platform/dreamchip/rppx1/rppx1_lsc.c +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_lsc.c @@ -54,6 +54,10 @@ #define LSC_TABLE_SEL_REG 0x00a8 #define LSC_STATUS_REG 0x00ac =20 +#define LSC_R_TABLE_DATA_VALUE(v1, v2) (((v1) & 0xfff) | (((v2) & 0xfff) <= < 12)) +#define LSC_GRAD_VALUE(v1, v2) (((v1) & 0xfff) | (((v2) & 0xfff) << 16)) +#define LSC_SIZE_VALUE(v1, v2) (((v1) & 0x1ff) | (((v2) & 0x1ff) << 16)) + static int rppx1_lsc_probe(struct rpp_module *mod) { /* Version check. */ @@ -63,6 +67,128 @@ static int rppx1_lsc_probe(struct rpp_module *mod) return 0; } =20 +static int +rppx1_lsc_param_rkisp1(struct rpp_module *mod, + const union rppx1_params_rkisp1_config *block, + rppx1_reg_write write, void *priv) +{ + const struct rkisp1_ext_params_lsc_config *cfg =3D &block->lsc; + const __u16 *v; + + /* Always disable module as it needs be disabled before configuring. */ + write(priv, mod->base + LSC_CTRL_REG, 0); + if (cfg->header.flags & RKISP1_EXT_PARAMS_FL_BLOCK_DISABLE) + return 0; + + /* + * Program the color correction sectors. + * + * There are two tables to one can program and switch between. As the + * RPPX1 supports preparing a buffer of commands to be applied later + * only use table 0. This works as long as the ISP is not used in + * inline-mode. + * + * For inline-mode support using DMA for configuration is not possible + * so this is not an issue, but needs to be address if inline-mode + * support is added to the driver. + */ + + /* Start writing at beginning of table 0. */ + write(priv, mod->base + LSC_R_TABLE_ADDR_REG, 0); + write(priv, mod->base + LSC_GR_TABLE_ADDR_REG, 0); + write(priv, mod->base + LSC_B_TABLE_ADDR_REG, 0); + write(priv, mod->base + LSC_GB_TABLE_ADDR_REG, 0); + + /* Program data tables. */ + for (unsigned int i =3D 0; i < RKISP1_CIF_ISP_LSC_SAMPLES_MAX; i++) { + const __u16 *r =3D cfg->config.r_data_tbl[i]; + const __u16 *gr =3D cfg->config.gr_data_tbl[i]; + const __u16 *b =3D cfg->config.b_data_tbl[i]; + const __u16 *gb =3D cfg->config.gb_data_tbl[i]; + unsigned int j; + + for (j =3D 0; j < RKISP1_CIF_ISP_LSC_SAMPLES_MAX - 1; j +=3D 2) { + write(priv, mod->base + LSC_R_TABLE_DATA_REG, + LSC_R_TABLE_DATA_VALUE(r[j], r[j + 1])); + write(priv, mod->base + LSC_GR_TABLE_DATA_REG, + LSC_R_TABLE_DATA_VALUE(gr[j], gr[j + 1])); + write(priv, mod->base + LSC_B_TABLE_DATA_REG, + LSC_R_TABLE_DATA_VALUE(b[j], b[j + 1])); + write(priv, mod->base + LSC_GB_TABLE_DATA_REG, + LSC_R_TABLE_DATA_VALUE(gb[j], gb[j + 1])); + } + + write(priv, mod->base + LSC_R_TABLE_DATA_REG, + LSC_R_TABLE_DATA_VALUE(r[j], 0)); + write(priv, mod->base + LSC_GR_TABLE_DATA_REG, + LSC_R_TABLE_DATA_VALUE(gr[j], 0)); + write(priv, mod->base + LSC_B_TABLE_DATA_REG, + LSC_R_TABLE_DATA_VALUE(b[j], 0)); + write(priv, mod->base + LSC_GB_TABLE_DATA_REG, + LSC_R_TABLE_DATA_VALUE(gb[j], 0)); + } + + /* Activate table 0. */ + write(priv, mod->base + LSC_TABLE_SEL_REG, 0); + + /* + * Program X- and Y- sizes, and gradients. + * + * The RPP ISP can describe each quarter of the lens individually, this + * differs from the Rk1ISP which can only describe one quarter of lens + * with software and then extrapolates the other three. + * + * To adjust for this extrapolate the three missing quadrants using + * software for the RPP ISP. + */ + + v =3D cfg->config.x_grad_tbl; + write(priv, mod->base + LSC_XGRAD_01_REG, LSC_GRAD_VALUE(v[0], v[1])); + write(priv, mod->base + LSC_XGRAD_23_REG, LSC_GRAD_VALUE(v[2], v[3])); + write(priv, mod->base + LSC_XGRAD_45_REG, LSC_GRAD_VALUE(v[4], v[5])); + write(priv, mod->base + LSC_XGRAD_67_REG, LSC_GRAD_VALUE(v[6], v[7])); + write(priv, mod->base + LSC_XGRAD_89_REG, LSC_GRAD_VALUE(v[7], v[6])); + write(priv, mod->base + LSC_XGRAD_1011_REG, LSC_GRAD_VALUE(v[5], v[4])); + write(priv, mod->base + LSC_XGRAD_1213_REG, LSC_GRAD_VALUE(v[3], v[2])); + write(priv, mod->base + LSC_XGRAD_1415_REG, LSC_GRAD_VALUE(v[1], v[0])); + + v =3D cfg->config.y_grad_tbl; + write(priv, mod->base + LSC_YGRAD_01_REG, LSC_GRAD_VALUE(v[0], v[1])); + write(priv, mod->base + LSC_YGRAD_23_REG, LSC_GRAD_VALUE(v[2], v[3])); + write(priv, mod->base + LSC_YGRAD_45_REG, LSC_GRAD_VALUE(v[4], v[5])); + write(priv, mod->base + LSC_YGRAD_67_REG, LSC_GRAD_VALUE(v[6], v[7])); + write(priv, mod->base + LSC_YGRAD_89_REG, LSC_GRAD_VALUE(v[7], v[6])); + write(priv, mod->base + LSC_YGRAD_1011_REG, LSC_GRAD_VALUE(v[5], v[4])); + write(priv, mod->base + LSC_YGRAD_1213_REG, LSC_GRAD_VALUE(v[3], v[2])); + write(priv, mod->base + LSC_YGRAD_1415_REG, LSC_GRAD_VALUE(v[1], v[0])); + + v =3D cfg->config.x_size_tbl; + write(priv, mod->base + LSC_XSIZE_01_REG, LSC_GRAD_VALUE(v[0], v[1])); + write(priv, mod->base + LSC_XSIZE_23_REG, LSC_GRAD_VALUE(v[2], v[3])); + write(priv, mod->base + LSC_XSIZE_45_REG, LSC_GRAD_VALUE(v[4], v[5])); + write(priv, mod->base + LSC_XSIZE_67_REG, LSC_GRAD_VALUE(v[6], v[7])); + write(priv, mod->base + LSC_XSIZE_89_REG, LSC_GRAD_VALUE(v[7], v[6])); + write(priv, mod->base + LSC_XSIZE_1011_REG, LSC_GRAD_VALUE(v[5], v[4])); + write(priv, mod->base + LSC_XSIZE_1213_REG, LSC_GRAD_VALUE(v[3], v[2])); + write(priv, mod->base + LSC_XSIZE_1415_REG, LSC_GRAD_VALUE(v[1], v[0])); + + v =3D cfg->config.y_size_tbl; + write(priv, mod->base + LSC_YSIZE_01_REG, LSC_GRAD_VALUE(v[0], v[1])); + write(priv, mod->base + LSC_YSIZE_23_REG, LSC_GRAD_VALUE(v[2], v[3])); + write(priv, mod->base + LSC_YSIZE_45_REG, LSC_GRAD_VALUE(v[4], v[5])); + write(priv, mod->base + LSC_YSIZE_67_REG, LSC_GRAD_VALUE(v[6], v[7])); + write(priv, mod->base + LSC_YSIZE_89_REG, LSC_GRAD_VALUE(v[7], v[6])); + write(priv, mod->base + LSC_YSIZE_1011_REG, LSC_GRAD_VALUE(v[5], v[4])); + write(priv, mod->base + LSC_YSIZE_1213_REG, LSC_GRAD_VALUE(v[3], v[2])); + write(priv, mod->base + LSC_YSIZE_1415_REG, LSC_GRAD_VALUE(v[1], v[0])); + + /* Enable module. */ + write(priv, mod->base + LSC_CTRL_REG, LSC_CTRL_LSC_EN); + + return 0; +} + const struct rpp_module_ops rppx1_lsc_ops =3D { .probe =3D rppx1_lsc_probe, + .param_rkisp1 =3D rppx1_lsc_param_rkisp1, }; --=20 2.51.0 From nobody Thu Oct 2 14:12:04 2025 Received: from fout-b1-smtp.messagingengine.com (fout-b1-smtp.messagingengine.com [202.12.124.144]) (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 9BC802E8898; Mon, 15 Sep 2025 17:10:49 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=202.12.124.144 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757956251; cv=none; b=MmVmcRsaMtJaylVy339Zf78PplWXlHfrSnAnjYr2XMo3Ql+ktnzCCn2CjlIVE9xb+bH++qUJ0RP47AV/Zf3qE5tWlB+/LRMgcJZYSQzbMyf4FTbOWv5eO8Jmgly9+yvmGtYg55XYegTEif5+w+RIdAskmwl5a5RfjFPk3YxmbRQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757956251; c=relaxed/simple; bh=9jLfsL29twbk73qCdvUOsFap3ZSR6S454TnERf29xjU=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=ktKOzikP1A6V3XyXW5y5/Uf5ppgg8yoydVEtf68m6M3+xzS9IaZbnio/hPq/1Yq81a56WvRv7IxGKysfB/PeAU3A4RLZG0rQmcHPRJMrX+nEFHiBaDAFa73IXUW9IWtWof8O9q66rVssn+m2ndN43JFkis+GUNR5W5U3bvX1su4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=ragnatech.se; spf=pass smtp.mailfrom=ragnatech.se; dkim=pass (2048-bit key) header.d=ragnatech.se header.i=@ragnatech.se header.b=YsfQ8rkY; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=W6buPIGS; arc=none smtp.client-ip=202.12.124.144 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=ragnatech.se Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=ragnatech.se Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=ragnatech.se header.i=@ragnatech.se header.b="YsfQ8rkY"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="W6buPIGS" Received: from phl-compute-06.internal (phl-compute-06.internal [10.202.2.46]) by mailfout.stl.internal (Postfix) with ESMTP id B1E6E1D000DA; Mon, 15 Sep 2025 13:10:48 -0400 (EDT) Received: from phl-mailfrontend-02 ([10.202.2.163]) by phl-compute-06.internal (MEProxy); Mon, 15 Sep 2025 13:10:48 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ragnatech.se; h= cc:cc:content-transfer-encoding:content-type:content-type:date :date:from:from:in-reply-to:in-reply-to:message-id:mime-version :references:reply-to:subject:subject:to:to; s=fm3; t=1757956248; x=1758042648; bh=8lA0JfCOB0gy3cxcc2e66XgBZDeOEuWImdLphWXoGOY=; b= YsfQ8rkYD5oJ000TFmgK9Q/EeiTDneZ2qjrqa/NnSRjPDEcpjmy/iWROLr1DuIh7 XccGrhPk1K/5tNMjEHJBoXGCV5SQR5I53nM4K1Cp5b2fBEsKizX/czoMx3N3lc3m rfbbSSmsTHpCaiptfthhGRQ2G3HHDjOXdh/SjVghJO/LHPuHLIE0Bo68XNXRzURL N2cEzucaUJFy1yB+qgEIfVmPzcgRxM9ikIZhw1PN1RaNDtLFNsDnaVhLHaYasXXy 9AduAliUAmMJhHf3AuF5zhu1Mcmk5eMifz0dMbz+K2HLOEVf926MAcnkeSKD3Fwr HOUv0Ho77IfUdVD+rVv0oA== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:content-type:date:date:feedback-id:feedback-id :from:from:in-reply-to:in-reply-to:message-id:mime-version :references:reply-to:subject:subject:to:to:x-me-proxy :x-me-sender:x-me-sender:x-sasl-enc; s=fm1; t=1757956248; x= 1758042648; bh=8lA0JfCOB0gy3cxcc2e66XgBZDeOEuWImdLphWXoGOY=; b=W 6buPIGSRouAlUFfTAypG8ZD1gilGWpFN56L3P7Nh+DWDdd4RcPMURiRw8HpQN++3 tCavmw/ND9Vu8ODSk+TVZsPIw0FtHOFXDH9/E2HT/gqggnwmJcRVKVKsWzOLSifn fZR0AwKVrZPl3LWcZRKnLJYtgHOxbZiapazLUj0SH8pUO7fyUjs1nEPciBCfnOS7 TXGXfNj6pHnsaTrM3/pdaa0h9UG8kmt8pQr7V5vnpeJx4A48yctNX9jSdFG5q3Aq c1zZJ8LSvuP9RWJyxW9ZWACvpvLcl+1YXNjs+XXGzZUPaI4IxlnlK2+CWMAUZ1ic CuU7+DOHo19jKekcoi45Q== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeeffedrtdeggdefkedviecutefuodetggdotefrod ftvfcurfhrohhfihhlvgemucfhrghsthforghilhdpuffrtefokffrpgfnqfghnecuuegr ihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmdenucfjug hrpefhvfevufffkffojghfgggtgfesthekredtredtjeenucfhrhhomheppfhikhhlrghs ucfunpguvghrlhhunhguuceonhhikhhlrghsrdhsohguvghrlhhunhguodhrvghnvghsrg hssehrrghgnhgrthgvtghhrdhsvgeqnecuggftrfgrthhtvghrnhepheeigfeuveeutdef hfehgeekvedtleeuueekveefudehhffhjeffgfegffelfeegnecuvehluhhsthgvrhfuih iivgeptdenucfrrghrrghmpehmrghilhhfrhhomhepnhhikhhlrghsrdhsohguvghrlhhu nhgusehrrghgnhgrthgvtghhrdhsvgdpnhgspghrtghpthhtohepjedpmhhouggvpehsmh htphhouhhtpdhrtghpthhtohepmhgthhgvhhgrsgeskhgvrhhnvghlrdhorhhgpdhrtghp thhtohepjhgrtghophhordhmohhnughisehiuggvrghsohhnsghorghrugdrtghomhdprh gtphhtthhopehlrghurhgvnhhtrdhpihhntghhrghrthesihguvggrshhonhgsohgrrhgu rdgtohhmpdhrtghpthhtoheplhhinhhugidqmhgvughirgesvhhgvghrrdhkvghrnhgvlh drohhrghdprhgtphhtthhopehlihhnuhigqdhrvghnvghsrghsqdhsohgtsehvghgvrhdr khgvrhhnvghlrdhorhhgpdhrtghpthhtoheplhhinhhugidqkhgvrhhnvghlsehvghgvrh drkhgvrhhnvghlrdhorhhgpdhrtghpthhtohepnhhikhhlrghsrdhsohguvghrlhhunhgu odhrvghnvghsrghssehrrghgnhgrthgvtghhrdhsvg X-ME-Proxy: Feedback-ID: i80c9496c:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Mon, 15 Sep 2025 13:10:47 -0400 (EDT) From: =?UTF-8?q?Niklas=20S=C3=B6derlund?= To: Mauro Carvalho Chehab , Jacopo Mondi , Laurent Pinchart , linux-media@vger.kernel.org, linux-renesas-soc@vger.kernel.org, linux-kernel@vger.kernel.org Cc: =?UTF-8?q?Niklas=20S=C3=B6derlund?= Subject: [PATCH v2 10/12] media: rppx1: Add support for Gamma Correction Date: Mon, 15 Sep 2025 19:07:41 +0200 Message-ID: <20250915170743.106249-11-niklas.soderlund+renesas@ragnatech.se> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20250915170743.106249-1-niklas.soderlund+renesas@ragnatech.se> References: <20250915170743.106249-1-niklas.soderlund+renesas@ragnatech.se> 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 Extend the RPPX1 driver to allow setting the Gamma Correction configuration using the RkISP1 parameter buffer format. It uses the RPPX1 framework for parameters and its writer abstraction to allow the user to control how (and when) configuration is applied to the RPPX1. As the RkISP1 parameters are all 10-bit while RPP can be either 12- or 24-bit, the driver corrects for this allowing the RkISP1 parameters to be used. Signed-off-by: Niklas S=C3=B6derlund --- .../platform/dreamchip/rppx1/rpp_params.c | 3 ++ .../media/platform/dreamchip/rppx1/rppx1_ga.c | 34 +++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/drivers/media/platform/dreamchip/rppx1/rpp_params.c b/drivers/= media/platform/dreamchip/rppx1/rpp_params.c index 8491ce88ab90..323ee792426e 100644 --- a/drivers/media/platform/dreamchip/rppx1/rpp_params.c +++ b/drivers/media/platform/dreamchip/rppx1/rpp_params.c @@ -33,6 +33,9 @@ int rppx1_params_rkisp1(struct rppx1 *rpp, struct rkisp1_= ext_params_cfg *cfg, case RKISP1_EXT_PARAMS_BLOCK_TYPE_CTK: module =3D &rpp->post.ccor; break; + case RKISP1_EXT_PARAMS_BLOCK_TYPE_GOC: + module =3D &rpp->hv.ga; + break; case RKISP1_EXT_PARAMS_BLOCK_TYPE_LSC: module =3D &rpp->pre1.lsc; break; diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_ga.c b/drivers/me= dia/platform/dreamchip/rppx1/rppx1_ga.c index d6c7f951cf29..a748190ef2dc 100644 --- a/drivers/media/platform/dreamchip/rppx1/rppx1_ga.c +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_ga.c @@ -43,7 +43,41 @@ static int rppx1_ga_start(struct rpp_module *mod, return 0; } =20 +static int +rppx1_ga_param_rkisp1(struct rpp_module *mod, + const union rppx1_params_rkisp1_config *block, + rppx1_reg_write write, void *priv) +{ + const struct rkisp1_ext_params_goc_config *cfg =3D &block->goc; + + /* If the modules is disabled, simply bypass it. */ + if (cfg->header.flags & RKISP1_EXT_PARAMS_FL_BLOCK_DISABLE) { + write(priv, mod->base + GAMMA_OUT_ENABLE_REG, 0); + return 0; + } + + write(priv, mod->base + GAMMA_OUT_MODE_REG, + cfg->config.mode ? GAMMA_OUT_ENABLE_GAMMA_OUT_EN : 0); + + /* + * The RkISP mean values are 10-bit while the RPP can be 12 or 24 bit. + * Figure out how much we need to adjust the output values. + */ + const unsigned int shift =3D mod->info.ga.colorbits - 10; + + for (unsigned int i =3D 0; i < RKISP1_CIF_ISP_GAMMA_OUT_MAX_SAMPLES_V10; = i++) + write(priv, mod->base + GAMMA_OUT_Y_REG(i), + cfg->config.gamma_y[i] << shift); + + /* Enable module. */ + write(priv, mod->base + GAMMA_OUT_ENABLE_REG, + GAMMA_OUT_ENABLE_GAMMA_OUT_EN); + + return 0; +} + const struct rpp_module_ops rppx1_ga_ops =3D { .probe =3D rppx1_ga_probe, .start =3D rppx1_ga_start, + .param_rkisp1 =3D rppx1_ga_param_rkisp1, }; --=20 2.51.0 From nobody Thu Oct 2 14:12:04 2025 Received: from fout-b1-smtp.messagingengine.com (fout-b1-smtp.messagingengine.com [202.12.124.144]) (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 01C0C2E8E11; Mon, 15 Sep 2025 17:10:51 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=202.12.124.144 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757956254; cv=none; b=XsqPrDGU0zPP+3RwGaNRQAXCTkMovT2JwlBZ11qNtqa4yhe9Fx6ZBm4ybCN6eEVe/YRTEOSb6C07STMReokK01Kb7Fe5+cEOWKoJ3LjozR8E0FcbSNLF64SQp7nzf7lZlWUeOz+9aWuTU99XQ2RxRqKmm4W0ftU+zuxlNqnDiDY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757956254; c=relaxed/simple; bh=JdKksoleHwDfypyqI1C2y1PS/6OG2Bc8sLaAhqgSsR0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=rRYENYJmZ9TtR6SB458kYvyUvFiWeN0jDMtJv9m3IXxx1eme5Xh/H8D7maZtJDEhgVVZWYkiaZZY8z5ZGqpjv6KuNgEz2pBqsspabA/x5tzahEv1XwaF1OBtPhIV/uFUTBBF9HjjwSC2W9KwzG50DMUTEuAcgR16BYuT5pVzp3Q= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=ragnatech.se; spf=pass smtp.mailfrom=ragnatech.se; dkim=pass (2048-bit key) header.d=ragnatech.se header.i=@ragnatech.se header.b=dUtag4jD; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=Ps7a37jN; arc=none smtp.client-ip=202.12.124.144 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=ragnatech.se Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=ragnatech.se Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=ragnatech.se header.i=@ragnatech.se header.b="dUtag4jD"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="Ps7a37jN" Received: from phl-compute-02.internal (phl-compute-02.internal [10.202.2.42]) by mailfout.stl.internal (Postfix) with ESMTP id E4CD51D0019E; Mon, 15 Sep 2025 13:10:50 -0400 (EDT) Received: from phl-mailfrontend-01 ([10.202.2.162]) by phl-compute-02.internal (MEProxy); Mon, 15 Sep 2025 13:10:51 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ragnatech.se; h= cc:cc:content-transfer-encoding:content-type:content-type:date :date:from:from:in-reply-to:in-reply-to:message-id:mime-version :references:reply-to:subject:subject:to:to; s=fm3; t=1757956250; x=1758042650; bh=k1c6FF/0ffYhghyfOZg2sbeFixAoZwRJZ/7I6n8Zyys=; b= dUtag4jDFhm8SLp7ewcTYtTE52Yk8LhLNPs+kmyx8ItSogrqe+syPVGRXXgcLzEo jOrTj0VpH8MJGKPcG8qq2aOa4lbGfseUX/gBRm+UasZ0xLfo6CDTlZJfnyNpArTI V1psuBNQoP5Pbz/RosaFOZK5m+s8q26jvm+k1oIe56RZukfbCQZoYN/DNpk3m5Gs QIUOMqOGWzV2nm3Cp2/VVqXMucukXT95fpHrseUPF8khai/cgpIkJD9/GZAS7yPy FnhAT08InpVim6XEs40WsBXWeIEWFdyW0DKlsloYgtVu8kX5+PKclbRphQtMc+Vy hKp88fnyXQ6zTm2xAEO+Zw== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:content-type:date:date:feedback-id:feedback-id :from:from:in-reply-to:in-reply-to:message-id:mime-version :references:reply-to:subject:subject:to:to:x-me-proxy :x-me-sender:x-me-sender:x-sasl-enc; s=fm1; t=1757956250; x= 1758042650; bh=k1c6FF/0ffYhghyfOZg2sbeFixAoZwRJZ/7I6n8Zyys=; b=P s7a37jNl6f/769ye1erG3iqu3cd86b6bG9R7Gq7THguEukCvQcGDcFYeWhkVMYxg 85xX8ZgKFXNO37Lzq5AygYgGDazEB00sfbyQ5qg3D5CLvwz69jy45Gal+01o1Jin VNJvqHVUd5a+5y2dERzvYTLGCigKXQShx7hpLQavVN/NhUE3Qj960+xzbgMPT+Uv IzELybrkRFnhIGnkJDdge8TrsTKpUvSSBT+ENFfNhcOejFg9RVz86w5A8Vj3QSgP xT5a/Od2MDFW5LT3z7NHrZn9skOUCUm+wKGd3RpuIVP9bz+esoiKRlxaLrj9pofe k5OlzV1Q0s4Dl0gFW/CbQ== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeeffedrtdeggdefkedviecutefuodetggdotefrod ftvfcurfhrohhfihhlvgemucfhrghsthforghilhdpuffrtefokffrpgfnqfghnecuuegr ihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmdenucfjug hrpefhvfevufffkffojghfgggtgfesthekredtredtjeenucfhrhhomheppfhikhhlrghs ucfunpguvghrlhhunhguuceonhhikhhlrghsrdhsohguvghrlhhunhguodhrvghnvghsrg hssehrrghgnhgrthgvtghhrdhsvgeqnecuggftrfgrthhtvghrnhepheeigfeuveeutdef hfehgeekvedtleeuueekveefudehhffhjeffgfegffelfeegnecuvehluhhsthgvrhfuih iivgepvdenucfrrghrrghmpehmrghilhhfrhhomhepnhhikhhlrghsrdhsohguvghrlhhu nhgusehrrghgnhgrthgvtghhrdhsvgdpnhgspghrtghpthhtohepjedpmhhouggvpehsmh htphhouhhtpdhrtghpthhtohepmhgthhgvhhgrsgeskhgvrhhnvghlrdhorhhgpdhrtghp thhtohepjhgrtghophhordhmohhnughisehiuggvrghsohhnsghorghrugdrtghomhdprh gtphhtthhopehlrghurhgvnhhtrdhpihhntghhrghrthesihguvggrshhonhgsohgrrhgu rdgtohhmpdhrtghpthhtoheplhhinhhugidqmhgvughirgesvhhgvghrrdhkvghrnhgvlh drohhrghdprhgtphhtthhopehlihhnuhigqdhrvghnvghsrghsqdhsohgtsehvghgvrhdr khgvrhhnvghlrdhorhhgpdhrtghpthhtoheplhhinhhugidqkhgvrhhnvghlsehvghgvrh drkhgvrhhnvghlrdhorhhgpdhrtghpthhtohepnhhikhhlrghsrdhsohguvghrlhhunhgu odhrvghnvghsrghssehrrghgnhgrthgvtghhrdhsvg X-ME-Proxy: Feedback-ID: i80c9496c:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Mon, 15 Sep 2025 13:10:50 -0400 (EDT) From: =?UTF-8?q?Niklas=20S=C3=B6derlund?= To: Mauro Carvalho Chehab , Jacopo Mondi , Laurent Pinchart , linux-media@vger.kernel.org, linux-renesas-soc@vger.kernel.org, linux-kernel@vger.kernel.org Cc: =?UTF-8?q?Niklas=20S=C3=B6derlund?= Subject: [PATCH v2 11/12] media: rppx1: Add support for Bayer Demosaicing Date: Mon, 15 Sep 2025 19:07:42 +0200 Message-ID: <20250915170743.106249-12-niklas.soderlund+renesas@ragnatech.se> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20250915170743.106249-1-niklas.soderlund+renesas@ragnatech.se> References: <20250915170743.106249-1-niklas.soderlund+renesas@ragnatech.se> 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 Extend the RPPX1 driver to allow setting the Bayer Demosaicing configuration using the RkISP1 parameter buffer format. It uses the RPPX1 framework for parameters and its writer abstraction to allow the user to control how (and when) configuration is applied to the RPPX1. As the RkISP1 parameters are all 6- or 10-bit while RPP are either 8- or 16-bit, the driver corrects for this allowing the RkISP1 parameters to be used. One particularity is that the RkISP1 driver lumps all settings in the FILT_LUM_WEIGHT register in a single value in the configuration buffer. As the format is slightly different for RPP we need to break it out and fix it before applying it to the RPP. Signed-off-by: Niklas S=C3=B6derlund --- .../platform/dreamchip/rppx1/rpp_params.c | 5 + .../media/platform/dreamchip/rppx1/rppx1_db.c | 112 ++++++++++++++++++ 2 files changed, 117 insertions(+) diff --git a/drivers/media/platform/dreamchip/rppx1/rpp_params.c b/drivers/= media/platform/dreamchip/rppx1/rpp_params.c index 323ee792426e..ff075d6b81a7 100644 --- a/drivers/media/platform/dreamchip/rppx1/rpp_params.c +++ b/drivers/media/platform/dreamchip/rppx1/rpp_params.c @@ -30,6 +30,11 @@ int rppx1_params_rkisp1(struct rppx1 *rpp, struct rkisp1= _ext_params_cfg *cfg, case RKISP1_EXT_PARAMS_BLOCK_TYPE_AWB_GAIN: module =3D &rpp->pre1.awbg; break; + case RKISP1_EXT_PARAMS_BLOCK_TYPE_FLT: + case RKISP1_EXT_PARAMS_BLOCK_TYPE_BDM: + /* Both types handled by the same block. */ + module =3D &rpp->post.db; + break; case RKISP1_EXT_PARAMS_BLOCK_TYPE_CTK: module =3D &rpp->post.ccor; break; diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_db.c b/drivers/me= dia/platform/dreamchip/rppx1/rppx1_db.c index 5e233896cfc8..4a2a3719d7ed 100644 --- a/drivers/media/platform/dreamchip/rppx1/rppx1_db.c +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_db.c @@ -39,6 +39,118 @@ static int rppx1_db_probe(struct rpp_module *mod) return 0; } =20 +static int +rppx1_db_param_rkisp1_flt(struct rpp_module *mod, + const union rppx1_params_rkisp1_config *block, + rppx1_reg_write write, void *priv) +{ + const struct rkisp1_ext_params_flt_config *cfg =3D &block->flt; + u32 gain, kink, min; + + /* If the modules is disabled, simply bypass it. */ + if (cfg->header.flags & RKISP1_EXT_PARAMS_FL_BLOCK_DISABLE) { + write(priv, mod->base + FILT_MODE_REG, 0); + return 0; + } + + /* + * RkISP1 values are 10-bit, RPP are 18-bit. Conversion verified with + * table in datasheet and libcamera pipeline for rkisp1. + */ + write(priv, mod->base + FILT_THRESH_BL0_REG, cfg->config.thresh_bl0 << 8); + write(priv, mod->base + FILT_THRESH_BL0_REG, cfg->config.thresh_bl1 << 8); + write(priv, mod->base + FILT_THRESH_SH0_REG, cfg->config.thresh_sh0 << 8); + write(priv, mod->base + FILT_THRESH_SH1_REG, cfg->config.thresh_sh1 << 8); + + /* + * RkISP1 values are 6-bit, RPP are 8-bit. Conversion verified with + * table in datasheet and libcamera pipeline for rkisp1. + */ + write(priv, mod->base + FILT_FAC_BL0_REG, cfg->config.fac_bl0 << 2); + write(priv, mod->base + FILT_FAC_BL1_REG, cfg->config.fac_bl1 << 2); + write(priv, mod->base + FILT_FAC_MID_REG, cfg->config.fac_mid << 2); + write(priv, mod->base + FILT_FAC_SH0_REG, cfg->config.fac_sh0 << 2); + write(priv, mod->base + FILT_FAC_SH1_REG, cfg->config.fac_sh1 << 2); + + /* + * For unknown reasons the 3 fields of the FILT_LUM_WEIGHT register + * have been lumped together in a single field in the configuration + * data and written as is to the hardware. For RkISP1 the register + * layout is, + * + * 31:19 unused + * 18:16 lum_weight_gain + * 15:8 lum_weight_kink + * 7:0 lum_weight_min + * + * For RPP the register layout is similar but kink and gain have higher + * precision. + * + * 31 unused + * 30:28 lum_weight_gain + * 27:24 unused + * 23:12 lum_weight_kink + * 11:0 lum_weight_min + * + * Break apart the RkISP1 format, scale kink and min, and map to RPP. + */ + gain =3D (cfg->config.lum_weight & GENMASK(18, 16)) >> 16; + kink =3D (cfg->config.lum_weight & GENMASK(15, 8)) >> 8; + min =3D cfg->config.lum_weight & GENMASK(7, 0); + + write(priv, mod->base + FILT_LUM_WEIGHT_REG, + (gain << 28) | ((kink << 4) << 12) | (min << 4)); + + write(priv, mod->base + FILT_MODE_REG, + (cfg->config.chr_v_mode << 4) | + (cfg->config.chr_h_mode << 6) | + (cfg->config.grn_stage1 << 8) | + (cfg->config.mode ? FILT_MODE_FILT_MODE : 0) | + FILT_MODE_FILT_ENABLE); + + return 0; +} + +static int +rppx1_db_param_rkisp1_bdm(struct rpp_module *mod, + const union rppx1_params_rkisp1_config *block, + rppx1_reg_write write, void *priv) +{ + const struct rkisp1_ext_params_bdm_config *cfg =3D &block->bdm; + + /* If the modules is disabled, simply bypass it. */ + if (cfg->header.flags & RKISP1_EXT_PARAMS_FL_BLOCK_DISABLE) { + write(priv, mod->base + DEMOSAIC_REG, 0x400); + return 0; + } + + /* + * Threshold for Bayer demosaicing texture detection. + * + * RkISP1 threshold are 8-bit, RPP threshold are 16-bit. Map the RkISP1 + * value range by left shifting by 8. + */ + write(priv, mod->base + DEMOSAIC_REG, cfg->config.demosaic_th << 8); + + return 0; +} + +static int +rppx1_db_param_rkisp1(struct rpp_module *mod, + const union rppx1_params_rkisp1_config *block, + rppx1_reg_write write, void *priv) +{ + switch (block->header.type) { + case RKISP1_EXT_PARAMS_BLOCK_TYPE_FLT: + return rppx1_db_param_rkisp1_flt(mod, block, write, priv); + case RKISP1_EXT_PARAMS_BLOCK_TYPE_BDM: + return rppx1_db_param_rkisp1_bdm(mod, block, write, priv); + } + + return -EINVAL; +} + const struct rpp_module_ops rppx1_db_ops =3D { .probe =3D rppx1_db_probe, + .param_rkisp1 =3D rppx1_db_param_rkisp1, }; --=20 2.51.0 From nobody Thu Oct 2 14:12:04 2025 Received: from fhigh-b2-smtp.messagingengine.com (fhigh-b2-smtp.messagingengine.com [202.12.124.153]) (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 14AEE2FB099; Mon, 15 Sep 2025 17:10:54 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=202.12.124.153 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757956256; cv=none; b=EYDB77cnmO80XHnqkZXz5HqjdkwFtkvQgdTJYicnQC/Q+q6/vco3r1FUG+VVagUBc3TIpbuZG0xUTbvmw8rwaAnJjmSzdMoA22QXVXTQW1/LdrAewYSCspQocHR9XMrf6CrlJJ8yKFT5kPv5xlj6NcmFycVAfuN9YiEsTWIxCBQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757956256; c=relaxed/simple; bh=B5XzzmfVL55ibXxzrC5j36Zc2gtZNUDaeNSlffTSryU=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=NQCY8qoa9QKpvsdEo4XmTraViac2IK+OfUDBLL439pADIvh/L/qp2X71f9E7u7vgYKGkuaQcLEkeO7b3J2pqKtlYF5xYbFUvupKOyPMa+JWp025RUupZ4i9rwgWoW/nXRgIUiHEJiSwzPbgjWxkwQkRuBodEhjxPtV6vV4oCtR4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=ragnatech.se; spf=pass smtp.mailfrom=ragnatech.se; dkim=pass (2048-bit key) header.d=ragnatech.se header.i=@ragnatech.se header.b=aRp16Vvp; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=gkxzzFP7; arc=none smtp.client-ip=202.12.124.153 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=ragnatech.se Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=ragnatech.se Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=ragnatech.se header.i=@ragnatech.se header.b="aRp16Vvp"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="gkxzzFP7" Received: from phl-compute-10.internal (phl-compute-10.internal [10.202.2.50]) by mailfhigh.stl.internal (Postfix) with ESMTP id 3882E7A0185; Mon, 15 Sep 2025 13:10:53 -0400 (EDT) Received: from phl-mailfrontend-02 ([10.202.2.163]) by phl-compute-10.internal (MEProxy); Mon, 15 Sep 2025 13:10:53 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ragnatech.se; h= cc:cc:content-transfer-encoding:content-type:content-type:date :date:from:from:in-reply-to:in-reply-to:message-id:mime-version :references:reply-to:subject:subject:to:to; s=fm3; t=1757956253; x=1758042653; bh=WeuVSMOFTQzdVY6K+1Y+/FCR6eqbyKn4bZi7CQ8MXOg=; b= aRp16VvpAsWP5HieLSvVwI4HwR433o7jIh3moo1RdXMr6y1IWGpbtuhuUzQlWQEt kG7QJzr133qRZvyy1qUWIl2g46GRSmzxliaM+wcwMs8mRsLOumRue7jG5os1Bcqe O/mHMjuogt4IWmK0/UEfYSLiNTvylbWe0uX0DZNlnNQwyvooB+PPN9qhXJRSzyvc wQ59s2W1yEiXtvndmufUoMDcIKWKVWEi3PE9Zz8MID479E84iCOYBcBtDMh0tgZx Gfzr625crBjIUaS1QRKOfljeBs2Y4a/5Aby07zLLc32DzE7JYJKNiPAv6J5v+HcC o5hJT5AM5o25OHcqofSohQ== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:content-type:date:date:feedback-id:feedback-id :from:from:in-reply-to:in-reply-to:message-id:mime-version :references:reply-to:subject:subject:to:to:x-me-proxy :x-me-sender:x-me-sender:x-sasl-enc; s=fm1; t=1757956253; x= 1758042653; bh=WeuVSMOFTQzdVY6K+1Y+/FCR6eqbyKn4bZi7CQ8MXOg=; b=g kxzzFP7uC4k6BUGKtFWVVsa7feIlrf/DdpDGkq4Im8WLlD7grOa/4hbxfAtoHcSw SO0cv8929+NMaTibLb4tIVk4Yg6SZFHEuGSwjeoHXMX89nWKwFe1IPN+SYN9P8KH LVoGiUdyUyjcljyKZE2b01fUyQNnLmIRJDkU/zlhBk8b16qEXwj7m71jCg4WBfnj RyvLyaLduNK9R6cwvK6hLzZkbqU72ylpRXrDejd13XQbvPD8IL0agDmQXTARHt7Y XIC1oiIYsCGNfm7sXWSwGe4ZFZFd53VfxpstQZgJ7+sY8pemk31OcFjJnRXD2TeC UfMpeMPgrjEpOQLBkKplA== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeeffedrtdeggdefkedvhecutefuodetggdotefrod ftvfcurfhrohhfihhlvgemucfhrghsthforghilhdpuffrtefokffrpgfnqfghnecuuegr ihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmdenucfjug hrpefhvfevufffkffojghfgggtgfesthekredtredtjeenucfhrhhomheppfhikhhlrghs ucfunpguvghrlhhunhguuceonhhikhhlrghsrdhsohguvghrlhhunhguodhrvghnvghsrg hssehrrghgnhgrthgvtghhrdhsvgeqnecuggftrfgrthhtvghrnhephfeuledvhfdvffeh tdeikedtgeejgeetgfffudffleduveetudehkedvvdelfedvnecuffhomhgrihhnpehgpg hflhhtrdhgsgdpghgpfhhlthdrghhrpdhgrghinhdrnhhfnecuvehluhhsthgvrhfuihii vgeptdenucfrrghrrghmpehmrghilhhfrhhomhepnhhikhhlrghsrdhsohguvghrlhhunh gusehrrghgnhgrthgvtghhrdhsvgdpnhgspghrtghpthhtohepjedpmhhouggvpehsmhht phhouhhtpdhrtghpthhtohepmhgthhgvhhgrsgeskhgvrhhnvghlrdhorhhgpdhrtghpth htohepjhgrtghophhordhmohhnughisehiuggvrghsohhnsghorghrugdrtghomhdprhgt phhtthhopehlrghurhgvnhhtrdhpihhntghhrghrthesihguvggrshhonhgsohgrrhgurd gtohhmpdhrtghpthhtoheplhhinhhugidqmhgvughirgesvhhgvghrrdhkvghrnhgvlhdr ohhrghdprhgtphhtthhopehlihhnuhigqdhrvghnvghsrghsqdhsohgtsehvghgvrhdrkh gvrhhnvghlrdhorhhgpdhrtghpthhtoheplhhinhhugidqkhgvrhhnvghlsehvghgvrhdr khgvrhhnvghlrdhorhhgpdhrtghpthhtohepnhhikhhlrghsrdhsohguvghrlhhunhguod hrvghnvghsrghssehrrghgnhgrthgvtghhrdhsvg X-ME-Proxy: Feedback-ID: i80c9496c:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Mon, 15 Sep 2025 13:10:52 -0400 (EDT) From: =?UTF-8?q?Niklas=20S=C3=B6derlund?= To: Mauro Carvalho Chehab , Jacopo Mondi , Laurent Pinchart , linux-media@vger.kernel.org, linux-renesas-soc@vger.kernel.org, linux-kernel@vger.kernel.org Cc: =?UTF-8?q?Niklas=20S=C3=B6derlund?= Subject: [PATCH v2 12/12] media: rppx1: Add support for Bilateral Denoising Date: Mon, 15 Sep 2025 19:07:43 +0200 Message-ID: <20250915170743.106249-13-niklas.soderlund+renesas@ragnatech.se> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20250915170743.106249-1-niklas.soderlund+renesas@ragnatech.se> References: <20250915170743.106249-1-niklas.soderlund+renesas@ragnatech.se> 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 Extend the RPPX1 driver to allow setting the Bilateral Denoising configuration using the RkISP1 parameter buffer format. It uses the RPPX1 framework for parameters and its writer abstraction to allow the user to control how (and when) configuration is applied to the RPPX1. The parameter bit-sizes matches RkISP1 so there is no need to convert between the two. Some bit flags are inverted however and RPP have different registers for each color components coefficients where RkISP1 have one for covering all. The biggest difference is that RPP have dropped the hardware bit AWB_GAIN_COMP. Luckily it's behavior is easy to emulate in software. Signed-off-by: Niklas S=C3=B6derlund --- .../platform/dreamchip/rppx1/rpp_params.c | 5 + .../media/platform/dreamchip/rppx1/rppx1_bd.c | 158 ++++++++++++++++++ 2 files changed, 163 insertions(+) diff --git a/drivers/media/platform/dreamchip/rppx1/rpp_params.c b/drivers/= media/platform/dreamchip/rppx1/rpp_params.c index ff075d6b81a7..b7b8adfe9337 100644 --- a/drivers/media/platform/dreamchip/rppx1/rpp_params.c +++ b/drivers/media/platform/dreamchip/rppx1/rpp_params.c @@ -41,6 +41,11 @@ int rppx1_params_rkisp1(struct rppx1 *rpp, struct rkisp1= _ext_params_cfg *cfg, case RKISP1_EXT_PARAMS_BLOCK_TYPE_GOC: module =3D &rpp->hv.ga; break; + case RKISP1_EXT_PARAMS_BLOCK_TYPE_DPF: + case RKISP1_EXT_PARAMS_BLOCK_TYPE_DPF_STRENGTH: + /* Both types handled by the same block. */ + module =3D &rpp->pre1.bd; + break; case RKISP1_EXT_PARAMS_BLOCK_TYPE_LSC: module =3D &rpp->pre1.lsc; break; diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_bd.c b/drivers/me= dia/platform/dreamchip/rppx1/rppx1_bd.c index acbfbcd59591..3bb717d87ec5 100644 --- a/drivers/media/platform/dreamchip/rppx1/rppx1_bd.c +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_bd.c @@ -47,6 +47,164 @@ static int rppx1_bd_probe(struct rpp_module *mod) return 0; } =20 +static int +rppx1_bd_param_rkisp1_main(struct rpp_module *mod, + const union rppx1_params_rkisp1_config *block, + rppx1_reg_write write, void *priv) +{ + const struct rkisp1_ext_params_dpf_config *cfg =3D &block->dpf; + unsigned int isp_dpf_mode, spatial_coeff; + + /* If the modules is disabled, simply bypass it. */ + if (cfg->header.flags & RKISP1_EXT_PARAMS_FL_BLOCK_DISABLE) { + write(priv, mod->base + DPF_MODE_REG, 0); + return 0; + } + + /* + * RkISP1 have an extra hardware flag AWB_GAIN_COMP which was removed + * in RPP DB module version 4 and later. If the bit is set the + * programmed gains will be processed, if it's not set a default value + * of 1 (0x100) will be used. From the RPP documentation for DB version + * 4 changelog. + * + * Removed RPP_DPF_MODE::awb_gain_comp. Always use programmed + * nf-gains for gain compensation. + * + * We can emulate this behavior if we keep track of when the RkISP1 do + * set the flag. + */ + bool awb_gain_comp =3D false; + + switch (cfg->config.gain.mode) { + case RKISP1_CIF_ISP_DPF_GAIN_USAGE_NF_GAINS: + awb_gain_comp =3D true; + isp_dpf_mode =3D DPF_MODE_USE_NF_GAIN; + break; + case RKISP1_CIF_ISP_DPF_GAIN_USAGE_LSC_GAINS: + isp_dpf_mode =3D DPF_MODE_LSC_GAIN_COMP; + break; + case RKISP1_CIF_ISP_DPF_GAIN_USAGE_NF_LSC_GAINS: + awb_gain_comp =3D true; + isp_dpf_mode =3D DPF_MODE_USE_NF_GAIN | DPF_MODE_LSC_GAIN_COMP; + break; + case RKISP1_CIF_ISP_DPF_GAIN_USAGE_AWB_GAINS: + awb_gain_comp =3D true; + isp_dpf_mode =3D 0; + break; + case RKISP1_CIF_ISP_DPF_GAIN_USAGE_AWB_LSC_GAINS: + awb_gain_comp =3D true; + isp_dpf_mode =3D DPF_MODE_LSC_GAIN_COMP; + break; + case RKISP1_CIF_ISP_DPF_GAIN_USAGE_DISABLED: + default: + isp_dpf_mode =3D 0; + break; + } + + /* NOTE: Hardware bit for scale_mode is inverted compared to RkISP1. */ + if (cfg->config.nll.scale_mode =3D=3D RKISP1_CIF_ISP_NLL_SCALE_LINEAR) + isp_dpf_mode |=3D DPF_MODE_NLL_SEGMENTATION; + if (cfg->config.rb_flt.fltsize =3D=3D RKISP1_CIF_ISP_DPF_RB_FILTERSIZE_9x= 9) + isp_dpf_mode |=3D DPF_MODE_RB_FILTER_SIZE; + if (!cfg->config.rb_flt.r_enable) + isp_dpf_mode |=3D DPF_MODE_R_FILTER_OFF; + if (!cfg->config.rb_flt.b_enable) + isp_dpf_mode |=3D DPF_MODE_B_FILTER_OFF; + if (!cfg->config.g_flt.gb_enable) + isp_dpf_mode |=3D DPF_MODE_GB_FILTER_OFF; + if (!cfg->config.g_flt.gr_enable) + isp_dpf_mode |=3D DPF_MODE_GR_FILTER_OFF; + + isp_dpf_mode |=3D DPF_MODE_DPF_ENABLE; + + if (awb_gain_comp) { + write(priv, mod->base + DPF_NF_GAIN_B_REG, cfg->config.gain.nf_b_gain); + write(priv, mod->base + DPF_NF_GAIN_R_REG, cfg->config.gain.nf_r_gain); + write(priv, mod->base + DPF_NF_GAIN_GB_REG, cfg->config.gain.nf_gb_gain); + write(priv, mod->base + DPF_NF_GAIN_GR_REG, cfg->config.gain.nf_gr_gain); + } else { + write(priv, mod->base + DPF_NF_GAIN_B_REG, 0x100); + write(priv, mod->base + DPF_NF_GAIN_R_REG, 0x100); + write(priv, mod->base + DPF_NF_GAIN_GB_REG, 0x100); + write(priv, mod->base + DPF_NF_GAIN_GR_REG, 0x100); + } + + /* The RkISP1 hardware have a single register for all components. */ + for (unsigned int i =3D 0; i < RKISP1_CIF_ISP_DPF_MAX_NLF_COEFFS; i++) { + write(priv, mod->base + DPF_NLL_G_COEFF_REG(i), cfg->config.nll.coeff[i]= ); + write(priv, mod->base + DPF_NLL_RB_COEFF_REG(i), cfg->config.nll.coeff[i= ]); + } + + spatial_coeff =3D cfg->config.g_flt.spatial_coeff[0] | + (cfg->config.g_flt.spatial_coeff[1] << 8) | + (cfg->config.g_flt.spatial_coeff[2] << 16) | + (cfg->config.g_flt.spatial_coeff[3] << 24); + write(priv, mod->base + DPF_S_WEIGHT_G_1_4_REG, spatial_coeff); + + spatial_coeff =3D cfg->config.g_flt.spatial_coeff[4] | + (cfg->config.g_flt.spatial_coeff[5] << 8); + write(priv, mod->base + DPF_S_WEIGHT_G_5_6_REG, spatial_coeff); + + spatial_coeff =3D cfg->config.rb_flt.spatial_coeff[0] | + (cfg->config.rb_flt.spatial_coeff[1] << 8) | + (cfg->config.rb_flt.spatial_coeff[2] << 16) | + (cfg->config.rb_flt.spatial_coeff[3] << 24); + write(priv, mod->base + DPF_S_WEIGHT_RB_1_4_REG, spatial_coeff); + + spatial_coeff =3D cfg->config.rb_flt.spatial_coeff[4] | + (cfg->config.rb_flt.spatial_coeff[5] << 8); + write(priv, mod->base + DPF_S_WEIGHT_RB_5_6_REG, spatial_coeff); + + /* + * Bilateral Denoising does not react on RPP_HDR_UPD::regs_gen_cfg_upd + * (see Table 25). A change in configuration needs write of 1 to + * RPP_HDR_UPD::regs_cfg_upd. + */ + write(priv, 4, 1); + + write(priv, mod->base + DPF_MODE_REG, isp_dpf_mode); + + return 0; +} + +static int +rppx1_bd_param_rkisp1_strength(struct rpp_module *mod, + const union rppx1_params_rkisp1_config *block, + rppx1_reg_write write, void *priv) +{ + const struct rkisp1_ext_params_dpf_strength_config *cfg =3D &block->dpfs; + + /* If the modules is disabled, simply bypass it. */ + if (cfg->header.flags & RKISP1_EXT_PARAMS_FL_BLOCK_DISABLE) { + write(priv, mod->base + DPF_MODE_REG, 0); + return 0; + } + + /* Module version 5 adds shadowing for mode and spatial weights. */ + write(priv, mod->base + DPF_STRENGTH_R_REG, cfg->config.r); + write(priv, mod->base + DPF_STRENGTH_G_REG, cfg->config.g); + write(priv, mod->base + DPF_STRENGTH_B_REG, cfg->config.b); + + return 0; +} + +static int +rppx1_bd_param_rkisp1(struct rpp_module *mod, + const union rppx1_params_rkisp1_config *block, + rppx1_reg_write write, void *priv) +{ + switch (block->header.type) { + case RKISP1_EXT_PARAMS_BLOCK_TYPE_DPF: + return rppx1_bd_param_rkisp1_main(mod, block, write, priv); + case RKISP1_EXT_PARAMS_BLOCK_TYPE_DPF_STRENGTH: + return rppx1_bd_param_rkisp1_strength(mod, block, write, priv); + } + + return -EINVAL; +} + const struct rpp_module_ops rppx1_bd_ops =3D { .probe =3D rppx1_bd_probe, + .param_rkisp1 =3D rppx1_bd_param_rkisp1, }; --=20 2.51.0