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

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


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

* [PATCH v12 00/11] Rockchip ISP Driver
@ 2019-12-27 20:01 ` Helen Koike
  0 siblings, 0 replies; 74+ 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] 74+ messages in thread

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

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


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

* [PATCH v12 01/11] media: staging: phy-rockchip-dphy: add Rockchip MIPI Synopsys DPHY driver
@ 2019-12-27 20:01   ` Helen Koike
  0 siblings, 0 replies; 74+ 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] 74+ messages in thread

* [PATCH v12 02/11] media: staging: rkisp1: add Rockchip ISP1 base driver
  2019-12-27 20:01 ` Helen Koike
  (?)
  (?)
@ 2019-12-27 20:01 ` Helen Koike
  2019-12-30 18:13     ` Ezequiel Garcia
  -1 siblings, 1 reply; 74+ messages in thread
From: Helen Koike @ 2019-12-27 20:01 UTC (permalink / raw)
  To: linux-rockchip
  Cc: mark.rutland, devicetree, eddie.cai.linux, mchehab, heiko,
	gregkh, andrey.konovalov, linux-kernel, tfiga, robh+dt,
	hans.verkuil, laurent.pinchart, sakari.ailus, joacim.zetterling,
	kernel, ezequiel, linux-media, jacob-chen, linux-arm-kernel,
	Helen Koike, Jacob Chen, Shunqian Zheng, Yichong Zhong,
	Jacob Chen, Jeffy Chen, Allon Huang

Add base driver for Rockchip Image Signal Processing v1 Unit, with isp
subdevice and sensor biddings.

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>
[fixed compilation and run time errors regarding new v4l2 async API]
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
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, re-structuring
- Fix format/crop pad propagation
- Commit re-organization to not break bisectability
- Fix module's license macro

Changes in v11:
- Fix compiling warnings
- Fix checkpatch errors

Changes in v10:
- unsquash

Changes in v9:
isp
- remove unnecessary double parenthesis
- remove double call to media_entity_remote_pad(local) in
get_remote_sensor()
- remove ctrl_handler from struct rkisp1_isp_subdev
- replace v4l2_{dgb,info,warn,err} by dev_*
- fix error returned in link_validate
- remove s_power() callback
- add regwrite/regread wrappers
- add macros RKISP1_DEF_SRC_PAD_FMT/RKISP1_DEF_SINK_PAD_FMT
- several minor cleanups
- s/RKISP1_ISP_PAD_SINK([^_])/RKISP1_ISP_PAD_SINK_VIDEO\1/
- merge tables rkisp1_isp_input_formats and rkisp1_isp_output_formats
- in_fmt and out_fmt as pointers
- simply struct rkisp1_isp_subdev to work correctly with try format
- fix crop/fmt propagation
- squash
- migrate to staging
core
- remove ctrl_handler from struct rkisp1_isp_subdev
- replace v4l2_{dgb,info,warn,err} by dev_*
- s/pr_info/dev_dbg
- s/int size/unsigned int size
- remove module param rkisp1_debug
- coding style fixes
- fix error in subdev_notifier_bound, check dphy before assigning to sensor->dphy
- remove subdevs fixed size array from rkisp1_pipeline
- remove sensors list, as it can be identified from the media topology
- Kconfig: add COMPILE_TEST in the dependency
- use v4l2_pipeline_pm_use and remove _isp_pipeline_s_power() and _subdev_set_power()
- remove struct rkisp1_pipeline and retrieve pipeline information from the media framework
- remove remaining rk3288 code
- cache pixel rate control in sctruct sensor_async_subdev
- remove enum rkisp1_sd_type
- squash
- move to staging

Changes in v8: None
Changes in v7:
isp
- fixed warning because of unknown entity type
- fixed v4l2-compliance errors regarding rkisp1 formats, try formats
and default values
- fix typo riksp1/rkisp1
- redesign: remove mipi/csi subdevice, sensors connect directly to the
isp subdevice in the media topology now. As a consequence, remove the
hack in mipidphy_g_mbus_config() where information from the sensor was
being propagated through the topology.
- From the old dphy:
        * cache get_remote_sensor() in s_stream
        * use V4L2_CID_PIXEL_RATE instead of V4L2_CID_LINK_FREQ
- Replace stream state with a boolean
- code styling and checkpatch fixes
- fix stop_stream (return after calling stop, do not reenable the stream)
- fix rkisp1_isp_sd_get_selection when V4L2_SUBDEV_FORMAT_TRY is set
- fix get format in output (isp_sd->out_fmt.mbus_code was being ignored)
- s/intput/input
- remove #define sd_to_isp_sd(_sd), add a static inline as it will be
reused by the capture
core
- VIDEO_ROCKCHIP_ISP1 selects VIDEOBUF2_VMALLOC
- add PHY_ROCKCHIP_DPHY as a dependency for VIDEO_ROCKCHIP_ISP1
- Fix compilation and runtime errors due to bitrotting
The code has bit-rotten since March 2018, fix compilation errors.
The new V4L2 async notifier API requires notifiers to be initialized by
a call to v4l2_async_notifier_init() before being used, do so.
- Add missing module device table
- use clk_bulk framework
- add missing notifiers cleanups
- s/strlcpy/strscpy
- normalize bus_info name
- fix s_stream error path, stream_cnt wans't being decremented properly
- use devm_platform_ioremap_resource() helper
- s/deice/device
- redesign: remove mipi/csi subdevice, sensors connect directly to the
isp subdevice in the media topology now.
- remove "saved_state" member from rkisp1_stream struct
- Reverse the order of MIs
- Simplify MI interrupt handling
Rather than adding unnecessary indirection, just use stream index to
handle MI interrupt enable/disable/clear, since the stream index matches
the order of bits now, thanks to previous patch. While at it, remove
some dead code.
- code styling and checkpatch fixes

 drivers/staging/media/Kconfig                |    2 +
 drivers/staging/media/Makefile               |    1 +
 drivers/staging/media/rkisp1/Kconfig         |   13 +
 drivers/staging/media/rkisp1/Makefile        |    4 +
 drivers/staging/media/rkisp1/rkisp1-common.c |   37 +
 drivers/staging/media/rkisp1/rkisp1-common.h |  200 +++
 drivers/staging/media/rkisp1/rkisp1-dev.c    |  466 +++++++
 drivers/staging/media/rkisp1/rkisp1-isp.c    | 1133 ++++++++++++++++
 drivers/staging/media/rkisp1/rkisp1-regs.h   | 1264 ++++++++++++++++++
 9 files changed, 3120 insertions(+)
 create mode 100644 drivers/staging/media/rkisp1/Kconfig
 create mode 100644 drivers/staging/media/rkisp1/Makefile
 create mode 100644 drivers/staging/media/rkisp1/rkisp1-common.c
 create mode 100644 drivers/staging/media/rkisp1/rkisp1-common.h
 create mode 100644 drivers/staging/media/rkisp1/rkisp1-dev.c
 create mode 100644 drivers/staging/media/rkisp1/rkisp1-isp.c
 create mode 100644 drivers/staging/media/rkisp1/rkisp1-regs.h

diff --git a/drivers/staging/media/Kconfig b/drivers/staging/media/Kconfig
index a47484473883..db467c5c2fd2 100644
--- a/drivers/staging/media/Kconfig
+++ b/drivers/staging/media/Kconfig
@@ -40,4 +40,6 @@ source "drivers/staging/media/soc_camera/Kconfig"
 
 source "drivers/staging/media/phy-rockchip-dphy/Kconfig"
 
+source "drivers/staging/media/rkisp1/Kconfig"
+
 endif
diff --git a/drivers/staging/media/Makefile b/drivers/staging/media/Makefile
index b0eae3906208..1beb9a6374b0 100644
--- a/drivers/staging/media/Makefile
+++ b/drivers/staging/media/Makefile
@@ -9,3 +9,4 @@ obj-$(CONFIG_VIDEO_HANTRO)	+= hantro/
 obj-$(CONFIG_VIDEO_IPU3_IMGU)	+= ipu3/
 obj-$(CONFIG_SOC_CAMERA)	+= soc_camera/
 obj-$(CONFIG_PHY_ROCKCHIP_DPHY)		+= phy-rockchip-dphy/
+obj-$(CONFIG_VIDEO_ROCKCHIP_ISP1)	+= rkisp1/
diff --git a/drivers/staging/media/rkisp1/Kconfig b/drivers/staging/media/rkisp1/Kconfig
new file mode 100644
index 000000000000..7fa7b402ae0d
--- /dev/null
+++ b/drivers/staging/media/rkisp1/Kconfig
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+config VIDEO_ROCKCHIP_ISP1
+	tristate "Rockchip Image Signal Processing v1 Unit driver"
+	depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
+	depends on ARCH_ROCKCHIP || COMPILE_TEST
+	select VIDEOBUF2_DMA_CONTIG
+	select VIDEOBUF2_VMALLOC
+	select V4L2_FWNODE
+	select PHY_ROCKCHIP_DPHY
+	default n
+	help
+	  Support for ISP1 on the rockchip SoC.
diff --git a/drivers/staging/media/rkisp1/Makefile b/drivers/staging/media/rkisp1/Makefile
new file mode 100644
index 000000000000..2faa73fc2b7f
--- /dev/null
+++ b/drivers/staging/media/rkisp1/Makefile
@@ -0,0 +1,4 @@
+obj-$(CONFIG_VIDEO_ROCKCHIP_ISP1) += rockchip-isp1.o
+rockchip-isp1-objs += 	rkisp1-common.o \
+			rkisp1-dev.o \
+			rkisp1-isp.o
diff --git a/drivers/staging/media/rkisp1/rkisp1-common.c b/drivers/staging/media/rkisp1/rkisp1-common.c
new file mode 100644
index 000000000000..cf889666e166
--- /dev/null
+++ b/drivers/staging/media/rkisp1/rkisp1-common.c
@@ -0,0 +1,37 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Rockchip ISP1 Driver - Common definitions
+ *
+ * Copyright (C) 2019 Collabora, Ltd.
+ */
+
+#include <media/v4l2-rect.h>
+
+#include "rkisp1-common.h"
+
+static const struct v4l2_rect rkisp1_sd_min_crop = {
+	.width = RKISP1_ISP_MIN_WIDTH,
+	.height = RKISP1_ISP_MIN_HEIGHT,
+	.top = 0,
+	.left = 0,
+};
+
+void rkisp1_sd_adjust_crop_rect(struct v4l2_rect *crop,
+				const struct v4l2_rect *bounds)
+{
+	v4l2_rect_set_min_size(crop, &rkisp1_sd_min_crop);
+	v4l2_rect_map_inside(crop, bounds);
+}
+
+void rkisp1_sd_adjust_crop(struct v4l2_rect *crop,
+			   const struct v4l2_mbus_framefmt *bounds)
+{
+	struct v4l2_rect crop_bounds = {
+		.left = 0,
+		.top = 0,
+		.width = bounds->width,
+		.height = bounds->height,
+	};
+
+	rkisp1_sd_adjust_crop_rect(crop, &crop_bounds);
+}
diff --git a/drivers/staging/media/rkisp1/rkisp1-common.h b/drivers/staging/media/rkisp1/rkisp1-common.h
new file mode 100644
index 000000000000..111f49224402
--- /dev/null
+++ b/drivers/staging/media/rkisp1/rkisp1-common.h
@@ -0,0 +1,200 @@
+/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
+/*
+ * Rockchip ISP1 Driver - Common definitions
+ *
+ * Copyright (C) 2019 Collabora, Ltd.
+ *
+ * Based on Rockchip ISP1 driver by Rockchip Electronics Co., Ltd.
+ * Copyright (C) 2017 Rockchip Electronics Co., Ltd.
+ */
+
+#ifndef _RKISP1_COMMON_H
+#define _RKISP1_COMMON_H
+
+#include <linux/clk.h>
+#include <linux/mutex.h>
+#include <media/media-device.h>
+#include <media/media-entity.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/videobuf2-v4l2.h>
+
+#include "rkisp1-regs.h"
+
+#define RKISP1_ISP_MAX_WIDTH		4032
+#define RKISP1_ISP_MAX_HEIGHT		3024
+#define RKISP1_ISP_MIN_WIDTH		32
+#define RKISP1_ISP_MIN_HEIGHT		32
+
+#define RKISP1_RSZ_MP_SRC_MAX_WIDTH		4416
+#define RKISP1_RSZ_MP_SRC_MAX_HEIGHT		3312
+#define RKISP1_RSZ_SP_SRC_MAX_WIDTH		1920
+#define RKISP1_RSZ_SP_SRC_MAX_HEIGHT		1920
+#define RKISP1_RSZ_SRC_MIN_WIDTH		32
+#define RKISP1_RSZ_SRC_MIN_HEIGHT		16
+
+#define RKISP1_DEFAULT_WIDTH		800
+#define RKISP1_DEFAULT_HEIGHT		600
+
+#define RKISP1_DRIVER_NAME	"rkisp1"
+#define RKISP1_BUS_INFO		"platform: " RKISP1_DRIVER_NAME
+
+#define RKISP1_MAX_BUS_CLK	8
+
+enum rkisp1_fmt_pix_type {
+	RKISP1_FMT_YUV,
+	RKISP1_FMT_RGB,
+	RKISP1_FMT_BAYER,
+	RKISP1_FMT_JPEG,
+};
+
+enum rkisp1_fmt_raw_pat_type {
+	RKISP1_RAW_RGGB = 0,
+	RKISP1_RAW_GRBG,
+	RKISP1_RAW_GBRG,
+	RKISP1_RAW_BGGR,
+};
+
+enum rkisp1_isp_pad {
+	RKISP1_ISP_PAD_SINK_VIDEO,
+	RKISP1_ISP_PAD_SINK_PARAMS,
+	RKISP1_ISP_PAD_SOURCE_VIDEO,
+	RKISP1_ISP_PAD_SOURCE_STATS,
+	RKISP1_ISP_PAD_MAX
+};
+
+/*
+ * struct rkisp1_sensor_async - Sensor information
+ * @mbus: media bus configuration
+ */
+struct rkisp1_sensor_async {
+	struct v4l2_async_subdev asd;
+	struct v4l2_mbus_config mbus;
+	unsigned int lanes;
+	struct v4l2_subdev *sd;
+	struct v4l2_ctrl *pixel_rate_ctrl;
+	struct phy *dphy;
+};
+
+/*
+ * struct rkisp1_isp - ISP sub-device
+ *
+ * See Cropping regions of ISP in rkisp1.c for details
+ * @sink_frm: input size, don't have to be equal to sensor size
+ * @sink_fmt: input format
+ * @sink_crop: crop for sink pad
+ * @src_fmt: output format
+ * @src_crop: output size
+ *
+ * @is_dphy_errctrl_disabled : if dphy errctrl is disabled (avoid endless interrupt)
+ * @frame_sequence: used to synchronize frame_id between video devices.
+ * @quantization: output quantization
+ */
+struct rkisp1_isp {
+	struct v4l2_subdev sd;
+	struct media_pad pads[RKISP1_ISP_PAD_MAX];
+	struct v4l2_subdev_pad_config pad_cfg[RKISP1_ISP_PAD_MAX];
+	const struct rkisp1_isp_mbus_info *sink_fmt;
+	const struct rkisp1_isp_mbus_info *src_fmt;
+	bool is_dphy_errctrl_disabled;
+	atomic_t frame_sequence;
+};
+
+struct rkisp1_vdev_node {
+	struct vb2_queue buf_queue;
+	struct mutex vlock; /* ioctl serialization mutex */
+	struct video_device vdev;
+	struct media_pad pad;
+};
+
+struct rkisp1_buffer {
+	struct vb2_v4l2_buffer vb;
+	struct list_head queue;
+	union {
+		u32 buff_addr[VIDEO_MAX_PLANES];
+		void *vaddr[VIDEO_MAX_PLANES];
+	};
+};
+
+struct rkisp1_dummy_buffer {
+	void *vaddr;
+	dma_addr_t dma_addr;
+	u32 size;
+};
+
+struct rkisp1_device;
+
+struct rkisp1_debug {
+	struct dentry *debugfs_dir;
+	unsigned long data_loss;
+	unsigned long pic_size_error;
+	unsigned long mipi_error;
+};
+
+/*
+ * struct rkisp1_device - ISP platform device
+ * @base_addr: base register address
+ * @active_sensor: sensor in-use, set when streaming on
+ * @isp: ISP sub-device
+ */
+struct rkisp1_device {
+	void __iomem *base_addr;
+	int irq;
+	struct device *dev;
+	unsigned int clk_size;
+	struct clk_bulk_data clks[RKISP1_MAX_BUS_CLK];
+	struct v4l2_device v4l2_dev;
+	struct v4l2_ctrl_handler ctrl_handler;
+	struct media_device media_dev;
+	struct v4l2_async_notifier notifier;
+	struct rkisp1_sensor_async *active_sensor;
+	struct rkisp1_isp isp;
+	struct media_pipeline pipe;
+	struct vb2_alloc_ctx *alloc_ctx;
+	struct rkisp1_debug debug;
+};
+
+/*
+ * struct rkisp1_isp_mbus_info - ISP pad format info
+ *
+ * Translate mbus_code to hardware format values
+ *
+ * @bus_width: used for parallel
+ */
+struct rkisp1_isp_mbus_info {
+	u32 mbus_code;
+	enum rkisp1_fmt_pix_type fmt_type;
+	u32 mipi_dt;
+	u32 yuv_seq;
+	u8 bus_width;
+	enum rkisp1_fmt_raw_pat_type bayer_pat;
+	unsigned int direction;
+};
+
+static inline void
+rkisp1_write(struct rkisp1_device *rkisp1, u32 val, unsigned int addr)
+{
+	writel(val, rkisp1->base_addr + addr);
+}
+
+static inline u32 rkisp1_read(struct rkisp1_device *rkisp1, unsigned int addr)
+{
+	return readl(rkisp1->base_addr + addr);
+}
+
+void rkisp1_sd_adjust_crop_rect(struct v4l2_rect *crop,
+				const struct v4l2_rect *bounds);
+
+void rkisp1_sd_adjust_crop(struct v4l2_rect *crop,
+			   const struct v4l2_mbus_framefmt *bounds);
+
+int rkisp1_isp_register(struct rkisp1_device *rkisp1,
+			struct v4l2_device *v4l2_dev);
+void rkisp1_isp_unregister(struct rkisp1_device *rkisp1);
+
+const struct rkisp1_isp_mbus_info *rkisp1_isp_mbus_info_get(u32 mbus_code);
+
+void rkisp1_isp_isr(struct rkisp1_device *rkisp1);
+void rkisp1_mipi_isr(struct rkisp1_device *rkisp1);
+
+#endif /* _RKISP1_COMMON_H */
diff --git a/drivers/staging/media/rkisp1/rkisp1-dev.c b/drivers/staging/media/rkisp1/rkisp1-dev.c
new file mode 100644
index 000000000000..fa8f8b673f9f
--- /dev/null
+++ b/drivers/staging/media/rkisp1/rkisp1-dev.c
@@ -0,0 +1,466 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Rockchip ISP1 Driver - Base driver
+ *
+ * Copyright (C) 2019 Collabora, Ltd.
+ *
+ * Based on Rockchip ISP1 driver by Rockchip Electronics Co., Ltd.
+ * Copyright (C) 2017 Rockchip Electronics Co., Ltd.
+ */
+
+#include <linux/clk.h>
+#include <linux/debugfs.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_graph.h>
+#include <linux/of_platform.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/phy/phy.h>
+#include <linux/phy/phy-mipi-dphy.h>
+#include <media/v4l2-fwnode.h>
+
+#include "rkisp1-common.h"
+
+/*
+ * ISP Details
+ * -----------
+ *
+ * ISP Comprises with:
+ *	MIPI serial camera interface
+ *	Image Signal Processing
+ *	Many Image Enhancement Blocks
+ *	Crop
+ *	Resizer
+ *	RBG display ready image
+ *	Image Rotation
+ *
+ * ISP Block Diagram
+ * -----------------
+ *                                rkisp1-isp.c                              Main Picture Path
+ *                        |==========================|      |===============================================|
+ *                        +-----------+  +--+--+--+--+      +--------+  +--------+              +-----------+
+ *                        |           |  |  |  |  |  |      |        |  |        |              |           |
+ * +--------+    |\       |           |  |  |  |  |  |   -->|  Crop  |->|  RSZ   |------------->|           |
+ * |  MIPI  |--->|  \     |           |  |  |  |  |  |   |  |        |  |        |              |           |
+ * +--------+    |   |    |           |  |IE|IE|IE|IE|   |  +--------+  +--------+              |  Memory   |
+ *               |MUX|--->|    ISP    |->|0 |1 |2 |3 |---+                                      | Interface |
+ * +--------+    |   |    |           |  |  |  |  |  |   |  +--------+  +--------+  +--------+  |           |
+ * |Parallel|--->|  /     |           |  |  |  |  |  |   |  |        |  |        |  |        |  |           |
+ * +--------+    |/       |           |  |  |  |  |  |   -->|  Crop  |->|  RSZ   |->|  RGB   |->|           |
+ *                        |           |  |  |  |  |  |      |        |  |        |  | Rotate |  |           |
+ *                        +-----------+  +--+--+--+--+      +--------+  +--------+  +--------+  +-----------+
+ *                                               ^
+ * +--------+                                    |          |===============================================|
+ * |  DMA   |------------------------------------+                          Self Picture Path
+ * +--------+
+ *
+ *
+ * Media Topology
+ * --------------
+ *      +----------+     +----------+
+ *      | Sensor 2 |     | Sensor X |
+ *      ------------ ... ------------
+ *      |    0     |     |    0     |
+ *      +----------+     +----------+
+ *                  \      |
+ *                   \     |
+ *    +----------+    \    |
+ *    | Sensor 1 |     v   v
+ *    ------------      +------+------+
+ *    |    0     |----->|  0   |  1   |
+ *    +----------+      |------+------|
+ *                      |     ISP     |
+ *                      |------+------|
+ *                      |  2   |  3   |
+ *                      +------+------+
+ */
+
+struct rkisp1_match_data {
+	const char * const *clks;
+	unsigned int size;
+};
+
+/* ----------------------------------------------------------------------------
+ * Sensor DT bindings
+ */
+
+static int rkisp1_create_links(struct rkisp1_device *rkisp1)
+{
+	unsigned int flags, source_pad;
+	struct v4l2_subdev *sd;
+	int ret;
+
+	/* sensor links */
+	flags = MEDIA_LNK_FL_ENABLED;
+	list_for_each_entry(sd, &rkisp1->v4l2_dev.subdevs, list) {
+		if (sd == &rkisp1->isp.sd)
+			continue;
+
+		ret = media_entity_get_fwnode_pad(&sd->entity, sd->fwnode,
+						  MEDIA_PAD_FL_SOURCE);
+		if (ret) {
+			dev_err(sd->dev, "failed to find src pad for %s\n",
+				sd->name);
+			return ret;
+		}
+		source_pad = ret;
+
+		ret = media_create_pad_link(&sd->entity, source_pad,
+					    &rkisp1->isp.sd.entity,
+					    RKISP1_ISP_PAD_SINK_VIDEO,
+					    flags);
+		if (ret)
+			return ret;
+
+		flags = 0;
+	}
+
+	return 0;
+}
+
+static int rkisp1_subdev_notifier_bound(struct v4l2_async_notifier *notifier,
+					struct v4l2_subdev *sd,
+					struct v4l2_async_subdev *asd)
+{
+	struct rkisp1_device *rkisp1 =
+		container_of(notifier, struct rkisp1_device, notifier);
+	struct rkisp1_sensor_async *s_asd =
+		container_of(asd, struct rkisp1_sensor_async, asd);
+
+	s_asd->pixel_rate_ctrl = v4l2_ctrl_find(sd->ctrl_handler,
+						V4L2_CID_PIXEL_RATE);
+	s_asd->sd = sd;
+	s_asd->dphy = devm_phy_get(rkisp1->dev, "dphy");
+	if (IS_ERR(s_asd->dphy)) {
+		if (PTR_ERR(s_asd->dphy) != -EPROBE_DEFER)
+			dev_err(rkisp1->dev, "Couldn't get the MIPI D-PHY\n");
+		return PTR_ERR(s_asd->dphy);
+	}
+
+	phy_init(s_asd->dphy);
+
+	return 0;
+}
+
+static void rkisp1_subdev_notifier_unbind(struct v4l2_async_notifier *notifier,
+					  struct v4l2_subdev *sd,
+					  struct v4l2_async_subdev *asd)
+{
+	struct rkisp1_sensor_async *s_asd =
+		container_of(asd, struct rkisp1_sensor_async, asd);
+
+	phy_exit(s_asd->dphy);
+}
+
+static int rkisp1_subdev_notifier_complete(struct v4l2_async_notifier *notifier)
+{
+	struct rkisp1_device *rkisp1 =
+		container_of(notifier, struct rkisp1_device, notifier);
+	int ret;
+
+	mutex_lock(&rkisp1->media_dev.graph_mutex);
+	ret = rkisp1_create_links(rkisp1);
+	if (ret)
+		goto unlock;
+	ret = v4l2_device_register_subdev_nodes(&rkisp1->v4l2_dev);
+	if (ret)
+		goto unlock;
+
+	dev_dbg(rkisp1->dev, "Async subdev notifier completed\n");
+
+unlock:
+	mutex_unlock(&rkisp1->media_dev.graph_mutex);
+	return ret;
+}
+
+static int rkisp1_fwnode_parse(struct device *dev,
+			       struct v4l2_fwnode_endpoint *vep,
+			       struct v4l2_async_subdev *asd)
+{
+	struct rkisp1_sensor_async *s_asd =
+			container_of(asd, struct rkisp1_sensor_async, asd);
+
+	if (vep->bus_type != V4L2_MBUS_CSI2_DPHY) {
+		dev_err(dev, "Only CSI2 bus type is currently supported\n");
+		return -EINVAL;
+	}
+
+	if (vep->base.port != 0) {
+		dev_err(dev, "The ISP has only port 0\n");
+		return -EINVAL;
+	}
+
+	s_asd->mbus.type = vep->bus_type;
+	s_asd->mbus.flags = vep->bus.mipi_csi2.flags;
+	s_asd->lanes = vep->bus.mipi_csi2.num_data_lanes;
+
+	switch (vep->bus.mipi_csi2.num_data_lanes) {
+	case 1:
+		s_asd->mbus.flags |= V4L2_MBUS_CSI2_1_LANE;
+		break;
+	case 2:
+		s_asd->mbus.flags |= V4L2_MBUS_CSI2_2_LANE;
+		break;
+	case 3:
+		s_asd->mbus.flags |= V4L2_MBUS_CSI2_3_LANE;
+		break;
+	case 4:
+		s_asd->mbus.flags |= V4L2_MBUS_CSI2_4_LANE;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static const struct v4l2_async_notifier_operations rkisp1_subdev_notifier_ops = {
+	.bound = rkisp1_subdev_notifier_bound,
+	.unbind = rkisp1_subdev_notifier_unbind,
+	.complete = rkisp1_subdev_notifier_complete,
+};
+
+static int rkisp1_subdev_notifier(struct rkisp1_device *rkisp1)
+{
+	struct v4l2_async_notifier *ntf = &rkisp1->notifier;
+	struct device *dev = rkisp1->dev;
+	int ret;
+
+	v4l2_async_notifier_init(ntf);
+
+	ret = v4l2_async_notifier_parse_fwnode_endpoints_by_port(dev, ntf,
+					sizeof(struct rkisp1_sensor_async),
+					0, rkisp1_fwnode_parse);
+	if (ret)
+		return ret;
+
+	if (list_empty(&ntf->asd_list))
+		return -ENODEV;
+
+	ntf->ops = &rkisp1_subdev_notifier_ops;
+
+	return v4l2_async_notifier_register(&rkisp1->v4l2_dev, ntf);
+}
+
+/* ----------------------------------------------------------------------------
+ * Power
+ */
+
+static int __maybe_unused rkisp1_runtime_suspend(struct device *dev)
+{
+	struct rkisp1_device *rkisp1 = dev_get_drvdata(dev);
+
+	clk_bulk_disable_unprepare(rkisp1->clk_size, rkisp1->clks);
+	return pinctrl_pm_select_sleep_state(dev);
+}
+
+static int __maybe_unused rkisp1_runtime_resume(struct device *dev)
+{
+	struct rkisp1_device *rkisp1 = dev_get_drvdata(dev);
+	int ret;
+
+	ret = pinctrl_pm_select_default_state(dev);
+	if (ret)
+		return ret;
+	ret = clk_bulk_prepare_enable(rkisp1->clk_size, rkisp1->clks);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static const struct dev_pm_ops rkisp1_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+				pm_runtime_force_resume)
+	SET_RUNTIME_PM_OPS(rkisp1_runtime_suspend, rkisp1_runtime_resume, NULL)
+};
+
+/* ----------------------------------------------------------------------------
+ * Core
+ */
+
+static int rkisp1_entities_register(struct rkisp1_device *rkisp1)
+{
+	int ret;
+
+	ret = rkisp1_isp_register(rkisp1, &rkisp1->v4l2_dev);
+	if (ret)
+		return ret;
+
+	ret = rkisp1_subdev_notifier(rkisp1);
+	if (ret) {
+		dev_err(rkisp1->dev,
+			"Failed to register subdev notifier(%d)\n", ret);
+		rkisp1_isp_unregister(rkisp1);
+		return ret;
+	}
+
+	return 0;
+}
+
+static irqreturn_t rkisp1_isr(int irq, void *ctx)
+{
+	struct device *dev = ctx;
+	struct rkisp1_device *rkisp1 = dev_get_drvdata(dev);
+
+	rkisp1_isp_isr(rkisp1);
+	rkisp1_mipi_isr(rkisp1);
+
+	return IRQ_HANDLED;
+}
+
+static const char * const rk3399_isp_clks[] = {
+	"clk_isp",
+	"aclk_isp",
+	"hclk_isp",
+	"aclk_isp_wrap",
+	"hclk_isp_wrap",
+};
+
+static const struct rkisp1_match_data rk3399_isp_clk_data = {
+	.clks = rk3399_isp_clks,
+	.size = ARRAY_SIZE(rk3399_isp_clks),
+};
+
+static const struct of_device_id rkisp1_of_match[] = {
+	{
+		.compatible = "rockchip,rk3399-cif-isp",
+		.data = &rk3399_isp_clk_data,
+	},
+	{},
+};
+MODULE_DEVICE_TABLE(of, rkisp1_of_match);
+
+static void rkisp1_debug_init(struct rkisp1_device *rkisp1)
+{
+	struct rkisp1_debug *debug = &rkisp1->debug;
+
+	debug->debugfs_dir = debugfs_create_dir(RKISP1_DRIVER_NAME, NULL);
+	if (!debug->debugfs_dir) {
+		dev_dbg(rkisp1->dev, "failed to create debugfs directory\n");
+		return;
+	}
+	debugfs_create_ulong("data_loss", 0444, debug->debugfs_dir,
+			     &debug->data_loss);
+	debugfs_create_ulong("pic_size_error", 0444,  debug->debugfs_dir,
+			     &debug->pic_size_error);
+	debugfs_create_ulong("mipi_error", 0444, debug->debugfs_dir,
+			     &debug->mipi_error);
+}
+
+static int rkisp1_probe(struct platform_device *pdev)
+{
+	struct device_node *node = pdev->dev.of_node;
+	const struct rkisp1_match_data *clk_data;
+	const struct of_device_id *match;
+	struct device *dev = &pdev->dev;
+	struct rkisp1_device *rkisp1;
+	struct v4l2_device *v4l2_dev;
+	unsigned int i;
+	int ret, irq;
+
+	match = of_match_node(rkisp1_of_match, node);
+	rkisp1 = devm_kzalloc(dev, sizeof(*rkisp1), GFP_KERNEL);
+	if (!rkisp1)
+		return -ENOMEM;
+
+	dev_set_drvdata(dev, rkisp1);
+	rkisp1->dev = dev;
+
+	rkisp1_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);
+	return ret;
+}
+
+static int rkisp1_remove(struct platform_device *pdev)
+{
+	struct rkisp1_device *rkisp1 = platform_get_drvdata(pdev);
+
+	v4l2_async_notifier_unregister(&rkisp1->notifier);
+	v4l2_async_notifier_cleanup(&rkisp1->notifier);
+
+	rkisp1_isp_unregister(rkisp1);
+
+	media_device_unregister(&rkisp1->media_dev);
+	v4l2_device_unregister(&rkisp1->v4l2_dev);
+
+	pm_runtime_disable(&pdev->dev);
+
+	debugfs_remove_recursive(rkisp1->debug.debugfs_dir);
+	return 0;
+}
+
+static struct platform_driver rkisp1_drv = {
+	.driver = {
+		.name = RKISP1_DRIVER_NAME,
+		.of_match_table = of_match_ptr(rkisp1_of_match),
+		.pm = &rkisp1_pm_ops,
+	},
+	.probe = rkisp1_probe,
+	.remove = rkisp1_remove,
+};
+
+module_platform_driver(rkisp1_drv);
+MODULE_DESCRIPTION("Rockchip ISP1 platform driver");
+MODULE_LICENSE("Dual MIT/GPL");
diff --git a/drivers/staging/media/rkisp1/rkisp1-isp.c b/drivers/staging/media/rkisp1/rkisp1-isp.c
new file mode 100644
index 000000000000..abf63e7f74bd
--- /dev/null
+++ b/drivers/staging/media/rkisp1/rkisp1-isp.c
@@ -0,0 +1,1133 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Rockchip ISP1 Driver - ISP Subdevice
+ *
+ * Copyright (C) 2019 Collabora, Ltd.
+ *
+ * Based on Rockchip ISP1 driver by Rockchip Electronics Co., Ltd.
+ * Copyright (C) 2017 Rockchip Electronics Co., Ltd.
+ */
+
+#include <linux/iopoll.h>
+#include <linux/phy/phy.h>
+#include <linux/phy/phy-mipi-dphy.h>
+#include <linux/pm_runtime.h>
+#include <linux/videodev2.h>
+#include <linux/vmalloc.h>
+#include <media/v4l2-event.h>
+
+#include "rkisp1-common.h"
+
+#define RKISP1_DEF_SINK_PAD_FMT MEDIA_BUS_FMT_SRGGB10_1X10
+#define RKISP1_DEF_SRC_PAD_FMT MEDIA_BUS_FMT_YUYV8_2X8
+
+#define RKISP1_ISP_DEV_NAME	RKISP1_DRIVER_NAME "_isp"
+
+#define RKISP1_DIR_SRC BIT(0)
+#define RKISP1_DIR_SINK BIT(1)
+#define RKISP1_DIR_SINK_SRC (RKISP1_DIR_SINK | RKISP1_DIR_SRC)
+
+/*
+ * NOTE: MIPI controller and input MUX are also configured in this file,
+ * because ISP Subdev is not only describe ISP submodule(input size,format,
+ * output size, format), but also a virtual route device.
+ */
+
+/*
+ * There are many variables named with format/frame in below code,
+ * please see here for their meaning.
+ * Cropping in the sink pad defines the image region from the sensor.
+ * Cropping in the source pad defines the region for the Image Stabilizer (IS)
+ *
+ * Cropping regions of ISP
+ *
+ * +---------------------------------------------------------+
+ * | Sensor image                                            |
+ * | +---------------------------------------------------+   |
+ * | | CIF_ISP_ACQ (for black level)                     |   |
+ * | | sink pad format                                   |   |
+ * | | +--------------------------------------------+    |   |
+ * | | |    CIF_ISP_OUT                             |    |   |
+ * | | |    sink pad crop                           |    |   |
+ * | | |    +---------------------------------+     |    |   |
+ * | | |    |   CIF_ISP_IS                    |     |    |   |
+ * | | |    |   source pad crop and format    |     |    |   |
+ * | | |    +---------------------------------+     |    |   |
+ * | | +--------------------------------------------+    |   |
+ * | +---------------------------------------------------+   |
+ * +---------------------------------------------------------+
+ */
+
+static const struct rkisp1_isp_mbus_info rkisp1_isp_formats[] = {
+	{
+		.mbus_code	= MEDIA_BUS_FMT_YUYV8_2X8,
+		.fmt_type	= RKISP1_FMT_YUV,
+		.direction	= RKISP1_DIR_SRC,
+	}, {
+		.mbus_code	= MEDIA_BUS_FMT_SRGGB10_1X10,
+		.fmt_type	= RKISP1_FMT_BAYER,
+		.mipi_dt	= RKISP1_CIF_CSI2_DT_RAW10,
+		.bayer_pat	= RKISP1_RAW_RGGB,
+		.bus_width	= 10,
+		.direction	= RKISP1_DIR_SINK_SRC,
+	}, {
+		.mbus_code	= MEDIA_BUS_FMT_SBGGR10_1X10,
+		.fmt_type	= RKISP1_FMT_BAYER,
+		.mipi_dt	= RKISP1_CIF_CSI2_DT_RAW10,
+		.bayer_pat	= RKISP1_RAW_BGGR,
+		.bus_width	= 10,
+		.direction	= RKISP1_DIR_SINK_SRC,
+	}, {
+		.mbus_code	= MEDIA_BUS_FMT_SGBRG10_1X10,
+		.fmt_type	= RKISP1_FMT_BAYER,
+		.mipi_dt	= RKISP1_CIF_CSI2_DT_RAW10,
+		.bayer_pat	= RKISP1_RAW_GBRG,
+		.bus_width	= 10,
+		.direction	= RKISP1_DIR_SINK_SRC,
+	}, {
+		.mbus_code	= MEDIA_BUS_FMT_SGRBG10_1X10,
+		.fmt_type	= RKISP1_FMT_BAYER,
+		.mipi_dt	= RKISP1_CIF_CSI2_DT_RAW10,
+		.bayer_pat	= RKISP1_RAW_GRBG,
+		.bus_width	= 10,
+		.direction	= RKISP1_DIR_SINK_SRC,
+	}, {
+		.mbus_code	= MEDIA_BUS_FMT_SRGGB12_1X12,
+		.fmt_type	= RKISP1_FMT_BAYER,
+		.mipi_dt	= RKISP1_CIF_CSI2_DT_RAW12,
+		.bayer_pat	= RKISP1_RAW_RGGB,
+		.bus_width	= 12,
+		.direction	= RKISP1_DIR_SINK_SRC,
+	}, {
+		.mbus_code	= MEDIA_BUS_FMT_SBGGR12_1X12,
+		.fmt_type	= RKISP1_FMT_BAYER,
+		.mipi_dt	= RKISP1_CIF_CSI2_DT_RAW12,
+		.bayer_pat	= RKISP1_RAW_BGGR,
+		.bus_width	= 12,
+		.direction	= RKISP1_DIR_SINK_SRC,
+	}, {
+		.mbus_code	= MEDIA_BUS_FMT_SGBRG12_1X12,
+		.fmt_type	= RKISP1_FMT_BAYER,
+		.mipi_dt	= RKISP1_CIF_CSI2_DT_RAW12,
+		.bayer_pat	= RKISP1_RAW_GBRG,
+		.bus_width	= 12,
+		.direction	= RKISP1_DIR_SINK_SRC,
+	}, {
+		.mbus_code	= MEDIA_BUS_FMT_SGRBG12_1X12,
+		.fmt_type	= RKISP1_FMT_BAYER,
+		.mipi_dt	= RKISP1_CIF_CSI2_DT_RAW12,
+		.bayer_pat	= RKISP1_RAW_GRBG,
+		.bus_width	= 12,
+		.direction	= RKISP1_DIR_SINK_SRC,
+	}, {
+		.mbus_code	= MEDIA_BUS_FMT_SRGGB8_1X8,
+		.fmt_type	= RKISP1_FMT_BAYER,
+		.mipi_dt	= RKISP1_CIF_CSI2_DT_RAW8,
+		.bayer_pat	= RKISP1_RAW_RGGB,
+		.bus_width	= 8,
+		.direction	= RKISP1_DIR_SINK_SRC,
+	}, {
+		.mbus_code	= MEDIA_BUS_FMT_SBGGR8_1X8,
+		.fmt_type	= RKISP1_FMT_BAYER,
+		.mipi_dt	= RKISP1_CIF_CSI2_DT_RAW8,
+		.bayer_pat	= RKISP1_RAW_BGGR,
+		.bus_width	= 8,
+		.direction	= RKISP1_DIR_SINK_SRC,
+	}, {
+		.mbus_code	= MEDIA_BUS_FMT_SGBRG8_1X8,
+		.fmt_type	= RKISP1_FMT_BAYER,
+		.mipi_dt	= RKISP1_CIF_CSI2_DT_RAW8,
+		.bayer_pat	= RKISP1_RAW_GBRG,
+		.bus_width	= 8,
+		.direction	= RKISP1_DIR_SINK_SRC,
+	}, {
+		.mbus_code	= MEDIA_BUS_FMT_SGRBG8_1X8,
+		.fmt_type	= RKISP1_FMT_BAYER,
+		.mipi_dt	= RKISP1_CIF_CSI2_DT_RAW8,
+		.bayer_pat	= RKISP1_RAW_GRBG,
+		.bus_width	= 8,
+		.direction	= RKISP1_DIR_SINK_SRC,
+	}, {
+		.mbus_code	= MEDIA_BUS_FMT_YUYV8_1X16,
+		.fmt_type	= RKISP1_FMT_YUV,
+		.mipi_dt	= RKISP1_CIF_CSI2_DT_YUV422_8b,
+		.yuv_seq	= RKISP1_CIF_ISP_ACQ_PROP_YCBYCR,
+		.bus_width	= 16,
+		.direction	= RKISP1_DIR_SINK,
+	}, {
+		.mbus_code	= MEDIA_BUS_FMT_YVYU8_1X16,
+		.fmt_type	= RKISP1_FMT_YUV,
+		.mipi_dt	= RKISP1_CIF_CSI2_DT_YUV422_8b,
+		.yuv_seq	= RKISP1_CIF_ISP_ACQ_PROP_YCRYCB,
+		.bus_width	= 16,
+		.direction	= RKISP1_DIR_SINK,
+	}, {
+		.mbus_code	= MEDIA_BUS_FMT_UYVY8_1X16,
+		.fmt_type	= RKISP1_FMT_YUV,
+		.mipi_dt	= RKISP1_CIF_CSI2_DT_YUV422_8b,
+		.yuv_seq	= RKISP1_CIF_ISP_ACQ_PROP_CBYCRY,
+		.bus_width	= 16,
+		.direction	= RKISP1_DIR_SINK,
+	}, {
+		.mbus_code	= MEDIA_BUS_FMT_VYUY8_1X16,
+		.fmt_type	= RKISP1_FMT_YUV,
+		.mipi_dt	= RKISP1_CIF_CSI2_DT_YUV422_8b,
+		.yuv_seq	= RKISP1_CIF_ISP_ACQ_PROP_CRYCBY,
+		.bus_width	= 16,
+		.direction	= RKISP1_DIR_SINK,
+	},
+};
+
+/* ----------------------------------------------------------------------------
+ * Helpers
+ */
+
+const struct rkisp1_isp_mbus_info *rkisp1_isp_mbus_info_get(u32 mbus_code)
+{
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(rkisp1_isp_formats); i++) {
+		const struct rkisp1_isp_mbus_info *fmt = &rkisp1_isp_formats[i];
+
+		if (fmt->mbus_code == mbus_code)
+			return fmt;
+	}
+
+	return NULL;
+}
+
+static struct v4l2_subdev *rkisp1_get_remote_sensor(struct v4l2_subdev *sd)
+{
+	struct media_pad *local, *remote;
+	struct media_entity *sensor_me;
+
+	local = &sd->entity.pads[RKISP1_ISP_PAD_SINK_VIDEO];
+	remote = media_entity_remote_pad(local);
+	if (!remote) {
+		dev_warn(sd->dev, "No link between isp and sensor\n");
+		return NULL;
+	}
+
+	sensor_me = remote->entity;
+	return media_entity_to_v4l2_subdev(sensor_me);
+}
+
+static struct v4l2_mbus_framefmt *
+rkisp1_isp_get_pad_fmt(struct rkisp1_isp *isp,
+		       struct v4l2_subdev_pad_config *cfg,
+		       unsigned int pad, u32 which)
+{
+	if (which == V4L2_SUBDEV_FORMAT_TRY)
+		return v4l2_subdev_get_try_format(&isp->sd, cfg, pad);
+	else
+		return v4l2_subdev_get_try_format(&isp->sd, isp->pad_cfg, pad);
+}
+
+static struct v4l2_rect *
+rkisp1_isp_get_pad_crop(struct rkisp1_isp *isp,
+			struct v4l2_subdev_pad_config *cfg,
+			unsigned int pad, u32 which)
+{
+	if (which == V4L2_SUBDEV_FORMAT_TRY)
+		return v4l2_subdev_get_try_crop(&isp->sd, cfg, pad);
+	else
+		return v4l2_subdev_get_try_crop(&isp->sd, isp->pad_cfg, pad);
+}
+
+/* ----------------------------------------------------------------------------
+ * Camera Interface registers configurations
+ */
+
+/*
+ * Image Stabilization.
+ * This should only be called when configuring CIF
+ * or at the frame end interrupt
+ */
+static void rkisp1_config_ism(struct rkisp1_device *rkisp1)
+{
+	struct v4l2_rect *src_crop =
+		rkisp1_isp_get_pad_crop(&rkisp1->isp, NULL,
+					RKISP1_ISP_PAD_SOURCE_VIDEO,
+					V4L2_SUBDEV_FORMAT_ACTIVE);
+	u32 val;
+
+	rkisp1_write(rkisp1, 0, RKISP1_CIF_ISP_IS_RECENTER);
+	rkisp1_write(rkisp1, 0, RKISP1_CIF_ISP_IS_MAX_DX);
+	rkisp1_write(rkisp1, 0, RKISP1_CIF_ISP_IS_MAX_DY);
+	rkisp1_write(rkisp1, 0, RKISP1_CIF_ISP_IS_DISPLACE);
+	rkisp1_write(rkisp1, src_crop->left, RKISP1_CIF_ISP_IS_H_OFFS);
+	rkisp1_write(rkisp1, src_crop->top, RKISP1_CIF_ISP_IS_V_OFFS);
+	rkisp1_write(rkisp1, src_crop->width, RKISP1_CIF_ISP_IS_H_SIZE);
+	rkisp1_write(rkisp1, src_crop->height, RKISP1_CIF_ISP_IS_V_SIZE);
+
+	/* IS(Image Stabilization) is always on, working as output crop */
+	rkisp1_write(rkisp1, 1, RKISP1_CIF_ISP_IS_CTRL);
+	val = rkisp1_read(rkisp1, RKISP1_CIF_ISP_CTRL);
+	val |= RKISP1_CIF_ISP_CTRL_ISP_CFG_UPD;
+	rkisp1_write(rkisp1, val, RKISP1_CIF_ISP_CTRL);
+}
+
+/*
+ * configure ISP blocks with input format, size......
+ */
+static int rkisp1_config_isp(struct rkisp1_device *rkisp1)
+{
+	u32 isp_ctrl = 0, irq_mask = 0, acq_mult = 0, signal = 0;
+	const struct rkisp1_isp_mbus_info *src_fmt, *sink_fmt;
+	struct rkisp1_sensor_async *sensor;
+	struct v4l2_mbus_framefmt *sink_frm;
+	struct v4l2_rect *sink_crop;
+
+	sensor = rkisp1->active_sensor;
+	sink_fmt = rkisp1->isp.sink_fmt;
+	src_fmt = rkisp1->isp.src_fmt;
+	sink_frm = rkisp1_isp_get_pad_fmt(&rkisp1->isp, NULL,
+					  RKISP1_ISP_PAD_SINK_VIDEO,
+					  V4L2_SUBDEV_FORMAT_ACTIVE);
+	sink_crop = rkisp1_isp_get_pad_crop(&rkisp1->isp, NULL,
+					    RKISP1_ISP_PAD_SINK_VIDEO,
+					    V4L2_SUBDEV_FORMAT_ACTIVE);
+
+	if (sink_fmt->fmt_type == RKISP1_FMT_BAYER) {
+		acq_mult = 1;
+		if (src_fmt->fmt_type == RKISP1_FMT_BAYER) {
+			if (sensor->mbus.type == V4L2_MBUS_BT656)
+				isp_ctrl = RKISP1_CIF_ISP_CTRL_ISP_MODE_RAW_PICT_ITU656;
+			else
+				isp_ctrl = RKISP1_CIF_ISP_CTRL_ISP_MODE_RAW_PICT;
+		} else {
+			rkisp1_write(rkisp1, RKISP1_CIF_ISP_DEMOSAIC_TH(0xc),
+				     RKISP1_CIF_ISP_DEMOSAIC);
+
+			if (sensor->mbus.type == V4L2_MBUS_BT656)
+				isp_ctrl = RKISP1_CIF_ISP_CTRL_ISP_MODE_BAYER_ITU656;
+			else
+				isp_ctrl = RKISP1_CIF_ISP_CTRL_ISP_MODE_BAYER_ITU601;
+		}
+	} else if (sink_fmt->fmt_type == RKISP1_FMT_YUV) {
+		acq_mult = 2;
+		if (sensor->mbus.type == V4L2_MBUS_CSI2_DPHY) {
+			isp_ctrl = RKISP1_CIF_ISP_CTRL_ISP_MODE_ITU601;
+		} else {
+			if (sensor->mbus.type == V4L2_MBUS_BT656)
+				isp_ctrl = RKISP1_CIF_ISP_CTRL_ISP_MODE_ITU656;
+			else
+				isp_ctrl = RKISP1_CIF_ISP_CTRL_ISP_MODE_ITU601;
+		}
+
+		irq_mask |= RKISP1_CIF_ISP_DATA_LOSS;
+	}
+
+	/* Set up input acquisition properties */
+	if (sensor->mbus.type == V4L2_MBUS_BT656 ||
+	    sensor->mbus.type == V4L2_MBUS_PARALLEL) {
+		if (sensor->mbus.flags & V4L2_MBUS_PCLK_SAMPLE_RISING)
+			signal = RKISP1_CIF_ISP_ACQ_PROP_POS_EDGE;
+	}
+
+	if (sensor->mbus.type == V4L2_MBUS_PARALLEL) {
+		if (sensor->mbus.flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
+			signal |= RKISP1_CIF_ISP_ACQ_PROP_VSYNC_LOW;
+
+		if (sensor->mbus.flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)
+			signal |= RKISP1_CIF_ISP_ACQ_PROP_HSYNC_LOW;
+	}
+
+	rkisp1_write(rkisp1, isp_ctrl, RKISP1_CIF_ISP_CTRL);
+	rkisp1_write(rkisp1, signal | sink_fmt->yuv_seq |
+		     RKISP1_CIF_ISP_ACQ_PROP_BAYER_PAT(sink_fmt->bayer_pat) |
+		     RKISP1_CIF_ISP_ACQ_PROP_FIELD_SEL_ALL,
+		     RKISP1_CIF_ISP_ACQ_PROP);
+	rkisp1_write(rkisp1, 0, RKISP1_CIF_ISP_ACQ_NR_FRAMES);
+
+	/* Acquisition Size */
+	rkisp1_write(rkisp1, 0, RKISP1_CIF_ISP_ACQ_H_OFFS);
+	rkisp1_write(rkisp1, 0, RKISP1_CIF_ISP_ACQ_V_OFFS);
+	rkisp1_write(rkisp1,
+		     acq_mult * sink_frm->width, RKISP1_CIF_ISP_ACQ_H_SIZE);
+	rkisp1_write(rkisp1, sink_frm->height, RKISP1_CIF_ISP_ACQ_V_SIZE);
+
+	/* ISP Out Area */
+	rkisp1_write(rkisp1, sink_crop->left, RKISP1_CIF_ISP_OUT_H_OFFS);
+	rkisp1_write(rkisp1, sink_crop->top, RKISP1_CIF_ISP_OUT_V_OFFS);
+	rkisp1_write(rkisp1, sink_crop->width, RKISP1_CIF_ISP_OUT_H_SIZE);
+	rkisp1_write(rkisp1, sink_crop->height, RKISP1_CIF_ISP_OUT_V_SIZE);
+
+	irq_mask |= RKISP1_CIF_ISP_FRAME | RKISP1_CIF_ISP_V_START |
+		    RKISP1_CIF_ISP_PIC_SIZE_ERROR | RKISP1_CIF_ISP_FRAME_IN;
+	rkisp1_write(rkisp1, irq_mask, RKISP1_CIF_ISP_IMSC);
+
+	return 0;
+}
+
+static int rkisp1_config_dvp(struct rkisp1_device *rkisp1)
+{
+	const struct rkisp1_isp_mbus_info *sink_fmt = rkisp1->isp.sink_fmt;
+	u32 val, input_sel;
+
+	switch (sink_fmt->bus_width) {
+	case 8:
+		input_sel = RKISP1_CIF_ISP_ACQ_PROP_IN_SEL_8B_ZERO;
+		break;
+	case 10:
+		input_sel = RKISP1_CIF_ISP_ACQ_PROP_IN_SEL_10B_ZERO;
+		break;
+	case 12:
+		input_sel = RKISP1_CIF_ISP_ACQ_PROP_IN_SEL_12B;
+		break;
+	default:
+		dev_err(rkisp1->dev, "Invalid bus width\n");
+		return -EINVAL;
+	}
+
+	val = rkisp1_read(rkisp1, RKISP1_CIF_ISP_ACQ_PROP);
+	rkisp1_write(rkisp1, val | input_sel, RKISP1_CIF_ISP_ACQ_PROP);
+
+	return 0;
+}
+
+static int rkisp1_config_mipi(struct rkisp1_device *rkisp1)
+{
+	const struct rkisp1_isp_mbus_info *sink_fmt = rkisp1->isp.sink_fmt;
+	unsigned int lanes;
+	u32 mipi_ctrl;
+
+	/*
+	 * rkisp1->active_sensor->mbus is set in isp or d-phy notifier_bound
+	 * function
+	 */
+	switch (rkisp1->active_sensor->mbus.flags & V4L2_MBUS_CSI2_LANES) {
+	case V4L2_MBUS_CSI2_4_LANE:
+		lanes = 4;
+		break;
+	case V4L2_MBUS_CSI2_3_LANE:
+		lanes = 3;
+		break;
+	case V4L2_MBUS_CSI2_2_LANE:
+		lanes = 2;
+		break;
+	case V4L2_MBUS_CSI2_1_LANE:
+		lanes = 1;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	mipi_ctrl = RKISP1_CIF_MIPI_CTRL_NUM_LANES(lanes - 1) |
+		    RKISP1_CIF_MIPI_CTRL_SHUTDOWNLANES(0xf) |
+		    RKISP1_CIF_MIPI_CTRL_ERR_SOT_SYNC_HS_SKIP |
+		    RKISP1_CIF_MIPI_CTRL_CLOCKLANE_ENA;
+
+	rkisp1_write(rkisp1, mipi_ctrl, RKISP1_CIF_MIPI_CTRL);
+
+	/* Configure Data Type and Virtual Channel */
+	rkisp1_write(rkisp1,
+		     RKISP1_CIF_MIPI_DATA_SEL_DT(sink_fmt->mipi_dt) |
+		     RKISP1_CIF_MIPI_DATA_SEL_VC(0),
+		     RKISP1_CIF_MIPI_IMG_DATA_SEL);
+
+	/* Clear MIPI interrupts */
+	rkisp1_write(rkisp1, ~0, RKISP1_CIF_MIPI_ICR);
+	/*
+	 * Disable RKISP1_CIF_MIPI_ERR_DPHY interrupt here temporary for
+	 * isp bus may be dead when switch isp.
+	 */
+	rkisp1_write(rkisp1,
+		     RKISP1_CIF_MIPI_FRAME_END | RKISP1_CIF_MIPI_ERR_CSI |
+		     RKISP1_CIF_MIPI_ERR_DPHY |
+		     RKISP1_CIF_MIPI_SYNC_FIFO_OVFLW(0x03) |
+		     RKISP1_CIF_MIPI_ADD_DATA_OVFLW,
+		     RKISP1_CIF_MIPI_IMSC);
+
+	dev_dbg(rkisp1->dev, "\n  MIPI_CTRL 0x%08x\n"
+		"  MIPI_IMG_DATA_SEL 0x%08x\n"
+		"  MIPI_STATUS 0x%08x\n"
+		"  MIPI_IMSC 0x%08x\n",
+		rkisp1_read(rkisp1, RKISP1_CIF_MIPI_CTRL),
+		rkisp1_read(rkisp1, RKISP1_CIF_MIPI_IMG_DATA_SEL),
+		rkisp1_read(rkisp1, RKISP1_CIF_MIPI_STATUS),
+		rkisp1_read(rkisp1, RKISP1_CIF_MIPI_IMSC));
+
+	return 0;
+}
+
+/* Configure MUX */
+static int rkisp1_config_path(struct rkisp1_device *rkisp1)
+{
+	struct rkisp1_sensor_async *sensor = rkisp1->active_sensor;
+	u32 dpcl = rkisp1_read(rkisp1, RKISP1_CIF_VI_DPCL);
+	int ret = 0;
+
+	if (sensor->mbus.type == V4L2_MBUS_BT656 ||
+	    sensor->mbus.type == V4L2_MBUS_PARALLEL) {
+		ret = rkisp1_config_dvp(rkisp1);
+		dpcl |= RKISP1_CIF_VI_DPCL_IF_SEL_PARALLEL;
+	} else if (sensor->mbus.type == V4L2_MBUS_CSI2_DPHY) {
+		ret = rkisp1_config_mipi(rkisp1);
+		dpcl |= RKISP1_CIF_VI_DPCL_IF_SEL_MIPI;
+	}
+
+	rkisp1_write(rkisp1, dpcl, RKISP1_CIF_VI_DPCL);
+
+	return ret;
+}
+
+/* Hardware configure Entry */
+static int rkisp1_config_cif(struct rkisp1_device *rkisp1)
+{
+	u32 cif_id;
+	int ret;
+
+	cif_id = rkisp1_read(rkisp1, RKISP1_CIF_VI_ID);
+	dev_dbg(rkisp1->dev, "CIF_ID 0x%08x\n", cif_id);
+
+	ret = rkisp1_config_isp(rkisp1);
+	if (ret)
+		return ret;
+	ret = rkisp1_config_path(rkisp1);
+	if (ret)
+		return ret;
+	rkisp1_config_ism(rkisp1);
+
+	return 0;
+}
+
+static int rkisp1_isp_stop(struct rkisp1_device *rkisp1)
+{
+	u32 val;
+
+	/*
+	 * ISP(mi) stop in mi frame end -> Stop ISP(mipi) ->
+	 * Stop ISP(isp) ->wait for ISP isp off
+	 */
+	/* stop and clear MI, MIPI, and ISP interrupts */
+	rkisp1_write(rkisp1, 0, RKISP1_CIF_MIPI_IMSC);
+	rkisp1_write(rkisp1, ~0, RKISP1_CIF_MIPI_ICR);
+
+	rkisp1_write(rkisp1, 0, RKISP1_CIF_ISP_IMSC);
+	rkisp1_write(rkisp1, ~0, RKISP1_CIF_ISP_ICR);
+
+	rkisp1_write(rkisp1, 0, RKISP1_CIF_MI_IMSC);
+	rkisp1_write(rkisp1, ~0, RKISP1_CIF_MI_ICR);
+	val = rkisp1_read(rkisp1, RKISP1_CIF_MIPI_CTRL);
+	rkisp1_write(rkisp1, val & (~RKISP1_CIF_MIPI_CTRL_OUTPUT_ENA),
+		     RKISP1_CIF_MIPI_CTRL);
+	/* stop ISP */
+	val = rkisp1_read(rkisp1, RKISP1_CIF_ISP_CTRL);
+	val &= ~(RKISP1_CIF_ISP_CTRL_ISP_INFORM_ENABLE |
+		 RKISP1_CIF_ISP_CTRL_ISP_ENABLE);
+	rkisp1_write(rkisp1, val, RKISP1_CIF_ISP_CTRL);
+
+	val = rkisp1_read(rkisp1,	RKISP1_CIF_ISP_CTRL);
+	rkisp1_write(rkisp1, val | RKISP1_CIF_ISP_CTRL_ISP_CFG_UPD,
+		     RKISP1_CIF_ISP_CTRL);
+
+	readx_poll_timeout(readl, rkisp1->base_addr + RKISP1_CIF_ISP_RIS,
+			   val, val & RKISP1_CIF_ISP_OFF, 20, 100);
+	rkisp1_write(rkisp1,
+		     RKISP1_CIF_IRCL_MIPI_SW_RST | RKISP1_CIF_IRCL_ISP_SW_RST,
+		     RKISP1_CIF_IRCL);
+	rkisp1_write(rkisp1, 0x0, RKISP1_CIF_IRCL);
+
+	return 0;
+}
+
+static void rkisp1_config_clk(struct rkisp1_device *rkisp1)
+{
+	u32 val = RKISP1_CIF_ICCL_ISP_CLK | RKISP1_CIF_ICCL_CP_CLK |
+		  RKISP1_CIF_ICCL_MRSZ_CLK | RKISP1_CIF_ICCL_SRSZ_CLK |
+		  RKISP1_CIF_ICCL_JPEG_CLK | RKISP1_CIF_ICCL_MI_CLK |
+		  RKISP1_CIF_ICCL_IE_CLK | RKISP1_CIF_ICCL_MIPI_CLK |
+		  RKISP1_CIF_ICCL_DCROP_CLK;
+
+	rkisp1_write(rkisp1, val, RKISP1_CIF_ICCL);
+}
+
+static int rkisp1_isp_start(struct rkisp1_device *rkisp1)
+{
+	struct rkisp1_sensor_async *sensor = rkisp1->active_sensor;
+	u32 val;
+
+	rkisp1_config_clk(rkisp1);
+
+	/* Activate MIPI */
+	if (sensor->mbus.type == V4L2_MBUS_CSI2_DPHY) {
+		val = rkisp1_read(rkisp1, RKISP1_CIF_MIPI_CTRL);
+		rkisp1_write(rkisp1, val | RKISP1_CIF_MIPI_CTRL_OUTPUT_ENA,
+			     RKISP1_CIF_MIPI_CTRL);
+	}
+	/* Activate ISP */
+	val = rkisp1_read(rkisp1, RKISP1_CIF_ISP_CTRL);
+	val |= RKISP1_CIF_ISP_CTRL_ISP_CFG_UPD |
+	       RKISP1_CIF_ISP_CTRL_ISP_ENABLE |
+	       RKISP1_CIF_ISP_CTRL_ISP_INFORM_ENABLE;
+	rkisp1_write(rkisp1, val, RKISP1_CIF_ISP_CTRL);
+
+	/*
+	 * CIF spec says to wait for sufficient time after enabling
+	 * the MIPI interface and before starting the sensor output.
+	 */
+	usleep_range(1000, 1200);
+
+	return 0;
+}
+
+/* ----------------------------------------------------------------------------
+ * Subdev pad operations
+ */
+
+static int rkisp1_isp_enum_mbus_code(struct v4l2_subdev *sd,
+				     struct v4l2_subdev_pad_config *cfg,
+				     struct v4l2_subdev_mbus_code_enum *code)
+{
+	unsigned int i, dir;
+	int pos = 0;
+
+	if (code->pad == RKISP1_ISP_PAD_SINK_VIDEO) {
+		dir = RKISP1_DIR_SINK;
+	} else if (code->pad == RKISP1_ISP_PAD_SOURCE_VIDEO) {
+		dir = RKISP1_DIR_SRC;
+	} else {
+		if (code->index > 0)
+			return -EINVAL;
+		code->code = MEDIA_BUS_FMT_FIXED;
+		return 0;
+	}
+
+	if (code->index >= ARRAY_SIZE(rkisp1_isp_formats))
+		return -EINVAL;
+
+	for (i = 0; i < ARRAY_SIZE(rkisp1_isp_formats); i++) {
+		const struct rkisp1_isp_mbus_info *fmt = &rkisp1_isp_formats[i];
+
+		if (fmt->direction & dir)
+			pos++;
+
+		if (code->index == pos - 1) {
+			code->code = fmt->mbus_code;
+			return 0;
+		}
+	}
+
+	return -EINVAL;
+}
+
+static int rkisp1_isp_init_config(struct v4l2_subdev *sd,
+				  struct v4l2_subdev_pad_config *cfg)
+{
+	struct v4l2_mbus_framefmt *sink_fmt, *src_fmt;
+	struct v4l2_rect *sink_crop, *src_crop;
+
+	sink_fmt = v4l2_subdev_get_try_format(sd, cfg,
+					      RKISP1_ISP_PAD_SINK_VIDEO);
+	sink_fmt->width = RKISP1_DEFAULT_WIDTH;
+	sink_fmt->height = RKISP1_DEFAULT_HEIGHT;
+	sink_fmt->field = V4L2_FIELD_NONE;
+	sink_fmt->code = RKISP1_DEF_SINK_PAD_FMT;
+
+	sink_crop = v4l2_subdev_get_try_crop(sd, cfg,
+					     RKISP1_ISP_PAD_SINK_VIDEO);
+	sink_crop->width = RKISP1_DEFAULT_WIDTH;
+	sink_crop->height = RKISP1_DEFAULT_HEIGHT;
+	sink_crop->left = 0;
+	sink_crop->top = 0;
+
+	src_fmt = v4l2_subdev_get_try_format(sd, cfg,
+					     RKISP1_ISP_PAD_SOURCE_VIDEO);
+	*src_fmt = *sink_fmt;
+	src_fmt->code = RKISP1_DEF_SRC_PAD_FMT;
+	src_fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE;
+
+	src_crop = v4l2_subdev_get_try_crop(sd, cfg,
+					    RKISP1_ISP_PAD_SOURCE_VIDEO);
+	*src_crop = *sink_crop;
+
+	sink_fmt = v4l2_subdev_get_try_format(sd, cfg,
+					      RKISP1_ISP_PAD_SINK_PARAMS);
+	src_fmt = v4l2_subdev_get_try_format(sd, cfg,
+					     RKISP1_ISP_PAD_SOURCE_STATS);
+	sink_fmt->width = RKISP1_DEFAULT_WIDTH;
+	sink_fmt->height = RKISP1_DEFAULT_HEIGHT;
+	sink_fmt->field = V4L2_FIELD_NONE;
+	sink_fmt->code = MEDIA_BUS_FMT_FIXED;
+	*src_fmt = *sink_fmt;
+
+	return 0;
+}
+
+static void rkisp1_isp_set_src_fmt(struct rkisp1_isp *isp,
+				   struct v4l2_subdev_pad_config *cfg,
+				   struct v4l2_mbus_framefmt *format,
+				   unsigned int which)
+{
+	const struct rkisp1_isp_mbus_info *mbus_info;
+	struct v4l2_mbus_framefmt *src_fmt;
+	const struct v4l2_rect *src_crop;
+
+	src_fmt = rkisp1_isp_get_pad_fmt(isp, cfg,
+					 RKISP1_ISP_PAD_SOURCE_VIDEO, which);
+	src_crop = rkisp1_isp_get_pad_crop(isp, cfg,
+					   RKISP1_ISP_PAD_SOURCE_VIDEO, which);
+
+	src_fmt->code = format->code;
+	mbus_info = rkisp1_isp_mbus_info_get(src_fmt->code);
+	if (!mbus_info) {
+		src_fmt->code = RKISP1_DEF_SRC_PAD_FMT;
+		mbus_info = rkisp1_isp_mbus_info_get(src_fmt->code);
+	}
+	if (which == V4L2_SUBDEV_FORMAT_ACTIVE)
+		isp->src_fmt = mbus_info;
+	src_fmt->width  = src_crop->width;
+	src_fmt->height = src_crop->height;
+	src_fmt->quantization = format->quantization;
+	/* full range by default */
+	if (!src_fmt->quantization)
+		src_fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE;
+
+	*format = *src_fmt;
+}
+
+static void rkisp1_isp_set_src_crop(struct rkisp1_isp *isp,
+				    struct v4l2_subdev_pad_config *cfg,
+				    struct v4l2_rect *r, unsigned int which)
+{
+	struct v4l2_mbus_framefmt *src_fmt;
+	const struct v4l2_rect *sink_crop;
+	struct v4l2_rect *src_crop;
+
+	src_crop = rkisp1_isp_get_pad_crop(isp, cfg,
+					   RKISP1_ISP_PAD_SOURCE_VIDEO,
+					   which);
+	sink_crop = rkisp1_isp_get_pad_crop(isp, cfg,
+					    RKISP1_ISP_PAD_SINK_VIDEO,
+					    which);
+
+	src_crop->left = ALIGN(r->left, 2);
+	src_crop->width = ALIGN(r->width, 2);
+	src_crop->top = r->top;
+	src_crop->height = r->height;
+	rkisp1_sd_adjust_crop_rect(src_crop, sink_crop);
+
+	*r = *src_crop;
+
+	/* Propagate to out format */
+	src_fmt = rkisp1_isp_get_pad_fmt(isp, cfg,
+					 RKISP1_ISP_PAD_SOURCE_VIDEO, which);
+	rkisp1_isp_set_src_fmt(isp, cfg, src_fmt, which);
+}
+
+static void rkisp1_isp_set_sink_crop(struct rkisp1_isp *isp,
+				     struct v4l2_subdev_pad_config *cfg,
+				     struct v4l2_rect *r, unsigned int which)
+{
+	struct v4l2_rect *sink_crop, *src_crop;
+	struct v4l2_mbus_framefmt *sink_fmt;
+
+	sink_crop = rkisp1_isp_get_pad_crop(isp, cfg, RKISP1_ISP_PAD_SINK_VIDEO,
+					    which);
+	sink_fmt = rkisp1_isp_get_pad_fmt(isp, cfg, RKISP1_ISP_PAD_SINK_VIDEO,
+					  which);
+
+	sink_crop->left = ALIGN(r->left, 2);
+	sink_crop->width = ALIGN(r->width, 2);
+	sink_crop->top = r->top;
+	sink_crop->height = r->height;
+	rkisp1_sd_adjust_crop(sink_crop, sink_fmt);
+
+	*r = *sink_crop;
+
+	/* Propagate to out crop */
+	src_crop = rkisp1_isp_get_pad_crop(isp, cfg,
+					   RKISP1_ISP_PAD_SOURCE_VIDEO, which);
+	rkisp1_isp_set_src_crop(isp, cfg, src_crop, which);
+}
+
+static void rkisp1_isp_set_sink_fmt(struct rkisp1_isp *isp,
+				    struct v4l2_subdev_pad_config *cfg,
+				    struct v4l2_mbus_framefmt *format,
+				    unsigned int which)
+{
+	const struct rkisp1_isp_mbus_info *mbus_info;
+	struct v4l2_mbus_framefmt *sink_fmt;
+	struct v4l2_rect *sink_crop;
+
+	sink_fmt = rkisp1_isp_get_pad_fmt(isp, cfg, RKISP1_ISP_PAD_SINK_VIDEO,
+					  which);
+	sink_fmt->code = format->code;
+	mbus_info = rkisp1_isp_mbus_info_get(sink_fmt->code);
+	if (!mbus_info) {
+		sink_fmt->code = RKISP1_DEF_SINK_PAD_FMT;
+		mbus_info = rkisp1_isp_mbus_info_get(sink_fmt->code);
+	}
+	if (which == V4L2_SUBDEV_FORMAT_ACTIVE)
+		isp->sink_fmt = mbus_info;
+
+	sink_fmt->width = clamp_t(u32, format->width,
+				  RKISP1_ISP_MIN_WIDTH,
+				  RKISP1_ISP_MAX_WIDTH);
+	sink_fmt->height = clamp_t(u32, format->height,
+				   RKISP1_ISP_MIN_HEIGHT,
+				   RKISP1_ISP_MAX_HEIGHT);
+
+	*format = *sink_fmt;
+
+	/* Propagate to in crop */
+	sink_crop = rkisp1_isp_get_pad_crop(isp, cfg, RKISP1_ISP_PAD_SINK_VIDEO,
+					    which);
+	rkisp1_isp_set_sink_crop(isp, cfg, sink_crop, which);
+}
+
+static int rkisp1_isp_get_fmt(struct v4l2_subdev *sd,
+			      struct v4l2_subdev_pad_config *cfg,
+			      struct v4l2_subdev_format *fmt)
+{
+	struct rkisp1_isp *isp = container_of(sd, struct rkisp1_isp, sd);
+
+	fmt->format = *rkisp1_isp_get_pad_fmt(isp, cfg, fmt->pad, fmt->which);
+	return 0;
+}
+
+static int rkisp1_isp_set_fmt(struct v4l2_subdev *sd,
+			      struct v4l2_subdev_pad_config *cfg,
+			      struct v4l2_subdev_format *fmt)
+{
+	struct rkisp1_isp *isp = container_of(sd, struct rkisp1_isp, sd);
+
+	if (fmt->pad == RKISP1_ISP_PAD_SINK_VIDEO)
+		rkisp1_isp_set_sink_fmt(isp, cfg, &fmt->format, fmt->which);
+	else if (fmt->pad == RKISP1_ISP_PAD_SOURCE_VIDEO)
+		rkisp1_isp_set_src_fmt(isp, cfg, &fmt->format, fmt->which);
+	else
+		fmt->format = *rkisp1_isp_get_pad_fmt(isp, cfg, fmt->pad,
+						      fmt->which);
+
+	return 0;
+}
+
+static int rkisp1_isp_get_selection(struct v4l2_subdev *sd,
+				    struct v4l2_subdev_pad_config *cfg,
+				    struct v4l2_subdev_selection *sel)
+{
+	struct rkisp1_isp *isp = container_of(sd, struct rkisp1_isp, sd);
+
+	if (sel->pad != RKISP1_ISP_PAD_SOURCE_VIDEO &&
+	    sel->pad != RKISP1_ISP_PAD_SINK_VIDEO)
+		return -EINVAL;
+
+	switch (sel->target) {
+	case V4L2_SEL_TGT_CROP_BOUNDS:
+		if (sel->pad == RKISP1_ISP_PAD_SINK_VIDEO) {
+			struct v4l2_mbus_framefmt *fmt;
+
+			fmt = rkisp1_isp_get_pad_fmt(isp, cfg, sel->pad,
+						     sel->which);
+			sel->r.height = fmt->height;
+			sel->r.width = fmt->width;
+			sel->r.left = 0;
+			sel->r.top = 0;
+		} else {
+			sel->r = *rkisp1_isp_get_pad_crop(isp, cfg,
+						RKISP1_ISP_PAD_SINK_VIDEO,
+						sel->which);
+		}
+		break;
+	case V4L2_SEL_TGT_CROP:
+		sel->r = *rkisp1_isp_get_pad_crop(isp, cfg, sel->pad,
+						  sel->which);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int rkisp1_isp_set_selection(struct v4l2_subdev *sd,
+				    struct v4l2_subdev_pad_config *cfg,
+				    struct v4l2_subdev_selection *sel)
+{
+	struct rkisp1_device *rkisp1 =
+		container_of(sd->v4l2_dev, struct rkisp1_device, v4l2_dev);
+	struct rkisp1_isp *isp = container_of(sd, struct rkisp1_isp, sd);
+
+	if (sel->target != V4L2_SEL_TGT_CROP)
+		return -EINVAL;
+
+	dev_dbg(rkisp1->dev, "%s: pad: %d sel(%d,%d)/%dx%d\n", __func__,
+		sel->pad, sel->r.left, sel->r.top, sel->r.width, sel->r.height);
+
+	if (sel->pad == RKISP1_ISP_PAD_SINK_VIDEO)
+		rkisp1_isp_set_sink_crop(isp, cfg, &sel->r, sel->which);
+	else if (sel->pad == RKISP1_ISP_PAD_SOURCE_VIDEO)
+		rkisp1_isp_set_src_crop(isp, cfg, &sel->r, sel->which);
+	else
+		return -EINVAL;
+
+	return 0;
+}
+
+static int rkisp1_subdev_link_validate(struct media_link *link)
+{
+	if (link->sink->index == RKISP1_ISP_PAD_SINK_PARAMS)
+		return 0;
+
+	return v4l2_subdev_link_validate(link);
+}
+
+static const struct v4l2_subdev_pad_ops rkisp1_isp_pad_ops = {
+	.enum_mbus_code = rkisp1_isp_enum_mbus_code,
+	.get_selection = rkisp1_isp_get_selection,
+	.set_selection = rkisp1_isp_set_selection,
+	.init_cfg = rkisp1_isp_init_config,
+	.get_fmt = rkisp1_isp_get_fmt,
+	.set_fmt = rkisp1_isp_set_fmt,
+	.link_validate = v4l2_subdev_link_validate_default,
+};
+
+/* ----------------------------------------------------------------------------
+ * Stream operations
+ */
+
+static int rkisp1_mipi_csi2_start(struct rkisp1_isp *isp,
+				  struct rkisp1_sensor_async *sensor)
+{
+	union phy_configure_opts opts;
+	struct phy_configure_opts_mipi_dphy *cfg = &opts.mipi_dphy;
+	s64 pixel_clock;
+
+	if (!sensor->pixel_rate_ctrl) {
+		dev_warn(sensor->sd->dev, "No pixel rate control in subdev\n");
+		return -EPIPE;
+	}
+
+	pixel_clock = v4l2_ctrl_g_ctrl_int64(sensor->pixel_rate_ctrl);
+	if (!pixel_clock) {
+		dev_err(sensor->sd->dev, "Invalid pixel rate value\n");
+		return -EINVAL;
+	}
+
+	phy_mipi_dphy_get_default_config(pixel_clock, isp->sink_fmt->bus_width,
+					 sensor->lanes, cfg);
+	phy_set_mode(sensor->dphy, PHY_MODE_MIPI_DPHY);
+	phy_configure(sensor->dphy, &opts);
+	phy_power_on(sensor->dphy);
+
+	return 0;
+}
+
+static void rkisp1_mipi_csi2_stop(struct rkisp1_sensor_async *sensor)
+{
+	phy_power_off(sensor->dphy);
+}
+
+static int rkisp1_isp_s_stream(struct v4l2_subdev *sd, int enable)
+{
+	struct rkisp1_device *rkisp1 =
+		container_of(sd->v4l2_dev, struct rkisp1_device, v4l2_dev);
+	struct v4l2_subdev *sensor_sd;
+	int ret = 0;
+
+	if (!enable) {
+		ret = rkisp1_isp_stop(rkisp1);
+		if (ret)
+			return ret;
+		rkisp1_mipi_csi2_stop(rkisp1->active_sensor);
+		return 0;
+	}
+
+	sensor_sd = rkisp1_get_remote_sensor(sd);
+	if (!sensor_sd)
+		return -ENODEV;
+	rkisp1->active_sensor = container_of(sensor_sd->asd,
+					     struct rkisp1_sensor_async, asd);
+
+	atomic_set(&rkisp1->isp.frame_sequence, -1);
+	ret = rkisp1_config_cif(rkisp1);
+	if (ret)
+		return ret;
+
+	if (rkisp1->active_sensor->mbus.type != V4L2_MBUS_CSI2_DPHY)
+		return -EINVAL;
+
+	ret = rkisp1_mipi_csi2_start(&rkisp1->isp, rkisp1->active_sensor);
+	if (ret)
+		return ret;
+
+	ret = rkisp1_isp_start(rkisp1);
+	if (ret)
+		rkisp1_mipi_csi2_stop(rkisp1->active_sensor);
+
+	return ret;
+}
+
+static int rkisp1_isp_subs_evt(struct v4l2_subdev *sd, struct v4l2_fh *fh,
+			       struct v4l2_event_subscription *sub)
+{
+	if (sub->type != V4L2_EVENT_FRAME_SYNC)
+		return -EINVAL;
+
+	/* V4L2_EVENT_FRAME_SYNC doesn't require an id, so zero should be set */
+	if (sub->id != 0)
+		return -EINVAL;
+
+	return v4l2_event_subscribe(fh, sub, 0, NULL);
+}
+
+static const struct media_entity_operations rkisp1_isp_media_ops = {
+	.link_validate = rkisp1_subdev_link_validate,
+};
+
+static const struct v4l2_subdev_video_ops rkisp1_isp_video_ops = {
+	.s_stream = rkisp1_isp_s_stream,
+};
+
+static const struct v4l2_subdev_core_ops rkisp1_isp_core_ops = {
+	.subscribe_event = rkisp1_isp_subs_evt,
+	.unsubscribe_event = v4l2_event_subdev_unsubscribe,
+};
+
+static const struct v4l2_subdev_ops rkisp1_isp_ops = {
+	.core = &rkisp1_isp_core_ops,
+	.video = &rkisp1_isp_video_ops,
+	.pad = &rkisp1_isp_pad_ops,
+};
+
+int rkisp1_isp_register(struct rkisp1_device *rkisp1,
+			struct v4l2_device *v4l2_dev)
+{
+	struct rkisp1_isp *isp = &rkisp1->isp;
+	struct media_pad *pads = isp->pads;
+	struct v4l2_subdev *sd = &isp->sd;
+	int ret;
+
+	v4l2_subdev_init(sd, &rkisp1_isp_ops);
+	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS;
+	sd->entity.ops = &rkisp1_isp_media_ops;
+	sd->entity.function = MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER;
+	sd->owner = THIS_MODULE;
+	strscpy(sd->name, RKISP1_ISP_DEV_NAME, sizeof(sd->name));
+
+	pads[RKISP1_ISP_PAD_SINK_VIDEO].flags = MEDIA_PAD_FL_SINK |
+						MEDIA_PAD_FL_MUST_CONNECT;
+	pads[RKISP1_ISP_PAD_SINK_PARAMS].flags = MEDIA_PAD_FL_SINK;
+	pads[RKISP1_ISP_PAD_SOURCE_VIDEO].flags = MEDIA_PAD_FL_SOURCE;
+	pads[RKISP1_ISP_PAD_SOURCE_STATS].flags = MEDIA_PAD_FL_SOURCE;
+
+	isp->sink_fmt = rkisp1_isp_mbus_info_get(RKISP1_DEF_SINK_PAD_FMT);
+	isp->src_fmt = rkisp1_isp_mbus_info_get(RKISP1_DEF_SRC_PAD_FMT);
+
+	ret = media_entity_pads_init(&sd->entity, RKISP1_ISP_PAD_MAX, pads);
+	if (ret)
+		return ret;
+
+	ret = v4l2_device_register_subdev(v4l2_dev, sd);
+	if (ret) {
+		dev_err(sd->dev, "Failed to register isp subdev\n");
+		goto err_cleanup_media_entity;
+	}
+
+	rkisp1_isp_init_config(sd, rkisp1->isp.pad_cfg);
+	return 0;
+
+err_cleanup_media_entity:
+	media_entity_cleanup(&sd->entity);
+
+	return ret;
+}
+
+void rkisp1_isp_unregister(struct rkisp1_device *rkisp1)
+{
+	struct v4l2_subdev *sd = &rkisp1->isp.sd;
+
+	v4l2_device_unregister_subdev(sd);
+	media_entity_cleanup(&sd->entity);
+}
+
+/* ----------------------------------------------------------------------------
+ * Interrupt handlers
+ */
+
+void rkisp1_mipi_isr(struct rkisp1_device *rkisp1)
+{
+	u32 val, status;
+
+	status = rkisp1_read(rkisp1, RKISP1_CIF_MIPI_MIS);
+	if (!status)
+		return;
+
+	rkisp1_write(rkisp1, status, RKISP1_CIF_MIPI_ICR);
+
+	/*
+	 * Disable DPHY errctrl interrupt, because this dphy
+	 * erctrl signal is asserted until the next changes
+	 * of line state. This time is may be too long and cpu
+	 * is hold in this interrupt.
+	 */
+	if (status & RKISP1_CIF_MIPI_ERR_CTRL(0x0f)) {
+		val = rkisp1_read(rkisp1, RKISP1_CIF_MIPI_IMSC);
+		rkisp1_write(rkisp1, val & ~RKISP1_CIF_MIPI_ERR_CTRL(0x0f),
+			     RKISP1_CIF_MIPI_IMSC);
+		rkisp1->isp.is_dphy_errctrl_disabled = true;
+	}
+
+	/*
+	 * Enable DPHY errctrl interrupt again, if mipi have receive
+	 * the whole frame without any error.
+	 */
+	if (status == RKISP1_CIF_MIPI_FRAME_END) {
+		/*
+		 * Enable DPHY errctrl interrupt again, if mipi have receive
+		 * the whole frame without any error.
+		 */
+		if (rkisp1->isp.is_dphy_errctrl_disabled) {
+			val = rkisp1_read(rkisp1, RKISP1_CIF_MIPI_IMSC);
+			val |= RKISP1_CIF_MIPI_ERR_CTRL(0x0f);
+			rkisp1_write(rkisp1, val, RKISP1_CIF_MIPI_IMSC);
+			rkisp1->isp.is_dphy_errctrl_disabled = false;
+		}
+	} else {
+		rkisp1->debug.mipi_error++;
+	}
+}
+
+static void rkisp1_isp_queue_event_sof(struct rkisp1_isp *isp)
+{
+	struct v4l2_event event = {
+		.type = V4L2_EVENT_FRAME_SYNC,
+	};
+
+	/*
+	 * Increment the frame sequence on the vsync signal.
+	 * This will allow applications to detect dropped.
+	 * Note that there is a debugfs counter for dropped
+	 * frames, but using this event is more accurate.
+	 */
+	event.u.frame_sync.frame_sequence =
+		atomic_inc_return(&isp->frame_sequence);
+	v4l2_event_queue(isp->sd.devnode, &event);
+}
+
+void rkisp1_isp_isr(struct rkisp1_device *rkisp1)
+{
+	u32 status, isp_err;
+
+	status = rkisp1_read(rkisp1, RKISP1_CIF_ISP_MIS);
+	if (!status)
+		return;
+
+	rkisp1_write(rkisp1, status, RKISP1_CIF_ISP_ICR);
+
+	/* Vertical sync signal, starting generating new frame */
+	if (status & RKISP1_CIF_ISP_V_START)
+		rkisp1_isp_queue_event_sof(&rkisp1->isp);
+
+	if (status & RKISP1_CIF_ISP_PIC_SIZE_ERROR) {
+		/* Clear pic_size_error */
+		isp_err = rkisp1_read(rkisp1, RKISP1_CIF_ISP_ERR);
+		rkisp1_write(rkisp1, isp_err, RKISP1_CIF_ISP_ERR_CLR);
+		rkisp1->debug.pic_size_error++;
+	} else if (status & RKISP1_CIF_ISP_DATA_LOSS) {
+		/* keep track of data_loss in debugfs */
+		rkisp1->debug.data_loss++;
+	}
+}
diff --git a/drivers/staging/media/rkisp1/rkisp1-regs.h b/drivers/staging/media/rkisp1/rkisp1-regs.h
new file mode 100644
index 000000000000..46018f435b6f
--- /dev/null
+++ b/drivers/staging/media/rkisp1/rkisp1-regs.h
@@ -0,0 +1,1264 @@
+/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
+/*
+ * Rockchip ISP1 Driver - Registers header
+ *
+ * Copyright (C) 2017 Rockchip Electronics Co., Ltd.
+ */
+
+#ifndef _RKISP1_REGS_H
+#define _RKISP1_REGS_H
+
+/* ISP_CTRL */
+#define RKISP1_CIF_ISP_CTRL_ISP_ENABLE			BIT(0)
+#define RKISP1_CIF_ISP_CTRL_ISP_MODE_RAW_PICT		(0 << 1)
+#define RKISP1_CIF_ISP_CTRL_ISP_MODE_ITU656		BIT(1)
+#define RKISP1_CIF_ISP_CTRL_ISP_MODE_ITU601		(2 << 1)
+#define RKISP1_CIF_ISP_CTRL_ISP_MODE_BAYER_ITU601	(3 << 1)
+#define RKISP1_CIF_ISP_CTRL_ISP_MODE_DATA_MODE		(4 << 1)
+#define RKISP1_CIF_ISP_CTRL_ISP_MODE_BAYER_ITU656	(5 << 1)
+#define RKISP1_CIF_ISP_CTRL_ISP_MODE_RAW_PICT_ITU656	(6 << 1)
+#define RKISP1_CIF_ISP_CTRL_ISP_INFORM_ENABLE		BIT(4)
+#define RKISP1_CIF_ISP_CTRL_ISP_GAMMA_IN_ENA		BIT(6)
+#define RKISP1_CIF_ISP_CTRL_ISP_AWB_ENA			BIT(7)
+#define RKISP1_CIF_ISP_CTRL_ISP_CFG_UPD_PERMANENT	BIT(8)
+#define RKISP1_CIF_ISP_CTRL_ISP_CFG_UPD			BIT(9)
+#define RKISP1_CIF_ISP_CTRL_ISP_GEN_CFG_UPD		BIT(10)
+#define RKISP1_CIF_ISP_CTRL_ISP_GAMMA_OUT_ENA		BIT(11)
+#define RKISP1_CIF_ISP_CTRL_ISP_FLASH_MODE_ENA		BIT(12)
+#define RKISP1_CIF_ISP_CTRL_ISP_CSM_Y_FULL_ENA		BIT(13)
+#define RKISP1_CIF_ISP_CTRL_ISP_CSM_C_FULL_ENA		BIT(14)
+
+/* ISP_ACQ_PROP */
+#define RKISP1_CIF_ISP_ACQ_PROP_POS_EDGE		BIT(0)
+#define RKISP1_CIF_ISP_ACQ_PROP_HSYNC_LOW		BIT(1)
+#define RKISP1_CIF_ISP_ACQ_PROP_VSYNC_LOW		BIT(2)
+#define RKISP1_CIF_ISP_ACQ_PROP_BAYER_PAT_RGGB		(0 << 3)
+#define RKISP1_CIF_ISP_ACQ_PROP_BAYER_PAT_GRBG		BIT(3)
+#define RKISP1_CIF_ISP_ACQ_PROP_BAYER_PAT_GBRG		(2 << 3)
+#define RKISP1_CIF_ISP_ACQ_PROP_BAYER_PAT_BGGR		(3 << 3)
+#define RKISP1_CIF_ISP_ACQ_PROP_BAYER_PAT(pat)		((pat) << 3)
+#define RKISP1_CIF_ISP_ACQ_PROP_YCBYCR			(0 << 7)
+#define RKISP1_CIF_ISP_ACQ_PROP_YCRYCB			BIT(7)
+#define RKISP1_CIF_ISP_ACQ_PROP_CBYCRY			(2 << 7)
+#define RKISP1_CIF_ISP_ACQ_PROP_CRYCBY			(3 << 7)
+#define RKISP1_CIF_ISP_ACQ_PROP_FIELD_SEL_ALL		(0 << 9)
+#define RKISP1_CIF_ISP_ACQ_PROP_FIELD_SEL_EVEN		BIT(9)
+#define RKISP1_CIF_ISP_ACQ_PROP_FIELD_SEL_ODD		(2 << 9)
+#define RKISP1_CIF_ISP_ACQ_PROP_IN_SEL_12B		(0 << 12)
+#define RKISP1_CIF_ISP_ACQ_PROP_IN_SEL_10B_ZERO		BIT(12)
+#define RKISP1_CIF_ISP_ACQ_PROP_IN_SEL_10B_MSB		(2 << 12)
+#define RKISP1_CIF_ISP_ACQ_PROP_IN_SEL_8B_ZERO		(3 << 12)
+#define RKISP1_CIF_ISP_ACQ_PROP_IN_SEL_8B_MSB		(4 << 12)
+
+/* VI_DPCL */
+#define RKISP1_CIF_VI_DPCL_DMA_JPEG			(0 << 0)
+#define RKISP1_CIF_VI_DPCL_MP_MUX_MRSZ_MI		BIT(0)
+#define RKISP1_CIF_VI_DPCL_MP_MUX_MRSZ_JPEG		(2 << 0)
+#define RKISP1_CIF_VI_DPCL_CHAN_MODE_MP			BIT(2)
+#define RKISP1_CIF_VI_DPCL_CHAN_MODE_SP			(2 << 2)
+#define RKISP1_CIF_VI_DPCL_CHAN_MODE_MPSP		(3 << 2)
+#define RKISP1_CIF_VI_DPCL_DMA_SW_SPMUX			(0 << 4)
+#define RKISP1_CIF_VI_DPCL_DMA_SW_SI			BIT(4)
+#define RKISP1_CIF_VI_DPCL_DMA_SW_IE			(2 << 4)
+#define RKISP1_CIF_VI_DPCL_DMA_SW_JPEG			(3 << 4)
+#define RKISP1_CIF_VI_DPCL_DMA_SW_ISP			(4 << 4)
+#define RKISP1_CIF_VI_DPCL_IF_SEL_PARALLEL		(0 << 8)
+#define RKISP1_CIF_VI_DPCL_IF_SEL_SMIA			BIT(8)
+#define RKISP1_CIF_VI_DPCL_IF_SEL_MIPI			(2 << 8)
+#define RKISP1_CIF_VI_DPCL_DMA_IE_MUX_DMA		BIT(10)
+#define RKISP1_CIF_VI_DPCL_DMA_SP_MUX_DMA		BIT(11)
+
+/* ISP_IMSC - ISP_MIS - ISP_RIS - ISP_ICR - ISP_ISR */
+#define RKISP1_CIF_ISP_OFF				BIT(0)
+#define RKISP1_CIF_ISP_FRAME				BIT(1)
+#define RKISP1_CIF_ISP_DATA_LOSS			BIT(2)
+#define RKISP1_CIF_ISP_PIC_SIZE_ERROR			BIT(3)
+#define RKISP1_CIF_ISP_AWB_DONE				BIT(4)
+#define RKISP1_CIF_ISP_FRAME_IN				BIT(5)
+#define RKISP1_CIF_ISP_V_START				BIT(6)
+#define RKISP1_CIF_ISP_H_START				BIT(7)
+#define RKISP1_CIF_ISP_FLASH_ON				BIT(8)
+#define RKISP1_CIF_ISP_FLASH_OFF			BIT(9)
+#define RKISP1_CIF_ISP_SHUTTER_ON			BIT(10)
+#define RKISP1_CIF_ISP_SHUTTER_OFF			BIT(11)
+#define RKISP1_CIF_ISP_AFM_SUM_OF			BIT(12)
+#define RKISP1_CIF_ISP_AFM_LUM_OF			BIT(13)
+#define RKISP1_CIF_ISP_AFM_FIN				BIT(14)
+#define RKISP1_CIF_ISP_HIST_MEASURE_RDY			BIT(15)
+#define RKISP1_CIF_ISP_FLASH_CAP			BIT(17)
+#define RKISP1_CIF_ISP_EXP_END				BIT(18)
+#define RKISP1_CIF_ISP_VSM_END				BIT(19)
+
+/* ISP_ERR */
+#define RKISP1_CIF_ISP_ERR_INFORM_SIZE			BIT(0)
+#define RKISP1_CIF_ISP_ERR_IS_SIZE			BIT(1)
+#define RKISP1_CIF_ISP_ERR_OUTFORM_SIZE			BIT(2)
+
+/* MI_CTRL */
+#define RKISP1_CIF_MI_CTRL_MP_ENABLE			BIT(0)
+#define RKISP1_CIF_MI_CTRL_SP_ENABLE			(2 << 0)
+#define RKISP1_CIF_MI_CTRL_JPEG_ENABLE			(4 << 0)
+#define RKISP1_CIF_MI_CTRL_RAW_ENABLE			(8 << 0)
+#define RKISP1_CIF_MI_CTRL_HFLIP			BIT(4)
+#define RKISP1_CIF_MI_CTRL_VFLIP			BIT(5)
+#define RKISP1_CIF_MI_CTRL_ROT				BIT(6)
+#define RKISP1_CIF_MI_BYTE_SWAP				BIT(7)
+#define RKISP1_CIF_MI_SP_Y_FULL_YUV2RGB			BIT(8)
+#define RKISP1_CIF_MI_SP_CBCR_FULL_YUV2RGB		BIT(9)
+#define RKISP1_CIF_MI_SP_422NONCOSITEED			BIT(10)
+#define RKISP1_CIF_MI_MP_PINGPONG_ENABEL		BIT(11)
+#define RKISP1_CIF_MI_SP_PINGPONG_ENABEL		BIT(12)
+#define RKISP1_CIF_MI_MP_AUTOUPDATE_ENABLE		BIT(13)
+#define RKISP1_CIF_MI_SP_AUTOUPDATE_ENABLE		BIT(14)
+#define RKISP1_CIF_MI_LAST_PIXEL_SIG_ENABLE		BIT(15)
+#define RKISP1_CIF_MI_CTRL_BURST_LEN_LUM_16		(0 << 16)
+#define RKISP1_CIF_MI_CTRL_BURST_LEN_LUM_32		BIT(16)
+#define RKISP1_CIF_MI_CTRL_BURST_LEN_LUM_64		(2 << 16)
+#define RKISP1_CIF_MI_CTRL_BURST_LEN_CHROM_16		(0 << 18)
+#define RKISP1_CIF_MI_CTRL_BURST_LEN_CHROM_32		BIT(18)
+#define RKISP1_CIF_MI_CTRL_BURST_LEN_CHROM_64		(2 << 18)
+#define RKISP1_CIF_MI_CTRL_INIT_BASE_EN			BIT(20)
+#define RKISP1_CIF_MI_CTRL_INIT_OFFSET_EN		BIT(21)
+#define RKISP1_MI_CTRL_MP_WRITE_YUV_PLA_OR_RAW8		(0 << 22)
+#define RKISP1_MI_CTRL_MP_WRITE_YUV_SPLA		BIT(22)
+#define RKISP1_MI_CTRL_MP_WRITE_YUVINT			(2 << 22)
+#define RKISP1_MI_CTRL_MP_WRITE_RAW12			(2 << 22)
+#define RKISP1_MI_CTRL_SP_WRITE_PLA			(0 << 24)
+#define RKISP1_MI_CTRL_SP_WRITE_SPLA			BIT(24)
+#define RKISP1_MI_CTRL_SP_WRITE_INT			(2 << 24)
+#define RKISP1_MI_CTRL_SP_INPUT_YUV400			(0 << 26)
+#define RKISP1_MI_CTRL_SP_INPUT_YUV420			BIT(26)
+#define RKISP1_MI_CTRL_SP_INPUT_YUV422			(2 << 26)
+#define RKISP1_MI_CTRL_SP_INPUT_YUV444			(3 << 26)
+#define RKISP1_MI_CTRL_SP_OUTPUT_YUV400			(0 << 28)
+#define RKISP1_MI_CTRL_SP_OUTPUT_YUV420			BIT(28)
+#define RKISP1_MI_CTRL_SP_OUTPUT_YUV422			(2 << 28)
+#define RKISP1_MI_CTRL_SP_OUTPUT_YUV444			(3 << 28)
+#define RKISP1_MI_CTRL_SP_OUTPUT_RGB565			(4 << 28)
+#define RKISP1_MI_CTRL_SP_OUTPUT_RGB666			(5 << 28)
+#define RKISP1_MI_CTRL_SP_OUTPUT_RGB888			(6 << 28)
+
+#define RKISP1_MI_CTRL_MP_FMT_MASK			GENMASK(23, 22)
+#define RKISP1_MI_CTRL_SP_FMT_MASK			GENMASK(30, 24)
+
+/* MI_INIT */
+#define RKISP1_CIF_MI_INIT_SKIP				BIT(2)
+#define RKISP1_CIF_MI_INIT_SOFT_UPD			BIT(4)
+
+/* MI_CTRL_SHD */
+#define RKISP1_CIF_MI_CTRL_SHD_MP_IN_ENABLED		BIT(0)
+#define RKISP1_CIF_MI_CTRL_SHD_SP_IN_ENABLED		BIT(1)
+#define RKISP1_CIF_MI_CTRL_SHD_JPEG_IN_ENABLED		BIT(2)
+#define RKISP1_CIF_MI_CTRL_SHD_RAW_IN_ENABLED		BIT(3)
+#define RKISP1_CIF_MI_CTRL_SHD_MP_OUT_ENABLED		BIT(16)
+#define RKISP1_CIF_MI_CTRL_SHD_SP_OUT_ENABLED		BIT(17)
+#define RKISP1_CIF_MI_CTRL_SHD_JPEG_OUT_ENABLED		BIT(18)
+#define RKISP1_CIF_MI_CTRL_SHD_RAW_OUT_ENABLED		BIT(19)
+
+/* RSZ_CTRL */
+#define RKISP1_CIF_RSZ_CTRL_SCALE_HY_ENABLE		BIT(0)
+#define RKISP1_CIF_RSZ_CTRL_SCALE_HC_ENABLE		BIT(1)
+#define RKISP1_CIF_RSZ_CTRL_SCALE_VY_ENABLE		BIT(2)
+#define RKISP1_CIF_RSZ_CTRL_SCALE_VC_ENABLE		BIT(3)
+#define RKISP1_CIF_RSZ_CTRL_SCALE_HY_UP			BIT(4)
+#define RKISP1_CIF_RSZ_CTRL_SCALE_HC_UP			BIT(5)
+#define RKISP1_CIF_RSZ_CTRL_SCALE_VY_UP			BIT(6)
+#define RKISP1_CIF_RSZ_CTRL_SCALE_VC_UP			BIT(7)
+#define RKISP1_CIF_RSZ_CTRL_CFG_UPD			BIT(8)
+#define RKISP1_CIF_RSZ_CTRL_CFG_UPD_AUTO		BIT(9)
+#define RKISP1_CIF_RSZ_SCALER_FACTOR			BIT(16)
+
+/* MI_IMSC - MI_MIS - MI_RIS - MI_ICR - MI_ISR */
+#define RKISP1_CIF_MI_FRAME(stream)			BIT((stream)->id)
+#define RKISP1_CIF_MI_MBLK_LINE				BIT(2)
+#define RKISP1_CIF_MI_FILL_MP_Y				BIT(3)
+#define RKISP1_CIF_MI_WRAP_MP_Y				BIT(4)
+#define RKISP1_CIF_MI_WRAP_MP_CB			BIT(5)
+#define RKISP1_CIF_MI_WRAP_MP_CR			BIT(6)
+#define RKISP1_CIF_MI_WRAP_SP_Y				BIT(7)
+#define RKISP1_CIF_MI_WRAP_SP_CB			BIT(8)
+#define RKISP1_CIF_MI_WRAP_SP_CR			BIT(9)
+#define RKISP1_CIF_MI_DMA_READY				BIT(11)
+
+/* MI_STATUS */
+#define RKISP1_CIF_MI_STATUS_MP_Y_FIFO_FULL		BIT(0)
+#define RKISP1_CIF_MI_STATUS_SP_Y_FIFO_FULL		BIT(4)
+
+/* MI_DMA_CTRL */
+#define RKISP1_CIF_MI_DMA_CTRL_BURST_LEN_LUM_16		(0 << 0)
+#define RKISP1_CIF_MI_DMA_CTRL_BURST_LEN_LUM_32		BIT(0)
+#define RKISP1_CIF_MI_DMA_CTRL_BURST_LEN_LUM_64		(2 << 0)
+#define RKISP1_CIF_MI_DMA_CTRL_BURST_LEN_CHROM_16	(0 << 2)
+#define RKISP1_CIF_MI_DMA_CTRL_BURST_LEN_CHROM_32	BIT(2)
+#define RKISP1_CIF_MI_DMA_CTRL_BURST_LEN_CHROM_64	(2 << 2)
+#define RKISP1_CIF_MI_DMA_CTRL_READ_FMT_PLANAR		(0 << 4)
+#define RKISP1_CIF_MI_DMA_CTRL_READ_FMT_SPLANAR		BIT(4)
+#define RKISP1_CIF_MI_DMA_CTRL_FMT_YUV400		(0 << 6)
+#define RKISP1_CIF_MI_DMA_CTRL_FMT_YUV420		BIT(6)
+#define RKISP1_CIF_MI_DMA_CTRL_READ_FMT_PACKED		(2 << 4)
+#define RKISP1_CIF_MI_DMA_CTRL_FMT_YUV422		(2 << 6)
+#define RKISP1_CIF_MI_DMA_CTRL_FMT_YUV444		(3 << 6)
+#define RKISP1_CIF_MI_DMA_CTRL_BYTE_SWAP		BIT(8)
+#define RKISP1_CIF_MI_DMA_CTRL_CONTINUOUS_ENA		BIT(9)
+#define RKISP1_CIF_MI_DMA_CTRL_RGB_BAYER_NO		(0 << 12)
+#define RKISP1_CIF_MI_DMA_CTRL_RGB_BAYER_8BIT		BIT(12)
+#define RKISP1_CIF_MI_DMA_CTRL_RGB_BAYER_16BIT		(2 << 12)
+/* MI_DMA_START */
+#define RKISP1_CIF_MI_DMA_START_ENABLE			BIT(0)
+/* MI_XTD_FORMAT_CTRL  */
+#define RKISP1_CIF_MI_XTD_FMT_CTRL_MP_CB_CR_SWAP	BIT(0)
+#define RKISP1_CIF_MI_XTD_FMT_CTRL_SP_CB_CR_SWAP	BIT(1)
+#define RKISP1_CIF_MI_XTD_FMT_CTRL_DMA_CB_CR_SWAP	BIT(2)
+
+/* CCL */
+#define RKISP1_CIF_CCL_CIF_CLK_DIS			BIT(2)
+/* ICCL */
+#define RKISP1_CIF_ICCL_ISP_CLK				BIT(0)
+#define RKISP1_CIF_ICCL_CP_CLK				BIT(1)
+#define RKISP1_CIF_ICCL_RES_2				BIT(2)
+#define RKISP1_CIF_ICCL_MRSZ_CLK			BIT(3)
+#define RKISP1_CIF_ICCL_SRSZ_CLK			BIT(4)
+#define RKISP1_CIF_ICCL_JPEG_CLK			BIT(5)
+#define RKISP1_CIF_ICCL_MI_CLK				BIT(6)
+#define RKISP1_CIF_ICCL_RES_7				BIT(7)
+#define RKISP1_CIF_ICCL_IE_CLK				BIT(8)
+#define RKISP1_CIF_ICCL_SIMP_CLK			BIT(9)
+#define RKISP1_CIF_ICCL_SMIA_CLK			BIT(10)
+#define RKISP1_CIF_ICCL_MIPI_CLK			BIT(11)
+#define RKISP1_CIF_ICCL_DCROP_CLK			BIT(12)
+/* IRCL */
+#define RKISP1_CIF_IRCL_ISP_SW_RST			BIT(0)
+#define RKISP1_CIF_IRCL_CP_SW_RST			BIT(1)
+#define RKISP1_CIF_IRCL_YCS_SW_RST			BIT(2)
+#define RKISP1_CIF_IRCL_MRSZ_SW_RST			BIT(3)
+#define RKISP1_CIF_IRCL_SRSZ_SW_RST			BIT(4)
+#define RKISP1_CIF_IRCL_JPEG_SW_RST			BIT(5)
+#define RKISP1_CIF_IRCL_MI_SW_RST			BIT(6)
+#define RKISP1_CIF_IRCL_CIF_SW_RST			BIT(7)
+#define RKISP1_CIF_IRCL_IE_SW_RST			BIT(8)
+#define RKISP1_CIF_IRCL_SI_SW_RST			BIT(9)
+#define RKISP1_CIF_IRCL_MIPI_SW_RST			BIT(11)
+
+/* C_PROC_CTR */
+#define RKISP1_CIF_C_PROC_CTR_ENABLE			BIT(0)
+#define RKISP1_CIF_C_PROC_YOUT_FULL			BIT(1)
+#define RKISP1_CIF_C_PROC_YIN_FULL			BIT(2)
+#define RKISP1_CIF_C_PROC_COUT_FULL			BIT(3)
+#define RKISP1_CIF_C_PROC_CTRL_RESERVED			0xFFFFFFFE
+#define RKISP1_CIF_C_PROC_CONTRAST_RESERVED		0xFFFFFF00
+#define RKISP1_CIF_C_PROC_BRIGHTNESS_RESERVED		0xFFFFFF00
+#define RKISP1_CIF_C_PROC_HUE_RESERVED			0xFFFFFF00
+#define RKISP1_CIF_C_PROC_SATURATION_RESERVED		0xFFFFFF00
+#define RKISP1_CIF_C_PROC_MACC_RESERVED			0xE000E000
+#define RKISP1_CIF_C_PROC_TONE_RESERVED			0xF000
+/* DUAL_CROP_CTRL */
+#define RKISP1_CIF_DUAL_CROP_MP_MODE_BYPASS		(0 << 0)
+#define RKISP1_CIF_DUAL_CROP_MP_MODE_YUV		BIT(0)
+#define RKISP1_CIF_DUAL_CROP_MP_MODE_RAW		(2 << 0)
+#define RKISP1_CIF_DUAL_CROP_SP_MODE_BYPASS		(0 << 2)
+#define RKISP1_CIF_DUAL_CROP_SP_MODE_YUV		BIT(2)
+#define RKISP1_CIF_DUAL_CROP_SP_MODE_RAW		(2 << 2)
+#define RKISP1_CIF_DUAL_CROP_CFG_UPD_PERMANENT		BIT(4)
+#define RKISP1_CIF_DUAL_CROP_CFG_UPD			BIT(5)
+#define RKISP1_CIF_DUAL_CROP_GEN_CFG_UPD		BIT(6)
+
+/* IMG_EFF_CTRL */
+#define RKISP1_CIF_IMG_EFF_CTRL_ENABLE			BIT(0)
+#define RKISP1_CIF_IMG_EFF_CTRL_MODE_BLACKWHITE		(0 << 1)
+#define RKISP1_CIF_IMG_EFF_CTRL_MODE_NEGATIVE		BIT(1)
+#define RKISP1_CIF_IMG_EFF_CTRL_MODE_SEPIA		(2 << 1)
+#define RKISP1_CIF_IMG_EFF_CTRL_MODE_COLOR_SEL		(3 << 1)
+#define RKISP1_CIF_IMG_EFF_CTRL_MODE_EMBOSS		(4 << 1)
+#define RKISP1_CIF_IMG_EFF_CTRL_MODE_SKETCH		(5 << 1)
+#define RKISP1_CIF_IMG_EFF_CTRL_MODE_SHARPEN		(6 << 1)
+#define RKISP1_CIF_IMG_EFF_CTRL_CFG_UPD			BIT(4)
+#define RKISP1_CIF_IMG_EFF_CTRL_YCBCR_FULL		BIT(5)
+
+#define RKISP1_CIF_IMG_EFF_CTRL_MODE_BLACKWHITE_SHIFT	0
+#define RKISP1_CIF_IMG_EFF_CTRL_MODE_NEGATIVE_SHIFT	1
+#define RKISP1_CIF_IMG_EFF_CTRL_MODE_SEPIA_SHIFT	2
+#define RKISP1_CIF_IMG_EFF_CTRL_MODE_COLOR_SEL_SHIFT	3
+#define RKISP1_CIF_IMG_EFF_CTRL_MODE_EMBOSS_SHIFT	4
+#define RKISP1_CIF_IMG_EFF_CTRL_MODE_SKETCH_SHIFT	5
+#define RKISP1_CIF_IMG_EFF_CTRL_MODE_SHARPEN_SHIFT	6
+#define RKISP1_CIF_IMG_EFF_CTRL_MODE_MASK		0xE
+
+/* IMG_EFF_COLOR_SEL */
+#define RKISP1_CIF_IMG_EFF_COLOR_RGB			0
+#define RKISP1_CIF_IMG_EFF_COLOR_B			BIT(0)
+#define RKISP1_CIF_IMG_EFF_COLOR_G			(2 << 0)
+#define RKISP1_CIF_IMG_EFF_COLOR_GB			(3 << 0)
+#define RKISP1_CIF_IMG_EFF_COLOR_R			(4 << 0)
+#define RKISP1_CIF_IMG_EFF_COLOR_RB			(5 << 0)
+#define RKISP1_CIF_IMG_EFF_COLOR_RG			(6 << 0)
+#define RKISP1_CIF_IMG_EFF_COLOR_RGB2			(7 << 0)
+
+/* MIPI_CTRL */
+#define RKISP1_CIF_MIPI_CTRL_OUTPUT_ENA			BIT(0)
+#define RKISP1_CIF_MIPI_CTRL_SHUTDOWNLANES(a)		(((a) & 0xF) << 8)
+#define RKISP1_CIF_MIPI_CTRL_NUM_LANES(a)		(((a) & 0x3) << 12)
+#define RKISP1_CIF_MIPI_CTRL_ERR_SOT_HS_SKIP		BIT(16)
+#define RKISP1_CIF_MIPI_CTRL_ERR_SOT_SYNC_HS_SKIP	BIT(17)
+#define RKISP1_CIF_MIPI_CTRL_CLOCKLANE_ENA		BIT(18)
+
+/* MIPI_DATA_SEL */
+#define RKISP1_CIF_MIPI_DATA_SEL_VC(a)			(((a) & 0x3) << 6)
+#define RKISP1_CIF_MIPI_DATA_SEL_DT(a)			(((a) & 0x3F) << 0)
+/* MIPI DATA_TYPE */
+#define RKISP1_CIF_CSI2_DT_YUV420_8b			0x18
+#define RKISP1_CIF_CSI2_DT_YUV420_10b			0x19
+#define RKISP1_CIF_CSI2_DT_YUV422_8b			0x1E
+#define RKISP1_CIF_CSI2_DT_YUV422_10b			0x1F
+#define RKISP1_CIF_CSI2_DT_RGB565			0x22
+#define RKISP1_CIF_CSI2_DT_RGB666			0x23
+#define RKISP1_CIF_CSI2_DT_RGB888			0x24
+#define RKISP1_CIF_CSI2_DT_RAW8				0x2A
+#define RKISP1_CIF_CSI2_DT_RAW10			0x2B
+#define RKISP1_CIF_CSI2_DT_RAW12			0x2C
+
+/* MIPI_IMSC, MIPI_RIS, MIPI_MIS, MIPI_ICR, MIPI_ISR */
+#define RKISP1_CIF_MIPI_SYNC_FIFO_OVFLW(a)		(((a) & 0xF) << 0)
+#define RKISP1_CIF_MIPI_ERR_SOT(a)			(((a) & 0xF) << 4)
+#define RKISP1_CIF_MIPI_ERR_SOT_SYNC(a)			(((a) & 0xF) << 8)
+#define RKISP1_CIF_MIPI_ERR_EOT_SYNC(a)			(((a) & 0xF) << 12)
+#define RKISP1_CIF_MIPI_ERR_CTRL(a)			(((a) & 0xF) << 16)
+#define RKISP1_CIF_MIPI_ERR_PROTOCOL			BIT(20)
+#define RKISP1_CIF_MIPI_ERR_ECC1			BIT(21)
+#define RKISP1_CIF_MIPI_ERR_ECC2			BIT(22)
+#define RKISP1_CIF_MIPI_ERR_CS				BIT(23)
+#define RKISP1_CIF_MIPI_FRAME_END			BIT(24)
+#define RKISP1_CIF_MIPI_ADD_DATA_OVFLW			BIT(25)
+#define RKISP1_CIF_MIPI_ADD_DATA_WATER_MARK		BIT(26)
+
+#define RKISP1_CIF_MIPI_ERR_CSI  (RKISP1_CIF_MIPI_ERR_PROTOCOL | \
+	RKISP1_CIF_MIPI_ERR_ECC1 | \
+	RKISP1_CIF_MIPI_ERR_ECC2 | \
+	RKISP1_CIF_MIPI_ERR_CS)
+
+#define RKISP1_CIF_MIPI_ERR_DPHY  (RKISP1_CIF_MIPI_ERR_SOT(3) | \
+	RKISP1_CIF_MIPI_ERR_SOT_SYNC(3) | \
+	RKISP1_CIF_MIPI_ERR_EOT_SYNC(3) | \
+	RKISP1_CIF_MIPI_ERR_CTRL(3))
+
+/* SUPER_IMPOSE */
+#define RKISP1_CIF_SUPER_IMP_CTRL_NORMAL_MODE		BIT(0)
+#define RKISP1_CIF_SUPER_IMP_CTRL_REF_IMG_MEM		BIT(1)
+#define RKISP1_CIF_SUPER_IMP_CTRL_TRANSP_DIS		BIT(2)
+
+/* ISP HISTOGRAM CALCULATION : ISP_HIST_PROP */
+#define RKISP1_CIF_ISP_HIST_PROP_MODE_DIS		(0 << 0)
+#define RKISP1_CIF_ISP_HIST_PROP_MODE_RGB		BIT(0)
+#define RKISP1_CIF_ISP_HIST_PROP_MODE_RED		(2 << 0)
+#define RKISP1_CIF_ISP_HIST_PROP_MODE_GREEN		(3 << 0)
+#define RKISP1_CIF_ISP_HIST_PROP_MODE_BLUE		(4 << 0)
+#define RKISP1_CIF_ISP_HIST_PROP_MODE_LUM		(5 << 0)
+#define RKISP1_CIF_ISP_HIST_PROP_MODE_MASK		0x7
+#define RKISP1_CIF_ISP_HIST_PREDIV_SET(x)		(((x) & 0x7F) << 3)
+#define RKISP1_CIF_ISP_HIST_WEIGHT_SET(v0, v1, v2, v3)	\
+				     (((v0) & 0x1F) | (((v1) & 0x1F) << 8)  |\
+				     (((v2) & 0x1F) << 16) | \
+				     (((v3) & 0x1F) << 24))
+
+#define RKISP1_CIF_ISP_HIST_WINDOW_OFFSET_RESERVED	0xFFFFF000
+#define RKISP1_CIF_ISP_HIST_WINDOW_SIZE_RESERVED	0xFFFFF800
+#define RKISP1_CIF_ISP_HIST_WEIGHT_RESERVED		0xE0E0E0E0
+#define RKISP1_CIF_ISP_MAX_HIST_PREDIVIDER		0x0000007F
+#define RKISP1_CIF_ISP_HIST_ROW_NUM			5
+#define RKISP1_CIF_ISP_HIST_COLUMN_NUM			5
+
+/* AUTO FOCUS MEASUREMENT:  ISP_AFM_CTRL */
+#define RKISP1_ISP_AFM_CTRL_ENABLE			BIT(0)
+
+/* SHUTTER CONTROL */
+#define RKISP1_CIF_ISP_SH_CTRL_SH_ENA			BIT(0)
+#define RKISP1_CIF_ISP_SH_CTRL_REP_EN			BIT(1)
+#define RKISP1_CIF_ISP_SH_CTRL_SRC_SH_TRIG		BIT(2)
+#define RKISP1_CIF_ISP_SH_CTRL_EDGE_POS			BIT(3)
+#define RKISP1_CIF_ISP_SH_CTRL_POL_LOW			BIT(4)
+
+/* FLASH MODULE */
+/* ISP_FLASH_CMD */
+#define RKISP1_CIFFLASH_CMD_PRELIGHT_ON			BIT(0)
+#define RKISP1_CIFFLASH_CMD_FLASH_ON			BIT(1)
+#define RKISP1_CIFFLASH_CMD_PRE_FLASH_ON		BIT(2)
+/* ISP_FLASH_CONFIG */
+#define RKISP1_CIFFLASH_CONFIG_PRELIGHT_END		BIT(0)
+#define RKISP1_CIFFLASH_CONFIG_VSYNC_POS		BIT(1)
+#define RKISP1_CIFFLASH_CONFIG_PRELIGHT_LOW		BIT(2)
+#define RKISP1_CIFFLASH_CONFIG_SRC_FL_TRIG		BIT(3)
+#define RKISP1_CIFFLASH_CONFIG_DELAY(a)			(((a) & 0xF) << 4)
+
+/* Demosaic:  ISP_DEMOSAIC */
+#define RKISP1_CIF_ISP_DEMOSAIC_BYPASS			BIT(10)
+#define RKISP1_CIF_ISP_DEMOSAIC_TH(x)			((x) & 0xFF)
+
+/* AWB */
+/* ISP_AWB_PROP */
+#define RKISP1_CIF_ISP_AWB_YMAX_CMP_EN			BIT(2)
+#define RKISP1_CIF_ISP_AWB_YMAX_READ(x)			(((x) >> 2) & 1)
+#define RKISP1_CIF_ISP_AWB_MODE_RGB_EN			((1 << 31) | (0x2 << 0))
+#define RKISP1_CIF_ISP_AWB_MODE_YCBCR_EN		((0 << 31) | (0x2 << 0))
+#define RKISP1_CIF_ISP_AWB_MODE_YCBCR_EN		((0 << 31) | (0x2 << 0))
+#define RKISP1_CIF_ISP_AWB_MODE_MASK_NONE		0xFFFFFFFC
+#define RKISP1_CIF_ISP_AWB_MODE_READ(x)			((x) & 3)
+/* ISP_AWB_GAIN_RB, ISP_AWB_GAIN_G  */
+#define RKISP1_CIF_ISP_AWB_GAIN_R_SET(x)		(((x) & 0x3FF) << 16)
+#define RKISP1_CIF_ISP_AWB_GAIN_R_READ(x)		(((x) >> 16) & 0x3FF)
+#define RKISP1_CIF_ISP_AWB_GAIN_B_SET(x)		((x) & 0x3FFF)
+#define RKISP1_CIF_ISP_AWB_GAIN_B_READ(x)		((x) & 0x3FFF)
+/* ISP_AWB_REF */
+#define RKISP1_CIF_ISP_AWB_REF_CR_SET(x)		(((x) & 0xFF) << 8)
+#define RKISP1_CIF_ISP_AWB_REF_CR_READ(x)		(((x) >> 8) & 0xFF)
+#define RKISP1_CIF_ISP_AWB_REF_CB_READ(x)		((x) & 0xFF)
+/* ISP_AWB_THRESH */
+#define RKISP1_CIF_ISP_AWB_MAX_CS_SET(x)		(((x) & 0xFF) << 8)
+#define RKISP1_CIF_ISP_AWB_MAX_CS_READ(x)		(((x) >> 8) & 0xFF)
+#define RKISP1_CIF_ISP_AWB_MIN_C_READ(x)		((x) & 0xFF)
+#define RKISP1_CIF_ISP_AWB_MIN_Y_SET(x)			(((x) & 0xFF) << 16)
+#define RKISP1_CIF_ISP_AWB_MIN_Y_READ(x)		(((x) >> 16) & 0xFF)
+#define RKISP1_CIF_ISP_AWB_MAX_Y_SET(x)			(((x) & 0xFF) << 24)
+#define RKISP1_CIF_ISP_AWB_MAX_Y_READ(x)			(((x) >> 24) & 0xFF)
+/* ISP_AWB_MEAN */
+#define RKISP1_CIF_ISP_AWB_GET_MEAN_CR_R(x)		((x) & 0xFF)
+#define RKISP1_CIF_ISP_AWB_GET_MEAN_CB_B(x)		(((x) >> 8) & 0xFF)
+#define RKISP1_CIF_ISP_AWB_GET_MEAN_Y_G(x)		(((x) >> 16) & 0xFF)
+/* ISP_AWB_WHITE_CNT */
+#define RKISP1_CIF_ISP_AWB_GET_PIXEL_CNT(x)		((x) & 0x3FFFFFF)
+
+#define RKISP1_CIF_ISP_AWB_GAINS_MAX_VAL		0x000003FF
+#define RKISP1_CIF_ISP_AWB_WINDOW_OFFSET_MAX		0x00000FFF
+#define RKISP1_CIF_ISP_AWB_WINDOW_MAX_SIZE		0x00001FFF
+#define RKISP1_CIF_ISP_AWB_CBCR_MAX_REF			0x000000FF
+#define RKISP1_CIF_ISP_AWB_THRES_MAX_YC			0x000000FF
+
+/* AE */
+/* ISP_EXP_CTRL */
+#define RKISP1_CIF_ISP_EXP_ENA				BIT(0)
+#define RKISP1_CIF_ISP_EXP_CTRL_AUTOSTOP		BIT(1)
+/*
+ *'1' luminance calculation according to  Y=(R+G+B) x 0.332 (85/256)
+ *'0' luminance calculation according to Y=16+0.25R+0.5G+0.1094B
+ */
+#define RKISP1_CIF_ISP_EXP_CTRL_MEASMODE_1		BIT(31)
+
+/* ISP_EXP_H_SIZE */
+#define RKISP1_CIF_ISP_EXP_H_SIZE_SET(x)		((x) & 0x7FF)
+#define RKISP1_CIF_ISP_EXP_HEIGHT_MASK			0x000007FF
+/* ISP_EXP_V_SIZE : vertical size must be a multiple of 2). */
+#define RKISP1_CIF_ISP_EXP_V_SIZE_SET(x)		((x) & 0x7FE)
+
+/* ISP_EXP_H_OFFSET */
+#define RKISP1_CIF_ISP_EXP_H_OFFSET_SET(x)		((x) & 0x1FFF)
+#define RKISP1_CIF_ISP_EXP_MAX_HOFFS			2424
+/* ISP_EXP_V_OFFSET */
+#define RKISP1_CIF_ISP_EXP_V_OFFSET_SET(x)		((x) & 0x1FFF)
+#define RKISP1_CIF_ISP_EXP_MAX_VOFFS			1806
+
+#define RKISP1_CIF_ISP_EXP_ROW_NUM			5
+#define RKISP1_CIF_ISP_EXP_COLUMN_NUM			5
+#define RKISP1_CIF_ISP_EXP_NUM_LUMA_REGS \
+	(RKISP1_CIF_ISP_EXP_ROW_NUM * RKISP1_CIF_ISP_EXP_COLUMN_NUM)
+#define RKISP1_CIF_ISP_EXP_BLOCK_MAX_HSIZE		516
+#define RKISP1_CIF_ISP_EXP_BLOCK_MIN_HSIZE		35
+#define RKISP1_CIF_ISP_EXP_BLOCK_MAX_VSIZE		390
+#define RKISP1_CIF_ISP_EXP_BLOCK_MIN_VSIZE		28
+#define RKISP1_CIF_ISP_EXP_MAX_HSIZE	\
+	(RKISP1_CIF_ISP_EXP_BLOCK_MAX_HSIZE * RKISP1_CIF_ISP_EXP_COLUMN_NUM + 1)
+#define RKISP1_CIF_ISP_EXP_MIN_HSIZE	\
+	(RKISP1_CIF_ISP_EXP_BLOCK_MIN_HSIZE * RKISP1_CIF_ISP_EXP_COLUMN_NUM + 1)
+#define RKISP1_CIF_ISP_EXP_MAX_VSIZE	\
+	(RKISP1_CIF_ISP_EXP_BLOCK_MAX_VSIZE * RKISP1_CIF_ISP_EXP_ROW_NUM + 1)
+#define RKISP1_CIF_ISP_EXP_MIN_VSIZE	\
+	(RKISP1_CIF_ISP_EXP_BLOCK_MIN_VSIZE * RKISP1_CIF_ISP_EXP_ROW_NUM + 1)
+
+/* LSC: ISP_LSC_CTRL */
+#define RKISP1_CIF_ISP_LSC_CTRL_ENA			BIT(0)
+#define RKISP1_CIF_ISP_LSC_SECT_SIZE_RESERVED		0xFC00FC00
+#define RKISP1_CIF_ISP_LSC_GRAD_RESERVED		0xF000F000
+#define RKISP1_CIF_ISP_LSC_SAMPLE_RESERVED		0xF000F000
+#define RKISP1_CIF_ISP_LSC_SECTORS_MAX			17
+#define RKISP1_CIF_ISP_LSC_TABLE_DATA(v0, v1)     \
+	(((v0) & 0xFFF) | (((v1) & 0xFFF) << 12))
+#define RKISP1_CIF_ISP_LSC_SECT_SIZE(v0, v1)      \
+	(((v0) & 0xFFF) | (((v1) & 0xFFF) << 16))
+#define RKISP1_CIF_ISP_LSC_GRAD_SIZE(v0, v1)      \
+	(((v0) & 0xFFF) | (((v1) & 0xFFF) << 16))
+
+/* LSC: ISP_LSC_TABLE_SEL */
+#define RKISP1_CIF_ISP_LSC_TABLE_0			0
+#define RKISP1_CIF_ISP_LSC_TABLE_1			1
+
+/* LSC: ISP_LSC_STATUS */
+#define RKISP1_CIF_ISP_LSC_ACTIVE_TABLE			BIT(1)
+#define RKISP1_CIF_ISP_LSC_TABLE_ADDRESS_0		0
+#define RKISP1_CIF_ISP_LSC_TABLE_ADDRESS_153		153
+
+/* FLT */
+/* ISP_FILT_MODE */
+#define RKISP1_CIF_ISP_FLT_ENA				BIT(0)
+
+/*
+ * 0: green filter static mode (active filter factor = FILT_FAC_MID)
+ * 1: dynamic noise reduction/sharpen Default
+ */
+#define RKISP1_CIF_ISP_FLT_MODE_DNR			BIT(1)
+#define RKISP1_CIF_ISP_FLT_MODE_MAX			1
+#define RKISP1_CIF_ISP_FLT_CHROMA_V_MODE(x)		(((x) & 0x3) << 4)
+#define RKISP1_CIF_ISP_FLT_CHROMA_H_MODE(x)		(((x) & 0x3) << 6)
+#define RKISP1_CIF_ISP_FLT_CHROMA_MODE_MAX		3
+#define RKISP1_CIF_ISP_FLT_GREEN_STAGE1(x)		(((x) & 0xF) << 8)
+#define RKISP1_CIF_ISP_FLT_GREEN_STAGE1_MAX		8
+#define RKISP1_CIF_ISP_FLT_THREAD_RESERVED		0xFFFFFC00
+#define RKISP1_CIF_ISP_FLT_FAC_RESERVED			0xFFFFFFC0
+#define RKISP1_CIF_ISP_FLT_LUM_WEIGHT_RESERVED		0xFFF80000
+
+#define RKISP1_CIF_ISP_CTK_COEFF_RESERVED		0xFFFFF800
+#define RKISP1_CIF_ISP_XTALK_OFFSET_RESERVED		0xFFFFF000
+
+/* GOC */
+#define RKISP1_CIF_ISP_GAMMA_OUT_MODE_EQU		BIT(0)
+#define RKISP1_CIF_ISP_GOC_MODE_MAX			1
+#define RKISP1_CIF_ISP_GOC_RESERVED			0xFFFFF800
+/* ISP_CTRL BIT 11*/
+#define RKISP1_CIF_ISP_CTRL_ISP_GAMMA_OUT_ENA_READ(x)	(((x) >> 11) & 1)
+
+/* DPCC */
+/* ISP_DPCC_MODE */
+#define RKISP1_CIF_ISP_DPCC_ENA				BIT(0)
+#define RKISP1_CIF_ISP_DPCC_MODE_MAX			0x07
+#define RKISP1_CIF_ISP_DPCC_OUTPUTMODE_MAX		0x0F
+#define RKISP1_CIF_ISP_DPCC_SETUSE_MAX			0x0F
+#define RKISP1_CIF_ISP_DPCC_METHODS_SET_RESERVED	0xFFFFE000
+#define RKISP1_CIF_ISP_DPCC_LINE_THRESH_RESERVED	0xFFFF0000
+#define RKISP1_CIF_ISP_DPCC_LINE_MAD_FAC_RESERVED	0xFFFFC0C0
+#define RKISP1_CIF_ISP_DPCC_PG_FAC_RESERVED		0xFFFFC0C0
+#define RKISP1_CIF_ISP_DPCC_RND_THRESH_RESERVED		0xFFFF0000
+#define RKISP1_CIF_ISP_DPCC_RG_FAC_RESERVED		0xFFFFC0C0
+#define RKISP1_CIF_ISP_DPCC_RO_LIMIT_RESERVED		0xFFFFF000
+#define RKISP1_CIF_ISP_DPCC_RND_OFFS_RESERVED		0xFFFFF000
+
+/* BLS */
+/* ISP_BLS_CTRL */
+#define RKISP1_CIF_ISP_BLS_ENA				BIT(0)
+#define RKISP1_CIF_ISP_BLS_MODE_MEASURED		BIT(1)
+#define RKISP1_CIF_ISP_BLS_MODE_FIXED			0
+#define RKISP1_CIF_ISP_BLS_WINDOW_1			BIT(2)
+#define RKISP1_CIF_ISP_BLS_WINDOW_2			(2 << 2)
+
+/* GAMMA-IN */
+#define RKISP1_CIFISP_DEGAMMA_X_RESERVED	\
+	((1 << 31) | (1 << 27) | (1 << 23) | (1 << 19) |\
+	(1 << 15) | (1 << 11) | (1 << 7) | (1 << 3))
+#define RKISP1_CIFISP_DEGAMMA_Y_RESERVED		0xFFFFF000
+
+/* AFM */
+#define RKISP1_CIF_ISP_AFM_ENA				BIT(0)
+#define RKISP1_CIF_ISP_AFM_THRES_RESERVED		0xFFFF0000
+#define RKISP1_CIF_ISP_AFM_VAR_SHIFT_RESERVED		0xFFF8FFF8
+#define RKISP1_CIF_ISP_AFM_WINDOW_X_RESERVED		0xE000
+#define RKISP1_CIF_ISP_AFM_WINDOW_Y_RESERVED		0xF000
+#define RKISP1_CIF_ISP_AFM_WINDOW_X_MIN			0x5
+#define RKISP1_CIF_ISP_AFM_WINDOW_Y_MIN			0x2
+#define RKISP1_CIF_ISP_AFM_WINDOW_X(x)			(((x) & 0x1FFF) << 16)
+#define RKISP1_CIF_ISP_AFM_WINDOW_Y(x)			((x) & 0x1FFF)
+
+/* DPF */
+#define RKISP1_CIF_ISP_DPF_MODE_EN			BIT(0)
+#define RKISP1_CIF_ISP_DPF_MODE_B_FLT_DIS		BIT(1)
+#define RKISP1_CIF_ISP_DPF_MODE_GB_FLT_DIS		BIT(2)
+#define RKISP1_CIF_ISP_DPF_MODE_GR_FLT_DIS		BIT(3)
+#define RKISP1_CIF_ISP_DPF_MODE_R_FLT_DIS		BIT(4)
+#define RKISP1_CIF_ISP_DPF_MODE_RB_FLTSIZE_9x9		BIT(5)
+#define RKISP1_CIF_ISP_DPF_MODE_NLL_SEGMENTATION	BIT(6)
+#define RKISP1_CIF_ISP_DPF_MODE_AWB_GAIN_COMP		BIT(7)
+#define RKISP1_CIF_ISP_DPF_MODE_LSC_GAIN_COMP		BIT(8)
+#define RKISP1_CIF_ISP_DPF_MODE_USE_NF_GAIN		BIT(9)
+#define RKISP1_CIF_ISP_DPF_NF_GAIN_RESERVED		0xFFFFF000
+#define RKISP1_CIF_ISP_DPF_SPATIAL_COEFF_MAX		0x1F
+#define RKISP1_CIF_ISP_DPF_NLL_COEFF_N_MAX		0x3FF
+
+/* =================================================================== */
+/*                            CIF Registers                            */
+/* =================================================================== */
+#define RKISP1_CIF_CTRL_BASE			0x00000000
+#define RKISP1_CIF_CCL				(RKISP1_CIF_CTRL_BASE + 0x00000000)
+#define RKISP1_CIF_VI_ID			(RKISP1_CIF_CTRL_BASE + 0x00000008)
+#define RKISP1_CIF_ICCL				(RKISP1_CIF_CTRL_BASE + 0x00000010)
+#define RKISP1_CIF_IRCL				(RKISP1_CIF_CTRL_BASE + 0x00000014)
+#define RKISP1_CIF_VI_DPCL			(RKISP1_CIF_CTRL_BASE + 0x00000018)
+
+#define RKISP1_CIF_IMG_EFF_BASE			0x00000200
+#define RKISP1_CIF_IMG_EFF_CTRL			(RKISP1_CIF_IMG_EFF_BASE + 0x00000000)
+#define RKISP1_CIF_IMG_EFF_COLOR_SEL		(RKISP1_CIF_IMG_EFF_BASE + 0x00000004)
+#define RKISP1_CIF_IMG_EFF_MAT_1		(RKISP1_CIF_IMG_EFF_BASE + 0x00000008)
+#define RKISP1_CIF_IMG_EFF_MAT_2		(RKISP1_CIF_IMG_EFF_BASE + 0x0000000C)
+#define RKISP1_CIF_IMG_EFF_MAT_3		(RKISP1_CIF_IMG_EFF_BASE + 0x00000010)
+#define RKISP1_CIF_IMG_EFF_MAT_4		(RKISP1_CIF_IMG_EFF_BASE + 0x00000014)
+#define RKISP1_CIF_IMG_EFF_MAT_5		(RKISP1_CIF_IMG_EFF_BASE + 0x00000018)
+#define RKISP1_CIF_IMG_EFF_TINT			(RKISP1_CIF_IMG_EFF_BASE + 0x0000001C)
+#define RKISP1_CIF_IMG_EFF_CTRL_SHD		(RKISP1_CIF_IMG_EFF_BASE + 0x00000020)
+#define RKISP1_CIF_IMG_EFF_SHARPEN		(RKISP1_CIF_IMG_EFF_BASE + 0x00000024)
+
+#define RKISP1_CIF_SUPER_IMP_BASE		0x00000300
+#define RKISP1_CIF_SUPER_IMP_CTRL		(RKISP1_CIF_SUPER_IMP_BASE + 0x00000000)
+#define RKISP1_CIF_SUPER_IMP_OFFSET_X		(RKISP1_CIF_SUPER_IMP_BASE + 0x00000004)
+#define RKISP1_CIF_SUPER_IMP_OFFSET_Y		(RKISP1_CIF_SUPER_IMP_BASE + 0x00000008)
+#define RKISP1_CIF_SUPER_IMP_COLOR_Y		(RKISP1_CIF_SUPER_IMP_BASE + 0x0000000C)
+#define RKISP1_CIF_SUPER_IMP_COLOR_CB		(RKISP1_CIF_SUPER_IMP_BASE + 0x00000010)
+#define RKISP1_CIF_SUPER_IMP_COLOR_CR		(RKISP1_CIF_SUPER_IMP_BASE + 0x00000014)
+
+#define RKISP1_CIF_ISP_BASE			0x00000400
+#define RKISP1_CIF_ISP_CTRL			(RKISP1_CIF_ISP_BASE + 0x00000000)
+#define RKISP1_CIF_ISP_ACQ_PROP			(RKISP1_CIF_ISP_BASE + 0x00000004)
+#define RKISP1_CIF_ISP_ACQ_H_OFFS		(RKISP1_CIF_ISP_BASE + 0x00000008)
+#define RKISP1_CIF_ISP_ACQ_V_OFFS		(RKISP1_CIF_ISP_BASE + 0x0000000C)
+#define RKISP1_CIF_ISP_ACQ_H_SIZE		(RKISP1_CIF_ISP_BASE + 0x00000010)
+#define RKISP1_CIF_ISP_ACQ_V_SIZE		(RKISP1_CIF_ISP_BASE + 0x00000014)
+#define RKISP1_CIF_ISP_ACQ_NR_FRAMES		(RKISP1_CIF_ISP_BASE + 0x00000018)
+#define RKISP1_CIF_ISP_GAMMA_DX_LO		(RKISP1_CIF_ISP_BASE + 0x0000001C)
+#define RKISP1_CIF_ISP_GAMMA_DX_HI		(RKISP1_CIF_ISP_BASE + 0x00000020)
+#define RKISP1_CIF_ISP_GAMMA_R_Y0		(RKISP1_CIF_ISP_BASE + 0x00000024)
+#define RKISP1_CIF_ISP_GAMMA_R_Y1		(RKISP1_CIF_ISP_BASE + 0x00000028)
+#define RKISP1_CIF_ISP_GAMMA_R_Y2		(RKISP1_CIF_ISP_BASE + 0x0000002C)
+#define RKISP1_CIF_ISP_GAMMA_R_Y3		(RKISP1_CIF_ISP_BASE + 0x00000030)
+#define RKISP1_CIF_ISP_GAMMA_R_Y4		(RKISP1_CIF_ISP_BASE + 0x00000034)
+#define RKISP1_CIF_ISP_GAMMA_R_Y5		(RKISP1_CIF_ISP_BASE + 0x00000038)
+#define RKISP1_CIF_ISP_GAMMA_R_Y6		(RKISP1_CIF_ISP_BASE + 0x0000003C)
+#define RKISP1_CIF_ISP_GAMMA_R_Y7		(RKISP1_CIF_ISP_BASE + 0x00000040)
+#define RKISP1_CIF_ISP_GAMMA_R_Y8		(RKISP1_CIF_ISP_BASE + 0x00000044)
+#define RKISP1_CIF_ISP_GAMMA_R_Y9		(RKISP1_CIF_ISP_BASE + 0x00000048)
+#define RKISP1_CIF_ISP_GAMMA_R_Y10		(RKISP1_CIF_ISP_BASE + 0x0000004C)
+#define RKISP1_CIF_ISP_GAMMA_R_Y11		(RKISP1_CIF_ISP_BASE + 0x00000050)
+#define RKISP1_CIF_ISP_GAMMA_R_Y12		(RKISP1_CIF_ISP_BASE + 0x00000054)
+#define RKISP1_CIF_ISP_GAMMA_R_Y13		(RKISP1_CIF_ISP_BASE + 0x00000058)
+#define RKISP1_CIF_ISP_GAMMA_R_Y14		(RKISP1_CIF_ISP_BASE + 0x0000005C)
+#define RKISP1_CIF_ISP_GAMMA_R_Y15		(RKISP1_CIF_ISP_BASE + 0x00000060)
+#define RKISP1_CIF_ISP_GAMMA_R_Y16		(RKISP1_CIF_ISP_BASE + 0x00000064)
+#define RKISP1_CIF_ISP_GAMMA_G_Y0		(RKISP1_CIF_ISP_BASE + 0x00000068)
+#define RKISP1_CIF_ISP_GAMMA_G_Y1		(RKISP1_CIF_ISP_BASE + 0x0000006C)
+#define RKISP1_CIF_ISP_GAMMA_G_Y2		(RKISP1_CIF_ISP_BASE + 0x00000070)
+#define RKISP1_CIF_ISP_GAMMA_G_Y3		(RKISP1_CIF_ISP_BASE + 0x00000074)
+#define RKISP1_CIF_ISP_GAMMA_G_Y4		(RKISP1_CIF_ISP_BASE + 0x00000078)
+#define RKISP1_CIF_ISP_GAMMA_G_Y5		(RKISP1_CIF_ISP_BASE + 0x0000007C)
+#define RKISP1_CIF_ISP_GAMMA_G_Y6		(RKISP1_CIF_ISP_BASE + 0x00000080)
+#define RKISP1_CIF_ISP_GAMMA_G_Y7		(RKISP1_CIF_ISP_BASE + 0x00000084)
+#define RKISP1_CIF_ISP_GAMMA_G_Y8		(RKISP1_CIF_ISP_BASE + 0x00000088)
+#define RKISP1_CIF_ISP_GAMMA_G_Y9		(RKISP1_CIF_ISP_BASE + 0x0000008C)
+#define RKISP1_CIF_ISP_GAMMA_G_Y10		(RKISP1_CIF_ISP_BASE + 0x00000090)
+#define RKISP1_CIF_ISP_GAMMA_G_Y11		(RKISP1_CIF_ISP_BASE + 0x00000094)
+#define RKISP1_CIF_ISP_GAMMA_G_Y12		(RKISP1_CIF_ISP_BASE + 0x00000098)
+#define RKISP1_CIF_ISP_GAMMA_G_Y13		(RKISP1_CIF_ISP_BASE + 0x0000009C)
+#define RKISP1_CIF_ISP_GAMMA_G_Y14		(RKISP1_CIF_ISP_BASE + 0x000000A0)
+#define RKISP1_CIF_ISP_GAMMA_G_Y15		(RKISP1_CIF_ISP_BASE + 0x000000A4)
+#define RKISP1_CIF_ISP_GAMMA_G_Y16		(RKISP1_CIF_ISP_BASE + 0x000000A8)
+#define RKISP1_CIF_ISP_GAMMA_B_Y0		(RKISP1_CIF_ISP_BASE + 0x000000AC)
+#define RKISP1_CIF_ISP_GAMMA_B_Y1		(RKISP1_CIF_ISP_BASE + 0x000000B0)
+#define RKISP1_CIF_ISP_GAMMA_B_Y2		(RKISP1_CIF_ISP_BASE + 0x000000B4)
+#define RKISP1_CIF_ISP_GAMMA_B_Y3		(RKISP1_CIF_ISP_BASE + 0x000000B8)
+#define RKISP1_CIF_ISP_GAMMA_B_Y4		(RKISP1_CIF_ISP_BASE + 0x000000BC)
+#define RKISP1_CIF_ISP_GAMMA_B_Y5		(RKISP1_CIF_ISP_BASE + 0x000000C0)
+#define RKISP1_CIF_ISP_GAMMA_B_Y6		(RKISP1_CIF_ISP_BASE + 0x000000C4)
+#define RKISP1_CIF_ISP_GAMMA_B_Y7		(RKISP1_CIF_ISP_BASE + 0x000000C8)
+#define RKISP1_CIF_ISP_GAMMA_B_Y8		(RKISP1_CIF_ISP_BASE + 0x000000CC)
+#define RKISP1_CIF_ISP_GAMMA_B_Y9		(RKISP1_CIF_ISP_BASE + 0x000000D0)
+#define RKISP1_CIF_ISP_GAMMA_B_Y10		(RKISP1_CIF_ISP_BASE + 0x000000D4)
+#define RKISP1_CIF_ISP_GAMMA_B_Y11		(RKISP1_CIF_ISP_BASE + 0x000000D8)
+#define RKISP1_CIF_ISP_GAMMA_B_Y12		(RKISP1_CIF_ISP_BASE + 0x000000DC)
+#define RKISP1_CIF_ISP_GAMMA_B_Y13		(RKISP1_CIF_ISP_BASE + 0x000000E0)
+#define RKISP1_CIF_ISP_GAMMA_B_Y14		(RKISP1_CIF_ISP_BASE + 0x000000E4)
+#define RKISP1_CIF_ISP_GAMMA_B_Y15		(RKISP1_CIF_ISP_BASE + 0x000000E8)
+#define RKISP1_CIF_ISP_GAMMA_B_Y16		(RKISP1_CIF_ISP_BASE + 0x000000EC)
+#define RKISP1_CIF_ISP_AWB_PROP			(RKISP1_CIF_ISP_BASE + 0x00000110)
+#define RKISP1_CIF_ISP_AWB_WND_H_OFFS		(RKISP1_CIF_ISP_BASE + 0x00000114)
+#define RKISP1_CIF_ISP_AWB_WND_V_OFFS		(RKISP1_CIF_ISP_BASE + 0x00000118)
+#define RKISP1_CIF_ISP_AWB_WND_H_SIZE		(RKISP1_CIF_ISP_BASE + 0x0000011C)
+#define RKISP1_CIF_ISP_AWB_WND_V_SIZE		(RKISP1_CIF_ISP_BASE + 0x00000120)
+#define RKISP1_CIF_ISP_AWB_FRAMES		(RKISP1_CIF_ISP_BASE + 0x00000124)
+#define RKISP1_CIF_ISP_AWB_REF			(RKISP1_CIF_ISP_BASE + 0x00000128)
+#define RKISP1_CIF_ISP_AWB_THRESH		(RKISP1_CIF_ISP_BASE + 0x0000012C)
+#define RKISP1_CIF_ISP_AWB_GAIN_G		(RKISP1_CIF_ISP_BASE + 0x00000138)
+#define RKISP1_CIF_ISP_AWB_GAIN_RB		(RKISP1_CIF_ISP_BASE + 0x0000013C)
+#define RKISP1_CIF_ISP_AWB_WHITE_CNT		(RKISP1_CIF_ISP_BASE + 0x00000140)
+#define RKISP1_CIF_ISP_AWB_MEAN			(RKISP1_CIF_ISP_BASE + 0x00000144)
+#define RKISP1_CIF_ISP_CC_COEFF_0		(RKISP1_CIF_ISP_BASE + 0x00000170)
+#define RKISP1_CIF_ISP_CC_COEFF_1		(RKISP1_CIF_ISP_BASE + 0x00000174)
+#define RKISP1_CIF_ISP_CC_COEFF_2		(RKISP1_CIF_ISP_BASE + 0x00000178)
+#define RKISP1_CIF_ISP_CC_COEFF_3		(RKISP1_CIF_ISP_BASE + 0x0000017C)
+#define RKISP1_CIF_ISP_CC_COEFF_4		(RKISP1_CIF_ISP_BASE + 0x00000180)
+#define RKISP1_CIF_ISP_CC_COEFF_5		(RKISP1_CIF_ISP_BASE + 0x00000184)
+#define RKISP1_CIF_ISP_CC_COEFF_6		(RKISP1_CIF_ISP_BASE + 0x00000188)
+#define RKISP1_CIF_ISP_CC_COEFF_7		(RKISP1_CIF_ISP_BASE + 0x0000018C)
+#define RKISP1_CIF_ISP_CC_COEFF_8		(RKISP1_CIF_ISP_BASE + 0x00000190)
+#define RKISP1_CIF_ISP_OUT_H_OFFS		(RKISP1_CIF_ISP_BASE + 0x00000194)
+#define RKISP1_CIF_ISP_OUT_V_OFFS		(RKISP1_CIF_ISP_BASE + 0x00000198)
+#define RKISP1_CIF_ISP_OUT_H_SIZE		(RKISP1_CIF_ISP_BASE + 0x0000019C)
+#define RKISP1_CIF_ISP_OUT_V_SIZE		(RKISP1_CIF_ISP_BASE + 0x000001A0)
+#define RKISP1_CIF_ISP_DEMOSAIC			(RKISP1_CIF_ISP_BASE + 0x000001A4)
+#define RKISP1_CIF_ISP_FLAGS_SHD		(RKISP1_CIF_ISP_BASE + 0x000001A8)
+#define RKISP1_CIF_ISP_OUT_H_OFFS_SHD		(RKISP1_CIF_ISP_BASE + 0x000001AC)
+#define RKISP1_CIF_ISP_OUT_V_OFFS_SHD		(RKISP1_CIF_ISP_BASE + 0x000001B0)
+#define RKISP1_CIF_ISP_OUT_H_SIZE_SHD		(RKISP1_CIF_ISP_BASE + 0x000001B4)
+#define RKISP1_CIF_ISP_OUT_V_SIZE_SHD		(RKISP1_CIF_ISP_BASE + 0x000001B8)
+#define RKISP1_CIF_ISP_IMSC			(RKISP1_CIF_ISP_BASE + 0x000001BC)
+#define RKISP1_CIF_ISP_RIS			(RKISP1_CIF_ISP_BASE + 0x000001C0)
+#define RKISP1_CIF_ISP_MIS			(RKISP1_CIF_ISP_BASE + 0x000001C4)
+#define RKISP1_CIF_ISP_ICR			(RKISP1_CIF_ISP_BASE + 0x000001C8)
+#define RKISP1_CIF_ISP_ISR			(RKISP1_CIF_ISP_BASE + 0x000001CC)
+#define RKISP1_CIF_ISP_CT_COEFF_0		(RKISP1_CIF_ISP_BASE + 0x000001D0)
+#define RKISP1_CIF_ISP_CT_COEFF_1		(RKISP1_CIF_ISP_BASE + 0x000001D4)
+#define RKISP1_CIF_ISP_CT_COEFF_2		(RKISP1_CIF_ISP_BASE + 0x000001D8)
+#define RKISP1_CIF_ISP_CT_COEFF_3		(RKISP1_CIF_ISP_BASE + 0x000001DC)
+#define RKISP1_CIF_ISP_CT_COEFF_4		(RKISP1_CIF_ISP_BASE + 0x000001E0)
+#define RKISP1_CIF_ISP_CT_COEFF_5		(RKISP1_CIF_ISP_BASE + 0x000001E4)
+#define RKISP1_CIF_ISP_CT_COEFF_6		(RKISP1_CIF_ISP_BASE + 0x000001E8)
+#define RKISP1_CIF_ISP_CT_COEFF_7		(RKISP1_CIF_ISP_BASE + 0x000001EC)
+#define RKISP1_CIF_ISP_CT_COEFF_8		(RKISP1_CIF_ISP_BASE + 0x000001F0)
+#define RKISP1_CIF_ISP_GAMMA_OUT_MODE		(RKISP1_CIF_ISP_BASE + 0x000001F4)
+#define RKISP1_CIF_ISP_GAMMA_OUT_Y_0		(RKISP1_CIF_ISP_BASE + 0x000001F8)
+#define RKISP1_CIF_ISP_GAMMA_OUT_Y_1		(RKISP1_CIF_ISP_BASE + 0x000001FC)
+#define RKISP1_CIF_ISP_GAMMA_OUT_Y_2		(RKISP1_CIF_ISP_BASE + 0x00000200)
+#define RKISP1_CIF_ISP_GAMMA_OUT_Y_3		(RKISP1_CIF_ISP_BASE + 0x00000204)
+#define RKISP1_CIF_ISP_GAMMA_OUT_Y_4		(RKISP1_CIF_ISP_BASE + 0x00000208)
+#define RKISP1_CIF_ISP_GAMMA_OUT_Y_5		(RKISP1_CIF_ISP_BASE + 0x0000020C)
+#define RKISP1_CIF_ISP_GAMMA_OUT_Y_6		(RKISP1_CIF_ISP_BASE + 0x00000210)
+#define RKISP1_CIF_ISP_GAMMA_OUT_Y_7		(RKISP1_CIF_ISP_BASE + 0x00000214)
+#define RKISP1_CIF_ISP_GAMMA_OUT_Y_8		(RKISP1_CIF_ISP_BASE + 0x00000218)
+#define RKISP1_CIF_ISP_GAMMA_OUT_Y_9		(RKISP1_CIF_ISP_BASE + 0x0000021C)
+#define RKISP1_CIF_ISP_GAMMA_OUT_Y_10		(RKISP1_CIF_ISP_BASE + 0x00000220)
+#define RKISP1_CIF_ISP_GAMMA_OUT_Y_11		(RKISP1_CIF_ISP_BASE + 0x00000224)
+#define RKISP1_CIF_ISP_GAMMA_OUT_Y_12		(RKISP1_CIF_ISP_BASE + 0x00000228)
+#define RKISP1_CIF_ISP_GAMMA_OUT_Y_13		(RKISP1_CIF_ISP_BASE + 0x0000022C)
+#define RKISP1_CIF_ISP_GAMMA_OUT_Y_14		(RKISP1_CIF_ISP_BASE + 0x00000230)
+#define RKISP1_CIF_ISP_GAMMA_OUT_Y_15		(RKISP1_CIF_ISP_BASE + 0x00000234)
+#define RKISP1_CIF_ISP_GAMMA_OUT_Y_16		(RKISP1_CIF_ISP_BASE + 0x00000238)
+#define RKISP1_CIF_ISP_ERR			(RKISP1_CIF_ISP_BASE + 0x0000023C)
+#define RKISP1_CIF_ISP_ERR_CLR			(RKISP1_CIF_ISP_BASE + 0x00000240)
+#define RKISP1_CIF_ISP_FRAME_COUNT		(RKISP1_CIF_ISP_BASE + 0x00000244)
+#define RKISP1_CIF_ISP_CT_OFFSET_R		(RKISP1_CIF_ISP_BASE + 0x00000248)
+#define RKISP1_CIF_ISP_CT_OFFSET_G		(RKISP1_CIF_ISP_BASE + 0x0000024C)
+#define RKISP1_CIF_ISP_CT_OFFSET_B		(RKISP1_CIF_ISP_BASE + 0x00000250)
+
+#define RKISP1_CIF_ISP_FLASH_BASE		0x00000660
+#define RKISP1_CIF_ISP_FLASH_CMD		(RKISP1_CIF_ISP_FLASH_BASE + 0x00000000)
+#define RKISP1_CIF_ISP_FLASH_CONFIG		(RKISP1_CIF_ISP_FLASH_BASE + 0x00000004)
+#define RKISP1_CIF_ISP_FLASH_PREDIV		(RKISP1_CIF_ISP_FLASH_BASE + 0x00000008)
+#define RKISP1_CIF_ISP_FLASH_DELAY		(RKISP1_CIF_ISP_FLASH_BASE + 0x0000000C)
+#define RKISP1_CIF_ISP_FLASH_TIME		(RKISP1_CIF_ISP_FLASH_BASE + 0x00000010)
+#define RKISP1_CIF_ISP_FLASH_MAXP		(RKISP1_CIF_ISP_FLASH_BASE + 0x00000014)
+
+#define RKISP1_CIF_ISP_SH_BASE			0x00000680
+#define RKISP1_CIF_ISP_SH_CTRL			(RKISP1_CIF_ISP_SH_BASE + 0x00000000)
+#define RKISP1_CIF_ISP_SH_PREDIV		(RKISP1_CIF_ISP_SH_BASE + 0x00000004)
+#define RKISP1_CIF_ISP_SH_DELAY			(RKISP1_CIF_ISP_SH_BASE + 0x00000008)
+#define RKISP1_CIF_ISP_SH_TIME			(RKISP1_CIF_ISP_SH_BASE + 0x0000000C)
+
+#define RKISP1_CIF_C_PROC_BASE			0x00000800
+#define RKISP1_CIF_C_PROC_CTRL			(RKISP1_CIF_C_PROC_BASE + 0x00000000)
+#define RKISP1_CIF_C_PROC_CONTRAST		(RKISP1_CIF_C_PROC_BASE + 0x00000004)
+#define RKISP1_CIF_C_PROC_BRIGHTNESS		(RKISP1_CIF_C_PROC_BASE + 0x00000008)
+#define RKISP1_CIF_C_PROC_SATURATION		(RKISP1_CIF_C_PROC_BASE + 0x0000000C)
+#define RKISP1_CIF_C_PROC_HUE			(RKISP1_CIF_C_PROC_BASE + 0x00000010)
+
+#define RKISP1_CIF_DUAL_CROP_BASE		0x00000880
+#define RKISP1_CIF_DUAL_CROP_CTRL		(RKISP1_CIF_DUAL_CROP_BASE + 0x00000000)
+#define RKISP1_CIF_DUAL_CROP_M_H_OFFS		(RKISP1_CIF_DUAL_CROP_BASE + 0x00000004)
+#define RKISP1_CIF_DUAL_CROP_M_V_OFFS		(RKISP1_CIF_DUAL_CROP_BASE + 0x00000008)
+#define RKISP1_CIF_DUAL_CROP_M_H_SIZE		(RKISP1_CIF_DUAL_CROP_BASE + 0x0000000C)
+#define RKISP1_CIF_DUAL_CROP_M_V_SIZE		(RKISP1_CIF_DUAL_CROP_BASE + 0x00000010)
+#define RKISP1_CIF_DUAL_CROP_S_H_OFFS		(RKISP1_CIF_DUAL_CROP_BASE + 0x00000014)
+#define RKISP1_CIF_DUAL_CROP_S_V_OFFS		(RKISP1_CIF_DUAL_CROP_BASE + 0x00000018)
+#define RKISP1_CIF_DUAL_CROP_S_H_SIZE		(RKISP1_CIF_DUAL_CROP_BASE + 0x0000001C)
+#define RKISP1_CIF_DUAL_CROP_S_V_SIZE		(RKISP1_CIF_DUAL_CROP_BASE + 0x00000020)
+#define RKISP1_CIF_DUAL_CROP_M_H_OFFS_SHD	(RKISP1_CIF_DUAL_CROP_BASE + 0x00000024)
+#define RKISP1_CIF_DUAL_CROP_M_V_OFFS_SHD	(RKISP1_CIF_DUAL_CROP_BASE + 0x00000028)
+#define RKISP1_CIF_DUAL_CROP_M_H_SIZE_SHD	(RKISP1_CIF_DUAL_CROP_BASE + 0x0000002C)
+#define RKISP1_CIF_DUAL_CROP_M_V_SIZE_SHD	(RKISP1_CIF_DUAL_CROP_BASE + 0x00000030)
+#define RKISP1_CIF_DUAL_CROP_S_H_OFFS_SHD	(RKISP1_CIF_DUAL_CROP_BASE + 0x00000034)
+#define RKISP1_CIF_DUAL_CROP_S_V_OFFS_SHD	(RKISP1_CIF_DUAL_CROP_BASE + 0x00000038)
+#define RKISP1_CIF_DUAL_CROP_S_H_SIZE_SHD	(RKISP1_CIF_DUAL_CROP_BASE + 0x0000003C)
+#define RKISP1_CIF_DUAL_CROP_S_V_SIZE_SHD	(RKISP1_CIF_DUAL_CROP_BASE + 0x00000040)
+
+#define RKISP1_CIF_MRSZ_BASE			0x00000C00
+#define RKISP1_CIF_MRSZ_CTRL			(RKISP1_CIF_MRSZ_BASE + 0x00000000)
+#define RKISP1_CIF_MRSZ_SCALE_HY		(RKISP1_CIF_MRSZ_BASE + 0x00000004)
+#define RKISP1_CIF_MRSZ_SCALE_HCB		(RKISP1_CIF_MRSZ_BASE + 0x00000008)
+#define RKISP1_CIF_MRSZ_SCALE_HCR		(RKISP1_CIF_MRSZ_BASE + 0x0000000C)
+#define RKISP1_CIF_MRSZ_SCALE_VY		(RKISP1_CIF_MRSZ_BASE + 0x00000010)
+#define RKISP1_CIF_MRSZ_SCALE_VC		(RKISP1_CIF_MRSZ_BASE + 0x00000014)
+#define RKISP1_CIF_MRSZ_PHASE_HY		(RKISP1_CIF_MRSZ_BASE + 0x00000018)
+#define RKISP1_CIF_MRSZ_PHASE_HC		(RKISP1_CIF_MRSZ_BASE + 0x0000001C)
+#define RKISP1_CIF_MRSZ_PHASE_VY		(RKISP1_CIF_MRSZ_BASE + 0x00000020)
+#define RKISP1_CIF_MRSZ_PHASE_VC		(RKISP1_CIF_MRSZ_BASE + 0x00000024)
+#define RKISP1_CIF_MRSZ_SCALE_LUT_ADDR		(RKISP1_CIF_MRSZ_BASE + 0x00000028)
+#define RKISP1_CIF_MRSZ_SCALE_LUT		(RKISP1_CIF_MRSZ_BASE + 0x0000002C)
+#define RKISP1_CIF_MRSZ_CTRL_SHD		(RKISP1_CIF_MRSZ_BASE + 0x00000030)
+#define RKISP1_CIF_MRSZ_SCALE_HY_SHD		(RKISP1_CIF_MRSZ_BASE + 0x00000034)
+#define RKISP1_CIF_MRSZ_SCALE_HCB_SHD		(RKISP1_CIF_MRSZ_BASE + 0x00000038)
+#define RKISP1_CIF_MRSZ_SCALE_HCR_SHD		(RKISP1_CIF_MRSZ_BASE + 0x0000003C)
+#define RKISP1_CIF_MRSZ_SCALE_VY_SHD		(RKISP1_CIF_MRSZ_BASE + 0x00000040)
+#define RKISP1_CIF_MRSZ_SCALE_VC_SHD		(RKISP1_CIF_MRSZ_BASE + 0x00000044)
+#define RKISP1_CIF_MRSZ_PHASE_HY_SHD		(RKISP1_CIF_MRSZ_BASE + 0x00000048)
+#define RKISP1_CIF_MRSZ_PHASE_HC_SHD		(RKISP1_CIF_MRSZ_BASE + 0x0000004C)
+#define RKISP1_CIF_MRSZ_PHASE_VY_SHD		(RKISP1_CIF_MRSZ_BASE + 0x00000050)
+#define RKISP1_CIF_MRSZ_PHASE_VC_SHD		(RKISP1_CIF_MRSZ_BASE + 0x00000054)
+
+#define RKISP1_CIF_SRSZ_BASE			0x00001000
+#define RKISP1_CIF_SRSZ_CTRL			(RKISP1_CIF_SRSZ_BASE + 0x00000000)
+#define RKISP1_CIF_SRSZ_SCALE_HY		(RKISP1_CIF_SRSZ_BASE + 0x00000004)
+#define RKISP1_CIF_SRSZ_SCALE_HCB		(RKISP1_CIF_SRSZ_BASE + 0x00000008)
+#define RKISP1_CIF_SRSZ_SCALE_HCR		(RKISP1_CIF_SRSZ_BASE + 0x0000000C)
+#define RKISP1_CIF_SRSZ_SCALE_VY		(RKISP1_CIF_SRSZ_BASE + 0x00000010)
+#define RKISP1_CIF_SRSZ_SCALE_VC		(RKISP1_CIF_SRSZ_BASE + 0x00000014)
+#define RKISP1_CIF_SRSZ_PHASE_HY		(RKISP1_CIF_SRSZ_BASE + 0x00000018)
+#define RKISP1_CIF_SRSZ_PHASE_HC		(RKISP1_CIF_SRSZ_BASE + 0x0000001C)
+#define RKISP1_CIF_SRSZ_PHASE_VY		(RKISP1_CIF_SRSZ_BASE + 0x00000020)
+#define RKISP1_CIF_SRSZ_PHASE_VC		(RKISP1_CIF_SRSZ_BASE + 0x00000024)
+#define RKISP1_CIF_SRSZ_SCALE_LUT_ADDR		(RKISP1_CIF_SRSZ_BASE + 0x00000028)
+#define RKISP1_CIF_SRSZ_SCALE_LUT		(RKISP1_CIF_SRSZ_BASE + 0x0000002C)
+#define RKISP1_CIF_SRSZ_CTRL_SHD		(RKISP1_CIF_SRSZ_BASE + 0x00000030)
+#define RKISP1_CIF_SRSZ_SCALE_HY_SHD		(RKISP1_CIF_SRSZ_BASE + 0x00000034)
+#define RKISP1_CIF_SRSZ_SCALE_HCB_SHD		(RKISP1_CIF_SRSZ_BASE + 0x00000038)
+#define RKISP1_CIF_SRSZ_SCALE_HCR_SHD		(RKISP1_CIF_SRSZ_BASE + 0x0000003C)
+#define RKISP1_CIF_SRSZ_SCALE_VY_SHD		(RKISP1_CIF_SRSZ_BASE + 0x00000040)
+#define RKISP1_CIF_SRSZ_SCALE_VC_SHD		(RKISP1_CIF_SRSZ_BASE + 0x00000044)
+#define RKISP1_CIF_SRSZ_PHASE_HY_SHD		(RKISP1_CIF_SRSZ_BASE + 0x00000048)
+#define RKISP1_CIF_SRSZ_PHASE_HC_SHD		(RKISP1_CIF_SRSZ_BASE + 0x0000004C)
+#define RKISP1_CIF_SRSZ_PHASE_VY_SHD		(RKISP1_CIF_SRSZ_BASE + 0x00000050)
+#define RKISP1_CIF_SRSZ_PHASE_VC_SHD		(RKISP1_CIF_SRSZ_BASE + 0x00000054)
+
+#define RKISP1_CIF_MI_BASE			0x00001400
+#define RKISP1_CIF_MI_CTRL			(RKISP1_CIF_MI_BASE + 0x00000000)
+#define RKISP1_CIF_MI_INIT			(RKISP1_CIF_MI_BASE + 0x00000004)
+#define RKISP1_CIF_MI_MP_Y_BASE_AD_INIT		(RKISP1_CIF_MI_BASE + 0x00000008)
+#define RKISP1_CIF_MI_MP_Y_SIZE_INIT		(RKISP1_CIF_MI_BASE + 0x0000000C)
+#define RKISP1_CIF_MI_MP_Y_OFFS_CNT_INIT	(RKISP1_CIF_MI_BASE + 0x00000010)
+#define RKISP1_CIF_MI_MP_Y_OFFS_CNT_START	(RKISP1_CIF_MI_BASE + 0x00000014)
+#define RKISP1_CIF_MI_MP_Y_IRQ_OFFS_INIT	(RKISP1_CIF_MI_BASE + 0x00000018)
+#define RKISP1_CIF_MI_MP_CB_BASE_AD_INIT	(RKISP1_CIF_MI_BASE + 0x0000001C)
+#define RKISP1_CIF_MI_MP_CB_SIZE_INIT		(RKISP1_CIF_MI_BASE + 0x00000020)
+#define RKISP1_CIF_MI_MP_CB_OFFS_CNT_INIT	(RKISP1_CIF_MI_BASE + 0x00000024)
+#define RKISP1_CIF_MI_MP_CB_OFFS_CNT_START	(RKISP1_CIF_MI_BASE + 0x00000028)
+#define RKISP1_CIF_MI_MP_CR_BASE_AD_INIT	(RKISP1_CIF_MI_BASE + 0x0000002C)
+#define RKISP1_CIF_MI_MP_CR_SIZE_INIT		(RKISP1_CIF_MI_BASE + 0x00000030)
+#define RKISP1_CIF_MI_MP_CR_OFFS_CNT_INIT	(RKISP1_CIF_MI_BASE + 0x00000034)
+#define RKISP1_CIF_MI_MP_CR_OFFS_CNT_START	(RKISP1_CIF_MI_BASE + 0x00000038)
+#define RKISP1_CIF_MI_SP_Y_BASE_AD_INIT		(RKISP1_CIF_MI_BASE + 0x0000003C)
+#define RKISP1_CIF_MI_SP_Y_SIZE_INIT		(RKISP1_CIF_MI_BASE + 0x00000040)
+#define RKISP1_CIF_MI_SP_Y_OFFS_CNT_INIT	(RKISP1_CIF_MI_BASE + 0x00000044)
+#define RKISP1_CIF_MI_SP_Y_OFFS_CNT_START	(RKISP1_CIF_MI_BASE + 0x00000048)
+#define RKISP1_CIF_MI_SP_Y_LLENGTH		(RKISP1_CIF_MI_BASE + 0x0000004C)
+#define RKISP1_CIF_MI_SP_CB_BASE_AD_INIT	(RKISP1_CIF_MI_BASE + 0x00000050)
+#define RKISP1_CIF_MI_SP_CB_SIZE_INIT		(RKISP1_CIF_MI_BASE + 0x00000054)
+#define RKISP1_CIF_MI_SP_CB_OFFS_CNT_INIT	(RKISP1_CIF_MI_BASE + 0x00000058)
+#define RKISP1_CIF_MI_SP_CB_OFFS_CNT_START	(RKISP1_CIF_MI_BASE + 0x0000005C)
+#define RKISP1_CIF_MI_SP_CR_BASE_AD_INIT	(RKISP1_CIF_MI_BASE + 0x00000060)
+#define RKISP1_CIF_MI_SP_CR_SIZE_INIT		(RKISP1_CIF_MI_BASE + 0x00000064)
+#define RKISP1_CIF_MI_SP_CR_OFFS_CNT_INIT	(RKISP1_CIF_MI_BASE + 0x00000068)
+#define RKISP1_CIF_MI_SP_CR_OFFS_CNT_START	(RKISP1_CIF_MI_BASE + 0x0000006C)
+#define RKISP1_CIF_MI_BYTE_CNT			(RKISP1_CIF_MI_BASE + 0x00000070)
+#define RKISP1_CIF_MI_CTRL_SHD			(RKISP1_CIF_MI_BASE + 0x00000074)
+#define RKISP1_CIF_MI_MP_Y_BASE_AD_SHD		(RKISP1_CIF_MI_BASE + 0x00000078)
+#define RKISP1_CIF_MI_MP_Y_SIZE_SHD		(RKISP1_CIF_MI_BASE + 0x0000007C)
+#define RKISP1_CIF_MI_MP_Y_OFFS_CNT_SHD		(RKISP1_CIF_MI_BASE + 0x00000080)
+#define RKISP1_CIF_MI_MP_Y_IRQ_OFFS_SHD		(RKISP1_CIF_MI_BASE + 0x00000084)
+#define RKISP1_CIF_MI_MP_CB_BASE_AD_SHD		(RKISP1_CIF_MI_BASE + 0x00000088)
+#define RKISP1_CIF_MI_MP_CB_SIZE_SHD		(RKISP1_CIF_MI_BASE + 0x0000008C)
+#define RKISP1_CIF_MI_MP_CB_OFFS_CNT_SHD	(RKISP1_CIF_MI_BASE + 0x00000090)
+#define RKISP1_CIF_MI_MP_CR_BASE_AD_SHD		(RKISP1_CIF_MI_BASE + 0x00000094)
+#define RKISP1_CIF_MI_MP_CR_SIZE_SHD		(RKISP1_CIF_MI_BASE + 0x00000098)
+#define RKISP1_CIF_MI_MP_CR_OFFS_CNT_SHD	(RKISP1_CIF_MI_BASE + 0x0000009C)
+#define RKISP1_CIF_MI_SP_Y_BASE_AD_SHD		(RKISP1_CIF_MI_BASE + 0x000000A0)
+#define RKISP1_CIF_MI_SP_Y_SIZE_SHD		(RKISP1_CIF_MI_BASE + 0x000000A4)
+#define RKISP1_CIF_MI_SP_Y_OFFS_CNT_SHD		(RKISP1_CIF_MI_BASE + 0x000000A8)
+#define RKISP1_CIF_MI_SP_CB_BASE_AD_SHD		(RKISP1_CIF_MI_BASE + 0x000000B0)
+#define RKISP1_CIF_MI_SP_CB_SIZE_SHD		(RKISP1_CIF_MI_BASE + 0x000000B4)
+#define RKISP1_CIF_MI_SP_CB_OFFS_CNT_SHD	(RKISP1_CIF_MI_BASE + 0x000000B8)
+#define RKISP1_CIF_MI_SP_CR_BASE_AD_SHD		(RKISP1_CIF_MI_BASE + 0x000000BC)
+#define RKISP1_CIF_MI_SP_CR_SIZE_SHD		(RKISP1_CIF_MI_BASE + 0x000000C0)
+#define RKISP1_CIF_MI_SP_CR_OFFS_CNT_SHD	(RKISP1_CIF_MI_BASE + 0x000000C4)
+#define RKISP1_CIF_MI_DMA_Y_PIC_START_AD	(RKISP1_CIF_MI_BASE + 0x000000C8)
+#define RKISP1_CIF_MI_DMA_Y_PIC_WIDTH		(RKISP1_CIF_MI_BASE + 0x000000CC)
+#define RKISP1_CIF_MI_DMA_Y_LLENGTH		(RKISP1_CIF_MI_BASE + 0x000000D0)
+#define RKISP1_CIF_MI_DMA_Y_PIC_SIZE		(RKISP1_CIF_MI_BASE + 0x000000D4)
+#define RKISP1_CIF_MI_DMA_CB_PIC_START_AD	(RKISP1_CIF_MI_BASE + 0x000000D8)
+#define RKISP1_CIF_MI_DMA_CR_PIC_START_AD	(RKISP1_CIF_MI_BASE + 0x000000E8)
+#define RKISP1_CIF_MI_IMSC			(RKISP1_CIF_MI_BASE + 0x000000F8)
+#define RKISP1_CIF_MI_RIS			(RKISP1_CIF_MI_BASE + 0x000000FC)
+#define RKISP1_CIF_MI_MIS			(RKISP1_CIF_MI_BASE + 0x00000100)
+#define RKISP1_CIF_MI_ICR			(RKISP1_CIF_MI_BASE + 0x00000104)
+#define RKISP1_CIF_MI_ISR			(RKISP1_CIF_MI_BASE + 0x00000108)
+#define RKISP1_CIF_MI_STATUS			(RKISP1_CIF_MI_BASE + 0x0000010C)
+#define RKISP1_CIF_MI_STATUS_CLR		(RKISP1_CIF_MI_BASE + 0x00000110)
+#define RKISP1_CIF_MI_SP_Y_PIC_WIDTH		(RKISP1_CIF_MI_BASE + 0x00000114)
+#define RKISP1_CIF_MI_SP_Y_PIC_HEIGHT		(RKISP1_CIF_MI_BASE + 0x00000118)
+#define RKISP1_CIF_MI_SP_Y_PIC_SIZE		(RKISP1_CIF_MI_BASE + 0x0000011C)
+#define RKISP1_CIF_MI_DMA_CTRL			(RKISP1_CIF_MI_BASE + 0x00000120)
+#define RKISP1_CIF_MI_DMA_START			(RKISP1_CIF_MI_BASE + 0x00000124)
+#define RKISP1_CIF_MI_DMA_STATUS		(RKISP1_CIF_MI_BASE + 0x00000128)
+#define RKISP1_CIF_MI_PIXEL_COUNT		(RKISP1_CIF_MI_BASE + 0x0000012C)
+#define RKISP1_CIF_MI_MP_Y_BASE_AD_INIT2	(RKISP1_CIF_MI_BASE + 0x00000130)
+#define RKISP1_CIF_MI_MP_CB_BASE_AD_INIT2	(RKISP1_CIF_MI_BASE + 0x00000134)
+#define RKISP1_CIF_MI_MP_CR_BASE_AD_INIT2	(RKISP1_CIF_MI_BASE + 0x00000138)
+#define RKISP1_CIF_MI_SP_Y_BASE_AD_INIT2	(RKISP1_CIF_MI_BASE + 0x0000013C)
+#define RKISP1_CIF_MI_SP_CB_BASE_AD_INIT2	(RKISP1_CIF_MI_BASE + 0x00000140)
+#define RKISP1_CIF_MI_SP_CR_BASE_AD_INIT2	(RKISP1_CIF_MI_BASE + 0x00000144)
+#define RKISP1_CIF_MI_XTD_FORMAT_CTRL		(RKISP1_CIF_MI_BASE + 0x00000148)
+
+#define RKISP1_CIF_SMIA_BASE			0x00001A00
+#define RKISP1_CIF_SMIA_CTRL			(RKISP1_CIF_SMIA_BASE + 0x00000000)
+#define RKISP1_CIF_SMIA_STATUS			(RKISP1_CIF_SMIA_BASE + 0x00000004)
+#define RKISP1_CIF_SMIA_IMSC			(RKISP1_CIF_SMIA_BASE + 0x00000008)
+#define RKISP1_CIF_SMIA_RIS			(RKISP1_CIF_SMIA_BASE + 0x0000000C)
+#define RKISP1_CIF_SMIA_MIS			(RKISP1_CIF_SMIA_BASE + 0x00000010)
+#define RKISP1_CIF_SMIA_ICR			(RKISP1_CIF_SMIA_BASE + 0x00000014)
+#define RKISP1_CIF_SMIA_ISR			(RKISP1_CIF_SMIA_BASE + 0x00000018)
+#define RKISP1_CIF_SMIA_DATA_FORMAT_SEL		(RKISP1_CIF_SMIA_BASE + 0x0000001C)
+#define RKISP1_CIF_SMIA_SOF_EMB_DATA_LINES	(RKISP1_CIF_SMIA_BASE + 0x00000020)
+#define RKISP1_CIF_SMIA_EMB_HSTART		(RKISP1_CIF_SMIA_BASE + 0x00000024)
+#define RKISP1_CIF_SMIA_EMB_HSIZE		(RKISP1_CIF_SMIA_BASE + 0x00000028)
+#define RKISP1_CIF_SMIA_EMB_VSTART		(RKISP1_CIF_SMIA_BASE + 0x0000002c)
+#define RKISP1_CIF_SMIA_NUM_LINES		(RKISP1_CIF_SMIA_BASE + 0x00000030)
+#define RKISP1_CIF_SMIA_EMB_DATA_FIFO		(RKISP1_CIF_SMIA_BASE + 0x00000034)
+#define RKISP1_CIF_SMIA_EMB_DATA_WATERMARK	(RKISP1_CIF_SMIA_BASE + 0x00000038)
+
+#define RKISP1_CIF_MIPI_BASE			0x00001C00
+#define RKISP1_CIF_MIPI_CTRL			(RKISP1_CIF_MIPI_BASE + 0x00000000)
+#define RKISP1_CIF_MIPI_STATUS			(RKISP1_CIF_MIPI_BASE + 0x00000004)
+#define RKISP1_CIF_MIPI_IMSC			(RKISP1_CIF_MIPI_BASE + 0x00000008)
+#define RKISP1_CIF_MIPI_RIS			(RKISP1_CIF_MIPI_BASE + 0x0000000C)
+#define RKISP1_CIF_MIPI_MIS			(RKISP1_CIF_MIPI_BASE + 0x00000010)
+#define RKISP1_CIF_MIPI_ICR			(RKISP1_CIF_MIPI_BASE + 0x00000014)
+#define RKISP1_CIF_MIPI_ISR			(RKISP1_CIF_MIPI_BASE + 0x00000018)
+#define RKISP1_CIF_MIPI_CUR_DATA_ID		(RKISP1_CIF_MIPI_BASE + 0x0000001C)
+#define RKISP1_CIF_MIPI_IMG_DATA_SEL		(RKISP1_CIF_MIPI_BASE + 0x00000020)
+#define RKISP1_CIF_MIPI_ADD_DATA_SEL_1		(RKISP1_CIF_MIPI_BASE + 0x00000024)
+#define RKISP1_CIF_MIPI_ADD_DATA_SEL_2		(RKISP1_CIF_MIPI_BASE + 0x00000028)
+#define RKISP1_CIF_MIPI_ADD_DATA_SEL_3		(RKISP1_CIF_MIPI_BASE + 0x0000002C)
+#define RKISP1_CIF_MIPI_ADD_DATA_SEL_4		(RKISP1_CIF_MIPI_BASE + 0x00000030)
+#define RKISP1_CIF_MIPI_ADD_DATA_FIFO		(RKISP1_CIF_MIPI_BASE + 0x00000034)
+#define RKISP1_CIF_MIPI_FIFO_FILL_LEVEL		(RKISP1_CIF_MIPI_BASE + 0x00000038)
+#define RKISP1_CIF_MIPI_COMPRESSED_MODE		(RKISP1_CIF_MIPI_BASE + 0x0000003C)
+#define RKISP1_CIF_MIPI_FRAME			(RKISP1_CIF_MIPI_BASE + 0x00000040)
+#define RKISP1_CIF_MIPI_GEN_SHORT_DT		(RKISP1_CIF_MIPI_BASE + 0x00000044)
+#define RKISP1_CIF_MIPI_GEN_SHORT_8_9		(RKISP1_CIF_MIPI_BASE + 0x00000048)
+#define RKISP1_CIF_MIPI_GEN_SHORT_A_B		(RKISP1_CIF_MIPI_BASE + 0x0000004C)
+#define RKISP1_CIF_MIPI_GEN_SHORT_C_D		(RKISP1_CIF_MIPI_BASE + 0x00000050)
+#define RKISP1_CIF_MIPI_GEN_SHORT_E_F		(RKISP1_CIF_MIPI_BASE + 0x00000054)
+
+#define RKISP1_CIF_ISP_AFM_BASE			0x00002000
+#define RKISP1_CIF_ISP_AFM_CTRL			(RKISP1_CIF_ISP_AFM_BASE + 0x00000000)
+#define RKISP1_CIF_ISP_AFM_LT_A			(RKISP1_CIF_ISP_AFM_BASE + 0x00000004)
+#define RKISP1_CIF_ISP_AFM_RB_A			(RKISP1_CIF_ISP_AFM_BASE + 0x00000008)
+#define RKISP1_CIF_ISP_AFM_LT_B			(RKISP1_CIF_ISP_AFM_BASE + 0x0000000C)
+#define RKISP1_CIF_ISP_AFM_RB_B			(RKISP1_CIF_ISP_AFM_BASE + 0x00000010)
+#define RKISP1_CIF_ISP_AFM_LT_C			(RKISP1_CIF_ISP_AFM_BASE + 0x00000014)
+#define RKISP1_CIF_ISP_AFM_RB_C			(RKISP1_CIF_ISP_AFM_BASE + 0x00000018)
+#define RKISP1_CIF_ISP_AFM_THRES		(RKISP1_CIF_ISP_AFM_BASE + 0x0000001C)
+#define RKISP1_CIF_ISP_AFM_VAR_SHIFT		(RKISP1_CIF_ISP_AFM_BASE + 0x00000020)
+#define RKISP1_CIF_ISP_AFM_SUM_A		(RKISP1_CIF_ISP_AFM_BASE + 0x00000024)
+#define RKISP1_CIF_ISP_AFM_SUM_B		(RKISP1_CIF_ISP_AFM_BASE + 0x00000028)
+#define RKISP1_CIF_ISP_AFM_SUM_C		(RKISP1_CIF_ISP_AFM_BASE + 0x0000002C)
+#define RKISP1_CIF_ISP_AFM_LUM_A		(RKISP1_CIF_ISP_AFM_BASE + 0x00000030)
+#define RKISP1_CIF_ISP_AFM_LUM_B		(RKISP1_CIF_ISP_AFM_BASE + 0x00000034)
+#define RKISP1_CIF_ISP_AFM_LUM_C		(RKISP1_CIF_ISP_AFM_BASE + 0x00000038)
+
+#define RKISP1_CIF_ISP_LSC_BASE			0x00002200
+#define RKISP1_CIF_ISP_LSC_CTRL			(RKISP1_CIF_ISP_LSC_BASE + 0x00000000)
+#define RKISP1_CIF_ISP_LSC_R_TABLE_ADDR		(RKISP1_CIF_ISP_LSC_BASE + 0x00000004)
+#define RKISP1_CIF_ISP_LSC_GR_TABLE_ADDR	(RKISP1_CIF_ISP_LSC_BASE + 0x00000008)
+#define RKISP1_CIF_ISP_LSC_B_TABLE_ADDR		(RKISP1_CIF_ISP_LSC_BASE + 0x0000000C)
+#define RKISP1_CIF_ISP_LSC_GB_TABLE_ADDR	(RKISP1_CIF_ISP_LSC_BASE + 0x00000010)
+#define RKISP1_CIF_ISP_LSC_R_TABLE_DATA		(RKISP1_CIF_ISP_LSC_BASE + 0x00000014)
+#define RKISP1_CIF_ISP_LSC_GR_TABLE_DATA	(RKISP1_CIF_ISP_LSC_BASE + 0x00000018)
+#define RKISP1_CIF_ISP_LSC_B_TABLE_DATA		(RKISP1_CIF_ISP_LSC_BASE + 0x0000001C)
+#define RKISP1_CIF_ISP_LSC_GB_TABLE_DATA	(RKISP1_CIF_ISP_LSC_BASE + 0x00000020)
+#define RKISP1_CIF_ISP_LSC_XGRAD_01		(RKISP1_CIF_ISP_LSC_BASE + 0x00000024)
+#define RKISP1_CIF_ISP_LSC_XGRAD_23		(RKISP1_CIF_ISP_LSC_BASE + 0x00000028)
+#define RKISP1_CIF_ISP_LSC_XGRAD_45		(RKISP1_CIF_ISP_LSC_BASE + 0x0000002C)
+#define RKISP1_CIF_ISP_LSC_XGRAD_67		(RKISP1_CIF_ISP_LSC_BASE + 0x00000030)
+#define RKISP1_CIF_ISP_LSC_YGRAD_01		(RKISP1_CIF_ISP_LSC_BASE + 0x00000034)
+#define RKISP1_CIF_ISP_LSC_YGRAD_23		(RKISP1_CIF_ISP_LSC_BASE + 0x00000038)
+#define RKISP1_CIF_ISP_LSC_YGRAD_45		(RKISP1_CIF_ISP_LSC_BASE + 0x0000003C)
+#define RKISP1_CIF_ISP_LSC_YGRAD_67		(RKISP1_CIF_ISP_LSC_BASE + 0x00000040)
+#define RKISP1_CIF_ISP_LSC_XSIZE_01		(RKISP1_CIF_ISP_LSC_BASE + 0x00000044)
+#define RKISP1_CIF_ISP_LSC_XSIZE_23		(RKISP1_CIF_ISP_LSC_BASE + 0x00000048)
+#define RKISP1_CIF_ISP_LSC_XSIZE_45		(RKISP1_CIF_ISP_LSC_BASE + 0x0000004C)
+#define RKISP1_CIF_ISP_LSC_XSIZE_67		(RKISP1_CIF_ISP_LSC_BASE + 0x00000050)
+#define RKISP1_CIF_ISP_LSC_YSIZE_01		(RKISP1_CIF_ISP_LSC_BASE + 0x00000054)
+#define RKISP1_CIF_ISP_LSC_YSIZE_23		(RKISP1_CIF_ISP_LSC_BASE + 0x00000058)
+#define RKISP1_CIF_ISP_LSC_YSIZE_45		(RKISP1_CIF_ISP_LSC_BASE + 0x0000005C)
+#define RKISP1_CIF_ISP_LSC_YSIZE_67		(RKISP1_CIF_ISP_LSC_BASE + 0x00000060)
+#define RKISP1_CIF_ISP_LSC_TABLE_SEL		(RKISP1_CIF_ISP_LSC_BASE + 0x00000064)
+#define RKISP1_CIF_ISP_LSC_STATUS		(RKISP1_CIF_ISP_LSC_BASE + 0x00000068)
+
+#define RKISP1_CIF_ISP_IS_BASE			0x00002300
+#define RKISP1_CIF_ISP_IS_CTRL			(RKISP1_CIF_ISP_IS_BASE + 0x00000000)
+#define RKISP1_CIF_ISP_IS_RECENTER		(RKISP1_CIF_ISP_IS_BASE + 0x00000004)
+#define RKISP1_CIF_ISP_IS_H_OFFS		(RKISP1_CIF_ISP_IS_BASE + 0x00000008)
+#define RKISP1_CIF_ISP_IS_V_OFFS		(RKISP1_CIF_ISP_IS_BASE + 0x0000000C)
+#define RKISP1_CIF_ISP_IS_H_SIZE		(RKISP1_CIF_ISP_IS_BASE + 0x00000010)
+#define RKISP1_CIF_ISP_IS_V_SIZE		(RKISP1_CIF_ISP_IS_BASE + 0x00000014)
+#define RKISP1_CIF_ISP_IS_MAX_DX		(RKISP1_CIF_ISP_IS_BASE + 0x00000018)
+#define RKISP1_CIF_ISP_IS_MAX_DY		(RKISP1_CIF_ISP_IS_BASE + 0x0000001C)
+#define RKISP1_CIF_ISP_IS_DISPLACE		(RKISP1_CIF_ISP_IS_BASE + 0x00000020)
+#define RKISP1_CIF_ISP_IS_H_OFFS_SHD		(RKISP1_CIF_ISP_IS_BASE + 0x00000024)
+#define RKISP1_CIF_ISP_IS_V_OFFS_SHD		(RKISP1_CIF_ISP_IS_BASE + 0x00000028)
+#define RKISP1_CIF_ISP_IS_H_SIZE_SHD		(RKISP1_CIF_ISP_IS_BASE + 0x0000002C)
+#define RKISP1_CIF_ISP_IS_V_SIZE_SHD		(RKISP1_CIF_ISP_IS_BASE + 0x00000030)
+
+#define RKISP1_CIF_ISP_HIST_BASE		0x00002400
+
+#define RKISP1_CIF_ISP_HIST_PROP		(RKISP1_CIF_ISP_HIST_BASE + 0x00000000)
+#define RKISP1_CIF_ISP_HIST_H_OFFS		(RKISP1_CIF_ISP_HIST_BASE + 0x00000004)
+#define RKISP1_CIF_ISP_HIST_V_OFFS		(RKISP1_CIF_ISP_HIST_BASE + 0x00000008)
+#define RKISP1_CIF_ISP_HIST_H_SIZE		(RKISP1_CIF_ISP_HIST_BASE + 0x0000000C)
+#define RKISP1_CIF_ISP_HIST_V_SIZE		(RKISP1_CIF_ISP_HIST_BASE + 0x00000010)
+#define RKISP1_CIF_ISP_HIST_BIN_0		(RKISP1_CIF_ISP_HIST_BASE + 0x00000014)
+#define RKISP1_CIF_ISP_HIST_BIN_1		(RKISP1_CIF_ISP_HIST_BASE + 0x00000018)
+#define RKISP1_CIF_ISP_HIST_BIN_2		(RKISP1_CIF_ISP_HIST_BASE + 0x0000001C)
+#define RKISP1_CIF_ISP_HIST_BIN_3		(RKISP1_CIF_ISP_HIST_BASE + 0x00000020)
+#define RKISP1_CIF_ISP_HIST_BIN_4		(RKISP1_CIF_ISP_HIST_BASE + 0x00000024)
+#define RKISP1_CIF_ISP_HIST_BIN_5		(RKISP1_CIF_ISP_HIST_BASE + 0x00000028)
+#define RKISP1_CIF_ISP_HIST_BIN_6		(RKISP1_CIF_ISP_HIST_BASE + 0x0000002C)
+#define RKISP1_CIF_ISP_HIST_BIN_7		(RKISP1_CIF_ISP_HIST_BASE + 0x00000030)
+#define RKISP1_CIF_ISP_HIST_BIN_8		(RKISP1_CIF_ISP_HIST_BASE + 0x00000034)
+#define RKISP1_CIF_ISP_HIST_BIN_9		(RKISP1_CIF_ISP_HIST_BASE + 0x00000038)
+#define RKISP1_CIF_ISP_HIST_BIN_10		(RKISP1_CIF_ISP_HIST_BASE + 0x0000003C)
+#define RKISP1_CIF_ISP_HIST_BIN_11		(RKISP1_CIF_ISP_HIST_BASE + 0x00000040)
+#define RKISP1_CIF_ISP_HIST_BIN_12		(RKISP1_CIF_ISP_HIST_BASE + 0x00000044)
+#define RKISP1_CIF_ISP_HIST_BIN_13		(RKISP1_CIF_ISP_HIST_BASE + 0x00000048)
+#define RKISP1_CIF_ISP_HIST_BIN_14		(RKISP1_CIF_ISP_HIST_BASE + 0x0000004C)
+#define RKISP1_CIF_ISP_HIST_BIN_15		(RKISP1_CIF_ISP_HIST_BASE + 0x00000050)
+#define RKISP1_CIF_ISP_HIST_WEIGHT_00TO30	(RKISP1_CIF_ISP_HIST_BASE + 0x00000054)
+#define RKISP1_CIF_ISP_HIST_WEIGHT_40TO21	(RKISP1_CIF_ISP_HIST_BASE + 0x00000058)
+#define RKISP1_CIF_ISP_HIST_WEIGHT_31TO12	(RKISP1_CIF_ISP_HIST_BASE + 0x0000005C)
+#define RKISP1_CIF_ISP_HIST_WEIGHT_22TO03	(RKISP1_CIF_ISP_HIST_BASE + 0x00000060)
+#define RKISP1_CIF_ISP_HIST_WEIGHT_13TO43	(RKISP1_CIF_ISP_HIST_BASE + 0x00000064)
+#define RKISP1_CIF_ISP_HIST_WEIGHT_04TO34	(RKISP1_CIF_ISP_HIST_BASE + 0x00000068)
+#define RKISP1_CIF_ISP_HIST_WEIGHT_44		(RKISP1_CIF_ISP_HIST_BASE + 0x0000006C)
+
+#define RKISP1_CIF_ISP_FILT_BASE		0x00002500
+#define RKISP1_CIF_ISP_FILT_MODE		(RKISP1_CIF_ISP_FILT_BASE + 0x00000000)
+#define RKISP1_CIF_ISP_FILT_THRESH_BL0		(RKISP1_CIF_ISP_FILT_BASE + 0x00000028)
+#define RKISP1_CIF_ISP_FILT_THRESH_BL1		(RKISP1_CIF_ISP_FILT_BASE + 0x0000002c)
+#define RKISP1_CIF_ISP_FILT_THRESH_SH0		(RKISP1_CIF_ISP_FILT_BASE + 0x00000030)
+#define RKISP1_CIF_ISP_FILT_THRESH_SH1		(RKISP1_CIF_ISP_FILT_BASE + 0x00000034)
+#define RKISP1_CIF_ISP_FILT_LUM_WEIGHT		(RKISP1_CIF_ISP_FILT_BASE + 0x00000038)
+#define RKISP1_CIF_ISP_FILT_FAC_SH1		(RKISP1_CIF_ISP_FILT_BASE + 0x0000003c)
+#define RKISP1_CIF_ISP_FILT_FAC_SH0		(RKISP1_CIF_ISP_FILT_BASE + 0x00000040)
+#define RKISP1_CIF_ISP_FILT_FAC_MID		(RKISP1_CIF_ISP_FILT_BASE + 0x00000044)
+#define RKISP1_CIF_ISP_FILT_FAC_BL0		(RKISP1_CIF_ISP_FILT_BASE + 0x00000048)
+#define RKISP1_CIF_ISP_FILT_FAC_BL1		(RKISP1_CIF_ISP_FILT_BASE + 0x0000004C)
+
+#define RKISP1_CIF_ISP_CAC_BASE			0x00002580
+#define RKISP1_CIF_ISP_CAC_CTRL			(RKISP1_CIF_ISP_CAC_BASE + 0x00000000)
+#define RKISP1_CIF_ISP_CAC_COUNT_START		(RKISP1_CIF_ISP_CAC_BASE + 0x00000004)
+#define RKISP1_CIF_ISP_CAC_A			(RKISP1_CIF_ISP_CAC_BASE + 0x00000008)
+#define RKISP1_CIF_ISP_CAC_B			(RKISP1_CIF_ISP_CAC_BASE + 0x0000000C)
+#define RKISP1_CIF_ISP_CAC_C			(RKISP1_CIF_ISP_CAC_BASE + 0x00000010)
+#define RKISP1_CIF_ISP_X_NORM			(RKISP1_CIF_ISP_CAC_BASE + 0x00000014)
+#define RKISP1_CIF_ISP_Y_NORM			(RKISP1_CIF_ISP_CAC_BASE + 0x00000018)
+
+#define RKISP1_CIF_ISP_EXP_BASE			0x00002600
+#define RKISP1_CIF_ISP_EXP_CTRL			(RKISP1_CIF_ISP_EXP_BASE + 0x00000000)
+#define RKISP1_CIF_ISP_EXP_H_OFFSET		(RKISP1_CIF_ISP_EXP_BASE + 0x00000004)
+#define RKISP1_CIF_ISP_EXP_V_OFFSET		(RKISP1_CIF_ISP_EXP_BASE + 0x00000008)
+#define RKISP1_CIF_ISP_EXP_H_SIZE		(RKISP1_CIF_ISP_EXP_BASE + 0x0000000C)
+#define RKISP1_CIF_ISP_EXP_V_SIZE		(RKISP1_CIF_ISP_EXP_BASE + 0x00000010)
+#define RKISP1_CIF_ISP_EXP_MEAN_00		(RKISP1_CIF_ISP_EXP_BASE + 0x00000014)
+#define RKISP1_CIF_ISP_EXP_MEAN_10		(RKISP1_CIF_ISP_EXP_BASE + 0x00000018)
+#define RKISP1_CIF_ISP_EXP_MEAN_20		(RKISP1_CIF_ISP_EXP_BASE + 0x0000001c)
+#define RKISP1_CIF_ISP_EXP_MEAN_30		(RKISP1_CIF_ISP_EXP_BASE + 0x00000020)
+#define RKISP1_CIF_ISP_EXP_MEAN_40		(RKISP1_CIF_ISP_EXP_BASE + 0x00000024)
+#define RKISP1_CIF_ISP_EXP_MEAN_01		(RKISP1_CIF_ISP_EXP_BASE + 0x00000028)
+#define RKISP1_CIF_ISP_EXP_MEAN_11		(RKISP1_CIF_ISP_EXP_BASE + 0x0000002c)
+#define RKISP1_CIF_ISP_EXP_MEAN_21		(RKISP1_CIF_ISP_EXP_BASE + 0x00000030)
+#define RKISP1_CIF_ISP_EXP_MEAN_31		(RKISP1_CIF_ISP_EXP_BASE + 0x00000034)
+#define RKISP1_CIF_ISP_EXP_MEAN_41		(RKISP1_CIF_ISP_EXP_BASE + 0x00000038)
+#define RKISP1_CIF_ISP_EXP_MEAN_02		(RKISP1_CIF_ISP_EXP_BASE + 0x0000003c)
+#define RKISP1_CIF_ISP_EXP_MEAN_12		(RKISP1_CIF_ISP_EXP_BASE + 0x00000040)
+#define RKISP1_CIF_ISP_EXP_MEAN_22		(RKISP1_CIF_ISP_EXP_BASE + 0x00000044)
+#define RKISP1_CIF_ISP_EXP_MEAN_32		(RKISP1_CIF_ISP_EXP_BASE + 0x00000048)
+#define RKISP1_CIF_ISP_EXP_MEAN_42		(RKISP1_CIF_ISP_EXP_BASE + 0x0000004c)
+#define RKISP1_CIF_ISP_EXP_MEAN_03		(RKISP1_CIF_ISP_EXP_BASE + 0x00000050)
+#define RKISP1_CIF_ISP_EXP_MEAN_13		(RKISP1_CIF_ISP_EXP_BASE + 0x00000054)
+#define RKISP1_CIF_ISP_EXP_MEAN_23		(RKISP1_CIF_ISP_EXP_BASE + 0x00000058)
+#define RKISP1_CIF_ISP_EXP_MEAN_33		(RKISP1_CIF_ISP_EXP_BASE + 0x0000005c)
+#define RKISP1_CIF_ISP_EXP_MEAN_43		(RKISP1_CIF_ISP_EXP_BASE + 0x00000060)
+#define RKISP1_CIF_ISP_EXP_MEAN_04		(RKISP1_CIF_ISP_EXP_BASE + 0x00000064)
+#define RKISP1_CIF_ISP_EXP_MEAN_14		(RKISP1_CIF_ISP_EXP_BASE + 0x00000068)
+#define RKISP1_CIF_ISP_EXP_MEAN_24		(RKISP1_CIF_ISP_EXP_BASE + 0x0000006c)
+#define RKISP1_CIF_ISP_EXP_MEAN_34		(RKISP1_CIF_ISP_EXP_BASE + 0x00000070)
+#define RKISP1_CIF_ISP_EXP_MEAN_44		(RKISP1_CIF_ISP_EXP_BASE + 0x00000074)
+
+#define RKISP1_CIF_ISP_BLS_BASE			0x00002700
+#define RKISP1_CIF_ISP_BLS_CTRL			(RKISP1_CIF_ISP_BLS_BASE + 0x00000000)
+#define RKISP1_CIF_ISP_BLS_SAMPLES		(RKISP1_CIF_ISP_BLS_BASE + 0x00000004)
+#define RKISP1_CIF_ISP_BLS_H1_START		(RKISP1_CIF_ISP_BLS_BASE + 0x00000008)
+#define RKISP1_CIF_ISP_BLS_H1_STOP		(RKISP1_CIF_ISP_BLS_BASE + 0x0000000c)
+#define RKISP1_CIF_ISP_BLS_V1_START		(RKISP1_CIF_ISP_BLS_BASE + 0x00000010)
+#define RKISP1_CIF_ISP_BLS_V1_STOP		(RKISP1_CIF_ISP_BLS_BASE + 0x00000014)
+#define RKISP1_CIF_ISP_BLS_H2_START		(RKISP1_CIF_ISP_BLS_BASE + 0x00000018)
+#define RKISP1_CIF_ISP_BLS_H2_STOP		(RKISP1_CIF_ISP_BLS_BASE + 0x0000001c)
+#define RKISP1_CIF_ISP_BLS_V2_START		(RKISP1_CIF_ISP_BLS_BASE + 0x00000020)
+#define RKISP1_CIF_ISP_BLS_V2_STOP		(RKISP1_CIF_ISP_BLS_BASE + 0x00000024)
+#define RKISP1_CIF_ISP_BLS_A_FIXED		(RKISP1_CIF_ISP_BLS_BASE + 0x00000028)
+#define RKISP1_CIF_ISP_BLS_B_FIXED		(RKISP1_CIF_ISP_BLS_BASE + 0x0000002c)
+#define RKISP1_CIF_ISP_BLS_C_FIXED		(RKISP1_CIF_ISP_BLS_BASE + 0x00000030)
+#define RKISP1_CIF_ISP_BLS_D_FIXED		(RKISP1_CIF_ISP_BLS_BASE + 0x00000034)
+#define RKISP1_CIF_ISP_BLS_A_MEASURED		(RKISP1_CIF_ISP_BLS_BASE + 0x00000038)
+#define RKISP1_CIF_ISP_BLS_B_MEASURED		(RKISP1_CIF_ISP_BLS_BASE + 0x0000003c)
+#define RKISP1_CIF_ISP_BLS_C_MEASURED		(RKISP1_CIF_ISP_BLS_BASE + 0x00000040)
+#define RKISP1_CIF_ISP_BLS_D_MEASURED		(RKISP1_CIF_ISP_BLS_BASE + 0x00000044)
+
+#define RKISP1_CIF_ISP_DPF_BASE			0x00002800
+#define RKISP1_CIF_ISP_DPF_MODE			(RKISP1_CIF_ISP_DPF_BASE + 0x00000000)
+#define RKISP1_CIF_ISP_DPF_STRENGTH_R		(RKISP1_CIF_ISP_DPF_BASE + 0x00000004)
+#define RKISP1_CIF_ISP_DPF_STRENGTH_G		(RKISP1_CIF_ISP_DPF_BASE + 0x00000008)
+#define RKISP1_CIF_ISP_DPF_STRENGTH_B		(RKISP1_CIF_ISP_DPF_BASE + 0x0000000C)
+#define RKISP1_CIF_ISP_DPF_S_WEIGHT_G_1_4	(RKISP1_CIF_ISP_DPF_BASE + 0x00000010)
+#define RKISP1_CIF_ISP_DPF_S_WEIGHT_G_5_6	(RKISP1_CIF_ISP_DPF_BASE + 0x00000014)
+#define RKISP1_CIF_ISP_DPF_S_WEIGHT_RB_1_4	(RKISP1_CIF_ISP_DPF_BASE + 0x00000018)
+#define RKISP1_CIF_ISP_DPF_S_WEIGHT_RB_5_6	(RKISP1_CIF_ISP_DPF_BASE + 0x0000001C)
+#define RKISP1_CIF_ISP_DPF_NULL_COEFF_0		(RKISP1_CIF_ISP_DPF_BASE + 0x00000020)
+#define RKISP1_CIF_ISP_DPF_NULL_COEFF_1		(RKISP1_CIF_ISP_DPF_BASE + 0x00000024)
+#define RKISP1_CIF_ISP_DPF_NULL_COEFF_2		(RKISP1_CIF_ISP_DPF_BASE + 0x00000028)
+#define RKISP1_CIF_ISP_DPF_NULL_COEFF_3		(RKISP1_CIF_ISP_DPF_BASE + 0x0000002C)
+#define RKISP1_CIF_ISP_DPF_NULL_COEFF_4		(RKISP1_CIF_ISP_DPF_BASE + 0x00000030)
+#define RKISP1_CIF_ISP_DPF_NULL_COEFF_5		(RKISP1_CIF_ISP_DPF_BASE + 0x00000034)
+#define RKISP1_CIF_ISP_DPF_NULL_COEFF_6		(RKISP1_CIF_ISP_DPF_BASE + 0x00000038)
+#define RKISP1_CIF_ISP_DPF_NULL_COEFF_7		(RKISP1_CIF_ISP_DPF_BASE + 0x0000003C)
+#define RKISP1_CIF_ISP_DPF_NULL_COEFF_8		(RKISP1_CIF_ISP_DPF_BASE + 0x00000040)
+#define RKISP1_CIF_ISP_DPF_NULL_COEFF_9		(RKISP1_CIF_ISP_DPF_BASE + 0x00000044)
+#define RKISP1_CIF_ISP_DPF_NULL_COEFF_10	(RKISP1_CIF_ISP_DPF_BASE + 0x00000048)
+#define RKISP1_CIF_ISP_DPF_NULL_COEFF_11	(RKISP1_CIF_ISP_DPF_BASE + 0x0000004C)
+#define RKISP1_CIF_ISP_DPF_NULL_COEFF_12	(RKISP1_CIF_ISP_DPF_BASE + 0x00000050)
+#define RKISP1_CIF_ISP_DPF_NULL_COEFF_13	(RKISP1_CIF_ISP_DPF_BASE + 0x00000054)
+#define RKISP1_CIF_ISP_DPF_NULL_COEFF_14	(RKISP1_CIF_ISP_DPF_BASE + 0x00000058)
+#define RKISP1_CIF_ISP_DPF_NULL_COEFF_15	(RKISP1_CIF_ISP_DPF_BASE + 0x0000005C)
+#define RKISP1_CIF_ISP_DPF_NULL_COEFF_16	(RKISP1_CIF_ISP_DPF_BASE + 0x00000060)
+#define RKISP1_CIF_ISP_DPF_NF_GAIN_R		(RKISP1_CIF_ISP_DPF_BASE + 0x00000064)
+#define RKISP1_CIF_ISP_DPF_NF_GAIN_GR		(RKISP1_CIF_ISP_DPF_BASE + 0x00000068)
+#define RKISP1_CIF_ISP_DPF_NF_GAIN_GB		(RKISP1_CIF_ISP_DPF_BASE + 0x0000006C)
+#define RKISP1_CIF_ISP_DPF_NF_GAIN_B		(RKISP1_CIF_ISP_DPF_BASE + 0x00000070)
+
+#define RKISP1_CIF_ISP_DPCC_BASE		0x00002900
+#define RKISP1_CIF_ISP_DPCC_MODE		(RKISP1_CIF_ISP_DPCC_BASE + 0x00000000)
+#define RKISP1_CIF_ISP_DPCC_OUTPUT_MODE		(RKISP1_CIF_ISP_DPCC_BASE + 0x00000004)
+#define RKISP1_CIF_ISP_DPCC_SET_USE		(RKISP1_CIF_ISP_DPCC_BASE + 0x00000008)
+#define RKISP1_CIF_ISP_DPCC_METHODS_SET_1	(RKISP1_CIF_ISP_DPCC_BASE + 0x0000000C)
+#define RKISP1_CIF_ISP_DPCC_METHODS_SET_2	(RKISP1_CIF_ISP_DPCC_BASE + 0x00000010)
+#define RKISP1_CIF_ISP_DPCC_METHODS_SET_3	(RKISP1_CIF_ISP_DPCC_BASE + 0x00000014)
+#define RKISP1_CIF_ISP_DPCC_LINE_THRESH_1	(RKISP1_CIF_ISP_DPCC_BASE + 0x00000018)
+#define RKISP1_CIF_ISP_DPCC_LINE_MAD_FAC_1	(RKISP1_CIF_ISP_DPCC_BASE + 0x0000001C)
+#define RKISP1_CIF_ISP_DPCC_PG_FAC_1		(RKISP1_CIF_ISP_DPCC_BASE + 0x00000020)
+#define RKISP1_CIF_ISP_DPCC_RND_THRESH_1	(RKISP1_CIF_ISP_DPCC_BASE + 0x00000024)
+#define RKISP1_CIF_ISP_DPCC_RG_FAC_1		(RKISP1_CIF_ISP_DPCC_BASE + 0x00000028)
+#define RKISP1_CIF_ISP_DPCC_LINE_THRESH_2	(RKISP1_CIF_ISP_DPCC_BASE + 0x0000002C)
+#define RKISP1_CIF_ISP_DPCC_LINE_MAD_FAC_2	(RKISP1_CIF_ISP_DPCC_BASE + 0x00000030)
+#define RKISP1_CIF_ISP_DPCC_PG_FAC_2		(RKISP1_CIF_ISP_DPCC_BASE + 0x00000034)
+#define RKISP1_CIF_ISP_DPCC_RND_THRESH_2	(RKISP1_CIF_ISP_DPCC_BASE + 0x00000038)
+#define RKISP1_CIF_ISP_DPCC_RG_FAC_2		(RKISP1_CIF_ISP_DPCC_BASE + 0x0000003C)
+#define RKISP1_CIF_ISP_DPCC_LINE_THRESH_3	(RKISP1_CIF_ISP_DPCC_BASE + 0x00000040)
+#define RKISP1_CIF_ISP_DPCC_LINE_MAD_FAC_3	(RKISP1_CIF_ISP_DPCC_BASE + 0x00000044)
+#define RKISP1_CIF_ISP_DPCC_PG_FAC_3		(RKISP1_CIF_ISP_DPCC_BASE + 0x00000048)
+#define RKISP1_CIF_ISP_DPCC_RND_THRESH_3	(RKISP1_CIF_ISP_DPCC_BASE + 0x0000004C)
+#define RKISP1_CIF_ISP_DPCC_RG_FAC_3		(RKISP1_CIF_ISP_DPCC_BASE + 0x00000050)
+#define RKISP1_CIF_ISP_DPCC_RO_LIMITS		(RKISP1_CIF_ISP_DPCC_BASE + 0x00000054)
+#define RKISP1_CIF_ISP_DPCC_RND_OFFS		(RKISP1_CIF_ISP_DPCC_BASE + 0x00000058)
+#define RKISP1_CIF_ISP_DPCC_BPT_CTRL		(RKISP1_CIF_ISP_DPCC_BASE + 0x0000005C)
+#define RKISP1_CIF_ISP_DPCC_BPT_NUMBER		(RKISP1_CIF_ISP_DPCC_BASE + 0x00000060)
+#define RKISP1_CIF_ISP_DPCC_BPT_ADDR		(RKISP1_CIF_ISP_DPCC_BASE + 0x00000064)
+#define RKISP1_CIF_ISP_DPCC_BPT_DATA		(RKISP1_CIF_ISP_DPCC_BASE + 0x00000068)
+
+#define RKISP1_CIF_ISP_WDR_BASE			0x00002A00
+#define RKISP1_CIF_ISP_WDR_CTRL			(RKISP1_CIF_ISP_WDR_BASE + 0x00000000)
+#define RKISP1_CIF_ISP_WDR_TONECURVE_1		(RKISP1_CIF_ISP_WDR_BASE + 0x00000004)
+#define RKISP1_CIF_ISP_WDR_TONECURVE_2		(RKISP1_CIF_ISP_WDR_BASE + 0x00000008)
+#define RKISP1_CIF_ISP_WDR_TONECURVE_3		(RKISP1_CIF_ISP_WDR_BASE + 0x0000000C)
+#define RKISP1_CIF_ISP_WDR_TONECURVE_4		(RKISP1_CIF_ISP_WDR_BASE + 0x00000010)
+#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_0	(RKISP1_CIF_ISP_WDR_BASE + 0x00000014)
+#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_1	(RKISP1_CIF_ISP_WDR_BASE + 0x00000018)
+#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_2	(RKISP1_CIF_ISP_WDR_BASE + 0x0000001C)
+#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_3	(RKISP1_CIF_ISP_WDR_BASE + 0x00000020)
+#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_4	(RKISP1_CIF_ISP_WDR_BASE + 0x00000024)
+#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_5	(RKISP1_CIF_ISP_WDR_BASE + 0x00000028)
+#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_6	(RKISP1_CIF_ISP_WDR_BASE + 0x0000002C)
+#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_7	(RKISP1_CIF_ISP_WDR_BASE + 0x00000030)
+#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_8	(RKISP1_CIF_ISP_WDR_BASE + 0x00000034)
+#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_9	(RKISP1_CIF_ISP_WDR_BASE + 0x00000038)
+#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_10	(RKISP1_CIF_ISP_WDR_BASE + 0x0000003C)
+#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_11	(RKISP1_CIF_ISP_WDR_BASE + 0x00000040)
+#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_12	(RKISP1_CIF_ISP_WDR_BASE + 0x00000044)
+#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_13	(RKISP1_CIF_ISP_WDR_BASE + 0x00000048)
+#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_14	(RKISP1_CIF_ISP_WDR_BASE + 0x0000004C)
+#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_15	(RKISP1_CIF_ISP_WDR_BASE + 0x00000050)
+#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_16	(RKISP1_CIF_ISP_WDR_BASE + 0x00000054)
+#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_17	(RKISP1_CIF_ISP_WDR_BASE + 0x00000058)
+#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_18	(RKISP1_CIF_ISP_WDR_BASE + 0x0000005C)
+#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_19	(RKISP1_CIF_ISP_WDR_BASE + 0x00000060)
+#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_20	(RKISP1_CIF_ISP_WDR_BASE + 0x00000064)
+#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_21	(RKISP1_CIF_ISP_WDR_BASE + 0x00000068)
+#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_22	(RKISP1_CIF_ISP_WDR_BASE + 0x0000006C)
+#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_23	(RKISP1_CIF_ISP_WDR_BASE + 0x00000070)
+#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_24	(RKISP1_CIF_ISP_WDR_BASE + 0x00000074)
+#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_25	(RKISP1_CIF_ISP_WDR_BASE + 0x00000078)
+#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_26	(RKISP1_CIF_ISP_WDR_BASE + 0x0000007C)
+#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_27	(RKISP1_CIF_ISP_WDR_BASE + 0x00000080)
+#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_28	(RKISP1_CIF_ISP_WDR_BASE + 0x00000084)
+#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_29	(RKISP1_CIF_ISP_WDR_BASE + 0x00000088)
+#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_30	(RKISP1_CIF_ISP_WDR_BASE + 0x0000008C)
+#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_31	(RKISP1_CIF_ISP_WDR_BASE + 0x00000090)
+#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_32	(RKISP1_CIF_ISP_WDR_BASE + 0x00000094)
+#define RKISP1_CIF_ISP_WDR_OFFSET		(RKISP1_CIF_ISP_WDR_BASE + 0x00000098)
+#define RKISP1_CIF_ISP_WDR_DELTAMIN		(RKISP1_CIF_ISP_WDR_BASE + 0x0000009C)
+#define RKISP1_CIF_ISP_WDR_TONECURVE_1_SHD	(RKISP1_CIF_ISP_WDR_BASE + 0x000000A0)
+#define RKISP1_CIF_ISP_WDR_TONECURVE_2_SHD	(RKISP1_CIF_ISP_WDR_BASE + 0x000000A4)
+#define RKISP1_CIF_ISP_WDR_TONECURVE_3_SHD	(RKISP1_CIF_ISP_WDR_BASE + 0x000000A8)
+#define RKISP1_CIF_ISP_WDR_TONECURVE_4_SHD	(RKISP1_CIF_ISP_WDR_BASE + 0x000000AC)
+#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_0_SHD	(RKISP1_CIF_ISP_WDR_BASE + 0x000000B0)
+#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_1_SHD	(RKISP1_CIF_ISP_WDR_BASE + 0x000000B4)
+#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_2_SHD	(RKISP1_CIF_ISP_WDR_BASE + 0x000000B8)
+#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_3_SHD	(RKISP1_CIF_ISP_WDR_BASE + 0x000000BC)
+#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_4_SHD	(RKISP1_CIF_ISP_WDR_BASE + 0x000000C0)
+#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_5_SHD	(RKISP1_CIF_ISP_WDR_BASE + 0x000000C4)
+#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_6_SHD	(RKISP1_CIF_ISP_WDR_BASE + 0x000000C8)
+#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_7_SHD	(RKISP1_CIF_ISP_WDR_BASE + 0x000000CC)
+#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_8_SHD	(RKISP1_CIF_ISP_WDR_BASE + 0x000000D0)
+#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_9_SHD	(RKISP1_CIF_ISP_WDR_BASE + 0x000000D4)
+#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_10_SHD	(RKISP1_CIF_ISP_WDR_BASE + 0x000000D8)
+#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_11_SHD	(RKISP1_CIF_ISP_WDR_BASE + 0x000000DC)
+#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_12_SHD	(RKISP1_CIF_ISP_WDR_BASE + 0x000000E0)
+#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_13_SHD	(RKISP1_CIF_ISP_WDR_BASE + 0x000000E4)
+#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_14_SHD	(RKISP1_CIF_ISP_WDR_BASE + 0x000000E8)
+#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_15_SHD	(RKISP1_CIF_ISP_WDR_BASE + 0x000000EC)
+#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_16_SHD	(RKISP1_CIF_ISP_WDR_BASE + 0x000000F0)
+#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_17_SHD	(RKISP1_CIF_ISP_WDR_BASE + 0x000000F4)
+#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_18_SHD	(RKISP1_CIF_ISP_WDR_BASE + 0x000000F8)
+#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_19_SHD	(RKISP1_CIF_ISP_WDR_BASE + 0x000000FC)
+#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_20_SHD	(RKISP1_CIF_ISP_WDR_BASE + 0x00000100)
+#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_21_SHD	(RKISP1_CIF_ISP_WDR_BASE + 0x00000104)
+#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_22_SHD	(RKISP1_CIF_ISP_WDR_BASE + 0x00000108)
+#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_23_SHD	(RKISP1_CIF_ISP_WDR_BASE + 0x0000010C)
+#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_24_SHD	(RKISP1_CIF_ISP_WDR_BASE + 0x00000110)
+#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_25_SHD	(RKISP1_CIF_ISP_WDR_BASE + 0x00000114)
+#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_26_SHD	(RKISP1_CIF_ISP_WDR_BASE + 0x00000118)
+#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_27_SHD	(RKISP1_CIF_ISP_WDR_BASE + 0x0000011C)
+#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_28_SHD	(RKISP1_CIF_ISP_WDR_BASE + 0x00000120)
+#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_29_SHD	(RKISP1_CIF_ISP_WDR_BASE + 0x00000124)
+#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_30_SHD	(RKISP1_CIF_ISP_WDR_BASE + 0x00000128)
+#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_31_SHD	(RKISP1_CIF_ISP_WDR_BASE + 0x0000012C)
+#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_32_SHD	(RKISP1_CIF_ISP_WDR_BASE + 0x00000130)
+
+#define RKISP1_CIF_ISP_VSM_BASE			0x00002F00
+#define RKISP1_CIF_ISP_VSM_MODE			(RKISP1_CIF_ISP_VSM_BASE + 0x00000000)
+#define RKISP1_CIF_ISP_VSM_H_OFFS		(RKISP1_CIF_ISP_VSM_BASE + 0x00000004)
+#define RKISP1_CIF_ISP_VSM_V_OFFS		(RKISP1_CIF_ISP_VSM_BASE + 0x00000008)
+#define RKISP1_CIF_ISP_VSM_H_SIZE		(RKISP1_CIF_ISP_VSM_BASE + 0x0000000C)
+#define RKISP1_CIF_ISP_VSM_V_SIZE		(RKISP1_CIF_ISP_VSM_BASE + 0x00000010)
+#define RKISP1_CIF_ISP_VSM_H_SEGMENTS		(RKISP1_CIF_ISP_VSM_BASE + 0x00000014)
+#define RKISP1_CIF_ISP_VSM_V_SEGMENTS		(RKISP1_CIF_ISP_VSM_BASE + 0x00000018)
+#define RKISP1_CIF_ISP_VSM_DELTA_H		(RKISP1_CIF_ISP_VSM_BASE + 0x0000001C)
+#define RKISP1_CIF_ISP_VSM_DELTA_V		(RKISP1_CIF_ISP_VSM_BASE + 0x00000020)
+
+#endif /* _RKISP1_REGS_H */
-- 
2.24.0


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

* [PATCH v12 03/11] media: staging: rkisp1: add streaming paths
  2019-12-27 20:01 ` Helen Koike
