linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v12 00/11] Rockchip ISP Driver
@ 2019-12-27 20:01 Helen Koike
  2019-12-27 20:01 ` [PATCH v12 01/11] media: staging: phy-rockchip-dphy: add Rockchip MIPI Synopsys DPHY driver Helen Koike
                   ` (10 more replies)
  0 siblings, 11 replies; 35+ messages in thread
From: Helen Koike @ 2019-12-27 20:01 UTC (permalink / raw)
  To: linux-rockchip
  Cc: mark.rutland, devicetree, eddie.cai.linux, kernel, heiko,
	linux-arm-kernel, ezequiel, gregkh, linux-kernel, tfiga,
	Helen Koike, robh+dt, hans.verkuil, laurent.pinchart,
	sakari.ailus, joacim.zetterling, mchehab, andrey.konovalov,
	jacob-chen, linux-media

Hi,

This patchset adds support for the Image signal processor unit version 1.0 of
the Rockchip RK3399 SoC in the staging tree.
There are still some missing things to move it from staging (please, see
TODO file), but the driver is already being used by several people
(libcamera, for instance, already supports an older version of the driver)
and adding in staging make the work flow easier for collaboration within
the community.
I plan to be actively working on the driver to move it out of staging asap.

It is also available at
https://gitlab.collabora.com/koike/linux/tree/rockchip/isp/v12

NOTE: This series only touches MAINTAINERS file and drivers/staging/

Major changes in V12
--------------------
* Cleanups
For this version of the patchset, several cleanups were made, including renaming
functions, variables, structs, enum and files to have the "rkisp1" prefix.
Some print and comments were re-written, and several of them that were unecessary
were removed.
regs.c and all the headers besides rkisp1-common.h were removed.
Several unecessary functions were removed, parts of the code were re-written to
be readable, reduce indentation, and remove redundant code.
More helper functions from the media core is being used.
Header files were removed, except for rkisp1-common.h and rkisp1-regs.h,
there are not that much shared code, keep then in a single place instead
of spreading it through several header files, it is easier to navigate.
More cleanups are still possible, but at least now we have a more organized and
standardized code, which makes it easier to read and to maintain.

* An entry in Debugfs was added to keep track of errors and data loss.

* A new subdevice entity for the resizer was added.
Previously, resizer was being implemented in the capture devices, but since
capture devices don't have pad operations, the code was accepting unmatching
links between ISP and the capture.
Separating the resizer to it's own entity removed several hacks from the
capture, besides simplifying the code, making it easier to read.
Cropping was also moved out from the capture to the resizer subdevices.
This also changes userspace API (as the topology changed), but now resizing is
more explicitly represented instead of hided in the capture.

* Format propagation between pads was fixed.

* Ascii art block diagram to remove the http link reference.

* More items in the TODO file, including reviewing the locks.

* Fix Jacob Chen's email address, keep the original jacob2.chen@rock-chips.com
email.

* yaml Device Tree bindings: the txt bindings docs got replaced, so it
can be verified with make dt_bindings_check and make dtbs_check

NOTE: the changes were focused on the main loop sensor->isp->capture, I almost
didn't touch params and stats, mostly because I didn't setup a testing framework
yet for those, so they have lots of space for improvements.

Commands output:
----------------
media-ctl -p : http://ix.io/25DG
media-ctl --print-dot: http://col.la/rkisp1v12dot
v4l2-compliance -m0: http://ix.io/25DI
NOTE: there is a failure in v4l2-compliance, but comes from the sensor, not from the ISP.

Testing:
--------
SEN_DEV=/dev/v4l-subdev3
ISP_DEV=/dev/v4l-subdev0
RSZ_SP_DEV=/dev/v4l-subdev2
RSZ_MP_DEV=/dev/v4l-subdev1
CAP_SP_DEV=/dev/video1
CAP_MP_DEV=/dev/video0

WIDTH=1280
HEIGHT=960

v4l2-ctl --set-subdev-fmt pad=0,width=$WIDTH,height=$HEIGHT,code=0x3001 -d $SEN_DEV

v4l2-ctl --set-subdev-fmt pad=0,width=$WIDTH,height=$HEIGHT,code=0x3001 -d $ISP_DEV
v4l2-ctl --set-subdev-selection pad=0,target=crop,top=0,left=0,width=$WIDTH,height=$HEIGHT -d $ISP_DEV

v4l2-ctl --set-subdev-selection pad=2,target=crop,top=0,left=0,width=$WIDTH,height=$HEIGHT -d $ISP_DEV
v4l2-ctl --set-subdev-fmt pad=2,width=$WIDTH,height=$HEIGHT,code=0x2008 -d $ISP_DEV

v4l2-ctl --set-subdev-fmt pad=0,width=$WIDTH,height=$HEIGHT,code=0x2008 -d $RSZ_SP_DEV
v4l2-ctl --set-subdev-fmt pad=1,width=$WIDTH,height=$HEIGHT,code=0x2008 -d $RSZ_SP_DEV

v4l2-ctl --set-subdev-selection pad=0,target=crop,top=0,left=0,width=$WIDTH,height=$HEIGHT -d $RSZ_SP_DEV

v4l2-ctl --set-subdev-fmt pad=0,width=$WIDTH,height=$HEIGHT,code=0x2008 -d $RSZ_MP_DEV
v4l2-ctl --set-subdev-fmt pad=1,width=$WIDTH,height=$HEIGHT,code=0x2008 -d $RSZ_MP_DEV

v4l2-ctl --set-subdev-selection pad=0,target=crop,top=0,left=0,width=$WIDTH,height=$HEIGHT -d $RSZ_MP_DEV

v4l2-ctl -v width=$WIDTH,height=$HEIGHT,pixelformat=NV12 -d $CAP_SP_DEV
v4l2-ctl -v width=$WIDTH,height=$HEIGHT,pixelformat=NV12 -d $CAP_MP_DEV

v4l2-ctl --stream-mmap --stream-count=100 -d $CAP_SP_DEV --stream-to=/tmp/test_sp.raw
v4l2-ctl --stream-mmap --stream-count=100 -d $CAP_MP_DEV --stream-to=/tmp/test_mp.raw

ffplay -loglevel warning -v info -f rawvideo -pixel_format nv12 -video_size "1280x960" tmp/test_sp.raw
ffplay -loglevel warning -v info -f rawvideo -pixel_format nv12 -video_size "1280x960" tmp/test_mp.raw

Thanks
Helen

Ezequiel Garcia (1):
  media: staging: phy-rockchip-dphy: add Rockchip MIPI Synopsys DPHY
    driver

Helen Koike (6):
  media: staging: rkisp1: add Rockchip ISP1 base driver
  media: staging: rkisp1: add streaming paths
  media: staging: dt-bindings: add Rockchip ISP1 yaml bindings
  media: staging: dt-bindings: add Rockchip MIPI RX D-PHY yaml bindings
  media: staging: rkisp1: add TODO file for staging
  MAINTAINERS: add entry for Rockchip ISP1 driver

Jacob Chen (3):
  media: staging: rkisp1: add capture device for statistics
  media: staging: rkisp1: add output device for parameters
  media: staging: rkisp1: add document for rkisp1 meta buffer format

Jeffy Chen (1):
  media: staging: rkisp1: add user space ABI definitions

 MAINTAINERS                                   |    6 +
 drivers/staging/media/Kconfig                 |    4 +
 drivers/staging/media/Makefile                |    2 +
 .../bindings/phy/rockchip-mipi-dphy.yaml      |   75 +
 .../staging/media/phy-rockchip-dphy/Kconfig   |   11 +
 .../staging/media/phy-rockchip-dphy/Makefile  |    2 +
 drivers/staging/media/phy-rockchip-dphy/TODO  |    6 +
 .../phy-rockchip-dphy/phy-rockchip-dphy.c     |  396 ++++
 .../bindings/media/rockchip-isp1.yaml         |  193 ++
 .../uapi/v4l/pixfmt-meta-rkisp1-params.rst    |   23 +
 .../uapi/v4l/pixfmt-meta-rkisp1-stat.rst      |   22 +
 drivers/staging/media/rkisp1/Kconfig          |   13 +
 drivers/staging/media/rkisp1/Makefile         |    8 +
 drivers/staging/media/rkisp1/TODO             |   23 +
 drivers/staging/media/rkisp1/rkisp1-capture.c | 1437 +++++++++++++++
 drivers/staging/media/rkisp1/rkisp1-common.c  |   37 +
 drivers/staging/media/rkisp1/rkisp1-common.h  |  337 ++++
 drivers/staging/media/rkisp1/rkisp1-dev.c     |  574 ++++++
 drivers/staging/media/rkisp1/rkisp1-isp.c     | 1164 ++++++++++++
 drivers/staging/media/rkisp1/rkisp1-params.c  | 1630 +++++++++++++++++
 drivers/staging/media/rkisp1/rkisp1-regs.h    | 1264 +++++++++++++
 drivers/staging/media/rkisp1/rkisp1-resizer.c |  775 ++++++++
 drivers/staging/media/rkisp1/rkisp1-stats.c   |  530 ++++++
 .../staging/media/rkisp1/uapi/rkisp1-config.h |  819 +++++++++
 24 files changed, 9351 insertions(+)
 create mode 100644 drivers/staging/media/phy-rockchip-dphy/Documentation/devicetree/bindings/phy/rockchip-mipi-dphy.yaml
 create mode 100644 drivers/staging/media/phy-rockchip-dphy/Kconfig
 create mode 100644 drivers/staging/media/phy-rockchip-dphy/Makefile
 create mode 100644 drivers/staging/media/phy-rockchip-dphy/TODO
 create mode 100644 drivers/staging/media/phy-rockchip-dphy/phy-rockchip-dphy.c
 create mode 100644 drivers/staging/media/rkisp1/Documentation/devicetree/bindings/media/rockchip-isp1.yaml
 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
 create mode 100644 drivers/staging/media/rkisp1/Kconfig
 create mode 100644 drivers/staging/media/rkisp1/Makefile
 create mode 100644 drivers/staging/media/rkisp1/TODO
 create mode 100644 drivers/staging/media/rkisp1/rkisp1-capture.c
 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-params.c
 create mode 100644 drivers/staging/media/rkisp1/rkisp1-regs.h
 create mode 100644 drivers/staging/media/rkisp1/rkisp1-resizer.c
 create mode 100644 drivers/staging/media/rkisp1/rkisp1-stats.c
 create mode 100644 drivers/staging/media/rkisp1/uapi/rkisp1-config.h

-- 
2.24.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 35+ messages in thread

* [PATCH v12 01/11] media: staging: phy-rockchip-dphy: add Rockchip MIPI Synopsys DPHY driver
  2019-12-27 20:01 [PATCH v12 00/11] Rockchip ISP Driver Helen Koike
@ 2019-12-27 20:01 ` Helen Koike
  2019-12-30 18:25   ` Ezequiel Garcia
  2020-01-07  1:11   ` Laurent Pinchart
  2019-12-27 20:01 ` [PATCH v12 03/11] media: staging: rkisp1: add streaming paths Helen Koike
                   ` (9 subsequent siblings)
  10 siblings, 2 replies; 35+ messages in thread
From: Helen Koike @ 2019-12-27 20:01 UTC (permalink / raw)
  To: linux-rockchip
  Cc: mark.rutland, devicetree, eddie.cai.linux, kernel, heiko,
	linux-arm-kernel, ezequiel, gregkh, linux-kernel, tfiga,
	Helen Koike, robh+dt, hans.verkuil, laurent.pinchart,
	sakari.ailus, joacim.zetterling, mchehab, andrey.konovalov,
	jacob-chen, linux-media

From: Ezequiel Garcia <ezequiel@collabora.com>

Add driver for Rockchip MIPI Synopsys DPHY driver

Signed-off-by: Tomasz Figa <tfiga@chromium.org>
Signed-off-by: Ezequiel Garcia <ezequiel@collabora.com>
Signed-off-by: Helen Koike <helen.koike@collabora.com>

---

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 +
 .../staging/media/phy-rockchip-dphy/Kconfig   |  11 +
 .../staging/media/phy-rockchip-dphy/Makefile  |   2 +
 drivers/staging/media/phy-rockchip-dphy/TODO  |   6 +
 .../phy-rockchip-dphy/phy-rockchip-dphy.c     | 396 ++++++++++++++++++
 6 files changed, 418 insertions(+)
 create mode 100644 drivers/staging/media/phy-rockchip-dphy/Kconfig
 create mode 100644 drivers/staging/media/phy-rockchip-dphy/Makefile
 create mode 100644 drivers/staging/media/phy-rockchip-dphy/TODO
 create mode 100644 drivers/staging/media/phy-rockchip-dphy/phy-rockchip-dphy.c

diff --git a/drivers/staging/media/Kconfig b/drivers/staging/media/Kconfig
index 642adc4c24d2..a47484473883 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/Kconfig"
+
 endif
diff --git a/drivers/staging/media/Makefile b/drivers/staging/media/Makefile
index 2f1711a8aeed..b0eae3906208 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)		+= phy-rockchip-dphy/
diff --git a/drivers/staging/media/phy-rockchip-dphy/Kconfig b/drivers/staging/media/phy-rockchip-dphy/Kconfig
new file mode 100644
index 000000000000..7378bd75fa7c
--- /dev/null
+++ b/drivers/staging/media/phy-rockchip-dphy/Kconfig
@@ -0,0 +1,11 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Phy drivers for Rockchip platforms
+#
+config PHY_ROCKCHIP_DPHY
+	tristate "Rockchip MIPI Synopsys DPHY 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.
diff --git a/drivers/staging/media/phy-rockchip-dphy/Makefile b/drivers/staging/media/phy-rockchip-dphy/Makefile
new file mode 100644
index 000000000000..24679dc950cd
--- /dev/null
+++ b/drivers/staging/media/phy-rockchip-dphy/Makefile
@@ -0,0 +1,2 @@
+# SPDX-License-Identifier: GPL-2.0
+obj-$(CONFIG_PHY_ROCKCHIP_DPHY)		+= phy-rockchip-dphy.o
diff --git a/drivers/staging/media/phy-rockchip-dphy/TODO b/drivers/staging/media/phy-rockchip-dphy/TODO
new file mode 100644
index 000000000000..e1fda55babef
--- /dev/null
+++ b/drivers/staging/media/phy-rockchip-dphy/TODO
@@ -0,0 +1,6 @@
+The major reason for keeping this in staging is because the only driver
+who uses this is rkisp1 who is also in staging. It should be moved together
+rkisp1.
+
+Please CC patches to Linux Media <linux-media@vger.kernel.org> and
+Helen Koike <helen.koike@collabora.com>.
diff --git a/drivers/staging/media/phy-rockchip-dphy/phy-rockchip-dphy.c b/drivers/staging/media/phy-rockchip-dphy/phy-rockchip-dphy.c
new file mode 100644
index 000000000000..c3fe9c64b45f
--- /dev/null
+++ b/drivers/staging/media/phy-rockchip-dphy/phy-rockchip-dphy.c
@@ -0,0 +1,396 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Rockchip MIPI Synopsys DPHY 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 <jacob2.chen@rock-chips.com>
+ *   Shunqian Zheng <zhengsq@rock-chips.com>
+ */
+
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/phy/phy.h>
+#include <linux/phy/phy-mipi-dphy.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#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));
+
+	WARN_ON(!reg->offset);
+	regmap_write(priv->grf, reg->offset, val);
+}
+
+static void rk_dphy_write(struct rk_dphy *priv,
+			  u8 test_code, u8 test_data)
+{
+	/*
+	 * 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.
+	 */
+	rk_dphy_write_grf(priv, GRF_DPHY_RX0_TESTCLK, 1);
+	rk_dphy_write_grf(priv, GRF_DPHY_RX0_TESTDIN, test_code);
+	rk_dphy_write_grf(priv, GRF_DPHY_RX0_TESTEN, 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 i, hsfreq = 0, data_rate_mbps = config->hs_clk_rate;
+	int ret;
+
+	/* pass with phy_mipi_dphy_get_default_config (with pixel rate?) */
+	ret = phy_mipi_dphy_config_validate(config);
+	if (ret)
+		return ret;
+	do_div(data_rate_mbps, 1000 * 1000);
+
+	dev_dbg(priv->dev, "lanes %d - data_rate_mbps %u\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",
+		.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 regmap *grf;
+	struct phy *phy;
+	unsigned int i;
+	int ret;
+
+	if (!dev->parent || !dev->parent->of_node)
+		return -ENODEV;
+
+	if (platform_get_resource(pdev, IORESOURCE_MEM, 0)) {
+		dev_err(dev, "Rockchip DPHY driver only suports RX mode\n");
+		return -EINVAL;
+	}
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+	priv->dev = dev;
+
+	grf = syscon_node_to_regmap(dev->parent->of_node);
+	if (IS_ERR(grf)) {
+		grf = syscon_regmap_lookup_by_phandle(dev->of_node,
+						      "rockchip,grf");
+		if (IS_ERR(grf)) {
+			dev_err(dev, "Can't find GRF syscon\n");
+			return -ENODEV;
+		}
+	}
+	priv->grf = grf;
+
+	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",
+		.of_match_table = rk_dphy_dt_ids,
+	},
+};
+module_platform_driver(rk_dphy_driver);
+
+MODULE_AUTHOR("Ezequiel Garcia <ezequiel@collabora.com>");
+MODULE_DESCRIPTION("Rockchip MIPI Synopsys DPHY driver");
+MODULE_LICENSE("Dual MIT/GPL");
-- 
2.24.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v12 03/11] media: staging: rkisp1: add streaming paths
  2019-12-27 20:01 [PATCH v12 00/11] Rockchip ISP Driver Helen Koike
  2019-12-27 20:01 ` [PATCH v12 01/11] media: staging: phy-rockchip-dphy: add Rockchip MIPI Synopsys DPHY driver Helen Koike
@ 2019-12-27 20:01 ` Helen Koike
  2019-12-27 20:01 ` [PATCH v12 04/11] media: staging: rkisp1: add user space ABI definitions Helen Koike
                   ` (8 subsequent siblings)
  10 siblings, 0 replies; 35+ messages in thread
From: Helen Koike @ 2019-12-27 20:01 UTC (permalink / raw)
  To: linux-rockchip
  Cc: mark.rutland, eddie.cai.linux, heiko, laurent.pinchart,
	joacim.zetterling, kernel, andrey.konovalov, Yichong Zhong,
	jacob-chen, hans.verkuil, Allon Huang, Shunqian Zheng,
	linux-media, devicetree, Jacob Chen, Jeffy Chen, Helen Koike,
	robh+dt, mchehab, ezequiel, linux-arm-kernel, gregkh,
	linux-kernel, tfiga, sakari.ailus, Jacob Chen

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 <jacob2.chen@rock-chips.com>
Signed-off-by: Shunqian Zheng <zhengsq@rock-chips.com>
Signed-off-by: Yichong Zhong <zyc@rock-chips.com>
Signed-off-by: Jacob Chen <cc@rock-chips.com>
Signed-off-by: Eddie Cai <eddie.cai.linux@gmail.com>
Signed-off-by: Jeffy Chen <jeffy.chen@rock-chips.com>
Signed-off-by: Allon Huang <allon.huang@rock-chips.com>
Signed-off-by: Tomasz Figa <tfiga@chromium.org>
Signed-off-by: Ezequiel Garcia <ezequiel@collabora.com>
Signed-off-by: Helen Koike <helen.koike@collabora.com>

---

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 <linux/delay.h>
+#include <linux/pm_runtime.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-mc.h>
+#include <media/v4l2-subdev.h>
+#include <media/videobuf2-dma-contig.h>
+
+#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 111f49224402..9815aaf67424 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 fa8f8b673f9f..3644563badd0 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);
+}
-- 
2.24.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v12 04/11] media: staging: rkisp1: add user space ABI definitions
  2019-12-27 20:01 [PATCH v12 00/11] Rockchip ISP Driver Helen Koike
  2019-12-27 20:01 ` [PATCH v12 01/11] media: staging: phy-rockchip-dphy: add Rockchip MIPI Synopsys DPHY driver Helen Koike
  2019-12-27 20:01 ` [PATCH v12 03/11] media: staging: rkisp1: add streaming paths Helen Koike
@ 2019-12-27 20:01 ` Helen Koike
  2019-12-27 20:01 ` [PATCH v12 05/11] media: staging: rkisp1: add capture device for statistics Helen Koike
                   ` (7 subsequent siblings)
  10 siblings, 0 replies; 35+ messages in thread
From: Helen Koike @ 2019-12-27 20:01 UTC (permalink / raw)
  To: linux-rockchip
  Cc: mark.rutland, eddie.cai.linux, heiko, laurent.pinchart,
	joacim.zetterling, kernel, jacob-chen, hans.verkuil,
	andrey.konovalov, linux-media, devicetree, Jeffy Chen,
	Helen Koike, robh+dt, mchehab, ezequiel, linux-arm-kernel,
	gregkh, linux-kernel, tfiga, sakari.ailus, Jacob Chen

From: Jeffy Chen <jeffy.chen@rock-chips.com>

Add the header for userspace

Signed-off-by: Jeffy Chen <jeffy.chen@rock-chips.com>
Signed-off-by: Jacob Chen <jacob2.chen@rock-chips.com>
Signed-off-by: Helen Koike <helen.koike@collabora.com>

