From patchwork Wed Jan 8 18:44:44 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Helen Koike X-Patchwork-Id: 11324301 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 16327921 for ; Wed, 8 Jan 2020 18:45:58 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id E5D202051A for ; Wed, 8 Jan 2020 18:45:57 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="FAC6JMwN" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org E5D202051A Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=collabora.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-rockchip-bounces+patchwork-linux-rockchip=patchwork.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=fn07AYk0HIVr++7kjinCJHN20pu9khYaCEZxiL1NRiw=; b=FAC6JMwNLu9rxC J9IyYCSV/mYolAGvG6iw1tdbie88aB9rkLWeInK8mL6VhyxIsgOx8tjs0Dc6hETJ0IDfTgPkh4J6u 2GHly/8SVtmPpAWqa4kCh5U6yQg8CjjKSP19wW2dHRAg9etbXHA8G1DT5eCLJ44C5iHtz3tK+H+vf NCO0RjX8VyUdyIkslU/VNopCRbNgPLJLGMrRzYzZmKsIXFyiHicRFg1tNwq9+4pjA7Ti/9MmgRKJE PlJpEh9FWZN5gOjeYn1dVEvrOsxA2HBioPDF7yuHUpRTCbLn1DWSUnOW4WNIa0hosgVqhMFkJDV34 lq1meaJuraKR82U2pUNw==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1ipGL3-0008Ki-IV; Wed, 08 Jan 2020 18:45:53 +0000 Received: from bhuna.collabora.co.uk ([46.235.227.227]) by bombadil.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1ipGKg-0007s5-Lw; Wed, 08 Jan 2020 18:45:33 +0000 Received: from [127.0.0.1] (localhost [127.0.0.1]) (Authenticated sender: koike) with ESMTPSA id 4CBF42912EF From: Helen Koike To: linux-rockchip@lists.infradead.org Subject: [PATCH v13 01/11] media: staging: phy-rockchip-dphy-rx0: add Rockchip MIPI Synopsys DPHY RX0 driver Date: Wed, 8 Jan 2020 15:44:44 -0300 Message-Id: <20200108184454.825725-2-helen.koike@collabora.com> X-Mailer: git-send-email 2.24.0 In-Reply-To: <20200108184454.825725-1-helen.koike@collabora.com> References: <20200108184454.825725-1-helen.koike@collabora.com> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20200108_104531_013095_5990AD06 X-CRM114-Status: GOOD ( 19.68 ) X-Spam-Score: -0.0 (/) X-Spam-Report: SpamAssassin version 3.4.2 on bombadil.infradead.org summary: Content analysis details: (-0.0 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at https://www.dnswl.org/, no trust [46.235.227.227 listed in list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record -0.0 SPF_HELO_PASS SPF: HELO matches SPF record 0.0 UNPARSEABLE_RELAY Informational: message has unparseable relay lines X-BeenThere: linux-rockchip@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Upstream kernel work for Rockchip platforms List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: mark.rutland@arm.com, devicetree@vger.kernel.org, eddie.cai.linux@gmail.com, kernel@collabora.com, heiko@sntech.de, linux-arm-kernel@lists.infradead.org, ezequiel@collabora.com, gregkh@linuxfoundation.org, linux-kernel@vger.kernel.org, tfiga@chromium.org, Helen Koike , robh+dt@kernel.org, hans.verkuil@cisco.com, laurent.pinchart@ideasonboard.com, sakari.ailus@linux.intel.com, joacim.zetterling@gmail.com, mchehab@kernel.org, andrey.konovalov@linaro.org, jacob-chen@iotwrt.com, linux-media@vger.kernel.org Sender: "Linux-rockchip" Errors-To: linux-rockchip-bounces+patchwork-linux-rockchip=patchwork.kernel.org@lists.infradead.org From: Ezequiel Garcia Add driver for Rockchip MIPI Synopsys DPHY driver Signed-off-by: Tomasz Figa Signed-off-by: Ezequiel Garcia Signed-off-by: Helen Koike Reviewed-by: Laurent Pinchart --- Changes in v13: - This driver only supports dphy RX0, and won't support TX1RX1, as it will be provided by the dsi1 controller. So rename it to add rx0 suffixe. - Fixed text and descriptions as pointed by Laurent, Ezequiel and Sakari. - Removed redundant register update GRF_DPHY_RX0_TESTCLK=1 - Minor coding style adjustments as suggested by Laurent. - Removed gfr lookup by phandler. Changes in v12: - several cleanups - remove "rx" from function names, as this driver only supports rx Changes in v11: - fix checkpatch errors Changes in v10: None Changes in v9: - Move to staging - replace memcpy by a directly assignment - remove unecessary ret variable in rockchip_dphy_init - s/0x1/1 - s/0x0/0 - coding style changes - dphy_reg variable sizes - variables from int to unsigned int - rename functions to start with rk_ - rename dphy0 to rx - fix hardcoded lane0 usage - disable rx on power off - general cleanups of unused variables Changes in v8: - Remove boiler plate license text Changes in v7: - Migrate dphy specific code from drivers/media/platform/rockchip/isp1/mipi_dphy_sy.c to drivers/phy/rockchip/phy-rockchip-dphy.c - Drop support for rk3288 - Drop support for dphy txrx - code styling and checkpatch fixes drivers/staging/media/Kconfig | 2 + drivers/staging/media/Makefile | 1 + .../media/phy-rockchip-dphy-rx0/Kconfig | 13 + .../media/phy-rockchip-dphy-rx0/Makefile | 2 + .../staging/media/phy-rockchip-dphy-rx0/TODO | 6 + .../phy-rockchip-dphy-rx0.c | 388 ++++++++++++++++++ 6 files changed, 412 insertions(+) create mode 100644 drivers/staging/media/phy-rockchip-dphy-rx0/Kconfig create mode 100644 drivers/staging/media/phy-rockchip-dphy-rx0/Makefile create mode 100644 drivers/staging/media/phy-rockchip-dphy-rx0/TODO create mode 100644 drivers/staging/media/phy-rockchip-dphy-rx0/phy-rockchip-dphy-rx0.c diff --git a/drivers/staging/media/Kconfig b/drivers/staging/media/Kconfig index 642adc4c24d2..7cbc739ff182 100644 --- a/drivers/staging/media/Kconfig +++ b/drivers/staging/media/Kconfig @@ -38,4 +38,6 @@ source "drivers/staging/media/ipu3/Kconfig" source "drivers/staging/media/soc_camera/Kconfig" +source "drivers/staging/media/phy-rockchip-dphy-rx0/Kconfig" + endif diff --git a/drivers/staging/media/Makefile b/drivers/staging/media/Makefile index 2f1711a8aeed..33395e439301 100644 --- a/drivers/staging/media/Makefile +++ b/drivers/staging/media/Makefile @@ -8,3 +8,4 @@ obj-$(CONFIG_TEGRA_VDE) += tegra-vde/ obj-$(CONFIG_VIDEO_HANTRO) += hantro/ obj-$(CONFIG_VIDEO_IPU3_IMGU) += ipu3/ obj-$(CONFIG_SOC_CAMERA) += soc_camera/ +obj-$(CONFIG_PHY_ROCKCHIP_DPHY_RX0) += phy-rockchip-dphy-rx0/ diff --git a/drivers/staging/media/phy-rockchip-dphy-rx0/Kconfig b/drivers/staging/media/phy-rockchip-dphy-rx0/Kconfig new file mode 100644 index 000000000000..bd0147624de1 --- /dev/null +++ b/drivers/staging/media/phy-rockchip-dphy-rx0/Kconfig @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: GPL-2.0-only + +config PHY_ROCKCHIP_DPHY_RX0 + tristate "Rockchip MIPI Synopsys DPHY RX0 driver" + depends on (ARCH_ROCKCHIP || COMPILE_TEST) && OF + select GENERIC_PHY_MIPI_DPHY + select GENERIC_PHY + help + Enable this to support the Rockchip MIPI Synopsys DPHY RX0 + associated to the Rockchip ISP module present in RK3399 SoCs. + + To compile this driver as a module, choose M here: the module + will be called phy-rockchip-dphy-rx0. diff --git a/drivers/staging/media/phy-rockchip-dphy-rx0/Makefile b/drivers/staging/media/phy-rockchip-dphy-rx0/Makefile new file mode 100644 index 000000000000..507e5d0593ab --- /dev/null +++ b/drivers/staging/media/phy-rockchip-dphy-rx0/Makefile @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0 +obj-$(CONFIG_PHY_ROCKCHIP_DPHY_RX0) += phy-rockchip-dphy-rx0.o diff --git a/drivers/staging/media/phy-rockchip-dphy-rx0/TODO b/drivers/staging/media/phy-rockchip-dphy-rx0/TODO new file mode 100644 index 000000000000..ab612e5b27dc --- /dev/null +++ b/drivers/staging/media/phy-rockchip-dphy-rx0/TODO @@ -0,0 +1,6 @@ +The main reason for keeping this in staging is because the only driver +that uses this is rkisp1, which is also in staging. It should be moved together +with rkisp1. + +Please CC patches to Linux Media and +Helen Koike . diff --git a/drivers/staging/media/phy-rockchip-dphy-rx0/phy-rockchip-dphy-rx0.c b/drivers/staging/media/phy-rockchip-dphy-rx0/phy-rockchip-dphy-rx0.c new file mode 100644 index 000000000000..7c4df6d48c43 --- /dev/null +++ b/drivers/staging/media/phy-rockchip-dphy-rx0/phy-rockchip-dphy-rx0.c @@ -0,0 +1,388 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Rockchip MIPI Synopsys DPHY RX0 driver + * + * Copyright (C) 2019 Collabora, Ltd. + * + * Based on: + * + * drivers/media/platform/rockchip/isp1/mipi_dphy_sy.c + * in https://chromium.googlesource.com/chromiumos/third_party/kernel, + * chromeos-4.4 branch. + * + * Copyright (C) 2017 Fuzhou Rockchip Electronics Co., Ltd. + * Jacob Chen + * Shunqian Zheng + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define RK3399_GRF_SOC_CON9 0x6224 +#define RK3399_GRF_SOC_CON21 0x6254 +#define RK3399_GRF_SOC_CON22 0x6258 +#define RK3399_GRF_SOC_CON23 0x625c +#define RK3399_GRF_SOC_CON24 0x6260 +#define RK3399_GRF_SOC_CON25 0x6264 +#define RK3399_GRF_SOC_STATUS1 0xe2a4 + +#define CLOCK_LANE_HS_RX_CONTROL 0x34 +#define LANE0_HS_RX_CONTROL 0x44 +#define LANE1_HS_RX_CONTROL 0x54 +#define LANE2_HS_RX_CONTROL 0x84 +#define LANE3_HS_RX_CONTROL 0x94 +#define LANES_THS_SETTLE_CONTROL 0x75 +#define THS_SETTLE_COUNTER_THRESHOLD 0x04 + +struct hsfreq_range { + u16 range_h; + u8 cfg_bit; +}; + +static const struct hsfreq_range rk3399_mipidphy_hsfreq_ranges[] = { + { 89, 0x00 }, { 99, 0x10 }, { 109, 0x20 }, { 129, 0x01 }, + { 139, 0x11 }, { 149, 0x21 }, { 169, 0x02 }, { 179, 0x12 }, + { 199, 0x22 }, { 219, 0x03 }, { 239, 0x13 }, { 249, 0x23 }, + { 269, 0x04 }, { 299, 0x14 }, { 329, 0x05 }, { 359, 0x15 }, + { 399, 0x25 }, { 449, 0x06 }, { 499, 0x16 }, { 549, 0x07 }, + { 599, 0x17 }, { 649, 0x08 }, { 699, 0x18 }, { 749, 0x09 }, + { 799, 0x19 }, { 849, 0x29 }, { 899, 0x39 }, { 949, 0x0a }, + { 999, 0x1a }, { 1049, 0x2a }, { 1099, 0x3a }, { 1149, 0x0b }, + { 1199, 0x1b }, { 1249, 0x2b }, { 1299, 0x3b }, { 1349, 0x0c }, + { 1399, 0x1c }, { 1449, 0x2c }, { 1500, 0x3c } +}; + +static const char * const rk3399_mipidphy_clks[] = { + "dphy-ref", + "dphy-cfg", + "grf", +}; + +enum dphy_reg_id { + GRF_DPHY_RX0_TURNDISABLE = 0, + GRF_DPHY_RX0_FORCERXMODE, + GRF_DPHY_RX0_FORCETXSTOPMODE, + GRF_DPHY_RX0_ENABLE, + GRF_DPHY_RX0_TESTCLR, + GRF_DPHY_RX0_TESTCLK, + GRF_DPHY_RX0_TESTEN, + GRF_DPHY_RX0_TESTDIN, + GRF_DPHY_RX0_TURNREQUEST, + GRF_DPHY_RX0_TESTDOUT, + GRF_DPHY_TX0_TURNDISABLE, + GRF_DPHY_TX0_FORCERXMODE, + GRF_DPHY_TX0_FORCETXSTOPMODE, + GRF_DPHY_TX0_TURNREQUEST, + GRF_DPHY_TX1RX1_TURNDISABLE, + GRF_DPHY_TX1RX1_FORCERXMODE, + GRF_DPHY_TX1RX1_FORCETXSTOPMODE, + GRF_DPHY_TX1RX1_ENABLE, + GRF_DPHY_TX1RX1_MASTERSLAVEZ, + GRF_DPHY_TX1RX1_BASEDIR, + GRF_DPHY_TX1RX1_ENABLECLK, + GRF_DPHY_TX1RX1_TURNREQUEST, + GRF_DPHY_RX1_SRC_SEL, + /* rk3288 only */ + GRF_CON_DISABLE_ISP, + GRF_CON_ISP_DPHY_SEL, + GRF_DSI_CSI_TESTBUS_SEL, + GRF_DVP_V18SEL, + /* below is for rk3399 only */ + GRF_DPHY_RX0_CLK_INV_SEL, + GRF_DPHY_RX1_CLK_INV_SEL, +}; + +struct dphy_reg { + u16 offset; + u8 mask; + u8 shift; +}; + +#define PHY_REG(_offset, _width, _shift) \ + { .offset = _offset, .mask = BIT(_width) - 1, .shift = _shift, } + +static const struct dphy_reg rk3399_grf_dphy_regs[] = { + [GRF_DPHY_RX0_TURNREQUEST] = PHY_REG(RK3399_GRF_SOC_CON9, 4, 0), + [GRF_DPHY_RX0_CLK_INV_SEL] = PHY_REG(RK3399_GRF_SOC_CON9, 1, 10), + [GRF_DPHY_RX1_CLK_INV_SEL] = PHY_REG(RK3399_GRF_SOC_CON9, 1, 11), + [GRF_DPHY_RX0_ENABLE] = PHY_REG(RK3399_GRF_SOC_CON21, 4, 0), + [GRF_DPHY_RX0_FORCERXMODE] = PHY_REG(RK3399_GRF_SOC_CON21, 4, 4), + [GRF_DPHY_RX0_FORCETXSTOPMODE] = PHY_REG(RK3399_GRF_SOC_CON21, 4, 8), + [GRF_DPHY_RX0_TURNDISABLE] = PHY_REG(RK3399_GRF_SOC_CON21, 4, 12), + [GRF_DPHY_TX0_FORCERXMODE] = PHY_REG(RK3399_GRF_SOC_CON22, 4, 0), + [GRF_DPHY_TX0_FORCETXSTOPMODE] = PHY_REG(RK3399_GRF_SOC_CON22, 4, 4), + [GRF_DPHY_TX0_TURNDISABLE] = PHY_REG(RK3399_GRF_SOC_CON22, 4, 8), + [GRF_DPHY_TX0_TURNREQUEST] = PHY_REG(RK3399_GRF_SOC_CON22, 4, 12), + [GRF_DPHY_TX1RX1_ENABLE] = PHY_REG(RK3399_GRF_SOC_CON23, 4, 0), + [GRF_DPHY_TX1RX1_FORCERXMODE] = PHY_REG(RK3399_GRF_SOC_CON23, 4, 4), + [GRF_DPHY_TX1RX1_FORCETXSTOPMODE] = PHY_REG(RK3399_GRF_SOC_CON23, 4, 8), + [GRF_DPHY_TX1RX1_TURNDISABLE] = PHY_REG(RK3399_GRF_SOC_CON23, 4, 12), + [GRF_DPHY_TX1RX1_TURNREQUEST] = PHY_REG(RK3399_GRF_SOC_CON24, 4, 0), + [GRF_DPHY_RX1_SRC_SEL] = PHY_REG(RK3399_GRF_SOC_CON24, 1, 4), + [GRF_DPHY_TX1RX1_BASEDIR] = PHY_REG(RK3399_GRF_SOC_CON24, 1, 5), + [GRF_DPHY_TX1RX1_ENABLECLK] = PHY_REG(RK3399_GRF_SOC_CON24, 1, 6), + [GRF_DPHY_TX1RX1_MASTERSLAVEZ] = PHY_REG(RK3399_GRF_SOC_CON24, 1, 7), + [GRF_DPHY_RX0_TESTDIN] = PHY_REG(RK3399_GRF_SOC_CON25, 8, 0), + [GRF_DPHY_RX0_TESTEN] = PHY_REG(RK3399_GRF_SOC_CON25, 1, 8), + [GRF_DPHY_RX0_TESTCLK] = PHY_REG(RK3399_GRF_SOC_CON25, 1, 9), + [GRF_DPHY_RX0_TESTCLR] = PHY_REG(RK3399_GRF_SOC_CON25, 1, 10), + [GRF_DPHY_RX0_TESTDOUT] = PHY_REG(RK3399_GRF_SOC_STATUS1, 8, 0), +}; + +struct rk_dphy_drv_data { + const char * const *clks; + unsigned int num_clks; + const struct hsfreq_range *hsfreq_ranges; + unsigned int num_hsfreq_ranges; + const struct dphy_reg *regs; +}; + +struct rk_dphy { + struct device *dev; + struct regmap *grf; + struct clk_bulk_data *clks; + + const struct rk_dphy_drv_data *drv_data; + struct phy_configure_opts_mipi_dphy config; + + u8 hsfreq; +}; + +static inline void rk_dphy_write_grf(struct rk_dphy *priv, + unsigned int index, u8 value) +{ + const struct dphy_reg *reg = &priv->drv_data->regs[index]; + /* Update high word */ + unsigned int val = (value << reg->shift) | + (reg->mask << (reg->shift + 16)); + + if (WARN_ON(!reg->offset)) + return; + regmap_write(priv->grf, reg->offset, val); +} + +static void rk_dphy_write(struct rk_dphy *priv, u8 test_code, u8 test_data) +{ + rk_dphy_write_grf(priv, GRF_DPHY_RX0_TESTDIN, test_code); + rk_dphy_write_grf(priv, GRF_DPHY_RX0_TESTEN, 1); + /* + * With the falling edge on TESTCLK, the TESTDIN[7:0] signal content + * is latched internally as the current test code. Test data is + * programmed internally by rising edge on TESTCLK. + * This code assumes that TESTCLK is already 1. + */ + rk_dphy_write_grf(priv, GRF_DPHY_RX0_TESTCLK, 0); + rk_dphy_write_grf(priv, GRF_DPHY_RX0_TESTEN, 0); + rk_dphy_write_grf(priv, GRF_DPHY_RX0_TESTDIN, test_data); + rk_dphy_write_grf(priv, GRF_DPHY_RX0_TESTCLK, 1); +} + +static void rk_dphy_enable(struct rk_dphy *priv) +{ + rk_dphy_write_grf(priv, GRF_DPHY_RX0_FORCERXMODE, 0); + rk_dphy_write_grf(priv, GRF_DPHY_RX0_FORCETXSTOPMODE, 0); + + /* Disable lane turn around, which is ignored in receive mode */ + rk_dphy_write_grf(priv, GRF_DPHY_RX0_TURNREQUEST, 0); + rk_dphy_write_grf(priv, GRF_DPHY_RX0_TURNDISABLE, 0xf); + + rk_dphy_write_grf(priv, GRF_DPHY_RX0_ENABLE, + GENMASK(priv->config.lanes - 1, 0)); + + /* dphy start */ + rk_dphy_write_grf(priv, GRF_DPHY_RX0_TESTCLK, 1); + rk_dphy_write_grf(priv, GRF_DPHY_RX0_TESTCLR, 1); + usleep_range(100, 150); + rk_dphy_write_grf(priv, GRF_DPHY_RX0_TESTCLR, 0); + usleep_range(100, 150); + + /* set clock lane */ + /* HS hsfreq_range & lane 0 settle bypass */ + rk_dphy_write(priv, CLOCK_LANE_HS_RX_CONTROL, 0); + /* HS RX Control of lane0 */ + rk_dphy_write(priv, LANE0_HS_RX_CONTROL, priv->hsfreq << 1); + /* HS RX Control of lane1 */ + rk_dphy_write(priv, LANE1_HS_RX_CONTROL, priv->hsfreq << 1); + /* HS RX Control of lane2 */ + rk_dphy_write(priv, LANE2_HS_RX_CONTROL, priv->hsfreq << 1); + /* HS RX Control of lane3 */ + rk_dphy_write(priv, LANE3_HS_RX_CONTROL, priv->hsfreq << 1); + /* HS RX Data Lanes Settle State Time Control */ + rk_dphy_write(priv, LANES_THS_SETTLE_CONTROL, + THS_SETTLE_COUNTER_THRESHOLD); + + /* Normal operation */ + rk_dphy_write(priv, 0x0, 0); +} + +static int rk_dphy_configure(struct phy *phy, union phy_configure_opts *opts) +{ + struct rk_dphy *priv = phy_get_drvdata(phy); + const struct rk_dphy_drv_data *drv_data = priv->drv_data; + struct phy_configure_opts_mipi_dphy *config = &opts->mipi_dphy; + unsigned int hsfreq = 0; + unsigned int i; + u64 data_rate_mbps; + int ret; + + /* pass with phy_mipi_dphy_get_default_config (with pixel rate?) */ + ret = phy_mipi_dphy_config_validate(config); + if (ret) + return ret; + + data_rate_mbps = div_u64(config->hs_clk_rate, 1000 * 1000); + + dev_dbg(priv->dev, "lanes %d - data_rate_mbps %llu\n", + config->lanes, data_rate_mbps); + for (i = 0; i < drv_data->num_hsfreq_ranges; i++) { + if (drv_data->hsfreq_ranges[i].range_h >= data_rate_mbps) { + hsfreq = drv_data->hsfreq_ranges[i].cfg_bit; + break; + } + } + if (!hsfreq) + return -EINVAL; + + priv->hsfreq = hsfreq; + priv->config = *config; + return 0; +} + +static int rk_dphy_power_on(struct phy *phy) +{ + struct rk_dphy *priv = phy_get_drvdata(phy); + int ret; + + ret = clk_bulk_enable(priv->drv_data->num_clks, priv->clks); + if (ret) + return ret; + + rk_dphy_enable(priv); + + return 0; +} + +static int rk_dphy_power_off(struct phy *phy) +{ + struct rk_dphy *priv = phy_get_drvdata(phy); + + rk_dphy_write_grf(priv, GRF_DPHY_RX0_ENABLE, 0); + clk_bulk_disable(priv->drv_data->num_clks, priv->clks); + return 0; +} + +static int rk_dphy_init(struct phy *phy) +{ + struct rk_dphy *priv = phy_get_drvdata(phy); + + return clk_bulk_prepare(priv->drv_data->num_clks, priv->clks); +} + +static int rk_dphy_exit(struct phy *phy) +{ + struct rk_dphy *priv = phy_get_drvdata(phy); + + clk_bulk_unprepare(priv->drv_data->num_clks, priv->clks); + return 0; +} + +static const struct phy_ops rk_dphy_ops = { + .power_on = rk_dphy_power_on, + .power_off = rk_dphy_power_off, + .init = rk_dphy_init, + .exit = rk_dphy_exit, + .configure = rk_dphy_configure, + .owner = THIS_MODULE, +}; + +static const struct rk_dphy_drv_data rk3399_mipidphy_drv_data = { + .clks = rk3399_mipidphy_clks, + .num_clks = ARRAY_SIZE(rk3399_mipidphy_clks), + .hsfreq_ranges = rk3399_mipidphy_hsfreq_ranges, + .num_hsfreq_ranges = ARRAY_SIZE(rk3399_mipidphy_hsfreq_ranges), + .regs = rk3399_grf_dphy_regs, +}; + +static const struct of_device_id rk_dphy_dt_ids[] = { + { + .compatible = "rockchip,rk3399-mipi-dphy-rx0", + .data = &rk3399_mipidphy_drv_data, + }, + {} +}; +MODULE_DEVICE_TABLE(of, rk_dphy_dt_ids); + +static int rk_dphy_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + const struct rk_dphy_drv_data *drv_data; + struct phy_provider *phy_provider; + const struct of_device_id *of_id; + struct rk_dphy *priv; + struct phy *phy; + unsigned int i; + int ret; + + if (!dev->parent || !dev->parent->of_node) + return -ENODEV; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + priv->dev = dev; + + priv->grf = syscon_node_to_regmap(dev->parent->of_node); + if (IS_ERR(priv->grf)) { + dev_err(dev, "Can't find GRF syscon\n"); + return -ENODEV; + } + + of_id = of_match_device(rk_dphy_dt_ids, dev); + if (!of_id) + return -EINVAL; + + drv_data = of_id->data; + priv->drv_data = drv_data; + priv->clks = devm_kcalloc(&pdev->dev, drv_data->num_clks, + sizeof(*priv->clks), GFP_KERNEL); + if (!priv->clks) + return -ENOMEM; + for (i = 0; i < drv_data->num_clks; i++) + priv->clks[i].id = drv_data->clks[i]; + ret = devm_clk_bulk_get(&pdev->dev, drv_data->num_clks, priv->clks); + if (ret) + return ret; + + phy = devm_phy_create(dev, np, &rk_dphy_ops); + if (IS_ERR(phy)) { + dev_err(dev, "failed to create phy\n"); + return PTR_ERR(phy); + } + phy_set_drvdata(phy, priv); + + phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); + + return PTR_ERR_OR_ZERO(phy_provider); +} + +static struct platform_driver rk_dphy_driver = { + .probe = rk_dphy_probe, + .driver = { + .name = "rockchip-mipi-dphy-rx0", + .of_match_table = rk_dphy_dt_ids, + }, +}; +module_platform_driver(rk_dphy_driver); + +MODULE_AUTHOR("Ezequiel Garcia "); +MODULE_DESCRIPTION("Rockchip MIPI Synopsys DPHY RX0 driver"); +MODULE_LICENSE("Dual MIT/GPL"); From patchwork Wed Jan 8 18:44:45 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Helen Koike X-Patchwork-Id: 11324307 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 7102E921 for ; Wed, 8 Jan 2020 18:46:04 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 300CF2067D for ; Wed, 8 Jan 2020 18:46:04 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="Fgt9fV4E" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 300CF2067D Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=collabora.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-rockchip-bounces+patchwork-linux-rockchip=patchwork.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=iaH7DUSPSiz8lsLgmfwp0MQstxFcqxvwE6Z5DWp5LP8=; b=Fgt9fV4EXVAl53 njDUxERPNQGK0kiQGCe7Be7nWdYT39ZEqPLD4JnGBcTebAC7a2mWfadv2XJUqdZ3GkpB/Buy/RWU7 YkHa+eOKU/vgYDzxTferMegjLJquQgGupke3Cxyxc/HiVq2FU4j5C70vrQGqF5GFZnxgkkTh01pDs ntgalHQtc5iLTWG9i3nbne8ch6V63p5D5DAhMESyRCUeEEAkqnDR4LPvyafm+OfC77BTiWAtLvfgc /wtTumqLf4pjAk21eaTxeQ21x7Fe79hVwGgahMLPvt52RCzGbJuAuZhjTWg+pOKdZn/iDgsi74Y+Q f0T8H2laWZkfPkyy+pLg==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1ipGL9-0008Qq-2k; Wed, 08 Jan 2020 18:45:59 +0000 Received: from bhuna.collabora.co.uk ([2a00:1098:0:82:1000:25:2eeb:e3e3]) by bombadil.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1ipGKl-00084h-Ho; Wed, 08 Jan 2020 18:45:49 +0000 Received: from [127.0.0.1] (localhost [127.0.0.1]) (Authenticated sender: koike) with ESMTPSA id 888BB2912ED From: Helen Koike To: linux-rockchip@lists.infradead.org Subject: [PATCH v13 02/11] media: staging: rkisp1: add Rockchip ISP1 base driver Date: Wed, 8 Jan 2020 15:44:45 -0300 Message-Id: <20200108184454.825725-3-helen.koike@collabora.com> X-Mailer: git-send-email 2.24.0 In-Reply-To: <20200108184454.825725-1-helen.koike@collabora.com> References: <20200108184454.825725-1-helen.koike@collabora.com> MIME-Version: 1.0 X-Spam-Note: CRM114 run bypassed due to message size (138500 bytes) X-Spam-Score: -0.0 (/) X-Spam-Report: SpamAssassin version 3.4.2 on bombadil.infradead.org summary: Content analysis details: (-0.0 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 SPF_PASS SPF: sender matches SPF record -0.0 SPF_HELO_PASS SPF: HELO matches SPF record 0.0 UNPARSEABLE_RELAY Informational: message has unparseable relay lines X-BeenThere: linux-rockchip@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Upstream kernel work for Rockchip platforms List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: mark.rutland@arm.com, eddie.cai.linux@gmail.com, heiko@sntech.de, laurent.pinchart@ideasonboard.com, joacim.zetterling@gmail.com, kernel@collabora.com, andrey.konovalov@linaro.org, Yichong Zhong , jacob-chen@iotwrt.com, hans.verkuil@cisco.com, Allon Huang , Shunqian Zheng , linux-media@vger.kernel.org, devicetree@vger.kernel.org, Jacob Chen , Jeffy Chen , Helen Koike , robh+dt@kernel.org, mchehab@kernel.org, ezequiel@collabora.com, linux-arm-kernel@lists.infradead.org, gregkh@linuxfoundation.org, linux-kernel@vger.kernel.org, tfiga@chromium.org, sakari.ailus@linux.intel.com, Jacob Chen Sender: "Linux-rockchip" Errors-To: linux-rockchip-bounces+patchwork-linux-rockchip=patchwork.kernel.org@lists.infradead.org Add base driver for Rockchip Image Signal Processing v1 Unit, with isp subdevice and sensor biddings. Signed-off-by: Jacob Chen Signed-off-by: Shunqian Zheng Signed-off-by: Yichong Zhong Signed-off-by: Jacob Chen Signed-off-by: Eddie Cai Signed-off-by: Jeffy Chen Signed-off-by: Allon Huang Signed-off-by: Tomasz Figa [fixed compilation and run time errors regarding new v4l2 async API] Signed-off-by: Laurent Pinchart Signed-off-by: Ezequiel Garcia Signed-off-by: Helen Koike --- Changes in v13: - Remove space from bus_info to be "platform:rkisp1", similar to "platform:vimc" and "platform:vivid" - Call rkisp1_debug_init() at the end of probe, so debugfs_remove_recursive() is not required in the error path. - Improve description in KConfig - Fixed typo Changes in v12: - Several cleanups, renaming, removal of unecessary code, re-writting for redability, re-structuring - Fix format/crop pad propagation - Commit re-organization to not break bisectability - Fix module's license macro Changes in v11: - Fix compiling warnings - Fix checkpatch errors Changes in v10: - unsquash Changes in v9: isp - remove unnecessary double parenthesis - remove double call to media_entity_remote_pad(local) in get_remote_sensor() - remove ctrl_handler from struct rkisp1_isp_subdev - replace v4l2_{dgb,info,warn,err} by dev_* - fix error returned in link_validate - remove s_power() callback - add regwrite/regread wrappers - add macros RKISP1_DEF_SRC_PAD_FMT/RKISP1_DEF_SINK_PAD_FMT - several minor cleanups - s/RKISP1_ISP_PAD_SINK([^_])/RKISP1_ISP_PAD_SINK_VIDEO\1/ - merge tables rkisp1_isp_input_formats and rkisp1_isp_output_formats - in_fmt and out_fmt as pointers - simply struct rkisp1_isp_subdev to work correctly with try format - fix crop/fmt propagation - squash - migrate to staging core - remove ctrl_handler from struct rkisp1_isp_subdev - replace v4l2_{dgb,info,warn,err} by dev_* - s/pr_info/dev_dbg - s/int size/unsigned int size - remove module param rkisp1_debug - coding style fixes - fix error in subdev_notifier_bound, check dphy before assigning to sensor->dphy - remove subdevs fixed size array from rkisp1_pipeline - remove sensors list, as it can be identified from the media topology - Kconfig: add COMPILE_TEST in the dependency - use v4l2_pipeline_pm_use and remove _isp_pipeline_s_power() and _subdev_set_power() - remove struct rkisp1_pipeline and retrieve pipeline information from the media framework - remove remaining rk3288 code - cache pixel rate control in sctruct sensor_async_subdev - remove enum rkisp1_sd_type - squash - move to staging Changes in v8: None Changes in v7: isp - fixed warning because of unknown entity type - fixed v4l2-compliance errors regarding rkisp1 formats, try formats and default values - fix typo riksp1/rkisp1 - redesign: remove mipi/csi subdevice, sensors connect directly to the isp subdevice in the media topology now. As a consequence, remove the hack in mipidphy_g_mbus_config() where information from the sensor was being propagated through the topology. - From the old dphy: * cache get_remote_sensor() in s_stream * use V4L2_CID_PIXEL_RATE instead of V4L2_CID_LINK_FREQ - Replace stream state with a boolean - code styling and checkpatch fixes - fix stop_stream (return after calling stop, do not reenable the stream) - fix rkisp1_isp_sd_get_selection when V4L2_SUBDEV_FORMAT_TRY is set - fix get format in output (isp_sd->out_fmt.mbus_code was being ignored) - s/intput/input - remove #define sd_to_isp_sd(_sd), add a static inline as it will be reused by the capture core - VIDEO_ROCKCHIP_ISP1 selects VIDEOBUF2_VMALLOC - add PHY_ROCKCHIP_DPHY as a dependency for VIDEO_ROCKCHIP_ISP1 - Fix compilation and runtime errors due to bitrotting The code has bit-rotten since March 2018, fix compilation errors. The new V4L2 async notifier API requires notifiers to be initialized by a call to v4l2_async_notifier_init() before being used, do so. - Add missing module device table - use clk_bulk framework - add missing notifiers cleanups - s/strlcpy/strscpy - normalize bus_info name - fix s_stream error path, stream_cnt wans't being decremented properly - use devm_platform_ioremap_resource() helper - s/deice/device - redesign: remove mipi/csi subdevice, sensors connect directly to the isp subdevice in the media topology now. - remove "saved_state" member from rkisp1_stream struct - Reverse the order of MIs - Simplify MI interrupt handling Rather than adding unnecessary indirection, just use stream index to handle MI interrupt enable/disable/clear, since the stream index matches the order of bits now, thanks to previous patch. While at it, remove some dead code. - code styling and checkpatch fixes drivers/staging/media/Kconfig | 2 + drivers/staging/media/Makefile | 1 + drivers/staging/media/rkisp1/Kconfig | 17 + drivers/staging/media/rkisp1/Makefile | 4 + drivers/staging/media/rkisp1/rkisp1-common.c | 37 + drivers/staging/media/rkisp1/rkisp1-common.h | 200 +++ drivers/staging/media/rkisp1/rkisp1-dev.c | 466 +++++++ drivers/staging/media/rkisp1/rkisp1-isp.c | 1133 ++++++++++++++++ drivers/staging/media/rkisp1/rkisp1-regs.h | 1264 ++++++++++++++++++ 9 files changed, 3124 insertions(+) create mode 100644 drivers/staging/media/rkisp1/Kconfig create mode 100644 drivers/staging/media/rkisp1/Makefile create mode 100644 drivers/staging/media/rkisp1/rkisp1-common.c create mode 100644 drivers/staging/media/rkisp1/rkisp1-common.h create mode 100644 drivers/staging/media/rkisp1/rkisp1-dev.c create mode 100644 drivers/staging/media/rkisp1/rkisp1-isp.c create mode 100644 drivers/staging/media/rkisp1/rkisp1-regs.h diff --git a/drivers/staging/media/Kconfig b/drivers/staging/media/Kconfig index 7cbc739ff182..c394abffea86 100644 --- a/drivers/staging/media/Kconfig +++ b/drivers/staging/media/Kconfig @@ -40,4 +40,6 @@ source "drivers/staging/media/soc_camera/Kconfig" source "drivers/staging/media/phy-rockchip-dphy-rx0/Kconfig" +source "drivers/staging/media/rkisp1/Kconfig" + endif diff --git a/drivers/staging/media/Makefile b/drivers/staging/media/Makefile index 33395e439301..ea9fce8014bb 100644 --- a/drivers/staging/media/Makefile +++ b/drivers/staging/media/Makefile @@ -9,3 +9,4 @@ obj-$(CONFIG_VIDEO_HANTRO) += hantro/ obj-$(CONFIG_VIDEO_IPU3_IMGU) += ipu3/ obj-$(CONFIG_SOC_CAMERA) += soc_camera/ obj-$(CONFIG_PHY_ROCKCHIP_DPHY_RX0) += phy-rockchip-dphy-rx0/ +obj-$(CONFIG_VIDEO_ROCKCHIP_ISP1) += rkisp1/ diff --git a/drivers/staging/media/rkisp1/Kconfig b/drivers/staging/media/rkisp1/Kconfig new file mode 100644 index 000000000000..b859a493caba --- /dev/null +++ b/drivers/staging/media/rkisp1/Kconfig @@ -0,0 +1,17 @@ +# SPDX-License-Identifier: GPL-2.0-only + +config VIDEO_ROCKCHIP_ISP1 + tristate "Rockchip Image Signal Processing v1 Unit driver" + depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API + depends on ARCH_ROCKCHIP || COMPILE_TEST + select VIDEOBUF2_DMA_CONTIG + select VIDEOBUF2_VMALLOC + select V4L2_FWNODE + select PHY_ROCKCHIP_DPHY_RX0 + default n + help + Enable this to support the Image Signal Processing (ISP) module + present in RK3399 SoCs. + + To compile this driver as a module, choose M here: the module + will be called rockchip-isp1. diff --git a/drivers/staging/media/rkisp1/Makefile b/drivers/staging/media/rkisp1/Makefile new file mode 100644 index 000000000000..2faa73fc2b7f --- /dev/null +++ b/drivers/staging/media/rkisp1/Makefile @@ -0,0 +1,4 @@ +obj-$(CONFIG_VIDEO_ROCKCHIP_ISP1) += rockchip-isp1.o +rockchip-isp1-objs += rkisp1-common.o \ + rkisp1-dev.o \ + rkisp1-isp.o diff --git a/drivers/staging/media/rkisp1/rkisp1-common.c b/drivers/staging/media/rkisp1/rkisp1-common.c new file mode 100644 index 000000000000..cf889666e166 --- /dev/null +++ b/drivers/staging/media/rkisp1/rkisp1-common.c @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Rockchip ISP1 Driver - Common definitions + * + * Copyright (C) 2019 Collabora, Ltd. + */ + +#include + +#include "rkisp1-common.h" + +static const struct v4l2_rect rkisp1_sd_min_crop = { + .width = RKISP1_ISP_MIN_WIDTH, + .height = RKISP1_ISP_MIN_HEIGHT, + .top = 0, + .left = 0, +}; + +void rkisp1_sd_adjust_crop_rect(struct v4l2_rect *crop, + const struct v4l2_rect *bounds) +{ + v4l2_rect_set_min_size(crop, &rkisp1_sd_min_crop); + v4l2_rect_map_inside(crop, bounds); +} + +void rkisp1_sd_adjust_crop(struct v4l2_rect *crop, + const struct v4l2_mbus_framefmt *bounds) +{ + struct v4l2_rect crop_bounds = { + .left = 0, + .top = 0, + .width = bounds->width, + .height = bounds->height, + }; + + rkisp1_sd_adjust_crop_rect(crop, &crop_bounds); +} diff --git a/drivers/staging/media/rkisp1/rkisp1-common.h b/drivers/staging/media/rkisp1/rkisp1-common.h new file mode 100644 index 000000000000..97e06e9ada28 --- /dev/null +++ b/drivers/staging/media/rkisp1/rkisp1-common.h @@ -0,0 +1,200 @@ +/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */ +/* + * Rockchip ISP1 Driver - Common definitions + * + * Copyright (C) 2019 Collabora, Ltd. + * + * Based on Rockchip ISP1 driver by Rockchip Electronics Co., Ltd. + * Copyright (C) 2017 Rockchip Electronics Co., Ltd. + */ + +#ifndef _RKISP1_COMMON_H +#define _RKISP1_COMMON_H + +#include +#include +#include +#include +#include +#include +#include + +#include "rkisp1-regs.h" + +#define RKISP1_ISP_MAX_WIDTH 4032 +#define RKISP1_ISP_MAX_HEIGHT 3024 +#define RKISP1_ISP_MIN_WIDTH 32 +#define RKISP1_ISP_MIN_HEIGHT 32 + +#define RKISP1_RSZ_MP_SRC_MAX_WIDTH 4416 +#define RKISP1_RSZ_MP_SRC_MAX_HEIGHT 3312 +#define RKISP1_RSZ_SP_SRC_MAX_WIDTH 1920 +#define RKISP1_RSZ_SP_SRC_MAX_HEIGHT 1920 +#define RKISP1_RSZ_SRC_MIN_WIDTH 32 +#define RKISP1_RSZ_SRC_MIN_HEIGHT 16 + +#define RKISP1_DEFAULT_WIDTH 800 +#define RKISP1_DEFAULT_HEIGHT 600 + +#define RKISP1_DRIVER_NAME "rkisp1" +#define RKISP1_BUS_INFO "platform:" RKISP1_DRIVER_NAME + +#define RKISP1_MAX_BUS_CLK 8 + +enum rkisp1_fmt_pix_type { + RKISP1_FMT_YUV, + RKISP1_FMT_RGB, + RKISP1_FMT_BAYER, + RKISP1_FMT_JPEG, +}; + +enum rkisp1_fmt_raw_pat_type { + RKISP1_RAW_RGGB = 0, + RKISP1_RAW_GRBG, + RKISP1_RAW_GBRG, + RKISP1_RAW_BGGR, +}; + +enum rkisp1_isp_pad { + RKISP1_ISP_PAD_SINK_VIDEO, + RKISP1_ISP_PAD_SINK_PARAMS, + RKISP1_ISP_PAD_SOURCE_VIDEO, + RKISP1_ISP_PAD_SOURCE_STATS, + RKISP1_ISP_PAD_MAX +}; + +/* + * struct rkisp1_sensor_async - Sensor information + * @mbus: media bus configuration + */ +struct rkisp1_sensor_async { + struct v4l2_async_subdev asd; + struct v4l2_mbus_config mbus; + unsigned int lanes; + struct v4l2_subdev *sd; + struct v4l2_ctrl *pixel_rate_ctrl; + struct phy *dphy; +}; + +/* + * struct rkisp1_isp - ISP sub-device + * + * See Cropping regions of ISP in rkisp1.c for details + * @sink_frm: input size, don't have to be equal to sensor size + * @sink_fmt: input format + * @sink_crop: crop for sink pad + * @src_fmt: output format + * @src_crop: output size + * + * @is_dphy_errctrl_disabled : if dphy errctrl is disabled (avoid endless interrupt) + * @frame_sequence: used to synchronize frame_id between video devices. + * @quantization: output quantization + */ +struct rkisp1_isp { + struct v4l2_subdev sd; + struct media_pad pads[RKISP1_ISP_PAD_MAX]; + struct v4l2_subdev_pad_config pad_cfg[RKISP1_ISP_PAD_MAX]; + const struct rkisp1_isp_mbus_info *sink_fmt; + const struct rkisp1_isp_mbus_info *src_fmt; + bool is_dphy_errctrl_disabled; + atomic_t frame_sequence; +}; + +struct rkisp1_vdev_node { + struct vb2_queue buf_queue; + struct mutex vlock; /* ioctl serialization mutex */ + struct video_device vdev; + struct media_pad pad; +}; + +struct rkisp1_buffer { + struct vb2_v4l2_buffer vb; + struct list_head queue; + union { + u32 buff_addr[VIDEO_MAX_PLANES]; + void *vaddr[VIDEO_MAX_PLANES]; + }; +}; + +struct rkisp1_dummy_buffer { + void *vaddr; + dma_addr_t dma_addr; + u32 size; +}; + +struct rkisp1_device; + +struct rkisp1_debug { + struct dentry *debugfs_dir; + unsigned long data_loss; + unsigned long pic_size_error; + unsigned long mipi_error; +}; + +/* + * struct rkisp1_device - ISP platform device + * @base_addr: base register address + * @active_sensor: sensor in-use, set when streaming on + * @isp: ISP sub-device + */ +struct rkisp1_device { + void __iomem *base_addr; + int irq; + struct device *dev; + unsigned int clk_size; + struct clk_bulk_data clks[RKISP1_MAX_BUS_CLK]; + struct v4l2_device v4l2_dev; + struct v4l2_ctrl_handler ctrl_handler; + struct media_device media_dev; + struct v4l2_async_notifier notifier; + struct rkisp1_sensor_async *active_sensor; + struct rkisp1_isp isp; + struct media_pipeline pipe; + struct vb2_alloc_ctx *alloc_ctx; + struct rkisp1_debug debug; +}; + +/* + * struct rkisp1_isp_mbus_info - ISP pad format info + * + * Translate mbus_code to hardware format values + * + * @bus_width: used for parallel + */ +struct rkisp1_isp_mbus_info { + u32 mbus_code; + enum rkisp1_fmt_pix_type fmt_type; + u32 mipi_dt; + u32 yuv_seq; + u8 bus_width; + enum rkisp1_fmt_raw_pat_type bayer_pat; + unsigned int direction; +}; + +static inline void +rkisp1_write(struct rkisp1_device *rkisp1, u32 val, unsigned int addr) +{ + writel(val, rkisp1->base_addr + addr); +} + +static inline u32 rkisp1_read(struct rkisp1_device *rkisp1, unsigned int addr) +{ + return readl(rkisp1->base_addr + addr); +} + +void rkisp1_sd_adjust_crop_rect(struct v4l2_rect *crop, + const struct v4l2_rect *bounds); + +void rkisp1_sd_adjust_crop(struct v4l2_rect *crop, + const struct v4l2_mbus_framefmt *bounds); + +int rkisp1_isp_register(struct rkisp1_device *rkisp1, + struct v4l2_device *v4l2_dev); +void rkisp1_isp_unregister(struct rkisp1_device *rkisp1); + +const struct rkisp1_isp_mbus_info *rkisp1_isp_mbus_info_get(u32 mbus_code); + +void rkisp1_isp_isr(struct rkisp1_device *rkisp1); +void rkisp1_mipi_isr(struct rkisp1_device *rkisp1); + +#endif /* _RKISP1_COMMON_H */ diff --git a/drivers/staging/media/rkisp1/rkisp1-dev.c b/drivers/staging/media/rkisp1/rkisp1-dev.c new file mode 100644 index 000000000000..a49442e98bf0 --- /dev/null +++ b/drivers/staging/media/rkisp1/rkisp1-dev.c @@ -0,0 +1,466 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Rockchip ISP1 Driver - Base driver + * + * Copyright (C) 2019 Collabora, Ltd. + * + * Based on Rockchip ISP1 driver by Rockchip Electronics Co., Ltd. + * Copyright (C) 2017 Rockchip Electronics Co., Ltd. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rkisp1-common.h" + +/* + * ISP Details + * ----------- + * + * ISP Comprises with: + * MIPI serial camera interface + * Image Signal Processing + * Many Image Enhancement Blocks + * Crop + * Resizer + * RBG display ready image + * Image Rotation + * + * ISP Block Diagram + * ----------------- + * rkisp1-isp.c Main Picture Path + * |==========================| |===============================================| + * +-----------+ +--+--+--+--+ +--------+ +--------+ +-----------+ + * | | | | | | | | | | | | | + * +--------+ |\ | | | | | | | -->| Crop |->| RSZ |------------->| | + * | MIPI |--->| \ | | | | | | | | | | | | | | + * +--------+ | | | | |IE|IE|IE|IE| | +--------+ +--------+ | Memory | + * |MUX|--->| ISP |->|0 |1 |2 |3 |---+ | Interface | + * +--------+ | | | | | | | | | | +--------+ +--------+ +--------+ | | + * |Parallel|--->| / | | | | | | | | | | | | | | | | + * +--------+ |/ | | | | | | | -->| Crop |->| RSZ |->| RGB |->| | + * | | | | | | | | | | | | Rotate | | | + * +-----------+ +--+--+--+--+ +--------+ +--------+ +--------+ +-----------+ + * ^ + * +--------+ | |===============================================| + * | DMA |------------------------------------+ Self Picture Path + * +--------+ + * + * + * Media Topology + * -------------- + * +----------+ +----------+ + * | Sensor 2 | | Sensor X | + * ------------ ... ------------ + * | 0 | | 0 | + * +----------+ +----------+ + * \ | + * \ | + * +----------+ \ | + * | Sensor 1 | v v + * ------------ +------+------+ + * | 0 |----->| 0 | 1 | + * +----------+ |------+------| + * | ISP | + * |------+------| + * | 2 | 3 | + * +------+------+ + */ + +struct rkisp1_match_data { + const char * const *clks; + unsigned int size; +}; + +/* ---------------------------------------------------------------------------- + * Sensor DT bindings + */ + +static int rkisp1_create_links(struct rkisp1_device *rkisp1) +{ + unsigned int flags, source_pad; + struct v4l2_subdev *sd; + int ret; + + /* sensor links */ + flags = MEDIA_LNK_FL_ENABLED; + list_for_each_entry(sd, &rkisp1->v4l2_dev.subdevs, list) { + if (sd == &rkisp1->isp.sd) + continue; + + ret = media_entity_get_fwnode_pad(&sd->entity, sd->fwnode, + MEDIA_PAD_FL_SOURCE); + if (ret) { + dev_err(sd->dev, "failed to find src pad for %s\n", + sd->name); + return ret; + } + source_pad = ret; + + ret = media_create_pad_link(&sd->entity, source_pad, + &rkisp1->isp.sd.entity, + RKISP1_ISP_PAD_SINK_VIDEO, + flags); + if (ret) + return ret; + + flags = 0; + } + + return 0; +} + +static int rkisp1_subdev_notifier_bound(struct v4l2_async_notifier *notifier, + struct v4l2_subdev *sd, + struct v4l2_async_subdev *asd) +{ + struct rkisp1_device *rkisp1 = + container_of(notifier, struct rkisp1_device, notifier); + struct rkisp1_sensor_async *s_asd = + container_of(asd, struct rkisp1_sensor_async, asd); + + s_asd->pixel_rate_ctrl = v4l2_ctrl_find(sd->ctrl_handler, + V4L2_CID_PIXEL_RATE); + s_asd->sd = sd; + s_asd->dphy = devm_phy_get(rkisp1->dev, "dphy"); + if (IS_ERR(s_asd->dphy)) { + if (PTR_ERR(s_asd->dphy) != -EPROBE_DEFER) + dev_err(rkisp1->dev, "Couldn't get the MIPI D-PHY\n"); + return PTR_ERR(s_asd->dphy); + } + + phy_init(s_asd->dphy); + + return 0; +} + +static void rkisp1_subdev_notifier_unbind(struct v4l2_async_notifier *notifier, + struct v4l2_subdev *sd, + struct v4l2_async_subdev *asd) +{ + struct rkisp1_sensor_async *s_asd = + container_of(asd, struct rkisp1_sensor_async, asd); + + phy_exit(s_asd->dphy); +} + +static int rkisp1_subdev_notifier_complete(struct v4l2_async_notifier *notifier) +{ + struct rkisp1_device *rkisp1 = + container_of(notifier, struct rkisp1_device, notifier); + int ret; + + mutex_lock(&rkisp1->media_dev.graph_mutex); + ret = rkisp1_create_links(rkisp1); + if (ret) + goto unlock; + ret = v4l2_device_register_subdev_nodes(&rkisp1->v4l2_dev); + if (ret) + goto unlock; + + dev_dbg(rkisp1->dev, "Async subdev notifier completed\n"); + +unlock: + mutex_unlock(&rkisp1->media_dev.graph_mutex); + return ret; +} + +static int rkisp1_fwnode_parse(struct device *dev, + struct v4l2_fwnode_endpoint *vep, + struct v4l2_async_subdev *asd) +{ + struct rkisp1_sensor_async *s_asd = + container_of(asd, struct rkisp1_sensor_async, asd); + + if (vep->bus_type != V4L2_MBUS_CSI2_DPHY) { + dev_err(dev, "Only CSI2 bus type is currently supported\n"); + return -EINVAL; + } + + if (vep->base.port != 0) { + dev_err(dev, "The ISP has only port 0\n"); + return -EINVAL; + } + + s_asd->mbus.type = vep->bus_type; + s_asd->mbus.flags = vep->bus.mipi_csi2.flags; + s_asd->lanes = vep->bus.mipi_csi2.num_data_lanes; + + switch (vep->bus.mipi_csi2.num_data_lanes) { + case 1: + s_asd->mbus.flags |= V4L2_MBUS_CSI2_1_LANE; + break; + case 2: + s_asd->mbus.flags |= V4L2_MBUS_CSI2_2_LANE; + break; + case 3: + s_asd->mbus.flags |= V4L2_MBUS_CSI2_3_LANE; + break; + case 4: + s_asd->mbus.flags |= V4L2_MBUS_CSI2_4_LANE; + break; + default: + return -EINVAL; + } + + return 0; +} + +static const struct v4l2_async_notifier_operations rkisp1_subdev_notifier_ops = { + .bound = rkisp1_subdev_notifier_bound, + .unbind = rkisp1_subdev_notifier_unbind, + .complete = rkisp1_subdev_notifier_complete, +}; + +static int rkisp1_subdev_notifier(struct rkisp1_device *rkisp1) +{ + struct v4l2_async_notifier *ntf = &rkisp1->notifier; + struct device *dev = rkisp1->dev; + int ret; + + v4l2_async_notifier_init(ntf); + + ret = v4l2_async_notifier_parse_fwnode_endpoints_by_port(dev, ntf, + sizeof(struct rkisp1_sensor_async), + 0, rkisp1_fwnode_parse); + if (ret) + return ret; + + if (list_empty(&ntf->asd_list)) + return -ENODEV; + + ntf->ops = &rkisp1_subdev_notifier_ops; + + return v4l2_async_notifier_register(&rkisp1->v4l2_dev, ntf); +} + +/* ---------------------------------------------------------------------------- + * Power + */ + +static int __maybe_unused rkisp1_runtime_suspend(struct device *dev) +{ + struct rkisp1_device *rkisp1 = dev_get_drvdata(dev); + + clk_bulk_disable_unprepare(rkisp1->clk_size, rkisp1->clks); + return pinctrl_pm_select_sleep_state(dev); +} + +static int __maybe_unused rkisp1_runtime_resume(struct device *dev) +{ + struct rkisp1_device *rkisp1 = dev_get_drvdata(dev); + int ret; + + ret = pinctrl_pm_select_default_state(dev); + if (ret) + return ret; + ret = clk_bulk_prepare_enable(rkisp1->clk_size, rkisp1->clks); + if (ret) + return ret; + + return 0; +} + +static const struct dev_pm_ops rkisp1_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) + SET_RUNTIME_PM_OPS(rkisp1_runtime_suspend, rkisp1_runtime_resume, NULL) +}; + +/* ---------------------------------------------------------------------------- + * Core + */ + +static int rkisp1_entities_register(struct rkisp1_device *rkisp1) +{ + int ret; + + ret = rkisp1_isp_register(rkisp1, &rkisp1->v4l2_dev); + if (ret) + return ret; + + ret = rkisp1_subdev_notifier(rkisp1); + if (ret) { + dev_err(rkisp1->dev, + "Failed to register subdev notifier(%d)\n", ret); + rkisp1_isp_unregister(rkisp1); + return ret; + } + + return 0; +} + +static irqreturn_t rkisp1_isr(int irq, void *ctx) +{ + struct device *dev = ctx; + struct rkisp1_device *rkisp1 = dev_get_drvdata(dev); + + rkisp1_isp_isr(rkisp1); + rkisp1_mipi_isr(rkisp1); + + return IRQ_HANDLED; +} + +static const char * const rk3399_isp_clks[] = { + "clk_isp", + "aclk_isp", + "hclk_isp", + "aclk_isp_wrap", + "hclk_isp_wrap", +}; + +static const struct rkisp1_match_data rk3399_isp_clk_data = { + .clks = rk3399_isp_clks, + .size = ARRAY_SIZE(rk3399_isp_clks), +}; + +static const struct of_device_id rkisp1_of_match[] = { + { + .compatible = "rockchip,rk3399-cif-isp", + .data = &rk3399_isp_clk_data, + }, + {}, +}; +MODULE_DEVICE_TABLE(of, rkisp1_of_match); + +static void rkisp1_debug_init(struct rkisp1_device *rkisp1) +{ + struct rkisp1_debug *debug = &rkisp1->debug; + + debug->debugfs_dir = debugfs_create_dir(RKISP1_DRIVER_NAME, NULL); + if (!debug->debugfs_dir) { + dev_dbg(rkisp1->dev, "failed to create debugfs directory\n"); + return; + } + debugfs_create_ulong("data_loss", 0444, debug->debugfs_dir, + &debug->data_loss); + debugfs_create_ulong("pic_size_error", 0444, debug->debugfs_dir, + &debug->pic_size_error); + debugfs_create_ulong("mipi_error", 0444, debug->debugfs_dir, + &debug->mipi_error); +} + +static int rkisp1_probe(struct platform_device *pdev) +{ + struct device_node *node = pdev->dev.of_node; + const struct rkisp1_match_data *clk_data; + const struct of_device_id *match; + struct device *dev = &pdev->dev; + struct rkisp1_device *rkisp1; + struct v4l2_device *v4l2_dev; + unsigned int i; + int ret, irq; + + match = of_match_node(rkisp1_of_match, node); + rkisp1 = devm_kzalloc(dev, sizeof(*rkisp1), GFP_KERNEL); + if (!rkisp1) + return -ENOMEM; + + dev_set_drvdata(dev, rkisp1); + rkisp1->dev = dev; + + rkisp1->base_addr = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(rkisp1->base_addr)) + return PTR_ERR(rkisp1->base_addr); + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + ret = devm_request_irq(dev, irq, rkisp1_isr, IRQF_SHARED, + dev_driver_string(dev), dev); + if (ret) { + dev_err(dev, "request irq failed: %d\n", ret); + return ret; + } + + rkisp1->irq = irq; + clk_data = match->data; + + for (i = 0; i < clk_data->size; i++) + rkisp1->clks[i].id = clk_data->clks[i]; + ret = devm_clk_bulk_get(dev, clk_data->size, rkisp1->clks); + if (ret) + return ret; + rkisp1->clk_size = clk_data->size; + + pm_runtime_enable(&pdev->dev); + + strscpy(rkisp1->media_dev.model, RKISP1_DRIVER_NAME, + sizeof(rkisp1->media_dev.model)); + rkisp1->media_dev.dev = &pdev->dev; + strscpy(rkisp1->media_dev.bus_info, + "platform: " RKISP1_DRIVER_NAME, + sizeof(rkisp1->media_dev.bus_info)); + media_device_init(&rkisp1->media_dev); + + v4l2_dev = &rkisp1->v4l2_dev; + v4l2_dev->mdev = &rkisp1->media_dev; + strscpy(v4l2_dev->name, RKISP1_DRIVER_NAME, sizeof(v4l2_dev->name)); + + ret = v4l2_device_register(rkisp1->dev, &rkisp1->v4l2_dev); + if (ret) + return ret; + + ret = media_device_register(&rkisp1->media_dev); + if (ret) { + dev_err(dev, "Failed to register media device: %d\n", ret); + goto err_unreg_v4l2_dev; + } + + ret = rkisp1_entities_register(rkisp1); + if (ret) + goto err_unreg_media_dev; + + rkisp1_debug_init(rkisp1); + + return 0; + +err_unreg_media_dev: + media_device_unregister(&rkisp1->media_dev); +err_unreg_v4l2_dev: + v4l2_device_unregister(&rkisp1->v4l2_dev); + pm_runtime_disable(&pdev->dev); + return ret; +} + +static int rkisp1_remove(struct platform_device *pdev) +{ + struct rkisp1_device *rkisp1 = platform_get_drvdata(pdev); + + v4l2_async_notifier_unregister(&rkisp1->notifier); + v4l2_async_notifier_cleanup(&rkisp1->notifier); + + rkisp1_isp_unregister(rkisp1); + + media_device_unregister(&rkisp1->media_dev); + v4l2_device_unregister(&rkisp1->v4l2_dev); + + pm_runtime_disable(&pdev->dev); + + debugfs_remove_recursive(rkisp1->debug.debugfs_dir); + return 0; +} + +static struct platform_driver rkisp1_drv = { + .driver = { + .name = RKISP1_DRIVER_NAME, + .of_match_table = of_match_ptr(rkisp1_of_match), + .pm = &rkisp1_pm_ops, + }, + .probe = rkisp1_probe, + .remove = rkisp1_remove, +}; + +module_platform_driver(rkisp1_drv); +MODULE_DESCRIPTION("Rockchip ISP1 platform driver"); +MODULE_LICENSE("Dual MIT/GPL"); diff --git a/drivers/staging/media/rkisp1/rkisp1-isp.c b/drivers/staging/media/rkisp1/rkisp1-isp.c new file mode 100644 index 000000000000..abf63e7f74bd --- /dev/null +++ b/drivers/staging/media/rkisp1/rkisp1-isp.c @@ -0,0 +1,1133 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Rockchip ISP1 Driver - ISP Subdevice + * + * Copyright (C) 2019 Collabora, Ltd. + * + * Based on Rockchip ISP1 driver by Rockchip Electronics Co., Ltd. + * Copyright (C) 2017 Rockchip Electronics Co., Ltd. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "rkisp1-common.h" + +#define RKISP1_DEF_SINK_PAD_FMT MEDIA_BUS_FMT_SRGGB10_1X10 +#define RKISP1_DEF_SRC_PAD_FMT MEDIA_BUS_FMT_YUYV8_2X8 + +#define RKISP1_ISP_DEV_NAME RKISP1_DRIVER_NAME "_isp" + +#define RKISP1_DIR_SRC BIT(0) +#define RKISP1_DIR_SINK BIT(1) +#define RKISP1_DIR_SINK_SRC (RKISP1_DIR_SINK | RKISP1_DIR_SRC) + +/* + * NOTE: MIPI controller and input MUX are also configured in this file, + * because ISP Subdev is not only describe ISP submodule(input size,format, + * output size, format), but also a virtual route device. + */ + +/* + * There are many variables named with format/frame in below code, + * please see here for their meaning. + * Cropping in the sink pad defines the image region from the sensor. + * Cropping in the source pad defines the region for the Image Stabilizer (IS) + * + * Cropping regions of ISP + * + * +---------------------------------------------------------+ + * | Sensor image | + * | +---------------------------------------------------+ | + * | | CIF_ISP_ACQ (for black level) | | + * | | sink pad format | | + * | | +--------------------------------------------+ | | + * | | | CIF_ISP_OUT | | | + * | | | sink pad crop | | | + * | | | +---------------------------------+ | | | + * | | | | CIF_ISP_IS | | | | + * | | | | source pad crop and format | | | | + * | | | +---------------------------------+ | | | + * | | +--------------------------------------------+ | | + * | +---------------------------------------------------+ | + * +---------------------------------------------------------+ + */ + +static const struct rkisp1_isp_mbus_info rkisp1_isp_formats[] = { + { + .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, + .fmt_type = RKISP1_FMT_YUV, + .direction = RKISP1_DIR_SRC, + }, { + .mbus_code = MEDIA_BUS_FMT_SRGGB10_1X10, + .fmt_type = RKISP1_FMT_BAYER, + .mipi_dt = RKISP1_CIF_CSI2_DT_RAW10, + .bayer_pat = RKISP1_RAW_RGGB, + .bus_width = 10, + .direction = RKISP1_DIR_SINK_SRC, + }, { + .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10, + .fmt_type = RKISP1_FMT_BAYER, + .mipi_dt = RKISP1_CIF_CSI2_DT_RAW10, + .bayer_pat = RKISP1_RAW_BGGR, + .bus_width = 10, + .direction = RKISP1_DIR_SINK_SRC, + }, { + .mbus_code = MEDIA_BUS_FMT_SGBRG10_1X10, + .fmt_type = RKISP1_FMT_BAYER, + .mipi_dt = RKISP1_CIF_CSI2_DT_RAW10, + .bayer_pat = RKISP1_RAW_GBRG, + .bus_width = 10, + .direction = RKISP1_DIR_SINK_SRC, + }, { + .mbus_code = MEDIA_BUS_FMT_SGRBG10_1X10, + .fmt_type = RKISP1_FMT_BAYER, + .mipi_dt = RKISP1_CIF_CSI2_DT_RAW10, + .bayer_pat = RKISP1_RAW_GRBG, + .bus_width = 10, + .direction = RKISP1_DIR_SINK_SRC, + }, { + .mbus_code = MEDIA_BUS_FMT_SRGGB12_1X12, + .fmt_type = RKISP1_FMT_BAYER, + .mipi_dt = RKISP1_CIF_CSI2_DT_RAW12, + .bayer_pat = RKISP1_RAW_RGGB, + .bus_width = 12, + .direction = RKISP1_DIR_SINK_SRC, + }, { + .mbus_code = MEDIA_BUS_FMT_SBGGR12_1X12, + .fmt_type = RKISP1_FMT_BAYER, + .mipi_dt = RKISP1_CIF_CSI2_DT_RAW12, + .bayer_pat = RKISP1_RAW_BGGR, + .bus_width = 12, + .direction = RKISP1_DIR_SINK_SRC, + }, { + .mbus_code = MEDIA_BUS_FMT_SGBRG12_1X12, + .fmt_type = RKISP1_FMT_BAYER, + .mipi_dt = RKISP1_CIF_CSI2_DT_RAW12, + .bayer_pat = RKISP1_RAW_GBRG, + .bus_width = 12, + .direction = RKISP1_DIR_SINK_SRC, + }, { + .mbus_code = MEDIA_BUS_FMT_SGRBG12_1X12, + .fmt_type = RKISP1_FMT_BAYER, + .mipi_dt = RKISP1_CIF_CSI2_DT_RAW12, + .bayer_pat = RKISP1_RAW_GRBG, + .bus_width = 12, + .direction = RKISP1_DIR_SINK_SRC, + }, { + .mbus_code = MEDIA_BUS_FMT_SRGGB8_1X8, + .fmt_type = RKISP1_FMT_BAYER, + .mipi_dt = RKISP1_CIF_CSI2_DT_RAW8, + .bayer_pat = RKISP1_RAW_RGGB, + .bus_width = 8, + .direction = RKISP1_DIR_SINK_SRC, + }, { + .mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8, + .fmt_type = RKISP1_FMT_BAYER, + .mipi_dt = RKISP1_CIF_CSI2_DT_RAW8, + .bayer_pat = RKISP1_RAW_BGGR, + .bus_width = 8, + .direction = RKISP1_DIR_SINK_SRC, + }, { + .mbus_code = MEDIA_BUS_FMT_SGBRG8_1X8, + .fmt_type = RKISP1_FMT_BAYER, + .mipi_dt = RKISP1_CIF_CSI2_DT_RAW8, + .bayer_pat = RKISP1_RAW_GBRG, + .bus_width = 8, + .direction = RKISP1_DIR_SINK_SRC, + }, { + .mbus_code = MEDIA_BUS_FMT_SGRBG8_1X8, + .fmt_type = RKISP1_FMT_BAYER, + .mipi_dt = RKISP1_CIF_CSI2_DT_RAW8, + .bayer_pat = RKISP1_RAW_GRBG, + .bus_width = 8, + .direction = RKISP1_DIR_SINK_SRC, + }, { + .mbus_code = MEDIA_BUS_FMT_YUYV8_1X16, + .fmt_type = RKISP1_FMT_YUV, + .mipi_dt = RKISP1_CIF_CSI2_DT_YUV422_8b, + .yuv_seq = RKISP1_CIF_ISP_ACQ_PROP_YCBYCR, + .bus_width = 16, + .direction = RKISP1_DIR_SINK, + }, { + .mbus_code = MEDIA_BUS_FMT_YVYU8_1X16, + .fmt_type = RKISP1_FMT_YUV, + .mipi_dt = RKISP1_CIF_CSI2_DT_YUV422_8b, + .yuv_seq = RKISP1_CIF_ISP_ACQ_PROP_YCRYCB, + .bus_width = 16, + .direction = RKISP1_DIR_SINK, + }, { + .mbus_code = MEDIA_BUS_FMT_UYVY8_1X16, + .fmt_type = RKISP1_FMT_YUV, + .mipi_dt = RKISP1_CIF_CSI2_DT_YUV422_8b, + .yuv_seq = RKISP1_CIF_ISP_ACQ_PROP_CBYCRY, + .bus_width = 16, + .direction = RKISP1_DIR_SINK, + }, { + .mbus_code = MEDIA_BUS_FMT_VYUY8_1X16, + .fmt_type = RKISP1_FMT_YUV, + .mipi_dt = RKISP1_CIF_CSI2_DT_YUV422_8b, + .yuv_seq = RKISP1_CIF_ISP_ACQ_PROP_CRYCBY, + .bus_width = 16, + .direction = RKISP1_DIR_SINK, + }, +}; + +/* ---------------------------------------------------------------------------- + * Helpers + */ + +const struct rkisp1_isp_mbus_info *rkisp1_isp_mbus_info_get(u32 mbus_code) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(rkisp1_isp_formats); i++) { + const struct rkisp1_isp_mbus_info *fmt = &rkisp1_isp_formats[i]; + + if (fmt->mbus_code == mbus_code) + return fmt; + } + + return NULL; +} + +static struct v4l2_subdev *rkisp1_get_remote_sensor(struct v4l2_subdev *sd) +{ + struct media_pad *local, *remote; + struct media_entity *sensor_me; + + local = &sd->entity.pads[RKISP1_ISP_PAD_SINK_VIDEO]; + remote = media_entity_remote_pad(local); + if (!remote) { + dev_warn(sd->dev, "No link between isp and sensor\n"); + return NULL; + } + + sensor_me = remote->entity; + return media_entity_to_v4l2_subdev(sensor_me); +} + +static struct v4l2_mbus_framefmt * +rkisp1_isp_get_pad_fmt(struct rkisp1_isp *isp, + struct v4l2_subdev_pad_config *cfg, + unsigned int pad, u32 which) +{ + if (which == V4L2_SUBDEV_FORMAT_TRY) + return v4l2_subdev_get_try_format(&isp->sd, cfg, pad); + else + return v4l2_subdev_get_try_format(&isp->sd, isp->pad_cfg, pad); +} + +static struct v4l2_rect * +rkisp1_isp_get_pad_crop(struct rkisp1_isp *isp, + struct v4l2_subdev_pad_config *cfg, + unsigned int pad, u32 which) +{ + if (which == V4L2_SUBDEV_FORMAT_TRY) + return v4l2_subdev_get_try_crop(&isp->sd, cfg, pad); + else + return v4l2_subdev_get_try_crop(&isp->sd, isp->pad_cfg, pad); +} + +/* ---------------------------------------------------------------------------- + * Camera Interface registers configurations + */ + +/* + * Image Stabilization. + * This should only be called when configuring CIF + * or at the frame end interrupt + */ +static void rkisp1_config_ism(struct rkisp1_device *rkisp1) +{ + struct v4l2_rect *src_crop = + rkisp1_isp_get_pad_crop(&rkisp1->isp, NULL, + RKISP1_ISP_PAD_SOURCE_VIDEO, + V4L2_SUBDEV_FORMAT_ACTIVE); + u32 val; + + rkisp1_write(rkisp1, 0, RKISP1_CIF_ISP_IS_RECENTER); + rkisp1_write(rkisp1, 0, RKISP1_CIF_ISP_IS_MAX_DX); + rkisp1_write(rkisp1, 0, RKISP1_CIF_ISP_IS_MAX_DY); + rkisp1_write(rkisp1, 0, RKISP1_CIF_ISP_IS_DISPLACE); + rkisp1_write(rkisp1, src_crop->left, RKISP1_CIF_ISP_IS_H_OFFS); + rkisp1_write(rkisp1, src_crop->top, RKISP1_CIF_ISP_IS_V_OFFS); + rkisp1_write(rkisp1, src_crop->width, RKISP1_CIF_ISP_IS_H_SIZE); + rkisp1_write(rkisp1, src_crop->height, RKISP1_CIF_ISP_IS_V_SIZE); + + /* IS(Image Stabilization) is always on, working as output crop */ + rkisp1_write(rkisp1, 1, RKISP1_CIF_ISP_IS_CTRL); + val = rkisp1_read(rkisp1, RKISP1_CIF_ISP_CTRL); + val |= RKISP1_CIF_ISP_CTRL_ISP_CFG_UPD; + rkisp1_write(rkisp1, val, RKISP1_CIF_ISP_CTRL); +} + +/* + * configure ISP blocks with input format, size...... + */ +static int rkisp1_config_isp(struct rkisp1_device *rkisp1) +{ + u32 isp_ctrl = 0, irq_mask = 0, acq_mult = 0, signal = 0; + const struct rkisp1_isp_mbus_info *src_fmt, *sink_fmt; + struct rkisp1_sensor_async *sensor; + struct v4l2_mbus_framefmt *sink_frm; + struct v4l2_rect *sink_crop; + + sensor = rkisp1->active_sensor; + sink_fmt = rkisp1->isp.sink_fmt; + src_fmt = rkisp1->isp.src_fmt; + sink_frm = rkisp1_isp_get_pad_fmt(&rkisp1->isp, NULL, + RKISP1_ISP_PAD_SINK_VIDEO, + V4L2_SUBDEV_FORMAT_ACTIVE); + sink_crop = rkisp1_isp_get_pad_crop(&rkisp1->isp, NULL, + RKISP1_ISP_PAD_SINK_VIDEO, + V4L2_SUBDEV_FORMAT_ACTIVE); + + if (sink_fmt->fmt_type == RKISP1_FMT_BAYER) { + acq_mult = 1; + if (src_fmt->fmt_type == RKISP1_FMT_BAYER) { + if (sensor->mbus.type == V4L2_MBUS_BT656) + isp_ctrl = RKISP1_CIF_ISP_CTRL_ISP_MODE_RAW_PICT_ITU656; + else + isp_ctrl = RKISP1_CIF_ISP_CTRL_ISP_MODE_RAW_PICT; + } else { + rkisp1_write(rkisp1, RKISP1_CIF_ISP_DEMOSAIC_TH(0xc), + RKISP1_CIF_ISP_DEMOSAIC); + + if (sensor->mbus.type == V4L2_MBUS_BT656) + isp_ctrl = RKISP1_CIF_ISP_CTRL_ISP_MODE_BAYER_ITU656; + else + isp_ctrl = RKISP1_CIF_ISP_CTRL_ISP_MODE_BAYER_ITU601; + } + } else if (sink_fmt->fmt_type == RKISP1_FMT_YUV) { + acq_mult = 2; + if (sensor->mbus.type == V4L2_MBUS_CSI2_DPHY) { + isp_ctrl = RKISP1_CIF_ISP_CTRL_ISP_MODE_ITU601; + } else { + if (sensor->mbus.type == V4L2_MBUS_BT656) + isp_ctrl = RKISP1_CIF_ISP_CTRL_ISP_MODE_ITU656; + else + isp_ctrl = RKISP1_CIF_ISP_CTRL_ISP_MODE_ITU601; + } + + irq_mask |= RKISP1_CIF_ISP_DATA_LOSS; + } + + /* Set up input acquisition properties */ + if (sensor->mbus.type == V4L2_MBUS_BT656 || + sensor->mbus.type == V4L2_MBUS_PARALLEL) { + if (sensor->mbus.flags & V4L2_MBUS_PCLK_SAMPLE_RISING) + signal = RKISP1_CIF_ISP_ACQ_PROP_POS_EDGE; + } + + if (sensor->mbus.type == V4L2_MBUS_PARALLEL) { + if (sensor->mbus.flags & V4L2_MBUS_VSYNC_ACTIVE_LOW) + signal |= RKISP1_CIF_ISP_ACQ_PROP_VSYNC_LOW; + + if (sensor->mbus.flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) + signal |= RKISP1_CIF_ISP_ACQ_PROP_HSYNC_LOW; + } + + rkisp1_write(rkisp1, isp_ctrl, RKISP1_CIF_ISP_CTRL); + rkisp1_write(rkisp1, signal | sink_fmt->yuv_seq | + RKISP1_CIF_ISP_ACQ_PROP_BAYER_PAT(sink_fmt->bayer_pat) | + RKISP1_CIF_ISP_ACQ_PROP_FIELD_SEL_ALL, + RKISP1_CIF_ISP_ACQ_PROP); + rkisp1_write(rkisp1, 0, RKISP1_CIF_ISP_ACQ_NR_FRAMES); + + /* Acquisition Size */ + rkisp1_write(rkisp1, 0, RKISP1_CIF_ISP_ACQ_H_OFFS); + rkisp1_write(rkisp1, 0, RKISP1_CIF_ISP_ACQ_V_OFFS); + rkisp1_write(rkisp1, + acq_mult * sink_frm->width, RKISP1_CIF_ISP_ACQ_H_SIZE); + rkisp1_write(rkisp1, sink_frm->height, RKISP1_CIF_ISP_ACQ_V_SIZE); + + /* ISP Out Area */ + rkisp1_write(rkisp1, sink_crop->left, RKISP1_CIF_ISP_OUT_H_OFFS); + rkisp1_write(rkisp1, sink_crop->top, RKISP1_CIF_ISP_OUT_V_OFFS); + rkisp1_write(rkisp1, sink_crop->width, RKISP1_CIF_ISP_OUT_H_SIZE); + rkisp1_write(rkisp1, sink_crop->height, RKISP1_CIF_ISP_OUT_V_SIZE); + + irq_mask |= RKISP1_CIF_ISP_FRAME | RKISP1_CIF_ISP_V_START | + RKISP1_CIF_ISP_PIC_SIZE_ERROR | RKISP1_CIF_ISP_FRAME_IN; + rkisp1_write(rkisp1, irq_mask, RKISP1_CIF_ISP_IMSC); + + return 0; +} + +static int rkisp1_config_dvp(struct rkisp1_device *rkisp1) +{ + const struct rkisp1_isp_mbus_info *sink_fmt = rkisp1->isp.sink_fmt; + u32 val, input_sel; + + switch (sink_fmt->bus_width) { + case 8: + input_sel = RKISP1_CIF_ISP_ACQ_PROP_IN_SEL_8B_ZERO; + break; + case 10: + input_sel = RKISP1_CIF_ISP_ACQ_PROP_IN_SEL_10B_ZERO; + break; + case 12: + input_sel = RKISP1_CIF_ISP_ACQ_PROP_IN_SEL_12B; + break; + default: + dev_err(rkisp1->dev, "Invalid bus width\n"); + return -EINVAL; + } + + val = rkisp1_read(rkisp1, RKISP1_CIF_ISP_ACQ_PROP); + rkisp1_write(rkisp1, val | input_sel, RKISP1_CIF_ISP_ACQ_PROP); + + return 0; +} + +static int rkisp1_config_mipi(struct rkisp1_device *rkisp1) +{ + const struct rkisp1_isp_mbus_info *sink_fmt = rkisp1->isp.sink_fmt; + unsigned int lanes; + u32 mipi_ctrl; + + /* + * rkisp1->active_sensor->mbus is set in isp or d-phy notifier_bound + * function + */ + switch (rkisp1->active_sensor->mbus.flags & V4L2_MBUS_CSI2_LANES) { + case V4L2_MBUS_CSI2_4_LANE: + lanes = 4; + break; + case V4L2_MBUS_CSI2_3_LANE: + lanes = 3; + break; + case V4L2_MBUS_CSI2_2_LANE: + lanes = 2; + break; + case V4L2_MBUS_CSI2_1_LANE: + lanes = 1; + break; + default: + return -EINVAL; + } + + mipi_ctrl = RKISP1_CIF_MIPI_CTRL_NUM_LANES(lanes - 1) | + RKISP1_CIF_MIPI_CTRL_SHUTDOWNLANES(0xf) | + RKISP1_CIF_MIPI_CTRL_ERR_SOT_SYNC_HS_SKIP | + RKISP1_CIF_MIPI_CTRL_CLOCKLANE_ENA; + + rkisp1_write(rkisp1, mipi_ctrl, RKISP1_CIF_MIPI_CTRL); + + /* Configure Data Type and Virtual Channel */ + rkisp1_write(rkisp1, + RKISP1_CIF_MIPI_DATA_SEL_DT(sink_fmt->mipi_dt) | + RKISP1_CIF_MIPI_DATA_SEL_VC(0), + RKISP1_CIF_MIPI_IMG_DATA_SEL); + + /* Clear MIPI interrupts */ + rkisp1_write(rkisp1, ~0, RKISP1_CIF_MIPI_ICR); + /* + * Disable RKISP1_CIF_MIPI_ERR_DPHY interrupt here temporary for + * isp bus may be dead when switch isp. + */ + rkisp1_write(rkisp1, + RKISP1_CIF_MIPI_FRAME_END | RKISP1_CIF_MIPI_ERR_CSI | + RKISP1_CIF_MIPI_ERR_DPHY | + RKISP1_CIF_MIPI_SYNC_FIFO_OVFLW(0x03) | + RKISP1_CIF_MIPI_ADD_DATA_OVFLW, + RKISP1_CIF_MIPI_IMSC); + + dev_dbg(rkisp1->dev, "\n MIPI_CTRL 0x%08x\n" + " MIPI_IMG_DATA_SEL 0x%08x\n" + " MIPI_STATUS 0x%08x\n" + " MIPI_IMSC 0x%08x\n", + rkisp1_read(rkisp1, RKISP1_CIF_MIPI_CTRL), + rkisp1_read(rkisp1, RKISP1_CIF_MIPI_IMG_DATA_SEL), + rkisp1_read(rkisp1, RKISP1_CIF_MIPI_STATUS), + rkisp1_read(rkisp1, RKISP1_CIF_MIPI_IMSC)); + + return 0; +} + +/* Configure MUX */ +static int rkisp1_config_path(struct rkisp1_device *rkisp1) +{ + struct rkisp1_sensor_async *sensor = rkisp1->active_sensor; + u32 dpcl = rkisp1_read(rkisp1, RKISP1_CIF_VI_DPCL); + int ret = 0; + + if (sensor->mbus.type == V4L2_MBUS_BT656 || + sensor->mbus.type == V4L2_MBUS_PARALLEL) { + ret = rkisp1_config_dvp(rkisp1); + dpcl |= RKISP1_CIF_VI_DPCL_IF_SEL_PARALLEL; + } else if (sensor->mbus.type == V4L2_MBUS_CSI2_DPHY) { + ret = rkisp1_config_mipi(rkisp1); + dpcl |= RKISP1_CIF_VI_DPCL_IF_SEL_MIPI; + } + + rkisp1_write(rkisp1, dpcl, RKISP1_CIF_VI_DPCL); + + return ret; +} + +/* Hardware configure Entry */ +static int rkisp1_config_cif(struct rkisp1_device *rkisp1) +{ + u32 cif_id; + int ret; + + cif_id = rkisp1_read(rkisp1, RKISP1_CIF_VI_ID); + dev_dbg(rkisp1->dev, "CIF_ID 0x%08x\n", cif_id); + + ret = rkisp1_config_isp(rkisp1); + if (ret) + return ret; + ret = rkisp1_config_path(rkisp1); + if (ret) + return ret; + rkisp1_config_ism(rkisp1); + + return 0; +} + +static int rkisp1_isp_stop(struct rkisp1_device *rkisp1) +{ + u32 val; + + /* + * ISP(mi) stop in mi frame end -> Stop ISP(mipi) -> + * Stop ISP(isp) ->wait for ISP isp off + */ + /* stop and clear MI, MIPI, and ISP interrupts */ + rkisp1_write(rkisp1, 0, RKISP1_CIF_MIPI_IMSC); + rkisp1_write(rkisp1, ~0, RKISP1_CIF_MIPI_ICR); + + rkisp1_write(rkisp1, 0, RKISP1_CIF_ISP_IMSC); + rkisp1_write(rkisp1, ~0, RKISP1_CIF_ISP_ICR); + + rkisp1_write(rkisp1, 0, RKISP1_CIF_MI_IMSC); + rkisp1_write(rkisp1, ~0, RKISP1_CIF_MI_ICR); + val = rkisp1_read(rkisp1, RKISP1_CIF_MIPI_CTRL); + rkisp1_write(rkisp1, val & (~RKISP1_CIF_MIPI_CTRL_OUTPUT_ENA), + RKISP1_CIF_MIPI_CTRL); + /* stop ISP */ + val = rkisp1_read(rkisp1, RKISP1_CIF_ISP_CTRL); + val &= ~(RKISP1_CIF_ISP_CTRL_ISP_INFORM_ENABLE | + RKISP1_CIF_ISP_CTRL_ISP_ENABLE); + rkisp1_write(rkisp1, val, RKISP1_CIF_ISP_CTRL); + + val = rkisp1_read(rkisp1, RKISP1_CIF_ISP_CTRL); + rkisp1_write(rkisp1, val | RKISP1_CIF_ISP_CTRL_ISP_CFG_UPD, + RKISP1_CIF_ISP_CTRL); + + readx_poll_timeout(readl, rkisp1->base_addr + RKISP1_CIF_ISP_RIS, + val, val & RKISP1_CIF_ISP_OFF, 20, 100); + rkisp1_write(rkisp1, + RKISP1_CIF_IRCL_MIPI_SW_RST | RKISP1_CIF_IRCL_ISP_SW_RST, + RKISP1_CIF_IRCL); + rkisp1_write(rkisp1, 0x0, RKISP1_CIF_IRCL); + + return 0; +} + +static void rkisp1_config_clk(struct rkisp1_device *rkisp1) +{ + u32 val = RKISP1_CIF_ICCL_ISP_CLK | RKISP1_CIF_ICCL_CP_CLK | + RKISP1_CIF_ICCL_MRSZ_CLK | RKISP1_CIF_ICCL_SRSZ_CLK | + RKISP1_CIF_ICCL_JPEG_CLK | RKISP1_CIF_ICCL_MI_CLK | + RKISP1_CIF_ICCL_IE_CLK | RKISP1_CIF_ICCL_MIPI_CLK | + RKISP1_CIF_ICCL_DCROP_CLK; + + rkisp1_write(rkisp1, val, RKISP1_CIF_ICCL); +} + +static int rkisp1_isp_start(struct rkisp1_device *rkisp1) +{ + struct rkisp1_sensor_async *sensor = rkisp1->active_sensor; + u32 val; + + rkisp1_config_clk(rkisp1); + + /* Activate MIPI */ + if (sensor->mbus.type == V4L2_MBUS_CSI2_DPHY) { + val = rkisp1_read(rkisp1, RKISP1_CIF_MIPI_CTRL); + rkisp1_write(rkisp1, val | RKISP1_CIF_MIPI_CTRL_OUTPUT_ENA, + RKISP1_CIF_MIPI_CTRL); + } + /* Activate ISP */ + val = rkisp1_read(rkisp1, RKISP1_CIF_ISP_CTRL); + val |= RKISP1_CIF_ISP_CTRL_ISP_CFG_UPD | + RKISP1_CIF_ISP_CTRL_ISP_ENABLE | + RKISP1_CIF_ISP_CTRL_ISP_INFORM_ENABLE; + rkisp1_write(rkisp1, val, RKISP1_CIF_ISP_CTRL); + + /* + * CIF spec says to wait for sufficient time after enabling + * the MIPI interface and before starting the sensor output. + */ + usleep_range(1000, 1200); + + return 0; +} + +/* ---------------------------------------------------------------------------- + * Subdev pad operations + */ + +static int rkisp1_isp_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) +{ + unsigned int i, dir; + int pos = 0; + + if (code->pad == RKISP1_ISP_PAD_SINK_VIDEO) { + dir = RKISP1_DIR_SINK; + } else if (code->pad == RKISP1_ISP_PAD_SOURCE_VIDEO) { + dir = RKISP1_DIR_SRC; + } else { + if (code->index > 0) + return -EINVAL; + code->code = MEDIA_BUS_FMT_FIXED; + return 0; + } + + if (code->index >= ARRAY_SIZE(rkisp1_isp_formats)) + return -EINVAL; + + for (i = 0; i < ARRAY_SIZE(rkisp1_isp_formats); i++) { + const struct rkisp1_isp_mbus_info *fmt = &rkisp1_isp_formats[i]; + + if (fmt->direction & dir) + pos++; + + if (code->index == pos - 1) { + code->code = fmt->mbus_code; + return 0; + } + } + + return -EINVAL; +} + +static int rkisp1_isp_init_config(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg) +{ + struct v4l2_mbus_framefmt *sink_fmt, *src_fmt; + struct v4l2_rect *sink_crop, *src_crop; + + sink_fmt = v4l2_subdev_get_try_format(sd, cfg, + RKISP1_ISP_PAD_SINK_VIDEO); + sink_fmt->width = RKISP1_DEFAULT_WIDTH; + sink_fmt->height = RKISP1_DEFAULT_HEIGHT; + sink_fmt->field = V4L2_FIELD_NONE; + sink_fmt->code = RKISP1_DEF_SINK_PAD_FMT; + + sink_crop = v4l2_subdev_get_try_crop(sd, cfg, + RKISP1_ISP_PAD_SINK_VIDEO); + sink_crop->width = RKISP1_DEFAULT_WIDTH; + sink_crop->height = RKISP1_DEFAULT_HEIGHT; + sink_crop->left = 0; + sink_crop->top = 0; + + src_fmt = v4l2_subdev_get_try_format(sd, cfg, + RKISP1_ISP_PAD_SOURCE_VIDEO); + *src_fmt = *sink_fmt; + src_fmt->code = RKISP1_DEF_SRC_PAD_FMT; + src_fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE; + + src_crop = v4l2_subdev_get_try_crop(sd, cfg, + RKISP1_ISP_PAD_SOURCE_VIDEO); + *src_crop = *sink_crop; + + sink_fmt = v4l2_subdev_get_try_format(sd, cfg, + RKISP1_ISP_PAD_SINK_PARAMS); + src_fmt = v4l2_subdev_get_try_format(sd, cfg, + RKISP1_ISP_PAD_SOURCE_STATS); + sink_fmt->width = RKISP1_DEFAULT_WIDTH; + sink_fmt->height = RKISP1_DEFAULT_HEIGHT; + sink_fmt->field = V4L2_FIELD_NONE; + sink_fmt->code = MEDIA_BUS_FMT_FIXED; + *src_fmt = *sink_fmt; + + return 0; +} + +static void rkisp1_isp_set_src_fmt(struct rkisp1_isp *isp, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_mbus_framefmt *format, + unsigned int which) +{ + const struct rkisp1_isp_mbus_info *mbus_info; + struct v4l2_mbus_framefmt *src_fmt; + const struct v4l2_rect *src_crop; + + src_fmt = rkisp1_isp_get_pad_fmt(isp, cfg, + RKISP1_ISP_PAD_SOURCE_VIDEO, which); + src_crop = rkisp1_isp_get_pad_crop(isp, cfg, + RKISP1_ISP_PAD_SOURCE_VIDEO, which); + + src_fmt->code = format->code; + mbus_info = rkisp1_isp_mbus_info_get(src_fmt->code); + if (!mbus_info) { + src_fmt->code = RKISP1_DEF_SRC_PAD_FMT; + mbus_info = rkisp1_isp_mbus_info_get(src_fmt->code); + } + if (which == V4L2_SUBDEV_FORMAT_ACTIVE) + isp->src_fmt = mbus_info; + src_fmt->width = src_crop->width; + src_fmt->height = src_crop->height; + src_fmt->quantization = format->quantization; + /* full range by default */ + if (!src_fmt->quantization) + src_fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE; + + *format = *src_fmt; +} + +static void rkisp1_isp_set_src_crop(struct rkisp1_isp *isp, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_rect *r, unsigned int which) +{ + struct v4l2_mbus_framefmt *src_fmt; + const struct v4l2_rect *sink_crop; + struct v4l2_rect *src_crop; + + src_crop = rkisp1_isp_get_pad_crop(isp, cfg, + RKISP1_ISP_PAD_SOURCE_VIDEO, + which); + sink_crop = rkisp1_isp_get_pad_crop(isp, cfg, + RKISP1_ISP_PAD_SINK_VIDEO, + which); + + src_crop->left = ALIGN(r->left, 2); + src_crop->width = ALIGN(r->width, 2); + src_crop->top = r->top; + src_crop->height = r->height; + rkisp1_sd_adjust_crop_rect(src_crop, sink_crop); + + *r = *src_crop; + + /* Propagate to out format */ + src_fmt = rkisp1_isp_get_pad_fmt(isp, cfg, + RKISP1_ISP_PAD_SOURCE_VIDEO, which); + rkisp1_isp_set_src_fmt(isp, cfg, src_fmt, which); +} + +static void rkisp1_isp_set_sink_crop(struct rkisp1_isp *isp, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_rect *r, unsigned int which) +{ + struct v4l2_rect *sink_crop, *src_crop; + struct v4l2_mbus_framefmt *sink_fmt; + + sink_crop = rkisp1_isp_get_pad_crop(isp, cfg, RKISP1_ISP_PAD_SINK_VIDEO, + which); + sink_fmt = rkisp1_isp_get_pad_fmt(isp, cfg, RKISP1_ISP_PAD_SINK_VIDEO, + which); + + sink_crop->left = ALIGN(r->left, 2); + sink_crop->width = ALIGN(r->width, 2); + sink_crop->top = r->top; + sink_crop->height = r->height; + rkisp1_sd_adjust_crop(sink_crop, sink_fmt); + + *r = *sink_crop; + + /* Propagate to out crop */ + src_crop = rkisp1_isp_get_pad_crop(isp, cfg, + RKISP1_ISP_PAD_SOURCE_VIDEO, which); + rkisp1_isp_set_src_crop(isp, cfg, src_crop, which); +} + +static void rkisp1_isp_set_sink_fmt(struct rkisp1_isp *isp, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_mbus_framefmt *format, + unsigned int which) +{ + const struct rkisp1_isp_mbus_info *mbus_info; + struct v4l2_mbus_framefmt *sink_fmt; + struct v4l2_rect *sink_crop; + + sink_fmt = rkisp1_isp_get_pad_fmt(isp, cfg, RKISP1_ISP_PAD_SINK_VIDEO, + which); + sink_fmt->code = format->code; + mbus_info = rkisp1_isp_mbus_info_get(sink_fmt->code); + if (!mbus_info) { + sink_fmt->code = RKISP1_DEF_SINK_PAD_FMT; + mbus_info = rkisp1_isp_mbus_info_get(sink_fmt->code); + } + if (which == V4L2_SUBDEV_FORMAT_ACTIVE) + isp->sink_fmt = mbus_info; + + sink_fmt->width = clamp_t(u32, format->width, + RKISP1_ISP_MIN_WIDTH, + RKISP1_ISP_MAX_WIDTH); + sink_fmt->height = clamp_t(u32, format->height, + RKISP1_ISP_MIN_HEIGHT, + RKISP1_ISP_MAX_HEIGHT); + + *format = *sink_fmt; + + /* Propagate to in crop */ + sink_crop = rkisp1_isp_get_pad_crop(isp, cfg, RKISP1_ISP_PAD_SINK_VIDEO, + which); + rkisp1_isp_set_sink_crop(isp, cfg, sink_crop, which); +} + +static int rkisp1_isp_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *fmt) +{ + struct rkisp1_isp *isp = container_of(sd, struct rkisp1_isp, sd); + + fmt->format = *rkisp1_isp_get_pad_fmt(isp, cfg, fmt->pad, fmt->which); + return 0; +} + +static int rkisp1_isp_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *fmt) +{ + struct rkisp1_isp *isp = container_of(sd, struct rkisp1_isp, sd); + + if (fmt->pad == RKISP1_ISP_PAD_SINK_VIDEO) + rkisp1_isp_set_sink_fmt(isp, cfg, &fmt->format, fmt->which); + else if (fmt->pad == RKISP1_ISP_PAD_SOURCE_VIDEO) + rkisp1_isp_set_src_fmt(isp, cfg, &fmt->format, fmt->which); + else + fmt->format = *rkisp1_isp_get_pad_fmt(isp, cfg, fmt->pad, + fmt->which); + + return 0; +} + +static int rkisp1_isp_get_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_selection *sel) +{ + struct rkisp1_isp *isp = container_of(sd, struct rkisp1_isp, sd); + + if (sel->pad != RKISP1_ISP_PAD_SOURCE_VIDEO && + sel->pad != RKISP1_ISP_PAD_SINK_VIDEO) + return -EINVAL; + + switch (sel->target) { + case V4L2_SEL_TGT_CROP_BOUNDS: + if (sel->pad == RKISP1_ISP_PAD_SINK_VIDEO) { + struct v4l2_mbus_framefmt *fmt; + + fmt = rkisp1_isp_get_pad_fmt(isp, cfg, sel->pad, + sel->which); + sel->r.height = fmt->height; + sel->r.width = fmt->width; + sel->r.left = 0; + sel->r.top = 0; + } else { + sel->r = *rkisp1_isp_get_pad_crop(isp, cfg, + RKISP1_ISP_PAD_SINK_VIDEO, + sel->which); + } + break; + case V4L2_SEL_TGT_CROP: + sel->r = *rkisp1_isp_get_pad_crop(isp, cfg, sel->pad, + sel->which); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int rkisp1_isp_set_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_selection *sel) +{ + struct rkisp1_device *rkisp1 = + container_of(sd->v4l2_dev, struct rkisp1_device, v4l2_dev); + struct rkisp1_isp *isp = container_of(sd, struct rkisp1_isp, sd); + + if (sel->target != V4L2_SEL_TGT_CROP) + return -EINVAL; + + dev_dbg(rkisp1->dev, "%s: pad: %d sel(%d,%d)/%dx%d\n", __func__, + sel->pad, sel->r.left, sel->r.top, sel->r.width, sel->r.height); + + if (sel->pad == RKISP1_ISP_PAD_SINK_VIDEO) + rkisp1_isp_set_sink_crop(isp, cfg, &sel->r, sel->which); + else if (sel->pad == RKISP1_ISP_PAD_SOURCE_VIDEO) + rkisp1_isp_set_src_crop(isp, cfg, &sel->r, sel->which); + else + return -EINVAL; + + return 0; +} + +static int rkisp1_subdev_link_validate(struct media_link *link) +{ + if (link->sink->index == RKISP1_ISP_PAD_SINK_PARAMS) + return 0; + + return v4l2_subdev_link_validate(link); +} + +static const struct v4l2_subdev_pad_ops rkisp1_isp_pad_ops = { + .enum_mbus_code = rkisp1_isp_enum_mbus_code, + .get_selection = rkisp1_isp_get_selection, + .set_selection = rkisp1_isp_set_selection, + .init_cfg = rkisp1_isp_init_config, + .get_fmt = rkisp1_isp_get_fmt, + .set_fmt = rkisp1_isp_set_fmt, + .link_validate = v4l2_subdev_link_validate_default, +}; + +/* ---------------------------------------------------------------------------- + * Stream operations + */ + +static int rkisp1_mipi_csi2_start(struct rkisp1_isp *isp, + struct rkisp1_sensor_async *sensor) +{ + union phy_configure_opts opts; + struct phy_configure_opts_mipi_dphy *cfg = &opts.mipi_dphy; + s64 pixel_clock; + + if (!sensor->pixel_rate_ctrl) { + dev_warn(sensor->sd->dev, "No pixel rate control in subdev\n"); + return -EPIPE; + } + + pixel_clock = v4l2_ctrl_g_ctrl_int64(sensor->pixel_rate_ctrl); + if (!pixel_clock) { + dev_err(sensor->sd->dev, "Invalid pixel rate value\n"); + return -EINVAL; + } + + phy_mipi_dphy_get_default_config(pixel_clock, isp->sink_fmt->bus_width, + sensor->lanes, cfg); + phy_set_mode(sensor->dphy, PHY_MODE_MIPI_DPHY); + phy_configure(sensor->dphy, &opts); + phy_power_on(sensor->dphy); + + return 0; +} + +static void rkisp1_mipi_csi2_stop(struct rkisp1_sensor_async *sensor) +{ + phy_power_off(sensor->dphy); +} + +static int rkisp1_isp_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct rkisp1_device *rkisp1 = + container_of(sd->v4l2_dev, struct rkisp1_device, v4l2_dev); + struct v4l2_subdev *sensor_sd; + int ret = 0; + + if (!enable) { + ret = rkisp1_isp_stop(rkisp1); + if (ret) + return ret; + rkisp1_mipi_csi2_stop(rkisp1->active_sensor); + return 0; + } + + sensor_sd = rkisp1_get_remote_sensor(sd); + if (!sensor_sd) + return -ENODEV; + rkisp1->active_sensor = container_of(sensor_sd->asd, + struct rkisp1_sensor_async, asd); + + atomic_set(&rkisp1->isp.frame_sequence, -1); + ret = rkisp1_config_cif(rkisp1); + if (ret) + return ret; + + if (rkisp1->active_sensor->mbus.type != V4L2_MBUS_CSI2_DPHY) + return -EINVAL; + + ret = rkisp1_mipi_csi2_start(&rkisp1->isp, rkisp1->active_sensor); + if (ret) + return ret; + + ret = rkisp1_isp_start(rkisp1); + if (ret) + rkisp1_mipi_csi2_stop(rkisp1->active_sensor); + + return ret; +} + +static int rkisp1_isp_subs_evt(struct v4l2_subdev *sd, struct v4l2_fh *fh, + struct v4l2_event_subscription *sub) +{ + if (sub->type != V4L2_EVENT_FRAME_SYNC) + return -EINVAL; + + /* V4L2_EVENT_FRAME_SYNC doesn't require an id, so zero should be set */ + if (sub->id != 0) + return -EINVAL; + + return v4l2_event_subscribe(fh, sub, 0, NULL); +} + +static const struct media_entity_operations rkisp1_isp_media_ops = { + .link_validate = rkisp1_subdev_link_validate, +}; + +static const struct v4l2_subdev_video_ops rkisp1_isp_video_ops = { + .s_stream = rkisp1_isp_s_stream, +}; + +static const struct v4l2_subdev_core_ops rkisp1_isp_core_ops = { + .subscribe_event = rkisp1_isp_subs_evt, + .unsubscribe_event = v4l2_event_subdev_unsubscribe, +}; + +static const struct v4l2_subdev_ops rkisp1_isp_ops = { + .core = &rkisp1_isp_core_ops, + .video = &rkisp1_isp_video_ops, + .pad = &rkisp1_isp_pad_ops, +}; + +int rkisp1_isp_register(struct rkisp1_device *rkisp1, + struct v4l2_device *v4l2_dev) +{ + struct rkisp1_isp *isp = &rkisp1->isp; + struct media_pad *pads = isp->pads; + struct v4l2_subdev *sd = &isp->sd; + int ret; + + v4l2_subdev_init(sd, &rkisp1_isp_ops); + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; + sd->entity.ops = &rkisp1_isp_media_ops; + sd->entity.function = MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER; + sd->owner = THIS_MODULE; + strscpy(sd->name, RKISP1_ISP_DEV_NAME, sizeof(sd->name)); + + pads[RKISP1_ISP_PAD_SINK_VIDEO].flags = MEDIA_PAD_FL_SINK | + MEDIA_PAD_FL_MUST_CONNECT; + pads[RKISP1_ISP_PAD_SINK_PARAMS].flags = MEDIA_PAD_FL_SINK; + pads[RKISP1_ISP_PAD_SOURCE_VIDEO].flags = MEDIA_PAD_FL_SOURCE; + pads[RKISP1_ISP_PAD_SOURCE_STATS].flags = MEDIA_PAD_FL_SOURCE; + + isp->sink_fmt = rkisp1_isp_mbus_info_get(RKISP1_DEF_SINK_PAD_FMT); + isp->src_fmt = rkisp1_isp_mbus_info_get(RKISP1_DEF_SRC_PAD_FMT); + + ret = media_entity_pads_init(&sd->entity, RKISP1_ISP_PAD_MAX, pads); + if (ret) + return ret; + + ret = v4l2_device_register_subdev(v4l2_dev, sd); + if (ret) { + dev_err(sd->dev, "Failed to register isp subdev\n"); + goto err_cleanup_media_entity; + } + + rkisp1_isp_init_config(sd, rkisp1->isp.pad_cfg); + return 0; + +err_cleanup_media_entity: + media_entity_cleanup(&sd->entity); + + return ret; +} + +void rkisp1_isp_unregister(struct rkisp1_device *rkisp1) +{ + struct v4l2_subdev *sd = &rkisp1->isp.sd; + + v4l2_device_unregister_subdev(sd); + media_entity_cleanup(&sd->entity); +} + +/* ---------------------------------------------------------------------------- + * Interrupt handlers + */ + +void rkisp1_mipi_isr(struct rkisp1_device *rkisp1) +{ + u32 val, status; + + status = rkisp1_read(rkisp1, RKISP1_CIF_MIPI_MIS); + if (!status) + return; + + rkisp1_write(rkisp1, status, RKISP1_CIF_MIPI_ICR); + + /* + * Disable DPHY errctrl interrupt, because this dphy + * erctrl signal is asserted until the next changes + * of line state. This time is may be too long and cpu + * is hold in this interrupt. + */ + if (status & RKISP1_CIF_MIPI_ERR_CTRL(0x0f)) { + val = rkisp1_read(rkisp1, RKISP1_CIF_MIPI_IMSC); + rkisp1_write(rkisp1, val & ~RKISP1_CIF_MIPI_ERR_CTRL(0x0f), + RKISP1_CIF_MIPI_IMSC); + rkisp1->isp.is_dphy_errctrl_disabled = true; + } + + /* + * Enable DPHY errctrl interrupt again, if mipi have receive + * the whole frame without any error. + */ + if (status == RKISP1_CIF_MIPI_FRAME_END) { + /* + * Enable DPHY errctrl interrupt again, if mipi have receive + * the whole frame without any error. + */ + if (rkisp1->isp.is_dphy_errctrl_disabled) { + val = rkisp1_read(rkisp1, RKISP1_CIF_MIPI_IMSC); + val |= RKISP1_CIF_MIPI_ERR_CTRL(0x0f); + rkisp1_write(rkisp1, val, RKISP1_CIF_MIPI_IMSC); + rkisp1->isp.is_dphy_errctrl_disabled = false; + } + } else { + rkisp1->debug.mipi_error++; + } +} + +static void rkisp1_isp_queue_event_sof(struct rkisp1_isp *isp) +{ + struct v4l2_event event = { + .type = V4L2_EVENT_FRAME_SYNC, + }; + + /* + * Increment the frame sequence on the vsync signal. + * This will allow applications to detect dropped. + * Note that there is a debugfs counter for dropped + * frames, but using this event is more accurate. + */ + event.u.frame_sync.frame_sequence = + atomic_inc_return(&isp->frame_sequence); + v4l2_event_queue(isp->sd.devnode, &event); +} + +void rkisp1_isp_isr(struct rkisp1_device *rkisp1) +{ + u32 status, isp_err; + + status = rkisp1_read(rkisp1, RKISP1_CIF_ISP_MIS); + if (!status) + return; + + rkisp1_write(rkisp1, status, RKISP1_CIF_ISP_ICR); + + /* Vertical sync signal, starting generating new frame */ + if (status & RKISP1_CIF_ISP_V_START) + rkisp1_isp_queue_event_sof(&rkisp1->isp); + + if (status & RKISP1_CIF_ISP_PIC_SIZE_ERROR) { + /* Clear pic_size_error */ + isp_err = rkisp1_read(rkisp1, RKISP1_CIF_ISP_ERR); + rkisp1_write(rkisp1, isp_err, RKISP1_CIF_ISP_ERR_CLR); + rkisp1->debug.pic_size_error++; + } else if (status & RKISP1_CIF_ISP_DATA_LOSS) { + /* keep track of data_loss in debugfs */ + rkisp1->debug.data_loss++; + } +} diff --git a/drivers/staging/media/rkisp1/rkisp1-regs.h b/drivers/staging/media/rkisp1/rkisp1-regs.h new file mode 100644 index 000000000000..46018f435b6f --- /dev/null +++ b/drivers/staging/media/rkisp1/rkisp1-regs.h @@ -0,0 +1,1264 @@ +/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */ +/* + * Rockchip ISP1 Driver - Registers header + * + * Copyright (C) 2017 Rockchip Electronics Co., Ltd. + */ + +#ifndef _RKISP1_REGS_H +#define _RKISP1_REGS_H + +/* ISP_CTRL */ +#define RKISP1_CIF_ISP_CTRL_ISP_ENABLE BIT(0) +#define RKISP1_CIF_ISP_CTRL_ISP_MODE_RAW_PICT (0 << 1) +#define RKISP1_CIF_ISP_CTRL_ISP_MODE_ITU656 BIT(1) +#define RKISP1_CIF_ISP_CTRL_ISP_MODE_ITU601 (2 << 1) +#define RKISP1_CIF_ISP_CTRL_ISP_MODE_BAYER_ITU601 (3 << 1) +#define RKISP1_CIF_ISP_CTRL_ISP_MODE_DATA_MODE (4 << 1) +#define RKISP1_CIF_ISP_CTRL_ISP_MODE_BAYER_ITU656 (5 << 1) +#define RKISP1_CIF_ISP_CTRL_ISP_MODE_RAW_PICT_ITU656 (6 << 1) +#define RKISP1_CIF_ISP_CTRL_ISP_INFORM_ENABLE BIT(4) +#define RKISP1_CIF_ISP_CTRL_ISP_GAMMA_IN_ENA BIT(6) +#define RKISP1_CIF_ISP_CTRL_ISP_AWB_ENA BIT(7) +#define RKISP1_CIF_ISP_CTRL_ISP_CFG_UPD_PERMANENT BIT(8) +#define RKISP1_CIF_ISP_CTRL_ISP_CFG_UPD BIT(9) +#define RKISP1_CIF_ISP_CTRL_ISP_GEN_CFG_UPD BIT(10) +#define RKISP1_CIF_ISP_CTRL_ISP_GAMMA_OUT_ENA BIT(11) +#define RKISP1_CIF_ISP_CTRL_ISP_FLASH_MODE_ENA BIT(12) +#define RKISP1_CIF_ISP_CTRL_ISP_CSM_Y_FULL_ENA BIT(13) +#define RKISP1_CIF_ISP_CTRL_ISP_CSM_C_FULL_ENA BIT(14) + +/* ISP_ACQ_PROP */ +#define RKISP1_CIF_ISP_ACQ_PROP_POS_EDGE BIT(0) +#define RKISP1_CIF_ISP_ACQ_PROP_HSYNC_LOW BIT(1) +#define RKISP1_CIF_ISP_ACQ_PROP_VSYNC_LOW BIT(2) +#define RKISP1_CIF_ISP_ACQ_PROP_BAYER_PAT_RGGB (0 << 3) +#define RKISP1_CIF_ISP_ACQ_PROP_BAYER_PAT_GRBG BIT(3) +#define RKISP1_CIF_ISP_ACQ_PROP_BAYER_PAT_GBRG (2 << 3) +#define RKISP1_CIF_ISP_ACQ_PROP_BAYER_PAT_BGGR (3 << 3) +#define RKISP1_CIF_ISP_ACQ_PROP_BAYER_PAT(pat) ((pat) << 3) +#define RKISP1_CIF_ISP_ACQ_PROP_YCBYCR (0 << 7) +#define RKISP1_CIF_ISP_ACQ_PROP_YCRYCB BIT(7) +#define RKISP1_CIF_ISP_ACQ_PROP_CBYCRY (2 << 7) +#define RKISP1_CIF_ISP_ACQ_PROP_CRYCBY (3 << 7) +#define RKISP1_CIF_ISP_ACQ_PROP_FIELD_SEL_ALL (0 << 9) +#define RKISP1_CIF_ISP_ACQ_PROP_FIELD_SEL_EVEN BIT(9) +#define RKISP1_CIF_ISP_ACQ_PROP_FIELD_SEL_ODD (2 << 9) +#define RKISP1_CIF_ISP_ACQ_PROP_IN_SEL_12B (0 << 12) +#define RKISP1_CIF_ISP_ACQ_PROP_IN_SEL_10B_ZERO BIT(12) +#define RKISP1_CIF_ISP_ACQ_PROP_IN_SEL_10B_MSB (2 << 12) +#define RKISP1_CIF_ISP_ACQ_PROP_IN_SEL_8B_ZERO (3 << 12) +#define RKISP1_CIF_ISP_ACQ_PROP_IN_SEL_8B_MSB (4 << 12) + +/* VI_DPCL */ +#define RKISP1_CIF_VI_DPCL_DMA_JPEG (0 << 0) +#define RKISP1_CIF_VI_DPCL_MP_MUX_MRSZ_MI BIT(0) +#define RKISP1_CIF_VI_DPCL_MP_MUX_MRSZ_JPEG (2 << 0) +#define RKISP1_CIF_VI_DPCL_CHAN_MODE_MP BIT(2) +#define RKISP1_CIF_VI_DPCL_CHAN_MODE_SP (2 << 2) +#define RKISP1_CIF_VI_DPCL_CHAN_MODE_MPSP (3 << 2) +#define RKISP1_CIF_VI_DPCL_DMA_SW_SPMUX (0 << 4) +#define RKISP1_CIF_VI_DPCL_DMA_SW_SI BIT(4) +#define RKISP1_CIF_VI_DPCL_DMA_SW_IE (2 << 4) +#define RKISP1_CIF_VI_DPCL_DMA_SW_JPEG (3 << 4) +#define RKISP1_CIF_VI_DPCL_DMA_SW_ISP (4 << 4) +#define RKISP1_CIF_VI_DPCL_IF_SEL_PARALLEL (0 << 8) +#define RKISP1_CIF_VI_DPCL_IF_SEL_SMIA BIT(8) +#define RKISP1_CIF_VI_DPCL_IF_SEL_MIPI (2 << 8) +#define RKISP1_CIF_VI_DPCL_DMA_IE_MUX_DMA BIT(10) +#define RKISP1_CIF_VI_DPCL_DMA_SP_MUX_DMA BIT(11) + +/* ISP_IMSC - ISP_MIS - ISP_RIS - ISP_ICR - ISP_ISR */ +#define RKISP1_CIF_ISP_OFF BIT(0) +#define RKISP1_CIF_ISP_FRAME BIT(1) +#define RKISP1_CIF_ISP_DATA_LOSS BIT(2) +#define RKISP1_CIF_ISP_PIC_SIZE_ERROR BIT(3) +#define RKISP1_CIF_ISP_AWB_DONE BIT(4) +#define RKISP1_CIF_ISP_FRAME_IN BIT(5) +#define RKISP1_CIF_ISP_V_START BIT(6) +#define RKISP1_CIF_ISP_H_START BIT(7) +#define RKISP1_CIF_ISP_FLASH_ON BIT(8) +#define RKISP1_CIF_ISP_FLASH_OFF BIT(9) +#define RKISP1_CIF_ISP_SHUTTER_ON BIT(10) +#define RKISP1_CIF_ISP_SHUTTER_OFF BIT(11) +#define RKISP1_CIF_ISP_AFM_SUM_OF BIT(12) +#define RKISP1_CIF_ISP_AFM_LUM_OF BIT(13) +#define RKISP1_CIF_ISP_AFM_FIN BIT(14) +#define RKISP1_CIF_ISP_HIST_MEASURE_RDY BIT(15) +#define RKISP1_CIF_ISP_FLASH_CAP BIT(17) +#define RKISP1_CIF_ISP_EXP_END BIT(18) +#define RKISP1_CIF_ISP_VSM_END BIT(19) + +/* ISP_ERR */ +#define RKISP1_CIF_ISP_ERR_INFORM_SIZE BIT(0) +#define RKISP1_CIF_ISP_ERR_IS_SIZE BIT(1) +#define RKISP1_CIF_ISP_ERR_OUTFORM_SIZE BIT(2) + +/* MI_CTRL */ +#define RKISP1_CIF_MI_CTRL_MP_ENABLE BIT(0) +#define RKISP1_CIF_MI_CTRL_SP_ENABLE (2 << 0) +#define RKISP1_CIF_MI_CTRL_JPEG_ENABLE (4 << 0) +#define RKISP1_CIF_MI_CTRL_RAW_ENABLE (8 << 0) +#define RKISP1_CIF_MI_CTRL_HFLIP BIT(4) +#define RKISP1_CIF_MI_CTRL_VFLIP BIT(5) +#define RKISP1_CIF_MI_CTRL_ROT BIT(6) +#define RKISP1_CIF_MI_BYTE_SWAP BIT(7) +#define RKISP1_CIF_MI_SP_Y_FULL_YUV2RGB BIT(8) +#define RKISP1_CIF_MI_SP_CBCR_FULL_YUV2RGB BIT(9) +#define RKISP1_CIF_MI_SP_422NONCOSITEED BIT(10) +#define RKISP1_CIF_MI_MP_PINGPONG_ENABEL BIT(11) +#define RKISP1_CIF_MI_SP_PINGPONG_ENABEL BIT(12) +#define RKISP1_CIF_MI_MP_AUTOUPDATE_ENABLE BIT(13) +#define RKISP1_CIF_MI_SP_AUTOUPDATE_ENABLE BIT(14) +#define RKISP1_CIF_MI_LAST_PIXEL_SIG_ENABLE BIT(15) +#define RKISP1_CIF_MI_CTRL_BURST_LEN_LUM_16 (0 << 16) +#define RKISP1_CIF_MI_CTRL_BURST_LEN_LUM_32 BIT(16) +#define RKISP1_CIF_MI_CTRL_BURST_LEN_LUM_64 (2 << 16) +#define RKISP1_CIF_MI_CTRL_BURST_LEN_CHROM_16 (0 << 18) +#define RKISP1_CIF_MI_CTRL_BURST_LEN_CHROM_32 BIT(18) +#define RKISP1_CIF_MI_CTRL_BURST_LEN_CHROM_64 (2 << 18) +#define RKISP1_CIF_MI_CTRL_INIT_BASE_EN BIT(20) +#define RKISP1_CIF_MI_CTRL_INIT_OFFSET_EN BIT(21) +#define RKISP1_MI_CTRL_MP_WRITE_YUV_PLA_OR_RAW8 (0 << 22) +#define RKISP1_MI_CTRL_MP_WRITE_YUV_SPLA BIT(22) +#define RKISP1_MI_CTRL_MP_WRITE_YUVINT (2 << 22) +#define RKISP1_MI_CTRL_MP_WRITE_RAW12 (2 << 22) +#define RKISP1_MI_CTRL_SP_WRITE_PLA (0 << 24) +#define RKISP1_MI_CTRL_SP_WRITE_SPLA BIT(24) +#define RKISP1_MI_CTRL_SP_WRITE_INT (2 << 24) +#define RKISP1_MI_CTRL_SP_INPUT_YUV400 (0 << 26) +#define RKISP1_MI_CTRL_SP_INPUT_YUV420 BIT(26) +#define RKISP1_MI_CTRL_SP_INPUT_YUV422 (2 << 26) +#define RKISP1_MI_CTRL_SP_INPUT_YUV444 (3 << 26) +#define RKISP1_MI_CTRL_SP_OUTPUT_YUV400 (0 << 28) +#define RKISP1_MI_CTRL_SP_OUTPUT_YUV420 BIT(28) +#define RKISP1_MI_CTRL_SP_OUTPUT_YUV422 (2 << 28) +#define RKISP1_MI_CTRL_SP_OUTPUT_YUV444 (3 << 28) +#define RKISP1_MI_CTRL_SP_OUTPUT_RGB565 (4 << 28) +#define RKISP1_MI_CTRL_SP_OUTPUT_RGB666 (5 << 28) +#define RKISP1_MI_CTRL_SP_OUTPUT_RGB888 (6 << 28) + +#define RKISP1_MI_CTRL_MP_FMT_MASK GENMASK(23, 22) +#define RKISP1_MI_CTRL_SP_FMT_MASK GENMASK(30, 24) + +/* MI_INIT */ +#define RKISP1_CIF_MI_INIT_SKIP BIT(2) +#define RKISP1_CIF_MI_INIT_SOFT_UPD BIT(4) + +/* MI_CTRL_SHD */ +#define RKISP1_CIF_MI_CTRL_SHD_MP_IN_ENABLED BIT(0) +#define RKISP1_CIF_MI_CTRL_SHD_SP_IN_ENABLED BIT(1) +#define RKISP1_CIF_MI_CTRL_SHD_JPEG_IN_ENABLED BIT(2) +#define RKISP1_CIF_MI_CTRL_SHD_RAW_IN_ENABLED BIT(3) +#define RKISP1_CIF_MI_CTRL_SHD_MP_OUT_ENABLED BIT(16) +#define RKISP1_CIF_MI_CTRL_SHD_SP_OUT_ENABLED BIT(17) +#define RKISP1_CIF_MI_CTRL_SHD_JPEG_OUT_ENABLED BIT(18) +#define RKISP1_CIF_MI_CTRL_SHD_RAW_OUT_ENABLED BIT(19) + +/* RSZ_CTRL */ +#define RKISP1_CIF_RSZ_CTRL_SCALE_HY_ENABLE BIT(0) +#define RKISP1_CIF_RSZ_CTRL_SCALE_HC_ENABLE BIT(1) +#define RKISP1_CIF_RSZ_CTRL_SCALE_VY_ENABLE BIT(2) +#define RKISP1_CIF_RSZ_CTRL_SCALE_VC_ENABLE BIT(3) +#define RKISP1_CIF_RSZ_CTRL_SCALE_HY_UP BIT(4) +#define RKISP1_CIF_RSZ_CTRL_SCALE_HC_UP BIT(5) +#define RKISP1_CIF_RSZ_CTRL_SCALE_VY_UP BIT(6) +#define RKISP1_CIF_RSZ_CTRL_SCALE_VC_UP BIT(7) +#define RKISP1_CIF_RSZ_CTRL_CFG_UPD BIT(8) +#define RKISP1_CIF_RSZ_CTRL_CFG_UPD_AUTO BIT(9) +#define RKISP1_CIF_RSZ_SCALER_FACTOR BIT(16) + +/* MI_IMSC - MI_MIS - MI_RIS - MI_ICR - MI_ISR */ +#define RKISP1_CIF_MI_FRAME(stream) BIT((stream)->id) +#define RKISP1_CIF_MI_MBLK_LINE BIT(2) +#define RKISP1_CIF_MI_FILL_MP_Y BIT(3) +#define RKISP1_CIF_MI_WRAP_MP_Y BIT(4) +#define RKISP1_CIF_MI_WRAP_MP_CB BIT(5) +#define RKISP1_CIF_MI_WRAP_MP_CR BIT(6) +#define RKISP1_CIF_MI_WRAP_SP_Y BIT(7) +#define RKISP1_CIF_MI_WRAP_SP_CB BIT(8) +#define RKISP1_CIF_MI_WRAP_SP_CR BIT(9) +#define RKISP1_CIF_MI_DMA_READY BIT(11) + +/* MI_STATUS */ +#define RKISP1_CIF_MI_STATUS_MP_Y_FIFO_FULL BIT(0) +#define RKISP1_CIF_MI_STATUS_SP_Y_FIFO_FULL BIT(4) + +/* MI_DMA_CTRL */ +#define RKISP1_CIF_MI_DMA_CTRL_BURST_LEN_LUM_16 (0 << 0) +#define RKISP1_CIF_MI_DMA_CTRL_BURST_LEN_LUM_32 BIT(0) +#define RKISP1_CIF_MI_DMA_CTRL_BURST_LEN_LUM_64 (2 << 0) +#define RKISP1_CIF_MI_DMA_CTRL_BURST_LEN_CHROM_16 (0 << 2) +#define RKISP1_CIF_MI_DMA_CTRL_BURST_LEN_CHROM_32 BIT(2) +#define RKISP1_CIF_MI_DMA_CTRL_BURST_LEN_CHROM_64 (2 << 2) +#define RKISP1_CIF_MI_DMA_CTRL_READ_FMT_PLANAR (0 << 4) +#define RKISP1_CIF_MI_DMA_CTRL_READ_FMT_SPLANAR BIT(4) +#define RKISP1_CIF_MI_DMA_CTRL_FMT_YUV400 (0 << 6) +#define RKISP1_CIF_MI_DMA_CTRL_FMT_YUV420 BIT(6) +#define RKISP1_CIF_MI_DMA_CTRL_READ_FMT_PACKED (2 << 4) +#define RKISP1_CIF_MI_DMA_CTRL_FMT_YUV422 (2 << 6) +#define RKISP1_CIF_MI_DMA_CTRL_FMT_YUV444 (3 << 6) +#define RKISP1_CIF_MI_DMA_CTRL_BYTE_SWAP BIT(8) +#define RKISP1_CIF_MI_DMA_CTRL_CONTINUOUS_ENA BIT(9) +#define RKISP1_CIF_MI_DMA_CTRL_RGB_BAYER_NO (0 << 12) +#define RKISP1_CIF_MI_DMA_CTRL_RGB_BAYER_8BIT BIT(12) +#define RKISP1_CIF_MI_DMA_CTRL_RGB_BAYER_16BIT (2 << 12) +/* MI_DMA_START */ +#define RKISP1_CIF_MI_DMA_START_ENABLE BIT(0) +/* MI_XTD_FORMAT_CTRL */ +#define RKISP1_CIF_MI_XTD_FMT_CTRL_MP_CB_CR_SWAP BIT(0) +#define RKISP1_CIF_MI_XTD_FMT_CTRL_SP_CB_CR_SWAP BIT(1) +#define RKISP1_CIF_MI_XTD_FMT_CTRL_DMA_CB_CR_SWAP BIT(2) + +/* CCL */ +#define RKISP1_CIF_CCL_CIF_CLK_DIS BIT(2) +/* ICCL */ +#define RKISP1_CIF_ICCL_ISP_CLK BIT(0) +#define RKISP1_CIF_ICCL_CP_CLK BIT(1) +#define RKISP1_CIF_ICCL_RES_2 BIT(2) +#define RKISP1_CIF_ICCL_MRSZ_CLK BIT(3) +#define RKISP1_CIF_ICCL_SRSZ_CLK BIT(4) +#define RKISP1_CIF_ICCL_JPEG_CLK BIT(5) +#define RKISP1_CIF_ICCL_MI_CLK BIT(6) +#define RKISP1_CIF_ICCL_RES_7 BIT(7) +#define RKISP1_CIF_ICCL_IE_CLK BIT(8) +#define RKISP1_CIF_ICCL_SIMP_CLK BIT(9) +#define RKISP1_CIF_ICCL_SMIA_CLK BIT(10) +#define RKISP1_CIF_ICCL_MIPI_CLK BIT(11) +#define RKISP1_CIF_ICCL_DCROP_CLK BIT(12) +/* IRCL */ +#define RKISP1_CIF_IRCL_ISP_SW_RST BIT(0) +#define RKISP1_CIF_IRCL_CP_SW_RST BIT(1) +#define RKISP1_CIF_IRCL_YCS_SW_RST BIT(2) +#define RKISP1_CIF_IRCL_MRSZ_SW_RST BIT(3) +#define RKISP1_CIF_IRCL_SRSZ_SW_RST BIT(4) +#define RKISP1_CIF_IRCL_JPEG_SW_RST BIT(5) +#define RKISP1_CIF_IRCL_MI_SW_RST BIT(6) +#define RKISP1_CIF_IRCL_CIF_SW_RST BIT(7) +#define RKISP1_CIF_IRCL_IE_SW_RST BIT(8) +#define RKISP1_CIF_IRCL_SI_SW_RST BIT(9) +#define RKISP1_CIF_IRCL_MIPI_SW_RST BIT(11) + +/* C_PROC_CTR */ +#define RKISP1_CIF_C_PROC_CTR_ENABLE BIT(0) +#define RKISP1_CIF_C_PROC_YOUT_FULL BIT(1) +#define RKISP1_CIF_C_PROC_YIN_FULL BIT(2) +#define RKISP1_CIF_C_PROC_COUT_FULL BIT(3) +#define RKISP1_CIF_C_PROC_CTRL_RESERVED 0xFFFFFFFE +#define RKISP1_CIF_C_PROC_CONTRAST_RESERVED 0xFFFFFF00 +#define RKISP1_CIF_C_PROC_BRIGHTNESS_RESERVED 0xFFFFFF00 +#define RKISP1_CIF_C_PROC_HUE_RESERVED 0xFFFFFF00 +#define RKISP1_CIF_C_PROC_SATURATION_RESERVED 0xFFFFFF00 +#define RKISP1_CIF_C_PROC_MACC_RESERVED 0xE000E000 +#define RKISP1_CIF_C_PROC_TONE_RESERVED 0xF000 +/* DUAL_CROP_CTRL */ +#define RKISP1_CIF_DUAL_CROP_MP_MODE_BYPASS (0 << 0) +#define RKISP1_CIF_DUAL_CROP_MP_MODE_YUV BIT(0) +#define RKISP1_CIF_DUAL_CROP_MP_MODE_RAW (2 << 0) +#define RKISP1_CIF_DUAL_CROP_SP_MODE_BYPASS (0 << 2) +#define RKISP1_CIF_DUAL_CROP_SP_MODE_YUV BIT(2) +#define RKISP1_CIF_DUAL_CROP_SP_MODE_RAW (2 << 2) +#define RKISP1_CIF_DUAL_CROP_CFG_UPD_PERMANENT BIT(4) +#define RKISP1_CIF_DUAL_CROP_CFG_UPD BIT(5) +#define RKISP1_CIF_DUAL_CROP_GEN_CFG_UPD BIT(6) + +/* IMG_EFF_CTRL */ +#define RKISP1_CIF_IMG_EFF_CTRL_ENABLE BIT(0) +#define RKISP1_CIF_IMG_EFF_CTRL_MODE_BLACKWHITE (0 << 1) +#define RKISP1_CIF_IMG_EFF_CTRL_MODE_NEGATIVE BIT(1) +#define RKISP1_CIF_IMG_EFF_CTRL_MODE_SEPIA (2 << 1) +#define RKISP1_CIF_IMG_EFF_CTRL_MODE_COLOR_SEL (3 << 1) +#define RKISP1_CIF_IMG_EFF_CTRL_MODE_EMBOSS (4 << 1) +#define RKISP1_CIF_IMG_EFF_CTRL_MODE_SKETCH (5 << 1) +#define RKISP1_CIF_IMG_EFF_CTRL_MODE_SHARPEN (6 << 1) +#define RKISP1_CIF_IMG_EFF_CTRL_CFG_UPD BIT(4) +#define RKISP1_CIF_IMG_EFF_CTRL_YCBCR_FULL BIT(5) + +#define RKISP1_CIF_IMG_EFF_CTRL_MODE_BLACKWHITE_SHIFT 0 +#define RKISP1_CIF_IMG_EFF_CTRL_MODE_NEGATIVE_SHIFT 1 +#define RKISP1_CIF_IMG_EFF_CTRL_MODE_SEPIA_SHIFT 2 +#define RKISP1_CIF_IMG_EFF_CTRL_MODE_COLOR_SEL_SHIFT 3 +#define RKISP1_CIF_IMG_EFF_CTRL_MODE_EMBOSS_SHIFT 4 +#define RKISP1_CIF_IMG_EFF_CTRL_MODE_SKETCH_SHIFT 5 +#define RKISP1_CIF_IMG_EFF_CTRL_MODE_SHARPEN_SHIFT 6 +#define RKISP1_CIF_IMG_EFF_CTRL_MODE_MASK 0xE + +/* IMG_EFF_COLOR_SEL */ +#define RKISP1_CIF_IMG_EFF_COLOR_RGB 0 +#define RKISP1_CIF_IMG_EFF_COLOR_B BIT(0) +#define RKISP1_CIF_IMG_EFF_COLOR_G (2 << 0) +#define RKISP1_CIF_IMG_EFF_COLOR_GB (3 << 0) +#define RKISP1_CIF_IMG_EFF_COLOR_R (4 << 0) +#define RKISP1_CIF_IMG_EFF_COLOR_RB (5 << 0) +#define RKISP1_CIF_IMG_EFF_COLOR_RG (6 << 0) +#define RKISP1_CIF_IMG_EFF_COLOR_RGB2 (7 << 0) + +/* MIPI_CTRL */ +#define RKISP1_CIF_MIPI_CTRL_OUTPUT_ENA BIT(0) +#define RKISP1_CIF_MIPI_CTRL_SHUTDOWNLANES(a) (((a) & 0xF) << 8) +#define RKISP1_CIF_MIPI_CTRL_NUM_LANES(a) (((a) & 0x3) << 12) +#define RKISP1_CIF_MIPI_CTRL_ERR_SOT_HS_SKIP BIT(16) +#define RKISP1_CIF_MIPI_CTRL_ERR_SOT_SYNC_HS_SKIP BIT(17) +#define RKISP1_CIF_MIPI_CTRL_CLOCKLANE_ENA BIT(18) + +/* MIPI_DATA_SEL */ +#define RKISP1_CIF_MIPI_DATA_SEL_VC(a) (((a) & 0x3) << 6) +#define RKISP1_CIF_MIPI_DATA_SEL_DT(a) (((a) & 0x3F) << 0) +/* MIPI DATA_TYPE */ +#define RKISP1_CIF_CSI2_DT_YUV420_8b 0x18 +#define RKISP1_CIF_CSI2_DT_YUV420_10b 0x19 +#define RKISP1_CIF_CSI2_DT_YUV422_8b 0x1E +#define RKISP1_CIF_CSI2_DT_YUV422_10b 0x1F +#define RKISP1_CIF_CSI2_DT_RGB565 0x22 +#define RKISP1_CIF_CSI2_DT_RGB666 0x23 +#define RKISP1_CIF_CSI2_DT_RGB888 0x24 +#define RKISP1_CIF_CSI2_DT_RAW8 0x2A +#define RKISP1_CIF_CSI2_DT_RAW10 0x2B +#define RKISP1_CIF_CSI2_DT_RAW12 0x2C + +/* MIPI_IMSC, MIPI_RIS, MIPI_MIS, MIPI_ICR, MIPI_ISR */ +#define RKISP1_CIF_MIPI_SYNC_FIFO_OVFLW(a) (((a) & 0xF) << 0) +#define RKISP1_CIF_MIPI_ERR_SOT(a) (((a) & 0xF) << 4) +#define RKISP1_CIF_MIPI_ERR_SOT_SYNC(a) (((a) & 0xF) << 8) +#define RKISP1_CIF_MIPI_ERR_EOT_SYNC(a) (((a) & 0xF) << 12) +#define RKISP1_CIF_MIPI_ERR_CTRL(a) (((a) & 0xF) << 16) +#define RKISP1_CIF_MIPI_ERR_PROTOCOL BIT(20) +#define RKISP1_CIF_MIPI_ERR_ECC1 BIT(21) +#define RKISP1_CIF_MIPI_ERR_ECC2 BIT(22) +#define RKISP1_CIF_MIPI_ERR_CS BIT(23) +#define RKISP1_CIF_MIPI_FRAME_END BIT(24) +#define RKISP1_CIF_MIPI_ADD_DATA_OVFLW BIT(25) +#define RKISP1_CIF_MIPI_ADD_DATA_WATER_MARK BIT(26) + +#define RKISP1_CIF_MIPI_ERR_CSI (RKISP1_CIF_MIPI_ERR_PROTOCOL | \ + RKISP1_CIF_MIPI_ERR_ECC1 | \ + RKISP1_CIF_MIPI_ERR_ECC2 | \ + RKISP1_CIF_MIPI_ERR_CS) + +#define RKISP1_CIF_MIPI_ERR_DPHY (RKISP1_CIF_MIPI_ERR_SOT(3) | \ + RKISP1_CIF_MIPI_ERR_SOT_SYNC(3) | \ + RKISP1_CIF_MIPI_ERR_EOT_SYNC(3) | \ + RKISP1_CIF_MIPI_ERR_CTRL(3)) + +/* SUPER_IMPOSE */ +#define RKISP1_CIF_SUPER_IMP_CTRL_NORMAL_MODE BIT(0) +#define RKISP1_CIF_SUPER_IMP_CTRL_REF_IMG_MEM BIT(1) +#define RKISP1_CIF_SUPER_IMP_CTRL_TRANSP_DIS BIT(2) + +/* ISP HISTOGRAM CALCULATION : ISP_HIST_PROP */ +#define RKISP1_CIF_ISP_HIST_PROP_MODE_DIS (0 << 0) +#define RKISP1_CIF_ISP_HIST_PROP_MODE_RGB BIT(0) +#define RKISP1_CIF_ISP_HIST_PROP_MODE_RED (2 << 0) +#define RKISP1_CIF_ISP_HIST_PROP_MODE_GREEN (3 << 0) +#define RKISP1_CIF_ISP_HIST_PROP_MODE_BLUE (4 << 0) +#define RKISP1_CIF_ISP_HIST_PROP_MODE_LUM (5 << 0) +#define RKISP1_CIF_ISP_HIST_PROP_MODE_MASK 0x7 +#define RKISP1_CIF_ISP_HIST_PREDIV_SET(x) (((x) & 0x7F) << 3) +#define RKISP1_CIF_ISP_HIST_WEIGHT_SET(v0, v1, v2, v3) \ + (((v0) & 0x1F) | (((v1) & 0x1F) << 8) |\ + (((v2) & 0x1F) << 16) | \ + (((v3) & 0x1F) << 24)) + +#define RKISP1_CIF_ISP_HIST_WINDOW_OFFSET_RESERVED 0xFFFFF000 +#define RKISP1_CIF_ISP_HIST_WINDOW_SIZE_RESERVED 0xFFFFF800 +#define RKISP1_CIF_ISP_HIST_WEIGHT_RESERVED 0xE0E0E0E0 +#define RKISP1_CIF_ISP_MAX_HIST_PREDIVIDER 0x0000007F +#define RKISP1_CIF_ISP_HIST_ROW_NUM 5 +#define RKISP1_CIF_ISP_HIST_COLUMN_NUM 5 + +/* AUTO FOCUS MEASUREMENT: ISP_AFM_CTRL */ +#define RKISP1_ISP_AFM_CTRL_ENABLE BIT(0) + +/* SHUTTER CONTROL */ +#define RKISP1_CIF_ISP_SH_CTRL_SH_ENA BIT(0) +#define RKISP1_CIF_ISP_SH_CTRL_REP_EN BIT(1) +#define RKISP1_CIF_ISP_SH_CTRL_SRC_SH_TRIG BIT(2) +#define RKISP1_CIF_ISP_SH_CTRL_EDGE_POS BIT(3) +#define RKISP1_CIF_ISP_SH_CTRL_POL_LOW BIT(4) + +/* FLASH MODULE */ +/* ISP_FLASH_CMD */ +#define RKISP1_CIFFLASH_CMD_PRELIGHT_ON BIT(0) +#define RKISP1_CIFFLASH_CMD_FLASH_ON BIT(1) +#define RKISP1_CIFFLASH_CMD_PRE_FLASH_ON BIT(2) +/* ISP_FLASH_CONFIG */ +#define RKISP1_CIFFLASH_CONFIG_PRELIGHT_END BIT(0) +#define RKISP1_CIFFLASH_CONFIG_VSYNC_POS BIT(1) +#define RKISP1_CIFFLASH_CONFIG_PRELIGHT_LOW BIT(2) +#define RKISP1_CIFFLASH_CONFIG_SRC_FL_TRIG BIT(3) +#define RKISP1_CIFFLASH_CONFIG_DELAY(a) (((a) & 0xF) << 4) + +/* Demosaic: ISP_DEMOSAIC */ +#define RKISP1_CIF_ISP_DEMOSAIC_BYPASS BIT(10) +#define RKISP1_CIF_ISP_DEMOSAIC_TH(x) ((x) & 0xFF) + +/* AWB */ +/* ISP_AWB_PROP */ +#define RKISP1_CIF_ISP_AWB_YMAX_CMP_EN BIT(2) +#define RKISP1_CIF_ISP_AWB_YMAX_READ(x) (((x) >> 2) & 1) +#define RKISP1_CIF_ISP_AWB_MODE_RGB_EN ((1 << 31) | (0x2 << 0)) +#define RKISP1_CIF_ISP_AWB_MODE_YCBCR_EN ((0 << 31) | (0x2 << 0)) +#define RKISP1_CIF_ISP_AWB_MODE_YCBCR_EN ((0 << 31) | (0x2 << 0)) +#define RKISP1_CIF_ISP_AWB_MODE_MASK_NONE 0xFFFFFFFC +#define RKISP1_CIF_ISP_AWB_MODE_READ(x) ((x) & 3) +/* ISP_AWB_GAIN_RB, ISP_AWB_GAIN_G */ +#define RKISP1_CIF_ISP_AWB_GAIN_R_SET(x) (((x) & 0x3FF) << 16) +#define RKISP1_CIF_ISP_AWB_GAIN_R_READ(x) (((x) >> 16) & 0x3FF) +#define RKISP1_CIF_ISP_AWB_GAIN_B_SET(x) ((x) & 0x3FFF) +#define RKISP1_CIF_ISP_AWB_GAIN_B_READ(x) ((x) & 0x3FFF) +/* ISP_AWB_REF */ +#define RKISP1_CIF_ISP_AWB_REF_CR_SET(x) (((x) & 0xFF) << 8) +#define RKISP1_CIF_ISP_AWB_REF_CR_READ(x) (((x) >> 8) & 0xFF) +#define RKISP1_CIF_ISP_AWB_REF_CB_READ(x) ((x) & 0xFF) +/* ISP_AWB_THRESH */ +#define RKISP1_CIF_ISP_AWB_MAX_CS_SET(x) (((x) & 0xFF) << 8) +#define RKISP1_CIF_ISP_AWB_MAX_CS_READ(x) (((x) >> 8) & 0xFF) +#define RKISP1_CIF_ISP_AWB_MIN_C_READ(x) ((x) & 0xFF) +#define RKISP1_CIF_ISP_AWB_MIN_Y_SET(x) (((x) & 0xFF) << 16) +#define RKISP1_CIF_ISP_AWB_MIN_Y_READ(x) (((x) >> 16) & 0xFF) +#define RKISP1_CIF_ISP_AWB_MAX_Y_SET(x) (((x) & 0xFF) << 24) +#define RKISP1_CIF_ISP_AWB_MAX_Y_READ(x) (((x) >> 24) & 0xFF) +/* ISP_AWB_MEAN */ +#define RKISP1_CIF_ISP_AWB_GET_MEAN_CR_R(x) ((x) & 0xFF) +#define RKISP1_CIF_ISP_AWB_GET_MEAN_CB_B(x) (((x) >> 8) & 0xFF) +#define RKISP1_CIF_ISP_AWB_GET_MEAN_Y_G(x) (((x) >> 16) & 0xFF) +/* ISP_AWB_WHITE_CNT */ +#define RKISP1_CIF_ISP_AWB_GET_PIXEL_CNT(x) ((x) & 0x3FFFFFF) + +#define RKISP1_CIF_ISP_AWB_GAINS_MAX_VAL 0x000003FF +#define RKISP1_CIF_ISP_AWB_WINDOW_OFFSET_MAX 0x00000FFF +#define RKISP1_CIF_ISP_AWB_WINDOW_MAX_SIZE 0x00001FFF +#define RKISP1_CIF_ISP_AWB_CBCR_MAX_REF 0x000000FF +#define RKISP1_CIF_ISP_AWB_THRES_MAX_YC 0x000000FF + +/* AE */ +/* ISP_EXP_CTRL */ +#define RKISP1_CIF_ISP_EXP_ENA BIT(0) +#define RKISP1_CIF_ISP_EXP_CTRL_AUTOSTOP BIT(1) +/* + *'1' luminance calculation according to Y=(R+G+B) x 0.332 (85/256) + *'0' luminance calculation according to Y=16+0.25R+0.5G+0.1094B + */ +#define RKISP1_CIF_ISP_EXP_CTRL_MEASMODE_1 BIT(31) + +/* ISP_EXP_H_SIZE */ +#define RKISP1_CIF_ISP_EXP_H_SIZE_SET(x) ((x) & 0x7FF) +#define RKISP1_CIF_ISP_EXP_HEIGHT_MASK 0x000007FF +/* ISP_EXP_V_SIZE : vertical size must be a multiple of 2). */ +#define RKISP1_CIF_ISP_EXP_V_SIZE_SET(x) ((x) & 0x7FE) + +/* ISP_EXP_H_OFFSET */ +#define RKISP1_CIF_ISP_EXP_H_OFFSET_SET(x) ((x) & 0x1FFF) +#define RKISP1_CIF_ISP_EXP_MAX_HOFFS 2424 +/* ISP_EXP_V_OFFSET */ +#define RKISP1_CIF_ISP_EXP_V_OFFSET_SET(x) ((x) & 0x1FFF) +#define RKISP1_CIF_ISP_EXP_MAX_VOFFS 1806 + +#define RKISP1_CIF_ISP_EXP_ROW_NUM 5 +#define RKISP1_CIF_ISP_EXP_COLUMN_NUM 5 +#define RKISP1_CIF_ISP_EXP_NUM_LUMA_REGS \ + (RKISP1_CIF_ISP_EXP_ROW_NUM * RKISP1_CIF_ISP_EXP_COLUMN_NUM) +#define RKISP1_CIF_ISP_EXP_BLOCK_MAX_HSIZE 516 +#define RKISP1_CIF_ISP_EXP_BLOCK_MIN_HSIZE 35 +#define RKISP1_CIF_ISP_EXP_BLOCK_MAX_VSIZE 390 +#define RKISP1_CIF_ISP_EXP_BLOCK_MIN_VSIZE 28 +#define RKISP1_CIF_ISP_EXP_MAX_HSIZE \ + (RKISP1_CIF_ISP_EXP_BLOCK_MAX_HSIZE * RKISP1_CIF_ISP_EXP_COLUMN_NUM + 1) +#define RKISP1_CIF_ISP_EXP_MIN_HSIZE \ + (RKISP1_CIF_ISP_EXP_BLOCK_MIN_HSIZE * RKISP1_CIF_ISP_EXP_COLUMN_NUM + 1) +#define RKISP1_CIF_ISP_EXP_MAX_VSIZE \ + (RKISP1_CIF_ISP_EXP_BLOCK_MAX_VSIZE * RKISP1_CIF_ISP_EXP_ROW_NUM + 1) +#define RKISP1_CIF_ISP_EXP_MIN_VSIZE \ + (RKISP1_CIF_ISP_EXP_BLOCK_MIN_VSIZE * RKISP1_CIF_ISP_EXP_ROW_NUM + 1) + +/* LSC: ISP_LSC_CTRL */ +#define RKISP1_CIF_ISP_LSC_CTRL_ENA BIT(0) +#define RKISP1_CIF_ISP_LSC_SECT_SIZE_RESERVED 0xFC00FC00 +#define RKISP1_CIF_ISP_LSC_GRAD_RESERVED 0xF000F000 +#define RKISP1_CIF_ISP_LSC_SAMPLE_RESERVED 0xF000F000 +#define RKISP1_CIF_ISP_LSC_SECTORS_MAX 17 +#define RKISP1_CIF_ISP_LSC_TABLE_DATA(v0, v1) \ + (((v0) & 0xFFF) | (((v1) & 0xFFF) << 12)) +#define RKISP1_CIF_ISP_LSC_SECT_SIZE(v0, v1) \ + (((v0) & 0xFFF) | (((v1) & 0xFFF) << 16)) +#define RKISP1_CIF_ISP_LSC_GRAD_SIZE(v0, v1) \ + (((v0) & 0xFFF) | (((v1) & 0xFFF) << 16)) + +/* LSC: ISP_LSC_TABLE_SEL */ +#define RKISP1_CIF_ISP_LSC_TABLE_0 0 +#define RKISP1_CIF_ISP_LSC_TABLE_1 1 + +/* LSC: ISP_LSC_STATUS */ +#define RKISP1_CIF_ISP_LSC_ACTIVE_TABLE BIT(1) +#define RKISP1_CIF_ISP_LSC_TABLE_ADDRESS_0 0 +#define RKISP1_CIF_ISP_LSC_TABLE_ADDRESS_153 153 + +/* FLT */ +/* ISP_FILT_MODE */ +#define RKISP1_CIF_ISP_FLT_ENA BIT(0) + +/* + * 0: green filter static mode (active filter factor = FILT_FAC_MID) + * 1: dynamic noise reduction/sharpen Default + */ +#define RKISP1_CIF_ISP_FLT_MODE_DNR BIT(1) +#define RKISP1_CIF_ISP_FLT_MODE_MAX 1 +#define RKISP1_CIF_ISP_FLT_CHROMA_V_MODE(x) (((x) & 0x3) << 4) +#define RKISP1_CIF_ISP_FLT_CHROMA_H_MODE(x) (((x) & 0x3) << 6) +#define RKISP1_CIF_ISP_FLT_CHROMA_MODE_MAX 3 +#define RKISP1_CIF_ISP_FLT_GREEN_STAGE1(x) (((x) & 0xF) << 8) +#define RKISP1_CIF_ISP_FLT_GREEN_STAGE1_MAX 8 +#define RKISP1_CIF_ISP_FLT_THREAD_RESERVED 0xFFFFFC00 +#define RKISP1_CIF_ISP_FLT_FAC_RESERVED 0xFFFFFFC0 +#define RKISP1_CIF_ISP_FLT_LUM_WEIGHT_RESERVED 0xFFF80000 + +#define RKISP1_CIF_ISP_CTK_COEFF_RESERVED 0xFFFFF800 +#define RKISP1_CIF_ISP_XTALK_OFFSET_RESERVED 0xFFFFF000 + +/* GOC */ +#define RKISP1_CIF_ISP_GAMMA_OUT_MODE_EQU BIT(0) +#define RKISP1_CIF_ISP_GOC_MODE_MAX 1 +#define RKISP1_CIF_ISP_GOC_RESERVED 0xFFFFF800 +/* ISP_CTRL BIT 11*/ +#define RKISP1_CIF_ISP_CTRL_ISP_GAMMA_OUT_ENA_READ(x) (((x) >> 11) & 1) + +/* DPCC */ +/* ISP_DPCC_MODE */ +#define RKISP1_CIF_ISP_DPCC_ENA BIT(0) +#define RKISP1_CIF_ISP_DPCC_MODE_MAX 0x07 +#define RKISP1_CIF_ISP_DPCC_OUTPUTMODE_MAX 0x0F +#define RKISP1_CIF_ISP_DPCC_SETUSE_MAX 0x0F +#define RKISP1_CIF_ISP_DPCC_METHODS_SET_RESERVED 0xFFFFE000 +#define RKISP1_CIF_ISP_DPCC_LINE_THRESH_RESERVED 0xFFFF0000 +#define RKISP1_CIF_ISP_DPCC_LINE_MAD_FAC_RESERVED 0xFFFFC0C0 +#define RKISP1_CIF_ISP_DPCC_PG_FAC_RESERVED 0xFFFFC0C0 +#define RKISP1_CIF_ISP_DPCC_RND_THRESH_RESERVED 0xFFFF0000 +#define RKISP1_CIF_ISP_DPCC_RG_FAC_RESERVED 0xFFFFC0C0 +#define RKISP1_CIF_ISP_DPCC_RO_LIMIT_RESERVED 0xFFFFF000 +#define RKISP1_CIF_ISP_DPCC_RND_OFFS_RESERVED 0xFFFFF000 + +/* BLS */ +/* ISP_BLS_CTRL */ +#define RKISP1_CIF_ISP_BLS_ENA BIT(0) +#define RKISP1_CIF_ISP_BLS_MODE_MEASURED BIT(1) +#define RKISP1_CIF_ISP_BLS_MODE_FIXED 0 +#define RKISP1_CIF_ISP_BLS_WINDOW_1 BIT(2) +#define RKISP1_CIF_ISP_BLS_WINDOW_2 (2 << 2) + +/* GAMMA-IN */ +#define RKISP1_CIFISP_DEGAMMA_X_RESERVED \ + ((1 << 31) | (1 << 27) | (1 << 23) | (1 << 19) |\ + (1 << 15) | (1 << 11) | (1 << 7) | (1 << 3)) +#define RKISP1_CIFISP_DEGAMMA_Y_RESERVED 0xFFFFF000 + +/* AFM */ +#define RKISP1_CIF_ISP_AFM_ENA BIT(0) +#define RKISP1_CIF_ISP_AFM_THRES_RESERVED 0xFFFF0000 +#define RKISP1_CIF_ISP_AFM_VAR_SHIFT_RESERVED 0xFFF8FFF8 +#define RKISP1_CIF_ISP_AFM_WINDOW_X_RESERVED 0xE000 +#define RKISP1_CIF_ISP_AFM_WINDOW_Y_RESERVED 0xF000 +#define RKISP1_CIF_ISP_AFM_WINDOW_X_MIN 0x5 +#define RKISP1_CIF_ISP_AFM_WINDOW_Y_MIN 0x2 +#define RKISP1_CIF_ISP_AFM_WINDOW_X(x) (((x) & 0x1FFF) << 16) +#define RKISP1_CIF_ISP_AFM_WINDOW_Y(x) ((x) & 0x1FFF) + +/* DPF */ +#define RKISP1_CIF_ISP_DPF_MODE_EN BIT(0) +#define RKISP1_CIF_ISP_DPF_MODE_B_FLT_DIS BIT(1) +#define RKISP1_CIF_ISP_DPF_MODE_GB_FLT_DIS BIT(2) +#define RKISP1_CIF_ISP_DPF_MODE_GR_FLT_DIS BIT(3) +#define RKISP1_CIF_ISP_DPF_MODE_R_FLT_DIS BIT(4) +#define RKISP1_CIF_ISP_DPF_MODE_RB_FLTSIZE_9x9 BIT(5) +#define RKISP1_CIF_ISP_DPF_MODE_NLL_SEGMENTATION BIT(6) +#define RKISP1_CIF_ISP_DPF_MODE_AWB_GAIN_COMP BIT(7) +#define RKISP1_CIF_ISP_DPF_MODE_LSC_GAIN_COMP BIT(8) +#define RKISP1_CIF_ISP_DPF_MODE_USE_NF_GAIN BIT(9) +#define RKISP1_CIF_ISP_DPF_NF_GAIN_RESERVED 0xFFFFF000 +#define RKISP1_CIF_ISP_DPF_SPATIAL_COEFF_MAX 0x1F +#define RKISP1_CIF_ISP_DPF_NLL_COEFF_N_MAX 0x3FF + +/* =================================================================== */ +/* CIF Registers */ +/* =================================================================== */ +#define RKISP1_CIF_CTRL_BASE 0x00000000 +#define RKISP1_CIF_CCL (RKISP1_CIF_CTRL_BASE + 0x00000000) +#define RKISP1_CIF_VI_ID (RKISP1_CIF_CTRL_BASE + 0x00000008) +#define RKISP1_CIF_ICCL (RKISP1_CIF_CTRL_BASE + 0x00000010) +#define RKISP1_CIF_IRCL (RKISP1_CIF_CTRL_BASE + 0x00000014) +#define RKISP1_CIF_VI_DPCL (RKISP1_CIF_CTRL_BASE + 0x00000018) + +#define RKISP1_CIF_IMG_EFF_BASE 0x00000200 +#define RKISP1_CIF_IMG_EFF_CTRL (RKISP1_CIF_IMG_EFF_BASE + 0x00000000) +#define RKISP1_CIF_IMG_EFF_COLOR_SEL (RKISP1_CIF_IMG_EFF_BASE + 0x00000004) +#define RKISP1_CIF_IMG_EFF_MAT_1 (RKISP1_CIF_IMG_EFF_BASE + 0x00000008) +#define RKISP1_CIF_IMG_EFF_MAT_2 (RKISP1_CIF_IMG_EFF_BASE + 0x0000000C) +#define RKISP1_CIF_IMG_EFF_MAT_3 (RKISP1_CIF_IMG_EFF_BASE + 0x00000010) +#define RKISP1_CIF_IMG_EFF_MAT_4 (RKISP1_CIF_IMG_EFF_BASE + 0x00000014) +#define RKISP1_CIF_IMG_EFF_MAT_5 (RKISP1_CIF_IMG_EFF_BASE + 0x00000018) +#define RKISP1_CIF_IMG_EFF_TINT (RKISP1_CIF_IMG_EFF_BASE + 0x0000001C) +#define RKISP1_CIF_IMG_EFF_CTRL_SHD (RKISP1_CIF_IMG_EFF_BASE + 0x00000020) +#define RKISP1_CIF_IMG_EFF_SHARPEN (RKISP1_CIF_IMG_EFF_BASE + 0x00000024) + +#define RKISP1_CIF_SUPER_IMP_BASE 0x00000300 +#define RKISP1_CIF_SUPER_IMP_CTRL (RKISP1_CIF_SUPER_IMP_BASE + 0x00000000) +#define RKISP1_CIF_SUPER_IMP_OFFSET_X (RKISP1_CIF_SUPER_IMP_BASE + 0x00000004) +#define RKISP1_CIF_SUPER_IMP_OFFSET_Y (RKISP1_CIF_SUPER_IMP_BASE + 0x00000008) +#define RKISP1_CIF_SUPER_IMP_COLOR_Y (RKISP1_CIF_SUPER_IMP_BASE + 0x0000000C) +#define RKISP1_CIF_SUPER_IMP_COLOR_CB (RKISP1_CIF_SUPER_IMP_BASE + 0x00000010) +#define RKISP1_CIF_SUPER_IMP_COLOR_CR (RKISP1_CIF_SUPER_IMP_BASE + 0x00000014) + +#define RKISP1_CIF_ISP_BASE 0x00000400 +#define RKISP1_CIF_ISP_CTRL (RKISP1_CIF_ISP_BASE + 0x00000000) +#define RKISP1_CIF_ISP_ACQ_PROP (RKISP1_CIF_ISP_BASE + 0x00000004) +#define RKISP1_CIF_ISP_ACQ_H_OFFS (RKISP1_CIF_ISP_BASE + 0x00000008) +#define RKISP1_CIF_ISP_ACQ_V_OFFS (RKISP1_CIF_ISP_BASE + 0x0000000C) +#define RKISP1_CIF_ISP_ACQ_H_SIZE (RKISP1_CIF_ISP_BASE + 0x00000010) +#define RKISP1_CIF_ISP_ACQ_V_SIZE (RKISP1_CIF_ISP_BASE + 0x00000014) +#define RKISP1_CIF_ISP_ACQ_NR_FRAMES (RKISP1_CIF_ISP_BASE + 0x00000018) +#define RKISP1_CIF_ISP_GAMMA_DX_LO (RKISP1_CIF_ISP_BASE + 0x0000001C) +#define RKISP1_CIF_ISP_GAMMA_DX_HI (RKISP1_CIF_ISP_BASE + 0x00000020) +#define RKISP1_CIF_ISP_GAMMA_R_Y0 (RKISP1_CIF_ISP_BASE + 0x00000024) +#define RKISP1_CIF_ISP_GAMMA_R_Y1 (RKISP1_CIF_ISP_BASE + 0x00000028) +#define RKISP1_CIF_ISP_GAMMA_R_Y2 (RKISP1_CIF_ISP_BASE + 0x0000002C) +#define RKISP1_CIF_ISP_GAMMA_R_Y3 (RKISP1_CIF_ISP_BASE + 0x00000030) +#define RKISP1_CIF_ISP_GAMMA_R_Y4 (RKISP1_CIF_ISP_BASE + 0x00000034) +#define RKISP1_CIF_ISP_GAMMA_R_Y5 (RKISP1_CIF_ISP_BASE + 0x00000038) +#define RKISP1_CIF_ISP_GAMMA_R_Y6 (RKISP1_CIF_ISP_BASE + 0x0000003C) +#define RKISP1_CIF_ISP_GAMMA_R_Y7 (RKISP1_CIF_ISP_BASE + 0x00000040) +#define RKISP1_CIF_ISP_GAMMA_R_Y8 (RKISP1_CIF_ISP_BASE + 0x00000044) +#define RKISP1_CIF_ISP_GAMMA_R_Y9 (RKISP1_CIF_ISP_BASE + 0x00000048) +#define RKISP1_CIF_ISP_GAMMA_R_Y10 (RKISP1_CIF_ISP_BASE + 0x0000004C) +#define RKISP1_CIF_ISP_GAMMA_R_Y11 (RKISP1_CIF_ISP_BASE + 0x00000050) +#define RKISP1_CIF_ISP_GAMMA_R_Y12 (RKISP1_CIF_ISP_BASE + 0x00000054) +#define RKISP1_CIF_ISP_GAMMA_R_Y13 (RKISP1_CIF_ISP_BASE + 0x00000058) +#define RKISP1_CIF_ISP_GAMMA_R_Y14 (RKISP1_CIF_ISP_BASE + 0x0000005C) +#define RKISP1_CIF_ISP_GAMMA_R_Y15 (RKISP1_CIF_ISP_BASE + 0x00000060) +#define RKISP1_CIF_ISP_GAMMA_R_Y16 (RKISP1_CIF_ISP_BASE + 0x00000064) +#define RKISP1_CIF_ISP_GAMMA_G_Y0 (RKISP1_CIF_ISP_BASE + 0x00000068) +#define RKISP1_CIF_ISP_GAMMA_G_Y1 (RKISP1_CIF_ISP_BASE + 0x0000006C) +#define RKISP1_CIF_ISP_GAMMA_G_Y2 (RKISP1_CIF_ISP_BASE + 0x00000070) +#define RKISP1_CIF_ISP_GAMMA_G_Y3 (RKISP1_CIF_ISP_BASE + 0x00000074) +#define RKISP1_CIF_ISP_GAMMA_G_Y4 (RKISP1_CIF_ISP_BASE + 0x00000078) +#define RKISP1_CIF_ISP_GAMMA_G_Y5 (RKISP1_CIF_ISP_BASE + 0x0000007C) +#define RKISP1_CIF_ISP_GAMMA_G_Y6 (RKISP1_CIF_ISP_BASE + 0x00000080) +#define RKISP1_CIF_ISP_GAMMA_G_Y7 (RKISP1_CIF_ISP_BASE + 0x00000084) +#define RKISP1_CIF_ISP_GAMMA_G_Y8 (RKISP1_CIF_ISP_BASE + 0x00000088) +#define RKISP1_CIF_ISP_GAMMA_G_Y9 (RKISP1_CIF_ISP_BASE + 0x0000008C) +#define RKISP1_CIF_ISP_GAMMA_G_Y10 (RKISP1_CIF_ISP_BASE + 0x00000090) +#define RKISP1_CIF_ISP_GAMMA_G_Y11 (RKISP1_CIF_ISP_BASE + 0x00000094) +#define RKISP1_CIF_ISP_GAMMA_G_Y12 (RKISP1_CIF_ISP_BASE + 0x00000098) +#define RKISP1_CIF_ISP_GAMMA_G_Y13 (RKISP1_CIF_ISP_BASE + 0x0000009C) +#define RKISP1_CIF_ISP_GAMMA_G_Y14 (RKISP1_CIF_ISP_BASE + 0x000000A0) +#define RKISP1_CIF_ISP_GAMMA_G_Y15 (RKISP1_CIF_ISP_BASE + 0x000000A4) +#define RKISP1_CIF_ISP_GAMMA_G_Y16 (RKISP1_CIF_ISP_BASE + 0x000000A8) +#define RKISP1_CIF_ISP_GAMMA_B_Y0 (RKISP1_CIF_ISP_BASE + 0x000000AC) +#define RKISP1_CIF_ISP_GAMMA_B_Y1 (RKISP1_CIF_ISP_BASE + 0x000000B0) +#define RKISP1_CIF_ISP_GAMMA_B_Y2 (RKISP1_CIF_ISP_BASE + 0x000000B4) +#define RKISP1_CIF_ISP_GAMMA_B_Y3 (RKISP1_CIF_ISP_BASE + 0x000000B8) +#define RKISP1_CIF_ISP_GAMMA_B_Y4 (RKISP1_CIF_ISP_BASE + 0x000000BC) +#define RKISP1_CIF_ISP_GAMMA_B_Y5 (RKISP1_CIF_ISP_BASE + 0x000000C0) +#define RKISP1_CIF_ISP_GAMMA_B_Y6 (RKISP1_CIF_ISP_BASE + 0x000000C4) +#define RKISP1_CIF_ISP_GAMMA_B_Y7 (RKISP1_CIF_ISP_BASE + 0x000000C8) +#define RKISP1_CIF_ISP_GAMMA_B_Y8 (RKISP1_CIF_ISP_BASE + 0x000000CC) +#define RKISP1_CIF_ISP_GAMMA_B_Y9 (RKISP1_CIF_ISP_BASE + 0x000000D0) +#define RKISP1_CIF_ISP_GAMMA_B_Y10 (RKISP1_CIF_ISP_BASE + 0x000000D4) +#define RKISP1_CIF_ISP_GAMMA_B_Y11 (RKISP1_CIF_ISP_BASE + 0x000000D8) +#define RKISP1_CIF_ISP_GAMMA_B_Y12 (RKISP1_CIF_ISP_BASE + 0x000000DC) +#define RKISP1_CIF_ISP_GAMMA_B_Y13 (RKISP1_CIF_ISP_BASE + 0x000000E0) +#define RKISP1_CIF_ISP_GAMMA_B_Y14 (RKISP1_CIF_ISP_BASE + 0x000000E4) +#define RKISP1_CIF_ISP_GAMMA_B_Y15 (RKISP1_CIF_ISP_BASE + 0x000000E8) +#define RKISP1_CIF_ISP_GAMMA_B_Y16 (RKISP1_CIF_ISP_BASE + 0x000000EC) +#define RKISP1_CIF_ISP_AWB_PROP (RKISP1_CIF_ISP_BASE + 0x00000110) +#define RKISP1_CIF_ISP_AWB_WND_H_OFFS (RKISP1_CIF_ISP_BASE + 0x00000114) +#define RKISP1_CIF_ISP_AWB_WND_V_OFFS (RKISP1_CIF_ISP_BASE + 0x00000118) +#define RKISP1_CIF_ISP_AWB_WND_H_SIZE (RKISP1_CIF_ISP_BASE + 0x0000011C) +#define RKISP1_CIF_ISP_AWB_WND_V_SIZE (RKISP1_CIF_ISP_BASE + 0x00000120) +#define RKISP1_CIF_ISP_AWB_FRAMES (RKISP1_CIF_ISP_BASE + 0x00000124) +#define RKISP1_CIF_ISP_AWB_REF (RKISP1_CIF_ISP_BASE + 0x00000128) +#define RKISP1_CIF_ISP_AWB_THRESH (RKISP1_CIF_ISP_BASE + 0x0000012C) +#define RKISP1_CIF_ISP_AWB_GAIN_G (RKISP1_CIF_ISP_BASE + 0x00000138) +#define RKISP1_CIF_ISP_AWB_GAIN_RB (RKISP1_CIF_ISP_BASE + 0x0000013C) +#define RKISP1_CIF_ISP_AWB_WHITE_CNT (RKISP1_CIF_ISP_BASE + 0x00000140) +#define RKISP1_CIF_ISP_AWB_MEAN (RKISP1_CIF_ISP_BASE + 0x00000144) +#define RKISP1_CIF_ISP_CC_COEFF_0 (RKISP1_CIF_ISP_BASE + 0x00000170) +#define RKISP1_CIF_ISP_CC_COEFF_1 (RKISP1_CIF_ISP_BASE + 0x00000174) +#define RKISP1_CIF_ISP_CC_COEFF_2 (RKISP1_CIF_ISP_BASE + 0x00000178) +#define RKISP1_CIF_ISP_CC_COEFF_3 (RKISP1_CIF_ISP_BASE + 0x0000017C) +#define RKISP1_CIF_ISP_CC_COEFF_4 (RKISP1_CIF_ISP_BASE + 0x00000180) +#define RKISP1_CIF_ISP_CC_COEFF_5 (RKISP1_CIF_ISP_BASE + 0x00000184) +#define RKISP1_CIF_ISP_CC_COEFF_6 (RKISP1_CIF_ISP_BASE + 0x00000188) +#define RKISP1_CIF_ISP_CC_COEFF_7 (RKISP1_CIF_ISP_BASE + 0x0000018C) +#define RKISP1_CIF_ISP_CC_COEFF_8 (RKISP1_CIF_ISP_BASE + 0x00000190) +#define RKISP1_CIF_ISP_OUT_H_OFFS (RKISP1_CIF_ISP_BASE + 0x00000194) +#define RKISP1_CIF_ISP_OUT_V_OFFS (RKISP1_CIF_ISP_BASE + 0x00000198) +#define RKISP1_CIF_ISP_OUT_H_SIZE (RKISP1_CIF_ISP_BASE + 0x0000019C) +#define RKISP1_CIF_ISP_OUT_V_SIZE (RKISP1_CIF_ISP_BASE + 0x000001A0) +#define RKISP1_CIF_ISP_DEMOSAIC (RKISP1_CIF_ISP_BASE + 0x000001A4) +#define RKISP1_CIF_ISP_FLAGS_SHD (RKISP1_CIF_ISP_BASE + 0x000001A8) +#define RKISP1_CIF_ISP_OUT_H_OFFS_SHD (RKISP1_CIF_ISP_BASE + 0x000001AC) +#define RKISP1_CIF_ISP_OUT_V_OFFS_SHD (RKISP1_CIF_ISP_BASE + 0x000001B0) +#define RKISP1_CIF_ISP_OUT_H_SIZE_SHD (RKISP1_CIF_ISP_BASE + 0x000001B4) +#define RKISP1_CIF_ISP_OUT_V_SIZE_SHD (RKISP1_CIF_ISP_BASE + 0x000001B8) +#define RKISP1_CIF_ISP_IMSC (RKISP1_CIF_ISP_BASE + 0x000001BC) +#define RKISP1_CIF_ISP_RIS (RKISP1_CIF_ISP_BASE + 0x000001C0) +#define RKISP1_CIF_ISP_MIS (RKISP1_CIF_ISP_BASE + 0x000001C4) +#define RKISP1_CIF_ISP_ICR (RKISP1_CIF_ISP_BASE + 0x000001C8) +#define RKISP1_CIF_ISP_ISR (RKISP1_CIF_ISP_BASE + 0x000001CC) +#define RKISP1_CIF_ISP_CT_COEFF_0 (RKISP1_CIF_ISP_BASE + 0x000001D0) +#define RKISP1_CIF_ISP_CT_COEFF_1 (RKISP1_CIF_ISP_BASE + 0x000001D4) +#define RKISP1_CIF_ISP_CT_COEFF_2 (RKISP1_CIF_ISP_BASE + 0x000001D8) +#define RKISP1_CIF_ISP_CT_COEFF_3 (RKISP1_CIF_ISP_BASE + 0x000001DC) +#define RKISP1_CIF_ISP_CT_COEFF_4 (RKISP1_CIF_ISP_BASE + 0x000001E0) +#define RKISP1_CIF_ISP_CT_COEFF_5 (RKISP1_CIF_ISP_BASE + 0x000001E4) +#define RKISP1_CIF_ISP_CT_COEFF_6 (RKISP1_CIF_ISP_BASE + 0x000001E8) +#define RKISP1_CIF_ISP_CT_COEFF_7 (RKISP1_CIF_ISP_BASE + 0x000001EC) +#define RKISP1_CIF_ISP_CT_COEFF_8 (RKISP1_CIF_ISP_BASE + 0x000001F0) +#define RKISP1_CIF_ISP_GAMMA_OUT_MODE (RKISP1_CIF_ISP_BASE + 0x000001F4) +#define RKISP1_CIF_ISP_GAMMA_OUT_Y_0 (RKISP1_CIF_ISP_BASE + 0x000001F8) +#define RKISP1_CIF_ISP_GAMMA_OUT_Y_1 (RKISP1_CIF_ISP_BASE + 0x000001FC) +#define RKISP1_CIF_ISP_GAMMA_OUT_Y_2 (RKISP1_CIF_ISP_BASE + 0x00000200) +#define RKISP1_CIF_ISP_GAMMA_OUT_Y_3 (RKISP1_CIF_ISP_BASE + 0x00000204) +#define RKISP1_CIF_ISP_GAMMA_OUT_Y_4 (RKISP1_CIF_ISP_BASE + 0x00000208) +#define RKISP1_CIF_ISP_GAMMA_OUT_Y_5 (RKISP1_CIF_ISP_BASE + 0x0000020C) +#define RKISP1_CIF_ISP_GAMMA_OUT_Y_6 (RKISP1_CIF_ISP_BASE + 0x00000210) +#define RKISP1_CIF_ISP_GAMMA_OUT_Y_7 (RKISP1_CIF_ISP_BASE + 0x00000214) +#define RKISP1_CIF_ISP_GAMMA_OUT_Y_8 (RKISP1_CIF_ISP_BASE + 0x00000218) +#define RKISP1_CIF_ISP_GAMMA_OUT_Y_9 (RKISP1_CIF_ISP_BASE + 0x0000021C) +#define RKISP1_CIF_ISP_GAMMA_OUT_Y_10 (RKISP1_CIF_ISP_BASE + 0x00000220) +#define RKISP1_CIF_ISP_GAMMA_OUT_Y_11 (RKISP1_CIF_ISP_BASE + 0x00000224) +#define RKISP1_CIF_ISP_GAMMA_OUT_Y_12 (RKISP1_CIF_ISP_BASE + 0x00000228) +#define RKISP1_CIF_ISP_GAMMA_OUT_Y_13 (RKISP1_CIF_ISP_BASE + 0x0000022C) +#define RKISP1_CIF_ISP_GAMMA_OUT_Y_14 (RKISP1_CIF_ISP_BASE + 0x00000230) +#define RKISP1_CIF_ISP_GAMMA_OUT_Y_15 (RKISP1_CIF_ISP_BASE + 0x00000234) +#define RKISP1_CIF_ISP_GAMMA_OUT_Y_16 (RKISP1_CIF_ISP_BASE + 0x00000238) +#define RKISP1_CIF_ISP_ERR (RKISP1_CIF_ISP_BASE + 0x0000023C) +#define RKISP1_CIF_ISP_ERR_CLR (RKISP1_CIF_ISP_BASE + 0x00000240) +#define RKISP1_CIF_ISP_FRAME_COUNT (RKISP1_CIF_ISP_BASE + 0x00000244) +#define RKISP1_CIF_ISP_CT_OFFSET_R (RKISP1_CIF_ISP_BASE + 0x00000248) +#define RKISP1_CIF_ISP_CT_OFFSET_G (RKISP1_CIF_ISP_BASE + 0x0000024C) +#define RKISP1_CIF_ISP_CT_OFFSET_B (RKISP1_CIF_ISP_BASE + 0x00000250) + +#define RKISP1_CIF_ISP_FLASH_BASE 0x00000660 +#define RKISP1_CIF_ISP_FLASH_CMD (RKISP1_CIF_ISP_FLASH_BASE + 0x00000000) +#define RKISP1_CIF_ISP_FLASH_CONFIG (RKISP1_CIF_ISP_FLASH_BASE + 0x00000004) +#define RKISP1_CIF_ISP_FLASH_PREDIV (RKISP1_CIF_ISP_FLASH_BASE + 0x00000008) +#define RKISP1_CIF_ISP_FLASH_DELAY (RKISP1_CIF_ISP_FLASH_BASE + 0x0000000C) +#define RKISP1_CIF_ISP_FLASH_TIME (RKISP1_CIF_ISP_FLASH_BASE + 0x00000010) +#define RKISP1_CIF_ISP_FLASH_MAXP (RKISP1_CIF_ISP_FLASH_BASE + 0x00000014) + +#define RKISP1_CIF_ISP_SH_BASE 0x00000680 +#define RKISP1_CIF_ISP_SH_CTRL (RKISP1_CIF_ISP_SH_BASE + 0x00000000) +#define RKISP1_CIF_ISP_SH_PREDIV (RKISP1_CIF_ISP_SH_BASE + 0x00000004) +#define RKISP1_CIF_ISP_SH_DELAY (RKISP1_CIF_ISP_SH_BASE + 0x00000008) +#define RKISP1_CIF_ISP_SH_TIME (RKISP1_CIF_ISP_SH_BASE + 0x0000000C) + +#define RKISP1_CIF_C_PROC_BASE 0x00000800 +#define RKISP1_CIF_C_PROC_CTRL (RKISP1_CIF_C_PROC_BASE + 0x00000000) +#define RKISP1_CIF_C_PROC_CONTRAST (RKISP1_CIF_C_PROC_BASE + 0x00000004) +#define RKISP1_CIF_C_PROC_BRIGHTNESS (RKISP1_CIF_C_PROC_BASE + 0x00000008) +#define RKISP1_CIF_C_PROC_SATURATION (RKISP1_CIF_C_PROC_BASE + 0x0000000C) +#define RKISP1_CIF_C_PROC_HUE (RKISP1_CIF_C_PROC_BASE + 0x00000010) + +#define RKISP1_CIF_DUAL_CROP_BASE 0x00000880 +#define RKISP1_CIF_DUAL_CROP_CTRL (RKISP1_CIF_DUAL_CROP_BASE + 0x00000000) +#define RKISP1_CIF_DUAL_CROP_M_H_OFFS (RKISP1_CIF_DUAL_CROP_BASE + 0x00000004) +#define RKISP1_CIF_DUAL_CROP_M_V_OFFS (RKISP1_CIF_DUAL_CROP_BASE + 0x00000008) +#define RKISP1_CIF_DUAL_CROP_M_H_SIZE (RKISP1_CIF_DUAL_CROP_BASE + 0x0000000C) +#define RKISP1_CIF_DUAL_CROP_M_V_SIZE (RKISP1_CIF_DUAL_CROP_BASE + 0x00000010) +#define RKISP1_CIF_DUAL_CROP_S_H_OFFS (RKISP1_CIF_DUAL_CROP_BASE + 0x00000014) +#define RKISP1_CIF_DUAL_CROP_S_V_OFFS (RKISP1_CIF_DUAL_CROP_BASE + 0x00000018) +#define RKISP1_CIF_DUAL_CROP_S_H_SIZE (RKISP1_CIF_DUAL_CROP_BASE + 0x0000001C) +#define RKISP1_CIF_DUAL_CROP_S_V_SIZE (RKISP1_CIF_DUAL_CROP_BASE + 0x00000020) +#define RKISP1_CIF_DUAL_CROP_M_H_OFFS_SHD (RKISP1_CIF_DUAL_CROP_BASE + 0x00000024) +#define RKISP1_CIF_DUAL_CROP_M_V_OFFS_SHD (RKISP1_CIF_DUAL_CROP_BASE + 0x00000028) +#define RKISP1_CIF_DUAL_CROP_M_H_SIZE_SHD (RKISP1_CIF_DUAL_CROP_BASE + 0x0000002C) +#define RKISP1_CIF_DUAL_CROP_M_V_SIZE_SHD (RKISP1_CIF_DUAL_CROP_BASE + 0x00000030) +#define RKISP1_CIF_DUAL_CROP_S_H_OFFS_SHD (RKISP1_CIF_DUAL_CROP_BASE + 0x00000034) +#define RKISP1_CIF_DUAL_CROP_S_V_OFFS_SHD (RKISP1_CIF_DUAL_CROP_BASE + 0x00000038) +#define RKISP1_CIF_DUAL_CROP_S_H_SIZE_SHD (RKISP1_CIF_DUAL_CROP_BASE + 0x0000003C) +#define RKISP1_CIF_DUAL_CROP_S_V_SIZE_SHD (RKISP1_CIF_DUAL_CROP_BASE + 0x00000040) + +#define RKISP1_CIF_MRSZ_BASE 0x00000C00 +#define RKISP1_CIF_MRSZ_CTRL (RKISP1_CIF_MRSZ_BASE + 0x00000000) +#define RKISP1_CIF_MRSZ_SCALE_HY (RKISP1_CIF_MRSZ_BASE + 0x00000004) +#define RKISP1_CIF_MRSZ_SCALE_HCB (RKISP1_CIF_MRSZ_BASE + 0x00000008) +#define RKISP1_CIF_MRSZ_SCALE_HCR (RKISP1_CIF_MRSZ_BASE + 0x0000000C) +#define RKISP1_CIF_MRSZ_SCALE_VY (RKISP1_CIF_MRSZ_BASE + 0x00000010) +#define RKISP1_CIF_MRSZ_SCALE_VC (RKISP1_CIF_MRSZ_BASE + 0x00000014) +#define RKISP1_CIF_MRSZ_PHASE_HY (RKISP1_CIF_MRSZ_BASE + 0x00000018) +#define RKISP1_CIF_MRSZ_PHASE_HC (RKISP1_CIF_MRSZ_BASE + 0x0000001C) +#define RKISP1_CIF_MRSZ_PHASE_VY (RKISP1_CIF_MRSZ_BASE + 0x00000020) +#define RKISP1_CIF_MRSZ_PHASE_VC (RKISP1_CIF_MRSZ_BASE + 0x00000024) +#define RKISP1_CIF_MRSZ_SCALE_LUT_ADDR (RKISP1_CIF_MRSZ_BASE + 0x00000028) +#define RKISP1_CIF_MRSZ_SCALE_LUT (RKISP1_CIF_MRSZ_BASE + 0x0000002C) +#define RKISP1_CIF_MRSZ_CTRL_SHD (RKISP1_CIF_MRSZ_BASE + 0x00000030) +#define RKISP1_CIF_MRSZ_SCALE_HY_SHD (RKISP1_CIF_MRSZ_BASE + 0x00000034) +#define RKISP1_CIF_MRSZ_SCALE_HCB_SHD (RKISP1_CIF_MRSZ_BASE + 0x00000038) +#define RKISP1_CIF_MRSZ_SCALE_HCR_SHD (RKISP1_CIF_MRSZ_BASE + 0x0000003C) +#define RKISP1_CIF_MRSZ_SCALE_VY_SHD (RKISP1_CIF_MRSZ_BASE + 0x00000040) +#define RKISP1_CIF_MRSZ_SCALE_VC_SHD (RKISP1_CIF_MRSZ_BASE + 0x00000044) +#define RKISP1_CIF_MRSZ_PHASE_HY_SHD (RKISP1_CIF_MRSZ_BASE + 0x00000048) +#define RKISP1_CIF_MRSZ_PHASE_HC_SHD (RKISP1_CIF_MRSZ_BASE + 0x0000004C) +#define RKISP1_CIF_MRSZ_PHASE_VY_SHD (RKISP1_CIF_MRSZ_BASE + 0x00000050) +#define RKISP1_CIF_MRSZ_PHASE_VC_SHD (RKISP1_CIF_MRSZ_BASE + 0x00000054) + +#define RKISP1_CIF_SRSZ_BASE 0x00001000 +#define RKISP1_CIF_SRSZ_CTRL (RKISP1_CIF_SRSZ_BASE + 0x00000000) +#define RKISP1_CIF_SRSZ_SCALE_HY (RKISP1_CIF_SRSZ_BASE + 0x00000004) +#define RKISP1_CIF_SRSZ_SCALE_HCB (RKISP1_CIF_SRSZ_BASE + 0x00000008) +#define RKISP1_CIF_SRSZ_SCALE_HCR (RKISP1_CIF_SRSZ_BASE + 0x0000000C) +#define RKISP1_CIF_SRSZ_SCALE_VY (RKISP1_CIF_SRSZ_BASE + 0x00000010) +#define RKISP1_CIF_SRSZ_SCALE_VC (RKISP1_CIF_SRSZ_BASE + 0x00000014) +#define RKISP1_CIF_SRSZ_PHASE_HY (RKISP1_CIF_SRSZ_BASE + 0x00000018) +#define RKISP1_CIF_SRSZ_PHASE_HC (RKISP1_CIF_SRSZ_BASE + 0x0000001C) +#define RKISP1_CIF_SRSZ_PHASE_VY (RKISP1_CIF_SRSZ_BASE + 0x00000020) +#define RKISP1_CIF_SRSZ_PHASE_VC (RKISP1_CIF_SRSZ_BASE + 0x00000024) +#define RKISP1_CIF_SRSZ_SCALE_LUT_ADDR (RKISP1_CIF_SRSZ_BASE + 0x00000028) +#define RKISP1_CIF_SRSZ_SCALE_LUT (RKISP1_CIF_SRSZ_BASE + 0x0000002C) +#define RKISP1_CIF_SRSZ_CTRL_SHD (RKISP1_CIF_SRSZ_BASE + 0x00000030) +#define RKISP1_CIF_SRSZ_SCALE_HY_SHD (RKISP1_CIF_SRSZ_BASE + 0x00000034) +#define RKISP1_CIF_SRSZ_SCALE_HCB_SHD (RKISP1_CIF_SRSZ_BASE + 0x00000038) +#define RKISP1_CIF_SRSZ_SCALE_HCR_SHD (RKISP1_CIF_SRSZ_BASE + 0x0000003C) +#define RKISP1_CIF_SRSZ_SCALE_VY_SHD (RKISP1_CIF_SRSZ_BASE + 0x00000040) +#define RKISP1_CIF_SRSZ_SCALE_VC_SHD (RKISP1_CIF_SRSZ_BASE + 0x00000044) +#define RKISP1_CIF_SRSZ_PHASE_HY_SHD (RKISP1_CIF_SRSZ_BASE + 0x00000048) +#define RKISP1_CIF_SRSZ_PHASE_HC_SHD (RKISP1_CIF_SRSZ_BASE + 0x0000004C) +#define RKISP1_CIF_SRSZ_PHASE_VY_SHD (RKISP1_CIF_SRSZ_BASE + 0x00000050) +#define RKISP1_CIF_SRSZ_PHASE_VC_SHD (RKISP1_CIF_SRSZ_BASE + 0x00000054) + +#define RKISP1_CIF_MI_BASE 0x00001400 +#define RKISP1_CIF_MI_CTRL (RKISP1_CIF_MI_BASE + 0x00000000) +#define RKISP1_CIF_MI_INIT (RKISP1_CIF_MI_BASE + 0x00000004) +#define RKISP1_CIF_MI_MP_Y_BASE_AD_INIT (RKISP1_CIF_MI_BASE + 0x00000008) +#define RKISP1_CIF_MI_MP_Y_SIZE_INIT (RKISP1_CIF_MI_BASE + 0x0000000C) +#define RKISP1_CIF_MI_MP_Y_OFFS_CNT_INIT (RKISP1_CIF_MI_BASE + 0x00000010) +#define RKISP1_CIF_MI_MP_Y_OFFS_CNT_START (RKISP1_CIF_MI_BASE + 0x00000014) +#define RKISP1_CIF_MI_MP_Y_IRQ_OFFS_INIT (RKISP1_CIF_MI_BASE + 0x00000018) +#define RKISP1_CIF_MI_MP_CB_BASE_AD_INIT (RKISP1_CIF_MI_BASE + 0x0000001C) +#define RKISP1_CIF_MI_MP_CB_SIZE_INIT (RKISP1_CIF_MI_BASE + 0x00000020) +#define RKISP1_CIF_MI_MP_CB_OFFS_CNT_INIT (RKISP1_CIF_MI_BASE + 0x00000024) +#define RKISP1_CIF_MI_MP_CB_OFFS_CNT_START (RKISP1_CIF_MI_BASE + 0x00000028) +#define RKISP1_CIF_MI_MP_CR_BASE_AD_INIT (RKISP1_CIF_MI_BASE + 0x0000002C) +#define RKISP1_CIF_MI_MP_CR_SIZE_INIT (RKISP1_CIF_MI_BASE + 0x00000030) +#define RKISP1_CIF_MI_MP_CR_OFFS_CNT_INIT (RKISP1_CIF_MI_BASE + 0x00000034) +#define RKISP1_CIF_MI_MP_CR_OFFS_CNT_START (RKISP1_CIF_MI_BASE + 0x00000038) +#define RKISP1_CIF_MI_SP_Y_BASE_AD_INIT (RKISP1_CIF_MI_BASE + 0x0000003C) +#define RKISP1_CIF_MI_SP_Y_SIZE_INIT (RKISP1_CIF_MI_BASE + 0x00000040) +#define RKISP1_CIF_MI_SP_Y_OFFS_CNT_INIT (RKISP1_CIF_MI_BASE + 0x00000044) +#define RKISP1_CIF_MI_SP_Y_OFFS_CNT_START (RKISP1_CIF_MI_BASE + 0x00000048) +#define RKISP1_CIF_MI_SP_Y_LLENGTH (RKISP1_CIF_MI_BASE + 0x0000004C) +#define RKISP1_CIF_MI_SP_CB_BASE_AD_INIT (RKISP1_CIF_MI_BASE + 0x00000050) +#define RKISP1_CIF_MI_SP_CB_SIZE_INIT (RKISP1_CIF_MI_BASE + 0x00000054) +#define RKISP1_CIF_MI_SP_CB_OFFS_CNT_INIT (RKISP1_CIF_MI_BASE + 0x00000058) +#define RKISP1_CIF_MI_SP_CB_OFFS_CNT_START (RKISP1_CIF_MI_BASE + 0x0000005C) +#define RKISP1_CIF_MI_SP_CR_BASE_AD_INIT (RKISP1_CIF_MI_BASE + 0x00000060) +#define RKISP1_CIF_MI_SP_CR_SIZE_INIT (RKISP1_CIF_MI_BASE + 0x00000064) +#define RKISP1_CIF_MI_SP_CR_OFFS_CNT_INIT (RKISP1_CIF_MI_BASE + 0x00000068) +#define RKISP1_CIF_MI_SP_CR_OFFS_CNT_START (RKISP1_CIF_MI_BASE + 0x0000006C) +#define RKISP1_CIF_MI_BYTE_CNT (RKISP1_CIF_MI_BASE + 0x00000070) +#define RKISP1_CIF_MI_CTRL_SHD (RKISP1_CIF_MI_BASE + 0x00000074) +#define RKISP1_CIF_MI_MP_Y_BASE_AD_SHD (RKISP1_CIF_MI_BASE + 0x00000078) +#define RKISP1_CIF_MI_MP_Y_SIZE_SHD (RKISP1_CIF_MI_BASE + 0x0000007C) +#define RKISP1_CIF_MI_MP_Y_OFFS_CNT_SHD (RKISP1_CIF_MI_BASE + 0x00000080) +#define RKISP1_CIF_MI_MP_Y_IRQ_OFFS_SHD (RKISP1_CIF_MI_BASE + 0x00000084) +#define RKISP1_CIF_MI_MP_CB_BASE_AD_SHD (RKISP1_CIF_MI_BASE + 0x00000088) +#define RKISP1_CIF_MI_MP_CB_SIZE_SHD (RKISP1_CIF_MI_BASE + 0x0000008C) +#define RKISP1_CIF_MI_MP_CB_OFFS_CNT_SHD (RKISP1_CIF_MI_BASE + 0x00000090) +#define RKISP1_CIF_MI_MP_CR_BASE_AD_SHD (RKISP1_CIF_MI_BASE + 0x00000094) +#define RKISP1_CIF_MI_MP_CR_SIZE_SHD (RKISP1_CIF_MI_BASE + 0x00000098) +#define RKISP1_CIF_MI_MP_CR_OFFS_CNT_SHD (RKISP1_CIF_MI_BASE + 0x0000009C) +#define RKISP1_CIF_MI_SP_Y_BASE_AD_SHD (RKISP1_CIF_MI_BASE + 0x000000A0) +#define RKISP1_CIF_MI_SP_Y_SIZE_SHD (RKISP1_CIF_MI_BASE + 0x000000A4) +#define RKISP1_CIF_MI_SP_Y_OFFS_CNT_SHD (RKISP1_CIF_MI_BASE + 0x000000A8) +#define RKISP1_CIF_MI_SP_CB_BASE_AD_SHD (RKISP1_CIF_MI_BASE + 0x000000B0) +#define RKISP1_CIF_MI_SP_CB_SIZE_SHD (RKISP1_CIF_MI_BASE + 0x000000B4) +#define RKISP1_CIF_MI_SP_CB_OFFS_CNT_SHD (RKISP1_CIF_MI_BASE + 0x000000B8) +#define RKISP1_CIF_MI_SP_CR_BASE_AD_SHD (RKISP1_CIF_MI_BASE + 0x000000BC) +#define RKISP1_CIF_MI_SP_CR_SIZE_SHD (RKISP1_CIF_MI_BASE + 0x000000C0) +#define RKISP1_CIF_MI_SP_CR_OFFS_CNT_SHD (RKISP1_CIF_MI_BASE + 0x000000C4) +#define RKISP1_CIF_MI_DMA_Y_PIC_START_AD (RKISP1_CIF_MI_BASE + 0x000000C8) +#define RKISP1_CIF_MI_DMA_Y_PIC_WIDTH (RKISP1_CIF_MI_BASE + 0x000000CC) +#define RKISP1_CIF_MI_DMA_Y_LLENGTH (RKISP1_CIF_MI_BASE + 0x000000D0) +#define RKISP1_CIF_MI_DMA_Y_PIC_SIZE (RKISP1_CIF_MI_BASE + 0x000000D4) +#define RKISP1_CIF_MI_DMA_CB_PIC_START_AD (RKISP1_CIF_MI_BASE + 0x000000D8) +#define RKISP1_CIF_MI_DMA_CR_PIC_START_AD (RKISP1_CIF_MI_BASE + 0x000000E8) +#define RKISP1_CIF_MI_IMSC (RKISP1_CIF_MI_BASE + 0x000000F8) +#define RKISP1_CIF_MI_RIS (RKISP1_CIF_MI_BASE + 0x000000FC) +#define RKISP1_CIF_MI_MIS (RKISP1_CIF_MI_BASE + 0x00000100) +#define RKISP1_CIF_MI_ICR (RKISP1_CIF_MI_BASE + 0x00000104) +#define RKISP1_CIF_MI_ISR (RKISP1_CIF_MI_BASE + 0x00000108) +#define RKISP1_CIF_MI_STATUS (RKISP1_CIF_MI_BASE + 0x0000010C) +#define RKISP1_CIF_MI_STATUS_CLR (RKISP1_CIF_MI_BASE + 0x00000110) +#define RKISP1_CIF_MI_SP_Y_PIC_WIDTH (RKISP1_CIF_MI_BASE + 0x00000114) +#define RKISP1_CIF_MI_SP_Y_PIC_HEIGHT (RKISP1_CIF_MI_BASE + 0x00000118) +#define RKISP1_CIF_MI_SP_Y_PIC_SIZE (RKISP1_CIF_MI_BASE + 0x0000011C) +#define RKISP1_CIF_MI_DMA_CTRL (RKISP1_CIF_MI_BASE + 0x00000120) +#define RKISP1_CIF_MI_DMA_START (RKISP1_CIF_MI_BASE + 0x00000124) +#define RKISP1_CIF_MI_DMA_STATUS (RKISP1_CIF_MI_BASE + 0x00000128) +#define RKISP1_CIF_MI_PIXEL_COUNT (RKISP1_CIF_MI_BASE + 0x0000012C) +#define RKISP1_CIF_MI_MP_Y_BASE_AD_INIT2 (RKISP1_CIF_MI_BASE + 0x00000130) +#define RKISP1_CIF_MI_MP_CB_BASE_AD_INIT2 (RKISP1_CIF_MI_BASE + 0x00000134) +#define RKISP1_CIF_MI_MP_CR_BASE_AD_INIT2 (RKISP1_CIF_MI_BASE + 0x00000138) +#define RKISP1_CIF_MI_SP_Y_BASE_AD_INIT2 (RKISP1_CIF_MI_BASE + 0x0000013C) +#define RKISP1_CIF_MI_SP_CB_BASE_AD_INIT2 (RKISP1_CIF_MI_BASE + 0x00000140) +#define RKISP1_CIF_MI_SP_CR_BASE_AD_INIT2 (RKISP1_CIF_MI_BASE + 0x00000144) +#define RKISP1_CIF_MI_XTD_FORMAT_CTRL (RKISP1_CIF_MI_BASE + 0x00000148) + +#define RKISP1_CIF_SMIA_BASE 0x00001A00 +#define RKISP1_CIF_SMIA_CTRL (RKISP1_CIF_SMIA_BASE + 0x00000000) +#define RKISP1_CIF_SMIA_STATUS (RKISP1_CIF_SMIA_BASE + 0x00000004) +#define RKISP1_CIF_SMIA_IMSC (RKISP1_CIF_SMIA_BASE + 0x00000008) +#define RKISP1_CIF_SMIA_RIS (RKISP1_CIF_SMIA_BASE + 0x0000000C) +#define RKISP1_CIF_SMIA_MIS (RKISP1_CIF_SMIA_BASE + 0x00000010) +#define RKISP1_CIF_SMIA_ICR (RKISP1_CIF_SMIA_BASE + 0x00000014) +#define RKISP1_CIF_SMIA_ISR (RKISP1_CIF_SMIA_BASE + 0x00000018) +#define RKISP1_CIF_SMIA_DATA_FORMAT_SEL (RKISP1_CIF_SMIA_BASE + 0x0000001C) +#define RKISP1_CIF_SMIA_SOF_EMB_DATA_LINES (RKISP1_CIF_SMIA_BASE + 0x00000020) +#define RKISP1_CIF_SMIA_EMB_HSTART (RKISP1_CIF_SMIA_BASE + 0x00000024) +#define RKISP1_CIF_SMIA_EMB_HSIZE (RKISP1_CIF_SMIA_BASE + 0x00000028) +#define RKISP1_CIF_SMIA_EMB_VSTART (RKISP1_CIF_SMIA_BASE + 0x0000002c) +#define RKISP1_CIF_SMIA_NUM_LINES (RKISP1_CIF_SMIA_BASE + 0x00000030) +#define RKISP1_CIF_SMIA_EMB_DATA_FIFO (RKISP1_CIF_SMIA_BASE + 0x00000034) +#define RKISP1_CIF_SMIA_EMB_DATA_WATERMARK (RKISP1_CIF_SMIA_BASE + 0x00000038) + +#define RKISP1_CIF_MIPI_BASE 0x00001C00 +#define RKISP1_CIF_MIPI_CTRL (RKISP1_CIF_MIPI_BASE + 0x00000000) +#define RKISP1_CIF_MIPI_STATUS (RKISP1_CIF_MIPI_BASE + 0x00000004) +#define RKISP1_CIF_MIPI_IMSC (RKISP1_CIF_MIPI_BASE + 0x00000008) +#define RKISP1_CIF_MIPI_RIS (RKISP1_CIF_MIPI_BASE + 0x0000000C) +#define RKISP1_CIF_MIPI_MIS (RKISP1_CIF_MIPI_BASE + 0x00000010) +#define RKISP1_CIF_MIPI_ICR (RKISP1_CIF_MIPI_BASE + 0x00000014) +#define RKISP1_CIF_MIPI_ISR (RKISP1_CIF_MIPI_BASE + 0x00000018) +#define RKISP1_CIF_MIPI_CUR_DATA_ID (RKISP1_CIF_MIPI_BASE + 0x0000001C) +#define RKISP1_CIF_MIPI_IMG_DATA_SEL (RKISP1_CIF_MIPI_BASE + 0x00000020) +#define RKISP1_CIF_MIPI_ADD_DATA_SEL_1 (RKISP1_CIF_MIPI_BASE + 0x00000024) +#define RKISP1_CIF_MIPI_ADD_DATA_SEL_2 (RKISP1_CIF_MIPI_BASE + 0x00000028) +#define RKISP1_CIF_MIPI_ADD_DATA_SEL_3 (RKISP1_CIF_MIPI_BASE + 0x0000002C) +#define RKISP1_CIF_MIPI_ADD_DATA_SEL_4 (RKISP1_CIF_MIPI_BASE + 0x00000030) +#define RKISP1_CIF_MIPI_ADD_DATA_FIFO (RKISP1_CIF_MIPI_BASE + 0x00000034) +#define RKISP1_CIF_MIPI_FIFO_FILL_LEVEL (RKISP1_CIF_MIPI_BASE + 0x00000038) +#define RKISP1_CIF_MIPI_COMPRESSED_MODE (RKISP1_CIF_MIPI_BASE + 0x0000003C) +#define RKISP1_CIF_MIPI_FRAME (RKISP1_CIF_MIPI_BASE + 0x00000040) +#define RKISP1_CIF_MIPI_GEN_SHORT_DT (RKISP1_CIF_MIPI_BASE + 0x00000044) +#define RKISP1_CIF_MIPI_GEN_SHORT_8_9 (RKISP1_CIF_MIPI_BASE + 0x00000048) +#define RKISP1_CIF_MIPI_GEN_SHORT_A_B (RKISP1_CIF_MIPI_BASE + 0x0000004C) +#define RKISP1_CIF_MIPI_GEN_SHORT_C_D (RKISP1_CIF_MIPI_BASE + 0x00000050) +#define RKISP1_CIF_MIPI_GEN_SHORT_E_F (RKISP1_CIF_MIPI_BASE + 0x00000054) + +#define RKISP1_CIF_ISP_AFM_BASE 0x00002000 +#define RKISP1_CIF_ISP_AFM_CTRL (RKISP1_CIF_ISP_AFM_BASE + 0x00000000) +#define RKISP1_CIF_ISP_AFM_LT_A (RKISP1_CIF_ISP_AFM_BASE + 0x00000004) +#define RKISP1_CIF_ISP_AFM_RB_A (RKISP1_CIF_ISP_AFM_BASE + 0x00000008) +#define RKISP1_CIF_ISP_AFM_LT_B (RKISP1_CIF_ISP_AFM_BASE + 0x0000000C) +#define RKISP1_CIF_ISP_AFM_RB_B (RKISP1_CIF_ISP_AFM_BASE + 0x00000010) +#define RKISP1_CIF_ISP_AFM_LT_C (RKISP1_CIF_ISP_AFM_BASE + 0x00000014) +#define RKISP1_CIF_ISP_AFM_RB_C (RKISP1_CIF_ISP_AFM_BASE + 0x00000018) +#define RKISP1_CIF_ISP_AFM_THRES (RKISP1_CIF_ISP_AFM_BASE + 0x0000001C) +#define RKISP1_CIF_ISP_AFM_VAR_SHIFT (RKISP1_CIF_ISP_AFM_BASE + 0x00000020) +#define RKISP1_CIF_ISP_AFM_SUM_A (RKISP1_CIF_ISP_AFM_BASE + 0x00000024) +#define RKISP1_CIF_ISP_AFM_SUM_B (RKISP1_CIF_ISP_AFM_BASE + 0x00000028) +#define RKISP1_CIF_ISP_AFM_SUM_C (RKISP1_CIF_ISP_AFM_BASE + 0x0000002C) +#define RKISP1_CIF_ISP_AFM_LUM_A (RKISP1_CIF_ISP_AFM_BASE + 0x00000030) +#define RKISP1_CIF_ISP_AFM_LUM_B (RKISP1_CIF_ISP_AFM_BASE + 0x00000034) +#define RKISP1_CIF_ISP_AFM_LUM_C (RKISP1_CIF_ISP_AFM_BASE + 0x00000038) + +#define RKISP1_CIF_ISP_LSC_BASE 0x00002200 +#define RKISP1_CIF_ISP_LSC_CTRL (RKISP1_CIF_ISP_LSC_BASE + 0x00000000) +#define RKISP1_CIF_ISP_LSC_R_TABLE_ADDR (RKISP1_CIF_ISP_LSC_BASE + 0x00000004) +#define RKISP1_CIF_ISP_LSC_GR_TABLE_ADDR (RKISP1_CIF_ISP_LSC_BASE + 0x00000008) +#define RKISP1_CIF_ISP_LSC_B_TABLE_ADDR (RKISP1_CIF_ISP_LSC_BASE + 0x0000000C) +#define RKISP1_CIF_ISP_LSC_GB_TABLE_ADDR (RKISP1_CIF_ISP_LSC_BASE + 0x00000010) +#define RKISP1_CIF_ISP_LSC_R_TABLE_DATA (RKISP1_CIF_ISP_LSC_BASE + 0x00000014) +#define RKISP1_CIF_ISP_LSC_GR_TABLE_DATA (RKISP1_CIF_ISP_LSC_BASE + 0x00000018) +#define RKISP1_CIF_ISP_LSC_B_TABLE_DATA (RKISP1_CIF_ISP_LSC_BASE + 0x0000001C) +#define RKISP1_CIF_ISP_LSC_GB_TABLE_DATA (RKISP1_CIF_ISP_LSC_BASE + 0x00000020) +#define RKISP1_CIF_ISP_LSC_XGRAD_01 (RKISP1_CIF_ISP_LSC_BASE + 0x00000024) +#define RKISP1_CIF_ISP_LSC_XGRAD_23 (RKISP1_CIF_ISP_LSC_BASE + 0x00000028) +#define RKISP1_CIF_ISP_LSC_XGRAD_45 (RKISP1_CIF_ISP_LSC_BASE + 0x0000002C) +#define RKISP1_CIF_ISP_LSC_XGRAD_67 (RKISP1_CIF_ISP_LSC_BASE + 0x00000030) +#define RKISP1_CIF_ISP_LSC_YGRAD_01 (RKISP1_CIF_ISP_LSC_BASE + 0x00000034) +#define RKISP1_CIF_ISP_LSC_YGRAD_23 (RKISP1_CIF_ISP_LSC_BASE + 0x00000038) +#define RKISP1_CIF_ISP_LSC_YGRAD_45 (RKISP1_CIF_ISP_LSC_BASE + 0x0000003C) +#define RKISP1_CIF_ISP_LSC_YGRAD_67 (RKISP1_CIF_ISP_LSC_BASE + 0x00000040) +#define RKISP1_CIF_ISP_LSC_XSIZE_01 (RKISP1_CIF_ISP_LSC_BASE + 0x00000044) +#define RKISP1_CIF_ISP_LSC_XSIZE_23 (RKISP1_CIF_ISP_LSC_BASE + 0x00000048) +#define RKISP1_CIF_ISP_LSC_XSIZE_45 (RKISP1_CIF_ISP_LSC_BASE + 0x0000004C) +#define RKISP1_CIF_ISP_LSC_XSIZE_67 (RKISP1_CIF_ISP_LSC_BASE + 0x00000050) +#define RKISP1_CIF_ISP_LSC_YSIZE_01 (RKISP1_CIF_ISP_LSC_BASE + 0x00000054) +#define RKISP1_CIF_ISP_LSC_YSIZE_23 (RKISP1_CIF_ISP_LSC_BASE + 0x00000058) +#define RKISP1_CIF_ISP_LSC_YSIZE_45 (RKISP1_CIF_ISP_LSC_BASE + 0x0000005C) +#define RKISP1_CIF_ISP_LSC_YSIZE_67 (RKISP1_CIF_ISP_LSC_BASE + 0x00000060) +#define RKISP1_CIF_ISP_LSC_TABLE_SEL (RKISP1_CIF_ISP_LSC_BASE + 0x00000064) +#define RKISP1_CIF_ISP_LSC_STATUS (RKISP1_CIF_ISP_LSC_BASE + 0x00000068) + +#define RKISP1_CIF_ISP_IS_BASE 0x00002300 +#define RKISP1_CIF_ISP_IS_CTRL (RKISP1_CIF_ISP_IS_BASE + 0x00000000) +#define RKISP1_CIF_ISP_IS_RECENTER (RKISP1_CIF_ISP_IS_BASE + 0x00000004) +#define RKISP1_CIF_ISP_IS_H_OFFS (RKISP1_CIF_ISP_IS_BASE + 0x00000008) +#define RKISP1_CIF_ISP_IS_V_OFFS (RKISP1_CIF_ISP_IS_BASE + 0x0000000C) +#define RKISP1_CIF_ISP_IS_H_SIZE (RKISP1_CIF_ISP_IS_BASE + 0x00000010) +#define RKISP1_CIF_ISP_IS_V_SIZE (RKISP1_CIF_ISP_IS_BASE + 0x00000014) +#define RKISP1_CIF_ISP_IS_MAX_DX (RKISP1_CIF_ISP_IS_BASE + 0x00000018) +#define RKISP1_CIF_ISP_IS_MAX_DY (RKISP1_CIF_ISP_IS_BASE + 0x0000001C) +#define RKISP1_CIF_ISP_IS_DISPLACE (RKISP1_CIF_ISP_IS_BASE + 0x00000020) +#define RKISP1_CIF_ISP_IS_H_OFFS_SHD (RKISP1_CIF_ISP_IS_BASE + 0x00000024) +#define RKISP1_CIF_ISP_IS_V_OFFS_SHD (RKISP1_CIF_ISP_IS_BASE + 0x00000028) +#define RKISP1_CIF_ISP_IS_H_SIZE_SHD (RKISP1_CIF_ISP_IS_BASE + 0x0000002C) +#define RKISP1_CIF_ISP_IS_V_SIZE_SHD (RKISP1_CIF_ISP_IS_BASE + 0x00000030) + +#define RKISP1_CIF_ISP_HIST_BASE 0x00002400 + +#define RKISP1_CIF_ISP_HIST_PROP (RKISP1_CIF_ISP_HIST_BASE + 0x00000000) +#define RKISP1_CIF_ISP_HIST_H_OFFS (RKISP1_CIF_ISP_HIST_BASE + 0x00000004) +#define RKISP1_CIF_ISP_HIST_V_OFFS (RKISP1_CIF_ISP_HIST_BASE + 0x00000008) +#define RKISP1_CIF_ISP_HIST_H_SIZE (RKISP1_CIF_ISP_HIST_BASE + 0x0000000C) +#define RKISP1_CIF_ISP_HIST_V_SIZE (RKISP1_CIF_ISP_HIST_BASE + 0x00000010) +#define RKISP1_CIF_ISP_HIST_BIN_0 (RKISP1_CIF_ISP_HIST_BASE + 0x00000014) +#define RKISP1_CIF_ISP_HIST_BIN_1 (RKISP1_CIF_ISP_HIST_BASE + 0x00000018) +#define RKISP1_CIF_ISP_HIST_BIN_2 (RKISP1_CIF_ISP_HIST_BASE + 0x0000001C) +#define RKISP1_CIF_ISP_HIST_BIN_3 (RKISP1_CIF_ISP_HIST_BASE + 0x00000020) +#define RKISP1_CIF_ISP_HIST_BIN_4 (RKISP1_CIF_ISP_HIST_BASE + 0x00000024) +#define RKISP1_CIF_ISP_HIST_BIN_5 (RKISP1_CIF_ISP_HIST_BASE + 0x00000028) +#define RKISP1_CIF_ISP_HIST_BIN_6 (RKISP1_CIF_ISP_HIST_BASE + 0x0000002C) +#define RKISP1_CIF_ISP_HIST_BIN_7 (RKISP1_CIF_ISP_HIST_BASE + 0x00000030) +#define RKISP1_CIF_ISP_HIST_BIN_8 (RKISP1_CIF_ISP_HIST_BASE + 0x00000034) +#define RKISP1_CIF_ISP_HIST_BIN_9 (RKISP1_CIF_ISP_HIST_BASE + 0x00000038) +#define RKISP1_CIF_ISP_HIST_BIN_10 (RKISP1_CIF_ISP_HIST_BASE + 0x0000003C) +#define RKISP1_CIF_ISP_HIST_BIN_11 (RKISP1_CIF_ISP_HIST_BASE + 0x00000040) +#define RKISP1_CIF_ISP_HIST_BIN_12 (RKISP1_CIF_ISP_HIST_BASE + 0x00000044) +#define RKISP1_CIF_ISP_HIST_BIN_13 (RKISP1_CIF_ISP_HIST_BASE + 0x00000048) +#define RKISP1_CIF_ISP_HIST_BIN_14 (RKISP1_CIF_ISP_HIST_BASE + 0x0000004C) +#define RKISP1_CIF_ISP_HIST_BIN_15 (RKISP1_CIF_ISP_HIST_BASE + 0x00000050) +#define RKISP1_CIF_ISP_HIST_WEIGHT_00TO30 (RKISP1_CIF_ISP_HIST_BASE + 0x00000054) +#define RKISP1_CIF_ISP_HIST_WEIGHT_40TO21 (RKISP1_CIF_ISP_HIST_BASE + 0x00000058) +#define RKISP1_CIF_ISP_HIST_WEIGHT_31TO12 (RKISP1_CIF_ISP_HIST_BASE + 0x0000005C) +#define RKISP1_CIF_ISP_HIST_WEIGHT_22TO03 (RKISP1_CIF_ISP_HIST_BASE + 0x00000060) +#define RKISP1_CIF_ISP_HIST_WEIGHT_13TO43 (RKISP1_CIF_ISP_HIST_BASE + 0x00000064) +#define RKISP1_CIF_ISP_HIST_WEIGHT_04TO34 (RKISP1_CIF_ISP_HIST_BASE + 0x00000068) +#define RKISP1_CIF_ISP_HIST_WEIGHT_44 (RKISP1_CIF_ISP_HIST_BASE + 0x0000006C) + +#define RKISP1_CIF_ISP_FILT_BASE 0x00002500 +#define RKISP1_CIF_ISP_FILT_MODE (RKISP1_CIF_ISP_FILT_BASE + 0x00000000) +#define RKISP1_CIF_ISP_FILT_THRESH_BL0 (RKISP1_CIF_ISP_FILT_BASE + 0x00000028) +#define RKISP1_CIF_ISP_FILT_THRESH_BL1 (RKISP1_CIF_ISP_FILT_BASE + 0x0000002c) +#define RKISP1_CIF_ISP_FILT_THRESH_SH0 (RKISP1_CIF_ISP_FILT_BASE + 0x00000030) +#define RKISP1_CIF_ISP_FILT_THRESH_SH1 (RKISP1_CIF_ISP_FILT_BASE + 0x00000034) +#define RKISP1_CIF_ISP_FILT_LUM_WEIGHT (RKISP1_CIF_ISP_FILT_BASE + 0x00000038) +#define RKISP1_CIF_ISP_FILT_FAC_SH1 (RKISP1_CIF_ISP_FILT_BASE + 0x0000003c) +#define RKISP1_CIF_ISP_FILT_FAC_SH0 (RKISP1_CIF_ISP_FILT_BASE + 0x00000040) +#define RKISP1_CIF_ISP_FILT_FAC_MID (RKISP1_CIF_ISP_FILT_BASE + 0x00000044) +#define RKISP1_CIF_ISP_FILT_FAC_BL0 (RKISP1_CIF_ISP_FILT_BASE + 0x00000048) +#define RKISP1_CIF_ISP_FILT_FAC_BL1 (RKISP1_CIF_ISP_FILT_BASE + 0x0000004C) + +#define RKISP1_CIF_ISP_CAC_BASE 0x00002580 +#define RKISP1_CIF_ISP_CAC_CTRL (RKISP1_CIF_ISP_CAC_BASE + 0x00000000) +#define RKISP1_CIF_ISP_CAC_COUNT_START (RKISP1_CIF_ISP_CAC_BASE + 0x00000004) +#define RKISP1_CIF_ISP_CAC_A (RKISP1_CIF_ISP_CAC_BASE + 0x00000008) +#define RKISP1_CIF_ISP_CAC_B (RKISP1_CIF_ISP_CAC_BASE + 0x0000000C) +#define RKISP1_CIF_ISP_CAC_C (RKISP1_CIF_ISP_CAC_BASE + 0x00000010) +#define RKISP1_CIF_ISP_X_NORM (RKISP1_CIF_ISP_CAC_BASE + 0x00000014) +#define RKISP1_CIF_ISP_Y_NORM (RKISP1_CIF_ISP_CAC_BASE + 0x00000018) + +#define RKISP1_CIF_ISP_EXP_BASE 0x00002600 +#define RKISP1_CIF_ISP_EXP_CTRL (RKISP1_CIF_ISP_EXP_BASE + 0x00000000) +#define RKISP1_CIF_ISP_EXP_H_OFFSET (RKISP1_CIF_ISP_EXP_BASE + 0x00000004) +#define RKISP1_CIF_ISP_EXP_V_OFFSET (RKISP1_CIF_ISP_EXP_BASE + 0x00000008) +#define RKISP1_CIF_ISP_EXP_H_SIZE (RKISP1_CIF_ISP_EXP_BASE + 0x0000000C) +#define RKISP1_CIF_ISP_EXP_V_SIZE (RKISP1_CIF_ISP_EXP_BASE + 0x00000010) +#define RKISP1_CIF_ISP_EXP_MEAN_00 (RKISP1_CIF_ISP_EXP_BASE + 0x00000014) +#define RKISP1_CIF_ISP_EXP_MEAN_10 (RKISP1_CIF_ISP_EXP_BASE + 0x00000018) +#define RKISP1_CIF_ISP_EXP_MEAN_20 (RKISP1_CIF_ISP_EXP_BASE + 0x0000001c) +#define RKISP1_CIF_ISP_EXP_MEAN_30 (RKISP1_CIF_ISP_EXP_BASE + 0x00000020) +#define RKISP1_CIF_ISP_EXP_MEAN_40 (RKISP1_CIF_ISP_EXP_BASE + 0x00000024) +#define RKISP1_CIF_ISP_EXP_MEAN_01 (RKISP1_CIF_ISP_EXP_BASE + 0x00000028) +#define RKISP1_CIF_ISP_EXP_MEAN_11 (RKISP1_CIF_ISP_EXP_BASE + 0x0000002c) +#define RKISP1_CIF_ISP_EXP_MEAN_21 (RKISP1_CIF_ISP_EXP_BASE + 0x00000030) +#define RKISP1_CIF_ISP_EXP_MEAN_31 (RKISP1_CIF_ISP_EXP_BASE + 0x00000034) +#define RKISP1_CIF_ISP_EXP_MEAN_41 (RKISP1_CIF_ISP_EXP_BASE + 0x00000038) +#define RKISP1_CIF_ISP_EXP_MEAN_02 (RKISP1_CIF_ISP_EXP_BASE + 0x0000003c) +#define RKISP1_CIF_ISP_EXP_MEAN_12 (RKISP1_CIF_ISP_EXP_BASE + 0x00000040) +#define RKISP1_CIF_ISP_EXP_MEAN_22 (RKISP1_CIF_ISP_EXP_BASE + 0x00000044) +#define RKISP1_CIF_ISP_EXP_MEAN_32 (RKISP1_CIF_ISP_EXP_BASE + 0x00000048) +#define RKISP1_CIF_ISP_EXP_MEAN_42 (RKISP1_CIF_ISP_EXP_BASE + 0x0000004c) +#define RKISP1_CIF_ISP_EXP_MEAN_03 (RKISP1_CIF_ISP_EXP_BASE + 0x00000050) +#define RKISP1_CIF_ISP_EXP_MEAN_13 (RKISP1_CIF_ISP_EXP_BASE + 0x00000054) +#define RKISP1_CIF_ISP_EXP_MEAN_23 (RKISP1_CIF_ISP_EXP_BASE + 0x00000058) +#define RKISP1_CIF_ISP_EXP_MEAN_33 (RKISP1_CIF_ISP_EXP_BASE + 0x0000005c) +#define RKISP1_CIF_ISP_EXP_MEAN_43 (RKISP1_CIF_ISP_EXP_BASE + 0x00000060) +#define RKISP1_CIF_ISP_EXP_MEAN_04 (RKISP1_CIF_ISP_EXP_BASE + 0x00000064) +#define RKISP1_CIF_ISP_EXP_MEAN_14 (RKISP1_CIF_ISP_EXP_BASE + 0x00000068) +#define RKISP1_CIF_ISP_EXP_MEAN_24 (RKISP1_CIF_ISP_EXP_BASE + 0x0000006c) +#define RKISP1_CIF_ISP_EXP_MEAN_34 (RKISP1_CIF_ISP_EXP_BASE + 0x00000070) +#define RKISP1_CIF_ISP_EXP_MEAN_44 (RKISP1_CIF_ISP_EXP_BASE + 0x00000074) + +#define RKISP1_CIF_ISP_BLS_BASE 0x00002700 +#define RKISP1_CIF_ISP_BLS_CTRL (RKISP1_CIF_ISP_BLS_BASE + 0x00000000) +#define RKISP1_CIF_ISP_BLS_SAMPLES (RKISP1_CIF_ISP_BLS_BASE + 0x00000004) +#define RKISP1_CIF_ISP_BLS_H1_START (RKISP1_CIF_ISP_BLS_BASE + 0x00000008) +#define RKISP1_CIF_ISP_BLS_H1_STOP (RKISP1_CIF_ISP_BLS_BASE + 0x0000000c) +#define RKISP1_CIF_ISP_BLS_V1_START (RKISP1_CIF_ISP_BLS_BASE + 0x00000010) +#define RKISP1_CIF_ISP_BLS_V1_STOP (RKISP1_CIF_ISP_BLS_BASE + 0x00000014) +#define RKISP1_CIF_ISP_BLS_H2_START (RKISP1_CIF_ISP_BLS_BASE + 0x00000018) +#define RKISP1_CIF_ISP_BLS_H2_STOP (RKISP1_CIF_ISP_BLS_BASE + 0x0000001c) +#define RKISP1_CIF_ISP_BLS_V2_START (RKISP1_CIF_ISP_BLS_BASE + 0x00000020) +#define RKISP1_CIF_ISP_BLS_V2_STOP (RKISP1_CIF_ISP_BLS_BASE + 0x00000024) +#define RKISP1_CIF_ISP_BLS_A_FIXED (RKISP1_CIF_ISP_BLS_BASE + 0x00000028) +#define RKISP1_CIF_ISP_BLS_B_FIXED (RKISP1_CIF_ISP_BLS_BASE + 0x0000002c) +#define RKISP1_CIF_ISP_BLS_C_FIXED (RKISP1_CIF_ISP_BLS_BASE + 0x00000030) +#define RKISP1_CIF_ISP_BLS_D_FIXED (RKISP1_CIF_ISP_BLS_BASE + 0x00000034) +#define RKISP1_CIF_ISP_BLS_A_MEASURED (RKISP1_CIF_ISP_BLS_BASE + 0x00000038) +#define RKISP1_CIF_ISP_BLS_B_MEASURED (RKISP1_CIF_ISP_BLS_BASE + 0x0000003c) +#define RKISP1_CIF_ISP_BLS_C_MEASURED (RKISP1_CIF_ISP_BLS_BASE + 0x00000040) +#define RKISP1_CIF_ISP_BLS_D_MEASURED (RKISP1_CIF_ISP_BLS_BASE + 0x00000044) + +#define RKISP1_CIF_ISP_DPF_BASE 0x00002800 +#define RKISP1_CIF_ISP_DPF_MODE (RKISP1_CIF_ISP_DPF_BASE + 0x00000000) +#define RKISP1_CIF_ISP_DPF_STRENGTH_R (RKISP1_CIF_ISP_DPF_BASE + 0x00000004) +#define RKISP1_CIF_ISP_DPF_STRENGTH_G (RKISP1_CIF_ISP_DPF_BASE + 0x00000008) +#define RKISP1_CIF_ISP_DPF_STRENGTH_B (RKISP1_CIF_ISP_DPF_BASE + 0x0000000C) +#define RKISP1_CIF_ISP_DPF_S_WEIGHT_G_1_4 (RKISP1_CIF_ISP_DPF_BASE + 0x00000010) +#define RKISP1_CIF_ISP_DPF_S_WEIGHT_G_5_6 (RKISP1_CIF_ISP_DPF_BASE + 0x00000014) +#define RKISP1_CIF_ISP_DPF_S_WEIGHT_RB_1_4 (RKISP1_CIF_ISP_DPF_BASE + 0x00000018) +#define RKISP1_CIF_ISP_DPF_S_WEIGHT_RB_5_6 (RKISP1_CIF_ISP_DPF_BASE + 0x0000001C) +#define RKISP1_CIF_ISP_DPF_NULL_COEFF_0 (RKISP1_CIF_ISP_DPF_BASE + 0x00000020) +#define RKISP1_CIF_ISP_DPF_NULL_COEFF_1 (RKISP1_CIF_ISP_DPF_BASE + 0x00000024) +#define RKISP1_CIF_ISP_DPF_NULL_COEFF_2 (RKISP1_CIF_ISP_DPF_BASE + 0x00000028) +#define RKISP1_CIF_ISP_DPF_NULL_COEFF_3 (RKISP1_CIF_ISP_DPF_BASE + 0x0000002C) +#define RKISP1_CIF_ISP_DPF_NULL_COEFF_4 (RKISP1_CIF_ISP_DPF_BASE + 0x00000030) +#define RKISP1_CIF_ISP_DPF_NULL_COEFF_5 (RKISP1_CIF_ISP_DPF_BASE + 0x00000034) +#define RKISP1_CIF_ISP_DPF_NULL_COEFF_6 (RKISP1_CIF_ISP_DPF_BASE + 0x00000038) +#define RKISP1_CIF_ISP_DPF_NULL_COEFF_7 (RKISP1_CIF_ISP_DPF_BASE + 0x0000003C) +#define RKISP1_CIF_ISP_DPF_NULL_COEFF_8 (RKISP1_CIF_ISP_DPF_BASE + 0x00000040) +#define RKISP1_CIF_ISP_DPF_NULL_COEFF_9 (RKISP1_CIF_ISP_DPF_BASE + 0x00000044) +#define RKISP1_CIF_ISP_DPF_NULL_COEFF_10 (RKISP1_CIF_ISP_DPF_BASE + 0x00000048) +#define RKISP1_CIF_ISP_DPF_NULL_COEFF_11 (RKISP1_CIF_ISP_DPF_BASE + 0x0000004C) +#define RKISP1_CIF_ISP_DPF_NULL_COEFF_12 (RKISP1_CIF_ISP_DPF_BASE + 0x00000050) +#define RKISP1_CIF_ISP_DPF_NULL_COEFF_13 (RKISP1_CIF_ISP_DPF_BASE + 0x00000054) +#define RKISP1_CIF_ISP_DPF_NULL_COEFF_14 (RKISP1_CIF_ISP_DPF_BASE + 0x00000058) +#define RKISP1_CIF_ISP_DPF_NULL_COEFF_15 (RKISP1_CIF_ISP_DPF_BASE + 0x0000005C) +#define RKISP1_CIF_ISP_DPF_NULL_COEFF_16 (RKISP1_CIF_ISP_DPF_BASE + 0x00000060) +#define RKISP1_CIF_ISP_DPF_NF_GAIN_R (RKISP1_CIF_ISP_DPF_BASE + 0x00000064) +#define RKISP1_CIF_ISP_DPF_NF_GAIN_GR (RKISP1_CIF_ISP_DPF_BASE + 0x00000068) +#define RKISP1_CIF_ISP_DPF_NF_GAIN_GB (RKISP1_CIF_ISP_DPF_BASE + 0x0000006C) +#define RKISP1_CIF_ISP_DPF_NF_GAIN_B (RKISP1_CIF_ISP_DPF_BASE + 0x00000070) + +#define RKISP1_CIF_ISP_DPCC_BASE 0x00002900 +#define RKISP1_CIF_ISP_DPCC_MODE (RKISP1_CIF_ISP_DPCC_BASE + 0x00000000) +#define RKISP1_CIF_ISP_DPCC_OUTPUT_MODE (RKISP1_CIF_ISP_DPCC_BASE + 0x00000004) +#define RKISP1_CIF_ISP_DPCC_SET_USE (RKISP1_CIF_ISP_DPCC_BASE + 0x00000008) +#define RKISP1_CIF_ISP_DPCC_METHODS_SET_1 (RKISP1_CIF_ISP_DPCC_BASE + 0x0000000C) +#define RKISP1_CIF_ISP_DPCC_METHODS_SET_2 (RKISP1_CIF_ISP_DPCC_BASE + 0x00000010) +#define RKISP1_CIF_ISP_DPCC_METHODS_SET_3 (RKISP1_CIF_ISP_DPCC_BASE + 0x00000014) +#define RKISP1_CIF_ISP_DPCC_LINE_THRESH_1 (RKISP1_CIF_ISP_DPCC_BASE + 0x00000018) +#define RKISP1_CIF_ISP_DPCC_LINE_MAD_FAC_1 (RKISP1_CIF_ISP_DPCC_BASE + 0x0000001C) +#define RKISP1_CIF_ISP_DPCC_PG_FAC_1 (RKISP1_CIF_ISP_DPCC_BASE + 0x00000020) +#define RKISP1_CIF_ISP_DPCC_RND_THRESH_1 (RKISP1_CIF_ISP_DPCC_BASE + 0x00000024) +#define RKISP1_CIF_ISP_DPCC_RG_FAC_1 (RKISP1_CIF_ISP_DPCC_BASE + 0x00000028) +#define RKISP1_CIF_ISP_DPCC_LINE_THRESH_2 (RKISP1_CIF_ISP_DPCC_BASE + 0x0000002C) +#define RKISP1_CIF_ISP_DPCC_LINE_MAD_FAC_2 (RKISP1_CIF_ISP_DPCC_BASE + 0x00000030) +#define RKISP1_CIF_ISP_DPCC_PG_FAC_2 (RKISP1_CIF_ISP_DPCC_BASE + 0x00000034) +#define RKISP1_CIF_ISP_DPCC_RND_THRESH_2 (RKISP1_CIF_ISP_DPCC_BASE + 0x00000038) +#define RKISP1_CIF_ISP_DPCC_RG_FAC_2 (RKISP1_CIF_ISP_DPCC_BASE + 0x0000003C) +#define RKISP1_CIF_ISP_DPCC_LINE_THRESH_3 (RKISP1_CIF_ISP_DPCC_BASE + 0x00000040) +#define RKISP1_CIF_ISP_DPCC_LINE_MAD_FAC_3 (RKISP1_CIF_ISP_DPCC_BASE + 0x00000044) +#define RKISP1_CIF_ISP_DPCC_PG_FAC_3 (RKISP1_CIF_ISP_DPCC_BASE + 0x00000048) +#define RKISP1_CIF_ISP_DPCC_RND_THRESH_3 (RKISP1_CIF_ISP_DPCC_BASE + 0x0000004C) +#define RKISP1_CIF_ISP_DPCC_RG_FAC_3 (RKISP1_CIF_ISP_DPCC_BASE + 0x00000050) +#define RKISP1_CIF_ISP_DPCC_RO_LIMITS (RKISP1_CIF_ISP_DPCC_BASE + 0x00000054) +#define RKISP1_CIF_ISP_DPCC_RND_OFFS (RKISP1_CIF_ISP_DPCC_BASE + 0x00000058) +#define RKISP1_CIF_ISP_DPCC_BPT_CTRL (RKISP1_CIF_ISP_DPCC_BASE + 0x0000005C) +#define RKISP1_CIF_ISP_DPCC_BPT_NUMBER (RKISP1_CIF_ISP_DPCC_BASE + 0x00000060) +#define RKISP1_CIF_ISP_DPCC_BPT_ADDR (RKISP1_CIF_ISP_DPCC_BASE + 0x00000064) +#define RKISP1_CIF_ISP_DPCC_BPT_DATA (RKISP1_CIF_ISP_DPCC_BASE + 0x00000068) + +#define RKISP1_CIF_ISP_WDR_BASE 0x00002A00 +#define RKISP1_CIF_ISP_WDR_CTRL (RKISP1_CIF_ISP_WDR_BASE + 0x00000000) +#define RKISP1_CIF_ISP_WDR_TONECURVE_1 (RKISP1_CIF_ISP_WDR_BASE + 0x00000004) +#define RKISP1_CIF_ISP_WDR_TONECURVE_2 (RKISP1_CIF_ISP_WDR_BASE + 0x00000008) +#define RKISP1_CIF_ISP_WDR_TONECURVE_3 (RKISP1_CIF_ISP_WDR_BASE + 0x0000000C) +#define RKISP1_CIF_ISP_WDR_TONECURVE_4 (RKISP1_CIF_ISP_WDR_BASE + 0x00000010) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_0 (RKISP1_CIF_ISP_WDR_BASE + 0x00000014) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_1 (RKISP1_CIF_ISP_WDR_BASE + 0x00000018) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_2 (RKISP1_CIF_ISP_WDR_BASE + 0x0000001C) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_3 (RKISP1_CIF_ISP_WDR_BASE + 0x00000020) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_4 (RKISP1_CIF_ISP_WDR_BASE + 0x00000024) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_5 (RKISP1_CIF_ISP_WDR_BASE + 0x00000028) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_6 (RKISP1_CIF_ISP_WDR_BASE + 0x0000002C) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_7 (RKISP1_CIF_ISP_WDR_BASE + 0x00000030) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_8 (RKISP1_CIF_ISP_WDR_BASE + 0x00000034) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_9 (RKISP1_CIF_ISP_WDR_BASE + 0x00000038) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_10 (RKISP1_CIF_ISP_WDR_BASE + 0x0000003C) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_11 (RKISP1_CIF_ISP_WDR_BASE + 0x00000040) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_12 (RKISP1_CIF_ISP_WDR_BASE + 0x00000044) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_13 (RKISP1_CIF_ISP_WDR_BASE + 0x00000048) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_14 (RKISP1_CIF_ISP_WDR_BASE + 0x0000004C) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_15 (RKISP1_CIF_ISP_WDR_BASE + 0x00000050) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_16 (RKISP1_CIF_ISP_WDR_BASE + 0x00000054) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_17 (RKISP1_CIF_ISP_WDR_BASE + 0x00000058) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_18 (RKISP1_CIF_ISP_WDR_BASE + 0x0000005C) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_19 (RKISP1_CIF_ISP_WDR_BASE + 0x00000060) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_20 (RKISP1_CIF_ISP_WDR_BASE + 0x00000064) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_21 (RKISP1_CIF_ISP_WDR_BASE + 0x00000068) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_22 (RKISP1_CIF_ISP_WDR_BASE + 0x0000006C) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_23 (RKISP1_CIF_ISP_WDR_BASE + 0x00000070) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_24 (RKISP1_CIF_ISP_WDR_BASE + 0x00000074) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_25 (RKISP1_CIF_ISP_WDR_BASE + 0x00000078) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_26 (RKISP1_CIF_ISP_WDR_BASE + 0x0000007C) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_27 (RKISP1_CIF_ISP_WDR_BASE + 0x00000080) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_28 (RKISP1_CIF_ISP_WDR_BASE + 0x00000084) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_29 (RKISP1_CIF_ISP_WDR_BASE + 0x00000088) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_30 (RKISP1_CIF_ISP_WDR_BASE + 0x0000008C) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_31 (RKISP1_CIF_ISP_WDR_BASE + 0x00000090) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_32 (RKISP1_CIF_ISP_WDR_BASE + 0x00000094) +#define RKISP1_CIF_ISP_WDR_OFFSET (RKISP1_CIF_ISP_WDR_BASE + 0x00000098) +#define RKISP1_CIF_ISP_WDR_DELTAMIN (RKISP1_CIF_ISP_WDR_BASE + 0x0000009C) +#define RKISP1_CIF_ISP_WDR_TONECURVE_1_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000A0) +#define RKISP1_CIF_ISP_WDR_TONECURVE_2_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000A4) +#define RKISP1_CIF_ISP_WDR_TONECURVE_3_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000A8) +#define RKISP1_CIF_ISP_WDR_TONECURVE_4_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000AC) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_0_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000B0) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_1_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000B4) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_2_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000B8) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_3_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000BC) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_4_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000C0) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_5_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000C4) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_6_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000C8) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_7_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000CC) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_8_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000D0) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_9_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000D4) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_10_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000D8) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_11_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000DC) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_12_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000E0) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_13_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000E4) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_14_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000E8) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_15_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000EC) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_16_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000F0) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_17_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000F4) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_18_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000F8) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_19_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000FC) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_20_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x00000100) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_21_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x00000104) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_22_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x00000108) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_23_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x0000010C) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_24_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x00000110) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_25_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x00000114) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_26_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x00000118) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_27_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x0000011C) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_28_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x00000120) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_29_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x00000124) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_30_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x00000128) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_31_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x0000012C) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_32_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x00000130) + +#define RKISP1_CIF_ISP_VSM_BASE 0x00002F00 +#define RKISP1_CIF_ISP_VSM_MODE (RKISP1_CIF_ISP_VSM_BASE + 0x00000000) +#define RKISP1_CIF_ISP_VSM_H_OFFS (RKISP1_CIF_ISP_VSM_BASE + 0x00000004) +#define RKISP1_CIF_ISP_VSM_V_OFFS (RKISP1_CIF_ISP_VSM_BASE + 0x00000008) +#define RKISP1_CIF_ISP_VSM_H_SIZE (RKISP1_CIF_ISP_VSM_BASE + 0x0000000C) +#define RKISP1_CIF_ISP_VSM_V_SIZE (RKISP1_CIF_ISP_VSM_BASE + 0x00000010) +#define RKISP1_CIF_ISP_VSM_H_SEGMENTS (RKISP1_CIF_ISP_VSM_BASE + 0x00000014) +#define RKISP1_CIF_ISP_VSM_V_SEGMENTS (RKISP1_CIF_ISP_VSM_BASE + 0x00000018) +#define RKISP1_CIF_ISP_VSM_DELTA_H (RKISP1_CIF_ISP_VSM_BASE + 0x0000001C) +#define RKISP1_CIF_ISP_VSM_DELTA_V (RKISP1_CIF_ISP_VSM_BASE + 0x00000020) + +#endif /* _RKISP1_REGS_H */ From patchwork Wed Jan 8 18:44:46 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Helen Koike X-Patchwork-Id: 11324327 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 34775139A for ; Wed, 8 Jan 2020 18:46:55 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 0543B20705 for ; Wed, 8 Jan 2020 18:46:54 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="TRd2KyiS" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 0543B20705 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=collabora.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-rockchip-bounces+patchwork-linux-rockchip=patchwork.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=EKi8eGS1oP4gVzituHqi2yNGprlou0jt/0z996K5aYY=; b=TRd2KyiSUace/u j7/fVoXsS78DCOjYPf1aj3XxNhi0PHCgvH4Qlqovss/hThrw9Zt5tRCT9XiKxrgJTJISy9kUnmWkd yLRvpu2gDl5Qxtyiin+yhxYOAVkjBIuWY/SvAcwamytJTQUpWqkYN2JlW0Bjab1UdysM2Dp38B9li 6pNtIAvD3j8yfI4MPd2r+gzGMQsAMiUC1Yrlp1LQB4uYHmsd8mkWdBMYyYWNUC2BMDbkeZXJ+Bunl adG4UHa8fdzbwhSkdQx5E5qPmq43+ewok5EZTNQ90JOosIBbq6L+8LnfK50bf1EkBKGPHWGrkpcYY hWqOFErlljLVgiupTD2w==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1ipGLy-0000iX-ET; Wed, 08 Jan 2020 18:46:50 +0000 Received: from bhuna.collabora.co.uk ([46.235.227.227]) by bombadil.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1ipGKw-0008Dm-FF; Wed, 08 Jan 2020 18:45:58 +0000 Received: from [127.0.0.1] (localhost [127.0.0.1]) (Authenticated sender: koike) with ESMTPSA id 6705F2912F0 From: Helen Koike To: linux-rockchip@lists.infradead.org Subject: [PATCH v13 03/11] media: staging: rkisp1: add streaming paths Date: Wed, 8 Jan 2020 15:44:46 -0300 Message-Id: <20200108184454.825725-4-helen.koike@collabora.com> X-Mailer: git-send-email 2.24.0 In-Reply-To: <20200108184454.825725-1-helen.koike@collabora.com> References: <20200108184454.825725-1-helen.koike@collabora.com> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20200108_104547_148384_B3BBB497 X-CRM114-Status: GOOD ( 16.30 ) X-Spam-Score: -0.0 (/) X-Spam-Report: SpamAssassin version 3.4.2 on bombadil.infradead.org summary: Content analysis details: (-0.0 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at https://www.dnswl.org/, no trust [46.235.227.227 listed in list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record -0.0 SPF_HELO_PASS SPF: HELO matches SPF record 0.0 UNPARSEABLE_RELAY Informational: message has unparseable relay lines X-BeenThere: linux-rockchip@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Upstream kernel work for Rockchip platforms List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: mark.rutland@arm.com, eddie.cai.linux@gmail.com, heiko@sntech.de, laurent.pinchart@ideasonboard.com, joacim.zetterling@gmail.com, kernel@collabora.com, andrey.konovalov@linaro.org, Yichong Zhong , jacob-chen@iotwrt.com, hans.verkuil@cisco.com, Allon Huang , Shunqian Zheng , linux-media@vger.kernel.org, devicetree@vger.kernel.org, Jacob Chen , Jeffy Chen , Helen Koike , robh+dt@kernel.org, mchehab@kernel.org, ezequiel@collabora.com, linux-arm-kernel@lists.infradead.org, gregkh@linuxfoundation.org, linux-kernel@vger.kernel.org, tfiga@chromium.org, sakari.ailus@linux.intel.com, Jacob Chen Sender: "Linux-rockchip" Errors-To: linux-rockchip-bounces+patchwork-linux-rockchip=patchwork.kernel.org@lists.infradead.org Add v4l2 capture device interface to rkisp1 driver, allowing users to get frames from ISP1. ISP1 has two major streaming paths, mainpah and selfpah, with different capabilities. Each one has an independent crop and resizer, thus add a capture video device and a resizer subdevice for each of the paths. Signed-off-by: Jacob Chen Signed-off-by: Shunqian Zheng Signed-off-by: Yichong Zhong Signed-off-by: Jacob Chen Signed-off-by: Eddie Cai Signed-off-by: Jeffy Chen Signed-off-by: Allon Huang Signed-off-by: Tomasz Figa Signed-off-by: Ezequiel Garcia Signed-off-by: Helen Koike --- Changes in v13: None Changes in v12: - Several cleanups, renaming, removal of unecessary code, re-writting for redability, code re-structuring to increase maintainability - debugfs - resizer and crop was moved out from the capture to its own media subdevice implemented in rkisp1-resizer.c - Commit re-organization to not break bisectability Changes in v11: capture - fix checkpatch errors Changes in v10: - unsquash Changes in v9: - fix typos - fix queue_setup: different behaviour when num_plane is 0 or not - replace v4l2_{dgb,info,warn,err} by dev_* - squash - move to staging Changes in v8: None Changes in v7: - s/strlcpy/strscpy - Fix v4l2-compliance issues: * remove input ioctls media api can be used to define the topology, this input api is not required. Besides it, if an input is enumerated, v4l2-compliance is not happy with G_FMT returning the default colorspace instead of something more specific. * return the pixelformat to the userspace G_/S_/TRY_ FORMAT should return a valid pixelformat to the user, even if the user gave an invalid one * add missing default colorspace and ycbcr * fix wrong pixformat in mp_fmts[] table * add buf type check in s_/g_selection * queue_setup - check sizes * normalize bus_info name * fix field any v4l2-compliance -s complain - set field none when streaming - Fix compiling error: s/vidioc_enum_fmt_vid_cap_mplane/vidioc_enum_fmt_vid_cap - Replace stream state with a boolean The rkisp1_state enum consists only of 3 entries, where 1 is completely unused and the other two respectively mean not streaming or streaming. Replace it with a boolean called "streaming". - Simplify MI interrupt handling Rather than adding unnecessary indirection, just use stream index to handle MI interrupt enable/disable/clear, since the stream index matches the order of bits now, thanks to previous patch. While at it, remove some dead code. - code styling and checkpatch fixes - add link_validate: don't allow a link with bayer/non-bayer mismatch drivers/staging/media/rkisp1/Makefile | 6 +- drivers/staging/media/rkisp1/rkisp1-capture.c | 1437 +++++++++++++++++ drivers/staging/media/rkisp1/rkisp1-common.h | 72 + drivers/staging/media/rkisp1/rkisp1-dev.c | 81 +- drivers/staging/media/rkisp1/rkisp1-resizer.c | 775 +++++++++ 5 files changed, 2364 insertions(+), 7 deletions(-) create mode 100644 drivers/staging/media/rkisp1/rkisp1-capture.c create mode 100644 drivers/staging/media/rkisp1/rkisp1-resizer.c diff --git a/drivers/staging/media/rkisp1/Makefile b/drivers/staging/media/rkisp1/Makefile index 2faa73fc2b7f..1725b990d669 100644 --- a/drivers/staging/media/rkisp1/Makefile +++ b/drivers/staging/media/rkisp1/Makefile @@ -1,4 +1,6 @@ obj-$(CONFIG_VIDEO_ROCKCHIP_ISP1) += rockchip-isp1.o -rockchip-isp1-objs += rkisp1-common.o \ +rockchip-isp1-objs += rkisp1-capture.o \ + rkisp1-common.o \ rkisp1-dev.o \ - rkisp1-isp.o + rkisp1-isp.o \ + rkisp1-resizer.o diff --git a/drivers/staging/media/rkisp1/rkisp1-capture.c b/drivers/staging/media/rkisp1/rkisp1-capture.c new file mode 100644 index 000000000000..524e0dd38c1b --- /dev/null +++ b/drivers/staging/media/rkisp1/rkisp1-capture.c @@ -0,0 +1,1437 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Rockchip ISP1 Driver - V4l capture device + * + * Copyright (C) 2019 Collabora, Ltd. + * + * Based on Rockchip ISP1 driver by Rockchip Electronics Co., Ltd. + * Copyright (C) 2017 Rockchip Electronics Co., Ltd. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rkisp1-common.h" + +/* + * NOTE: There are two capture video devices in rkisp1, selfpath and mainpath. + * + * differences between selfpath and mainpath + * available mp sink input: isp + * available sp sink input : isp, dma(TODO) + * available mp sink pad fmts: yuv422, raw + * available sp sink pad fmts: yuv422, yuv420...... + * available mp source fmts: yuv, raw, jpeg(TODO) + * available sp source fmts: yuv, rgb + */ + +#define RKISP1_SP_DEV_NAME RKISP1_DRIVER_NAME "_selfpath" +#define RKISP1_MP_DEV_NAME RKISP1_DRIVER_NAME "_mainpath" + +#define RKISP1_MIN_BUFFERS_NEEDED 3 + +enum rkisp1_plane { + RKISP1_PLANE_Y = 0, + RKISP1_PLANE_CB = 1, + RKISP1_PLANE_CR = 2 +}; + +/* + * @fourcc: pixel format + * @fmt_type: helper filed for pixel format + * @uv_swap: if cb cr swaped, for yuv + * @write_format: defines how YCbCr self picture data is written to memory + * @output_format: defines sp output format + */ +struct rkisp1_capture_fmt_cfg { + u32 fourcc; + u8 fmt_type; + u8 uv_swap; + u32 write_format; + u32 output_format; +}; + +struct rkisp1_capture_ops { + void (*config)(struct rkisp1_capture *cap); + void (*stop)(struct rkisp1_capture *cap); + void (*enable)(struct rkisp1_capture *cap); + void (*disable)(struct rkisp1_capture *cap); + void (*set_data_path)(struct rkisp1_capture *cap); + bool (*is_stopped)(struct rkisp1_capture *cap); +}; + +struct rkisp1_capture_config { + const struct rkisp1_capture_fmt_cfg *fmts; + int fmt_size; + struct { + u32 y_size_init; + u32 cb_size_init; + u32 cr_size_init; + u32 y_base_ad_init; + u32 cb_base_ad_init; + u32 cr_base_ad_init; + u32 y_offs_cnt_init; + u32 cb_offs_cnt_init; + u32 cr_offs_cnt_init; + } mi; +}; + +static const struct rkisp1_capture_fmt_cfg rkisp1_mp_fmts[] = { + /* yuv422 */ + { + .fourcc = V4L2_PIX_FMT_YUYV, + .fmt_type = RKISP1_FMT_YUV, + .uv_swap = 0, + .write_format = RKISP1_MI_CTRL_MP_WRITE_YUVINT, + }, { + .fourcc = V4L2_PIX_FMT_YVYU, + .fmt_type = RKISP1_FMT_YUV, + .uv_swap = 1, + .write_format = RKISP1_MI_CTRL_MP_WRITE_YUVINT, + }, { + .fourcc = V4L2_PIX_FMT_VYUY, + .fmt_type = RKISP1_FMT_YUV, + .write_format = RKISP1_MI_CTRL_MP_WRITE_YUVINT, + }, { + .fourcc = V4L2_PIX_FMT_YUV422P, + .fmt_type = RKISP1_FMT_YUV, + .uv_swap = 0, + .write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_PLA_OR_RAW8, + }, { + .fourcc = V4L2_PIX_FMT_NV16, + .fmt_type = RKISP1_FMT_YUV, + .uv_swap = 0, + .write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_SPLA, + }, { + .fourcc = V4L2_PIX_FMT_NV61, + .fmt_type = RKISP1_FMT_YUV, + .uv_swap = 1, + .write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_SPLA, + }, { + .fourcc = V4L2_PIX_FMT_YVU422M, + .fmt_type = RKISP1_FMT_YUV, + .uv_swap = 1, + .write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_PLA_OR_RAW8, + }, + /* yuv420 */ + { + .fourcc = V4L2_PIX_FMT_NV21, + .fmt_type = RKISP1_FMT_YUV, + .uv_swap = 1, + .write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_SPLA, + }, { + .fourcc = V4L2_PIX_FMT_NV12, + .fmt_type = RKISP1_FMT_YUV, + .uv_swap = 0, + .write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_SPLA, + }, { + .fourcc = V4L2_PIX_FMT_NV21M, + .fmt_type = RKISP1_FMT_YUV, + .uv_swap = 1, + .write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_SPLA, + }, { + .fourcc = V4L2_PIX_FMT_NV12M, + .fmt_type = RKISP1_FMT_YUV, + .uv_swap = 0, + .write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_SPLA, + }, { + .fourcc = V4L2_PIX_FMT_YUV420, + .fmt_type = RKISP1_FMT_YUV, + .uv_swap = 0, + .write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_PLA_OR_RAW8, + }, { + .fourcc = V4L2_PIX_FMT_YVU420, + .fmt_type = RKISP1_FMT_YUV, + .uv_swap = 1, + .write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_PLA_OR_RAW8, + }, + /* yuv444 */ + { + .fourcc = V4L2_PIX_FMT_YUV444M, + .fmt_type = RKISP1_FMT_YUV, + .uv_swap = 0, + .write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_PLA_OR_RAW8, + }, + /* yuv400 */ + { + .fourcc = V4L2_PIX_FMT_GREY, + .fmt_type = RKISP1_FMT_YUV, + .uv_swap = 0, + .write_format = RKISP1_MI_CTRL_MP_WRITE_YUVINT, + }, + /* raw */ + { + .fourcc = V4L2_PIX_FMT_SRGGB8, + .fmt_type = RKISP1_FMT_BAYER, + .write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_PLA_OR_RAW8, + }, { + .fourcc = V4L2_PIX_FMT_SGRBG8, + .fmt_type = RKISP1_FMT_BAYER, + .write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_PLA_OR_RAW8, + }, { + .fourcc = V4L2_PIX_FMT_SGBRG8, + .fmt_type = RKISP1_FMT_BAYER, + .write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_PLA_OR_RAW8, + }, { + .fourcc = V4L2_PIX_FMT_SBGGR8, + .fmt_type = RKISP1_FMT_BAYER, + .write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_PLA_OR_RAW8, + }, { + .fourcc = V4L2_PIX_FMT_SRGGB10, + .fmt_type = RKISP1_FMT_BAYER, + .write_format = RKISP1_MI_CTRL_MP_WRITE_RAW12, + }, { + .fourcc = V4L2_PIX_FMT_SGRBG10, + .fmt_type = RKISP1_FMT_BAYER, + .write_format = RKISP1_MI_CTRL_MP_WRITE_RAW12, + }, { + .fourcc = V4L2_PIX_FMT_SGBRG10, + .fmt_type = RKISP1_FMT_BAYER, + .write_format = RKISP1_MI_CTRL_MP_WRITE_RAW12, + }, { + .fourcc = V4L2_PIX_FMT_SBGGR10, + .fmt_type = RKISP1_FMT_BAYER, + .write_format = RKISP1_MI_CTRL_MP_WRITE_RAW12, + }, { + .fourcc = V4L2_PIX_FMT_SRGGB12, + .fmt_type = RKISP1_FMT_BAYER, + .write_format = RKISP1_MI_CTRL_MP_WRITE_RAW12, + }, { + .fourcc = V4L2_PIX_FMT_SGRBG12, + .fmt_type = RKISP1_FMT_BAYER, + .write_format = RKISP1_MI_CTRL_MP_WRITE_RAW12, + }, { + .fourcc = V4L2_PIX_FMT_SGBRG12, + .fmt_type = RKISP1_FMT_BAYER, + .write_format = RKISP1_MI_CTRL_MP_WRITE_RAW12, + }, { + .fourcc = V4L2_PIX_FMT_SBGGR12, + .fmt_type = RKISP1_FMT_BAYER, + .write_format = RKISP1_MI_CTRL_MP_WRITE_RAW12, + }, +}; + +static const struct rkisp1_capture_fmt_cfg rkisp1_sp_fmts[] = { + /* yuv422 */ + { + .fourcc = V4L2_PIX_FMT_YUYV, + .fmt_type = RKISP1_FMT_YUV, + .uv_swap = 0, + .write_format = RKISP1_MI_CTRL_SP_WRITE_INT, + .output_format = RKISP1_MI_CTRL_SP_OUTPUT_YUV422, + }, { + .fourcc = V4L2_PIX_FMT_YVYU, + .fmt_type = RKISP1_FMT_YUV, + .uv_swap = 1, + .write_format = RKISP1_MI_CTRL_SP_WRITE_INT, + .output_format = RKISP1_MI_CTRL_SP_OUTPUT_YUV422, + }, { + .fourcc = V4L2_PIX_FMT_VYUY, + .fmt_type = RKISP1_FMT_YUV, + .uv_swap = 1, + .write_format = RKISP1_MI_CTRL_SP_WRITE_INT, + .output_format = RKISP1_MI_CTRL_SP_OUTPUT_YUV422, + }, { + .fourcc = V4L2_PIX_FMT_YUV422P, + .fmt_type = RKISP1_FMT_YUV, + .uv_swap = 0, + .write_format = RKISP1_MI_CTRL_SP_WRITE_PLA, + .output_format = RKISP1_MI_CTRL_SP_OUTPUT_YUV422, + }, { + .fourcc = V4L2_PIX_FMT_NV16, + .fmt_type = RKISP1_FMT_YUV, + .uv_swap = 0, + .write_format = RKISP1_MI_CTRL_SP_WRITE_SPLA, + .output_format = RKISP1_MI_CTRL_SP_OUTPUT_YUV422, + }, { + .fourcc = V4L2_PIX_FMT_NV61, + .fmt_type = RKISP1_FMT_YUV, + .uv_swap = 1, + .write_format = RKISP1_MI_CTRL_SP_WRITE_SPLA, + .output_format = RKISP1_MI_CTRL_SP_OUTPUT_YUV422, + }, { + .fourcc = V4L2_PIX_FMT_YVU422M, + .fmt_type = RKISP1_FMT_YUV, + .uv_swap = 1, + .write_format = RKISP1_MI_CTRL_SP_WRITE_PLA, + .output_format = RKISP1_MI_CTRL_SP_OUTPUT_YUV422, + }, + /* yuv420 */ + { + .fourcc = V4L2_PIX_FMT_NV21, + .fmt_type = RKISP1_FMT_YUV, + .uv_swap = 1, + .write_format = RKISP1_MI_CTRL_SP_WRITE_SPLA, + .output_format = RKISP1_MI_CTRL_SP_OUTPUT_YUV420, + }, { + .fourcc = V4L2_PIX_FMT_NV12, + .fmt_type = RKISP1_FMT_YUV, + .uv_swap = 0, + .write_format = RKISP1_MI_CTRL_SP_WRITE_SPLA, + .output_format = RKISP1_MI_CTRL_SP_OUTPUT_YUV420, + }, { + .fourcc = V4L2_PIX_FMT_NV21M, + .fmt_type = RKISP1_FMT_YUV, + .uv_swap = 1, + .write_format = RKISP1_MI_CTRL_SP_WRITE_SPLA, + .output_format = RKISP1_MI_CTRL_SP_OUTPUT_YUV420, + }, { + .fourcc = V4L2_PIX_FMT_NV12M, + .fmt_type = RKISP1_FMT_YUV, + .uv_swap = 0, + .write_format = RKISP1_MI_CTRL_SP_WRITE_SPLA, + .output_format = RKISP1_MI_CTRL_SP_OUTPUT_YUV420, + }, { + .fourcc = V4L2_PIX_FMT_YUV420, + .fmt_type = RKISP1_FMT_YUV, + .uv_swap = 0, + .write_format = RKISP1_MI_CTRL_SP_WRITE_PLA, + .output_format = RKISP1_MI_CTRL_SP_OUTPUT_YUV420, + }, { + .fourcc = V4L2_PIX_FMT_YVU420, + .fmt_type = RKISP1_FMT_YUV, + .uv_swap = 1, + .write_format = RKISP1_MI_CTRL_SP_WRITE_PLA, + .output_format = RKISP1_MI_CTRL_SP_OUTPUT_YUV420, + }, + /* yuv444 */ + { + .fourcc = V4L2_PIX_FMT_YUV444M, + .fmt_type = RKISP1_FMT_YUV, + .uv_swap = 0, + .write_format = RKISP1_MI_CTRL_SP_WRITE_PLA, + .output_format = RKISP1_MI_CTRL_SP_OUTPUT_YUV444, + }, + /* yuv400 */ + { + .fourcc = V4L2_PIX_FMT_GREY, + .fmt_type = RKISP1_FMT_YUV, + .uv_swap = 0, + .write_format = RKISP1_MI_CTRL_SP_WRITE_INT, + .output_format = RKISP1_MI_CTRL_SP_OUTPUT_YUV400, + }, + /* rgb */ + { + .fourcc = V4L2_PIX_FMT_RGB24, + .fmt_type = RKISP1_FMT_RGB, + .write_format = RKISP1_MI_CTRL_SP_WRITE_PLA, + .output_format = RKISP1_MI_CTRL_SP_OUTPUT_RGB888, + }, { + .fourcc = V4L2_PIX_FMT_RGB565, + .fmt_type = RKISP1_FMT_RGB, + .write_format = RKISP1_MI_CTRL_SP_WRITE_PLA, + .output_format = RKISP1_MI_CTRL_SP_OUTPUT_RGB565, + }, { + .fourcc = V4L2_PIX_FMT_BGR666, + .fmt_type = RKISP1_FMT_RGB, + .write_format = RKISP1_MI_CTRL_SP_WRITE_PLA, + .output_format = RKISP1_MI_CTRL_SP_OUTPUT_RGB666, + }, +}; + +static const struct rkisp1_capture_config rkisp1_capture_config_mp = { + .fmts = rkisp1_mp_fmts, + .fmt_size = ARRAY_SIZE(rkisp1_mp_fmts), + .mi = { + .y_size_init = RKISP1_CIF_MI_MP_Y_SIZE_INIT, + .cb_size_init = RKISP1_CIF_MI_MP_CB_SIZE_INIT, + .cr_size_init = RKISP1_CIF_MI_MP_CR_SIZE_INIT, + .y_base_ad_init = RKISP1_CIF_MI_MP_Y_BASE_AD_INIT, + .cb_base_ad_init = RKISP1_CIF_MI_MP_CB_BASE_AD_INIT, + .cr_base_ad_init = RKISP1_CIF_MI_MP_CR_BASE_AD_INIT, + .y_offs_cnt_init = RKISP1_CIF_MI_MP_Y_OFFS_CNT_INIT, + .cb_offs_cnt_init = RKISP1_CIF_MI_MP_CB_OFFS_CNT_INIT, + .cr_offs_cnt_init = RKISP1_CIF_MI_MP_CR_OFFS_CNT_INIT, + }, +}; + +static const struct rkisp1_capture_config rkisp1_capture_config_sp = { + .fmts = rkisp1_sp_fmts, + .fmt_size = ARRAY_SIZE(rkisp1_sp_fmts), + .mi = { + .y_size_init = RKISP1_CIF_MI_SP_Y_SIZE_INIT, + .cb_size_init = RKISP1_CIF_MI_SP_CB_SIZE_INIT, + .cr_size_init = RKISP1_CIF_MI_SP_CR_SIZE_INIT, + .y_base_ad_init = RKISP1_CIF_MI_SP_Y_BASE_AD_INIT, + .cb_base_ad_init = RKISP1_CIF_MI_SP_CB_BASE_AD_INIT, + .cr_base_ad_init = RKISP1_CIF_MI_SP_CR_BASE_AD_INIT, + .y_offs_cnt_init = RKISP1_CIF_MI_SP_Y_OFFS_CNT_INIT, + .cb_offs_cnt_init = RKISP1_CIF_MI_SP_CB_OFFS_CNT_INIT, + .cr_offs_cnt_init = RKISP1_CIF_MI_SP_CR_OFFS_CNT_INIT, + }, +}; + +static inline struct rkisp1_vdev_node * +rkisp1_vdev_to_node(struct video_device *vdev) +{ + return container_of(vdev, struct rkisp1_vdev_node, vdev); +} + +/* ---------------------------------------------------------------------------- + * Stream operations for self-picture path (sp) and main-picture path (mp) + */ + +static void rkisp1_mi_config_ctrl(struct rkisp1_capture *cap) +{ + u32 mi_ctrl = rkisp1_read(cap->rkisp1, RKISP1_CIF_MI_CTRL); + + mi_ctrl &= ~GENMASK(17, 16); + mi_ctrl |= RKISP1_CIF_MI_CTRL_BURST_LEN_LUM_64; + + mi_ctrl &= ~GENMASK(19, 18); + mi_ctrl |= RKISP1_CIF_MI_CTRL_BURST_LEN_CHROM_64; + + mi_ctrl |= RKISP1_CIF_MI_CTRL_INIT_BASE_EN | + RKISP1_CIF_MI_CTRL_INIT_OFFSET_EN; + + rkisp1_write(cap->rkisp1, mi_ctrl, RKISP1_CIF_MI_CTRL); +} + +static u32 rkisp1_pixfmt_comp_size(const struct v4l2_pix_format_mplane *pixm, + unsigned int component) +{ + /* + * If packed format, then plane_fmt[0].sizeimage is the sum of all + * components, so we need to calculate just the size of Y component. + * See rkisp1_fill_pixfmt(). + */ + if (!component && pixm->num_planes == 1) + return pixm->plane_fmt[0].bytesperline * pixm->height; + return pixm->plane_fmt[component].sizeimage; +} + +static void rkisp1_irq_frame_end_enable(struct rkisp1_capture *cap) +{ + u32 mi_imsc = rkisp1_read(cap->rkisp1, RKISP1_CIF_MI_IMSC); + + mi_imsc |= RKISP1_CIF_MI_FRAME(cap); + rkisp1_write(cap->rkisp1, mi_imsc, RKISP1_CIF_MI_IMSC); +} + +static void rkisp1_mp_config(struct rkisp1_capture *cap) +{ + const struct v4l2_pix_format_mplane *pixm = &cap->pix.fmt; + struct rkisp1_device *rkisp1 = cap->rkisp1; + u32 reg; + + rkisp1_write(rkisp1, rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_Y), + cap->config->mi.y_size_init); + rkisp1_write(rkisp1, rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_CB), + cap->config->mi.cb_size_init); + rkisp1_write(rkisp1, rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_CR), + cap->config->mi.cr_size_init); + + rkisp1_irq_frame_end_enable(cap); + if (cap->pix.cfg->uv_swap) { + reg = rkisp1_read(rkisp1, RKISP1_CIF_MI_XTD_FORMAT_CTRL); + + reg = (reg & ~BIT(0)) | + RKISP1_CIF_MI_XTD_FMT_CTRL_MP_CB_CR_SWAP; + rkisp1_write(rkisp1, reg, RKISP1_CIF_MI_XTD_FORMAT_CTRL); + } + + rkisp1_mi_config_ctrl(cap); + + reg = rkisp1_read(rkisp1, RKISP1_CIF_MI_CTRL); + reg &= ~RKISP1_MI_CTRL_MP_FMT_MASK; + reg |= cap->pix.cfg->write_format; + rkisp1_write(rkisp1, reg, RKISP1_CIF_MI_CTRL); + + reg = rkisp1_read(rkisp1, RKISP1_CIF_MI_CTRL); + reg |= RKISP1_CIF_MI_MP_AUTOUPDATE_ENABLE; + rkisp1_write(rkisp1, reg, RKISP1_CIF_MI_CTRL); +} + +static void rkisp1_sp_config(struct rkisp1_capture *cap) +{ + const struct v4l2_pix_format_mplane *pixm = &cap->pix.fmt; + struct rkisp1_device *rkisp1 = cap->rkisp1; + u32 mi_ctrl; + + rkisp1_write(rkisp1, rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_Y), + cap->config->mi.y_size_init); + rkisp1_write(rkisp1, rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_CB), + cap->config->mi.cb_size_init); + rkisp1_write(rkisp1, rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_CR), + cap->config->mi.cr_size_init); + + rkisp1_write(rkisp1, pixm->width, RKISP1_CIF_MI_SP_Y_PIC_WIDTH); + rkisp1_write(rkisp1, pixm->height, RKISP1_CIF_MI_SP_Y_PIC_HEIGHT); + rkisp1_write(rkisp1, cap->sp_y_stride, RKISP1_CIF_MI_SP_Y_LLENGTH); + + rkisp1_irq_frame_end_enable(cap); + if (cap->pix.cfg->uv_swap) { + u32 reg = rkisp1_read(rkisp1, RKISP1_CIF_MI_XTD_FORMAT_CTRL); + + rkisp1_write(rkisp1, reg & ~BIT(1), + RKISP1_CIF_MI_XTD_FORMAT_CTRL); + } + + rkisp1_mi_config_ctrl(cap); + + mi_ctrl = rkisp1_read(rkisp1, RKISP1_CIF_MI_CTRL); + mi_ctrl &= ~RKISP1_MI_CTRL_SP_FMT_MASK; + mi_ctrl |= cap->pix.cfg->write_format | + RKISP1_MI_CTRL_SP_INPUT_YUV422 | + cap->pix.cfg->output_format | + RKISP1_CIF_MI_SP_AUTOUPDATE_ENABLE; + rkisp1_write(rkisp1, mi_ctrl, RKISP1_CIF_MI_CTRL); +} + +static void rkisp1_mp_disable(struct rkisp1_capture *cap) +{ + u32 mi_ctrl = rkisp1_read(cap->rkisp1, RKISP1_CIF_MI_CTRL); + + mi_ctrl &= ~(RKISP1_CIF_MI_CTRL_MP_ENABLE | + RKISP1_CIF_MI_CTRL_RAW_ENABLE); + rkisp1_write(cap->rkisp1, mi_ctrl, RKISP1_CIF_MI_CTRL); +} + +static void rkisp1_sp_disable(struct rkisp1_capture *cap) +{ + u32 mi_ctrl = rkisp1_read(cap->rkisp1, RKISP1_CIF_MI_CTRL); + + mi_ctrl &= ~RKISP1_CIF_MI_CTRL_SP_ENABLE; + rkisp1_write(cap->rkisp1, mi_ctrl, RKISP1_CIF_MI_CTRL); +} + +static void rkisp1_mp_enable(struct rkisp1_capture *cap) +{ + const struct rkisp1_capture_fmt_cfg *isp_fmt = cap->pix.cfg; + u32 mi_ctrl; + + rkisp1_mp_disable(cap); + + mi_ctrl = rkisp1_read(cap->rkisp1, RKISP1_CIF_MI_CTRL); + if (isp_fmt->fmt_type == RKISP1_FMT_BAYER) + mi_ctrl |= RKISP1_CIF_MI_CTRL_RAW_ENABLE; + /* YUV */ + else + mi_ctrl |= RKISP1_CIF_MI_CTRL_MP_ENABLE; + + rkisp1_write(cap->rkisp1, mi_ctrl, RKISP1_CIF_MI_CTRL); +} + +static void rkisp1_sp_enable(struct rkisp1_capture *cap) +{ + u32 mi_ctrl = rkisp1_read(cap->rkisp1, RKISP1_CIF_MI_CTRL); + + mi_ctrl |= RKISP1_CIF_MI_CTRL_SP_ENABLE; + rkisp1_write(cap->rkisp1, mi_ctrl, RKISP1_CIF_MI_CTRL); +} + +static void rkisp1_mp_sp_stop(struct rkisp1_capture *cap) +{ + if (!cap->is_streaming) + return; + rkisp1_write(cap->rkisp1, + RKISP1_CIF_MI_FRAME(cap), RKISP1_CIF_MI_ICR); + cap->ops->disable(cap); +} + +static bool rkisp1_mp_is_stopped(struct rkisp1_capture *cap) +{ + u32 en = RKISP1_CIF_MI_CTRL_SHD_MP_IN_ENABLED | + RKISP1_CIF_MI_CTRL_SHD_RAW_OUT_ENABLED; + + return !(rkisp1_read(cap->rkisp1, RKISP1_CIF_MI_CTRL_SHD) & en); +} + +static bool rkisp1_sp_is_stopped(struct rkisp1_capture *cap) +{ + return !(rkisp1_read(cap->rkisp1, RKISP1_CIF_MI_CTRL_SHD) & + RKISP1_CIF_MI_CTRL_SHD_SP_IN_ENABLED); +} + +static void rkisp1_mp_set_data_path(struct rkisp1_capture *cap) +{ + u32 dpcl = rkisp1_read(cap->rkisp1, RKISP1_CIF_VI_DPCL); + + dpcl = dpcl | RKISP1_CIF_VI_DPCL_CHAN_MODE_MP | + RKISP1_CIF_VI_DPCL_MP_MUX_MRSZ_MI; + rkisp1_write(cap->rkisp1, dpcl, RKISP1_CIF_VI_DPCL); +} + +static void rkisp1_sp_set_data_path(struct rkisp1_capture *cap) +{ + u32 dpcl = rkisp1_read(cap->rkisp1, RKISP1_CIF_VI_DPCL); + + dpcl |= RKISP1_CIF_VI_DPCL_CHAN_MODE_SP; + rkisp1_write(cap->rkisp1, dpcl, RKISP1_CIF_VI_DPCL); +} + +static struct rkisp1_capture_ops rkisp1_capture_ops_mp = { + .config = rkisp1_mp_config, + .enable = rkisp1_mp_enable, + .disable = rkisp1_mp_disable, + .stop = rkisp1_mp_sp_stop, + .set_data_path = rkisp1_mp_set_data_path, + .is_stopped = rkisp1_mp_is_stopped, +}; + +static struct rkisp1_capture_ops rkisp1_capture_ops_sp = { + .config = rkisp1_sp_config, + .enable = rkisp1_sp_enable, + .disable = rkisp1_sp_disable, + .stop = rkisp1_mp_sp_stop, + .set_data_path = rkisp1_sp_set_data_path, + .is_stopped = rkisp1_sp_is_stopped, +}; + +/* ---------------------------------------------------------------------------- + * Frame buffer operations + */ + +static int rkisp1_dummy_buf_create(struct rkisp1_capture *cap) +{ + const struct v4l2_pix_format_mplane *pixm = &cap->pix.fmt; + struct rkisp1_dummy_buffer *dummy_buf = &cap->buf.dummy; + + dummy_buf->size = max3(rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_Y), + rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_CB), + rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_CR)); + + /* The driver never access vaddr, no mapping is required */ + dummy_buf->vaddr = dma_alloc_attrs(cap->rkisp1->dev, + dummy_buf->size, + &dummy_buf->dma_addr, + GFP_KERNEL, + DMA_ATTR_NO_KERNEL_MAPPING); + if (!dummy_buf->vaddr) + return -ENOMEM; + + return 0; +} + +static void rkisp1_dummy_buf_destroy(struct rkisp1_capture *cap) +{ + dma_free_attrs(cap->rkisp1->dev, + cap->buf.dummy.size, cap->buf.dummy.vaddr, + cap->buf.dummy.dma_addr, DMA_ATTR_NO_KERNEL_MAPPING); +} + +static void rkisp1_set_next_buf(struct rkisp1_capture *cap) +{ + /* + * Use the dummy space allocated by dma_alloc_coherent to + * throw data if there is no available buffer. + */ + if (cap->buf.next) { + u32 *buff_addr = cap->buf.next->buff_addr; + + rkisp1_write(cap->rkisp1, + buff_addr[RKISP1_PLANE_Y], + cap->config->mi.y_base_ad_init); + rkisp1_write(cap->rkisp1, + buff_addr[RKISP1_PLANE_CB], + cap->config->mi.cb_base_ad_init); + rkisp1_write(cap->rkisp1, + buff_addr[RKISP1_PLANE_CR], + cap->config->mi.cr_base_ad_init); + } else { + rkisp1_write(cap->rkisp1, + cap->buf.dummy.dma_addr, + cap->config->mi.y_base_ad_init); + rkisp1_write(cap->rkisp1, + cap->buf.dummy.dma_addr, + cap->config->mi.cb_base_ad_init); + rkisp1_write(cap->rkisp1, + cap->buf.dummy.dma_addr, + cap->config->mi.cr_base_ad_init); + } + + /* Set plane offsets */ + rkisp1_write(cap->rkisp1, 0, cap->config->mi.y_offs_cnt_init); + rkisp1_write(cap->rkisp1, 0, cap->config->mi.cb_offs_cnt_init); + rkisp1_write(cap->rkisp1, 0, cap->config->mi.cr_offs_cnt_init); +} + +/* + * This function is called when a frame end comes. The next frame + * is processing and we should set up buffer for next-next frame, + * otherwise it will overflow. + */ +static void rkisp1_handle_buffer(struct rkisp1_capture *cap) +{ + struct rkisp1_isp *isp = &cap->rkisp1->isp; + struct rkisp1_buffer *curr_buf = cap->buf.curr; + unsigned long flags; + + spin_lock_irqsave(&cap->buf.lock, flags); + + if (curr_buf) { + curr_buf->vb.sequence = atomic_read(&isp->frame_sequence); + curr_buf->vb.vb2_buf.timestamp = ktime_get_boottime_ns(); + curr_buf->vb.field = V4L2_FIELD_NONE; + vb2_buffer_done(&curr_buf->vb.vb2_buf, VB2_BUF_STATE_DONE); + } else { + cap->rkisp1->debug.frame_drop[cap->id]++; + } + + cap->buf.curr = cap->buf.next; + cap->buf.next = NULL; + + if (!list_empty(&cap->buf.queue)) { + cap->buf.next = list_first_entry(&cap->buf.queue, + struct rkisp1_buffer, + queue); + list_del(&cap->buf.next->queue); + } + spin_unlock_irqrestore(&cap->buf.lock, flags); + + rkisp1_set_next_buf(cap); +} + +void rkisp1_capture_isr(struct rkisp1_device *rkisp1) +{ + unsigned int i; + u32 status; + + status = rkisp1_read(rkisp1, RKISP1_CIF_MI_MIS); + rkisp1_write(rkisp1, status, RKISP1_CIF_MI_ICR); + + for (i = 0; i < ARRAY_SIZE(rkisp1->capture_devs); ++i) { + struct rkisp1_capture *cap = &rkisp1->capture_devs[i]; + + if (!(status & RKISP1_CIF_MI_FRAME(cap))) + continue; + if (!cap->is_stopping) { + rkisp1_handle_buffer(cap); + continue; + } + /* + * Make sure stream is actually stopped, whose state + * can be read from the shadow register, before + * wake_up() thread which would immediately free all + * frame buffers. stop() takes effect at the next + * frame end that sync the configurations to shadow + * regs. + */ + if (!cap->ops->is_stopped(cap)) { + cap->ops->stop(cap); + continue; + } + cap->is_stopping = false; + cap->is_streaming = false; + wake_up(&cap->done); + } +} + +/* ---------------------------------------------------------------------------- + * Vb2 operations + */ + +static int rkisp1_vb2_queue_setup(struct vb2_queue *queue, + unsigned int *num_buffers, + unsigned int *num_planes, + unsigned int sizes[], + struct device *alloc_devs[]) +{ + struct rkisp1_capture *cap = queue->drv_priv; + const struct v4l2_pix_format_mplane *pixm = &cap->pix.fmt; + unsigned int i; + + if (*num_planes) { + if (*num_planes != pixm->num_planes) + return -EINVAL; + + for (i = 0; i < pixm->num_planes; i++) + if (sizes[i] < pixm->plane_fmt[i].sizeimage) + return -EINVAL; + } else { + *num_planes = pixm->num_planes; + for (i = 0; i < pixm->num_planes; i++) + sizes[i] = pixm->plane_fmt[i].sizeimage; + } + + return 0; +} + +static void rkisp1_vb2_buf_queue(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct rkisp1_buffer *ispbuf = + container_of(vbuf, struct rkisp1_buffer, vb); + struct rkisp1_capture *cap = vb->vb2_queue->drv_priv; + const struct v4l2_pix_format_mplane *pixm = &cap->pix.fmt; + unsigned long flags; + unsigned int i; + + memset(ispbuf->buff_addr, 0, sizeof(ispbuf->buff_addr)); + for (i = 0; i < pixm->num_planes; i++) + ispbuf->buff_addr[i] = vb2_dma_contig_plane_dma_addr(vb, i); + + /* Convert to non-MPLANE */ + if (pixm->num_planes == 1) { + ispbuf->buff_addr[RKISP1_PLANE_CB] = + ispbuf->buff_addr[RKISP1_PLANE_Y] + + rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_Y); + ispbuf->buff_addr[RKISP1_PLANE_CR] = + ispbuf->buff_addr[RKISP1_PLANE_CB] + + rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_CB); + } + + spin_lock_irqsave(&cap->buf.lock, flags); + + /* + * If there's no next buffer assigned, queue this buffer directly + * as the next buffer, and update the memory interface. + */ + if (cap->is_streaming && !cap->buf.next && + atomic_read(&cap->rkisp1->isp.frame_sequence) == -1) { + cap->buf.next = ispbuf; + rkisp1_set_next_buf(cap); + } else { + list_add_tail(&ispbuf->queue, &cap->buf.queue); + } + spin_unlock_irqrestore(&cap->buf.lock, flags); +} + +static int rkisp1_vb2_buf_prepare(struct vb2_buffer *vb) +{ + struct rkisp1_capture *cap = vb->vb2_queue->drv_priv; + unsigned int i; + + for (i = 0; i < cap->pix.fmt.num_planes; i++) { + unsigned long size = cap->pix.fmt.plane_fmt[i].sizeimage; + + if (vb2_plane_size(vb, i) < size) { + dev_err(cap->rkisp1->dev, + "User buffer too small (%ld < %ld)\n", + vb2_plane_size(vb, i), size); + return -EINVAL; + } + vb2_set_plane_payload(vb, i, size); + } + + return 0; +} + +static void rkisp1_return_all_buffers(struct rkisp1_capture *cap, + enum vb2_buffer_state state) +{ + unsigned long flags; + struct rkisp1_buffer *buf; + + spin_lock_irqsave(&cap->buf.lock, flags); + if (cap->buf.curr) { + vb2_buffer_done(&cap->buf.curr->vb.vb2_buf, state); + cap->buf.curr = NULL; + } + if (cap->buf.next) { + vb2_buffer_done(&cap->buf.next->vb.vb2_buf, state); + cap->buf.next = NULL; + } + while (!list_empty(&cap->buf.queue)) { + buf = list_first_entry(&cap->buf.queue, + struct rkisp1_buffer, queue); + list_del(&buf->queue); + vb2_buffer_done(&buf->vb.vb2_buf, state); + } + spin_unlock_irqrestore(&cap->buf.lock, flags); +} + +/* + * rkisp1_pipeline_sink_walk - Walk through the pipeline and call cb + * @from: entity at which to start pipeline walk + * @until: entity at which to stop pipeline walk + * + * Walk the entities chain starting at the pipeline video node and stop + * all subdevices in the chain. + * + * If the until argument isn't NULL, stop the pipeline walk when reaching the + * until entity. This is used to disable a partially started pipeline due to a + * subdev start error. + */ +static int rkisp1_pipeline_sink_walk(struct media_entity *from, + struct media_entity *until, + int (*cb)(struct media_entity *from, + struct media_entity *curr)) +{ + struct media_entity *entity = from; + struct media_pad *pad; + unsigned int i; + int ret; + + while (1) { + pad = NULL; + /* Find remote source pad */ + for (i = 0; i < entity->num_pads; i++) { + struct media_pad *spad = &entity->pads[i]; + + if (!(spad->flags & MEDIA_PAD_FL_SINK)) + continue; + pad = media_entity_remote_pad(spad); + if (pad && is_media_entity_v4l2_subdev(pad->entity)) + break; + } + if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) + break; + + entity = pad->entity; + if (entity == until) + break; + + ret = cb(from, entity); + if (ret) + return ret; + } + + return 0; +} + +static int rkisp1_pipeline_disable_cb(struct media_entity *from, + struct media_entity *curr) +{ + struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(curr); + + return v4l2_subdev_call(sd, video, s_stream, false); +} + +static int rkisp1_pipeline_enable_cb(struct media_entity *from, + struct media_entity *curr) +{ + struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(curr); + + return v4l2_subdev_call(sd, video, s_stream, true); +} + +static void rkisp1_stream_stop(struct rkisp1_capture *cap) +{ + int ret; + + /* Stream should stop in interrupt. If it dosn't, stop it by force. */ + cap->is_stopping = true; + ret = wait_event_timeout(cap->done, + !cap->is_streaming, + msecs_to_jiffies(1000)); + if (!ret) { + cap->rkisp1->debug.stop_timeout[cap->id]++; + cap->ops->stop(cap); + cap->is_stopping = false; + cap->is_streaming = false; + } +} + +static void rkisp1_vb2_stop_streaming(struct vb2_queue *queue) +{ + struct rkisp1_capture *cap = queue->drv_priv; + struct rkisp1_vdev_node *node = &cap->vnode; + struct rkisp1_device *rkisp1 = cap->rkisp1; + int ret; + + rkisp1_stream_stop(cap); + media_pipeline_stop(&node->vdev.entity); + ret = rkisp1_pipeline_sink_walk(&node->vdev.entity, NULL, + rkisp1_pipeline_disable_cb); + if (ret) + dev_err(rkisp1->dev, + "pipeline stream-off failed error:%d\n", ret); + + rkisp1_return_all_buffers(cap, VB2_BUF_STATE_ERROR); + + ret = v4l2_pipeline_pm_use(&node->vdev.entity, 0); + if (ret) + dev_err(rkisp1->dev, "pipeline close failed error:%d\n", ret); + + ret = pm_runtime_put(rkisp1->dev); + if (ret) + dev_err(rkisp1->dev, "power down failed error:%d\n", ret); + + rkisp1_dummy_buf_destroy(cap); +} + +/* + * Most of registers inside rockchip ISP1 have shadow register since + * they must be not be changed during processing a frame. + * Usually, each sub-module updates its shadow register after + * processing the last pixel of a frame. + */ +static void rkisp1_stream_start(struct rkisp1_capture *cap) +{ + struct rkisp1_device *rkisp1 = cap->rkisp1; + struct rkisp1_capture *other = &rkisp1->capture_devs[cap->id ^ 1]; + + cap->ops->set_data_path(cap); + cap->ops->config(cap); + + /* Setup a buffer for the next frame */ + rkisp1_handle_buffer(cap); + cap->ops->enable(cap); + /* It's safe to config ACTIVE and SHADOW regs for the + * first stream. While when the second is starting, do NOT + * force update because it also update the first one. + * + * The latter case would drop one more buf(that is 2) since + * there's not buf in shadow when the second FE received. This's + * also required because the second FE maybe corrupt especially + * when run at 120fps. + */ + if (!other->is_streaming) { + /* force cfg update */ + rkisp1_write(rkisp1, + RKISP1_CIF_MI_INIT_SOFT_UPD, RKISP1_CIF_MI_INIT); + rkisp1_handle_buffer(cap); + } + cap->is_streaming = true; +} + +static int +rkisp1_vb2_start_streaming(struct vb2_queue *queue, unsigned int count) +{ + struct rkisp1_capture *cap = queue->drv_priv; + struct media_entity *entity = &cap->vnode.vdev.entity; + int ret; + + ret = rkisp1_dummy_buf_create(cap); + if (ret) + goto err_ret_buffers; + + ret = pm_runtime_get_sync(cap->rkisp1->dev); + if (ret) { + dev_err(cap->rkisp1->dev, "power up failed %d\n", ret); + goto err_destroy_dummy; + } + ret = v4l2_pipeline_pm_use(entity, 1); + if (ret) { + dev_err(cap->rkisp1->dev, "open cif pipeline failed %d\n", ret); + goto err_pipe_pm_put; + } + + rkisp1_stream_start(cap); + + /* start sub-devices */ + ret = rkisp1_pipeline_sink_walk(entity, NULL, + rkisp1_pipeline_enable_cb); + if (ret) + goto err_stop_stream; + + ret = media_pipeline_start(entity, &cap->rkisp1->pipe); + if (ret) { + dev_err(cap->rkisp1->dev, "start pipeline failed %d\n", ret); + goto err_pipe_disable; + } + + return 0; + +err_pipe_disable: + rkisp1_pipeline_sink_walk(entity, NULL, rkisp1_pipeline_disable_cb); +err_stop_stream: + rkisp1_stream_stop(cap); + v4l2_pipeline_pm_use(entity, 0); +err_pipe_pm_put: + pm_runtime_put(cap->rkisp1->dev); +err_destroy_dummy: + rkisp1_dummy_buf_destroy(cap); +err_ret_buffers: + rkisp1_return_all_buffers(cap, VB2_BUF_STATE_QUEUED); + + return ret; +} + +static struct vb2_ops rkisp1_vb2_ops = { + .queue_setup = rkisp1_vb2_queue_setup, + .buf_queue = rkisp1_vb2_buf_queue, + .buf_prepare = rkisp1_vb2_buf_prepare, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, + .stop_streaming = rkisp1_vb2_stop_streaming, + .start_streaming = rkisp1_vb2_start_streaming, +}; + +/* ---------------------------------------------------------------------------- + * IOCTLs operations + */ + +static const struct v4l2_format_info * +rkisp1_fill_pixfmt(struct v4l2_pix_format_mplane *pixm, + enum rkisp1_stream_id id) +{ + struct v4l2_plane_pix_format *plane_y = &pixm->plane_fmt[0]; + const struct v4l2_format_info *info; + unsigned int i; + u32 stride; + + info = v4l2_format_info(pixm->pixelformat); + pixm->num_planes = info->mem_planes; + stride = info->bpp[0] * pixm->width; + /* Self path supports custom stride but Main path doesn't */ + if (id == RKISP1_MAINPATH || plane_y->bytesperline < stride) + plane_y->bytesperline = stride; + plane_y->sizeimage = plane_y->bytesperline * pixm->height; + + /* normalize stride to pixels per line */ + stride = DIV_ROUND_UP(plane_y->bytesperline, info->bpp[0]); + + for (i = 1; i < info->comp_planes; i++) { + struct v4l2_plane_pix_format *plane = &pixm->plane_fmt[i]; + + /* bytesperline for other components derive from Y component */ + plane->bytesperline = DIV_ROUND_UP(stride, info->hdiv) * + info->bpp[i]; + plane->sizeimage = plane->bytesperline * + DIV_ROUND_UP(pixm->height, info->vdiv); + } + + /* + * If pixfmt is packed, then plane_fmt[0] should contain the total size + * considering all components. plane_fmt[i] for i > 0 should be ignored + * by userspace as mem_planes == 1, but we are keeping information there + * for convenience. + */ + if (info->mem_planes == 1) + for (i = 1; i < info->comp_planes; i++) + plane_y->sizeimage += pixm->plane_fmt[i].sizeimage; + + return info; +} + +static const struct rkisp1_capture_fmt_cfg * +rkisp1_find_fmt_cfg(const struct rkisp1_capture *cap, const u32 pixelfmt) +{ + unsigned int i; + + for (i = 0; i < cap->config->fmt_size; i++) { + if (cap->config->fmts[i].fourcc == pixelfmt) + return &cap->config->fmts[i]; + } + return NULL; +} + +static void rkisp1_try_fmt(const struct rkisp1_capture *cap, + struct v4l2_pix_format_mplane *pixm, + const struct rkisp1_capture_fmt_cfg **fmt_cfg, + const struct v4l2_format_info **fmt_info) +{ + const struct rkisp1_capture_config *config = cap->config; + struct rkisp1_capture *other_cap = + &cap->rkisp1->capture_devs[cap->id ^ 1]; + const struct rkisp1_capture_fmt_cfg *fmt; + const struct v4l2_format_info *info; + const unsigned int max_widths[] = { RKISP1_RSZ_MP_SRC_MAX_WIDTH, + RKISP1_RSZ_SP_SRC_MAX_WIDTH }; + const unsigned int max_heights[] = { RKISP1_RSZ_MP_SRC_MAX_HEIGHT, + RKISP1_RSZ_SP_SRC_MAX_HEIGHT}; + + fmt = rkisp1_find_fmt_cfg(cap, pixm->pixelformat); + if (!fmt) { + fmt = config->fmts; + pixm->pixelformat = fmt->fourcc; + } + + pixm->width = clamp_t(u32, pixm->width, + RKISP1_RSZ_SRC_MIN_WIDTH, max_widths[cap->id]); + pixm->height = clamp_t(u32, pixm->height, + RKISP1_RSZ_SRC_MIN_HEIGHT, max_heights[cap->id]); + + pixm->field = V4L2_FIELD_NONE; + pixm->colorspace = V4L2_COLORSPACE_DEFAULT; + pixm->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; + + info = rkisp1_fill_pixfmt(pixm, cap->id); + + /* can not change quantization when stream-on */ + if (other_cap->is_streaming) + pixm->quantization = other_cap->pix.fmt.quantization; + /* output full range by default, take effect in params */ + else if (!pixm->quantization || + pixm->quantization > V4L2_QUANTIZATION_LIM_RANGE) + pixm->quantization = V4L2_QUANTIZATION_FULL_RANGE; + + if (fmt_cfg) + *fmt_cfg = fmt; + if (fmt_info) + *fmt_info = info; +} + +static void rkisp1_set_fmt(struct rkisp1_capture *cap, + struct v4l2_pix_format_mplane *pixm) +{ + rkisp1_try_fmt(cap, pixm, &cap->pix.cfg, &cap->pix.info); + cap->pix.fmt = *pixm; + + /* SP supports custom stride in number of pixels of the Y plane */ + if (cap->id == RKISP1_SELFPATH) + cap->sp_y_stride = pixm->plane_fmt[0].bytesperline / + cap->pix.info->bpp[0]; +} + +static int rkisp1_try_fmt_vid_cap_mplane(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct rkisp1_capture *cap = video_drvdata(file); + + rkisp1_try_fmt(cap, &f->fmt.pix_mp, NULL, NULL); + + return 0; +} + +static int rkisp1_enum_fmt_vid_cap_mplane(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + struct rkisp1_capture *cap = video_drvdata(file); + const struct rkisp1_capture_fmt_cfg *fmt = NULL; + + if (f->index >= cap->config->fmt_size) + return -EINVAL; + + fmt = &cap->config->fmts[f->index]; + f->pixelformat = fmt->fourcc; + + return 0; +} + +static int rkisp1_s_fmt_vid_cap_mplane(struct file *file, + void *priv, struct v4l2_format *f) +{ + struct rkisp1_capture *cap = video_drvdata(file); + struct rkisp1_vdev_node *node = + rkisp1_vdev_to_node(&cap->vnode.vdev); + + if (vb2_is_busy(&node->buf_queue)) + return -EBUSY; + + rkisp1_set_fmt(cap, &f->fmt.pix_mp); + + return 0; +} + +static int rkisp1_g_fmt_vid_cap_mplane(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct rkisp1_capture *cap = video_drvdata(file); + + f->fmt.pix_mp = cap->pix.fmt; + + return 0; +} + +static int +rkisp1_querycap(struct file *file, void *priv, struct v4l2_capability *cap) +{ + struct rkisp1_capture *cap_dev = video_drvdata(file); + struct rkisp1_device *rkisp1 = cap_dev->rkisp1; + + strscpy(cap->driver, rkisp1->dev->driver->name, sizeof(cap->driver)); + strscpy(cap->card, rkisp1->dev->driver->name, sizeof(cap->card)); + strscpy(cap->bus_info, RKISP1_BUS_INFO, sizeof(cap->bus_info)); + + return 0; +} + +static const struct v4l2_ioctl_ops rkisp1_v4l2_ioctl_ops = { + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_expbuf = vb2_ioctl_expbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, + .vidioc_try_fmt_vid_cap_mplane = rkisp1_try_fmt_vid_cap_mplane, + .vidioc_s_fmt_vid_cap_mplane = rkisp1_s_fmt_vid_cap_mplane, + .vidioc_g_fmt_vid_cap_mplane = rkisp1_g_fmt_vid_cap_mplane, + .vidioc_enum_fmt_vid_cap = rkisp1_enum_fmt_vid_cap_mplane, + .vidioc_querycap = rkisp1_querycap, + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, +}; + +static int rkisp1_capture_link_validate(struct media_link *link) +{ + struct video_device *vdev = + media_entity_to_video_device(link->sink->entity); + struct v4l2_subdev *sd = + media_entity_to_v4l2_subdev(link->source->entity); + struct rkisp1_capture *cap = video_get_drvdata(vdev); + struct rkisp1_isp *isp = &cap->rkisp1->isp; + struct v4l2_subdev_format sd_fmt; + int ret; + + if (cap->id == RKISP1_SELFPATH && + isp->src_fmt->mbus_code != MEDIA_BUS_FMT_YUYV8_2X8) { + dev_err(cap->rkisp1->dev, + "selfpath only supports MEDIA_BUS_FMT_YUYV8_2X8\n"); + return -EPIPE; + } + + if (cap->pix.cfg->fmt_type != isp->src_fmt->fmt_type) { + dev_err(cap->rkisp1->dev, + "format type mismatch in link '%s:%d->%s:%d'\n", + link->source->entity->name, link->source->index, + link->sink->entity->name, link->sink->index); + return -EPIPE; + } + + sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; + sd_fmt.pad = link->source->index; + ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &sd_fmt); + if (ret) + return ret; + + if (sd_fmt.format.height != cap->pix.fmt.height || + sd_fmt.format.width != cap->pix.fmt.width) + return -EPIPE; + + return 0; +} + +/* ---------------------------------------------------------------------------- + * core functions + */ + +static const struct media_entity_operations rkisp1_media_ops = { + .link_validate = rkisp1_capture_link_validate, +}; + +static const struct v4l2_file_operations rkisp1_fops = { + .open = v4l2_fh_open, + .release = vb2_fop_release, + .unlocked_ioctl = video_ioctl2, + .poll = vb2_fop_poll, + .mmap = vb2_fop_mmap, +}; + +static void rkisp1_unregister_capture(struct rkisp1_capture *cap) +{ + media_entity_cleanup(&cap->vnode.vdev.entity); + video_unregister_device(&cap->vnode.vdev); +} + +void rkisp1_capture_devs_unregister(struct rkisp1_device *rkisp1) +{ + struct rkisp1_capture *mp = &rkisp1->capture_devs[RKISP1_MAINPATH]; + struct rkisp1_capture *sp = &rkisp1->capture_devs[RKISP1_SELFPATH]; + + rkisp1_unregister_capture(mp); + rkisp1_unregister_capture(sp); +} + +static int rkisp1_register_capture(struct rkisp1_capture *cap) +{ + const char * const dev_names[] = {RKISP1_MP_DEV_NAME, + RKISP1_SP_DEV_NAME}; + struct v4l2_device *v4l2_dev = &cap->rkisp1->v4l2_dev; + struct video_device *vdev = &cap->vnode.vdev; + struct rkisp1_vdev_node *node; + struct vb2_queue *q; + int ret; + + strscpy(vdev->name, dev_names[cap->id], sizeof(vdev->name)); + node = rkisp1_vdev_to_node(vdev); + mutex_init(&node->vlock); + + vdev->ioctl_ops = &rkisp1_v4l2_ioctl_ops; + vdev->release = video_device_release_empty; + vdev->fops = &rkisp1_fops; + vdev->minor = -1; + vdev->v4l2_dev = v4l2_dev; + vdev->lock = &node->vlock; + vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE_MPLANE | + V4L2_CAP_STREAMING; + vdev->entity.ops = &rkisp1_media_ops; + video_set_drvdata(vdev, cap); + vdev->vfl_dir = VFL_DIR_RX; + node->pad.flags = MEDIA_PAD_FL_SINK; + + q = &node->buf_queue; + q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + q->io_modes = VB2_MMAP | VB2_DMABUF | VB2_USERPTR; + q->drv_priv = cap; + q->ops = &rkisp1_vb2_ops; + q->mem_ops = &vb2_dma_contig_memops; + q->buf_struct_size = sizeof(struct rkisp1_buffer); + q->min_buffers_needed = RKISP1_MIN_BUFFERS_NEEDED; + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->lock = &node->vlock; + q->dev = cap->rkisp1->dev; + ret = vb2_queue_init(q); + if (ret) { + dev_err(cap->rkisp1->dev, + "vb2 queue init failed (err=%d)\n", ret); + return ret; + } + + vdev->queue = q; + + ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1); + if (ret) { + dev_err(cap->rkisp1->dev, + "failed to register %s, ret=%d\n", vdev->name, ret); + return ret; + } + v4l2_info(v4l2_dev, "registered %s as /dev/video%d\n", vdev->name, + vdev->num); + + ret = media_entity_pads_init(&vdev->entity, 1, &node->pad); + if (ret) { + video_unregister_device(vdev); + return ret; + } + + return 0; +} + +static void +rkisp1_capture_init(struct rkisp1_device *rkisp1, enum rkisp1_stream_id id) +{ + struct rkisp1_capture *cap = &rkisp1->capture_devs[id]; + struct v4l2_pix_format_mplane pixm; + + memset(cap, 0, sizeof(*cap)); + cap->id = id; + cap->rkisp1 = rkisp1; + + INIT_LIST_HEAD(&cap->buf.queue); + init_waitqueue_head(&cap->done); + spin_lock_init(&cap->buf.lock); + if (cap->id == RKISP1_SELFPATH) { + cap->ops = &rkisp1_capture_ops_sp; + cap->config = &rkisp1_capture_config_sp; + } else { + cap->ops = &rkisp1_capture_ops_mp; + cap->config = &rkisp1_capture_config_mp; + } + + cap->is_streaming = false; + + memset(&pixm, 0, sizeof(pixm)); + pixm.pixelformat = V4L2_PIX_FMT_YUYV; + pixm.width = RKISP1_DEFAULT_WIDTH; + pixm.height = RKISP1_DEFAULT_HEIGHT; + rkisp1_set_fmt(cap, &pixm); +} + +int rkisp1_capture_devs_register(struct rkisp1_device *rkisp1) +{ + struct rkisp1_capture *cap; + unsigned int i, j; + int ret; + + for (i = 0; i < ARRAY_SIZE(rkisp1->capture_devs); i++) { + rkisp1_capture_init(rkisp1, i); + cap = &rkisp1->capture_devs[i]; + cap->rkisp1 = rkisp1; + ret = rkisp1_register_capture(cap); + if (ret) + goto err_unreg_capture_devs; + } + + return 0; + +err_unreg_capture_devs: + for (j = 0; j < i; j++) { + cap = &rkisp1->capture_devs[j]; + rkisp1_unregister_capture(cap); + } + + return ret; +} diff --git a/drivers/staging/media/rkisp1/rkisp1-common.h b/drivers/staging/media/rkisp1/rkisp1-common.h index 97e06e9ada28..e47916296b5b 100644 --- a/drivers/staging/media/rkisp1/rkisp1-common.h +++ b/drivers/staging/media/rkisp1/rkisp1-common.h @@ -41,6 +41,16 @@ #define RKISP1_MAX_BUS_CLK 8 +enum rkisp1_rsz_pad { + RKISP1_RSZ_PAD_SINK, + RKISP1_RSZ_PAD_SRC, +}; + +enum rkisp1_stream_id { + RKISP1_MAINPATH, + RKISP1_SELFPATH, +}; + enum rkisp1_fmt_pix_type { RKISP1_FMT_YUV, RKISP1_FMT_RGB, @@ -124,11 +134,63 @@ struct rkisp1_dummy_buffer { struct rkisp1_device; +/* + * struct rkisp1_capture - ISP capture video device + * + * @pix.fmt: buffer format + * @pix.info: pixel information + * @pix.cfg: pixel configuration + * + * @buf.lock: lock to protect buf_queue + * @buf.queue: queued buffer list + * @buf.dummy: dummy space to store dropped data + * + * rkisp1 use shadowsock registers, so it need two buffer at a time + * @buf.curr: the buffer used for current frame + * @buf.next: the buffer used for next frame + */ +struct rkisp1_capture { + struct rkisp1_vdev_node vnode; + struct rkisp1_device *rkisp1; + enum rkisp1_stream_id id; + struct rkisp1_capture_ops *ops; + const struct rkisp1_capture_config *config; + bool is_streaming; + bool is_stopping; + wait_queue_head_t done; + unsigned int sp_y_stride; + struct { + /* protects queue, curr and next */ + spinlock_t lock; + struct list_head queue; + struct rkisp1_dummy_buffer dummy; + struct rkisp1_buffer *curr; + struct rkisp1_buffer *next; + } buf; + struct { + const struct rkisp1_capture_fmt_cfg *cfg; + const struct v4l2_format_info *info; + struct v4l2_pix_format_mplane fmt; + } pix; +}; + +struct rkisp1_resizer { + struct v4l2_subdev sd; + enum rkisp1_stream_id id; + struct rkisp1_device *rkisp1; + struct media_pad pads[RKISP1_ISP_PAD_MAX]; + struct v4l2_subdev_pad_config pad_cfg[RKISP1_ISP_PAD_MAX]; + const struct rkisp1_rsz_config *config; + enum rkisp1_fmt_pix_type fmt_type; +}; + struct rkisp1_debug { struct dentry *debugfs_dir; unsigned long data_loss; unsigned long pic_size_error; unsigned long mipi_error; + unsigned long stop_timeout[2]; + unsigned long frame_drop[2]; }; /* @@ -136,6 +198,7 @@ struct rkisp1_debug { * @base_addr: base register address * @active_sensor: sensor in-use, set when streaming on * @isp: ISP sub-device + * @rkisp1_capture: capture video device */ struct rkisp1_device { void __iomem *base_addr; @@ -149,6 +212,8 @@ struct rkisp1_device { struct v4l2_async_notifier notifier; struct rkisp1_sensor_async *active_sensor; struct rkisp1_isp isp; + struct rkisp1_resizer resizer_devs[2]; + struct rkisp1_capture capture_devs[2]; struct media_pipeline pipe; struct vb2_alloc_ctx *alloc_ctx; struct rkisp1_debug debug; @@ -196,5 +261,12 @@ const struct rkisp1_isp_mbus_info *rkisp1_isp_mbus_info_get(u32 mbus_code); void rkisp1_isp_isr(struct rkisp1_device *rkisp1); void rkisp1_mipi_isr(struct rkisp1_device *rkisp1); +void rkisp1_capture_isr(struct rkisp1_device *rkisp1); + +int rkisp1_capture_devs_register(struct rkisp1_device *rkisp1); +void rkisp1_capture_devs_unregister(struct rkisp1_device *rkisp1); + +int rkisp1_resizer_devs_register(struct rkisp1_device *rkisp1); +void rkisp1_resizer_devs_unregister(struct rkisp1_device *rkisp1); #endif /* _RKISP1_COMMON_H */ diff --git a/drivers/staging/media/rkisp1/rkisp1-dev.c b/drivers/staging/media/rkisp1/rkisp1-dev.c index a49442e98bf0..3d0a0f65eb19 100644 --- a/drivers/staging/media/rkisp1/rkisp1-dev.c +++ b/drivers/staging/media/rkisp1/rkisp1-dev.c @@ -37,6 +37,8 @@ * * ISP Block Diagram * ----------------- + * rkisp1-resizer.c rkisp1-capture.c + * |====================| |=======================| * rkisp1-isp.c Main Picture Path * |==========================| |===============================================| * +-----------+ +--+--+--+--+ +--------+ +--------+ +-----------+ @@ -72,8 +74,23 @@ * +----------+ |------+------| * | ISP | * |------+------| - * | 2 | 3 | - * +------+------+ + * +-------------| 2 | 3 | + * | +------+------+ + * | | + * v v + * +- ---------+ +-----------+ + * | 0 | | 0 | + * ------------- ------------- + * | Resizer | | Resizer | + * ------------| ------------| + * | 1 | | 1 | + * +-----------+ +-----------+ + * | | + * v v + * +-----------+ +-----------+ + * | selfpath | | mainpath | + * | (capture) | | (capture) | + * +-----------+ +-----------+ */ struct rkisp1_match_data { @@ -87,14 +104,18 @@ struct rkisp1_match_data { static int rkisp1_create_links(struct rkisp1_device *rkisp1) { + struct media_entity *source, *sink; unsigned int flags, source_pad; struct v4l2_subdev *sd; + unsigned int i; int ret; /* sensor links */ flags = MEDIA_LNK_FL_ENABLED; list_for_each_entry(sd, &rkisp1->v4l2_dev.subdevs, list) { - if (sd == &rkisp1->isp.sd) + if (sd == &rkisp1->isp.sd || + sd == &rkisp1->resizer_devs[RKISP1_MAINPATH].sd || + sd == &rkisp1->resizer_devs[RKISP1_SELFPATH].sd) continue; ret = media_entity_get_fwnode_pad(&sd->entity, sd->fwnode, @@ -116,6 +137,25 @@ static int rkisp1_create_links(struct rkisp1_device *rkisp1) flags = 0; } + flags = MEDIA_LNK_FL_ENABLED; + + /* create ISP->RSZ->CAP links */ + for (i = 0; i < 2; i++) { + source = &rkisp1->isp.sd.entity; + sink = &rkisp1->resizer_devs[i].sd.entity; + ret = media_create_pad_link(source, RKISP1_ISP_PAD_SOURCE_VIDEO, + sink, RKISP1_RSZ_PAD_SINK, flags); + if (ret) + return ret; + + source = sink; + sink = &rkisp1->capture_devs[i].vnode.vdev.entity; + ret = media_create_pad_link(source, RKISP1_RSZ_PAD_SRC, + sink, 0, flags); + if (ret) + return ret; + } + return 0; } @@ -288,15 +328,29 @@ static int rkisp1_entities_register(struct rkisp1_device *rkisp1) if (ret) return ret; + ret = rkisp1_resizer_devs_register(rkisp1); + if (ret) + goto err_unreg_isp_subdev; + + ret = rkisp1_capture_devs_register(rkisp1); + if (ret) + goto err_unreg_resizer_devs; + ret = rkisp1_subdev_notifier(rkisp1); if (ret) { dev_err(rkisp1->dev, "Failed to register subdev notifier(%d)\n", ret); - rkisp1_isp_unregister(rkisp1); - return ret; + goto err_unreg_capture_devs; } return 0; +err_unreg_capture_devs: + rkisp1_capture_devs_unregister(rkisp1); +err_unreg_resizer_devs: + rkisp1_resizer_devs_unregister(rkisp1); +err_unreg_isp_subdev: + rkisp1_isp_unregister(rkisp1); + return ret; } static irqreturn_t rkisp1_isr(int irq, void *ctx) @@ -304,6 +358,13 @@ static irqreturn_t rkisp1_isr(int irq, void *ctx) struct device *dev = ctx; struct rkisp1_device *rkisp1 = dev_get_drvdata(dev); + /* + * Call rkisp1_capture_isr() first to handle the frame that + * potentially completed using the current frame_sequence number before + * it is potentially incremented by rkisp1_isp_isr() in the vertical + * sync. + */ + rkisp1_capture_isr(rkisp1); rkisp1_isp_isr(rkisp1); rkisp1_mipi_isr(rkisp1); @@ -347,6 +408,14 @@ static void rkisp1_debug_init(struct rkisp1_device *rkisp1) &debug->pic_size_error); debugfs_create_ulong("mipi_error", 0444, debug->debugfs_dir, &debug->mipi_error); + debugfs_create_ulong("mp_stop_timeout", 0444, debug->debugfs_dir, + &debug->stop_timeout[RKISP1_MAINPATH]); + debugfs_create_ulong("sp_stop_timeout", 0444, debug->debugfs_dir, + &debug->stop_timeout[RKISP1_SELFPATH]); + debugfs_create_ulong("mp_frame_drop", 0444, debug->debugfs_dir, + &debug->frame_drop[RKISP1_MAINPATH]); + debugfs_create_ulong("sp_frame_drop", 0444, debug->debugfs_dir, + &debug->frame_drop[RKISP1_SELFPATH]); } static int rkisp1_probe(struct platform_device *pdev) @@ -440,6 +509,8 @@ static int rkisp1_remove(struct platform_device *pdev) v4l2_async_notifier_unregister(&rkisp1->notifier); v4l2_async_notifier_cleanup(&rkisp1->notifier); + rkisp1_capture_devs_unregister(rkisp1); + rkisp1_resizer_devs_unregister(rkisp1); rkisp1_isp_unregister(rkisp1); media_device_unregister(&rkisp1->media_dev); diff --git a/drivers/staging/media/rkisp1/rkisp1-resizer.c b/drivers/staging/media/rkisp1/rkisp1-resizer.c new file mode 100644 index 000000000000..8cdc29c1a178 --- /dev/null +++ b/drivers/staging/media/rkisp1/rkisp1-resizer.c @@ -0,0 +1,775 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Rockchip ISP1 Driver - V4l resizer device + * + * Copyright (C) 2019 Collabora, Ltd. + * + * Based on Rockchip ISP1 driver by Rockchip Electronics Co., Ltd. + * Copyright (C) 2017 Rockchip Electronics Co., Ltd. + */ + +#include "rkisp1-common.h" + +#define RKISP1_RSZ_SP_DEV_NAME RKISP1_DRIVER_NAME "_resizer_selfpath" +#define RKISP1_RSZ_MP_DEV_NAME RKISP1_DRIVER_NAME "_resizer_mainpath" + +#define RKISP1_DEF_FMT MEDIA_BUS_FMT_YUYV8_2X8 +#define RKISP1_DEF_FMT_TYPE RKISP1_FMT_YUV + +#define RKISP1_MBUS_FMT_HDIV 2 +#define RKISP1_MBUS_FMT_VDIV 1 + +enum rkisp1_shadow_regs_when { + RKISP1_SHADOW_REGS_SYNC, + RKISP1_SHADOW_REGS_ASYNC, +}; + +struct rkisp1_rsz_config { + /* constrains */ + const int max_rsz_width; + const int max_rsz_height; + const int min_rsz_width; + const int min_rsz_height; + /* registers */ + struct { + u32 ctrl; + u32 ctrl_shd; + u32 scale_hy; + u32 scale_hcr; + u32 scale_hcb; + u32 scale_vy; + u32 scale_vc; + u32 scale_lut; + u32 scale_lut_addr; + u32 scale_hy_shd; + u32 scale_hcr_shd; + u32 scale_hcb_shd; + u32 scale_vy_shd; + u32 scale_vc_shd; + u32 phase_hy; + u32 phase_hc; + u32 phase_vy; + u32 phase_vc; + u32 phase_hy_shd; + u32 phase_hc_shd; + u32 phase_vy_shd; + u32 phase_vc_shd; + } rsz; + struct { + u32 ctrl; + u32 yuvmode_mask; + u32 rawmode_mask; + u32 h_offset; + u32 v_offset; + u32 h_size; + u32 v_size; + } dual_crop; +}; + +static const struct rkisp1_rsz_config rkisp1_rsz_config_mp = { + /* constraints */ + .max_rsz_width = RKISP1_RSZ_MP_SRC_MAX_WIDTH, + .max_rsz_height = RKISP1_RSZ_MP_SRC_MAX_HEIGHT, + .min_rsz_width = RKISP1_RSZ_SRC_MIN_WIDTH, + .min_rsz_height = RKISP1_RSZ_SRC_MIN_HEIGHT, + /* registers */ + .rsz = { + .ctrl = RKISP1_CIF_MRSZ_CTRL, + .scale_hy = RKISP1_CIF_MRSZ_SCALE_HY, + .scale_hcr = RKISP1_CIF_MRSZ_SCALE_HCR, + .scale_hcb = RKISP1_CIF_MRSZ_SCALE_HCB, + .scale_vy = RKISP1_CIF_MRSZ_SCALE_VY, + .scale_vc = RKISP1_CIF_MRSZ_SCALE_VC, + .scale_lut = RKISP1_CIF_MRSZ_SCALE_LUT, + .scale_lut_addr = RKISP1_CIF_MRSZ_SCALE_LUT_ADDR, + .scale_hy_shd = RKISP1_CIF_MRSZ_SCALE_HY_SHD, + .scale_hcr_shd = RKISP1_CIF_MRSZ_SCALE_HCR_SHD, + .scale_hcb_shd = RKISP1_CIF_MRSZ_SCALE_HCB_SHD, + .scale_vy_shd = RKISP1_CIF_MRSZ_SCALE_VY_SHD, + .scale_vc_shd = RKISP1_CIF_MRSZ_SCALE_VC_SHD, + .phase_hy = RKISP1_CIF_MRSZ_PHASE_HY, + .phase_hc = RKISP1_CIF_MRSZ_PHASE_HC, + .phase_vy = RKISP1_CIF_MRSZ_PHASE_VY, + .phase_vc = RKISP1_CIF_MRSZ_PHASE_VC, + .ctrl_shd = RKISP1_CIF_MRSZ_CTRL_SHD, + .phase_hy_shd = RKISP1_CIF_MRSZ_PHASE_HY_SHD, + .phase_hc_shd = RKISP1_CIF_MRSZ_PHASE_HC_SHD, + .phase_vy_shd = RKISP1_CIF_MRSZ_PHASE_VY_SHD, + .phase_vc_shd = RKISP1_CIF_MRSZ_PHASE_VC_SHD, + }, + .dual_crop = { + .ctrl = RKISP1_CIF_DUAL_CROP_CTRL, + .yuvmode_mask = RKISP1_CIF_DUAL_CROP_MP_MODE_YUV, + .rawmode_mask = RKISP1_CIF_DUAL_CROP_MP_MODE_RAW, + .h_offset = RKISP1_CIF_DUAL_CROP_M_H_OFFS, + .v_offset = RKISP1_CIF_DUAL_CROP_M_V_OFFS, + .h_size = RKISP1_CIF_DUAL_CROP_M_H_SIZE, + .v_size = RKISP1_CIF_DUAL_CROP_M_V_SIZE, + }, +}; + +static const struct rkisp1_rsz_config rkisp1_rsz_config_sp = { + /* constraints */ + .max_rsz_width = RKISP1_RSZ_SP_SRC_MAX_WIDTH, + .max_rsz_height = RKISP1_RSZ_SP_SRC_MAX_HEIGHT, + .min_rsz_width = RKISP1_RSZ_SRC_MIN_WIDTH, + .min_rsz_height = RKISP1_RSZ_SRC_MIN_HEIGHT, + /* registers */ + .rsz = { + .ctrl = RKISP1_CIF_SRSZ_CTRL, + .scale_hy = RKISP1_CIF_SRSZ_SCALE_HY, + .scale_hcr = RKISP1_CIF_SRSZ_SCALE_HCR, + .scale_hcb = RKISP1_CIF_SRSZ_SCALE_HCB, + .scale_vy = RKISP1_CIF_SRSZ_SCALE_VY, + .scale_vc = RKISP1_CIF_SRSZ_SCALE_VC, + .scale_lut = RKISP1_CIF_SRSZ_SCALE_LUT, + .scale_lut_addr = RKISP1_CIF_SRSZ_SCALE_LUT_ADDR, + .scale_hy_shd = RKISP1_CIF_SRSZ_SCALE_HY_SHD, + .scale_hcr_shd = RKISP1_CIF_SRSZ_SCALE_HCR_SHD, + .scale_hcb_shd = RKISP1_CIF_SRSZ_SCALE_HCB_SHD, + .scale_vy_shd = RKISP1_CIF_SRSZ_SCALE_VY_SHD, + .scale_vc_shd = RKISP1_CIF_SRSZ_SCALE_VC_SHD, + .phase_hy = RKISP1_CIF_SRSZ_PHASE_HY, + .phase_hc = RKISP1_CIF_SRSZ_PHASE_HC, + .phase_vy = RKISP1_CIF_SRSZ_PHASE_VY, + .phase_vc = RKISP1_CIF_SRSZ_PHASE_VC, + .ctrl_shd = RKISP1_CIF_SRSZ_CTRL_SHD, + .phase_hy_shd = RKISP1_CIF_SRSZ_PHASE_HY_SHD, + .phase_hc_shd = RKISP1_CIF_SRSZ_PHASE_HC_SHD, + .phase_vy_shd = RKISP1_CIF_SRSZ_PHASE_VY_SHD, + .phase_vc_shd = RKISP1_CIF_SRSZ_PHASE_VC_SHD, + }, + .dual_crop = { + .ctrl = RKISP1_CIF_DUAL_CROP_CTRL, + .yuvmode_mask = RKISP1_CIF_DUAL_CROP_SP_MODE_YUV, + .rawmode_mask = RKISP1_CIF_DUAL_CROP_SP_MODE_RAW, + .h_offset = RKISP1_CIF_DUAL_CROP_S_H_OFFS, + .v_offset = RKISP1_CIF_DUAL_CROP_S_V_OFFS, + .h_size = RKISP1_CIF_DUAL_CROP_S_H_SIZE, + .v_size = RKISP1_CIF_DUAL_CROP_S_V_SIZE, + }, +}; + +static struct v4l2_mbus_framefmt * +rkisp1_rsz_get_pad_fmt(struct rkisp1_resizer *rsz, + struct v4l2_subdev_pad_config *cfg, + unsigned int pad, u32 which) +{ + if (which == V4L2_SUBDEV_FORMAT_TRY) + return v4l2_subdev_get_try_format(&rsz->sd, cfg, pad); + else + return v4l2_subdev_get_try_format(&rsz->sd, rsz->pad_cfg, pad); +} + +static struct v4l2_rect * +rkisp1_rsz_get_pad_crop(struct rkisp1_resizer *rsz, + struct v4l2_subdev_pad_config *cfg, + unsigned int pad, u32 which) +{ + if (which == V4L2_SUBDEV_FORMAT_TRY) + return v4l2_subdev_get_try_crop(&rsz->sd, cfg, pad); + else + return v4l2_subdev_get_try_crop(&rsz->sd, rsz->pad_cfg, pad); +} + +/* ---------------------------------------------------------------------------- + * Dual crop hw configs + */ + +static void rkisp1_dcrop_disable(struct rkisp1_resizer *rsz, + enum rkisp1_shadow_regs_when when) +{ + u32 dc_ctrl = rkisp1_read(rsz->rkisp1, rsz->config->dual_crop.ctrl); + u32 mask = ~(rsz->config->dual_crop.yuvmode_mask | + rsz->config->dual_crop.rawmode_mask); + + dc_ctrl &= mask; + if (when == RKISP1_SHADOW_REGS_ASYNC) + dc_ctrl |= RKISP1_CIF_DUAL_CROP_GEN_CFG_UPD; + else + dc_ctrl |= RKISP1_CIF_DUAL_CROP_CFG_UPD; + rkisp1_write(rsz->rkisp1, dc_ctrl, rsz->config->dual_crop.ctrl); +} + +/* configure dual-crop unit */ +static void rkisp1_dcrop_config(struct rkisp1_resizer *rsz) +{ + struct rkisp1_device *rkisp1 = rsz->rkisp1; + struct v4l2_mbus_framefmt *sink_fmt; + struct v4l2_rect *sink_crop; + u32 dc_ctrl; + + sink_crop = rkisp1_rsz_get_pad_crop(rsz, NULL, RKISP1_RSZ_PAD_SINK, + V4L2_SUBDEV_FORMAT_ACTIVE); + sink_fmt = rkisp1_rsz_get_pad_fmt(rsz, NULL, RKISP1_RSZ_PAD_SINK, + V4L2_SUBDEV_FORMAT_ACTIVE); + + if (sink_crop->width == sink_fmt->width && + sink_crop->height == sink_fmt->height && + sink_crop->left == 0 && sink_crop->top == 0) { + rkisp1_dcrop_disable(rsz, RKISP1_SHADOW_REGS_SYNC); + dev_dbg(rkisp1->dev, "capture %d crop disabled\n", rsz->id); + return; + } + + dc_ctrl = rkisp1_read(rkisp1, rsz->config->dual_crop.ctrl); + rkisp1_write(rkisp1, sink_crop->left, rsz->config->dual_crop.h_offset); + rkisp1_write(rkisp1, sink_crop->top, rsz->config->dual_crop.v_offset); + rkisp1_write(rkisp1, sink_crop->width, rsz->config->dual_crop.h_size); + rkisp1_write(rkisp1, sink_crop->height, rsz->config->dual_crop.v_size); + dc_ctrl |= rsz->config->dual_crop.yuvmode_mask; + dc_ctrl |= RKISP1_CIF_DUAL_CROP_CFG_UPD; + rkisp1_write(rkisp1, dc_ctrl, rsz->config->dual_crop.ctrl); + + dev_dbg(rkisp1->dev, "stream %d crop: %dx%d -> %dx%d\n", rsz->id, + sink_fmt->width, sink_fmt->height, + sink_crop->width, sink_crop->height); +} + +/* ---------------------------------------------------------------------------- + * Resizer hw configs + */ + +static void rkisp1_rsz_dump_regs(struct rkisp1_resizer *rsz) +{ + dev_dbg(rsz->rkisp1->dev, + "RSZ_CTRL 0x%08x/0x%08x\n" + "RSZ_SCALE_HY %d/%d\n" + "RSZ_SCALE_HCB %d/%d\n" + "RSZ_SCALE_HCR %d/%d\n" + "RSZ_SCALE_VY %d/%d\n" + "RSZ_SCALE_VC %d/%d\n" + "RSZ_PHASE_HY %d/%d\n" + "RSZ_PHASE_HC %d/%d\n" + "RSZ_PHASE_VY %d/%d\n" + "RSZ_PHASE_VC %d/%d\n", + rkisp1_read(rsz->rkisp1, rsz->config->rsz.ctrl), + rkisp1_read(rsz->rkisp1, rsz->config->rsz.ctrl_shd), + rkisp1_read(rsz->rkisp1, rsz->config->rsz.scale_hy), + rkisp1_read(rsz->rkisp1, rsz->config->rsz.scale_hy_shd), + rkisp1_read(rsz->rkisp1, rsz->config->rsz.scale_hcb), + rkisp1_read(rsz->rkisp1, rsz->config->rsz.scale_hcb_shd), + rkisp1_read(rsz->rkisp1, rsz->config->rsz.scale_hcr), + rkisp1_read(rsz->rkisp1, rsz->config->rsz.scale_hcr_shd), + rkisp1_read(rsz->rkisp1, rsz->config->rsz.scale_vy), + rkisp1_read(rsz->rkisp1, rsz->config->rsz.scale_vy_shd), + rkisp1_read(rsz->rkisp1, rsz->config->rsz.scale_vc), + rkisp1_read(rsz->rkisp1, rsz->config->rsz.scale_vc_shd), + rkisp1_read(rsz->rkisp1, rsz->config->rsz.phase_hy), + rkisp1_read(rsz->rkisp1, rsz->config->rsz.phase_hy_shd), + rkisp1_read(rsz->rkisp1, rsz->config->rsz.phase_hc), + rkisp1_read(rsz->rkisp1, rsz->config->rsz.phase_hc_shd), + rkisp1_read(rsz->rkisp1, rsz->config->rsz.phase_vy), + rkisp1_read(rsz->rkisp1, rsz->config->rsz.phase_vy_shd), + rkisp1_read(rsz->rkisp1, rsz->config->rsz.phase_vc), + rkisp1_read(rsz->rkisp1, rsz->config->rsz.phase_vc_shd)); +} + +static void rkisp1_rsz_update_shadow(struct rkisp1_resizer *rsz, + enum rkisp1_shadow_regs_when when) +{ + u32 ctrl_cfg = rkisp1_read(rsz->rkisp1, rsz->config->rsz.ctrl); + + if (when == RKISP1_SHADOW_REGS_ASYNC) + ctrl_cfg |= RKISP1_CIF_RSZ_CTRL_CFG_UPD_AUTO; + else + ctrl_cfg |= RKISP1_CIF_RSZ_CTRL_CFG_UPD; + + rkisp1_write(rsz->rkisp1, ctrl_cfg, rsz->config->rsz.ctrl); +} + +static u32 rkisp1_rsz_calc_ratio(u32 len_sink, u32 len_src) +{ + if (len_sink < len_src) + return ((len_sink - 1) * RKISP1_CIF_RSZ_SCALER_FACTOR) / + (len_src - 1); + + return ((len_src - 1) * RKISP1_CIF_RSZ_SCALER_FACTOR) / + (len_sink - 1) + 1; +} + +static void rkisp1_rsz_disable(struct rkisp1_resizer *rsz, + enum rkisp1_shadow_regs_when when) +{ + rkisp1_write(rsz->rkisp1, 0, rsz->config->rsz.ctrl); + + if (when == RKISP1_SHADOW_REGS_SYNC) + rkisp1_rsz_update_shadow(rsz, when); +} + +static void rkisp1_rsz_config_regs(struct rkisp1_resizer *rsz, + struct v4l2_rect *sink_y, + struct v4l2_rect *sink_c, + struct v4l2_rect *src_y, + struct v4l2_rect *src_c, + enum rkisp1_shadow_regs_when when) +{ + struct rkisp1_device *rkisp1 = rsz->rkisp1; + u32 ratio, rsz_ctrl = 0; + unsigned int i; + + /* No phase offset */ + rkisp1_write(rkisp1, 0, rsz->config->rsz.phase_hy); + rkisp1_write(rkisp1, 0, rsz->config->rsz.phase_hc); + rkisp1_write(rkisp1, 0, rsz->config->rsz.phase_vy); + rkisp1_write(rkisp1, 0, rsz->config->rsz.phase_vc); + + /* Linear interpolation */ + for (i = 0; i < 64; i++) { + rkisp1_write(rkisp1, i, rsz->config->rsz.scale_lut_addr); + rkisp1_write(rkisp1, i, rsz->config->rsz.scale_lut); + } + + if (sink_y->width != src_y->width) { + rsz_ctrl |= RKISP1_CIF_RSZ_CTRL_SCALE_HY_ENABLE; + if (sink_y->width < src_y->width) + rsz_ctrl |= RKISP1_CIF_RSZ_CTRL_SCALE_HY_UP; + ratio = rkisp1_rsz_calc_ratio(sink_y->width, src_y->width); + rkisp1_write(rkisp1, ratio, rsz->config->rsz.scale_hy); + } + + if (sink_c->width != src_c->width) { + rsz_ctrl |= RKISP1_CIF_RSZ_CTRL_SCALE_HC_ENABLE; + if (sink_c->width < src_c->width) + rsz_ctrl |= RKISP1_CIF_RSZ_CTRL_SCALE_HC_UP; + ratio = rkisp1_rsz_calc_ratio(sink_c->width, src_c->width); + rkisp1_write(rkisp1, ratio, rsz->config->rsz.scale_hcb); + rkisp1_write(rkisp1, ratio, rsz->config->rsz.scale_hcr); + } + + if (sink_y->height != src_y->height) { + rsz_ctrl |= RKISP1_CIF_RSZ_CTRL_SCALE_VY_ENABLE; + if (sink_y->height < src_y->height) + rsz_ctrl |= RKISP1_CIF_RSZ_CTRL_SCALE_VY_UP; + ratio = rkisp1_rsz_calc_ratio(sink_y->height, src_y->height); + rkisp1_write(rkisp1, ratio, rsz->config->rsz.scale_vy); + } + + if (sink_c->height != src_c->height) { + rsz_ctrl |= RKISP1_CIF_RSZ_CTRL_SCALE_VC_ENABLE; + if (sink_c->height < src_c->height) + rsz_ctrl |= RKISP1_CIF_RSZ_CTRL_SCALE_VC_UP; + ratio = rkisp1_rsz_calc_ratio(sink_c->height, src_c->height); + rkisp1_write(rkisp1, ratio, rsz->config->rsz.scale_vc); + } + + rkisp1_write(rkisp1, rsz_ctrl, rsz->config->rsz.ctrl); + + rkisp1_rsz_update_shadow(rsz, when); +} + +static void rkisp1_rsz_config(struct rkisp1_resizer *rsz, + enum rkisp1_shadow_regs_when when) +{ + u8 hdiv = RKISP1_MBUS_FMT_HDIV, vdiv = RKISP1_MBUS_FMT_VDIV; + struct v4l2_rect sink_y, sink_c, src_y, src_c; + struct v4l2_mbus_framefmt *src_fmt; + struct v4l2_rect *sink_crop; + + sink_crop = rkisp1_rsz_get_pad_crop(rsz, NULL, RKISP1_RSZ_PAD_SINK, + V4L2_SUBDEV_FORMAT_ACTIVE); + src_fmt = rkisp1_rsz_get_pad_fmt(rsz, NULL, RKISP1_RSZ_PAD_SRC, + V4L2_SUBDEV_FORMAT_ACTIVE); + + if (rsz->fmt_type == RKISP1_FMT_BAYER) { + rkisp1_rsz_disable(rsz, when); + return; + } + + sink_y.width = sink_crop->width; + sink_y.height = sink_crop->height; + src_y.width = src_fmt->width; + src_y.height = src_fmt->height; + + sink_c.width = sink_y.width / RKISP1_MBUS_FMT_HDIV; + sink_c.height = sink_y.height / RKISP1_MBUS_FMT_VDIV; + + if (rsz->fmt_type == RKISP1_FMT_YUV) { + struct rkisp1_capture *cap = + &rsz->rkisp1->capture_devs[rsz->id]; + const struct v4l2_format_info *pixfmt_info = + v4l2_format_info(cap->pix.fmt.pixelformat); + + hdiv = pixfmt_info->hdiv; + vdiv = pixfmt_info->vdiv; + } + src_c.width = src_y.width / hdiv; + src_c.height = src_y.height / vdiv; + + if (sink_c.width == src_c.width && sink_c.height == src_c.height) { + rkisp1_rsz_disable(rsz, when); + return; + } + + dev_dbg(rsz->rkisp1->dev, "stream %d rsz/scale: %dx%d -> %dx%d\n", + rsz->id, sink_crop->width, sink_crop->height, + src_fmt->width, src_fmt->height); + dev_dbg(rsz->rkisp1->dev, "chroma scaling %dx%d -> %dx%d\n", + sink_c.width, sink_c.height, src_c.width, src_c.height); + + /* set values in the hw */ + rkisp1_rsz_config_regs(rsz, &sink_y, &sink_c, &src_y, &src_c, when); + + rkisp1_rsz_dump_regs(rsz); +} + +/* ---------------------------------------------------------------------------- + * Subdev pad operations + */ + +static int rkisp1_rsz_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) +{ + struct rkisp1_resizer *rsz = + container_of(sd, struct rkisp1_resizer, sd); + struct v4l2_subdev_pad_config dummy_cfg; + u32 pad = code->pad; + int ret; + + /* supported mbus codes are the same in isp sink pad */ + code->pad = RKISP1_ISP_PAD_SINK_VIDEO; + ret = v4l2_subdev_call(&rsz->rkisp1->isp.sd, pad, enum_mbus_code, + &dummy_cfg, code); + + /* restore pad */ + code->pad = pad; + return ret; +} + +static int rkisp1_rsz_init_config(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg) +{ + struct v4l2_mbus_framefmt *sink_fmt, *src_fmt; + struct v4l2_rect *sink_crop; + + sink_fmt = v4l2_subdev_get_try_format(sd, cfg, RKISP1_RSZ_PAD_SRC); + sink_fmt->width = RKISP1_DEFAULT_WIDTH; + sink_fmt->height = RKISP1_DEFAULT_HEIGHT; + sink_fmt->field = V4L2_FIELD_NONE; + sink_fmt->code = RKISP1_DEF_FMT; + + sink_crop = v4l2_subdev_get_try_crop(sd, cfg, RKISP1_RSZ_PAD_SINK); + sink_crop->width = RKISP1_DEFAULT_WIDTH; + sink_crop->height = RKISP1_DEFAULT_HEIGHT; + sink_crop->left = 0; + sink_crop->top = 0; + + src_fmt = v4l2_subdev_get_try_format(sd, cfg, RKISP1_RSZ_PAD_SINK); + *src_fmt = *sink_fmt; + + /* NOTE: there is no crop in the source pad, only in the sink */ + + return 0; +} + +static void rkisp1_rsz_set_src_fmt(struct rkisp1_resizer *rsz, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_mbus_framefmt *format, + unsigned int which) +{ + struct v4l2_mbus_framefmt *src_fmt; + + src_fmt = rkisp1_rsz_get_pad_fmt(rsz, cfg, RKISP1_RSZ_PAD_SRC, which); + src_fmt->width = clamp_t(u32, format->width, + rsz->config->min_rsz_width, + rsz->config->max_rsz_width); + src_fmt->height = clamp_t(u32, format->height, + rsz->config->min_rsz_height, + rsz->config->max_rsz_height); + + *format = *src_fmt; +} + +static void rkisp1_rsz_set_sink_crop(struct rkisp1_resizer *rsz, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_rect *r, + unsigned int which) +{ + const struct rkisp1_isp_mbus_info *mbus_info; + struct v4l2_mbus_framefmt *sink_fmt; + struct v4l2_rect *sink_crop; + + sink_fmt = rkisp1_rsz_get_pad_fmt(rsz, cfg, RKISP1_RSZ_PAD_SINK, which); + sink_crop = rkisp1_rsz_get_pad_crop(rsz, cfg, RKISP1_RSZ_PAD_SINK, + which); + + /* Not crop for MP bayer raw data */ + mbus_info = rkisp1_isp_mbus_info_get(sink_fmt->code); + + if (rsz->id == RKISP1_MAINPATH && + mbus_info->fmt_type == RKISP1_FMT_BAYER) { + sink_crop->left = 0; + sink_crop->top = 0; + sink_crop->width = sink_fmt->width; + sink_crop->height = sink_fmt->height; + return; + } + + sink_crop->left = ALIGN(r->left, 2); + sink_crop->width = ALIGN(r->width, 2); + sink_crop->top = r->top; + sink_crop->height = r->height; + rkisp1_sd_adjust_crop(sink_crop, sink_fmt); + + *r = *sink_crop; +} + +static void rkisp1_rsz_set_sink_fmt(struct rkisp1_resizer *rsz, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_mbus_framefmt *format, + unsigned int which) +{ + const struct rkisp1_isp_mbus_info *mbus_info; + struct v4l2_mbus_framefmt *sink_fmt, *src_fmt; + struct v4l2_rect *sink_crop; + + sink_fmt = rkisp1_rsz_get_pad_fmt(rsz, cfg, RKISP1_RSZ_PAD_SINK, which); + src_fmt = rkisp1_rsz_get_pad_fmt(rsz, cfg, RKISP1_RSZ_PAD_SRC, which); + sink_crop = rkisp1_rsz_get_pad_crop(rsz, cfg, RKISP1_RSZ_PAD_SINK, + which); + sink_fmt->code = format->code; + mbus_info = rkisp1_isp_mbus_info_get(sink_fmt->code); + if (!mbus_info) { + sink_fmt->code = RKISP1_DEF_FMT; + mbus_info = rkisp1_isp_mbus_info_get(sink_fmt->code); + } + if (which == V4L2_SUBDEV_FORMAT_ACTIVE) + rsz->fmt_type = mbus_info->fmt_type; + + if (rsz->id == RKISP1_MAINPATH && + mbus_info->fmt_type == RKISP1_FMT_BAYER) { + sink_crop->left = 0; + sink_crop->top = 0; + sink_crop->width = sink_fmt->width; + sink_crop->height = sink_fmt->height; + return; + } + + /* Propagete to source pad */ + src_fmt->code = sink_fmt->code; + + sink_fmt->width = clamp_t(u32, format->width, + rsz->config->min_rsz_width, + rsz->config->max_rsz_width); + sink_fmt->height = clamp_t(u32, format->height, + rsz->config->min_rsz_height, + rsz->config->max_rsz_height); + + *format = *sink_fmt; + + /* Update sink crop */ + rkisp1_rsz_set_sink_crop(rsz, cfg, sink_crop, which); +} + +static int rkisp1_rsz_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *fmt) +{ + struct rkisp1_resizer *rsz = + container_of(sd, struct rkisp1_resizer, sd); + + fmt->format = *rkisp1_rsz_get_pad_fmt(rsz, cfg, fmt->pad, fmt->which); + return 0; +} + +static int rkisp1_rsz_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *fmt) +{ + struct rkisp1_resizer *rsz = + container_of(sd, struct rkisp1_resizer, sd); + + if (fmt->pad == RKISP1_RSZ_PAD_SINK) + rkisp1_rsz_set_sink_fmt(rsz, cfg, &fmt->format, fmt->which); + else + rkisp1_rsz_set_src_fmt(rsz, cfg, &fmt->format, fmt->which); + + return 0; +} + +static int rkisp1_rsz_get_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_selection *sel) +{ + struct rkisp1_resizer *rsz = + container_of(sd, struct rkisp1_resizer, sd); + struct v4l2_mbus_framefmt *mf_sink; + + if (sel->pad == RKISP1_RSZ_PAD_SRC) + return -EINVAL; + + switch (sel->target) { + case V4L2_SEL_TGT_CROP_BOUNDS: + mf_sink = rkisp1_rsz_get_pad_fmt(rsz, cfg, RKISP1_RSZ_PAD_SINK, + sel->which); + sel->r.height = mf_sink->height; + sel->r.width = mf_sink->width; + sel->r.left = 0; + sel->r.top = 0; + break; + case V4L2_SEL_TGT_CROP: + sel->r = *rkisp1_rsz_get_pad_crop(rsz, cfg, RKISP1_RSZ_PAD_SINK, + sel->which); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int rkisp1_rsz_set_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_selection *sel) +{ + struct rkisp1_resizer *rsz = + container_of(sd, struct rkisp1_resizer, sd); + + if (sel->target != V4L2_SEL_TGT_CROP || sel->pad == RKISP1_RSZ_PAD_SRC) + return -EINVAL; + + dev_dbg(sd->dev, "%s: pad: %d sel(%d,%d)/%dx%d\n", __func__, + sel->pad, sel->r.left, sel->r.top, sel->r.width, sel->r.height); + + rkisp1_rsz_set_sink_crop(rsz, cfg, &sel->r, sel->which); + + return 0; +} + +static const struct media_entity_operations rkisp1_rsz_media_ops = { + .link_validate = v4l2_subdev_link_validate, +}; + +static const struct v4l2_subdev_pad_ops rkisp1_rsz_pad_ops = { + .enum_mbus_code = rkisp1_rsz_enum_mbus_code, + .get_selection = rkisp1_rsz_get_selection, + .set_selection = rkisp1_rsz_set_selection, + .init_cfg = rkisp1_rsz_init_config, + .get_fmt = rkisp1_rsz_get_fmt, + .set_fmt = rkisp1_rsz_set_fmt, + .link_validate = v4l2_subdev_link_validate_default, +}; + +/* ---------------------------------------------------------------------------- + * Stream operations + */ + +static int rkisp1_rsz_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct rkisp1_resizer *rsz = + container_of(sd, struct rkisp1_resizer, sd); + struct rkisp1_device *rkisp1 = rsz->rkisp1; + struct rkisp1_capture *other = &rkisp1->capture_devs[rsz->id ^ 1]; + enum rkisp1_shadow_regs_when when = RKISP1_SHADOW_REGS_SYNC; + + if (!enable) { + rkisp1_dcrop_disable(rsz, RKISP1_SHADOW_REGS_ASYNC); + rkisp1_rsz_disable(rsz, RKISP1_SHADOW_REGS_ASYNC); + return 0; + } + + if (other->is_streaming) + when = RKISP1_SHADOW_REGS_ASYNC; + + rkisp1_rsz_config(rsz, when); + rkisp1_dcrop_config(rsz); + + return 0; +} + +static const struct v4l2_subdev_video_ops rkisp1_rsz_video_ops = { + .s_stream = rkisp1_rsz_s_stream, +}; + +static const struct v4l2_subdev_ops rkisp1_rsz_ops = { + .video = &rkisp1_rsz_video_ops, + .pad = &rkisp1_rsz_pad_ops, +}; + +static void rkisp1_rsz_unregister(struct rkisp1_resizer *rsz) +{ + v4l2_device_unregister_subdev(&rsz->sd); + media_entity_cleanup(&rsz->sd.entity); +} + +static int rkisp1_rsz_register(struct rkisp1_resizer *rsz) +{ + const char * const dev_names[] = {RKISP1_RSZ_MP_DEV_NAME, + RKISP1_RSZ_SP_DEV_NAME}; + struct media_pad *pads = rsz->pads; + struct v4l2_subdev *sd = &rsz->sd; + int ret; + + if (rsz->id == RKISP1_SELFPATH) + rsz->config = &rkisp1_rsz_config_sp; + else + rsz->config = &rkisp1_rsz_config_mp; + + v4l2_subdev_init(sd, &rkisp1_rsz_ops); + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + sd->entity.ops = &rkisp1_rsz_media_ops; + sd->entity.function = MEDIA_ENT_F_PROC_VIDEO_SCALER; + sd->owner = THIS_MODULE; + strscpy(sd->name, dev_names[rsz->id], sizeof(sd->name)); + + pads[RKISP1_RSZ_PAD_SINK].flags = MEDIA_PAD_FL_SINK | + MEDIA_PAD_FL_MUST_CONNECT; + pads[RKISP1_RSZ_PAD_SRC].flags = MEDIA_PAD_FL_SOURCE | + MEDIA_PAD_FL_MUST_CONNECT; + + rsz->fmt_type = RKISP1_DEF_FMT_TYPE; + + ret = media_entity_pads_init(&sd->entity, 2, pads); + if (ret) + return ret; + + ret = v4l2_device_register_subdev(&rsz->rkisp1->v4l2_dev, sd); + if (ret) { + dev_err(sd->dev, "Failed to register resizer subdev\n"); + goto err_cleanup_media_entity; + } + + rkisp1_rsz_init_config(sd, rsz->pad_cfg); + return 0; + +err_cleanup_media_entity: + media_entity_cleanup(&sd->entity); + + return ret; +} + +int rkisp1_resizer_devs_register(struct rkisp1_device *rkisp1) +{ + struct rkisp1_resizer *rsz; + unsigned int i, j; + int ret; + + for (i = 0; i < ARRAY_SIZE(rkisp1->resizer_devs); i++) { + rsz = &rkisp1->resizer_devs[i]; + rsz->rkisp1 = rkisp1; + rsz->id = i; + ret = rkisp1_rsz_register(rsz); + if (ret) + goto err_unreg_resizer_devs; + } + + return 0; + +err_unreg_resizer_devs: + for (j = 0; j < i; j++) { + rsz = &rkisp1->resizer_devs[j]; + rkisp1_rsz_unregister(rsz); + } + + return ret; +} + +void rkisp1_resizer_devs_unregister(struct rkisp1_device *rkisp1) +{ + struct rkisp1_resizer *mp = &rkisp1->resizer_devs[RKISP1_MAINPATH]; + struct rkisp1_resizer *sp = &rkisp1->resizer_devs[RKISP1_SELFPATH]; + + rkisp1_rsz_unregister(mp); + rkisp1_rsz_unregister(sp); +} From patchwork Wed Jan 8 18:44:47 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Helen Koike X-Patchwork-Id: 11324329 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 35690139A for ; Wed, 8 Jan 2020 18:46:58 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 1000420705 for ; Wed, 8 Jan 2020 18:46:57 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="opTTN5Vs" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 1000420705 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=collabora.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-rockchip-bounces+patchwork-linux-rockchip=patchwork.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=l1tV3zcHgygI9tebneNUJD9OiXZg/HnEaY8kPsfSn/E=; b=opTTN5Vs7Gt8b9 WUjNqQ7pmcMioTvh8xmFks+pFUXfuy/QeN1ncS0yaS/kbqtZPcYZD73pr1yqy3Z4eYrzhsIMtDgGE xehM5B4XUM0WagNaSKKS00g1VNcI2e9f25YuYueUG4t1xjRJ6nvJjMFGTR9hb8Lzx34jg13i3npZB b4wlIFhskrglldYFmhB91ZDpg/jwqyF4bHO5wdzHMKsJT8z1XPI7z+zwfqrRa0LemfOtBb/+Yt9zc T15rx9bqCKDyRECJ4FHjVs0DXBJdQeR9X4LQm3sgNWzqYQwGq2wlhSXPeSryCxPC9WyiI0Bs3I17B b08xJ3DE2UcsF3MSREvQ==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1ipGM2-0000m9-Ci; Wed, 08 Jan 2020 18:46:54 +0000 Received: from bhuna.collabora.co.uk ([46.235.227.227]) by bombadil.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1ipGL2-0008K8-5l; Wed, 08 Jan 2020 18:45:58 +0000 Received: from [127.0.0.1] (localhost [127.0.0.1]) (Authenticated sender: koike) with ESMTPSA id 0902A2912EC From: Helen Koike To: linux-rockchip@lists.infradead.org Subject: [PATCH v13 04/11] media: staging: rkisp1: add user space ABI definitions Date: Wed, 8 Jan 2020 15:44:47 -0300 Message-Id: <20200108184454.825725-5-helen.koike@collabora.com> X-Mailer: git-send-email 2.24.0 In-Reply-To: <20200108184454.825725-1-helen.koike@collabora.com> References: <20200108184454.825725-1-helen.koike@collabora.com> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20200108_104552_519035_3401FFD4 X-CRM114-Status: GOOD ( 12.22 ) X-Spam-Score: -0.0 (/) X-Spam-Report: SpamAssassin version 3.4.2 on bombadil.infradead.org summary: Content analysis details: (-0.0 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at https://www.dnswl.org/, no trust [46.235.227.227 listed in list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record -0.0 SPF_HELO_PASS SPF: HELO matches SPF record 0.0 UNPARSEABLE_RELAY Informational: message has unparseable relay lines X-BeenThere: linux-rockchip@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Upstream kernel work for Rockchip platforms List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: mark.rutland@arm.com, eddie.cai.linux@gmail.com, heiko@sntech.de, laurent.pinchart@ideasonboard.com, joacim.zetterling@gmail.com, kernel@collabora.com, jacob-chen@iotwrt.com, hans.verkuil@cisco.com, andrey.konovalov@linaro.org, linux-media@vger.kernel.org, devicetree@vger.kernel.org, Jeffy Chen , Helen Koike , robh+dt@kernel.org, mchehab@kernel.org, ezequiel@collabora.com, linux-arm-kernel@lists.infradead.org, gregkh@linuxfoundation.org, linux-kernel@vger.kernel.org, tfiga@chromium.org, sakari.ailus@linux.intel.com, Jacob Chen Sender: "Linux-rockchip" Errors-To: linux-rockchip-bounces+patchwork-linux-rockchip=patchwork.kernel.org@lists.infradead.org From: Jeffy Chen Add the header for userspace Signed-off-by: Jeffy Chen Signed-off-by: Jacob Chen Signed-off-by: Helen Koike --- Changes in v13: None Changes in v12: - Change Jacob's email to original jacob2.chen@rock-chips.com Changes in v11: - fix checkpatch errors Changes in v10: - unsquash - define metadata pixelformats in uapi/rkisp1-config.h Changes in v9: - squash - move to staging Changes in v8: None Changes in v7: - Fix checkpatch errors (lines over 80 and SPDX) - Add TODO to improve docs .../staging/media/rkisp1/uapi/rkisp1-config.h | 819 ++++++++++++++++++ 1 file changed, 819 insertions(+) create mode 100644 drivers/staging/media/rkisp1/uapi/rkisp1-config.h diff --git a/drivers/staging/media/rkisp1/uapi/rkisp1-config.h b/drivers/staging/media/rkisp1/uapi/rkisp1-config.h new file mode 100644 index 000000000000..ca0d031b14ac --- /dev/null +++ b/drivers/staging/media/rkisp1/uapi/rkisp1-config.h @@ -0,0 +1,819 @@ +/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */ +/* + * Rockchip ISP1 userspace API + * Copyright (C) 2017 Rockchip Electronics Co., Ltd. + */ + +/* + * TODO: Improve documentation, mostly regarding abbreviation and hardware + * specificities. Reference: "REF_01 - ISP_user_manual, Rev 2.57" (not public) + */ + +#ifndef _UAPI_RKISP1_CONFIG_H +#define _UAPI_RKISP1_CONFIG_H + +#include + +/* Vendor specific - used for RK_ISP1 camera sub-system */ +#define V4L2_META_FMT_RK_ISP1_PARAMS v4l2_fourcc('R', 'K', '1', 'P') /* Rockchip ISP1 params */ +#define V4L2_META_FMT_RK_ISP1_STAT_3A v4l2_fourcc('R', 'K', '1', 'S') /* Rockchip ISP1 3A statistics */ + +#define RKISP1_CIF_ISP_MODULE_DPCC BIT(0) +#define RKISP1_CIF_ISP_MODULE_BLS BIT(1) +#define RKISP1_CIF_ISP_MODULE_SDG BIT(2) +#define RKISP1_CIF_ISP_MODULE_HST BIT(3) +#define RKISP1_CIF_ISP_MODULE_LSC BIT(4) +#define RKISP1_CIF_ISP_MODULE_AWB_GAIN BIT(5) +#define RKISP1_CIF_ISP_MODULE_FLT BIT(6) +#define RKISP1_CIF_ISP_MODULE_BDM BIT(7) +#define RKISP1_CIF_ISP_MODULE_CTK BIT(8) +#define RKISP1_CIF_ISP_MODULE_GOC BIT(9) +#define RKISP1_CIF_ISP_MODULE_CPROC BIT(10) +#define RKISP1_CIF_ISP_MODULE_AFC BIT(11) +#define RKISP1_CIF_ISP_MODULE_AWB BIT(12) +#define RKISP1_CIF_ISP_MODULE_IE BIT(13) +#define RKISP1_CIF_ISP_MODULE_AEC BIT(14) +#define RKISP1_CIF_ISP_MODULE_WDR BIT(15) +#define RKISP1_CIF_ISP_MODULE_DPF BIT(16) +#define RKISP1_CIF_ISP_MODULE_DPF_STRENGTH BIT(17) + +#define RKISP1_CIF_ISP_CTK_COEFF_MAX 0x100 +#define RKISP1_CIF_ISP_CTK_OFFSET_MAX 0x800 + +#define RKISP1_CIF_ISP_AE_MEAN_MAX 25 +#define RKISP1_CIF_ISP_HIST_BIN_N_MAX 16 +#define RKISP1_CIF_ISP_AFM_MAX_WINDOWS 3 +#define RKISP1_CIF_ISP_DEGAMMA_CURVE_SIZE 17 + +#define RKISP1_CIF_ISP_BDM_MAX_TH 0xff + +/* + * Black level compensation + */ +/* maximum value for horizontal start address */ +#define RKISP1_CIF_ISP_BLS_START_H_MAX 0x00000fff +/* maximum value for horizontal stop address */ +#define RKISP1_CIF_ISP_BLS_STOP_H_MAX 0x00000fff +/* maximum value for vertical start address */ +#define RKISP1_CIF_ISP_BLS_START_V_MAX 0x00000fff +/* maximum value for vertical stop address */ +#define RKISP1_CIF_ISP_BLS_STOP_V_MAX 0x00000fff +/* maximum is 2^18 = 262144*/ +#define RKISP1_CIF_ISP_BLS_SAMPLES_MAX 0x00000012 +/* maximum value for fixed black level */ +#define RKISP1_CIF_ISP_BLS_FIX_SUB_MAX 0x00000fff +/* minimum value for fixed black level */ +#define RKISP1_CIF_ISP_BLS_FIX_SUB_MIN 0xfffff000 +/* 13 bit range (signed)*/ +#define RKISP1_CIF_ISP_BLS_FIX_MASK 0x00001fff + +/* + * Automatic white balance measurments + */ +#define RKISP1_CIF_ISP_AWB_MAX_GRID 1 +#define RKISP1_CIF_ISP_AWB_MAX_FRAMES 7 + +/* + * Gamma out + */ +/* Maximum number of color samples supported */ +#define RKISP1_CIF_ISP_GAMMA_OUT_MAX_SAMPLES 17 + +/* + * Lens shade correction + */ +#define RKISP1_CIF_ISP_LSC_GRAD_TBL_SIZE 8 +#define RKISP1_CIF_ISP_LSC_SIZE_TBL_SIZE 8 +/* + * The following matches the tuning process, + * not the max capabilities of the chip. + * Last value unused. + */ +#define RKISP1_CIF_ISP_LSC_DATA_TBL_SIZE 290 + +/* + * Histogram calculation + */ +/* Last 3 values unused. */ +#define RKISP1_CIF_ISP_HISTOGRAM_WEIGHT_GRIDS_SIZE 28 + +/* + * Defect Pixel Cluster Correction + */ +#define RKISP1_CIF_ISP_DPCC_METHODS_MAX 3 + +/* + * Denoising pre filter + */ +#define RKISP1_CIF_ISP_DPF_MAX_NLF_COEFFS 17 +#define RKISP1_CIF_ISP_DPF_MAX_SPATIAL_COEFFS 6 + +/* + * Measurement types + */ +#define RKISP1_CIF_ISP_STAT_AWB BIT(0) +#define RKISP1_CIF_ISP_STAT_AUTOEXP BIT(1) +#define RKISP1_CIF_ISP_STAT_AFM_FIN BIT(2) +#define RKISP1_CIF_ISP_STAT_HIST BIT(3) + +enum rkisp1_cif_isp_histogram_mode { + RKISP1_CIF_ISP_HISTOGRAM_MODE_DISABLE, + RKISP1_CIF_ISP_HISTOGRAM_MODE_RGB_COMBINED, + RKISP1_CIF_ISP_HISTOGRAM_MODE_R_HISTOGRAM, + RKISP1_CIF_ISP_HISTOGRAM_MODE_G_HISTOGRAM, + RKISP1_CIF_ISP_HISTOGRAM_MODE_B_HISTOGRAM, + RKISP1_CIF_ISP_HISTOGRAM_MODE_Y_HISTOGRAM +}; + +enum rkisp1_cif_isp_awb_mode_type { + RKISP1_CIF_ISP_AWB_MODE_MANUAL, + RKISP1_CIF_ISP_AWB_MODE_RGB, + RKISP1_CIF_ISP_AWB_MODE_YCBCR +}; + +enum rkisp1_cif_isp_flt_mode { + RKISP1_CIF_ISP_FLT_STATIC_MODE, + RKISP1_CIF_ISP_FLT_DYNAMIC_MODE +}; + +/** + * enum rkisp1_cif_isp_exp_ctrl_autostop - stop modes + * @RKISP1_CIF_ISP_EXP_CTRL_AUTOSTOP_0: continuous measurement + * @RKISP1_CIF_ISP_EXP_CTRL_AUTOSTOP_1: stop measuring after a complete frame + */ +enum rkisp1_cif_isp_exp_ctrl_autostop { + RKISP1_CIF_ISP_EXP_CTRL_AUTOSTOP_0 = 0, + RKISP1_CIF_ISP_EXP_CTRL_AUTOSTOP_1 = 1, +}; + +/** + * enum rkisp1_cif_isp_exp_meas_mode - Exposure measure mode + * @RKISP1_CIF_ISP_EXP_MEASURING_MODE_0: Y = 16 + 0.25R + 0.5G + 0.1094B + * @RKISP1_CIF_ISP_EXP_MEASURING_MODE_1: Y = (R + G + B) x (85/256) + */ +enum rkisp1_cif_isp_exp_meas_mode { + RKISP1_CIF_ISP_EXP_MEASURING_MODE_0, + RKISP1_CIF_ISP_EXP_MEASURING_MODE_1, +}; + +/*---------- PART1: Input Parameters ------------*/ + +struct rkisp1_cif_isp_window { + __u16 h_offs; + __u16 v_offs; + __u16 h_size; + __u16 v_size; +} __packed; + +/** + * struct rkisp1_cif_isp_bls_fixed_val - BLS fixed subtraction values + * + * The values will be subtracted from the sensor + * values. Therefore a negative value means addition instead of subtraction! + * + * @r: Fixed (signed!) subtraction value for Bayer pattern R + * @gr: Fixed (signed!) subtraction value for Bayer pattern Gr + * @gb: Fixed (signed!) subtraction value for Bayer pattern Gb + * @b: Fixed (signed!) subtraction value for Bayer pattern B + */ +struct rkisp1_cif_isp_bls_fixed_val { + __s16 r; + __s16 gr; + __s16 gb; + __s16 b; +} __packed; + +/** + * struct rkisp1_cif_isp_bls_config - Configuration used by black level subtraction + * + * @enable_auto: Automatic mode activated means that the measured values + * are subtracted. Otherwise the fixed subtraction + * values will be subtracted. + * @en_windows: enabled window + * @bls_window1: Measurement window 1 size + * @bls_window2: Measurement window 2 size + * @bls_samples: Set amount of measured pixels for each Bayer position + * (A, B,C and D) to 2^bls_samples. + * @fixed_val: Fixed subtraction values + */ +struct rkisp1_cif_isp_bls_config { + __u8 enable_auto; + __u8 en_windows; + struct rkisp1_cif_isp_window bls_window1; + struct rkisp1_cif_isp_window bls_window2; + __u8 bls_samples; + struct rkisp1_cif_isp_bls_fixed_val fixed_val; +} __packed; + +/** + * struct rkisp1_cif_isp_dpcc_methods_config - Methods Configuration used by DPCC + * + * Methods Configuration used by Defect Pixel Cluster Correction + * + * @method: Method enable bits + * @line_thresh: Line threshold + * @line_mad_fac: Line MAD factor + * @pg_fac: Peak gradient factor + * @rnd_thresh: Rank Neighbor Difference threshold + * @rg_fac: Rank gradient factor + */ +struct rkisp1_cif_isp_dpcc_methods_config { + __u32 method; + __u32 line_thresh; + __u32 line_mad_fac; + __u32 pg_fac; + __u32 rnd_thresh; + __u32 rg_fac; +} __packed; + +/** + * struct rkisp1_cif_isp_dpcc_config - Configuration used by DPCC + * + * Configuration used by Defect Pixel Cluster Correction + * + * @mode: dpcc output mode + * @output_mode: whether use hard coded methods + * @set_use: stage1 methods set + * @methods: methods config + * @ro_limits: rank order limits + * @rnd_offs: differential rank offsets for rank neighbor difference + */ +struct rkisp1_cif_isp_dpcc_config { + __u32 mode; + __u32 output_mode; + __u32 set_use; + struct rkisp1_cif_isp_dpcc_methods_config methods[RKISP1_CIF_ISP_DPCC_METHODS_MAX]; + __u32 ro_limits; + __u32 rnd_offs; +} __packed; + +struct rkisp1_cif_isp_gamma_corr_curve { + __u16 gamma_y[RKISP1_CIF_ISP_DEGAMMA_CURVE_SIZE]; +} __packed; + +struct rkisp1_cif_isp_gamma_curve_x_axis_pnts { + __u32 gamma_dx0; + __u32 gamma_dx1; +} __packed; + +/** + * struct rkisp1_cif_isp_sdg_config - Configuration used by sensor degamma + * + * @curve_x: gamma curve point definition axis for x + * @xa_pnts: x increments + */ +struct rkisp1_cif_isp_sdg_config { + struct rkisp1_cif_isp_gamma_corr_curve curve_r; + struct rkisp1_cif_isp_gamma_corr_curve curve_g; + struct rkisp1_cif_isp_gamma_corr_curve curve_b; + struct rkisp1_cif_isp_gamma_curve_x_axis_pnts xa_pnts; +} __packed; + +/** + * struct rkisp1_cif_isp_lsc_config - Configuration used by Lens shading correction + * + * refer to REF_01 for details + */ +struct rkisp1_cif_isp_lsc_config { + __u32 r_data_tbl[RKISP1_CIF_ISP_LSC_DATA_TBL_SIZE]; + __u32 gr_data_tbl[RKISP1_CIF_ISP_LSC_DATA_TBL_SIZE]; + __u32 gb_data_tbl[RKISP1_CIF_ISP_LSC_DATA_TBL_SIZE]; + __u32 b_data_tbl[RKISP1_CIF_ISP_LSC_DATA_TBL_SIZE]; + + __u32 x_grad_tbl[RKISP1_CIF_ISP_LSC_GRAD_TBL_SIZE]; + __u32 y_grad_tbl[RKISP1_CIF_ISP_LSC_GRAD_TBL_SIZE]; + + __u32 x_size_tbl[RKISP1_CIF_ISP_LSC_SIZE_TBL_SIZE]; + __u32 y_size_tbl[RKISP1_CIF_ISP_LSC_SIZE_TBL_SIZE]; + __u16 config_width; + __u16 config_height; +} __packed; + +/** + * struct rkisp1_cif_isp_ie_config - Configuration used by image effects + * + * @eff_mat_1: 3x3 Matrix Coefficients for Emboss Effect 1 + * @eff_mat_2: 3x3 Matrix Coefficients for Emboss Effect 2 + * @eff_mat_3: 3x3 Matrix Coefficients for Emboss 3/Sketch 1 + * @eff_mat_4: 3x3 Matrix Coefficients for Sketch Effect 2 + * @eff_mat_5: 3x3 Matrix Coefficients for Sketch Effect 3 + * @eff_tint: Chrominance increment values of tint (used for sepia effect) + */ +struct rkisp1_cif_isp_ie_config { + __u16 effect; + __u16 color_sel; + __u16 eff_mat_1; + __u16 eff_mat_2; + __u16 eff_mat_3; + __u16 eff_mat_4; + __u16 eff_mat_5; + __u16 eff_tint; +} __packed; + +/** + * struct rkisp1_cif_isp_cproc_config - Configuration used by Color Processing + * + * @c_out_range: Chrominance pixel clipping range at output. + * (0 for limit, 1 for full) + * @y_in_range: Luminance pixel clipping range at output. + * @y_out_range: Luminance pixel clipping range at output. + * @contrast: 00~ff, 0.0~1.992 + * @brightness: 80~7F, -128~+127 + * @sat: saturation, 00~FF, 0.0~1.992 + * @hue: 80~7F, -90~+87.188 + */ +struct rkisp1_cif_isp_cproc_config { + __u8 c_out_range; + __u8 y_in_range; + __u8 y_out_range; + __u8 contrast; + __u8 brightness; + __u8 sat; + __u8 hue; +} __packed; + +/** + * struct rkisp1_cif_isp_awb_meas_config - Configuration used by auto white balance + * + * @awb_wnd: white balance measurement window (in pixels) + * (from enum rkisp1_cif_isp_awb_mode_type) + * @max_y: only pixels values < max_y contribute to awb measurement, set to 0 + * to disable this feature + * @min_y: only pixels values > min_y contribute to awb measurement + * @max_csum: Chrominance sum maximum value, only consider pixels with Cb+Cr, + * smaller than threshold for awb measurements + * @min_c: Chrominance minimum value, only consider pixels with Cb/Cr + * each greater than threshold value for awb measurements + * @frames: number of frames - 1 used for mean value calculation + * (ucFrames=0 means 1 Frame) + * @awb_ref_cr: reference Cr value for AWB regulation, target for AWB + * @awb_ref_cb: reference Cb value for AWB regulation, target for AWB + */ +struct rkisp1_cif_isp_awb_meas_config { + /* + * Note: currently the h and v offsets are mapped to grid offsets + */ + struct rkisp1_cif_isp_window awb_wnd; + __u32 awb_mode; + __u8 max_y; + __u8 min_y; + __u8 max_csum; + __u8 min_c; + __u8 frames; + __u8 awb_ref_cr; + __u8 awb_ref_cb; + __u8 enable_ymax_cmp; +} __packed; + +/** + * struct rkisp1_cif_isp_awb_gain_config - Configuration used by auto white balance gain + * + * out_data_x = ( AWB_GEAIN_X * in_data + 128) >> 8 + */ +struct rkisp1_cif_isp_awb_gain_config { + __u16 gain_red; + __u16 gain_green_r; + __u16 gain_blue; + __u16 gain_green_b; +} __packed; + +/** + * struct rkisp1_cif_isp_flt_config - Configuration used by ISP filtering + * + * @mode: ISP_FILT_MODE register fields (from enum rkisp1_cif_isp_flt_mode) + * @grn_stage1: ISP_FILT_MODE register fields + * @chr_h_mode: ISP_FILT_MODE register fields + * @chr_v_mode: ISP_FILT_MODE register fields + * + * refer to REF_01 for details. + */ + +struct rkisp1_cif_isp_flt_config { + __u32 mode; + __u8 grn_stage1; + __u8 chr_h_mode; + __u8 chr_v_mode; + __u32 thresh_bl0; + __u32 thresh_bl1; + __u32 thresh_sh0; + __u32 thresh_sh1; + __u32 lum_weight; + __u32 fac_sh1; + __u32 fac_sh0; + __u32 fac_mid; + __u32 fac_bl0; + __u32 fac_bl1; +} __packed; + +/** + * struct rkisp1_cif_isp_bdm_config - Configuration used by Bayer DeMosaic + * + * @demosaic_th: threshod for bayer demosaicing texture detection + */ +struct rkisp1_cif_isp_bdm_config { + __u8 demosaic_th; +} __packed; + +/** + * struct rkisp1_cif_isp_ctk_config - Configuration used by Cross Talk correction + * + * @coeff: color correction matrix + * @ct_offset_b: offset for the crosstalk correction matrix + */ +struct rkisp1_cif_isp_ctk_config { + __u16 coeff0; + __u16 coeff1; + __u16 coeff2; + __u16 coeff3; + __u16 coeff4; + __u16 coeff5; + __u16 coeff6; + __u16 coeff7; + __u16 coeff8; + __u16 ct_offset_r; + __u16 ct_offset_g; + __u16 ct_offset_b; +} __packed; + +enum rkisp1_cif_isp_goc_mode { + RKISP1_CIF_ISP_GOC_MODE_LOGARITHMIC, + RKISP1_CIF_ISP_GOC_MODE_EQUIDISTANT +}; + +/** + * struct rkisp1_cif_isp_goc_config - Configuration used by Gamma Out correction + * + * @mode: goc mode (from enum rkisp1_cif_isp_goc_mode) + * @gamma_y: gamma out curve y-axis for all color components + */ +struct rkisp1_cif_isp_goc_config { + __u32 mode; + __u16 gamma_y[RKISP1_CIF_ISP_GAMMA_OUT_MAX_SAMPLES]; +} __packed; + +/** + * struct rkisp1_cif_isp_hst_config - Configuration used by Histogram + * + * @mode: histogram mode (from enum rkisp1_cif_isp_histogram_mode) + * @histogram_predivider: process every stepsize pixel, all other pixels are + * skipped + * @meas_window: coordinates of the measure window + * @hist_weight: weighting factor for sub-windows + */ +struct rkisp1_cif_isp_hst_config { + __u32 mode; + __u8 histogram_predivider; + struct rkisp1_cif_isp_window meas_window; + __u8 hist_weight[RKISP1_CIF_ISP_HISTOGRAM_WEIGHT_GRIDS_SIZE]; +} __packed; + +/** + * struct rkisp1_cif_isp_aec_config - Configuration used by Auto Exposure Control + * + * @mode: Exposure measure mode (from enum rkisp1_cif_isp_exp_meas_mode) + * @autostop: stop mode (from enum rkisp1_cif_isp_exp_ctrl_autostop) + * @meas_window: coordinates of the measure window + */ +struct rkisp1_cif_isp_aec_config { + __u32 mode; + __u32 autostop; + struct rkisp1_cif_isp_window meas_window; +} __packed; + +/** + * struct rkisp1_cif_isp_afc_config - Configuration used by Auto Focus Control + * + * @num_afm_win: max RKISP1_CIF_ISP_AFM_MAX_WINDOWS + * @afm_win: coordinates of the meas window + * @thres: threshold used for minimizing the influence of noise + * @var_shift: the number of bits for the shift operation at the end of the + * calculation chain. + */ +struct rkisp1_cif_isp_afc_config { + __u8 num_afm_win; + struct rkisp1_cif_isp_window afm_win[RKISP1_CIF_ISP_AFM_MAX_WINDOWS]; + __u32 thres; + __u32 var_shift; +} __packed; + +/** + * enum rkisp1_cif_isp_dpf_gain_usage - dpf gain usage + * @RKISP1_CIF_ISP_DPF_GAIN_USAGE_DISABLED: don't use any gains in preprocessing stage + * @RKISP1_CIF_ISP_DPF_GAIN_USAGE_NF_GAINS: use only the noise function gains from + * registers DPF_NF_GAIN_R, ... + * @RKISP1_CIF_ISP_DPF_GAIN_USAGE_LSC_GAINS: use only the gains from LSC module + * @RKISP1_CIF_ISP_DPF_GAIN_USAGE_NF_LSC_GAINS: use the noise function gains and the + * gains from LSC module + * @RKISP1_CIF_ISP_DPF_GAIN_USAGE_AWB_GAINS: use only the gains from AWB module + * @RKISP1_CIF_ISP_DPF_GAIN_USAGE_AWB_LSC_GAINS: use the gains from AWB and LSC module + * @RKISP1_CIF_ISP_DPF_GAIN_USAGE_MAX: upper border (only for an internal evaluation) + */ +enum rkisp1_cif_isp_dpf_gain_usage { + RKISP1_CIF_ISP_DPF_GAIN_USAGE_DISABLED, + RKISP1_CIF_ISP_DPF_GAIN_USAGE_NF_GAINS, + RKISP1_CIF_ISP_DPF_GAIN_USAGE_LSC_GAINS, + RKISP1_CIF_ISP_DPF_GAIN_USAGE_NF_LSC_GAINS, + RKISP1_CIF_ISP_DPF_GAIN_USAGE_AWB_GAINS, + RKISP1_CIF_ISP_DPF_GAIN_USAGE_AWB_LSC_GAINS, + RKISP1_CIF_ISP_DPF_GAIN_USAGE_MAX +}; + +/** + * enum rkisp1_cif_isp_dpf_rb_filtersize - Red and blue filter sizes + * @RKISP1_CIF_ISP_DPF_RB_FILTERSIZE_13x9: red and blue filter kernel size 13x9 + * (means 7x5 active pixel) + * @RKISP1_CIF_ISP_DPF_RB_FILTERSIZE_9x9: red and blue filter kernel size 9x9 + * (means 5x5 active pixel) + */ +enum rkisp1_cif_isp_dpf_rb_filtersize { + RKISP1_CIF_ISP_DPF_RB_FILTERSIZE_13x9, + RKISP1_CIF_ISP_DPF_RB_FILTERSIZE_9x9, +}; + +/** + * enum rkisp1_cif_isp_dpf_nll_scale_mode - dpf noise level scale mode + * @RKISP1_CIF_ISP_NLL_SCALE_LINEAR: use a linear scaling + * @RKISP1_CIF_ISP_NLL_SCALE_LOGARITHMIC: use a logarithmic scaling + */ +enum rkisp1_cif_isp_dpf_nll_scale_mode { + RKISP1_CIF_ISP_NLL_SCALE_LINEAR, + RKISP1_CIF_ISP_NLL_SCALE_LOGARITHMIC, +}; + +/** + * struct rkisp1_cif_isp_dpf_nll - Noise level lookup + * + * @coeff: Noise level Lookup coefficient + * @scale_mode: dpf noise level scale mode (from enum rkisp1_cif_isp_dpf_nll_scale_mode) + */ +struct rkisp1_cif_isp_dpf_nll { + __u16 coeff[RKISP1_CIF_ISP_DPF_MAX_NLF_COEFFS]; + __u32 scale_mode; +} __packed; + +/** + * struct rkisp1_cif_isp_dpf_rb_flt - Red blue filter config + * + * @fltsize: The filter size for the red and blue pixels + * (from enum rkisp1_cif_isp_dpf_rb_filtersize) + * @spatial_coeff: Spatial weights + * @r_enable: enable filter processing for red pixels + * @b_enable: enable filter processing for blue pixels + */ +struct rkisp1_cif_isp_dpf_rb_flt { + __u32 fltsize; + __u8 spatial_coeff[RKISP1_CIF_ISP_DPF_MAX_SPATIAL_COEFFS]; + __u8 r_enable; + __u8 b_enable; +} __packed; + +/** + * struct rkisp1_cif_isp_dpf_g_flt - Green filter Configuration + * + * @spatial_coeff: Spatial weights + * @gr_enable: enable filter processing for green pixels in green/red lines + * @gb_enable: enable filter processing for green pixels in green/blue lines + */ +struct rkisp1_cif_isp_dpf_g_flt { + __u8 spatial_coeff[RKISP1_CIF_ISP_DPF_MAX_SPATIAL_COEFFS]; + __u8 gr_enable; + __u8 gb_enable; +} __packed; + +/** + * struct rkisp1_cif_isp_dpf_gain - Noise function Configuration + * + * @mode: dpf gain usage (from enum rkisp1_cif_isp_dpf_gain_usage) + * @nf_r_gain: Noise function Gain that replaces the AWB gain for red pixels + * @nf_b_gain: Noise function Gain that replaces the AWB gain for blue pixels + * @nf_gr_gain: Noise function Gain that replaces the AWB gain + * for green pixels in a red line + * @nf_gb_gain: Noise function Gain that replaces the AWB gain + * for green pixels in a blue line + */ +struct rkisp1_cif_isp_dpf_gain { + __u32 mode; + __u16 nf_r_gain; + __u16 nf_b_gain; + __u16 nf_gr_gain; + __u16 nf_gb_gain; +} __packed; + +/** + * struct rkisp1_cif_isp_dpf_config - Configuration used by De-noising pre-filter + * + * @gain: noise function gain + * @g_flt: green filter config + * @rb_flt: red blue filter config + * @nll: noise level lookup + */ +struct rkisp1_cif_isp_dpf_config { + struct rkisp1_cif_isp_dpf_gain gain; + struct rkisp1_cif_isp_dpf_g_flt g_flt; + struct rkisp1_cif_isp_dpf_rb_flt rb_flt; + struct rkisp1_cif_isp_dpf_nll nll; +} __packed; + +/** + * struct rkisp1_cif_isp_dpf_strength_config - strength of the filter + * + * @r: filter strength of the RED filter + * @g: filter strength of the GREEN filter + * @b: filter strength of the BLUE filter + */ +struct rkisp1_cif_isp_dpf_strength_config { + __u8 r; + __u8 g; + __u8 b; +} __packed; + +/** + * struct rkisp1_cif_isp_isp_other_cfg - Parameters for some blocks in rockchip isp1 + * + * @dpcc_config: Defect Pixel Cluster Correction config + * @bls_config: Black Level Subtraction config + * @sdg_config: sensor degamma config + * @lsc_config: Lens Shade config + * @awb_gain_config: Auto White balance gain config + * @flt_config: filter config + * @bdm_config: demosaic config + * @ctk_config: cross talk config + * @goc_config: gamma out config + * @bls_config: black level subtraction config + * @dpf_config: De-noising pre-filter config + * @dpf_strength_config: dpf strength config + * @cproc_config: color process config + * @ie_config: image effects config + */ +struct rkisp1_cif_isp_isp_other_cfg { + struct rkisp1_cif_isp_dpcc_config dpcc_config; + struct rkisp1_cif_isp_bls_config bls_config; + struct rkisp1_cif_isp_sdg_config sdg_config; + struct rkisp1_cif_isp_lsc_config lsc_config; + struct rkisp1_cif_isp_awb_gain_config awb_gain_config; + struct rkisp1_cif_isp_flt_config flt_config; + struct rkisp1_cif_isp_bdm_config bdm_config; + struct rkisp1_cif_isp_ctk_config ctk_config; + struct rkisp1_cif_isp_goc_config goc_config; + struct rkisp1_cif_isp_dpf_config dpf_config; + struct rkisp1_cif_isp_dpf_strength_config dpf_strength_config; + struct rkisp1_cif_isp_cproc_config cproc_config; + struct rkisp1_cif_isp_ie_config ie_config; +} __packed; + +/** + * struct rkisp1_cif_isp_isp_meas_cfg - Rockchip ISP1 Measure Parameters + * + * @awb_meas_config: auto white balance config + * @hst_config: histogram config + * @aec_config: auto exposure config + * @afc_config: auto focus config + */ +struct rkisp1_cif_isp_isp_meas_cfg { + struct rkisp1_cif_isp_awb_meas_config awb_meas_config; + struct rkisp1_cif_isp_hst_config hst_config; + struct rkisp1_cif_isp_aec_config aec_config; + struct rkisp1_cif_isp_afc_config afc_config; +} __packed; + +/** + * struct rkisp1_params_cfg - Rockchip ISP1 Input Parameters Meta Data + * + * @module_en_update: mask the enable bits of which module should be updated + * @module_ens: mask the enable value of each module, only update the module + * which correspond bit was set in module_en_update + * @module_cfg_update: mask the config bits of which module should be updated + * @meas: measurement config + * @others: other config + */ +struct rkisp1_params_cfg { + __u32 module_en_update; + __u32 module_ens; + __u32 module_cfg_update; + + struct rkisp1_cif_isp_isp_meas_cfg meas; + struct rkisp1_cif_isp_isp_other_cfg others; +} __packed; + +/*---------- PART2: Measurement Statistics ------------*/ + +/** + * struct rkisp1_cif_isp_awb_meas - AWB measured values + * + * @cnt: White pixel count, number of "white pixels" found during last + * measurement + * @mean_y_or_g: Mean value of Y within window and frames, + * Green if RGB is selected. + * @mean_cb_or_b: Mean value of Cb within window and frames, + * Blue if RGB is selected. + * @mean_cr_or_r: Mean value of Cr within window and frames, + * Red if RGB is selected. + */ +struct rkisp1_cif_isp_awb_meas { + __u32 cnt; + __u8 mean_y_or_g; + __u8 mean_cb_or_b; + __u8 mean_cr_or_r; +} __packed; + +/** + * struct rkisp1_cif_isp_awb_stat - statistics automatic white balance data + * + * @awb_mean: Mean measured data + */ +struct rkisp1_cif_isp_awb_stat { + struct rkisp1_cif_isp_awb_meas awb_mean[RKISP1_CIF_ISP_AWB_MAX_GRID]; +} __packed; + +/** + * struct rkisp1_cif_isp_bls_meas_val - BLS measured values + * + * @meas_r: Mean measured value for Bayer pattern R + * @meas_gr: Mean measured value for Bayer pattern Gr + * @meas_gb: Mean measured value for Bayer pattern Gb + * @meas_b: Mean measured value for Bayer pattern B + */ +struct rkisp1_cif_isp_bls_meas_val { + __u16 meas_r; + __u16 meas_gr; + __u16 meas_gb; + __u16 meas_b; +} __packed; + +/** + * struct rkisp1_cif_isp_ae_stat - statistics auto exposure data + * + * @exp_mean: Mean luminance value of block xx + * @bls_val: BLS measured values + * + * Image is divided into 5x5 blocks. + */ +struct rkisp1_cif_isp_ae_stat { + __u8 exp_mean[RKISP1_CIF_ISP_AE_MEAN_MAX]; + struct rkisp1_cif_isp_bls_meas_val bls_val; +} __packed; + +/** + * struct rkisp1_cif_isp_af_meas_val - AF measured values + * + * @sum: sharpness, refer to REF_01 for definition + * @lum: luminance, refer to REF_01 for definition + */ +struct rkisp1_cif_isp_af_meas_val { + __u32 sum; + __u32 lum; +} __packed; + +/** + * struct rkisp1_cif_isp_af_stat - statistics auto focus data + * + * @window: AF measured value of window x + * + * The module measures the sharpness in 3 windows of selectable size via + * register settings(ISP_AFM_*_A/B/C) + */ +struct rkisp1_cif_isp_af_stat { + struct rkisp1_cif_isp_af_meas_val window[RKISP1_CIF_ISP_AFM_MAX_WINDOWS]; +} __packed; + +/** + * struct rkisp1_cif_isp_hist_stat - statistics histogram data + * + * @hist_bins: measured bin counters + * + * Measurement window divided into 25 sub-windows, set + * with ISP_HIST_XXX + */ +struct rkisp1_cif_isp_hist_stat { + __u16 hist_bins[RKISP1_CIF_ISP_HIST_BIN_N_MAX]; +} __packed; + +/** + * struct rkisp1_stat_buffer - Rockchip ISP1 Statistics Data + * + * @rkisp1_cif_isp_awb_stat: statistics data for automatic white balance + * @rkisp1_cif_isp_ae_stat: statistics data for auto exposure + * @rkisp1_cif_isp_af_stat: statistics data for auto focus + * @rkisp1_cif_isp_hist_stat: statistics histogram data + */ +struct rkisp1_cif_isp_stat { + struct rkisp1_cif_isp_awb_stat awb; + struct rkisp1_cif_isp_ae_stat ae; + struct rkisp1_cif_isp_af_stat af; + struct rkisp1_cif_isp_hist_stat hist; +} __packed; + +/** + * struct rkisp1_stat_buffer - Rockchip ISP1 Statistics Meta Data + * + * @meas_type: measurement types (RKISP1_CIF_ISP_STAT_ definitions) + * @frame_id: frame ID for sync + * @params: statistics data + */ +struct rkisp1_stat_buffer { + __u32 meas_type; + __u32 frame_id; + struct rkisp1_cif_isp_stat params; +} __packed; + +#endif /* _UAPI_RKISP1_CONFIG_H */ From patchwork Wed Jan 8 18:44:48 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Helen Koike X-Patchwork-Id: 11324333 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id E061E921 for ; Wed, 8 Jan 2020 18:47:19 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id AA5BC20705 for ; Wed, 8 Jan 2020 18:47:19 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="uv/roPmB" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org AA5BC20705 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=collabora.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-rockchip-bounces+patchwork-linux-rockchip=patchwork.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=BRr614MPOYhBEX8O8PxM80Nbqd4JjAMPOv9qGQQDMgY=; b=uv/roPmBRxHwvF eImlzUtu4fAbOs6qcfdkakRQZKeYixnNF2axd5iAxBPd/o7BiuKxXhpdf49XpcZ25zkwM4C4umkIi 4Rzq9rjgRRZEi4AGJC3zlYCXRG3Paht4for0kW7hVuRDGmAkQK9ZyDJDm0br2sbVanrJjL1Zd8tdP ENV7JwuCCbbdwCVpLpVvAhMhLuu5GWYGYWnFek7arWZmtmZU/RLhqmlc5P1EZhL6gBpF1jGq3cgLF jVpKbgZ42r5GBluDcMd4sq14jDX9Nfk9XT1Kki+6jVLY4mAyVkx7fbk8rh/M3MYpZAkzwDanBYy9B h/PLblaQNX+P+wKaXxfw==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1ipGMN-00013r-N0; Wed, 08 Jan 2020 18:47:15 +0000 Received: from bhuna.collabora.co.uk ([2a00:1098:0:82:1000:25:2eeb:e3e3]) by bombadil.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1ipGLE-0008U0-BB; Wed, 08 Jan 2020 18:46:08 +0000 Received: from [127.0.0.1] (localhost [127.0.0.1]) (Authenticated sender: koike) with ESMTPSA id A23B126BBC2 From: Helen Koike To: linux-rockchip@lists.infradead.org Subject: [PATCH v13 05/11] media: staging: rkisp1: add capture device for statistics Date: Wed, 8 Jan 2020 15:44:48 -0300 Message-Id: <20200108184454.825725-6-helen.koike@collabora.com> X-Mailer: git-send-email 2.24.0 In-Reply-To: <20200108184454.825725-1-helen.koike@collabora.com> References: <20200108184454.825725-1-helen.koike@collabora.com> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20200108_104604_699844_AA34E34A X-CRM114-Status: GOOD ( 20.87 ) X-Spam-Score: -0.0 (/) X-Spam-Report: SpamAssassin version 3.4.2 on bombadil.infradead.org summary: Content analysis details: (-0.0 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 SPF_PASS SPF: sender matches SPF record -0.0 SPF_HELO_PASS SPF: HELO matches SPF record 0.0 UNPARSEABLE_RELAY Informational: message has unparseable relay lines X-BeenThere: linux-rockchip@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Upstream kernel work for Rockchip platforms List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: mark.rutland@arm.com, eddie.cai.linux@gmail.com, heiko@sntech.de, laurent.pinchart@ideasonboard.com, joacim.zetterling@gmail.com, kernel@collabora.com, andrey.konovalov@linaro.org, Yichong Zhong , jacob-chen@iotwrt.com, hans.verkuil@cisco.com, Allon Huang , Shunqian Zheng , linux-media@vger.kernel.org, devicetree@vger.kernel.org, Jacob Chen , Jeffy Chen , Helen Koike , robh+dt@kernel.org, mchehab@kernel.org, ezequiel@collabora.com, linux-arm-kernel@lists.infradead.org, gregkh@linuxfoundation.org, linux-kernel@vger.kernel.org, tfiga@chromium.org, sakari.ailus@linux.intel.com, Jacob Chen Sender: "Linux-rockchip" Errors-To: linux-rockchip-bounces+patchwork-linux-rockchip=patchwork.kernel.org@lists.infradead.org From: Jacob Chen Add the capture video driver for rockchip isp1 statistics block. Signed-off-by: Jacob Chen Signed-off-by: Shunqian Zheng Signed-off-by: Yichong Zhong Signed-off-by: Jacob Chen Signed-off-by: Eddie Cai Signed-off-by: Jeffy Chen Signed-off-by: Allon Huang Signed-off-by: Tomasz Figa Signed-off-by: Helen Koike --- Changes in v13: None Changes in v12: - Several cleanups - Commit re-organization to not break bisectability Changes in v11: stats - fix compiling warnings - fix checkpatch errors Changes in v10: - unsquash Changes in v9: - replace v4l2_{dgb,info,warn,err} by dev_* - remove LOG_ISR_EXE_TIME ifndef's - constify ops structs - s/strlcpy/strscpy - add missing mutex_destroy() calls in rkisp1_register_stats_vdev error path - squash - move to staging Changes in v8: None Changes in v7: - s/strlcpy/strscpy - sort out the locks in isp stats - code styling and checkpatch fixes drivers/staging/media/rkisp1/Makefile | 3 +- drivers/staging/media/rkisp1/rkisp1-common.h | 30 ++ drivers/staging/media/rkisp1/rkisp1-dev.c | 41 +- drivers/staging/media/rkisp1/rkisp1-isp.c | 12 + drivers/staging/media/rkisp1/rkisp1-stats.c | 530 +++++++++++++++++++ 5 files changed, 605 insertions(+), 11 deletions(-) create mode 100644 drivers/staging/media/rkisp1/rkisp1-stats.c diff --git a/drivers/staging/media/rkisp1/Makefile b/drivers/staging/media/rkisp1/Makefile index 1725b990d669..399f5c5f4d92 100644 --- a/drivers/staging/media/rkisp1/Makefile +++ b/drivers/staging/media/rkisp1/Makefile @@ -3,4 +3,5 @@ rockchip-isp1-objs += rkisp1-capture.o \ rkisp1-common.o \ rkisp1-dev.o \ rkisp1-isp.o \ - rkisp1-resizer.o + rkisp1-resizer.o \ + rkisp1-stats.o diff --git a/drivers/staging/media/rkisp1/rkisp1-common.h b/drivers/staging/media/rkisp1/rkisp1-common.h index e47916296b5b..c61bc2629412 100644 --- a/drivers/staging/media/rkisp1/rkisp1-common.h +++ b/drivers/staging/media/rkisp1/rkisp1-common.h @@ -20,6 +20,7 @@ #include #include "rkisp1-regs.h" +#include "uapi/rkisp1-config.h" #define RKISP1_ISP_MAX_WIDTH 4032 #define RKISP1_ISP_MAX_HEIGHT 3024 @@ -174,6 +175,26 @@ struct rkisp1_capture { } pix; }; +/* + * struct rkisp1_stats - ISP Statistics device + * + * @irq_lock: buffer queue lock + * @stat: stats buffer list + * @readout_wq: workqueue for statistics information read + */ +struct rkisp1_stats { + struct rkisp1_vdev_node vnode; + struct rkisp1_device *rkisp1; + + spinlock_t irq_lock; + struct list_head stat; + struct v4l2_format vdev_fmt; + bool is_streaming; + + struct workqueue_struct *readout_wq; + struct mutex wq_lock; +}; + struct rkisp1_resizer { struct v4l2_subdev sd; enum rkisp1_stream_id id; @@ -189,6 +210,7 @@ struct rkisp1_debug { unsigned long data_loss; unsigned long pic_size_error; unsigned long mipi_error; + unsigned long stats_error; unsigned long stop_timeout[2]; unsigned long frame_drop[2]; }; @@ -199,6 +221,7 @@ struct rkisp1_debug { * @active_sensor: sensor in-use, set when streaming on * @isp: ISP sub-device * @rkisp1_capture: capture video device + * @stats: ISP statistics output device */ struct rkisp1_device { void __iomem *base_addr; @@ -214,6 +237,7 @@ struct rkisp1_device { struct rkisp1_isp isp; struct rkisp1_resizer resizer_devs[2]; struct rkisp1_capture capture_devs[2]; + struct rkisp1_stats stats; struct media_pipeline pipe; struct vb2_alloc_ctx *alloc_ctx; struct rkisp1_debug debug; @@ -262,6 +286,7 @@ const struct rkisp1_isp_mbus_info *rkisp1_isp_mbus_info_get(u32 mbus_code); void rkisp1_isp_isr(struct rkisp1_device *rkisp1); void rkisp1_mipi_isr(struct rkisp1_device *rkisp1); void rkisp1_capture_isr(struct rkisp1_device *rkisp1); +void rkisp1_stats_isr(struct rkisp1_stats *stats, u32 isp_ris); int rkisp1_capture_devs_register(struct rkisp1_device *rkisp1); void rkisp1_capture_devs_unregister(struct rkisp1_device *rkisp1); @@ -269,4 +294,9 @@ void rkisp1_capture_devs_unregister(struct rkisp1_device *rkisp1); int rkisp1_resizer_devs_register(struct rkisp1_device *rkisp1); void rkisp1_resizer_devs_unregister(struct rkisp1_device *rkisp1); +int rkisp1_stats_register(struct rkisp1_stats *stats, + struct v4l2_device *v4l2_dev, + struct rkisp1_device *rkisp1); +void rkisp1_stats_unregister(struct rkisp1_stats *stats); + #endif /* _RKISP1_COMMON_H */ diff --git a/drivers/staging/media/rkisp1/rkisp1-dev.c b/drivers/staging/media/rkisp1/rkisp1-dev.c index 3d0a0f65eb19..07a1cbbea889 100644 --- a/drivers/staging/media/rkisp1/rkisp1-dev.c +++ b/drivers/staging/media/rkisp1/rkisp1-dev.c @@ -57,6 +57,14 @@ * | DMA |------------------------------------+ Self Picture Path * +--------+ * + * rkisp1-stats.c + * |===============| + * +---------------+ + * | | + * | ISP | + * | | + * +---------------+ + * * * Media Topology * -------------- @@ -74,14 +82,14 @@ * +----------+ |------+------| * | ISP | * |------+------| - * +-------------| 2 | 3 | - * | +------+------+ - * | | - * v v - * +- ---------+ +-----------+ - * | 0 | | 0 | - * ------------- ------------- - * | Resizer | | Resizer | + * +-------------| 2 | 3 |----------+ + * | +------+------+ | + * | | | + * v v v + * +- ---------+ +-----------+ +-----------+ + * | 0 | | 0 | | stats | + * ------------- ------------- | (capture) | + * | Resizer | | Resizer | +-----------+ * ------------| ------------| * | 1 | | 1 | * +-----------+ +-----------+ @@ -156,7 +164,11 @@ static int rkisp1_create_links(struct rkisp1_device *rkisp1) return ret; } - return 0; + /* 3A stats links */ + source = &rkisp1->isp.sd.entity; + sink = &rkisp1->stats.vnode.vdev.entity; + return media_create_pad_link(source, RKISP1_ISP_PAD_SOURCE_STATS, + sink, 0, flags); } static int rkisp1_subdev_notifier_bound(struct v4l2_async_notifier *notifier, @@ -336,14 +348,20 @@ static int rkisp1_entities_register(struct rkisp1_device *rkisp1) if (ret) goto err_unreg_resizer_devs; + ret = rkisp1_stats_register(&rkisp1->stats, &rkisp1->v4l2_dev, rkisp1); + if (ret) + goto err_unreg_capture_devs; + ret = rkisp1_subdev_notifier(rkisp1); if (ret) { dev_err(rkisp1->dev, "Failed to register subdev notifier(%d)\n", ret); - goto err_unreg_capture_devs; + goto err_unreg_stats; } return 0; +err_unreg_stats: + rkisp1_stats_unregister(&rkisp1->stats); err_unreg_capture_devs: rkisp1_capture_devs_unregister(rkisp1); err_unreg_resizer_devs: @@ -408,6 +426,8 @@ static void rkisp1_debug_init(struct rkisp1_device *rkisp1) &debug->pic_size_error); debugfs_create_ulong("mipi_error", 0444, debug->debugfs_dir, &debug->mipi_error); + debugfs_create_ulong("stats_error", 0444, debug->debugfs_dir, + &debug->stats_error); debugfs_create_ulong("mp_stop_timeout", 0444, debug->debugfs_dir, &debug->stop_timeout[RKISP1_MAINPATH]); debugfs_create_ulong("sp_stop_timeout", 0444, debug->debugfs_dir, @@ -509,6 +529,7 @@ static int rkisp1_remove(struct platform_device *pdev) v4l2_async_notifier_unregister(&rkisp1->notifier); v4l2_async_notifier_cleanup(&rkisp1->notifier); + rkisp1_stats_unregister(&rkisp1->stats); rkisp1_capture_devs_unregister(rkisp1); rkisp1_resizer_devs_unregister(rkisp1); rkisp1_isp_unregister(rkisp1); diff --git a/drivers/staging/media/rkisp1/rkisp1-isp.c b/drivers/staging/media/rkisp1/rkisp1-isp.c index abf63e7f74bd..ca0d088970be 100644 --- a/drivers/staging/media/rkisp1/rkisp1-isp.c +++ b/drivers/staging/media/rkisp1/rkisp1-isp.c @@ -1130,4 +1130,16 @@ void rkisp1_isp_isr(struct rkisp1_device *rkisp1) /* keep track of data_loss in debugfs */ rkisp1->debug.data_loss++; } + + if (status & RKISP1_CIF_ISP_FRAME) { + u32 isp_ris; + + /* New frame from the sensor received */ + isp_ris = rkisp1_read(rkisp1, RKISP1_CIF_ISP_RIS); + if (isp_ris & (RKISP1_CIF_ISP_AWB_DONE | + RKISP1_CIF_ISP_AFM_FIN | + RKISP1_CIF_ISP_EXP_END | + RKISP1_CIF_ISP_HIST_MEASURE_RDY)) + rkisp1_stats_isr(&rkisp1->stats, isp_ris); + } } diff --git a/drivers/staging/media/rkisp1/rkisp1-stats.c b/drivers/staging/media/rkisp1/rkisp1-stats.c new file mode 100644 index 000000000000..d98ea15837de --- /dev/null +++ b/drivers/staging/media/rkisp1/rkisp1-stats.c @@ -0,0 +1,530 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Rockchip ISP1 Driver - Stats subdevice + * + * Copyright (C) 2017 Rockchip Electronics Co., Ltd. + */ + +#include +#include +#include +#include +#include /* for ISP statistics */ + +#include "rkisp1-common.h" + +#define RKISP1_STATS_DEV_NAME RKISP1_DRIVER_NAME "_stats" + +#define RKISP1_ISP_STATS_REQ_BUFS_MIN 2 +#define RKISP1_ISP_STATS_REQ_BUFS_MAX 8 + +enum rkisp1_isp_readout_cmd { + RKISP1_ISP_READOUT_MEAS, + RKISP1_ISP_READOUT_META, +}; + +struct rkisp1_isp_readout_work { + struct work_struct work; + struct rkisp1_stats *stats; + + unsigned int frame_id; + unsigned int isp_ris; + enum rkisp1_isp_readout_cmd readout; + struct vb2_buffer *vb; +}; + +static int rkisp1_stats_enum_fmt_meta_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + struct video_device *video = video_devdata(file); + struct rkisp1_stats *stats = video_get_drvdata(video); + + if (f->index > 0 || f->type != video->queue->type) + return -EINVAL; + + f->pixelformat = stats->vdev_fmt.fmt.meta.dataformat; + return 0; +} + +static int rkisp1_stats_g_fmt_meta_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct video_device *video = video_devdata(file); + struct rkisp1_stats *stats = video_get_drvdata(video); + struct v4l2_meta_format *meta = &f->fmt.meta; + + if (f->type != video->queue->type) + return -EINVAL; + + memset(meta, 0, sizeof(*meta)); + meta->dataformat = stats->vdev_fmt.fmt.meta.dataformat; + meta->buffersize = stats->vdev_fmt.fmt.meta.buffersize; + + return 0; +} + +static int rkisp1_stats_querycap(struct file *file, + void *priv, struct v4l2_capability *cap) +{ + struct video_device *vdev = video_devdata(file); + + strscpy(cap->driver, RKISP1_DRIVER_NAME, sizeof(cap->driver)); + strscpy(cap->card, vdev->name, sizeof(cap->card)); + strscpy(cap->bus_info, "platform: " RKISP1_DRIVER_NAME, + sizeof(cap->bus_info)); + + return 0; +} + +/* ISP video device IOCTLs */ +static const struct v4l2_ioctl_ops rkisp1_stats_ioctl = { + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_expbuf = vb2_ioctl_expbuf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, + .vidioc_enum_fmt_meta_cap = rkisp1_stats_enum_fmt_meta_cap, + .vidioc_g_fmt_meta_cap = rkisp1_stats_g_fmt_meta_cap, + .vidioc_s_fmt_meta_cap = rkisp1_stats_g_fmt_meta_cap, + .vidioc_try_fmt_meta_cap = rkisp1_stats_g_fmt_meta_cap, + .vidioc_querycap = rkisp1_stats_querycap, + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, +}; + +static const struct v4l2_file_operations rkisp1_stats_fops = { + .mmap = vb2_fop_mmap, + .unlocked_ioctl = video_ioctl2, + .poll = vb2_fop_poll, + .open = v4l2_fh_open, + .release = vb2_fop_release +}; + +static int rkisp1_stats_vb2_queue_setup(struct vb2_queue *vq, + unsigned int *num_buffers, + unsigned int *num_planes, + unsigned int sizes[], + struct device *alloc_devs[]) +{ + struct rkisp1_stats *stats = vq->drv_priv; + + *num_planes = 1; + + *num_buffers = clamp_t(u32, *num_buffers, RKISP1_ISP_STATS_REQ_BUFS_MIN, + RKISP1_ISP_STATS_REQ_BUFS_MAX); + + sizes[0] = sizeof(struct rkisp1_stat_buffer); + + INIT_LIST_HEAD(&stats->stat); + + return 0; +} + +static void rkisp1_stats_vb2_buf_queue(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct rkisp1_buffer *stats_buf = + container_of(vbuf, struct rkisp1_buffer, vb); + struct vb2_queue *vq = vb->vb2_queue; + struct rkisp1_stats *stats_dev = vq->drv_priv; + + stats_buf->vaddr[0] = vb2_plane_vaddr(vb, 0); + + mutex_lock(&stats_dev->wq_lock); + list_add_tail(&stats_buf->queue, &stats_dev->stat); + mutex_unlock(&stats_dev->wq_lock); +} + +static int rkisp1_stats_vb2_buf_prepare(struct vb2_buffer *vb) +{ + if (vb2_plane_size(vb, 0) < sizeof(struct rkisp1_stat_buffer)) + return -EINVAL; + + vb2_set_plane_payload(vb, 0, sizeof(struct rkisp1_stat_buffer)); + + return 0; +} + +static void rkisp1_stats_vb2_stop_streaming(struct vb2_queue *vq) +{ + struct rkisp1_stats *stats = vq->drv_priv; + struct rkisp1_buffer *buf; + unsigned long flags; + unsigned int i; + + /* Make sure no new work queued in isr before draining wq */ + spin_lock_irqsave(&stats->irq_lock, flags); + stats->is_streaming = false; + spin_unlock_irqrestore(&stats->irq_lock, flags); + + drain_workqueue(stats->readout_wq); + + mutex_lock(&stats->wq_lock); + for (i = 0; i < RKISP1_ISP_STATS_REQ_BUFS_MAX; i++) { + if (list_empty(&stats->stat)) + break; + buf = list_first_entry(&stats->stat, + struct rkisp1_buffer, queue); + list_del(&buf->queue); + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); + } + mutex_unlock(&stats->wq_lock); +} + +static int +rkisp1_stats_vb2_start_streaming(struct vb2_queue *queue, unsigned int count) +{ + struct rkisp1_stats *stats = queue->drv_priv; + + stats->is_streaming = true; + + return 0; +} + +static const struct vb2_ops rkisp1_stats_vb2_ops = { + .queue_setup = rkisp1_stats_vb2_queue_setup, + .buf_queue = rkisp1_stats_vb2_buf_queue, + .buf_prepare = rkisp1_stats_vb2_buf_prepare, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, + .stop_streaming = rkisp1_stats_vb2_stop_streaming, + .start_streaming = rkisp1_stats_vb2_start_streaming, +}; + +static int +rkisp1_stats_init_vb2_queue(struct vb2_queue *q, struct rkisp1_stats *stats) +{ + struct rkisp1_vdev_node *node; + + node = container_of(q, struct rkisp1_vdev_node, buf_queue); + + q->type = V4L2_BUF_TYPE_META_CAPTURE; + q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; + q->drv_priv = stats; + q->ops = &rkisp1_stats_vb2_ops; + q->mem_ops = &vb2_vmalloc_memops; + q->buf_struct_size = sizeof(struct rkisp1_buffer); + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->lock = &node->vlock; + + return vb2_queue_init(q); +} + +static void rkisp1_stats_get_awb_meas(struct rkisp1_stats *stats, + struct rkisp1_stat_buffer *pbuf) +{ + /* Protect against concurrent access from ISR? */ + struct rkisp1_device *rkisp1 = stats->rkisp1; + u32 reg_val; + + pbuf->meas_type |= RKISP1_CIF_ISP_STAT_AWB; + reg_val = rkisp1_read(rkisp1, RKISP1_CIF_ISP_AWB_WHITE_CNT); + pbuf->params.awb.awb_mean[0].cnt = + RKISP1_CIF_ISP_AWB_GET_PIXEL_CNT(reg_val); + reg_val = rkisp1_read(rkisp1, RKISP1_CIF_ISP_AWB_MEAN); + + pbuf->params.awb.awb_mean[0].mean_cr_or_r = + RKISP1_CIF_ISP_AWB_GET_MEAN_CR_R(reg_val); + pbuf->params.awb.awb_mean[0].mean_cb_or_b = + RKISP1_CIF_ISP_AWB_GET_MEAN_CB_B(reg_val); + pbuf->params.awb.awb_mean[0].mean_y_or_g = + RKISP1_CIF_ISP_AWB_GET_MEAN_Y_G(reg_val); +} + +static void rkisp1_stats_get_aec_meas(struct rkisp1_stats *stats, + struct rkisp1_stat_buffer *pbuf) +{ + struct rkisp1_device *rkisp1 = stats->rkisp1; + unsigned int i; + + pbuf->meas_type |= RKISP1_CIF_ISP_STAT_AUTOEXP; + for (i = 0; i < RKISP1_CIF_ISP_AE_MEAN_MAX; i++) + pbuf->params.ae.exp_mean[i] = + (u8)rkisp1_read(rkisp1, + RKISP1_CIF_ISP_EXP_MEAN_00 + i * 4); +} + +static void rkisp1_stats_get_afc_meas(struct rkisp1_stats *stats, + struct rkisp1_stat_buffer *pbuf) +{ + struct rkisp1_device *rkisp1 = stats->rkisp1; + struct rkisp1_cif_isp_af_stat *af; + + pbuf->meas_type = RKISP1_CIF_ISP_STAT_AFM_FIN; + + af = &pbuf->params.af; + af->window[0].sum = rkisp1_read(rkisp1, RKISP1_CIF_ISP_AFM_SUM_A); + af->window[0].lum = rkisp1_read(rkisp1, RKISP1_CIF_ISP_AFM_LUM_A); + af->window[1].sum = rkisp1_read(rkisp1, RKISP1_CIF_ISP_AFM_SUM_B); + af->window[1].lum = rkisp1_read(rkisp1, RKISP1_CIF_ISP_AFM_LUM_B); + af->window[2].sum = rkisp1_read(rkisp1, RKISP1_CIF_ISP_AFM_SUM_C); + af->window[2].lum = rkisp1_read(rkisp1, RKISP1_CIF_ISP_AFM_LUM_C); +} + +static void rkisp1_stats_get_hst_meas(struct rkisp1_stats *stats, + struct rkisp1_stat_buffer *pbuf) +{ + struct rkisp1_device *rkisp1 = stats->rkisp1; + unsigned int i; + + pbuf->meas_type |= RKISP1_CIF_ISP_STAT_HIST; + for (i = 0; i < RKISP1_CIF_ISP_HIST_BIN_N_MAX; i++) + pbuf->params.hist.hist_bins[i] = + (u8)rkisp1_read(rkisp1, + RKISP1_CIF_ISP_HIST_BIN_0 + i * 4); +} + +static void rkisp1_stats_get_bls_meas(struct rkisp1_stats *stats, + struct rkisp1_stat_buffer *pbuf) +{ + struct rkisp1_device *rkisp1 = stats->rkisp1; + const struct rkisp1_isp_mbus_info *in_fmt = rkisp1->isp.sink_fmt; + struct rkisp1_cif_isp_bls_meas_val *bls_val; + + bls_val = &pbuf->params.ae.bls_val; + if (in_fmt->bayer_pat == RKISP1_RAW_BGGR) { + bls_val->meas_b = + rkisp1_read(rkisp1, RKISP1_CIF_ISP_BLS_A_MEASURED); + bls_val->meas_gb = + rkisp1_read(rkisp1, RKISP1_CIF_ISP_BLS_B_MEASURED); + bls_val->meas_gr = + rkisp1_read(rkisp1, RKISP1_CIF_ISP_BLS_C_MEASURED); + bls_val->meas_r = + rkisp1_read(rkisp1, RKISP1_CIF_ISP_BLS_D_MEASURED); + } else if (in_fmt->bayer_pat == RKISP1_RAW_GBRG) { + bls_val->meas_gb = + rkisp1_read(rkisp1, RKISP1_CIF_ISP_BLS_A_MEASURED); + bls_val->meas_b = + rkisp1_read(rkisp1, RKISP1_CIF_ISP_BLS_B_MEASURED); + bls_val->meas_r = + rkisp1_read(rkisp1, RKISP1_CIF_ISP_BLS_C_MEASURED); + bls_val->meas_gr = + rkisp1_read(rkisp1, RKISP1_CIF_ISP_BLS_D_MEASURED); + } else if (in_fmt->bayer_pat == RKISP1_RAW_GRBG) { + bls_val->meas_gr = + rkisp1_read(rkisp1, RKISP1_CIF_ISP_BLS_A_MEASURED); + bls_val->meas_r = + rkisp1_read(rkisp1, RKISP1_CIF_ISP_BLS_B_MEASURED); + bls_val->meas_b = + rkisp1_read(rkisp1, RKISP1_CIF_ISP_BLS_C_MEASURED); + bls_val->meas_gb = + rkisp1_read(rkisp1, RKISP1_CIF_ISP_BLS_D_MEASURED); + } else if (in_fmt->bayer_pat == RKISP1_RAW_RGGB) { + bls_val->meas_r = + rkisp1_read(rkisp1, RKISP1_CIF_ISP_BLS_A_MEASURED); + bls_val->meas_gr = + rkisp1_read(rkisp1, RKISP1_CIF_ISP_BLS_B_MEASURED); + bls_val->meas_gb = + rkisp1_read(rkisp1, RKISP1_CIF_ISP_BLS_C_MEASURED); + bls_val->meas_b = + rkisp1_read(rkisp1, RKISP1_CIF_ISP_BLS_D_MEASURED); + } +} + +static void +rkisp1_stats_send_measurement(struct rkisp1_stats *stats, + struct rkisp1_isp_readout_work *meas_work) +{ + struct rkisp1_stat_buffer *cur_stat_buf; + struct rkisp1_buffer *cur_buf = NULL; + unsigned int frame_sequence = + atomic_read(&stats->rkisp1->isp.frame_sequence); + u64 timestamp = ktime_get_ns(); + + if (frame_sequence != meas_work->frame_id) { + dev_warn(stats->rkisp1->dev, + "Measurement late(%d, %d)\n", + frame_sequence, meas_work->frame_id); + frame_sequence = meas_work->frame_id; + } + + mutex_lock(&stats->wq_lock); + /* get one empty buffer */ + if (!list_empty(&stats->stat)) { + cur_buf = list_first_entry(&stats->stat, + struct rkisp1_buffer, queue); + list_del(&cur_buf->queue); + } + mutex_unlock(&stats->wq_lock); + + if (!cur_buf) + return; + + cur_stat_buf = + (struct rkisp1_stat_buffer *)(cur_buf->vaddr[0]); + + if (meas_work->isp_ris & RKISP1_CIF_ISP_AWB_DONE) { + rkisp1_stats_get_awb_meas(stats, cur_stat_buf); + cur_stat_buf->meas_type |= RKISP1_CIF_ISP_STAT_AWB; + } + + if (meas_work->isp_ris & RKISP1_CIF_ISP_AFM_FIN) { + rkisp1_stats_get_afc_meas(stats, cur_stat_buf); + cur_stat_buf->meas_type |= RKISP1_CIF_ISP_STAT_AFM_FIN; + } + + if (meas_work->isp_ris & RKISP1_CIF_ISP_EXP_END) { + rkisp1_stats_get_aec_meas(stats, cur_stat_buf); + rkisp1_stats_get_bls_meas(stats, cur_stat_buf); + cur_stat_buf->meas_type |= RKISP1_CIF_ISP_STAT_AUTOEXP; + } + + if (meas_work->isp_ris & RKISP1_CIF_ISP_HIST_MEASURE_RDY) { + rkisp1_stats_get_hst_meas(stats, cur_stat_buf); + cur_stat_buf->meas_type |= RKISP1_CIF_ISP_STAT_HIST; + } + + vb2_set_plane_payload(&cur_buf->vb.vb2_buf, 0, + sizeof(struct rkisp1_stat_buffer)); + cur_buf->vb.sequence = frame_sequence; + cur_buf->vb.vb2_buf.timestamp = timestamp; + vb2_buffer_done(&cur_buf->vb.vb2_buf, VB2_BUF_STATE_DONE); +} + +static void rkisp1_stats_readout_work(struct work_struct *work) +{ + struct rkisp1_isp_readout_work *readout_work = + container_of(work, struct rkisp1_isp_readout_work, work); + struct rkisp1_stats *stats = readout_work->stats; + + if (readout_work->readout == RKISP1_ISP_READOUT_MEAS) + rkisp1_stats_send_measurement(stats, readout_work); + + kfree(readout_work); +} + +void rkisp1_stats_isr(struct rkisp1_stats *stats, u32 isp_ris) +{ + unsigned int frame_sequence = + atomic_read(&stats->rkisp1->isp.frame_sequence); + struct rkisp1_device *rkisp1 = stats->rkisp1; + struct rkisp1_isp_readout_work *work; + unsigned int isp_mis_tmp = 0; + u32 val; + + spin_lock(&stats->irq_lock); + + val = RKISP1_CIF_ISP_AWB_DONE | RKISP1_CIF_ISP_AFM_FIN | + RKISP1_CIF_ISP_EXP_END | RKISP1_CIF_ISP_HIST_MEASURE_RDY; + rkisp1_write(rkisp1, val, RKISP1_CIF_ISP_ICR); + + isp_mis_tmp = rkisp1_read(rkisp1, RKISP1_CIF_ISP_MIS); + if (isp_mis_tmp & + (RKISP1_CIF_ISP_AWB_DONE | RKISP1_CIF_ISP_AFM_FIN | + RKISP1_CIF_ISP_EXP_END | RKISP1_CIF_ISP_HIST_MEASURE_RDY)) + rkisp1->debug.stats_error++; + + if (!stats->is_streaming) + goto unlock; + if (isp_ris & (RKISP1_CIF_ISP_AWB_DONE | + RKISP1_CIF_ISP_AFM_FIN | + RKISP1_CIF_ISP_EXP_END | + RKISP1_CIF_ISP_HIST_MEASURE_RDY)) { + work = kzalloc(sizeof(*work), GFP_ATOMIC); + if (work) { + INIT_WORK(&work->work, + rkisp1_stats_readout_work); + work->readout = RKISP1_ISP_READOUT_MEAS; + work->stats = stats; + work->frame_id = frame_sequence; + work->isp_ris = isp_ris; + if (!queue_work(stats->readout_wq, + &work->work)) + kfree(work); + } else { + dev_err(stats->rkisp1->dev, + "Could not allocate work\n"); + } + } + +unlock: + spin_unlock(&stats->irq_lock); +} + +static void rkisp1_init_stats(struct rkisp1_stats *stats) +{ + stats->vdev_fmt.fmt.meta.dataformat = + V4L2_META_FMT_RK_ISP1_STAT_3A; + stats->vdev_fmt.fmt.meta.buffersize = + sizeof(struct rkisp1_stat_buffer); +} + +int rkisp1_stats_register(struct rkisp1_stats *stats, + struct v4l2_device *v4l2_dev, + struct rkisp1_device *rkisp1) +{ + struct rkisp1_vdev_node *node = &stats->vnode; + struct video_device *vdev = &node->vdev; + int ret; + + stats->rkisp1 = rkisp1; + mutex_init(&stats->wq_lock); + mutex_init(&node->vlock); + INIT_LIST_HEAD(&stats->stat); + spin_lock_init(&stats->irq_lock); + + strscpy(vdev->name, RKISP1_STATS_DEV_NAME, sizeof(vdev->name)); + + video_set_drvdata(vdev, stats); + vdev->ioctl_ops = &rkisp1_stats_ioctl; + vdev->fops = &rkisp1_stats_fops; + vdev->release = video_device_release_empty; + vdev->lock = &node->vlock; + vdev->v4l2_dev = v4l2_dev; + vdev->queue = &node->buf_queue; + vdev->device_caps = V4L2_CAP_META_CAPTURE | V4L2_CAP_STREAMING; + vdev->vfl_dir = VFL_DIR_RX; + rkisp1_stats_init_vb2_queue(vdev->queue, stats); + rkisp1_init_stats(stats); + video_set_drvdata(vdev, stats); + + node->pad.flags = MEDIA_PAD_FL_SINK; + ret = media_entity_pads_init(&vdev->entity, 1, &node->pad); + if (ret) + goto err_release_queue; + + ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1); + if (ret) { + dev_err(&vdev->dev, + "failed to register %s, ret=%d\n", vdev->name, ret); + goto err_cleanup_media_entity; + } + + stats->readout_wq = alloc_workqueue("measurement_queue", + WQ_UNBOUND | WQ_MEM_RECLAIM, + 1); + + if (!stats->readout_wq) { + ret = -ENOMEM; + goto err_unreg_vdev; + } + + return 0; + +err_unreg_vdev: + video_unregister_device(vdev); +err_cleanup_media_entity: + media_entity_cleanup(&vdev->entity); +err_release_queue: + vb2_queue_release(vdev->queue); + mutex_destroy(&node->vlock); + mutex_destroy(&stats->wq_lock); + return ret; +} + +void rkisp1_stats_unregister(struct rkisp1_stats *stats) +{ + struct rkisp1_vdev_node *node = &stats->vnode; + struct video_device *vdev = &node->vdev; + + destroy_workqueue(stats->readout_wq); + video_unregister_device(vdev); + media_entity_cleanup(&vdev->entity); + vb2_queue_release(vdev->queue); + mutex_destroy(&node->vlock); + mutex_destroy(&stats->wq_lock); +} From patchwork Wed Jan 8 18:44:49 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Helen Koike X-Patchwork-Id: 11324337 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 6AD16921 for ; Wed, 8 Jan 2020 18:47:48 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 2AE072067D for ; Wed, 8 Jan 2020 18:47:48 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="Armaz/Ww" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 2AE072067D Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=collabora.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-rockchip-bounces+patchwork-linux-rockchip=patchwork.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=1B6g5jOo5nkCNPlz0AOwblJOrfbjJmHzR0QYcVb11tI=; b=Armaz/Ww4Bt25t XFndOLJXawAA1dYUI3SQWTdj8pvDMkEC6ivJicLJsbawQlj0ehE3YRPd8+sRppTw+JhxX/42tysId BQQPdYR6R3r7hGdLphp7F2BGtbfwpe7hySlySETRF7bN4MHnpyfpbZaSNvkdZGA3K4sXyDlXsgcCP bk5VF7kZA04CUi34KGtgkdhBJRIO2ewIMG4gjDIWarBrzCMobQh9tI7SfEVeZ27l+zmslE67eyCZs ZOORFRo3kEmtaFmfBYUhcfdXiFExo+vN21yAzyCgdQrU2603AMP7OPMJ3VIDE9YdwC3I27w1+BEkG SMyuuOnNV3FOMzRLQZbA==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1ipGMp-0001Ot-5j; Wed, 08 Jan 2020 18:47:43 +0000 Received: from bhuna.collabora.co.uk ([46.235.227.227]) by bombadil.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1ipGLM-0000Ai-5C; Wed, 08 Jan 2020 18:46:17 +0000 Received: from [127.0.0.1] (localhost [127.0.0.1]) (Authenticated sender: koike) with ESMTPSA id EED36291340 From: Helen Koike To: linux-rockchip@lists.infradead.org Subject: [PATCH v13 06/11] media: staging: rkisp1: add output device for parameters Date: Wed, 8 Jan 2020 15:44:49 -0300 Message-Id: <20200108184454.825725-7-helen.koike@collabora.com> X-Mailer: git-send-email 2.24.0 In-Reply-To: <20200108184454.825725-1-helen.koike@collabora.com> References: <20200108184454.825725-1-helen.koike@collabora.com> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20200108_104612_831373_644FDBC2 X-CRM114-Status: GOOD ( 21.69 ) X-Spam-Score: -0.0 (/) X-Spam-Report: SpamAssassin version 3.4.2 on bombadil.infradead.org summary: Content analysis details: (-0.0 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at https://www.dnswl.org/, no trust [46.235.227.227 listed in list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record -0.0 SPF_HELO_PASS SPF: HELO matches SPF record 0.0 UNPARSEABLE_RELAY Informational: message has unparseable relay lines X-BeenThere: linux-rockchip@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Upstream kernel work for Rockchip platforms List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: mark.rutland@arm.com, eddie.cai.linux@gmail.com, heiko@sntech.de, laurent.pinchart@ideasonboard.com, joacim.zetterling@gmail.com, kernel@collabora.com, andrey.konovalov@linaro.org, Yichong Zhong , jacob-chen@iotwrt.com, hans.verkuil@cisco.com, Allon Huang , Shunqian Zheng , linux-media@vger.kernel.org, devicetree@vger.kernel.org, Jacob Chen , Jeffy Chen , Helen Koike , robh+dt@kernel.org, mchehab@kernel.org, ezequiel@collabora.com, linux-arm-kernel@lists.infradead.org, gregkh@linuxfoundation.org, linux-kernel@vger.kernel.org, tfiga@chromium.org, sakari.ailus@linux.intel.com, Jacob Chen Sender: "Linux-rockchip" Errors-To: linux-rockchip-bounces+patchwork-linux-rockchip=patchwork.kernel.org@lists.infradead.org From: Jacob Chen Add the output video driver that accept parameters from userspace. Signed-off-by: Jacob Chen Signed-off-by: Shunqian Zheng Signed-off-by: Yichong Zhong Signed-off-by: Jacob Chen Signed-off-by: Eddie Cai Signed-off-by: Jeffy Chen Signed-off-by: Allon Huang Signed-off-by: Tomasz Figa Signed-off-by: Helen Koike --- Changes in v13: None Changes in v12: - Several cleanups - Commit re-organization to not break bisectability Changes in v11: params - fix compiling warnings - fix checkpatch errors Changes in v10: - unsquash Changes in v9: - squash - move to staging Changes in v8: None Changes in v7: - s/strlcpy/strscpy - s/strcpy/strscpy - fix config lsc error LSC data table size is 17x17, but when configuring data to ISP, should be aligned to 18x17. That means every last data of last line should be filled with 0, and not filled with the data of next line. - Update new ISP parameters immediately For those sub modules that have shadow registers in core isp, the new programing parameters would not be active if both CIF_ISP_CTRL_ISP_CFG_UPD_PERMANENT and CFG_UPD are not set. Now we configure CFG_UPD to force update the shadow registers when new ISP parameters are configured. - fix some ISP parameters config error Some ISP parameter config functions may override the old enable bit value, because the enable bits of these modules are in the same registers with parameters. So we should save the old enable bits firstly. - code styling and checkpatch fixes drivers/staging/media/rkisp1/Makefile | 3 +- drivers/staging/media/rkisp1/rkisp1-common.h | 35 + drivers/staging/media/rkisp1/rkisp1-dev.c | 46 +- drivers/staging/media/rkisp1/rkisp1-isp.c | 19 + drivers/staging/media/rkisp1/rkisp1-params.c | 1630 ++++++++++++++++++ 5 files changed, 1717 insertions(+), 16 deletions(-) create mode 100644 drivers/staging/media/rkisp1/rkisp1-params.c diff --git a/drivers/staging/media/rkisp1/Makefile b/drivers/staging/media/rkisp1/Makefile index 399f5c5f4d92..69ca59c7ef34 100644 --- a/drivers/staging/media/rkisp1/Makefile +++ b/drivers/staging/media/rkisp1/Makefile @@ -4,4 +4,5 @@ rockchip-isp1-objs += rkisp1-capture.o \ rkisp1-dev.o \ rkisp1-isp.o \ rkisp1-resizer.o \ - rkisp1-stats.o + rkisp1-stats.o \ + rkisp1-params.o diff --git a/drivers/staging/media/rkisp1/rkisp1-common.h b/drivers/staging/media/rkisp1/rkisp1-common.h index c61bc2629412..369a401b098a 100644 --- a/drivers/staging/media/rkisp1/rkisp1-common.h +++ b/drivers/staging/media/rkisp1/rkisp1-common.h @@ -195,6 +195,27 @@ struct rkisp1_stats { struct mutex wq_lock; }; +/* + * struct rkisp1_params - ISP input parameters device + * + * @cur_params: Current ISP parameters + * @is_first_params: the first params should take effect immediately + */ +struct rkisp1_params { + struct rkisp1_vdev_node vnode; + struct rkisp1_device *rkisp1; + + spinlock_t config_lock; + struct list_head params; + struct rkisp1_params_cfg cur_params; + struct v4l2_format vdev_fmt; + bool is_streaming; + bool is_first_params; + + enum v4l2_quantization quantization; + enum rkisp1_fmt_raw_pat_type raw_type; +}; + struct rkisp1_resizer { struct v4l2_subdev sd; enum rkisp1_stream_id id; @@ -222,6 +243,7 @@ struct rkisp1_debug { * @isp: ISP sub-device * @rkisp1_capture: capture video device * @stats: ISP statistics output device + * @params: ISP input parameters device */ struct rkisp1_device { void __iomem *base_addr; @@ -238,6 +260,7 @@ struct rkisp1_device { struct rkisp1_resizer resizer_devs[2]; struct rkisp1_capture capture_devs[2]; struct rkisp1_stats stats; + struct rkisp1_params params; struct media_pipeline pipe; struct vb2_alloc_ctx *alloc_ctx; struct rkisp1_debug debug; @@ -287,6 +310,7 @@ void rkisp1_isp_isr(struct rkisp1_device *rkisp1); void rkisp1_mipi_isr(struct rkisp1_device *rkisp1); void rkisp1_capture_isr(struct rkisp1_device *rkisp1); void rkisp1_stats_isr(struct rkisp1_stats *stats, u32 isp_ris); +void rkisp1_params_isr(struct rkisp1_device *rkisp1, u32 isp_mis); int rkisp1_capture_devs_register(struct rkisp1_device *rkisp1); void rkisp1_capture_devs_unregister(struct rkisp1_device *rkisp1); @@ -299,4 +323,15 @@ int rkisp1_stats_register(struct rkisp1_stats *stats, struct rkisp1_device *rkisp1); void rkisp1_stats_unregister(struct rkisp1_stats *stats); +void rkisp1_params_configure(struct rkisp1_params *params, + enum rkisp1_fmt_raw_pat_type bayer_pat, + enum v4l2_quantization quantization); +void rkisp1_params_disable(struct rkisp1_params *params); +int rkisp1_params_register(struct rkisp1_params *params, + struct v4l2_device *v4l2_dev, + struct rkisp1_device *rkisp1); +void rkisp1_params_unregister(struct rkisp1_params *params); + +void rkisp1_params_isr_handler(struct rkisp1_device *rkisp1, u32 isp_mis); + #endif /* _RKISP1_COMMON_H */ diff --git a/drivers/staging/media/rkisp1/rkisp1-dev.c b/drivers/staging/media/rkisp1/rkisp1-dev.c index 07a1cbbea889..558126e66465 100644 --- a/drivers/staging/media/rkisp1/rkisp1-dev.c +++ b/drivers/staging/media/rkisp1/rkisp1-dev.c @@ -57,13 +57,13 @@ * | DMA |------------------------------------+ Self Picture Path * +--------+ * - * rkisp1-stats.c - * |===============| - * +---------------+ - * | | - * | ISP | - * | | - * +---------------+ + * rkisp1-stats.c rkisp1-params.c + * |===============| |===============| + * +---------------+ +---------------+ + * | | | | + * | ISP | | ISP | + * | | | | + * +---------------+ +---------------+ * * * Media Topology @@ -72,13 +72,13 @@ * | Sensor 2 | | Sensor X | * ------------ ... ------------ * | 0 | | 0 | - * +----------+ +----------+ - * \ | - * \ | - * +----------+ \ | - * | Sensor 1 | v v - * ------------ +------+------+ - * | 0 |----->| 0 | 1 | + * +----------+ +----------+ +-----------+ + * \ | | params | + * \ | | (output) | + * +----------+ \ | +-----------+ + * | Sensor 1 | v v | + * ------------ +------+------+ | + * | 0 |----->| 0 | 1 |<---------+ * +----------+ |------+------| * | ISP | * |------+------| @@ -164,6 +164,14 @@ static int rkisp1_create_links(struct rkisp1_device *rkisp1) return ret; } + /* params links */ + source = &rkisp1->params.vnode.vdev.entity; + sink = &rkisp1->isp.sd.entity; + ret = media_create_pad_link(source, 0, sink, + RKISP1_ISP_PAD_SINK_PARAMS, flags); + if (ret) + return ret; + /* 3A stats links */ source = &rkisp1->isp.sd.entity; sink = &rkisp1->stats.vnode.vdev.entity; @@ -352,14 +360,21 @@ static int rkisp1_entities_register(struct rkisp1_device *rkisp1) if (ret) goto err_unreg_capture_devs; + ret = rkisp1_params_register(&rkisp1->params, + &rkisp1->v4l2_dev, rkisp1); + if (ret) + goto err_unreg_stats; + ret = rkisp1_subdev_notifier(rkisp1); if (ret) { dev_err(rkisp1->dev, "Failed to register subdev notifier(%d)\n", ret); - goto err_unreg_stats; + goto err_unreg_params; } return 0; +err_unreg_params: + rkisp1_params_unregister(&rkisp1->params); err_unreg_stats: rkisp1_stats_unregister(&rkisp1->stats); err_unreg_capture_devs: @@ -529,6 +544,7 @@ static int rkisp1_remove(struct platform_device *pdev) v4l2_async_notifier_unregister(&rkisp1->notifier); v4l2_async_notifier_cleanup(&rkisp1->notifier); + rkisp1_params_unregister(&rkisp1->params); rkisp1_stats_unregister(&rkisp1->stats); rkisp1_capture_devs_unregister(rkisp1); rkisp1_resizer_devs_unregister(rkisp1); diff --git a/drivers/staging/media/rkisp1/rkisp1-isp.c b/drivers/staging/media/rkisp1/rkisp1-isp.c index ca0d088970be..328c7ea60971 100644 --- a/drivers/staging/media/rkisp1/rkisp1-isp.c +++ b/drivers/staging/media/rkisp1/rkisp1-isp.c @@ -357,6 +357,18 @@ static int rkisp1_config_isp(struct rkisp1_device *rkisp1) RKISP1_CIF_ISP_PIC_SIZE_ERROR | RKISP1_CIF_ISP_FRAME_IN; rkisp1_write(rkisp1, irq_mask, RKISP1_CIF_ISP_IMSC); + if (src_fmt->fmt_type == RKISP1_FMT_BAYER) { + rkisp1_params_disable(&rkisp1->params); + } else { + struct v4l2_mbus_framefmt *src_frm; + + src_frm = rkisp1_isp_get_pad_fmt(&rkisp1->isp, NULL, + RKISP1_ISP_PAD_SINK_VIDEO, + V4L2_SUBDEV_FORMAT_ACTIVE); + rkisp1_params_configure(&rkisp1->params, sink_fmt->bayer_pat, + src_frm->quantization); + } + return 0; } @@ -1142,4 +1154,11 @@ void rkisp1_isp_isr(struct rkisp1_device *rkisp1) RKISP1_CIF_ISP_HIST_MEASURE_RDY)) rkisp1_stats_isr(&rkisp1->stats, isp_ris); } + + /* + * Then update changed configs. Some of them involve + * lot of register writes. Do those only one per frame. + * Do the updates in the order of the processing flow. + */ + rkisp1_params_isr(rkisp1, status); } diff --git a/drivers/staging/media/rkisp1/rkisp1-params.c b/drivers/staging/media/rkisp1/rkisp1-params.c new file mode 100644 index 000000000000..781f0ca85af1 --- /dev/null +++ b/drivers/staging/media/rkisp1/rkisp1-params.c @@ -0,0 +1,1630 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Rockchip ISP1 Driver - Params subdevice + * + * Copyright (C) 2017 Rockchip Electronics Co., Ltd. + */ + +#include +#include +#include +#include +#include /* for ISP params */ + +#include "rkisp1-common.h" + +#define RKISP1_PARAMS_DEV_NAME RKISP1_DRIVER_NAME "_params" + +#define RKISP1_ISP_PARAMS_REQ_BUFS_MIN 2 +#define RKISP1_ISP_PARAMS_REQ_BUFS_MAX 8 + +#define RKISP1_ISP_DPCC_LINE_THRESH(n) \ + (RKISP1_CIF_ISP_DPCC_LINE_THRESH_1 + 0x14 * (n)) +#define RKISP1_ISP_DPCC_LINE_MAD_FAC(n) \ + (RKISP1_CIF_ISP_DPCC_LINE_MAD_FAC_1 + 0x14 * (n)) +#define RKISP1_ISP_DPCC_PG_FAC(n) \ + (RKISP1_CIF_ISP_DPCC_PG_FAC_1 + 0x14 * (n)) +#define RKISP1_ISP_DPCC_RND_THRESH(n) \ + (RKISP1_CIF_ISP_DPCC_RND_THRESH_1 + 0x14 * (n)) +#define RKISP1_ISP_DPCC_RG_FAC(n) \ + (RKISP1_CIF_ISP_DPCC_RG_FAC_1 + 0x14 * (n)) +#define RKISP1_ISP_CC_COEFF(n) \ + (RKISP1_CIF_ISP_CC_COEFF_0 + (n) * 4) + +static inline void +rkisp1_param_set_bits(struct rkisp1_params *params, u32 reg, u32 bit_mask) +{ + u32 val; + + val = rkisp1_read(params->rkisp1, reg); + rkisp1_write(params->rkisp1, val | bit_mask, reg); +} + +static inline void +rkisp1_param_clear_bits(struct rkisp1_params *params, u32 reg, u32 bit_mask) +{ + u32 val; + + val = rkisp1_read(params->rkisp1, reg); + rkisp1_write(params->rkisp1, val & ~bit_mask, reg); +} + +/* ISP BP interface function */ +static void rkisp1_dpcc_config(struct rkisp1_params *params, + const struct rkisp1_cif_isp_dpcc_config *arg) +{ + unsigned int i; + u32 mode; + + /* avoid to override the old enable value */ + mode = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_DPCC_MODE); + mode &= RKISP1_CIF_ISP_DPCC_ENA; + mode |= arg->mode & ~RKISP1_CIF_ISP_DPCC_ENA; + rkisp1_write(params->rkisp1, mode, RKISP1_CIF_ISP_DPCC_MODE); + rkisp1_write(params->rkisp1, arg->output_mode, + RKISP1_CIF_ISP_DPCC_OUTPUT_MODE); + rkisp1_write(params->rkisp1, arg->set_use, + RKISP1_CIF_ISP_DPCC_SET_USE); + + rkisp1_write(params->rkisp1, arg->methods[0].method, + RKISP1_CIF_ISP_DPCC_METHODS_SET_1); + rkisp1_write(params->rkisp1, arg->methods[1].method, + RKISP1_CIF_ISP_DPCC_METHODS_SET_2); + rkisp1_write(params->rkisp1, arg->methods[2].method, + RKISP1_CIF_ISP_DPCC_METHODS_SET_3); + for (i = 0; i < RKISP1_CIF_ISP_DPCC_METHODS_MAX; i++) { + rkisp1_write(params->rkisp1, arg->methods[i].line_thresh, + RKISP1_ISP_DPCC_LINE_THRESH(i)); + rkisp1_write(params->rkisp1, arg->methods[i].line_mad_fac, + RKISP1_ISP_DPCC_LINE_MAD_FAC(i)); + rkisp1_write(params->rkisp1, arg->methods[i].pg_fac, + RKISP1_ISP_DPCC_PG_FAC(i)); + rkisp1_write(params->rkisp1, arg->methods[i].rnd_thresh, + RKISP1_ISP_DPCC_RND_THRESH(i)); + rkisp1_write(params->rkisp1, arg->methods[i].rg_fac, + RKISP1_ISP_DPCC_RG_FAC(i)); + } + + rkisp1_write(params->rkisp1, arg->rnd_offs, + RKISP1_CIF_ISP_DPCC_RND_OFFS); + rkisp1_write(params->rkisp1, arg->ro_limits, + RKISP1_CIF_ISP_DPCC_RO_LIMITS); +} + +/* ISP black level subtraction interface function */ +static void rkisp1_bls_config(struct rkisp1_params *params, + const struct rkisp1_cif_isp_bls_config *arg) +{ + /* avoid to override the old enable value */ + u32 new_control; + + new_control = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_BLS_CTRL); + new_control &= RKISP1_CIF_ISP_BLS_ENA; + /* fixed subtraction values */ + if (!arg->enable_auto) { + const struct rkisp1_cif_isp_bls_fixed_val *pval = + &arg->fixed_val; + + switch (params->raw_type) { + case RKISP1_RAW_BGGR: + rkisp1_write(params->rkisp1, + pval->r, RKISP1_CIF_ISP_BLS_D_FIXED); + rkisp1_write(params->rkisp1, + pval->gr, RKISP1_CIF_ISP_BLS_C_FIXED); + rkisp1_write(params->rkisp1, + pval->gb, RKISP1_CIF_ISP_BLS_B_FIXED); + rkisp1_write(params->rkisp1, + pval->b, RKISP1_CIF_ISP_BLS_A_FIXED); + break; + case RKISP1_RAW_GBRG: + rkisp1_write(params->rkisp1, + pval->r, RKISP1_CIF_ISP_BLS_C_FIXED); + rkisp1_write(params->rkisp1, + pval->gr, RKISP1_CIF_ISP_BLS_D_FIXED); + rkisp1_write(params->rkisp1, + pval->gb, RKISP1_CIF_ISP_BLS_A_FIXED); + rkisp1_write(params->rkisp1, + pval->b, RKISP1_CIF_ISP_BLS_B_FIXED); + break; + case RKISP1_RAW_GRBG: + rkisp1_write(params->rkisp1, + pval->r, RKISP1_CIF_ISP_BLS_B_FIXED); + rkisp1_write(params->rkisp1, + pval->gr, RKISP1_CIF_ISP_BLS_A_FIXED); + rkisp1_write(params->rkisp1, + pval->gb, RKISP1_CIF_ISP_BLS_D_FIXED); + rkisp1_write(params->rkisp1, + pval->b, RKISP1_CIF_ISP_BLS_C_FIXED); + break; + case RKISP1_RAW_RGGB: + rkisp1_write(params->rkisp1, + pval->r, RKISP1_CIF_ISP_BLS_A_FIXED); + rkisp1_write(params->rkisp1, + pval->gr, RKISP1_CIF_ISP_BLS_B_FIXED); + rkisp1_write(params->rkisp1, + pval->gb, RKISP1_CIF_ISP_BLS_C_FIXED); + rkisp1_write(params->rkisp1, + pval->b, RKISP1_CIF_ISP_BLS_D_FIXED); + break; + default: + break; + } + + } else { + if (arg->en_windows & BIT(1)) { + rkisp1_write(params->rkisp1, arg->bls_window2.h_offs, + RKISP1_CIF_ISP_BLS_H2_START); + rkisp1_write(params->rkisp1, arg->bls_window2.h_size, + RKISP1_CIF_ISP_BLS_H2_STOP); + rkisp1_write(params->rkisp1, arg->bls_window2.v_offs, + RKISP1_CIF_ISP_BLS_V2_START); + rkisp1_write(params->rkisp1, arg->bls_window2.v_size, + RKISP1_CIF_ISP_BLS_V2_STOP); + new_control |= RKISP1_CIF_ISP_BLS_WINDOW_2; + } + + if (arg->en_windows & BIT(0)) { + rkisp1_write(params->rkisp1, arg->bls_window1.h_offs, + RKISP1_CIF_ISP_BLS_H1_START); + rkisp1_write(params->rkisp1, arg->bls_window1.h_size, + RKISP1_CIF_ISP_BLS_H1_STOP); + rkisp1_write(params->rkisp1, arg->bls_window1.v_offs, + RKISP1_CIF_ISP_BLS_V1_START); + rkisp1_write(params->rkisp1, arg->bls_window1.v_size, + RKISP1_CIF_ISP_BLS_V1_STOP); + new_control |= RKISP1_CIF_ISP_BLS_WINDOW_1; + } + + rkisp1_write(params->rkisp1, arg->bls_samples, + RKISP1_CIF_ISP_BLS_SAMPLES); + + new_control |= RKISP1_CIF_ISP_BLS_MODE_MEASURED; + } + rkisp1_write(params->rkisp1, new_control, RKISP1_CIF_ISP_BLS_CTRL); +} + +/* ISP LS correction interface function */ +static void +rkisp1_lsc_correct_matrix_config(struct rkisp1_params *params, + const struct rkisp1_cif_isp_lsc_config *pconfig) +{ + unsigned int isp_lsc_status, sram_addr, isp_lsc_table_sel, i, j, data; + + isp_lsc_status = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_LSC_STATUS); + + /* RKISP1_CIF_ISP_LSC_TABLE_ADDRESS_153 = ( 17 * 18 ) >> 1 */ + sram_addr = (isp_lsc_status & RKISP1_CIF_ISP_LSC_ACTIVE_TABLE) ? + RKISP1_CIF_ISP_LSC_TABLE_ADDRESS_0 : + RKISP1_CIF_ISP_LSC_TABLE_ADDRESS_153; + rkisp1_write(params->rkisp1, sram_addr, + RKISP1_CIF_ISP_LSC_R_TABLE_ADDR); + rkisp1_write(params->rkisp1, sram_addr, + RKISP1_CIF_ISP_LSC_GR_TABLE_ADDR); + rkisp1_write(params->rkisp1, sram_addr, + RKISP1_CIF_ISP_LSC_GB_TABLE_ADDR); + rkisp1_write(params->rkisp1, sram_addr, + RKISP1_CIF_ISP_LSC_B_TABLE_ADDR); + + /* program data tables (table size is 9 * 17 = 153) */ + for (i = 0; + i < RKISP1_CIF_ISP_LSC_SECTORS_MAX * RKISP1_CIF_ISP_LSC_SECTORS_MAX; + i += RKISP1_CIF_ISP_LSC_SECTORS_MAX) { + /* + * 17 sectors with 2 values in one DWORD = 9 + * DWORDs (2nd value of last DWORD unused) + */ + for (j = 0; j < RKISP1_CIF_ISP_LSC_SECTORS_MAX - 1; j += 2) { + data = RKISP1_CIF_ISP_LSC_TABLE_DATA(pconfig->r_data_tbl[i + j], + pconfig->r_data_tbl[i + j + 1]); + rkisp1_write(params->rkisp1, data, + RKISP1_CIF_ISP_LSC_R_TABLE_DATA); + + data = RKISP1_CIF_ISP_LSC_TABLE_DATA(pconfig->gr_data_tbl[i + j], + pconfig->gr_data_tbl[i + j + 1]); + rkisp1_write(params->rkisp1, data, + RKISP1_CIF_ISP_LSC_GR_TABLE_DATA); + + data = RKISP1_CIF_ISP_LSC_TABLE_DATA(pconfig->gb_data_tbl[i + j], + pconfig->gb_data_tbl[i + j + 1]); + rkisp1_write(params->rkisp1, data, + RKISP1_CIF_ISP_LSC_GB_TABLE_DATA); + + data = RKISP1_CIF_ISP_LSC_TABLE_DATA(pconfig->b_data_tbl[i + j], + pconfig->b_data_tbl[i + j + 1]); + rkisp1_write(params->rkisp1, data, + RKISP1_CIF_ISP_LSC_B_TABLE_DATA); + } + data = RKISP1_CIF_ISP_LSC_TABLE_DATA(pconfig->r_data_tbl[i + j], 0); + rkisp1_write(params->rkisp1, data, + RKISP1_CIF_ISP_LSC_R_TABLE_DATA); + + data = RKISP1_CIF_ISP_LSC_TABLE_DATA(pconfig->gr_data_tbl[i + j], 0); + rkisp1_write(params->rkisp1, data, + RKISP1_CIF_ISP_LSC_GR_TABLE_DATA); + + data = RKISP1_CIF_ISP_LSC_TABLE_DATA(pconfig->gb_data_tbl[i + j], 0); + rkisp1_write(params->rkisp1, data, + RKISP1_CIF_ISP_LSC_GB_TABLE_DATA); + + data = RKISP1_CIF_ISP_LSC_TABLE_DATA(pconfig->b_data_tbl[i + j], 0); + rkisp1_write(params->rkisp1, data, + RKISP1_CIF_ISP_LSC_B_TABLE_DATA); + } + isp_lsc_table_sel = (isp_lsc_status & RKISP1_CIF_ISP_LSC_ACTIVE_TABLE) ? + RKISP1_CIF_ISP_LSC_TABLE_0 : + RKISP1_CIF_ISP_LSC_TABLE_1; + rkisp1_write(params->rkisp1, isp_lsc_table_sel, + RKISP1_CIF_ISP_LSC_TABLE_SEL); +} + +static void rkisp1_lsc_config(struct rkisp1_params *params, + const struct rkisp1_cif_isp_lsc_config *arg) +{ + unsigned int i, data; + u32 lsc_ctrl; + + /* To config must be off , store the current status firstly */ + lsc_ctrl = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_LSC_CTRL); + rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_LSC_CTRL, + RKISP1_CIF_ISP_LSC_CTRL_ENA); + rkisp1_lsc_correct_matrix_config(params, arg); + + for (i = 0; i < 4; i++) { + /* program x size tables */ + data = RKISP1_CIF_ISP_LSC_SECT_SIZE(arg->x_size_tbl[i * 2], + arg->x_size_tbl[i * 2 + 1]); + rkisp1_write(params->rkisp1, data, + RKISP1_CIF_ISP_LSC_XSIZE_01 + i * 4); + + /* program x grad tables */ + data = RKISP1_CIF_ISP_LSC_SECT_SIZE(arg->x_grad_tbl[i * 2], + arg->x_grad_tbl[i * 2 + 1]); + rkisp1_write(params->rkisp1, data, + RKISP1_CIF_ISP_LSC_XGRAD_01 + i * 4); + + /* program y size tables */ + data = RKISP1_CIF_ISP_LSC_SECT_SIZE(arg->y_size_tbl[i * 2], + arg->y_size_tbl[i * 2 + 1]); + rkisp1_write(params->rkisp1, data, + RKISP1_CIF_ISP_LSC_YSIZE_01 + i * 4); + + /* program y grad tables */ + data = RKISP1_CIF_ISP_LSC_SECT_SIZE(arg->y_grad_tbl[i * 2], + arg->y_grad_tbl[i * 2 + 1]); + rkisp1_write(params->rkisp1, data, + RKISP1_CIF_ISP_LSC_YGRAD_01 + i * 4); + } + + /* restore the lsc ctrl status */ + if (lsc_ctrl & RKISP1_CIF_ISP_LSC_CTRL_ENA) { + rkisp1_param_set_bits(params, + RKISP1_CIF_ISP_LSC_CTRL, + RKISP1_CIF_ISP_LSC_CTRL_ENA); + } else { + rkisp1_param_clear_bits(params, + RKISP1_CIF_ISP_LSC_CTRL, + RKISP1_CIF_ISP_LSC_CTRL_ENA); + } +} + +/* ISP Filtering function */ +static void rkisp1_flt_config(struct rkisp1_params *params, + const struct rkisp1_cif_isp_flt_config *arg) +{ + u32 filt_mode; + + rkisp1_write(params->rkisp1, + arg->thresh_bl0, RKISP1_CIF_ISP_FILT_THRESH_BL0); + rkisp1_write(params->rkisp1, + arg->thresh_bl1, RKISP1_CIF_ISP_FILT_THRESH_BL1); + rkisp1_write(params->rkisp1, + arg->thresh_sh0, RKISP1_CIF_ISP_FILT_THRESH_SH0); + rkisp1_write(params->rkisp1, + arg->thresh_sh1, RKISP1_CIF_ISP_FILT_THRESH_SH1); + rkisp1_write(params->rkisp1, arg->fac_bl0, RKISP1_CIF_ISP_FILT_FAC_BL0); + rkisp1_write(params->rkisp1, arg->fac_bl1, RKISP1_CIF_ISP_FILT_FAC_BL1); + rkisp1_write(params->rkisp1, arg->fac_mid, RKISP1_CIF_ISP_FILT_FAC_MID); + rkisp1_write(params->rkisp1, arg->fac_sh0, RKISP1_CIF_ISP_FILT_FAC_SH0); + rkisp1_write(params->rkisp1, arg->fac_sh1, RKISP1_CIF_ISP_FILT_FAC_SH1); + rkisp1_write(params->rkisp1, + arg->lum_weight, RKISP1_CIF_ISP_FILT_LUM_WEIGHT); + + rkisp1_write(params->rkisp1, + (arg->mode ? RKISP1_CIF_ISP_FLT_MODE_DNR : 0) | + RKISP1_CIF_ISP_FLT_CHROMA_V_MODE(arg->chr_v_mode) | + RKISP1_CIF_ISP_FLT_CHROMA_H_MODE(arg->chr_h_mode) | + RKISP1_CIF_ISP_FLT_GREEN_STAGE1(arg->grn_stage1), + RKISP1_CIF_ISP_FILT_MODE); + + /* avoid to override the old enable value */ + filt_mode = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_FILT_MODE); + filt_mode &= RKISP1_CIF_ISP_FLT_ENA; + if (arg->mode) + filt_mode |= RKISP1_CIF_ISP_FLT_MODE_DNR; + filt_mode |= RKISP1_CIF_ISP_FLT_CHROMA_V_MODE(arg->chr_v_mode) | + RKISP1_CIF_ISP_FLT_CHROMA_H_MODE(arg->chr_h_mode) | + RKISP1_CIF_ISP_FLT_GREEN_STAGE1(arg->grn_stage1); + rkisp1_write(params->rkisp1, filt_mode, RKISP1_CIF_ISP_FILT_MODE); +} + +/* ISP demosaic interface function */ +static int rkisp1_bdm_config(struct rkisp1_params *params, + const struct rkisp1_cif_isp_bdm_config *arg) +{ + u32 bdm_th; + + /* avoid to override the old enable value */ + bdm_th = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_DEMOSAIC); + bdm_th &= RKISP1_CIF_ISP_DEMOSAIC_BYPASS; + bdm_th |= arg->demosaic_th & ~RKISP1_CIF_ISP_DEMOSAIC_BYPASS; + /* set demosaic threshold */ + rkisp1_write(params->rkisp1, bdm_th, RKISP1_CIF_ISP_DEMOSAIC); + return 0; +} + +/* ISP GAMMA correction interface function */ +static void rkisp1_sdg_config(struct rkisp1_params *params, + const struct rkisp1_cif_isp_sdg_config *arg) +{ + unsigned int i; + + rkisp1_write(params->rkisp1, + arg->xa_pnts.gamma_dx0, RKISP1_CIF_ISP_GAMMA_DX_LO); + rkisp1_write(params->rkisp1, + arg->xa_pnts.gamma_dx1, RKISP1_CIF_ISP_GAMMA_DX_HI); + + for (i = 0; i < RKISP1_CIF_ISP_DEGAMMA_CURVE_SIZE; i++) { + rkisp1_write(params->rkisp1, arg->curve_r.gamma_y[i], + RKISP1_CIF_ISP_GAMMA_R_Y0 + i * 4); + rkisp1_write(params->rkisp1, arg->curve_g.gamma_y[i], + RKISP1_CIF_ISP_GAMMA_G_Y0 + i * 4); + rkisp1_write(params->rkisp1, arg->curve_b.gamma_y[i], + RKISP1_CIF_ISP_GAMMA_B_Y0 + i * 4); + } +} + +/* ISP GAMMA correction interface function */ +static void rkisp1_goc_config(struct rkisp1_params *params, + const struct rkisp1_cif_isp_goc_config *arg) +{ + unsigned int i; + + rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_CTRL, + RKISP1_CIF_ISP_CTRL_ISP_GAMMA_OUT_ENA); + rkisp1_write(params->rkisp1, arg->mode, RKISP1_CIF_ISP_GAMMA_OUT_MODE); + + for (i = 0; i < RKISP1_CIF_ISP_GAMMA_OUT_MAX_SAMPLES; i++) + rkisp1_write(params->rkisp1, arg->gamma_y[i], + RKISP1_CIF_ISP_GAMMA_OUT_Y_0 + i * 4); +} + +/* ISP Cross Talk */ +static void rkisp1_ctk_config(struct rkisp1_params *params, + const struct rkisp1_cif_isp_ctk_config *arg) +{ + rkisp1_write(params->rkisp1, arg->coeff0, RKISP1_CIF_ISP_CT_COEFF_0); + rkisp1_write(params->rkisp1, arg->coeff1, RKISP1_CIF_ISP_CT_COEFF_1); + rkisp1_write(params->rkisp1, arg->coeff2, RKISP1_CIF_ISP_CT_COEFF_2); + rkisp1_write(params->rkisp1, arg->coeff3, RKISP1_CIF_ISP_CT_COEFF_3); + rkisp1_write(params->rkisp1, arg->coeff4, RKISP1_CIF_ISP_CT_COEFF_4); + rkisp1_write(params->rkisp1, arg->coeff5, RKISP1_CIF_ISP_CT_COEFF_5); + rkisp1_write(params->rkisp1, arg->coeff6, RKISP1_CIF_ISP_CT_COEFF_6); + rkisp1_write(params->rkisp1, arg->coeff7, RKISP1_CIF_ISP_CT_COEFF_7); + rkisp1_write(params->rkisp1, arg->coeff8, RKISP1_CIF_ISP_CT_COEFF_8); + rkisp1_write(params->rkisp1, arg->ct_offset_r, + RKISP1_CIF_ISP_CT_OFFSET_R); + rkisp1_write(params->rkisp1, arg->ct_offset_g, + RKISP1_CIF_ISP_CT_OFFSET_G); + rkisp1_write(params->rkisp1, arg->ct_offset_b, + RKISP1_CIF_ISP_CT_OFFSET_B); +} + +static void rkisp1_ctk_enable(struct rkisp1_params *params, bool en) +{ + if (en) + return; + + /* Write back the default values. */ + rkisp1_write(params->rkisp1, 0x80, RKISP1_CIF_ISP_CT_COEFF_0); + rkisp1_write(params->rkisp1, 0, RKISP1_CIF_ISP_CT_COEFF_1); + rkisp1_write(params->rkisp1, 0, RKISP1_CIF_ISP_CT_COEFF_2); + rkisp1_write(params->rkisp1, 0, RKISP1_CIF_ISP_CT_COEFF_3); + rkisp1_write(params->rkisp1, 0x80, RKISP1_CIF_ISP_CT_COEFF_4); + rkisp1_write(params->rkisp1, 0, RKISP1_CIF_ISP_CT_COEFF_5); + rkisp1_write(params->rkisp1, 0, RKISP1_CIF_ISP_CT_COEFF_6); + rkisp1_write(params->rkisp1, 0, RKISP1_CIF_ISP_CT_COEFF_7); + rkisp1_write(params->rkisp1, 0x80, RKISP1_CIF_ISP_CT_COEFF_8); + + rkisp1_write(params->rkisp1, 0, RKISP1_CIF_ISP_CT_OFFSET_R); + rkisp1_write(params->rkisp1, 0, RKISP1_CIF_ISP_CT_OFFSET_G); + rkisp1_write(params->rkisp1, 0, RKISP1_CIF_ISP_CT_OFFSET_B); +} + +/* ISP White Balance Mode */ +static void rkisp1_awb_meas_config(struct rkisp1_params *params, + const struct rkisp1_cif_isp_awb_meas_config *arg) +{ + u32 reg_val = 0; + /* based on the mode,configure the awb module */ + if (arg->awb_mode == RKISP1_CIF_ISP_AWB_MODE_YCBCR) { + /* Reference Cb and Cr */ + rkisp1_write(params->rkisp1, + RKISP1_CIF_ISP_AWB_REF_CR_SET(arg->awb_ref_cr) | + arg->awb_ref_cb, RKISP1_CIF_ISP_AWB_REF); + /* Yc Threshold */ + rkisp1_write(params->rkisp1, + RKISP1_CIF_ISP_AWB_MAX_Y_SET(arg->max_y) | + RKISP1_CIF_ISP_AWB_MIN_Y_SET(arg->min_y) | + RKISP1_CIF_ISP_AWB_MAX_CS_SET(arg->max_csum) | + arg->min_c, RKISP1_CIF_ISP_AWB_THRESH); + } + + reg_val = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_AWB_PROP); + if (arg->enable_ymax_cmp) + reg_val |= RKISP1_CIF_ISP_AWB_YMAX_CMP_EN; + else + reg_val &= ~RKISP1_CIF_ISP_AWB_YMAX_CMP_EN; + rkisp1_write(params->rkisp1, reg_val, RKISP1_CIF_ISP_AWB_PROP); + + /* window offset */ + rkisp1_write(params->rkisp1, + arg->awb_wnd.v_offs, RKISP1_CIF_ISP_AWB_WND_V_OFFS); + rkisp1_write(params->rkisp1, + arg->awb_wnd.h_offs, RKISP1_CIF_ISP_AWB_WND_H_OFFS); + /* AWB window size */ + rkisp1_write(params->rkisp1, + arg->awb_wnd.v_size, RKISP1_CIF_ISP_AWB_WND_V_SIZE); + rkisp1_write(params->rkisp1, + arg->awb_wnd.h_size, RKISP1_CIF_ISP_AWB_WND_H_SIZE); + /* Number of frames */ + rkisp1_write(params->rkisp1, + arg->frames, RKISP1_CIF_ISP_AWB_FRAMES); +} + +static void +rkisp1_awb_meas_enable(struct rkisp1_params *params, + const struct rkisp1_cif_isp_awb_meas_config *arg, + bool en) +{ + u32 reg_val = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_AWB_PROP); + + /* switch off */ + reg_val &= RKISP1_CIF_ISP_AWB_MODE_MASK_NONE; + + if (en) { + if (arg->awb_mode == RKISP1_CIF_ISP_AWB_MODE_RGB) + reg_val |= RKISP1_CIF_ISP_AWB_MODE_RGB_EN; + else + reg_val |= RKISP1_CIF_ISP_AWB_MODE_YCBCR_EN; + + rkisp1_write(params->rkisp1, reg_val, RKISP1_CIF_ISP_AWB_PROP); + + /* Measurements require AWB block be active. */ + rkisp1_param_set_bits(params, RKISP1_CIF_ISP_CTRL, + RKISP1_CIF_ISP_CTRL_ISP_AWB_ENA); + } else { + rkisp1_write(params->rkisp1, + reg_val, RKISP1_CIF_ISP_AWB_PROP); + rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_CTRL, + RKISP1_CIF_ISP_CTRL_ISP_AWB_ENA); + } +} + +static void +rkisp1_awb_gain_config(struct rkisp1_params *params, + const struct rkisp1_cif_isp_awb_gain_config *arg) +{ + rkisp1_write(params->rkisp1, + RKISP1_CIF_ISP_AWB_GAIN_R_SET(arg->gain_green_r) | + arg->gain_green_b, RKISP1_CIF_ISP_AWB_GAIN_G); + + rkisp1_write(params->rkisp1, + RKISP1_CIF_ISP_AWB_GAIN_R_SET(arg->gain_red) | + arg->gain_blue, RKISP1_CIF_ISP_AWB_GAIN_RB); +} + +static void rkisp1_aec_config(struct rkisp1_params *params, + const struct rkisp1_cif_isp_aec_config *arg) +{ + unsigned int block_hsize, block_vsize; + u32 exp_ctrl; + + /* avoid to override the old enable value */ + exp_ctrl = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_EXP_CTRL); + exp_ctrl &= RKISP1_CIF_ISP_EXP_ENA; + if (arg->autostop) + exp_ctrl |= RKISP1_CIF_ISP_EXP_CTRL_AUTOSTOP; + if (arg->mode == RKISP1_CIF_ISP_EXP_MEASURING_MODE_1) + exp_ctrl |= RKISP1_CIF_ISP_EXP_CTRL_MEASMODE_1; + rkisp1_write(params->rkisp1, exp_ctrl, RKISP1_CIF_ISP_EXP_CTRL); + + rkisp1_write(params->rkisp1, + arg->meas_window.h_offs, RKISP1_CIF_ISP_EXP_H_OFFSET); + rkisp1_write(params->rkisp1, + arg->meas_window.v_offs, RKISP1_CIF_ISP_EXP_V_OFFSET); + + block_hsize = arg->meas_window.h_size / + RKISP1_CIF_ISP_EXP_COLUMN_NUM - 1; + block_vsize = arg->meas_window.v_size / + RKISP1_CIF_ISP_EXP_ROW_NUM - 1; + + rkisp1_write(params->rkisp1, + RKISP1_CIF_ISP_EXP_H_SIZE_SET(block_hsize), + RKISP1_CIF_ISP_EXP_H_SIZE); + rkisp1_write(params->rkisp1, + RKISP1_CIF_ISP_EXP_V_SIZE_SET(block_vsize), + RKISP1_CIF_ISP_EXP_V_SIZE); +} + +static void rkisp1_cproc_config(struct rkisp1_params *params, + const struct rkisp1_cif_isp_cproc_config *arg) +{ + struct rkisp1_cif_isp_isp_other_cfg *cur_other_cfg = + ¶ms->cur_params.others; + struct rkisp1_cif_isp_ie_config *cur_ie_config = + &cur_other_cfg->ie_config; + u32 effect = cur_ie_config->effect; + u32 quantization = params->quantization; + + rkisp1_write(params->rkisp1, arg->contrast, RKISP1_CIF_C_PROC_CONTRAST); + rkisp1_write(params->rkisp1, arg->hue, RKISP1_CIF_C_PROC_HUE); + rkisp1_write(params->rkisp1, arg->sat, RKISP1_CIF_C_PROC_SATURATION); + rkisp1_write(params->rkisp1, arg->brightness, + RKISP1_CIF_C_PROC_BRIGHTNESS); + + if (quantization != V4L2_QUANTIZATION_FULL_RANGE || + effect != V4L2_COLORFX_NONE) { + rkisp1_param_clear_bits(params, RKISP1_CIF_C_PROC_CTRL, + RKISP1_CIF_C_PROC_YOUT_FULL | + RKISP1_CIF_C_PROC_YIN_FULL | + RKISP1_CIF_C_PROC_COUT_FULL); + } else { + rkisp1_param_set_bits(params, RKISP1_CIF_C_PROC_CTRL, + RKISP1_CIF_C_PROC_YOUT_FULL | + RKISP1_CIF_C_PROC_YIN_FULL | + RKISP1_CIF_C_PROC_COUT_FULL); + } +} + +static void rkisp1_hst_config(struct rkisp1_params *params, + const struct rkisp1_cif_isp_hst_config *arg) +{ + unsigned int block_hsize, block_vsize; + static const u32 hist_weight_regs[] = { + RKISP1_CIF_ISP_HIST_WEIGHT_00TO30, + RKISP1_CIF_ISP_HIST_WEIGHT_40TO21, + RKISP1_CIF_ISP_HIST_WEIGHT_31TO12, + RKISP1_CIF_ISP_HIST_WEIGHT_22TO03, + RKISP1_CIF_ISP_HIST_WEIGHT_13TO43, + RKISP1_CIF_ISP_HIST_WEIGHT_04TO34, + RKISP1_CIF_ISP_HIST_WEIGHT_44, + }; + const u8 *weight; + unsigned int i; + u32 hist_prop; + + /* avoid to override the old enable value */ + hist_prop = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_HIST_PROP); + hist_prop &= RKISP1_CIF_ISP_HIST_PROP_MODE_MASK; + hist_prop |= RKISP1_CIF_ISP_HIST_PREDIV_SET(arg->histogram_predivider); + rkisp1_write(params->rkisp1, hist_prop, RKISP1_CIF_ISP_HIST_PROP); + rkisp1_write(params->rkisp1, + arg->meas_window.h_offs, + RKISP1_CIF_ISP_HIST_H_OFFS); + rkisp1_write(params->rkisp1, + arg->meas_window.v_offs, + RKISP1_CIF_ISP_HIST_V_OFFS); + + block_hsize = arg->meas_window.h_size / + RKISP1_CIF_ISP_HIST_COLUMN_NUM - 1; + block_vsize = arg->meas_window.v_size / RKISP1_CIF_ISP_HIST_ROW_NUM - 1; + + rkisp1_write(params->rkisp1, block_hsize, RKISP1_CIF_ISP_HIST_H_SIZE); + rkisp1_write(params->rkisp1, block_vsize, RKISP1_CIF_ISP_HIST_V_SIZE); + + weight = arg->hist_weight; + for (i = 0; i < ARRAY_SIZE(hist_weight_regs); ++i, weight += 4) + rkisp1_write(params->rkisp1, + RKISP1_CIF_ISP_HIST_WEIGHT_SET(weight[0], + weight[1], + weight[2], + weight[3]), + hist_weight_regs[i]); +} + +static void +rkisp1_hst_enable(struct rkisp1_params *params, + const struct rkisp1_cif_isp_hst_config *arg, bool en) +{ + if (en) { + u32 hist_prop = rkisp1_read(params->rkisp1, + RKISP1_CIF_ISP_HIST_PROP); + + hist_prop &= ~RKISP1_CIF_ISP_HIST_PROP_MODE_MASK; + hist_prop |= arg->mode; + rkisp1_param_set_bits(params, RKISP1_CIF_ISP_HIST_PROP, + hist_prop); + } else { + rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_HIST_PROP, + RKISP1_CIF_ISP_HIST_PROP_MODE_MASK); + } +} + +static void rkisp1_afm_config(struct rkisp1_params *params, + const struct rkisp1_cif_isp_afc_config *arg) +{ + size_t num_of_win = min_t(size_t, ARRAY_SIZE(arg->afm_win), + arg->num_afm_win); + u32 afm_ctrl = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_AFM_CTRL); + unsigned int i; + + /* Switch off to configure. */ + rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_AFM_CTRL, + RKISP1_CIF_ISP_AFM_ENA); + + for (i = 0; i < num_of_win; i++) { + rkisp1_write(params->rkisp1, + RKISP1_CIF_ISP_AFM_WINDOW_X(arg->afm_win[i].h_offs) | + RKISP1_CIF_ISP_AFM_WINDOW_Y(arg->afm_win[i].v_offs), + RKISP1_CIF_ISP_AFM_LT_A + i * 8); + rkisp1_write(params->rkisp1, + RKISP1_CIF_ISP_AFM_WINDOW_X(arg->afm_win[i].h_size + + arg->afm_win[i].h_offs) | + RKISP1_CIF_ISP_AFM_WINDOW_Y(arg->afm_win[i].v_size + + arg->afm_win[i].v_offs), + RKISP1_CIF_ISP_AFM_RB_A + i * 8); + } + rkisp1_write(params->rkisp1, arg->thres, RKISP1_CIF_ISP_AFM_THRES); + rkisp1_write(params->rkisp1, arg->var_shift, + RKISP1_CIF_ISP_AFM_VAR_SHIFT); + /* restore afm status */ + rkisp1_write(params->rkisp1, afm_ctrl, RKISP1_CIF_ISP_AFM_CTRL); +} + +static void rkisp1_ie_config(struct rkisp1_params *params, + const struct rkisp1_cif_isp_ie_config *arg) +{ + u32 eff_ctrl; + + eff_ctrl = rkisp1_read(params->rkisp1, RKISP1_CIF_IMG_EFF_CTRL); + eff_ctrl &= ~RKISP1_CIF_IMG_EFF_CTRL_MODE_MASK; + + if (params->quantization == V4L2_QUANTIZATION_FULL_RANGE) + eff_ctrl |= RKISP1_CIF_IMG_EFF_CTRL_YCBCR_FULL; + + switch (arg->effect) { + case V4L2_COLORFX_SEPIA: + eff_ctrl |= RKISP1_CIF_IMG_EFF_CTRL_MODE_SEPIA; + break; + case V4L2_COLORFX_SET_CBCR: + rkisp1_write(params->rkisp1, arg->eff_tint, + RKISP1_CIF_IMG_EFF_TINT); + eff_ctrl |= RKISP1_CIF_IMG_EFF_CTRL_MODE_SEPIA; + break; + /* + * Color selection is similar to water color(AQUA): + * grayscale + selected color w threshold + */ + case V4L2_COLORFX_AQUA: + eff_ctrl |= RKISP1_CIF_IMG_EFF_CTRL_MODE_COLOR_SEL; + rkisp1_write(params->rkisp1, arg->color_sel, + RKISP1_CIF_IMG_EFF_COLOR_SEL); + break; + case V4L2_COLORFX_EMBOSS: + eff_ctrl |= RKISP1_CIF_IMG_EFF_CTRL_MODE_EMBOSS; + rkisp1_write(params->rkisp1, arg->eff_mat_1, + RKISP1_CIF_IMG_EFF_MAT_1); + rkisp1_write(params->rkisp1, arg->eff_mat_2, + RKISP1_CIF_IMG_EFF_MAT_2); + rkisp1_write(params->rkisp1, arg->eff_mat_3, + RKISP1_CIF_IMG_EFF_MAT_3); + break; + case V4L2_COLORFX_SKETCH: + eff_ctrl |= RKISP1_CIF_IMG_EFF_CTRL_MODE_SKETCH; + rkisp1_write(params->rkisp1, arg->eff_mat_3, + RKISP1_CIF_IMG_EFF_MAT_3); + rkisp1_write(params->rkisp1, arg->eff_mat_4, + RKISP1_CIF_IMG_EFF_MAT_4); + rkisp1_write(params->rkisp1, arg->eff_mat_5, + RKISP1_CIF_IMG_EFF_MAT_5); + break; + case V4L2_COLORFX_BW: + eff_ctrl |= RKISP1_CIF_IMG_EFF_CTRL_MODE_BLACKWHITE; + break; + case V4L2_COLORFX_NEGATIVE: + eff_ctrl |= RKISP1_CIF_IMG_EFF_CTRL_MODE_NEGATIVE; + break; + default: + break; + } + + rkisp1_write(params->rkisp1, eff_ctrl, RKISP1_CIF_IMG_EFF_CTRL); +} + +static void rkisp1_ie_enable(struct rkisp1_params *params, bool en) +{ + if (en) { + rkisp1_param_set_bits(params, RKISP1_CIF_ICCL, + RKISP1_CIF_ICCL_IE_CLK); + rkisp1_write(params->rkisp1, RKISP1_CIF_IMG_EFF_CTRL_ENABLE, + RKISP1_CIF_IMG_EFF_CTRL); + rkisp1_param_set_bits(params, RKISP1_CIF_IMG_EFF_CTRL, + RKISP1_CIF_IMG_EFF_CTRL_CFG_UPD); + } else { + rkisp1_param_clear_bits(params, RKISP1_CIF_IMG_EFF_CTRL, + RKISP1_CIF_IMG_EFF_CTRL_ENABLE); + rkisp1_param_clear_bits(params, RKISP1_CIF_ICCL, + RKISP1_CIF_ICCL_IE_CLK); + } +} + +static void rkisp1_csm_config(struct rkisp1_params *params, bool full_range) +{ + static const u16 full_range_coeff[] = { + 0x0026, 0x004b, 0x000f, + 0x01ea, 0x01d6, 0x0040, + 0x0040, 0x01ca, 0x01f6 + }; + static const u16 limited_range_coeff[] = { + 0x0021, 0x0040, 0x000d, + 0x01ed, 0x01db, 0x0038, + 0x0038, 0x01d1, 0x01f7, + }; + unsigned int i; + + if (full_range) { + for (i = 0; i < ARRAY_SIZE(full_range_coeff); i++) + rkisp1_write(params->rkisp1, full_range_coeff[i], + RKISP1_CIF_ISP_CC_COEFF_0 + i * 4); + + rkisp1_param_set_bits(params, RKISP1_CIF_ISP_CTRL, + RKISP1_CIF_ISP_CTRL_ISP_CSM_Y_FULL_ENA | + RKISP1_CIF_ISP_CTRL_ISP_CSM_C_FULL_ENA); + } else { + for (i = 0; i < ARRAY_SIZE(limited_range_coeff); i++) + rkisp1_write(params->rkisp1, limited_range_coeff[i], + RKISP1_CIF_ISP_CC_COEFF_0 + i * 4); + + rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_CTRL, + RKISP1_CIF_ISP_CTRL_ISP_CSM_Y_FULL_ENA | + RKISP1_CIF_ISP_CTRL_ISP_CSM_C_FULL_ENA); + } +} + +/* ISP De-noise Pre-Filter(DPF) function */ +static void rkisp1_dpf_config(struct rkisp1_params *params, + const struct rkisp1_cif_isp_dpf_config *arg) +{ + unsigned int isp_dpf_mode, spatial_coeff, i; + + switch (arg->gain.mode) { + case RKISP1_CIF_ISP_DPF_GAIN_USAGE_NF_GAINS: + isp_dpf_mode = RKISP1_CIF_ISP_DPF_MODE_USE_NF_GAIN | + RKISP1_CIF_ISP_DPF_MODE_AWB_GAIN_COMP; + break; + case RKISP1_CIF_ISP_DPF_GAIN_USAGE_LSC_GAINS: + isp_dpf_mode = RKISP1_CIF_ISP_DPF_MODE_LSC_GAIN_COMP; + break; + case RKISP1_CIF_ISP_DPF_GAIN_USAGE_NF_LSC_GAINS: + isp_dpf_mode = RKISP1_CIF_ISP_DPF_MODE_USE_NF_GAIN | + RKISP1_CIF_ISP_DPF_MODE_AWB_GAIN_COMP | + RKISP1_CIF_ISP_DPF_MODE_LSC_GAIN_COMP; + break; + case RKISP1_CIF_ISP_DPF_GAIN_USAGE_AWB_GAINS: + isp_dpf_mode = RKISP1_CIF_ISP_DPF_MODE_AWB_GAIN_COMP; + break; + case RKISP1_CIF_ISP_DPF_GAIN_USAGE_AWB_LSC_GAINS: + isp_dpf_mode = RKISP1_CIF_ISP_DPF_MODE_LSC_GAIN_COMP | + RKISP1_CIF_ISP_DPF_MODE_AWB_GAIN_COMP; + break; + case RKISP1_CIF_ISP_DPF_GAIN_USAGE_DISABLED: + default: + isp_dpf_mode = 0; + break; + } + + if (arg->nll.scale_mode == RKISP1_CIF_ISP_NLL_SCALE_LOGARITHMIC) + isp_dpf_mode |= RKISP1_CIF_ISP_DPF_MODE_NLL_SEGMENTATION; + if (arg->rb_flt.fltsize == RKISP1_CIF_ISP_DPF_RB_FILTERSIZE_9x9) + isp_dpf_mode |= RKISP1_CIF_ISP_DPF_MODE_RB_FLTSIZE_9x9; + if (!arg->rb_flt.r_enable) + isp_dpf_mode |= RKISP1_CIF_ISP_DPF_MODE_R_FLT_DIS; + if (!arg->rb_flt.b_enable) + isp_dpf_mode |= RKISP1_CIF_ISP_DPF_MODE_B_FLT_DIS; + if (!arg->g_flt.gb_enable) + isp_dpf_mode |= RKISP1_CIF_ISP_DPF_MODE_GB_FLT_DIS; + if (!arg->g_flt.gr_enable) + isp_dpf_mode |= RKISP1_CIF_ISP_DPF_MODE_GR_FLT_DIS; + + rkisp1_param_set_bits(params, RKISP1_CIF_ISP_DPF_MODE, + isp_dpf_mode); + rkisp1_write(params->rkisp1, arg->gain.nf_b_gain, + RKISP1_CIF_ISP_DPF_NF_GAIN_B); + rkisp1_write(params->rkisp1, arg->gain.nf_r_gain, + RKISP1_CIF_ISP_DPF_NF_GAIN_R); + rkisp1_write(params->rkisp1, arg->gain.nf_gb_gain, + RKISP1_CIF_ISP_DPF_NF_GAIN_GB); + rkisp1_write(params->rkisp1, arg->gain.nf_gr_gain, + RKISP1_CIF_ISP_DPF_NF_GAIN_GR); + + for (i = 0; i < RKISP1_CIF_ISP_DPF_MAX_NLF_COEFFS; i++) { + rkisp1_write(params->rkisp1, arg->nll.coeff[i], + RKISP1_CIF_ISP_DPF_NULL_COEFF_0 + i * 4); + } + + spatial_coeff = arg->g_flt.spatial_coeff[0] | + (arg->g_flt.spatial_coeff[1] << 8) | + (arg->g_flt.spatial_coeff[2] << 16) | + (arg->g_flt.spatial_coeff[3] << 24); + rkisp1_write(params->rkisp1, spatial_coeff, + RKISP1_CIF_ISP_DPF_S_WEIGHT_G_1_4); + + spatial_coeff = arg->g_flt.spatial_coeff[4] | + (arg->g_flt.spatial_coeff[5] << 8); + rkisp1_write(params->rkisp1, spatial_coeff, + RKISP1_CIF_ISP_DPF_S_WEIGHT_G_5_6); + + spatial_coeff = arg->rb_flt.spatial_coeff[0] | + (arg->rb_flt.spatial_coeff[1] << 8) | + (arg->rb_flt.spatial_coeff[2] << 16) | + (arg->rb_flt.spatial_coeff[3] << 24); + rkisp1_write(params->rkisp1, spatial_coeff, + RKISP1_CIF_ISP_DPF_S_WEIGHT_RB_1_4); + + spatial_coeff = arg->rb_flt.spatial_coeff[4] | + (arg->rb_flt.spatial_coeff[5] << 8); + rkisp1_write(params->rkisp1, spatial_coeff, + RKISP1_CIF_ISP_DPF_S_WEIGHT_RB_5_6); +} + +static void +rkisp1_dpf_strength_config(struct rkisp1_params *params, + const struct rkisp1_cif_isp_dpf_strength_config *arg) +{ + rkisp1_write(params->rkisp1, arg->b, RKISP1_CIF_ISP_DPF_STRENGTH_B); + rkisp1_write(params->rkisp1, arg->g, RKISP1_CIF_ISP_DPF_STRENGTH_G); + rkisp1_write(params->rkisp1, arg->r, RKISP1_CIF_ISP_DPF_STRENGTH_R); +} + +static void +rkisp1_isp_isr_other_config(struct rkisp1_params *params, + const struct rkisp1_params_cfg *new_params) +{ + unsigned int module_en_update, module_cfg_update, module_ens; + + module_en_update = new_params->module_en_update; + module_cfg_update = new_params->module_cfg_update; + module_ens = new_params->module_ens; + + if ((module_en_update & RKISP1_CIF_ISP_MODULE_DPCC) || + (module_cfg_update & RKISP1_CIF_ISP_MODULE_DPCC)) { + /*update dpc config */ + if ((module_cfg_update & RKISP1_CIF_ISP_MODULE_DPCC)) + rkisp1_dpcc_config(params, + &new_params->others.dpcc_config); + + if (module_en_update & RKISP1_CIF_ISP_MODULE_DPCC) { + if (!!(module_ens & RKISP1_CIF_ISP_MODULE_DPCC)) + rkisp1_param_set_bits(params, + RKISP1_CIF_ISP_DPCC_MODE, + RKISP1_CIF_ISP_DPCC_ENA); + else + rkisp1_param_clear_bits(params, + RKISP1_CIF_ISP_DPCC_MODE, + RKISP1_CIF_ISP_DPCC_ENA); + } + } + + if ((module_en_update & RKISP1_CIF_ISP_MODULE_BLS) || + (module_cfg_update & RKISP1_CIF_ISP_MODULE_BLS)) { + /* update bls config */ + if ((module_cfg_update & RKISP1_CIF_ISP_MODULE_BLS)) + rkisp1_bls_config(params, + &new_params->others.bls_config); + + if (module_en_update & RKISP1_CIF_ISP_MODULE_BLS) { + if (!!(module_ens & RKISP1_CIF_ISP_MODULE_BLS)) + rkisp1_param_set_bits(params, + RKISP1_CIF_ISP_BLS_CTRL, + RKISP1_CIF_ISP_BLS_ENA); + else + rkisp1_param_clear_bits(params, + RKISP1_CIF_ISP_BLS_CTRL, + RKISP1_CIF_ISP_BLS_ENA); + } + } + + if ((module_en_update & RKISP1_CIF_ISP_MODULE_SDG) || + (module_cfg_update & RKISP1_CIF_ISP_MODULE_SDG)) { + /* update sdg config */ + if ((module_cfg_update & RKISP1_CIF_ISP_MODULE_SDG)) + rkisp1_sdg_config(params, + &new_params->others.sdg_config); + + if (module_en_update & RKISP1_CIF_ISP_MODULE_SDG) { + if (!!(module_ens & RKISP1_CIF_ISP_MODULE_SDG)) + rkisp1_param_set_bits(params, + RKISP1_CIF_ISP_CTRL, + RKISP1_CIF_ISP_CTRL_ISP_GAMMA_IN_ENA); + else + rkisp1_param_clear_bits(params, + RKISP1_CIF_ISP_CTRL, + RKISP1_CIF_ISP_CTRL_ISP_GAMMA_IN_ENA); + } + } + + if ((module_en_update & RKISP1_CIF_ISP_MODULE_LSC) || + (module_cfg_update & RKISP1_CIF_ISP_MODULE_LSC)) { + /* update lsc config */ + if ((module_cfg_update & RKISP1_CIF_ISP_MODULE_LSC)) + rkisp1_lsc_config(params, + &new_params->others.lsc_config); + + if (module_en_update & RKISP1_CIF_ISP_MODULE_LSC) { + if (!!(module_ens & RKISP1_CIF_ISP_MODULE_LSC)) + rkisp1_param_set_bits(params, + RKISP1_CIF_ISP_LSC_CTRL, + RKISP1_CIF_ISP_LSC_CTRL_ENA); + else + rkisp1_param_clear_bits(params, + RKISP1_CIF_ISP_LSC_CTRL, + RKISP1_CIF_ISP_LSC_CTRL_ENA); + } + } + + if ((module_en_update & RKISP1_CIF_ISP_MODULE_AWB_GAIN) || + (module_cfg_update & RKISP1_CIF_ISP_MODULE_AWB_GAIN)) { + /* update awb gains */ + if ((module_cfg_update & RKISP1_CIF_ISP_MODULE_AWB_GAIN)) + rkisp1_awb_gain_config(params, + &new_params->others.awb_gain_config); + + if (module_en_update & RKISP1_CIF_ISP_MODULE_AWB_GAIN) { + if (!!(module_ens & RKISP1_CIF_ISP_MODULE_AWB_GAIN)) + rkisp1_param_set_bits(params, + RKISP1_CIF_ISP_CTRL, + RKISP1_CIF_ISP_CTRL_ISP_AWB_ENA); + else + rkisp1_param_clear_bits(params, + RKISP1_CIF_ISP_CTRL, + RKISP1_CIF_ISP_CTRL_ISP_AWB_ENA); + } + } + + if ((module_en_update & RKISP1_CIF_ISP_MODULE_BDM) || + (module_cfg_update & RKISP1_CIF_ISP_MODULE_BDM)) { + /* update bdm config */ + if ((module_cfg_update & RKISP1_CIF_ISP_MODULE_BDM)) + rkisp1_bdm_config(params, + &new_params->others.bdm_config); + + if (module_en_update & RKISP1_CIF_ISP_MODULE_BDM) { + if (!!(module_ens & RKISP1_CIF_ISP_MODULE_BDM)) + rkisp1_param_set_bits(params, + RKISP1_CIF_ISP_DEMOSAIC, + RKISP1_CIF_ISP_DEMOSAIC_BYPASS); + else + rkisp1_param_clear_bits(params, + RKISP1_CIF_ISP_DEMOSAIC, + RKISP1_CIF_ISP_DEMOSAIC_BYPASS); + } + } + + if ((module_en_update & RKISP1_CIF_ISP_MODULE_FLT) || + (module_cfg_update & RKISP1_CIF_ISP_MODULE_FLT)) { + /* update filter config */ + if ((module_cfg_update & RKISP1_CIF_ISP_MODULE_FLT)) + rkisp1_flt_config(params, + &new_params->others.flt_config); + + if (module_en_update & RKISP1_CIF_ISP_MODULE_FLT) { + if (!!(module_ens & RKISP1_CIF_ISP_MODULE_FLT)) + rkisp1_param_set_bits(params, + RKISP1_CIF_ISP_FILT_MODE, + RKISP1_CIF_ISP_FLT_ENA); + else + rkisp1_param_clear_bits(params, + RKISP1_CIF_ISP_FILT_MODE, + RKISP1_CIF_ISP_FLT_ENA); + } + } + + if ((module_en_update & RKISP1_CIF_ISP_MODULE_CTK) || + (module_cfg_update & RKISP1_CIF_ISP_MODULE_CTK)) { + /* update ctk config */ + if ((module_cfg_update & RKISP1_CIF_ISP_MODULE_CTK)) + rkisp1_ctk_config(params, + &new_params->others.ctk_config); + + if (module_en_update & RKISP1_CIF_ISP_MODULE_CTK) + rkisp1_ctk_enable(params, + !!(module_ens & RKISP1_CIF_ISP_MODULE_CTK)); + } + + if ((module_en_update & RKISP1_CIF_ISP_MODULE_GOC) || + (module_cfg_update & RKISP1_CIF_ISP_MODULE_GOC)) { + /* update goc config */ + if ((module_cfg_update & RKISP1_CIF_ISP_MODULE_GOC)) + rkisp1_goc_config(params, + &new_params->others.goc_config); + + if (module_en_update & RKISP1_CIF_ISP_MODULE_GOC) { + if (!!(module_ens & RKISP1_CIF_ISP_MODULE_GOC)) + rkisp1_param_set_bits(params, + RKISP1_CIF_ISP_CTRL, + RKISP1_CIF_ISP_CTRL_ISP_GAMMA_OUT_ENA); + else + rkisp1_param_clear_bits(params, + RKISP1_CIF_ISP_CTRL, + RKISP1_CIF_ISP_CTRL_ISP_GAMMA_OUT_ENA); + } + } + + if ((module_en_update & RKISP1_CIF_ISP_MODULE_CPROC) || + (module_cfg_update & RKISP1_CIF_ISP_MODULE_CPROC)) { + /* update cproc config */ + if ((module_cfg_update & RKISP1_CIF_ISP_MODULE_CPROC)) { + rkisp1_cproc_config(params, + &new_params->others.cproc_config); + } + + if (module_en_update & RKISP1_CIF_ISP_MODULE_CPROC) { + if (!!(module_ens & RKISP1_CIF_ISP_MODULE_CPROC)) + rkisp1_param_set_bits(params, + RKISP1_CIF_C_PROC_CTRL, + RKISP1_CIF_C_PROC_CTR_ENABLE); + else + rkisp1_param_clear_bits(params, + RKISP1_CIF_C_PROC_CTRL, + RKISP1_CIF_C_PROC_CTR_ENABLE); + } + } + + if ((module_en_update & RKISP1_CIF_ISP_MODULE_IE) || + (module_cfg_update & RKISP1_CIF_ISP_MODULE_IE)) { + /* update ie config */ + if ((module_cfg_update & RKISP1_CIF_ISP_MODULE_IE)) + rkisp1_ie_config(params, + &new_params->others.ie_config); + + if (module_en_update & RKISP1_CIF_ISP_MODULE_IE) + rkisp1_ie_enable(params, + !!(module_ens & RKISP1_CIF_ISP_MODULE_IE)); + } + + if ((module_en_update & RKISP1_CIF_ISP_MODULE_DPF) || + (module_cfg_update & RKISP1_CIF_ISP_MODULE_DPF)) { + /* update dpf config */ + if ((module_cfg_update & RKISP1_CIF_ISP_MODULE_DPF)) + rkisp1_dpf_config(params, + &new_params->others.dpf_config); + + if (module_en_update & RKISP1_CIF_ISP_MODULE_DPF) { + if (!!(module_ens & RKISP1_CIF_ISP_MODULE_DPF)) + rkisp1_param_set_bits(params, + RKISP1_CIF_ISP_DPF_MODE, + RKISP1_CIF_ISP_DPF_MODE_EN); + else + rkisp1_param_clear_bits(params, + RKISP1_CIF_ISP_DPF_MODE, + RKISP1_CIF_ISP_DPF_MODE_EN); + } + } + + if ((module_en_update & RKISP1_CIF_ISP_MODULE_DPF_STRENGTH) || + (module_cfg_update & RKISP1_CIF_ISP_MODULE_DPF_STRENGTH)) { + /* update dpf strength config */ + rkisp1_dpf_strength_config(params, + &new_params->others.dpf_strength_config); + } +} + +static void rkisp1_isp_isr_meas_config(struct rkisp1_params *params, + struct rkisp1_params_cfg *new_params) +{ + unsigned int module_en_update, module_cfg_update, module_ens; + + module_en_update = new_params->module_en_update; + module_cfg_update = new_params->module_cfg_update; + module_ens = new_params->module_ens; + + if ((module_en_update & RKISP1_CIF_ISP_MODULE_AWB) || + (module_cfg_update & RKISP1_CIF_ISP_MODULE_AWB)) { + /* update awb config */ + if ((module_cfg_update & RKISP1_CIF_ISP_MODULE_AWB)) + rkisp1_awb_meas_config(params, + &new_params->meas.awb_meas_config); + + if (module_en_update & RKISP1_CIF_ISP_MODULE_AWB) + rkisp1_awb_meas_enable(params, + &new_params->meas.awb_meas_config, + !!(module_ens & RKISP1_CIF_ISP_MODULE_AWB)); + } + + if ((module_en_update & RKISP1_CIF_ISP_MODULE_AFC) || + (module_cfg_update & RKISP1_CIF_ISP_MODULE_AFC)) { + /* update afc config */ + if ((module_cfg_update & RKISP1_CIF_ISP_MODULE_AFC)) + rkisp1_afm_config(params, + &new_params->meas.afc_config); + + if (module_en_update & RKISP1_CIF_ISP_MODULE_AFC) { + if (!!(module_ens & RKISP1_CIF_ISP_MODULE_AFC)) + rkisp1_param_set_bits(params, + RKISP1_CIF_ISP_AFM_CTRL, + RKISP1_CIF_ISP_AFM_ENA); + else + rkisp1_param_clear_bits(params, + RKISP1_CIF_ISP_AFM_CTRL, + RKISP1_CIF_ISP_AFM_ENA); + } + } + + if ((module_en_update & RKISP1_CIF_ISP_MODULE_HST) || + (module_cfg_update & RKISP1_CIF_ISP_MODULE_HST)) { + /* update hst config */ + if ((module_cfg_update & RKISP1_CIF_ISP_MODULE_HST)) + rkisp1_hst_config(params, + &new_params->meas.hst_config); + + if (module_en_update & RKISP1_CIF_ISP_MODULE_HST) + rkisp1_hst_enable(params, + &new_params->meas.hst_config, + !!(module_ens & RKISP1_CIF_ISP_MODULE_HST)); + } + + if ((module_en_update & RKISP1_CIF_ISP_MODULE_AEC) || + (module_cfg_update & RKISP1_CIF_ISP_MODULE_AEC)) { + /* update aec config */ + if ((module_cfg_update & RKISP1_CIF_ISP_MODULE_AEC)) + rkisp1_aec_config(params, + &new_params->meas.aec_config); + + if (module_en_update & RKISP1_CIF_ISP_MODULE_AEC) { + if (!!(module_ens & RKISP1_CIF_ISP_MODULE_AEC)) + rkisp1_param_set_bits(params, + RKISP1_CIF_ISP_EXP_CTRL, + RKISP1_CIF_ISP_EXP_ENA); + else + rkisp1_param_clear_bits(params, + RKISP1_CIF_ISP_EXP_CTRL, + RKISP1_CIF_ISP_EXP_ENA); + } + } +} + +void rkisp1_params_isr(struct rkisp1_device *rkisp1, u32 isp_mis) +{ + unsigned int frame_sequence = atomic_read(&rkisp1->isp.frame_sequence); + struct rkisp1_params *params = &rkisp1->params; + struct rkisp1_params_cfg *new_params; + struct rkisp1_buffer *cur_buf = NULL; + + spin_lock(¶ms->config_lock); + if (!params->is_streaming) { + spin_unlock(¶ms->config_lock); + return; + } + + /* get one empty buffer */ + if (!list_empty(¶ms->params)) + cur_buf = list_first_entry(¶ms->params, + struct rkisp1_buffer, queue); + spin_unlock(¶ms->config_lock); + + if (!cur_buf) + return; + + new_params = (struct rkisp1_params_cfg *)(cur_buf->vaddr[0]); + + if (isp_mis & RKISP1_CIF_ISP_FRAME) { + u32 isp_ctrl; + + rkisp1_isp_isr_other_config(params, new_params); + rkisp1_isp_isr_meas_config(params, new_params); + + /* update shadow register immediately */ + isp_ctrl = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_CTRL); + isp_ctrl |= RKISP1_CIF_ISP_CTRL_ISP_CFG_UPD; + rkisp1_write(params->rkisp1, isp_ctrl, RKISP1_CIF_ISP_CTRL); + + spin_lock(¶ms->config_lock); + list_del(&cur_buf->queue); + spin_unlock(¶ms->config_lock); + + cur_buf->vb.sequence = frame_sequence; + vb2_buffer_done(&cur_buf->vb.vb2_buf, VB2_BUF_STATE_DONE); + } +} + +static const struct rkisp1_cif_isp_awb_meas_config rkisp1_awb_params_default_config = { + { + 0, 0, RKISP1_DEFAULT_WIDTH, RKISP1_DEFAULT_HEIGHT + }, + RKISP1_CIF_ISP_AWB_MODE_YCBCR, 200, 30, 20, 20, 0, 128, 128 +}; + +static const struct rkisp1_cif_isp_aec_config rkisp1_aec_params_default_config = { + RKISP1_CIF_ISP_EXP_MEASURING_MODE_0, + RKISP1_CIF_ISP_EXP_CTRL_AUTOSTOP_0, + { + RKISP1_DEFAULT_WIDTH >> 2, RKISP1_DEFAULT_HEIGHT >> 2, + RKISP1_DEFAULT_WIDTH >> 1, RKISP1_DEFAULT_HEIGHT >> 1 + } +}; + +static const struct rkisp1_cif_isp_hst_config rkisp1_hst_params_default_config = { + RKISP1_CIF_ISP_HISTOGRAM_MODE_RGB_COMBINED, + 3, + { + RKISP1_DEFAULT_WIDTH >> 2, RKISP1_DEFAULT_HEIGHT >> 2, + RKISP1_DEFAULT_WIDTH >> 1, RKISP1_DEFAULT_HEIGHT >> 1 + }, + { + 0, /* To be filled in with 0x01 at runtime. */ + } +}; + +static const struct rkisp1_cif_isp_afc_config rkisp1_afc_params_default_config = { + 1, + { + { + 300, 225, 200, 150 + } + }, + 4, + 14 +}; + +static void rkisp1_params_config_parameter(struct rkisp1_params *params) +{ + struct rkisp1_cif_isp_hst_config hst = rkisp1_hst_params_default_config; + + spin_lock(¶ms->config_lock); + + rkisp1_awb_meas_config(params, &rkisp1_awb_params_default_config); + rkisp1_awb_meas_enable(params, &rkisp1_awb_params_default_config, + true); + + rkisp1_aec_config(params, &rkisp1_aec_params_default_config); + rkisp1_param_set_bits(params, RKISP1_CIF_ISP_EXP_CTRL, + RKISP1_CIF_ISP_EXP_ENA); + + rkisp1_afm_config(params, &rkisp1_afc_params_default_config); + rkisp1_param_set_bits(params, RKISP1_CIF_ISP_AFM_CTRL, + RKISP1_CIF_ISP_AFM_ENA); + + memset(hst.hist_weight, 0x01, sizeof(hst.hist_weight)); + rkisp1_hst_config(params, &hst); + rkisp1_param_set_bits(params, RKISP1_CIF_ISP_HIST_PROP, + ~RKISP1_CIF_ISP_HIST_PROP_MODE_MASK | + rkisp1_hst_params_default_config.mode); + + /* set the range */ + if (params->quantization == V4L2_QUANTIZATION_FULL_RANGE) + rkisp1_csm_config(params, true); + else + rkisp1_csm_config(params, false); + + /* override the default things */ + rkisp1_isp_isr_other_config(params, ¶ms->cur_params); + rkisp1_isp_isr_meas_config(params, ¶ms->cur_params); + + spin_unlock(¶ms->config_lock); +} + +/* Not called when the camera active, thus not isr protection. */ +void rkisp1_params_configure(struct rkisp1_params *params, + enum rkisp1_fmt_raw_pat_type bayer_pat, + enum v4l2_quantization quantization) +{ + params->quantization = quantization; + params->raw_type = bayer_pat; + rkisp1_params_config_parameter(params); +} + +/* Not called when the camera active, thus not isr protection. */ +void rkisp1_params_disable(struct rkisp1_params *params) +{ + rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_DPCC_MODE, + RKISP1_CIF_ISP_DPCC_ENA); + rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_LSC_CTRL, + RKISP1_CIF_ISP_LSC_CTRL_ENA); + rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_BLS_CTRL, + RKISP1_CIF_ISP_BLS_ENA); + rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_CTRL, + RKISP1_CIF_ISP_CTRL_ISP_GAMMA_IN_ENA); + rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_CTRL, + RKISP1_CIF_ISP_CTRL_ISP_GAMMA_OUT_ENA); + rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_DEMOSAIC, + RKISP1_CIF_ISP_DEMOSAIC_BYPASS); + rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_FILT_MODE, + RKISP1_CIF_ISP_FLT_ENA); + rkisp1_awb_meas_enable(params, NULL, false); + rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_CTRL, + RKISP1_CIF_ISP_CTRL_ISP_AWB_ENA); + rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_EXP_CTRL, + RKISP1_CIF_ISP_EXP_ENA); + rkisp1_ctk_enable(params, false); + rkisp1_param_clear_bits(params, RKISP1_CIF_C_PROC_CTRL, + RKISP1_CIF_C_PROC_CTR_ENABLE); + rkisp1_hst_enable(params, NULL, false); + rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_AFM_CTRL, + RKISP1_CIF_ISP_AFM_ENA); + rkisp1_ie_enable(params, false); + rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_DPF_MODE, + RKISP1_CIF_ISP_DPF_MODE_EN); +} + +static int rkisp1_params_enum_fmt_meta_out(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + struct video_device *video = video_devdata(file); + struct rkisp1_params *params = video_get_drvdata(video); + + if (f->index > 0 || f->type != video->queue->type) + return -EINVAL; + + f->pixelformat = params->vdev_fmt.fmt.meta.dataformat; + + return 0; +} + +static int rkisp1_params_g_fmt_meta_out(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct video_device *video = video_devdata(file); + struct rkisp1_params *params = video_get_drvdata(video); + struct v4l2_meta_format *meta = &f->fmt.meta; + + if (f->type != video->queue->type) + return -EINVAL; + + memset(meta, 0, sizeof(*meta)); + meta->dataformat = params->vdev_fmt.fmt.meta.dataformat; + meta->buffersize = params->vdev_fmt.fmt.meta.buffersize; + + return 0; +} + +static int rkisp1_params_querycap(struct file *file, + void *priv, struct v4l2_capability *cap) +{ + struct video_device *vdev = video_devdata(file); + + strscpy(cap->driver, RKISP1_DRIVER_NAME, sizeof(cap->driver)); + strscpy(cap->card, vdev->name, sizeof(cap->card)); + strscpy(cap->bus_info, RKISP1_BUS_INFO, sizeof(cap->bus_info)); + + return 0; +} + +/* ISP params video device IOCTLs */ +static const struct v4l2_ioctl_ops rkisp1_params_ioctl = { + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_expbuf = vb2_ioctl_expbuf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, + .vidioc_enum_fmt_meta_out = rkisp1_params_enum_fmt_meta_out, + .vidioc_g_fmt_meta_out = rkisp1_params_g_fmt_meta_out, + .vidioc_s_fmt_meta_out = rkisp1_params_g_fmt_meta_out, + .vidioc_try_fmt_meta_out = rkisp1_params_g_fmt_meta_out, + .vidioc_querycap = rkisp1_params_querycap, + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, +}; + +static int rkisp1_params_vb2_queue_setup(struct vb2_queue *vq, + unsigned int *num_buffers, + unsigned int *num_planes, + unsigned int sizes[], + struct device *alloc_devs[]) +{ + struct rkisp1_params *params = vq->drv_priv; + + *num_buffers = clamp_t(u32, *num_buffers, + RKISP1_ISP_PARAMS_REQ_BUFS_MIN, + RKISP1_ISP_PARAMS_REQ_BUFS_MAX); + + *num_planes = 1; + + sizes[0] = sizeof(struct rkisp1_params_cfg); + + INIT_LIST_HEAD(¶ms->params); + params->is_first_params = true; + + return 0; +} + +static void rkisp1_params_vb2_buf_queue(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct rkisp1_buffer *params_buf = + container_of(vbuf, struct rkisp1_buffer, vb); + struct vb2_queue *vq = vb->vb2_queue; + struct rkisp1_params *params = vq->drv_priv; + struct rkisp1_params_cfg *new_params; + unsigned long flags; + unsigned int frame_sequence = + atomic_read(¶ms->rkisp1->isp.frame_sequence); + + if (params->is_first_params) { + new_params = (struct rkisp1_params_cfg *) + (vb2_plane_vaddr(vb, 0)); + vbuf->sequence = frame_sequence; + vb2_buffer_done(¶ms_buf->vb.vb2_buf, VB2_BUF_STATE_DONE); + params->is_first_params = false; + params->cur_params = *new_params; + return; + } + + params_buf->vaddr[0] = vb2_plane_vaddr(vb, 0); + spin_lock_irqsave(¶ms->config_lock, flags); + list_add_tail(¶ms_buf->queue, ¶ms->params); + spin_unlock_irqrestore(¶ms->config_lock, flags); +} + +static int rkisp1_params_vb2_buf_prepare(struct vb2_buffer *vb) +{ + if (vb2_plane_size(vb, 0) < sizeof(struct rkisp1_params_cfg)) + return -EINVAL; + + vb2_set_plane_payload(vb, 0, sizeof(struct rkisp1_params_cfg)); + + return 0; +} + +static void rkisp1_params_vb2_stop_streaming(struct vb2_queue *vq) +{ + struct rkisp1_params *params = vq->drv_priv; + struct rkisp1_buffer *buf; + unsigned long flags; + unsigned int i; + + /* stop params input firstly */ + spin_lock_irqsave(¶ms->config_lock, flags); + params->is_streaming = false; + spin_unlock_irqrestore(¶ms->config_lock, flags); + + for (i = 0; i < RKISP1_ISP_PARAMS_REQ_BUFS_MAX; i++) { + spin_lock_irqsave(¶ms->config_lock, flags); + if (!list_empty(¶ms->params)) { + buf = list_first_entry(¶ms->params, + struct rkisp1_buffer, queue); + list_del(&buf->queue); + spin_unlock_irqrestore(¶ms->config_lock, + flags); + } else { + spin_unlock_irqrestore(¶ms->config_lock, + flags); + break; + } + + if (buf) + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); + buf = NULL; + } +} + +static int +rkisp1_params_vb2_start_streaming(struct vb2_queue *queue, unsigned int count) +{ + struct rkisp1_params *params = queue->drv_priv; + unsigned long flags; + + spin_lock_irqsave(¶ms->config_lock, flags); + params->is_streaming = true; + spin_unlock_irqrestore(¶ms->config_lock, flags); + + return 0; +} + +static struct vb2_ops rkisp1_params_vb2_ops = { + .queue_setup = rkisp1_params_vb2_queue_setup, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, + .buf_queue = rkisp1_params_vb2_buf_queue, + .buf_prepare = rkisp1_params_vb2_buf_prepare, + .start_streaming = rkisp1_params_vb2_start_streaming, + .stop_streaming = rkisp1_params_vb2_stop_streaming, + +}; + +static struct v4l2_file_operations rkisp1_params_fops = { + .mmap = vb2_fop_mmap, + .unlocked_ioctl = video_ioctl2, + .poll = vb2_fop_poll, + .open = v4l2_fh_open, + .release = vb2_fop_release +}; + +static int rkisp1_params_init_vb2_queue(struct vb2_queue *q, + struct rkisp1_params *params) +{ + struct rkisp1_vdev_node *node; + + node = container_of(q, struct rkisp1_vdev_node, buf_queue); + + q->type = V4L2_BUF_TYPE_META_OUTPUT; + q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; + q->drv_priv = params; + q->ops = &rkisp1_params_vb2_ops; + q->mem_ops = &vb2_vmalloc_memops; + q->buf_struct_size = sizeof(struct rkisp1_buffer); + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->lock = &node->vlock; + + return vb2_queue_init(q); +} + +static void rkisp1_init_params(struct rkisp1_params *params) +{ + params->vdev_fmt.fmt.meta.dataformat = + V4L2_META_FMT_RK_ISP1_PARAMS; + params->vdev_fmt.fmt.meta.buffersize = + sizeof(struct rkisp1_params_cfg); +} + +int rkisp1_params_register(struct rkisp1_params *params, + struct v4l2_device *v4l2_dev, + struct rkisp1_device *rkisp1) +{ + struct rkisp1_vdev_node *node = ¶ms->vnode; + struct video_device *vdev = &node->vdev; + int ret; + + params->rkisp1 = rkisp1; + mutex_init(&node->vlock); + spin_lock_init(¶ms->config_lock); + + strscpy(vdev->name, RKISP1_PARAMS_DEV_NAME, sizeof(vdev->name)); + + video_set_drvdata(vdev, params); + vdev->ioctl_ops = &rkisp1_params_ioctl; + vdev->fops = &rkisp1_params_fops; + vdev->release = video_device_release_empty; + /* + * Provide a mutex to v4l2 core. It will be used + * to protect all fops and v4l2 ioctls. + */ + vdev->lock = &node->vlock; + vdev->v4l2_dev = v4l2_dev; + vdev->queue = &node->buf_queue; + vdev->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_META_OUTPUT; + vdev->vfl_dir = VFL_DIR_TX; + rkisp1_params_init_vb2_queue(vdev->queue, params); + rkisp1_init_params(params); + video_set_drvdata(vdev, params); + + node->pad.flags = MEDIA_PAD_FL_SOURCE; + ret = media_entity_pads_init(&vdev->entity, 1, &node->pad); + if (ret) + goto err_release_queue; + ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1); + if (ret) { + dev_err(&vdev->dev, + "failed to register %s, ret=%d\n", vdev->name, ret); + goto err_cleanup_media_entity; + } + return 0; +err_cleanup_media_entity: + media_entity_cleanup(&vdev->entity); +err_release_queue: + vb2_queue_release(vdev->queue); + return ret; +} + +void rkisp1_params_unregister(struct rkisp1_params *params) +{ + struct rkisp1_vdev_node *node = ¶ms->vnode; + struct video_device *vdev = &node->vdev; + + video_unregister_device(vdev); + media_entity_cleanup(&vdev->entity); + vb2_queue_release(vdev->queue); +} From patchwork Wed Jan 8 18:44:50 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Helen Koike X-Patchwork-Id: 11324341 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 376AB921 for ; Wed, 8 Jan 2020 18:48:09 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id D2AEF2067D for ; Wed, 8 Jan 2020 18:48:08 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="YXxB/ARr" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org D2AEF2067D Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=collabora.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-rockchip-bounces+patchwork-linux-rockchip=patchwork.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=DHF2EBdaKZXwtBFFw6/ph74dOrdqf+8TUEpRY5b/pys=; b=YXxB/ARrd7DoNX /nU0q7jrIf5ORAP/7TLJv2jh2oAyPW/yXDQ8wRfLmrdJiRixXaF/Z24KPm4Ap9X7u1wiGhd1ljV9a ysFlZu2texbUnJhlN9oOY6Jw+3g5DbiZaXJT8eHjwLQwsHu4fmS6G4aTGk4ChoXeeVPZRRuffJiBa VvWH+6JWfe48IqICvA9Jve5qDNNiAGMUvx7oAzk8yWa5XsUj2N86FmDuNNPUTnEbOUxGmWP+x/Z61 QPpuPMKOjgYDVuz+fc8wPt4JcZ/DT+T3/cjU9NtAZ7ekVfSey+00uMJvhD5p9kacP5iBc4cMff/17 oOquEcte+EMO1mQzhazw==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1ipGNA-0001gi-J8; Wed, 08 Jan 2020 18:48:04 +0000 Received: from bhuna.collabora.co.uk ([2a00:1098:0:82:1000:25:2eeb:e3e3]) by bombadil.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1ipGLT-0000I7-Go; Wed, 08 Jan 2020 18:46:22 +0000 Received: from [127.0.0.1] (localhost [127.0.0.1]) (Authenticated sender: koike) with ESMTPSA id 7E79C2912ED From: Helen Koike To: linux-rockchip@lists.infradead.org Subject: [PATCH v13 07/11] media: staging: rkisp1: add document for rkisp1 meta buffer format Date: Wed, 8 Jan 2020 15:44:50 -0300 Message-Id: <20200108184454.825725-8-helen.koike@collabora.com> X-Mailer: git-send-email 2.24.0 In-Reply-To: <20200108184454.825725-1-helen.koike@collabora.com> References: <20200108184454.825725-1-helen.koike@collabora.com> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20200108_104619_819690_70F67EB2 X-CRM114-Status: UNSURE ( 8.25 ) X-CRM114-Notice: Please train this message. X-Spam-Score: -0.0 (/) X-Spam-Report: SpamAssassin version 3.4.2 on bombadil.infradead.org summary: Content analysis details: (-0.0 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 SPF_PASS SPF: sender matches SPF record -0.0 SPF_HELO_PASS SPF: HELO matches SPF record 0.0 UNPARSEABLE_RELAY Informational: message has unparseable relay lines X-BeenThere: linux-rockchip@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Upstream kernel work for Rockchip platforms List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: mark.rutland@arm.com, devicetree@vger.kernel.org, eddie.cai.linux@gmail.com, kernel@collabora.com, heiko@sntech.de, linux-arm-kernel@lists.infradead.org, ezequiel@collabora.com, gregkh@linuxfoundation.org, linux-kernel@vger.kernel.org, tfiga@chromium.org, Helen Koike , robh+dt@kernel.org, hans.verkuil@cisco.com, laurent.pinchart@ideasonboard.com, sakari.ailus@linux.intel.com, Jacob Chen , joacim.zetterling@gmail.com, mchehab@kernel.org, andrey.konovalov@linaro.org, jacob-chen@iotwrt.com, linux-media@vger.kernel.org Sender: "Linux-rockchip" Errors-To: linux-rockchip-bounces+patchwork-linux-rockchip=patchwork.kernel.org@lists.infradead.org From: Jacob Chen This commit add document for rkisp1 meta buffer format Signed-off-by: Jacob Chen Signed-off-by: Helen Koike --- Changes in v13: None Changes in v12: - Change Jacob's email to original jacob2.chen@rock-chips.com Changes in v11: None Changes in v10: - unsquash Changes in v9: - squash - migrate to staging - remove meta-formats.rst update Changes in v8: - Add SPDX in the header - Remove emacs configs - Fix doc style Changes in v7: - s/correspond/corresponding - s/use/uses - s/docuemnt/document .../uapi/v4l/pixfmt-meta-rkisp1-params.rst | 23 +++++++++++++++++++ .../uapi/v4l/pixfmt-meta-rkisp1-stat.rst | 22 ++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 drivers/staging/media/rkisp1/Documentation/media/uapi/v4l/pixfmt-meta-rkisp1-params.rst create mode 100644 drivers/staging/media/rkisp1/Documentation/media/uapi/v4l/pixfmt-meta-rkisp1-stat.rst diff --git a/drivers/staging/media/rkisp1/Documentation/media/uapi/v4l/pixfmt-meta-rkisp1-params.rst b/drivers/staging/media/rkisp1/Documentation/media/uapi/v4l/pixfmt-meta-rkisp1-params.rst new file mode 100644 index 000000000000..32034e481357 --- /dev/null +++ b/drivers/staging/media/rkisp1/Documentation/media/uapi/v4l/pixfmt-meta-rkisp1-params.rst @@ -0,0 +1,23 @@ +.. SPDX-License-Identifier: (GPL-2.0+ OR MIT) + +.. _v4l2-meta-fmt-rkisp1-params: + +============================ +V4L2_META_FMT_RK_ISP1_PARAMS +============================ + +Rockchip ISP1 Parameters Data + +Description +=========== + +This format describes input parameters for the Rockchip ISP1. + +It uses c-struct :c:type:`rkisp1_params_cfg`, which is defined in +the ``linux/rkisp1-config.h`` header file. + +The parameters consist of multiple modules. +The module won't be updated if the corresponding bit was not set in module_*_update. + +.. kernel-doc:: include/uapi/linux/rkisp1-config.h + :functions: rkisp1_params_cfg diff --git a/drivers/staging/media/rkisp1/Documentation/media/uapi/v4l/pixfmt-meta-rkisp1-stat.rst b/drivers/staging/media/rkisp1/Documentation/media/uapi/v4l/pixfmt-meta-rkisp1-stat.rst new file mode 100644 index 000000000000..4ad303f96421 --- /dev/null +++ b/drivers/staging/media/rkisp1/Documentation/media/uapi/v4l/pixfmt-meta-rkisp1-stat.rst @@ -0,0 +1,22 @@ +.. SPDX-License-Identifier: (GPL-2.0+ OR MIT) + +.. _v4l2-meta-fmt-rkisp1-stat: + +============================= +V4L2_META_FMT_RK_ISP1_STAT_3A +============================= + + +Rockchip ISP1 Statistics Data + +Description +=========== + +This format describes image color statistics information generated by the Rockchip +ISP1. + +It uses c-struct :c:type:`rkisp1_stat_buffer`, which is defined in +the ``linux/rkisp1-config.h`` header file. + +.. kernel-doc:: include/uapi/linux/rkisp1-config.h + :functions: rkisp1_stat_buffer From patchwork Wed Jan 8 18:44:51 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Helen Koike X-Patchwork-Id: 11324345 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 6AA67139A for ; Wed, 8 Jan 2020 18:48:30 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 464042067D for ; Wed, 8 Jan 2020 18:48:30 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="AjrZtmJP" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 464042067D Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=collabora.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-rockchip-bounces+patchwork-linux-rockchip=patchwork.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=gllhqjeRvhyILnVphX5yrTUxmsvgXuLcq+oZsdjntk8=; b=AjrZtmJPZp82fT v0Y5clkhrIqhamHLnHGwh2ZgmStb3BqeSXLlWCWUXS6FWY94gXCcb86lq8gMeyzaoasUUoW8RLpy1 E7JAdzFOLcsXS+70GcnqsV13emrNcfpi8ZnMBnPOjauCVUgqfwtytxJeFCPZF01x8B/gmT6PHGRNN 26QbTvpeX9Vb8ovclRH+Gmn4l7kk5WLaV5nnTRYq1pijwlkzVQEtOM4Hqme3TlLRRlcWIEvajJ5Dw cMa7bKZ++rroeQCD8kWPhp/PFRCKHS90M1yHTfMUdU+DR6NvNx7xz88mthM2BppsajKv8nZLZ4eEz sLXHd2Jzq+Ames1XIRuA==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1ipGNW-00020Y-Ea; Wed, 08 Jan 2020 18:48:26 +0000 Received: from bhuna.collabora.co.uk ([2a00:1098:0:82:1000:25:2eeb:e3e3]) by bombadil.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1ipGLa-0000Nh-L1; Wed, 08 Jan 2020 18:46:29 +0000 Received: from [127.0.0.1] (localhost [127.0.0.1]) (Authenticated sender: koike) with ESMTPSA id 93FE82912EE From: Helen Koike To: linux-rockchip@lists.infradead.org Subject: [PATCH v13 08/11] media: staging: dt-bindings: add Rockchip ISP1 yaml bindings Date: Wed, 8 Jan 2020 15:44:51 -0300 Message-Id: <20200108184454.825725-9-helen.koike@collabora.com> X-Mailer: git-send-email 2.24.0 In-Reply-To: <20200108184454.825725-1-helen.koike@collabora.com> References: <20200108184454.825725-1-helen.koike@collabora.com> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20200108_104627_048231_E192ECBA X-CRM114-Status: GOOD ( 10.15 ) X-Spam-Score: -0.0 (/) X-Spam-Report: SpamAssassin version 3.4.2 on bombadil.infradead.org summary: Content analysis details: (-0.0 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 SPF_PASS SPF: sender matches SPF record -0.0 SPF_HELO_PASS SPF: HELO matches SPF record 0.0 UNPARSEABLE_RELAY Informational: message has unparseable relay lines X-BeenThere: linux-rockchip@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Upstream kernel work for Rockchip platforms List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: mark.rutland@arm.com, devicetree@vger.kernel.org, eddie.cai.linux@gmail.com, kernel@collabora.com, heiko@sntech.de, linux-arm-kernel@lists.infradead.org, Rob Herring , ezequiel@collabora.com, gregkh@linuxfoundation.org, linux-kernel@vger.kernel.org, tfiga@chromium.org, Helen Koike , robh+dt@kernel.org, hans.verkuil@cisco.com, laurent.pinchart@ideasonboard.com, sakari.ailus@linux.intel.com, joacim.zetterling@gmail.com, mchehab@kernel.org, andrey.konovalov@linaro.org, jacob-chen@iotwrt.com, linux-media@vger.kernel.org Sender: "Linux-rockchip" Errors-To: linux-rockchip-bounces+patchwork-linux-rockchip=patchwork.kernel.org@lists.infradead.org Add yaml DT bindings for Rockchip ISP1. This was tested and verified with: mv drivers/staging/media/rkisp1/Documentation/devicetree/bindings/media/rockchip-isp1.yaml Documentation/devicetree/bindings/media/ make dt_binding_check DT_SCHEMA_FILES=Documentation/devicetree/bindings/media/rockchip-isp1.yaml make dtbs_check DT_SCHEMA_FILES=Documentation/devicetree/bindings/media/rockchip-isp1.yaml Signed-off-by: Helen Koike Reviewed-by: Rob Herring Reviewed-by: Laurent Pinchart --- Changes in v13: - improve clock descriptions - fixed typo - add description to port@0 - remove unecessary description in reg Changes in v12: - The commit replaces the following commit in previous series named media: staging: dt-bindings: Document the Rockchip ISP1 bindings This new patch adds yaml binding and was verified with make dtbs_check and make dt_binding_check Changes in v11: - add clock-names values Changes in v10: - unsquash Changes in v9: - squash - move to staging Changes in v8: - fix title division style Changes in v7: - update document with new design and tested example .../bindings/media/rockchip-isp1.yaml | 192 ++++++++++++++++++ 1 file changed, 192 insertions(+) create mode 100644 drivers/staging/media/rkisp1/Documentation/devicetree/bindings/media/rockchip-isp1.yaml diff --git a/drivers/staging/media/rkisp1/Documentation/devicetree/bindings/media/rockchip-isp1.yaml b/drivers/staging/media/rkisp1/Documentation/devicetree/bindings/media/rockchip-isp1.yaml new file mode 100644 index 000000000000..af246b71eac6 --- /dev/null +++ b/drivers/staging/media/rkisp1/Documentation/devicetree/bindings/media/rockchip-isp1.yaml @@ -0,0 +1,192 @@ +# SPDX-License-Identifier: (GPL-2.0+ OR MIT) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/rockchip-isp1.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Rockchip SoC Image Signal Processing unit v1 + +maintainers: + - Helen Koike + +description: | + Rockchip ISP1 is the Camera interface for the Rockchip series of SoCs + which contains image processing, scaling, and compression functions. + +properties: + compatible: + const: rockchip,rk3399-cif-isp + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + iommus: + maxItems: 1 + + power-domains: + maxItems: 1 + + phys: + maxItems: 1 + description: phandle for the PHY port + + phy-names: + const: dphy + + clocks: + items: + - description: ISP clock + - description: ISP AXI clock clock + - description: ISP AXI clock wrapper clock + - description: ISP AHB clock clock + - description: ISP AHB wrapper clock + + clock-names: + items: + - const: clk_isp + - const: aclk_isp + - const: aclk_isp_wrap + - const: hclk_isp + - const: hclk_isp_wrap + + # See ./video-interfaces.txt for details + ports: + type: object + additionalProperties: false + + properties: + "#address-cells": + const: 1 + + "#size-cells": + const: 0 + + port@0: + type: object + description: connection point for sensors at MIPI-DPHY RX0 + additionalProperties: false + + properties: + "#address-cells": + const: 1 + + "#size-cells": + const: 0 + + reg: + const: 0 + + patternProperties: + endpoint: + type: object + additionalProperties: false + + properties: + reg: + maxItems: 1 + + data-lanes: + minItems: 1 + maxItems: 4 + + remote-endpoint: true + + required: + - port@0 + +required: + - compatible + - interrupts + - clocks + - clock-names + - power-domains + - iommus + - phys + - phy-names + - ports + +additionalProperties: false + +examples: + - | + + #include + #include + #include + + parent0: parent@0 { + #address-cells = <2>; + #size-cells = <2>; + + isp0: isp0@ff910000 { + compatible = "rockchip,rk3399-cif-isp"; + reg = <0x0 0xff910000 0x0 0x4000>; + interrupts = ; + clocks = <&cru SCLK_ISP0>, + <&cru ACLK_ISP0>, <&cru ACLK_ISP0_WRAPPER>, + <&cru HCLK_ISP0>, <&cru HCLK_ISP0_WRAPPER>; + clock-names = "clk_isp", + "aclk_isp", "aclk_isp_wrap", + "hclk_isp", "hclk_isp_wrap"; + power-domains = <&power RK3399_PD_ISP0>; + iommus = <&isp0_mmu>; + phys = <&dphy>; + phy-names = "dphy"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + + mipi_in_wcam: endpoint@0 { + reg = <0>; + remote-endpoint = <&wcam_out>; + data-lanes = <1 2>; + }; + + mipi_in_ucam: endpoint@1 { + reg = <1>; + remote-endpoint = <&ucam_out>; + data-lanes = <1>; + }; + }; + }; + }; + + i2c7: i2c@ff160000 { + clock-frequency = <400000>; + #address-cells = <1>; + #size-cells = <0>; + + wcam: camera@36 { + compatible = "ovti,ov5695"; + reg = <0x36>; + + port { + wcam_out: endpoint { + remote-endpoint = <&mipi_in_wcam>; + data-lanes = <1 2>; + }; + }; + }; + + ucam: camera@3c { + compatible = "ovti,ov2685"; + reg = <0x3c>; + + port { + ucam_out: endpoint { + remote-endpoint = <&mipi_in_ucam>; + data-lanes = <1>; + }; + }; + }; + }; + }; From patchwork Wed Jan 8 18:44:52 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Helen Koike X-Patchwork-Id: 11324349 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id EC9B8921 for ; Wed, 8 Jan 2020 18:48:45 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id C57F42067D for ; Wed, 8 Jan 2020 18:48:45 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="KIPjQ/ZV" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org C57F42067D Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=collabora.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-rockchip-bounces+patchwork-linux-rockchip=patchwork.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=otDviY/mKpEQodSiR1T+XknY75UcrE9rpl9N3omeUPA=; b=KIPjQ/ZV3gjslw yYJmalIuvMq+p3SfxaDHd0LheoA+HWi1QjJpExVWP1Uy+/hDvDdOEClwZmMoE40IUsfaDPQfJBbIn 0L48hZnsEgkk3FLlqcu/JotQgLhVM4o0gLRyuU61vBQqmAIIOFKLSXog64vQzRsBTBmYR/lna6nkf fXXWKiCKffZW3REMB5wwAmnwrKm7N2ugCcMGcALUG/BmOXSwKxpTUsrOh6201zSZ6jhGlZq21BVc4 nAndia+7zxeTicD+8dkvuSCyJS5MQS7mY4+eQylDVGuZVUFn5xe5g8RdUge5TwXuUmPp6JoeHTQrw igXZflfa7mxZahfwt67w==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1ipGNk-0002EX-Gv; Wed, 08 Jan 2020 18:48:40 +0000 Received: from bhuna.collabora.co.uk ([2a00:1098:0:82:1000:25:2eeb:e3e3]) by bombadil.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1ipGLg-0000Tj-7Z; Wed, 08 Jan 2020 18:46:39 +0000 Received: from [127.0.0.1] (localhost [127.0.0.1]) (Authenticated sender: koike) with ESMTPSA id 0022F2912EF From: Helen Koike To: linux-rockchip@lists.infradead.org Subject: [PATCH v13 09/11] media: staging: dt-bindings: add Rockchip MIPI RX D-PHY RX0 yaml bindings Date: Wed, 8 Jan 2020 15:44:52 -0300 Message-Id: <20200108184454.825725-10-helen.koike@collabora.com> X-Mailer: git-send-email 2.24.0 In-Reply-To: <20200108184454.825725-1-helen.koike@collabora.com> References: <20200108184454.825725-1-helen.koike@collabora.com> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20200108_104632_564956_35BCA5D6 X-CRM114-Status: GOOD ( 10.01 ) X-Spam-Score: -0.0 (/) X-Spam-Report: SpamAssassin version 3.4.2 on bombadil.infradead.org summary: Content analysis details: (-0.0 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 SPF_PASS SPF: sender matches SPF record -0.0 SPF_HELO_PASS SPF: HELO matches SPF record 0.0 UNPARSEABLE_RELAY Informational: message has unparseable relay lines X-BeenThere: linux-rockchip@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Upstream kernel work for Rockchip platforms List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: mark.rutland@arm.com, devicetree@vger.kernel.org, eddie.cai.linux@gmail.com, kernel@collabora.com, heiko@sntech.de, linux-arm-kernel@lists.infradead.org, Rob Herring , ezequiel@collabora.com, gregkh@linuxfoundation.org, linux-kernel@vger.kernel.org, tfiga@chromium.org, Helen Koike , robh+dt@kernel.org, hans.verkuil@cisco.com, laurent.pinchart@ideasonboard.com, sakari.ailus@linux.intel.com, joacim.zetterling@gmail.com, mchehab@kernel.org, andrey.konovalov@linaro.org, jacob-chen@iotwrt.com, linux-media@vger.kernel.org Sender: "Linux-rockchip" Errors-To: linux-rockchip-bounces+patchwork-linux-rockchip=patchwork.kernel.org@lists.infradead.org Add yaml DT bindings for Rockchip MIPI D-PHY RX This was tested and verified with: mv drivers/staging/media/phy-rockchip-dphy-rx0/Documentation/devicetree/bindings/phy/rockchip-mipi-dphy-rx0.yaml Documentation/devicetree/bindings/phy/ make dt_binding_check DT_SCHEMA_FILES=Documentation/devicetree/bindings/phy/rockchip-mipi-dphy-rx0.yaml make dtbs_check DT_SCHEMA_FILES=Documentation/devicetree/bindings/phy/rockchip-mipi-dphy-rx0.yaml Signed-off-by: Helen Koike Reviewed-by: Rob Herring --- Changes in v13: - renamed with rx0 suffix - improved clock description Changes in v12: - The commit replaces the following commit in previous series named media: staging: dt-bindings: Document the Rockchip MIPI RX D-PHY bindings This new patch adds yaml binding and was verified with make dtbs_check and make dt_binding_check Changes in v11: None Changes in v10: - unsquash Changes in v9: - fix title division style - squash - move to staging Changes in v8: None Changes in v7: - updated doc with new design and tested example .../bindings/phy/rockchip-mipi-dphy-rx0.yaml | 76 +++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 drivers/staging/media/phy-rockchip-dphy-rx0/Documentation/devicetree/bindings/phy/rockchip-mipi-dphy-rx0.yaml diff --git a/drivers/staging/media/phy-rockchip-dphy-rx0/Documentation/devicetree/bindings/phy/rockchip-mipi-dphy-rx0.yaml b/drivers/staging/media/phy-rockchip-dphy-rx0/Documentation/devicetree/bindings/phy/rockchip-mipi-dphy-rx0.yaml new file mode 100644 index 000000000000..5dacece35702 --- /dev/null +++ b/drivers/staging/media/phy-rockchip-dphy-rx0/Documentation/devicetree/bindings/phy/rockchip-mipi-dphy-rx0.yaml @@ -0,0 +1,76 @@ +# SPDX-License-Identifier: (GPL-2.0+ OR MIT) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/phy/rockchip-mipi-dphy-rx0.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Rockchip SoC MIPI RX0 D-PHY Device Tree Bindings + +maintainers: + - Helen Koike + - Ezequiel Garcia + +description: | + The Rockchip SoC has a MIPI D-PHY bus with an RX0 entry which connects to + the ISP1 (Image Signal Processing unit v1.0) for CSI cameras. + +properties: + compatible: + const: rockchip,rk3399-mipi-dphy-rx0 + + reg: + maxItems: 1 + + clocks: + items: + - description: MIPI D-PHY ref clock + - description: MIPI D-PHY RX0 cfg clock + - description: Video in/out general register file clock + + clock-names: + items: + - const: dphy-ref + - const: dphy-cfg + - const: grf + + '#phy-cells': + const: 0 + + power-domains: + description: Video in/out power domain. + maxItems: 1 + +required: + - compatible + - clocks + - clock-names + - '#phy-cells' + - power-domains + +additionalProperties: false + +examples: + - | + + /* + * MIPI D-PHY RX0 use registers in "general register files", it + * should be a child of the GRF. + * + * grf: syscon@ff770000 { + * compatible = "rockchip,rk3399-grf", "syscon", "simple-mfd"; + * ... + * }; + */ + + #include + #include + + mipi_dphy_rx0: mipi-dphy-rx0 { + compatible = "rockchip,rk3399-mipi-dphy-rx0"; + clocks = <&cru SCLK_MIPIDPHY_REF>, + <&cru SCLK_DPHY_RX0_CFG>, + <&cru PCLK_VIO_GRF>; + clock-names = "dphy-ref", "dphy-cfg", "grf"; + power-domains = <&power RK3399_PD_VIO>; + #phy-cells = <0>; + }; From patchwork Wed Jan 8 18:44:53 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Helen Koike X-Patchwork-Id: 11324353 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 2D0ED139A for ; Wed, 8 Jan 2020 18:49:02 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id F394C2067D for ; Wed, 8 Jan 2020 18:49:01 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="PLL76jEs" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org F394C2067D Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=collabora.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-rockchip-bounces+patchwork-linux-rockchip=patchwork.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=K0jYaYgKT9/IlxokgyIAWgd2kMMzb5sq40oHbj8cwJg=; b=PLL76jEs6jA0sw Mj6DKlP+APvk/t2ij7JEsgbYSuJA9SoW33epvt25IcyCkGaCpBMOYmAF8jyC+ijDH7yr9kUud1VYZ bHj2t/dNRfkXv5dqTsdLnNNpVE/TJDuM4sKctT9RkUza8mhPigSq5MQ0umENxdW9AUor5ir6XPWDJ 0wYTlPOb81RFSr9SH7qYmsB274YDxnNRBvgDQ8hqXlxaRGQaRRXTGJb00ZgyXyvZ97mT/IUZ1L7MF aSyI6oT+2ET434jT4u8xUeI8GF/F2UAut8AfsI3d77eBzN45P+t8nKIdy8wJ8N6yYZn32K0bmwdNQ t3g0ORiJlqS62RTUf+OQ==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1ipGO1-0002WS-B0; Wed, 08 Jan 2020 18:48:57 +0000 Received: from bhuna.collabora.co.uk ([46.235.227.227]) by bombadil.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1ipGLp-0000aG-EG; Wed, 08 Jan 2020 18:46:43 +0000 Received: from [127.0.0.1] (localhost [127.0.0.1]) (Authenticated sender: koike) with ESMTPSA id 94C8A2912F1 From: Helen Koike To: linux-rockchip@lists.infradead.org Subject: [PATCH v13 10/11] media: staging: rkisp1: add TODO file for staging Date: Wed, 8 Jan 2020 15:44:53 -0300 Message-Id: <20200108184454.825725-11-helen.koike@collabora.com> X-Mailer: git-send-email 2.24.0 In-Reply-To: <20200108184454.825725-1-helen.koike@collabora.com> References: <20200108184454.825725-1-helen.koike@collabora.com> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20200108_104641_636677_34CAD8FE X-CRM114-Status: UNSURE ( 8.45 ) X-CRM114-Notice: Please train this message. X-Spam-Score: -0.0 (/) X-Spam-Report: SpamAssassin version 3.4.2 on bombadil.infradead.org summary: Content analysis details: (-0.0 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at https://www.dnswl.org/, no trust [46.235.227.227 listed in list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record -0.0 SPF_HELO_PASS SPF: HELO matches SPF record 0.0 UNPARSEABLE_RELAY Informational: message has unparseable relay lines X-BeenThere: linux-rockchip@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Upstream kernel work for Rockchip platforms List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: mark.rutland@arm.com, devicetree@vger.kernel.org, eddie.cai.linux@gmail.com, kernel@collabora.com, heiko@sntech.de, linux-arm-kernel@lists.infradead.org, ezequiel@collabora.com, gregkh@linuxfoundation.org, linux-kernel@vger.kernel.org, tfiga@chromium.org, Helen Koike , robh+dt@kernel.org, hans.verkuil@cisco.com, laurent.pinchart@ideasonboard.com, sakari.ailus@linux.intel.com, joacim.zetterling@gmail.com, mchehab@kernel.org, andrey.konovalov@linaro.org, jacob-chen@iotwrt.com, linux-media@vger.kernel.org Sender: "Linux-rockchip" Errors-To: linux-rockchip-bounces+patchwork-linux-rockchip=patchwork.kernel.org@lists.infradead.org Add TODO file with requirements to move this driver out of staging. Signed-off-by: Helen Koike --- Changes in v13: None Changes in v12: None Changes in v11: None Changes in v10: None Changes in v9: None Changes in v8: None Changes in v7: None drivers/staging/media/rkisp1/TODO | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 drivers/staging/media/rkisp1/TODO diff --git a/drivers/staging/media/rkisp1/TODO b/drivers/staging/media/rkisp1/TODO new file mode 100644 index 000000000000..03cd9a4e70f7 --- /dev/null +++ b/drivers/staging/media/rkisp1/TODO @@ -0,0 +1,23 @@ +* Fix serialization on subdev ops. +* Don't use v4l2_async_notifier_parse_fwnode_endpoints_by_port(). +e.g. isp_parse_of_endpoints in drivers/media/platform/omap3isp/isp.c +cio2_parse_firmware in drivers/media/pci/intel/ipu3/ipu3-cio2.c. +* Fix pad format size for statistics and parameters entities. +* Use threaded interrupt for rkisp1_stats_isr(), remove work queue. +* Fix checkpatch errors. +* Make sure uapi structs have the same size and layout in 32 and 62 bits, +and that there are no holes in the structures (pahole is a utility that +can be used to test this). +* Review and comment every lock +* Handle quantization +* Document rkisp1-common.h +* streaming paths (mainpath and selfpath) check if the other path is streaming +in several places of the code, review this, specially that it doesn't seem it +supports streaming from both paths at the same time. + +NOTES: +* All v4l2-compliance test must pass. +* Stats and params can be tested with libcamera and ChromiumOS stack. + +Please CC patches to Linux Media and +Helen Koike . From patchwork Wed Jan 8 18:44:54 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Helen Koike X-Patchwork-Id: 11324357 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 4C3C6139A for ; Wed, 8 Jan 2020 18:49:19 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 2A4952067D for ; Wed, 8 Jan 2020 18:49:19 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="Mpz53Ed9" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 2A4952067D Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=collabora.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-rockchip-bounces+patchwork-linux-rockchip=patchwork.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=lm5T4PAPwNxxBUwSvKi2+fc/7l/cIG4jWNC0Wszav9E=; b=Mpz53Ed9dQgx8z zv5FBKjo/s31KhsgEqZo4aZx9UVeAefBfE5LT0oOHD2ANHmjsxglinCJv7Bfk2Mm4YgoCOrPk/hNq 3lTNd0OgoMKCcc0+0e2DJli6w+/TG+MetwJ3S8Na6e3QUzsLMmOHLluquTEm3nItnFGoo8+2eV4RD Eg39ZKAVskibNJw4FGMnkPSUdr1uwvhllJG7q2VtTzccvA3VoncYjjLlEgNn577j6bB/kBIUxHXuL rfc5X/8+nsXN2gk+CVTxmiQTAjshZYrRm+PV0cpHFBBajGM3KkCnHKQRWRXuS9PdlajKmg7f0ygOh plnfAAFB/VQLuz+tTl/w==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1ipGOJ-0002r3-5t; Wed, 08 Jan 2020 18:49:15 +0000 Received: from bhuna.collabora.co.uk ([46.235.227.227]) by bombadil.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1ipGLu-0000fM-RV; Wed, 08 Jan 2020 18:46:54 +0000 Received: from [127.0.0.1] (localhost [127.0.0.1]) (Authenticated sender: koike) with ESMTPSA id A5F8829131A From: Helen Koike To: linux-rockchip@lists.infradead.org Subject: [PATCH v13 11/11] MAINTAINERS: add entry for Rockchip ISP1 driver Date: Wed, 8 Jan 2020 15:44:54 -0300 Message-Id: <20200108184454.825725-12-helen.koike@collabora.com> X-Mailer: git-send-email 2.24.0 In-Reply-To: <20200108184454.825725-1-helen.koike@collabora.com> References: <20200108184454.825725-1-helen.koike@collabora.com> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20200108_104647_078378_7581060E X-CRM114-Status: UNSURE ( 5.80 ) X-CRM114-Notice: Please train this message. X-Spam-Score: -0.0 (/) X-Spam-Report: SpamAssassin version 3.4.2 on bombadil.infradead.org summary: Content analysis details: (-0.0 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at https://www.dnswl.org/, no trust [46.235.227.227 listed in list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record -0.0 SPF_HELO_PASS SPF: HELO matches SPF record 0.0 UNPARSEABLE_RELAY Informational: message has unparseable relay lines X-BeenThere: linux-rockchip@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Upstream kernel work for Rockchip platforms List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: mark.rutland@arm.com, devicetree@vger.kernel.org, eddie.cai.linux@gmail.com, kernel@collabora.com, heiko@sntech.de, linux-arm-kernel@lists.infradead.org, ezequiel@collabora.com, gregkh@linuxfoundation.org, linux-kernel@vger.kernel.org, tfiga@chromium.org, Helen Koike , robh+dt@kernel.org, hans.verkuil@cisco.com, laurent.pinchart@ideasonboard.com, sakari.ailus@linux.intel.com, joacim.zetterling@gmail.com, mchehab@kernel.org, andrey.konovalov@linaro.org, jacob-chen@iotwrt.com, linux-media@vger.kernel.org Sender: "Linux-rockchip" Errors-To: linux-rockchip-bounces+patchwork-linux-rockchip=patchwork.kernel.org@lists.infradead.org Add MAINTAINERS entry for the rockchip isp1 driver. Signed-off-by: Helen Koike --- Changes in v13: None Changes in v12: None Changes in v11: None Changes in v10: None Changes in v9: - Move to staging Changes in v8: None Changes in v7: None MAINTAINERS | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 87f3d89d44a2..5ed1287cbb1c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -14117,6 +14117,12 @@ F: drivers/hid/hid-roccat* F: include/linux/hid-roccat* F: Documentation/ABI/*/sysfs-driver-hid-roccat* +ROCKCHIP ISP V1 DRIVER +M: Helen Koike +L: linux-media@vger.kernel.org +S: Maintained +F: drivers/staging/media/rkisp1/ + ROCKCHIP RASTER 2D GRAPHIC ACCELERATION UNIT DRIVER M: Jacob Chen M: Ezequiel Garcia