@ 2019-12-27 20:01   ` Helen Koike
  -1 siblings, 0 replies; 74+ messages in thread
From: Helen Koike @ 2019-12-27 20:01 UTC (permalink / raw)
  To: linux-rockchip
  Cc: mark.rutland, devicetree, eddie.cai.linux, mchehab, heiko,
	gregkh, andrey.konovalov, linux-kernel, tfiga, robh+dt,
	hans.verkuil, laurent.pinchart, sakari.ailus, joacim.zetterling,
	kernel, ezequiel, linux-media, jacob-chen, linux-arm-kernel,
	Helen Koike, Jacob Chen, Shunqian Zheng, Yichong Zhong,
	Jacob Chen, Jeffy Chen, Allon Huang

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


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

* [PATCH v12 03/11] media: staging: rkisp1: add streaming paths
@ 2019-12-27 20:01   ` Helen Koike
  0 siblings, 0 replies; 74+ 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] 74+ messages in thread

* [PATCH v12 04/11] media: staging: rkisp1: add user space ABI definitions
  2019-12-27 20:01 ` Helen Koike
@ 2019-12-27 20:01   ` Helen Koike
  -1 siblings, 0 replies; 74+ messages in thread
From: Helen Koike @ 2019-12-27 20:01 UTC (permalink / raw)
  To: linux-rockchip
  Cc: mark.rutland, devicetree, eddie.cai.linux, mchehab, heiko,
	gregkh, andrey.konovalov, linux-kernel, tfiga, robh+dt,
	hans.verkuil, laurent.pinchart, sakari.ailus, joacim.zetterling,
	kernel, ezequiel, linux-media, jacob-chen, linux-arm-kernel,
	Jeffy Chen, Jacob Chen, Helen Koike

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


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