---

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 <linux/types.h>
+
+/* 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 */
-- 
2.24.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v12 05/11] media: staging: rkisp1: add capture device for statistics
  2019-12-27 20:01 [PATCH v12 00/11] Rockchip ISP Driver Helen Koike
                   ` (2 preceding siblings ...)
  2019-12-27 20:01 ` [PATCH v12 04/11] media: staging: rkisp1: add user space ABI definitions Helen Koike
@ 2019-12-27 20:01 ` Helen Koike
  2019-12-27 20:01 ` [PATCH v12 06/11] media: staging: rkisp1: add output device for parameters Helen Koike
                   ` (6 subsequent siblings)
  10 siblings, 0 replies; 35+ messages in thread
From: Helen Koike @ 2019-12-27 20:01 UTC (permalink / raw)
  To: linux-rockchip
  Cc: mark.rutland, eddie.cai.linux, heiko, laurent.pinchart,
	joacim.zetterling, kernel, andrey.konovalov, Yichong Zhong,
	jacob-chen, hans.verkuil, Allon Huang, Shunqian Zheng,
	linux-media, devicetree, Jacob Chen, Jeffy Chen, Helen Koike,
	robh+dt, mchehab, ezequiel, linux-arm-kernel, gregkh,
	linux-kernel, tfiga, sakari.ailus, Jacob Chen

From: Jacob Chen <jacob2.chen@rock-chips.com>

Add the capture video driver for rockchip isp1 statistics block.

Signed-off-by: Jacob Chen <jacob2.chen@rock-chips.com>
Signed-off-by: Shunqian Zheng <zhengsq@rock-chips.com>
Signed-off-by: Yichong Zhong <zyc@rock-chips.com>
Signed-off-by: Jacob Chen <cc@rock-chips.com>
Signed-off-by: Eddie Cai <eddie.cai.linux@gmail.com>
Signed-off-by: Jeffy Chen <jeffy.chen@rock-chips.com>
Signed-off-by: Allon Huang <allon.huang@rock-chips.com>
Signed-off-by: Tomasz Figa <tfiga@chromium.org>
Signed-off-by: Helen Koike <helen.koike@collabora.com>

---

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 9815aaf67424..60efcedf26cc 100644
--- a/drivers/staging/media/rkisp1/rkisp1-common.h
+++ b/drivers/staging/media/rkisp1/rkisp1-common.h
@@ -20,6 +20,7 @@
 #include <media/videobuf2-v4l2.h>
 
 #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 3644563badd0..63d1b92b5dac 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 <media/v4l2-common.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-ioctl.h>
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-vmalloc.h>	/* 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);
+}
-- 
2.24.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v12 06/11] media: staging: rkisp1: add output device for parameters
  2019-12-27 20:01 [PATCH v12 00/11] Rockchip ISP Driver Helen Koike
                   ` (3 preceding siblings ...)
  2019-12-27 20:01 ` [PATCH v12 05/11] media: staging: rkisp1: add capture device for statistics Helen Koike
@ 2019-12-27 20:01 ` Helen Koike
  2019-12-27 20:01 ` [PATCH v12 07/11] media: staging: rkisp1: add document for rkisp1 meta buffer format Helen Koike
                   ` (5 subsequent siblings)
  10 siblings, 0 replies; 35+ messages in thread
From: Helen Koike @ 2019-12-27 20:01 UTC (permalink / raw)
  To: linux-rockchip
  Cc: mark.rutland, eddie.cai.linux, heiko, laurent.pinchart,
	joacim.zetterling, kernel, andrey.konovalov, Yichong Zhong,
	jacob-chen, hans.verkuil, Allon Huang, Shunqian Zheng,
	linux-media, devicetree, Jacob Chen, Jeffy Chen, Helen Koike,
	robh+dt, mchehab, ezequiel, linux-arm-kernel, gregkh,
	linux-kernel, tfiga, sakari.ailus, Jacob Chen

From: Jacob Chen <jacob2.chen@rock-chips.com>

Add the output video driver that accept parameters from userspace.

Signed-off-by: Jacob Chen <jacob2.chen@rock-chips.com>
Signed-off-by: Shunqian Zheng <zhengsq@rock-chips.com>
Signed-off-by: Yichong Zhong <zyc@rock-chips.com>
Signed-off-by: Jacob Chen <cc@rock-chips.com>
Signed-off-by: Eddie Cai <eddie.cai.linux@gmail.com>
Signed-off-by: Jeffy Chen <jeffy.chen@rock-chips.com>
Signed-off-by: Allon Huang <allon.huang@rock-chips.com>
Signed-off-by: Tomasz Figa <tfiga@chromium.org>
Signed-off-by: Helen Koike <helen.koike@collabora.com>