* [PATCH v12 04/11] media: staging: rkisp1: add user space ABI definitions
@ 2019-12-27 20:01   ` Helen Koike
  0 siblings, 0 replies; 74+ 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] 74+ messages in thread

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

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


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

* [PATCH v12 05/11] media: staging: rkisp1: add capture device for statistics
@ 2019-12-27 20:01   ` Helen Koike
  0 siblings, 0 replies; 74+ 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] 74+ messages in thread

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

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


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

* [PATCH v12 06/11] media: staging: rkisp1: add output device for parameters
@ 2019-12-27 20:01   ` Helen Koike
  0 siblings, 0 replies; 74+ 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] 74+ messages in thread

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

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


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

* [PATCH v12 07/11] media: staging: rkisp1: add document for rkisp1 meta buffer format
@ 2019-12-27 20:01   ` Helen Koike
  0 siblings, 0 replies; 74+ 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] 74+ messages in thread

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

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


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

* [PATCH v12 08/11] media: staging: dt-bindings: add Rockchip ISP1 yaml bindings
@ 2019-12-27 20:01   ` Helen Koike
  0 siblings, 0 replies; 74+ 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] 74+ messages in thread

* [PATCH v12 09/11] media: staging: dt-bindings: add Rockchip MIPI RX D-PHY yaml bindings
  2019-12-27 20:01 ` Helen Koike