---

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 60efcedf26cc..a4f680fa2a81 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 63d1b92b5dac..11dd33ba1ab9 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 <media/v4l2-common.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-ioctl.h>
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-vmalloc.h>	/* 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 =
+						&params->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(&params->config_lock);
+	if (!params->is_streaming) {
+		spin_unlock(&params->config_lock);
+		return;
+	}
+
+	/* get one empty buffer */
+	if (!list_empty(&params->params))
+		cur_buf = list_first_entry(&params->params,
+					   struct rkisp1_buffer, queue);
+	spin_unlock(&params->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(&params->config_lock);
+		list_del(&cur_buf->queue);
+		spin_unlock(&params->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(&params->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, &params->cur_params);
+	rkisp1_isp_isr_meas_config(params, &params->cur_params);
+
+	spin_unlock(&params->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(&params->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(&params->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(&params_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(&params->config_lock, flags);
+	list_add_tail(&params_buf->queue, &params->params);
+	spin_unlock_irqrestore(&params->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(&params->config_lock, flags);
+	params->is_streaming = false;
+	spin_unlock_irqrestore(&params->config_lock, flags);
+
+	for (i = 0; i < RKISP1_ISP_PARAMS_REQ_BUFS_MAX; i++) {
+		spin_lock_irqsave(&params->config_lock, flags);
+		if (!list_empty(&params->params)) {
+			buf = list_first_entry(&params->params,
+					       struct rkisp1_buffer, queue);
+			list_del(&buf->queue);
+			spin_unlock_irqrestore(&params->config_lock,
+					       flags);
+		} else {
+			spin_unlock_irqrestore(&params->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(&params->config_lock, flags);
+	params->is_streaming = true;
+	spin_unlock_irqrestore(&params->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 = &params->vnode;
+	struct video_device *vdev = &node->vdev;
+	int ret;
+
+	params->rkisp1 = rkisp1;
+	mutex_init(&node->vlock);
+	spin_lock_init(&params->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 = &params->vnode;
+	struct video_device *vdev = &node->vdev;
+
+	video_unregister_device(vdev);
+	media_entity_cleanup(&vdev->entity);
+	vb2_queue_release(vdev->queue);
+}
-- 
2.24.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v12 07/11] media: staging: rkisp1: add document for rkisp1 meta buffer format
  2019-12-27 20:01 [PATCH v12 00/11] Rockchip ISP Driver Helen Koike
                   ` (4 preceding siblings ...)
  2019-12-27 20:01 ` [PATCH v12 06/11] media: staging: rkisp1: add output device for parameters Helen Koike
@ 2019-12-27 20:01 ` Helen Koike
  2019-12-27 20:01 ` [PATCH v12 08/11] media: staging: dt-bindings: add Rockchip ISP1 yaml bindings Helen Koike
                   ` (4 subsequent siblings)
  10 siblings, 0 replies; 35+ messages in thread
From: Helen Koike @ 2019-12-27 20:01 UTC (permalink / raw)
  To: linux-rockchip
  Cc: mark.rutland, devicetree, eddie.cai.linux, kernel, heiko,
	linux-arm-kernel, ezequiel, gregkh, linux-kernel, tfiga,
	Helen Koike, robh+dt, hans.verkuil, laurent.pinchart,
	sakari.ailus, Jacob Chen, joacim.zetterling, mchehab,
	andrey.konovalov, jacob-chen, linux-media

From: Jacob Chen <jacob2.chen@rock-chips.com>

This commit add document for rkisp1 meta buffer format

Signed-off-by: Jacob Chen <jacob2.chen@rock-chips.com>
Signed-off-by: Helen Koike <helen.koike@collabora.com>

---

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
-- 
2.24.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v12 08/11] media: staging: dt-bindings: add Rockchip ISP1 yaml bindings
  2019-12-27 20:01 [PATCH v12 00/11] Rockchip ISP Driver Helen Koike
                   ` (5 preceding siblings ...)
  2019-12-27 20:01 ` [PATCH v12 07/11] media: staging: rkisp1: add document for rkisp1 meta buffer format Helen Koike
@ 2019-12-27 20:01 ` Helen Koike
  2020-01-06 22:27   ` Rob Herring
                     ` (2 more replies)
  2019-12-27 20:01 ` [PATCH v12 09/11] media: staging: dt-bindings: add Rockchip MIPI RX D-PHY " Helen Koike
                   ` (3 subsequent siblings)
  10 siblings, 3 replies; 35+ messages in thread
From: Helen Koike @ 2019-12-27 20:01 UTC (permalink / raw)
  To: linux-rockchip
  Cc: mark.rutland, devicetree, eddie.cai.linux, kernel, heiko,
	linux-arm-kernel, ezequiel, gregkh, linux-kernel, tfiga,
	Helen Koike, robh+dt, hans.verkuil, laurent.pinchart,
	sakari.ailus, joacim.zetterling, mchehab, andrey.konovalov,
	jacob-chen, linux-media

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 <helen.koike@collabora.com>

---

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         | 193 ++++++++++++++++++
 1 file changed, 193 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..4d1b2c67a4cd
--- /dev/null
+++ b/drivers/staging/media/rkisp1/Documentation/devicetree/bindings/media/rockchip-isp1.yaml
@@ -0,0 +1,193 @@
+# 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 <helen.koike@collabora.com>
+
+description: |
+  Rockchip ISP1 is the Camera interface for the Rockchip series of SoCs
+  which contains image processing, scaling, and compression funcitons.
+
+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 aclk clock
+      - description: ISP aclk wrapper clock
+      - description: ISP hclk clock
+      - description: ISP hclk 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
+        additionalProperties: false
+
+        properties:
+          "#address-cells":
+            const: 1
+
+          "#size-cells":
+            const: 0
+
+          reg:
+            const: 0
+            description: port identifier.
+
+        patternProperties:
+          endpoint:
+            type: object
+            additionalProperties: false
+
+            properties:
+              reg:
+                maxItems: 1
+                description: endpoint identifier.
+
+              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 <dt-bindings/clock/rk3399-cru.h>
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/power/rk3399-power.h>
+
+    parent0: parent@0 {
+        #address-cells = <2>;
+        #size-cells = <2>;
+
+        isp0: isp0@ff910000 {
+            compatible = "rockchip,rk3399-cif-isp";
+            reg = <0x0 0xff910000 0x0 0x4000>;
+            interrupts = <GIC_SPI 43 IRQ_TYPE_LEVEL_HIGH 0>;
+            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>;
+                      };
+                  };
+            };
+        };
+    };
-- 
2.24.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v12 09/11] media: staging: dt-bindings: add Rockchip MIPI RX D-PHY yaml bindings
  2019-12-27 20:01 [PATCH v12 00/11] Rockchip ISP Driver Helen Koike
                   ` (6 preceding siblings ...)
  2019-12-27 20:01 ` [PATCH v12 08/11] media: staging: dt-bindings: add Rockchip ISP1 yaml bindings Helen Koike
@ 2019-12-27 20:01 ` Helen Koike
  2020-01-06 22:29   ` Rob Herring
  2020-01-07  0:10   ` Laurent Pinchart
  2019-12-27 20:01 ` [PATCH v12 10/11] media: staging: rkisp1: add TODO file for staging Helen Koike
                   ` (2 subsequent siblings)
  10 siblings, 2 replies; 35+ messages in thread
From: Helen Koike @ 2019-12-27 20:01 UTC (permalink / raw)
  To: linux-rockchip
  Cc: mark.rutland, devicetree, eddie.cai.linux, kernel, heiko,
	linux-arm-kernel, ezequiel, gregkh, linux-kernel, tfiga,
	Helen Koike, robh+dt, hans.verkuil, laurent.pinchart,
	sakari.ailus, joacim.zetterling, mchehab, andrey.konovalov,
	jacob-chen, linux-media

Add yaml DT bindings for Rockchip MIPI D-PHY RX

This was tested and verified with:
mv drivers/staging/media/phy-rockchip-dphy/Documentation/devicetree/bindings/phy/rockchip-mipi-dphy.yaml  Documentation/devicetree/bindings/phy/
make dt_binding_check DT_SCHEMA_FILES=Documentation/devicetree/bindings/phy/rockchip-mipi-dphy.yaml
make dtbs_check DT_SCHEMA_FILES=Documentation/devicetree/bindings/phy/rockchip-mipi-dphy.yaml

Signed-off-by: Helen Koike <helen.koike@collabora.com>

---

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.yaml      | 75 +++++++++++++++++++
 1 file changed, 75 insertions(+)
 create mode 100644 drivers/staging/media/phy-rockchip-dphy/Documentation/devicetree/bindings/phy/rockchip-mipi-dphy.yaml

diff --git a/drivers/staging/media/phy-rockchip-dphy/Documentation/devicetree/bindings/phy/rockchip-mipi-dphy.yaml b/drivers/staging/media/phy-rockchip-dphy/Documentation/devicetree/bindings/phy/rockchip-mipi-dphy.yaml
new file mode 100644
index 000000000000..af97f1b3e005
--- /dev/null
+++ b/drivers/staging/media/phy-rockchip-dphy/Documentation/devicetree/bindings/phy/rockchip-mipi-dphy.yaml
@@ -0,0 +1,75 @@
+# SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/phy/rockchip-mipi-dphy.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Rockchip SoC MIPI RX0 D-PHY Device Tree Bindings
+
+maintainers:
+  - Helen Koike <helen.koike@collabora.com>
+  - Ezequiel Garcia <ezequiel@collabora.com>
+
+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
+
+  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 RX D-PHY 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 <dt-bindings/clock/rk3399-cru.h>
+    #include <dt-bindings/power/rk3399-power.h>
+
+    dphy: mipi-dphy {
+        compatible = "rockchip,rk3399-mipi-dphy";
+        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>;
+    };
-- 
2.24.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v12 10/11] media: staging: rkisp1: add TODO file for staging
  2019-12-27 20:01 [PATCH v12 00/11] Rockchip ISP Driver Helen Koike
                   ` (7 preceding siblings ...)
  2019-12-27 20:01 ` [PATCH v12 09/11] media: staging: dt-bindings: add Rockchip MIPI RX D-PHY " Helen Koike
@ 2019-12-27 20:01 ` Helen Koike
  2019-12-27 20:01 ` [PATCH v12 11/11] MAINTAINERS: add entry for Rockchip ISP1 driver Helen Koike
       [not found] ` <20191227200116.2612137-3-helen.koike@collabora.com>
  10 siblings, 0 replies; 35+ messages in thread
From: Helen Koike @ 2019-12-27 20:01 UTC (permalink / raw)
  To: linux-rockchip
  Cc: mark.rutland, devicetree, eddie.cai.linux, kernel, heiko,
	linux-arm-kernel, ezequiel, gregkh, linux-kernel, tfiga,
	Helen Koike, robh+dt, hans.verkuil, laurent.pinchart,
	sakari.ailus, joacim.zetterling, mchehab, andrey.konovalov,
	jacob-chen, linux-media

Add TODO file with requirements to move this driver out of staging.

Signed-off-by: Helen Koike <helen.koike@collabora.com>
---

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 <linux-media@vger.kernel.org> and
+Helen Koike <helen.koike@collabora.com>.
-- 
2.24.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v12 11/11] MAINTAINERS: add entry for Rockchip ISP1 driver
  2019-12-27 20:01 [PATCH v12 00/11] Rockchip ISP Driver Helen Koike
                   ` (8 preceding siblings ...)
  2019-12-27 20:01 ` [PATCH v12 10/11] media: staging: rkisp1: add TODO file for staging Helen Koike
@ 2019-12-27 20:01 ` Helen Koike
       [not found] ` <20191227200116.2612137-3-helen.koike@collabora.com>
  10 siblings, 0 replies; 35+ messages in thread
From: Helen Koike @ 2019-12-27 20:01 UTC (permalink / raw)
  To: linux-rockchip
  Cc: mark.rutland, devicetree, eddie.cai.linux, kernel, heiko,
	linux-arm-kernel, ezequiel, gregkh, linux-kernel, tfiga,
	Helen Koike, robh+dt, hans.verkuil, laurent.pinchart,
	sakari.ailus, joacim.zetterling, mchehab, andrey.konovalov,
	jacob-chen, linux-media

Add MAINTAINERS entry for the rockchip isp1 driver.

Signed-off-by: Helen Koike <helen.koike@collabora.com>

---

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 <helen.koike@collabora.com>
+L:	linux-media@vger.kernel.org
+S:	Maintained
+F:	drivers/staging/media/rkisp1/
+
 ROCKCHIP RASTER 2D GRAPHIC ACCELERATION UNIT DRIVER
 M:	Jacob Chen <jacob-chen@iotwrt.com>
 M:	Ezequiel Garcia <ezequiel@collabora.com>
-- 
2.24.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 35+ messages in thread

* Re: [PATCH v12 02/11] media: staging: rkisp1: add Rockchip ISP1 base driver
       [not found] ` <20191227200116.2612137-3-helen.koike@collabora.com>
@ 2019-12-30 18:13   ` Ezequiel Garcia
  0 siblings, 0 replies; 35+ messages in thread
From: Ezequiel Garcia @ 2019-12-30 18:13 UTC (permalink / raw)
  To: Helen Koike, linux-rockchip
  Cc: mark.rutland, eddie.cai.linux, heiko, laurent.pinchart,
	joacim.zetterling, kernel, andrey.konovalov, Yichong Zhong,
	jacob-chen, hans.verkuil, Allon Huang, Shunqian Zheng,
	linux-media, devicetree, Jacob Chen, Jeffy Chen, robh+dt,
	mchehab, linux-arm-kernel, gregkh, linux-kernel, tfiga,
	sakari.ailus, Jacob Chen

Hi Helen,

Just spotted a small thing.

On Fri, 2019-12-27 at 17:01 -0300, Helen Koike wrote:
[..]
> +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_debug_init(rkisp1);
> +
> +       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;
> +
> +       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);

There's a missing call to debugfs_remove_recursive here.

> +       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;
> +}
> +

Thanks,
Ezequiel



_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v12 01/11] media: staging: phy-rockchip-dphy: add Rockchip MIPI Synopsys DPHY driver
  2019-12-27 20:01 ` [PATCH v12 01/11] media: staging: phy-rockchip-dphy: add Rockchip MIPI Synopsys DPHY driver Helen Koike
@ 2019-12-30 18:25   ` Ezequiel Garcia
  2020-01-07  1:11   ` Laurent Pinchart
  1 sibling, 0 replies; 35+ messages in thread
From: Ezequiel Garcia @ 2019-12-30 18:25 UTC (permalink / raw)
  To: Helen Koike, linux-rockchip
  Cc: mark.rutland, devicetree, eddie.cai.linux, kernel, heiko,
	linux-arm-kernel, gregkh, linux-kernel, tfiga, robh+dt,
	hans.verkuil, laurent.pinchart, sakari.ailus, joacim.zetterling,
	mchehab, andrey.konovalov, jacob-chen, linux-media

Hi Helen,

Thanks for taking care of this.

On Fri, 2019-12-27 at 17:01 -0300, Helen Koike wrote:
> From: Ezequiel Garcia <ezequiel@collabora.com>
> 
> Add driver for Rockchip MIPI Synopsys DPHY driver
> 
> Signed-off-by: Tomasz Figa <tfiga@chromium.org>
> Signed-off-by: Ezequiel Garcia <ezequiel@collabora.com>
> Signed-off-by: Helen Koike <helen.koike@collabora.com>
> 
> ---
> 
> 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 +
>  .../staging/media/phy-rockchip-dphy/Kconfig   |  11 +
>  .../staging/media/phy-rockchip-dphy/Makefile  |   2 +
>  drivers/staging/media/phy-rockchip-dphy/TODO  |   6 +
>  .../phy-rockchip-dphy/phy-rockchip-dphy.c     | 396 ++++++++++++++++++
>  6 files changed, 418 insertions(+)
>  create mode 100644 drivers/staging/media/phy-rockchip-dphy/Kconfig
>  create mode 100644 drivers/staging/media/phy-rockchip-dphy/Makefile
>  create mode 100644 drivers/staging/media/phy-rockchip-dphy/TODO
>  create mode 100644 drivers/staging/media/phy-rockchip-dphy/phy-rockchip-dphy.c
> 
> diff --git a/drivers/staging/media/Kconfig b/drivers/staging/media/Kconfig
> index 642adc4c24d2..a47484473883 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/Kconfig"
> +
>  endif
> diff --git a/drivers/staging/media/Makefile b/drivers/staging/media/Makefile
> index 2f1711a8aeed..b0eae3906208 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)		+= phy-rockchip-dphy/
> diff --git a/drivers/staging/media/phy-rockchip-dphy/Kconfig b/drivers/staging/media/phy-rockchip-dphy/Kconfig
> new file mode 100644
> index 000000000000..7378bd75fa7c
> --- /dev/null

Seems I overlooked the Kconfig file for this driver,
sorry about that!

> +++ b/drivers/staging/media/phy-rockchip-dphy/Kconfig
> @@ -0,0 +1,11 @@
> +# SPDX-License-Identifier: GPL-2.0-only
> +#
> +# Phy drivers for Rockchip platforms
> +#
> +config PHY_ROCKCHIP_DPHY
> +	tristate "Rockchip MIPI Synopsys DPHY 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.

Following a more user-friendly convention, this should read
more like:

"""
Enable this to support the Rockchip MIPI Synopsys DPHY
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. 
"""

And I believe the same improvement should be applied to the
ISP driver Kconfig help.

Thanks,
Ezequiel


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v12 08/11] media: staging: dt-bindings: add Rockchip ISP1 yaml bindings
  2019-12-27 20:01 ` [PATCH v12 08/11] media: staging: dt-bindings: add Rockchip ISP1 yaml bindings Helen Koike
@ 2020-01-06 22:27   ` Rob Herring
  2020-01-06 23:59   ` Laurent Pinchart
  2020-01-07 14:01   ` Sakari Ailus
  2 siblings, 0 replies; 35+ messages in thread
From: Rob Herring @ 2020-01-06 22:27 UTC (permalink / raw)
  To: Helen Koike
  Cc: Mark Rutland, devicetree, Eddie Cai, kernel, heiko,
	Ezequiel Garcia, Greg Kroah-Hartman, linux-kernel, Tomasz Figa,
	open list:ARM/Rockchip SoC...,
	Jacob Chen, Hans Verkuil, Laurent Pinchart, Sakari Ailus,
	joacim.zetterling, Mauro Carvalho Chehab, Andrey Konovalov,
	moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE,
	Linux Media Mailing List

On Fri, Dec 27, 2019 at 2:02 PM Helen Koike <helen.koike@collabora.com> wrote:
>
> 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 <helen.koike@collabora.com>
>
> ---
>
> 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         | 193 ++++++++++++++++++
>  1 file changed, 193 insertions(+)
>  create mode 100644 drivers/staging/media/rkisp1/Documentation/devicetree/bindings/media/rockchip-isp1.yaml

Reviewed-by: Rob Herring <robh@kernel.org>

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v12 09/11] media: staging: dt-bindings: add Rockchip MIPI RX D-PHY yaml bindings
  2019-12-27 20:01 ` [PATCH v12 09/11] media: staging: dt-bindings: add Rockchip MIPI RX D-PHY " Helen Koike
@ 2020-01-06 22:29   ` Rob Herring
  2020-01-07  0:10   ` Laurent Pinchart
  1 sibling, 0 replies; 35+ messages in thread
From: Rob Herring @ 2020-01-06 22:29 UTC (permalink / raw)
  To: Helen Koike
  Cc: Mark Rutland, devicetree, Eddie Cai, kernel, heiko,
	Ezequiel Garcia, Greg Kroah-Hartman, linux-kernel, Tomasz Figa,
	open list:ARM/Rockchip SoC...,
	Jacob Chen, Hans Verkuil, Laurent Pinchart, Sakari Ailus,
	joacim.zetterling, Mauro Carvalho Chehab, Andrey Konovalov,
	moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE,
	Linux Media Mailing List

On Fri, Dec 27, 2019 at 2:02 PM Helen Koike <helen.koike@collabora.com> wrote:
>
> Add yaml DT bindings for Rockchip MIPI D-PHY RX
>
> This was tested and verified with:
> mv drivers/staging/media/phy-rockchip-dphy/Documentation/devicetree/bindings/phy/rockchip-mipi-dphy.yaml  Documentation/devicetree/bindings/phy/
> make dt_binding_check DT_SCHEMA_FILES=Documentation/devicetree/bindings/phy/rockchip-mipi-dphy.yaml
> make dtbs_check DT_SCHEMA_FILES=Documentation/devicetree/bindings/phy/rockchip-mipi-dphy.yaml
>
> Signed-off-by: Helen Koike <helen.koike@collabora.com>
>
> ---
>
> 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.yaml      | 75 +++++++++++++++++++
>  1 file changed, 75 insertions(+)
>  create mode 100644 drivers/staging/media/phy-rockchip-dphy/Documentation/devicetree/bindings/phy/rockchip-mipi-dphy.yaml

Reviewed-by: Rob Herring <robh@kernel.org>

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v12 08/11] media: staging: dt-bindings: add Rockchip ISP1 yaml bindings
  2019-12-27 20:01 ` [PATCH v12 08/11] media: staging: dt-bindings: add Rockchip ISP1 yaml bindings Helen Koike
  2020-01-06 22:27   ` Rob Herring
@ 2020-01-06 23:59   ` Laurent Pinchart
  2020-01-07 13:45     ` Ezequiel Garcia
  2020-01-07 14:01   ` Sakari Ailus
  2 siblings, 1 reply; 35+ messages in thread
From: Laurent Pinchart @ 2020-01-06 23:59 UTC (permalink / raw)
  To: Helen Koike
  Cc: mark.rutland, devicetree, eddie.cai.linux, kernel, heiko,
	ezequiel, gregkh, linux-kernel, tfiga, linux-rockchip, robh+dt,
	hans.verkuil, linux-arm-kernel, sakari.ailus, joacim.zetterling,
	mchehab, andrey.konovalov, jacob-chen, linux-media

Hi Helen,

Thank you for the patch.

On Fri, Dec 27, 2019 at 05:01:13PM -0300, Helen Koike wrote:
> 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 <helen.koike@collabora.com>
> 
> ---
> 
> 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         | 193 ++++++++++++++++++
>  1 file changed, 193 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..4d1b2c67a4cd
> --- /dev/null
> +++ b/drivers/staging/media/rkisp1/Documentation/devicetree/bindings/media/rockchip-isp1.yaml
> @@ -0,0 +1,193 @@
> +# 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 <helen.koike@collabora.com>
> +
> +description: |
> +  Rockchip ISP1 is the Camera interface for the Rockchip series of SoCs
> +  which contains image processing, scaling, and compression funcitons.
> +
> +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

According to http://opensource.rock-chips.com/wiki_Camera_driver, RK3388
can route either of DPHY RX0 or DPHY RX1 to the single ISP instance,
while RK3399 has one PHY per ISP instance, with DPHY RX1 being shared
with the display. Have you given any thought on how we will support this
in a backward-compatible way in the DT bindings ?

> +
> +  phy-names:
> +    const: dphy
> +
> +  clocks:
> +    items:
> +      - description: ISP clock
> +      - description: ISP aclk clock
> +      - description: ISP aclk wrapper clock
> +      - description: ISP hclk clock
> +      - description: ISP hclk wrapper clock

I wonder what aclk and hclk stand far. In any case those names match the
CRU documentation, so that seems fine.

> +
> +  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
> +        additionalProperties: false

I think this should have a description to tell what this port
corresponds to.

> +
> +        properties:
> +          "#address-cells":
> +            const: 1
> +
> +          "#size-cells":
> +            const: 0
> +
> +          reg:
> +            const: 0
> +            description: port identifier.

Here and for the endpoint below the description is probably not needed.

> +
> +        patternProperties:
> +          endpoint:
> +            type: object
> +            additionalProperties: false
> +
> +            properties:
> +              reg:
> +                maxItems: 1
> +                description: endpoint identifier.
> +
> +              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 <dt-bindings/clock/rk3399-cru.h>
> +    #include <dt-bindings/interrupt-controller/arm-gic.h>
> +    #include <dt-bindings/power/rk3399-power.h>
> +
> +    parent0: parent@0 {
> +        #address-cells = <2>;
> +        #size-cells = <2>;
> +
> +        isp0: isp0@ff910000 {
> +            compatible = "rockchip,rk3399-cif-isp";
> +            reg = <0x0 0xff910000 0x0 0x4000>;
> +            interrupts = <GIC_SPI 43 IRQ_TYPE_LEVEL_HIGH 0>;
> +            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>;
> +                    };

Are those two cameras connected to the same CSI-2 lines with at most one
sensor out of reset ?

With the above small issues addressed,

Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

> +                };
> +            };
> +        };
> +
> +        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>;
> +                      };
> +                  };
> +            };
> +        };
> +    };

-- 
Regards,

Laurent Pinchart

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v12 09/11] media: staging: dt-bindings: add Rockchip MIPI RX D-PHY yaml bindings
  2019-12-27 20:01 ` [PATCH v12 09/11] media: staging: dt-bindings: add Rockchip MIPI RX D-PHY " Helen Koike
  2020-01-06 22:29   ` Rob Herring
@ 2020-01-07  0:10   ` Laurent Pinchart
  2020-01-07  2:06     ` Ezequiel Garcia
  1 sibling, 1 reply; 35+ messages in thread
From: Laurent Pinchart @ 2020-01-07  0:10 UTC (permalink / raw)
  To: Helen Koike
  Cc: mark.rutland, devicetree, eddie.cai.linux, kernel, heiko,
	ezequiel, gregkh, linux-kernel, tfiga, linux-rockchip, robh+dt,
	hans.verkuil, linux-arm-kernel, sakari.ailus, joacim.zetterling,
	mchehab, andrey.konovalov, jacob-chen, linux-media

Hi Helen,

Thank you for the patch.

On Fri, Dec 27, 2019 at 05:01:14PM -0300, Helen Koike wrote:
> Add yaml DT bindings for Rockchip MIPI D-PHY RX
> 
> This was tested and verified with:
> mv drivers/staging/media/phy-rockchip-dphy/Documentation/devicetree/bindings/phy/rockchip-mipi-dphy.yaml  Documentation/devicetree/bindings/phy/
> make dt_binding_check DT_SCHEMA_FILES=Documentation/devicetree/bindings/phy/rockchip-mipi-dphy.yaml
> make dtbs_check DT_SCHEMA_FILES=Documentation/devicetree/bindings/phy/rockchip-mipi-dphy.yaml
> 
> Signed-off-by: Helen Koike <helen.koike@collabora.com>
> 
> ---
> 
> 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.yaml      | 75 +++++++++++++++++++
>  1 file changed, 75 insertions(+)
>  create mode 100644 drivers/staging/media/phy-rockchip-dphy/Documentation/devicetree/bindings/phy/rockchip-mipi-dphy.yaml
> 
> diff --git a/drivers/staging/media/phy-rockchip-dphy/Documentation/devicetree/bindings/phy/rockchip-mipi-dphy.yaml b/drivers/staging/media/phy-rockchip-dphy/Documentation/devicetree/bindings/phy/rockchip-mipi-dphy.yaml
> new file mode 100644
> index 000000000000..af97f1b3e005
> --- /dev/null
> +++ b/drivers/staging/media/phy-rockchip-dphy/Documentation/devicetree/bindings/phy/rockchip-mipi-dphy.yaml
> @@ -0,0 +1,75 @@
> +# SPDX-License-Identifier: (GPL-2.0+ OR MIT)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/phy/rockchip-mipi-dphy.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Rockchip SoC MIPI RX0 D-PHY Device Tree Bindings

Should this be s/RX0/RX/ ? Or do you expect different bindings for RX1 ?
Looking at the PHY driver, it seems to handle all PHYs with a single
struct device. Should we thus use #phy-cells = <1> to select the PHY ?

> +
> +maintainers:
> +  - Helen Koike <helen.koike@collabora.com>
> +  - Ezequiel Garcia <ezequiel@collabora.com>
> +
> +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
> +
> +  reg:
> +    maxItems: 1
> +
> +  clocks:
> +    items:
> +      - description: Mipi d-phy ref clock
> +      - description: Mipi d-phy rx0 cfg clock

s/Mipi d-phy/MIPI D-PHY/

> +      - 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 RX D-PHY use registers in "general register files", it
> +     * should be a child of the GRF.
> +     *
> +     * grf: syscon@ff770000 {
> +     *  compatible = "rockchip,rk3399-grf", "syscon", "simple-mfd";
> +     *  ...

missing

	* };

> +     */
> +
> +    #include <dt-bindings/clock/rk3399-cru.h>
> +    #include <dt-bindings/power/rk3399-power.h>
> +
> +    dphy: mipi-dphy {
> +        compatible = "rockchip,rk3399-mipi-dphy";
> +        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>;
> +    };

-- 
Regards,

Laurent Pinchart

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v12 01/11] media: staging: phy-rockchip-dphy: add Rockchip MIPI Synopsys DPHY driver
  2019-12-27 20:01 ` [PATCH v12 01/11] media: staging: phy-rockchip-dphy: add Rockchip MIPI Synopsys DPHY driver Helen Koike
  2019-12-30 18:25   ` Ezequiel Garcia
@ 2020-01-07  1:11   ` Laurent Pinchart
  2020-01-07 15:58     ` Ezequiel Garcia
  1 sibling, 1 reply; 35+ messages in thread
From: Laurent Pinchart @ 2020-01-07  1:11 UTC (permalink / raw)
  To: Helen Koike
  Cc: mark.rutland, devicetree, eddie.cai.linux, kernel, heiko,
	ezequiel, gregkh, linux-kernel, tfiga, linux-rockchip, robh+dt,
	hans.verkuil, linux-arm-kernel, sakari.ailus, joacim.zetterling,
	mchehab, andrey.konovalov, jacob-chen, linux-media

Hi Helen and Ezequiel,

Thank you for the patch.

On Fri, Dec 27, 2019 at 05:01:06PM -0300, Helen Koike wrote:
> From: Ezequiel Garcia <ezequiel@collabora.com>
> 
> Add driver for Rockchip MIPI Synopsys DPHY driver
> 
> Signed-off-by: Tomasz Figa <tfiga@chromium.org>
> Signed-off-by: Ezequiel Garcia <ezequiel@collabora.com>
> Signed-off-by: Helen Koike <helen.koike@collabora.com>
> 
> ---
> 
> 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 +
>  .../staging/media/phy-rockchip-dphy/Kconfig   |  11 +
>  .../staging/media/phy-rockchip-dphy/Makefile  |   2 +
>  drivers/staging/media/phy-rockchip-dphy/TODO  |   6 +
>  .../phy-rockchip-dphy/phy-rockchip-dphy.c     | 396 ++++++++++++++++++
>  6 files changed, 418 insertions(+)
>  create mode 100644 drivers/staging/media/phy-rockchip-dphy/Kconfig
>  create mode 100644 drivers/staging/media/phy-rockchip-dphy/Makefile
>  create mode 100644 drivers/staging/media/phy-rockchip-dphy/TODO
>  create mode 100644 drivers/staging/media/phy-rockchip-dphy/phy-rockchip-dphy.c
> 
> diff --git a/drivers/staging/media/Kconfig b/drivers/staging/media/Kconfig
> index 642adc4c24d2..a47484473883 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/Kconfig"
> +
>  endif
> diff --git a/drivers/staging/media/Makefile b/drivers/staging/media/Makefile
> index 2f1711a8aeed..b0eae3906208 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)		+= phy-rockchip-dphy/
> diff --git a/drivers/staging/media/phy-rockchip-dphy/Kconfig b/drivers/staging/media/phy-rockchip-dphy/Kconfig
> new file mode 100644
> index 000000000000..7378bd75fa7c
> --- /dev/null
> +++ b/drivers/staging/media/phy-rockchip-dphy/Kconfig
> @@ -0,0 +1,11 @@
> +# SPDX-License-Identifier: GPL-2.0-only
> +#
> +# Phy drivers for Rockchip platforms

s/Phy/MIPI D-PHY/

> +#
> +config PHY_ROCKCHIP_DPHY
> +	tristate "Rockchip MIPI Synopsys DPHY 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.
> diff --git a/drivers/staging/media/phy-rockchip-dphy/Makefile b/drivers/staging/media/phy-rockchip-dphy/Makefile
> new file mode 100644
> index 000000000000..24679dc950cd
> --- /dev/null
> +++ b/drivers/staging/media/phy-rockchip-dphy/Makefile
> @@ -0,0 +1,2 @@
> +# SPDX-License-Identifier: GPL-2.0
> +obj-$(CONFIG_PHY_ROCKCHIP_DPHY)		+= phy-rockchip-dphy.o
> diff --git a/drivers/staging/media/phy-rockchip-dphy/TODO b/drivers/staging/media/phy-rockchip-dphy/TODO
> new file mode 100644
> index 000000000000..e1fda55babef
> --- /dev/null
> +++ b/drivers/staging/media/phy-rockchip-dphy/TODO
> @@ -0,0 +1,6 @@
> +The major reason for keeping this in staging is because the only driver

s/major/main/

> +who uses this is rkisp1 who is also in staging. It should be moved together

s/who uses this/that uses this/
s/who is also/, which is also/

> +rkisp1.

s/rkisp1/with rkisp1/ ?

> +
> +Please CC patches to Linux Media <linux-media@vger.kernel.org> and
> +Helen Koike <helen.koike@collabora.com>.
> diff --git a/drivers/staging/media/phy-rockchip-dphy/phy-rockchip-dphy.c b/drivers/staging/media/phy-rockchip-dphy/phy-rockchip-dphy.c
> new file mode 100644
> index 000000000000..c3fe9c64b45f
> --- /dev/null
> +++ b/drivers/staging/media/phy-rockchip-dphy/phy-rockchip-dphy.c
> @@ -0,0 +1,396 @@
> +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)

Any reason for this ? Kernel code is usually GPL-2.0.

> +/*
> + * Rockchip MIPI Synopsys DPHY 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 <jacob2.chen@rock-chips.com>
> + *   Shunqian Zheng <zhengsq@rock-chips.com>
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/io.h>
> +#include <linux/mfd/syscon.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_device.h>
> +#include <linux/phy/phy.h>
> +#include <linux/phy/phy-mipi-dphy.h>
> +#include <linux/platform_device.h>
> +#include <linux/regmap.h>
> +
> +#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));
> +
> +	WARN_ON(!reg->offset);

Maybe

	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)
> +{
> +	/*
> +	 * 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.
> +	 */
> +	rk_dphy_write_grf(priv, GRF_DPHY_RX0_TESTCLK, 1);

Do we need this first line, as the function always exits with TESTCLK=1,
and TESTCLK is initialized to 1 before calling rk_dphy_write for the
first time ?

> +	rk_dphy_write_grf(priv, GRF_DPHY_RX0_TESTDIN, test_code);
> +	rk_dphy_write_grf(priv, GRF_DPHY_RX0_TESTEN, 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 i, hsfreq = 0, data_rate_mbps = config->hs_clk_rate;

Maybe one variable per line ?

> +	int ret;
> +
> +	/* pass with phy_mipi_dphy_get_default_config (with pixel rate?) */
> +	ret = phy_mipi_dphy_config_validate(config);
> +	if (ret)
> +		return ret;

I would add a blank line here.

> +	do_div(data_rate_mbps, 1000 * 1000);

data_rate_mbps is an unsigned int, so you can use

	data_rate_mbps /= 1000 * 1000;

However, you're potentially truncating hs_clk_rate by assigning it to
data_rate_mbps, so I would remove the assignment at declaration time and
do

	data_rate_mbps = div_u64(config->hs_clk_rate, 1000 * 1000);

or define data_rate_mbps as an unsigned long.

> +
> +	dev_dbg(priv->dev, "lanes %d - data_rate_mbps %u\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",
> +		.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 regmap *grf;
> +	struct phy *phy;
> +	unsigned int i;
> +	int ret;
> +
> +	if (!dev->parent || !dev->parent->of_node)
> +		return -ENODEV;
> +
> +	if (platform_get_resource(pdev, IORESOURCE_MEM, 0)) {
> +		dev_err(dev, "Rockchip DPHY driver only suports RX mode\n");
> +		return -EINVAL;
> +	}
> +
> +	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> +	if (!priv)
> +		return -ENOMEM;
> +	priv->dev = dev;
> +
> +	grf = syscon_node_to_regmap(dev->parent->of_node);
> +	if (IS_ERR(grf)) {
> +		grf = syscon_regmap_lookup_by_phandle(dev->of_node,
> +						      "rockchip,grf");

Is this for backward compatibility with older bindings ? Do we still
need it ? If so I would add a comment to explain why.

With the above small issues fixed,

Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

> +		if (IS_ERR(grf)) {
> +			dev_err(dev, "Can't find GRF syscon\n");
> +			return -ENODEV;
> +		}
> +	}
> +	priv->grf = grf;
> +
> +	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",
> +		.of_match_table = rk_dphy_dt_ids,
> +	},
> +};
> +module_platform_driver(rk_dphy_driver);
> +
> +MODULE_AUTHOR("Ezequiel Garcia <ezequiel@collabora.com>");
> +MODULE_DESCRIPTION("Rockchip MIPI Synopsys DPHY driver");
> +MODULE_LICENSE("Dual MIT/GPL");

-- 
Regards,

Laurent Pinchart

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v12 09/11] media: staging: dt-bindings: add Rockchip MIPI RX D-PHY yaml bindings
  2020-01-07  0:10   ` Laurent Pinchart
@ 2020-01-07  2:06     ` Ezequiel Garcia
  2020-01-07  2:37       ` Laurent Pinchart
  0 siblings, 1 reply; 35+ messages in thread
From: Ezequiel Garcia @ 2020-01-07  2:06 UTC (permalink / raw)
  To: Laurent Pinchart, Helen Koike
  Cc: mark.rutland, devicetree, eddie.cai.linux, kernel, heiko, gregkh,
	linux-kernel, tfiga, linux-rockchip, robh+dt, hans.verkuil,
	linux-arm-kernel, sakari.ailus, joacim.zetterling, mchehab,
	andrey.konovalov, jacob-chen, linux-media

Hi Laurent,

Thanks a lot for reviewing this.

On Tue, 2020-01-07 at 02:10 +0200, Laurent Pinchart wrote:
> Hi Helen,
> 
> Thank you for the patch.
> 
> On Fri, Dec 27, 2019 at 05:01:14PM -0300, Helen Koike wrote:
> > Add yaml DT bindings for Rockchip MIPI D-PHY RX
> > 
> > This was tested and verified with:
> > mv drivers/staging/media/phy-rockchip-dphy/Documentation/devicetree/bindings/phy/rockchip-mipi-dphy.yaml  Documentation/devicetree/bindings/phy/
> > make dt_binding_check DT_SCHEMA_FILES=Documentation/devicetree/bindings/phy/rockchip-mipi-dphy.yaml
> > make dtbs_check DT_SCHEMA_FILES=Documentation/devicetree/bindings/phy/rockchip-mipi-dphy.yaml
> > 
> > Signed-off-by: Helen Koike <helen.koike@collabora.com>
> > 
> > ---
> > 
> > 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.yaml      | 75 +++++++++++++++++++
> >  1 file changed, 75 insertions(+)
> >  create mode 100644 drivers/staging/media/phy-rockchip-dphy/Documentation/devicetree/bindings/phy/rockchip-mipi-dphy.yaml
> > 
> > diff --git a/drivers/staging/media/phy-rockchip-dphy/Documentation/devicetree/bindings/phy/rockchip-mipi-dphy.yaml b/drivers/staging/media/phy-
> > rockchip-dphy/Documentation/devicetree/bindings/phy/rockchip-mipi-dphy.yaml
> > new file mode 100644
> > index 000000000000..af97f1b3e005
> > --- /dev/null
> > +++ b/drivers/staging/media/phy-rockchip-dphy/Documentation/devicetree/bindings/phy/rockchip-mipi-dphy.yaml
> > @@ -0,0 +1,75 @@
> > +# SPDX-License-Identifier: (GPL-2.0+ OR MIT)
> > +%YAML 1.2
> > +---
> > +$id: http://devicetree.org/schemas/phy/rockchip-mipi-dphy.yaml#
> > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > +
> > +title: Rockchip SoC MIPI RX0 D-PHY Device Tree Bindings
> 
> Should this be s/RX0/RX/ ? Or do you expect different bindings for RX1 ?

The driver currently only supports RX0, but I think you are right,
it should say RX here. This binding could be extended for RX1.

> Looking at the PHY driver, it seems to handle all PHYs with a single
> struct device. Should we thus use #phy-cells = <1> to select the PHY ?
> 

I am not following this. The driver handles just one PHY. Each PHY
should have its own node.

> > +
> > +maintainers:
> > +  - Helen Koike <helen.koike@collabora.com>
> > +  - Ezequiel Garcia <ezequiel@collabora.com>
> > +
> > +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
> > +
> > +  reg:
> > +    maxItems: 1
> > +
> > +  clocks:
> > +    items:
> > +      - description: Mipi d-phy ref clock
> > +      - description: Mipi d-phy rx0 cfg clock
> 
> s/Mipi d-phy/MIPI D-PHY/
> 

Yep.

> > +      - 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 RX D-PHY use registers in "general register files", it
> > +     * should be a child of the GRF.
> > +     *
> > +     * grf: syscon@ff770000 {
> > +     *  compatible = "rockchip,rk3399-grf", "syscon", "simple-mfd";
> > +     *  ...
> 
> missing
> 
> 	* };
> 

OK.

> > +     */
> > +
> > +    #include <dt-bindings/clock/rk3399-cru.h>
> > +    #include <dt-bindings/power/rk3399-power.h>
> > +
> > +    dphy: mipi-dphy {
> > +        compatible = "rockchip,rk3399-mipi-dphy";
> > +        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>;
> > +    };



_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v12 09/11] media: staging: dt-bindings: add Rockchip MIPI RX D-PHY yaml bindings
  2020-01-07  2:06     ` Ezequiel Garcia
@ 2020-01-07  2:37       ` Laurent Pinchart
  2020-01-07  9:28         ` Heiko Stübner
  0 siblings, 1 reply; 35+ messages in thread
From: Laurent Pinchart @ 2020-01-07  2:37 UTC (permalink / raw)
  To: Ezequiel Garcia
  Cc: mark.rutland, devicetree, eddie.cai.linux, kernel, heiko, gregkh,
	linux-kernel, tfiga, linux-rockchip, Helen Koike, robh+dt,
	hans.verkuil, linux-arm-kernel, sakari.ailus, joacim.zetterling,
	mchehab, andrey.konovalov, jacob-chen, linux-media

On Mon, Jan 06, 2020 at 11:06:12PM -0300, Ezequiel Garcia wrote:
> On Tue, 2020-01-07 at 02:10 +0200, Laurent Pinchart wrote:
> > Hi Helen,
> > 
> > Thank you for the patch.
> > 
> > On Fri, Dec 27, 2019 at 05:01:14PM -0300, Helen Koike wrote:
> > > Add yaml DT bindings for Rockchip MIPI D-PHY RX
> > > 
> > > This was tested and verified with:
> > > mv drivers/staging/media/phy-rockchip-dphy/Documentation/devicetree/bindings/phy/rockchip-mipi-dphy.yaml  Documentation/devicetree/bindings/phy/
> > > make dt_binding_check DT_SCHEMA_FILES=Documentation/devicetree/bindings/phy/rockchip-mipi-dphy.yaml
> > > make dtbs_check DT_SCHEMA_FILES=Documentation/devicetree/bindings/phy/rockchip-mipi-dphy.yaml
> > > 
> > > Signed-off-by: Helen Koike <helen.koike@collabora.com>
> > > 
> > > ---
> > > 
> > > 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.yaml      | 75 +++++++++++++++++++
> > >  1 file changed, 75 insertions(+)
> > >  create mode 100644 drivers/staging/media/phy-rockchip-dphy/Documentation/devicetree/bindings/phy/rockchip-mipi-dphy.yaml
> > > 
> > > diff --git a/drivers/staging/media/phy-rockchip-dphy/Documentation/devicetree/bindings/phy/rockchip-mipi-dphy.yaml b/drivers/staging/media/phy-
> > > rockchip-dphy/Documentation/devicetree/bindings/phy/rockchip-mipi-dphy.yaml
> > > new file mode 100644
> > > index 000000000000..af97f1b3e005
> > > --- /dev/null
> > > +++ b/drivers/staging/media/phy-rockchip-dphy/Documentation/devicetree/bindings/phy/rockchip-mipi-dphy.yaml
> > > @@ -0,0 +1,75 @@
> > > +# SPDX-License-Identifier: (GPL-2.0+ OR MIT)
> > > +%YAML 1.2
> > > +---
> > > +$id: http://devicetree.org/schemas/phy/rockchip-mipi-dphy.yaml#
> > > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > > +
> > > +title: Rockchip SoC MIPI RX0 D-PHY Device Tree Bindings
> > 
> > Should this be s/RX0/RX/ ? Or do you expect different bindings for RX1 ?
> 
> The driver currently only supports RX0, but I think you are right,
> it should say RX here. This binding could be extended for RX1.
> 
> > Looking at the PHY driver, it seems to handle all PHYs with a single
> > struct device. Should we thus use #phy-cells = <1> to select the PHY ?
> 
> I am not following this. The driver handles just one PHY. Each PHY
> should have its own node.

Looking at the registers, it seems that the different PHYs are
intertwined and we would could have trouble handling the different PHYs
with different DT nodes and thus struct device instances.

> > > +
> > > +maintainers:
> > > +  - Helen Koike <helen.koike@collabora.com>
> > > +  - Ezequiel Garcia <ezequiel@collabora.com>
> > > +
> > > +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
> > > +
> > > +  reg:
> > > +    maxItems: 1
> > > +
> > > +  clocks:
> > > +    items:
> > > +      - description: Mipi d-phy ref clock
> > > +      - description: Mipi d-phy rx0 cfg clock
> > 
> > s/Mipi d-phy/MIPI D-PHY/
> 
> Yep.
> 
> > > +      - 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 RX D-PHY use registers in "general register files", it
> > > +     * should be a child of the GRF.
> > > +     *
> > > +     * grf: syscon@ff770000 {
> > > +     *  compatible = "rockchip,rk3399-grf", "syscon", "simple-mfd";
> > > +     *  ...
> > 
> > missing
> > 
> > 	* };
> 
> OK.
> 
> > > +     */
> > > +
> > > +    #include <dt-bindings/clock/rk3399-cru.h>
> > > +    #include <dt-bindings/power/rk3399-power.h>
> > > +
> > > +    dphy: mipi-dphy {
> > > +        compatible = "rockchip,rk3399-mipi-dphy";
> > > +        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>;
> > > +    };

-- 
Regards,

Laurent Pinchart

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v12 09/11] media: staging: dt-bindings: add Rockchip MIPI RX D-PHY yaml bindings
  2020-01-07  2:37       ` Laurent Pinchart
@ 2020-01-07  9:28         ` Heiko Stübner
  2020-01-07 13:20           ` Ezequiel Garcia
  0 siblings, 1 reply; 35+ messages in thread
From: Heiko Stübner @ 2020-01-07  9:28 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: mark.rutland, devicetree, eddie.cai.linux, kernel, gregkh,
	andrey.konovalov, linux-kernel, tfiga, linux-rockchip,
	Helen Koike, robh+dt, hans.verkuil, linux-arm-kernel,
	sakari.ailus, joacim.zetterling, mchehab, Ezequiel Garcia,
	jacob-chen, linux-media

Am Dienstag, 7. Januar 2020, 03:37:21 CET schrieb Laurent Pinchart:
> On Mon, Jan 06, 2020 at 11:06:12PM -0300, Ezequiel Garcia wrote:
> > On Tue, 2020-01-07 at 02:10 +0200, Laurent Pinchart wrote:
> > > Hi Helen,
> > > 
> > > Thank you for the patch.
> > > 
> > > On Fri, Dec 27, 2019 at 05:01:14PM -0300, Helen Koike wrote:
> > > > Add yaml DT bindings for Rockchip MIPI D-PHY RX
> > > > 
> > > > This was tested and verified with:
> > > > mv drivers/staging/media/phy-rockchip-dphy/Documentation/devicetree/bindings/phy/rockchip-mipi-dphy.yaml  Documentation/devicetree/bindings/phy/
> > > > make dt_binding_check DT_SCHEMA_FILES=Documentation/devicetree/bindings/phy/rockchip-mipi-dphy.yaml
> > > > make dtbs_check DT_SCHEMA_FILES=Documentation/devicetree/bindings/phy/rockchip-mipi-dphy.yaml
> > > > 
> > > > Signed-off-by: Helen Koike <helen.koike@collabora.com>
> > > > 
> > > > ---
> > > > 
> > > > 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.yaml      | 75 +++++++++++++++++++
> > > >  1 file changed, 75 insertions(+)
> > > >  create mode 100644 drivers/staging/media/phy-rockchip-dphy/Documentation/devicetree/bindings/phy/rockchip-mipi-dphy.yaml
> > > > 
> > > > diff --git a/drivers/staging/media/phy-rockchip-dphy/Documentation/devicetree/bindings/phy/rockchip-mipi-dphy.yaml b/drivers/staging/media/phy-
> > > > rockchip-dphy/Documentation/devicetree/bindings/phy/rockchip-mipi-dphy.yaml
> > > > new file mode 100644
> > > > index 000000000000..af97f1b3e005
> > > > --- /dev/null
> > > > +++ b/drivers/staging/media/phy-rockchip-dphy/Documentation/devicetree/bindings/phy/rockchip-mipi-dphy.yaml
> > > > @@ -0,0 +1,75 @@
> > > > +# SPDX-License-Identifier: (GPL-2.0+ OR MIT)
> > > > +%YAML 1.2
> > > > +---
> > > > +$id: http://devicetree.org/schemas/phy/rockchip-mipi-dphy.yaml#
> > > > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > > > +
> > > > +title: Rockchip SoC MIPI RX0 D-PHY Device Tree Bindings
> > > 
> > > Should this be s/RX0/RX/ ? Or do you expect different bindings for RX1 ?
> > 
> > The driver currently only supports RX0, but I think you are right,
> > it should say RX here. This binding could be extended for RX1.
> > 
> > > Looking at the PHY driver, it seems to handle all PHYs with a single
> > > struct device. Should we thus use #phy-cells = <1> to select the PHY ?
> > 
> > I am not following this. The driver handles just one PHY. Each PHY
> > should have its own node.
> 
> Looking at the registers, it seems that the different PHYs are
> intertwined and we would could have trouble handling the different PHYs
> with different DT nodes and thus struct device instances.

I have to confess to not following _ALL_ of the threads, so may say
something stupid, but I don't think the PHYs are intertwined so much.

Where RX0 is controlled from the "General Register Files" alone
[register dumping ground for soc designers], the TX1RX1-phy
actually gets controlled from inside the dsi1 register area it seems.

So in my previous (still unsucessful) tests, I was rolling with something like
https://github.com/mmind/linux-rockchip/commit/e0d4b03976d2aab85a8c1630be937ea003b5df88

With the actual "logic" picked from the vendor kernel, that just double-
maps the dsi1-registers in both dsi and dphy driver, which was strange.


Heiko



_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v12 09/11] media: staging: dt-bindings: add Rockchip MIPI RX D-PHY yaml bindings
  2020-01-07  9:28         ` Heiko Stübner
@ 2020-01-07 13:20           ` Ezequiel Garcia
  2020-01-07 21:30             ` Heiko Stübner
  0 siblings, 1 reply; 35+ messages in thread
From: Ezequiel Garcia @ 2020-01-07 13:20 UTC (permalink / raw)
  To: Heiko Stübner, Laurent Pinchart
  Cc: mark.rutland, devicetree, eddie.cai.linux, kernel, gregkh,
	linux-kernel, tfiga, linux-rockchip, Helen Koike, robh+dt,
	hans.verkuil, linux-arm-kernel, sakari.ailus, joacim.zetterling,
	mchehab, andrey.konovalov, jacob-chen, linux-media

Hi Heiko, Laurent,

On Tue, 2020-01-07 at 10:28 +0100, Heiko Stübner wrote:
> Am Dienstag, 7. Januar 2020, 03:37:21 CET schrieb Laurent Pinchart:
> > On Mon, Jan 06, 2020 at 11:06:12PM -0300, Ezequiel Garcia wrote:
> > > On Tue, 2020-01-07 at 02:10 +0200, Laurent Pinchart wrote:
> > > > Hi Helen,
> > > > 
> > > > Thank you for the patch.
> > > > 
> > > > On Fri, Dec 27, 2019 at 05:01:14PM -0300, Helen Koike wrote:
> > > > > Add yaml DT bindings for Rockchip MIPI D-PHY RX
> > > > > 
> > > > > This was tested and verified with:
> > > > > mv drivers/staging/media/phy-rockchip-dphy/Documentation/devicetree/bindings/phy/rockchip-mipi-
> > > > > dphy.yaml  Documentation/devicetree/bindings/phy/
> > > > > make dt_binding_check DT_SCHEMA_FILES=Documentation/devicetree/bindings/phy/rockchip-mipi-dphy.yaml
> > > > > make dtbs_check DT_SCHEMA_FILES=Documentation/devicetree/bindings/phy/rockchip-mipi-dphy.yaml
> > > > > 
> > > > > Signed-off-by: Helen Koike <helen.koike@collabora.com>
> > > > > 
> > > > > ---
> > > > > 
> > > > > 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.yaml      | 75 +++++++++++++++++++
> > > > >  1 file changed, 75 insertions(+)
> > > > >  create mode 100644 drivers/staging/media/phy-rockchip-dphy/Documentation/devicetree/bindings/phy/rockchip-mipi-dphy.yaml
> > > > > 
> > > > > diff --git a/drivers/staging/media/phy-rockchip-dphy/Documentation/devicetree/bindings/phy/rockchip-mipi-dphy.yaml
> > > > > b/drivers/staging/media/phy-
> > > > > rockchip-dphy/Documentation/devicetree/bindings/phy/rockchip-mipi-dphy.yaml
> > > > > new file mode 100644
> > > > > index 000000000000..af97f1b3e005
> > > > > --- /dev/null
> > > > > +++ b/drivers/staging/media/phy-rockchip-dphy/Documentation/devicetree/bindings/phy/rockchip-mipi-dphy.yaml
> > > > > @@ -0,0 +1,75 @@
> > > > > +# SPDX-License-Identifier: (GPL-2.0+ OR MIT)
> > > > > +%YAML 1.2
> > > > > +---
> > > > > +$id: http://devicetree.org/schemas/phy/rockchip-mipi-dphy.yaml#
> > > > > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > > > > +
> > > > > +title: Rockchip SoC MIPI RX0 D-PHY Device Tree Bindings
> > > > 
> > > > Should this be s/RX0/RX/ ? Or do you expect different bindings for RX1 ?
> > > 
> > > The driver currently only supports RX0, but I think you are right,
> > > it should say RX here. This binding could be extended for RX1.
> > > 
> > > > Looking at the PHY driver, it seems to handle all PHYs with a single
> > > > struct device. Should we thus use #phy-cells = <1> to select the PHY ?
> > > 
> > > I am not following this. The driver handles just one PHY. Each PHY
> > > should have its own node.
> > 
> > Looking at the registers, it seems that the different PHYs are
> > intertwined and we would could have trouble handling the different PHYs
> > with different DT nodes and thus struct device instances.
> 
> I have to confess to not following _ALL_ of the threads, so may say
> something stupid, but I don't think the PHYs are intertwined so much.
> 
> Where RX0 is controlled from the "General Register Files" alone
> [register dumping ground for soc designers], the TX1RX1-phy
> actually gets controlled from inside the dsi1 register area it seems.
> 
> So in my previous (still unsucessful) tests, I was rolling with something like
> https://github.com/mmind/linux-rockchip/commit/e0d4b03976d2aab85a8c1630be937ea003b5df88
> 
> With the actual "logic" picked from the vendor kernel, that just double-
> maps the dsi1-registers in both dsi and dphy driver, which was strange.
> 
> 

Describing each PHY in its own device node (as we currently do)
results in:

        mipi_dphy_tx1rx1: mipi-dphy-tx1rx1@ff968000 {
                compatible = "rockchip,rk3399-mipi-dphy";
                reg = <0x0 0xff968000 0x0 0x8000>;
                rockchip,grf = <&grf>;
        };

        grf: syscon@ff770000 {
                mipi_dphy_rx0: mipi-dphy-rx0 {
                        compatible = "rockchip,rk3399-mipi-dphy";
                };
        };

Which is mildly ugly, as it uses two mechanism to describe
the GRF resource. In addition, the driver will then _infer_
which device node is RX0 and which is TX1RX1, from this.

Perhaps Laurent's proposal, describing each PHY explicitly,
would be cleaner?

Thanks,
Ezequiel




_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v12 08/11] media: staging: dt-bindings: add Rockchip ISP1 yaml bindings
  2020-01-06 23:59   ` Laurent Pinchart
@ 2020-01-07 13:45     ` Ezequiel Garcia
  2020-01-07 16:19       ` Laurent Pinchart
  0 siblings, 1 reply; 35+ messages in thread
From: Ezequiel Garcia @ 2020-01-07 13:45 UTC (permalink / raw)
  To: Laurent Pinchart, Helen Koike
  Cc: mark.rutland, devicetree, eddie.cai.linux, kernel, heiko, gregkh,
	linux-kernel, tfiga, linux-rockchip, robh+dt, hans.verkuil,
	linux-arm-kernel, sakari.ailus, joacim.zetterling, mchehab,
	andrey.konovalov, jacob-chen, linux-media

On Tue, 2020-01-07 at 01:59 +0200, Laurent Pinchart wrote:
> Hi Helen,
> 
> Thank you for the patch.
> 
> On Fri, Dec 27, 2019 at 05:01:13PM -0300, Helen Koike wrote:
> > 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 <helen.koike@collabora.com>
> > 
> > ---
> > 
> > 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         | 193 ++++++++++++++++++
> >  1 file changed, 193 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..4d1b2c67a4cd
> > --- /dev/null
> > +++ b/drivers/staging/media/rkisp1/Documentation/devicetree/bindings/media/rockchip-isp1.yaml
> > @@ -0,0 +1,193 @@
> > +# 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 <helen.koike@collabora.com>
> > +
> > +description: |
> > +  Rockchip ISP1 is the Camera interface for the Rockchip series of SoCs
> > +  which contains image processing, scaling, and compression funcitons.
> > +
> > +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
> 
> According to http://opensource.rock-chips.com/wiki_Camera_driver, RK3388
> can route either of DPHY RX0 or DPHY RX1 to the single ISP instance,
> while RK3399 has one PHY per ISP instance, with DPHY RX1 being shared
> with the display. Have you given any thought on how we will support this
> in a backward-compatible way in the DT bindings ?
> 

As discussed on IRC, we could have multiple PHYs specifiers
in the phy property. The ISP would have multiple ports,
with one PHY per port.