@ 2019-12-27 20:01   ` Helen Koike
  -1 siblings, 0 replies; 74+ messages in thread
From: Helen Koike @ 2019-12-27 20:01 UTC (permalink / raw)
  To: linux-rockchip
  Cc: mark.rutland, devicetree, eddie.cai.linux, mchehab, heiko,
	gregkh, andrey.konovalov, linux-kernel, tfiga, robh+dt,
	hans.verkuil, laurent.pinchart, sakari.ailus, joacim.zetterling,
	kernel, ezequiel, linux-media, jacob-chen, linux-arm-kernel,
	Helen Koike

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


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

* [PATCH v12 09/11] media: staging: dt-bindings: add Rockchip MIPI RX D-PHY yaml bindings
@ 2019-12-27 20:01   ` Helen Koike
  0 siblings, 0 replies; 74+ 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] 74+ messages in thread

* [PATCH v12 10/11] media: staging: rkisp1: add TODO file for staging
  2019-12-27 20:01 ` Helen Koike
@ 2019-12-27 20:01   ` Helen Koike
  -1 siblings, 0 replies; 74+ messages in thread
From: Helen Koike @ 2019-12-27 20:01 UTC (permalink / raw)
  To: linux-rockchip
  Cc: mark.rutland, devicetree, eddie.cai.linux, mchehab, heiko,
	gregkh, andrey.konovalov, linux-kernel, tfiga, robh+dt,
	hans.verkuil, laurent.pinchart, sakari.ailus, joacim.zetterling,
	kernel, ezequiel, linux-media, jacob-chen, linux-arm-kernel,
	Helen Koike

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


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