> > +
> > +  phy-names:
> > +    const: dphy
> > +
> > +  clocks:
> > +    items:
> > +      - description: ISP clock
> > +      - description: ISP aclk clock
> > +      - description: ISP aclk wrapper clock
> > +      - description: ISP hclk clock
> > +      - description: ISP hclk wrapper clock
> 
> I wonder what aclk and hclk stand far. In any case those names match the
> CRU documentation, so that seems fine.
> 

IIRC, traditionally, Rockchip calls aclk to the AXI clock,
and hclk to the AHB. We'll improve this description.

> > +
> > +  clock-names:
> > +    items:
> > +      - const: clk_isp
> > +      - const: aclk_isp
> > +      - const: aclk_isp_wrap
> > +      - const: hclk_isp
> > +      - const: hclk_isp_wrap
> > +

I wonder if we should better amend the names as well.

> > +  # See ./video-interfaces.txt for details
> > +  ports:
> > +    type: object
> > +    additionalProperties: false
> > +
> > +    properties:
> > +      "#address-cells":
> > +        const: 1
> > +
> > +      "#size-cells":
> > +        const: 0
> > +
> > +      port@0:
> > +        type: object
> > +        additionalProperties: false
> 
> I think this should have a description to tell what this port
> corresponds to.
> 

OK.

> > +
> > +        properties:
> > +          "#address-cells":
> > +            const: 1
> > +
> > +          "#size-cells":
> > +            const: 0
> > +
> > +          reg:
> > +            const: 0
> > +            description: port identifier.
> 
> Here and for the endpoint below the description is probably not needed.
> 

OK.

> > +
> > +        patternProperties:
> > +          endpoint:
> > +            type: object
> > +            additionalProperties: false
> > +
> > +            properties:
> > +              reg:
> > +                maxItems: 1
> > +                description: endpoint identifier.
> > +
> > +              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 <dt-bindings/clock/rk3399-cru.h>
> > +    #include <dt-bindings/interrupt-controller/arm-gic.h>
> > +    #include <dt-bindings/power/rk3399-power.h>
> > +
> > +    parent0: parent@0 {
> > +        #address-cells = <2>;
> > +        #size-cells = <2>;
> > +
> > +        isp0: isp0@ff910000 {
> > +            compatible = "rockchip,rk3399-cif-isp";
> > +            reg = <0x0 0xff910000 0x0 0x4000>;
> > +            interrupts = <GIC_SPI 43 IRQ_TYPE_LEVEL_HIGH 0>;
> > +            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>;
> > +                    };
> 
> Are those two cameras connected to the same CSI-2 lines with at most one
> sensor out of reset ?
> 

Indeed, these are two cameras connected to the same DPHY,
and only one can work at a time.

> With the above small issues addressed,
> 
> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> 

Thanks for the review!
Ezequiel


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v12 08/11] media: staging: dt-bindings: add Rockchip ISP1 yaml bindings
  2019-12-27 20:01 ` [PATCH v12 08/11] media: staging: dt-bindings: add Rockchip ISP1 yaml bindings Helen Koike
  2020-01-06 22:27   ` Rob Herring
  2020-01-06 23:59   ` Laurent Pinchart
@ 2020-01-07 14:01   ` Sakari Ailus
  2020-01-08 16:50     ` Helen Koike
  2 siblings, 1 reply; 35+ messages in thread
From: Sakari Ailus @ 2020-01-07 14:01 UTC (permalink / raw)
  To: Helen Koike
  Cc: mark.rutland, devicetree, eddie.cai.linux, kernel, heiko,
	linux-arm-kernel, ezequiel, gregkh, linux-kernel, tfiga,
	linux-rockchip, robh+dt, hans.verkuil, laurent.pinchart,
	joacim.zetterling, mchehab, andrey.konovalov, jacob-chen,
	linux-media

Hi Helen,

On Fri, Dec 27, 2019 at 05:01:13PM -0300, Helen Koike wrote:
> 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 <helen.koike@collabora.com>
> 
> ---
> 
> 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         | 193 ++++++++++++++++++
>  1 file changed, 193 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..4d1b2c67a4cd
> --- /dev/null
> +++ b/drivers/staging/media/rkisp1/Documentation/devicetree/bindings/media/rockchip-isp1.yaml
> @@ -0,0 +1,193 @@
> +# 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 <helen.koike@collabora.com>
> +
> +description: |
> +  Rockchip ISP1 is the Camera interface for the Rockchip series of SoCs
> +  which contains image processing, scaling, and compression funcitons.

"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 aclk clock
> +      - description: ISP aclk wrapper clock
> +      - description: ISP hclk clock
> +      - description: ISP hclk 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:

If you only have a single port node, you could drop reg as well as @0 on
the port node.

> +        type: object
> +        additionalProperties: false
> +
> +        properties:
> +          "#address-cells":
> +            const: 1
> +
> +          "#size-cells":
> +            const: 0
> +
> +          reg:
> +            const: 0
> +            description: port identifier.
> +
> +        patternProperties:
> +          endpoint:
> +            type: object
> +            additionalProperties: false
> +
> +            properties:
> +              reg:
> +                maxItems: 1
> +                description: endpoint identifier.
> +
> +              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 <dt-bindings/clock/rk3399-cru.h>
> +    #include <dt-bindings/interrupt-controller/arm-gic.h>
> +    #include <dt-bindings/power/rk3399-power.h>
> +
> +    parent0: parent@0 {
> +        #address-cells = <2>;
> +        #size-cells = <2>;
> +
> +        isp0: isp0@ff910000 {
> +            compatible = "rockchip,rk3399-cif-isp";
> +            reg = <0x0 0xff910000 0x0 0x4000>;
> +            interrupts = <GIC_SPI 43 IRQ_TYPE_LEVEL_HIGH 0>;
> +            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>;
> +                      };
> +                  };
> +            };
> +        };
> +    };

-- 
Kind regards,

Sakari Ailus

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v12 01/11] media: staging: phy-rockchip-dphy: add Rockchip MIPI Synopsys DPHY driver
  2020-01-07  1:11   ` Laurent Pinchart
@ 2020-01-07 15:58     ` Ezequiel Garcia
  2020-01-07 16:18       ` Laurent Pinchart
  0 siblings, 1 reply; 35+ messages in thread
From: Ezequiel Garcia @ 2020-01-07 15:58 UTC (permalink / raw)
  To: Laurent Pinchart, Helen Koike
  Cc: mark.rutland, devicetree, eddie.cai.linux, kernel, heiko, gregkh,
	linux-kernel, tfiga, linux-rockchip, robh+dt, hans.verkuil,
	linux-arm-kernel, sakari.ailus, joacim.zetterling, mchehab,
	andrey.konovalov, jacob-chen, linux-media

On Tue, 2020-01-07 at 03:11 +0200, Laurent Pinchart wrote:
> Hi Helen and Ezequiel,
> 
> Thank you for the patch.
> 
> On Fri, Dec 27, 2019 at 05:01:06PM -0300, Helen Koike wrote:
> > From: Ezequiel Garcia <ezequiel@collabora.com>
> > 
> > Add driver for Rockchip MIPI Synopsys DPHY driver
> > 
> > Signed-off-by: Tomasz Figa <tfiga@chromium.org>
> > Signed-off-by: Ezequiel Garcia <ezequiel@collabora.com>
> > Signed-off-by: Helen Koike <helen.koike@collabora.com>
> > 
> > ---
> > 
> > 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 +
> >  .../staging/media/phy-rockchip-dphy/Kconfig   |  11 +
> >  .../staging/media/phy-rockchip-dphy/Makefile  |   2 +
> >  drivers/staging/media/phy-rockchip-dphy/TODO  |   6 +
> >  .../phy-rockchip-dphy/phy-rockchip-dphy.c     | 396 ++++++++++++++++++
> >  6 files changed, 418 insertions(+)
> >  create mode 100644 drivers/staging/media/phy-rockchip-dphy/Kconfig
> >  create mode 100644 drivers/staging/media/phy-rockchip-dphy/Makefile
> >  create mode 100644 drivers/staging/media/phy-rockchip-dphy/TODO
> >  create mode 100644 drivers/staging/media/phy-rockchip-dphy/phy-rockchip-dphy.c
> > 
> > diff --git a/drivers/staging/media/Kconfig b/drivers/staging/media/Kconfig
> > index 642adc4c24d2..a47484473883 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/Kconfig"
> > +
> >  endif
> > diff --git a/drivers/staging/media/Makefile b/drivers/staging/media/Makefile
> > index 2f1711a8aeed..b0eae3906208 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)		+= phy-rockchip-dphy/
> > diff --git a/drivers/staging/media/phy-rockchip-dphy/Kconfig b/drivers/staging/media/phy-rockchip-dphy/Kconfig
> > new file mode 100644
> > index 000000000000..7378bd75fa7c
> > --- /dev/null
> > +++ b/drivers/staging/media/phy-rockchip-dphy/Kconfig
> > @@ -0,0 +1,11 @@
> > +# SPDX-License-Identifier: GPL-2.0-only
> > +#
> > +# Phy drivers for Rockchip platforms
> 
> s/Phy/MIPI D-PHY/
> 

Ack.

> > +#
> > +config PHY_ROCKCHIP_DPHY
> > +	tristate "Rockchip MIPI Synopsys DPHY 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.
> > diff --git a/drivers/staging/media/phy-rockchip-dphy/Makefile b/drivers/staging/media/phy-rockchip-dphy/Makefile
> > new file mode 100644
> > index 000000000000..24679dc950cd
> > --- /dev/null
> > +++ b/drivers/staging/media/phy-rockchip-dphy/Makefile
> > @@ -0,0 +1,2 @@
> > +# SPDX-License-Identifier: GPL-2.0
> > +obj-$(CONFIG_PHY_ROCKCHIP_DPHY)		+= phy-rockchip-dphy.o
> > diff --git a/drivers/staging/media/phy-rockchip-dphy/TODO b/drivers/staging/media/phy-rockchip-dphy/TODO
> > new file mode 100644
> > index 000000000000..e1fda55babef
> > --- /dev/null
> > +++ b/drivers/staging/media/phy-rockchip-dphy/TODO
> > @@ -0,0 +1,6 @@
> > +The major reason for keeping this in staging is because the only driver
> 
> s/major/main/
> 

What's wrong with "The major reason"?

> > +who uses this is rkisp1 who is also in staging. It should be moved together
> 
> s/who uses this/that uses this/
> s/who is also/, which is also/
> 
> > +rkisp1.
> 
> s/rkisp1/with rkisp1/ ?
> 

I see your point. Let me rephrase it.

> > +
> > +Please CC patches to Linux Media <linux-media@vger.kernel.org> and
> > +Helen Koike <helen.koike@collabora.com>.
> > diff --git a/drivers/staging/media/phy-rockchip-dphy/phy-rockchip-dphy.c b/drivers/staging/media/phy-rockchip-dphy/phy-rockchip-dphy.c
> > new file mode 100644
> > index 000000000000..c3fe9c64b45f
> > --- /dev/null
> > +++ b/drivers/staging/media/phy-rockchip-dphy/phy-rockchip-dphy.c
> > @@ -0,0 +1,396 @@
> > +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
> 
> Any reason for this ? Kernel code is usually GPL-2.0.
> 

The ChromeOS driver is originally dual licensed,
so we tried to respect that.

> > +/*
> > + * Rockchip MIPI Synopsys DPHY 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 <jacob2.chen@rock-chips.com>
> > + *   Shunqian Zheng <zhengsq@rock-chips.com>
> > + */
> > +
> > +#include <linux/clk.h>
> > +#include <linux/io.h>
> > +#include <linux/mfd/syscon.h>
> > +#include <linux/module.h>
> > +#include <linux/of.h>
> > +#include <linux/of_device.h>
> > +#include <linux/phy/phy.h>
> > +#include <linux/phy/phy-mipi-dphy.h>
> > +#include <linux/platform_device.h>
> > +#include <linux/regmap.h>
> > +
> > +#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));
> > +
> > +	WARN_ON(!reg->offset);
> 
> Maybe
> 
> 	if (WARN_ON(!reg->offset))
> 		return;
> 

Right.