* [PATCH v12 10/11] media: staging: rkisp1: add TODO file for staging
@ 2019-12-27 20:01   ` Helen Koike
  0 siblings, 0 replies; 74+ 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] 74+ messages in thread

* [PATCH v12 11/11] MAINTAINERS: add entry for Rockchip ISP1 driver
  2019-12-27 20:01 ` Helen Koike
@ 2019-12-27 20:01   ` Helen Koike
  -1 siblings, 0 replies; 74+ messages in thread
From: Helen Koike @ 2019-12-27 20:01 UTC (permalink / raw)
  To: linux-rockchip
  Cc: mark.rutland, devicetree, eddie.cai.linux, mchehab, heiko,
	gregkh, andrey.konovalov, linux-kernel, tfiga, robh+dt,
	hans.verkuil, laurent.pinchart, sakari.ailus, joacim.zetterling,
	kernel, ezequiel, linux-media, jacob-chen, linux-arm-kernel,
	Helen Koike

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


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

* [PATCH v12 11/11] MAINTAINERS: add entry for Rockchip ISP1 driver
@ 2019-12-27 20:01   ` Helen Koike
  0 siblings, 0 replies; 74+ 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] 74+ messages in thread

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

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



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

* Re: [PATCH v12 02/11] media: staging: rkisp1: add Rockchip ISP1 base driver
@ 2019-12-30 18:13     ` Ezequiel Garcia
  0 siblings, 0 replies; 74+ 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] 74+ messages in thread

* Re: [PATCH v12 01/11] media: staging: phy-rockchip-dphy: add Rockchip MIPI Synopsys DPHY driver
  2019-12-27 20:01   ` Helen Koike