> > +	regmap_write(priv->grf, reg->offset, val);
> > +}
> > +
> > +static void rk_dphy_write(struct rk_dphy *priv,
> > +			  u8 test_code, u8 test_data)
> > +{
> > +	/*
> > +	 * 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.
> > +	 */
> > +	rk_dphy_write_grf(priv, GRF_DPHY_RX0_TESTCLK, 1);
> 
> Do we need this first line, as the function always exits with TESTCLK=1,
> and TESTCLK is initialized to 1 before calling rk_dphy_write for the
> first time ?
> 

You might be right.

Perhaps we can test if it's fine to drop it, and put a comment
saying TESTCLK must be =1 here, so the assumption is clearly
stated.

> > +	rk_dphy_write_grf(priv, GRF_DPHY_RX0_TESTDIN, test_code);
> > +	rk_dphy_write_grf(priv, GRF_DPHY_RX0_TESTEN, 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 i, hsfreq = 0, data_rate_mbps = config->hs_clk_rate;
> 
> Maybe one variable per line ?
> 

Yeah.

> > +	int ret;
> > +
> > +	/* pass with phy_mipi_dphy_get_default_config (with pixel rate?) */
> > +	ret = phy_mipi_dphy_config_validate(config);
> > +	if (ret)
> > +		return ret;
> 
> I would add a blank line here.
> 
> > +	do_div(data_rate_mbps, 1000 * 1000);
> 
> data_rate_mbps is an unsigned int, so you can use
> 
> 	data_rate_mbps /= 1000 * 1000;
> 
> However, you're potentially truncating hs_clk_rate by assigning it to
> data_rate_mbps, so I would remove the assignment at declaration time and
> do
> 
> 	data_rate_mbps = div_u64(config->hs_clk_rate, 1000 * 1000);
> 
> or define data_rate_mbps as an unsigned long.
> 

Ah, good catch.

> > +
> > +	dev_dbg(priv->dev, "lanes %d - data_rate_mbps %u\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",
> > +		.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 regmap *grf;
> > +	struct phy *phy;
> > +	unsigned int i;
> > +	int ret;
> > +
> > +	if (!dev->parent || !dev->parent->of_node)
> > +		return -ENODEV;
> > +
> > +	if (platform_get_resource(pdev, IORESOURCE_MEM, 0)) {
> > +		dev_err(dev, "Rockchip DPHY driver only suports RX mode\n");
> > +		return -EINVAL;
> > +	}
> > +
> > +	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> > +	if (!priv)
> > +		return -ENOMEM;
> > +	priv->dev = dev;
> > +
> > +	grf = syscon_node_to_regmap(dev->parent->of_node);
> > +	if (IS_ERR(grf)) {
> > +		grf = syscon_regmap_lookup_by_phandle(dev->of_node,
> > +						      "rockchip,grf");
> 
> Is this for backward compatibility with older bindings ? Do we still
> need it ? If so I would add a comment to explain why.
> 

Right. I think this might end up being required, depending
on how the bindings end up loooking like.

> With the above small issues fixed,
> 
> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> 

Thanks,
Ezequiel


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v12 01/11] media: staging: phy-rockchip-dphy: add Rockchip MIPI Synopsys DPHY driver
  2020-01-07 15:58     ` Ezequiel Garcia
@ 2020-01-07 16:18       ` Laurent Pinchart
  0 siblings, 0 replies; 35+ messages in thread
From: Laurent Pinchart @ 2020-01-07 16:18 UTC (permalink / raw)
  To: Ezequiel Garcia
  Cc: mark.rutland, devicetree, eddie.cai.linux, kernel, heiko, gregkh,
	linux-kernel, tfiga, linux-rockchip, Helen Koike, robh+dt,
	hans.verkuil, linux-arm-kernel, sakari.ailus, joacim.zetterling,
	mchehab, andrey.konovalov, jacob-chen, linux-media

Hi Ezequiel,

On Tue, Jan 07, 2020 at 12:58:21PM -0300, Ezequiel Garcia wrote:
> On Tue, 2020-01-07 at 03:11 +0200, Laurent Pinchart wrote:
> > On Fri, Dec 27, 2019 at 05:01:06PM -0300, Helen Koike wrote:
> > > From: Ezequiel Garcia <ezequiel@collabora.com>
> > > 
> > > Add driver for Rockchip MIPI Synopsys DPHY driver
> > > 
> > > Signed-off-by: Tomasz Figa <tfiga@chromium.org>
> > > Signed-off-by: Ezequiel Garcia <ezequiel@collabora.com>
> > > Signed-off-by: Helen Koike <helen.koike@collabora.com>
> > > 
> > > ---
> > > 
> > > 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 +
> > >  .../staging/media/phy-rockchip-dphy/Kconfig   |  11 +
> > >  .../staging/media/phy-rockchip-dphy/Makefile  |   2 +
> > >  drivers/staging/media/phy-rockchip-dphy/TODO  |   6 +
> > >  .../phy-rockchip-dphy/phy-rockchip-dphy.c     | 396 ++++++++++++++++++
> > >  6 files changed, 418 insertions(+)
> > >  create mode 100644 drivers/staging/media/phy-rockchip-dphy/Kconfig
> > >  create mode 100644 drivers/staging/media/phy-rockchip-dphy/Makefile
> > >  create mode 100644 drivers/staging/media/phy-rockchip-dphy/TODO
> > >  create mode 100644 drivers/staging/media/phy-rockchip-dphy/phy-rockchip-dphy.c
> > > 
> > > diff --git a/drivers/staging/media/Kconfig b/drivers/staging/media/Kconfig
> > > index 642adc4c24d2..a47484473883 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/Kconfig"
> > > +
> > >  endif
> > > diff --git a/drivers/staging/media/Makefile b/drivers/staging/media/Makefile
> > > index 2f1711a8aeed..b0eae3906208 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)		+= phy-rockchip-dphy/
> > > diff --git a/drivers/staging/media/phy-rockchip-dphy/Kconfig b/drivers/staging/media/phy-rockchip-dphy/Kconfig
> > > new file mode 100644
> > > index 000000000000..7378bd75fa7c
> > > --- /dev/null
> > > +++ b/drivers/staging/media/phy-rockchip-dphy/Kconfig
> > > @@ -0,0 +1,11 @@
> > > +# SPDX-License-Identifier: GPL-2.0-only
> > > +#
> > > +# Phy drivers for Rockchip platforms
> > 
> > s/Phy/MIPI D-PHY/
> 
> Ack.
> 
> > > +#
> > > +config PHY_ROCKCHIP_DPHY
> > > +	tristate "Rockchip MIPI Synopsys DPHY 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.
> > > diff --git a/drivers/staging/media/phy-rockchip-dphy/Makefile b/drivers/staging/media/phy-rockchip-dphy/Makefile
> > > new file mode 100644
> > > index 000000000000..24679dc950cd
> > > --- /dev/null
> > > +++ b/drivers/staging/media/phy-rockchip-dphy/Makefile
> > > @@ -0,0 +1,2 @@
> > > +# SPDX-License-Identifier: GPL-2.0
> > > +obj-$(CONFIG_PHY_ROCKCHIP_DPHY)		+= phy-rockchip-dphy.o
> > > diff --git a/drivers/staging/media/phy-rockchip-dphy/TODO b/drivers/staging/media/phy-rockchip-dphy/TODO
> > > new file mode 100644
> > > index 000000000000..e1fda55babef
> > > --- /dev/null
> > > +++ b/drivers/staging/media/phy-rockchip-dphy/TODO
> > > @@ -0,0 +1,6 @@
> > > +The major reason for keeping this in staging is because the only driver
> > 
> > s/major/main/
> 
> What's wrong with "The major reason"?

I was under the impression you could say "A major reason" but not "The
major reason", but I could be wrong.

> > > +who uses this is rkisp1 who is also in staging. It should be moved together
> > 
> > s/who uses this/that uses this/
> > s/who is also/, which is also/
> > 
> > > +rkisp1.
> > 
> > s/rkisp1/with rkisp1/ ?
> 
> I see your point. Let me rephrase it.
> 
> > > +
> > > +Please CC patches to Linux Media <linux-media@vger.kernel.org> and
> > > +Helen Koike <helen.koike@collabora.com>.
> > > diff --git a/drivers/staging/media/phy-rockchip-dphy/phy-rockchip-dphy.c b/drivers/staging/media/phy-rockchip-dphy/phy-rockchip-dphy.c
> > > new file mode 100644
> > > index 000000000000..c3fe9c64b45f
> > > --- /dev/null
> > > +++ b/drivers/staging/media/phy-rockchip-dphy/phy-rockchip-dphy.c
> > > @@ -0,0 +1,396 @@
> > > +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
> > 
> > Any reason for this ? Kernel code is usually GPL-2.0.
> 
> The ChromeOS driver is originally dual licensed,
> so we tried to respect that.

That's up to you, but you can pick any license you want as long as it's
compatible with the original license. GPL-2.0 is a subset of GPL-2.0+ OR
MIT, so it would be fine. Of course you can't enforce a !MIT restriction
on the original code as you're not the copyright holder :-) But it may
make future contributions easier, as many people expect kernel code to
be licensed under GPL only. Furthermore the kernel binary compiled with
this driver included would have to be GPL-licensed anyway, so it's not
very useful to add a OR MIT.

> > > +/*
> > > + * Rockchip MIPI Synopsys DPHY 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 <jacob2.chen@rock-chips.com>
> > > + *   Shunqian Zheng <zhengsq@rock-chips.com>
> > > + */
> > > +
> > > +#include <linux/clk.h>
> > > +#include <linux/io.h>
> > > +#include <linux/mfd/syscon.h>
> > > +#include <linux/module.h>
> > > +#include <linux/of.h>
> > > +#include <linux/of_device.h>
> > > +#include <linux/phy/phy.h>
> > > +#include <linux/phy/phy-mipi-dphy.h>
> > > +#include <linux/platform_device.h>
> > > +#include <linux/regmap.h>
> > > +
> > > +#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));
> > > +
> > > +	WARN_ON(!reg->offset);
> > 
> > Maybe
> > 
> > 	if (WARN_ON(!reg->offset))
> > 		return;
> 
> Right.
> 
> > > +	regmap_write(priv->grf, reg->offset, val);
> > > +}
> > > +
> > > +static void rk_dphy_write(struct rk_dphy *priv,
> > > +			  u8 test_code, u8 test_data)
> > > +{
> > > +	/*
> > > +	 * 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.
> > > +	 */
> > > +	rk_dphy_write_grf(priv, GRF_DPHY_RX0_TESTCLK, 1);
> > 
> > Do we need this first line, as the function always exits with TESTCLK=1,
> > and TESTCLK is initialized to 1 before calling rk_dphy_write for the
> > first time ?
> 
> You might be right.
> 
> Perhaps we can test if it's fine to drop it, and put a comment
> saying TESTCLK must be =1 here, so the assumption is clearly
> stated.

Sounds good to me.

> > > +	rk_dphy_write_grf(priv, GRF_DPHY_RX0_TESTDIN, test_code);
> > > +	rk_dphy_write_grf(priv, GRF_DPHY_RX0_TESTEN, 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 i, hsfreq = 0, data_rate_mbps = config->hs_clk_rate;
> > 
> > Maybe one variable per line ?
> 
> Yeah.
> 
> > > +	int ret;
> > > +
> > > +	/* pass with phy_mipi_dphy_get_default_config (with pixel rate?) */
> > > +	ret = phy_mipi_dphy_config_validate(config);
> > > +	if (ret)
> > > +		return ret;
> > 
> > I would add a blank line here.
> > 
> > > +	do_div(data_rate_mbps, 1000 * 1000);
> > 
> > data_rate_mbps is an unsigned int, so you can use
> > 
> > 	data_rate_mbps /= 1000 * 1000;
> > 
> > However, you're potentially truncating hs_clk_rate by assigning it to
> > data_rate_mbps, so I would remove the assignment at declaration time and
> > do
> > 
> > 	data_rate_mbps = div_u64(config->hs_clk_rate, 1000 * 1000);
> > 
> > or define data_rate_mbps as an unsigned long.
> 
> Ah, good catch.
> 
> > > +
> > > +	dev_dbg(priv->dev, "lanes %d - data_rate_mbps %u\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",
> > > +		.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 regmap *grf;
> > > +	struct phy *phy;
> > > +	unsigned int i;
> > > +	int ret;
> > > +
> > > +	if (!dev->parent || !dev->parent->of_node)
> > > +		return -ENODEV;
> > > +
> > > +	if (platform_get_resource(pdev, IORESOURCE_MEM, 0)) {
> > > +		dev_err(dev, "Rockchip DPHY driver only suports RX mode\n");
> > > +		return -EINVAL;
> > > +	}
> > > +
> > > +	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> > > +	if (!priv)
> > > +		return -ENOMEM;
> > > +	priv->dev = dev;
> > > +
> > > +	grf = syscon_node_to_regmap(dev->parent->of_node);
> > > +	if (IS_ERR(grf)) {
> > > +		grf = syscon_regmap_lookup_by_phandle(dev->of_node,
> > > +						      "rockchip,grf");
> > 
> > Is this for backward compatibility with older bindings ? Do we still
> > need it ? If so I would add a comment to explain why.
> 
> Right. I think this might end up being required, depending
> on how the bindings end up loooking like.
> 
> > With the above small issues fixed,
> > 
> > Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

-- 
Regards,

Laurent Pinchart

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v12 08/11] media: staging: dt-bindings: add Rockchip ISP1 yaml bindings
  2020-01-07 13:45     ` Ezequiel Garcia
@ 2020-01-07 16:19       ` Laurent Pinchart
  0 siblings, 0 replies; 35+ messages in thread
From: Laurent Pinchart @ 2020-01-07 16:19 UTC (permalink / raw)
  To: Ezequiel Garcia
  Cc: mark.rutland, devicetree, eddie.cai.linux, kernel, heiko, gregkh,
	linux-kernel, tfiga, linux-rockchip, Helen Koike, robh+dt,
	hans.verkuil, linux-arm-kernel, sakari.ailus, joacim.zetterling,
	mchehab, andrey.konovalov, jacob-chen, linux-media

Hi Ezequiel,

On Tue, Jan 07, 2020 at 10:45:15AM -0300, Ezequiel Garcia wrote:
> On Tue, 2020-01-07 at 01:59 +0200, Laurent Pinchart wrote:
> > On Fri, Dec 27, 2019 at 05:01:13PM -0300, Helen Koike wrote:
> > > 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 <helen.koike@collabora.com>
> > > 
> > > ---
> > > 
> > > 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         | 193 ++++++++++++++++++
> > >  1 file changed, 193 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..4d1b2c67a4cd
> > > --- /dev/null
> > > +++ b/drivers/staging/media/rkisp1/Documentation/devicetree/bindings/media/rockchip-isp1.yaml
> > > @@ -0,0 +1,193 @@
> > > +# 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 <helen.koike@collabora.com>
> > > +
> > > +description: |
> > > +  Rockchip ISP1 is the Camera interface for the Rockchip series of SoCs
> > > +  which contains image processing, scaling, and compression funcitons.
> > > +
> > > +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
> > 
> > According to http://opensource.rock-chips.com/wiki_Camera_driver, RK3388
> > can route either of DPHY RX0 or DPHY RX1 to the single ISP instance,
> > while RK3399 has one PHY per ISP instance, with DPHY RX1 being shared
> > with the display. Have you given any thought on how we will support this
> > in a backward-compatible way in the DT bindings ?
> 
> As discussed on IRC, we could have multiple PHYs specifiers
> in the phy property. The ISP would have multiple ports,
> with one PHY per port.
> 
> > > +
> > > +  phy-names:
> > > +    const: dphy
> > > +
> > > +  clocks:
> > > +    items:
> > > +      - description: ISP clock
> > > +      - description: ISP aclk clock
> > > +      - description: ISP aclk wrapper clock
> > > +      - description: ISP hclk clock
> > > +      - description: ISP hclk wrapper clock
> > 
> > I wonder what aclk and hclk stand far. In any case those names match the
> > CRU documentation, so that seems fine.
> 
> IIRC, traditionally, Rockchip calls aclk to the AXI clock,
> and hclk to the AHB. We'll improve this description.
> 
> > > +
> > > +  clock-names:
> > > +    items:
> > > +      - const: clk_isp
> > > +      - const: aclk_isp
> > > +      - const: aclk_isp_wrap
> > > +      - const: hclk_isp
> > > +      - const: hclk_isp_wrap
> > > +
> 
> I wonder if we should better amend the names as well.

We could, but they match the names in the CRU documentation, so I think
they're fine.

> > > +  # See ./video-interfaces.txt for details
> > > +  ports:
> > > +    type: object
> > > +    additionalProperties: false
> > > +
> > > +    properties:
> > > +      "#address-cells":
> > > +        const: 1
> > > +
> > > +      "#size-cells":
> > > +        const: 0
> > > +
> > > +      port@0:
> > > +        type: object
> > > +        additionalProperties: false
> > 
> > I think this should have a description to tell what this port
> > corresponds to.
> 
> OK.
> 
> > > +
> > > +        properties:
> > > +          "#address-cells":
> > > +            const: 1
> > > +
> > > +          "#size-cells":
> > > +            const: 0
> > > +
> > > +          reg:
> > > +            const: 0
> > > +            description: port identifier.
> > 
> > Here and for the endpoint below the description is probably not needed.
> 
> OK.
> 
> > > +
> > > +        patternProperties:
> > > +          endpoint:
> > > +            type: object
> > > +            additionalProperties: false
> > > +
> > > +            properties:
> > > +              reg:
> > > +                maxItems: 1
> > > +                description: endpoint identifier.
> > > +
> > > +              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 <dt-bindings/clock/rk3399-cru.h>
> > > +    #include <dt-bindings/interrupt-controller/arm-gic.h>
> > > +    #include <dt-bindings/power/rk3399-power.h>
> > > +
> > > +    parent0: parent@0 {
> > > +        #address-cells = <2>;
> > > +        #size-cells = <2>;
> > > +
> > > +        isp0: isp0@ff910000 {
> > > +            compatible = "rockchip,rk3399-cif-isp";
> > > +            reg = <0x0 0xff910000 0x0 0x4000>;
> > > +            interrupts = <GIC_SPI 43 IRQ_TYPE_LEVEL_HIGH 0>;
> > > +            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>;
> > > +                    };
> > 
> > Are those two cameras connected to the same CSI-2 lines with at most one
> > sensor out of reset ?
> 
> Indeed, these are two cameras connected to the same DPHY,
> and only one can work at a time.
> 
> > With the above small issues addressed,
> > 
> > Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

-- 
Regards,

Laurent Pinchart

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v12 09/11] media: staging: dt-bindings: add Rockchip MIPI RX D-PHY yaml bindings
  2020-01-07 13:20           ` Ezequiel Garcia
@ 2020-01-07 21:30             ` Heiko Stübner
  2020-01-07 21:57               ` Laurent Pinchart
  2020-01-07 22:03               ` Ezequiel Garcia
  0 siblings, 2 replies; 35+ messages in thread
From: Heiko Stübner @ 2020-01-07 21:30 UTC (permalink / raw)
  To: Ezequiel Garcia
  Cc: mark.rutland, devicetree, eddie.cai.linux, kernel,
	linux-arm-kernel, gregkh, linux-kernel, tfiga, linux-rockchip,
	Helen Koike, robh+dt, hans.verkuil, Laurent Pinchart,
	sakari.ailus, joacim.zetterling, mchehab, andrey.konovalov,
	jacob-chen, linux-media

Hi Ezequiel,

Am Dienstag, 7. Januar 2020, 14:20:10 CET schrieb Ezequiel Garcia:
> Hi Heiko, Laurent,
> 
> On Tue, 2020-01-07 at 10:28 +0100, Heiko Stübner wrote:
> > Am Dienstag, 7. Januar 2020, 03:37:21 CET schrieb Laurent Pinchart:
> > > On Mon, Jan 06, 2020 at 11:06:12PM -0300, Ezequiel Garcia wrote:
> > > > On Tue, 2020-01-07 at 02:10 +0200, Laurent Pinchart wrote:
> > > > > Hi Helen,
> > > > > 
> > > > > Thank you for the patch.
> > > > > 
> > > > > On Fri, Dec 27, 2019 at 05:01:14PM -0300, Helen Koike wrote:
> > > > > > Add yaml DT bindings for Rockchip MIPI D-PHY RX
> > > > > > 
> > > > > > This was tested and verified with:
> > > > > > mv drivers/staging/media/phy-rockchip-dphy/Documentation/devicetree/bindings/phy/rockchip-mipi-
> > > > > > dphy.yaml  Documentation/devicetree/bindings/phy/
> > > > > > make dt_binding_check DT_SCHEMA_FILES=Documentation/devicetree/bindings/phy/rockchip-mipi-dphy.yaml
> > > > > > make dtbs_check DT_SCHEMA_FILES=Documentation/devicetree/bindings/phy/rockchip-mipi-dphy.yaml
> > > > > > 
> > > > > > Signed-off-by: Helen Koike <helen.koike@collabora.com>
> > > > > > 
> > > > > > ---
> > > > > > 
> > > > > > 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.yaml      | 75 +++++++++++++++++++
> > > > > >  1 file changed, 75 insertions(+)
> > > > > >  create mode 100644 drivers/staging/media/phy-rockchip-dphy/Documentation/devicetree/bindings/phy/rockchip-mipi-dphy.yaml
> > > > > > 
> > > > > > diff --git a/drivers/staging/media/phy-rockchip-dphy/Documentation/devicetree/bindings/phy/rockchip-mipi-dphy.yaml
> > > > > > b/drivers/staging/media/phy-
> > > > > > rockchip-dphy/Documentation/devicetree/bindings/phy/rockchip-mipi-dphy.yaml
> > > > > > new file mode 100644
> > > > > > index 000000000000..af97f1b3e005
> > > > > > --- /dev/null
> > > > > > +++ b/drivers/staging/media/phy-rockchip-dphy/Documentation/devicetree/bindings/phy/rockchip-mipi-dphy.yaml
> > > > > > @@ -0,0 +1,75 @@
> > > > > > +# SPDX-License-Identifier: (GPL-2.0+ OR MIT)
> > > > > > +%YAML 1.2
> > > > > > +---
> > > > > > +$id: http://devicetree.org/schemas/phy/rockchip-mipi-dphy.yaml#
> > > > > > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > > > > > +
> > > > > > +title: Rockchip SoC MIPI RX0 D-PHY Device Tree Bindings
> > > > > 
> > > > > Should this be s/RX0/RX/ ? Or do you expect different bindings for RX1 ?
> > > > 
> > > > The driver currently only supports RX0, but I think you are right,
> > > > it should say RX here. This binding could be extended for RX1.
> > > > 
> > > > > Looking at the PHY driver, it seems to handle all PHYs with a single
> > > > > struct device. Should we thus use #phy-cells = <1> to select the PHY ?
> > > > 
> > > > I am not following this. The driver handles just one PHY. Each PHY
> > > > should have its own node.
> > > 
> > > Looking at the registers, it seems that the different PHYs are
> > > intertwined and we would could have trouble handling the different PHYs
> > > with different DT nodes and thus struct device instances.
> > 
> > I have to confess to not following _ALL_ of the threads, so may say
> > something stupid, but I don't think the PHYs are intertwined so much.
> > 
> > Where RX0 is controlled from the "General Register Files" alone
> > [register dumping ground for soc designers], the TX1RX1-phy
> > actually gets controlled from inside the dsi1 register area it seems.
> > 
> > So in my previous (still unsucessful) tests, I was rolling with something like
> > https://github.com/mmind/linux-rockchip/commit/e0d4b03976d2aab85a8c1630be937ea003b5df88
> > 
> > With the actual "logic" picked from the vendor kernel, that just double-
> > maps the dsi1-registers in both dsi and dphy driver, which was strange.
> > 
> > 
> 
> Describing each PHY in its own device node (as we currently do)
> results in:
> 
>         mipi_dphy_tx1rx1: mipi-dphy-tx1rx1@ff968000 {
>                 compatible = "rockchip,rk3399-mipi-dphy";
>                 reg = <0x0 0xff968000 0x0 0x8000>;
>                 rockchip,grf = <&grf>;
>         };

0xff968000 actually really is the dsi1 controller, so we'll already
have a node for that area. That is the reason I went that way to make
the rockchip-dsi optionally also behave as phy-provider.

So when it's used in combination with drm and a panel or so it will
behave as dsi controller, but when requested via the phy-framework
it will expose the dphy functionality.


>         grf: syscon@ff770000 {
>                 mipi_dphy_rx0: mipi-dphy-rx0 {
>                         compatible = "rockchip,rk3399-mipi-dphy";
>                 };
>         };
> 
> Which is mildly ugly, as it uses two mechanism to describe
> the GRF resource. In addition, the driver will then _infer_
> which device node is RX0 and which is TX1RX1, from this.
> 
> Perhaps Laurent's proposal, describing each PHY explicitly,
> would be cleaner?

so I really think we shouldn't merge these two things together,
especially to not break the dsi1 controller part.


Heiko




_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v12 09/11] media: staging: dt-bindings: add Rockchip MIPI RX D-PHY yaml bindings
  2020-01-07 21:30             ` Heiko Stübner
@ 2020-01-07 21:57               ` Laurent Pinchart
  2020-01-07 22:12                 ` Heiko Stuebner
  2020-01-07 22:03               ` Ezequiel Garcia
  1 sibling, 1 reply; 35+ messages in thread
From: Laurent Pinchart @ 2020-01-07 21:57 UTC (permalink / raw)
  To: Heiko Stübner
  Cc: mark.rutland, devicetree, eddie.cai.linux, kernel, gregkh,
	andrey.konovalov, linux-kernel, tfiga, linux-rockchip,
	Helen Koike, robh+dt, hans.verkuil, linux-arm-kernel,
	sakari.ailus, joacim.zetterling, mchehab, Ezequiel Garcia,
	jacob-chen, linux-media

Hi Heiko,

On Tue, Jan 07, 2020 at 10:30:28PM +0100, Heiko Stübner wrote:
> Am Dienstag, 7. Januar 2020, 14:20:10 CET schrieb Ezequiel Garcia:
> > On Tue, 2020-01-07 at 10:28 +0100, Heiko Stübner wrote:
> > > Am Dienstag, 7. Januar 2020, 03:37:21 CET schrieb Laurent Pinchart:
> > > > On Mon, Jan 06, 2020 at 11:06:12PM -0300, Ezequiel Garcia wrote:
> > > > > On Tue, 2020-01-07 at 02:10 +0200, Laurent Pinchart wrote:
> > > > > > Hi Helen,
> > > > > > 
> > > > > > Thank you for the patch.
> > > > > > 
> > > > > > On Fri, Dec 27, 2019 at 05:01:14PM -0300, Helen Koike wrote:
> > > > > > > Add yaml DT bindings for Rockchip MIPI D-PHY RX
> > > > > > > 
> > > > > > > This was tested and verified with:
> > > > > > > mv drivers/staging/media/phy-rockchip-dphy/Documentation/devicetree/bindings/phy/rockchip-mipi-
> > > > > > > dphy.yaml  Documentation/devicetree/bindings/phy/
> > > > > > > make dt_binding_check DT_SCHEMA_FILES=Documentation/devicetree/bindings/phy/rockchip-mipi-dphy.yaml
> > > > > > > make dtbs_check DT_SCHEMA_FILES=Documentation/devicetree/bindings/phy/rockchip-mipi-dphy.yaml
> > > > > > > 
> > > > > > > Signed-off-by: Helen Koike <helen.koike@collabora.com>
> > > > > > > 
> > > > > > > ---
> > > > > > > 
> > > > > > > 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.yaml      | 75 +++++++++++++++++++
> > > > > > >  1 file changed, 75 insertions(+)
> > > > > > >  create mode 100644 drivers/staging/media/phy-rockchip-dphy/Documentation/devicetree/bindings/phy/rockchip-mipi-dphy.yaml
> > > > > > > 
> > > > > > > diff --git a/drivers/staging/media/phy-rockchip-dphy/Documentation/devicetree/bindings/phy/rockchip-mipi-dphy.yaml
> > > > > > > b/drivers/staging/media/phy-
> > > > > > > rockchip-dphy/Documentation/devicetree/bindings/phy/rockchip-mipi-dphy.yaml
> > > > > > > new file mode 100644
> > > > > > > index 000000000000..af97f1b3e005
> > > > > > > --- /dev/null
> > > > > > > +++ b/drivers/staging/media/phy-rockchip-dphy/Documentation/devicetree/bindings/phy/rockchip-mipi-dphy.yaml
> > > > > > > @@ -0,0 +1,75 @@
> > > > > > > +# SPDX-License-Identifier: (GPL-2.0+ OR MIT)
> > > > > > > +%YAML 1.2
> > > > > > > +---
> > > > > > > +$id: http://devicetree.org/schemas/phy/rockchip-mipi-dphy.yaml#
> > > > > > > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > > > > > > +
> > > > > > > +title: Rockchip SoC MIPI RX0 D-PHY Device Tree Bindings
> > > > > > 
> > > > > > Should this be s/RX0/RX/ ? Or do you expect different bindings for RX1 ?
> > > > > 
> > > > > The driver currently only supports RX0, but I think you are right,
> > > > > it should say RX here. This binding could be extended for RX1.
> > > > > 
> > > > > > Looking at the PHY driver, it seems to handle all PHYs with a single
> > > > > > struct device. Should we thus use #phy-cells = <1> to select the PHY ?
> > > > > 
> > > > > I am not following this. The driver handles just one PHY. Each PHY
> > > > > should have its own node.
> > > > 
> > > > Looking at the registers, it seems that the different PHYs are
> > > > intertwined and we would could have trouble handling the different PHYs
> > > > with different DT nodes and thus struct device instances.
> > > 
> > > I have to confess to not following _ALL_ of the threads, so may say
> > > something stupid, but I don't think the PHYs are intertwined so much.
> > > 
> > > Where RX0 is controlled from the "General Register Files" alone
> > > [register dumping ground for soc designers], the TX1RX1-phy
> > > actually gets controlled from inside the dsi1 register area it seems.
> > > 
> > > So in my previous (still unsucessful) tests, I was rolling with something like
> > > https://github.com/mmind/linux-rockchip/commit/e0d4b03976d2aab85a8c1630be937ea003b5df88
> > > 
> > > With the actual "logic" picked from the vendor kernel, that just double-
> > > maps the dsi1-registers in both dsi and dphy driver, which was strange.
> > 
> > Describing each PHY in its own device node (as we currently do)
> > results in:
> > 
> >         mipi_dphy_tx1rx1: mipi-dphy-tx1rx1@ff968000 {
> >                 compatible = "rockchip,rk3399-mipi-dphy";
> >                 reg = <0x0 0xff968000 0x0 0x8000>;
> >                 rockchip,grf = <&grf>;
> >         };
> 
> 0xff968000 actually really is the dsi1 controller, so we'll already
> have a node for that area. That is the reason I went that way to make
> the rockchip-dsi optionally also behave as phy-provider.
> 
> So when it's used in combination with drm and a panel or so it will
> behave as dsi controller, but when requested via the phy-framework
> it will expose the dphy functionality.

Doesn't RX1/TX1 also expose controls through GRF ? For instance
GRF_SOC_CON9 has a dphy_rx1_clk_inv_sel bit.

> >         grf: syscon@ff770000 {
> >                 mipi_dphy_rx0: mipi-dphy-rx0 {
> >                         compatible = "rockchip,rk3399-mipi-dphy";
> >                 };
> >         };
> > 
> > Which is mildly ugly, as it uses two mechanism to describe
> > the GRF resource. In addition, the driver will then _infer_
> > which device node is RX0 and which is TX1RX1, from this.
> > 
> > Perhaps Laurent's proposal, describing each PHY explicitly,
> > would be cleaner?
> 
> so I really think we shouldn't merge these two things together,
> especially to not break the dsi1 controller part.

-- 
Regards,

Laurent Pinchart

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v12 09/11] media: staging: dt-bindings: add Rockchip MIPI RX D-PHY yaml bindings
  2020-01-07 21:30             ` Heiko Stübner
  2020-01-07 21:57               ` Laurent Pinchart
@ 2020-01-07 22:03               ` Ezequiel Garcia
  2020-01-07 22:25                 ` Heiko Stuebner
  1 sibling, 1 reply; 35+ messages in thread
From: Ezequiel Garcia @ 2020-01-07 22:03 UTC (permalink / raw)
  To: Heiko Stübner
  Cc: mark.rutland, devicetree, eddie.cai.linux, kernel,
	linux-arm-kernel, gregkh, linux-kernel, tfiga, linux-rockchip,
	Helen Koike, robh+dt, hans.verkuil, Laurent Pinchart,
	sakari.ailus, joacim.zetterling, mchehab, andrey.konovalov,
	jacob-chen, linux-media

On Tue, 2020-01-07 at 22:30 +0100, Heiko Stübner wrote:
> Hi Ezequiel,
> 
> Am Dienstag, 7. Januar 2020, 14:20:10 CET schrieb Ezequiel Garcia:
> > Hi Heiko, Laurent,
> > 
> > On Tue, 2020-01-07 at 10:28 +0100, Heiko Stübner wrote:
> > > Am Dienstag, 7. Januar 2020, 03:37:21 CET schrieb Laurent Pinchart:
> > > > On Mon, Jan 06, 2020 at 11:06:12PM -0300, Ezequiel Garcia wrote:
> > > > > On Tue, 2020-01-07 at 02:10 +0200, Laurent Pinchart wrote:
> > > > > > Hi Helen,
> > > > > > 
> > > > > > Thank you for the patch.
> > > > > > 
> > > > > > On Fri, Dec 27, 2019 at 05:01:14PM -0300, Helen Koike wrote:
> > > > > > > Add yaml DT bindings for Rockchip MIPI D-PHY RX
> > > > > > > 
> > > > > > > This was tested and verified with:
> > > > > > > mv drivers/staging/media/phy-rockchip-dphy/Documentation/devicetree/bindings/phy/rockchip-mipi-
> > > > > > > dphy.yaml  Documentation/devicetree/bindings/phy/
> > > > > > > make dt_binding_check DT_SCHEMA_FILES=Documentation/devicetree/bindings/phy/rockchip-mipi-dphy.yaml
> > > > > > > make dtbs_check DT_SCHEMA_FILES=Documentation/devicetree/bindings/phy/rockchip-mipi-dphy.yaml
> > > > > > > 
> > > > > > > Signed-off-by: Helen Koike <helen.koike@collabora.com>
> > > > > > > 
> > > > > > > ---
> > > > > > > 
> > > > > > > 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.yaml      | 75 +++++++++++++++++++
> > > > > > >  1 file changed, 75 insertions(+)
> > > > > > >  create mode 100644 drivers/staging/media/phy-rockchip-dphy/Documentation/devicetree/bindings/phy/rockchip-mipi-dphy.yaml
> > > > > > > 
> > > > > > > diff --git a/drivers/staging/media/phy-rockchip-dphy/Documentation/devicetree/bindings/phy/rockchip-mipi-dphy.yaml
> > > > > > > b/drivers/staging/media/phy-
> > > > > > > rockchip-dphy/Documentation/devicetree/bindings/phy/rockchip-mipi-dphy.yaml
> > > > > > > new file mode 100644
> > > > > > > index 000000000000..af97f1b3e005
> > > > > > > --- /dev/null
> > > > > > > +++ b/drivers/staging/media/phy-rockchip-dphy/Documentation/devicetree/bindings/phy/rockchip-mipi-dphy.yaml
> > > > > > > @@ -0,0 +1,75 @@
> > > > > > > +# SPDX-License-Identifier: (GPL-2.0+ OR MIT)
> > > > > > > +%YAML 1.2
> > > > > > > +---
> > > > > > > +$id: http://devicetree.org/schemas/phy/rockchip-mipi-dphy.yaml#
> > > > > > > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > > > > > > +
> > > > > > > +title: Rockchip SoC MIPI RX0 D-PHY Device Tree Bindings
> > > > > > 
> > > > > > Should this be s/RX0/RX/ ? Or do you expect different bindings for RX1 ?
> > > > > 
> > > > > The driver currently only supports RX0, but I think you are right,
> > > > > it should say RX here. This binding could be extended for RX1.
> > > > > 
> > > > > > Looking at the PHY driver, it seems to handle all PHYs with a single
> > > > > > struct device. Should we thus use #phy-cells = <1> to select the PHY ?
> > > > > 
> > > > > I am not following this. The driver handles just one PHY. Each PHY
> > > > > should have its own node.
> > > > 
> > > > Looking at the registers, it seems that the different PHYs are
> > > > intertwined and we would could have trouble handling the different PHYs
> > > > with different DT nodes and thus struct device instances.
> > > 
> > > I have to confess to not following _ALL_ of the threads, so may say
> > > something stupid, but I don't think the PHYs are intertwined so much.
> > > 
> > > Where RX0 is controlled from the "General Register Files" alone
> > > [register dumping ground for soc designers], the TX1RX1-phy
> > > actually gets controlled from inside the dsi1 register area it seems.
> > > 
> > > So in my previous (still unsucessful) tests, I was rolling with something like
> > > https://github.com/mmind/linux-rockchip/commit/e0d4b03976d2aab85a8c1630be937ea003b5df88
> > > 
> > > With the actual "logic" picked from the vendor kernel, that just double-
> > > maps the dsi1-registers in both dsi and dphy driver, which was strange.
> > > 
> > > 
> > 
> > Describing each PHY in its own device node (as we currently do)
> > results in:
> > 
> >         mipi_dphy_tx1rx1: mipi-dphy-tx1rx1@ff968000 {
> >                 compatible = "rockchip,rk3399-mipi-dphy";
> >                 reg = <0x0 0xff968000 0x0 0x8000>;
> >                 rockchip,grf = <&grf>;
> >         };
> 
> 0xff968000 actually really is the dsi1 controller, so we'll already
> have a node for that area. That is the reason I went that way to make
> the rockchip-dsi optionally also behave as phy-provider.
> 
> So when it's used in combination with drm and a panel or so it will
> behave as dsi controller, but when requested via the phy-framework
> it will expose the dphy functionality.
> 

Hm, and will this driver also support RX1?

> 
> >         grf: syscon@ff770000 {
> >                 mipi_dphy_rx0: mipi-dphy-rx0 {
> >                         compatible = "rockchip,rk3399-mipi-dphy";
> >                 };
> >         };
> > 
> > Which is mildly ugly, as it uses two mechanism to describe
> > the GRF resource. In addition, the driver will then _infer_
> > which device node is RX0 and which is TX1RX1, from this.
> > 
> > Perhaps Laurent's proposal, describing each PHY explicitly,
> > would be cleaner?
> 
> so I really think we shouldn't merge these two things together,
> especially to not break the dsi1 controller part.
> 

I don't think it would necesarily break the dsi1 controller part.

You can declare both device nodes as sharing the address region,
and then the driver can request the I/O resource only when it needs to,
i.e. in the PHY .init hook.

It's not super nice, but there's no real reason two devices
can't share an I/O memory resource.

I like this approach because it exposes the different PHYs
explicitly, instead of implicitly.

Thanks,
Ezequiel



_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v12 09/11] media: staging: dt-bindings: add Rockchip MIPI RX D-PHY yaml bindings
  2020-01-07 21:57               ` Laurent Pinchart
@ 2020-01-07 22:12                 ` Heiko Stuebner
  0 siblings, 0 replies; 35+ messages in thread
From: Heiko Stuebner @ 2020-01-07 22:12 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: mark.rutland, devicetree, eddie.cai.linux, kernel, gregkh,
	andrey.konovalov, linux-kernel, tfiga, linux-rockchip,
	Helen Koike, robh+dt, hans.verkuil, linux-arm-kernel,
	sakari.ailus, joacim.zetterling, mchehab, Ezequiel Garcia,
	jacob-chen, linux-media

Am Dienstag, 7. Januar 2020, 22:57:39 CET schrieb Laurent Pinchart:
> Hi Heiko,
> 
> On Tue, Jan 07, 2020 at 10:30:28PM +0100, Heiko Stübner wrote:
> > Am Dienstag, 7. Januar 2020, 14:20:10 CET schrieb Ezequiel Garcia:
> > > On Tue, 2020-01-07 at 10:28 +0100, Heiko Stübner wrote:
> > > > Am Dienstag, 7. Januar 2020, 03:37:21 CET schrieb Laurent Pinchart:
> > > > > On Mon, Jan 06, 2020 at 11:06:12PM -0300, Ezequiel Garcia wrote:
> > > > > > On Tue, 2020-01-07 at 02:10 +0200, Laurent Pinchart wrote:
> > > > > > > Hi Helen,
> > > > > > > 
> > > > > > > Thank you for the patch.
> > > > > > > 
> > > > > > > On Fri, Dec 27, 2019 at 05:01:14PM -0300, Helen Koike wrote:
> > > > > > > > Add yaml DT bindings for Rockchip MIPI D-PHY RX
> > > > > > > > 
> > > > > > > > This was tested and verified with:
> > > > > > > > mv drivers/staging/media/phy-rockchip-dphy/Documentation/devicetree/bindings/phy/rockchip-mipi-
> > > > > > > > dphy.yaml  Documentation/devicetree/bindings/phy/
> > > > > > > > make dt_binding_check DT_SCHEMA_FILES=Documentation/devicetree/bindings/phy/rockchip-mipi-dphy.yaml
> > > > > > > > make dtbs_check DT_SCHEMA_FILES=Documentation/devicetree/bindings/phy/rockchip-mipi-dphy.yaml
> > > > > > > > 
> > > > > > > > Signed-off-by: Helen Koike <helen.koike@collabora.com>
> > > > > > > > 
> > > > > > > > ---
> > > > > > > > 
> > > > > > > > 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.yaml      | 75 +++++++++++++++++++
> > > > > > > >  1 file changed, 75 insertions(+)
> > > > > > > >  create mode 100644 drivers/staging/media/phy-rockchip-dphy/Documentation/devicetree/bindings/phy/rockchip-mipi-dphy.yaml
> > > > > > > > 
> > > > > > > > diff --git a/drivers/staging/media/phy-rockchip-dphy/Documentation/devicetree/bindings/phy/rockchip-mipi-dphy.yaml
> > > > > > > > b/drivers/staging/media/phy-
> > > > > > > > rockchip-dphy/Documentation/devicetree/bindings/phy/rockchip-mipi-dphy.yaml
> > > > > > > > new file mode 100644
> > > > > > > > index 000000000000..af97f1b3e005
> > > > > > > > --- /dev/null
> > > > > > > > +++ b/drivers/staging/media/phy-rockchip-dphy/Documentation/devicetree/bindings/phy/rockchip-mipi-dphy.yaml
> > > > > > > > @@ -0,0 +1,75 @@
> > > > > > > > +# SPDX-License-Identifier: (GPL-2.0+ OR MIT)
> > > > > > > > +%YAML 1.2
> > > > > > > > +---
> > > > > > > > +$id: http://devicetree.org/schemas/phy/rockchip-mipi-dphy.yaml#
> > > > > > > > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > > > > > > > +
> > > > > > > > +title: Rockchip SoC MIPI RX0 D-PHY Device Tree Bindings
> > > > > > > 
> > > > > > > Should this be s/RX0/RX/ ? Or do you expect different bindings for RX1 ?
> > > > > > 
> > > > > > The driver currently only supports RX0, but I think you are right,
> > > > > > it should say RX here. This binding could be extended for RX1.
> > > > > > 
> > > > > > > Looking at the PHY driver, it seems to handle all PHYs with a single
> > > > > > > struct device. Should we thus use #phy-cells = <1> to select the PHY ?
> > > > > > 
> > > > > > I am not following this. The driver handles just one PHY. Each PHY
> > > > > > should have its own node.
> > > > > 
> > > > > Looking at the registers, it seems that the different PHYs are
> > > > > intertwined and we would could have trouble handling the different PHYs
> > > > > with different DT nodes and thus struct device instances.
> > > > 
> > > > I have to confess to not following _ALL_ of the threads, so may say
> > > > something stupid, but I don't think the PHYs are intertwined so much.
> > > > 
> > > > Where RX0 is controlled from the "General Register Files" alone
> > > > [register dumping ground for soc designers], the TX1RX1-phy
> > > > actually gets controlled from inside the dsi1 register area it seems.
> > > > 
> > > > So in my previous (still unsucessful) tests, I was rolling with something like
> > > > https://github.com/mmind/linux-rockchip/commit/e0d4b03976d2aab85a8c1630be937ea003b5df88
> > > > 
> > > > With the actual "logic" picked from the vendor kernel, that just double-
> > > > maps the dsi1-registers in both dsi and dphy driver, which was strange.
> > > 
> > > Describing each PHY in its own device node (as we currently do)
> > > results in:
> > > 
> > >         mipi_dphy_tx1rx1: mipi-dphy-tx1rx1@ff968000 {
> > >                 compatible = "rockchip,rk3399-mipi-dphy";
> > >                 reg = <0x0 0xff968000 0x0 0x8000>;
> > >                 rockchip,grf = <&grf>;
> > >         };
> > 
> > 0xff968000 actually really is the dsi1 controller, so we'll already
> > have a node for that area. That is the reason I went that way to make
> > the rockchip-dsi optionally also behave as phy-provider.
> > 
> > So when it's used in combination with drm and a panel or so it will
> > behave as dsi controller, but when requested via the phy-framework
> > it will expose the dphy functionality.
> 
> Doesn't RX1/TX1 also expose controls through GRF ? For instance
> GRF_SOC_CON9 has a dphy_rx1_clk_inv_sel bit.

There are parts in the GRF but the whole phy-write stuff is inside
the dsi controller area. See the vendor kernel at
	https://github.com/rockchip-linux/kernel/blob/develop-4.4/drivers/phy/rockchip/phy-rockchip-mipi-rx.c#L1427

where you get write_grf_reg() for GRF bits but also the write_txrx_reg()
and mipidphy1_wr_reg() calls that access registers inside the dsi1
controller space.


Heiko

> 
> > >         grf: syscon@ff770000 {
> > >                 mipi_dphy_rx0: mipi-dphy-rx0 {
> > >                         compatible = "rockchip,rk3399-mipi-dphy";
> > >                 };
> > >         };
> > > 
> > > Which is mildly ugly, as it uses two mechanism to describe
> > > the GRF resource. In addition, the driver will then _infer_
> > > which device node is RX0 and which is TX1RX1, from this.
> > > 
> > > Perhaps Laurent's proposal, describing each PHY explicitly,
> > > would be cleaner?
> > 
> > so I really think we shouldn't merge these two things together,
> > especially to not break the dsi1 controller part.
> 
> 





_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v12 09/11] media: staging: dt-bindings: add Rockchip MIPI RX D-PHY yaml bindings
  2020-01-07 22:03               ` Ezequiel Garcia
@ 2020-01-07 22:25                 ` Heiko Stuebner
  2020-01-07 22:41                   ` Ezequiel Garcia
  0 siblings, 1 reply; 35+ messages in thread
From: Heiko Stuebner @ 2020-01-07 22:25 UTC (permalink / raw)
  To: Ezequiel Garcia
  Cc: mark.rutland, devicetree, eddie.cai.linux, kernel,
	linux-arm-kernel, gregkh, linux-kernel, tfiga, linux-rockchip,
	Helen Koike, robh+dt, hans.verkuil, Laurent Pinchart,
	sakari.ailus, joacim.zetterling, mchehab, andrey.konovalov,
	jacob-chen, linux-media

Am Dienstag, 7. Januar 2020, 23:03:54 CET schrieb Ezequiel Garcia:
> On Tue, 2020-01-07 at 22:30 +0100, Heiko Stübner wrote:
> > Hi Ezequiel,
> > 
> > Am Dienstag, 7. Januar 2020, 14:20:10 CET schrieb Ezequiel Garcia:
> > > Hi Heiko, Laurent,
> > > 
> > > On Tue, 2020-01-07 at 10:28 +0100, Heiko Stübner wrote:
> > > > Am Dienstag, 7. Januar 2020, 03:37:21 CET schrieb Laurent Pinchart:
> > > > > On Mon, Jan 06, 2020 at 11:06:12PM -0300, Ezequiel Garcia wrote:
> > > > > > On Tue, 2020-01-07 at 02:10 +0200, Laurent Pinchart wrote:
> > > > > > > Hi Helen,
> > > > > > > 
> > > > > > > Thank you for the patch.
> > > > > > > 
> > > > > > > On Fri, Dec 27, 2019 at 05:01:14PM -0300, Helen Koike wrote:
> > > > > > > > Add yaml DT bindings for Rockchip MIPI D-PHY RX
> > > > > > > > 
> > > > > > > > This was tested and verified with:
> > > > > > > > mv drivers/staging/media/phy-rockchip-dphy/Documentation/devicetree/bindings/phy/rockchip-mipi-
> > > > > > > > dphy.yaml  Documentation/devicetree/bindings/phy/
> > > > > > > > make dt_binding_check DT_SCHEMA_FILES=Documentation/devicetree/bindings/phy/rockchip-mipi-dphy.yaml
> > > > > > > > make dtbs_check DT_SCHEMA_FILES=Documentation/devicetree/bindings/phy/rockchip-mipi-dphy.yaml
> > > > > > > > 
> > > > > > > > Signed-off-by: Helen Koike <helen.koike@collabora.com>
> > > > > > > > 
> > > > > > > > ---
> > > > > > > > 
> > > > > > > > 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.yaml      | 75 +++++++++++++++++++
> > > > > > > >  1 file changed, 75 insertions(+)
> > > > > > > >  create mode 100644 drivers/staging/media/phy-rockchip-dphy/Documentation/devicetree/bindings/phy/rockchip-mipi-dphy.yaml
> > > > > > > > 
> > > > > > > > diff --git a/drivers/staging/media/phy-rockchip-dphy/Documentation/devicetree/bindings/phy/rockchip-mipi-dphy.yaml
> > > > > > > > b/drivers/staging/media/phy-
> > > > > > > > rockchip-dphy/Documentation/devicetree/bindings/phy/rockchip-mipi-dphy.yaml
> > > > > > > > new file mode 100644
> > > > > > > > index 000000000000..af97f1b3e005
> > > > > > > > --- /dev/null
> > > > > > > > +++ b/drivers/staging/media/phy-rockchip-dphy/Documentation/devicetree/bindings/phy/rockchip-mipi-dphy.yaml
> > > > > > > > @@ -0,0 +1,75 @@
> > > > > > > > +# SPDX-License-Identifier: (GPL-2.0+ OR MIT)
> > > > > > > > +%YAML 1.2
> > > > > > > > +---
> > > > > > > > +$id: http://devicetree.org/schemas/phy/rockchip-mipi-dphy.yaml#
> > > > > > > > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > > > > > > > +
> > > > > > > > +title: Rockchip SoC MIPI RX0 D-PHY Device Tree Bindings
> > > > > > > 
> > > > > > > Should this be s/RX0/RX/ ? Or do you expect different bindings for RX1 ?
> > > > > > 
> > > > > > The driver currently only supports RX0, but I think you are right,
> > > > > > it should say RX here. This binding could be extended for RX1.
> > > > > > 
> > > > > > > Looking at the PHY driver, it seems to handle all PHYs with a single
> > > > > > > struct device. Should we thus use #phy-cells = <1> to select the PHY ?
> > > > > > 
> > > > > > I am not following this. The driver handles just one PHY. Each PHY
> > > > > > should have its own node.
> > > > > 
> > > > > Looking at the registers, it seems that the different PHYs are
> > > > > intertwined and we would could have trouble handling the different PHYs
> > > > > with different DT nodes and thus struct device instances.
> > > > 
> > > > I have to confess to not following _ALL_ of the threads, so may say
> > > > something stupid, but I don't think the PHYs are intertwined so much.
> > > > 
> > > > Where RX0 is controlled from the "General Register Files" alone
> > > > [register dumping ground for soc designers], the TX1RX1-phy
> > > > actually gets controlled from inside the dsi1 register area it seems.
> > > > 
> > > > So in my previous (still unsucessful) tests, I was rolling with something like
> > > > https://github.com/mmind/linux-rockchip/commit/e0d4b03976d2aab85a8c1630be937ea003b5df88
> > > > 
> > > > With the actual "logic" picked from the vendor kernel, that just double-
> > > > maps the dsi1-registers in both dsi and dphy driver, which was strange.
> > > > 
> > > > 
> > > 
> > > Describing each PHY in its own device node (as we currently do)
> > > results in:
> > > 
> > >         mipi_dphy_tx1rx1: mipi-dphy-tx1rx1@ff968000 {
> > >                 compatible = "rockchip,rk3399-mipi-dphy";
> > >                 reg = <0x0 0xff968000 0x0 0x8000>;
> > >                 rockchip,grf = <&grf>;
> > >         };
> > 
> > 0xff968000 actually really is the dsi1 controller, so we'll already
> > have a node for that area. That is the reason I went that way to make
> > the rockchip-dsi optionally also behave as phy-provider.
> > 
> > So when it's used in combination with drm and a panel or so it will
> > behave as dsi controller, but when requested via the phy-framework
> > it will expose the dphy functionality.
> > 
> 
> Hm, and will this driver also support RX1?

what is RX1 in your book? :-)

According to the TRM the rk3399 has 3 DPHYs,
tx0 - connected exclusively to dsi0
      (this is handled internally by the dw-mipi-dsi driver with controls
       in the dsi0 register space)
rx0 - connected exclusively to isp0
      (this is handled by the individual dphy driver from Helen's series)
tx1rx1 - shared between dsi1 and isp1
      (again inside the dsi1 register space)


> 
> > 
> > >         grf: syscon@ff770000 {
> > >                 mipi_dphy_rx0: mipi-dphy-rx0 {
> > >                         compatible = "rockchip,rk3399-mipi-dphy";
> > >                 };
> > >         };
> > > 
> > > Which is mildly ugly, as it uses two mechanism to describe
> > > the GRF resource. In addition, the driver will then _infer_
> > > which device node is RX0 and which is TX1RX1, from this.
> > > 
> > > Perhaps Laurent's proposal, describing each PHY explicitly,
> > > would be cleaner?
> > 
> > so I really think we shouldn't merge these two things together,
> > especially to not break the dsi1 controller part.
> > 
> 
> I don't think it would necesarily break the dsi1 controller part.
> 
> You can declare both device nodes as sharing the address region,
> and then the driver can request the I/O resource only when it needs to,
> i.e. in the PHY .init hook.

dsi1 is of course a dw-mipi-dsi one, which in turn shares a common bridge
driver over multiple variants (non-rockchip), which expects its registers
mapped during probe.

I think it would not really work well if you need to make the whole world
follow that idea ;-) .


Hence my approach with exposing the phy interface from the dsi driver.
If you look at the dts part, it also just looks like it should be ... as
a regular phy:
	https://github.com/mmind/linux-rockchip/blob/wip/tc358749/arch/arm64/boot/dts/rockchip/rk3399.dtsi#L1764

And on the driver side there is even some short circuit protection.
When used as phy, it won't allow to be used as a component and
vice versa.


> It's not super nice, but there's no real reason two devices
> can't share an I/O memory resource.

Counter argument, devicetree is not a means to handle Linux
peculiarites - instead it should describe the hardware ...
and the area there _is_ the dsi1 controller ;-)

Heiko



_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v12 09/11] media: staging: dt-bindings: add Rockchip MIPI RX D-PHY yaml bindings
  2020-01-07 22:25                 ` Heiko Stuebner