@ 2019-12-30 18:25     ` Ezequiel Garcia
  -1 siblings, 0 replies; 74+ 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, mchehab, heiko,
	gregkh, andrey.konovalov, linux-kernel, tfiga, robh+dt,
	hans.verkuil, laurent.pinchart, sakari.ailus, joacim.zetterling,
	kernel, linux-media, jacob-chen, linux-arm-kernel

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


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

* Re: [PATCH v12 01/11] media: staging: phy-rockchip-dphy: add Rockchip MIPI Synopsys DPHY driver
@ 2019-12-30 18:25     ` Ezequiel Garcia
  0 siblings, 0 replies; 74+ 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] 74+ messages in thread

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

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>

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

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

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>

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

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

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>

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

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

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>

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

* Re: [PATCH v12 09/11] media: staging: dt-bindings: add Rockchip MIPI RX D-PHY yaml bindings
@ 2020-01-06 22:29     ` Rob Herring
  0 siblings, 0 replies; 74+ 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] 74+ messages in thread

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

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

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

* Re: [PATCH v12 08/11] media: staging: dt-bindings: add Rockchip ISP1 yaml bindings
@ 2020-01-06 23:59     ` Laurent Pinchart
  0 siblings, 0 replies; 74+ 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] 74+ 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   ` Helen Koike
@ 2020-01-07  0:10     ` Laurent Pinchart
  -1 siblings, 0 replies; 74+ messages in thread