@ 2020-01-07 22:41                   ` Ezequiel Garcia
  0 siblings, 0 replies; 35+ messages in thread
From: Ezequiel Garcia @ 2020-01-07 22:41 UTC (permalink / raw)
  To: Heiko Stuebner
  Cc: mark.rutland, devicetree, eddie.cai.linux, kernel,
	linux-arm-kernel, gregkh, linux-kernel, tfiga, linux-rockchip,
	Helen Koike, robh+dt, hans.verkuil, Laurent Pinchart,
	sakari.ailus, joacim.zetterling, mchehab, andrey.konovalov,
	jacob-chen, linux-media

On Tue, 2020-01-07 at 23:25 +0100, Heiko Stuebner wrote:
> Am Dienstag, 7. Januar 2020, 23:03:54 CET schrieb Ezequiel Garcia:
> > On Tue, 2020-01-07 at 22:30 +0100, Heiko Stübner wrote:
> > > Hi Ezequiel,
> > > 
> > > Am Dienstag, 7. Januar 2020, 14:20:10 CET schrieb Ezequiel Garcia:
> > > > Hi Heiko, Laurent,
> > > > 
> > > > On Tue, 2020-01-07 at 10:28 +0100, Heiko Stübner wrote:
> > > > > Am Dienstag, 7. Januar 2020, 03:37:21 CET schrieb Laurent Pinchart:
> > > > > > On Mon, Jan 06, 2020 at 11:06:12PM -0300, Ezequiel Garcia wrote:
> > > > > > > On Tue, 2020-01-07 at 02:10 +0200, Laurent Pinchart wrote:
> > > > > > > > Hi Helen,
> > > > > > > > 
> > > > > > > > Thank you for the patch.
> > > > > > > > 
> > > > > > > > On Fri, Dec 27, 2019 at 05:01:14PM -0300, Helen Koike wrote:
> > > > > > > > > Add yaml DT bindings for Rockchip MIPI D-PHY RX
> > > > > > > > > 
> > > > > > > > > This was tested and verified with:
> > > > > > > > > mv drivers/staging/media/phy-rockchip-dphy/Documentation/devicetree/bindings/phy/rockchip-mipi-
> > > > > > > > > dphy.yaml  Documentation/devicetree/bindings/phy/
> > > > > > > > > make dt_binding_check DT_SCHEMA_FILES=Documentation/devicetree/bindings/phy/rockchip-mipi-dphy.yaml
> > > > > > > > > make dtbs_check DT_SCHEMA_FILES=Documentation/devicetree/bindings/phy/rockchip-mipi-dphy.yaml
> > > > > > > > > 
> > > > > > > > > Signed-off-by: Helen Koike <helen.koike@collabora.com>
> > > > > > > > > 
> > > > > > > > > ---
> > > > > > > > > 
> > > > > > > > > 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.yaml      | 75 +++++++++++++++++++
> > > > > > > > >  1 file changed, 75 insertions(+)
> > > > > > > > >  create mode 100644 drivers/staging/media/phy-rockchip-dphy/Documentation/devicetree/bindings/phy/rockchip-mipi-dphy.yaml
> > > > > > > > > 
> > > > > > > > > diff --git a/drivers/staging/media/phy-rockchip-dphy/Documentation/devicetree/bindings/phy/rockchip-mipi-dphy.yaml
> > > > > > > > > b/drivers/staging/media/phy-
> > > > > > > > > rockchip-dphy/Documentation/devicetree/bindings/phy/rockchip-mipi-dphy.yaml
> > > > > > > > > new file mode 100644
> > > > > > > > > index 000000000000..af97f1b3e005
> > > > > > > > > --- /dev/null
> > > > > > > > > +++ b/drivers/staging/media/phy-rockchip-dphy/Documentation/devicetree/bindings/phy/rockchip-mipi-dphy.yaml
> > > > > > > > > @@ -0,0 +1,75 @@
> > > > > > > > > +# SPDX-License-Identifier: (GPL-2.0+ OR MIT)
> > > > > > > > > +%YAML 1.2
> > > > > > > > > +---
> > > > > > > > > +$id: http://devicetree.org/schemas/phy/rockchip-mipi-dphy.yaml#
> > > > > > > > > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > > > > > > > > +
> > > > > > > > > +title: Rockchip SoC MIPI RX0 D-PHY Device Tree Bindings
> > > > > > > > 
> > > > > > > > Should this be s/RX0/RX/ ? Or do you expect different bindings for RX1 ?
> > > > > > > 
> > > > > > > The driver currently only supports RX0, but I think you are right,
> > > > > > > it should say RX here. This binding could be extended for RX1.
> > > > > > > 
> > > > > > > > Looking at the PHY driver, it seems to handle all PHYs with a single
> > > > > > > > struct device. Should we thus use #phy-cells = <1> to select the PHY ?
> > > > > > > 
> > > > > > > I am not following this. The driver handles just one PHY. Each PHY
> > > > > > > should have its own node.
> > > > > > 
> > > > > > Looking at the registers, it seems that the different PHYs are
> > > > > > intertwined and we would could have trouble handling the different PHYs
> > > > > > with different DT nodes and thus struct device instances.
> > > > > 
> > > > > I have to confess to not following _ALL_ of the threads, so may say
> > > > > something stupid, but I don't think the PHYs are intertwined so much.
> > > > > 
> > > > > Where RX0 is controlled from the "General Register Files" alone
> > > > > [register dumping ground for soc designers], the TX1RX1-phy
> > > > > actually gets controlled from inside the dsi1 register area it seems.
> > > > > 
> > > > > So in my previous (still unsucessful) tests, I was rolling with something like
> > > > > https://github.com/mmind/linux-rockchip/commit/e0d4b03976d2aab85a8c1630be937ea003b5df88
> > > > > 
> > > > > With the actual "logic" picked from the vendor kernel, that just double-
> > > > > maps the dsi1-registers in both dsi and dphy driver, which was strange.
> > > > > 
> > > > > 
> > > > 
> > > > Describing each PHY in its own device node (as we currently do)
> > > > results in:
> > > > 
> > > >         mipi_dphy_tx1rx1: mipi-dphy-tx1rx1@ff968000 {
> > > >                 compatible = "rockchip,rk3399-mipi-dphy";
> > > >                 reg = <0x0 0xff968000 0x0 0x8000>;
> > > >                 rockchip,grf = <&grf>;
> > > >         };
> > > 
> > > 0xff968000 actually really is the dsi1 controller, so we'll already
> > > have a node for that area. That is the reason I went that way to make
> > > the rockchip-dsi optionally also behave as phy-provider.
> > > 
> > > So when it's used in combination with drm and a panel or so it will
> > > behave as dsi controller, but when requested via the phy-framework
> > > it will expose the dphy functionality.
> > > 
> > 
> > Hm, and will this driver also support RX1?
> 
> what is RX1 in your book? :-)
> 

I meant tx1rx1 configured as a receiver,
sorry for the confusion!

> According to the TRM the rk3399 has 3 DPHYs,
> tx0 - connected exclusively to dsi0
>       (this is handled internally by the dw-mipi-dsi driver with controls
>        in the dsi0 register space)
> rx0 - connected exclusively to isp0
>       (this is handled by the individual dphy driver from Helen's series)
> tx1rx1 - shared between dsi1 and isp1
>       (again inside the dsi1 register space)
> 

Exactly.

> 
> > > >         grf: syscon@ff770000 {
> > > >                 mipi_dphy_rx0: mipi-dphy-rx0 {
> > > >                         compatible = "rockchip,rk3399-mipi-dphy";
> > > >                 };
> > > >         };
> > > > 
> > > > Which is mildly ugly, as it uses two mechanism to describe
> > > > the GRF resource. In addition, the driver will then _infer_
> > > > which device node is RX0 and which is TX1RX1, from this.
> > > > 
> > > > Perhaps Laurent's proposal, describing each PHY explicitly,
> > > > would be cleaner?
> > > 
> > > so I really think we shouldn't merge these two things together,
> > > especially to not break the dsi1 controller part.
> > > 
> > 
> > I don't think it would necesarily break the dsi1 controller part.
> > 
> > You can declare both device nodes as sharing the address region,
> > and then the driver can request the I/O resource only when it needs to,
> > i.e. in the PHY .init hook.
> 
> dsi1 is of course a dw-mipi-dsi one, which in turn shares a common bridge
> driver over multiple variants (non-rockchip), which expects its registers
> mapped during probe.
> 
> I think it would not really work well if you need to make the whole world
> follow that idea ;-) .
> 
> 
> Hence my approach with exposing the phy interface from the dsi driver.
> If you look at the dts part, it also just looks like it should be ... as
> a regular phy:
> 	https://github.com/mmind/linux-rockchip/blob/wip/tc358749/arch/arm64/boot/dts/rockchip/rk3399.dtsi#L1764
> 
> And on the driver side there is even some short circuit protection.
> When used as phy, it won't allow to be used as a component and
> vice versa.
> 

OK, it's more clear now.

If this bindings will only ever support the RX0 PHY,
will not support anything else, then we don't need
to worry.

It can stay as a GRF syscon child, and will have
phy-cells = 0.

Thanks,
Ezequiel


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v12 08/11] media: staging: dt-bindings: add Rockchip ISP1 yaml bindings
  2020-01-07 14:01   ` Sakari Ailus