From: Laurent Pinchart @ 2020-01-07  0:10 UTC (permalink / raw)
  To: Helen Koike
  Cc: linux-rockchip, mark.rutland, devicetree, eddie.cai.linux,
	mchehab, heiko, gregkh, andrey.konovalov, linux-kernel, tfiga,
	robh+dt, hans.verkuil, sakari.ailus, joacim.zetterling, kernel,
	ezequiel, linux-media, jacob-chen, linux-arm-kernel

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

^ permalink raw reply	[flat|nested] 74+ 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
  0 siblings, 0 replies; 74+ 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] 74+ messages in thread

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

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

^ permalink raw reply	[flat|nested] 74+ 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
  0 siblings, 0 replies; 74+ 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] 74+ 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
  -1 siblings, 0 replies; 74+ messages in thread
From: Ezequiel Garcia @ 2020-01-07  2:06 UTC (permalink / raw)
  To: Laurent Pinchart, Helen Koike
  Cc: linux-rockchip, mark.rutland, devicetree, eddie.cai.linux,
	mchehab, heiko, gregkh, andrey.konovalov, linux-kernel, tfiga,
	robh+dt, hans.verkuil, sakari.ailus, joacim.zetterling, kernel,
	linux-media, jacob-chen, linux-arm-kernel

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



^ permalink raw reply	[flat|nested] 74+ 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
  0 siblings, 0 replies; 74+ 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] 74+ 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
  -1 siblings, 0 replies; 74+ messages in thread
From: Laurent Pinchart @ 2020-01-07  2:37 UTC (permalink / raw)
  To: Ezequiel Garcia
  Cc: Helen Koike, linux-rockchip, mark.rutland, devicetree,
	eddie.cai.linux, mchehab, heiko, gregkh, andrey.konovalov,
	linux-kernel, tfiga, robh+dt, hans.verkuil, sakari.ailus,
	joacim.zetterling, kernel, linux-media, jacob-chen,
	linux-arm-kernel

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

^ permalink raw reply	[flat|nested] 74+ 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
  0 siblings, 0 replies; 74+ 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] 74+ 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
  -1 siblings, 0 replies; 74+ messages in thread
From: Heiko Stübner @ 2020-01-07  9:28 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Ezequiel Garcia, Helen Koike, linux-rockchip, mark.rutland,
	devicetree, eddie.cai.linux, mchehab, gregkh, andrey.konovalov,
	linux-kernel, tfiga, robh+dt, hans.verkuil, sakari.ailus,
	joacim.zetterling, kernel, linux-media, jacob-chen,
	linux-arm-kernel

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



^ permalink raw reply	[flat|nested] 74+ 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
  0 siblings, 0 replies; 74+ 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] 74+ 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
  -1 siblings, 0 replies; 74+ messages in thread
From: Ezequiel Garcia @ 2020-01-07 13:20 UTC (permalink / raw)
  To: Heiko Stübner, Laurent Pinchart
  Cc: Helen Koike, linux-rockchip, mark.rutland, devicetree,
	eddie.cai.linux, mchehab, gregkh, andrey.konovalov, linux-kernel,
	tfiga, robh+dt, hans.verkuil, sakari.ailus, joacim.zetterling,
	kernel, linux-media, jacob-chen, linux-arm-kernel

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




^ permalink raw reply	[flat|nested] 74+ 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
  0 siblings, 0 replies; 74+ 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] 74+ 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
  -1 siblings, 0 replies; 74+ messages in thread
From: Ezequiel Garcia @ 2020-01-07 13:45 UTC (permalink / raw)
  To: Laurent Pinchart, Helen Koike
  Cc: linux-rockchip, mark.rutland, devicetree, eddie.cai.linux,
	mchehab, heiko, gregkh, andrey.konovalov, linux-kernel, tfiga,
	robh+dt, hans.verkuil, sakari.ailus, joacim.zetterling, kernel,
	linux-media, jacob-chen, linux-arm-kernel

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


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

* Re: [PATCH v12 08/11] media: staging: dt-bindings: add Rockchip ISP1 yaml bindings
@ 2020-01-07 13:45       ` Ezequiel Garcia
  0 siblings, 0 replies; 74+ 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] 74+ messages in thread

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

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

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

* Re: [PATCH v12 08/11] media: staging: dt-bindings: add Rockchip ISP1 yaml bindings
@ 2020-01-07 14:01     ` Sakari Ailus
  0 siblings, 0 replies; 74+ 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] 74+ 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
  -1 siblings, 0 replies; 74+ messages in thread
From: Ezequiel Garcia @ 2020-01-07 15:58 UTC (permalink / raw)
  To: Laurent Pinchart, Helen Koike
  Cc: linux-rockchip, mark.rutland, devicetree, eddie.cai.linux,
	mchehab, heiko, gregkh, andrey.konovalov, linux-kernel, tfiga,
	robh+dt, hans.verkuil, sakari.ailus, joacim.zetterling, kernel,
	linux-media, jacob-chen, linux-arm-kernel

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


^ permalink raw reply	[flat|nested] 74+ 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
  0 siblings, 0 replies; 74+ 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] 74+ 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
  -1 siblings, 0 replies; 74+ messages in thread
From: Laurent Pinchart @ 2020-01-07 16:18 UTC (permalink / raw)
  To: Ezequiel Garcia
  Cc: Helen Koike, linux-rockchip, mark.rutland, devicetree,
	eddie.cai.linux, mchehab, heiko, gregkh, andrey.konovalov,
	linux-kernel, tfiga, robh+dt, hans.verkuil, sakari.ailus,
	joacim.zetterling, kernel, linux-media, jacob-chen,
	linux-arm-kernel

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

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

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

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

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

* Re: [PATCH v12 08/11] media: staging: dt-bindings: add Rockchip ISP1 yaml bindings
@ 2020-01-07 16:19         ` Laurent Pinchart
  0 siblings, 0 replies; 74+ 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] 74+ 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
  -1 siblings, 0 replies; 74+ messages in thread
From: Heiko Stübner @ 2020-01-07 21:30 UTC (permalink / raw)
  To: Ezequiel Garcia
  Cc: Laurent Pinchart, Helen Koike, linux-rockchip, mark.rutland,
	devicetree, eddie.cai.linux, mchehab, gregkh, andrey.konovalov,
	linux-kernel, tfiga, robh+dt, hans.verkuil, sakari.ailus,
	joacim.zetterling, kernel, linux-media, jacob-chen,
	linux-arm-kernel

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




^ permalink raw reply	[flat|nested] 74+ 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
  0 siblings, 0 replies; 74+ 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] 74+ 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
  -1 siblings, 0 replies; 74+ messages in thread
From: Laurent Pinchart @ 2020-01-07 21:57 UTC (permalink / raw)
  To: Heiko Stübner
  Cc: Ezequiel Garcia, Helen Koike, linux-rockchip, mark.rutland,
	devicetree, eddie.cai.linux, mchehab, gregkh, andrey.konovalov,
	linux-kernel, tfiga, robh+dt, hans.verkuil, sakari.ailus,
	joacim.zetterling, kernel, linux-media, jacob-chen,
	linux-arm-kernel

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

^ permalink raw reply	[flat|nested] 74+ 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
  0 siblings, 0 replies; 74+ 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] 74+ 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 22:03                 ` Ezequiel Garcia
  -1 siblings, 0 replies; 74+ messages in thread
From: Ezequiel Garcia @ 2020-01-07 22:03 UTC (permalink / raw)
  To: Heiko Stübner
  Cc: Laurent Pinchart, Helen Koike, linux-rockchip, mark.rutland,
	devicetree, eddie.cai.linux, mchehab, gregkh, andrey.konovalov,
	linux-kernel, tfiga, robh+dt, hans.verkuil, sakari.ailus,
	joacim.zetterling, kernel, linux-media, jacob-chen,
	linux-arm-kernel

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



^ permalink raw reply	[flat|nested] 74+ 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
  0 siblings, 0 replies; 74+ 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] 74+ 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
  -1 siblings, 0 replies; 74+ messages in thread
From: Heiko Stuebner @ 2020-01-07 22:12 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Ezequiel Garcia, Helen Koike, linux-rockchip, mark.rutland,
	devicetree, eddie.cai.linux, mchehab, gregkh, andrey.konovalov,
	linux-kernel, tfiga, robh+dt, hans.verkuil, sakari.ailus,
	joacim.zetterling, kernel, linux-media, jacob-chen,
	linux-arm-kernel

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





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

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

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



^ permalink raw reply	[flat|nested] 74+ 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
  0 siblings, 0 replies; 74+ 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] 74+ 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
  -1 siblings, 0 replies; 74+ messages in thread
From: Ezequiel Garcia @ 2020-01-07 22:41 UTC (permalink / raw)
  To: Heiko Stuebner
  Cc: Laurent Pinchart, Helen Koike, linux-rockchip, mark.rutland,
	devicetree, eddie.cai.linux, mchehab, gregkh, andrey.konovalov,
	linux-kernel, tfiga, robh+dt, hans.verkuil, sakari.ailus,
	joacim.zetterling, kernel, linux-media, jacob-chen,
	linux-arm-kernel

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


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

* Re: [PATCH v12 09/11] media: staging: dt-bindings: add Rockchip MIPI RX D-PHY yaml bindings
@ 2020-01-07 22:41                     ` Ezequiel Garcia
  0 siblings, 0 replies; 74+ 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] 74+ 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
  -1 siblings, 0 replies; 74+ messages in thread
From: Helen Koike @ 2020-01-08 16:50 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: linux-rockchip, mark.rutland, devicetree, eddie.cai.linux,
	mchehab, heiko, gregkh, andrey.konovalov, linux-kernel, tfiga,
	robh+dt, hans.verkuil, laurent.pinchart, joacim.zetterling,
	kernel, ezequiel, linux-media, jacob-chen, linux-arm-kernel

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

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

* Re: [PATCH v12 08/11] media: staging: dt-bindings: add Rockchip ISP1 yaml bindings
@ 2020-01-08 16:50       ` Helen Koike
  0 siblings, 0 replies; 74+ 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] 74+ messages in thread

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

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

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

* Re: [PATCH v12 08/11] media: staging: dt-bindings: add Rockchip ISP1 yaml bindings
@ 2020-01-08 18:08         ` Sakari Ailus
  0 siblings, 0 replies; 74+ messages in thread
From: Sakari Ailus @ 2020-01-08 18:08 UTC (permalink / raw)
  To: Helen Koike
  Cc: mark.rutland-5wv7dgnIgG8, devicetree-u79uwXL29TY76Z2rM5mHXA,
	eddie.cai.linux-Re5JQEeQqe8AvxtiuMwx3w,
	kernel-ZGY8ohtN/8qB+jHODAdFcQ, heiko-4mtYJXux2i+zQB+pC5nmwQ,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	ezequiel-ZGY8ohtN/8qB+jHODAdFcQ,
	gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	tfiga-F7+t8E8rja9g9hUCZPvPmw,
	linux-rockchip-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
	hans.verkuil-FYB4Gu1CFyUAvxtiuMwx3w,
	laurent.pinchart-ryLnwIuWjnjg/C1BVhZhaw,
	joacim.zetterling-Re5JQEeQqe8AvxtiuMwx3w,
	mchehab-DgEjT+Ai2ygdnm+yROfE0A,
	andrey.konovalov-QSEj5FYQhm4dnm+yROfE0A,
	jacob-chen-fyOeoxGR3m/QT0dZR+AlfA,
	linux-media-u79uwXL29TY76Z2rM5mHXA

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-ZGY8ohtN/8qB+jHODAdFcQ@public.gmane.org>
> >>
> >> ---
> >>
> >> 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-ZGY8ohtN/8qB+jHODAdFcQ@public.gmane.org>
> >> +
> >> +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-VuQAYsv1563Yd54FQh9/CA@public.gmane.org

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

* Re: [PATCH v12 08/11] media: staging: dt-bindings: add Rockchip ISP1 yaml bindings
@ 2020-01-08 18:08         ` Sakari Ailus
  0 siblings, 0 replies; 74+ 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] 74+ messages in thread

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

Thread overview: 74+ 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 ` 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-30 18:25   ` Ezequiel Garcia
2019-12-30 18:25     ` Ezequiel Garcia
2020-01-07  1:11   ` Laurent Pinchart
2020-01-07  1:11     ` Laurent Pinchart
2020-01-07 15:58     ` Ezequiel Garcia
2020-01-07 15:58       ` Ezequiel Garcia
2020-01-07 16:18       ` Laurent Pinchart
2020-01-07 16:18         ` Laurent Pinchart
2019-12-27 20:01 ` [PATCH v12 02/11] media: staging: rkisp1: add Rockchip ISP1 base driver Helen Koike
2019-12-30 18:13   ` Ezequiel Garcia
2019-12-30 18:13     ` Ezequiel Garcia
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 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 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 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 07/11] media: staging: rkisp1: add document for rkisp1 meta buffer format 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
2019-12-27 20:01   ` Helen Koike
2020-01-06 22:27   ` Rob Herring
2020-01-06 22:27     ` Rob Herring
2020-01-06 22:27     ` Rob Herring
2020-01-06 23:59   ` Laurent Pinchart
2020-01-06 23:59     ` Laurent Pinchart
2020-01-07 13:45     ` Ezequiel Garcia
2020-01-07 13:45       ` Ezequiel Garcia
2020-01-07 16:19       ` Laurent Pinchart
2020-01-07 16:19         ` Laurent Pinchart
2020-01-07 14:01   ` Sakari Ailus
2020-01-07 14:01     ` Sakari Ailus
2020-01-08 16:50     ` Helen Koike
2020-01-08 16:50       ` Helen Koike
2020-01-08 18:08       ` Sakari Ailus
2020-01-08 18:08         ` Sakari Ailus
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
2019-12-27 20:01   ` Helen Koike
2020-01-06 22:29   ` Rob Herring
2020-01-06 22:29     ` Rob Herring
2020-01-06 22:29     ` Rob Herring
2020-01-07  0:10   ` Laurent Pinchart
2020-01-07  0:10     ` Laurent Pinchart
2020-01-07  2:06     ` Ezequiel Garcia
2020-01-07  2:06       ` Ezequiel Garcia
2020-01-07  2:37       ` Laurent Pinchart
2020-01-07  2:37         ` Laurent Pinchart
2020-01-07  9:28         ` Heiko Stübner
2020-01-07  9:28           ` Heiko Stübner
2020-01-07 13:20           ` Ezequiel Garcia
2020-01-07 13:20             ` Ezequiel Garcia
2020-01-07 21:30             ` Heiko Stübner
2020-01-07 21:30               ` Heiko Stübner
2020-01-07 21:57               ` Laurent Pinchart
2020-01-07 21:57                 ` Laurent Pinchart
2020-01-07 22:12                 ` Heiko Stuebner
2020-01-07 22:12                   ` Heiko Stuebner
2020-01-07 22:03               ` Ezequiel Garcia
2020-01-07 22:03                 ` Ezequiel Garcia
2020-01-07 22:25                 ` Heiko Stuebner
2020-01-07 22:25                   ` Heiko Stuebner
2020-01-07 22:41                   ` Ezequiel Garcia
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   ` Helen Koike
2019-12-27 20:01 ` [PATCH v12 11/11] MAINTAINERS: add entry for Rockchip ISP1 driver Helen Koike
2019-12-27 20:01   ` Helen Koike

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.