@ 2020-01-08 16:50     ` Helen Koike
  2020-01-08 18:08       ` Sakari Ailus
  0 siblings, 1 reply; 35+ messages in thread
From: Helen Koike @ 2020-01-08 16:50 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: mark.rutland, devicetree, eddie.cai.linux, kernel, heiko,
	linux-arm-kernel, ezequiel, gregkh, linux-kernel, tfiga,
	linux-rockchip, robh+dt, hans.verkuil, laurent.pinchart,
	joacim.zetterling, mchehab, andrey.konovalov, jacob-chen,
	linux-media

Hi,

Thank you for your review.

On 1/7/20 12:01 PM, Sakari Ailus wrote:
> Hi Helen,
> 
> On Fri, Dec 27, 2019 at 05:01:13PM -0300, Helen Koike wrote:
>> 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 <helen.koike@collabora.com>
>>
>> ---
>>
>> 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         | 193 ++++++++++++++++++
>>  1 file changed, 193 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..4d1b2c67a4cd
>> --- /dev/null
>> +++ b/drivers/staging/media/rkisp1/Documentation/devicetree/bindings/media/rockchip-isp1.yaml
>> @@ -0,0 +1,193 @@
>> +# 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 <helen.koike@collabora.com>
>> +
>> +description: |
>> +  Rockchip ISP1 is the Camera interface for the Rockchip series of SoCs
>> +  which contains image processing, scaling, and compression funcitons.
> 
> "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 aclk clock
>> +      - description: ISP aclk wrapper clock
>> +      - description: ISP hclk clock
>> +      - description: ISP hclk 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:
> 
> If you only have a single port node, you could drop reg as well as @0 on
> the port node.

After the discussions, we have a single port for now, but we might have port@1
for tx1rx1 in the future.

Helen

> 
>> +        type: object
>> +        additionalProperties: false
>> +
>> +        properties:
>> +          "#address-cells":
>> +            const: 1
>> +
>> +          "#size-cells":
>> +            const: 0
>> +
>> +          reg:
>> +            const: 0
>> +            description: port identifier.
>> +
>> +        patternProperties:
>> +          endpoint:
>> +            type: object
>> +            additionalProperties: false
>> +
>> +            properties:
>> +              reg:
>> +                maxItems: 1
>> +                description: endpoint identifier.
>> +
>> +              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 <dt-bindings/clock/rk3399-cru.h>
>> +    #include <dt-bindings/interrupt-controller/arm-gic.h>
>> +    #include <dt-bindings/power/rk3399-power.h>
>> +
>> +    parent0: parent@0 {
>> +        #address-cells = <2>;
>> +        #size-cells = <2>;
>> +
>> +        isp0: isp0@ff910000 {
>> +            compatible = "rockchip,rk3399-cif-isp";
>> +            reg = <0x0 0xff910000 0x0 0x4000>;
>> +            interrupts = <GIC_SPI 43 IRQ_TYPE_LEVEL_HIGH 0>;
>> +            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>;
>> +                      };
>> +                  };
>> +            };
>> +        };
>> +    };
> 

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v12 08/11] media: staging: dt-bindings: add Rockchip ISP1 yaml bindings
  2020-01-08 16:50     ` Helen Koike
@ 2020-01-08 18:08       ` Sakari Ailus
  0 siblings, 0 replies; 35+ messages in thread
From: Sakari Ailus @ 2020-01-08 18:08 UTC (permalink / raw)
  To: Helen Koike
  Cc: mark.rutland, devicetree, eddie.cai.linux, kernel, heiko,
	linux-arm-kernel, ezequiel, gregkh, linux-kernel, tfiga,
	linux-rockchip, robh+dt, hans.verkuil, laurent.pinchart,
	joacim.zetterling, mchehab, andrey.konovalov, jacob-chen,
	linux-media

On Wed, Jan 08, 2020 at 01:50:38PM -0300, Helen Koike wrote:
> Hi,
> 
> Thank you for your review.
> 
> On 1/7/20 12:01 PM, Sakari Ailus wrote:
> > Hi Helen,
> > 
> > On Fri, Dec 27, 2019 at 05:01:13PM -0300, Helen Koike wrote:
> >> 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 <helen.koike@collabora.com>
> >>
> >> ---
> >>
> >> 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         | 193 ++++++++++++++++++
> >>  1 file changed, 193 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..4d1b2c67a4cd
> >> --- /dev/null
> >> +++ b/drivers/staging/media/rkisp1/Documentation/devicetree/bindings/media/rockchip-isp1.yaml
> >> @@ -0,0 +1,193 @@
> >> +# 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 <helen.koike@collabora.com>
> >> +
> >> +description: |
> >> +  Rockchip ISP1 is the Camera interface for the Rockchip series of SoCs
> >> +  which contains image processing, scaling, and compression funcitons.
> > 
> > "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 aclk clock
> >> +      - description: ISP aclk wrapper clock
> >> +      - description: ISP hclk clock
> >> +      - description: ISP hclk 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:
> > 
> > If you only have a single port node, you could drop reg as well as @0 on
> > the port node.
> 
> After the discussions, we have a single port for now, but we might have port@1
> for tx1rx1 in the future.

Ack. Please keep it as-is then.

-- 
Sakari Ailus
sakari.ailus@linux.intel.com

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 35+ messages in thread

end of thread, other threads:[~2020-01-08 18:09 UTC | newest]

Thread overview: 35+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-12-27 20:01 [PATCH v12 00/11] Rockchip ISP Driver Helen Koike
2019-12-27 20:01 ` [PATCH v12 01/11] media: staging: phy-rockchip-dphy: add Rockchip MIPI Synopsys DPHY driver Helen Koike
2019-12-30 18:25   ` Ezequiel Garcia
2020-01-07  1:11   ` Laurent Pinchart
2020-01-07 15:58     ` Ezequiel Garcia
2020-01-07 16:18       ` Laurent Pinchart
2019-12-27 20:01 ` [PATCH v12 03/11] media: staging: rkisp1: add streaming paths Helen Koike
2019-12-27 20:01 ` [PATCH v12 04/11] media: staging: rkisp1: add user space ABI definitions Helen Koike
2019-12-27 20:01 ` [PATCH v12 05/11] media: staging: rkisp1: add capture device for statistics Helen Koike
2019-12-27 20:01 ` [PATCH v12 06/11] media: staging: rkisp1: add output device for parameters Helen Koike
2019-12-27 20:01 ` [PATCH v12 07/11] media: staging: rkisp1: add document for rkisp1 meta buffer format Helen Koike
2019-12-27 20:01 ` [PATCH v12 08/11] media: staging: dt-bindings: add Rockchip ISP1 yaml bindings Helen Koike
2020-01-06 22:27   ` Rob Herring
2020-01-06 23:59   ` Laurent Pinchart
2020-01-07 13:45     ` Ezequiel Garcia
2020-01-07 16:19       ` Laurent Pinchart
2020-01-07 14:01   ` Sakari Ailus
2020-01-08 16:50     ` Helen Koike
2020-01-08 18:08       ` Sakari Ailus
2019-12-27 20:01 ` [PATCH v12 09/11] media: staging: dt-bindings: add Rockchip MIPI RX D-PHY " Helen Koike
2020-01-06 22:29   ` Rob Herring
2020-01-07  0:10   ` Laurent Pinchart
2020-01-07  2:06     ` Ezequiel Garcia
2020-01-07  2:37       ` Laurent Pinchart
2020-01-07  9:28         ` Heiko Stübner
2020-01-07 13:20           ` Ezequiel Garcia
2020-01-07 21:30             ` Heiko Stübner
2020-01-07 21:57               ` Laurent Pinchart
2020-01-07 22:12                 ` Heiko Stuebner
2020-01-07 22:03               ` Ezequiel Garcia
2020-01-07 22:25                 ` Heiko Stuebner
2020-01-07 22:41                   ` Ezequiel Garcia
2019-12-27 20:01 ` [PATCH v12 10/11] media: staging: rkisp1: add TODO file for staging Helen Koike
2019-12-27 20:01 ` [PATCH v12 11/11] MAINTAINERS: add entry for Rockchip ISP1 driver Helen Koike
     [not found] ` <20191227200116.2612137-3-helen.koike@collabora.com>
2019-12-30 18:13   ` [PATCH v12 02/11] media: staging: rkisp1: add Rockchip ISP1 base driver Ezequiel Garcia

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).