All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/8] v4.19.0 Added Color Management Module
@ 2019-04-03 13:14 ` VenkataRajesh.Kalakodima
  0 siblings, 0 replies; 36+ messages in thread
From: VenkataRajesh.Kalakodima @ 2019-04-03 13:14 UTC (permalink / raw)
  To: linux-renesas-soc, devicetree, linux-kernel, linux-clk, dri-devel
  Cc: kalakodima venkata rajesh

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="n", Size: 3755 bytes --]

From: kalakodima venkata rajesh <venkatarajesh.kalakodima@in.bosch.com>

This patchset adds rcar- display unit color management module (CMM) function feature, Which allows correction and adjustment of the display data, through updating Look up table (gamma) and  Cubic look up table (CTM)  property values 

Base color management module reference code taken from below link,
https://github.com/renesas-rcar/du_cmm .
-	In above code, modified variable naming’s and removed un used functionalities.
-	Introduce new functions for queueing cubic look up table and look up table events.

-	Implemented interfaces in color management module to set CLU /LUT table using standard DRM data structures as input.
	Look up table is a 1D-LUT that converts each of three-color components by using a lookup table. LUT is used for gamma correction.							
	Cubic look up table is a three-dimensional LUT (3D-LUT) that converts the input three-color-component data into desired three color Components by using a lookup table

-	Implemented atomic check helper functions for enable/disable LUT and CLU (Gamma and Color Transformation Matrix properties).
-	Allocated memory necessary for cubic look up table and look up table and added mode fix up callback function
-	Added update gamma and color transformation matrix properties in commit tail function, If any change in property values.

kalakodima venkata rajesh (8):
  drm: Add DU CMM support functions
  drm: Add DU CMM support boot and clk changes
  drm: rcar-du: Give a name to clu table samples
  drm: rcar-du: Refactor the code with new functions
  drm: rcar-du: Implement interfaces to set clu and lut using drm data
    structures
  drm: rcar-du: Implement atomic_check to check for gamma and ctm
    properties
  drm: rcar-du: update gamma and ctm properties in commit tail
  drm: rcar-du: Add shutdown callback function in platform_driver

 .../boot/dts/renesas/r8a7795-es1-salvator-x.dts    |    5 +
 arch/arm64/boot/dts/renesas/r8a7795-salvator-x.dts |    5 +
 .../arm64/boot/dts/renesas/r8a7795-salvator-xs.dts |    5 +
 arch/arm64/boot/dts/renesas/r8a7795.dtsi           |   29 +-
 arch/arm64/boot/dts/renesas/r8a7796-salvator-x.dts |    6 +-
 .../arm64/boot/dts/renesas/r8a7796-salvator-xs.dts |    4 +
 arch/arm64/boot/dts/renesas/r8a7796.dtsi           |   25 +-
 .../arm64/boot/dts/renesas/r8a77965-salvator-x.dts |    7 +-
 .../boot/dts/renesas/r8a77965-salvator-xs.dts      |    7 +-
 arch/arm64/boot/dts/renesas/r8a77965.dtsi          |   27 +-
 drivers/clk/renesas/r8a7795-cpg-mssr.c             |    4 +
 drivers/clk/renesas/r8a7796-cpg-mssr.c             |    3 +
 drivers/clk/renesas/r8a77965-cpg-mssr.c            |  106 +-
 drivers/gpu/drm/bridge/synopsys/dw-hdmi.c          |   35 +
 drivers/gpu/drm/rcar-du/Makefile                   |    2 +
 drivers/gpu/drm/rcar-du/rcar_du_cmm.c              | 1470 ++++++++++++++++++++
 drivers/gpu/drm/rcar-du/rcar_du_crtc.c             |   82 ++
 drivers/gpu/drm/rcar-du/rcar_du_crtc.h             |   28 +
 drivers/gpu/drm/rcar-du/rcar_du_drv.c              |   85 +-
 drivers/gpu/drm/rcar-du/rcar_du_drv.h              |   16 +-
 drivers/gpu/drm/rcar-du/rcar_du_encoder.c          |    2 +-
 drivers/gpu/drm/rcar-du/rcar_du_encoder.h          |    1 +
 drivers/gpu/drm/rcar-du/rcar_du_group.c            |    5 +
 drivers/gpu/drm/rcar-du/rcar_du_kms.c              |   25 +
 drivers/gpu/drm/rcar-du/rcar_du_regs.h             |   92 ++
 include/drm/bridge/dw_hdmi.h                       |    1 +
 include/drm/drm_atomic.h                           |   25 +
 include/drm/drm_ioctl.h                            |    7 +
 28 files changed, 2082 insertions(+), 27 deletions(-)
 create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_cmm.c

-- 
2.7.4


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

* [PATCH 0/8] v4.19.0 Added Color Management Module
@ 2019-04-03 13:14 ` VenkataRajesh.Kalakodima
  0 siblings, 0 replies; 36+ messages in thread
From: VenkataRajesh.Kalakodima @ 2019-04-03 13:14 UTC (permalink / raw)
  To: linux-renesas-soc, devicetree, linux-kernel, linux-clk, dri-devel
  Cc: kalakodima venkata rajesh

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="n", Size: 3754 bytes --]

From: kalakodima venkata rajesh <venkatarajesh.kalakodima@in.bosch.com>

This patchset adds rcar- display unit color management module (CMM) function feature, Which allows correction and adjustment of the display data, through updating Look up table (gamma) and  Cubic look up table (CTM)  property values 

Base color management module reference code taken from below link,
https://github.com/renesas-rcar/du_cmm .
-	In above code, modified variable naming’s and removed un used functionalities.
-	Introduce new functions for queueing cubic look up table and look up table events.

-	Implemented interfaces in color management module to set CLU /LUT table using standard DRM data structures as input.
	Look up table is a 1D-LUT that converts each of three-color components by using a lookup table. LUT is used for gamma correction.							
	Cubic look up table is a three-dimensional LUT (3D-LUT) that converts the input three-color-component data into desired three color Components by using a lookup table

-	Implemented atomic check helper functions for enable/disable LUT and CLU (Gamma and Color Transformation Matrix properties).
-	Allocated memory necessary for cubic look up table and look up table and added mode fix up callback function
-	Added update gamma and color transformation matrix properties in commit tail function, If any change in property values.

kalakodima venkata rajesh (8):
  drm: Add DU CMM support functions
  drm: Add DU CMM support boot and clk changes
  drm: rcar-du: Give a name to clu table samples
  drm: rcar-du: Refactor the code with new functions
  drm: rcar-du: Implement interfaces to set clu and lut using drm data
    structures
  drm: rcar-du: Implement atomic_check to check for gamma and ctm
    properties
  drm: rcar-du: update gamma and ctm properties in commit tail
  drm: rcar-du: Add shutdown callback function in platform_driver

 .../boot/dts/renesas/r8a7795-es1-salvator-x.dts    |    5 +
 arch/arm64/boot/dts/renesas/r8a7795-salvator-x.dts |    5 +
 .../arm64/boot/dts/renesas/r8a7795-salvator-xs.dts |    5 +
 arch/arm64/boot/dts/renesas/r8a7795.dtsi           |   29 +-
 arch/arm64/boot/dts/renesas/r8a7796-salvator-x.dts |    6 +-
 .../arm64/boot/dts/renesas/r8a7796-salvator-xs.dts |    4 +
 arch/arm64/boot/dts/renesas/r8a7796.dtsi           |   25 +-
 .../arm64/boot/dts/renesas/r8a77965-salvator-x.dts |    7 +-
 .../boot/dts/renesas/r8a77965-salvator-xs.dts      |    7 +-
 arch/arm64/boot/dts/renesas/r8a77965.dtsi          |   27 +-
 drivers/clk/renesas/r8a7795-cpg-mssr.c             |    4 +
 drivers/clk/renesas/r8a7796-cpg-mssr.c             |    3 +
 drivers/clk/renesas/r8a77965-cpg-mssr.c            |  106 +-
 drivers/gpu/drm/bridge/synopsys/dw-hdmi.c          |   35 +
 drivers/gpu/drm/rcar-du/Makefile                   |    2 +
 drivers/gpu/drm/rcar-du/rcar_du_cmm.c              | 1470 ++++++++++++++++++++
 drivers/gpu/drm/rcar-du/rcar_du_crtc.c             |   82 ++
 drivers/gpu/drm/rcar-du/rcar_du_crtc.h             |   28 +
 drivers/gpu/drm/rcar-du/rcar_du_drv.c              |   85 +-
 drivers/gpu/drm/rcar-du/rcar_du_drv.h              |   16 +-
 drivers/gpu/drm/rcar-du/rcar_du_encoder.c          |    2 +-
 drivers/gpu/drm/rcar-du/rcar_du_encoder.h          |    1 +
 drivers/gpu/drm/rcar-du/rcar_du_group.c            |    5 +
 drivers/gpu/drm/rcar-du/rcar_du_kms.c              |   25 +
 drivers/gpu/drm/rcar-du/rcar_du_regs.h             |   92 ++
 include/drm/bridge/dw_hdmi.h                       |    1 +
 include/drm/drm_atomic.h                           |   25 +
 include/drm/drm_ioctl.h                            |    7 +
 28 files changed, 2082 insertions(+), 27 deletions(-)
 create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_cmm.c

-- 
2.7.4

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

* [PATCH 1/8] drm: Add DU CMM support functions
  2019-04-03 13:14 ` VenkataRajesh.Kalakodima
@ 2019-04-03 13:14   ` VenkataRajesh.Kalakodima
  -1 siblings, 0 replies; 36+ messages in thread
From: VenkataRajesh.Kalakodima @ 2019-04-03 13:14 UTC (permalink / raw)
  To: linux-renesas-soc, devicetree, linux-kernel, linux-clk, dri-devel
  Cc: kalakodima venkata rajesh, Koji Matsuoka, Tsutomu Muroya,
	Steve Longerbeam

From: kalakodima venkata rajesh <venkatarajesh.kalakodima@in.bosch.com>

This is the out-of-tree patch for DU CMM driver support from
Yocto release v3.4.0.

Link: https://github.com/renesas-rcar/du_cmm/commit/2d8ea2b667ad4616aa639c54ecc11f7c4b58959d.patch

Following is from the patch description:

    du_cmm: Release for Yocto v3.4.0

    This patch made the following correspondence.

      - Corresponds to kernel v 4.14.
      - Double buffer only is supported.
      - Fix CLU / LUT update timing.
      - Add CMM Channel occupation mode.
      - Fix Close process.

Signed-off-by: Koji Matsuoka <koji.matsuoka.xm@renesas.com>
Signed-off-by: Tsutomu Muroya <muroya@ksk.co.jp>
Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>

      - Removal of rcar specific ioctals
      - Resolved checkpatch errors
      - Resolved merge conflicts according to latest version
      - Included CMM drivers and included files from base patch
      - Removed rcar_du_drm.h include file

Signed-off-by: kalakodima venkata rajesh <venkatarajesh.kalakodima@in.bosch.com>
---
 drivers/gpu/drm/rcar-du/Makefile        |    2 +
 drivers/gpu/drm/rcar-du/rcar_du_cmm.c   | 1200 +++++++++++++++++++++++++++++++
 drivers/gpu/drm/rcar-du/rcar_du_crtc.c  |   24 +
 drivers/gpu/drm/rcar-du/rcar_du_crtc.h  |   16 +
 drivers/gpu/drm/rcar-du/rcar_du_drv.c   |   43 +-
 drivers/gpu/drm/rcar-du/rcar_du_drv.h   |   16 +-
 drivers/gpu/drm/rcar-du/rcar_du_group.c |    5 +
 drivers/gpu/drm/rcar-du/rcar_du_regs.h  |   92 +++
 include/drm/drm_ioctl.h                 |    7 +
 9 files changed, 1398 insertions(+), 7 deletions(-)
 create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_cmm.c

diff --git a/drivers/gpu/drm/rcar-du/Makefile b/drivers/gpu/drm/rcar-du/Makefile
index 2a3b8d7..595e719 100644
--- a/drivers/gpu/drm/rcar-du/Makefile
+++ b/drivers/gpu/drm/rcar-du/Makefile
@@ -6,12 +6,14 @@ rcar-du-drm-y := rcar_du_crtc.o \
 		 rcar_du_kms.o \
 		 rcar_du_plane.o
 
+rcar-du-drm-y += rcar_du_cmm.o
 rcar-du-drm-$(CONFIG_DRM_RCAR_LVDS)	+= rcar_du_of.o \
 					   rcar_du_of_lvds_r8a7790.dtb.o \
 					   rcar_du_of_lvds_r8a7791.dtb.o \
 					   rcar_du_of_lvds_r8a7793.dtb.o \
 					   rcar_du_of_lvds_r8a7795.dtb.o \
 					   rcar_du_of_lvds_r8a7796.dtb.o
+
 rcar-du-drm-$(CONFIG_DRM_RCAR_VSP)	+= rcar_du_vsp.o
 
 obj-$(CONFIG_DRM_RCAR_DU)		+= rcar-du-drm.o
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_cmm.c b/drivers/gpu/drm/rcar-du/rcar_du_cmm.c
new file mode 100644
index 0000000..ac613a6e
--- /dev/null
+++ b/drivers/gpu/drm/rcar-du/rcar_du_cmm.c
@@ -0,0 +1,1200 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*************************************************************************/ /*
+ * DU CMM
+ *
+ * Copyright (C) 2018 Renesas Electronics Corporation
+ *
+ * License        Dual MIT/GPLv2
+ *
+ * The contents of this file are subject to the MIT license as set out below.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * the GNU General Public License Version 2 ("GPL") in which case the provisions
+ * of GPL are applicable instead of those above.
+ *
+ * If you wish to allow use of your version of this file only under the terms of
+ * GPL, and not to allow others to use your version of this file under the terms
+ * of the MIT license, indicate your decision by deleting the provisions above
+ * and replace them with the notice and other provisions required by GPL as set
+ * out in the file called "GPL-COPYING" included in this distribution. If you do
+ * not delete the provisions above, a recipient may use your version of this
+ * file under the terms of either the MIT license or GPL.
+ *
+ * This License is also included in this distribution in the file called
+ * "MIT-COPYING".
+ *
+ * EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) THE SOFTWARE IS
+ * PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE AND NONINFRINGEMENT; AND (B) IN NO EVENT SHALL THE AUTHORS
+ * OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+ * IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ *
+ * GPLv2:
+ * If you wish to use this file under the terms of GPL, following terms are
+ * effective.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */ /*************************************************************************/
+#include <linux/syscalls.h>
+#include <linux/workqueue.h>
+
+#include <linux/reset.h>
+#include <linux/sys_soc.h>
+
+#include <drm/drmP.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_gem_cma_helper.h>
+
+#include "rcar_du_crtc.h"
+#include "rcar_du_drv.h"
+#include "rcar_du_kms.h"
+#include "rcar_du_plane.h"
+#include "rcar_du_regs.h"
+#include <linux/clk.h>
+
+/* #define DEBUG_PROCE_TIME 1 */
+
+#define CMM_LUT_NUM 256
+#define CMM_CLU_NUM (17 * 17 * 17)
+#define CMM_HGO_NUM 64
+/* rcar_du_drm.h Include */
+#define LUT_DOUBLE_BUFFER_AUTO		0
+#define LUT_DOUBLE_BUFFER_A		1
+#define LUT_DOUBLE_BUFFER_B		2
+/* DRM_RCAR_DU_CMM_WAIT_EVENT: DU-CMM done event */
+#define CMM_EVENT_CLU_DONE		BIT(0)
+#define CMM_EVENT_HGO_DONE		BIT(1)
+#define CMM_EVENT_LUT_DONE		BIT(2)
+
+#define CLU_DOUBLE_BUFFER_AUTO		0
+#define CLU_DOUBLE_BUFFER_A		1
+#define CLU_DOUBLE_BUFFER_B		2
+enum {
+	QUE_STAT_PENDING,
+	QUE_STAT_ACTIVE,
+	QUE_STAT_DONE,
+};
+
+static const struct soc_device_attribute rcar_du_cmm_r8a7795_es1[] = {
+	{ .soc_id = "r8a7795", .revision = "ES1.*" },
+	{ /* sentinel */ }
+};
+
+struct rcar_du_cmm;
+struct rcar_du_cmm_file_priv;
+
+struct rcar_du_cmm_pending_event {
+	struct list_head link;
+	struct list_head  fpriv_link;
+	unsigned int event;
+	unsigned int stat;
+	unsigned long callback_data;
+	struct drm_gem_object *gem_obj;
+	struct rcar_du_cmm *du_cmm;
+	struct rcar_du_cmm_file_priv *fpriv;
+};
+
+struct cmm_module_t {
+	struct list_head list;
+	union {
+		struct {
+			struct rcar_du_cmm_pending_event *p;
+			int buf_mode;
+			bool one_side;
+		};
+		int reset;
+	};
+};
+
+struct cmm_reg_save {
+#ifdef CONFIG_PM_SLEEP
+	wait_queue_head_t wait;
+
+	u32 *lut_table;
+	u32 *clu_table;
+#endif /* CONFIG_PM_SLEEP */
+
+	u32 cm2_ctl0;	/* CM2_CTL0 */
+	u32 hgo_offset;	/* CMM_HGO_OFFSET */
+	u32 hgo_size;	/* CMM_HGO_SIZE */
+	u32 hgo_mode;	/* CMM_HGO_MODE */
+};
+
+struct rcar_du_cmm {
+	struct rcar_du_crtc *rcrtc;
+
+	/* CMM base address */
+	void __iomem *cmm_base;
+	struct clk *clock;
+
+	struct cmm_module_t lut;
+	struct cmm_module_t clu;
+	struct cmm_module_t hgo;
+
+	struct mutex lock;	/* lock for register setting */
+	struct workqueue_struct *workqueue;
+	struct work_struct work;
+
+	struct cmm_reg_save reg_save;
+	bool active;
+	bool dbuf;
+	bool clu_dbuf;
+	bool init;
+	bool direct;
+	bool vsync;
+	bool authority;
+	pid_t pid;
+	bool soc_support;
+};
+
+struct rcar_du_cmm_file_priv {
+	wait_queue_head_t event_wait;
+	struct list_head list;
+	struct list_head active_list;
+	struct list_head *done_list;
+};
+
+static DEFINE_MUTEX(cmm_event_lock);
+static DEFINE_SPINLOCK(cmm_direct_lock);
+
+static inline void event_prev_cancel_locked(struct cmm_module_t *module);
+
+static inline u32 cmm_index(struct rcar_du_cmm *_cmm)
+{
+	struct rcar_du_device *rcdu = _cmm->rcrtc->group->dev;
+
+	if (rcar_du_has(rcdu, RCAR_DU_FEATURE_R8A77965_REGS)) {
+		if ((_cmm)->rcrtc->index == 3)
+			return 2;
+	}
+	return (_cmm)->rcrtc->index;
+}
+
+#define cmm_done_list(_cmm, _fpriv) \
+	(&((_fpriv)->done_list[cmm_index(_cmm)]))
+
+static inline u32 rcar_du_cmm_read(struct rcar_du_cmm *du_cmm, u32 reg)
+{
+	return ioread32(du_cmm->cmm_base + reg);
+}
+
+static inline void rcar_du_cmm_write(struct rcar_du_cmm *du_cmm,
+				     u32 reg, u32 data)
+{
+	iowrite32(data, du_cmm->cmm_base + reg);
+}
+
+/* create default CLU table data */
+static inline u32 index_to_clu_data(int index)
+{
+	int r, g, b;
+
+	r = index % 17;
+	index /= 17;
+	g = index % 17;
+	index /= 17;
+	b = index % 17;
+
+	r = (r << 20);
+	if (r > (255 << 16))
+		r = (255 << 16);
+	g = (g << 12);
+	if (g > (255 << 8))
+		g = (255 << 8);
+	b = (b << 4);
+	if (b > (255 << 0))
+		b = (255 << 0);
+
+	return r | g | b;
+}
+
+#ifdef DEBUG_PROCE_TIME
+static long long diff_timevals(struct timeval *start, struct timeval *end)
+{
+	return (end->tv_sec * 1000000LL + end->tv_usec) -
+		(start->tv_sec * 1000000LL + start->tv_usec);
+}
+#endif
+
+static void du_cmm_clk(struct rcar_du_cmm *du_cmm, bool on)
+{
+	if (on)
+		clk_prepare_enable(du_cmm->clock);
+	else
+		clk_disable_unprepare(du_cmm->clock);
+}
+
+int rcar_du_cmm_start_stop(struct rcar_du_crtc *rcrtc, bool on)
+{
+	struct rcar_du_cmm *du_cmm = rcrtc->cmm_handle;
+	int i;
+	u32 table_data;
+	const struct drm_display_mode *mode;
+	int w, h, x, y;
+
+	if (!du_cmm)
+		return -EINVAL;
+
+	mutex_lock(&du_cmm->lock);
+
+	if (!on) {
+		du_cmm->active = false;
+
+		rcar_du_cmm_write(du_cmm, CMM_LUT_CTRL, 0x00000000);
+		rcar_du_cmm_write(du_cmm, CMM_CLU_CTRL, 0x00000000);
+
+		du_cmm_clk(du_cmm, false);
+
+		goto end;
+	}
+
+	du_cmm_clk(du_cmm, true);
+
+	if (du_cmm->init)
+		goto init_done;
+
+	du_cmm->init = true;
+
+	mode = &du_cmm->rcrtc->crtc.mode;
+
+	x = (du_cmm->reg_save.hgo_offset >> 16) & 0xFFFF;
+	y = (du_cmm->reg_save.hgo_offset >> 0)  & 0xFFFF;
+	w = (du_cmm->reg_save.hgo_size >> 16) & 0xFFFF;
+	h = (du_cmm->reg_save.hgo_size >> 0)  & 0xFFFF;
+	if ((mode->hdisplay < (w + x)) || w == 0) {
+		x = 0;
+		w = mode->hdisplay;
+	}
+	if ((mode->vdisplay < (h + y)) || h == 0) {
+		y = 0;
+		h = mode->vdisplay;
+	}
+	du_cmm->reg_save.hgo_offset = (x << 16) | y;
+	du_cmm->reg_save.hgo_size = (w << 16) | h;
+
+	if (mode->flags & DRM_MODE_FLAG_PVSYNC)
+		du_cmm->reg_save.cm2_ctl0 |= CMM_CTL0_VPOL;
+	else
+		du_cmm->reg_save.cm2_ctl0 &= ~CMM_CTL0_VPOL;
+
+	rcar_du_cmm_write(du_cmm, CM2_CTL0, du_cmm->reg_save.cm2_ctl0);
+	rcar_du_cmm_write(du_cmm, CMM_HGO_OFFSET, du_cmm->reg_save.hgo_offset);
+	rcar_du_cmm_write(du_cmm, CMM_HGO_SIZE, du_cmm->reg_save.hgo_size);
+	rcar_du_cmm_write(du_cmm, CMM_HGO_MODE, du_cmm->reg_save.hgo_mode);
+	rcar_du_cmm_write(du_cmm, CMM_HGO_LB_TH, 0);
+	rcar_du_cmm_write(du_cmm, CMM_HGO_LB0_H, 0);
+	rcar_du_cmm_write(du_cmm, CMM_HGO_LB0_V, 0);
+	rcar_du_cmm_write(du_cmm, CMM_HGO_LB1_H, 0);
+	rcar_du_cmm_write(du_cmm, CMM_HGO_LB1_V, 0);
+	rcar_du_cmm_write(du_cmm, CMM_HGO_LB2_H, 0);
+	rcar_du_cmm_write(du_cmm, CMM_HGO_LB2_V, 0);
+	rcar_du_cmm_write(du_cmm, CMM_HGO_LB3_H, 0);
+	rcar_du_cmm_write(du_cmm, CMM_HGO_LB3_V, 0);
+
+	/* init color table */
+	for (i = 0; i < CMM_LUT_NUM; i++) {
+	#ifdef CONFIG_PM_SLEEP
+		table_data = du_cmm->reg_save.lut_table[i];
+	#else
+		table_data = ((i << 16) | (i << 8) | (i << 0));
+	#endif /* CONFIG_PM_SLEEP */
+		rcar_du_cmm_write(du_cmm, CMM_LUT_TBLA(i), table_data);
+
+		if (du_cmm->dbuf)
+			rcar_du_cmm_write(du_cmm, CMM_LUT_TBLB(i),
+					  table_data);
+	}
+
+	rcar_du_cmm_write(du_cmm, CMM_CLU_CTRL,
+			  CMM_CLU_CTRL_AAI | CMM_CLU_CTRL_MVS);
+
+	rcar_du_cmm_write(du_cmm, CMM_CLU_ADDR, 0);
+	if (du_cmm->clu_dbuf)
+		rcar_du_cmm_write(du_cmm, CMM_CLU_ADDR2, 0);
+
+	for (i = 0; i < CMM_CLU_NUM; i++) {
+	#ifdef CONFIG_PM_SLEEP
+		table_data = du_cmm->reg_save.clu_table[i];
+	#else
+		table_data = index_to_clu_data(i);
+	#endif /* CONFIG_PM_SLEEP */
+		rcar_du_cmm_write(du_cmm, CMM_CLU_DATA, table_data);
+
+		if (du_cmm->dbuf)
+			rcar_du_cmm_write(du_cmm, CMM_CLU_DATA2,
+					  table_data);
+	}
+
+init_done:
+	/* enable color table */
+	rcar_du_cmm_write(du_cmm, CMM_LUT_CTRL, CMM_LUT_CTRL_EN);
+	rcar_du_cmm_write(du_cmm, CMM_CLU_CTRL, CMM_CLU_CTRL_AAI |
+			  CMM_CLU_CTRL_MVS | CMM_CLU_CTRL_EN);
+
+	du_cmm->active = true;
+end:
+	mutex_unlock(&du_cmm->lock);
+
+	return 0;
+}
+
+#define gem_to_vaddr(gem_obj) \
+	(container_of((gem_obj), struct drm_gem_cma_object, base)->vaddr)
+
+static inline void cmm_vblank_put(struct rcar_du_cmm_pending_event *p)
+{
+	if (p->du_cmm)
+		drm_crtc_vblank_put(&p->du_cmm->rcrtc->crtc);
+}
+
+static inline void
+cmm_gem_object_unreference(struct rcar_du_cmm_pending_event *p)
+{
+	if (p->gem_obj)
+		drm_gem_object_unreference_unlocked(p->gem_obj);
+}
+
+static inline void _event_done_locked(struct rcar_du_cmm_pending_event *p)
+{
+	cmm_gem_object_unreference(p);
+
+	if (p->fpriv) {
+		p->stat = QUE_STAT_DONE;
+		list_del(&p->link); /* delete from p->fpriv->active_list */
+		list_add_tail(&p->link, cmm_done_list(p->du_cmm, p->fpriv));
+		wake_up_interruptible(&p->fpriv->event_wait);
+	} else {
+		/* link deleted by rcar_du_cmm_postclose */
+		kfree(p);
+	}
+}
+
+/* cancel from active_list (case of LUT/CLU double buffer mode) */
+static inline void event_prev_cancel_locked(struct cmm_module_t *module)
+{
+	struct rcar_du_cmm_pending_event *p = module->p;
+
+	if (!p)
+		return;
+
+	module->p = NULL;
+
+	_event_done_locked(p);
+}
+
+static inline void event_done(struct rcar_du_cmm_pending_event *p)
+{
+	/* vblank is put */
+
+	mutex_lock(&cmm_event_lock);
+
+	_event_done_locked(p);
+
+	mutex_unlock(&cmm_event_lock);
+}
+
+static inline void lc_event_done(struct cmm_module_t *module,
+				 struct rcar_du_cmm_pending_event *p,
+				 bool done)
+{
+	/* vblank is put */
+
+	mutex_lock(&cmm_event_lock);
+
+	if (!done && list_empty(&module->list))
+		module->p = p;
+	else
+		_event_done_locked(p);
+
+	mutex_unlock(&cmm_event_lock);
+}
+
+static inline struct rcar_du_cmm_pending_event *
+event_pop_locked(struct cmm_module_t *module)
+{
+	struct rcar_du_cmm_pending_event *p =
+		list_first_entry(&module->list,
+				 struct rcar_du_cmm_pending_event,
+				 link);
+
+	p->stat = QUE_STAT_ACTIVE;
+	list_del(&p->link); /* delete from du_cmm->[lut|clu|hgo].list */
+	list_add_tail(&p->link, &p->fpriv->active_list);
+	cmm_vblank_put(p);
+
+	return p;
+}
+
+struct rcar_du_cmm_work_stat {
+	union {
+		struct {
+			struct rcar_du_cmm_pending_event *p;
+			bool done;
+			bool table_copy;
+		};
+		struct {
+			struct rcar_du_cmm_pending_event *p2;
+			bool reset;
+		};
+	};
+};
+
+static inline void one_side(struct rcar_du_cmm *du_cmm,
+			    struct cmm_module_t *module,
+			    bool on)
+{
+	if (on && !module->one_side) {
+		module->one_side = true;
+		drm_crtc_vblank_get(&du_cmm->rcrtc->crtc);
+	} else if (!on && module->one_side) {
+		module->one_side = false;
+		drm_crtc_vblank_put(&du_cmm->rcrtc->crtc);
+	}
+}
+
+/* pop LUT que */
+static int lut_pop_locked(struct rcar_du_cmm *du_cmm,
+			  struct rcar_du_cmm_work_stat *stat)
+{
+	bool is_one_side = false;
+
+	stat->done = true;
+	stat->table_copy = false;
+
+	if (!list_empty(&du_cmm->lut.list)) {
+		stat->p = event_pop_locked(&du_cmm->lut);
+
+		/* prev lut table */
+		event_prev_cancel_locked(&du_cmm->lut);
+
+		if (du_cmm->lut.buf_mode == LUT_DOUBLE_BUFFER_AUTO) {
+			is_one_side = true;
+			if (list_empty(&du_cmm->lut.list))
+				stat->done = false;
+		}
+
+	} else if (du_cmm->lut.p) {
+		/* prev lut table */
+		stat->p = du_cmm->lut.p;
+		du_cmm->lut.p = NULL;
+	} else {
+		stat->done = false;
+		stat->p = NULL;
+		stat->table_copy = du_cmm->lut.one_side;
+	}
+
+	one_side(du_cmm, &du_cmm->lut, is_one_side);
+
+	return 0;
+}
+
+static int lut_table_copy(struct rcar_du_cmm *du_cmm)
+{
+	int i;
+	u32 src, dst;
+
+	if (rcar_du_cmm_read(du_cmm, CM2_CTL1) & CMM_CTL1_BFS) {
+		dst = CMM_LUT_TBLA(0);
+		src = CMM_LUT_TBLB(0);
+	} else {
+		dst = CMM_LUT_TBLB(0);
+		src = CMM_LUT_TBLA(0);
+	}
+
+	for (i = 0; i < CMM_LUT_NUM; i++) {
+		rcar_du_cmm_write(du_cmm, dst, rcar_du_cmm_read(du_cmm, src));
+		dst += 4;
+		src += 4;
+	}
+
+	return 0;
+}
+
+/* set 1D look up table */
+static int lut_set(struct rcar_du_cmm *du_cmm,
+		   struct rcar_du_cmm_work_stat *stat)
+{
+	int i;
+	u32 lut_base;
+	u32 *lut_buf;
+
+	if (!stat->p) {
+		if (stat->table_copy)
+			lut_table_copy(du_cmm);
+		return 0; /* skip */
+	}
+
+	/* set LUT */
+	switch (du_cmm->lut.buf_mode) {
+	case LUT_DOUBLE_BUFFER_A:
+		lut_base = CMM_LUT_TBLA(0);
+		break;
+
+	case LUT_DOUBLE_BUFFER_AUTO:
+		if (rcar_du_cmm_read(du_cmm, CM2_CTL1) & CMM_CTL1_BFS) {
+			lut_base = CMM_LUT_TBLA(0);
+			break;
+		}
+		lut_base = CMM_LUT_TBLB(0);
+		break;
+	case LUT_DOUBLE_BUFFER_B:
+		lut_base = CMM_LUT_TBLB(0);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	lut_buf = gem_to_vaddr(stat->p->gem_obj);
+	for (i = 0; i < CMM_LUT_NUM; i++)
+		rcar_du_cmm_write(du_cmm, lut_base + i * 4, lut_buf[i]);
+
+	lc_event_done(&du_cmm->lut, stat->p, stat->done);
+
+	return 0;
+}
+
+/* pop CLU que */
+static int clu_pop_locked(struct rcar_du_cmm *du_cmm,
+			  struct rcar_du_cmm_work_stat *stat)
+{
+	bool is_one_side = false;
+
+	stat->done = true;
+	stat->table_copy = false;
+
+	if (!list_empty(&du_cmm->clu.list)) {
+		stat->p = event_pop_locked(&du_cmm->clu);
+
+		/* prev clu table */
+		event_prev_cancel_locked(&du_cmm->clu);
+
+		if (du_cmm->clu.buf_mode == CLU_DOUBLE_BUFFER_AUTO) {
+			is_one_side = true;
+			if (list_empty(&du_cmm->clu.list))
+				stat->done = false;
+		}
+
+	} else if (du_cmm->clu.p) {
+		/* prev clu table */
+		stat->p = du_cmm->clu.p;
+		du_cmm->clu.p = NULL;
+	} else {
+		stat->done = false;
+		stat->p = NULL;
+		stat->table_copy = du_cmm->clu.one_side;
+	}
+
+	one_side(du_cmm, &du_cmm->clu, is_one_side);
+
+	return 0;
+}
+
+static int clu_table_copy(struct rcar_du_cmm *du_cmm)
+{
+	int i, j, k;
+	u32 src_addr, src_data, dst_addr, dst_data;
+
+	if (rcar_du_cmm_read(du_cmm, CM2_CTL1) & CMM_CTL1_BFS) {
+		dst_addr = CMM_CLU_ADDR;
+		dst_data = CMM_CLU_DATA;
+		src_addr = CMM_CLU_ADDR2;
+		src_data = CMM_CLU_DATA2;
+	} else {
+		dst_addr = CMM_CLU_ADDR2;
+		dst_data = CMM_CLU_DATA2;
+		src_addr = CMM_CLU_ADDR;
+		src_data = CMM_CLU_DATA;
+	}
+
+	rcar_du_cmm_write(du_cmm, dst_addr, 0);
+	for (i = 0; i < 17; i++) {
+		for (j = 0; j < 17; j++) {
+			for (k = 0; k < 17; k++) {
+				rcar_du_cmm_write(du_cmm, src_addr,
+						  (k << 16) | (j << 8) |
+						  (i << 0));
+				rcar_du_cmm_write(du_cmm, dst_data,
+						  rcar_du_cmm_read(du_cmm,
+								   src_data));
+			}
+		}
+	}
+
+	return 0;
+}
+
+/* set 3D look up table */
+static int clu_set(struct rcar_du_cmm *du_cmm,
+		   struct rcar_du_cmm_work_stat *stat)
+{
+	int i;
+	u32 addr_reg, data_reg;
+	u32 *clu_buf;
+
+	if (!stat->p) {
+		if (stat->table_copy)
+			clu_table_copy(du_cmm);
+		return 0; /* skip */
+	}
+
+	/* set CLU */
+	switch (du_cmm->clu.buf_mode) {
+	case CLU_DOUBLE_BUFFER_A:
+		addr_reg = CMM_CLU_ADDR;
+		data_reg = CMM_CLU_DATA;
+		break;
+
+	case CLU_DOUBLE_BUFFER_AUTO:
+		if (rcar_du_cmm_read(du_cmm, CM2_CTL1) & CMM_CTL1_BFS) {
+			addr_reg = CMM_CLU_ADDR;
+			data_reg = CMM_CLU_DATA;
+			break;
+		}
+		addr_reg = CMM_CLU_ADDR2;
+		data_reg = CMM_CLU_DATA2;
+		break;
+	case CLU_DOUBLE_BUFFER_B:
+		addr_reg = CMM_CLU_ADDR2;
+		data_reg = CMM_CLU_DATA2;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	clu_buf = gem_to_vaddr(stat->p->gem_obj);
+	rcar_du_cmm_write(du_cmm, addr_reg, 0);
+	for (i = 0; i < CMM_CLU_NUM; i++)
+		rcar_du_cmm_write(du_cmm, data_reg, clu_buf[i]);
+
+	lc_event_done(&du_cmm->clu, stat->p, stat->done);
+
+	return 0;
+}
+
+/* pop HGO que */
+static int hgo_pop_locked(struct rcar_du_cmm *du_cmm,
+			  struct rcar_du_cmm_work_stat *stat)
+{
+	struct rcar_du_cmm_pending_event *_p = NULL;
+
+	if (!list_empty(&du_cmm->hgo.list))
+		_p = event_pop_locked(&du_cmm->hgo);
+
+	if (du_cmm->hgo.reset) {
+		drm_crtc_vblank_put(&du_cmm->rcrtc->crtc);
+		du_cmm->hgo.reset = 0;
+		stat->reset = true;
+	} else {
+		stat->reset = false;
+	}
+
+	stat->p2 = _p;
+
+	return 0;
+}
+
+/* get histogram */
+static int hgo_get(struct rcar_du_cmm *du_cmm,
+		   struct rcar_du_cmm_work_stat *stat)
+{
+	int i, j;
+	const u32 histo_offset[3] = {
+		CMM_HGO_R_HISTO(0),
+		CMM_HGO_G_HISTO(0),
+		CMM_HGO_B_HISTO(0),
+	};
+	void *vaddr;
+
+	if (!stat->p2) {
+		if (stat->reset)
+			goto hgo_reset;
+
+		return 0; /* skip */
+	}
+
+	vaddr = gem_to_vaddr(stat->p2->gem_obj);
+	for (i = 0; i < 3; i++) {
+		u32 *hgo_buf = vaddr + CMM_HGO_NUM * 4 * i;
+
+		for (j = 0; j < CMM_HGO_NUM; j++)
+			hgo_buf[j] = rcar_du_cmm_read(du_cmm,
+						      histo_offset[i] + j * 4);
+	}
+
+	event_done(stat->p2);
+
+hgo_reset:
+	rcar_du_cmm_write(du_cmm, CMM_HGO_REGRST, CMM_HGO_REGRST_RCLEA);
+
+	return 0;
+}
+
+static bool du_cmm_vsync_get(struct rcar_du_cmm *du_cmm)
+{
+	unsigned long flags;
+	bool vsync;
+
+	spin_lock_irqsave(&cmm_direct_lock, flags);
+	vsync = du_cmm->vsync;
+	du_cmm->vsync = false;
+	spin_unlock_irqrestore(&cmm_direct_lock, flags);
+
+	return vsync;
+}
+
+static void du_cmm_vsync_set(struct rcar_du_cmm *du_cmm, bool vsync)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&cmm_direct_lock, flags);
+	du_cmm->vsync = vsync;
+	spin_unlock_irqrestore(&cmm_direct_lock, flags);
+}
+
+static void du_cmm_work(struct work_struct *work)
+{
+	struct rcar_du_cmm *du_cmm =
+			container_of(work, struct rcar_du_cmm, work);
+	struct rcar_du_cmm_work_stat s_lut;
+	struct rcar_du_cmm_work_stat s_clu;
+	struct rcar_du_cmm_work_stat s_hgo;
+#ifdef DEBUG_PROCE_TIME
+	struct timeval start_time, end_time;
+	unsigned long lut_time, clu_time, hgo_time;
+#endif
+	bool vsync_status = false;
+
+	memset(&s_lut, 0, sizeof(struct rcar_du_cmm_work_stat));
+	memset(&s_clu, 0, sizeof(struct rcar_du_cmm_work_stat));
+	memset(&s_hgo, 0, sizeof(struct rcar_du_cmm_work_stat));
+
+	vsync_status = du_cmm_vsync_get(du_cmm);
+
+	mutex_lock(&cmm_event_lock);
+
+	lut_pop_locked(du_cmm, &s_lut);
+	clu_pop_locked(du_cmm, &s_clu);
+	if (vsync_status)
+		hgo_pop_locked(du_cmm, &s_hgo);
+
+	mutex_unlock(&cmm_event_lock);
+
+	/* set LUT */
+#ifdef DEBUG_PROCE_TIME
+	do_gettimeofday(&start_time);
+#endif
+	lut_set(du_cmm, &s_lut);
+#ifdef DEBUG_PROCE_TIME
+	do_gettimeofday(&end_time);
+	lut_time = (long)diff_timevals(&start_time, &end_time);
+#endif
+
+	/* set CLU */
+#ifdef DEBUG_PROCE_TIME
+	do_gettimeofday(&start_time);
+#endif
+	clu_set(du_cmm, &s_clu);
+#ifdef DEBUG_PROCE_TIME
+	do_gettimeofday(&end_time);
+	clu_time = (long)diff_timevals(&start_time, &end_time);
+#endif
+
+	/* get HGO */
+#ifdef DEBUG_PROCE_TIME
+	do_gettimeofday(&start_time);
+#endif
+	if (vsync_status)
+		hgo_get(du_cmm, &s_hgo);
+#ifdef DEBUG_PROCE_TIME
+	do_gettimeofday(&end_time);
+	hgo_time = (long)diff_timevals(&start_time, &end_time);
+#endif
+
+#ifdef CONFIG_PM_SLEEP
+	wake_up_interruptible(&du_cmm->reg_save.wait);
+#endif /* CONFIG_PM_SLEEP */
+
+#ifdef DEBUG_PROCE_TIME
+	{
+		struct rcar_du_device *rcdu = du_cmm->rcrtc->group->dev;
+
+		if (s_lut.p)
+			dev_info(rcdu->dev, "LUT %ld usec.\n", lut_time);
+		if (s_clu.p)
+			dev_info(rcdu->dev, "LUT %ld usec.\n", clu_time);
+		if (s_hgo.p2)
+			dev_info(rcdu->dev, "HGO %ld usec.\n", hgo_time);
+	}
+#endif
+}
+
+static int du_cmm_que_empty(struct rcar_du_cmm *du_cmm)
+{
+	if (list_empty(&du_cmm->lut.list) && !du_cmm->lut.p &&
+	    !du_cmm->lut.one_side &&
+	    list_empty(&du_cmm->clu.list) && !du_cmm->clu.p &&
+	    !du_cmm->clu.one_side &&
+	    list_empty(&du_cmm->hgo.list) && !du_cmm->hgo.reset)
+		return 1;
+
+	return 0;
+}
+
+void rcar_du_cmm_kick(struct rcar_du_crtc *rcrtc)
+{
+	struct rcar_du_cmm *du_cmm = rcrtc->cmm_handle;
+
+	if (!du_cmm)
+		return;
+
+	if (!du_cmm->active)
+		return;
+
+	if (!du_cmm_que_empty(du_cmm)) {
+		du_cmm_vsync_set(du_cmm, true);
+		queue_work(du_cmm->workqueue, &du_cmm->work);
+	}
+}
+
+#ifdef CONFIG_PM_SLEEP
+int rcar_du_cmm_pm_suspend(struct rcar_du_crtc *rcrtc)
+{
+	struct rcar_du_cmm *du_cmm = rcrtc->cmm_handle;
+	struct rcar_du_device *rcdu = rcrtc->group->dev;
+	int i, j, k, index;
+	int ret;
+
+	if (!du_cmm)
+		return 0;
+
+	ret = wait_event_timeout(du_cmm->reg_save.wait,
+				 du_cmm_que_empty(du_cmm),
+				 msecs_to_jiffies(500));
+	if (ret == 0)
+		dev_err(rcdu->dev, "rcar-du cmm suspend : timeout\n");
+
+	if (!du_cmm->init)
+		return 0;
+
+	du_cmm->init = false;
+
+	if (!du_cmm->active)
+		du_cmm_clk(du_cmm, true);
+
+	/* table save */
+	for (i = 0; i < CMM_LUT_NUM; i++) {
+		du_cmm->reg_save.lut_table[i] =
+			rcar_du_cmm_read(du_cmm, CMM_LUT_TBLA(i));
+	}
+
+	index = 0;
+	for (i = 0; i < 17; i++) {
+		for (j = 0; j < 17; j++) {
+			for (k = 0; k < 17; k++) {
+				rcar_du_cmm_write(du_cmm, CMM_CLU_ADDR,
+						  (k << 16) | (j << 8) |
+						  (i << 0));
+				du_cmm->reg_save.clu_table[index++] =
+					rcar_du_cmm_read(du_cmm, CMM_CLU_DATA);
+			}
+		}
+	}
+
+	if (!du_cmm->active)
+		du_cmm_clk(du_cmm, false);
+
+	return 0;
+}
+
+int rcar_du_cmm_pm_resume(struct rcar_du_crtc *rcrtc)
+{
+	/* none */
+	return 0;
+}
+#endif /* CONFIG_PM_SLEEP */
+
+int rcar_du_cmm_driver_open(struct drm_device *dev, struct drm_file *file_priv)
+{
+	struct rcar_du_device *rcdu = dev->dev_private;
+	struct rcar_du_cmm_file_priv *fpriv;
+	int i;
+
+	if (!rcar_du_has(rcdu, RCAR_DU_FEATURE_CMM))
+		return 0;
+
+	file_priv->driver_priv = NULL;
+
+	fpriv = kzalloc(sizeof(*fpriv), GFP_KERNEL);
+	if (unlikely(!fpriv))
+		return -ENOMEM;
+
+	fpriv->done_list = kcalloc(rcdu->info->num_crtcs,
+				   sizeof(*fpriv->done_list),
+				   GFP_KERNEL);
+	if (unlikely(!fpriv->done_list)) {
+		kfree(fpriv);
+		return -ENOMEM;
+	}
+
+	init_waitqueue_head(&fpriv->event_wait);
+	INIT_LIST_HEAD(&fpriv->list);
+	INIT_LIST_HEAD(&fpriv->active_list);
+	for (i = 0; i < rcdu->info->num_crtcs; i++)
+		INIT_LIST_HEAD(&fpriv->done_list[i]);
+
+	file_priv->driver_priv = fpriv;
+
+	return 0;
+}
+
+void rcar_du_cmm_postclose(struct drm_device *dev, struct drm_file *file_priv)
+{
+	struct rcar_du_device *rcdu = dev->dev_private;
+	struct rcar_du_cmm_file_priv *fpriv = file_priv->driver_priv;
+	struct rcar_du_cmm_pending_event *p, *pt;
+	struct rcar_du_crtc *rcrtc;
+	struct rcar_du_cmm *du_cmm;
+	int i, crtcs_cnt, ret;
+	u32 table_data;
+
+	if (!rcar_du_has(rcdu, RCAR_DU_FEATURE_CMM))
+		return;
+
+	mutex_lock(&cmm_event_lock);
+
+	/* Unlink file priv events */
+	list_for_each_entry_safe(p, pt, &fpriv->list, fpriv_link) {
+		list_del(&p->fpriv_link);
+		list_del(&p->link);
+		switch (p->stat) {
+		case QUE_STAT_PENDING:
+			cmm_vblank_put(p);
+			cmm_gem_object_unreference(p);
+			kfree(p);
+			break;
+		case QUE_STAT_DONE:
+			kfree(p);
+			break;
+		case QUE_STAT_ACTIVE:
+			p->fpriv = NULL;
+			break;
+		}
+	}
+
+	mutex_unlock(&cmm_event_lock);
+
+	kfree(fpriv->done_list);
+	kfree(fpriv);
+	file_priv->driver_priv = NULL;
+
+	for (crtcs_cnt = 0; crtcs_cnt < rcdu->num_crtcs; crtcs_cnt++) {
+		rcrtc = &rcdu->crtcs[crtcs_cnt];
+		du_cmm = rcrtc->cmm_handle;
+		if (du_cmm->authority && du_cmm->pid == task_pid_nr(current)) {
+			du_cmm->authority = false;
+			du_cmm->pid = 0;
+			ret = wait_event_timeout(du_cmm->reg_save.wait,
+						 du_cmm_que_empty(du_cmm),
+						 msecs_to_jiffies(500));
+			if (ret == 0)
+				dev_err(rcdu->dev, "rcar-du cmm close : timeout\n");
+
+			for (i = 0; i < CMM_LUT_NUM; i++)
+				du_cmm->reg_save.lut_table[i] = (i << 16) |
+								(i << 8) |
+								(i << 0);
+
+			for (i = 0; i < CMM_CLU_NUM; i++) {
+				du_cmm->reg_save.clu_table[i] =
+							index_to_clu_data(i);
+			}
+
+			for (i = 0; i < CMM_LUT_NUM; i++) {
+#ifdef CONFIG_PM_SLEEP
+				table_data = du_cmm->reg_save.lut_table[i];
+#else
+				table_data = ((i << 16) | (i << 8) | (i << 0));
+#endif /* CONFIG_PM_SLEEP */
+				rcar_du_cmm_write(du_cmm, CMM_LUT_TBLA(i),
+						  table_data);
+				if (du_cmm->dbuf) {
+					rcar_du_cmm_write(du_cmm,
+							  CMM_LUT_TBLB(i),
+							  table_data);
+				}
+			}
+
+			for (i = 0; i < CMM_CLU_NUM; i++) {
+#ifdef CONFIG_PM_SLEEP
+				table_data = du_cmm->reg_save.clu_table[i];
+#else
+				table_data = index_to_clu_data(i);
+#endif /* CONFIG_PM_SLEEP */
+				rcar_du_cmm_write(du_cmm, CMM_CLU_DATA,
+						  table_data);
+
+				if (du_cmm->dbuf) {
+					rcar_du_cmm_write(du_cmm, CMM_CLU_DATA2,
+							  table_data);
+				}
+			}
+		}
+	}
+}
+
+int rcar_du_cmm_init(struct rcar_du_crtc *rcrtc)
+{
+	struct rcar_du_cmm *du_cmm;
+	int ret;
+	int i;
+	struct rcar_du_device *rcdu = rcrtc->group->dev;
+	char name[64];
+	struct resource *mem;
+
+	if (!rcar_du_has(rcdu, RCAR_DU_FEATURE_CMM))
+		return 0;
+
+	du_cmm = devm_kzalloc(rcdu->dev, sizeof(*du_cmm), GFP_KERNEL);
+	if (!du_cmm) {
+		ret = -ENOMEM;
+		goto error_alloc;
+	}
+
+	/* DU-CMM mapping */
+	sprintf(name, "cmm.%u", rcrtc->index);
+	mem = platform_get_resource_byname(to_platform_device(rcdu->dev),
+					   IORESOURCE_MEM, name);
+	if (!mem) {
+		dev_err(rcdu->dev, "rcar-du cmm init : failed to get memory resource\n");
+		ret = -EINVAL;
+		goto error_mapping_cmm;
+	}
+	du_cmm->cmm_base = devm_ioremap_nocache(rcdu->dev, mem->start,
+						resource_size(mem));
+	if (!du_cmm->cmm_base) {
+		dev_err(rcdu->dev, "rcar-du cmm init : failed to map iomem\n");
+		ret = -EINVAL;
+		goto error_mapping_cmm;
+	}
+	du_cmm->clock = devm_clk_get(rcdu->dev, name);
+	if (IS_ERR(du_cmm->clock)) {
+		dev_err(rcdu->dev, "failed to get clock\n");
+		ret = PTR_ERR(du_cmm->clock);
+		goto error_clock_cmm;
+	}
+
+	du_cmm->rcrtc = rcrtc;
+
+	du_cmm->reg_save.cm2_ctl0 = 0;
+	du_cmm->reg_save.hgo_offset = 0;
+	du_cmm->reg_save.hgo_size = 0;
+	du_cmm->reg_save.hgo_mode = 0;
+
+	du_cmm->dbuf = rcar_du_has(rcdu, RCAR_DU_FEATURE_CMM_LUT_DBUF);
+	if (du_cmm->dbuf) {
+		du_cmm->lut.buf_mode = LUT_DOUBLE_BUFFER_AUTO;
+		du_cmm->reg_save.cm2_ctl0 |= CMM_CTL0_DBUF;
+	} else {
+		dev_err(rcdu->dev, "single buffer is not supported.\n");
+		du_cmm->dbuf = true;
+		du_cmm->lut.buf_mode = LUT_DOUBLE_BUFFER_AUTO;
+		du_cmm->reg_save.cm2_ctl0 |= CMM_CTL0_DBUF;
+	}
+
+	du_cmm->clu_dbuf = rcar_du_has(rcdu, RCAR_DU_FEATURE_CMM_CLU_DBUF);
+	if (du_cmm->clu_dbuf) {
+		du_cmm->clu.buf_mode = CLU_DOUBLE_BUFFER_AUTO;
+		du_cmm->reg_save.cm2_ctl0 |= CMM_CTL0_CLUDB;
+	} else {
+		dev_err(rcdu->dev, "single buffer is not supported.\n");
+		du_cmm->clu_dbuf = true;
+		du_cmm->clu.buf_mode = CLU_DOUBLE_BUFFER_AUTO;
+		du_cmm->reg_save.cm2_ctl0 |= CMM_CTL0_CLUDB;
+	}
+
+#ifdef CONFIG_PM_SLEEP
+	du_cmm->reg_save.lut_table =
+		devm_kzalloc(rcdu->dev, CMM_LUT_NUM * 4, GFP_KERNEL);
+	if (!du_cmm->reg_save.lut_table) {
+		ret = -ENOMEM;
+		goto error_lut_reg_save_buf;
+	}
+	for (i = 0; i < CMM_LUT_NUM; i++)
+		du_cmm->reg_save.lut_table[i] = (i << 16) | (i << 8) | (i << 0);
+
+	du_cmm->reg_save.clu_table =
+		devm_kzalloc(rcdu->dev, CMM_CLU_NUM * 4, GFP_KERNEL);
+	if (!du_cmm->reg_save.clu_table) {
+		ret = -ENOMEM;
+		goto error_clu_reg_save_buf;
+	}
+	for (i = 0; i < CMM_CLU_NUM; i++)
+		du_cmm->reg_save.clu_table[i] = index_to_clu_data(i);
+
+	init_waitqueue_head(&du_cmm->reg_save.wait);
+#endif /* CONFIG_PM_SLEEP */
+	if (soc_device_match(rcar_du_cmm_r8a7795_es1))
+		du_cmm->soc_support = false;
+	else
+		du_cmm->soc_support = true;
+
+	du_cmm->active = false;
+	du_cmm->init = false;
+	du_cmm->direct = true;
+
+	mutex_init(&du_cmm->lock);
+	INIT_LIST_HEAD(&du_cmm->lut.list);
+	du_cmm->lut.p = NULL;
+	du_cmm->lut.one_side = false;
+	INIT_LIST_HEAD(&du_cmm->clu.list);
+	du_cmm->clu.p = NULL;
+	du_cmm->clu.one_side = false;
+	INIT_LIST_HEAD(&du_cmm->hgo.list);
+	du_cmm->hgo.reset = 0;
+
+	sprintf(name, "du-cmm%d", rcrtc->index);
+	du_cmm->workqueue = create_singlethread_workqueue(name);
+	INIT_WORK(&du_cmm->work, du_cmm_work);
+
+	rcrtc->cmm_handle = du_cmm;
+
+	dev_info(rcdu->dev, "DU%d use CMM(%s buffer)\n",
+		 rcrtc->index, du_cmm->dbuf ? "Double" : "Single");
+
+	return 0;
+
+#ifdef CONFIG_PM_SLEEP
+error_clu_reg_save_buf:
+error_lut_reg_save_buf:
+#endif /* CONFIG_PM_SLEEP */
+error_clock_cmm:
+	devm_iounmap(rcdu->dev, du_cmm->cmm_base);
+error_mapping_cmm:
+	devm_kfree(rcdu->dev, du_cmm);
+error_alloc:
+	return ret;
+}
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
index 15dc9ca..864fb94 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
@@ -296,6 +296,19 @@ static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc)
 	rcar_du_crtc_write(rcrtc, HDSR, mode->htotal - mode->hsync_start - 19);
 	rcar_du_crtc_write(rcrtc, HDER, mode->htotal - mode->hsync_start +
 					mode->hdisplay - 19);
+	if (rcar_du_has(rcrtc->group->dev, RCAR_DU_FEATURE_CMM)) {
+		rcar_du_crtc_write(rcrtc, HDSR, mode->htotal -
+						mode->hsync_start - 19 - 25);
+		rcar_du_crtc_write(rcrtc, HDER, mode->htotal -
+						mode->hsync_start +
+						mode->hdisplay - 19 - 25);
+	} else {
+		rcar_du_crtc_write(rcrtc, HDSR, mode->htotal -
+						mode->hsync_start - 19);
+		rcar_du_crtc_write(rcrtc, HDER, mode->htotal -
+						mode->hsync_start +
+						mode->hdisplay - 19);
+	}
 	rcar_du_crtc_write(rcrtc, HSWR, mode->hsync_end -
 					mode->hsync_start - 1);
 	rcar_du_crtc_write(rcrtc, HCR,  mode->htotal - 1);
@@ -530,6 +543,9 @@ static void rcar_du_crtc_start(struct rcar_du_crtc *rcrtc)
 			     DSYSR_TVM_MASTER);
 
 	rcar_du_group_start_stop(rcrtc->group, true);
+
+	if (rcar_du_has(rcrtc->group->dev, RCAR_DU_FEATURE_CMM))
+		rcar_du_cmm_start_stop(rcrtc, true);
 }
 
 static void rcar_du_crtc_disable_planes(struct rcar_du_crtc *rcrtc)
@@ -565,6 +581,9 @@ static void rcar_du_crtc_stop(struct rcar_du_crtc *rcrtc)
 {
 	struct drm_crtc *crtc = &rcrtc->crtc;
 
+	if (rcar_du_has(rcrtc->group->dev, RCAR_DU_FEATURE_CMM))
+		rcar_du_cmm_start_stop(rcrtc, false);
+
 	/*
 	 * Disable all planes and wait for the change to take effect. This is
 	 * required as the plane enable registers are updated on vblank, and no
@@ -899,6 +918,9 @@ static irqreturn_t rcar_du_crtc_irq(int irq, void *arg)
 			rcar_du_crtc_finish_page_flip(rcrtc);
 		}
 
+		if (rcar_du_has(rcrtc->group->dev, RCAR_DU_FEATURE_CMM))
+			rcar_du_cmm_kick(rcrtc);
+
 		ret = IRQ_HANDLED;
 	}
 
@@ -999,5 +1021,7 @@ int rcar_du_crtc_create(struct rcar_du_group *rgrp, unsigned int swindex,
 		return ret;
 	}
 
+	rcar_du_cmm_init(rcrtc);
+
 	return 0;
 }
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
index 7680cb2..74e0a22 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
+++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
@@ -67,6 +67,10 @@ struct rcar_du_crtc {
 	struct rcar_du_group *group;
 	struct rcar_du_vsp *vsp;
 	unsigned int vsp_pipe;
+	int lvds_ch;
+
+	void *cmm_handle;
+
 };
 
 #define to_rcar_crtc(c)	container_of(c, struct rcar_du_crtc, crtc)
@@ -104,4 +108,16 @@ void rcar_du_crtc_route_output(struct drm_crtc *crtc,
 			       enum rcar_du_output output);
 void rcar_du_crtc_finish_page_flip(struct rcar_du_crtc *rcrtc);
 
+/* DU-CMM functions */
+int rcar_du_cmm_init(struct rcar_du_crtc *rcrtc);
+int rcar_du_cmm_driver_open(struct drm_device *dev, struct drm_file *file_priv);
+void rcar_du_cmm_postclose(struct drm_device *dev, struct drm_file *file_priv);
+int rcar_du_cmm_start_stop(struct rcar_du_crtc *rcrtc, bool on);
+void rcar_du_cmm_kick(struct rcar_du_crtc *rcrtc);
+
+#ifdef CONFIG_PM_SLEEP
+int rcar_du_cmm_pm_suspend(struct rcar_du_crtc *rcrtc);
+int rcar_du_cmm_pm_resume(struct rcar_du_crtc *rcrtc);
+#endif /* CONFIG_PM_SLEEP */
+
 #endif /* __RCAR_DU_CRTC_H__ */
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
index 02aee6c..838b7c9 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
@@ -26,8 +26,8 @@
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_fb_cma_helper.h>
 #include <drm/drm_gem_cma_helper.h>
-
 #include "rcar_du_drv.h"
+#include "rcar_du_encoder.h"
 #include "rcar_du_kms.h"
 #include "rcar_du_of.h"
 #include "rcar_du_regs.h"
@@ -128,7 +128,9 @@ static const struct rcar_du_device_info rcar_du_r8a7790_info = {
 static const struct rcar_du_device_info rcar_du_r8a7791_info = {
 	.gen = 2,
 	.features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
-		  | RCAR_DU_FEATURE_EXT_CTRL_REGS,
+		  | RCAR_DU_FEATURE_EXT_CTRL_REGS
+		  | RCAR_DU_FEATURE_CMM,
+	.num_crtcs = 2,
 	.channels_mask = BIT(1) | BIT(0),
 	.routes = {
 		/*
@@ -190,7 +192,10 @@ static const struct rcar_du_device_info rcar_du_r8a7795_info = {
 	.gen = 3,
 	.features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
 		  | RCAR_DU_FEATURE_EXT_CTRL_REGS
-		  | RCAR_DU_FEATURE_VSP1_SOURCE,
+		  | RCAR_DU_FEATURE_VSP1_SOURCE
+		  | RCAR_DU_FEATURE_CMM | RCAR_DU_FEATURE_CMM_LUT_DBUF
+		  | RCAR_DU_FEATURE_CMM_CLU_DBUF,
+	.num_crtcs = 4,
 	.channels_mask = BIT(3) | BIT(2) | BIT(1) | BIT(0),
 	.routes = {
 		/*
@@ -222,7 +227,10 @@ static const struct rcar_du_device_info rcar_du_r8a7796_info = {
 	.gen = 3,
 	.features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
 		  | RCAR_DU_FEATURE_EXT_CTRL_REGS
-		  | RCAR_DU_FEATURE_VSP1_SOURCE,
+		  | RCAR_DU_FEATURE_VSP1_SOURCE
+		  | RCAR_DU_FEATURE_CMM | RCAR_DU_FEATURE_CMM_LUT_DBUF
+		  | RCAR_DU_FEATURE_CMM_CLU_DBUF,
+	.num_crtcs = 3,
 	.channels_mask = BIT(2) | BIT(1) | BIT(0),
 	.routes = {
 		/*
@@ -250,7 +258,11 @@ static const struct rcar_du_device_info rcar_du_r8a77965_info = {
 	.gen = 3,
 	.features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
 		  | RCAR_DU_FEATURE_EXT_CTRL_REGS
-		  | RCAR_DU_FEATURE_VSP1_SOURCE,
+		  | RCAR_DU_FEATURE_VSP1_SOURCE
+		  | RCAR_DU_FEATURE_R8A77965_REGS
+		  | RCAR_DU_FEATURE_CMM | RCAR_DU_FEATURE_CMM_LUT_DBUF
+		  | RCAR_DU_FEATURE_CMM_CLU_DBUF,
+	.num_crtcs = 3,
 	.channels_mask = BIT(3) | BIT(1) | BIT(0),
 	.routes = {
 		/*
@@ -328,6 +340,8 @@ DEFINE_DRM_GEM_CMA_FOPS(rcar_du_fops);
 static struct drm_driver rcar_du_driver = {
 	.driver_features	= DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME
 				| DRIVER_ATOMIC,
+	.open			= rcar_du_cmm_driver_open,
+	.postclose		= rcar_du_cmm_postclose,
 	.lastclose		= rcar_du_lastclose,
 	.gem_free_object_unlocked = drm_gem_cma_free_object,
 	.gem_vm_ops		= &drm_gem_cma_vm_ops,
@@ -358,6 +372,12 @@ static int rcar_du_pm_suspend(struct device *dev)
 {
 	struct rcar_du_device *rcdu = dev_get_drvdata(dev);
 	struct drm_atomic_state *state;
+	int i;
+
+	if (rcar_du_has(rcdu, RCAR_DU_FEATURE_CMM)) {
+		for (i = 0; i < rcdu->num_crtcs; ++i)
+			rcar_du_cmm_pm_suspend(&rcdu->crtcs[i]);
+	}
 
 	drm_kms_helper_poll_disable(rcdu->ddev);
 	drm_fbdev_cma_set_suspend_unlocked(rcdu->fbdev, true);
@@ -377,7 +397,20 @@ static int rcar_du_pm_suspend(struct device *dev)
 static int rcar_du_pm_resume(struct device *dev)
 {
 	struct rcar_du_device *rcdu = dev_get_drvdata(dev);
+#if IS_ENABLED(CONFIG_DRM_RCAR_DW_HDMI)
+	struct drm_encoder *encoder;
+	int i;
+
+	if (rcar_du_has(rcdu, RCAR_DU_FEATURE_CMM)) {
+		for (i = 0; (i < rcdu->num_crtcs); ++i)
+			rcar_du_cmm_pm_resume(&rcdu->crtcs[i]);
+	}
 
+	list_for_each_entry(encoder, &rcdu->ddev->mode_config.encoder_list,
+			    head) {
+		to_rcar_encoder(encoder);
+	}
+#endif
 	drm_atomic_helper_resume(rcdu->ddev, rcdu->suspend_state);
 	drm_fbdev_cma_set_suspend_unlocked(rcdu->fbdev, false);
 	drm_kms_helper_poll_enable(rcdu->ddev);
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.h b/drivers/gpu/drm/rcar-du/rcar_du_drv.h
index b3a25e8..f2afe36 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_drv.h
+++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.h
@@ -30,8 +30,19 @@ struct rcar_du_device;
 #define RCAR_DU_FEATURE_CRTC_IRQ_CLOCK	(1 << 0)	/* Per-CRTC IRQ and clock */
 #define RCAR_DU_FEATURE_EXT_CTRL_REGS	(1 << 1)	/* Has extended control registers */
 #define RCAR_DU_FEATURE_VSP1_SOURCE	(1 << 2)	/* Has inputs from VSP1 */
-
-#define RCAR_DU_QUIRK_ALIGN_128B	(1 << 0)	/* Align pitches to 128 bytes */
+/* Use R8A77965 registers */
+#define RCAR_DU_FEATURE_R8A77965_REGS	BIT(3)
+
+/* Has DEF7R register & CMM */
+#define RCAR_DU_FEATURE_CMM		BIT(10)
+/* Has CMM LUT Double buffer */
+#define RCAR_DU_FEATURE_CMM_LUT_DBUF	BIT(11)
+/* Has CMM CLU Double buffer */
+#define RCAR_DU_FEATURE_CMM_CLU_DBUF	BIT(12)
+/* Align pitches to 128 bytes */
+#define RCAR_DU_QUIRK_ALIGN_128B	BIT(0)
+/* LVDS lanes 1 and 3 inverted */
+#define RCAR_DU_QUIRK_LVDS_LANES	BIT(1)
 
 /*
  * struct rcar_du_output_routing - Output routing specification
@@ -61,6 +72,7 @@ struct rcar_du_device_info {
 	unsigned int features;
 	unsigned int quirks;
 	unsigned int channels_mask;
+	unsigned int num_crtcs;
 	struct rcar_du_output_routing routes[RCAR_DU_OUTPUT_MAX];
 	unsigned int num_lvds;
 	unsigned int dpll_ch;
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_group.c b/drivers/gpu/drm/rcar-du/rcar_du_group.c
index d539cb2..83a2836 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_group.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_group.c
@@ -130,6 +130,11 @@ static void rcar_du_group_setup(struct rcar_du_group *rgrp)
 	if (rcdu->info->gen >= 3)
 		rcar_du_group_write(rgrp, DEFR10, DEFR10_CODE | DEFR10_DEFE10);
 
+	if (rcar_du_has(rgrp->dev, RCAR_DU_FEATURE_CMM)) {
+		rcar_du_group_write(rgrp, DEF7R, DEF7R_CODE |
+				    DEF7R_CMME1 | DEF7R_CMME0);
+	}
+
 	/*
 	 * Use DS1PR and DS2PR to configure planes priorities and connects the
 	 * superposition 0 to DU0 pins. DU1 pins will be configured dynamically.
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_regs.h b/drivers/gpu/drm/rcar-du/rcar_du_regs.h
index 9dfd220..b20e783 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_regs.h
+++ b/drivers/gpu/drm/rcar-du/rcar_du_regs.h
@@ -200,6 +200,11 @@
 #define DEFR6_MLOS1		(1 << 2)
 #define DEFR6_DEFAULT		(DEFR6_CODE | DEFR6_TCNE1)
 
+#define DEF7R			0x000ec
+#define DEF7R_CODE		(0x7779 << 16)
+#define DEF7R_CMME1		BIT(6)
+#define DEF7R_CMME0		BIT(4)
+
 /* -----------------------------------------------------------------------------
  * R8A7790-only Control Registers
  */
@@ -552,4 +557,91 @@
 #define GCBCR			0x11098
 #define BCBCR			0x1109c
 
+/* -----------------------------------------------------------------------------
+ * DU Color Management Module Registers
+ */
+
+#define CMM_LUT_CTRL			0x0000
+#define CMM_LUT_CTRL_EN			BIT(0)
+
+#define CMM_CLU_CTRL			0x0100
+#define CMM_CLU_CTRL_EN			BIT(0)
+#define CMM_CLU_CTRL_MVS		BIT(24)
+#define CMM_CLU_CTRL_AAI		BIT(28)
+
+#define CMM_CTL0			0x0180
+#define CM2_CTL0			CMM_CTL0
+#define CMM_CTL0_CLUDB			BIT(24)
+#define CMM_CTL0_HISTS			BIT(20)
+#define CMM_CTL0_TM1_MASK		(3 << 16)
+#define CMM_CTL0_TM1_BT601_YC240	(0 << 16)
+#define CMM_CTL0_TM1_BT601_YC255	BIT(16)
+#define CMM_CTL0_TM1_BT709_RG255	(2 << 16)
+#define CMM_CTL0_TM1_BT709_RG235	(3 << 16)
+#define CMM_CTL0_TM0_MASK		(3 << 12)
+#define CMM_CTL0_TM0_BT601_YC240	(0 << 12)
+#define CMM_CTL0_TM0_BT601_YC255	BIT(12)
+#define CMM_CTL0_TM0_BT709_RG255	(2 << 12)
+#define CMM_CTL0_TM0_BT709_RG235	(3 << 12)
+#define CMM_CTL0_TM_BT601_YC240		(CMM_CTL0_TM1_BT601_YC240 |\
+					 CMM_CTL0_TM0_BT601_YC240)
+#define CMM_CTL0_TM_BT601_YC255		(CMM_CTL0_TM1_BT601_YC255 |\
+					 CMM_CTL0_TM0_BT601_YC255)
+#define CMM_CTL0_TM_BT709_RG255		(CMM_CTL0_TM1_BT709_RG255 |\
+					 CMM_CTL0_TM0_BT709_RG255)
+#define CMM_CTL0_TM_BT709_RG235		(CMM_CTL0_TM1_BT709_RG235 |\
+					 CMM_CTL0_TM0_BT709_RG235)
+#define CMM_CTL0_YC			BIT(8)
+#define CMM_CTL0_VPOL			BIT(4)
+#define CMM_CTL0_DBUF			BIT(0)
+
+#define CMM_CTL1			0x0184
+#define CM2_CTL1			CMM_CTL1
+#define CMM_CTL1_BFS			BIT(0)
+
+#define CMM_CTL2			0x0188
+#define CMM_HGO_OFFSET			0x0200
+#define CMM_HGO_SIZE			0x0204
+#define CMM_HGO_MODE			0x0208
+#define CMM_HGO_MODE_MASK		(0xFF)
+#define CMM_HGO_MODE_MAXRGB		BIT(7)
+#define CMM_HGO_MODE_OFSB_R		BIT(6)
+#define CMM_HGO_MODE_OFSB_G		BIT(5)
+#define CMM_HGO_MODE_OFSB_B		BIT(4)
+#define CMM_HGO_MODE_HRATIO_NO_SKIPP		(0 << 2)
+#define CMM_HGO_MODE_HRATIO_HALF_SKIPP		BIT(2)
+#define CMM_HGO_MODE_HRATIO_QUARTER_SKIPP	(2 << 2)
+#define CMM_HGO_MODE_VRATIO_NO_SKIPP		(0 << 0)
+#define CMM_HGO_MODE_VRATIO_HALF_SKIPP		BIT(0)
+#define CMM_HGO_MODE_VRATIO_QUARTER_SKIPP	(2 << 0)
+#define CMM_HGO_LB_TH			0x020C
+#define CMM_HGO_LB0_H			0x0210
+#define CMM_HGO_LB0_V			0x0214
+#define CMM_HGO_LB1_H			0x0218
+#define CMM_HGO_LB1_V			0x021C
+#define CMM_HGO_LB2_H			0x0220
+#define CMM_HGO_LB2_V			0x0224
+#define CMM_HGO_LB3_H			0x0228
+#define CMM_HGO_LB3_V			0x022C
+#define CMM_HGO_R_HISTO(n)		(0x0230 + ((n) * 4))
+#define CMM_HGO_R_MAXMIN		0x0330
+#define CMM_HGO_R_SUM			0x0334
+#define CMM_HGO_R_LB_DET		0x0338
+#define CMM_HGO_G_HISTO(n)		(0x0340 + ((n) * 4))
+#define CMM_HGO_G_MAXMIN		0x0440
+#define CMM_HGO_G_SUM			0x0444
+#define CMM_HGO_G_LB_DET		0x0448
+#define CMM_HGO_B_HISTO(n)		(0x0450 + ((n) * 4))
+#define CMM_HGO_B_MAXMIN		0x0550
+#define CMM_HGO_B_SUM			0x0554
+#define CMM_HGO_B_LB_DET		0x0558
+#define CMM_HGO_REGRST			0x05FC
+#define CMM_HGO_REGRST_RCLEA		BIT(0)
+#define CMM_LUT_TBLA(n)			(0x0600 + ((n) * 4))
+#define CMM_CLU_ADDR			0x0A00
+#define CMM_CLU_DATA			0x0A04
+#define CMM_LUT_TBLB(n)			(0x0B00 + ((n) * 4))
+#define CMM_CLU_ADDR2			0x0F00
+#define CMM_CLU_DATA2			0x0F04
+
 #endif /* __RCAR_DU_REGS_H__ */
diff --git a/include/drm/drm_ioctl.h b/include/drm/drm_ioctl.h
index fafb6f5..add4280 100644
--- a/include/drm/drm_ioctl.h
+++ b/include/drm/drm_ioctl.h
@@ -109,6 +109,13 @@ enum drm_ioctl_flags {
 	 */
 	DRM_ROOT_ONLY		= BIT(2),
 	/**
+	 * @DRM_CONTROL_ALLOW:
+	 *
+	 * Deprecated, do not use. Control nodes are in the process of getting
+	 * removed.
+	 */
+	DRM_CONTROL_ALLOW	= BIT(3),
+	/**
 	 * @DRM_UNLOCKED:
 	 *
 	 * Whether &drm_ioctl_desc.func should be called with the DRM BKL held
-- 
2.7.4


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

* [PATCH 1/8] drm: Add DU CMM support functions
@ 2019-04-03 13:14   ` VenkataRajesh.Kalakodima
  0 siblings, 0 replies; 36+ messages in thread
From: VenkataRajesh.Kalakodima @ 2019-04-03 13:14 UTC (permalink / raw)
  To: linux-renesas-soc, devicetree, linux-kernel, linux-clk, dri-devel
  Cc: kalakodima venkata rajesh, Koji Matsuoka, Tsutomu Muroya,
	Steve Longerbeam

From: kalakodima venkata rajesh <venkatarajesh.kalakodima@in.bosch.com>

This is the out-of-tree patch for DU CMM driver support from
Yocto release v3.4.0.

Link: https://github.com/renesas-rcar/du_cmm/commit/2d8ea2b667ad4616aa639c54ecc11f7c4b58959d.patch

Following is from the patch description:

    du_cmm: Release for Yocto v3.4.0

    This patch made the following correspondence.

      - Corresponds to kernel v 4.14.
      - Double buffer only is supported.
      - Fix CLU / LUT update timing.
      - Add CMM Channel occupation mode.
      - Fix Close process.

Signed-off-by: Koji Matsuoka <koji.matsuoka.xm@renesas.com>
Signed-off-by: Tsutomu Muroya <muroya@ksk.co.jp>
Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>

      - Removal of rcar specific ioctals
      - Resolved checkpatch errors
      - Resolved merge conflicts according to latest version
      - Included CMM drivers and included files from base patch
      - Removed rcar_du_drm.h include file

Signed-off-by: kalakodima venkata rajesh <venkatarajesh.kalakodima@in.bosch.com>
---
 drivers/gpu/drm/rcar-du/Makefile        |    2 +
 drivers/gpu/drm/rcar-du/rcar_du_cmm.c   | 1200 +++++++++++++++++++++++++++++++
 drivers/gpu/drm/rcar-du/rcar_du_crtc.c  |   24 +
 drivers/gpu/drm/rcar-du/rcar_du_crtc.h  |   16 +
 drivers/gpu/drm/rcar-du/rcar_du_drv.c   |   43 +-
 drivers/gpu/drm/rcar-du/rcar_du_drv.h   |   16 +-
 drivers/gpu/drm/rcar-du/rcar_du_group.c |    5 +
 drivers/gpu/drm/rcar-du/rcar_du_regs.h  |   92 +++
 include/drm/drm_ioctl.h                 |    7 +
 9 files changed, 1398 insertions(+), 7 deletions(-)
 create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_cmm.c

diff --git a/drivers/gpu/drm/rcar-du/Makefile b/drivers/gpu/drm/rcar-du/Makefile
index 2a3b8d7..595e719 100644
--- a/drivers/gpu/drm/rcar-du/Makefile
+++ b/drivers/gpu/drm/rcar-du/Makefile
@@ -6,12 +6,14 @@ rcar-du-drm-y := rcar_du_crtc.o \
 		 rcar_du_kms.o \
 		 rcar_du_plane.o
 
+rcar-du-drm-y += rcar_du_cmm.o
 rcar-du-drm-$(CONFIG_DRM_RCAR_LVDS)	+= rcar_du_of.o \
 					   rcar_du_of_lvds_r8a7790.dtb.o \
 					   rcar_du_of_lvds_r8a7791.dtb.o \
 					   rcar_du_of_lvds_r8a7793.dtb.o \
 					   rcar_du_of_lvds_r8a7795.dtb.o \
 					   rcar_du_of_lvds_r8a7796.dtb.o
+
 rcar-du-drm-$(CONFIG_DRM_RCAR_VSP)	+= rcar_du_vsp.o
 
 obj-$(CONFIG_DRM_RCAR_DU)		+= rcar-du-drm.o
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_cmm.c b/drivers/gpu/drm/rcar-du/rcar_du_cmm.c
new file mode 100644
index 0000000..ac613a6e
--- /dev/null
+++ b/drivers/gpu/drm/rcar-du/rcar_du_cmm.c
@@ -0,0 +1,1200 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*************************************************************************/ /*
+ * DU CMM
+ *
+ * Copyright (C) 2018 Renesas Electronics Corporation
+ *
+ * License        Dual MIT/GPLv2
+ *
+ * The contents of this file are subject to the MIT license as set out below.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * the GNU General Public License Version 2 ("GPL") in which case the provisions
+ * of GPL are applicable instead of those above.
+ *
+ * If you wish to allow use of your version of this file only under the terms of
+ * GPL, and not to allow others to use your version of this file under the terms
+ * of the MIT license, indicate your decision by deleting the provisions above
+ * and replace them with the notice and other provisions required by GPL as set
+ * out in the file called "GPL-COPYING" included in this distribution. If you do
+ * not delete the provisions above, a recipient may use your version of this
+ * file under the terms of either the MIT license or GPL.
+ *
+ * This License is also included in this distribution in the file called
+ * "MIT-COPYING".
+ *
+ * EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) THE SOFTWARE IS
+ * PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE AND NONINFRINGEMENT; AND (B) IN NO EVENT SHALL THE AUTHORS
+ * OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+ * IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ *
+ * GPLv2:
+ * If you wish to use this file under the terms of GPL, following terms are
+ * effective.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */ /*************************************************************************/
+#include <linux/syscalls.h>
+#include <linux/workqueue.h>
+
+#include <linux/reset.h>
+#include <linux/sys_soc.h>
+
+#include <drm/drmP.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_gem_cma_helper.h>
+
+#include "rcar_du_crtc.h"
+#include "rcar_du_drv.h"
+#include "rcar_du_kms.h"
+#include "rcar_du_plane.h"
+#include "rcar_du_regs.h"
+#include <linux/clk.h>
+
+/* #define DEBUG_PROCE_TIME 1 */
+
+#define CMM_LUT_NUM 256
+#define CMM_CLU_NUM (17 * 17 * 17)
+#define CMM_HGO_NUM 64
+/* rcar_du_drm.h Include */
+#define LUT_DOUBLE_BUFFER_AUTO		0
+#define LUT_DOUBLE_BUFFER_A		1
+#define LUT_DOUBLE_BUFFER_B		2
+/* DRM_RCAR_DU_CMM_WAIT_EVENT: DU-CMM done event */
+#define CMM_EVENT_CLU_DONE		BIT(0)
+#define CMM_EVENT_HGO_DONE		BIT(1)
+#define CMM_EVENT_LUT_DONE		BIT(2)
+
+#define CLU_DOUBLE_BUFFER_AUTO		0
+#define CLU_DOUBLE_BUFFER_A		1
+#define CLU_DOUBLE_BUFFER_B		2
+enum {
+	QUE_STAT_PENDING,
+	QUE_STAT_ACTIVE,
+	QUE_STAT_DONE,
+};
+
+static const struct soc_device_attribute rcar_du_cmm_r8a7795_es1[] = {
+	{ .soc_id = "r8a7795", .revision = "ES1.*" },
+	{ /* sentinel */ }
+};
+
+struct rcar_du_cmm;
+struct rcar_du_cmm_file_priv;
+
+struct rcar_du_cmm_pending_event {
+	struct list_head link;
+	struct list_head  fpriv_link;
+	unsigned int event;
+	unsigned int stat;
+	unsigned long callback_data;
+	struct drm_gem_object *gem_obj;
+	struct rcar_du_cmm *du_cmm;
+	struct rcar_du_cmm_file_priv *fpriv;
+};
+
+struct cmm_module_t {
+	struct list_head list;
+	union {
+		struct {
+			struct rcar_du_cmm_pending_event *p;
+			int buf_mode;
+			bool one_side;
+		};
+		int reset;
+	};
+};
+
+struct cmm_reg_save {
+#ifdef CONFIG_PM_SLEEP
+	wait_queue_head_t wait;
+
+	u32 *lut_table;
+	u32 *clu_table;
+#endif /* CONFIG_PM_SLEEP */
+
+	u32 cm2_ctl0;	/* CM2_CTL0 */
+	u32 hgo_offset;	/* CMM_HGO_OFFSET */
+	u32 hgo_size;	/* CMM_HGO_SIZE */
+	u32 hgo_mode;	/* CMM_HGO_MODE */
+};
+
+struct rcar_du_cmm {
+	struct rcar_du_crtc *rcrtc;
+
+	/* CMM base address */
+	void __iomem *cmm_base;
+	struct clk *clock;
+
+	struct cmm_module_t lut;
+	struct cmm_module_t clu;
+	struct cmm_module_t hgo;
+
+	struct mutex lock;	/* lock for register setting */
+	struct workqueue_struct *workqueue;
+	struct work_struct work;
+
+	struct cmm_reg_save reg_save;
+	bool active;
+	bool dbuf;
+	bool clu_dbuf;
+	bool init;
+	bool direct;
+	bool vsync;
+	bool authority;
+	pid_t pid;
+	bool soc_support;
+};
+
+struct rcar_du_cmm_file_priv {
+	wait_queue_head_t event_wait;
+	struct list_head list;
+	struct list_head active_list;
+	struct list_head *done_list;
+};
+
+static DEFINE_MUTEX(cmm_event_lock);
+static DEFINE_SPINLOCK(cmm_direct_lock);
+
+static inline void event_prev_cancel_locked(struct cmm_module_t *module);
+
+static inline u32 cmm_index(struct rcar_du_cmm *_cmm)
+{
+	struct rcar_du_device *rcdu = _cmm->rcrtc->group->dev;
+
+	if (rcar_du_has(rcdu, RCAR_DU_FEATURE_R8A77965_REGS)) {
+		if ((_cmm)->rcrtc->index == 3)
+			return 2;
+	}
+	return (_cmm)->rcrtc->index;
+}
+
+#define cmm_done_list(_cmm, _fpriv) \
+	(&((_fpriv)->done_list[cmm_index(_cmm)]))
+
+static inline u32 rcar_du_cmm_read(struct rcar_du_cmm *du_cmm, u32 reg)
+{
+	return ioread32(du_cmm->cmm_base + reg);
+}
+
+static inline void rcar_du_cmm_write(struct rcar_du_cmm *du_cmm,
+				     u32 reg, u32 data)
+{
+	iowrite32(data, du_cmm->cmm_base + reg);
+}
+
+/* create default CLU table data */
+static inline u32 index_to_clu_data(int index)
+{
+	int r, g, b;
+
+	r = index % 17;
+	index /= 17;
+	g = index % 17;
+	index /= 17;
+	b = index % 17;
+
+	r = (r << 20);
+	if (r > (255 << 16))
+		r = (255 << 16);
+	g = (g << 12);
+	if (g > (255 << 8))
+		g = (255 << 8);
+	b = (b << 4);
+	if (b > (255 << 0))
+		b = (255 << 0);
+
+	return r | g | b;
+}
+
+#ifdef DEBUG_PROCE_TIME
+static long long diff_timevals(struct timeval *start, struct timeval *end)
+{
+	return (end->tv_sec * 1000000LL + end->tv_usec) -
+		(start->tv_sec * 1000000LL + start->tv_usec);
+}
+#endif
+
+static void du_cmm_clk(struct rcar_du_cmm *du_cmm, bool on)
+{
+	if (on)
+		clk_prepare_enable(du_cmm->clock);
+	else
+		clk_disable_unprepare(du_cmm->clock);
+}
+
+int rcar_du_cmm_start_stop(struct rcar_du_crtc *rcrtc, bool on)
+{
+	struct rcar_du_cmm *du_cmm = rcrtc->cmm_handle;
+	int i;
+	u32 table_data;
+	const struct drm_display_mode *mode;
+	int w, h, x, y;
+
+	if (!du_cmm)
+		return -EINVAL;
+
+	mutex_lock(&du_cmm->lock);
+
+	if (!on) {
+		du_cmm->active = false;
+
+		rcar_du_cmm_write(du_cmm, CMM_LUT_CTRL, 0x00000000);
+		rcar_du_cmm_write(du_cmm, CMM_CLU_CTRL, 0x00000000);
+
+		du_cmm_clk(du_cmm, false);
+
+		goto end;
+	}
+
+	du_cmm_clk(du_cmm, true);
+
+	if (du_cmm->init)
+		goto init_done;
+
+	du_cmm->init = true;
+
+	mode = &du_cmm->rcrtc->crtc.mode;
+
+	x = (du_cmm->reg_save.hgo_offset >> 16) & 0xFFFF;
+	y = (du_cmm->reg_save.hgo_offset >> 0)  & 0xFFFF;
+	w = (du_cmm->reg_save.hgo_size >> 16) & 0xFFFF;
+	h = (du_cmm->reg_save.hgo_size >> 0)  & 0xFFFF;
+	if ((mode->hdisplay < (w + x)) || w == 0) {
+		x = 0;
+		w = mode->hdisplay;
+	}
+	if ((mode->vdisplay < (h + y)) || h == 0) {
+		y = 0;
+		h = mode->vdisplay;
+	}
+	du_cmm->reg_save.hgo_offset = (x << 16) | y;
+	du_cmm->reg_save.hgo_size = (w << 16) | h;
+
+	if (mode->flags & DRM_MODE_FLAG_PVSYNC)
+		du_cmm->reg_save.cm2_ctl0 |= CMM_CTL0_VPOL;
+	else
+		du_cmm->reg_save.cm2_ctl0 &= ~CMM_CTL0_VPOL;
+
+	rcar_du_cmm_write(du_cmm, CM2_CTL0, du_cmm->reg_save.cm2_ctl0);
+	rcar_du_cmm_write(du_cmm, CMM_HGO_OFFSET, du_cmm->reg_save.hgo_offset);
+	rcar_du_cmm_write(du_cmm, CMM_HGO_SIZE, du_cmm->reg_save.hgo_size);
+	rcar_du_cmm_write(du_cmm, CMM_HGO_MODE, du_cmm->reg_save.hgo_mode);
+	rcar_du_cmm_write(du_cmm, CMM_HGO_LB_TH, 0);
+	rcar_du_cmm_write(du_cmm, CMM_HGO_LB0_H, 0);
+	rcar_du_cmm_write(du_cmm, CMM_HGO_LB0_V, 0);
+	rcar_du_cmm_write(du_cmm, CMM_HGO_LB1_H, 0);
+	rcar_du_cmm_write(du_cmm, CMM_HGO_LB1_V, 0);
+	rcar_du_cmm_write(du_cmm, CMM_HGO_LB2_H, 0);
+	rcar_du_cmm_write(du_cmm, CMM_HGO_LB2_V, 0);
+	rcar_du_cmm_write(du_cmm, CMM_HGO_LB3_H, 0);
+	rcar_du_cmm_write(du_cmm, CMM_HGO_LB3_V, 0);
+
+	/* init color table */
+	for (i = 0; i < CMM_LUT_NUM; i++) {
+	#ifdef CONFIG_PM_SLEEP
+		table_data = du_cmm->reg_save.lut_table[i];
+	#else
+		table_data = ((i << 16) | (i << 8) | (i << 0));
+	#endif /* CONFIG_PM_SLEEP */
+		rcar_du_cmm_write(du_cmm, CMM_LUT_TBLA(i), table_data);
+
+		if (du_cmm->dbuf)
+			rcar_du_cmm_write(du_cmm, CMM_LUT_TBLB(i),
+					  table_data);
+	}
+
+	rcar_du_cmm_write(du_cmm, CMM_CLU_CTRL,
+			  CMM_CLU_CTRL_AAI | CMM_CLU_CTRL_MVS);
+
+	rcar_du_cmm_write(du_cmm, CMM_CLU_ADDR, 0);
+	if (du_cmm->clu_dbuf)
+		rcar_du_cmm_write(du_cmm, CMM_CLU_ADDR2, 0);
+
+	for (i = 0; i < CMM_CLU_NUM; i++) {
+	#ifdef CONFIG_PM_SLEEP
+		table_data = du_cmm->reg_save.clu_table[i];
+	#else
+		table_data = index_to_clu_data(i);
+	#endif /* CONFIG_PM_SLEEP */
+		rcar_du_cmm_write(du_cmm, CMM_CLU_DATA, table_data);
+
+		if (du_cmm->dbuf)
+			rcar_du_cmm_write(du_cmm, CMM_CLU_DATA2,
+					  table_data);
+	}
+
+init_done:
+	/* enable color table */
+	rcar_du_cmm_write(du_cmm, CMM_LUT_CTRL, CMM_LUT_CTRL_EN);
+	rcar_du_cmm_write(du_cmm, CMM_CLU_CTRL, CMM_CLU_CTRL_AAI |
+			  CMM_CLU_CTRL_MVS | CMM_CLU_CTRL_EN);
+
+	du_cmm->active = true;
+end:
+	mutex_unlock(&du_cmm->lock);
+
+	return 0;
+}
+
+#define gem_to_vaddr(gem_obj) \
+	(container_of((gem_obj), struct drm_gem_cma_object, base)->vaddr)
+
+static inline void cmm_vblank_put(struct rcar_du_cmm_pending_event *p)
+{
+	if (p->du_cmm)
+		drm_crtc_vblank_put(&p->du_cmm->rcrtc->crtc);
+}
+
+static inline void
+cmm_gem_object_unreference(struct rcar_du_cmm_pending_event *p)
+{
+	if (p->gem_obj)
+		drm_gem_object_unreference_unlocked(p->gem_obj);
+}
+
+static inline void _event_done_locked(struct rcar_du_cmm_pending_event *p)
+{
+	cmm_gem_object_unreference(p);
+
+	if (p->fpriv) {
+		p->stat = QUE_STAT_DONE;
+		list_del(&p->link); /* delete from p->fpriv->active_list */
+		list_add_tail(&p->link, cmm_done_list(p->du_cmm, p->fpriv));
+		wake_up_interruptible(&p->fpriv->event_wait);
+	} else {
+		/* link deleted by rcar_du_cmm_postclose */
+		kfree(p);
+	}
+}
+
+/* cancel from active_list (case of LUT/CLU double buffer mode) */
+static inline void event_prev_cancel_locked(struct cmm_module_t *module)
+{
+	struct rcar_du_cmm_pending_event *p = module->p;
+
+	if (!p)
+		return;
+
+	module->p = NULL;
+
+	_event_done_locked(p);
+}
+
+static inline void event_done(struct rcar_du_cmm_pending_event *p)
+{
+	/* vblank is put */
+
+	mutex_lock(&cmm_event_lock);
+
+	_event_done_locked(p);
+
+	mutex_unlock(&cmm_event_lock);
+}
+
+static inline void lc_event_done(struct cmm_module_t *module,
+				 struct rcar_du_cmm_pending_event *p,
+				 bool done)
+{
+	/* vblank is put */
+
+	mutex_lock(&cmm_event_lock);
+
+	if (!done && list_empty(&module->list))
+		module->p = p;
+	else
+		_event_done_locked(p);
+
+	mutex_unlock(&cmm_event_lock);
+}
+
+static inline struct rcar_du_cmm_pending_event *
+event_pop_locked(struct cmm_module_t *module)
+{
+	struct rcar_du_cmm_pending_event *p =
+		list_first_entry(&module->list,
+				 struct rcar_du_cmm_pending_event,
+				 link);
+
+	p->stat = QUE_STAT_ACTIVE;
+	list_del(&p->link); /* delete from du_cmm->[lut|clu|hgo].list */
+	list_add_tail(&p->link, &p->fpriv->active_list);
+	cmm_vblank_put(p);
+
+	return p;
+}
+
+struct rcar_du_cmm_work_stat {
+	union {
+		struct {
+			struct rcar_du_cmm_pending_event *p;
+			bool done;
+			bool table_copy;
+		};
+		struct {
+			struct rcar_du_cmm_pending_event *p2;
+			bool reset;
+		};
+	};
+};
+
+static inline void one_side(struct rcar_du_cmm *du_cmm,
+			    struct cmm_module_t *module,
+			    bool on)
+{
+	if (on && !module->one_side) {
+		module->one_side = true;
+		drm_crtc_vblank_get(&du_cmm->rcrtc->crtc);
+	} else if (!on && module->one_side) {
+		module->one_side = false;
+		drm_crtc_vblank_put(&du_cmm->rcrtc->crtc);
+	}
+}
+
+/* pop LUT que */
+static int lut_pop_locked(struct rcar_du_cmm *du_cmm,
+			  struct rcar_du_cmm_work_stat *stat)
+{
+	bool is_one_side = false;
+
+	stat->done = true;
+	stat->table_copy = false;
+
+	if (!list_empty(&du_cmm->lut.list)) {
+		stat->p = event_pop_locked(&du_cmm->lut);
+
+		/* prev lut table */
+		event_prev_cancel_locked(&du_cmm->lut);
+
+		if (du_cmm->lut.buf_mode == LUT_DOUBLE_BUFFER_AUTO) {
+			is_one_side = true;
+			if (list_empty(&du_cmm->lut.list))
+				stat->done = false;
+		}
+
+	} else if (du_cmm->lut.p) {
+		/* prev lut table */
+		stat->p = du_cmm->lut.p;
+		du_cmm->lut.p = NULL;
+	} else {
+		stat->done = false;
+		stat->p = NULL;
+		stat->table_copy = du_cmm->lut.one_side;
+	}
+
+	one_side(du_cmm, &du_cmm->lut, is_one_side);
+
+	return 0;
+}
+
+static int lut_table_copy(struct rcar_du_cmm *du_cmm)
+{
+	int i;
+	u32 src, dst;
+
+	if (rcar_du_cmm_read(du_cmm, CM2_CTL1) & CMM_CTL1_BFS) {
+		dst = CMM_LUT_TBLA(0);
+		src = CMM_LUT_TBLB(0);
+	} else {
+		dst = CMM_LUT_TBLB(0);
+		src = CMM_LUT_TBLA(0);
+	}
+
+	for (i = 0; i < CMM_LUT_NUM; i++) {
+		rcar_du_cmm_write(du_cmm, dst, rcar_du_cmm_read(du_cmm, src));
+		dst += 4;
+		src += 4;
+	}
+
+	return 0;
+}
+
+/* set 1D look up table */
+static int lut_set(struct rcar_du_cmm *du_cmm,
+		   struct rcar_du_cmm_work_stat *stat)
+{
+	int i;
+	u32 lut_base;
+	u32 *lut_buf;
+
+	if (!stat->p) {
+		if (stat->table_copy)
+			lut_table_copy(du_cmm);
+		return 0; /* skip */
+	}
+
+	/* set LUT */
+	switch (du_cmm->lut.buf_mode) {
+	case LUT_DOUBLE_BUFFER_A:
+		lut_base = CMM_LUT_TBLA(0);
+		break;
+
+	case LUT_DOUBLE_BUFFER_AUTO:
+		if (rcar_du_cmm_read(du_cmm, CM2_CTL1) & CMM_CTL1_BFS) {
+			lut_base = CMM_LUT_TBLA(0);
+			break;
+		}
+		lut_base = CMM_LUT_TBLB(0);
+		break;
+	case LUT_DOUBLE_BUFFER_B:
+		lut_base = CMM_LUT_TBLB(0);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	lut_buf = gem_to_vaddr(stat->p->gem_obj);
+	for (i = 0; i < CMM_LUT_NUM; i++)
+		rcar_du_cmm_write(du_cmm, lut_base + i * 4, lut_buf[i]);
+
+	lc_event_done(&du_cmm->lut, stat->p, stat->done);
+
+	return 0;
+}
+
+/* pop CLU que */
+static int clu_pop_locked(struct rcar_du_cmm *du_cmm,
+			  struct rcar_du_cmm_work_stat *stat)
+{
+	bool is_one_side = false;
+
+	stat->done = true;
+	stat->table_copy = false;
+
+	if (!list_empty(&du_cmm->clu.list)) {
+		stat->p = event_pop_locked(&du_cmm->clu);
+
+		/* prev clu table */
+		event_prev_cancel_locked(&du_cmm->clu);
+
+		if (du_cmm->clu.buf_mode == CLU_DOUBLE_BUFFER_AUTO) {
+			is_one_side = true;
+			if (list_empty(&du_cmm->clu.list))
+				stat->done = false;
+		}
+
+	} else if (du_cmm->clu.p) {
+		/* prev clu table */
+		stat->p = du_cmm->clu.p;
+		du_cmm->clu.p = NULL;
+	} else {
+		stat->done = false;
+		stat->p = NULL;
+		stat->table_copy = du_cmm->clu.one_side;
+	}
+
+	one_side(du_cmm, &du_cmm->clu, is_one_side);
+
+	return 0;
+}
+
+static int clu_table_copy(struct rcar_du_cmm *du_cmm)
+{
+	int i, j, k;
+	u32 src_addr, src_data, dst_addr, dst_data;
+
+	if (rcar_du_cmm_read(du_cmm, CM2_CTL1) & CMM_CTL1_BFS) {
+		dst_addr = CMM_CLU_ADDR;
+		dst_data = CMM_CLU_DATA;
+		src_addr = CMM_CLU_ADDR2;
+		src_data = CMM_CLU_DATA2;
+	} else {
+		dst_addr = CMM_CLU_ADDR2;
+		dst_data = CMM_CLU_DATA2;
+		src_addr = CMM_CLU_ADDR;
+		src_data = CMM_CLU_DATA;
+	}
+
+	rcar_du_cmm_write(du_cmm, dst_addr, 0);
+	for (i = 0; i < 17; i++) {
+		for (j = 0; j < 17; j++) {
+			for (k = 0; k < 17; k++) {
+				rcar_du_cmm_write(du_cmm, src_addr,
+						  (k << 16) | (j << 8) |
+						  (i << 0));
+				rcar_du_cmm_write(du_cmm, dst_data,
+						  rcar_du_cmm_read(du_cmm,
+								   src_data));
+			}
+		}
+	}
+
+	return 0;
+}
+
+/* set 3D look up table */
+static int clu_set(struct rcar_du_cmm *du_cmm,
+		   struct rcar_du_cmm_work_stat *stat)
+{
+	int i;
+	u32 addr_reg, data_reg;
+	u32 *clu_buf;
+
+	if (!stat->p) {
+		if (stat->table_copy)
+			clu_table_copy(du_cmm);
+		return 0; /* skip */
+	}
+
+	/* set CLU */
+	switch (du_cmm->clu.buf_mode) {
+	case CLU_DOUBLE_BUFFER_A:
+		addr_reg = CMM_CLU_ADDR;
+		data_reg = CMM_CLU_DATA;
+		break;
+
+	case CLU_DOUBLE_BUFFER_AUTO:
+		if (rcar_du_cmm_read(du_cmm, CM2_CTL1) & CMM_CTL1_BFS) {
+			addr_reg = CMM_CLU_ADDR;
+			data_reg = CMM_CLU_DATA;
+			break;
+		}
+		addr_reg = CMM_CLU_ADDR2;
+		data_reg = CMM_CLU_DATA2;
+		break;
+	case CLU_DOUBLE_BUFFER_B:
+		addr_reg = CMM_CLU_ADDR2;
+		data_reg = CMM_CLU_DATA2;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	clu_buf = gem_to_vaddr(stat->p->gem_obj);
+	rcar_du_cmm_write(du_cmm, addr_reg, 0);
+	for (i = 0; i < CMM_CLU_NUM; i++)
+		rcar_du_cmm_write(du_cmm, data_reg, clu_buf[i]);
+
+	lc_event_done(&du_cmm->clu, stat->p, stat->done);
+
+	return 0;
+}
+
+/* pop HGO que */
+static int hgo_pop_locked(struct rcar_du_cmm *du_cmm,
+			  struct rcar_du_cmm_work_stat *stat)
+{
+	struct rcar_du_cmm_pending_event *_p = NULL;
+
+	if (!list_empty(&du_cmm->hgo.list))
+		_p = event_pop_locked(&du_cmm->hgo);
+
+	if (du_cmm->hgo.reset) {
+		drm_crtc_vblank_put(&du_cmm->rcrtc->crtc);
+		du_cmm->hgo.reset = 0;
+		stat->reset = true;
+	} else {
+		stat->reset = false;
+	}
+
+	stat->p2 = _p;
+
+	return 0;
+}
+
+/* get histogram */
+static int hgo_get(struct rcar_du_cmm *du_cmm,
+		   struct rcar_du_cmm_work_stat *stat)
+{
+	int i, j;
+	const u32 histo_offset[3] = {
+		CMM_HGO_R_HISTO(0),
+		CMM_HGO_G_HISTO(0),
+		CMM_HGO_B_HISTO(0),
+	};
+	void *vaddr;
+
+	if (!stat->p2) {
+		if (stat->reset)
+			goto hgo_reset;
+
+		return 0; /* skip */
+	}
+
+	vaddr = gem_to_vaddr(stat->p2->gem_obj);
+	for (i = 0; i < 3; i++) {
+		u32 *hgo_buf = vaddr + CMM_HGO_NUM * 4 * i;
+
+		for (j = 0; j < CMM_HGO_NUM; j++)
+			hgo_buf[j] = rcar_du_cmm_read(du_cmm,
+						      histo_offset[i] + j * 4);
+	}
+
+	event_done(stat->p2);
+
+hgo_reset:
+	rcar_du_cmm_write(du_cmm, CMM_HGO_REGRST, CMM_HGO_REGRST_RCLEA);
+
+	return 0;
+}
+
+static bool du_cmm_vsync_get(struct rcar_du_cmm *du_cmm)
+{
+	unsigned long flags;
+	bool vsync;
+
+	spin_lock_irqsave(&cmm_direct_lock, flags);
+	vsync = du_cmm->vsync;
+	du_cmm->vsync = false;
+	spin_unlock_irqrestore(&cmm_direct_lock, flags);
+
+	return vsync;
+}
+
+static void du_cmm_vsync_set(struct rcar_du_cmm *du_cmm, bool vsync)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&cmm_direct_lock, flags);
+	du_cmm->vsync = vsync;
+	spin_unlock_irqrestore(&cmm_direct_lock, flags);
+}
+
+static void du_cmm_work(struct work_struct *work)
+{
+	struct rcar_du_cmm *du_cmm =
+			container_of(work, struct rcar_du_cmm, work);
+	struct rcar_du_cmm_work_stat s_lut;
+	struct rcar_du_cmm_work_stat s_clu;
+	struct rcar_du_cmm_work_stat s_hgo;
+#ifdef DEBUG_PROCE_TIME
+	struct timeval start_time, end_time;
+	unsigned long lut_time, clu_time, hgo_time;
+#endif
+	bool vsync_status = false;
+
+	memset(&s_lut, 0, sizeof(struct rcar_du_cmm_work_stat));
+	memset(&s_clu, 0, sizeof(struct rcar_du_cmm_work_stat));
+	memset(&s_hgo, 0, sizeof(struct rcar_du_cmm_work_stat));
+
+	vsync_status = du_cmm_vsync_get(du_cmm);
+
+	mutex_lock(&cmm_event_lock);
+
+	lut_pop_locked(du_cmm, &s_lut);
+	clu_pop_locked(du_cmm, &s_clu);
+	if (vsync_status)
+		hgo_pop_locked(du_cmm, &s_hgo);
+
+	mutex_unlock(&cmm_event_lock);
+
+	/* set LUT */
+#ifdef DEBUG_PROCE_TIME
+	do_gettimeofday(&start_time);
+#endif
+	lut_set(du_cmm, &s_lut);
+#ifdef DEBUG_PROCE_TIME
+	do_gettimeofday(&end_time);
+	lut_time = (long)diff_timevals(&start_time, &end_time);
+#endif
+
+	/* set CLU */
+#ifdef DEBUG_PROCE_TIME
+	do_gettimeofday(&start_time);
+#endif
+	clu_set(du_cmm, &s_clu);
+#ifdef DEBUG_PROCE_TIME
+	do_gettimeofday(&end_time);
+	clu_time = (long)diff_timevals(&start_time, &end_time);
+#endif
+
+	/* get HGO */
+#ifdef DEBUG_PROCE_TIME
+	do_gettimeofday(&start_time);
+#endif
+	if (vsync_status)
+		hgo_get(du_cmm, &s_hgo);
+#ifdef DEBUG_PROCE_TIME
+	do_gettimeofday(&end_time);
+	hgo_time = (long)diff_timevals(&start_time, &end_time);
+#endif
+
+#ifdef CONFIG_PM_SLEEP
+	wake_up_interruptible(&du_cmm->reg_save.wait);
+#endif /* CONFIG_PM_SLEEP */
+
+#ifdef DEBUG_PROCE_TIME
+	{
+		struct rcar_du_device *rcdu = du_cmm->rcrtc->group->dev;
+
+		if (s_lut.p)
+			dev_info(rcdu->dev, "LUT %ld usec.\n", lut_time);
+		if (s_clu.p)
+			dev_info(rcdu->dev, "LUT %ld usec.\n", clu_time);
+		if (s_hgo.p2)
+			dev_info(rcdu->dev, "HGO %ld usec.\n", hgo_time);
+	}
+#endif
+}
+
+static int du_cmm_que_empty(struct rcar_du_cmm *du_cmm)
+{
+	if (list_empty(&du_cmm->lut.list) && !du_cmm->lut.p &&
+	    !du_cmm->lut.one_side &&
+	    list_empty(&du_cmm->clu.list) && !du_cmm->clu.p &&
+	    !du_cmm->clu.one_side &&
+	    list_empty(&du_cmm->hgo.list) && !du_cmm->hgo.reset)
+		return 1;
+
+	return 0;
+}
+
+void rcar_du_cmm_kick(struct rcar_du_crtc *rcrtc)
+{
+	struct rcar_du_cmm *du_cmm = rcrtc->cmm_handle;
+
+	if (!du_cmm)
+		return;
+
+	if (!du_cmm->active)
+		return;
+
+	if (!du_cmm_que_empty(du_cmm)) {
+		du_cmm_vsync_set(du_cmm, true);
+		queue_work(du_cmm->workqueue, &du_cmm->work);
+	}
+}
+
+#ifdef CONFIG_PM_SLEEP
+int rcar_du_cmm_pm_suspend(struct rcar_du_crtc *rcrtc)
+{
+	struct rcar_du_cmm *du_cmm = rcrtc->cmm_handle;
+	struct rcar_du_device *rcdu = rcrtc->group->dev;
+	int i, j, k, index;
+	int ret;
+
+	if (!du_cmm)
+		return 0;
+
+	ret = wait_event_timeout(du_cmm->reg_save.wait,
+				 du_cmm_que_empty(du_cmm),
+				 msecs_to_jiffies(500));
+	if (ret == 0)
+		dev_err(rcdu->dev, "rcar-du cmm suspend : timeout\n");
+
+	if (!du_cmm->init)
+		return 0;
+
+	du_cmm->init = false;
+
+	if (!du_cmm->active)
+		du_cmm_clk(du_cmm, true);
+
+	/* table save */
+	for (i = 0; i < CMM_LUT_NUM; i++) {
+		du_cmm->reg_save.lut_table[i] =
+			rcar_du_cmm_read(du_cmm, CMM_LUT_TBLA(i));
+	}
+
+	index = 0;
+	for (i = 0; i < 17; i++) {
+		for (j = 0; j < 17; j++) {
+			for (k = 0; k < 17; k++) {
+				rcar_du_cmm_write(du_cmm, CMM_CLU_ADDR,
+						  (k << 16) | (j << 8) |
+						  (i << 0));
+				du_cmm->reg_save.clu_table[index++] =
+					rcar_du_cmm_read(du_cmm, CMM_CLU_DATA);
+			}
+		}
+	}
+
+	if (!du_cmm->active)
+		du_cmm_clk(du_cmm, false);
+
+	return 0;
+}
+
+int rcar_du_cmm_pm_resume(struct rcar_du_crtc *rcrtc)
+{
+	/* none */
+	return 0;
+}
+#endif /* CONFIG_PM_SLEEP */
+
+int rcar_du_cmm_driver_open(struct drm_device *dev, struct drm_file *file_priv)
+{
+	struct rcar_du_device *rcdu = dev->dev_private;
+	struct rcar_du_cmm_file_priv *fpriv;
+	int i;
+
+	if (!rcar_du_has(rcdu, RCAR_DU_FEATURE_CMM))
+		return 0;
+
+	file_priv->driver_priv = NULL;
+
+	fpriv = kzalloc(sizeof(*fpriv), GFP_KERNEL);
+	if (unlikely(!fpriv))
+		return -ENOMEM;
+
+	fpriv->done_list = kcalloc(rcdu->info->num_crtcs,
+				   sizeof(*fpriv->done_list),
+				   GFP_KERNEL);
+	if (unlikely(!fpriv->done_list)) {
+		kfree(fpriv);
+		return -ENOMEM;
+	}
+
+	init_waitqueue_head(&fpriv->event_wait);
+	INIT_LIST_HEAD(&fpriv->list);
+	INIT_LIST_HEAD(&fpriv->active_list);
+	for (i = 0; i < rcdu->info->num_crtcs; i++)
+		INIT_LIST_HEAD(&fpriv->done_list[i]);
+
+	file_priv->driver_priv = fpriv;
+
+	return 0;
+}
+
+void rcar_du_cmm_postclose(struct drm_device *dev, struct drm_file *file_priv)
+{
+	struct rcar_du_device *rcdu = dev->dev_private;
+	struct rcar_du_cmm_file_priv *fpriv = file_priv->driver_priv;
+	struct rcar_du_cmm_pending_event *p, *pt;
+	struct rcar_du_crtc *rcrtc;
+	struct rcar_du_cmm *du_cmm;
+	int i, crtcs_cnt, ret;
+	u32 table_data;
+
+	if (!rcar_du_has(rcdu, RCAR_DU_FEATURE_CMM))
+		return;
+
+	mutex_lock(&cmm_event_lock);
+
+	/* Unlink file priv events */
+	list_for_each_entry_safe(p, pt, &fpriv->list, fpriv_link) {
+		list_del(&p->fpriv_link);
+		list_del(&p->link);
+		switch (p->stat) {
+		case QUE_STAT_PENDING:
+			cmm_vblank_put(p);
+			cmm_gem_object_unreference(p);
+			kfree(p);
+			break;
+		case QUE_STAT_DONE:
+			kfree(p);
+			break;
+		case QUE_STAT_ACTIVE:
+			p->fpriv = NULL;
+			break;
+		}
+	}
+
+	mutex_unlock(&cmm_event_lock);
+
+	kfree(fpriv->done_list);
+	kfree(fpriv);
+	file_priv->driver_priv = NULL;
+
+	for (crtcs_cnt = 0; crtcs_cnt < rcdu->num_crtcs; crtcs_cnt++) {
+		rcrtc = &rcdu->crtcs[crtcs_cnt];
+		du_cmm = rcrtc->cmm_handle;
+		if (du_cmm->authority && du_cmm->pid == task_pid_nr(current)) {
+			du_cmm->authority = false;
+			du_cmm->pid = 0;
+			ret = wait_event_timeout(du_cmm->reg_save.wait,
+						 du_cmm_que_empty(du_cmm),
+						 msecs_to_jiffies(500));
+			if (ret == 0)
+				dev_err(rcdu->dev, "rcar-du cmm close : timeout\n");
+
+			for (i = 0; i < CMM_LUT_NUM; i++)
+				du_cmm->reg_save.lut_table[i] = (i << 16) |
+								(i << 8) |
+								(i << 0);
+
+			for (i = 0; i < CMM_CLU_NUM; i++) {
+				du_cmm->reg_save.clu_table[i] =
+							index_to_clu_data(i);
+			}
+
+			for (i = 0; i < CMM_LUT_NUM; i++) {
+#ifdef CONFIG_PM_SLEEP
+				table_data = du_cmm->reg_save.lut_table[i];
+#else
+				table_data = ((i << 16) | (i << 8) | (i << 0));
+#endif /* CONFIG_PM_SLEEP */
+				rcar_du_cmm_write(du_cmm, CMM_LUT_TBLA(i),
+						  table_data);
+				if (du_cmm->dbuf) {
+					rcar_du_cmm_write(du_cmm,
+							  CMM_LUT_TBLB(i),
+							  table_data);
+				}
+			}
+
+			for (i = 0; i < CMM_CLU_NUM; i++) {
+#ifdef CONFIG_PM_SLEEP
+				table_data = du_cmm->reg_save.clu_table[i];
+#else
+				table_data = index_to_clu_data(i);
+#endif /* CONFIG_PM_SLEEP */
+				rcar_du_cmm_write(du_cmm, CMM_CLU_DATA,
+						  table_data);
+
+				if (du_cmm->dbuf) {
+					rcar_du_cmm_write(du_cmm, CMM_CLU_DATA2,
+							  table_data);
+				}
+			}
+		}
+	}
+}
+
+int rcar_du_cmm_init(struct rcar_du_crtc *rcrtc)
+{
+	struct rcar_du_cmm *du_cmm;
+	int ret;
+	int i;
+	struct rcar_du_device *rcdu = rcrtc->group->dev;
+	char name[64];
+	struct resource *mem;
+
+	if (!rcar_du_has(rcdu, RCAR_DU_FEATURE_CMM))
+		return 0;
+
+	du_cmm = devm_kzalloc(rcdu->dev, sizeof(*du_cmm), GFP_KERNEL);
+	if (!du_cmm) {
+		ret = -ENOMEM;
+		goto error_alloc;
+	}
+
+	/* DU-CMM mapping */
+	sprintf(name, "cmm.%u", rcrtc->index);
+	mem = platform_get_resource_byname(to_platform_device(rcdu->dev),
+					   IORESOURCE_MEM, name);
+	if (!mem) {
+		dev_err(rcdu->dev, "rcar-du cmm init : failed to get memory resource\n");
+		ret = -EINVAL;
+		goto error_mapping_cmm;
+	}
+	du_cmm->cmm_base = devm_ioremap_nocache(rcdu->dev, mem->start,
+						resource_size(mem));
+	if (!du_cmm->cmm_base) {
+		dev_err(rcdu->dev, "rcar-du cmm init : failed to map iomem\n");
+		ret = -EINVAL;
+		goto error_mapping_cmm;
+	}
+	du_cmm->clock = devm_clk_get(rcdu->dev, name);
+	if (IS_ERR(du_cmm->clock)) {
+		dev_err(rcdu->dev, "failed to get clock\n");
+		ret = PTR_ERR(du_cmm->clock);
+		goto error_clock_cmm;
+	}
+
+	du_cmm->rcrtc = rcrtc;
+
+	du_cmm->reg_save.cm2_ctl0 = 0;
+	du_cmm->reg_save.hgo_offset = 0;
+	du_cmm->reg_save.hgo_size = 0;
+	du_cmm->reg_save.hgo_mode = 0;
+
+	du_cmm->dbuf = rcar_du_has(rcdu, RCAR_DU_FEATURE_CMM_LUT_DBUF);
+	if (du_cmm->dbuf) {
+		du_cmm->lut.buf_mode = LUT_DOUBLE_BUFFER_AUTO;
+		du_cmm->reg_save.cm2_ctl0 |= CMM_CTL0_DBUF;
+	} else {
+		dev_err(rcdu->dev, "single buffer is not supported.\n");
+		du_cmm->dbuf = true;
+		du_cmm->lut.buf_mode = LUT_DOUBLE_BUFFER_AUTO;
+		du_cmm->reg_save.cm2_ctl0 |= CMM_CTL0_DBUF;
+	}
+
+	du_cmm->clu_dbuf = rcar_du_has(rcdu, RCAR_DU_FEATURE_CMM_CLU_DBUF);
+	if (du_cmm->clu_dbuf) {
+		du_cmm->clu.buf_mode = CLU_DOUBLE_BUFFER_AUTO;
+		du_cmm->reg_save.cm2_ctl0 |= CMM_CTL0_CLUDB;
+	} else {
+		dev_err(rcdu->dev, "single buffer is not supported.\n");
+		du_cmm->clu_dbuf = true;
+		du_cmm->clu.buf_mode = CLU_DOUBLE_BUFFER_AUTO;
+		du_cmm->reg_save.cm2_ctl0 |= CMM_CTL0_CLUDB;
+	}
+
+#ifdef CONFIG_PM_SLEEP
+	du_cmm->reg_save.lut_table =
+		devm_kzalloc(rcdu->dev, CMM_LUT_NUM * 4, GFP_KERNEL);
+	if (!du_cmm->reg_save.lut_table) {
+		ret = -ENOMEM;
+		goto error_lut_reg_save_buf;
+	}
+	for (i = 0; i < CMM_LUT_NUM; i++)
+		du_cmm->reg_save.lut_table[i] = (i << 16) | (i << 8) | (i << 0);
+
+	du_cmm->reg_save.clu_table =
+		devm_kzalloc(rcdu->dev, CMM_CLU_NUM * 4, GFP_KERNEL);
+	if (!du_cmm->reg_save.clu_table) {
+		ret = -ENOMEM;
+		goto error_clu_reg_save_buf;
+	}
+	for (i = 0; i < CMM_CLU_NUM; i++)
+		du_cmm->reg_save.clu_table[i] = index_to_clu_data(i);
+
+	init_waitqueue_head(&du_cmm->reg_save.wait);
+#endif /* CONFIG_PM_SLEEP */
+	if (soc_device_match(rcar_du_cmm_r8a7795_es1))
+		du_cmm->soc_support = false;
+	else
+		du_cmm->soc_support = true;
+
+	du_cmm->active = false;
+	du_cmm->init = false;
+	du_cmm->direct = true;
+
+	mutex_init(&du_cmm->lock);
+	INIT_LIST_HEAD(&du_cmm->lut.list);
+	du_cmm->lut.p = NULL;
+	du_cmm->lut.one_side = false;
+	INIT_LIST_HEAD(&du_cmm->clu.list);
+	du_cmm->clu.p = NULL;
+	du_cmm->clu.one_side = false;
+	INIT_LIST_HEAD(&du_cmm->hgo.list);
+	du_cmm->hgo.reset = 0;
+
+	sprintf(name, "du-cmm%d", rcrtc->index);
+	du_cmm->workqueue = create_singlethread_workqueue(name);
+	INIT_WORK(&du_cmm->work, du_cmm_work);
+
+	rcrtc->cmm_handle = du_cmm;
+
+	dev_info(rcdu->dev, "DU%d use CMM(%s buffer)\n",
+		 rcrtc->index, du_cmm->dbuf ? "Double" : "Single");
+
+	return 0;
+
+#ifdef CONFIG_PM_SLEEP
+error_clu_reg_save_buf:
+error_lut_reg_save_buf:
+#endif /* CONFIG_PM_SLEEP */
+error_clock_cmm:
+	devm_iounmap(rcdu->dev, du_cmm->cmm_base);
+error_mapping_cmm:
+	devm_kfree(rcdu->dev, du_cmm);
+error_alloc:
+	return ret;
+}
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
index 15dc9ca..864fb94 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
@@ -296,6 +296,19 @@ static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc)
 	rcar_du_crtc_write(rcrtc, HDSR, mode->htotal - mode->hsync_start - 19);
 	rcar_du_crtc_write(rcrtc, HDER, mode->htotal - mode->hsync_start +
 					mode->hdisplay - 19);
+	if (rcar_du_has(rcrtc->group->dev, RCAR_DU_FEATURE_CMM)) {
+		rcar_du_crtc_write(rcrtc, HDSR, mode->htotal -
+						mode->hsync_start - 19 - 25);
+		rcar_du_crtc_write(rcrtc, HDER, mode->htotal -
+						mode->hsync_start +
+						mode->hdisplay - 19 - 25);
+	} else {
+		rcar_du_crtc_write(rcrtc, HDSR, mode->htotal -
+						mode->hsync_start - 19);
+		rcar_du_crtc_write(rcrtc, HDER, mode->htotal -
+						mode->hsync_start +
+						mode->hdisplay - 19);
+	}
 	rcar_du_crtc_write(rcrtc, HSWR, mode->hsync_end -
 					mode->hsync_start - 1);
 	rcar_du_crtc_write(rcrtc, HCR,  mode->htotal - 1);
@@ -530,6 +543,9 @@ static void rcar_du_crtc_start(struct rcar_du_crtc *rcrtc)
 			     DSYSR_TVM_MASTER);
 
 	rcar_du_group_start_stop(rcrtc->group, true);
+
+	if (rcar_du_has(rcrtc->group->dev, RCAR_DU_FEATURE_CMM))
+		rcar_du_cmm_start_stop(rcrtc, true);
 }
 
 static void rcar_du_crtc_disable_planes(struct rcar_du_crtc *rcrtc)
@@ -565,6 +581,9 @@ static void rcar_du_crtc_stop(struct rcar_du_crtc *rcrtc)
 {
 	struct drm_crtc *crtc = &rcrtc->crtc;
 
+	if (rcar_du_has(rcrtc->group->dev, RCAR_DU_FEATURE_CMM))
+		rcar_du_cmm_start_stop(rcrtc, false);
+
 	/*
 	 * Disable all planes and wait for the change to take effect. This is
 	 * required as the plane enable registers are updated on vblank, and no
@@ -899,6 +918,9 @@ static irqreturn_t rcar_du_crtc_irq(int irq, void *arg)
 			rcar_du_crtc_finish_page_flip(rcrtc);
 		}
 
+		if (rcar_du_has(rcrtc->group->dev, RCAR_DU_FEATURE_CMM))
+			rcar_du_cmm_kick(rcrtc);
+
 		ret = IRQ_HANDLED;
 	}
 
@@ -999,5 +1021,7 @@ int rcar_du_crtc_create(struct rcar_du_group *rgrp, unsigned int swindex,
 		return ret;
 	}
 
+	rcar_du_cmm_init(rcrtc);
+
 	return 0;
 }
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
index 7680cb2..74e0a22 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
+++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
@@ -67,6 +67,10 @@ struct rcar_du_crtc {
 	struct rcar_du_group *group;
 	struct rcar_du_vsp *vsp;
 	unsigned int vsp_pipe;
+	int lvds_ch;
+
+	void *cmm_handle;
+
 };
 
 #define to_rcar_crtc(c)	container_of(c, struct rcar_du_crtc, crtc)
@@ -104,4 +108,16 @@ void rcar_du_crtc_route_output(struct drm_crtc *crtc,
 			       enum rcar_du_output output);
 void rcar_du_crtc_finish_page_flip(struct rcar_du_crtc *rcrtc);
 
+/* DU-CMM functions */
+int rcar_du_cmm_init(struct rcar_du_crtc *rcrtc);
+int rcar_du_cmm_driver_open(struct drm_device *dev, struct drm_file *file_priv);
+void rcar_du_cmm_postclose(struct drm_device *dev, struct drm_file *file_priv);
+int rcar_du_cmm_start_stop(struct rcar_du_crtc *rcrtc, bool on);
+void rcar_du_cmm_kick(struct rcar_du_crtc *rcrtc);
+
+#ifdef CONFIG_PM_SLEEP
+int rcar_du_cmm_pm_suspend(struct rcar_du_crtc *rcrtc);
+int rcar_du_cmm_pm_resume(struct rcar_du_crtc *rcrtc);
+#endif /* CONFIG_PM_SLEEP */
+
 #endif /* __RCAR_DU_CRTC_H__ */
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
index 02aee6c..838b7c9 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
@@ -26,8 +26,8 @@
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_fb_cma_helper.h>
 #include <drm/drm_gem_cma_helper.h>
-
 #include "rcar_du_drv.h"
+#include "rcar_du_encoder.h"
 #include "rcar_du_kms.h"
 #include "rcar_du_of.h"
 #include "rcar_du_regs.h"
@@ -128,7 +128,9 @@ static const struct rcar_du_device_info rcar_du_r8a7790_info = {
 static const struct rcar_du_device_info rcar_du_r8a7791_info = {
 	.gen = 2,
 	.features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
-		  | RCAR_DU_FEATURE_EXT_CTRL_REGS,
+		  | RCAR_DU_FEATURE_EXT_CTRL_REGS
+		  | RCAR_DU_FEATURE_CMM,
+	.num_crtcs = 2,
 	.channels_mask = BIT(1) | BIT(0),
 	.routes = {
 		/*
@@ -190,7 +192,10 @@ static const struct rcar_du_device_info rcar_du_r8a7795_info = {
 	.gen = 3,
 	.features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
 		  | RCAR_DU_FEATURE_EXT_CTRL_REGS
-		  | RCAR_DU_FEATURE_VSP1_SOURCE,
+		  | RCAR_DU_FEATURE_VSP1_SOURCE
+		  | RCAR_DU_FEATURE_CMM | RCAR_DU_FEATURE_CMM_LUT_DBUF
+		  | RCAR_DU_FEATURE_CMM_CLU_DBUF,
+	.num_crtcs = 4,
 	.channels_mask = BIT(3) | BIT(2) | BIT(1) | BIT(0),
 	.routes = {
 		/*
@@ -222,7 +227,10 @@ static const struct rcar_du_device_info rcar_du_r8a7796_info = {
 	.gen = 3,
 	.features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
 		  | RCAR_DU_FEATURE_EXT_CTRL_REGS
-		  | RCAR_DU_FEATURE_VSP1_SOURCE,
+		  | RCAR_DU_FEATURE_VSP1_SOURCE
+		  | RCAR_DU_FEATURE_CMM | RCAR_DU_FEATURE_CMM_LUT_DBUF
+		  | RCAR_DU_FEATURE_CMM_CLU_DBUF,
+	.num_crtcs = 3,
 	.channels_mask = BIT(2) | BIT(1) | BIT(0),
 	.routes = {
 		/*
@@ -250,7 +258,11 @@ static const struct rcar_du_device_info rcar_du_r8a77965_info = {
 	.gen = 3,
 	.features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
 		  | RCAR_DU_FEATURE_EXT_CTRL_REGS
-		  | RCAR_DU_FEATURE_VSP1_SOURCE,
+		  | RCAR_DU_FEATURE_VSP1_SOURCE
+		  | RCAR_DU_FEATURE_R8A77965_REGS
+		  | RCAR_DU_FEATURE_CMM | RCAR_DU_FEATURE_CMM_LUT_DBUF
+		  | RCAR_DU_FEATURE_CMM_CLU_DBUF,
+	.num_crtcs = 3,
 	.channels_mask = BIT(3) | BIT(1) | BIT(0),
 	.routes = {
 		/*
@@ -328,6 +340,8 @@ DEFINE_DRM_GEM_CMA_FOPS(rcar_du_fops);
 static struct drm_driver rcar_du_driver = {
 	.driver_features	= DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME
 				| DRIVER_ATOMIC,
+	.open			= rcar_du_cmm_driver_open,
+	.postclose		= rcar_du_cmm_postclose,
 	.lastclose		= rcar_du_lastclose,
 	.gem_free_object_unlocked = drm_gem_cma_free_object,
 	.gem_vm_ops		= &drm_gem_cma_vm_ops,
@@ -358,6 +372,12 @@ static int rcar_du_pm_suspend(struct device *dev)
 {
 	struct rcar_du_device *rcdu = dev_get_drvdata(dev);
 	struct drm_atomic_state *state;
+	int i;
+
+	if (rcar_du_has(rcdu, RCAR_DU_FEATURE_CMM)) {
+		for (i = 0; i < rcdu->num_crtcs; ++i)
+			rcar_du_cmm_pm_suspend(&rcdu->crtcs[i]);
+	}
 
 	drm_kms_helper_poll_disable(rcdu->ddev);
 	drm_fbdev_cma_set_suspend_unlocked(rcdu->fbdev, true);
@@ -377,7 +397,20 @@ static int rcar_du_pm_suspend(struct device *dev)
 static int rcar_du_pm_resume(struct device *dev)
 {
 	struct rcar_du_device *rcdu = dev_get_drvdata(dev);
+#if IS_ENABLED(CONFIG_DRM_RCAR_DW_HDMI)
+	struct drm_encoder *encoder;
+	int i;
+
+	if (rcar_du_has(rcdu, RCAR_DU_FEATURE_CMM)) {
+		for (i = 0; (i < rcdu->num_crtcs); ++i)
+			rcar_du_cmm_pm_resume(&rcdu->crtcs[i]);
+	}
 
+	list_for_each_entry(encoder, &rcdu->ddev->mode_config.encoder_list,
+			    head) {
+		to_rcar_encoder(encoder);
+	}
+#endif
 	drm_atomic_helper_resume(rcdu->ddev, rcdu->suspend_state);
 	drm_fbdev_cma_set_suspend_unlocked(rcdu->fbdev, false);
 	drm_kms_helper_poll_enable(rcdu->ddev);
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.h b/drivers/gpu/drm/rcar-du/rcar_du_drv.h
index b3a25e8..f2afe36 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_drv.h
+++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.h
@@ -30,8 +30,19 @@ struct rcar_du_device;
 #define RCAR_DU_FEATURE_CRTC_IRQ_CLOCK	(1 << 0)	/* Per-CRTC IRQ and clock */
 #define RCAR_DU_FEATURE_EXT_CTRL_REGS	(1 << 1)	/* Has extended control registers */
 #define RCAR_DU_FEATURE_VSP1_SOURCE	(1 << 2)	/* Has inputs from VSP1 */
-
-#define RCAR_DU_QUIRK_ALIGN_128B	(1 << 0)	/* Align pitches to 128 bytes */
+/* Use R8A77965 registers */
+#define RCAR_DU_FEATURE_R8A77965_REGS	BIT(3)
+
+/* Has DEF7R register & CMM */
+#define RCAR_DU_FEATURE_CMM		BIT(10)
+/* Has CMM LUT Double buffer */
+#define RCAR_DU_FEATURE_CMM_LUT_DBUF	BIT(11)
+/* Has CMM CLU Double buffer */
+#define RCAR_DU_FEATURE_CMM_CLU_DBUF	BIT(12)
+/* Align pitches to 128 bytes */
+#define RCAR_DU_QUIRK_ALIGN_128B	BIT(0)
+/* LVDS lanes 1 and 3 inverted */
+#define RCAR_DU_QUIRK_LVDS_LANES	BIT(1)
 
 /*
  * struct rcar_du_output_routing - Output routing specification
@@ -61,6 +72,7 @@ struct rcar_du_device_info {
 	unsigned int features;
 	unsigned int quirks;
 	unsigned int channels_mask;
+	unsigned int num_crtcs;
 	struct rcar_du_output_routing routes[RCAR_DU_OUTPUT_MAX];
 	unsigned int num_lvds;
 	unsigned int dpll_ch;
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_group.c b/drivers/gpu/drm/rcar-du/rcar_du_group.c
index d539cb2..83a2836 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_group.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_group.c
@@ -130,6 +130,11 @@ static void rcar_du_group_setup(struct rcar_du_group *rgrp)
 	if (rcdu->info->gen >= 3)
 		rcar_du_group_write(rgrp, DEFR10, DEFR10_CODE | DEFR10_DEFE10);
 
+	if (rcar_du_has(rgrp->dev, RCAR_DU_FEATURE_CMM)) {
+		rcar_du_group_write(rgrp, DEF7R, DEF7R_CODE |
+				    DEF7R_CMME1 | DEF7R_CMME0);
+	}
+
 	/*
 	 * Use DS1PR and DS2PR to configure planes priorities and connects the
 	 * superposition 0 to DU0 pins. DU1 pins will be configured dynamically.
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_regs.h b/drivers/gpu/drm/rcar-du/rcar_du_regs.h
index 9dfd220..b20e783 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_regs.h
+++ b/drivers/gpu/drm/rcar-du/rcar_du_regs.h
@@ -200,6 +200,11 @@
 #define DEFR6_MLOS1		(1 << 2)
 #define DEFR6_DEFAULT		(DEFR6_CODE | DEFR6_TCNE1)
 
+#define DEF7R			0x000ec
+#define DEF7R_CODE		(0x7779 << 16)
+#define DEF7R_CMME1		BIT(6)
+#define DEF7R_CMME0		BIT(4)
+
 /* -----------------------------------------------------------------------------
  * R8A7790-only Control Registers
  */
@@ -552,4 +557,91 @@
 #define GCBCR			0x11098
 #define BCBCR			0x1109c
 
+/* -----------------------------------------------------------------------------
+ * DU Color Management Module Registers
+ */
+
+#define CMM_LUT_CTRL			0x0000
+#define CMM_LUT_CTRL_EN			BIT(0)
+
+#define CMM_CLU_CTRL			0x0100
+#define CMM_CLU_CTRL_EN			BIT(0)
+#define CMM_CLU_CTRL_MVS		BIT(24)
+#define CMM_CLU_CTRL_AAI		BIT(28)
+
+#define CMM_CTL0			0x0180
+#define CM2_CTL0			CMM_CTL0
+#define CMM_CTL0_CLUDB			BIT(24)
+#define CMM_CTL0_HISTS			BIT(20)
+#define CMM_CTL0_TM1_MASK		(3 << 16)
+#define CMM_CTL0_TM1_BT601_YC240	(0 << 16)
+#define CMM_CTL0_TM1_BT601_YC255	BIT(16)
+#define CMM_CTL0_TM1_BT709_RG255	(2 << 16)
+#define CMM_CTL0_TM1_BT709_RG235	(3 << 16)
+#define CMM_CTL0_TM0_MASK		(3 << 12)
+#define CMM_CTL0_TM0_BT601_YC240	(0 << 12)
+#define CMM_CTL0_TM0_BT601_YC255	BIT(12)
+#define CMM_CTL0_TM0_BT709_RG255	(2 << 12)
+#define CMM_CTL0_TM0_BT709_RG235	(3 << 12)
+#define CMM_CTL0_TM_BT601_YC240		(CMM_CTL0_TM1_BT601_YC240 |\
+					 CMM_CTL0_TM0_BT601_YC240)
+#define CMM_CTL0_TM_BT601_YC255		(CMM_CTL0_TM1_BT601_YC255 |\
+					 CMM_CTL0_TM0_BT601_YC255)
+#define CMM_CTL0_TM_BT709_RG255		(CMM_CTL0_TM1_BT709_RG255 |\
+					 CMM_CTL0_TM0_BT709_RG255)
+#define CMM_CTL0_TM_BT709_RG235		(CMM_CTL0_TM1_BT709_RG235 |\
+					 CMM_CTL0_TM0_BT709_RG235)
+#define CMM_CTL0_YC			BIT(8)
+#define CMM_CTL0_VPOL			BIT(4)
+#define CMM_CTL0_DBUF			BIT(0)
+
+#define CMM_CTL1			0x0184
+#define CM2_CTL1			CMM_CTL1
+#define CMM_CTL1_BFS			BIT(0)
+
+#define CMM_CTL2			0x0188
+#define CMM_HGO_OFFSET			0x0200
+#define CMM_HGO_SIZE			0x0204
+#define CMM_HGO_MODE			0x0208
+#define CMM_HGO_MODE_MASK		(0xFF)
+#define CMM_HGO_MODE_MAXRGB		BIT(7)
+#define CMM_HGO_MODE_OFSB_R		BIT(6)
+#define CMM_HGO_MODE_OFSB_G		BIT(5)
+#define CMM_HGO_MODE_OFSB_B		BIT(4)
+#define CMM_HGO_MODE_HRATIO_NO_SKIPP		(0 << 2)
+#define CMM_HGO_MODE_HRATIO_HALF_SKIPP		BIT(2)
+#define CMM_HGO_MODE_HRATIO_QUARTER_SKIPP	(2 << 2)
+#define CMM_HGO_MODE_VRATIO_NO_SKIPP		(0 << 0)
+#define CMM_HGO_MODE_VRATIO_HALF_SKIPP		BIT(0)
+#define CMM_HGO_MODE_VRATIO_QUARTER_SKIPP	(2 << 0)
+#define CMM_HGO_LB_TH			0x020C
+#define CMM_HGO_LB0_H			0x0210
+#define CMM_HGO_LB0_V			0x0214
+#define CMM_HGO_LB1_H			0x0218
+#define CMM_HGO_LB1_V			0x021C
+#define CMM_HGO_LB2_H			0x0220
+#define CMM_HGO_LB2_V			0x0224
+#define CMM_HGO_LB3_H			0x0228
+#define CMM_HGO_LB3_V			0x022C
+#define CMM_HGO_R_HISTO(n)		(0x0230 + ((n) * 4))
+#define CMM_HGO_R_MAXMIN		0x0330
+#define CMM_HGO_R_SUM			0x0334
+#define CMM_HGO_R_LB_DET		0x0338
+#define CMM_HGO_G_HISTO(n)		(0x0340 + ((n) * 4))
+#define CMM_HGO_G_MAXMIN		0x0440
+#define CMM_HGO_G_SUM			0x0444
+#define CMM_HGO_G_LB_DET		0x0448
+#define CMM_HGO_B_HISTO(n)		(0x0450 + ((n) * 4))
+#define CMM_HGO_B_MAXMIN		0x0550
+#define CMM_HGO_B_SUM			0x0554
+#define CMM_HGO_B_LB_DET		0x0558
+#define CMM_HGO_REGRST			0x05FC
+#define CMM_HGO_REGRST_RCLEA		BIT(0)
+#define CMM_LUT_TBLA(n)			(0x0600 + ((n) * 4))
+#define CMM_CLU_ADDR			0x0A00
+#define CMM_CLU_DATA			0x0A04
+#define CMM_LUT_TBLB(n)			(0x0B00 + ((n) * 4))
+#define CMM_CLU_ADDR2			0x0F00
+#define CMM_CLU_DATA2			0x0F04
+
 #endif /* __RCAR_DU_REGS_H__ */
diff --git a/include/drm/drm_ioctl.h b/include/drm/drm_ioctl.h
index fafb6f5..add4280 100644
--- a/include/drm/drm_ioctl.h
+++ b/include/drm/drm_ioctl.h
@@ -109,6 +109,13 @@ enum drm_ioctl_flags {
 	 */
 	DRM_ROOT_ONLY		= BIT(2),
 	/**
+	 * @DRM_CONTROL_ALLOW:
+	 *
+	 * Deprecated, do not use. Control nodes are in the process of getting
+	 * removed.
+	 */
+	DRM_CONTROL_ALLOW	= BIT(3),
+	/**
 	 * @DRM_UNLOCKED:
 	 *
 	 * Whether &drm_ioctl_desc.func should be called with the DRM BKL held
-- 
2.7.4

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

* [PATCH 2/8] drm: Add DU CMM support boot and clk changes
  2019-04-03 13:14 ` VenkataRajesh.Kalakodima
@ 2019-04-03 13:14   ` VenkataRajesh.Kalakodima
  -1 siblings, 0 replies; 36+ messages in thread
From: VenkataRajesh.Kalakodima @ 2019-04-03 13:14 UTC (permalink / raw)
  To: linux-renesas-soc, devicetree, linux-kernel, linux-clk, dri-devel
  Cc: kalakodima venkata rajesh, Koji Matsuoka, Tsutomu Muroya,
	Steve Longerbeam

From: kalakodima venkata rajesh <venkatarajesh.kalakodima@in.bosch.com>

This is the out-of-tree patch for DU CMM driver support from
Yocto release v3.4.0.

Link: https://github.com/renesas-rcar/du_cmm/commit/2d8ea2b667ad4616aa639c54ecc11f7c4b58959d.patch

Following is from the patch description:

    du_cmm: Release for Yocto v3.4.0

    This patch made the following correspondence.

      - Corresponds to kernel v 4.14.
      - Double buffer only is supported.
      - Fix CLU / LUT update timing.
      - Add CMM Channel occupation mode.
      - Fix Close process.

Signed-off-by: Koji Matsuoka <koji.matsuoka.xm@renesas.com>
Signed-off-by: Tsutomu Muroya <muroya@ksk.co.jp>
Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>

      - Resolved checkpatch errors
      - Resolved merge conflicts according to latest version
      - In patch included boot and clock files from base patch

Signed-off-by: kalakodima venkata rajesh <venkatarajesh.kalakodima@in.bosch.com>
---
 .../boot/dts/renesas/r8a7795-es1-salvator-x.dts    |   5 +
 arch/arm64/boot/dts/renesas/r8a7795-salvator-x.dts |   5 +
 .../arm64/boot/dts/renesas/r8a7795-salvator-xs.dts |   5 +
 arch/arm64/boot/dts/renesas/r8a7795.dtsi           |  29 +++++-
 arch/arm64/boot/dts/renesas/r8a7796-salvator-x.dts |   6 +-
 .../arm64/boot/dts/renesas/r8a7796-salvator-xs.dts |   4 +
 arch/arm64/boot/dts/renesas/r8a7796.dtsi           |  25 ++++-
 .../arm64/boot/dts/renesas/r8a77965-salvator-x.dts |   7 +-
 .../boot/dts/renesas/r8a77965-salvator-xs.dts      |   7 +-
 arch/arm64/boot/dts/renesas/r8a77965.dtsi          |  27 +++++-
 drivers/clk/renesas/r8a7795-cpg-mssr.c             |   4 +
 drivers/clk/renesas/r8a7796-cpg-mssr.c             |   3 +
 drivers/clk/renesas/r8a77965-cpg-mssr.c            | 106 ++++++++++++++++++++-
 13 files changed, 217 insertions(+), 16 deletions(-)

diff --git a/arch/arm64/boot/dts/renesas/r8a7795-es1-salvator-x.dts b/arch/arm64/boot/dts/renesas/r8a7795-es1-salvator-x.dts
index 6b5fa91..45c1f8a 100644
--- a/arch/arm64/boot/dts/renesas/r8a7795-es1-salvator-x.dts
+++ b/arch/arm64/boot/dts/renesas/r8a7795-es1-salvator-x.dts
@@ -41,11 +41,16 @@
 		 <&cpg CPG_MOD 722>,
 		 <&cpg CPG_MOD 721>,
 		 <&cpg CPG_MOD 727>,
+		 <&cpg CPG_MOD 711>,
+		 <&cpg CPG_MOD 710>,
+		 <&cpg CPG_MOD 709>,
+		 <&cpg CPG_MOD 708>,
 		 <&versaclock5 1>,
 		 <&x21_clk>,
 		 <&x22_clk>,
 		 <&versaclock5 2>;
 	clock-names = "du.0", "du.1", "du.2", "du.3", "lvds.0",
+		      "cmm.0", "cmm.1", "cmm.2", "cmm.3",
 		      "dclkin.0", "dclkin.1", "dclkin.2", "dclkin.3";
 };
 
diff --git a/arch/arm64/boot/dts/renesas/r8a7795-salvator-x.dts b/arch/arm64/boot/dts/renesas/r8a7795-salvator-x.dts
index 446822f..67b64e7 100644
--- a/arch/arm64/boot/dts/renesas/r8a7795-salvator-x.dts
+++ b/arch/arm64/boot/dts/renesas/r8a7795-salvator-x.dts
@@ -41,11 +41,16 @@
 		 <&cpg CPG_MOD 722>,
 		 <&cpg CPG_MOD 721>,
 		 <&cpg CPG_MOD 727>,
+		 <&cpg CPG_MOD 711>,
+		 <&cpg CPG_MOD 710>,
+		 <&cpg CPG_MOD 709>,
+		 <&cpg CPG_MOD 708>,
 		 <&versaclock5 1>,
 		 <&x21_clk>,
 		 <&x22_clk>,
 		 <&versaclock5 2>;
 	clock-names = "du.0", "du.1", "du.2", "du.3", "lvds.0",
+		      "cmm.0", "cmm.1", "cmm.2", "cmm.3",
 		      "dclkin.0", "dclkin.1", "dclkin.2", "dclkin.3";
 };
 
diff --git a/arch/arm64/boot/dts/renesas/r8a7795-salvator-xs.dts b/arch/arm64/boot/dts/renesas/r8a7795-salvator-xs.dts
index 8ded64d0..adcacea 100644
--- a/arch/arm64/boot/dts/renesas/r8a7795-salvator-xs.dts
+++ b/arch/arm64/boot/dts/renesas/r8a7795-salvator-xs.dts
@@ -41,11 +41,16 @@
 		 <&cpg CPG_MOD 722>,
 		 <&cpg CPG_MOD 721>,
 		 <&cpg CPG_MOD 727>,
+		 <&cpg CPG_MOD 711>,
+		 <&cpg CPG_MOD 710>,
+		 <&cpg CPG_MOD 709>,
+		 <&cpg CPG_MOD 708>,
 		 <&versaclock6 1>,
 		 <&x21_clk>,
 		 <&x22_clk>,
 		 <&versaclock6 2>;
 	clock-names = "du.0", "du.1", "du.2", "du.3", "lvds.0",
+		      "cmm.0", "cmm.1", "cmm.2", "cmm.3",
 		      "dclkin.0", "dclkin.1", "dclkin.2", "dclkin.3";
 };
 
diff --git a/arch/arm64/boot/dts/renesas/r8a7795.dtsi b/arch/arm64/boot/dts/renesas/r8a7795.dtsi
index fb9d08a..aa5fc3c 100644
--- a/arch/arm64/boot/dts/renesas/r8a7795.dtsi
+++ b/arch/arm64/boot/dts/renesas/r8a7795.dtsi
@@ -2783,8 +2783,13 @@
 		du: display@feb00000 {
 			compatible = "renesas,du-r8a7795";
 			reg = <0 0xfeb00000 0 0x80000>,
-			      <0 0xfeb90000 0 0x14>;
-			reg-names = "du", "lvds.0";
+			      <0 0xfeb90000 0 0x14>,
+			      <0 0xfea40000 0 0x00001000>,
+			      <0 0xfea50000 0 0x00001000>,
+			      <0 0xfea60000 0 0x00001000>,
+			      <0 0xfea70000 0 0x00001000>;
+			reg-names = "du", "lvds.0",
+				    "cmm.0", "cmm.1", "cmm.2", "cmm.3";
 			interrupts = <GIC_SPI 256 IRQ_TYPE_LEVEL_HIGH>,
 				     <GIC_SPI 268 IRQ_TYPE_LEVEL_HIGH>,
 				     <GIC_SPI 269 IRQ_TYPE_LEVEL_HIGH>,
@@ -2793,8 +2798,24 @@
 				 <&cpg CPG_MOD 723>,
 				 <&cpg CPG_MOD 722>,
 				 <&cpg CPG_MOD 721>,
-				 <&cpg CPG_MOD 727>;
-			clock-names = "du.0", "du.1", "du.2", "du.3", "lvds.0";
+				 <&cpg CPG_MOD 727>,
+				 <&cpg CPG_MOD 711>,
+				 <&cpg CPG_MOD 710>,
+				 <&cpg CPG_MOD 709>,
+				 <&cpg CPG_MOD 708>;
+			clock-names = "du.0", "du.1", "du.2", "du.3", "lvds.0",
+				      "cmm.0", "cmm.1", "cmm.2", "cmm.3";
+			resets = <&cpg 724>,
+				 <&cpg 724>,
+				 <&cpg 722>,
+				 <&cpg 722>,
+				 <&cpg 727>,
+				 <&cpg 711>,
+				 <&cpg 710>,
+				 <&cpg 709>,
+				 <&cpg 708>;
+			reset-names = "du.0", "du.1", "du.2", "du.3", "lvds.0",
+				      "cmm.0", "cmm.1", "cmm.2", "cmm.3";
 			vsps = <&vspd0 0 &vspd1 0 &vspd2 0 &vspd0 1>;
 			status = "disabled";
 
diff --git a/arch/arm64/boot/dts/renesas/r8a7796-salvator-x.dts b/arch/arm64/boot/dts/renesas/r8a7796-salvator-x.dts
index 052d72a..abe24e5 100644
--- a/arch/arm64/boot/dts/renesas/r8a7796-salvator-x.dts
+++ b/arch/arm64/boot/dts/renesas/r8a7796-salvator-x.dts
@@ -30,18 +30,22 @@
 		 <&cpg CPG_MOD 723>,
 		 <&cpg CPG_MOD 722>,
 		 <&cpg CPG_MOD 727>,
+		 <&cpg CPG_MOD 711>,
+		 <&cpg CPG_MOD 710>,
+		 <&cpg CPG_MOD 709>,
 		 <&versaclock5 1>,
 		 <&x21_clk>,
 		 <&versaclock5 2>;
 	clock-names = "du.0", "du.1", "du.2", "lvds.0",
+		      "cmm.0", "cmm.1", "cmm.2",
 		      "dclkin.0", "dclkin.1", "dclkin.2";
+
 };
 
 &sound_card {
 	dais = <&rsnd_port0	/* ak4613 */
 		&rsnd_port1>;	/* HDMI0  */
 };
-
 &hdmi0 {
 	status = "okay";
 
diff --git a/arch/arm64/boot/dts/renesas/r8a7796-salvator-xs.dts b/arch/arm64/boot/dts/renesas/r8a7796-salvator-xs.dts
index 8860be6..6c3af11 100644
--- a/arch/arm64/boot/dts/renesas/r8a7796-salvator-xs.dts
+++ b/arch/arm64/boot/dts/renesas/r8a7796-salvator-xs.dts
@@ -30,10 +30,14 @@
 		 <&cpg CPG_MOD 723>,
 		 <&cpg CPG_MOD 722>,
 		 <&cpg CPG_MOD 727>,
+		 <&cpg CPG_MOD 711>,
+		 <&cpg CPG_MOD 710>,
+		 <&cpg CPG_MOD 709>,
 		 <&versaclock6 1>,
 		 <&x21_clk>,
 		 <&versaclock6 2>;
 	clock-names = "du.0", "du.1", "du.2", "lvds.0",
+		      "cmm.0", "cmm.1", "cmm.2",
 		      "dclkin.0", "dclkin.1", "dclkin.2";
 };
 
diff --git a/arch/arm64/boot/dts/renesas/r8a7796.dtsi b/arch/arm64/boot/dts/renesas/r8a7796.dtsi
index cbd35c0..729b2b6 100644
--- a/arch/arm64/boot/dts/renesas/r8a7796.dtsi
+++ b/arch/arm64/boot/dts/renesas/r8a7796.dtsi
@@ -2438,16 +2438,33 @@
 		du: display@feb00000 {
 			compatible = "renesas,du-r8a7796";
 			reg = <0 0xfeb00000 0 0x70000>,
-			      <0 0xfeb90000 0 0x14>;
-			reg-names = "du", "lvds.0";
+			      <0 0xfeb90000 0 0x14>,
+			      <0 0xfea40000 0 0x00001000>,
+			      <0 0xfea50000 0 0x00001000>,
+			      <0 0xfea60000 0 0x00001000>;
+			reg-names = "du", "lvds.0",
+				    "cmm.0", "cmm.1", "cmm.2";
 			interrupts = <GIC_SPI 256 IRQ_TYPE_LEVEL_HIGH>,
 				     <GIC_SPI 268 IRQ_TYPE_LEVEL_HIGH>,
 				     <GIC_SPI 269 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&cpg CPG_MOD 724>,
 				 <&cpg CPG_MOD 723>,
 				 <&cpg CPG_MOD 722>,
-				 <&cpg CPG_MOD 727>;
-			clock-names = "du.0", "du.1", "du.2", "lvds.0";
+				 <&cpg CPG_MOD 727>,
+				 <&cpg CPG_MOD 711>,
+				 <&cpg CPG_MOD 710>,
+				 <&cpg CPG_MOD 709>;
+			clock-names = "du.0", "du.1", "du.2", "lvds.0",
+				      "cmm.0", "cmm.1", "cmm.2";
+			resets = <&cpg 724>,
+				 <&cpg 724>,
+				 <&cpg 722>,
+				 <&cpg 727>,
+				 <&cpg 711>,
+				 <&cpg 710>,
+				 <&cpg 709>;
+			reset-names = "du.0", "du.1", "du.2", "lvds.0",
+				      "cmm.0", "cmm.1", "cmm.2";
 			status = "disabled";
 
 			vsps = <&vspd0 &vspd1 &vspd2>;
diff --git a/arch/arm64/boot/dts/renesas/r8a77965-salvator-x.dts b/arch/arm64/boot/dts/renesas/r8a77965-salvator-x.dts
index 340a3c7..20992e2 100644
--- a/arch/arm64/boot/dts/renesas/r8a77965-salvator-x.dts
+++ b/arch/arm64/boot/dts/renesas/r8a77965-salvator-x.dts
@@ -24,10 +24,15 @@
 	clocks = <&cpg CPG_MOD 724>,
 		 <&cpg CPG_MOD 723>,
 		 <&cpg CPG_MOD 721>,
+		 <&cpg CPG_MOD 727>,
+		 <&cpg CPG_MOD 711>,
+		 <&cpg CPG_MOD 710>,
+		 <&cpg CPG_MOD 708>,
 		 <&versaclock5 1>,
 		 <&x21_clk>,
 		 <&versaclock5 2>;
-	clock-names = "du.0", "du.1", "du.3",
+	clock-names = "du.0", "du.1", "du.3", "lvds.0",
+		      "cmm.0", "cmm.1", "cmm.3",
 		      "dclkin.0", "dclkin.1", "dclkin.3";
 };
 
diff --git a/arch/arm64/boot/dts/renesas/r8a77965-salvator-xs.dts b/arch/arm64/boot/dts/renesas/r8a77965-salvator-xs.dts
index 9de4e3d..eb02075 100644
--- a/arch/arm64/boot/dts/renesas/r8a77965-salvator-xs.dts
+++ b/arch/arm64/boot/dts/renesas/r8a77965-salvator-xs.dts
@@ -24,10 +24,15 @@
 	clocks = <&cpg CPG_MOD 724>,
 		 <&cpg CPG_MOD 723>,
 		 <&cpg CPG_MOD 721>,
+		 <&cpg CPG_MOD 727>,
+		 <&cpg CPG_MOD 711>,
+		 <&cpg CPG_MOD 710>,
+		 <&cpg CPG_MOD 708>,
 		 <&versaclock6 1>,
 		 <&x21_clk>,
 		 <&versaclock6 2>;
-	clock-names = "du.0", "du.1", "du.3",
+	clock-names = "du.0", "du.1", "du.3", "lvds.0",
+		      "cmm.0", "cmm.1", "cmm.3",
 		      "dclkin.0", "dclkin.1", "dclkin.3";
 };
 
diff --git a/arch/arm64/boot/dts/renesas/r8a77965.dtsi b/arch/arm64/boot/dts/renesas/r8a77965.dtsi
index 0cd4446..37382b7 100644
--- a/arch/arm64/boot/dts/renesas/r8a77965.dtsi
+++ b/arch/arm64/boot/dts/renesas/r8a77965.dtsi
@@ -1801,15 +1801,34 @@
 
 		du: display@feb00000 {
 			compatible = "renesas,du-r8a77965";
-			reg = <0 0xfeb00000 0 0x80000>;
-			reg-names = "du";
+			reg = <0 0xfeb00000 0 0x80000>,
+			      <0 0xfeb90000 0 0x14>,
+			      <0 0xfea40000 0 0x00001000>,
+			      <0 0xfea50000 0 0x00001000>,
+			      <0 0xfea70000 0 0x00001000>;
+			reg-names = "du", "lvds.0",
+				    "cmm.0", "cmm.1", "cmm.3";
 			interrupts = <GIC_SPI 256 IRQ_TYPE_LEVEL_HIGH>,
 				     <GIC_SPI 268 IRQ_TYPE_LEVEL_HIGH>,
 				     <GIC_SPI 270 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&cpg CPG_MOD 724>,
 				 <&cpg CPG_MOD 723>,
-				 <&cpg CPG_MOD 721>;
-			clock-names = "du.0", "du.1", "du.3";
+				 <&cpg CPG_MOD 721>,
+				 <&cpg CPG_MOD 727>,
+				 <&cpg CPG_MOD 711>,
+				 <&cpg CPG_MOD 710>,
+				 <&cpg CPG_MOD 708>;
+			clock-names = "du.0", "du.1", "du.3", "lvds.0",
+				      "cmm.0", "cmm.1", "cmm.3";
+			resets = <&cpg 724>,
+				 <&cpg 724>,
+				 <&cpg 722>,
+				 <&cpg 727>,
+				 <&cpg 711>,
+				 <&cpg 710>,
+				 <&cpg 708>;
+			reset-names = "du.0", "du.1", "du.3", "lvds.0",
+				      "cmm.0", "cmm.1", "cmm.3";
 			status = "disabled";
 
 			vsps = <&vspd0 0 &vspd1 0 &vspd0 1>;
diff --git a/drivers/clk/renesas/r8a7795-cpg-mssr.c b/drivers/clk/renesas/r8a7795-cpg-mssr.c
index a85dd50..ba9e595 100644
--- a/drivers/clk/renesas/r8a7795-cpg-mssr.c
+++ b/drivers/clk/renesas/r8a7795-cpg-mssr.c
@@ -201,6 +201,10 @@ static struct mssr_mod_clk r8a7795_mod_clks[] __initdata = {
 	DEF_MOD("ehci0",		 703,	R8A7795_CLK_S3D4),
 	DEF_MOD("hsusb",		 704,	R8A7795_CLK_S3D4),
 	DEF_MOD("hsusb3",		 705,	R8A7795_CLK_S3D4),
+	DEF_MOD("cmm3",			 708,	R8A7795_CLK_S2D1),
+	DEF_MOD("cmm2",			 709,	R8A7795_CLK_S2D1),
+	DEF_MOD("cmm1",			 710,	R8A7795_CLK_S2D1),
+	DEF_MOD("cmm0",			 711,	R8A7795_CLK_S2D1),
 	DEF_MOD("csi21",		 713,	R8A7795_CLK_CSI0), /* ES1.x */
 	DEF_MOD("csi20",		 714,	R8A7795_CLK_CSI0),
 	DEF_MOD("csi41",		 715,	R8A7795_CLK_CSI0),
diff --git a/drivers/clk/renesas/r8a7796-cpg-mssr.c b/drivers/clk/renesas/r8a7796-cpg-mssr.c
index dfb267a..9f01fda 100644
--- a/drivers/clk/renesas/r8a7796-cpg-mssr.c
+++ b/drivers/clk/renesas/r8a7796-cpg-mssr.c
@@ -180,6 +180,9 @@ static const struct mssr_mod_clk r8a7796_mod_clks[] __initconst = {
 	DEF_MOD("ehci1",		 702,	R8A7796_CLK_S3D4),
 	DEF_MOD("ehci0",		 703,	R8A7796_CLK_S3D4),
 	DEF_MOD("hsusb",		 704,	R8A7796_CLK_S3D4),
+	DEF_MOD("cmm2",			 709,	R8A7796_CLK_S2D1),
+	DEF_MOD("cmm1",			 710,	R8A7796_CLK_S2D1),
+	DEF_MOD("cmm0",			 711,	R8A7796_CLK_S2D1),
 	DEF_MOD("csi20",		 714,	R8A7796_CLK_CSI0),
 	DEF_MOD("csi40",		 716,	R8A7796_CLK_CSI0),
 	DEF_MOD("du2",			 722,	R8A7796_CLK_S2D1),
diff --git a/drivers/clk/renesas/r8a77965-cpg-mssr.c b/drivers/clk/renesas/r8a77965-cpg-mssr.c
index 8fae5e9..cac4570 100644
--- a/drivers/clk/renesas/r8a77965-cpg-mssr.c
+++ b/drivers/clk/renesas/r8a77965-cpg-mssr.c
@@ -123,7 +123,6 @@ static const struct mssr_mod_clk r8a77965_mod_clks[] __initconst = {
 	DEF_MOD("sys-dmac2",		217,	R8A77965_CLK_S0D3),
 	DEF_MOD("sys-dmac1",		218,	R8A77965_CLK_S0D3),
 	DEF_MOD("sys-dmac0",		219,	R8A77965_CLK_S0D3),
-
 	DEF_MOD("cmt3",			300,	R8A77965_CLK_R),
 	DEF_MOD("cmt2",			301,	R8A77965_CLK_R),
 	DEF_MOD("cmt1",			302,	R8A77965_CLK_R),
@@ -215,6 +214,111 @@ static const struct mssr_mod_clk r8a77965_mod_clks[] __initconst = {
 	DEF_MOD("i2c1",			930,	R8A77965_CLK_S3D2),
 	DEF_MOD("i2c0",			931,	R8A77965_CLK_S3D2),
 
+	DEF_MOD("3dge",			 112,	R8A77965_CLK_ZG),
+	DEF_MOD("fdp0",			 119,	R8A77965_CLK_S0D1),
+	DEF_MOD("vcplf",		 130,	R8A77965_CLK_S0D2),
+	DEF_MOD("vdpb",			 131,	R8A77965_CLK_S0D2),
+	DEF_MOD("scif5",		 202,	R8A77965_CLK_S3D4),
+	DEF_MOD("scif4",		 203,	R8A77965_CLK_S3D4),
+	DEF_MOD("scif3",		 204,	R8A77965_CLK_S3D4),
+	DEF_MOD("scif1",		 206,	R8A77965_CLK_S3D4),
+	DEF_MOD("scif0",		 207,	R8A77965_CLK_S3D4),
+	DEF_MOD("msiof3",		 208,	R8A77965_CLK_MSO),
+	DEF_MOD("msiof2",		 209,	R8A77965_CLK_MSO),
+	DEF_MOD("msiof1",		 210,	R8A77965_CLK_MSO),
+	DEF_MOD("msiof0",		 211,	R8A77965_CLK_MSO),
+	DEF_MOD("sys-dmac2",		 217,	R8A77965_CLK_S0D3),
+	DEF_MOD("sys-dmac1",		 218,	R8A77965_CLK_S0D3),
+	DEF_MOD("sys-dmac0",		 219,	R8A77965_CLK_S0D3),
+	DEF_MOD("cmt3",			 300,	R8A77965_CLK_R),
+	DEF_MOD("cmt2",			 301,	R8A77965_CLK_R),
+	DEF_MOD("cmt1",			 302,	R8A77965_CLK_R),
+	DEF_MOD("cmt0",			 303,	R8A77965_CLK_R),
+	DEF_MOD("scif2",		 310,	R8A77965_CLK_S3D4),
+	DEF_MOD("sdif3",		 311,	R8A77965_CLK_SD3),
+	DEF_MOD("sdif2",		 312,	R8A77965_CLK_SD2),
+	DEF_MOD("sdif1",		 313,	R8A77965_CLK_SD1),
+	DEF_MOD("sdif0",		 314,	R8A77965_CLK_SD0),
+	DEF_MOD("pcie1",		 318,	R8A77965_CLK_S3D1),
+	DEF_MOD("pcie0",		 319,	R8A77965_CLK_S3D1),
+	DEF_MOD("usb3-if0",		 328,	R8A77965_CLK_S3D1),
+	DEF_MOD("usb-dmac0",		 330,	R8A77965_CLK_S3D1),
+	DEF_MOD("usb-dmac1",		 331,	R8A77965_CLK_S3D1),
+	DEF_MOD("rwdt0",		 402,	R8A77965_CLK_R),
+	DEF_MOD("intc-ex",		 407,	R8A77965_CLK_CP),
+	DEF_MOD("intc-ap",		 408,	R8A77965_CLK_S3D1),
+	DEF_MOD("audmac0",		 502,	R8A77965_CLK_S3D4),
+	DEF_MOD("audmac1",		 501,	R8A77965_CLK_S3D4),
+	DEF_MOD("adsp",			 506,	R8A77965_CLK_S1D1),
+	DEF_MOD("drif7",		 508,	R8A77965_CLK_S3D2),
+	DEF_MOD("drif6",		 509,	R8A77965_CLK_S3D2),
+	DEF_MOD("drif5",		 510,	R8A77965_CLK_S3D2),
+	DEF_MOD("drif4",		 511,	R8A77965_CLK_S3D2),
+	DEF_MOD("drif3",		 512,	R8A77965_CLK_S3D2),
+	DEF_MOD("drif2",		 513,	R8A77965_CLK_S3D2),
+	DEF_MOD("drif1",		 514,	R8A77965_CLK_S3D2),
+	DEF_MOD("drif0",		 515,	R8A77965_CLK_S3D2),
+	DEF_MOD("hscif4",		 516,	R8A77965_CLK_S3D1),
+	DEF_MOD("hscif3",		 517,	R8A77965_CLK_S3D1),
+	DEF_MOD("hscif2",		 518,	R8A77965_CLK_S3D1),
+	DEF_MOD("hscif1",		 519,	R8A77965_CLK_S3D1),
+	DEF_MOD("hscif0",		 520,	R8A77965_CLK_S3D1),
+	DEF_MOD("thermal",		 522,	R8A77965_CLK_CP),
+	DEF_MOD("pwm",			 523,	R8A77965_CLK_S3D4),
+	DEF_MOD("fcpvd1",		 602,	R8A77965_CLK_S0D2),
+	DEF_MOD("fcpvd0",		 603,	R8A77965_CLK_S0D2),
+	DEF_MOD("fcpvb0",		 607,	R8A77965_CLK_S0D1),
+	DEF_MOD("fcpvi0",		 611,	R8A77965_CLK_S0D1),
+	DEF_MOD("fcpf0",		 615,	R8A77965_CLK_S0D1),
+	DEF_MOD("fcpcs",		 619,	R8A77965_CLK_S0D2),
+	DEF_MOD("vspd1",		 622,	R8A77965_CLK_S0D2),
+	DEF_MOD("vspd0",		 623,	R8A77965_CLK_S0D2),
+	DEF_MOD("vspb",			 626,	R8A77965_CLK_S0D1),
+	DEF_MOD("vspi0",		 631,	R8A77965_CLK_S0D1),
+	DEF_MOD("ehci1",		 702,	R8A77965_CLK_S3D4),
+	DEF_MOD("ehci0",		 703,	R8A77965_CLK_S3D4),
+	DEF_MOD("hsusb",		 704,	R8A77965_CLK_S3D4),
+	DEF_MOD("cmm3",			 708,	R8A77965_CLK_S2D1),
+	DEF_MOD("cmm1",			 710,	R8A77965_CLK_S2D1),
+	DEF_MOD("cmm0",			 711,	R8A77965_CLK_S2D1),
+	DEF_MOD("csi20",		 714,	R8A77965_CLK_CSI0),
+	DEF_MOD("csi40",		 716,	R8A77965_CLK_CSI0),
+	DEF_MOD("du3",			 721,	R8A77965_CLK_S2D1),
+	DEF_MOD("du1",			 723,	R8A77965_CLK_S2D1),
+	DEF_MOD("du0",			 724,	R8A77965_CLK_S2D1),
+	DEF_MOD("lvds",			 727,	R8A77965_CLK_S2D1),
+	DEF_MOD("hdmi0",		 729,	R8A77965_CLK_HDMI),
+	DEF_MOD("vin7",			 804,	R8A77965_CLK_S0D2),
+	DEF_MOD("vin6",			 805,	R8A77965_CLK_S0D2),
+	DEF_MOD("vin5",			 806,	R8A77965_CLK_S0D2),
+	DEF_MOD("vin4",			 807,	R8A77965_CLK_S0D2),
+	DEF_MOD("vin3",			 808,	R8A77965_CLK_S0D2),
+	DEF_MOD("vin2",			 809,	R8A77965_CLK_S0D2),
+	DEF_MOD("vin1",			 810,	R8A77965_CLK_S0D2),
+	DEF_MOD("vin0",			 811,	R8A77965_CLK_S0D2),
+	DEF_MOD("etheravb",		 812,	R8A77965_CLK_S0D6),
+	DEF_MOD("sata0",		 815,	R8A77965_CLK_S3D2),
+	DEF_MOD("gpio7",		 905,	R8A77965_CLK_S3D4),
+	DEF_MOD("gpio6",		 906,	R8A77965_CLK_S3D4),
+	DEF_MOD("gpio5",		 907,	R8A77965_CLK_S3D4),
+	DEF_MOD("gpio4",		 908,	R8A77965_CLK_S3D4),
+	DEF_MOD("gpio3",		 909,	R8A77965_CLK_S3D4),
+	DEF_MOD("gpio2",		 910,	R8A77965_CLK_S3D4),
+	DEF_MOD("gpio1",		 911,	R8A77965_CLK_S3D4),
+	DEF_MOD("gpio0",		 912,	R8A77965_CLK_S3D4),
+	DEF_MOD("can-fd",		 914,	R8A77965_CLK_S3D2),
+	DEF_MOD("can-if1",		 915,	R8A77965_CLK_S3D4),
+	DEF_MOD("can-if0",		 916,	R8A77965_CLK_S3D4),
+	DEF_MOD("i2c6",			 918,	R8A77965_CLK_S0D6),
+	DEF_MOD("i2c5",			 919,	R8A77965_CLK_S0D6),
+	DEF_MOD("adg",			 922,	R8A77965_CLK_S0D1),
+	DEF_MOD("i2c-dvfs",		 926,	R8A77965_CLK_CP),
+	DEF_MOD("i2c4",			 927,	R8A77965_CLK_S0D6),
+	DEF_MOD("i2c3",			 928,	R8A77965_CLK_S0D6),
+	DEF_MOD("i2c2",			 929,	R8A77965_CLK_S3D2),
+	DEF_MOD("i2c1",			 930,	R8A77965_CLK_S3D2),
+	DEF_MOD("i2c0",			 931,	R8A77965_CLK_S3D2),
+
 	DEF_MOD("ssi-all",		1005,	R8A77965_CLK_S3D4),
 	DEF_MOD("ssi9",			1006,	MOD_CLK_ID(1005)),
 	DEF_MOD("ssi8",			1007,	MOD_CLK_ID(1005)),
-- 
2.7.4


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

* [PATCH 2/8] drm: Add DU CMM support boot and clk changes
@ 2019-04-03 13:14   ` VenkataRajesh.Kalakodima
  0 siblings, 0 replies; 36+ messages in thread
From: VenkataRajesh.Kalakodima @ 2019-04-03 13:14 UTC (permalink / raw)
  To: linux-renesas-soc, devicetree, linux-kernel, linux-clk, dri-devel
  Cc: kalakodima venkata rajesh, Koji Matsuoka, Tsutomu Muroya,
	Steve Longerbeam

From: kalakodima venkata rajesh <venkatarajesh.kalakodima@in.bosch.com>

This is the out-of-tree patch for DU CMM driver support from
Yocto release v3.4.0.

Link: https://github.com/renesas-rcar/du_cmm/commit/2d8ea2b667ad4616aa639c54ecc11f7c4b58959d.patch

Following is from the patch description:

    du_cmm: Release for Yocto v3.4.0

    This patch made the following correspondence.

      - Corresponds to kernel v 4.14.
      - Double buffer only is supported.
      - Fix CLU / LUT update timing.
      - Add CMM Channel occupation mode.
      - Fix Close process.

Signed-off-by: Koji Matsuoka <koji.matsuoka.xm@renesas.com>
Signed-off-by: Tsutomu Muroya <muroya@ksk.co.jp>
Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>

      - Resolved checkpatch errors
      - Resolved merge conflicts according to latest version
      - In patch included boot and clock files from base patch

Signed-off-by: kalakodima venkata rajesh <venkatarajesh.kalakodima@in.bosch.com>
---
 .../boot/dts/renesas/r8a7795-es1-salvator-x.dts    |   5 +
 arch/arm64/boot/dts/renesas/r8a7795-salvator-x.dts |   5 +
 .../arm64/boot/dts/renesas/r8a7795-salvator-xs.dts |   5 +
 arch/arm64/boot/dts/renesas/r8a7795.dtsi           |  29 +++++-
 arch/arm64/boot/dts/renesas/r8a7796-salvator-x.dts |   6 +-
 .../arm64/boot/dts/renesas/r8a7796-salvator-xs.dts |   4 +
 arch/arm64/boot/dts/renesas/r8a7796.dtsi           |  25 ++++-
 .../arm64/boot/dts/renesas/r8a77965-salvator-x.dts |   7 +-
 .../boot/dts/renesas/r8a77965-salvator-xs.dts      |   7 +-
 arch/arm64/boot/dts/renesas/r8a77965.dtsi          |  27 +++++-
 drivers/clk/renesas/r8a7795-cpg-mssr.c             |   4 +
 drivers/clk/renesas/r8a7796-cpg-mssr.c             |   3 +
 drivers/clk/renesas/r8a77965-cpg-mssr.c            | 106 ++++++++++++++++++++-
 13 files changed, 217 insertions(+), 16 deletions(-)

diff --git a/arch/arm64/boot/dts/renesas/r8a7795-es1-salvator-x.dts b/arch/arm64/boot/dts/renesas/r8a7795-es1-salvator-x.dts
index 6b5fa91..45c1f8a 100644
--- a/arch/arm64/boot/dts/renesas/r8a7795-es1-salvator-x.dts
+++ b/arch/arm64/boot/dts/renesas/r8a7795-es1-salvator-x.dts
@@ -41,11 +41,16 @@
 		 <&cpg CPG_MOD 722>,
 		 <&cpg CPG_MOD 721>,
 		 <&cpg CPG_MOD 727>,
+		 <&cpg CPG_MOD 711>,
+		 <&cpg CPG_MOD 710>,
+		 <&cpg CPG_MOD 709>,
+		 <&cpg CPG_MOD 708>,
 		 <&versaclock5 1>,
 		 <&x21_clk>,
 		 <&x22_clk>,
 		 <&versaclock5 2>;
 	clock-names = "du.0", "du.1", "du.2", "du.3", "lvds.0",
+		      "cmm.0", "cmm.1", "cmm.2", "cmm.3",
 		      "dclkin.0", "dclkin.1", "dclkin.2", "dclkin.3";
 };
 
diff --git a/arch/arm64/boot/dts/renesas/r8a7795-salvator-x.dts b/arch/arm64/boot/dts/renesas/r8a7795-salvator-x.dts
index 446822f..67b64e7 100644
--- a/arch/arm64/boot/dts/renesas/r8a7795-salvator-x.dts
+++ b/arch/arm64/boot/dts/renesas/r8a7795-salvator-x.dts
@@ -41,11 +41,16 @@
 		 <&cpg CPG_MOD 722>,
 		 <&cpg CPG_MOD 721>,
 		 <&cpg CPG_MOD 727>,
+		 <&cpg CPG_MOD 711>,
+		 <&cpg CPG_MOD 710>,
+		 <&cpg CPG_MOD 709>,
+		 <&cpg CPG_MOD 708>,
 		 <&versaclock5 1>,
 		 <&x21_clk>,
 		 <&x22_clk>,
 		 <&versaclock5 2>;
 	clock-names = "du.0", "du.1", "du.2", "du.3", "lvds.0",
+		      "cmm.0", "cmm.1", "cmm.2", "cmm.3",
 		      "dclkin.0", "dclkin.1", "dclkin.2", "dclkin.3";
 };
 
diff --git a/arch/arm64/boot/dts/renesas/r8a7795-salvator-xs.dts b/arch/arm64/boot/dts/renesas/r8a7795-salvator-xs.dts
index 8ded64d0..adcacea 100644
--- a/arch/arm64/boot/dts/renesas/r8a7795-salvator-xs.dts
+++ b/arch/arm64/boot/dts/renesas/r8a7795-salvator-xs.dts
@@ -41,11 +41,16 @@
 		 <&cpg CPG_MOD 722>,
 		 <&cpg CPG_MOD 721>,
 		 <&cpg CPG_MOD 727>,
+		 <&cpg CPG_MOD 711>,
+		 <&cpg CPG_MOD 710>,
+		 <&cpg CPG_MOD 709>,
+		 <&cpg CPG_MOD 708>,
 		 <&versaclock6 1>,
 		 <&x21_clk>,
 		 <&x22_clk>,
 		 <&versaclock6 2>;
 	clock-names = "du.0", "du.1", "du.2", "du.3", "lvds.0",
+		      "cmm.0", "cmm.1", "cmm.2", "cmm.3",
 		      "dclkin.0", "dclkin.1", "dclkin.2", "dclkin.3";
 };
 
diff --git a/arch/arm64/boot/dts/renesas/r8a7795.dtsi b/arch/arm64/boot/dts/renesas/r8a7795.dtsi
index fb9d08a..aa5fc3c 100644
--- a/arch/arm64/boot/dts/renesas/r8a7795.dtsi
+++ b/arch/arm64/boot/dts/renesas/r8a7795.dtsi
@@ -2783,8 +2783,13 @@
 		du: display@feb00000 {
 			compatible = "renesas,du-r8a7795";
 			reg = <0 0xfeb00000 0 0x80000>,
-			      <0 0xfeb90000 0 0x14>;
-			reg-names = "du", "lvds.0";
+			      <0 0xfeb90000 0 0x14>,
+			      <0 0xfea40000 0 0x00001000>,
+			      <0 0xfea50000 0 0x00001000>,
+			      <0 0xfea60000 0 0x00001000>,
+			      <0 0xfea70000 0 0x00001000>;
+			reg-names = "du", "lvds.0",
+				    "cmm.0", "cmm.1", "cmm.2", "cmm.3";
 			interrupts = <GIC_SPI 256 IRQ_TYPE_LEVEL_HIGH>,
 				     <GIC_SPI 268 IRQ_TYPE_LEVEL_HIGH>,
 				     <GIC_SPI 269 IRQ_TYPE_LEVEL_HIGH>,
@@ -2793,8 +2798,24 @@
 				 <&cpg CPG_MOD 723>,
 				 <&cpg CPG_MOD 722>,
 				 <&cpg CPG_MOD 721>,
-				 <&cpg CPG_MOD 727>;
-			clock-names = "du.0", "du.1", "du.2", "du.3", "lvds.0";
+				 <&cpg CPG_MOD 727>,
+				 <&cpg CPG_MOD 711>,
+				 <&cpg CPG_MOD 710>,
+				 <&cpg CPG_MOD 709>,
+				 <&cpg CPG_MOD 708>;
+			clock-names = "du.0", "du.1", "du.2", "du.3", "lvds.0",
+				      "cmm.0", "cmm.1", "cmm.2", "cmm.3";
+			resets = <&cpg 724>,
+				 <&cpg 724>,
+				 <&cpg 722>,
+				 <&cpg 722>,
+				 <&cpg 727>,
+				 <&cpg 711>,
+				 <&cpg 710>,
+				 <&cpg 709>,
+				 <&cpg 708>;
+			reset-names = "du.0", "du.1", "du.2", "du.3", "lvds.0",
+				      "cmm.0", "cmm.1", "cmm.2", "cmm.3";
 			vsps = <&vspd0 0 &vspd1 0 &vspd2 0 &vspd0 1>;
 			status = "disabled";
 
diff --git a/arch/arm64/boot/dts/renesas/r8a7796-salvator-x.dts b/arch/arm64/boot/dts/renesas/r8a7796-salvator-x.dts
index 052d72a..abe24e5 100644
--- a/arch/arm64/boot/dts/renesas/r8a7796-salvator-x.dts
+++ b/arch/arm64/boot/dts/renesas/r8a7796-salvator-x.dts
@@ -30,18 +30,22 @@
 		 <&cpg CPG_MOD 723>,
 		 <&cpg CPG_MOD 722>,
 		 <&cpg CPG_MOD 727>,
+		 <&cpg CPG_MOD 711>,
+		 <&cpg CPG_MOD 710>,
+		 <&cpg CPG_MOD 709>,
 		 <&versaclock5 1>,
 		 <&x21_clk>,
 		 <&versaclock5 2>;
 	clock-names = "du.0", "du.1", "du.2", "lvds.0",
+		      "cmm.0", "cmm.1", "cmm.2",
 		      "dclkin.0", "dclkin.1", "dclkin.2";
+
 };
 
 &sound_card {
 	dais = <&rsnd_port0	/* ak4613 */
 		&rsnd_port1>;	/* HDMI0  */
 };
-
 &hdmi0 {
 	status = "okay";
 
diff --git a/arch/arm64/boot/dts/renesas/r8a7796-salvator-xs.dts b/arch/arm64/boot/dts/renesas/r8a7796-salvator-xs.dts
index 8860be6..6c3af11 100644
--- a/arch/arm64/boot/dts/renesas/r8a7796-salvator-xs.dts
+++ b/arch/arm64/boot/dts/renesas/r8a7796-salvator-xs.dts
@@ -30,10 +30,14 @@
 		 <&cpg CPG_MOD 723>,
 		 <&cpg CPG_MOD 722>,
 		 <&cpg CPG_MOD 727>,
+		 <&cpg CPG_MOD 711>,
+		 <&cpg CPG_MOD 710>,
+		 <&cpg CPG_MOD 709>,
 		 <&versaclock6 1>,
 		 <&x21_clk>,
 		 <&versaclock6 2>;
 	clock-names = "du.0", "du.1", "du.2", "lvds.0",
+		      "cmm.0", "cmm.1", "cmm.2",
 		      "dclkin.0", "dclkin.1", "dclkin.2";
 };
 
diff --git a/arch/arm64/boot/dts/renesas/r8a7796.dtsi b/arch/arm64/boot/dts/renesas/r8a7796.dtsi
index cbd35c0..729b2b6 100644
--- a/arch/arm64/boot/dts/renesas/r8a7796.dtsi
+++ b/arch/arm64/boot/dts/renesas/r8a7796.dtsi
@@ -2438,16 +2438,33 @@
 		du: display@feb00000 {
 			compatible = "renesas,du-r8a7796";
 			reg = <0 0xfeb00000 0 0x70000>,
-			      <0 0xfeb90000 0 0x14>;
-			reg-names = "du", "lvds.0";
+			      <0 0xfeb90000 0 0x14>,
+			      <0 0xfea40000 0 0x00001000>,
+			      <0 0xfea50000 0 0x00001000>,
+			      <0 0xfea60000 0 0x00001000>;
+			reg-names = "du", "lvds.0",
+				    "cmm.0", "cmm.1", "cmm.2";
 			interrupts = <GIC_SPI 256 IRQ_TYPE_LEVEL_HIGH>,
 				     <GIC_SPI 268 IRQ_TYPE_LEVEL_HIGH>,
 				     <GIC_SPI 269 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&cpg CPG_MOD 724>,
 				 <&cpg CPG_MOD 723>,
 				 <&cpg CPG_MOD 722>,
-				 <&cpg CPG_MOD 727>;
-			clock-names = "du.0", "du.1", "du.2", "lvds.0";
+				 <&cpg CPG_MOD 727>,
+				 <&cpg CPG_MOD 711>,
+				 <&cpg CPG_MOD 710>,
+				 <&cpg CPG_MOD 709>;
+			clock-names = "du.0", "du.1", "du.2", "lvds.0",
+				      "cmm.0", "cmm.1", "cmm.2";
+			resets = <&cpg 724>,
+				 <&cpg 724>,
+				 <&cpg 722>,
+				 <&cpg 727>,
+				 <&cpg 711>,
+				 <&cpg 710>,
+				 <&cpg 709>;
+			reset-names = "du.0", "du.1", "du.2", "lvds.0",
+				      "cmm.0", "cmm.1", "cmm.2";
 			status = "disabled";
 
 			vsps = <&vspd0 &vspd1 &vspd2>;
diff --git a/arch/arm64/boot/dts/renesas/r8a77965-salvator-x.dts b/arch/arm64/boot/dts/renesas/r8a77965-salvator-x.dts
index 340a3c7..20992e2 100644
--- a/arch/arm64/boot/dts/renesas/r8a77965-salvator-x.dts
+++ b/arch/arm64/boot/dts/renesas/r8a77965-salvator-x.dts
@@ -24,10 +24,15 @@
 	clocks = <&cpg CPG_MOD 724>,
 		 <&cpg CPG_MOD 723>,
 		 <&cpg CPG_MOD 721>,
+		 <&cpg CPG_MOD 727>,
+		 <&cpg CPG_MOD 711>,
+		 <&cpg CPG_MOD 710>,
+		 <&cpg CPG_MOD 708>,
 		 <&versaclock5 1>,
 		 <&x21_clk>,
 		 <&versaclock5 2>;
-	clock-names = "du.0", "du.1", "du.3",
+	clock-names = "du.0", "du.1", "du.3", "lvds.0",
+		      "cmm.0", "cmm.1", "cmm.3",
 		      "dclkin.0", "dclkin.1", "dclkin.3";
 };
 
diff --git a/arch/arm64/boot/dts/renesas/r8a77965-salvator-xs.dts b/arch/arm64/boot/dts/renesas/r8a77965-salvator-xs.dts
index 9de4e3d..eb02075 100644
--- a/arch/arm64/boot/dts/renesas/r8a77965-salvator-xs.dts
+++ b/arch/arm64/boot/dts/renesas/r8a77965-salvator-xs.dts
@@ -24,10 +24,15 @@
 	clocks = <&cpg CPG_MOD 724>,
 		 <&cpg CPG_MOD 723>,
 		 <&cpg CPG_MOD 721>,
+		 <&cpg CPG_MOD 727>,
+		 <&cpg CPG_MOD 711>,
+		 <&cpg CPG_MOD 710>,
+		 <&cpg CPG_MOD 708>,
 		 <&versaclock6 1>,
 		 <&x21_clk>,
 		 <&versaclock6 2>;
-	clock-names = "du.0", "du.1", "du.3",
+	clock-names = "du.0", "du.1", "du.3", "lvds.0",
+		      "cmm.0", "cmm.1", "cmm.3",
 		      "dclkin.0", "dclkin.1", "dclkin.3";
 };
 
diff --git a/arch/arm64/boot/dts/renesas/r8a77965.dtsi b/arch/arm64/boot/dts/renesas/r8a77965.dtsi
index 0cd4446..37382b7 100644
--- a/arch/arm64/boot/dts/renesas/r8a77965.dtsi
+++ b/arch/arm64/boot/dts/renesas/r8a77965.dtsi
@@ -1801,15 +1801,34 @@
 
 		du: display@feb00000 {
 			compatible = "renesas,du-r8a77965";
-			reg = <0 0xfeb00000 0 0x80000>;
-			reg-names = "du";
+			reg = <0 0xfeb00000 0 0x80000>,
+			      <0 0xfeb90000 0 0x14>,
+			      <0 0xfea40000 0 0x00001000>,
+			      <0 0xfea50000 0 0x00001000>,
+			      <0 0xfea70000 0 0x00001000>;
+			reg-names = "du", "lvds.0",
+				    "cmm.0", "cmm.1", "cmm.3";
 			interrupts = <GIC_SPI 256 IRQ_TYPE_LEVEL_HIGH>,
 				     <GIC_SPI 268 IRQ_TYPE_LEVEL_HIGH>,
 				     <GIC_SPI 270 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&cpg CPG_MOD 724>,
 				 <&cpg CPG_MOD 723>,
-				 <&cpg CPG_MOD 721>;
-			clock-names = "du.0", "du.1", "du.3";
+				 <&cpg CPG_MOD 721>,
+				 <&cpg CPG_MOD 727>,
+				 <&cpg CPG_MOD 711>,
+				 <&cpg CPG_MOD 710>,
+				 <&cpg CPG_MOD 708>;
+			clock-names = "du.0", "du.1", "du.3", "lvds.0",
+				      "cmm.0", "cmm.1", "cmm.3";
+			resets = <&cpg 724>,
+				 <&cpg 724>,
+				 <&cpg 722>,
+				 <&cpg 727>,
+				 <&cpg 711>,
+				 <&cpg 710>,
+				 <&cpg 708>;
+			reset-names = "du.0", "du.1", "du.3", "lvds.0",
+				      "cmm.0", "cmm.1", "cmm.3";
 			status = "disabled";
 
 			vsps = <&vspd0 0 &vspd1 0 &vspd0 1>;
diff --git a/drivers/clk/renesas/r8a7795-cpg-mssr.c b/drivers/clk/renesas/r8a7795-cpg-mssr.c
index a85dd50..ba9e595 100644
--- a/drivers/clk/renesas/r8a7795-cpg-mssr.c
+++ b/drivers/clk/renesas/r8a7795-cpg-mssr.c
@@ -201,6 +201,10 @@ static struct mssr_mod_clk r8a7795_mod_clks[] __initdata = {
 	DEF_MOD("ehci0",		 703,	R8A7795_CLK_S3D4),
 	DEF_MOD("hsusb",		 704,	R8A7795_CLK_S3D4),
 	DEF_MOD("hsusb3",		 705,	R8A7795_CLK_S3D4),
+	DEF_MOD("cmm3",			 708,	R8A7795_CLK_S2D1),
+	DEF_MOD("cmm2",			 709,	R8A7795_CLK_S2D1),
+	DEF_MOD("cmm1",			 710,	R8A7795_CLK_S2D1),
+	DEF_MOD("cmm0",			 711,	R8A7795_CLK_S2D1),
 	DEF_MOD("csi21",		 713,	R8A7795_CLK_CSI0), /* ES1.x */
 	DEF_MOD("csi20",		 714,	R8A7795_CLK_CSI0),
 	DEF_MOD("csi41",		 715,	R8A7795_CLK_CSI0),
diff --git a/drivers/clk/renesas/r8a7796-cpg-mssr.c b/drivers/clk/renesas/r8a7796-cpg-mssr.c
index dfb267a..9f01fda 100644
--- a/drivers/clk/renesas/r8a7796-cpg-mssr.c
+++ b/drivers/clk/renesas/r8a7796-cpg-mssr.c
@@ -180,6 +180,9 @@ static const struct mssr_mod_clk r8a7796_mod_clks[] __initconst = {
 	DEF_MOD("ehci1",		 702,	R8A7796_CLK_S3D4),
 	DEF_MOD("ehci0",		 703,	R8A7796_CLK_S3D4),
 	DEF_MOD("hsusb",		 704,	R8A7796_CLK_S3D4),
+	DEF_MOD("cmm2",			 709,	R8A7796_CLK_S2D1),
+	DEF_MOD("cmm1",			 710,	R8A7796_CLK_S2D1),
+	DEF_MOD("cmm0",			 711,	R8A7796_CLK_S2D1),
 	DEF_MOD("csi20",		 714,	R8A7796_CLK_CSI0),
 	DEF_MOD("csi40",		 716,	R8A7796_CLK_CSI0),
 	DEF_MOD("du2",			 722,	R8A7796_CLK_S2D1),
diff --git a/drivers/clk/renesas/r8a77965-cpg-mssr.c b/drivers/clk/renesas/r8a77965-cpg-mssr.c
index 8fae5e9..cac4570 100644
--- a/drivers/clk/renesas/r8a77965-cpg-mssr.c
+++ b/drivers/clk/renesas/r8a77965-cpg-mssr.c
@@ -123,7 +123,6 @@ static const struct mssr_mod_clk r8a77965_mod_clks[] __initconst = {
 	DEF_MOD("sys-dmac2",		217,	R8A77965_CLK_S0D3),
 	DEF_MOD("sys-dmac1",		218,	R8A77965_CLK_S0D3),
 	DEF_MOD("sys-dmac0",		219,	R8A77965_CLK_S0D3),
-
 	DEF_MOD("cmt3",			300,	R8A77965_CLK_R),
 	DEF_MOD("cmt2",			301,	R8A77965_CLK_R),
 	DEF_MOD("cmt1",			302,	R8A77965_CLK_R),
@@ -215,6 +214,111 @@ static const struct mssr_mod_clk r8a77965_mod_clks[] __initconst = {
 	DEF_MOD("i2c1",			930,	R8A77965_CLK_S3D2),
 	DEF_MOD("i2c0",			931,	R8A77965_CLK_S3D2),
 
+	DEF_MOD("3dge",			 112,	R8A77965_CLK_ZG),
+	DEF_MOD("fdp0",			 119,	R8A77965_CLK_S0D1),
+	DEF_MOD("vcplf",		 130,	R8A77965_CLK_S0D2),
+	DEF_MOD("vdpb",			 131,	R8A77965_CLK_S0D2),
+	DEF_MOD("scif5",		 202,	R8A77965_CLK_S3D4),
+	DEF_MOD("scif4",		 203,	R8A77965_CLK_S3D4),
+	DEF_MOD("scif3",		 204,	R8A77965_CLK_S3D4),
+	DEF_MOD("scif1",		 206,	R8A77965_CLK_S3D4),
+	DEF_MOD("scif0",		 207,	R8A77965_CLK_S3D4),
+	DEF_MOD("msiof3",		 208,	R8A77965_CLK_MSO),
+	DEF_MOD("msiof2",		 209,	R8A77965_CLK_MSO),
+	DEF_MOD("msiof1",		 210,	R8A77965_CLK_MSO),
+	DEF_MOD("msiof0",		 211,	R8A77965_CLK_MSO),
+	DEF_MOD("sys-dmac2",		 217,	R8A77965_CLK_S0D3),
+	DEF_MOD("sys-dmac1",		 218,	R8A77965_CLK_S0D3),
+	DEF_MOD("sys-dmac0",		 219,	R8A77965_CLK_S0D3),
+	DEF_MOD("cmt3",			 300,	R8A77965_CLK_R),
+	DEF_MOD("cmt2",			 301,	R8A77965_CLK_R),
+	DEF_MOD("cmt1",			 302,	R8A77965_CLK_R),
+	DEF_MOD("cmt0",			 303,	R8A77965_CLK_R),
+	DEF_MOD("scif2",		 310,	R8A77965_CLK_S3D4),
+	DEF_MOD("sdif3",		 311,	R8A77965_CLK_SD3),
+	DEF_MOD("sdif2",		 312,	R8A77965_CLK_SD2),
+	DEF_MOD("sdif1",		 313,	R8A77965_CLK_SD1),
+	DEF_MOD("sdif0",		 314,	R8A77965_CLK_SD0),
+	DEF_MOD("pcie1",		 318,	R8A77965_CLK_S3D1),
+	DEF_MOD("pcie0",		 319,	R8A77965_CLK_S3D1),
+	DEF_MOD("usb3-if0",		 328,	R8A77965_CLK_S3D1),
+	DEF_MOD("usb-dmac0",		 330,	R8A77965_CLK_S3D1),
+	DEF_MOD("usb-dmac1",		 331,	R8A77965_CLK_S3D1),
+	DEF_MOD("rwdt0",		 402,	R8A77965_CLK_R),
+	DEF_MOD("intc-ex",		 407,	R8A77965_CLK_CP),
+	DEF_MOD("intc-ap",		 408,	R8A77965_CLK_S3D1),
+	DEF_MOD("audmac0",		 502,	R8A77965_CLK_S3D4),
+	DEF_MOD("audmac1",		 501,	R8A77965_CLK_S3D4),
+	DEF_MOD("adsp",			 506,	R8A77965_CLK_S1D1),
+	DEF_MOD("drif7",		 508,	R8A77965_CLK_S3D2),
+	DEF_MOD("drif6",		 509,	R8A77965_CLK_S3D2),
+	DEF_MOD("drif5",		 510,	R8A77965_CLK_S3D2),
+	DEF_MOD("drif4",		 511,	R8A77965_CLK_S3D2),
+	DEF_MOD("drif3",		 512,	R8A77965_CLK_S3D2),
+	DEF_MOD("drif2",		 513,	R8A77965_CLK_S3D2),
+	DEF_MOD("drif1",		 514,	R8A77965_CLK_S3D2),
+	DEF_MOD("drif0",		 515,	R8A77965_CLK_S3D2),
+	DEF_MOD("hscif4",		 516,	R8A77965_CLK_S3D1),
+	DEF_MOD("hscif3",		 517,	R8A77965_CLK_S3D1),
+	DEF_MOD("hscif2",		 518,	R8A77965_CLK_S3D1),
+	DEF_MOD("hscif1",		 519,	R8A77965_CLK_S3D1),
+	DEF_MOD("hscif0",		 520,	R8A77965_CLK_S3D1),
+	DEF_MOD("thermal",		 522,	R8A77965_CLK_CP),
+	DEF_MOD("pwm",			 523,	R8A77965_CLK_S3D4),
+	DEF_MOD("fcpvd1",		 602,	R8A77965_CLK_S0D2),
+	DEF_MOD("fcpvd0",		 603,	R8A77965_CLK_S0D2),
+	DEF_MOD("fcpvb0",		 607,	R8A77965_CLK_S0D1),
+	DEF_MOD("fcpvi0",		 611,	R8A77965_CLK_S0D1),
+	DEF_MOD("fcpf0",		 615,	R8A77965_CLK_S0D1),
+	DEF_MOD("fcpcs",		 619,	R8A77965_CLK_S0D2),
+	DEF_MOD("vspd1",		 622,	R8A77965_CLK_S0D2),
+	DEF_MOD("vspd0",		 623,	R8A77965_CLK_S0D2),
+	DEF_MOD("vspb",			 626,	R8A77965_CLK_S0D1),
+	DEF_MOD("vspi0",		 631,	R8A77965_CLK_S0D1),
+	DEF_MOD("ehci1",		 702,	R8A77965_CLK_S3D4),
+	DEF_MOD("ehci0",		 703,	R8A77965_CLK_S3D4),
+	DEF_MOD("hsusb",		 704,	R8A77965_CLK_S3D4),
+	DEF_MOD("cmm3",			 708,	R8A77965_CLK_S2D1),
+	DEF_MOD("cmm1",			 710,	R8A77965_CLK_S2D1),
+	DEF_MOD("cmm0",			 711,	R8A77965_CLK_S2D1),
+	DEF_MOD("csi20",		 714,	R8A77965_CLK_CSI0),
+	DEF_MOD("csi40",		 716,	R8A77965_CLK_CSI0),
+	DEF_MOD("du3",			 721,	R8A77965_CLK_S2D1),
+	DEF_MOD("du1",			 723,	R8A77965_CLK_S2D1),
+	DEF_MOD("du0",			 724,	R8A77965_CLK_S2D1),
+	DEF_MOD("lvds",			 727,	R8A77965_CLK_S2D1),
+	DEF_MOD("hdmi0",		 729,	R8A77965_CLK_HDMI),
+	DEF_MOD("vin7",			 804,	R8A77965_CLK_S0D2),
+	DEF_MOD("vin6",			 805,	R8A77965_CLK_S0D2),
+	DEF_MOD("vin5",			 806,	R8A77965_CLK_S0D2),
+	DEF_MOD("vin4",			 807,	R8A77965_CLK_S0D2),
+	DEF_MOD("vin3",			 808,	R8A77965_CLK_S0D2),
+	DEF_MOD("vin2",			 809,	R8A77965_CLK_S0D2),
+	DEF_MOD("vin1",			 810,	R8A77965_CLK_S0D2),
+	DEF_MOD("vin0",			 811,	R8A77965_CLK_S0D2),
+	DEF_MOD("etheravb",		 812,	R8A77965_CLK_S0D6),
+	DEF_MOD("sata0",		 815,	R8A77965_CLK_S3D2),
+	DEF_MOD("gpio7",		 905,	R8A77965_CLK_S3D4),
+	DEF_MOD("gpio6",		 906,	R8A77965_CLK_S3D4),
+	DEF_MOD("gpio5",		 907,	R8A77965_CLK_S3D4),
+	DEF_MOD("gpio4",		 908,	R8A77965_CLK_S3D4),
+	DEF_MOD("gpio3",		 909,	R8A77965_CLK_S3D4),
+	DEF_MOD("gpio2",		 910,	R8A77965_CLK_S3D4),
+	DEF_MOD("gpio1",		 911,	R8A77965_CLK_S3D4),
+	DEF_MOD("gpio0",		 912,	R8A77965_CLK_S3D4),
+	DEF_MOD("can-fd",		 914,	R8A77965_CLK_S3D2),
+	DEF_MOD("can-if1",		 915,	R8A77965_CLK_S3D4),
+	DEF_MOD("can-if0",		 916,	R8A77965_CLK_S3D4),
+	DEF_MOD("i2c6",			 918,	R8A77965_CLK_S0D6),
+	DEF_MOD("i2c5",			 919,	R8A77965_CLK_S0D6),
+	DEF_MOD("adg",			 922,	R8A77965_CLK_S0D1),
+	DEF_MOD("i2c-dvfs",		 926,	R8A77965_CLK_CP),
+	DEF_MOD("i2c4",			 927,	R8A77965_CLK_S0D6),
+	DEF_MOD("i2c3",			 928,	R8A77965_CLK_S0D6),
+	DEF_MOD("i2c2",			 929,	R8A77965_CLK_S3D2),
+	DEF_MOD("i2c1",			 930,	R8A77965_CLK_S3D2),
+	DEF_MOD("i2c0",			 931,	R8A77965_CLK_S3D2),
+
 	DEF_MOD("ssi-all",		1005,	R8A77965_CLK_S3D4),
 	DEF_MOD("ssi9",			1006,	MOD_CLK_ID(1005)),
 	DEF_MOD("ssi8",			1007,	MOD_CLK_ID(1005)),
-- 
2.7.4

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

* [PATCH 3/8] drm: rcar-du: Give a name to clu table samples
  2019-04-03 13:14 ` VenkataRajesh.Kalakodima
@ 2019-04-03 13:14   ` VenkataRajesh.Kalakodima
  -1 siblings, 0 replies; 36+ messages in thread
From: VenkataRajesh.Kalakodima @ 2019-04-03 13:14 UTC (permalink / raw)
  To: linux-renesas-soc, devicetree, linux-kernel, linux-clk, dri-devel
  Cc: kalakodima venkata rajesh, Harsha M M, Eugeniu Rosca

From: kalakodima venkata rajesh <venkatarajesh.kalakodima@in.bosch.com>

Replace the hardcoded value of clu table sample count with a
meaningful name.

Signed-off-by: Harsha M M <harsha.manjulamallikarjun@in.bosch.com>

This is the out-of-tree patch for DU CMM driver support from
    Yocto release v3.6.0. The part of this patch adding CMM support to
    the new Rcar E3 (R8A77990) SoC was filtered out due to lack of
    Yocto v3.6.0 (i.e. rcar-3.6.2) kernel updates on staging-414.

    Link: https://github.com/renesas-rcar/du_cmm/commit/53973b806881ed8f54500b0d42bdc40aaca60476.patch

    Following is from the patch description:

    Subject: [PATCH] du_cmm: Release for Yocto v3.6.0

    This patch made the following correspondence.

      - R-Car E3(R8A77990) device support.
      - Fix rewritting of parameter procedure in rcar_du_cmm_postclose

Signed-off-by: Eugeniu Rosca <erosca@de.adit-jv.com>

      - Resolved checkpatch errors
      - Resolved merge conflicts according to latest version

Signed-off-by: kalakodima venkata rajesh <venkatarajesh.kalakodima@in.bosch.com>
---
 drivers/gpu/drm/rcar-du/rcar_du_cmm.c | 28 +++++++++++++++-------------
 1 file changed, 15 insertions(+), 13 deletions(-)

diff --git a/drivers/gpu/drm/rcar-du/rcar_du_cmm.c b/drivers/gpu/drm/rcar-du/rcar_du_cmm.c
index ac613a6e..d380dd9 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_cmm.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_cmm.c
@@ -75,9 +75,9 @@
 #include <linux/clk.h>
 
 /* #define DEBUG_PROCE_TIME 1 */
-
+#define CMM_CLU_SAMPLES 17
 #define CMM_LUT_NUM 256
-#define CMM_CLU_NUM (17 * 17 * 17)
+#define CMM_CLU_NUM (CMM_CLU_SAMPLES * CMM_CLU_SAMPLES * CMM_CLU_SAMPLES)
 #define CMM_HGO_NUM 64
 /* rcar_du_drm.h Include */
 #define LUT_DOUBLE_BUFFER_AUTO		0
@@ -211,11 +211,11 @@ static inline u32 index_to_clu_data(int index)
 {
 	int r, g, b;
 
-	r = index % 17;
-	index /= 17;
-	g = index % 17;
-	index /= 17;
-	b = index % 17;
+	r = index % CMM_CLU_SAMPLES;
+	index /= CMM_CLU_SAMPLES;
+	g = index % CMM_CLU_SAMPLES;
+	index /= CMM_CLU_SAMPLES;
+	b = index % CMM_CLU_SAMPLES;
 
 	r = (r << 20);
 	if (r > (255 << 16))
@@ -630,9 +630,9 @@ static int clu_table_copy(struct rcar_du_cmm *du_cmm)
 	}
 
 	rcar_du_cmm_write(du_cmm, dst_addr, 0);
-	for (i = 0; i < 17; i++) {
-		for (j = 0; j < 17; j++) {
-			for (k = 0; k < 17; k++) {
+	for (i = 0; i < CMM_CLU_SAMPLES; i++) {
+		for (j = 0; j < CMM_CLU_SAMPLES; j++) {
+			for (k = 0; k < CMM_CLU_SAMPLES; k++) {
 				rcar_du_cmm_write(du_cmm, src_addr,
 						  (k << 16) | (j << 8) |
 						  (i << 0));
@@ -912,9 +912,9 @@ int rcar_du_cmm_pm_suspend(struct rcar_du_crtc *rcrtc)
 	}
 
 	index = 0;
-	for (i = 0; i < 17; i++) {
-		for (j = 0; j < 17; j++) {
-			for (k = 0; k < 17; k++) {
+	for (i = 0; i < CMM_CLU_SAMPLES; i++) {
+		for (j = 0; j < CMM_CLU_SAMPLES; j++) {
+			for (k = 0; k < CMM_CLU_SAMPLES; k++) {
 				rcar_du_cmm_write(du_cmm, CMM_CLU_ADDR,
 						  (k << 16) | (j << 8) |
 						  (i << 0));
@@ -1014,6 +1014,8 @@ void rcar_du_cmm_postclose(struct drm_device *dev, struct drm_file *file_priv)
 	for (crtcs_cnt = 0; crtcs_cnt < rcdu->num_crtcs; crtcs_cnt++) {
 		rcrtc = &rcdu->crtcs[crtcs_cnt];
 		du_cmm = rcrtc->cmm_handle;
+		if (!du_cmm)
+			continue;
 		if (du_cmm->authority && du_cmm->pid == task_pid_nr(current)) {
 			du_cmm->authority = false;
 			du_cmm->pid = 0;
-- 
2.7.4


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

* [PATCH 3/8] drm: rcar-du: Give a name to clu table samples
@ 2019-04-03 13:14   ` VenkataRajesh.Kalakodima
  0 siblings, 0 replies; 36+ messages in thread
From: VenkataRajesh.Kalakodima @ 2019-04-03 13:14 UTC (permalink / raw)
  To: linux-renesas-soc, devicetree, linux-kernel, linux-clk, dri-devel
  Cc: kalakodima venkata rajesh, Harsha M M, Eugeniu Rosca

From: kalakodima venkata rajesh <venkatarajesh.kalakodima@in.bosch.com>

Replace the hardcoded value of clu table sample count with a
meaningful name.

Signed-off-by: Harsha M M <harsha.manjulamallikarjun@in.bosch.com>

This is the out-of-tree patch for DU CMM driver support from
    Yocto release v3.6.0. The part of this patch adding CMM support to
    the new Rcar E3 (R8A77990) SoC was filtered out due to lack of
    Yocto v3.6.0 (i.e. rcar-3.6.2) kernel updates on staging-414.

    Link: https://github.com/renesas-rcar/du_cmm/commit/53973b806881ed8f54500b0d42bdc40aaca60476.patch

    Following is from the patch description:

    Subject: [PATCH] du_cmm: Release for Yocto v3.6.0

    This patch made the following correspondence.

      - R-Car E3(R8A77990) device support.
      - Fix rewritting of parameter procedure in rcar_du_cmm_postclose

Signed-off-by: Eugeniu Rosca <erosca@de.adit-jv.com>

      - Resolved checkpatch errors
      - Resolved merge conflicts according to latest version

Signed-off-by: kalakodima venkata rajesh <venkatarajesh.kalakodima@in.bosch.com>
---
 drivers/gpu/drm/rcar-du/rcar_du_cmm.c | 28 +++++++++++++++-------------
 1 file changed, 15 insertions(+), 13 deletions(-)

diff --git a/drivers/gpu/drm/rcar-du/rcar_du_cmm.c b/drivers/gpu/drm/rcar-du/rcar_du_cmm.c
index ac613a6e..d380dd9 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_cmm.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_cmm.c
@@ -75,9 +75,9 @@
 #include <linux/clk.h>
 
 /* #define DEBUG_PROCE_TIME 1 */
-
+#define CMM_CLU_SAMPLES 17
 #define CMM_LUT_NUM 256
-#define CMM_CLU_NUM (17 * 17 * 17)
+#define CMM_CLU_NUM (CMM_CLU_SAMPLES * CMM_CLU_SAMPLES * CMM_CLU_SAMPLES)
 #define CMM_HGO_NUM 64
 /* rcar_du_drm.h Include */
 #define LUT_DOUBLE_BUFFER_AUTO		0
@@ -211,11 +211,11 @@ static inline u32 index_to_clu_data(int index)
 {
 	int r, g, b;
 
-	r = index % 17;
-	index /= 17;
-	g = index % 17;
-	index /= 17;
-	b = index % 17;
+	r = index % CMM_CLU_SAMPLES;
+	index /= CMM_CLU_SAMPLES;
+	g = index % CMM_CLU_SAMPLES;
+	index /= CMM_CLU_SAMPLES;
+	b = index % CMM_CLU_SAMPLES;
 
 	r = (r << 20);
 	if (r > (255 << 16))
@@ -630,9 +630,9 @@ static int clu_table_copy(struct rcar_du_cmm *du_cmm)
 	}
 
 	rcar_du_cmm_write(du_cmm, dst_addr, 0);
-	for (i = 0; i < 17; i++) {
-		for (j = 0; j < 17; j++) {
-			for (k = 0; k < 17; k++) {
+	for (i = 0; i < CMM_CLU_SAMPLES; i++) {
+		for (j = 0; j < CMM_CLU_SAMPLES; j++) {
+			for (k = 0; k < CMM_CLU_SAMPLES; k++) {
 				rcar_du_cmm_write(du_cmm, src_addr,
 						  (k << 16) | (j << 8) |
 						  (i << 0));
@@ -912,9 +912,9 @@ int rcar_du_cmm_pm_suspend(struct rcar_du_crtc *rcrtc)
 	}
 
 	index = 0;
-	for (i = 0; i < 17; i++) {
-		for (j = 0; j < 17; j++) {
-			for (k = 0; k < 17; k++) {
+	for (i = 0; i < CMM_CLU_SAMPLES; i++) {
+		for (j = 0; j < CMM_CLU_SAMPLES; j++) {
+			for (k = 0; k < CMM_CLU_SAMPLES; k++) {
 				rcar_du_cmm_write(du_cmm, CMM_CLU_ADDR,
 						  (k << 16) | (j << 8) |
 						  (i << 0));
@@ -1014,6 +1014,8 @@ void rcar_du_cmm_postclose(struct drm_device *dev, struct drm_file *file_priv)
 	for (crtcs_cnt = 0; crtcs_cnt < rcdu->num_crtcs; crtcs_cnt++) {
 		rcrtc = &rcdu->crtcs[crtcs_cnt];
 		du_cmm = rcrtc->cmm_handle;
+		if (!du_cmm)
+			continue;
 		if (du_cmm->authority && du_cmm->pid == task_pid_nr(current)) {
 			du_cmm->authority = false;
 			du_cmm->pid = 0;
-- 
2.7.4

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

* [PATCH 4/8] drm: rcar-du: Refactor the code with new functions
  2019-04-03 13:14 ` VenkataRajesh.Kalakodima
@ 2019-04-03 13:14   ` VenkataRajesh.Kalakodima
  -1 siblings, 0 replies; 36+ messages in thread
From: VenkataRajesh.Kalakodima @ 2019-04-03 13:14 UTC (permalink / raw)
  To: linux-renesas-soc, devicetree, linux-kernel, linux-clk, dri-devel
  Cc: kalakodima venkata rajesh, Harsha M M

From: kalakodima venkata rajesh <venkatarajesh.kalakodima@in.bosch.com>

   - Introduce new functions for queueing clu and lut events.
   - Functionality remains same, only some code is moved to
     new functions.

Signed-off-by: Harsha M M <harsha.manjulamallikarjun@in.bosch.com>

      - Resolved checkpatch errors
      - Resolved merge conflicts according to latest version

Signed-off-by: kalakodima venkata rajesh <venkatarajesh.kalakodima@in.bosch.com>
---
 drivers/gpu/drm/rcar-du/rcar_du_cmm.c | 38 +++++++++++++++++++++++++++++++++++
 1 file changed, 38 insertions(+)

diff --git a/drivers/gpu/drm/rcar-du/rcar_du_cmm.c b/drivers/gpu/drm/rcar-du/rcar_du_cmm.c
index d380dd9..7983039 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_cmm.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_cmm.c
@@ -246,6 +246,44 @@ static void du_cmm_clk(struct rcar_du_cmm *du_cmm, bool on)
 		clk_disable_unprepare(du_cmm->clock);
 }
 
+static void rcar_du_cmm_queue_lut_update(struct rcar_du_cmm_pending_event *p)
+{
+	mutex_lock(&cmm_event_lock);
+
+	list_add_tail(&p->link, &p->du_cmm->lut.list);
+
+	if (p->fpriv)
+		list_add_tail(&p->fpriv_link, &p->fpriv->list);
+
+	event_prev_cancel_locked(&p->du_cmm->lut);
+
+	if (p->du_cmm->direct)
+		queue_work(p->du_cmm->workqueue, &p->du_cmm->work);
+
+	mutex_unlock(&cmm_event_lock);
+
+	drm_crtc_vblank_get(&p->du_cmm->rcrtc->crtc);
+}
+
+static void rcar_du_cmm_queue_clu_update(struct rcar_du_cmm_pending_event *p)
+{
+	mutex_lock(&cmm_event_lock);
+
+	list_add_tail(&p->link, &p->du_cmm->clu.list);
+
+	if (p->fpriv)
+		list_add_tail(&p->fpriv_link, &p->fpriv->list);
+
+	event_prev_cancel_locked(&p->du_cmm->clu);
+
+	if (p->du_cmm->direct)
+		queue_work(p->du_cmm->workqueue, &p->du_cmm->work);
+
+	mutex_unlock(&cmm_event_lock);
+
+	drm_crtc_vblank_get(&p->du_cmm->rcrtc->crtc);
+}
+
 int rcar_du_cmm_start_stop(struct rcar_du_crtc *rcrtc, bool on)
 {
 	struct rcar_du_cmm *du_cmm = rcrtc->cmm_handle;
-- 
2.7.4


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

* [PATCH 4/8] drm: rcar-du: Refactor the code with new functions
@ 2019-04-03 13:14   ` VenkataRajesh.Kalakodima
  0 siblings, 0 replies; 36+ messages in thread
From: VenkataRajesh.Kalakodima @ 2019-04-03 13:14 UTC (permalink / raw)
  To: linux-renesas-soc, devicetree, linux-kernel, linux-clk, dri-devel
  Cc: kalakodima venkata rajesh, Harsha M M

From: kalakodima venkata rajesh <venkatarajesh.kalakodima@in.bosch.com>

   - Introduce new functions for queueing clu and lut events.
   - Functionality remains same, only some code is moved to
     new functions.

Signed-off-by: Harsha M M <harsha.manjulamallikarjun@in.bosch.com>

      - Resolved checkpatch errors
      - Resolved merge conflicts according to latest version

Signed-off-by: kalakodima venkata rajesh <venkatarajesh.kalakodima@in.bosch.com>
---
 drivers/gpu/drm/rcar-du/rcar_du_cmm.c | 38 +++++++++++++++++++++++++++++++++++
 1 file changed, 38 insertions(+)

diff --git a/drivers/gpu/drm/rcar-du/rcar_du_cmm.c b/drivers/gpu/drm/rcar-du/rcar_du_cmm.c
index d380dd9..7983039 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_cmm.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_cmm.c
@@ -246,6 +246,44 @@ static void du_cmm_clk(struct rcar_du_cmm *du_cmm, bool on)
 		clk_disable_unprepare(du_cmm->clock);
 }
 
+static void rcar_du_cmm_queue_lut_update(struct rcar_du_cmm_pending_event *p)
+{
+	mutex_lock(&cmm_event_lock);
+
+	list_add_tail(&p->link, &p->du_cmm->lut.list);
+
+	if (p->fpriv)
+		list_add_tail(&p->fpriv_link, &p->fpriv->list);
+
+	event_prev_cancel_locked(&p->du_cmm->lut);
+
+	if (p->du_cmm->direct)
+		queue_work(p->du_cmm->workqueue, &p->du_cmm->work);
+
+	mutex_unlock(&cmm_event_lock);
+
+	drm_crtc_vblank_get(&p->du_cmm->rcrtc->crtc);
+}
+
+static void rcar_du_cmm_queue_clu_update(struct rcar_du_cmm_pending_event *p)
+{
+	mutex_lock(&cmm_event_lock);
+
+	list_add_tail(&p->link, &p->du_cmm->clu.list);
+
+	if (p->fpriv)
+		list_add_tail(&p->fpriv_link, &p->fpriv->list);
+
+	event_prev_cancel_locked(&p->du_cmm->clu);
+
+	if (p->du_cmm->direct)
+		queue_work(p->du_cmm->workqueue, &p->du_cmm->work);
+
+	mutex_unlock(&cmm_event_lock);
+
+	drm_crtc_vblank_get(&p->du_cmm->rcrtc->crtc);
+}
+
 int rcar_du_cmm_start_stop(struct rcar_du_crtc *rcrtc, bool on)
 {
 	struct rcar_du_cmm *du_cmm = rcrtc->cmm_handle;
-- 
2.7.4

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

* [PATCH 5/8] drm: rcar-du: Implement interfaces to set clu and lut using drm data structures
  2019-04-03 13:14 ` VenkataRajesh.Kalakodima
@ 2019-04-03 13:14   ` VenkataRajesh.Kalakodima
  -1 siblings, 0 replies; 36+ messages in thread
From: VenkataRajesh.Kalakodima @ 2019-04-03 13:14 UTC (permalink / raw)
  To: linux-renesas-soc, devicetree, linux-kernel, linux-clk, dri-devel
  Cc: kalakodima venkata rajesh, Harsha M M

From: kalakodima venkata rajesh <venkatarajesh.kalakodima@in.bosch.com>

Impelement interfaces in cmm to set clu and lut tables using standard
drm data structures as input.

Signed-off-by: Harsha M M <harsha.manjulamallikarjun@in.bosch.com>

      - Resolved checkpatch errors
      - Resolved merge conflicts according to latest version

Signed-off-by: kalakodima venkata rajesh <venkatarajesh.kalakodima@in.bosch.com>
---
 drivers/gpu/drm/rcar-du/rcar_du_cmm.c  | 256 +++++++++++++++++++++++++++++++--
 drivers/gpu/drm/rcar-du/rcar_du_crtc.h |  11 ++
 2 files changed, 254 insertions(+), 13 deletions(-)

diff --git a/drivers/gpu/drm/rcar-du/rcar_du_cmm.c b/drivers/gpu/drm/rcar-du/rcar_du_cmm.c
index 7983039..af4668f 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_cmm.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_cmm.c
@@ -114,6 +114,8 @@ struct rcar_du_cmm_pending_event {
 	struct drm_gem_object *gem_obj;
 	struct rcar_du_cmm *du_cmm;
 	struct rcar_du_cmm_file_priv *fpriv;
+	unsigned int *lut_buf;
+	unsigned int *clu_buf;
 };
 
 struct cmm_module_t {
@@ -238,14 +240,6 @@ static long long diff_timevals(struct timeval *start, struct timeval *end)
 }
 #endif
 
-static void du_cmm_clk(struct rcar_du_cmm *du_cmm, bool on)
-{
-	if (on)
-		clk_prepare_enable(du_cmm->clock);
-	else
-		clk_disable_unprepare(du_cmm->clock);
-}
-
 static void rcar_du_cmm_queue_lut_update(struct rcar_du_cmm_pending_event *p)
 {
 	mutex_lock(&cmm_event_lock);
@@ -284,6 +278,223 @@ static void rcar_du_cmm_queue_clu_update(struct rcar_du_cmm_pending_event *p)
 	drm_crtc_vblank_get(&p->du_cmm->rcrtc->crtc);
 }
 
+static s64 rcar_du_cmm_multiply_coeff(unsigned int color, s64 coeff)
+{
+	s64 r_val;
+	bool is_neg = false;
+
+	if (coeff & BIT_ULL(63)) {
+		is_neg = true;
+		coeff &= ~BIT_ULL(63);
+	}
+
+	r_val = DIV_ROUND_CLOSEST(((s64)(color * coeff)), BIT_ULL(32));
+
+	if (is_neg)
+		return -r_val;
+
+	return r_val;
+}
+
+static unsigned int rcar_du_cmm_scalar_product(unsigned int r, unsigned int g,
+					       unsigned int b, s64 coeff1,
+					       s64 coeff2, s64 coeff3)
+{
+	s64 product;
+
+	product = rcar_du_cmm_multiply_coeff(r, coeff1)
+			+ rcar_du_cmm_multiply_coeff(g, coeff2)
+			+ rcar_du_cmm_multiply_coeff(b, coeff3);
+
+	return (unsigned int)clamp_val(product, 0, U8_MAX);
+}
+
+#ifdef DEBUG_PROCE_TIME
+static long long diff_timevals(struct timeval *start, struct timeval *end)
+{
+	return (end->tv_sec * 1000000LL + end->tv_usec) -
+		(start->tv_sec * 1000000LL + start->tv_usec);
+}
+#endif
+
+void *rcar_du_cmm_alloc_lut(void *cmm_handle)
+{
+	struct rcar_du_cmm_pending_event *p;
+
+	if (!cmm_handle)
+		return NULL;
+
+	p = kzalloc(sizeof(*p), GFP_KERNEL);
+	if (!p)
+		return NULL;
+
+	p->gem_obj = NULL;
+	p->event = CMM_EVENT_LUT_DONE;
+	p->stat = QUE_STAT_PENDING;
+	p->callback_data = 0;
+	p->du_cmm = cmm_handle;
+	p->fpriv = NULL;
+	p->lut_buf = kmalloc(CMM_LUT_NUM * 4, GFP_KERNEL);
+	if (!p->lut_buf) {
+		kfree(p);
+		return NULL;
+	}
+
+	return p;
+}
+
+void rcar_du_cmm_free_lut(void *lut_handle)
+{
+	struct rcar_du_cmm_pending_event *p =
+			(struct rcar_du_cmm_pending_event *)lut_handle;
+
+	kfree(p->lut_buf);
+	kfree(p);
+}
+
+int rcar_du_cmm_lut_valid(unsigned int lut_length)
+{
+	return (lut_length == CMM_LUT_NUM) ? 0 : -EINVAL;
+}
+
+void rcar_du_cmm_update_lut_and_free(void *lut_handle,
+				     struct drm_color_lut *lut,
+				     unsigned int lut_length)
+{
+	struct rcar_du_cmm_pending_event *p =
+			(struct rcar_du_cmm_pending_event *)lut_handle;
+	unsigned int color;
+
+	if (!p)
+		return;
+
+	if (rcar_du_cmm_lut_valid(lut_length))
+		return;
+
+	/* Convert drm_color_lut to the format handled by hardware */
+	for (color = 0; color < lut_length; color++) {
+		p->lut_buf[color] = 0;
+		p->lut_buf[color] |= drm_color_lut_extract(lut[color].red, 8)
+					<< 16;
+		p->lut_buf[color] |= drm_color_lut_extract(lut[color].green, 8)
+					<< 8;
+		p->lut_buf[color] |= drm_color_lut_extract(lut[color].blue, 8);
+	}
+	rcar_du_cmm_queue_lut_update(p);
+}
+
+void *rcar_du_cmm_alloc_clu(void *cmm_handle)
+{
+	struct rcar_du_cmm_pending_event *p;
+
+	if (!cmm_handle)
+		return NULL;
+
+	p = kzalloc(sizeof(*p), GFP_KERNEL);
+	if (!p)
+		return NULL;
+
+	p->gem_obj = NULL;
+	p->event = CMM_EVENT_CLU_DONE;
+	p->stat = QUE_STAT_PENDING;
+	p->callback_data = 0;
+	p->du_cmm = cmm_handle;
+	p->fpriv = NULL;
+	p->clu_buf = kmalloc(CMM_CLU_NUM * 4, GFP_KERNEL);
+	if (!p->clu_buf) {
+		kfree(p);
+		return NULL;
+	}
+
+	return p;
+}
+
+void rcar_du_cmm_free_clu(void *clu_handle)
+{
+	struct rcar_du_cmm_pending_event *p =
+			(struct rcar_du_cmm_pending_event *)clu_handle;
+
+	kfree(p->clu_buf);
+	kfree(p);
+}
+
+void rcar_du_cmm_update_clu_and_free(void *clu_handle,
+				     struct drm_color_ctm *ctm)
+{
+	struct rcar_du_cmm_pending_event *p =
+			(struct rcar_du_cmm_pending_event *)clu_handle;
+	unsigned int r_loop;
+	unsigned int g_loop;
+	unsigned int b_loop;
+	unsigned int step_size;
+	unsigned int step_fraction;
+	unsigned int clu_index = 0;
+
+	if (!p)
+		return;
+
+	step_size = U8_MAX / (CMM_CLU_SAMPLES - 1);
+	step_fraction = U8_MAX % (CMM_CLU_SAMPLES - 1);
+
+	/*Update clu table*/
+	for (b_loop = 0; b_loop < CMM_CLU_SAMPLES; b_loop++) {
+		unsigned int b;
+
+		b = (b_loop * step_size) +
+		    DIV_ROUND_CLOSEST((b_loop * step_fraction),
+				      (CMM_CLU_SAMPLES - 1));
+
+		for (g_loop = 0; g_loop < CMM_CLU_SAMPLES; g_loop++) {
+			unsigned int g;
+
+			g = (g_loop * step_size) +
+			    DIV_ROUND_CLOSEST((g_loop * step_fraction),
+					      (CMM_CLU_SAMPLES - 1));
+
+			for (r_loop = 0; r_loop < CMM_CLU_SAMPLES; r_loop++) {
+				unsigned int r;
+				unsigned int r_val;
+				unsigned int g_val;
+				unsigned int b_val;
+
+				r = (r_loop * step_size) +
+				    DIV_ROUND_CLOSEST((r_loop * step_fraction),
+						      (CMM_CLU_SAMPLES - 1));
+
+				p->clu_buf[clu_index] = 0;
+
+				r_val =	rcar_du_cmm_scalar_product
+						(r, g, b,
+						 ctm->matrix[0], ctm->matrix[1],
+						 ctm->matrix[2]);
+
+				g_val =	rcar_du_cmm_scalar_product
+						(r, g, b,
+						 ctm->matrix[3], ctm->matrix[4],
+						 ctm->matrix[5]);
+
+				b_val =	rcar_du_cmm_scalar_product
+						(r, g, b,
+						 ctm->matrix[6], ctm->matrix[7],
+						 ctm->matrix[8]);
+
+				p->clu_buf[clu_index++] = (r_val << 16) |
+							  (g_val << 8) | b_val;
+			}
+		}
+	}
+
+	rcar_du_cmm_queue_clu_update(p);
+}
+
+static void du_cmm_clk(struct rcar_du_cmm *du_cmm, bool on)
+{
+	if (on)
+		clk_prepare_enable(du_cmm->clock);
+	else
+		clk_disable_unprepare(du_cmm->clock);
+}
+
 int rcar_du_cmm_start_stop(struct rcar_du_crtc *rcrtc, bool on)
 {
 	struct rcar_du_cmm *du_cmm = rcrtc->cmm_handle;
@@ -424,8 +635,16 @@ static inline void _event_done_locked(struct rcar_du_cmm_pending_event *p)
 		list_add_tail(&p->link, cmm_done_list(p->du_cmm, p->fpriv));
 		wake_up_interruptible(&p->fpriv->event_wait);
 	} else {
-		/* link deleted by rcar_du_cmm_postclose */
-		kfree(p);
+		/* link deleted by rcar_du_cmm_postclose
+		 * OR it could also be due to set of ctm and gamma
+		 * properties through drm APIs.
+		 */
+		if (p->event == CMM_EVENT_LUT_DONE)
+			rcar_du_cmm_free_lut(p);
+		else if (p->event == CMM_EVENT_CLU_DONE)
+			rcar_du_cmm_free_clu(p);
+		else
+			kfree(p);
 	}
 }
 
@@ -479,7 +698,8 @@ event_pop_locked(struct cmm_module_t *module)
 
 	p->stat = QUE_STAT_ACTIVE;
 	list_del(&p->link); /* delete from du_cmm->[lut|clu|hgo].list */
-	list_add_tail(&p->link, &p->fpriv->active_list);
+	if (p->fpriv)
+		list_add_tail(&p->link, &p->fpriv->active_list);
 	cmm_vblank_put(p);
 
 	return p;
@@ -605,7 +825,11 @@ static int lut_set(struct rcar_du_cmm *du_cmm,
 		return -EINVAL;
 	}
 
-	lut_buf = gem_to_vaddr(stat->p->gem_obj);
+	if (stat->p->gem_obj)
+		lut_buf = gem_to_vaddr(stat->p->gem_obj);
+	else
+		lut_buf = stat->p->lut_buf;
+
 	for (i = 0; i < CMM_LUT_NUM; i++)
 		rcar_du_cmm_write(du_cmm, lut_base + i * 4, lut_buf[i]);
 
@@ -723,7 +947,11 @@ static int clu_set(struct rcar_du_cmm *du_cmm,
 		return -EINVAL;
 	}
 
-	clu_buf = gem_to_vaddr(stat->p->gem_obj);
+	if (stat->p->gem_obj)
+		clu_buf = gem_to_vaddr(stat->p->gem_obj);
+	else
+		clu_buf = stat->p->clu_buf;
+
 	rcar_du_cmm_write(du_cmm, addr_reg, 0);
 	for (i = 0; i < CMM_CLU_NUM; i++)
 		rcar_du_cmm_write(du_cmm, data_reg, clu_buf[i]);
@@ -1222,6 +1450,8 @@ int rcar_du_cmm_init(struct rcar_du_crtc *rcrtc)
 
 	rcrtc->cmm_handle = du_cmm;
 
+	drm_crtc_enable_color_mgmt(&rcrtc->crtc, 0, true, CMM_LUT_NUM);
+
 	dev_info(rcdu->dev, "DU%d use CMM(%s buffer)\n",
 		 rcrtc->index, du_cmm->dbuf ? "Double" : "Single");
 
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
index 74e0a22..5b85de4 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
+++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
@@ -115,6 +115,17 @@ void rcar_du_cmm_postclose(struct drm_device *dev, struct drm_file *file_priv);
 int rcar_du_cmm_start_stop(struct rcar_du_crtc *rcrtc, bool on);
 void rcar_du_cmm_kick(struct rcar_du_crtc *rcrtc);
 
+void *rcar_du_cmm_alloc_lut(void *cmm_handle);
+void rcar_du_cmm_free_lut(void *lut_handle);
+int rcar_du_cmm_lut_valid(unsigned int lut_length);
+void rcar_du_cmm_update_lut_and_free(void *lut_handle,
+				     struct drm_color_lut *lut,
+				     unsigned int lut_length);
+
+void *rcar_du_cmm_alloc_clu(void *cmm_handle);
+void rcar_du_cmm_free_clu(void *clu_handle);
+void rcar_du_cmm_update_clu_and_free(void *clu_handle,
+				     struct drm_color_ctm *ctm);
 #ifdef CONFIG_PM_SLEEP
 int rcar_du_cmm_pm_suspend(struct rcar_du_crtc *rcrtc);
 int rcar_du_cmm_pm_resume(struct rcar_du_crtc *rcrtc);
-- 
2.7.4


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

* [PATCH 5/8] drm: rcar-du: Implement interfaces to set clu and lut using drm data structures
@ 2019-04-03 13:14   ` VenkataRajesh.Kalakodima
  0 siblings, 0 replies; 36+ messages in thread
From: VenkataRajesh.Kalakodima @ 2019-04-03 13:14 UTC (permalink / raw)
  To: linux-renesas-soc, devicetree, linux-kernel, linux-clk, dri-devel
  Cc: kalakodima venkata rajesh, Harsha M M

From: kalakodima venkata rajesh <venkatarajesh.kalakodima@in.bosch.com>

Impelement interfaces in cmm to set clu and lut tables using standard
drm data structures as input.

Signed-off-by: Harsha M M <harsha.manjulamallikarjun@in.bosch.com>

      - Resolved checkpatch errors
      - Resolved merge conflicts according to latest version

Signed-off-by: kalakodima venkata rajesh <venkatarajesh.kalakodima@in.bosch.com>
---
 drivers/gpu/drm/rcar-du/rcar_du_cmm.c  | 256 +++++++++++++++++++++++++++++++--
 drivers/gpu/drm/rcar-du/rcar_du_crtc.h |  11 ++
 2 files changed, 254 insertions(+), 13 deletions(-)

diff --git a/drivers/gpu/drm/rcar-du/rcar_du_cmm.c b/drivers/gpu/drm/rcar-du/rcar_du_cmm.c
index 7983039..af4668f 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_cmm.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_cmm.c
@@ -114,6 +114,8 @@ struct rcar_du_cmm_pending_event {
 	struct drm_gem_object *gem_obj;
 	struct rcar_du_cmm *du_cmm;
 	struct rcar_du_cmm_file_priv *fpriv;
+	unsigned int *lut_buf;
+	unsigned int *clu_buf;
 };
 
 struct cmm_module_t {
@@ -238,14 +240,6 @@ static long long diff_timevals(struct timeval *start, struct timeval *end)
 }
 #endif
 
-static void du_cmm_clk(struct rcar_du_cmm *du_cmm, bool on)
-{
-	if (on)
-		clk_prepare_enable(du_cmm->clock);
-	else
-		clk_disable_unprepare(du_cmm->clock);
-}
-
 static void rcar_du_cmm_queue_lut_update(struct rcar_du_cmm_pending_event *p)
 {
 	mutex_lock(&cmm_event_lock);
@@ -284,6 +278,223 @@ static void rcar_du_cmm_queue_clu_update(struct rcar_du_cmm_pending_event *p)
 	drm_crtc_vblank_get(&p->du_cmm->rcrtc->crtc);
 }
 
+static s64 rcar_du_cmm_multiply_coeff(unsigned int color, s64 coeff)
+{
+	s64 r_val;
+	bool is_neg = false;
+
+	if (coeff & BIT_ULL(63)) {
+		is_neg = true;
+		coeff &= ~BIT_ULL(63);
+	}
+
+	r_val = DIV_ROUND_CLOSEST(((s64)(color * coeff)), BIT_ULL(32));
+
+	if (is_neg)
+		return -r_val;
+
+	return r_val;
+}
+
+static unsigned int rcar_du_cmm_scalar_product(unsigned int r, unsigned int g,
+					       unsigned int b, s64 coeff1,
+					       s64 coeff2, s64 coeff3)
+{
+	s64 product;
+
+	product = rcar_du_cmm_multiply_coeff(r, coeff1)
+			+ rcar_du_cmm_multiply_coeff(g, coeff2)
+			+ rcar_du_cmm_multiply_coeff(b, coeff3);
+
+	return (unsigned int)clamp_val(product, 0, U8_MAX);
+}
+
+#ifdef DEBUG_PROCE_TIME
+static long long diff_timevals(struct timeval *start, struct timeval *end)
+{
+	return (end->tv_sec * 1000000LL + end->tv_usec) -
+		(start->tv_sec * 1000000LL + start->tv_usec);
+}
+#endif
+
+void *rcar_du_cmm_alloc_lut(void *cmm_handle)
+{
+	struct rcar_du_cmm_pending_event *p;
+
+	if (!cmm_handle)
+		return NULL;
+
+	p = kzalloc(sizeof(*p), GFP_KERNEL);
+	if (!p)
+		return NULL;
+
+	p->gem_obj = NULL;
+	p->event = CMM_EVENT_LUT_DONE;
+	p->stat = QUE_STAT_PENDING;
+	p->callback_data = 0;
+	p->du_cmm = cmm_handle;
+	p->fpriv = NULL;
+	p->lut_buf = kmalloc(CMM_LUT_NUM * 4, GFP_KERNEL);
+	if (!p->lut_buf) {
+		kfree(p);
+		return NULL;
+	}
+
+	return p;
+}
+
+void rcar_du_cmm_free_lut(void *lut_handle)
+{
+	struct rcar_du_cmm_pending_event *p =
+			(struct rcar_du_cmm_pending_event *)lut_handle;
+
+	kfree(p->lut_buf);
+	kfree(p);
+}
+
+int rcar_du_cmm_lut_valid(unsigned int lut_length)
+{
+	return (lut_length == CMM_LUT_NUM) ? 0 : -EINVAL;
+}
+
+void rcar_du_cmm_update_lut_and_free(void *lut_handle,
+				     struct drm_color_lut *lut,
+				     unsigned int lut_length)
+{
+	struct rcar_du_cmm_pending_event *p =
+			(struct rcar_du_cmm_pending_event *)lut_handle;
+	unsigned int color;
+
+	if (!p)
+		return;
+
+	if (rcar_du_cmm_lut_valid(lut_length))
+		return;
+
+	/* Convert drm_color_lut to the format handled by hardware */
+	for (color = 0; color < lut_length; color++) {
+		p->lut_buf[color] = 0;
+		p->lut_buf[color] |= drm_color_lut_extract(lut[color].red, 8)
+					<< 16;
+		p->lut_buf[color] |= drm_color_lut_extract(lut[color].green, 8)
+					<< 8;
+		p->lut_buf[color] |= drm_color_lut_extract(lut[color].blue, 8);
+	}
+	rcar_du_cmm_queue_lut_update(p);
+}
+
+void *rcar_du_cmm_alloc_clu(void *cmm_handle)
+{
+	struct rcar_du_cmm_pending_event *p;
+
+	if (!cmm_handle)
+		return NULL;
+
+	p = kzalloc(sizeof(*p), GFP_KERNEL);
+	if (!p)
+		return NULL;
+
+	p->gem_obj = NULL;
+	p->event = CMM_EVENT_CLU_DONE;
+	p->stat = QUE_STAT_PENDING;
+	p->callback_data = 0;
+	p->du_cmm = cmm_handle;
+	p->fpriv = NULL;
+	p->clu_buf = kmalloc(CMM_CLU_NUM * 4, GFP_KERNEL);
+	if (!p->clu_buf) {
+		kfree(p);
+		return NULL;
+	}
+
+	return p;
+}
+
+void rcar_du_cmm_free_clu(void *clu_handle)
+{
+	struct rcar_du_cmm_pending_event *p =
+			(struct rcar_du_cmm_pending_event *)clu_handle;
+
+	kfree(p->clu_buf);
+	kfree(p);
+}
+
+void rcar_du_cmm_update_clu_and_free(void *clu_handle,
+				     struct drm_color_ctm *ctm)
+{
+	struct rcar_du_cmm_pending_event *p =
+			(struct rcar_du_cmm_pending_event *)clu_handle;
+	unsigned int r_loop;
+	unsigned int g_loop;
+	unsigned int b_loop;
+	unsigned int step_size;
+	unsigned int step_fraction;
+	unsigned int clu_index = 0;
+
+	if (!p)
+		return;
+
+	step_size = U8_MAX / (CMM_CLU_SAMPLES - 1);
+	step_fraction = U8_MAX % (CMM_CLU_SAMPLES - 1);
+
+	/*Update clu table*/
+	for (b_loop = 0; b_loop < CMM_CLU_SAMPLES; b_loop++) {
+		unsigned int b;
+
+		b = (b_loop * step_size) +
+		    DIV_ROUND_CLOSEST((b_loop * step_fraction),
+				      (CMM_CLU_SAMPLES - 1));
+
+		for (g_loop = 0; g_loop < CMM_CLU_SAMPLES; g_loop++) {
+			unsigned int g;
+
+			g = (g_loop * step_size) +
+			    DIV_ROUND_CLOSEST((g_loop * step_fraction),
+					      (CMM_CLU_SAMPLES - 1));
+
+			for (r_loop = 0; r_loop < CMM_CLU_SAMPLES; r_loop++) {
+				unsigned int r;
+				unsigned int r_val;
+				unsigned int g_val;
+				unsigned int b_val;
+
+				r = (r_loop * step_size) +
+				    DIV_ROUND_CLOSEST((r_loop * step_fraction),
+						      (CMM_CLU_SAMPLES - 1));
+
+				p->clu_buf[clu_index] = 0;
+
+				r_val =	rcar_du_cmm_scalar_product
+						(r, g, b,
+						 ctm->matrix[0], ctm->matrix[1],
+						 ctm->matrix[2]);
+
+				g_val =	rcar_du_cmm_scalar_product
+						(r, g, b,
+						 ctm->matrix[3], ctm->matrix[4],
+						 ctm->matrix[5]);
+
+				b_val =	rcar_du_cmm_scalar_product
+						(r, g, b,
+						 ctm->matrix[6], ctm->matrix[7],
+						 ctm->matrix[8]);
+
+				p->clu_buf[clu_index++] = (r_val << 16) |
+							  (g_val << 8) | b_val;
+			}
+		}
+	}
+
+	rcar_du_cmm_queue_clu_update(p);
+}
+
+static void du_cmm_clk(struct rcar_du_cmm *du_cmm, bool on)
+{
+	if (on)
+		clk_prepare_enable(du_cmm->clock);
+	else
+		clk_disable_unprepare(du_cmm->clock);
+}
+
 int rcar_du_cmm_start_stop(struct rcar_du_crtc *rcrtc, bool on)
 {
 	struct rcar_du_cmm *du_cmm = rcrtc->cmm_handle;
@@ -424,8 +635,16 @@ static inline void _event_done_locked(struct rcar_du_cmm_pending_event *p)
 		list_add_tail(&p->link, cmm_done_list(p->du_cmm, p->fpriv));
 		wake_up_interruptible(&p->fpriv->event_wait);
 	} else {
-		/* link deleted by rcar_du_cmm_postclose */
-		kfree(p);
+		/* link deleted by rcar_du_cmm_postclose
+		 * OR it could also be due to set of ctm and gamma
+		 * properties through drm APIs.
+		 */
+		if (p->event == CMM_EVENT_LUT_DONE)
+			rcar_du_cmm_free_lut(p);
+		else if (p->event == CMM_EVENT_CLU_DONE)
+			rcar_du_cmm_free_clu(p);
+		else
+			kfree(p);
 	}
 }
 
@@ -479,7 +698,8 @@ event_pop_locked(struct cmm_module_t *module)
 
 	p->stat = QUE_STAT_ACTIVE;
 	list_del(&p->link); /* delete from du_cmm->[lut|clu|hgo].list */
-	list_add_tail(&p->link, &p->fpriv->active_list);
+	if (p->fpriv)
+		list_add_tail(&p->link, &p->fpriv->active_list);
 	cmm_vblank_put(p);
 
 	return p;
@@ -605,7 +825,11 @@ static int lut_set(struct rcar_du_cmm *du_cmm,
 		return -EINVAL;
 	}
 
-	lut_buf = gem_to_vaddr(stat->p->gem_obj);
+	if (stat->p->gem_obj)
+		lut_buf = gem_to_vaddr(stat->p->gem_obj);
+	else
+		lut_buf = stat->p->lut_buf;
+
 	for (i = 0; i < CMM_LUT_NUM; i++)
 		rcar_du_cmm_write(du_cmm, lut_base + i * 4, lut_buf[i]);
 
@@ -723,7 +947,11 @@ static int clu_set(struct rcar_du_cmm *du_cmm,
 		return -EINVAL;
 	}
 
-	clu_buf = gem_to_vaddr(stat->p->gem_obj);
+	if (stat->p->gem_obj)
+		clu_buf = gem_to_vaddr(stat->p->gem_obj);
+	else
+		clu_buf = stat->p->clu_buf;
+
 	rcar_du_cmm_write(du_cmm, addr_reg, 0);
 	for (i = 0; i < CMM_CLU_NUM; i++)
 		rcar_du_cmm_write(du_cmm, data_reg, clu_buf[i]);
@@ -1222,6 +1450,8 @@ int rcar_du_cmm_init(struct rcar_du_crtc *rcrtc)
 
 	rcrtc->cmm_handle = du_cmm;
 
+	drm_crtc_enable_color_mgmt(&rcrtc->crtc, 0, true, CMM_LUT_NUM);
+
 	dev_info(rcdu->dev, "DU%d use CMM(%s buffer)\n",
 		 rcrtc->index, du_cmm->dbuf ? "Double" : "Single");
 
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
index 74e0a22..5b85de4 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
+++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
@@ -115,6 +115,17 @@ void rcar_du_cmm_postclose(struct drm_device *dev, struct drm_file *file_priv);
 int rcar_du_cmm_start_stop(struct rcar_du_crtc *rcrtc, bool on);
 void rcar_du_cmm_kick(struct rcar_du_crtc *rcrtc);
 
+void *rcar_du_cmm_alloc_lut(void *cmm_handle);
+void rcar_du_cmm_free_lut(void *lut_handle);
+int rcar_du_cmm_lut_valid(unsigned int lut_length);
+void rcar_du_cmm_update_lut_and_free(void *lut_handle,
+				     struct drm_color_lut *lut,
+				     unsigned int lut_length);
+
+void *rcar_du_cmm_alloc_clu(void *cmm_handle);
+void rcar_du_cmm_free_clu(void *clu_handle);
+void rcar_du_cmm_update_clu_and_free(void *clu_handle,
+				     struct drm_color_ctm *ctm);
 #ifdef CONFIG_PM_SLEEP
 int rcar_du_cmm_pm_suspend(struct rcar_du_crtc *rcrtc);
 int rcar_du_cmm_pm_resume(struct rcar_du_crtc *rcrtc);
-- 
2.7.4

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

* [PATCH 6/8] drm: rcar-du: Implement atomic_check to check for gamma and ctm properties
  2019-04-03 13:14 ` VenkataRajesh.Kalakodima
@ 2019-04-03 13:14   ` VenkataRajesh.Kalakodima
  -1 siblings, 0 replies; 36+ messages in thread
From: VenkataRajesh.Kalakodima @ 2019-04-03 13:14 UTC (permalink / raw)
  To: linux-renesas-soc, devicetree, linux-kernel, linux-clk, dri-devel
  Cc: kalakodima venkata rajesh, Harsha M M

From: kalakodima venkata rajesh <venkatarajesh.kalakodima@in.bosch.com>

    Implement atomic helper check and allocate memory necessary for
    lut and clu tables

Signed-off-by: Harsha M M <harsha.manjulamallikarjun@in.bosch.com>

      - Resolved checkpatch errors
      - Resolved merge conflicts according to latest version
Signed-off-by: kalakodima venkata rajesh <venkatarajesh.kalakodima@in.bosch.com>
---
 drivers/gpu/drm/rcar-du/rcar_du_crtc.c | 58 ++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/rcar-du/rcar_du_crtc.h |  3 +-
 2 files changed, 60 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
index 864fb94..a00b7a7 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
@@ -622,6 +622,63 @@ static void rcar_du_crtc_stop(struct rcar_du_crtc *rcrtc)
  * CRTC Functions
  */
 
+static bool rcar_du_crtc_is_ctm_updated(struct drm_crtc *crtc,
+					struct drm_crtc_state *state)
+{
+	return (state->color_mgmt_changed && state->ctm &&
+		crtc->state->ctm &&
+		(crtc->state->ctm->base.id != state->ctm->base.id));
+}
+
+static bool rcar_du_crtc_is_gamma_updated(struct drm_crtc *crtc,
+					  struct drm_crtc_state *state)
+{
+	return (state->color_mgmt_changed && state->gamma_lut &&
+		crtc->state->gamma_lut &&
+		(crtc->state->gamma_lut->base.id != state->gamma_lut->base.id));
+}
+
+static int rcar_du_crtc_cmm_atomic_check(struct drm_crtc *crtc,
+					 struct drm_crtc_state *state)
+{
+	int ret = 0;
+	struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc);
+
+	/*Check gamma update and allocate memory*/
+	if (rcar_du_crtc_is_gamma_updated(crtc, state) &&
+	    !rcrtc->lut_handle) {
+		ret = rcar_du_cmm_lut_valid((crtc->state->gamma_lut->length /
+					     sizeof(struct drm_color_lut)));
+		if (ret >= 0) {
+			rcrtc->lut_handle =
+				rcar_du_cmm_alloc_lut(rcrtc->cmm_handle);
+			if (!rcrtc->lut_handle)
+				ret = -ENOMEM;
+		}
+	}
+
+	/*Check update of ctm and allocate memory*/
+	if (ret >= 0 && rcar_du_crtc_is_ctm_updated(crtc, state) &&
+	    !rcrtc->clu_handle) {
+		rcrtc->clu_handle = rcar_du_cmm_alloc_clu(rcrtc->cmm_handle);
+		if (!rcrtc->clu_handle) {
+			if (!rcrtc->lut_handle) {
+				rcar_du_cmm_free_lut(rcrtc->lut_handle);
+				rcrtc->lut_handle = NULL;
+			}
+			ret = -ENOMEM;
+		}
+	}
+
+	return ret;
+}
+
+static int rcar_du_crtc_atomic_check(struct drm_crtc *crtc,
+				     struct drm_crtc_state *state)
+{
+	return rcar_du_crtc_cmm_atomic_check(crtc, state);
+}
+
 static void rcar_du_crtc_atomic_enable(struct drm_crtc *crtc,
 				       struct drm_crtc_state *old_state)
 {
@@ -708,6 +765,7 @@ static const struct drm_crtc_helper_funcs crtc_helper_funcs = {
 	.atomic_flush = rcar_du_crtc_atomic_flush,
 	.atomic_enable = rcar_du_crtc_atomic_enable,
 	.atomic_disable = rcar_du_crtc_atomic_disable,
+	.atomic_check = rcar_du_crtc_atomic_check,
 };
 
 static struct drm_crtc_state *
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
index 5b85de4..b79080e 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
+++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
@@ -70,7 +70,8 @@ struct rcar_du_crtc {
 	int lvds_ch;
 
 	void *cmm_handle;
-
+	void *lut_handle;
+	void *clu_handle;
 };
 
 #define to_rcar_crtc(c)	container_of(c, struct rcar_du_crtc, crtc)
-- 
2.7.4


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

* [PATCH 6/8] drm: rcar-du: Implement atomic_check to check for gamma and ctm properties
@ 2019-04-03 13:14   ` VenkataRajesh.Kalakodima
  0 siblings, 0 replies; 36+ messages in thread
From: VenkataRajesh.Kalakodima @ 2019-04-03 13:14 UTC (permalink / raw)
  To: linux-renesas-soc, devicetree, linux-kernel, linux-clk, dri-devel
  Cc: kalakodima venkata rajesh, Harsha M M

From: kalakodima venkata rajesh <venkatarajesh.kalakodima@in.bosch.com>

    Implement atomic helper check and allocate memory necessary for
    lut and clu tables

Signed-off-by: Harsha M M <harsha.manjulamallikarjun@in.bosch.com>

      - Resolved checkpatch errors
      - Resolved merge conflicts according to latest version
Signed-off-by: kalakodima venkata rajesh <venkatarajesh.kalakodima@in.bosch.com>
---
 drivers/gpu/drm/rcar-du/rcar_du_crtc.c | 58 ++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/rcar-du/rcar_du_crtc.h |  3 +-
 2 files changed, 60 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
index 864fb94..a00b7a7 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
@@ -622,6 +622,63 @@ static void rcar_du_crtc_stop(struct rcar_du_crtc *rcrtc)
  * CRTC Functions
  */
 
+static bool rcar_du_crtc_is_ctm_updated(struct drm_crtc *crtc,
+					struct drm_crtc_state *state)
+{
+	return (state->color_mgmt_changed && state->ctm &&
+		crtc->state->ctm &&
+		(crtc->state->ctm->base.id != state->ctm->base.id));
+}
+
+static bool rcar_du_crtc_is_gamma_updated(struct drm_crtc *crtc,
+					  struct drm_crtc_state *state)
+{
+	return (state->color_mgmt_changed && state->gamma_lut &&
+		crtc->state->gamma_lut &&
+		(crtc->state->gamma_lut->base.id != state->gamma_lut->base.id));
+}
+
+static int rcar_du_crtc_cmm_atomic_check(struct drm_crtc *crtc,
+					 struct drm_crtc_state *state)
+{
+	int ret = 0;
+	struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc);
+
+	/*Check gamma update and allocate memory*/
+	if (rcar_du_crtc_is_gamma_updated(crtc, state) &&
+	    !rcrtc->lut_handle) {
+		ret = rcar_du_cmm_lut_valid((crtc->state->gamma_lut->length /
+					     sizeof(struct drm_color_lut)));
+		if (ret >= 0) {
+			rcrtc->lut_handle =
+				rcar_du_cmm_alloc_lut(rcrtc->cmm_handle);
+			if (!rcrtc->lut_handle)
+				ret = -ENOMEM;
+		}
+	}
+
+	/*Check update of ctm and allocate memory*/
+	if (ret >= 0 && rcar_du_crtc_is_ctm_updated(crtc, state) &&
+	    !rcrtc->clu_handle) {
+		rcrtc->clu_handle = rcar_du_cmm_alloc_clu(rcrtc->cmm_handle);
+		if (!rcrtc->clu_handle) {
+			if (!rcrtc->lut_handle) {
+				rcar_du_cmm_free_lut(rcrtc->lut_handle);
+				rcrtc->lut_handle = NULL;
+			}
+			ret = -ENOMEM;
+		}
+	}
+
+	return ret;
+}
+
+static int rcar_du_crtc_atomic_check(struct drm_crtc *crtc,
+				     struct drm_crtc_state *state)
+{
+	return rcar_du_crtc_cmm_atomic_check(crtc, state);
+}
+
 static void rcar_du_crtc_atomic_enable(struct drm_crtc *crtc,
 				       struct drm_crtc_state *old_state)
 {
@@ -708,6 +765,7 @@ static const struct drm_crtc_helper_funcs crtc_helper_funcs = {
 	.atomic_flush = rcar_du_crtc_atomic_flush,
 	.atomic_enable = rcar_du_crtc_atomic_enable,
 	.atomic_disable = rcar_du_crtc_atomic_disable,
+	.atomic_check = rcar_du_crtc_atomic_check,
 };
 
 static struct drm_crtc_state *
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
index 5b85de4..b79080e 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
+++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
@@ -70,7 +70,8 @@ struct rcar_du_crtc {
 	int lvds_ch;
 
 	void *cmm_handle;
-
+	void *lut_handle;
+	void *clu_handle;
 };
 
 #define to_rcar_crtc(c)	container_of(c, struct rcar_du_crtc, crtc)
-- 
2.7.4

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

* [PATCH 7/8] drm: rcar-du: update gamma and ctm properties in commit tail
  2019-04-03 13:14 ` VenkataRajesh.Kalakodima
@ 2019-04-03 13:14   ` VenkataRajesh.Kalakodima
  -1 siblings, 0 replies; 36+ messages in thread
From: VenkataRajesh.Kalakodima @ 2019-04-03 13:14 UTC (permalink / raw)
  To: linux-renesas-soc, devicetree, linux-kernel, linux-clk, dri-devel
  Cc: kalakodima venkata rajesh, Harsha M M

From: kalakodima venkata rajesh <venkatarajesh.kalakodima@in.bosch.com>

Update gamma and ctm properties if there is a change.

Signed-off-by: Harsha M M <harsha.manjulamallikarjun@in.bosch.com>

   - Fix compilation issues when for_each_crtc_in_state is not defined
   - Resolved checkpatch errors
   - Resolved merge conflicts according to latest version

Signed-off-by: kalakodima venkata rajesh <venkatarajesh.kalakodima@in.bosch.com>
---
 drivers/gpu/drm/rcar-du/rcar_du_kms.c | 25 +++++++++++++++++++++++++
 include/drm/drm_atomic.h              | 25 +++++++++++++++++++++++++
 2 files changed, 50 insertions(+)

diff --git a/drivers/gpu/drm/rcar-du/rcar_du_kms.c b/drivers/gpu/drm/rcar-du/rcar_du_kms.c
index f0bc7cc..4d9a19c 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_kms.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_kms.c
@@ -246,6 +246,10 @@ static int rcar_du_atomic_check(struct drm_device *dev,
 static void rcar_du_atomic_commit_tail(struct drm_atomic_state *old_state)
 {
 	struct drm_device *dev = old_state->dev;
+	struct drm_crtc *crtc;
+	struct drm_crtc_state *crtc_state;
+	struct rcar_du_crtc *rcrtc;
+	int i;
 
 	/* Apply the atomic update. */
 	drm_atomic_helper_commit_modeset_disables(dev, old_state);
@@ -253,6 +257,27 @@ static void rcar_du_atomic_commit_tail(struct drm_atomic_state *old_state)
 					DRM_PLANE_COMMIT_ACTIVE_ONLY);
 	drm_atomic_helper_commit_modeset_enables(dev, old_state);
 
+	/* Update gamma and ctm properties for all crtc in present
+	 * state. Update is done only if there is a change
+	 */
+	for_each_crtc_in_state(old_state, crtc, crtc_state, i) {
+		rcrtc = to_rcar_crtc(crtc);
+
+		if (rcrtc->lut_handle) {
+			rcar_du_cmm_update_lut_and_free
+			  (rcrtc->lut_handle,
+			   (struct drm_color_lut *)crtc->state->gamma_lut->data,
+			   (crtc->state->gamma_lut->length /
+			   sizeof(struct drm_color_lut)));
+			rcrtc->lut_handle = NULL;
+		}
+		if (rcrtc->clu_handle) {
+			rcar_du_cmm_update_clu_and_free
+			  (rcrtc->clu_handle,
+			   (struct drm_color_ctm *)crtc->state->ctm->data);
+			rcrtc->clu_handle = NULL;
+		}
+	}
 	drm_atomic_helper_commit_hw_done(old_state);
 	drm_atomic_helper_wait_for_flip_done(dev, old_state);
 
diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
index 1e71315..d22ccd8 100644
--- a/include/drm/drm_atomic.h
+++ b/include/drm/drm_atomic.h
@@ -693,6 +693,31 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p);
 			     (new_connector_state) = (__state)->connectors[__i].new_state, 1))
 
 /**
+ * for_each_crtc_in_state - iterate over all connectors in an atomic update
+ * @__state: &struct drm_atomic_state pointer
+ * @crtc: &struct drm_crtc iteration cursor
+ * @crtc_state: &struct drm_crtc_state iteration cursor
+ * @__i: int iteration cursor, for macro-internal use
+ *
+ * This iterates over all CRTCs in an atomic update. Note that before the
+ * software state is committed (by calling drm_atomic_helper_swap_state(), this
+ * points to the new state, while afterwards it points to the old state. Due to
+ * this tricky confusion this macro is deprecated.
+ *
+ * FIXME:
+ *
+ * Replace all usage of this with one of the explicit iterators below and then
+ * remove this macro.
+ */
+#define for_each_crtc_in_state(__state, crtc, crtc_state, __i)	\
+	for ((__i) = 0;						\
+	     ((__i) < ((__state)->dev->mode_config.num_crtc)) &&	\
+	     ((crtc) = ((__state)->crtcs[__i].ptr),			\
+	     (crtc_state) = ((__state)->crtcs[__i].state), 1);	\
+	     (__i)++)						\
+		for_each_if(crtc_state)
+
+/**
  * for_each_oldnew_crtc_in_state - iterate over all CRTCs in an atomic update
  * @__state: &struct drm_atomic_state pointer
  * @crtc: &struct drm_crtc iteration cursor
-- 
2.7.4


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

* [PATCH 7/8] drm: rcar-du: update gamma and ctm properties in commit tail
@ 2019-04-03 13:14   ` VenkataRajesh.Kalakodima
  0 siblings, 0 replies; 36+ messages in thread
From: VenkataRajesh.Kalakodima @ 2019-04-03 13:14 UTC (permalink / raw)
  To: linux-renesas-soc, devicetree, linux-kernel, linux-clk, dri-devel
  Cc: kalakodima venkata rajesh, Harsha M M

From: kalakodima venkata rajesh <venkatarajesh.kalakodima@in.bosch.com>

Update gamma and ctm properties if there is a change.

Signed-off-by: Harsha M M <harsha.manjulamallikarjun@in.bosch.com>

   - Fix compilation issues when for_each_crtc_in_state is not defined
   - Resolved checkpatch errors
   - Resolved merge conflicts according to latest version

Signed-off-by: kalakodima venkata rajesh <venkatarajesh.kalakodima@in.bosch.com>
---
 drivers/gpu/drm/rcar-du/rcar_du_kms.c | 25 +++++++++++++++++++++++++
 include/drm/drm_atomic.h              | 25 +++++++++++++++++++++++++
 2 files changed, 50 insertions(+)

diff --git a/drivers/gpu/drm/rcar-du/rcar_du_kms.c b/drivers/gpu/drm/rcar-du/rcar_du_kms.c
index f0bc7cc..4d9a19c 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_kms.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_kms.c
@@ -246,6 +246,10 @@ static int rcar_du_atomic_check(struct drm_device *dev,
 static void rcar_du_atomic_commit_tail(struct drm_atomic_state *old_state)
 {
 	struct drm_device *dev = old_state->dev;
+	struct drm_crtc *crtc;
+	struct drm_crtc_state *crtc_state;
+	struct rcar_du_crtc *rcrtc;
+	int i;
 
 	/* Apply the atomic update. */
 	drm_atomic_helper_commit_modeset_disables(dev, old_state);
@@ -253,6 +257,27 @@ static void rcar_du_atomic_commit_tail(struct drm_atomic_state *old_state)
 					DRM_PLANE_COMMIT_ACTIVE_ONLY);
 	drm_atomic_helper_commit_modeset_enables(dev, old_state);
 
+	/* Update gamma and ctm properties for all crtc in present
+	 * state. Update is done only if there is a change
+	 */
+	for_each_crtc_in_state(old_state, crtc, crtc_state, i) {
+		rcrtc = to_rcar_crtc(crtc);
+
+		if (rcrtc->lut_handle) {
+			rcar_du_cmm_update_lut_and_free
+			  (rcrtc->lut_handle,
+			   (struct drm_color_lut *)crtc->state->gamma_lut->data,
+			   (crtc->state->gamma_lut->length /
+			   sizeof(struct drm_color_lut)));
+			rcrtc->lut_handle = NULL;
+		}
+		if (rcrtc->clu_handle) {
+			rcar_du_cmm_update_clu_and_free
+			  (rcrtc->clu_handle,
+			   (struct drm_color_ctm *)crtc->state->ctm->data);
+			rcrtc->clu_handle = NULL;
+		}
+	}
 	drm_atomic_helper_commit_hw_done(old_state);
 	drm_atomic_helper_wait_for_flip_done(dev, old_state);
 
diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
index 1e71315..d22ccd8 100644
--- a/include/drm/drm_atomic.h
+++ b/include/drm/drm_atomic.h
@@ -693,6 +693,31 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p);
 			     (new_connector_state) = (__state)->connectors[__i].new_state, 1))
 
 /**
+ * for_each_crtc_in_state - iterate over all connectors in an atomic update
+ * @__state: &struct drm_atomic_state pointer
+ * @crtc: &struct drm_crtc iteration cursor
+ * @crtc_state: &struct drm_crtc_state iteration cursor
+ * @__i: int iteration cursor, for macro-internal use
+ *
+ * This iterates over all CRTCs in an atomic update. Note that before the
+ * software state is committed (by calling drm_atomic_helper_swap_state(), this
+ * points to the new state, while afterwards it points to the old state. Due to
+ * this tricky confusion this macro is deprecated.
+ *
+ * FIXME:
+ *
+ * Replace all usage of this with one of the explicit iterators below and then
+ * remove this macro.
+ */
+#define for_each_crtc_in_state(__state, crtc, crtc_state, __i)	\
+	for ((__i) = 0;						\
+	     ((__i) < ((__state)->dev->mode_config.num_crtc)) &&	\
+	     ((crtc) = ((__state)->crtcs[__i].ptr),			\
+	     (crtc_state) = ((__state)->crtcs[__i].state), 1);	\
+	     (__i)++)						\
+		for_each_if(crtc_state)
+
+/**
  * for_each_oldnew_crtc_in_state - iterate over all CRTCs in an atomic update
  * @__state: &struct drm_atomic_state pointer
  * @crtc: &struct drm_crtc iteration cursor
-- 
2.7.4

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

* [PATCH 8/8] drm: rcar-du: Add shutdown callback function in platform_driver
  2019-04-03 13:14 ` VenkataRajesh.Kalakodima
@ 2019-04-03 13:14   ` VenkataRajesh.Kalakodima
  -1 siblings, 0 replies; 36+ messages in thread
From: VenkataRajesh.Kalakodima @ 2019-04-03 13:14 UTC (permalink / raw)
  To: linux-renesas-soc, devicetree, linux-kernel, linux-clk, dri-devel
  Cc: kalakodima venkata rajesh, Koji Matsuoka, Steve Longerbeam,
	Balasubramani Vivekanandan

From: kalakodima venkata rajesh <venkatarajesh.kalakodima@in.bosch.com>

When rebooting, the Display driver is accessing H/W (reading DDR).
Therefore, there is a problem of hanging when setting DDR to self
refresh mode.

This patch implement the shutdown function and solve this problem
by stopping H/W access.

In addtion, on the ulcb board, since initial values of versaclock
are used as they are, signals are not output when initializing to
0 with shutdown, so this patch excludes processing to initialize
versaclock to 0.
drm: rcar-du: Add HDMI control clock when S2RAM

Signed-off-by: Koji Matsuoka <koji.matsuoka.xm@renesas.com>

(cherry picked from horms/renesas-bsp commit 3cfda6331c4069800dd4434427284aba8e6f1ed6)
[slongerbeam: keep integer i in rcar_du_pm_shutdown(), needed because of
 050e54d87f ("drm: rcar-du: drm: rcar-du: Add DU CMM support")]

Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>

drm: rcar-du: cmm: lut and clu backup not required during
 shutdown
rcar_du_cmm_pm_suspend function copies LUT and CLU hardare
register values to memory. In the patch which adds DU CMM
support (https://github.com/renesas-rcar/du_cmm/commit/
9a65d02119e4ae405a89a850463a6a0d0f2c1ecb), the intention of
the author was to backup the registers during suspend and
restore it on resume. But rcar_du_cmm_pm_suspend was also
called on system shutdown. Though it does not cause any harm,
it is not required during shutdown as it does not make sense
to backup. This patch ensures that rcar_du_cmm_pm_suspend is
called only during suspend

Fixes: https://github.com/renesas-rcar/du_cmm/commit/9a65d02119e4ae405a89a850463a6a0d0f2c1ecb

Signed-off-by: Balasubramani Vivekanandan <balasubramani_vivekanandan@mentor.com>

      - Resolved checkpatch errors
      - Resolved merge conflicts according to latest version

Signed-off-by: kalakodima venkata rajesh <venkatarajesh.kalakodima@in.bosch.com>
---
 drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 35 ++++++++++++++++++++
 drivers/gpu/drm/rcar-du/rcar_du_drv.c     | 54 +++++++++++++++++++++++++------
 drivers/gpu/drm/rcar-du/rcar_du_encoder.c |  2 +-
 drivers/gpu/drm/rcar-du/rcar_du_encoder.h |  1 +
 include/drm/bridge/dw_hdmi.h              |  1 +
 5 files changed, 83 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
index 5971976..aa257d7 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
@@ -2033,6 +2033,41 @@ static void dw_hdmi_bridge_enable(struct drm_bridge *bridge)
 	mutex_unlock(&hdmi->mutex);
 }
 
+/*
+ * This function controls clocks of dw_hdmi through drm_bridge
+ * at system suspend/resume.
+ * Arguments:
+ *  bridge: drm_bridge that contains dw_hdmi.
+ *  flag: controlled flag.
+ *		false: is used when suspend.
+ *		true: is used when resume.
+ */
+void dw_hdmi_s2r_ctrl(struct drm_bridge *bridge, int flag)
+{
+	struct dw_hdmi *hdmi = bridge->driver_private;
+
+	if (!hdmi)
+		return;
+
+	if (flag) { /* enable clk */
+		if (hdmi->isfr_clk)
+			clk_prepare_enable(hdmi->isfr_clk);
+		if (hdmi->iahb_clk)
+			clk_prepare_enable(hdmi->iahb_clk);
+
+		initialize_hdmi_ih_mutes(hdmi);
+		dw_hdmi_setup_i2c(hdmi);
+		dw_hdmi_i2c_init(hdmi);
+		dw_hdmi_phy_setup_hpd(hdmi, NULL);
+	} else { /* disable clk */
+		if (hdmi->isfr_clk)
+			clk_disable_unprepare(hdmi->isfr_clk);
+		if (hdmi->iahb_clk)
+			clk_disable_unprepare(hdmi->iahb_clk);
+	}
+}
+EXPORT_SYMBOL_GPL(dw_hdmi_s2r_ctrl);
+
 static const struct drm_bridge_funcs dw_hdmi_bridge_funcs = {
 	.attach = dw_hdmi_bridge_attach,
 	.enable = dw_hdmi_bridge_enable,
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
index 838b7c9..9eb63b0 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
@@ -21,6 +21,7 @@
 #include <linux/slab.h>
 #include <linux/wait.h>
 
+#include <drm/bridge/dw_hdmi.h>
 #include <drm/drmP.h>
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_crtc_helper.h>
@@ -368,18 +369,14 @@ static struct drm_driver rcar_du_driver = {
  */
 
 #ifdef CONFIG_PM_SLEEP
-static int rcar_du_pm_suspend(struct device *dev)
+static int rcar_du_pm_shutdown(struct device *dev)
 {
 	struct rcar_du_device *rcdu = dev_get_drvdata(dev);
 	struct drm_atomic_state *state;
-	int i;
-
-	if (rcar_du_has(rcdu, RCAR_DU_FEATURE_CMM)) {
-		for (i = 0; i < rcdu->num_crtcs; ++i)
-			rcar_du_cmm_pm_suspend(&rcdu->crtcs[i]);
-	}
-
-	drm_kms_helper_poll_disable(rcdu->ddev);
+#if IS_ENABLED(CONFIG_DRM_RCAR_DW_HDMI)
+	struct drm_encoder *encoder;
+#endif
+		drm_kms_helper_poll_disable(rcdu->ddev);
 	drm_fbdev_cma_set_suspend_unlocked(rcdu->fbdev, true);
 
 	state = drm_atomic_helper_suspend(rcdu->ddev);
@@ -389,11 +386,43 @@ static int rcar_du_pm_suspend(struct device *dev)
 		return PTR_ERR(state);
 	}
 
+#if IS_ENABLED(CONFIG_DRM_RCAR_DW_HDMI)
+	list_for_each_entry(encoder,
+			    &rcdu->ddev->mode_config.encoder_list,
+			    head) {
+		struct rcar_du_encoder *renc = to_rcar_encoder(encoder);
+
+		if (renc->bridge && (renc->output == RCAR_DU_OUTPUT_HDMI0 ||
+				     renc->output == RCAR_DU_OUTPUT_HDMI1))
+			dw_hdmi_s2r_ctrl(encoder->bridge, false);
+	}
+#endif
 	rcdu->suspend_state = state;
 
 	return 0;
 }
 
+static int rcar_du_pm_suspend(struct device *dev)
+{
+	struct rcar_du_device *rcdu = dev_get_drvdata(dev);
+
+	int i, ret;
+
+	if (rcar_du_has(rcdu, RCAR_DU_FEATURE_CMM)) {
+		for (i = 0; i < rcdu->num_crtcs; ++i)
+			rcar_du_cmm_pm_suspend(&rcdu->crtcs[i]);
+	}
+
+	ret = rcar_du_pm_shutdown(dev);
+
+	if (ret)
+		return ret;
+
+	for (i = 0; i < rcdu->num_crtcs; ++i)
+		clk_set_rate(rcdu->crtcs[i].extclock, 0);
+	return 0;
+}
+
 static int rcar_du_pm_resume(struct device *dev)
 {
 	struct rcar_du_device *rcdu = dev_get_drvdata(dev);
@@ -504,6 +533,12 @@ static int rcar_du_probe(struct platform_device *pdev)
 	return ret;
 }
 
+static void rcar_du_shutdown(struct platform_device *pdev)
+{
+#ifdef CONFIG_PM_SLEEP
+	rcar_du_pm_shutdown(&pdev->dev);
+#endif
+}
 static struct platform_driver rcar_du_platform_driver = {
 	.probe		= rcar_du_probe,
 	.remove		= rcar_du_remove,
@@ -512,6 +547,7 @@ static struct platform_driver rcar_du_platform_driver = {
 		.pm	= &rcar_du_pm_ops,
 		.of_match_table = rcar_du_of_table,
 	},
+	.shutdown       = rcar_du_shutdown,
 };
 
 static int __init rcar_du_init(void)
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_encoder.c b/drivers/gpu/drm/rcar-du/rcar_du_encoder.c
index f9c933d..98df8a2 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_encoder.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_encoder.c
@@ -62,7 +62,7 @@ int rcar_du_encoder_init(struct rcar_du_device *rcdu,
 
 	dev_dbg(rcdu->dev, "initializing encoder %pOF for output %u\n",
 		enc_node, output);
-
+	renc->bridge = bridge;
 	/* Locate the DRM bridge from the encoder DT node. */
 	bridge = of_drm_find_bridge(enc_node);
 	if (!bridge) {
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_encoder.h b/drivers/gpu/drm/rcar-du/rcar_du_encoder.h
index 2d2abca..cc5bfcb 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_encoder.h
+++ b/drivers/gpu/drm/rcar-du/rcar_du_encoder.h
@@ -23,6 +23,7 @@ struct rcar_du_device;
 struct rcar_du_encoder {
 	struct drm_encoder base;
 	enum rcar_du_output output;
+	struct drm_bridge *bridge;
 };
 
 #define to_rcar_encoder(e) \
diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h
index ccb5aa8..36383cf4 100644
--- a/include/drm/bridge/dw_hdmi.h
+++ b/include/drm/bridge/dw_hdmi.h
@@ -171,5 +171,6 @@ enum drm_connector_status dw_hdmi_phy_read_hpd(struct dw_hdmi *hdmi,
 void dw_hdmi_phy_update_hpd(struct dw_hdmi *hdmi, void *data,
 			    bool force, bool disabled, bool rxsense);
 void dw_hdmi_phy_setup_hpd(struct dw_hdmi *hdmi, void *data);
+void dw_hdmi_s2r_ctrl(struct drm_bridge *bridge, int flag);
 
 #endif /* __IMX_HDMI_H__ */
-- 
2.7.4


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

* [PATCH 8/8] drm: rcar-du: Add shutdown callback function in platform_driver
@ 2019-04-03 13:14   ` VenkataRajesh.Kalakodima
  0 siblings, 0 replies; 36+ messages in thread
From: VenkataRajesh.Kalakodima @ 2019-04-03 13:14 UTC (permalink / raw)
  To: linux-renesas-soc, devicetree, linux-kernel, linux-clk, dri-devel
  Cc: kalakodima venkata rajesh, Koji Matsuoka, Steve Longerbeam,
	Balasubramani Vivekanandan

From: kalakodima venkata rajesh <venkatarajesh.kalakodima@in.bosch.com>

When rebooting, the Display driver is accessing H/W (reading DDR).
Therefore, there is a problem of hanging when setting DDR to self
refresh mode.

This patch implement the shutdown function and solve this problem
by stopping H/W access.

In addtion, on the ulcb board, since initial values of versaclock
are used as they are, signals are not output when initializing to
0 with shutdown, so this patch excludes processing to initialize
versaclock to 0.
drm: rcar-du: Add HDMI control clock when S2RAM

Signed-off-by: Koji Matsuoka <koji.matsuoka.xm@renesas.com>

(cherry picked from horms/renesas-bsp commit 3cfda6331c4069800dd4434427284aba8e6f1ed6)
[slongerbeam: keep integer i in rcar_du_pm_shutdown(), needed because of
 050e54d87f ("drm: rcar-du: drm: rcar-du: Add DU CMM support")]

Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>

drm: rcar-du: cmm: lut and clu backup not required during
 shutdown
rcar_du_cmm_pm_suspend function copies LUT and CLU hardare
register values to memory. In the patch which adds DU CMM
support (https://github.com/renesas-rcar/du_cmm/commit/
9a65d02119e4ae405a89a850463a6a0d0f2c1ecb), the intention of
the author was to backup the registers during suspend and
restore it on resume. But rcar_du_cmm_pm_suspend was also
called on system shutdown. Though it does not cause any harm,
it is not required during shutdown as it does not make sense
to backup. This patch ensures that rcar_du_cmm_pm_suspend is
called only during suspend

Fixes: https://github.com/renesas-rcar/du_cmm/commit/9a65d02119e4ae405a89a850463a6a0d0f2c1ecb

Signed-off-by: Balasubramani Vivekanandan <balasubramani_vivekanandan@mentor.com>

      - Resolved checkpatch errors
      - Resolved merge conflicts according to latest version

Signed-off-by: kalakodima venkata rajesh <venkatarajesh.kalakodima@in.bosch.com>
---
 drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 35 ++++++++++++++++++++
 drivers/gpu/drm/rcar-du/rcar_du_drv.c     | 54 +++++++++++++++++++++++++------
 drivers/gpu/drm/rcar-du/rcar_du_encoder.c |  2 +-
 drivers/gpu/drm/rcar-du/rcar_du_encoder.h |  1 +
 include/drm/bridge/dw_hdmi.h              |  1 +
 5 files changed, 83 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
index 5971976..aa257d7 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
@@ -2033,6 +2033,41 @@ static void dw_hdmi_bridge_enable(struct drm_bridge *bridge)
 	mutex_unlock(&hdmi->mutex);
 }
 
+/*
+ * This function controls clocks of dw_hdmi through drm_bridge
+ * at system suspend/resume.
+ * Arguments:
+ *  bridge: drm_bridge that contains dw_hdmi.
+ *  flag: controlled flag.
+ *		false: is used when suspend.
+ *		true: is used when resume.
+ */
+void dw_hdmi_s2r_ctrl(struct drm_bridge *bridge, int flag)
+{
+	struct dw_hdmi *hdmi = bridge->driver_private;
+
+	if (!hdmi)
+		return;
+
+	if (flag) { /* enable clk */
+		if (hdmi->isfr_clk)
+			clk_prepare_enable(hdmi->isfr_clk);
+		if (hdmi->iahb_clk)
+			clk_prepare_enable(hdmi->iahb_clk);
+
+		initialize_hdmi_ih_mutes(hdmi);
+		dw_hdmi_setup_i2c(hdmi);
+		dw_hdmi_i2c_init(hdmi);
+		dw_hdmi_phy_setup_hpd(hdmi, NULL);
+	} else { /* disable clk */
+		if (hdmi->isfr_clk)
+			clk_disable_unprepare(hdmi->isfr_clk);
+		if (hdmi->iahb_clk)
+			clk_disable_unprepare(hdmi->iahb_clk);
+	}
+}
+EXPORT_SYMBOL_GPL(dw_hdmi_s2r_ctrl);
+
 static const struct drm_bridge_funcs dw_hdmi_bridge_funcs = {
 	.attach = dw_hdmi_bridge_attach,
 	.enable = dw_hdmi_bridge_enable,
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
index 838b7c9..9eb63b0 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
@@ -21,6 +21,7 @@
 #include <linux/slab.h>
 #include <linux/wait.h>
 
+#include <drm/bridge/dw_hdmi.h>
 #include <drm/drmP.h>
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_crtc_helper.h>
@@ -368,18 +369,14 @@ static struct drm_driver rcar_du_driver = {
  */
 
 #ifdef CONFIG_PM_SLEEP
-static int rcar_du_pm_suspend(struct device *dev)
+static int rcar_du_pm_shutdown(struct device *dev)
 {
 	struct rcar_du_device *rcdu = dev_get_drvdata(dev);
 	struct drm_atomic_state *state;
-	int i;
-
-	if (rcar_du_has(rcdu, RCAR_DU_FEATURE_CMM)) {
-		for (i = 0; i < rcdu->num_crtcs; ++i)
-			rcar_du_cmm_pm_suspend(&rcdu->crtcs[i]);
-	}
-
-	drm_kms_helper_poll_disable(rcdu->ddev);
+#if IS_ENABLED(CONFIG_DRM_RCAR_DW_HDMI)
+	struct drm_encoder *encoder;
+#endif
+		drm_kms_helper_poll_disable(rcdu->ddev);
 	drm_fbdev_cma_set_suspend_unlocked(rcdu->fbdev, true);
 
 	state = drm_atomic_helper_suspend(rcdu->ddev);
@@ -389,11 +386,43 @@ static int rcar_du_pm_suspend(struct device *dev)
 		return PTR_ERR(state);
 	}
 
+#if IS_ENABLED(CONFIG_DRM_RCAR_DW_HDMI)
+	list_for_each_entry(encoder,
+			    &rcdu->ddev->mode_config.encoder_list,
+			    head) {
+		struct rcar_du_encoder *renc = to_rcar_encoder(encoder);
+
+		if (renc->bridge && (renc->output == RCAR_DU_OUTPUT_HDMI0 ||
+				     renc->output == RCAR_DU_OUTPUT_HDMI1))
+			dw_hdmi_s2r_ctrl(encoder->bridge, false);
+	}
+#endif
 	rcdu->suspend_state = state;
 
 	return 0;
 }
 
+static int rcar_du_pm_suspend(struct device *dev)
+{
+	struct rcar_du_device *rcdu = dev_get_drvdata(dev);
+
+	int i, ret;
+
+	if (rcar_du_has(rcdu, RCAR_DU_FEATURE_CMM)) {
+		for (i = 0; i < rcdu->num_crtcs; ++i)
+			rcar_du_cmm_pm_suspend(&rcdu->crtcs[i]);
+	}
+
+	ret = rcar_du_pm_shutdown(dev);
+
+	if (ret)
+		return ret;
+
+	for (i = 0; i < rcdu->num_crtcs; ++i)
+		clk_set_rate(rcdu->crtcs[i].extclock, 0);
+	return 0;
+}
+
 static int rcar_du_pm_resume(struct device *dev)
 {
 	struct rcar_du_device *rcdu = dev_get_drvdata(dev);
@@ -504,6 +533,12 @@ static int rcar_du_probe(struct platform_device *pdev)
 	return ret;
 }
 
+static void rcar_du_shutdown(struct platform_device *pdev)
+{
+#ifdef CONFIG_PM_SLEEP
+	rcar_du_pm_shutdown(&pdev->dev);
+#endif
+}
 static struct platform_driver rcar_du_platform_driver = {
 	.probe		= rcar_du_probe,
 	.remove		= rcar_du_remove,
@@ -512,6 +547,7 @@ static struct platform_driver rcar_du_platform_driver = {
 		.pm	= &rcar_du_pm_ops,
 		.of_match_table = rcar_du_of_table,
 	},
+	.shutdown       = rcar_du_shutdown,
 };
 
 static int __init rcar_du_init(void)
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_encoder.c b/drivers/gpu/drm/rcar-du/rcar_du_encoder.c
index f9c933d..98df8a2 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_encoder.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_encoder.c
@@ -62,7 +62,7 @@ int rcar_du_encoder_init(struct rcar_du_device *rcdu,
 
 	dev_dbg(rcdu->dev, "initializing encoder %pOF for output %u\n",
 		enc_node, output);
-
+	renc->bridge = bridge;
 	/* Locate the DRM bridge from the encoder DT node. */
 	bridge = of_drm_find_bridge(enc_node);
 	if (!bridge) {
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_encoder.h b/drivers/gpu/drm/rcar-du/rcar_du_encoder.h
index 2d2abca..cc5bfcb 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_encoder.h
+++ b/drivers/gpu/drm/rcar-du/rcar_du_encoder.h
@@ -23,6 +23,7 @@ struct rcar_du_device;
 struct rcar_du_encoder {
 	struct drm_encoder base;
 	enum rcar_du_output output;
+	struct drm_bridge *bridge;
 };
 
 #define to_rcar_encoder(e) \
diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h
index ccb5aa8..36383cf4 100644
--- a/include/drm/bridge/dw_hdmi.h
+++ b/include/drm/bridge/dw_hdmi.h
@@ -171,5 +171,6 @@ enum drm_connector_status dw_hdmi_phy_read_hpd(struct dw_hdmi *hdmi,
 void dw_hdmi_phy_update_hpd(struct dw_hdmi *hdmi, void *data,
 			    bool force, bool disabled, bool rxsense);
 void dw_hdmi_phy_setup_hpd(struct dw_hdmi *hdmi, void *data);
+void dw_hdmi_s2r_ctrl(struct drm_bridge *bridge, int flag);
 
 #endif /* __IMX_HDMI_H__ */
-- 
2.7.4

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

* Re: [PATCH 8/8] drm: rcar-du: Add shutdown callback function in platform_driver
  2019-04-03 13:14   ` VenkataRajesh.Kalakodima
@ 2019-04-04  7:47     ` Daniel Vetter
  -1 siblings, 0 replies; 36+ messages in thread
From: Daniel Vetter @ 2019-04-04  7:47 UTC (permalink / raw)
  To: VenkataRajesh.Kalakodima
  Cc: linux-renesas-soc, devicetree, linux-kernel, linux-clk,
	dri-devel, Balasubramani Vivekanandan, Steve Longerbeam,
	Koji Matsuoka

On Wed, Apr 03, 2019 at 06:44:44PM +0530, VenkataRajesh.Kalakodima@in.bosch.com wrote:
> From: kalakodima venkata rajesh <venkatarajesh.kalakodima@in.bosch.com>
> 
> When rebooting, the Display driver is accessing H/W (reading DDR).
> Therefore, there is a problem of hanging when setting DDR to self
> refresh mode.
> 
> This patch implement the shutdown function and solve this problem
> by stopping H/W access.
> 
> In addtion, on the ulcb board, since initial values of versaclock
> are used as they are, signals are not output when initializing to
> 0 with shutdown, so this patch excludes processing to initialize
> versaclock to 0.
> drm: rcar-du: Add HDMI control clock when S2RAM
> 
> Signed-off-by: Koji Matsuoka <koji.matsuoka.xm@renesas.com>
> 
> (cherry picked from horms/renesas-bsp commit 3cfda6331c4069800dd4434427284aba8e6f1ed6)
> [slongerbeam: keep integer i in rcar_du_pm_shutdown(), needed because of
>  050e54d87f ("drm: rcar-du: drm: rcar-du: Add DU CMM support")]
> 
> Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>

Maybe look into drm_atomic_helper_shutdown instead of hand-rolling? That
should disable all display related stuff for you.
-Daniel

> 
> drm: rcar-du: cmm: lut and clu backup not required during
>  shutdown
> rcar_du_cmm_pm_suspend function copies LUT and CLU hardare
> register values to memory. In the patch which adds DU CMM
> support (https://github.com/renesas-rcar/du_cmm/commit/
> 9a65d02119e4ae405a89a850463a6a0d0f2c1ecb), the intention of
> the author was to backup the registers during suspend and
> restore it on resume. But rcar_du_cmm_pm_suspend was also
> called on system shutdown. Though it does not cause any harm,
> it is not required during shutdown as it does not make sense
> to backup. This patch ensures that rcar_du_cmm_pm_suspend is
> called only during suspend
> 
> Fixes: https://github.com/renesas-rcar/du_cmm/commit/9a65d02119e4ae405a89a850463a6a0d0f2c1ecb
> 
> Signed-off-by: Balasubramani Vivekanandan <balasubramani_vivekanandan@mentor.com>
> 
>       - Resolved checkpatch errors
>       - Resolved merge conflicts according to latest version
> 
> Signed-off-by: kalakodima venkata rajesh <venkatarajesh.kalakodima@in.bosch.com>
> ---
>  drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 35 ++++++++++++++++++++
>  drivers/gpu/drm/rcar-du/rcar_du_drv.c     | 54 +++++++++++++++++++++++++------
>  drivers/gpu/drm/rcar-du/rcar_du_encoder.c |  2 +-
>  drivers/gpu/drm/rcar-du/rcar_du_encoder.h |  1 +
>  include/drm/bridge/dw_hdmi.h              |  1 +
>  5 files changed, 83 insertions(+), 10 deletions(-)
> 
> diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> index 5971976..aa257d7 100644
> --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> @@ -2033,6 +2033,41 @@ static void dw_hdmi_bridge_enable(struct drm_bridge *bridge)
>  	mutex_unlock(&hdmi->mutex);
>  }
>  
> +/*
> + * This function controls clocks of dw_hdmi through drm_bridge
> + * at system suspend/resume.
> + * Arguments:
> + *  bridge: drm_bridge that contains dw_hdmi.
> + *  flag: controlled flag.
> + *		false: is used when suspend.
> + *		true: is used when resume.
> + */
> +void dw_hdmi_s2r_ctrl(struct drm_bridge *bridge, int flag)
> +{
> +	struct dw_hdmi *hdmi = bridge->driver_private;
> +
> +	if (!hdmi)
> +		return;
> +
> +	if (flag) { /* enable clk */
> +		if (hdmi->isfr_clk)
> +			clk_prepare_enable(hdmi->isfr_clk);
> +		if (hdmi->iahb_clk)
> +			clk_prepare_enable(hdmi->iahb_clk);
> +
> +		initialize_hdmi_ih_mutes(hdmi);
> +		dw_hdmi_setup_i2c(hdmi);
> +		dw_hdmi_i2c_init(hdmi);
> +		dw_hdmi_phy_setup_hpd(hdmi, NULL);
> +	} else { /* disable clk */
> +		if (hdmi->isfr_clk)
> +			clk_disable_unprepare(hdmi->isfr_clk);
> +		if (hdmi->iahb_clk)
> +			clk_disable_unprepare(hdmi->iahb_clk);
> +	}
> +}
> +EXPORT_SYMBOL_GPL(dw_hdmi_s2r_ctrl);
> +
>  static const struct drm_bridge_funcs dw_hdmi_bridge_funcs = {
>  	.attach = dw_hdmi_bridge_attach,
>  	.enable = dw_hdmi_bridge_enable,
> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
> index 838b7c9..9eb63b0 100644
> --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
> @@ -21,6 +21,7 @@
>  #include <linux/slab.h>
>  #include <linux/wait.h>
>  
> +#include <drm/bridge/dw_hdmi.h>
>  #include <drm/drmP.h>
>  #include <drm/drm_atomic_helper.h>
>  #include <drm/drm_crtc_helper.h>
> @@ -368,18 +369,14 @@ static struct drm_driver rcar_du_driver = {
>   */
>  
>  #ifdef CONFIG_PM_SLEEP
> -static int rcar_du_pm_suspend(struct device *dev)
> +static int rcar_du_pm_shutdown(struct device *dev)
>  {
>  	struct rcar_du_device *rcdu = dev_get_drvdata(dev);
>  	struct drm_atomic_state *state;
> -	int i;
> -
> -	if (rcar_du_has(rcdu, RCAR_DU_FEATURE_CMM)) {
> -		for (i = 0; i < rcdu->num_crtcs; ++i)
> -			rcar_du_cmm_pm_suspend(&rcdu->crtcs[i]);
> -	}
> -
> -	drm_kms_helper_poll_disable(rcdu->ddev);
> +#if IS_ENABLED(CONFIG_DRM_RCAR_DW_HDMI)
> +	struct drm_encoder *encoder;
> +#endif
> +		drm_kms_helper_poll_disable(rcdu->ddev);
>  	drm_fbdev_cma_set_suspend_unlocked(rcdu->fbdev, true);
>  
>  	state = drm_atomic_helper_suspend(rcdu->ddev);
> @@ -389,11 +386,43 @@ static int rcar_du_pm_suspend(struct device *dev)
>  		return PTR_ERR(state);
>  	}
>  
> +#if IS_ENABLED(CONFIG_DRM_RCAR_DW_HDMI)
> +	list_for_each_entry(encoder,
> +			    &rcdu->ddev->mode_config.encoder_list,
> +			    head) {
> +		struct rcar_du_encoder *renc = to_rcar_encoder(encoder);
> +
> +		if (renc->bridge && (renc->output == RCAR_DU_OUTPUT_HDMI0 ||
> +				     renc->output == RCAR_DU_OUTPUT_HDMI1))
> +			dw_hdmi_s2r_ctrl(encoder->bridge, false);
> +	}
> +#endif
>  	rcdu->suspend_state = state;
>  
>  	return 0;
>  }
>  
> +static int rcar_du_pm_suspend(struct device *dev)
> +{
> +	struct rcar_du_device *rcdu = dev_get_drvdata(dev);
> +
> +	int i, ret;
> +
> +	if (rcar_du_has(rcdu, RCAR_DU_FEATURE_CMM)) {
> +		for (i = 0; i < rcdu->num_crtcs; ++i)
> +			rcar_du_cmm_pm_suspend(&rcdu->crtcs[i]);
> +	}
> +
> +	ret = rcar_du_pm_shutdown(dev);
> +
> +	if (ret)
> +		return ret;
> +
> +	for (i = 0; i < rcdu->num_crtcs; ++i)
> +		clk_set_rate(rcdu->crtcs[i].extclock, 0);
> +	return 0;
> +}
> +
>  static int rcar_du_pm_resume(struct device *dev)
>  {
>  	struct rcar_du_device *rcdu = dev_get_drvdata(dev);
> @@ -504,6 +533,12 @@ static int rcar_du_probe(struct platform_device *pdev)
>  	return ret;
>  }
>  
> +static void rcar_du_shutdown(struct platform_device *pdev)
> +{
> +#ifdef CONFIG_PM_SLEEP
> +	rcar_du_pm_shutdown(&pdev->dev);
> +#endif
> +}
>  static struct platform_driver rcar_du_platform_driver = {
>  	.probe		= rcar_du_probe,
>  	.remove		= rcar_du_remove,
> @@ -512,6 +547,7 @@ static struct platform_driver rcar_du_platform_driver = {
>  		.pm	= &rcar_du_pm_ops,
>  		.of_match_table = rcar_du_of_table,
>  	},
> +	.shutdown       = rcar_du_shutdown,
>  };
>  
>  static int __init rcar_du_init(void)
> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_encoder.c b/drivers/gpu/drm/rcar-du/rcar_du_encoder.c
> index f9c933d..98df8a2 100644
> --- a/drivers/gpu/drm/rcar-du/rcar_du_encoder.c
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_encoder.c
> @@ -62,7 +62,7 @@ int rcar_du_encoder_init(struct rcar_du_device *rcdu,
>  
>  	dev_dbg(rcdu->dev, "initializing encoder %pOF for output %u\n",
>  		enc_node, output);
> -
> +	renc->bridge = bridge;
>  	/* Locate the DRM bridge from the encoder DT node. */
>  	bridge = of_drm_find_bridge(enc_node);
>  	if (!bridge) {
> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_encoder.h b/drivers/gpu/drm/rcar-du/rcar_du_encoder.h
> index 2d2abca..cc5bfcb 100644
> --- a/drivers/gpu/drm/rcar-du/rcar_du_encoder.h
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_encoder.h
> @@ -23,6 +23,7 @@ struct rcar_du_device;
>  struct rcar_du_encoder {
>  	struct drm_encoder base;
>  	enum rcar_du_output output;
> +	struct drm_bridge *bridge;
>  };
>  
>  #define to_rcar_encoder(e) \
> diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h
> index ccb5aa8..36383cf4 100644
> --- a/include/drm/bridge/dw_hdmi.h
> +++ b/include/drm/bridge/dw_hdmi.h
> @@ -171,5 +171,6 @@ enum drm_connector_status dw_hdmi_phy_read_hpd(struct dw_hdmi *hdmi,
>  void dw_hdmi_phy_update_hpd(struct dw_hdmi *hdmi, void *data,
>  			    bool force, bool disabled, bool rxsense);
>  void dw_hdmi_phy_setup_hpd(struct dw_hdmi *hdmi, void *data);
> +void dw_hdmi_s2r_ctrl(struct drm_bridge *bridge, int flag);
>  
>  #endif /* __IMX_HDMI_H__ */
> -- 
> 2.7.4
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

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

* Re: [PATCH 8/8] drm: rcar-du: Add shutdown callback function in platform_driver
@ 2019-04-04  7:47     ` Daniel Vetter
  0 siblings, 0 replies; 36+ messages in thread
From: Daniel Vetter @ 2019-04-04  7:47 UTC (permalink / raw)
  To: VenkataRajesh.Kalakodima
  Cc: linux-renesas-soc, devicetree, linux-kernel, linux-clk,
	dri-devel, Balasubramani Vivekanandan, Steve Longerbeam,
	Koji Matsuoka

On Wed, Apr 03, 2019 at 06:44:44PM +0530, VenkataRajesh.Kalakodima@in.bosch.com wrote:
> From: kalakodima venkata rajesh <venkatarajesh.kalakodima@in.bosch.com>
> 
> When rebooting, the Display driver is accessing H/W (reading DDR).
> Therefore, there is a problem of hanging when setting DDR to self
> refresh mode.
> 
> This patch implement the shutdown function and solve this problem
> by stopping H/W access.
> 
> In addtion, on the ulcb board, since initial values of versaclock
> are used as they are, signals are not output when initializing to
> 0 with shutdown, so this patch excludes processing to initialize
> versaclock to 0.
> drm: rcar-du: Add HDMI control clock when S2RAM
> 
> Signed-off-by: Koji Matsuoka <koji.matsuoka.xm@renesas.com>
> 
> (cherry picked from horms/renesas-bsp commit 3cfda6331c4069800dd4434427284aba8e6f1ed6)
> [slongerbeam: keep integer i in rcar_du_pm_shutdown(), needed because of
>  050e54d87f ("drm: rcar-du: drm: rcar-du: Add DU CMM support")]
> 
> Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>

Maybe look into drm_atomic_helper_shutdown instead of hand-rolling? That
should disable all display related stuff for you.
-Daniel

> 
> drm: rcar-du: cmm: lut and clu backup not required during
>  shutdown
> rcar_du_cmm_pm_suspend function copies LUT and CLU hardare
> register values to memory. In the patch which adds DU CMM
> support (https://github.com/renesas-rcar/du_cmm/commit/
> 9a65d02119e4ae405a89a850463a6a0d0f2c1ecb), the intention of
> the author was to backup the registers during suspend and
> restore it on resume. But rcar_du_cmm_pm_suspend was also
> called on system shutdown. Though it does not cause any harm,
> it is not required during shutdown as it does not make sense
> to backup. This patch ensures that rcar_du_cmm_pm_suspend is
> called only during suspend
> 
> Fixes: https://github.com/renesas-rcar/du_cmm/commit/9a65d02119e4ae405a89a850463a6a0d0f2c1ecb
> 
> Signed-off-by: Balasubramani Vivekanandan <balasubramani_vivekanandan@mentor.com>
> 
>       - Resolved checkpatch errors
>       - Resolved merge conflicts according to latest version
> 
> Signed-off-by: kalakodima venkata rajesh <venkatarajesh.kalakodima@in.bosch.com>
> ---
>  drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 35 ++++++++++++++++++++
>  drivers/gpu/drm/rcar-du/rcar_du_drv.c     | 54 +++++++++++++++++++++++++------
>  drivers/gpu/drm/rcar-du/rcar_du_encoder.c |  2 +-
>  drivers/gpu/drm/rcar-du/rcar_du_encoder.h |  1 +
>  include/drm/bridge/dw_hdmi.h              |  1 +
>  5 files changed, 83 insertions(+), 10 deletions(-)
> 
> diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> index 5971976..aa257d7 100644
> --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> @@ -2033,6 +2033,41 @@ static void dw_hdmi_bridge_enable(struct drm_bridge *bridge)
>  	mutex_unlock(&hdmi->mutex);
>  }
>  
> +/*
> + * This function controls clocks of dw_hdmi through drm_bridge
> + * at system suspend/resume.
> + * Arguments:
> + *  bridge: drm_bridge that contains dw_hdmi.
> + *  flag: controlled flag.
> + *		false: is used when suspend.
> + *		true: is used when resume.
> + */
> +void dw_hdmi_s2r_ctrl(struct drm_bridge *bridge, int flag)
> +{
> +	struct dw_hdmi *hdmi = bridge->driver_private;
> +
> +	if (!hdmi)
> +		return;
> +
> +	if (flag) { /* enable clk */
> +		if (hdmi->isfr_clk)
> +			clk_prepare_enable(hdmi->isfr_clk);
> +		if (hdmi->iahb_clk)
> +			clk_prepare_enable(hdmi->iahb_clk);
> +
> +		initialize_hdmi_ih_mutes(hdmi);
> +		dw_hdmi_setup_i2c(hdmi);
> +		dw_hdmi_i2c_init(hdmi);
> +		dw_hdmi_phy_setup_hpd(hdmi, NULL);
> +	} else { /* disable clk */
> +		if (hdmi->isfr_clk)
> +			clk_disable_unprepare(hdmi->isfr_clk);
> +		if (hdmi->iahb_clk)
> +			clk_disable_unprepare(hdmi->iahb_clk);
> +	}
> +}
> +EXPORT_SYMBOL_GPL(dw_hdmi_s2r_ctrl);
> +
>  static const struct drm_bridge_funcs dw_hdmi_bridge_funcs = {
>  	.attach = dw_hdmi_bridge_attach,
>  	.enable = dw_hdmi_bridge_enable,
> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
> index 838b7c9..9eb63b0 100644
> --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
> @@ -21,6 +21,7 @@
>  #include <linux/slab.h>
>  #include <linux/wait.h>
>  
> +#include <drm/bridge/dw_hdmi.h>
>  #include <drm/drmP.h>
>  #include <drm/drm_atomic_helper.h>
>  #include <drm/drm_crtc_helper.h>
> @@ -368,18 +369,14 @@ static struct drm_driver rcar_du_driver = {
>   */
>  
>  #ifdef CONFIG_PM_SLEEP
> -static int rcar_du_pm_suspend(struct device *dev)
> +static int rcar_du_pm_shutdown(struct device *dev)
>  {
>  	struct rcar_du_device *rcdu = dev_get_drvdata(dev);
>  	struct drm_atomic_state *state;
> -	int i;
> -
> -	if (rcar_du_has(rcdu, RCAR_DU_FEATURE_CMM)) {
> -		for (i = 0; i < rcdu->num_crtcs; ++i)
> -			rcar_du_cmm_pm_suspend(&rcdu->crtcs[i]);
> -	}
> -
> -	drm_kms_helper_poll_disable(rcdu->ddev);
> +#if IS_ENABLED(CONFIG_DRM_RCAR_DW_HDMI)
> +	struct drm_encoder *encoder;
> +#endif
> +		drm_kms_helper_poll_disable(rcdu->ddev);
>  	drm_fbdev_cma_set_suspend_unlocked(rcdu->fbdev, true);
>  
>  	state = drm_atomic_helper_suspend(rcdu->ddev);
> @@ -389,11 +386,43 @@ static int rcar_du_pm_suspend(struct device *dev)
>  		return PTR_ERR(state);
>  	}
>  
> +#if IS_ENABLED(CONFIG_DRM_RCAR_DW_HDMI)
> +	list_for_each_entry(encoder,
> +			    &rcdu->ddev->mode_config.encoder_list,
> +			    head) {
> +		struct rcar_du_encoder *renc = to_rcar_encoder(encoder);
> +
> +		if (renc->bridge && (renc->output == RCAR_DU_OUTPUT_HDMI0 ||
> +				     renc->output == RCAR_DU_OUTPUT_HDMI1))
> +			dw_hdmi_s2r_ctrl(encoder->bridge, false);
> +	}
> +#endif
>  	rcdu->suspend_state = state;
>  
>  	return 0;
>  }
>  
> +static int rcar_du_pm_suspend(struct device *dev)
> +{
> +	struct rcar_du_device *rcdu = dev_get_drvdata(dev);
> +
> +	int i, ret;
> +
> +	if (rcar_du_has(rcdu, RCAR_DU_FEATURE_CMM)) {
> +		for (i = 0; i < rcdu->num_crtcs; ++i)
> +			rcar_du_cmm_pm_suspend(&rcdu->crtcs[i]);
> +	}
> +
> +	ret = rcar_du_pm_shutdown(dev);
> +
> +	if (ret)
> +		return ret;
> +
> +	for (i = 0; i < rcdu->num_crtcs; ++i)
> +		clk_set_rate(rcdu->crtcs[i].extclock, 0);
> +	return 0;
> +}
> +
>  static int rcar_du_pm_resume(struct device *dev)
>  {
>  	struct rcar_du_device *rcdu = dev_get_drvdata(dev);
> @@ -504,6 +533,12 @@ static int rcar_du_probe(struct platform_device *pdev)
>  	return ret;
>  }
>  
> +static void rcar_du_shutdown(struct platform_device *pdev)
> +{
> +#ifdef CONFIG_PM_SLEEP
> +	rcar_du_pm_shutdown(&pdev->dev);
> +#endif
> +}
>  static struct platform_driver rcar_du_platform_driver = {
>  	.probe		= rcar_du_probe,
>  	.remove		= rcar_du_remove,
> @@ -512,6 +547,7 @@ static struct platform_driver rcar_du_platform_driver = {
>  		.pm	= &rcar_du_pm_ops,
>  		.of_match_table = rcar_du_of_table,
>  	},
> +	.shutdown       = rcar_du_shutdown,
>  };
>  
>  static int __init rcar_du_init(void)
> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_encoder.c b/drivers/gpu/drm/rcar-du/rcar_du_encoder.c
> index f9c933d..98df8a2 100644
> --- a/drivers/gpu/drm/rcar-du/rcar_du_encoder.c
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_encoder.c
> @@ -62,7 +62,7 @@ int rcar_du_encoder_init(struct rcar_du_device *rcdu,
>  
>  	dev_dbg(rcdu->dev, "initializing encoder %pOF for output %u\n",
>  		enc_node, output);
> -
> +	renc->bridge = bridge;
>  	/* Locate the DRM bridge from the encoder DT node. */
>  	bridge = of_drm_find_bridge(enc_node);
>  	if (!bridge) {
> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_encoder.h b/drivers/gpu/drm/rcar-du/rcar_du_encoder.h
> index 2d2abca..cc5bfcb 100644
> --- a/drivers/gpu/drm/rcar-du/rcar_du_encoder.h
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_encoder.h
> @@ -23,6 +23,7 @@ struct rcar_du_device;
>  struct rcar_du_encoder {
>  	struct drm_encoder base;
>  	enum rcar_du_output output;
> +	struct drm_bridge *bridge;
>  };
>  
>  #define to_rcar_encoder(e) \
> diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h
> index ccb5aa8..36383cf4 100644
> --- a/include/drm/bridge/dw_hdmi.h
> +++ b/include/drm/bridge/dw_hdmi.h
> @@ -171,5 +171,6 @@ enum drm_connector_status dw_hdmi_phy_read_hpd(struct dw_hdmi *hdmi,
>  void dw_hdmi_phy_update_hpd(struct dw_hdmi *hdmi, void *data,
>  			    bool force, bool disabled, bool rxsense);
>  void dw_hdmi_phy_setup_hpd(struct dw_hdmi *hdmi, void *data);
> +void dw_hdmi_s2r_ctrl(struct drm_bridge *bridge, int flag);
>  
>  #endif /* __IMX_HDMI_H__ */
> -- 
> 2.7.4
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

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

* Re: [PATCH 5/8] drm: rcar-du: Implement interfaces to set clu and lut using drm data structures
  2019-04-03 13:14   ` VenkataRajesh.Kalakodima
  (?)
@ 2019-04-04  7:50   ` Daniel Vetter
  2019-04-04 15:40     ` Ville Syrjälä
  -1 siblings, 1 reply; 36+ messages in thread
From: Daniel Vetter @ 2019-04-04  7:50 UTC (permalink / raw)
  To: VenkataRajesh.Kalakodima
  Cc: linux-renesas-soc, devicetree, linux-kernel, linux-clk,
	dri-devel, Harsha M M

On Wed, Apr 03, 2019 at 06:44:41PM +0530, VenkataRajesh.Kalakodima@in.bosch.com wrote:
> From: kalakodima venkata rajesh <venkatarajesh.kalakodima@in.bosch.com>
> 
> Impelement interfaces in cmm to set clu and lut tables using standard
> drm data structures as input.
> 
> Signed-off-by: Harsha M M <harsha.manjulamallikarjun@in.bosch.com>
> 
>       - Resolved checkpatch errors
>       - Resolved merge conflicts according to latest version
> 
> Signed-off-by: kalakodima venkata rajesh <venkatarajesh.kalakodima@in.bosch.com>
> ---
>  drivers/gpu/drm/rcar-du/rcar_du_cmm.c  | 256 +++++++++++++++++++++++++++++++--
>  drivers/gpu/drm/rcar-du/rcar_du_crtc.h |  11 ++
>  2 files changed, 254 insertions(+), 13 deletions(-)
> 
> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_cmm.c b/drivers/gpu/drm/rcar-du/rcar_du_cmm.c
> index 7983039..af4668f 100644
> --- a/drivers/gpu/drm/rcar-du/rcar_du_cmm.c
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_cmm.c
> @@ -114,6 +114,8 @@ struct rcar_du_cmm_pending_event {
>  	struct drm_gem_object *gem_obj;
>  	struct rcar_du_cmm *du_cmm;
>  	struct rcar_du_cmm_file_priv *fpriv;
> +	unsigned int *lut_buf;
> +	unsigned int *clu_buf;
>  };
>  
>  struct cmm_module_t {
> @@ -238,14 +240,6 @@ static long long diff_timevals(struct timeval *start, struct timeval *end)
>  }
>  #endif
>  
> -static void du_cmm_clk(struct rcar_du_cmm *du_cmm, bool on)
> -{
> -	if (on)
> -		clk_prepare_enable(du_cmm->clock);
> -	else
> -		clk_disable_unprepare(du_cmm->clock);
> -}
> -
>  static void rcar_du_cmm_queue_lut_update(struct rcar_du_cmm_pending_event *p)
>  {
>  	mutex_lock(&cmm_event_lock);
> @@ -284,6 +278,223 @@ static void rcar_du_cmm_queue_clu_update(struct rcar_du_cmm_pending_event *p)
>  	drm_crtc_vblank_get(&p->du_cmm->rcrtc->crtc);
>  }
>  
> +static s64 rcar_du_cmm_multiply_coeff(unsigned int color, s64 coeff)
> +{
> +	s64 r_val;
> +	bool is_neg = false;
> +
> +	if (coeff & BIT_ULL(63)) {
> +		is_neg = true;
> +		coeff &= ~BIT_ULL(63);
> +	}
> +
> +	r_val = DIV_ROUND_CLOSEST(((s64)(color * coeff)), BIT_ULL(32));
> +
> +	if (is_neg)
> +		return -r_val;
> +
> +	return r_val;
> +}
> +
> +static unsigned int rcar_du_cmm_scalar_product(unsigned int r, unsigned int g,
> +					       unsigned int b, s64 coeff1,
> +					       s64 coeff2, s64 coeff3)
> +{
> +	s64 product;
> +
> +	product = rcar_du_cmm_multiply_coeff(r, coeff1)
> +			+ rcar_du_cmm_multiply_coeff(g, coeff2)
> +			+ rcar_du_cmm_multiply_coeff(b, coeff3);
> +
> +	return (unsigned int)clamp_val(product, 0, U8_MAX);
> +}
> +
> +#ifdef DEBUG_PROCE_TIME
> +static long long diff_timevals(struct timeval *start, struct timeval *end)
> +{
> +	return (end->tv_sec * 1000000LL + end->tv_usec) -
> +		(start->tv_sec * 1000000LL + start->tv_usec);
> +}
> +#endif
> +
> +void *rcar_du_cmm_alloc_lut(void *cmm_handle)
> +{
> +	struct rcar_du_cmm_pending_event *p;
> +
> +	if (!cmm_handle)
> +		return NULL;
> +
> +	p = kzalloc(sizeof(*p), GFP_KERNEL);
> +	if (!p)
> +		return NULL;
> +
> +	p->gem_obj = NULL;
> +	p->event = CMM_EVENT_LUT_DONE;
> +	p->stat = QUE_STAT_PENDING;
> +	p->callback_data = 0;
> +	p->du_cmm = cmm_handle;
> +	p->fpriv = NULL;
> +	p->lut_buf = kmalloc(CMM_LUT_NUM * 4, GFP_KERNEL);
> +	if (!p->lut_buf) {
> +		kfree(p);
> +		return NULL;
> +	}
> +
> +	return p;
> +}
> +
> +void rcar_du_cmm_free_lut(void *lut_handle)
> +{
> +	struct rcar_du_cmm_pending_event *p =
> +			(struct rcar_du_cmm_pending_event *)lut_handle;
> +
> +	kfree(p->lut_buf);
> +	kfree(p);
> +}
> +
> +int rcar_du_cmm_lut_valid(unsigned int lut_length)
> +{
> +	return (lut_length == CMM_LUT_NUM) ? 0 : -EINVAL;
> +}
> +
> +void rcar_du_cmm_update_lut_and_free(void *lut_handle,
> +				     struct drm_color_lut *lut,
> +				     unsigned int lut_length)
> +{
> +	struct rcar_du_cmm_pending_event *p =
> +			(struct rcar_du_cmm_pending_event *)lut_handle;
> +	unsigned int color;
> +
> +	if (!p)
> +		return;
> +
> +	if (rcar_du_cmm_lut_valid(lut_length))
> +		return;
> +
> +	/* Convert drm_color_lut to the format handled by hardware */
> +	for (color = 0; color < lut_length; color++) {
> +		p->lut_buf[color] = 0;
> +		p->lut_buf[color] |= drm_color_lut_extract(lut[color].red, 8)
> +					<< 16;
> +		p->lut_buf[color] |= drm_color_lut_extract(lut[color].green, 8)
> +					<< 8;
> +		p->lut_buf[color] |= drm_color_lut_extract(lut[color].blue, 8);
> +	}
> +	rcar_du_cmm_queue_lut_update(p);
> +}
> +
> +void *rcar_du_cmm_alloc_clu(void *cmm_handle)
> +{
> +	struct rcar_du_cmm_pending_event *p;
> +
> +	if (!cmm_handle)
> +		return NULL;
> +
> +	p = kzalloc(sizeof(*p), GFP_KERNEL);
> +	if (!p)
> +		return NULL;
> +
> +	p->gem_obj = NULL;
> +	p->event = CMM_EVENT_CLU_DONE;
> +	p->stat = QUE_STAT_PENDING;
> +	p->callback_data = 0;
> +	p->du_cmm = cmm_handle;
> +	p->fpriv = NULL;
> +	p->clu_buf = kmalloc(CMM_CLU_NUM * 4, GFP_KERNEL);
> +	if (!p->clu_buf) {
> +		kfree(p);
> +		return NULL;
> +	}
> +
> +	return p;
> +}
> +
> +void rcar_du_cmm_free_clu(void *clu_handle)
> +{
> +	struct rcar_du_cmm_pending_event *p =
> +			(struct rcar_du_cmm_pending_event *)clu_handle;
> +
> +	kfree(p->clu_buf);
> +	kfree(p);
> +}
> +
> +void rcar_du_cmm_update_clu_and_free(void *clu_handle,
> +				     struct drm_color_ctm *ctm)
> +{
> +	struct rcar_du_cmm_pending_event *p =
> +			(struct rcar_du_cmm_pending_event *)clu_handle;
> +	unsigned int r_loop;
> +	unsigned int g_loop;
> +	unsigned int b_loop;
> +	unsigned int step_size;
> +	unsigned int step_fraction;
> +	unsigned int clu_index = 0;
> +
> +	if (!p)
> +		return;
> +
> +	step_size = U8_MAX / (CMM_CLU_SAMPLES - 1);
> +	step_fraction = U8_MAX % (CMM_CLU_SAMPLES - 1);
> +
> +	/*Update clu table*/
> +	for (b_loop = 0; b_loop < CMM_CLU_SAMPLES; b_loop++) {
> +		unsigned int b;
> +
> +		b = (b_loop * step_size) +
> +		    DIV_ROUND_CLOSEST((b_loop * step_fraction),
> +				      (CMM_CLU_SAMPLES - 1));
> +
> +		for (g_loop = 0; g_loop < CMM_CLU_SAMPLES; g_loop++) {
> +			unsigned int g;
> +
> +			g = (g_loop * step_size) +
> +			    DIV_ROUND_CLOSEST((g_loop * step_fraction),
> +					      (CMM_CLU_SAMPLES - 1));
> +
> +			for (r_loop = 0; r_loop < CMM_CLU_SAMPLES; r_loop++) {
> +				unsigned int r;
> +				unsigned int r_val;
> +				unsigned int g_val;
> +				unsigned int b_val;
> +
> +				r = (r_loop * step_size) +
> +				    DIV_ROUND_CLOSEST((r_loop * step_fraction),
> +						      (CMM_CLU_SAMPLES - 1));
> +
> +				p->clu_buf[clu_index] = 0;
> +
> +				r_val =	rcar_du_cmm_scalar_product
> +						(r, g, b,
> +						 ctm->matrix[0], ctm->matrix[1],
> +						 ctm->matrix[2]);
> +
> +				g_val =	rcar_du_cmm_scalar_product
> +						(r, g, b,
> +						 ctm->matrix[3], ctm->matrix[4],
> +						 ctm->matrix[5]);
> +
> +				b_val =	rcar_du_cmm_scalar_product
> +						(r, g, b,
> +						 ctm->matrix[6], ctm->matrix[7],
> +						 ctm->matrix[8]);
> +
> +				p->clu_buf[clu_index++] = (r_val << 16) |
> +							  (g_val << 8) | b_val;
> +			}
> +		}
> +	}
> +
> +	rcar_du_cmm_queue_clu_update(p);
> +}

Just quick drive-by: I think there's some interested (definitely from
intel, I pinged the relevant people from our team) to expose a 3D LUT
directly to userspace. I'm not sure whether we can do both 3D-LUT and
color matrix, and I'm also not sure whether remapping the ctm to a 3d-lut
is the best thing to do. Otoh adding new uapi is always a bunch more work.
-Daniel

> +
> +static void du_cmm_clk(struct rcar_du_cmm *du_cmm, bool on)
> +{
> +	if (on)
> +		clk_prepare_enable(du_cmm->clock);
> +	else
> +		clk_disable_unprepare(du_cmm->clock);
> +}
> +
>  int rcar_du_cmm_start_stop(struct rcar_du_crtc *rcrtc, bool on)
>  {
>  	struct rcar_du_cmm *du_cmm = rcrtc->cmm_handle;
> @@ -424,8 +635,16 @@ static inline void _event_done_locked(struct rcar_du_cmm_pending_event *p)
>  		list_add_tail(&p->link, cmm_done_list(p->du_cmm, p->fpriv));
>  		wake_up_interruptible(&p->fpriv->event_wait);
>  	} else {
> -		/* link deleted by rcar_du_cmm_postclose */
> -		kfree(p);
> +		/* link deleted by rcar_du_cmm_postclose
> +		 * OR it could also be due to set of ctm and gamma
> +		 * properties through drm APIs.
> +		 */
> +		if (p->event == CMM_EVENT_LUT_DONE)
> +			rcar_du_cmm_free_lut(p);
> +		else if (p->event == CMM_EVENT_CLU_DONE)
> +			rcar_du_cmm_free_clu(p);
> +		else
> +			kfree(p);
>  	}
>  }
>  
> @@ -479,7 +698,8 @@ event_pop_locked(struct cmm_module_t *module)
>  
>  	p->stat = QUE_STAT_ACTIVE;
>  	list_del(&p->link); /* delete from du_cmm->[lut|clu|hgo].list */
> -	list_add_tail(&p->link, &p->fpriv->active_list);
> +	if (p->fpriv)
> +		list_add_tail(&p->link, &p->fpriv->active_list);
>  	cmm_vblank_put(p);
>  
>  	return p;
> @@ -605,7 +825,11 @@ static int lut_set(struct rcar_du_cmm *du_cmm,
>  		return -EINVAL;
>  	}
>  
> -	lut_buf = gem_to_vaddr(stat->p->gem_obj);
> +	if (stat->p->gem_obj)
> +		lut_buf = gem_to_vaddr(stat->p->gem_obj);
> +	else
> +		lut_buf = stat->p->lut_buf;
> +
>  	for (i = 0; i < CMM_LUT_NUM; i++)
>  		rcar_du_cmm_write(du_cmm, lut_base + i * 4, lut_buf[i]);
>  
> @@ -723,7 +947,11 @@ static int clu_set(struct rcar_du_cmm *du_cmm,
>  		return -EINVAL;
>  	}
>  
> -	clu_buf = gem_to_vaddr(stat->p->gem_obj);
> +	if (stat->p->gem_obj)
> +		clu_buf = gem_to_vaddr(stat->p->gem_obj);
> +	else
> +		clu_buf = stat->p->clu_buf;
> +
>  	rcar_du_cmm_write(du_cmm, addr_reg, 0);
>  	for (i = 0; i < CMM_CLU_NUM; i++)
>  		rcar_du_cmm_write(du_cmm, data_reg, clu_buf[i]);
> @@ -1222,6 +1450,8 @@ int rcar_du_cmm_init(struct rcar_du_crtc *rcrtc)
>  
>  	rcrtc->cmm_handle = du_cmm;
>  
> +	drm_crtc_enable_color_mgmt(&rcrtc->crtc, 0, true, CMM_LUT_NUM);
> +
>  	dev_info(rcdu->dev, "DU%d use CMM(%s buffer)\n",
>  		 rcrtc->index, du_cmm->dbuf ? "Double" : "Single");
>  
> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
> index 74e0a22..5b85de4 100644
> --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
> @@ -115,6 +115,17 @@ void rcar_du_cmm_postclose(struct drm_device *dev, struct drm_file *file_priv);
>  int rcar_du_cmm_start_stop(struct rcar_du_crtc *rcrtc, bool on);
>  void rcar_du_cmm_kick(struct rcar_du_crtc *rcrtc);
>  
> +void *rcar_du_cmm_alloc_lut(void *cmm_handle);
> +void rcar_du_cmm_free_lut(void *lut_handle);
> +int rcar_du_cmm_lut_valid(unsigned int lut_length);
> +void rcar_du_cmm_update_lut_and_free(void *lut_handle,
> +				     struct drm_color_lut *lut,
> +				     unsigned int lut_length);
> +
> +void *rcar_du_cmm_alloc_clu(void *cmm_handle);
> +void rcar_du_cmm_free_clu(void *clu_handle);
> +void rcar_du_cmm_update_clu_and_free(void *clu_handle,
> +				     struct drm_color_ctm *ctm);
>  #ifdef CONFIG_PM_SLEEP
>  int rcar_du_cmm_pm_suspend(struct rcar_du_crtc *rcrtc);
>  int rcar_du_cmm_pm_resume(struct rcar_du_crtc *rcrtc);
> -- 
> 2.7.4
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

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

* Re: [PATCH 0/8] v4.19.0 Added Color Management Module
  2019-04-03 13:14 ` VenkataRajesh.Kalakodima
@ 2019-04-04  9:45   ` Laurent Pinchart
  -1 siblings, 0 replies; 36+ messages in thread
From: Laurent Pinchart @ 2019-04-04  9:45 UTC (permalink / raw)
  To: VenkataRajesh.Kalakodima
  Cc: linux-renesas-soc, devicetree, linux-kernel, linux-clk, dri-devel

Hi Kalakodima,

Thank you for the patch.

On Wed, Apr 03, 2019 at 06:44:36PM +0530, VenkataRajesh.Kalakodima@in.bosch.com wrote:
> From: kalakodima venkata rajesh <venkatarajesh.kalakodima@in.bosch.com>
> 
> This patchset adds rcar- display unit color management module (CMM)
> function feature, Which allows correction and adjustment of the
> display data, through updating Look up table (gamma) and  Cubic look
> up table (CTM)  property values 
> 
> Base color management module reference code taken from below link,
> https://github.com/renesas-rcar/du_cmm .
> - In above code, modified variable naming’s and removed un used
>   functionalities.
> - Introduce new functions for queueing cubic look up table and look up
>   table events.
> 
> - Implemented interfaces in color management module to set CLU /LUT
>   table using standard DRM data structures as input.
>   Look up table is a 1D-LUT that converts each of three-color
>   components by using a lookup table. LUT is used for gamma
>   correction.							
>   Cubic look up table is a three-dimensional LUT (3D-LUT) that
>   converts the input three-color-component data into desired three
>   color Components by using a lookup table
> 
> - Implemented atomic check helper functions for enable/disable LUT and
>   CLU (Gamma and Color Transformation Matrix properties).
> - Allocated memory necessary for cubic look up table and look up table
>   and added mode fix up callback function
> - Added update gamma and color transformation matrix properties in
>   commit tail function, If any change in property values.
> 
> kalakodima venkata rajesh (8):
>   drm: Add DU CMM support functions
>   drm: Add DU CMM support boot and clk changes
>   drm: rcar-du: Give a name to clu table samples
>   drm: rcar-du: Refactor the code with new functions
>   drm: rcar-du: Implement interfaces to set clu and lut using drm data
>     structures
>   drm: rcar-du: Implement atomic_check to check for gamma and ctm
>     properties
>   drm: rcar-du: update gamma and ctm properties in commit tail
>   drm: rcar-du: Add shutdown callback function in platform_driver
> 
>  .../boot/dts/renesas/r8a7795-es1-salvator-x.dts    |    5 +
>  arch/arm64/boot/dts/renesas/r8a7795-salvator-x.dts |    5 +
>  .../arm64/boot/dts/renesas/r8a7795-salvator-xs.dts |    5 +
>  arch/arm64/boot/dts/renesas/r8a7795.dtsi           |   29 +-
>  arch/arm64/boot/dts/renesas/r8a7796-salvator-x.dts |    6 +-
>  .../arm64/boot/dts/renesas/r8a7796-salvator-xs.dts |    4 +
>  arch/arm64/boot/dts/renesas/r8a7796.dtsi           |   25 +-
>  .../arm64/boot/dts/renesas/r8a77965-salvator-x.dts |    7 +-
>  .../boot/dts/renesas/r8a77965-salvator-xs.dts      |    7 +-
>  arch/arm64/boot/dts/renesas/r8a77965.dtsi          |   27 +-
>  drivers/clk/renesas/r8a7795-cpg-mssr.c             |    4 +
>  drivers/clk/renesas/r8a7796-cpg-mssr.c             |    3 +
>  drivers/clk/renesas/r8a77965-cpg-mssr.c            |  106 +-
>  drivers/gpu/drm/bridge/synopsys/dw-hdmi.c          |   35 +
>  drivers/gpu/drm/rcar-du/Makefile                   |    2 +
>  drivers/gpu/drm/rcar-du/rcar_du_cmm.c              | 1470 ++++++++++++++++++++
>  drivers/gpu/drm/rcar-du/rcar_du_crtc.c             |   82 ++
>  drivers/gpu/drm/rcar-du/rcar_du_crtc.h             |   28 +
>  drivers/gpu/drm/rcar-du/rcar_du_drv.c              |   85 +-
>  drivers/gpu/drm/rcar-du/rcar_du_drv.h              |   16 +-
>  drivers/gpu/drm/rcar-du/rcar_du_encoder.c          |    2 +-
>  drivers/gpu/drm/rcar-du/rcar_du_encoder.h          |    1 +
>  drivers/gpu/drm/rcar-du/rcar_du_group.c            |    5 +
>  drivers/gpu/drm/rcar-du/rcar_du_kms.c              |   25 +
>  drivers/gpu/drm/rcar-du/rcar_du_regs.h             |   92 ++
>  include/drm/bridge/dw_hdmi.h                       |    1 +
>  include/drm/drm_atomic.h                           |   25 +
>  include/drm/drm_ioctl.h                            |    7 +
>  28 files changed, 2082 insertions(+), 27 deletions(-)
>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_cmm.c

First of all, please split changes to DT, to the clock drivers, to the
dw-hdmi driver, to the DRM core and to the R-Car DU driver in separate
patches, with appropriate subject lines prefixes for each of them. As
you're modifying DT bindngs, you also need to update the bindings
documentation, which should go to a patch of its own.

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH 0/8] v4.19.0 Added Color Management Module
@ 2019-04-04  9:45   ` Laurent Pinchart
  0 siblings, 0 replies; 36+ messages in thread
From: Laurent Pinchart @ 2019-04-04  9:45 UTC (permalink / raw)
  To: VenkataRajesh.Kalakodima
  Cc: linux-renesas-soc, devicetree, linux-kernel, dri-devel, linux-clk

Hi Kalakodima,

Thank you for the patch.

On Wed, Apr 03, 2019 at 06:44:36PM +0530, VenkataRajesh.Kalakodima@in.bosch.com wrote:
> From: kalakodima venkata rajesh <venkatarajesh.kalakodima@in.bosch.com>
> 
> This patchset adds rcar- display unit color management module (CMM)
> function feature, Which allows correction and adjustment of the
> display data, through updating Look up table (gamma) and  Cubic look
> up table (CTM)  property values 
> 
> Base color management module reference code taken from below link,
> https://github.com/renesas-rcar/du_cmm .
> - In above code, modified variable naming’s and removed un used
>   functionalities.
> - Introduce new functions for queueing cubic look up table and look up
>   table events.
> 
> - Implemented interfaces in color management module to set CLU /LUT
>   table using standard DRM data structures as input.
>   Look up table is a 1D-LUT that converts each of three-color
>   components by using a lookup table. LUT is used for gamma
>   correction.							
>   Cubic look up table is a three-dimensional LUT (3D-LUT) that
>   converts the input three-color-component data into desired three
>   color Components by using a lookup table
> 
> - Implemented atomic check helper functions for enable/disable LUT and
>   CLU (Gamma and Color Transformation Matrix properties).
> - Allocated memory necessary for cubic look up table and look up table
>   and added mode fix up callback function
> - Added update gamma and color transformation matrix properties in
>   commit tail function, If any change in property values.
> 
> kalakodima venkata rajesh (8):
>   drm: Add DU CMM support functions
>   drm: Add DU CMM support boot and clk changes
>   drm: rcar-du: Give a name to clu table samples
>   drm: rcar-du: Refactor the code with new functions
>   drm: rcar-du: Implement interfaces to set clu and lut using drm data
>     structures
>   drm: rcar-du: Implement atomic_check to check for gamma and ctm
>     properties
>   drm: rcar-du: update gamma and ctm properties in commit tail
>   drm: rcar-du: Add shutdown callback function in platform_driver
> 
>  .../boot/dts/renesas/r8a7795-es1-salvator-x.dts    |    5 +
>  arch/arm64/boot/dts/renesas/r8a7795-salvator-x.dts |    5 +
>  .../arm64/boot/dts/renesas/r8a7795-salvator-xs.dts |    5 +
>  arch/arm64/boot/dts/renesas/r8a7795.dtsi           |   29 +-
>  arch/arm64/boot/dts/renesas/r8a7796-salvator-x.dts |    6 +-
>  .../arm64/boot/dts/renesas/r8a7796-salvator-xs.dts |    4 +
>  arch/arm64/boot/dts/renesas/r8a7796.dtsi           |   25 +-
>  .../arm64/boot/dts/renesas/r8a77965-salvator-x.dts |    7 +-
>  .../boot/dts/renesas/r8a77965-salvator-xs.dts      |    7 +-
>  arch/arm64/boot/dts/renesas/r8a77965.dtsi          |   27 +-
>  drivers/clk/renesas/r8a7795-cpg-mssr.c             |    4 +
>  drivers/clk/renesas/r8a7796-cpg-mssr.c             |    3 +
>  drivers/clk/renesas/r8a77965-cpg-mssr.c            |  106 +-
>  drivers/gpu/drm/bridge/synopsys/dw-hdmi.c          |   35 +
>  drivers/gpu/drm/rcar-du/Makefile                   |    2 +
>  drivers/gpu/drm/rcar-du/rcar_du_cmm.c              | 1470 ++++++++++++++++++++
>  drivers/gpu/drm/rcar-du/rcar_du_crtc.c             |   82 ++
>  drivers/gpu/drm/rcar-du/rcar_du_crtc.h             |   28 +
>  drivers/gpu/drm/rcar-du/rcar_du_drv.c              |   85 +-
>  drivers/gpu/drm/rcar-du/rcar_du_drv.h              |   16 +-
>  drivers/gpu/drm/rcar-du/rcar_du_encoder.c          |    2 +-
>  drivers/gpu/drm/rcar-du/rcar_du_encoder.h          |    1 +
>  drivers/gpu/drm/rcar-du/rcar_du_group.c            |    5 +
>  drivers/gpu/drm/rcar-du/rcar_du_kms.c              |   25 +
>  drivers/gpu/drm/rcar-du/rcar_du_regs.h             |   92 ++
>  include/drm/bridge/dw_hdmi.h                       |    1 +
>  include/drm/drm_atomic.h                           |   25 +
>  include/drm/drm_ioctl.h                            |    7 +
>  28 files changed, 2082 insertions(+), 27 deletions(-)
>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_cmm.c

First of all, please split changes to DT, to the clock drivers, to the
dw-hdmi driver, to the DRM core and to the R-Car DU driver in separate
patches, with appropriate subject lines prefixes for each of them. As
you're modifying DT bindngs, you also need to update the bindings
documentation, which should go to a patch of its own.

-- 
Regards,

Laurent Pinchart
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH 0/8] v4.19.0 Added Color Management Module
  2019-04-04  9:45   ` Laurent Pinchart
@ 2019-04-04  9:46     ` Laurent Pinchart
  -1 siblings, 0 replies; 36+ messages in thread
From: Laurent Pinchart @ 2019-04-04  9:46 UTC (permalink / raw)
  To: VenkataRajesh.Kalakodima
  Cc: linux-renesas-soc, devicetree, linux-kernel, linux-clk, dri-devel

On Thu, Apr 04, 2019 at 12:45:31PM +0300, Laurent Pinchart wrote:
> Hi Kalakodima,
> 
> Thank you for the patch.

And I forgot to mention, please CC me on all patches to the DU driver.
The script/get_maintainer.pl script should have told you about that.
> 
> On Wed, Apr 03, 2019 at 06:44:36PM +0530, VenkataRajesh.Kalakodima@in.bosch.com wrote:
> > From: kalakodima venkata rajesh <venkatarajesh.kalakodima@in.bosch.com>
> > 
> > This patchset adds rcar- display unit color management module (CMM)
> > function feature, Which allows correction and adjustment of the
> > display data, through updating Look up table (gamma) and  Cubic look
> > up table (CTM)  property values 
> > 
> > Base color management module reference code taken from below link,
> > https://github.com/renesas-rcar/du_cmm .
> > - In above code, modified variable naming’s and removed un used
> >   functionalities.
> > - Introduce new functions for queueing cubic look up table and look up
> >   table events.
> > 
> > - Implemented interfaces in color management module to set CLU /LUT
> >   table using standard DRM data structures as input.
> >   Look up table is a 1D-LUT that converts each of three-color
> >   components by using a lookup table. LUT is used for gamma
> >   correction.							
> >   Cubic look up table is a three-dimensional LUT (3D-LUT) that
> >   converts the input three-color-component data into desired three
> >   color Components by using a lookup table
> > 
> > - Implemented atomic check helper functions for enable/disable LUT and
> >   CLU (Gamma and Color Transformation Matrix properties).
> > - Allocated memory necessary for cubic look up table and look up table
> >   and added mode fix up callback function
> > - Added update gamma and color transformation matrix properties in
> >   commit tail function, If any change in property values.
> > 
> > kalakodima venkata rajesh (8):
> >   drm: Add DU CMM support functions
> >   drm: Add DU CMM support boot and clk changes
> >   drm: rcar-du: Give a name to clu table samples
> >   drm: rcar-du: Refactor the code with new functions
> >   drm: rcar-du: Implement interfaces to set clu and lut using drm data
> >     structures
> >   drm: rcar-du: Implement atomic_check to check for gamma and ctm
> >     properties
> >   drm: rcar-du: update gamma and ctm properties in commit tail
> >   drm: rcar-du: Add shutdown callback function in platform_driver
> > 
> >  .../boot/dts/renesas/r8a7795-es1-salvator-x.dts    |    5 +
> >  arch/arm64/boot/dts/renesas/r8a7795-salvator-x.dts |    5 +
> >  .../arm64/boot/dts/renesas/r8a7795-salvator-xs.dts |    5 +
> >  arch/arm64/boot/dts/renesas/r8a7795.dtsi           |   29 +-
> >  arch/arm64/boot/dts/renesas/r8a7796-salvator-x.dts |    6 +-
> >  .../arm64/boot/dts/renesas/r8a7796-salvator-xs.dts |    4 +
> >  arch/arm64/boot/dts/renesas/r8a7796.dtsi           |   25 +-
> >  .../arm64/boot/dts/renesas/r8a77965-salvator-x.dts |    7 +-
> >  .../boot/dts/renesas/r8a77965-salvator-xs.dts      |    7 +-
> >  arch/arm64/boot/dts/renesas/r8a77965.dtsi          |   27 +-
> >  drivers/clk/renesas/r8a7795-cpg-mssr.c             |    4 +
> >  drivers/clk/renesas/r8a7796-cpg-mssr.c             |    3 +
> >  drivers/clk/renesas/r8a77965-cpg-mssr.c            |  106 +-
> >  drivers/gpu/drm/bridge/synopsys/dw-hdmi.c          |   35 +
> >  drivers/gpu/drm/rcar-du/Makefile                   |    2 +
> >  drivers/gpu/drm/rcar-du/rcar_du_cmm.c              | 1470 ++++++++++++++++++++
> >  drivers/gpu/drm/rcar-du/rcar_du_crtc.c             |   82 ++
> >  drivers/gpu/drm/rcar-du/rcar_du_crtc.h             |   28 +
> >  drivers/gpu/drm/rcar-du/rcar_du_drv.c              |   85 +-
> >  drivers/gpu/drm/rcar-du/rcar_du_drv.h              |   16 +-
> >  drivers/gpu/drm/rcar-du/rcar_du_encoder.c          |    2 +-
> >  drivers/gpu/drm/rcar-du/rcar_du_encoder.h          |    1 +
> >  drivers/gpu/drm/rcar-du/rcar_du_group.c            |    5 +
> >  drivers/gpu/drm/rcar-du/rcar_du_kms.c              |   25 +
> >  drivers/gpu/drm/rcar-du/rcar_du_regs.h             |   92 ++
> >  include/drm/bridge/dw_hdmi.h                       |    1 +
> >  include/drm/drm_atomic.h                           |   25 +
> >  include/drm/drm_ioctl.h                            |    7 +
> >  28 files changed, 2082 insertions(+), 27 deletions(-)
> >  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_cmm.c
> 
> First of all, please split changes to DT, to the clock drivers, to the
> dw-hdmi driver, to the DRM core and to the R-Car DU driver in separate
> patches, with appropriate subject lines prefixes for each of them. As
> you're modifying DT bindngs, you also need to update the bindings
> documentation, which should go to a patch of its own.
> 
> -- 
> Regards,
> 
> Laurent Pinchart

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH 0/8] v4.19.0 Added Color Management Module
@ 2019-04-04  9:46     ` Laurent Pinchart
  0 siblings, 0 replies; 36+ messages in thread
From: Laurent Pinchart @ 2019-04-04  9:46 UTC (permalink / raw)
  To: VenkataRajesh.Kalakodima
  Cc: linux-renesas-soc, devicetree, linux-kernel, dri-devel, linux-clk

On Thu, Apr 04, 2019 at 12:45:31PM +0300, Laurent Pinchart wrote:
> Hi Kalakodima,
> 
> Thank you for the patch.

And I forgot to mention, please CC me on all patches to the DU driver.
The script/get_maintainer.pl script should have told you about that.
> 
> On Wed, Apr 03, 2019 at 06:44:36PM +0530, VenkataRajesh.Kalakodima@in.bosch.com wrote:
> > From: kalakodima venkata rajesh <venkatarajesh.kalakodima@in.bosch.com>
> > 
> > This patchset adds rcar- display unit color management module (CMM)
> > function feature, Which allows correction and adjustment of the
> > display data, through updating Look up table (gamma) and  Cubic look
> > up table (CTM)  property values 
> > 
> > Base color management module reference code taken from below link,
> > https://github.com/renesas-rcar/du_cmm .
> > - In above code, modified variable naming’s and removed un used
> >   functionalities.
> > - Introduce new functions for queueing cubic look up table and look up
> >   table events.
> > 
> > - Implemented interfaces in color management module to set CLU /LUT
> >   table using standard DRM data structures as input.
> >   Look up table is a 1D-LUT that converts each of three-color
> >   components by using a lookup table. LUT is used for gamma
> >   correction.							
> >   Cubic look up table is a three-dimensional LUT (3D-LUT) that
> >   converts the input three-color-component data into desired three
> >   color Components by using a lookup table
> > 
> > - Implemented atomic check helper functions for enable/disable LUT and
> >   CLU (Gamma and Color Transformation Matrix properties).
> > - Allocated memory necessary for cubic look up table and look up table
> >   and added mode fix up callback function
> > - Added update gamma and color transformation matrix properties in
> >   commit tail function, If any change in property values.
> > 
> > kalakodima venkata rajesh (8):
> >   drm: Add DU CMM support functions
> >   drm: Add DU CMM support boot and clk changes
> >   drm: rcar-du: Give a name to clu table samples
> >   drm: rcar-du: Refactor the code with new functions
> >   drm: rcar-du: Implement interfaces to set clu and lut using drm data
> >     structures
> >   drm: rcar-du: Implement atomic_check to check for gamma and ctm
> >     properties
> >   drm: rcar-du: update gamma and ctm properties in commit tail
> >   drm: rcar-du: Add shutdown callback function in platform_driver
> > 
> >  .../boot/dts/renesas/r8a7795-es1-salvator-x.dts    |    5 +
> >  arch/arm64/boot/dts/renesas/r8a7795-salvator-x.dts |    5 +
> >  .../arm64/boot/dts/renesas/r8a7795-salvator-xs.dts |    5 +
> >  arch/arm64/boot/dts/renesas/r8a7795.dtsi           |   29 +-
> >  arch/arm64/boot/dts/renesas/r8a7796-salvator-x.dts |    6 +-
> >  .../arm64/boot/dts/renesas/r8a7796-salvator-xs.dts |    4 +
> >  arch/arm64/boot/dts/renesas/r8a7796.dtsi           |   25 +-
> >  .../arm64/boot/dts/renesas/r8a77965-salvator-x.dts |    7 +-
> >  .../boot/dts/renesas/r8a77965-salvator-xs.dts      |    7 +-
> >  arch/arm64/boot/dts/renesas/r8a77965.dtsi          |   27 +-
> >  drivers/clk/renesas/r8a7795-cpg-mssr.c             |    4 +
> >  drivers/clk/renesas/r8a7796-cpg-mssr.c             |    3 +
> >  drivers/clk/renesas/r8a77965-cpg-mssr.c            |  106 +-
> >  drivers/gpu/drm/bridge/synopsys/dw-hdmi.c          |   35 +
> >  drivers/gpu/drm/rcar-du/Makefile                   |    2 +
> >  drivers/gpu/drm/rcar-du/rcar_du_cmm.c              | 1470 ++++++++++++++++++++
> >  drivers/gpu/drm/rcar-du/rcar_du_crtc.c             |   82 ++
> >  drivers/gpu/drm/rcar-du/rcar_du_crtc.h             |   28 +
> >  drivers/gpu/drm/rcar-du/rcar_du_drv.c              |   85 +-
> >  drivers/gpu/drm/rcar-du/rcar_du_drv.h              |   16 +-
> >  drivers/gpu/drm/rcar-du/rcar_du_encoder.c          |    2 +-
> >  drivers/gpu/drm/rcar-du/rcar_du_encoder.h          |    1 +
> >  drivers/gpu/drm/rcar-du/rcar_du_group.c            |    5 +
> >  drivers/gpu/drm/rcar-du/rcar_du_kms.c              |   25 +
> >  drivers/gpu/drm/rcar-du/rcar_du_regs.h             |   92 ++
> >  include/drm/bridge/dw_hdmi.h                       |    1 +
> >  include/drm/drm_atomic.h                           |   25 +
> >  include/drm/drm_ioctl.h                            |    7 +
> >  28 files changed, 2082 insertions(+), 27 deletions(-)
> >  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_cmm.c
> 
> First of all, please split changes to DT, to the clock drivers, to the
> dw-hdmi driver, to the DRM core and to the R-Car DU driver in separate
> patches, with appropriate subject lines prefixes for each of them. As
> you're modifying DT bindngs, you also need to update the bindings
> documentation, which should go to a patch of its own.
> 
> -- 
> Regards,
> 
> Laurent Pinchart

-- 
Regards,

Laurent Pinchart
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH 1/8] drm: Add DU CMM support functions
  2019-04-03 13:14   ` VenkataRajesh.Kalakodima
@ 2019-04-04 10:09     ` Laurent Pinchart
  -1 siblings, 0 replies; 36+ messages in thread
From: Laurent Pinchart @ 2019-04-04 10:09 UTC (permalink / raw)
  To: VenkataRajesh.Kalakodima
  Cc: linux-renesas-soc, devicetree, linux-kernel, linux-clk,
	dri-devel, Tsutomu Muroya, Steve Longerbeam, Koji Matsuoka

Hi Kalakodima,

Thank you for the patch.

On Wed, Apr 03, 2019 at 06:44:37PM +0530, VenkataRajesh.Kalakodima@in.bosch.com wrote:
> From: kalakodima venkata rajesh <venkatarajesh.kalakodima@in.bosch.com>
> 
> This is the out-of-tree patch for DU CMM driver support from
> Yocto release v3.4.0.
> 
> Link: https://github.com/renesas-rcar/du_cmm/commit/2d8ea2b667ad4616aa639c54ecc11f7c4b58959d.patch
> 
> Following is from the patch description:
> 
>     du_cmm: Release for Yocto v3.4.0
> 
>     This patch made the following correspondence.
> 
>       - Corresponds to kernel v 4.14.
>       - Double buffer only is supported.
>       - Fix CLU / LUT update timing.
>       - Add CMM Channel occupation mode.
>       - Fix Close process.
> 
> Signed-off-by: Koji Matsuoka <koji.matsuoka.xm@renesas.com>
> Signed-off-by: Tsutomu Muroya <muroya@ksk.co.jp>
> Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
> 
>       - Removal of rcar specific ioctals
>       - Resolved checkpatch errors
>       - Resolved merge conflicts according to latest version
>       - Included CMM drivers and included files from base patch
>       - Removed rcar_du_drm.h include file

What we're interested in from a mainline point of view is a commit
message that explains what the patch does and why, not a changelog
compared to an out-of-tree BSP. Please reword the commit messages in
this series accordingly. You can briefly mention where the code came
from in the first place, but that's secondary.

> Signed-off-by: kalakodima venkata rajesh <venkatarajesh.kalakodima@in.bosch.com>
> ---
>  drivers/gpu/drm/rcar-du/Makefile        |    2 +
>  drivers/gpu/drm/rcar-du/rcar_du_cmm.c   | 1200 +++++++++++++++++++++++++++++++
>  drivers/gpu/drm/rcar-du/rcar_du_crtc.c  |   24 +
>  drivers/gpu/drm/rcar-du/rcar_du_crtc.h  |   16 +
>  drivers/gpu/drm/rcar-du/rcar_du_drv.c   |   43 +-
>  drivers/gpu/drm/rcar-du/rcar_du_drv.h   |   16 +-
>  drivers/gpu/drm/rcar-du/rcar_du_group.c |    5 +
>  drivers/gpu/drm/rcar-du/rcar_du_regs.h  |   92 +++
>  include/drm/drm_ioctl.h                 |    7 +
>  9 files changed, 1398 insertions(+), 7 deletions(-)
>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_cmm.c
> 
> diff --git a/drivers/gpu/drm/rcar-du/Makefile b/drivers/gpu/drm/rcar-du/Makefile
> index 2a3b8d7..595e719 100644
> --- a/drivers/gpu/drm/rcar-du/Makefile
> +++ b/drivers/gpu/drm/rcar-du/Makefile
> @@ -6,12 +6,14 @@ rcar-du-drm-y := rcar_du_crtc.o \
>  		 rcar_du_kms.o \
>  		 rcar_du_plane.o
>  
> +rcar-du-drm-y += rcar_du_cmm.o
>  rcar-du-drm-$(CONFIG_DRM_RCAR_LVDS)	+= rcar_du_of.o \
>  					   rcar_du_of_lvds_r8a7790.dtb.o \
>  					   rcar_du_of_lvds_r8a7791.dtb.o \
>  					   rcar_du_of_lvds_r8a7793.dtb.o \
>  					   rcar_du_of_lvds_r8a7795.dtb.o \
>  					   rcar_du_of_lvds_r8a7796.dtb.o
> +
>  rcar-du-drm-$(CONFIG_DRM_RCAR_VSP)	+= rcar_du_vsp.o
>  
>  obj-$(CONFIG_DRM_RCAR_DU)		+= rcar-du-drm.o
> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_cmm.c b/drivers/gpu/drm/rcar-du/rcar_du_cmm.c
> new file mode 100644
> index 0000000..ac613a6e
> --- /dev/null
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_cmm.c
> @@ -0,0 +1,1200 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*************************************************************************/ /*
> + * DU CMM
> + *
> + * Copyright (C) 2018 Renesas Electronics Corporation
> + *
> + * License        Dual MIT/GPLv2

The DU driver is licensed under the terms of the GPL. Adding files with
a dual license will make license compliance more complex. Please use an
SPDX license header, remove all the boilerplate text below, and use the
GPL only.

> + *
> + * The contents of this file are subject to the MIT license as set out below.
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a copy
> + * of this software and associated documentation files (the "Software"), to deal
> + * in the Software without restriction, including without limitation the rights
> + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
> + * copies of the Software, and to permit persons to whom the Software is
> + * furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * Alternatively, the contents of this file may be used under the terms of
> + * the GNU General Public License Version 2 ("GPL") in which case the provisions
> + * of GPL are applicable instead of those above.
> + *
> + * If you wish to allow use of your version of this file only under the terms of
> + * GPL, and not to allow others to use your version of this file under the terms
> + * of the MIT license, indicate your decision by deleting the provisions above
> + * and replace them with the notice and other provisions required by GPL as set
> + * out in the file called "GPL-COPYING" included in this distribution. If you do
> + * not delete the provisions above, a recipient may use your version of this
> + * file under the terms of either the MIT license or GPL.
> + *
> + * This License is also included in this distribution in the file called
> + * "MIT-COPYING".
> + *
> + * EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) THE SOFTWARE IS
> + * PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
> + * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
> + * PARTICULAR PURPOSE AND NONINFRINGEMENT; AND (B) IN NO EVENT SHALL THE AUTHORS
> + * OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
> + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
> + * IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
> + *
> + *
> + * GPLv2:
> + * If you wish to use this file under the terms of GPL, following terms are
> + * effective.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; version 2 of the License.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + */ /*************************************************************************/
> +#include <linux/syscalls.h>
> +#include <linux/workqueue.h>
> +
> +#include <linux/reset.h>
> +#include <linux/sys_soc.h>
> +
> +#include <drm/drmP.h>

drmP.h is deprecated, please include the DRM headers you need directly.

> +#include <drm/drm_crtc.h>
> +#include <drm/drm_crtc_helper.h>
> +#include <drm/drm_fb_cma_helper.h>
> +#include <drm/drm_gem_cma_helper.h>
> +
> +#include "rcar_du_crtc.h"
> +#include "rcar_du_drv.h"
> +#include "rcar_du_kms.h"
> +#include "rcar_du_plane.h"
> +#include "rcar_du_regs.h"
> +#include <linux/clk.h>

Please sort headers alphabetically, with the linux/ headers first, then
drm/, then the local headers.

> +
> +/* #define DEBUG_PROCE_TIME 1 */

Please remove all commented-out code.

> +
> +#define CMM_LUT_NUM 256
> +#define CMM_CLU_NUM (17 * 17 * 17)
> +#define CMM_HGO_NUM 64
> +/* rcar_du_drm.h Include */
> +#define LUT_DOUBLE_BUFFER_AUTO		0
> +#define LUT_DOUBLE_BUFFER_A		1
> +#define LUT_DOUBLE_BUFFER_B		2
> +/* DRM_RCAR_DU_CMM_WAIT_EVENT: DU-CMM done event */
> +#define CMM_EVENT_CLU_DONE		BIT(0)
> +#define CMM_EVENT_HGO_DONE		BIT(1)
> +#define CMM_EVENT_LUT_DONE		BIT(2)
> +
> +#define CLU_DOUBLE_BUFFER_AUTO		0
> +#define CLU_DOUBLE_BUFFER_A		1
> +#define CLU_DOUBLE_BUFFER_B		2
> +enum {
> +	QUE_STAT_PENDING,
> +	QUE_STAT_ACTIVE,
> +	QUE_STAT_DONE,
> +};
> +
> +static const struct soc_device_attribute rcar_du_cmm_r8a7795_es1[] = {
> +	{ .soc_id = "r8a7795", .revision = "ES1.*" },
> +	{ /* sentinel */ }
> +};
> +
> +struct rcar_du_cmm;
> +struct rcar_du_cmm_file_priv;
> +
> +struct rcar_du_cmm_pending_event {
> +	struct list_head link;
> +	struct list_head  fpriv_link;
> +	unsigned int event;
> +	unsigned int stat;
> +	unsigned long callback_data;
> +	struct drm_gem_object *gem_obj;
> +	struct rcar_du_cmm *du_cmm;
> +	struct rcar_du_cmm_file_priv *fpriv;
> +};
> +
> +struct cmm_module_t {
> +	struct list_head list;
> +	union {
> +		struct {
> +			struct rcar_du_cmm_pending_event *p;
> +			int buf_mode;
> +			bool one_side;
> +		};
> +		int reset;
> +	};
> +};
> +
> +struct cmm_reg_save {
> +#ifdef CONFIG_PM_SLEEP
> +	wait_queue_head_t wait;
> +
> +	u32 *lut_table;
> +	u32 *clu_table;
> +#endif /* CONFIG_PM_SLEEP */
> +
> +	u32 cm2_ctl0;	/* CM2_CTL0 */
> +	u32 hgo_offset;	/* CMM_HGO_OFFSET */
> +	u32 hgo_size;	/* CMM_HGO_SIZE */
> +	u32 hgo_mode;	/* CMM_HGO_MODE */
> +};
> +
> +struct rcar_du_cmm {
> +	struct rcar_du_crtc *rcrtc;
> +
> +	/* CMM base address */
> +	void __iomem *cmm_base;
> +	struct clk *clock;
> +
> +	struct cmm_module_t lut;
> +	struct cmm_module_t clu;
> +	struct cmm_module_t hgo;
> +
> +	struct mutex lock;	/* lock for register setting */
> +	struct workqueue_struct *workqueue;
> +	struct work_struct work;
> +
> +	struct cmm_reg_save reg_save;

Please don't blindly save and restore registers. The device should be
reconfigured at resume time in an ordered maner, similar to what is done
at runtime. Restoring registers blindly usually leads to disasters as
the order of the register writes matter.

> +	bool active;
> +	bool dbuf;
> +	bool clu_dbuf;
> +	bool init;
> +	bool direct;
> +	bool vsync;
> +	bool authority;
> +	pid_t pid;

I don't know what this is for, but a pid_t field here is most probably a
sign that something is wrong.

> +	bool soc_support;
> +};
> +
> +struct rcar_du_cmm_file_priv {
> +	wait_queue_head_t event_wait;
> +	struct list_head list;
> +	struct list_head active_list;
> +	struct list_head *done_list;
> +};
> +
> +static DEFINE_MUTEX(cmm_event_lock);
> +static DEFINE_SPINLOCK(cmm_direct_lock);

No global variables please.

> +
> +static inline void event_prev_cancel_locked(struct cmm_module_t *module);

And no forward declarations for functions when possible.

> +static inline u32 cmm_index(struct rcar_du_cmm *_cmm)
> +{
> +	struct rcar_du_device *rcdu = _cmm->rcrtc->group->dev;
> +
> +	if (rcar_du_has(rcdu, RCAR_DU_FEATURE_R8A77965_REGS)) {
> +		if ((_cmm)->rcrtc->index == 3)
> +			return 2;
> +	}
> +	return (_cmm)->rcrtc->index;

CRTCs now have a hardware and a software index mechanism that should be
used instead of this hack.

I'll stop reviewing the implementation in details for now as I think
there are major issues in the series that will require large
refactoring, so I'll start with that, and review the code in details for
the next version.

> +}
> +
> +#define cmm_done_list(_cmm, _fpriv) \
> +	(&((_fpriv)->done_list[cmm_index(_cmm)]))
> +
> +static inline u32 rcar_du_cmm_read(struct rcar_du_cmm *du_cmm, u32 reg)
> +{
> +	return ioread32(du_cmm->cmm_base + reg);
> +}
> +
> +static inline void rcar_du_cmm_write(struct rcar_du_cmm *du_cmm,
> +				     u32 reg, u32 data)
> +{
> +	iowrite32(data, du_cmm->cmm_base + reg);
> +}
> +
> +/* create default CLU table data */
> +static inline u32 index_to_clu_data(int index)
> +{
> +	int r, g, b;
> +
> +	r = index % 17;
> +	index /= 17;
> +	g = index % 17;
> +	index /= 17;
> +	b = index % 17;
> +
> +	r = (r << 20);
> +	if (r > (255 << 16))
> +		r = (255 << 16);
> +	g = (g << 12);
> +	if (g > (255 << 8))
> +		g = (255 << 8);
> +	b = (b << 4);
> +	if (b > (255 << 0))
> +		b = (255 << 0);
> +
> +	return r | g | b;
> +}
> +
> +#ifdef DEBUG_PROCE_TIME
> +static long long diff_timevals(struct timeval *start, struct timeval *end)
> +{
> +	return (end->tv_sec * 1000000LL + end->tv_usec) -
> +		(start->tv_sec * 1000000LL + start->tv_usec);
> +}
> +#endif
> +
> +static void du_cmm_clk(struct rcar_du_cmm *du_cmm, bool on)
> +{
> +	if (on)
> +		clk_prepare_enable(du_cmm->clock);
> +	else
> +		clk_disable_unprepare(du_cmm->clock);
> +}
> +
> +int rcar_du_cmm_start_stop(struct rcar_du_crtc *rcrtc, bool on)
> +{
> +	struct rcar_du_cmm *du_cmm = rcrtc->cmm_handle;
> +	int i;
> +	u32 table_data;
> +	const struct drm_display_mode *mode;
> +	int w, h, x, y;
> +
> +	if (!du_cmm)
> +		return -EINVAL;
> +
> +	mutex_lock(&du_cmm->lock);
> +
> +	if (!on) {
> +		du_cmm->active = false;
> +
> +		rcar_du_cmm_write(du_cmm, CMM_LUT_CTRL, 0x00000000);
> +		rcar_du_cmm_write(du_cmm, CMM_CLU_CTRL, 0x00000000);
> +
> +		du_cmm_clk(du_cmm, false);
> +
> +		goto end;
> +	}
> +
> +	du_cmm_clk(du_cmm, true);
> +
> +	if (du_cmm->init)
> +		goto init_done;
> +
> +	du_cmm->init = true;
> +
> +	mode = &du_cmm->rcrtc->crtc.mode;
> +
> +	x = (du_cmm->reg_save.hgo_offset >> 16) & 0xFFFF;
> +	y = (du_cmm->reg_save.hgo_offset >> 0)  & 0xFFFF;
> +	w = (du_cmm->reg_save.hgo_size >> 16) & 0xFFFF;
> +	h = (du_cmm->reg_save.hgo_size >> 0)  & 0xFFFF;
> +	if ((mode->hdisplay < (w + x)) || w == 0) {
> +		x = 0;
> +		w = mode->hdisplay;
> +	}
> +	if ((mode->vdisplay < (h + y)) || h == 0) {
> +		y = 0;
> +		h = mode->vdisplay;
> +	}
> +	du_cmm->reg_save.hgo_offset = (x << 16) | y;
> +	du_cmm->reg_save.hgo_size = (w << 16) | h;
> +
> +	if (mode->flags & DRM_MODE_FLAG_PVSYNC)
> +		du_cmm->reg_save.cm2_ctl0 |= CMM_CTL0_VPOL;
> +	else
> +		du_cmm->reg_save.cm2_ctl0 &= ~CMM_CTL0_VPOL;
> +
> +	rcar_du_cmm_write(du_cmm, CM2_CTL0, du_cmm->reg_save.cm2_ctl0);
> +	rcar_du_cmm_write(du_cmm, CMM_HGO_OFFSET, du_cmm->reg_save.hgo_offset);
> +	rcar_du_cmm_write(du_cmm, CMM_HGO_SIZE, du_cmm->reg_save.hgo_size);
> +	rcar_du_cmm_write(du_cmm, CMM_HGO_MODE, du_cmm->reg_save.hgo_mode);
> +	rcar_du_cmm_write(du_cmm, CMM_HGO_LB_TH, 0);
> +	rcar_du_cmm_write(du_cmm, CMM_HGO_LB0_H, 0);
> +	rcar_du_cmm_write(du_cmm, CMM_HGO_LB0_V, 0);
> +	rcar_du_cmm_write(du_cmm, CMM_HGO_LB1_H, 0);
> +	rcar_du_cmm_write(du_cmm, CMM_HGO_LB1_V, 0);
> +	rcar_du_cmm_write(du_cmm, CMM_HGO_LB2_H, 0);
> +	rcar_du_cmm_write(du_cmm, CMM_HGO_LB2_V, 0);
> +	rcar_du_cmm_write(du_cmm, CMM_HGO_LB3_H, 0);
> +	rcar_du_cmm_write(du_cmm, CMM_HGO_LB3_V, 0);
> +
> +	/* init color table */
> +	for (i = 0; i < CMM_LUT_NUM; i++) {
> +	#ifdef CONFIG_PM_SLEEP
> +		table_data = du_cmm->reg_save.lut_table[i];
> +	#else
> +		table_data = ((i << 16) | (i << 8) | (i << 0));
> +	#endif /* CONFIG_PM_SLEEP */
> +		rcar_du_cmm_write(du_cmm, CMM_LUT_TBLA(i), table_data);
> +
> +		if (du_cmm->dbuf)
> +			rcar_du_cmm_write(du_cmm, CMM_LUT_TBLB(i),
> +					  table_data);
> +	}
> +
> +	rcar_du_cmm_write(du_cmm, CMM_CLU_CTRL,
> +			  CMM_CLU_CTRL_AAI | CMM_CLU_CTRL_MVS);
> +
> +	rcar_du_cmm_write(du_cmm, CMM_CLU_ADDR, 0);
> +	if (du_cmm->clu_dbuf)
> +		rcar_du_cmm_write(du_cmm, CMM_CLU_ADDR2, 0);
> +
> +	for (i = 0; i < CMM_CLU_NUM; i++) {
> +	#ifdef CONFIG_PM_SLEEP
> +		table_data = du_cmm->reg_save.clu_table[i];
> +	#else
> +		table_data = index_to_clu_data(i);
> +	#endif /* CONFIG_PM_SLEEP */
> +		rcar_du_cmm_write(du_cmm, CMM_CLU_DATA, table_data);
> +
> +		if (du_cmm->dbuf)
> +			rcar_du_cmm_write(du_cmm, CMM_CLU_DATA2,
> +					  table_data);
> +	}
> +
> +init_done:
> +	/* enable color table */
> +	rcar_du_cmm_write(du_cmm, CMM_LUT_CTRL, CMM_LUT_CTRL_EN);
> +	rcar_du_cmm_write(du_cmm, CMM_CLU_CTRL, CMM_CLU_CTRL_AAI |
> +			  CMM_CLU_CTRL_MVS | CMM_CLU_CTRL_EN);
> +
> +	du_cmm->active = true;
> +end:
> +	mutex_unlock(&du_cmm->lock);
> +
> +	return 0;
> +}
> +
> +#define gem_to_vaddr(gem_obj) \
> +	(container_of((gem_obj), struct drm_gem_cma_object, base)->vaddr)
> +
> +static inline void cmm_vblank_put(struct rcar_du_cmm_pending_event *p)
> +{
> +	if (p->du_cmm)
> +		drm_crtc_vblank_put(&p->du_cmm->rcrtc->crtc);
> +}
> +
> +static inline void
> +cmm_gem_object_unreference(struct rcar_du_cmm_pending_event *p)
> +{
> +	if (p->gem_obj)
> +		drm_gem_object_unreference_unlocked(p->gem_obj);
> +}
> +
> +static inline void _event_done_locked(struct rcar_du_cmm_pending_event *p)
> +{
> +	cmm_gem_object_unreference(p);
> +
> +	if (p->fpriv) {
> +		p->stat = QUE_STAT_DONE;
> +		list_del(&p->link); /* delete from p->fpriv->active_list */
> +		list_add_tail(&p->link, cmm_done_list(p->du_cmm, p->fpriv));
> +		wake_up_interruptible(&p->fpriv->event_wait);
> +	} else {
> +		/* link deleted by rcar_du_cmm_postclose */
> +		kfree(p);
> +	}
> +}
> +
> +/* cancel from active_list (case of LUT/CLU double buffer mode) */
> +static inline void event_prev_cancel_locked(struct cmm_module_t *module)
> +{
> +	struct rcar_du_cmm_pending_event *p = module->p;
> +
> +	if (!p)
> +		return;
> +
> +	module->p = NULL;
> +
> +	_event_done_locked(p);
> +}
> +
> +static inline void event_done(struct rcar_du_cmm_pending_event *p)
> +{
> +	/* vblank is put */
> +
> +	mutex_lock(&cmm_event_lock);
> +
> +	_event_done_locked(p);
> +
> +	mutex_unlock(&cmm_event_lock);
> +}
> +
> +static inline void lc_event_done(struct cmm_module_t *module,
> +				 struct rcar_du_cmm_pending_event *p,
> +				 bool done)
> +{
> +	/* vblank is put */
> +
> +	mutex_lock(&cmm_event_lock);
> +
> +	if (!done && list_empty(&module->list))
> +		module->p = p;
> +	else
> +		_event_done_locked(p);
> +
> +	mutex_unlock(&cmm_event_lock);
> +}
> +
> +static inline struct rcar_du_cmm_pending_event *
> +event_pop_locked(struct cmm_module_t *module)
> +{
> +	struct rcar_du_cmm_pending_event *p =
> +		list_first_entry(&module->list,
> +				 struct rcar_du_cmm_pending_event,
> +				 link);
> +
> +	p->stat = QUE_STAT_ACTIVE;
> +	list_del(&p->link); /* delete from du_cmm->[lut|clu|hgo].list */
> +	list_add_tail(&p->link, &p->fpriv->active_list);
> +	cmm_vblank_put(p);
> +
> +	return p;
> +}
> +
> +struct rcar_du_cmm_work_stat {
> +	union {
> +		struct {
> +			struct rcar_du_cmm_pending_event *p;
> +			bool done;
> +			bool table_copy;
> +		};
> +		struct {
> +			struct rcar_du_cmm_pending_event *p2;
> +			bool reset;
> +		};
> +	};
> +};
> +
> +static inline void one_side(struct rcar_du_cmm *du_cmm,
> +			    struct cmm_module_t *module,
> +			    bool on)
> +{
> +	if (on && !module->one_side) {
> +		module->one_side = true;
> +		drm_crtc_vblank_get(&du_cmm->rcrtc->crtc);
> +	} else if (!on && module->one_side) {
> +		module->one_side = false;
> +		drm_crtc_vblank_put(&du_cmm->rcrtc->crtc);
> +	}
> +}
> +
> +/* pop LUT que */
> +static int lut_pop_locked(struct rcar_du_cmm *du_cmm,
> +			  struct rcar_du_cmm_work_stat *stat)
> +{
> +	bool is_one_side = false;
> +
> +	stat->done = true;
> +	stat->table_copy = false;
> +
> +	if (!list_empty(&du_cmm->lut.list)) {
> +		stat->p = event_pop_locked(&du_cmm->lut);
> +
> +		/* prev lut table */
> +		event_prev_cancel_locked(&du_cmm->lut);
> +
> +		if (du_cmm->lut.buf_mode == LUT_DOUBLE_BUFFER_AUTO) {
> +			is_one_side = true;
> +			if (list_empty(&du_cmm->lut.list))
> +				stat->done = false;
> +		}
> +
> +	} else if (du_cmm->lut.p) {
> +		/* prev lut table */
> +		stat->p = du_cmm->lut.p;
> +		du_cmm->lut.p = NULL;
> +	} else {
> +		stat->done = false;
> +		stat->p = NULL;
> +		stat->table_copy = du_cmm->lut.one_side;
> +	}
> +
> +	one_side(du_cmm, &du_cmm->lut, is_one_side);
> +
> +	return 0;
> +}
> +
> +static int lut_table_copy(struct rcar_du_cmm *du_cmm)
> +{
> +	int i;
> +	u32 src, dst;
> +
> +	if (rcar_du_cmm_read(du_cmm, CM2_CTL1) & CMM_CTL1_BFS) {
> +		dst = CMM_LUT_TBLA(0);
> +		src = CMM_LUT_TBLB(0);
> +	} else {
> +		dst = CMM_LUT_TBLB(0);
> +		src = CMM_LUT_TBLA(0);
> +	}
> +
> +	for (i = 0; i < CMM_LUT_NUM; i++) {
> +		rcar_du_cmm_write(du_cmm, dst, rcar_du_cmm_read(du_cmm, src));
> +		dst += 4;
> +		src += 4;
> +	}
> +
> +	return 0;
> +}
> +
> +/* set 1D look up table */
> +static int lut_set(struct rcar_du_cmm *du_cmm,
> +		   struct rcar_du_cmm_work_stat *stat)
> +{
> +	int i;
> +	u32 lut_base;
> +	u32 *lut_buf;
> +
> +	if (!stat->p) {
> +		if (stat->table_copy)
> +			lut_table_copy(du_cmm);
> +		return 0; /* skip */
> +	}
> +
> +	/* set LUT */
> +	switch (du_cmm->lut.buf_mode) {
> +	case LUT_DOUBLE_BUFFER_A:
> +		lut_base = CMM_LUT_TBLA(0);
> +		break;
> +
> +	case LUT_DOUBLE_BUFFER_AUTO:
> +		if (rcar_du_cmm_read(du_cmm, CM2_CTL1) & CMM_CTL1_BFS) {
> +			lut_base = CMM_LUT_TBLA(0);
> +			break;
> +		}
> +		lut_base = CMM_LUT_TBLB(0);
> +		break;
> +	case LUT_DOUBLE_BUFFER_B:
> +		lut_base = CMM_LUT_TBLB(0);
> +		break;
> +
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	lut_buf = gem_to_vaddr(stat->p->gem_obj);
> +	for (i = 0; i < CMM_LUT_NUM; i++)
> +		rcar_du_cmm_write(du_cmm, lut_base + i * 4, lut_buf[i]);
> +
> +	lc_event_done(&du_cmm->lut, stat->p, stat->done);
> +
> +	return 0;
> +}
> +
> +/* pop CLU que */
> +static int clu_pop_locked(struct rcar_du_cmm *du_cmm,
> +			  struct rcar_du_cmm_work_stat *stat)
> +{
> +	bool is_one_side = false;
> +
> +	stat->done = true;
> +	stat->table_copy = false;
> +
> +	if (!list_empty(&du_cmm->clu.list)) {
> +		stat->p = event_pop_locked(&du_cmm->clu);
> +
> +		/* prev clu table */
> +		event_prev_cancel_locked(&du_cmm->clu);
> +
> +		if (du_cmm->clu.buf_mode == CLU_DOUBLE_BUFFER_AUTO) {
> +			is_one_side = true;
> +			if (list_empty(&du_cmm->clu.list))
> +				stat->done = false;
> +		}
> +
> +	} else if (du_cmm->clu.p) {
> +		/* prev clu table */
> +		stat->p = du_cmm->clu.p;
> +		du_cmm->clu.p = NULL;
> +	} else {
> +		stat->done = false;
> +		stat->p = NULL;
> +		stat->table_copy = du_cmm->clu.one_side;
> +	}
> +
> +	one_side(du_cmm, &du_cmm->clu, is_one_side);
> +
> +	return 0;
> +}
> +
> +static int clu_table_copy(struct rcar_du_cmm *du_cmm)
> +{
> +	int i, j, k;
> +	u32 src_addr, src_data, dst_addr, dst_data;
> +
> +	if (rcar_du_cmm_read(du_cmm, CM2_CTL1) & CMM_CTL1_BFS) {
> +		dst_addr = CMM_CLU_ADDR;
> +		dst_data = CMM_CLU_DATA;
> +		src_addr = CMM_CLU_ADDR2;
> +		src_data = CMM_CLU_DATA2;
> +	} else {
> +		dst_addr = CMM_CLU_ADDR2;
> +		dst_data = CMM_CLU_DATA2;
> +		src_addr = CMM_CLU_ADDR;
> +		src_data = CMM_CLU_DATA;
> +	}
> +
> +	rcar_du_cmm_write(du_cmm, dst_addr, 0);
> +	for (i = 0; i < 17; i++) {
> +		for (j = 0; j < 17; j++) {
> +			for (k = 0; k < 17; k++) {
> +				rcar_du_cmm_write(du_cmm, src_addr,
> +						  (k << 16) | (j << 8) |
> +						  (i << 0));
> +				rcar_du_cmm_write(du_cmm, dst_data,
> +						  rcar_du_cmm_read(du_cmm,
> +								   src_data));
> +			}
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +/* set 3D look up table */
> +static int clu_set(struct rcar_du_cmm *du_cmm,
> +		   struct rcar_du_cmm_work_stat *stat)
> +{
> +	int i;
> +	u32 addr_reg, data_reg;
> +	u32 *clu_buf;
> +
> +	if (!stat->p) {
> +		if (stat->table_copy)
> +			clu_table_copy(du_cmm);
> +		return 0; /* skip */
> +	}
> +
> +	/* set CLU */
> +	switch (du_cmm->clu.buf_mode) {
> +	case CLU_DOUBLE_BUFFER_A:
> +		addr_reg = CMM_CLU_ADDR;
> +		data_reg = CMM_CLU_DATA;
> +		break;
> +
> +	case CLU_DOUBLE_BUFFER_AUTO:
> +		if (rcar_du_cmm_read(du_cmm, CM2_CTL1) & CMM_CTL1_BFS) {
> +			addr_reg = CMM_CLU_ADDR;
> +			data_reg = CMM_CLU_DATA;
> +			break;
> +		}
> +		addr_reg = CMM_CLU_ADDR2;
> +		data_reg = CMM_CLU_DATA2;
> +		break;
> +	case CLU_DOUBLE_BUFFER_B:
> +		addr_reg = CMM_CLU_ADDR2;
> +		data_reg = CMM_CLU_DATA2;
> +		break;
> +
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	clu_buf = gem_to_vaddr(stat->p->gem_obj);
> +	rcar_du_cmm_write(du_cmm, addr_reg, 0);
> +	for (i = 0; i < CMM_CLU_NUM; i++)
> +		rcar_du_cmm_write(du_cmm, data_reg, clu_buf[i]);
> +
> +	lc_event_done(&du_cmm->clu, stat->p, stat->done);
> +
> +	return 0;
> +}
> +
> +/* pop HGO que */
> +static int hgo_pop_locked(struct rcar_du_cmm *du_cmm,
> +			  struct rcar_du_cmm_work_stat *stat)
> +{
> +	struct rcar_du_cmm_pending_event *_p = NULL;
> +
> +	if (!list_empty(&du_cmm->hgo.list))
> +		_p = event_pop_locked(&du_cmm->hgo);
> +
> +	if (du_cmm->hgo.reset) {
> +		drm_crtc_vblank_put(&du_cmm->rcrtc->crtc);
> +		du_cmm->hgo.reset = 0;
> +		stat->reset = true;
> +	} else {
> +		stat->reset = false;
> +	}
> +
> +	stat->p2 = _p;
> +
> +	return 0;
> +}
> +
> +/* get histogram */
> +static int hgo_get(struct rcar_du_cmm *du_cmm,
> +		   struct rcar_du_cmm_work_stat *stat)
> +{
> +	int i, j;
> +	const u32 histo_offset[3] = {
> +		CMM_HGO_R_HISTO(0),
> +		CMM_HGO_G_HISTO(0),
> +		CMM_HGO_B_HISTO(0),
> +	};
> +	void *vaddr;
> +
> +	if (!stat->p2) {
> +		if (stat->reset)
> +			goto hgo_reset;
> +
> +		return 0; /* skip */
> +	}
> +
> +	vaddr = gem_to_vaddr(stat->p2->gem_obj);
> +	for (i = 0; i < 3; i++) {
> +		u32 *hgo_buf = vaddr + CMM_HGO_NUM * 4 * i;
> +
> +		for (j = 0; j < CMM_HGO_NUM; j++)
> +			hgo_buf[j] = rcar_du_cmm_read(du_cmm,
> +						      histo_offset[i] + j * 4);
> +	}
> +
> +	event_done(stat->p2);
> +
> +hgo_reset:
> +	rcar_du_cmm_write(du_cmm, CMM_HGO_REGRST, CMM_HGO_REGRST_RCLEA);
> +
> +	return 0;
> +}
> +
> +static bool du_cmm_vsync_get(struct rcar_du_cmm *du_cmm)
> +{
> +	unsigned long flags;
> +	bool vsync;
> +
> +	spin_lock_irqsave(&cmm_direct_lock, flags);
> +	vsync = du_cmm->vsync;
> +	du_cmm->vsync = false;
> +	spin_unlock_irqrestore(&cmm_direct_lock, flags);
> +
> +	return vsync;
> +}
> +
> +static void du_cmm_vsync_set(struct rcar_du_cmm *du_cmm, bool vsync)
> +{
> +	unsigned long flags;
> +
> +	spin_lock_irqsave(&cmm_direct_lock, flags);
> +	du_cmm->vsync = vsync;
> +	spin_unlock_irqrestore(&cmm_direct_lock, flags);
> +}
> +
> +static void du_cmm_work(struct work_struct *work)
> +{
> +	struct rcar_du_cmm *du_cmm =
> +			container_of(work, struct rcar_du_cmm, work);
> +	struct rcar_du_cmm_work_stat s_lut;
> +	struct rcar_du_cmm_work_stat s_clu;
> +	struct rcar_du_cmm_work_stat s_hgo;
> +#ifdef DEBUG_PROCE_TIME
> +	struct timeval start_time, end_time;
> +	unsigned long lut_time, clu_time, hgo_time;
> +#endif
> +	bool vsync_status = false;
> +
> +	memset(&s_lut, 0, sizeof(struct rcar_du_cmm_work_stat));
> +	memset(&s_clu, 0, sizeof(struct rcar_du_cmm_work_stat));
> +	memset(&s_hgo, 0, sizeof(struct rcar_du_cmm_work_stat));
> +
> +	vsync_status = du_cmm_vsync_get(du_cmm);
> +
> +	mutex_lock(&cmm_event_lock);
> +
> +	lut_pop_locked(du_cmm, &s_lut);
> +	clu_pop_locked(du_cmm, &s_clu);
> +	if (vsync_status)
> +		hgo_pop_locked(du_cmm, &s_hgo);
> +
> +	mutex_unlock(&cmm_event_lock);
> +
> +	/* set LUT */
> +#ifdef DEBUG_PROCE_TIME
> +	do_gettimeofday(&start_time);
> +#endif
> +	lut_set(du_cmm, &s_lut);
> +#ifdef DEBUG_PROCE_TIME
> +	do_gettimeofday(&end_time);
> +	lut_time = (long)diff_timevals(&start_time, &end_time);
> +#endif
> +
> +	/* set CLU */
> +#ifdef DEBUG_PROCE_TIME
> +	do_gettimeofday(&start_time);
> +#endif
> +	clu_set(du_cmm, &s_clu);
> +#ifdef DEBUG_PROCE_TIME
> +	do_gettimeofday(&end_time);
> +	clu_time = (long)diff_timevals(&start_time, &end_time);
> +#endif
> +
> +	/* get HGO */
> +#ifdef DEBUG_PROCE_TIME
> +	do_gettimeofday(&start_time);
> +#endif
> +	if (vsync_status)
> +		hgo_get(du_cmm, &s_hgo);
> +#ifdef DEBUG_PROCE_TIME
> +	do_gettimeofday(&end_time);
> +	hgo_time = (long)diff_timevals(&start_time, &end_time);
> +#endif
> +
> +#ifdef CONFIG_PM_SLEEP
> +	wake_up_interruptible(&du_cmm->reg_save.wait);
> +#endif /* CONFIG_PM_SLEEP */
> +
> +#ifdef DEBUG_PROCE_TIME
> +	{
> +		struct rcar_du_device *rcdu = du_cmm->rcrtc->group->dev;
> +
> +		if (s_lut.p)
> +			dev_info(rcdu->dev, "LUT %ld usec.\n", lut_time);
> +		if (s_clu.p)
> +			dev_info(rcdu->dev, "LUT %ld usec.\n", clu_time);
> +		if (s_hgo.p2)
> +			dev_info(rcdu->dev, "HGO %ld usec.\n", hgo_time);
> +	}
> +#endif
> +}
> +
> +static int du_cmm_que_empty(struct rcar_du_cmm *du_cmm)
> +{
> +	if (list_empty(&du_cmm->lut.list) && !du_cmm->lut.p &&
> +	    !du_cmm->lut.one_side &&
> +	    list_empty(&du_cmm->clu.list) && !du_cmm->clu.p &&
> +	    !du_cmm->clu.one_side &&
> +	    list_empty(&du_cmm->hgo.list) && !du_cmm->hgo.reset)
> +		return 1;
> +
> +	return 0;
> +}
> +
> +void rcar_du_cmm_kick(struct rcar_du_crtc *rcrtc)
> +{
> +	struct rcar_du_cmm *du_cmm = rcrtc->cmm_handle;
> +
> +	if (!du_cmm)
> +		return;
> +
> +	if (!du_cmm->active)
> +		return;
> +
> +	if (!du_cmm_que_empty(du_cmm)) {
> +		du_cmm_vsync_set(du_cmm, true);
> +		queue_work(du_cmm->workqueue, &du_cmm->work);
> +	}
> +}
> +
> +#ifdef CONFIG_PM_SLEEP
> +int rcar_du_cmm_pm_suspend(struct rcar_du_crtc *rcrtc)
> +{
> +	struct rcar_du_cmm *du_cmm = rcrtc->cmm_handle;
> +	struct rcar_du_device *rcdu = rcrtc->group->dev;
> +	int i, j, k, index;
> +	int ret;
> +
> +	if (!du_cmm)
> +		return 0;
> +
> +	ret = wait_event_timeout(du_cmm->reg_save.wait,
> +				 du_cmm_que_empty(du_cmm),
> +				 msecs_to_jiffies(500));
> +	if (ret == 0)
> +		dev_err(rcdu->dev, "rcar-du cmm suspend : timeout\n");
> +
> +	if (!du_cmm->init)
> +		return 0;
> +
> +	du_cmm->init = false;
> +
> +	if (!du_cmm->active)
> +		du_cmm_clk(du_cmm, true);
> +
> +	/* table save */
> +	for (i = 0; i < CMM_LUT_NUM; i++) {
> +		du_cmm->reg_save.lut_table[i] =
> +			rcar_du_cmm_read(du_cmm, CMM_LUT_TBLA(i));
> +	}
> +
> +	index = 0;
> +	for (i = 0; i < 17; i++) {
> +		for (j = 0; j < 17; j++) {
> +			for (k = 0; k < 17; k++) {
> +				rcar_du_cmm_write(du_cmm, CMM_CLU_ADDR,
> +						  (k << 16) | (j << 8) |
> +						  (i << 0));
> +				du_cmm->reg_save.clu_table[index++] =
> +					rcar_du_cmm_read(du_cmm, CMM_CLU_DATA);
> +			}
> +		}
> +	}
> +
> +	if (!du_cmm->active)
> +		du_cmm_clk(du_cmm, false);
> +
> +	return 0;
> +}
> +
> +int rcar_du_cmm_pm_resume(struct rcar_du_crtc *rcrtc)
> +{
> +	/* none */
> +	return 0;
> +}
> +#endif /* CONFIG_PM_SLEEP */
> +
> +int rcar_du_cmm_driver_open(struct drm_device *dev, struct drm_file *file_priv)
> +{
> +	struct rcar_du_device *rcdu = dev->dev_private;
> +	struct rcar_du_cmm_file_priv *fpriv;
> +	int i;
> +
> +	if (!rcar_du_has(rcdu, RCAR_DU_FEATURE_CMM))
> +		return 0;
> +
> +	file_priv->driver_priv = NULL;
> +
> +	fpriv = kzalloc(sizeof(*fpriv), GFP_KERNEL);
> +	if (unlikely(!fpriv))
> +		return -ENOMEM;
> +
> +	fpriv->done_list = kcalloc(rcdu->info->num_crtcs,
> +				   sizeof(*fpriv->done_list),
> +				   GFP_KERNEL);
> +	if (unlikely(!fpriv->done_list)) {
> +		kfree(fpriv);
> +		return -ENOMEM;
> +	}
> +
> +	init_waitqueue_head(&fpriv->event_wait);
> +	INIT_LIST_HEAD(&fpriv->list);
> +	INIT_LIST_HEAD(&fpriv->active_list);
> +	for (i = 0; i < rcdu->info->num_crtcs; i++)
> +		INIT_LIST_HEAD(&fpriv->done_list[i]);
> +
> +	file_priv->driver_priv = fpriv;
> +
> +	return 0;
> +}
> +
> +void rcar_du_cmm_postclose(struct drm_device *dev, struct drm_file *file_priv)
> +{
> +	struct rcar_du_device *rcdu = dev->dev_private;
> +	struct rcar_du_cmm_file_priv *fpriv = file_priv->driver_priv;
> +	struct rcar_du_cmm_pending_event *p, *pt;
> +	struct rcar_du_crtc *rcrtc;
> +	struct rcar_du_cmm *du_cmm;
> +	int i, crtcs_cnt, ret;
> +	u32 table_data;
> +
> +	if (!rcar_du_has(rcdu, RCAR_DU_FEATURE_CMM))
> +		return;
> +
> +	mutex_lock(&cmm_event_lock);
> +
> +	/* Unlink file priv events */
> +	list_for_each_entry_safe(p, pt, &fpriv->list, fpriv_link) {
> +		list_del(&p->fpriv_link);
> +		list_del(&p->link);
> +		switch (p->stat) {
> +		case QUE_STAT_PENDING:
> +			cmm_vblank_put(p);
> +			cmm_gem_object_unreference(p);
> +			kfree(p);
> +			break;
> +		case QUE_STAT_DONE:
> +			kfree(p);
> +			break;
> +		case QUE_STAT_ACTIVE:
> +			p->fpriv = NULL;
> +			break;
> +		}
> +	}
> +
> +	mutex_unlock(&cmm_event_lock);
> +
> +	kfree(fpriv->done_list);
> +	kfree(fpriv);
> +	file_priv->driver_priv = NULL;
> +
> +	for (crtcs_cnt = 0; crtcs_cnt < rcdu->num_crtcs; crtcs_cnt++) {
> +		rcrtc = &rcdu->crtcs[crtcs_cnt];
> +		du_cmm = rcrtc->cmm_handle;
> +		if (du_cmm->authority && du_cmm->pid == task_pid_nr(current)) {
> +			du_cmm->authority = false;
> +			du_cmm->pid = 0;
> +			ret = wait_event_timeout(du_cmm->reg_save.wait,
> +						 du_cmm_que_empty(du_cmm),
> +						 msecs_to_jiffies(500));
> +			if (ret == 0)
> +				dev_err(rcdu->dev, "rcar-du cmm close : timeout\n");
> +
> +			for (i = 0; i < CMM_LUT_NUM; i++)
> +				du_cmm->reg_save.lut_table[i] = (i << 16) |
> +								(i << 8) |
> +								(i << 0);
> +
> +			for (i = 0; i < CMM_CLU_NUM; i++) {
> +				du_cmm->reg_save.clu_table[i] =
> +							index_to_clu_data(i);
> +			}
> +
> +			for (i = 0; i < CMM_LUT_NUM; i++) {
> +#ifdef CONFIG_PM_SLEEP
> +				table_data = du_cmm->reg_save.lut_table[i];
> +#else
> +				table_data = ((i << 16) | (i << 8) | (i << 0));
> +#endif /* CONFIG_PM_SLEEP */
> +				rcar_du_cmm_write(du_cmm, CMM_LUT_TBLA(i),
> +						  table_data);
> +				if (du_cmm->dbuf) {
> +					rcar_du_cmm_write(du_cmm,
> +							  CMM_LUT_TBLB(i),
> +							  table_data);
> +				}
> +			}
> +
> +			for (i = 0; i < CMM_CLU_NUM; i++) {
> +#ifdef CONFIG_PM_SLEEP
> +				table_data = du_cmm->reg_save.clu_table[i];
> +#else
> +				table_data = index_to_clu_data(i);
> +#endif /* CONFIG_PM_SLEEP */
> +				rcar_du_cmm_write(du_cmm, CMM_CLU_DATA,
> +						  table_data);
> +
> +				if (du_cmm->dbuf) {
> +					rcar_du_cmm_write(du_cmm, CMM_CLU_DATA2,
> +							  table_data);
> +				}
> +			}
> +		}
> +	}
> +}
> +
> +int rcar_du_cmm_init(struct rcar_du_crtc *rcrtc)
> +{
> +	struct rcar_du_cmm *du_cmm;
> +	int ret;
> +	int i;
> +	struct rcar_du_device *rcdu = rcrtc->group->dev;
> +	char name[64];
> +	struct resource *mem;
> +
> +	if (!rcar_du_has(rcdu, RCAR_DU_FEATURE_CMM))
> +		return 0;
> +
> +	du_cmm = devm_kzalloc(rcdu->dev, sizeof(*du_cmm), GFP_KERNEL);
> +	if (!du_cmm) {
> +		ret = -ENOMEM;
> +		goto error_alloc;
> +	}
> +
> +	/* DU-CMM mapping */
> +	sprintf(name, "cmm.%u", rcrtc->index);
> +	mem = platform_get_resource_byname(to_platform_device(rcdu->dev),
> +					   IORESOURCE_MEM, name);
> +	if (!mem) {
> +		dev_err(rcdu->dev, "rcar-du cmm init : failed to get memory resource\n");
> +		ret = -EINVAL;
> +		goto error_mapping_cmm;
> +	}
> +	du_cmm->cmm_base = devm_ioremap_nocache(rcdu->dev, mem->start,
> +						resource_size(mem));
> +	if (!du_cmm->cmm_base) {
> +		dev_err(rcdu->dev, "rcar-du cmm init : failed to map iomem\n");
> +		ret = -EINVAL;
> +		goto error_mapping_cmm;
> +	}
> +	du_cmm->clock = devm_clk_get(rcdu->dev, name);
> +	if (IS_ERR(du_cmm->clock)) {
> +		dev_err(rcdu->dev, "failed to get clock\n");
> +		ret = PTR_ERR(du_cmm->clock);
> +		goto error_clock_cmm;
> +	}
> +
> +	du_cmm->rcrtc = rcrtc;
> +
> +	du_cmm->reg_save.cm2_ctl0 = 0;
> +	du_cmm->reg_save.hgo_offset = 0;
> +	du_cmm->reg_save.hgo_size = 0;
> +	du_cmm->reg_save.hgo_mode = 0;
> +
> +	du_cmm->dbuf = rcar_du_has(rcdu, RCAR_DU_FEATURE_CMM_LUT_DBUF);
> +	if (du_cmm->dbuf) {
> +		du_cmm->lut.buf_mode = LUT_DOUBLE_BUFFER_AUTO;
> +		du_cmm->reg_save.cm2_ctl0 |= CMM_CTL0_DBUF;
> +	} else {
> +		dev_err(rcdu->dev, "single buffer is not supported.\n");
> +		du_cmm->dbuf = true;
> +		du_cmm->lut.buf_mode = LUT_DOUBLE_BUFFER_AUTO;
> +		du_cmm->reg_save.cm2_ctl0 |= CMM_CTL0_DBUF;
> +	}
> +
> +	du_cmm->clu_dbuf = rcar_du_has(rcdu, RCAR_DU_FEATURE_CMM_CLU_DBUF);
> +	if (du_cmm->clu_dbuf) {
> +		du_cmm->clu.buf_mode = CLU_DOUBLE_BUFFER_AUTO;
> +		du_cmm->reg_save.cm2_ctl0 |= CMM_CTL0_CLUDB;
> +	} else {
> +		dev_err(rcdu->dev, "single buffer is not supported.\n");
> +		du_cmm->clu_dbuf = true;
> +		du_cmm->clu.buf_mode = CLU_DOUBLE_BUFFER_AUTO;
> +		du_cmm->reg_save.cm2_ctl0 |= CMM_CTL0_CLUDB;
> +	}
> +
> +#ifdef CONFIG_PM_SLEEP
> +	du_cmm->reg_save.lut_table =
> +		devm_kzalloc(rcdu->dev, CMM_LUT_NUM * 4, GFP_KERNEL);
> +	if (!du_cmm->reg_save.lut_table) {
> +		ret = -ENOMEM;
> +		goto error_lut_reg_save_buf;
> +	}
> +	for (i = 0; i < CMM_LUT_NUM; i++)
> +		du_cmm->reg_save.lut_table[i] = (i << 16) | (i << 8) | (i << 0);
> +
> +	du_cmm->reg_save.clu_table =
> +		devm_kzalloc(rcdu->dev, CMM_CLU_NUM * 4, GFP_KERNEL);
> +	if (!du_cmm->reg_save.clu_table) {
> +		ret = -ENOMEM;
> +		goto error_clu_reg_save_buf;
> +	}
> +	for (i = 0; i < CMM_CLU_NUM; i++)
> +		du_cmm->reg_save.clu_table[i] = index_to_clu_data(i);
> +
> +	init_waitqueue_head(&du_cmm->reg_save.wait);
> +#endif /* CONFIG_PM_SLEEP */
> +	if (soc_device_match(rcar_du_cmm_r8a7795_es1))
> +		du_cmm->soc_support = false;
> +	else
> +		du_cmm->soc_support = true;
> +
> +	du_cmm->active = false;
> +	du_cmm->init = false;
> +	du_cmm->direct = true;
> +
> +	mutex_init(&du_cmm->lock);
> +	INIT_LIST_HEAD(&du_cmm->lut.list);
> +	du_cmm->lut.p = NULL;
> +	du_cmm->lut.one_side = false;
> +	INIT_LIST_HEAD(&du_cmm->clu.list);
> +	du_cmm->clu.p = NULL;
> +	du_cmm->clu.one_side = false;
> +	INIT_LIST_HEAD(&du_cmm->hgo.list);
> +	du_cmm->hgo.reset = 0;
> +
> +	sprintf(name, "du-cmm%d", rcrtc->index);
> +	du_cmm->workqueue = create_singlethread_workqueue(name);
> +	INIT_WORK(&du_cmm->work, du_cmm_work);
> +
> +	rcrtc->cmm_handle = du_cmm;
> +
> +	dev_info(rcdu->dev, "DU%d use CMM(%s buffer)\n",
> +		 rcrtc->index, du_cmm->dbuf ? "Double" : "Single");
> +
> +	return 0;
> +
> +#ifdef CONFIG_PM_SLEEP
> +error_clu_reg_save_buf:
> +error_lut_reg_save_buf:
> +#endif /* CONFIG_PM_SLEEP */
> +error_clock_cmm:
> +	devm_iounmap(rcdu->dev, du_cmm->cmm_base);
> +error_mapping_cmm:
> +	devm_kfree(rcdu->dev, du_cmm);
> +error_alloc:
> +	return ret;
> +}
> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
> index 15dc9ca..864fb94 100644
> --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
> @@ -296,6 +296,19 @@ static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc)
>  	rcar_du_crtc_write(rcrtc, HDSR, mode->htotal - mode->hsync_start - 19);
>  	rcar_du_crtc_write(rcrtc, HDER, mode->htotal - mode->hsync_start +
>  					mode->hdisplay - 19);
> +	if (rcar_du_has(rcrtc->group->dev, RCAR_DU_FEATURE_CMM)) {
> +		rcar_du_crtc_write(rcrtc, HDSR, mode->htotal -
> +						mode->hsync_start - 19 - 25);
> +		rcar_du_crtc_write(rcrtc, HDER, mode->htotal -
> +						mode->hsync_start +
> +						mode->hdisplay - 19 - 25);
> +	} else {
> +		rcar_du_crtc_write(rcrtc, HDSR, mode->htotal -
> +						mode->hsync_start - 19);
> +		rcar_du_crtc_write(rcrtc, HDER, mode->htotal -
> +						mode->hsync_start +
> +						mode->hdisplay - 19);
> +	}
>  	rcar_du_crtc_write(rcrtc, HSWR, mode->hsync_end -
>  					mode->hsync_start - 1);
>  	rcar_du_crtc_write(rcrtc, HCR,  mode->htotal - 1);
> @@ -530,6 +543,9 @@ static void rcar_du_crtc_start(struct rcar_du_crtc *rcrtc)
>  			     DSYSR_TVM_MASTER);
>  
>  	rcar_du_group_start_stop(rcrtc->group, true);
> +
> +	if (rcar_du_has(rcrtc->group->dev, RCAR_DU_FEATURE_CMM))
> +		rcar_du_cmm_start_stop(rcrtc, true);
>  }
>  
>  static void rcar_du_crtc_disable_planes(struct rcar_du_crtc *rcrtc)
> @@ -565,6 +581,9 @@ static void rcar_du_crtc_stop(struct rcar_du_crtc *rcrtc)
>  {
>  	struct drm_crtc *crtc = &rcrtc->crtc;
>  
> +	if (rcar_du_has(rcrtc->group->dev, RCAR_DU_FEATURE_CMM))
> +		rcar_du_cmm_start_stop(rcrtc, false);
> +
>  	/*
>  	 * Disable all planes and wait for the change to take effect. This is
>  	 * required as the plane enable registers are updated on vblank, and no
> @@ -899,6 +918,9 @@ static irqreturn_t rcar_du_crtc_irq(int irq, void *arg)
>  			rcar_du_crtc_finish_page_flip(rcrtc);
>  		}
>  
> +		if (rcar_du_has(rcrtc->group->dev, RCAR_DU_FEATURE_CMM))
> +			rcar_du_cmm_kick(rcrtc);

The fact that the SoC has a CMM doesn't mean it should be used
unconditionally. When the CMM features are not needed by userspace the
CMM should be disabled.

> +
>  		ret = IRQ_HANDLED;
>  	}
>  
> @@ -999,5 +1021,7 @@ int rcar_du_crtc_create(struct rcar_du_group *rgrp, unsigned int swindex,
>  		return ret;
>  	}
>  
> +	rcar_du_cmm_init(rcrtc);
> +
>  	return 0;
>  }
> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
> index 7680cb2..74e0a22 100644
> --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
> @@ -67,6 +67,10 @@ struct rcar_du_crtc {
>  	struct rcar_du_group *group;
>  	struct rcar_du_vsp *vsp;
>  	unsigned int vsp_pipe;
> +	int lvds_ch;

I think you need to figure out all the places where you pulled in BSP
code completely unrelated to the series :-)

> +
> +	void *cmm_handle;
> +
>  };
>  
>  #define to_rcar_crtc(c)	container_of(c, struct rcar_du_crtc, crtc)
> @@ -104,4 +108,16 @@ void rcar_du_crtc_route_output(struct drm_crtc *crtc,
>  			       enum rcar_du_output output);
>  void rcar_du_crtc_finish_page_flip(struct rcar_du_crtc *rcrtc);
>  
> +/* DU-CMM functions */
> +int rcar_du_cmm_init(struct rcar_du_crtc *rcrtc);
> +int rcar_du_cmm_driver_open(struct drm_device *dev, struct drm_file *file_priv);
> +void rcar_du_cmm_postclose(struct drm_device *dev, struct drm_file *file_priv);
> +int rcar_du_cmm_start_stop(struct rcar_du_crtc *rcrtc, bool on);
> +void rcar_du_cmm_kick(struct rcar_du_crtc *rcrtc);
> +
> +#ifdef CONFIG_PM_SLEEP
> +int rcar_du_cmm_pm_suspend(struct rcar_du_crtc *rcrtc);
> +int rcar_du_cmm_pm_resume(struct rcar_du_crtc *rcrtc);
> +#endif /* CONFIG_PM_SLEEP */
> +
>  #endif /* __RCAR_DU_CRTC_H__ */
> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
> index 02aee6c..838b7c9 100644
> --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
> @@ -26,8 +26,8 @@
>  #include <drm/drm_crtc_helper.h>
>  #include <drm/drm_fb_cma_helper.h>
>  #include <drm/drm_gem_cma_helper.h>
> -
>  #include "rcar_du_drv.h"
> +#include "rcar_du_encoder.h"
>  #include "rcar_du_kms.h"
>  #include "rcar_du_of.h"
>  #include "rcar_du_regs.h"
> @@ -128,7 +128,9 @@ static const struct rcar_du_device_info rcar_du_r8a7790_info = {
>  static const struct rcar_du_device_info rcar_du_r8a7791_info = {
>  	.gen = 2,
>  	.features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
> -		  | RCAR_DU_FEATURE_EXT_CTRL_REGS,
> +		  | RCAR_DU_FEATURE_EXT_CTRL_REGS
> +		  | RCAR_DU_FEATURE_CMM,
> +	.num_crtcs = 2,
>  	.channels_mask = BIT(1) | BIT(0),
>  	.routes = {
>  		/*
> @@ -190,7 +192,10 @@ static const struct rcar_du_device_info rcar_du_r8a7795_info = {
>  	.gen = 3,
>  	.features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
>  		  | RCAR_DU_FEATURE_EXT_CTRL_REGS
> -		  | RCAR_DU_FEATURE_VSP1_SOURCE,
> +		  | RCAR_DU_FEATURE_VSP1_SOURCE
> +		  | RCAR_DU_FEATURE_CMM | RCAR_DU_FEATURE_CMM_LUT_DBUF
> +		  | RCAR_DU_FEATURE_CMM_CLU_DBUF,
> +	.num_crtcs = 4,
>  	.channels_mask = BIT(3) | BIT(2) | BIT(1) | BIT(0),
>  	.routes = {
>  		/*
> @@ -222,7 +227,10 @@ static const struct rcar_du_device_info rcar_du_r8a7796_info = {
>  	.gen = 3,
>  	.features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
>  		  | RCAR_DU_FEATURE_EXT_CTRL_REGS
> -		  | RCAR_DU_FEATURE_VSP1_SOURCE,
> +		  | RCAR_DU_FEATURE_VSP1_SOURCE
> +		  | RCAR_DU_FEATURE_CMM | RCAR_DU_FEATURE_CMM_LUT_DBUF
> +		  | RCAR_DU_FEATURE_CMM_CLU_DBUF,
> +	.num_crtcs = 3,
>  	.channels_mask = BIT(2) | BIT(1) | BIT(0),
>  	.routes = {
>  		/*
> @@ -250,7 +258,11 @@ static const struct rcar_du_device_info rcar_du_r8a77965_info = {
>  	.gen = 3,
>  	.features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
>  		  | RCAR_DU_FEATURE_EXT_CTRL_REGS
> -		  | RCAR_DU_FEATURE_VSP1_SOURCE,
> +		  | RCAR_DU_FEATURE_VSP1_SOURCE
> +		  | RCAR_DU_FEATURE_R8A77965_REGS
> +		  | RCAR_DU_FEATURE_CMM | RCAR_DU_FEATURE_CMM_LUT_DBUF
> +		  | RCAR_DU_FEATURE_CMM_CLU_DBUF,
> +	.num_crtcs = 3,
>  	.channels_mask = BIT(3) | BIT(1) | BIT(0),
>  	.routes = {
>  		/*
> @@ -328,6 +340,8 @@ DEFINE_DRM_GEM_CMA_FOPS(rcar_du_fops);
>  static struct drm_driver rcar_du_driver = {
>  	.driver_features	= DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME
>  				| DRIVER_ATOMIC,
> +	.open			= rcar_du_cmm_driver_open,
> +	.postclose		= rcar_du_cmm_postclose,
>  	.lastclose		= rcar_du_lastclose,
>  	.gem_free_object_unlocked = drm_gem_cma_free_object,
>  	.gem_vm_ops		= &drm_gem_cma_vm_ops,
> @@ -358,6 +372,12 @@ static int rcar_du_pm_suspend(struct device *dev)
>  {
>  	struct rcar_du_device *rcdu = dev_get_drvdata(dev);
>  	struct drm_atomic_state *state;
> +	int i;
> +
> +	if (rcar_du_has(rcdu, RCAR_DU_FEATURE_CMM)) {
> +		for (i = 0; i < rcdu->num_crtcs; ++i)
> +			rcar_du_cmm_pm_suspend(&rcdu->crtcs[i]);
> +	}
>  
>  	drm_kms_helper_poll_disable(rcdu->ddev);
>  	drm_fbdev_cma_set_suspend_unlocked(rcdu->fbdev, true);
> @@ -377,7 +397,20 @@ static int rcar_du_pm_suspend(struct device *dev)
>  static int rcar_du_pm_resume(struct device *dev)
>  {
>  	struct rcar_du_device *rcdu = dev_get_drvdata(dev);
> +#if IS_ENABLED(CONFIG_DRM_RCAR_DW_HDMI)
> +	struct drm_encoder *encoder;
> +	int i;
> +
> +	if (rcar_du_has(rcdu, RCAR_DU_FEATURE_CMM)) {
> +		for (i = 0; (i < rcdu->num_crtcs); ++i)
> +			rcar_du_cmm_pm_resume(&rcdu->crtcs[i]);
> +	}
>  
> +	list_for_each_entry(encoder, &rcdu->ddev->mode_config.encoder_list,
> +			    head) {
> +		to_rcar_encoder(encoder);
> +	}
> +#endif
>  	drm_atomic_helper_resume(rcdu->ddev, rcdu->suspend_state);
>  	drm_fbdev_cma_set_suspend_unlocked(rcdu->fbdev, false);
>  	drm_kms_helper_poll_enable(rcdu->ddev);
> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.h b/drivers/gpu/drm/rcar-du/rcar_du_drv.h
> index b3a25e8..f2afe36 100644
> --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.h
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.h
> @@ -30,8 +30,19 @@ struct rcar_du_device;
>  #define RCAR_DU_FEATURE_CRTC_IRQ_CLOCK	(1 << 0)	/* Per-CRTC IRQ and clock */
>  #define RCAR_DU_FEATURE_EXT_CTRL_REGS	(1 << 1)	/* Has extended control registers */
>  #define RCAR_DU_FEATURE_VSP1_SOURCE	(1 << 2)	/* Has inputs from VSP1 */
> -
> -#define RCAR_DU_QUIRK_ALIGN_128B	(1 << 0)	/* Align pitches to 128 bytes */
> +/* Use R8A77965 registers */
> +#define RCAR_DU_FEATURE_R8A77965_REGS	BIT(3)
> +
> +/* Has DEF7R register & CMM */
> +#define RCAR_DU_FEATURE_CMM		BIT(10)
> +/* Has CMM LUT Double buffer */
> +#define RCAR_DU_FEATURE_CMM_LUT_DBUF	BIT(11)
> +/* Has CMM CLU Double buffer */
> +#define RCAR_DU_FEATURE_CMM_CLU_DBUF	BIT(12)
> +/* Align pitches to 128 bytes */
> +#define RCAR_DU_QUIRK_ALIGN_128B	BIT(0)
> +/* LVDS lanes 1 and 3 inverted */
> +#define RCAR_DU_QUIRK_LVDS_LANES	BIT(1)

The last define is not used here, and clearly unrelated to this patch
series. I think the series needs major cleanup.

>  
>  /*
>   * struct rcar_du_output_routing - Output routing specification
> @@ -61,6 +72,7 @@ struct rcar_du_device_info {
>  	unsigned int features;
>  	unsigned int quirks;
>  	unsigned int channels_mask;
> +	unsigned int num_crtcs;

There's already a way in the driver to count CRTCs, no need to duplicate
this in the rcar_du_device_info structure.

>  	struct rcar_du_output_routing routes[RCAR_DU_OUTPUT_MAX];
>  	unsigned int num_lvds;
>  	unsigned int dpll_ch;
> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_group.c b/drivers/gpu/drm/rcar-du/rcar_du_group.c
> index d539cb2..83a2836 100644
> --- a/drivers/gpu/drm/rcar-du/rcar_du_group.c
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_group.c
> @@ -130,6 +130,11 @@ static void rcar_du_group_setup(struct rcar_du_group *rgrp)
>  	if (rcdu->info->gen >= 3)
>  		rcar_du_group_write(rgrp, DEFR10, DEFR10_CODE | DEFR10_DEFE10);
>  
> +	if (rcar_du_has(rgrp->dev, RCAR_DU_FEATURE_CMM)) {
> +		rcar_du_group_write(rgrp, DEF7R, DEF7R_CODE |
> +				    DEF7R_CMME1 | DEF7R_CMME0);
> +	}
> +
>  	/*
>  	 * Use DS1PR and DS2PR to configure planes priorities and connects the
>  	 * superposition 0 to DU0 pins. DU1 pins will be configured dynamically.
> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_regs.h b/drivers/gpu/drm/rcar-du/rcar_du_regs.h
> index 9dfd220..b20e783 100644
> --- a/drivers/gpu/drm/rcar-du/rcar_du_regs.h
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_regs.h
> @@ -200,6 +200,11 @@
>  #define DEFR6_MLOS1		(1 << 2)
>  #define DEFR6_DEFAULT		(DEFR6_CODE | DEFR6_TCNE1)
>  
> +#define DEF7R			0x000ec
> +#define DEF7R_CODE		(0x7779 << 16)
> +#define DEF7R_CMME1		BIT(6)
> +#define DEF7R_CMME0		BIT(4)
> +
>  /* -----------------------------------------------------------------------------
>   * R8A7790-only Control Registers
>   */
> @@ -552,4 +557,91 @@
>  #define GCBCR			0x11098
>  #define BCBCR			0x1109c
>  
> +/* -----------------------------------------------------------------------------
> + * DU Color Management Module Registers
> + */
> +
> +#define CMM_LUT_CTRL			0x0000
> +#define CMM_LUT_CTRL_EN			BIT(0)
> +
> +#define CMM_CLU_CTRL			0x0100
> +#define CMM_CLU_CTRL_EN			BIT(0)
> +#define CMM_CLU_CTRL_MVS		BIT(24)
> +#define CMM_CLU_CTRL_AAI		BIT(28)
> +
> +#define CMM_CTL0			0x0180
> +#define CM2_CTL0			CMM_CTL0

Why do you need an alias here (and for CM2_CTL1 below) ?

> +#define CMM_CTL0_CLUDB			BIT(24)
> +#define CMM_CTL0_HISTS			BIT(20)
> +#define CMM_CTL0_TM1_MASK		(3 << 16)
> +#define CMM_CTL0_TM1_BT601_YC240	(0 << 16)
> +#define CMM_CTL0_TM1_BT601_YC255	BIT(16)
> +#define CMM_CTL0_TM1_BT709_RG255	(2 << 16)
> +#define CMM_CTL0_TM1_BT709_RG235	(3 << 16)
> +#define CMM_CTL0_TM0_MASK		(3 << 12)
> +#define CMM_CTL0_TM0_BT601_YC240	(0 << 12)
> +#define CMM_CTL0_TM0_BT601_YC255	BIT(12)
> +#define CMM_CTL0_TM0_BT709_RG255	(2 << 12)
> +#define CMM_CTL0_TM0_BT709_RG235	(3 << 12)
> +#define CMM_CTL0_TM_BT601_YC240		(CMM_CTL0_TM1_BT601_YC240 |\
> +					 CMM_CTL0_TM0_BT601_YC240)
> +#define CMM_CTL0_TM_BT601_YC255		(CMM_CTL0_TM1_BT601_YC255 |\
> +					 CMM_CTL0_TM0_BT601_YC255)
> +#define CMM_CTL0_TM_BT709_RG255		(CMM_CTL0_TM1_BT709_RG255 |\
> +					 CMM_CTL0_TM0_BT709_RG255)
> +#define CMM_CTL0_TM_BT709_RG235		(CMM_CTL0_TM1_BT709_RG235 |\
> +					 CMM_CTL0_TM0_BT709_RG235)
> +#define CMM_CTL0_YC			BIT(8)
> +#define CMM_CTL0_VPOL			BIT(4)
> +#define CMM_CTL0_DBUF			BIT(0)
> +
> +#define CMM_CTL1			0x0184
> +#define CM2_CTL1			CMM_CTL1
> +#define CMM_CTL1_BFS			BIT(0)
> +
> +#define CMM_CTL2			0x0188
> +#define CMM_HGO_OFFSET			0x0200
> +#define CMM_HGO_SIZE			0x0204
> +#define CMM_HGO_MODE			0x0208
> +#define CMM_HGO_MODE_MASK		(0xFF)

No need for parentheses. Hex constants in the DU code base use
lowercase.

> +#define CMM_HGO_MODE_MAXRGB		BIT(7)
> +#define CMM_HGO_MODE_OFSB_R		BIT(6)
> +#define CMM_HGO_MODE_OFSB_G		BIT(5)
> +#define CMM_HGO_MODE_OFSB_B		BIT(4)
> +#define CMM_HGO_MODE_HRATIO_NO_SKIPP		(0 << 2)
> +#define CMM_HGO_MODE_HRATIO_HALF_SKIPP		BIT(2)
> +#define CMM_HGO_MODE_HRATIO_QUARTER_SKIPP	(2 << 2)
> +#define CMM_HGO_MODE_VRATIO_NO_SKIPP		(0 << 0)
> +#define CMM_HGO_MODE_VRATIO_HALF_SKIPP		BIT(0)
> +#define CMM_HGO_MODE_VRATIO_QUARTER_SKIPP	(2 << 0)
> +#define CMM_HGO_LB_TH			0x020C
> +#define CMM_HGO_LB0_H			0x0210
> +#define CMM_HGO_LB0_V			0x0214
> +#define CMM_HGO_LB1_H			0x0218
> +#define CMM_HGO_LB1_V			0x021C
> +#define CMM_HGO_LB2_H			0x0220
> +#define CMM_HGO_LB2_V			0x0224
> +#define CMM_HGO_LB3_H			0x0228
> +#define CMM_HGO_LB3_V			0x022C
> +#define CMM_HGO_R_HISTO(n)		(0x0230 + ((n) * 4))
> +#define CMM_HGO_R_MAXMIN		0x0330
> +#define CMM_HGO_R_SUM			0x0334
> +#define CMM_HGO_R_LB_DET		0x0338
> +#define CMM_HGO_G_HISTO(n)		(0x0340 + ((n) * 4))
> +#define CMM_HGO_G_MAXMIN		0x0440
> +#define CMM_HGO_G_SUM			0x0444
> +#define CMM_HGO_G_LB_DET		0x0448
> +#define CMM_HGO_B_HISTO(n)		(0x0450 + ((n) * 4))
> +#define CMM_HGO_B_MAXMIN		0x0550
> +#define CMM_HGO_B_SUM			0x0554
> +#define CMM_HGO_B_LB_DET		0x0558
> +#define CMM_HGO_REGRST			0x05FC
> +#define CMM_HGO_REGRST_RCLEA		BIT(0)
> +#define CMM_LUT_TBLA(n)			(0x0600 + ((n) * 4))
> +#define CMM_CLU_ADDR			0x0A00
> +#define CMM_CLU_DATA			0x0A04
> +#define CMM_LUT_TBLB(n)			(0x0B00 + ((n) * 4))
> +#define CMM_CLU_ADDR2			0x0F00
> +#define CMM_CLU_DATA2			0x0F04

The CMM is a separate IP core, I think it would be best supported in a
separate platform_driver like the LVDS encoder, with the registers split
to a separate header.

> +
>  #endif /* __RCAR_DU_REGS_H__ */
> diff --git a/include/drm/drm_ioctl.h b/include/drm/drm_ioctl.h
> index fafb6f5..add4280 100644
> --- a/include/drm/drm_ioctl.h
> +++ b/include/drm/drm_ioctl.h
> @@ -109,6 +109,13 @@ enum drm_ioctl_flags {
>  	 */
>  	DRM_ROOT_ONLY		= BIT(2),
>  	/**
> +	 * @DRM_CONTROL_ALLOW:
> +	 *
> +	 * Deprecated, do not use. Control nodes are in the process of getting
> +	 * removed.
> +	 */

Do not use means do not use :-)

As commented on the cover letter, changes to the DRM core and DRM API
are fine, but need to be split to patches of their own, with
corresponding documentation and a clear explanation of what they do and
why they're needed.

> +	DRM_CONTROL_ALLOW	= BIT(3),
> +	/**
>  	 * @DRM_UNLOCKED:
>  	 *
>  	 * Whether &drm_ioctl_desc.func should be called with the DRM BKL held

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH 1/8] drm: Add DU CMM support functions
@ 2019-04-04 10:09     ` Laurent Pinchart
  0 siblings, 0 replies; 36+ messages in thread
From: Laurent Pinchart @ 2019-04-04 10:09 UTC (permalink / raw)
  To: VenkataRajesh.Kalakodima
  Cc: Tsutomu Muroya, devicetree, Steve Longerbeam, linux-kernel,
	dri-devel, Koji Matsuoka, linux-renesas-soc, linux-clk

Hi Kalakodima,

Thank you for the patch.

On Wed, Apr 03, 2019 at 06:44:37PM +0530, VenkataRajesh.Kalakodima@in.bosch.com wrote:
> From: kalakodima venkata rajesh <venkatarajesh.kalakodima@in.bosch.com>
> 
> This is the out-of-tree patch for DU CMM driver support from
> Yocto release v3.4.0.
> 
> Link: https://github.com/renesas-rcar/du_cmm/commit/2d8ea2b667ad4616aa639c54ecc11f7c4b58959d.patch
> 
> Following is from the patch description:
> 
>     du_cmm: Release for Yocto v3.4.0
> 
>     This patch made the following correspondence.
> 
>       - Corresponds to kernel v 4.14.
>       - Double buffer only is supported.
>       - Fix CLU / LUT update timing.
>       - Add CMM Channel occupation mode.
>       - Fix Close process.
> 
> Signed-off-by: Koji Matsuoka <koji.matsuoka.xm@renesas.com>
> Signed-off-by: Tsutomu Muroya <muroya@ksk.co.jp>
> Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
> 
>       - Removal of rcar specific ioctals
>       - Resolved checkpatch errors
>       - Resolved merge conflicts according to latest version
>       - Included CMM drivers and included files from base patch
>       - Removed rcar_du_drm.h include file

What we're interested in from a mainline point of view is a commit
message that explains what the patch does and why, not a changelog
compared to an out-of-tree BSP. Please reword the commit messages in
this series accordingly. You can briefly mention where the code came
from in the first place, but that's secondary.

> Signed-off-by: kalakodima venkata rajesh <venkatarajesh.kalakodima@in.bosch.com>
> ---
>  drivers/gpu/drm/rcar-du/Makefile        |    2 +
>  drivers/gpu/drm/rcar-du/rcar_du_cmm.c   | 1200 +++++++++++++++++++++++++++++++
>  drivers/gpu/drm/rcar-du/rcar_du_crtc.c  |   24 +
>  drivers/gpu/drm/rcar-du/rcar_du_crtc.h  |   16 +
>  drivers/gpu/drm/rcar-du/rcar_du_drv.c   |   43 +-
>  drivers/gpu/drm/rcar-du/rcar_du_drv.h   |   16 +-
>  drivers/gpu/drm/rcar-du/rcar_du_group.c |    5 +
>  drivers/gpu/drm/rcar-du/rcar_du_regs.h  |   92 +++
>  include/drm/drm_ioctl.h                 |    7 +
>  9 files changed, 1398 insertions(+), 7 deletions(-)
>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_cmm.c
> 
> diff --git a/drivers/gpu/drm/rcar-du/Makefile b/drivers/gpu/drm/rcar-du/Makefile
> index 2a3b8d7..595e719 100644
> --- a/drivers/gpu/drm/rcar-du/Makefile
> +++ b/drivers/gpu/drm/rcar-du/Makefile
> @@ -6,12 +6,14 @@ rcar-du-drm-y := rcar_du_crtc.o \
>  		 rcar_du_kms.o \
>  		 rcar_du_plane.o
>  
> +rcar-du-drm-y += rcar_du_cmm.o
>  rcar-du-drm-$(CONFIG_DRM_RCAR_LVDS)	+= rcar_du_of.o \
>  					   rcar_du_of_lvds_r8a7790.dtb.o \
>  					   rcar_du_of_lvds_r8a7791.dtb.o \
>  					   rcar_du_of_lvds_r8a7793.dtb.o \
>  					   rcar_du_of_lvds_r8a7795.dtb.o \
>  					   rcar_du_of_lvds_r8a7796.dtb.o
> +
>  rcar-du-drm-$(CONFIG_DRM_RCAR_VSP)	+= rcar_du_vsp.o
>  
>  obj-$(CONFIG_DRM_RCAR_DU)		+= rcar-du-drm.o
> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_cmm.c b/drivers/gpu/drm/rcar-du/rcar_du_cmm.c
> new file mode 100644
> index 0000000..ac613a6e
> --- /dev/null
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_cmm.c
> @@ -0,0 +1,1200 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*************************************************************************/ /*
> + * DU CMM
> + *
> + * Copyright (C) 2018 Renesas Electronics Corporation
> + *
> + * License        Dual MIT/GPLv2

The DU driver is licensed under the terms of the GPL. Adding files with
a dual license will make license compliance more complex. Please use an
SPDX license header, remove all the boilerplate text below, and use the
GPL only.

> + *
> + * The contents of this file are subject to the MIT license as set out below.
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a copy
> + * of this software and associated documentation files (the "Software"), to deal
> + * in the Software without restriction, including without limitation the rights
> + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
> + * copies of the Software, and to permit persons to whom the Software is
> + * furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * Alternatively, the contents of this file may be used under the terms of
> + * the GNU General Public License Version 2 ("GPL") in which case the provisions
> + * of GPL are applicable instead of those above.
> + *
> + * If you wish to allow use of your version of this file only under the terms of
> + * GPL, and not to allow others to use your version of this file under the terms
> + * of the MIT license, indicate your decision by deleting the provisions above
> + * and replace them with the notice and other provisions required by GPL as set
> + * out in the file called "GPL-COPYING" included in this distribution. If you do
> + * not delete the provisions above, a recipient may use your version of this
> + * file under the terms of either the MIT license or GPL.
> + *
> + * This License is also included in this distribution in the file called
> + * "MIT-COPYING".
> + *
> + * EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) THE SOFTWARE IS
> + * PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
> + * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
> + * PARTICULAR PURPOSE AND NONINFRINGEMENT; AND (B) IN NO EVENT SHALL THE AUTHORS
> + * OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
> + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
> + * IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
> + *
> + *
> + * GPLv2:
> + * If you wish to use this file under the terms of GPL, following terms are
> + * effective.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; version 2 of the License.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + */ /*************************************************************************/
> +#include <linux/syscalls.h>
> +#include <linux/workqueue.h>
> +
> +#include <linux/reset.h>
> +#include <linux/sys_soc.h>
> +
> +#include <drm/drmP.h>

drmP.h is deprecated, please include the DRM headers you need directly.

> +#include <drm/drm_crtc.h>
> +#include <drm/drm_crtc_helper.h>
> +#include <drm/drm_fb_cma_helper.h>
> +#include <drm/drm_gem_cma_helper.h>
> +
> +#include "rcar_du_crtc.h"
> +#include "rcar_du_drv.h"
> +#include "rcar_du_kms.h"
> +#include "rcar_du_plane.h"
> +#include "rcar_du_regs.h"
> +#include <linux/clk.h>

Please sort headers alphabetically, with the linux/ headers first, then
drm/, then the local headers.

> +
> +/* #define DEBUG_PROCE_TIME 1 */

Please remove all commented-out code.

> +
> +#define CMM_LUT_NUM 256
> +#define CMM_CLU_NUM (17 * 17 * 17)
> +#define CMM_HGO_NUM 64
> +/* rcar_du_drm.h Include */
> +#define LUT_DOUBLE_BUFFER_AUTO		0
> +#define LUT_DOUBLE_BUFFER_A		1
> +#define LUT_DOUBLE_BUFFER_B		2
> +/* DRM_RCAR_DU_CMM_WAIT_EVENT: DU-CMM done event */
> +#define CMM_EVENT_CLU_DONE		BIT(0)
> +#define CMM_EVENT_HGO_DONE		BIT(1)
> +#define CMM_EVENT_LUT_DONE		BIT(2)
> +
> +#define CLU_DOUBLE_BUFFER_AUTO		0
> +#define CLU_DOUBLE_BUFFER_A		1
> +#define CLU_DOUBLE_BUFFER_B		2
> +enum {
> +	QUE_STAT_PENDING,
> +	QUE_STAT_ACTIVE,
> +	QUE_STAT_DONE,
> +};
> +
> +static const struct soc_device_attribute rcar_du_cmm_r8a7795_es1[] = {
> +	{ .soc_id = "r8a7795", .revision = "ES1.*" },
> +	{ /* sentinel */ }
> +};
> +
> +struct rcar_du_cmm;
> +struct rcar_du_cmm_file_priv;
> +
> +struct rcar_du_cmm_pending_event {
> +	struct list_head link;
> +	struct list_head  fpriv_link;
> +	unsigned int event;
> +	unsigned int stat;
> +	unsigned long callback_data;
> +	struct drm_gem_object *gem_obj;
> +	struct rcar_du_cmm *du_cmm;
> +	struct rcar_du_cmm_file_priv *fpriv;
> +};
> +
> +struct cmm_module_t {
> +	struct list_head list;
> +	union {
> +		struct {
> +			struct rcar_du_cmm_pending_event *p;
> +			int buf_mode;
> +			bool one_side;
> +		};
> +		int reset;
> +	};
> +};
> +
> +struct cmm_reg_save {
> +#ifdef CONFIG_PM_SLEEP
> +	wait_queue_head_t wait;
> +
> +	u32 *lut_table;
> +	u32 *clu_table;
> +#endif /* CONFIG_PM_SLEEP */
> +
> +	u32 cm2_ctl0;	/* CM2_CTL0 */
> +	u32 hgo_offset;	/* CMM_HGO_OFFSET */
> +	u32 hgo_size;	/* CMM_HGO_SIZE */
> +	u32 hgo_mode;	/* CMM_HGO_MODE */
> +};
> +
> +struct rcar_du_cmm {
> +	struct rcar_du_crtc *rcrtc;
> +
> +	/* CMM base address */
> +	void __iomem *cmm_base;
> +	struct clk *clock;
> +
> +	struct cmm_module_t lut;
> +	struct cmm_module_t clu;
> +	struct cmm_module_t hgo;
> +
> +	struct mutex lock;	/* lock for register setting */
> +	struct workqueue_struct *workqueue;
> +	struct work_struct work;
> +
> +	struct cmm_reg_save reg_save;

Please don't blindly save and restore registers. The device should be
reconfigured at resume time in an ordered maner, similar to what is done
at runtime. Restoring registers blindly usually leads to disasters as
the order of the register writes matter.

> +	bool active;
> +	bool dbuf;
> +	bool clu_dbuf;
> +	bool init;
> +	bool direct;
> +	bool vsync;
> +	bool authority;
> +	pid_t pid;

I don't know what this is for, but a pid_t field here is most probably a
sign that something is wrong.

> +	bool soc_support;
> +};
> +
> +struct rcar_du_cmm_file_priv {
> +	wait_queue_head_t event_wait;
> +	struct list_head list;
> +	struct list_head active_list;
> +	struct list_head *done_list;
> +};
> +
> +static DEFINE_MUTEX(cmm_event_lock);
> +static DEFINE_SPINLOCK(cmm_direct_lock);

No global variables please.

> +
> +static inline void event_prev_cancel_locked(struct cmm_module_t *module);

And no forward declarations for functions when possible.

> +static inline u32 cmm_index(struct rcar_du_cmm *_cmm)
> +{
> +	struct rcar_du_device *rcdu = _cmm->rcrtc->group->dev;
> +
> +	if (rcar_du_has(rcdu, RCAR_DU_FEATURE_R8A77965_REGS)) {
> +		if ((_cmm)->rcrtc->index == 3)
> +			return 2;
> +	}
> +	return (_cmm)->rcrtc->index;

CRTCs now have a hardware and a software index mechanism that should be
used instead of this hack.

I'll stop reviewing the implementation in details for now as I think
there are major issues in the series that will require large
refactoring, so I'll start with that, and review the code in details for
the next version.

> +}
> +
> +#define cmm_done_list(_cmm, _fpriv) \
> +	(&((_fpriv)->done_list[cmm_index(_cmm)]))
> +
> +static inline u32 rcar_du_cmm_read(struct rcar_du_cmm *du_cmm, u32 reg)
> +{
> +	return ioread32(du_cmm->cmm_base + reg);
> +}
> +
> +static inline void rcar_du_cmm_write(struct rcar_du_cmm *du_cmm,
> +				     u32 reg, u32 data)
> +{
> +	iowrite32(data, du_cmm->cmm_base + reg);
> +}
> +
> +/* create default CLU table data */
> +static inline u32 index_to_clu_data(int index)
> +{
> +	int r, g, b;
> +
> +	r = index % 17;
> +	index /= 17;
> +	g = index % 17;
> +	index /= 17;
> +	b = index % 17;
> +
> +	r = (r << 20);
> +	if (r > (255 << 16))
> +		r = (255 << 16);
> +	g = (g << 12);
> +	if (g > (255 << 8))
> +		g = (255 << 8);
> +	b = (b << 4);
> +	if (b > (255 << 0))
> +		b = (255 << 0);
> +
> +	return r | g | b;
> +}
> +
> +#ifdef DEBUG_PROCE_TIME
> +static long long diff_timevals(struct timeval *start, struct timeval *end)
> +{
> +	return (end->tv_sec * 1000000LL + end->tv_usec) -
> +		(start->tv_sec * 1000000LL + start->tv_usec);
> +}
> +#endif
> +
> +static void du_cmm_clk(struct rcar_du_cmm *du_cmm, bool on)
> +{
> +	if (on)
> +		clk_prepare_enable(du_cmm->clock);
> +	else
> +		clk_disable_unprepare(du_cmm->clock);
> +}
> +
> +int rcar_du_cmm_start_stop(struct rcar_du_crtc *rcrtc, bool on)
> +{
> +	struct rcar_du_cmm *du_cmm = rcrtc->cmm_handle;
> +	int i;
> +	u32 table_data;
> +	const struct drm_display_mode *mode;
> +	int w, h, x, y;
> +
> +	if (!du_cmm)
> +		return -EINVAL;
> +
> +	mutex_lock(&du_cmm->lock);
> +
> +	if (!on) {
> +		du_cmm->active = false;
> +
> +		rcar_du_cmm_write(du_cmm, CMM_LUT_CTRL, 0x00000000);
> +		rcar_du_cmm_write(du_cmm, CMM_CLU_CTRL, 0x00000000);
> +
> +		du_cmm_clk(du_cmm, false);
> +
> +		goto end;
> +	}
> +
> +	du_cmm_clk(du_cmm, true);
> +
> +	if (du_cmm->init)
> +		goto init_done;
> +
> +	du_cmm->init = true;
> +
> +	mode = &du_cmm->rcrtc->crtc.mode;
> +
> +	x = (du_cmm->reg_save.hgo_offset >> 16) & 0xFFFF;
> +	y = (du_cmm->reg_save.hgo_offset >> 0)  & 0xFFFF;
> +	w = (du_cmm->reg_save.hgo_size >> 16) & 0xFFFF;
> +	h = (du_cmm->reg_save.hgo_size >> 0)  & 0xFFFF;
> +	if ((mode->hdisplay < (w + x)) || w == 0) {
> +		x = 0;
> +		w = mode->hdisplay;
> +	}
> +	if ((mode->vdisplay < (h + y)) || h == 0) {
> +		y = 0;
> +		h = mode->vdisplay;
> +	}
> +	du_cmm->reg_save.hgo_offset = (x << 16) | y;
> +	du_cmm->reg_save.hgo_size = (w << 16) | h;
> +
> +	if (mode->flags & DRM_MODE_FLAG_PVSYNC)
> +		du_cmm->reg_save.cm2_ctl0 |= CMM_CTL0_VPOL;
> +	else
> +		du_cmm->reg_save.cm2_ctl0 &= ~CMM_CTL0_VPOL;
> +
> +	rcar_du_cmm_write(du_cmm, CM2_CTL0, du_cmm->reg_save.cm2_ctl0);
> +	rcar_du_cmm_write(du_cmm, CMM_HGO_OFFSET, du_cmm->reg_save.hgo_offset);
> +	rcar_du_cmm_write(du_cmm, CMM_HGO_SIZE, du_cmm->reg_save.hgo_size);
> +	rcar_du_cmm_write(du_cmm, CMM_HGO_MODE, du_cmm->reg_save.hgo_mode);
> +	rcar_du_cmm_write(du_cmm, CMM_HGO_LB_TH, 0);
> +	rcar_du_cmm_write(du_cmm, CMM_HGO_LB0_H, 0);
> +	rcar_du_cmm_write(du_cmm, CMM_HGO_LB0_V, 0);
> +	rcar_du_cmm_write(du_cmm, CMM_HGO_LB1_H, 0);
> +	rcar_du_cmm_write(du_cmm, CMM_HGO_LB1_V, 0);
> +	rcar_du_cmm_write(du_cmm, CMM_HGO_LB2_H, 0);
> +	rcar_du_cmm_write(du_cmm, CMM_HGO_LB2_V, 0);
> +	rcar_du_cmm_write(du_cmm, CMM_HGO_LB3_H, 0);
> +	rcar_du_cmm_write(du_cmm, CMM_HGO_LB3_V, 0);
> +
> +	/* init color table */
> +	for (i = 0; i < CMM_LUT_NUM; i++) {
> +	#ifdef CONFIG_PM_SLEEP
> +		table_data = du_cmm->reg_save.lut_table[i];
> +	#else
> +		table_data = ((i << 16) | (i << 8) | (i << 0));
> +	#endif /* CONFIG_PM_SLEEP */
> +		rcar_du_cmm_write(du_cmm, CMM_LUT_TBLA(i), table_data);
> +
> +		if (du_cmm->dbuf)
> +			rcar_du_cmm_write(du_cmm, CMM_LUT_TBLB(i),
> +					  table_data);
> +	}
> +
> +	rcar_du_cmm_write(du_cmm, CMM_CLU_CTRL,
> +			  CMM_CLU_CTRL_AAI | CMM_CLU_CTRL_MVS);
> +
> +	rcar_du_cmm_write(du_cmm, CMM_CLU_ADDR, 0);
> +	if (du_cmm->clu_dbuf)
> +		rcar_du_cmm_write(du_cmm, CMM_CLU_ADDR2, 0);
> +
> +	for (i = 0; i < CMM_CLU_NUM; i++) {
> +	#ifdef CONFIG_PM_SLEEP
> +		table_data = du_cmm->reg_save.clu_table[i];
> +	#else
> +		table_data = index_to_clu_data(i);
> +	#endif /* CONFIG_PM_SLEEP */
> +		rcar_du_cmm_write(du_cmm, CMM_CLU_DATA, table_data);
> +
> +		if (du_cmm->dbuf)
> +			rcar_du_cmm_write(du_cmm, CMM_CLU_DATA2,
> +					  table_data);
> +	}
> +
> +init_done:
> +	/* enable color table */
> +	rcar_du_cmm_write(du_cmm, CMM_LUT_CTRL, CMM_LUT_CTRL_EN);
> +	rcar_du_cmm_write(du_cmm, CMM_CLU_CTRL, CMM_CLU_CTRL_AAI |
> +			  CMM_CLU_CTRL_MVS | CMM_CLU_CTRL_EN);
> +
> +	du_cmm->active = true;
> +end:
> +	mutex_unlock(&du_cmm->lock);
> +
> +	return 0;
> +}
> +
> +#define gem_to_vaddr(gem_obj) \
> +	(container_of((gem_obj), struct drm_gem_cma_object, base)->vaddr)
> +
> +static inline void cmm_vblank_put(struct rcar_du_cmm_pending_event *p)
> +{
> +	if (p->du_cmm)
> +		drm_crtc_vblank_put(&p->du_cmm->rcrtc->crtc);
> +}
> +
> +static inline void
> +cmm_gem_object_unreference(struct rcar_du_cmm_pending_event *p)
> +{
> +	if (p->gem_obj)
> +		drm_gem_object_unreference_unlocked(p->gem_obj);
> +}
> +
> +static inline void _event_done_locked(struct rcar_du_cmm_pending_event *p)
> +{
> +	cmm_gem_object_unreference(p);
> +
> +	if (p->fpriv) {
> +		p->stat = QUE_STAT_DONE;
> +		list_del(&p->link); /* delete from p->fpriv->active_list */
> +		list_add_tail(&p->link, cmm_done_list(p->du_cmm, p->fpriv));
> +		wake_up_interruptible(&p->fpriv->event_wait);
> +	} else {
> +		/* link deleted by rcar_du_cmm_postclose */
> +		kfree(p);
> +	}
> +}
> +
> +/* cancel from active_list (case of LUT/CLU double buffer mode) */
> +static inline void event_prev_cancel_locked(struct cmm_module_t *module)
> +{
> +	struct rcar_du_cmm_pending_event *p = module->p;
> +
> +	if (!p)
> +		return;
> +
> +	module->p = NULL;
> +
> +	_event_done_locked(p);
> +}
> +
> +static inline void event_done(struct rcar_du_cmm_pending_event *p)
> +{
> +	/* vblank is put */
> +
> +	mutex_lock(&cmm_event_lock);
> +
> +	_event_done_locked(p);
> +
> +	mutex_unlock(&cmm_event_lock);
> +}
> +
> +static inline void lc_event_done(struct cmm_module_t *module,
> +				 struct rcar_du_cmm_pending_event *p,
> +				 bool done)
> +{
> +	/* vblank is put */
> +
> +	mutex_lock(&cmm_event_lock);
> +
> +	if (!done && list_empty(&module->list))
> +		module->p = p;
> +	else
> +		_event_done_locked(p);
> +
> +	mutex_unlock(&cmm_event_lock);
> +}
> +
> +static inline struct rcar_du_cmm_pending_event *
> +event_pop_locked(struct cmm_module_t *module)
> +{
> +	struct rcar_du_cmm_pending_event *p =
> +		list_first_entry(&module->list,
> +				 struct rcar_du_cmm_pending_event,
> +				 link);
> +
> +	p->stat = QUE_STAT_ACTIVE;
> +	list_del(&p->link); /* delete from du_cmm->[lut|clu|hgo].list */
> +	list_add_tail(&p->link, &p->fpriv->active_list);
> +	cmm_vblank_put(p);
> +
> +	return p;
> +}
> +
> +struct rcar_du_cmm_work_stat {
> +	union {
> +		struct {
> +			struct rcar_du_cmm_pending_event *p;
> +			bool done;
> +			bool table_copy;
> +		};
> +		struct {
> +			struct rcar_du_cmm_pending_event *p2;
> +			bool reset;
> +		};
> +	};
> +};
> +
> +static inline void one_side(struct rcar_du_cmm *du_cmm,
> +			    struct cmm_module_t *module,
> +			    bool on)
> +{
> +	if (on && !module->one_side) {
> +		module->one_side = true;
> +		drm_crtc_vblank_get(&du_cmm->rcrtc->crtc);
> +	} else if (!on && module->one_side) {
> +		module->one_side = false;
> +		drm_crtc_vblank_put(&du_cmm->rcrtc->crtc);
> +	}
> +}
> +
> +/* pop LUT que */
> +static int lut_pop_locked(struct rcar_du_cmm *du_cmm,
> +			  struct rcar_du_cmm_work_stat *stat)
> +{
> +	bool is_one_side = false;
> +
> +	stat->done = true;
> +	stat->table_copy = false;
> +
> +	if (!list_empty(&du_cmm->lut.list)) {
> +		stat->p = event_pop_locked(&du_cmm->lut);
> +
> +		/* prev lut table */
> +		event_prev_cancel_locked(&du_cmm->lut);
> +
> +		if (du_cmm->lut.buf_mode == LUT_DOUBLE_BUFFER_AUTO) {
> +			is_one_side = true;
> +			if (list_empty(&du_cmm->lut.list))
> +				stat->done = false;
> +		}
> +
> +	} else if (du_cmm->lut.p) {
> +		/* prev lut table */
> +		stat->p = du_cmm->lut.p;
> +		du_cmm->lut.p = NULL;
> +	} else {
> +		stat->done = false;
> +		stat->p = NULL;
> +		stat->table_copy = du_cmm->lut.one_side;
> +	}
> +
> +	one_side(du_cmm, &du_cmm->lut, is_one_side);
> +
> +	return 0;
> +}
> +
> +static int lut_table_copy(struct rcar_du_cmm *du_cmm)
> +{
> +	int i;
> +	u32 src, dst;
> +
> +	if (rcar_du_cmm_read(du_cmm, CM2_CTL1) & CMM_CTL1_BFS) {
> +		dst = CMM_LUT_TBLA(0);
> +		src = CMM_LUT_TBLB(0);
> +	} else {
> +		dst = CMM_LUT_TBLB(0);
> +		src = CMM_LUT_TBLA(0);
> +	}
> +
> +	for (i = 0; i < CMM_LUT_NUM; i++) {
> +		rcar_du_cmm_write(du_cmm, dst, rcar_du_cmm_read(du_cmm, src));
> +		dst += 4;
> +		src += 4;
> +	}
> +
> +	return 0;
> +}
> +
> +/* set 1D look up table */
> +static int lut_set(struct rcar_du_cmm *du_cmm,
> +		   struct rcar_du_cmm_work_stat *stat)
> +{
> +	int i;
> +	u32 lut_base;
> +	u32 *lut_buf;
> +
> +	if (!stat->p) {
> +		if (stat->table_copy)
> +			lut_table_copy(du_cmm);
> +		return 0; /* skip */
> +	}
> +
> +	/* set LUT */
> +	switch (du_cmm->lut.buf_mode) {
> +	case LUT_DOUBLE_BUFFER_A:
> +		lut_base = CMM_LUT_TBLA(0);
> +		break;
> +
> +	case LUT_DOUBLE_BUFFER_AUTO:
> +		if (rcar_du_cmm_read(du_cmm, CM2_CTL1) & CMM_CTL1_BFS) {
> +			lut_base = CMM_LUT_TBLA(0);
> +			break;
> +		}
> +		lut_base = CMM_LUT_TBLB(0);
> +		break;
> +	case LUT_DOUBLE_BUFFER_B:
> +		lut_base = CMM_LUT_TBLB(0);
> +		break;
> +
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	lut_buf = gem_to_vaddr(stat->p->gem_obj);
> +	for (i = 0; i < CMM_LUT_NUM; i++)
> +		rcar_du_cmm_write(du_cmm, lut_base + i * 4, lut_buf[i]);
> +
> +	lc_event_done(&du_cmm->lut, stat->p, stat->done);
> +
> +	return 0;
> +}
> +
> +/* pop CLU que */
> +static int clu_pop_locked(struct rcar_du_cmm *du_cmm,
> +			  struct rcar_du_cmm_work_stat *stat)
> +{
> +	bool is_one_side = false;
> +
> +	stat->done = true;
> +	stat->table_copy = false;
> +
> +	if (!list_empty(&du_cmm->clu.list)) {
> +		stat->p = event_pop_locked(&du_cmm->clu);
> +
> +		/* prev clu table */
> +		event_prev_cancel_locked(&du_cmm->clu);
> +
> +		if (du_cmm->clu.buf_mode == CLU_DOUBLE_BUFFER_AUTO) {
> +			is_one_side = true;
> +			if (list_empty(&du_cmm->clu.list))
> +				stat->done = false;
> +		}
> +
> +	} else if (du_cmm->clu.p) {
> +		/* prev clu table */
> +		stat->p = du_cmm->clu.p;
> +		du_cmm->clu.p = NULL;
> +	} else {
> +		stat->done = false;
> +		stat->p = NULL;
> +		stat->table_copy = du_cmm->clu.one_side;
> +	}
> +
> +	one_side(du_cmm, &du_cmm->clu, is_one_side);
> +
> +	return 0;
> +}
> +
> +static int clu_table_copy(struct rcar_du_cmm *du_cmm)
> +{
> +	int i, j, k;
> +	u32 src_addr, src_data, dst_addr, dst_data;
> +
> +	if (rcar_du_cmm_read(du_cmm, CM2_CTL1) & CMM_CTL1_BFS) {
> +		dst_addr = CMM_CLU_ADDR;
> +		dst_data = CMM_CLU_DATA;
> +		src_addr = CMM_CLU_ADDR2;
> +		src_data = CMM_CLU_DATA2;
> +	} else {
> +		dst_addr = CMM_CLU_ADDR2;
> +		dst_data = CMM_CLU_DATA2;
> +		src_addr = CMM_CLU_ADDR;
> +		src_data = CMM_CLU_DATA;
> +	}
> +
> +	rcar_du_cmm_write(du_cmm, dst_addr, 0);
> +	for (i = 0; i < 17; i++) {
> +		for (j = 0; j < 17; j++) {
> +			for (k = 0; k < 17; k++) {
> +				rcar_du_cmm_write(du_cmm, src_addr,
> +						  (k << 16) | (j << 8) |
> +						  (i << 0));
> +				rcar_du_cmm_write(du_cmm, dst_data,
> +						  rcar_du_cmm_read(du_cmm,
> +								   src_data));
> +			}
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +/* set 3D look up table */
> +static int clu_set(struct rcar_du_cmm *du_cmm,
> +		   struct rcar_du_cmm_work_stat *stat)
> +{
> +	int i;
> +	u32 addr_reg, data_reg;
> +	u32 *clu_buf;
> +
> +	if (!stat->p) {
> +		if (stat->table_copy)
> +			clu_table_copy(du_cmm);
> +		return 0; /* skip */
> +	}
> +
> +	/* set CLU */
> +	switch (du_cmm->clu.buf_mode) {
> +	case CLU_DOUBLE_BUFFER_A:
> +		addr_reg = CMM_CLU_ADDR;
> +		data_reg = CMM_CLU_DATA;
> +		break;
> +
> +	case CLU_DOUBLE_BUFFER_AUTO:
> +		if (rcar_du_cmm_read(du_cmm, CM2_CTL1) & CMM_CTL1_BFS) {
> +			addr_reg = CMM_CLU_ADDR;
> +			data_reg = CMM_CLU_DATA;
> +			break;
> +		}
> +		addr_reg = CMM_CLU_ADDR2;
> +		data_reg = CMM_CLU_DATA2;
> +		break;
> +	case CLU_DOUBLE_BUFFER_B:
> +		addr_reg = CMM_CLU_ADDR2;
> +		data_reg = CMM_CLU_DATA2;
> +		break;
> +
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	clu_buf = gem_to_vaddr(stat->p->gem_obj);
> +	rcar_du_cmm_write(du_cmm, addr_reg, 0);
> +	for (i = 0; i < CMM_CLU_NUM; i++)
> +		rcar_du_cmm_write(du_cmm, data_reg, clu_buf[i]);
> +
> +	lc_event_done(&du_cmm->clu, stat->p, stat->done);
> +
> +	return 0;
> +}
> +
> +/* pop HGO que */
> +static int hgo_pop_locked(struct rcar_du_cmm *du_cmm,
> +			  struct rcar_du_cmm_work_stat *stat)
> +{
> +	struct rcar_du_cmm_pending_event *_p = NULL;
> +
> +	if (!list_empty(&du_cmm->hgo.list))
> +		_p = event_pop_locked(&du_cmm->hgo);
> +
> +	if (du_cmm->hgo.reset) {
> +		drm_crtc_vblank_put(&du_cmm->rcrtc->crtc);
> +		du_cmm->hgo.reset = 0;
> +		stat->reset = true;
> +	} else {
> +		stat->reset = false;
> +	}
> +
> +	stat->p2 = _p;
> +
> +	return 0;
> +}
> +
> +/* get histogram */
> +static int hgo_get(struct rcar_du_cmm *du_cmm,
> +		   struct rcar_du_cmm_work_stat *stat)
> +{
> +	int i, j;
> +	const u32 histo_offset[3] = {
> +		CMM_HGO_R_HISTO(0),
> +		CMM_HGO_G_HISTO(0),
> +		CMM_HGO_B_HISTO(0),
> +	};
> +	void *vaddr;
> +
> +	if (!stat->p2) {
> +		if (stat->reset)
> +			goto hgo_reset;
> +
> +		return 0; /* skip */
> +	}
> +
> +	vaddr = gem_to_vaddr(stat->p2->gem_obj);
> +	for (i = 0; i < 3; i++) {
> +		u32 *hgo_buf = vaddr + CMM_HGO_NUM * 4 * i;
> +
> +		for (j = 0; j < CMM_HGO_NUM; j++)
> +			hgo_buf[j] = rcar_du_cmm_read(du_cmm,
> +						      histo_offset[i] + j * 4);
> +	}
> +
> +	event_done(stat->p2);
> +
> +hgo_reset:
> +	rcar_du_cmm_write(du_cmm, CMM_HGO_REGRST, CMM_HGO_REGRST_RCLEA);
> +
> +	return 0;
> +}
> +
> +static bool du_cmm_vsync_get(struct rcar_du_cmm *du_cmm)
> +{
> +	unsigned long flags;
> +	bool vsync;
> +
> +	spin_lock_irqsave(&cmm_direct_lock, flags);
> +	vsync = du_cmm->vsync;
> +	du_cmm->vsync = false;
> +	spin_unlock_irqrestore(&cmm_direct_lock, flags);
> +
> +	return vsync;
> +}
> +
> +static void du_cmm_vsync_set(struct rcar_du_cmm *du_cmm, bool vsync)
> +{
> +	unsigned long flags;
> +
> +	spin_lock_irqsave(&cmm_direct_lock, flags);
> +	du_cmm->vsync = vsync;
> +	spin_unlock_irqrestore(&cmm_direct_lock, flags);
> +}
> +
> +static void du_cmm_work(struct work_struct *work)
> +{
> +	struct rcar_du_cmm *du_cmm =
> +			container_of(work, struct rcar_du_cmm, work);
> +	struct rcar_du_cmm_work_stat s_lut;
> +	struct rcar_du_cmm_work_stat s_clu;
> +	struct rcar_du_cmm_work_stat s_hgo;
> +#ifdef DEBUG_PROCE_TIME
> +	struct timeval start_time, end_time;
> +	unsigned long lut_time, clu_time, hgo_time;
> +#endif
> +	bool vsync_status = false;
> +
> +	memset(&s_lut, 0, sizeof(struct rcar_du_cmm_work_stat));
> +	memset(&s_clu, 0, sizeof(struct rcar_du_cmm_work_stat));
> +	memset(&s_hgo, 0, sizeof(struct rcar_du_cmm_work_stat));
> +
> +	vsync_status = du_cmm_vsync_get(du_cmm);
> +
> +	mutex_lock(&cmm_event_lock);
> +
> +	lut_pop_locked(du_cmm, &s_lut);
> +	clu_pop_locked(du_cmm, &s_clu);
> +	if (vsync_status)
> +		hgo_pop_locked(du_cmm, &s_hgo);
> +
> +	mutex_unlock(&cmm_event_lock);
> +
> +	/* set LUT */
> +#ifdef DEBUG_PROCE_TIME
> +	do_gettimeofday(&start_time);
> +#endif
> +	lut_set(du_cmm, &s_lut);
> +#ifdef DEBUG_PROCE_TIME
> +	do_gettimeofday(&end_time);
> +	lut_time = (long)diff_timevals(&start_time, &end_time);
> +#endif
> +
> +	/* set CLU */
> +#ifdef DEBUG_PROCE_TIME
> +	do_gettimeofday(&start_time);
> +#endif
> +	clu_set(du_cmm, &s_clu);
> +#ifdef DEBUG_PROCE_TIME
> +	do_gettimeofday(&end_time);
> +	clu_time = (long)diff_timevals(&start_time, &end_time);
> +#endif
> +
> +	/* get HGO */
> +#ifdef DEBUG_PROCE_TIME
> +	do_gettimeofday(&start_time);
> +#endif
> +	if (vsync_status)
> +		hgo_get(du_cmm, &s_hgo);
> +#ifdef DEBUG_PROCE_TIME
> +	do_gettimeofday(&end_time);
> +	hgo_time = (long)diff_timevals(&start_time, &end_time);
> +#endif
> +
> +#ifdef CONFIG_PM_SLEEP
> +	wake_up_interruptible(&du_cmm->reg_save.wait);
> +#endif /* CONFIG_PM_SLEEP */
> +
> +#ifdef DEBUG_PROCE_TIME
> +	{
> +		struct rcar_du_device *rcdu = du_cmm->rcrtc->group->dev;
> +
> +		if (s_lut.p)
> +			dev_info(rcdu->dev, "LUT %ld usec.\n", lut_time);
> +		if (s_clu.p)
> +			dev_info(rcdu->dev, "LUT %ld usec.\n", clu_time);
> +		if (s_hgo.p2)
> +			dev_info(rcdu->dev, "HGO %ld usec.\n", hgo_time);
> +	}
> +#endif
> +}
> +
> +static int du_cmm_que_empty(struct rcar_du_cmm *du_cmm)
> +{
> +	if (list_empty(&du_cmm->lut.list) && !du_cmm->lut.p &&
> +	    !du_cmm->lut.one_side &&
> +	    list_empty(&du_cmm->clu.list) && !du_cmm->clu.p &&
> +	    !du_cmm->clu.one_side &&
> +	    list_empty(&du_cmm->hgo.list) && !du_cmm->hgo.reset)
> +		return 1;
> +
> +	return 0;
> +}
> +
> +void rcar_du_cmm_kick(struct rcar_du_crtc *rcrtc)
> +{
> +	struct rcar_du_cmm *du_cmm = rcrtc->cmm_handle;
> +
> +	if (!du_cmm)
> +		return;
> +
> +	if (!du_cmm->active)
> +		return;
> +
> +	if (!du_cmm_que_empty(du_cmm)) {
> +		du_cmm_vsync_set(du_cmm, true);
> +		queue_work(du_cmm->workqueue, &du_cmm->work);
> +	}
> +}
> +
> +#ifdef CONFIG_PM_SLEEP
> +int rcar_du_cmm_pm_suspend(struct rcar_du_crtc *rcrtc)
> +{
> +	struct rcar_du_cmm *du_cmm = rcrtc->cmm_handle;
> +	struct rcar_du_device *rcdu = rcrtc->group->dev;
> +	int i, j, k, index;
> +	int ret;
> +
> +	if (!du_cmm)
> +		return 0;
> +
> +	ret = wait_event_timeout(du_cmm->reg_save.wait,
> +				 du_cmm_que_empty(du_cmm),
> +				 msecs_to_jiffies(500));
> +	if (ret == 0)
> +		dev_err(rcdu->dev, "rcar-du cmm suspend : timeout\n");
> +
> +	if (!du_cmm->init)
> +		return 0;
> +
> +	du_cmm->init = false;
> +
> +	if (!du_cmm->active)
> +		du_cmm_clk(du_cmm, true);
> +
> +	/* table save */
> +	for (i = 0; i < CMM_LUT_NUM; i++) {
> +		du_cmm->reg_save.lut_table[i] =
> +			rcar_du_cmm_read(du_cmm, CMM_LUT_TBLA(i));
> +	}
> +
> +	index = 0;
> +	for (i = 0; i < 17; i++) {
> +		for (j = 0; j < 17; j++) {
> +			for (k = 0; k < 17; k++) {
> +				rcar_du_cmm_write(du_cmm, CMM_CLU_ADDR,
> +						  (k << 16) | (j << 8) |
> +						  (i << 0));
> +				du_cmm->reg_save.clu_table[index++] =
> +					rcar_du_cmm_read(du_cmm, CMM_CLU_DATA);
> +			}
> +		}
> +	}
> +
> +	if (!du_cmm->active)
> +		du_cmm_clk(du_cmm, false);
> +
> +	return 0;
> +}
> +
> +int rcar_du_cmm_pm_resume(struct rcar_du_crtc *rcrtc)
> +{
> +	/* none */
> +	return 0;
> +}
> +#endif /* CONFIG_PM_SLEEP */
> +
> +int rcar_du_cmm_driver_open(struct drm_device *dev, struct drm_file *file_priv)
> +{
> +	struct rcar_du_device *rcdu = dev->dev_private;
> +	struct rcar_du_cmm_file_priv *fpriv;
> +	int i;
> +
> +	if (!rcar_du_has(rcdu, RCAR_DU_FEATURE_CMM))
> +		return 0;
> +
> +	file_priv->driver_priv = NULL;
> +
> +	fpriv = kzalloc(sizeof(*fpriv), GFP_KERNEL);
> +	if (unlikely(!fpriv))
> +		return -ENOMEM;
> +
> +	fpriv->done_list = kcalloc(rcdu->info->num_crtcs,
> +				   sizeof(*fpriv->done_list),
> +				   GFP_KERNEL);
> +	if (unlikely(!fpriv->done_list)) {
> +		kfree(fpriv);
> +		return -ENOMEM;
> +	}
> +
> +	init_waitqueue_head(&fpriv->event_wait);
> +	INIT_LIST_HEAD(&fpriv->list);
> +	INIT_LIST_HEAD(&fpriv->active_list);
> +	for (i = 0; i < rcdu->info->num_crtcs; i++)
> +		INIT_LIST_HEAD(&fpriv->done_list[i]);
> +
> +	file_priv->driver_priv = fpriv;
> +
> +	return 0;
> +}
> +
> +void rcar_du_cmm_postclose(struct drm_device *dev, struct drm_file *file_priv)
> +{
> +	struct rcar_du_device *rcdu = dev->dev_private;
> +	struct rcar_du_cmm_file_priv *fpriv = file_priv->driver_priv;
> +	struct rcar_du_cmm_pending_event *p, *pt;
> +	struct rcar_du_crtc *rcrtc;
> +	struct rcar_du_cmm *du_cmm;
> +	int i, crtcs_cnt, ret;
> +	u32 table_data;
> +
> +	if (!rcar_du_has(rcdu, RCAR_DU_FEATURE_CMM))
> +		return;
> +
> +	mutex_lock(&cmm_event_lock);
> +
> +	/* Unlink file priv events */
> +	list_for_each_entry_safe(p, pt, &fpriv->list, fpriv_link) {
> +		list_del(&p->fpriv_link);
> +		list_del(&p->link);
> +		switch (p->stat) {
> +		case QUE_STAT_PENDING:
> +			cmm_vblank_put(p);
> +			cmm_gem_object_unreference(p);
> +			kfree(p);
> +			break;
> +		case QUE_STAT_DONE:
> +			kfree(p);
> +			break;
> +		case QUE_STAT_ACTIVE:
> +			p->fpriv = NULL;
> +			break;
> +		}
> +	}
> +
> +	mutex_unlock(&cmm_event_lock);
> +
> +	kfree(fpriv->done_list);
> +	kfree(fpriv);
> +	file_priv->driver_priv = NULL;
> +
> +	for (crtcs_cnt = 0; crtcs_cnt < rcdu->num_crtcs; crtcs_cnt++) {
> +		rcrtc = &rcdu->crtcs[crtcs_cnt];
> +		du_cmm = rcrtc->cmm_handle;
> +		if (du_cmm->authority && du_cmm->pid == task_pid_nr(current)) {
> +			du_cmm->authority = false;
> +			du_cmm->pid = 0;
> +			ret = wait_event_timeout(du_cmm->reg_save.wait,
> +						 du_cmm_que_empty(du_cmm),
> +						 msecs_to_jiffies(500));
> +			if (ret == 0)
> +				dev_err(rcdu->dev, "rcar-du cmm close : timeout\n");
> +
> +			for (i = 0; i < CMM_LUT_NUM; i++)
> +				du_cmm->reg_save.lut_table[i] = (i << 16) |
> +								(i << 8) |
> +								(i << 0);
> +
> +			for (i = 0; i < CMM_CLU_NUM; i++) {
> +				du_cmm->reg_save.clu_table[i] =
> +							index_to_clu_data(i);
> +			}
> +
> +			for (i = 0; i < CMM_LUT_NUM; i++) {
> +#ifdef CONFIG_PM_SLEEP
> +				table_data = du_cmm->reg_save.lut_table[i];
> +#else
> +				table_data = ((i << 16) | (i << 8) | (i << 0));
> +#endif /* CONFIG_PM_SLEEP */
> +				rcar_du_cmm_write(du_cmm, CMM_LUT_TBLA(i),
> +						  table_data);
> +				if (du_cmm->dbuf) {
> +					rcar_du_cmm_write(du_cmm,
> +							  CMM_LUT_TBLB(i),
> +							  table_data);
> +				}
> +			}
> +
> +			for (i = 0; i < CMM_CLU_NUM; i++) {
> +#ifdef CONFIG_PM_SLEEP
> +				table_data = du_cmm->reg_save.clu_table[i];
> +#else
> +				table_data = index_to_clu_data(i);
> +#endif /* CONFIG_PM_SLEEP */
> +				rcar_du_cmm_write(du_cmm, CMM_CLU_DATA,
> +						  table_data);
> +
> +				if (du_cmm->dbuf) {
> +					rcar_du_cmm_write(du_cmm, CMM_CLU_DATA2,
> +							  table_data);
> +				}
> +			}
> +		}
> +	}
> +}
> +
> +int rcar_du_cmm_init(struct rcar_du_crtc *rcrtc)
> +{
> +	struct rcar_du_cmm *du_cmm;
> +	int ret;
> +	int i;
> +	struct rcar_du_device *rcdu = rcrtc->group->dev;
> +	char name[64];
> +	struct resource *mem;
> +
> +	if (!rcar_du_has(rcdu, RCAR_DU_FEATURE_CMM))
> +		return 0;
> +
> +	du_cmm = devm_kzalloc(rcdu->dev, sizeof(*du_cmm), GFP_KERNEL);
> +	if (!du_cmm) {
> +		ret = -ENOMEM;
> +		goto error_alloc;
> +	}
> +
> +	/* DU-CMM mapping */
> +	sprintf(name, "cmm.%u", rcrtc->index);
> +	mem = platform_get_resource_byname(to_platform_device(rcdu->dev),
> +					   IORESOURCE_MEM, name);
> +	if (!mem) {
> +		dev_err(rcdu->dev, "rcar-du cmm init : failed to get memory resource\n");
> +		ret = -EINVAL;
> +		goto error_mapping_cmm;
> +	}
> +	du_cmm->cmm_base = devm_ioremap_nocache(rcdu->dev, mem->start,
> +						resource_size(mem));
> +	if (!du_cmm->cmm_base) {
> +		dev_err(rcdu->dev, "rcar-du cmm init : failed to map iomem\n");
> +		ret = -EINVAL;
> +		goto error_mapping_cmm;
> +	}
> +	du_cmm->clock = devm_clk_get(rcdu->dev, name);
> +	if (IS_ERR(du_cmm->clock)) {
> +		dev_err(rcdu->dev, "failed to get clock\n");
> +		ret = PTR_ERR(du_cmm->clock);
> +		goto error_clock_cmm;
> +	}
> +
> +	du_cmm->rcrtc = rcrtc;
> +
> +	du_cmm->reg_save.cm2_ctl0 = 0;
> +	du_cmm->reg_save.hgo_offset = 0;
> +	du_cmm->reg_save.hgo_size = 0;
> +	du_cmm->reg_save.hgo_mode = 0;
> +
> +	du_cmm->dbuf = rcar_du_has(rcdu, RCAR_DU_FEATURE_CMM_LUT_DBUF);
> +	if (du_cmm->dbuf) {
> +		du_cmm->lut.buf_mode = LUT_DOUBLE_BUFFER_AUTO;
> +		du_cmm->reg_save.cm2_ctl0 |= CMM_CTL0_DBUF;
> +	} else {
> +		dev_err(rcdu->dev, "single buffer is not supported.\n");
> +		du_cmm->dbuf = true;
> +		du_cmm->lut.buf_mode = LUT_DOUBLE_BUFFER_AUTO;
> +		du_cmm->reg_save.cm2_ctl0 |= CMM_CTL0_DBUF;
> +	}
> +
> +	du_cmm->clu_dbuf = rcar_du_has(rcdu, RCAR_DU_FEATURE_CMM_CLU_DBUF);
> +	if (du_cmm->clu_dbuf) {
> +		du_cmm->clu.buf_mode = CLU_DOUBLE_BUFFER_AUTO;
> +		du_cmm->reg_save.cm2_ctl0 |= CMM_CTL0_CLUDB;
> +	} else {
> +		dev_err(rcdu->dev, "single buffer is not supported.\n");
> +		du_cmm->clu_dbuf = true;
> +		du_cmm->clu.buf_mode = CLU_DOUBLE_BUFFER_AUTO;
> +		du_cmm->reg_save.cm2_ctl0 |= CMM_CTL0_CLUDB;
> +	}
> +
> +#ifdef CONFIG_PM_SLEEP
> +	du_cmm->reg_save.lut_table =
> +		devm_kzalloc(rcdu->dev, CMM_LUT_NUM * 4, GFP_KERNEL);
> +	if (!du_cmm->reg_save.lut_table) {
> +		ret = -ENOMEM;
> +		goto error_lut_reg_save_buf;
> +	}
> +	for (i = 0; i < CMM_LUT_NUM; i++)
> +		du_cmm->reg_save.lut_table[i] = (i << 16) | (i << 8) | (i << 0);
> +
> +	du_cmm->reg_save.clu_table =
> +		devm_kzalloc(rcdu->dev, CMM_CLU_NUM * 4, GFP_KERNEL);
> +	if (!du_cmm->reg_save.clu_table) {
> +		ret = -ENOMEM;
> +		goto error_clu_reg_save_buf;
> +	}
> +	for (i = 0; i < CMM_CLU_NUM; i++)
> +		du_cmm->reg_save.clu_table[i] = index_to_clu_data(i);
> +
> +	init_waitqueue_head(&du_cmm->reg_save.wait);
> +#endif /* CONFIG_PM_SLEEP */
> +	if (soc_device_match(rcar_du_cmm_r8a7795_es1))
> +		du_cmm->soc_support = false;
> +	else
> +		du_cmm->soc_support = true;
> +
> +	du_cmm->active = false;
> +	du_cmm->init = false;
> +	du_cmm->direct = true;
> +
> +	mutex_init(&du_cmm->lock);
> +	INIT_LIST_HEAD(&du_cmm->lut.list);
> +	du_cmm->lut.p = NULL;
> +	du_cmm->lut.one_side = false;
> +	INIT_LIST_HEAD(&du_cmm->clu.list);
> +	du_cmm->clu.p = NULL;
> +	du_cmm->clu.one_side = false;
> +	INIT_LIST_HEAD(&du_cmm->hgo.list);
> +	du_cmm->hgo.reset = 0;
> +
> +	sprintf(name, "du-cmm%d", rcrtc->index);
> +	du_cmm->workqueue = create_singlethread_workqueue(name);
> +	INIT_WORK(&du_cmm->work, du_cmm_work);
> +
> +	rcrtc->cmm_handle = du_cmm;
> +
> +	dev_info(rcdu->dev, "DU%d use CMM(%s buffer)\n",
> +		 rcrtc->index, du_cmm->dbuf ? "Double" : "Single");
> +
> +	return 0;
> +
> +#ifdef CONFIG_PM_SLEEP
> +error_clu_reg_save_buf:
> +error_lut_reg_save_buf:
> +#endif /* CONFIG_PM_SLEEP */
> +error_clock_cmm:
> +	devm_iounmap(rcdu->dev, du_cmm->cmm_base);
> +error_mapping_cmm:
> +	devm_kfree(rcdu->dev, du_cmm);
> +error_alloc:
> +	return ret;
> +}
> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
> index 15dc9ca..864fb94 100644
> --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
> @@ -296,6 +296,19 @@ static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc)
>  	rcar_du_crtc_write(rcrtc, HDSR, mode->htotal - mode->hsync_start - 19);
>  	rcar_du_crtc_write(rcrtc, HDER, mode->htotal - mode->hsync_start +
>  					mode->hdisplay - 19);
> +	if (rcar_du_has(rcrtc->group->dev, RCAR_DU_FEATURE_CMM)) {
> +		rcar_du_crtc_write(rcrtc, HDSR, mode->htotal -
> +						mode->hsync_start - 19 - 25);
> +		rcar_du_crtc_write(rcrtc, HDER, mode->htotal -
> +						mode->hsync_start +
> +						mode->hdisplay - 19 - 25);
> +	} else {
> +		rcar_du_crtc_write(rcrtc, HDSR, mode->htotal -
> +						mode->hsync_start - 19);
> +		rcar_du_crtc_write(rcrtc, HDER, mode->htotal -
> +						mode->hsync_start +
> +						mode->hdisplay - 19);
> +	}
>  	rcar_du_crtc_write(rcrtc, HSWR, mode->hsync_end -
>  					mode->hsync_start - 1);
>  	rcar_du_crtc_write(rcrtc, HCR,  mode->htotal - 1);
> @@ -530,6 +543,9 @@ static void rcar_du_crtc_start(struct rcar_du_crtc *rcrtc)
>  			     DSYSR_TVM_MASTER);
>  
>  	rcar_du_group_start_stop(rcrtc->group, true);
> +
> +	if (rcar_du_has(rcrtc->group->dev, RCAR_DU_FEATURE_CMM))
> +		rcar_du_cmm_start_stop(rcrtc, true);
>  }
>  
>  static void rcar_du_crtc_disable_planes(struct rcar_du_crtc *rcrtc)
> @@ -565,6 +581,9 @@ static void rcar_du_crtc_stop(struct rcar_du_crtc *rcrtc)
>  {
>  	struct drm_crtc *crtc = &rcrtc->crtc;
>  
> +	if (rcar_du_has(rcrtc->group->dev, RCAR_DU_FEATURE_CMM))
> +		rcar_du_cmm_start_stop(rcrtc, false);
> +
>  	/*
>  	 * Disable all planes and wait for the change to take effect. This is
>  	 * required as the plane enable registers are updated on vblank, and no
> @@ -899,6 +918,9 @@ static irqreturn_t rcar_du_crtc_irq(int irq, void *arg)
>  			rcar_du_crtc_finish_page_flip(rcrtc);
>  		}
>  
> +		if (rcar_du_has(rcrtc->group->dev, RCAR_DU_FEATURE_CMM))
> +			rcar_du_cmm_kick(rcrtc);

The fact that the SoC has a CMM doesn't mean it should be used
unconditionally. When the CMM features are not needed by userspace the
CMM should be disabled.

> +
>  		ret = IRQ_HANDLED;
>  	}
>  
> @@ -999,5 +1021,7 @@ int rcar_du_crtc_create(struct rcar_du_group *rgrp, unsigned int swindex,
>  		return ret;
>  	}
>  
> +	rcar_du_cmm_init(rcrtc);
> +
>  	return 0;
>  }
> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
> index 7680cb2..74e0a22 100644
> --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
> @@ -67,6 +67,10 @@ struct rcar_du_crtc {
>  	struct rcar_du_group *group;
>  	struct rcar_du_vsp *vsp;
>  	unsigned int vsp_pipe;
> +	int lvds_ch;

I think you need to figure out all the places where you pulled in BSP
code completely unrelated to the series :-)

> +
> +	void *cmm_handle;
> +
>  };
>  
>  #define to_rcar_crtc(c)	container_of(c, struct rcar_du_crtc, crtc)
> @@ -104,4 +108,16 @@ void rcar_du_crtc_route_output(struct drm_crtc *crtc,
>  			       enum rcar_du_output output);
>  void rcar_du_crtc_finish_page_flip(struct rcar_du_crtc *rcrtc);
>  
> +/* DU-CMM functions */
> +int rcar_du_cmm_init(struct rcar_du_crtc *rcrtc);
> +int rcar_du_cmm_driver_open(struct drm_device *dev, struct drm_file *file_priv);
> +void rcar_du_cmm_postclose(struct drm_device *dev, struct drm_file *file_priv);
> +int rcar_du_cmm_start_stop(struct rcar_du_crtc *rcrtc, bool on);
> +void rcar_du_cmm_kick(struct rcar_du_crtc *rcrtc);
> +
> +#ifdef CONFIG_PM_SLEEP
> +int rcar_du_cmm_pm_suspend(struct rcar_du_crtc *rcrtc);
> +int rcar_du_cmm_pm_resume(struct rcar_du_crtc *rcrtc);
> +#endif /* CONFIG_PM_SLEEP */
> +
>  #endif /* __RCAR_DU_CRTC_H__ */
> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
> index 02aee6c..838b7c9 100644
> --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
> @@ -26,8 +26,8 @@
>  #include <drm/drm_crtc_helper.h>
>  #include <drm/drm_fb_cma_helper.h>
>  #include <drm/drm_gem_cma_helper.h>
> -
>  #include "rcar_du_drv.h"
> +#include "rcar_du_encoder.h"
>  #include "rcar_du_kms.h"
>  #include "rcar_du_of.h"
>  #include "rcar_du_regs.h"
> @@ -128,7 +128,9 @@ static const struct rcar_du_device_info rcar_du_r8a7790_info = {
>  static const struct rcar_du_device_info rcar_du_r8a7791_info = {
>  	.gen = 2,
>  	.features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
> -		  | RCAR_DU_FEATURE_EXT_CTRL_REGS,
> +		  | RCAR_DU_FEATURE_EXT_CTRL_REGS
> +		  | RCAR_DU_FEATURE_CMM,
> +	.num_crtcs = 2,
>  	.channels_mask = BIT(1) | BIT(0),
>  	.routes = {
>  		/*
> @@ -190,7 +192,10 @@ static const struct rcar_du_device_info rcar_du_r8a7795_info = {
>  	.gen = 3,
>  	.features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
>  		  | RCAR_DU_FEATURE_EXT_CTRL_REGS
> -		  | RCAR_DU_FEATURE_VSP1_SOURCE,
> +		  | RCAR_DU_FEATURE_VSP1_SOURCE
> +		  | RCAR_DU_FEATURE_CMM | RCAR_DU_FEATURE_CMM_LUT_DBUF
> +		  | RCAR_DU_FEATURE_CMM_CLU_DBUF,
> +	.num_crtcs = 4,
>  	.channels_mask = BIT(3) | BIT(2) | BIT(1) | BIT(0),
>  	.routes = {
>  		/*
> @@ -222,7 +227,10 @@ static const struct rcar_du_device_info rcar_du_r8a7796_info = {
>  	.gen = 3,
>  	.features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
>  		  | RCAR_DU_FEATURE_EXT_CTRL_REGS
> -		  | RCAR_DU_FEATURE_VSP1_SOURCE,
> +		  | RCAR_DU_FEATURE_VSP1_SOURCE
> +		  | RCAR_DU_FEATURE_CMM | RCAR_DU_FEATURE_CMM_LUT_DBUF
> +		  | RCAR_DU_FEATURE_CMM_CLU_DBUF,
> +	.num_crtcs = 3,
>  	.channels_mask = BIT(2) | BIT(1) | BIT(0),
>  	.routes = {
>  		/*
> @@ -250,7 +258,11 @@ static const struct rcar_du_device_info rcar_du_r8a77965_info = {
>  	.gen = 3,
>  	.features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
>  		  | RCAR_DU_FEATURE_EXT_CTRL_REGS
> -		  | RCAR_DU_FEATURE_VSP1_SOURCE,
> +		  | RCAR_DU_FEATURE_VSP1_SOURCE
> +		  | RCAR_DU_FEATURE_R8A77965_REGS
> +		  | RCAR_DU_FEATURE_CMM | RCAR_DU_FEATURE_CMM_LUT_DBUF
> +		  | RCAR_DU_FEATURE_CMM_CLU_DBUF,
> +	.num_crtcs = 3,
>  	.channels_mask = BIT(3) | BIT(1) | BIT(0),
>  	.routes = {
>  		/*
> @@ -328,6 +340,8 @@ DEFINE_DRM_GEM_CMA_FOPS(rcar_du_fops);
>  static struct drm_driver rcar_du_driver = {
>  	.driver_features	= DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME
>  				| DRIVER_ATOMIC,
> +	.open			= rcar_du_cmm_driver_open,
> +	.postclose		= rcar_du_cmm_postclose,
>  	.lastclose		= rcar_du_lastclose,
>  	.gem_free_object_unlocked = drm_gem_cma_free_object,
>  	.gem_vm_ops		= &drm_gem_cma_vm_ops,
> @@ -358,6 +372,12 @@ static int rcar_du_pm_suspend(struct device *dev)
>  {
>  	struct rcar_du_device *rcdu = dev_get_drvdata(dev);
>  	struct drm_atomic_state *state;
> +	int i;
> +
> +	if (rcar_du_has(rcdu, RCAR_DU_FEATURE_CMM)) {
> +		for (i = 0; i < rcdu->num_crtcs; ++i)
> +			rcar_du_cmm_pm_suspend(&rcdu->crtcs[i]);
> +	}
>  
>  	drm_kms_helper_poll_disable(rcdu->ddev);
>  	drm_fbdev_cma_set_suspend_unlocked(rcdu->fbdev, true);
> @@ -377,7 +397,20 @@ static int rcar_du_pm_suspend(struct device *dev)
>  static int rcar_du_pm_resume(struct device *dev)
>  {
>  	struct rcar_du_device *rcdu = dev_get_drvdata(dev);
> +#if IS_ENABLED(CONFIG_DRM_RCAR_DW_HDMI)
> +	struct drm_encoder *encoder;
> +	int i;
> +
> +	if (rcar_du_has(rcdu, RCAR_DU_FEATURE_CMM)) {
> +		for (i = 0; (i < rcdu->num_crtcs); ++i)
> +			rcar_du_cmm_pm_resume(&rcdu->crtcs[i]);
> +	}
>  
> +	list_for_each_entry(encoder, &rcdu->ddev->mode_config.encoder_list,
> +			    head) {
> +		to_rcar_encoder(encoder);
> +	}
> +#endif
>  	drm_atomic_helper_resume(rcdu->ddev, rcdu->suspend_state);
>  	drm_fbdev_cma_set_suspend_unlocked(rcdu->fbdev, false);
>  	drm_kms_helper_poll_enable(rcdu->ddev);
> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.h b/drivers/gpu/drm/rcar-du/rcar_du_drv.h
> index b3a25e8..f2afe36 100644
> --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.h
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.h
> @@ -30,8 +30,19 @@ struct rcar_du_device;
>  #define RCAR_DU_FEATURE_CRTC_IRQ_CLOCK	(1 << 0)	/* Per-CRTC IRQ and clock */
>  #define RCAR_DU_FEATURE_EXT_CTRL_REGS	(1 << 1)	/* Has extended control registers */
>  #define RCAR_DU_FEATURE_VSP1_SOURCE	(1 << 2)	/* Has inputs from VSP1 */
> -
> -#define RCAR_DU_QUIRK_ALIGN_128B	(1 << 0)	/* Align pitches to 128 bytes */
> +/* Use R8A77965 registers */
> +#define RCAR_DU_FEATURE_R8A77965_REGS	BIT(3)
> +
> +/* Has DEF7R register & CMM */
> +#define RCAR_DU_FEATURE_CMM		BIT(10)
> +/* Has CMM LUT Double buffer */
> +#define RCAR_DU_FEATURE_CMM_LUT_DBUF	BIT(11)
> +/* Has CMM CLU Double buffer */
> +#define RCAR_DU_FEATURE_CMM_CLU_DBUF	BIT(12)
> +/* Align pitches to 128 bytes */
> +#define RCAR_DU_QUIRK_ALIGN_128B	BIT(0)
> +/* LVDS lanes 1 and 3 inverted */
> +#define RCAR_DU_QUIRK_LVDS_LANES	BIT(1)

The last define is not used here, and clearly unrelated to this patch
series. I think the series needs major cleanup.

>  
>  /*
>   * struct rcar_du_output_routing - Output routing specification
> @@ -61,6 +72,7 @@ struct rcar_du_device_info {
>  	unsigned int features;
>  	unsigned int quirks;
>  	unsigned int channels_mask;
> +	unsigned int num_crtcs;

There's already a way in the driver to count CRTCs, no need to duplicate
this in the rcar_du_device_info structure.

>  	struct rcar_du_output_routing routes[RCAR_DU_OUTPUT_MAX];
>  	unsigned int num_lvds;
>  	unsigned int dpll_ch;
> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_group.c b/drivers/gpu/drm/rcar-du/rcar_du_group.c
> index d539cb2..83a2836 100644
> --- a/drivers/gpu/drm/rcar-du/rcar_du_group.c
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_group.c
> @@ -130,6 +130,11 @@ static void rcar_du_group_setup(struct rcar_du_group *rgrp)
>  	if (rcdu->info->gen >= 3)
>  		rcar_du_group_write(rgrp, DEFR10, DEFR10_CODE | DEFR10_DEFE10);
>  
> +	if (rcar_du_has(rgrp->dev, RCAR_DU_FEATURE_CMM)) {
> +		rcar_du_group_write(rgrp, DEF7R, DEF7R_CODE |
> +				    DEF7R_CMME1 | DEF7R_CMME0);
> +	}
> +
>  	/*
>  	 * Use DS1PR and DS2PR to configure planes priorities and connects the
>  	 * superposition 0 to DU0 pins. DU1 pins will be configured dynamically.
> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_regs.h b/drivers/gpu/drm/rcar-du/rcar_du_regs.h
> index 9dfd220..b20e783 100644
> --- a/drivers/gpu/drm/rcar-du/rcar_du_regs.h
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_regs.h
> @@ -200,6 +200,11 @@
>  #define DEFR6_MLOS1		(1 << 2)
>  #define DEFR6_DEFAULT		(DEFR6_CODE | DEFR6_TCNE1)
>  
> +#define DEF7R			0x000ec
> +#define DEF7R_CODE		(0x7779 << 16)
> +#define DEF7R_CMME1		BIT(6)
> +#define DEF7R_CMME0		BIT(4)
> +
>  /* -----------------------------------------------------------------------------
>   * R8A7790-only Control Registers
>   */
> @@ -552,4 +557,91 @@
>  #define GCBCR			0x11098
>  #define BCBCR			0x1109c
>  
> +/* -----------------------------------------------------------------------------
> + * DU Color Management Module Registers
> + */
> +
> +#define CMM_LUT_CTRL			0x0000
> +#define CMM_LUT_CTRL_EN			BIT(0)
> +
> +#define CMM_CLU_CTRL			0x0100
> +#define CMM_CLU_CTRL_EN			BIT(0)
> +#define CMM_CLU_CTRL_MVS		BIT(24)
> +#define CMM_CLU_CTRL_AAI		BIT(28)
> +
> +#define CMM_CTL0			0x0180
> +#define CM2_CTL0			CMM_CTL0

Why do you need an alias here (and for CM2_CTL1 below) ?

> +#define CMM_CTL0_CLUDB			BIT(24)
> +#define CMM_CTL0_HISTS			BIT(20)
> +#define CMM_CTL0_TM1_MASK		(3 << 16)
> +#define CMM_CTL0_TM1_BT601_YC240	(0 << 16)
> +#define CMM_CTL0_TM1_BT601_YC255	BIT(16)
> +#define CMM_CTL0_TM1_BT709_RG255	(2 << 16)
> +#define CMM_CTL0_TM1_BT709_RG235	(3 << 16)
> +#define CMM_CTL0_TM0_MASK		(3 << 12)
> +#define CMM_CTL0_TM0_BT601_YC240	(0 << 12)
> +#define CMM_CTL0_TM0_BT601_YC255	BIT(12)
> +#define CMM_CTL0_TM0_BT709_RG255	(2 << 12)
> +#define CMM_CTL0_TM0_BT709_RG235	(3 << 12)
> +#define CMM_CTL0_TM_BT601_YC240		(CMM_CTL0_TM1_BT601_YC240 |\
> +					 CMM_CTL0_TM0_BT601_YC240)
> +#define CMM_CTL0_TM_BT601_YC255		(CMM_CTL0_TM1_BT601_YC255 |\
> +					 CMM_CTL0_TM0_BT601_YC255)
> +#define CMM_CTL0_TM_BT709_RG255		(CMM_CTL0_TM1_BT709_RG255 |\
> +					 CMM_CTL0_TM0_BT709_RG255)
> +#define CMM_CTL0_TM_BT709_RG235		(CMM_CTL0_TM1_BT709_RG235 |\
> +					 CMM_CTL0_TM0_BT709_RG235)
> +#define CMM_CTL0_YC			BIT(8)
> +#define CMM_CTL0_VPOL			BIT(4)
> +#define CMM_CTL0_DBUF			BIT(0)
> +
> +#define CMM_CTL1			0x0184
> +#define CM2_CTL1			CMM_CTL1
> +#define CMM_CTL1_BFS			BIT(0)
> +
> +#define CMM_CTL2			0x0188
> +#define CMM_HGO_OFFSET			0x0200
> +#define CMM_HGO_SIZE			0x0204
> +#define CMM_HGO_MODE			0x0208
> +#define CMM_HGO_MODE_MASK		(0xFF)

No need for parentheses. Hex constants in the DU code base use
lowercase.

> +#define CMM_HGO_MODE_MAXRGB		BIT(7)
> +#define CMM_HGO_MODE_OFSB_R		BIT(6)
> +#define CMM_HGO_MODE_OFSB_G		BIT(5)
> +#define CMM_HGO_MODE_OFSB_B		BIT(4)
> +#define CMM_HGO_MODE_HRATIO_NO_SKIPP		(0 << 2)
> +#define CMM_HGO_MODE_HRATIO_HALF_SKIPP		BIT(2)
> +#define CMM_HGO_MODE_HRATIO_QUARTER_SKIPP	(2 << 2)
> +#define CMM_HGO_MODE_VRATIO_NO_SKIPP		(0 << 0)
> +#define CMM_HGO_MODE_VRATIO_HALF_SKIPP		BIT(0)
> +#define CMM_HGO_MODE_VRATIO_QUARTER_SKIPP	(2 << 0)
> +#define CMM_HGO_LB_TH			0x020C
> +#define CMM_HGO_LB0_H			0x0210
> +#define CMM_HGO_LB0_V			0x0214
> +#define CMM_HGO_LB1_H			0x0218
> +#define CMM_HGO_LB1_V			0x021C
> +#define CMM_HGO_LB2_H			0x0220
> +#define CMM_HGO_LB2_V			0x0224
> +#define CMM_HGO_LB3_H			0x0228
> +#define CMM_HGO_LB3_V			0x022C
> +#define CMM_HGO_R_HISTO(n)		(0x0230 + ((n) * 4))
> +#define CMM_HGO_R_MAXMIN		0x0330
> +#define CMM_HGO_R_SUM			0x0334
> +#define CMM_HGO_R_LB_DET		0x0338
> +#define CMM_HGO_G_HISTO(n)		(0x0340 + ((n) * 4))
> +#define CMM_HGO_G_MAXMIN		0x0440
> +#define CMM_HGO_G_SUM			0x0444
> +#define CMM_HGO_G_LB_DET		0x0448
> +#define CMM_HGO_B_HISTO(n)		(0x0450 + ((n) * 4))
> +#define CMM_HGO_B_MAXMIN		0x0550
> +#define CMM_HGO_B_SUM			0x0554
> +#define CMM_HGO_B_LB_DET		0x0558
> +#define CMM_HGO_REGRST			0x05FC
> +#define CMM_HGO_REGRST_RCLEA		BIT(0)
> +#define CMM_LUT_TBLA(n)			(0x0600 + ((n) * 4))
> +#define CMM_CLU_ADDR			0x0A00
> +#define CMM_CLU_DATA			0x0A04
> +#define CMM_LUT_TBLB(n)			(0x0B00 + ((n) * 4))
> +#define CMM_CLU_ADDR2			0x0F00
> +#define CMM_CLU_DATA2			0x0F04

The CMM is a separate IP core, I think it would be best supported in a
separate platform_driver like the LVDS encoder, with the registers split
to a separate header.

> +
>  #endif /* __RCAR_DU_REGS_H__ */
> diff --git a/include/drm/drm_ioctl.h b/include/drm/drm_ioctl.h
> index fafb6f5..add4280 100644
> --- a/include/drm/drm_ioctl.h
> +++ b/include/drm/drm_ioctl.h
> @@ -109,6 +109,13 @@ enum drm_ioctl_flags {
>  	 */
>  	DRM_ROOT_ONLY		= BIT(2),
>  	/**
> +	 * @DRM_CONTROL_ALLOW:
> +	 *
> +	 * Deprecated, do not use. Control nodes are in the process of getting
> +	 * removed.
> +	 */

Do not use means do not use :-)

As commented on the cover letter, changes to the DRM core and DRM API
are fine, but need to be split to patches of their own, with
corresponding documentation and a clear explanation of what they do and
why they're needed.

> +	DRM_CONTROL_ALLOW	= BIT(3),
> +	/**
>  	 * @DRM_UNLOCKED:
>  	 *
>  	 * Whether &drm_ioctl_desc.func should be called with the DRM BKL held

-- 
Regards,

Laurent Pinchart
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH 2/8] drm: Add DU CMM support boot and clk changes
  2019-04-03 13:14   ` VenkataRajesh.Kalakodima
  (?)
@ 2019-04-04 10:12   ` Laurent Pinchart
  -1 siblings, 0 replies; 36+ messages in thread
From: Laurent Pinchart @ 2019-04-04 10:12 UTC (permalink / raw)
  To: VenkataRajesh.Kalakodima
  Cc: linux-renesas-soc, devicetree, linux-kernel, linux-clk,
	dri-devel, Tsutomu Muroya, Steve Longerbeam, Koji Matsuoka

Hello Kalakodima,

Thank you for the patch.

On Wed, Apr 03, 2019 at 06:44:38PM +0530, VenkataRajesh.Kalakodima@in.bosch.com wrote:
> From: kalakodima venkata rajesh <venkatarajesh.kalakodima@in.bosch.com>
> 
> This is the out-of-tree patch for DU CMM driver support from
> Yocto release v3.4.0.
> 
> Link: https://github.com/renesas-rcar/du_cmm/commit/2d8ea2b667ad4616aa639c54ecc11f7c4b58959d.patch
> 
> Following is from the patch description:
> 
>     du_cmm: Release for Yocto v3.4.0
> 
>     This patch made the following correspondence.
> 
>       - Corresponds to kernel v 4.14.
>       - Double buffer only is supported.
>       - Fix CLU / LUT update timing.
>       - Add CMM Channel occupation mode.
>       - Fix Close process.
> 
> Signed-off-by: Koji Matsuoka <koji.matsuoka.xm@renesas.com>
> Signed-off-by: Tsutomu Muroya <muroya@ksk.co.jp>
> Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
> 
>       - Resolved checkpatch errors
>       - Resolved merge conflicts according to latest version
>       - In patch included boot and clock files from base patch

As for patch 1/8, and all other patches in this series, the commit
message needs an overhaul.

> Signed-off-by: kalakodima venkata rajesh <venkatarajesh.kalakodima@in.bosch.com>
> ---
>  .../boot/dts/renesas/r8a7795-es1-salvator-x.dts    |   5 +
>  arch/arm64/boot/dts/renesas/r8a7795-salvator-x.dts |   5 +
>  .../arm64/boot/dts/renesas/r8a7795-salvator-xs.dts |   5 +
>  arch/arm64/boot/dts/renesas/r8a7795.dtsi           |  29 +++++-
>  arch/arm64/boot/dts/renesas/r8a7796-salvator-x.dts |   6 +-
>  .../arm64/boot/dts/renesas/r8a7796-salvator-xs.dts |   4 +
>  arch/arm64/boot/dts/renesas/r8a7796.dtsi           |  25 ++++-
>  .../arm64/boot/dts/renesas/r8a77965-salvator-x.dts |   7 +-
>  .../boot/dts/renesas/r8a77965-salvator-xs.dts      |   7 +-
>  arch/arm64/boot/dts/renesas/r8a77965.dtsi          |  27 +++++-
>  drivers/clk/renesas/r8a7795-cpg-mssr.c             |   4 +
>  drivers/clk/renesas/r8a7796-cpg-mssr.c             |   3 +
>  drivers/clk/renesas/r8a77965-cpg-mssr.c            | 106 ++++++++++++++++++++-
>  13 files changed, 217 insertions(+), 16 deletions(-)
> 
> diff --git a/arch/arm64/boot/dts/renesas/r8a7795-es1-salvator-x.dts b/arch/arm64/boot/dts/renesas/r8a7795-es1-salvator-x.dts
> index 6b5fa91..45c1f8a 100644
> --- a/arch/arm64/boot/dts/renesas/r8a7795-es1-salvator-x.dts
> +++ b/arch/arm64/boot/dts/renesas/r8a7795-es1-salvator-x.dts
> @@ -41,11 +41,16 @@
>  		 <&cpg CPG_MOD 722>,
>  		 <&cpg CPG_MOD 721>,
>  		 <&cpg CPG_MOD 727>,
> +		 <&cpg CPG_MOD 711>,
> +		 <&cpg CPG_MOD 710>,
> +		 <&cpg CPG_MOD 709>,
> +		 <&cpg CPG_MOD 708>,
>  		 <&versaclock5 1>,
>  		 <&x21_clk>,
>  		 <&x22_clk>,
>  		 <&versaclock5 2>;
>  	clock-names = "du.0", "du.1", "du.2", "du.3", "lvds.0",
> +		      "cmm.0", "cmm.1", "cmm.2", "cmm.3",
>  		      "dclkin.0", "dclkin.1", "dclkin.2", "dclkin.3";

I think the CMM should be modeled as a separate DT node, as it's a
separate IP core. In any case DT bindings need to be updated.

>  };
>  
> diff --git a/arch/arm64/boot/dts/renesas/r8a7795-salvator-x.dts b/arch/arm64/boot/dts/renesas/r8a7795-salvator-x.dts
> index 446822f..67b64e7 100644
> --- a/arch/arm64/boot/dts/renesas/r8a7795-salvator-x.dts
> +++ b/arch/arm64/boot/dts/renesas/r8a7795-salvator-x.dts
> @@ -41,11 +41,16 @@
>  		 <&cpg CPG_MOD 722>,
>  		 <&cpg CPG_MOD 721>,
>  		 <&cpg CPG_MOD 727>,
> +		 <&cpg CPG_MOD 711>,
> +		 <&cpg CPG_MOD 710>,
> +		 <&cpg CPG_MOD 709>,
> +		 <&cpg CPG_MOD 708>,
>  		 <&versaclock5 1>,
>  		 <&x21_clk>,
>  		 <&x22_clk>,
>  		 <&versaclock5 2>;
>  	clock-names = "du.0", "du.1", "du.2", "du.3", "lvds.0",
> +		      "cmm.0", "cmm.1", "cmm.2", "cmm.3",
>  		      "dclkin.0", "dclkin.1", "dclkin.2", "dclkin.3";
>  };
>  
> diff --git a/arch/arm64/boot/dts/renesas/r8a7795-salvator-xs.dts b/arch/arm64/boot/dts/renesas/r8a7795-salvator-xs.dts
> index 8ded64d0..adcacea 100644
> --- a/arch/arm64/boot/dts/renesas/r8a7795-salvator-xs.dts
> +++ b/arch/arm64/boot/dts/renesas/r8a7795-salvator-xs.dts
> @@ -41,11 +41,16 @@
>  		 <&cpg CPG_MOD 722>,
>  		 <&cpg CPG_MOD 721>,
>  		 <&cpg CPG_MOD 727>,
> +		 <&cpg CPG_MOD 711>,
> +		 <&cpg CPG_MOD 710>,
> +		 <&cpg CPG_MOD 709>,
> +		 <&cpg CPG_MOD 708>,
>  		 <&versaclock6 1>,
>  		 <&x21_clk>,
>  		 <&x22_clk>,
>  		 <&versaclock6 2>;
>  	clock-names = "du.0", "du.1", "du.2", "du.3", "lvds.0",
> +		      "cmm.0", "cmm.1", "cmm.2", "cmm.3",
>  		      "dclkin.0", "dclkin.1", "dclkin.2", "dclkin.3";
>  };
>  
> diff --git a/arch/arm64/boot/dts/renesas/r8a7795.dtsi b/arch/arm64/boot/dts/renesas/r8a7795.dtsi
> index fb9d08a..aa5fc3c 100644
> --- a/arch/arm64/boot/dts/renesas/r8a7795.dtsi
> +++ b/arch/arm64/boot/dts/renesas/r8a7795.dtsi
> @@ -2783,8 +2783,13 @@
>  		du: display@feb00000 {
>  			compatible = "renesas,du-r8a7795";
>  			reg = <0 0xfeb00000 0 0x80000>,
> -			      <0 0xfeb90000 0 0x14>;
> -			reg-names = "du", "lvds.0";
> +			      <0 0xfeb90000 0 0x14>,
> +			      <0 0xfea40000 0 0x00001000>,
> +			      <0 0xfea50000 0 0x00001000>,
> +			      <0 0xfea60000 0 0x00001000>,
> +			      <0 0xfea70000 0 0x00001000>;
> +			reg-names = "du", "lvds.0",
> +				    "cmm.0", "cmm.1", "cmm.2", "cmm.3";
>  			interrupts = <GIC_SPI 256 IRQ_TYPE_LEVEL_HIGH>,
>  				     <GIC_SPI 268 IRQ_TYPE_LEVEL_HIGH>,
>  				     <GIC_SPI 269 IRQ_TYPE_LEVEL_HIGH>,
> @@ -2793,8 +2798,24 @@
>  				 <&cpg CPG_MOD 723>,
>  				 <&cpg CPG_MOD 722>,
>  				 <&cpg CPG_MOD 721>,
> -				 <&cpg CPG_MOD 727>;
> -			clock-names = "du.0", "du.1", "du.2", "du.3", "lvds.0";
> +				 <&cpg CPG_MOD 727>,
> +				 <&cpg CPG_MOD 711>,
> +				 <&cpg CPG_MOD 710>,
> +				 <&cpg CPG_MOD 709>,
> +				 <&cpg CPG_MOD 708>;
> +			clock-names = "du.0", "du.1", "du.2", "du.3", "lvds.0",
> +				      "cmm.0", "cmm.1", "cmm.2", "cmm.3";
> +			resets = <&cpg 724>,
> +				 <&cpg 724>,
> +				 <&cpg 722>,
> +				 <&cpg 722>,
> +				 <&cpg 727>,
> +				 <&cpg 711>,
> +				 <&cpg 710>,
> +				 <&cpg 709>,
> +				 <&cpg 708>;
> +			reset-names = "du.0", "du.1", "du.2", "du.3", "lvds.0",
> +				      "cmm.0", "cmm.1", "cmm.2", "cmm.3";
>  			vsps = <&vspd0 0 &vspd1 0 &vspd2 0 &vspd0 1>;
>  			status = "disabled";
>  
> diff --git a/arch/arm64/boot/dts/renesas/r8a7796-salvator-x.dts b/arch/arm64/boot/dts/renesas/r8a7796-salvator-x.dts
> index 052d72a..abe24e5 100644
> --- a/arch/arm64/boot/dts/renesas/r8a7796-salvator-x.dts
> +++ b/arch/arm64/boot/dts/renesas/r8a7796-salvator-x.dts
> @@ -30,18 +30,22 @@
>  		 <&cpg CPG_MOD 723>,
>  		 <&cpg CPG_MOD 722>,
>  		 <&cpg CPG_MOD 727>,
> +		 <&cpg CPG_MOD 711>,
> +		 <&cpg CPG_MOD 710>,
> +		 <&cpg CPG_MOD 709>,
>  		 <&versaclock5 1>,
>  		 <&x21_clk>,
>  		 <&versaclock5 2>;
>  	clock-names = "du.0", "du.1", "du.2", "lvds.0",
> +		      "cmm.0", "cmm.1", "cmm.2",
>  		      "dclkin.0", "dclkin.1", "dclkin.2";
> +
>  };
>  
>  &sound_card {
>  	dais = <&rsnd_port0	/* ak4613 */
>  		&rsnd_port1>;	/* HDMI0  */
>  };
> -
>  &hdmi0 {
>  	status = "okay";
>  
> diff --git a/arch/arm64/boot/dts/renesas/r8a7796-salvator-xs.dts b/arch/arm64/boot/dts/renesas/r8a7796-salvator-xs.dts
> index 8860be6..6c3af11 100644
> --- a/arch/arm64/boot/dts/renesas/r8a7796-salvator-xs.dts
> +++ b/arch/arm64/boot/dts/renesas/r8a7796-salvator-xs.dts
> @@ -30,10 +30,14 @@
>  		 <&cpg CPG_MOD 723>,
>  		 <&cpg CPG_MOD 722>,
>  		 <&cpg CPG_MOD 727>,
> +		 <&cpg CPG_MOD 711>,
> +		 <&cpg CPG_MOD 710>,
> +		 <&cpg CPG_MOD 709>,
>  		 <&versaclock6 1>,
>  		 <&x21_clk>,
>  		 <&versaclock6 2>;
>  	clock-names = "du.0", "du.1", "du.2", "lvds.0",
> +		      "cmm.0", "cmm.1", "cmm.2",
>  		      "dclkin.0", "dclkin.1", "dclkin.2";
>  };
>  
> diff --git a/arch/arm64/boot/dts/renesas/r8a7796.dtsi b/arch/arm64/boot/dts/renesas/r8a7796.dtsi
> index cbd35c0..729b2b6 100644
> --- a/arch/arm64/boot/dts/renesas/r8a7796.dtsi
> +++ b/arch/arm64/boot/dts/renesas/r8a7796.dtsi
> @@ -2438,16 +2438,33 @@
>  		du: display@feb00000 {
>  			compatible = "renesas,du-r8a7796";
>  			reg = <0 0xfeb00000 0 0x70000>,
> -			      <0 0xfeb90000 0 0x14>;
> -			reg-names = "du", "lvds.0";
> +			      <0 0xfeb90000 0 0x14>,
> +			      <0 0xfea40000 0 0x00001000>,
> +			      <0 0xfea50000 0 0x00001000>,
> +			      <0 0xfea60000 0 0x00001000>;
> +			reg-names = "du", "lvds.0",
> +				    "cmm.0", "cmm.1", "cmm.2";
>  			interrupts = <GIC_SPI 256 IRQ_TYPE_LEVEL_HIGH>,
>  				     <GIC_SPI 268 IRQ_TYPE_LEVEL_HIGH>,
>  				     <GIC_SPI 269 IRQ_TYPE_LEVEL_HIGH>;
>  			clocks = <&cpg CPG_MOD 724>,
>  				 <&cpg CPG_MOD 723>,
>  				 <&cpg CPG_MOD 722>,
> -				 <&cpg CPG_MOD 727>;
> -			clock-names = "du.0", "du.1", "du.2", "lvds.0";
> +				 <&cpg CPG_MOD 727>,
> +				 <&cpg CPG_MOD 711>,
> +				 <&cpg CPG_MOD 710>,
> +				 <&cpg CPG_MOD 709>;
> +			clock-names = "du.0", "du.1", "du.2", "lvds.0",
> +				      "cmm.0", "cmm.1", "cmm.2";
> +			resets = <&cpg 724>,
> +				 <&cpg 724>,
> +				 <&cpg 722>,
> +				 <&cpg 727>,
> +				 <&cpg 711>,
> +				 <&cpg 710>,
> +				 <&cpg 709>;
> +			reset-names = "du.0", "du.1", "du.2", "lvds.0",
> +				      "cmm.0", "cmm.1", "cmm.2";
>  			status = "disabled";
>  
>  			vsps = <&vspd0 &vspd1 &vspd2>;
> diff --git a/arch/arm64/boot/dts/renesas/r8a77965-salvator-x.dts b/arch/arm64/boot/dts/renesas/r8a77965-salvator-x.dts
> index 340a3c7..20992e2 100644
> --- a/arch/arm64/boot/dts/renesas/r8a77965-salvator-x.dts
> +++ b/arch/arm64/boot/dts/renesas/r8a77965-salvator-x.dts
> @@ -24,10 +24,15 @@
>  	clocks = <&cpg CPG_MOD 724>,
>  		 <&cpg CPG_MOD 723>,
>  		 <&cpg CPG_MOD 721>,
> +		 <&cpg CPG_MOD 727>,
> +		 <&cpg CPG_MOD 711>,
> +		 <&cpg CPG_MOD 710>,
> +		 <&cpg CPG_MOD 708>,
>  		 <&versaclock5 1>,
>  		 <&x21_clk>,
>  		 <&versaclock5 2>;
> -	clock-names = "du.0", "du.1", "du.3",
> +	clock-names = "du.0", "du.1", "du.3", "lvds.0",
> +		      "cmm.0", "cmm.1", "cmm.3",
>  		      "dclkin.0", "dclkin.1", "dclkin.3";
>  };
>  
> diff --git a/arch/arm64/boot/dts/renesas/r8a77965-salvator-xs.dts b/arch/arm64/boot/dts/renesas/r8a77965-salvator-xs.dts
> index 9de4e3d..eb02075 100644
> --- a/arch/arm64/boot/dts/renesas/r8a77965-salvator-xs.dts
> +++ b/arch/arm64/boot/dts/renesas/r8a77965-salvator-xs.dts
> @@ -24,10 +24,15 @@
>  	clocks = <&cpg CPG_MOD 724>,
>  		 <&cpg CPG_MOD 723>,
>  		 <&cpg CPG_MOD 721>,
> +		 <&cpg CPG_MOD 727>,
> +		 <&cpg CPG_MOD 711>,
> +		 <&cpg CPG_MOD 710>,
> +		 <&cpg CPG_MOD 708>,
>  		 <&versaclock6 1>,
>  		 <&x21_clk>,
>  		 <&versaclock6 2>;
> -	clock-names = "du.0", "du.1", "du.3",
> +	clock-names = "du.0", "du.1", "du.3", "lvds.0",
> +		      "cmm.0", "cmm.1", "cmm.3",
>  		      "dclkin.0", "dclkin.1", "dclkin.3";
>  };
>  
> diff --git a/arch/arm64/boot/dts/renesas/r8a77965.dtsi b/arch/arm64/boot/dts/renesas/r8a77965.dtsi
> index 0cd4446..37382b7 100644
> --- a/arch/arm64/boot/dts/renesas/r8a77965.dtsi
> +++ b/arch/arm64/boot/dts/renesas/r8a77965.dtsi
> @@ -1801,15 +1801,34 @@
>  
>  		du: display@feb00000 {
>  			compatible = "renesas,du-r8a77965";
> -			reg = <0 0xfeb00000 0 0x80000>;
> -			reg-names = "du";
> +			reg = <0 0xfeb00000 0 0x80000>,
> +			      <0 0xfeb90000 0 0x14>,
> +			      <0 0xfea40000 0 0x00001000>,
> +			      <0 0xfea50000 0 0x00001000>,
> +			      <0 0xfea70000 0 0x00001000>;
> +			reg-names = "du", "lvds.0",
> +				    "cmm.0", "cmm.1", "cmm.3";
>  			interrupts = <GIC_SPI 256 IRQ_TYPE_LEVEL_HIGH>,
>  				     <GIC_SPI 268 IRQ_TYPE_LEVEL_HIGH>,
>  				     <GIC_SPI 270 IRQ_TYPE_LEVEL_HIGH>;
>  			clocks = <&cpg CPG_MOD 724>,
>  				 <&cpg CPG_MOD 723>,
> -				 <&cpg CPG_MOD 721>;
> -			clock-names = "du.0", "du.1", "du.3";
> +				 <&cpg CPG_MOD 721>,
> +				 <&cpg CPG_MOD 727>,
> +				 <&cpg CPG_MOD 711>,
> +				 <&cpg CPG_MOD 710>,
> +				 <&cpg CPG_MOD 708>;
> +			clock-names = "du.0", "du.1", "du.3", "lvds.0",
> +				      "cmm.0", "cmm.1", "cmm.3";
> +			resets = <&cpg 724>,
> +				 <&cpg 724>,
> +				 <&cpg 722>,
> +				 <&cpg 727>,
> +				 <&cpg 711>,
> +				 <&cpg 710>,
> +				 <&cpg 708>;
> +			reset-names = "du.0", "du.1", "du.3", "lvds.0",
> +				      "cmm.0", "cmm.1", "cmm.3";
>  			status = "disabled";
>  
>  			vsps = <&vspd0 0 &vspd1 0 &vspd0 1>;
> diff --git a/drivers/clk/renesas/r8a7795-cpg-mssr.c b/drivers/clk/renesas/r8a7795-cpg-mssr.c
> index a85dd50..ba9e595 100644
> --- a/drivers/clk/renesas/r8a7795-cpg-mssr.c
> +++ b/drivers/clk/renesas/r8a7795-cpg-mssr.c
> @@ -201,6 +201,10 @@ static struct mssr_mod_clk r8a7795_mod_clks[] __initdata = {
>  	DEF_MOD("ehci0",		 703,	R8A7795_CLK_S3D4),
>  	DEF_MOD("hsusb",		 704,	R8A7795_CLK_S3D4),
>  	DEF_MOD("hsusb3",		 705,	R8A7795_CLK_S3D4),
> +	DEF_MOD("cmm3",			 708,	R8A7795_CLK_S2D1),
> +	DEF_MOD("cmm2",			 709,	R8A7795_CLK_S2D1),
> +	DEF_MOD("cmm1",			 710,	R8A7795_CLK_S2D1),
> +	DEF_MOD("cmm0",			 711,	R8A7795_CLK_S2D1),
>  	DEF_MOD("csi21",		 713,	R8A7795_CLK_CSI0), /* ES1.x */
>  	DEF_MOD("csi20",		 714,	R8A7795_CLK_CSI0),
>  	DEF_MOD("csi41",		 715,	R8A7795_CLK_CSI0),
> diff --git a/drivers/clk/renesas/r8a7796-cpg-mssr.c b/drivers/clk/renesas/r8a7796-cpg-mssr.c
> index dfb267a..9f01fda 100644
> --- a/drivers/clk/renesas/r8a7796-cpg-mssr.c
> +++ b/drivers/clk/renesas/r8a7796-cpg-mssr.c
> @@ -180,6 +180,9 @@ static const struct mssr_mod_clk r8a7796_mod_clks[] __initconst = {
>  	DEF_MOD("ehci1",		 702,	R8A7796_CLK_S3D4),
>  	DEF_MOD("ehci0",		 703,	R8A7796_CLK_S3D4),
>  	DEF_MOD("hsusb",		 704,	R8A7796_CLK_S3D4),
> +	DEF_MOD("cmm2",			 709,	R8A7796_CLK_S2D1),
> +	DEF_MOD("cmm1",			 710,	R8A7796_CLK_S2D1),
> +	DEF_MOD("cmm0",			 711,	R8A7796_CLK_S2D1),
>  	DEF_MOD("csi20",		 714,	R8A7796_CLK_CSI0),
>  	DEF_MOD("csi40",		 716,	R8A7796_CLK_CSI0),
>  	DEF_MOD("du2",			 722,	R8A7796_CLK_S2D1),
> diff --git a/drivers/clk/renesas/r8a77965-cpg-mssr.c b/drivers/clk/renesas/r8a77965-cpg-mssr.c
> index 8fae5e9..cac4570 100644
> --- a/drivers/clk/renesas/r8a77965-cpg-mssr.c
> +++ b/drivers/clk/renesas/r8a77965-cpg-mssr.c
> @@ -123,7 +123,6 @@ static const struct mssr_mod_clk r8a77965_mod_clks[] __initconst = {
>  	DEF_MOD("sys-dmac2",		217,	R8A77965_CLK_S0D3),
>  	DEF_MOD("sys-dmac1",		218,	R8A77965_CLK_S0D3),
>  	DEF_MOD("sys-dmac0",		219,	R8A77965_CLK_S0D3),
> -
>  	DEF_MOD("cmt3",			300,	R8A77965_CLK_R),
>  	DEF_MOD("cmt2",			301,	R8A77965_CLK_R),
>  	DEF_MOD("cmt1",			302,	R8A77965_CLK_R),
> @@ -215,6 +214,111 @@ static const struct mssr_mod_clk r8a77965_mod_clks[] __initconst = {
>  	DEF_MOD("i2c1",			930,	R8A77965_CLK_S3D2),
>  	DEF_MOD("i2c0",			931,	R8A77965_CLK_S3D2),
>  
> +	DEF_MOD("3dge",			 112,	R8A77965_CLK_ZG),
> +	DEF_MOD("fdp0",			 119,	R8A77965_CLK_S0D1),
> +	DEF_MOD("vcplf",		 130,	R8A77965_CLK_S0D2),
> +	DEF_MOD("vdpb",			 131,	R8A77965_CLK_S0D2),
> +	DEF_MOD("scif5",		 202,	R8A77965_CLK_S3D4),
> +	DEF_MOD("scif4",		 203,	R8A77965_CLK_S3D4),
> +	DEF_MOD("scif3",		 204,	R8A77965_CLK_S3D4),
> +	DEF_MOD("scif1",		 206,	R8A77965_CLK_S3D4),
> +	DEF_MOD("scif0",		 207,	R8A77965_CLK_S3D4),
> +	DEF_MOD("msiof3",		 208,	R8A77965_CLK_MSO),
> +	DEF_MOD("msiof2",		 209,	R8A77965_CLK_MSO),
> +	DEF_MOD("msiof1",		 210,	R8A77965_CLK_MSO),
> +	DEF_MOD("msiof0",		 211,	R8A77965_CLK_MSO),
> +	DEF_MOD("sys-dmac2",		 217,	R8A77965_CLK_S0D3),
> +	DEF_MOD("sys-dmac1",		 218,	R8A77965_CLK_S0D3),
> +	DEF_MOD("sys-dmac0",		 219,	R8A77965_CLK_S0D3),
> +	DEF_MOD("cmt3",			 300,	R8A77965_CLK_R),
> +	DEF_MOD("cmt2",			 301,	R8A77965_CLK_R),
> +	DEF_MOD("cmt1",			 302,	R8A77965_CLK_R),
> +	DEF_MOD("cmt0",			 303,	R8A77965_CLK_R),
> +	DEF_MOD("scif2",		 310,	R8A77965_CLK_S3D4),
> +	DEF_MOD("sdif3",		 311,	R8A77965_CLK_SD3),
> +	DEF_MOD("sdif2",		 312,	R8A77965_CLK_SD2),
> +	DEF_MOD("sdif1",		 313,	R8A77965_CLK_SD1),
> +	DEF_MOD("sdif0",		 314,	R8A77965_CLK_SD0),
> +	DEF_MOD("pcie1",		 318,	R8A77965_CLK_S3D1),
> +	DEF_MOD("pcie0",		 319,	R8A77965_CLK_S3D1),
> +	DEF_MOD("usb3-if0",		 328,	R8A77965_CLK_S3D1),
> +	DEF_MOD("usb-dmac0",		 330,	R8A77965_CLK_S3D1),
> +	DEF_MOD("usb-dmac1",		 331,	R8A77965_CLK_S3D1),
> +	DEF_MOD("rwdt0",		 402,	R8A77965_CLK_R),
> +	DEF_MOD("intc-ex",		 407,	R8A77965_CLK_CP),
> +	DEF_MOD("intc-ap",		 408,	R8A77965_CLK_S3D1),
> +	DEF_MOD("audmac0",		 502,	R8A77965_CLK_S3D4),
> +	DEF_MOD("audmac1",		 501,	R8A77965_CLK_S3D4),
> +	DEF_MOD("adsp",			 506,	R8A77965_CLK_S1D1),
> +	DEF_MOD("drif7",		 508,	R8A77965_CLK_S3D2),
> +	DEF_MOD("drif6",		 509,	R8A77965_CLK_S3D2),
> +	DEF_MOD("drif5",		 510,	R8A77965_CLK_S3D2),
> +	DEF_MOD("drif4",		 511,	R8A77965_CLK_S3D2),
> +	DEF_MOD("drif3",		 512,	R8A77965_CLK_S3D2),
> +	DEF_MOD("drif2",		 513,	R8A77965_CLK_S3D2),
> +	DEF_MOD("drif1",		 514,	R8A77965_CLK_S3D2),
> +	DEF_MOD("drif0",		 515,	R8A77965_CLK_S3D2),
> +	DEF_MOD("hscif4",		 516,	R8A77965_CLK_S3D1),
> +	DEF_MOD("hscif3",		 517,	R8A77965_CLK_S3D1),
> +	DEF_MOD("hscif2",		 518,	R8A77965_CLK_S3D1),
> +	DEF_MOD("hscif1",		 519,	R8A77965_CLK_S3D1),
> +	DEF_MOD("hscif0",		 520,	R8A77965_CLK_S3D1),
> +	DEF_MOD("thermal",		 522,	R8A77965_CLK_CP),
> +	DEF_MOD("pwm",			 523,	R8A77965_CLK_S3D4),
> +	DEF_MOD("fcpvd1",		 602,	R8A77965_CLK_S0D2),
> +	DEF_MOD("fcpvd0",		 603,	R8A77965_CLK_S0D2),
> +	DEF_MOD("fcpvb0",		 607,	R8A77965_CLK_S0D1),
> +	DEF_MOD("fcpvi0",		 611,	R8A77965_CLK_S0D1),
> +	DEF_MOD("fcpf0",		 615,	R8A77965_CLK_S0D1),
> +	DEF_MOD("fcpcs",		 619,	R8A77965_CLK_S0D2),
> +	DEF_MOD("vspd1",		 622,	R8A77965_CLK_S0D2),
> +	DEF_MOD("vspd0",		 623,	R8A77965_CLK_S0D2),
> +	DEF_MOD("vspb",			 626,	R8A77965_CLK_S0D1),
> +	DEF_MOD("vspi0",		 631,	R8A77965_CLK_S0D1),
> +	DEF_MOD("ehci1",		 702,	R8A77965_CLK_S3D4),
> +	DEF_MOD("ehci0",		 703,	R8A77965_CLK_S3D4),
> +	DEF_MOD("hsusb",		 704,	R8A77965_CLK_S3D4),
> +	DEF_MOD("cmm3",			 708,	R8A77965_CLK_S2D1),
> +	DEF_MOD("cmm1",			 710,	R8A77965_CLK_S2D1),
> +	DEF_MOD("cmm0",			 711,	R8A77965_CLK_S2D1),
> +	DEF_MOD("csi20",		 714,	R8A77965_CLK_CSI0),
> +	DEF_MOD("csi40",		 716,	R8A77965_CLK_CSI0),
> +	DEF_MOD("du3",			 721,	R8A77965_CLK_S2D1),
> +	DEF_MOD("du1",			 723,	R8A77965_CLK_S2D1),
> +	DEF_MOD("du0",			 724,	R8A77965_CLK_S2D1),
> +	DEF_MOD("lvds",			 727,	R8A77965_CLK_S2D1),
> +	DEF_MOD("hdmi0",		 729,	R8A77965_CLK_HDMI),
> +	DEF_MOD("vin7",			 804,	R8A77965_CLK_S0D2),
> +	DEF_MOD("vin6",			 805,	R8A77965_CLK_S0D2),
> +	DEF_MOD("vin5",			 806,	R8A77965_CLK_S0D2),
> +	DEF_MOD("vin4",			 807,	R8A77965_CLK_S0D2),
> +	DEF_MOD("vin3",			 808,	R8A77965_CLK_S0D2),
> +	DEF_MOD("vin2",			 809,	R8A77965_CLK_S0D2),
> +	DEF_MOD("vin1",			 810,	R8A77965_CLK_S0D2),
> +	DEF_MOD("vin0",			 811,	R8A77965_CLK_S0D2),
> +	DEF_MOD("etheravb",		 812,	R8A77965_CLK_S0D6),
> +	DEF_MOD("sata0",		 815,	R8A77965_CLK_S3D2),
> +	DEF_MOD("gpio7",		 905,	R8A77965_CLK_S3D4),
> +	DEF_MOD("gpio6",		 906,	R8A77965_CLK_S3D4),
> +	DEF_MOD("gpio5",		 907,	R8A77965_CLK_S3D4),
> +	DEF_MOD("gpio4",		 908,	R8A77965_CLK_S3D4),
> +	DEF_MOD("gpio3",		 909,	R8A77965_CLK_S3D4),
> +	DEF_MOD("gpio2",		 910,	R8A77965_CLK_S3D4),
> +	DEF_MOD("gpio1",		 911,	R8A77965_CLK_S3D4),
> +	DEF_MOD("gpio0",		 912,	R8A77965_CLK_S3D4),
> +	DEF_MOD("can-fd",		 914,	R8A77965_CLK_S3D2),
> +	DEF_MOD("can-if1",		 915,	R8A77965_CLK_S3D4),
> +	DEF_MOD("can-if0",		 916,	R8A77965_CLK_S3D4),
> +	DEF_MOD("i2c6",			 918,	R8A77965_CLK_S0D6),
> +	DEF_MOD("i2c5",			 919,	R8A77965_CLK_S0D6),
> +	DEF_MOD("adg",			 922,	R8A77965_CLK_S0D1),
> +	DEF_MOD("i2c-dvfs",		 926,	R8A77965_CLK_CP),
> +	DEF_MOD("i2c4",			 927,	R8A77965_CLK_S0D6),
> +	DEF_MOD("i2c3",			 928,	R8A77965_CLK_S0D6),
> +	DEF_MOD("i2c2",			 929,	R8A77965_CLK_S3D2),
> +	DEF_MOD("i2c1",			 930,	R8A77965_CLK_S3D2),
> +	DEF_MOD("i2c0",			 931,	R8A77965_CLK_S3D2),
> +

That's much more than adding CMM clocks... Please split the clocks
changes to separate patches. You can even repost them separately, as
they can be merged before the rest of the series.

>  	DEF_MOD("ssi-all",		1005,	R8A77965_CLK_S3D4),
>  	DEF_MOD("ssi9",			1006,	MOD_CLK_ID(1005)),
>  	DEF_MOD("ssi8",			1007,	MOD_CLK_ID(1005)),

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH 3/8] drm: rcar-du: Give a name to clu table samples
  2019-04-03 13:14   ` VenkataRajesh.Kalakodima
  (?)
@ 2019-04-04 10:15   ` Laurent Pinchart
  -1 siblings, 0 replies; 36+ messages in thread
From: Laurent Pinchart @ 2019-04-04 10:15 UTC (permalink / raw)
  To: VenkataRajesh.Kalakodima
  Cc: linux-renesas-soc, devicetree, linux-kernel, linux-clk,
	dri-devel, Harsha M M, Eugeniu Rosca

Hi Kalakodima,

Thank you for the patch.

PAtches 3/8, 4/8 and 5/8 modify the new
drivers/gpu/drm/rcar-du/rcar_du_cmm.c a file that was introduced in 1/8.
Please squash them all together, there's no point in adding a driver
with known to be incorrect code to then fix it in other patches.

On Wed, Apr 03, 2019 at 06:44:39PM +0530, VenkataRajesh.Kalakodima@in.bosch.com wrote:
> From: kalakodima venkata rajesh <venkatarajesh.kalakodima@in.bosch.com>
> 
> Replace the hardcoded value of clu table sample count with a
> meaningful name.
> 
> Signed-off-by: Harsha M M <harsha.manjulamallikarjun@in.bosch.com>
> 
> This is the out-of-tree patch for DU CMM driver support from
>     Yocto release v3.6.0. The part of this patch adding CMM support to
>     the new Rcar E3 (R8A77990) SoC was filtered out due to lack of
>     Yocto v3.6.0 (i.e. rcar-3.6.2) kernel updates on staging-414.
> 
>     Link: https://github.com/renesas-rcar/du_cmm/commit/53973b806881ed8f54500b0d42bdc40aaca60476.patch
> 
>     Following is from the patch description:
> 
>     Subject: [PATCH] du_cmm: Release for Yocto v3.6.0
> 
>     This patch made the following correspondence.
> 
>       - R-Car E3(R8A77990) device support.
>       - Fix rewritting of parameter procedure in rcar_du_cmm_postclose
> 
> Signed-off-by: Eugeniu Rosca <erosca@de.adit-jv.com>
> 
>       - Resolved checkpatch errors
>       - Resolved merge conflicts according to latest version
> 
> Signed-off-by: kalakodima venkata rajesh <venkatarajesh.kalakodima@in.bosch.com>
> ---
>  drivers/gpu/drm/rcar-du/rcar_du_cmm.c | 28 +++++++++++++++-------------
>  1 file changed, 15 insertions(+), 13 deletions(-)
> 
> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_cmm.c b/drivers/gpu/drm/rcar-du/rcar_du_cmm.c
> index ac613a6e..d380dd9 100644
> --- a/drivers/gpu/drm/rcar-du/rcar_du_cmm.c
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_cmm.c
> @@ -75,9 +75,9 @@
>  #include <linux/clk.h>
>  
>  /* #define DEBUG_PROCE_TIME 1 */
> -
> +#define CMM_CLU_SAMPLES 17
>  #define CMM_LUT_NUM 256
> -#define CMM_CLU_NUM (17 * 17 * 17)
> +#define CMM_CLU_NUM (CMM_CLU_SAMPLES * CMM_CLU_SAMPLES * CMM_CLU_SAMPLES)
>  #define CMM_HGO_NUM 64
>  /* rcar_du_drm.h Include */
>  #define LUT_DOUBLE_BUFFER_AUTO		0
> @@ -211,11 +211,11 @@ static inline u32 index_to_clu_data(int index)
>  {
>  	int r, g, b;
>  
> -	r = index % 17;
> -	index /= 17;
> -	g = index % 17;
> -	index /= 17;
> -	b = index % 17;
> +	r = index % CMM_CLU_SAMPLES;
> +	index /= CMM_CLU_SAMPLES;
> +	g = index % CMM_CLU_SAMPLES;
> +	index /= CMM_CLU_SAMPLES;
> +	b = index % CMM_CLU_SAMPLES;
>  
>  	r = (r << 20);
>  	if (r > (255 << 16))
> @@ -630,9 +630,9 @@ static int clu_table_copy(struct rcar_du_cmm *du_cmm)
>  	}
>  
>  	rcar_du_cmm_write(du_cmm, dst_addr, 0);
> -	for (i = 0; i < 17; i++) {
> -		for (j = 0; j < 17; j++) {
> -			for (k = 0; k < 17; k++) {
> +	for (i = 0; i < CMM_CLU_SAMPLES; i++) {
> +		for (j = 0; j < CMM_CLU_SAMPLES; j++) {
> +			for (k = 0; k < CMM_CLU_SAMPLES; k++) {
>  				rcar_du_cmm_write(du_cmm, src_addr,
>  						  (k << 16) | (j << 8) |
>  						  (i << 0));
> @@ -912,9 +912,9 @@ int rcar_du_cmm_pm_suspend(struct rcar_du_crtc *rcrtc)
>  	}
>  
>  	index = 0;
> -	for (i = 0; i < 17; i++) {
> -		for (j = 0; j < 17; j++) {
> -			for (k = 0; k < 17; k++) {
> +	for (i = 0; i < CMM_CLU_SAMPLES; i++) {
> +		for (j = 0; j < CMM_CLU_SAMPLES; j++) {
> +			for (k = 0; k < CMM_CLU_SAMPLES; k++) {
>  				rcar_du_cmm_write(du_cmm, CMM_CLU_ADDR,
>  						  (k << 16) | (j << 8) |
>  						  (i << 0));
> @@ -1014,6 +1014,8 @@ void rcar_du_cmm_postclose(struct drm_device *dev, struct drm_file *file_priv)
>  	for (crtcs_cnt = 0; crtcs_cnt < rcdu->num_crtcs; crtcs_cnt++) {
>  		rcrtc = &rcdu->crtcs[crtcs_cnt];
>  		du_cmm = rcrtc->cmm_handle;
> +		if (!du_cmm)
> +			continue;
>  		if (du_cmm->authority && du_cmm->pid == task_pid_nr(current)) {
>  			du_cmm->authority = false;
>  			du_cmm->pid = 0;

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH 7/8] drm: rcar-du: update gamma and ctm properties in commit tail
  2019-04-03 13:14   ` VenkataRajesh.Kalakodima
@ 2019-04-04 10:19     ` Laurent Pinchart
  -1 siblings, 0 replies; 36+ messages in thread
From: Laurent Pinchart @ 2019-04-04 10:19 UTC (permalink / raw)
  To: VenkataRajesh.Kalakodima
  Cc: linux-renesas-soc, devicetree, linux-kernel, linux-clk,
	dri-devel, Harsha M M

Hi Kalakodima,

Thank you for the patch.

On Wed, Apr 03, 2019 at 06:44:43PM +0530, VenkataRajesh.Kalakodima@in.bosch.com wrote:
> From: kalakodima venkata rajesh <venkatarajesh.kalakodima@in.bosch.com>
> 
> Update gamma and ctm properties if there is a change.
> 
> Signed-off-by: Harsha M M <harsha.manjulamallikarjun@in.bosch.com>
> 
>    - Fix compilation issues when for_each_crtc_in_state is not defined
>    - Resolved checkpatch errors
>    - Resolved merge conflicts according to latest version
> 
> Signed-off-by: kalakodima venkata rajesh <venkatarajesh.kalakodima@in.bosch.com>
> ---
>  drivers/gpu/drm/rcar-du/rcar_du_kms.c | 25 +++++++++++++++++++++++++
>  include/drm/drm_atomic.h              | 25 +++++++++++++++++++++++++
>  2 files changed, 50 insertions(+)
> 
> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_kms.c b/drivers/gpu/drm/rcar-du/rcar_du_kms.c
> index f0bc7cc..4d9a19c 100644
> --- a/drivers/gpu/drm/rcar-du/rcar_du_kms.c
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_kms.c
> @@ -246,6 +246,10 @@ static int rcar_du_atomic_check(struct drm_device *dev,
>  static void rcar_du_atomic_commit_tail(struct drm_atomic_state *old_state)
>  {
>  	struct drm_device *dev = old_state->dev;
> +	struct drm_crtc *crtc;
> +	struct drm_crtc_state *crtc_state;
> +	struct rcar_du_crtc *rcrtc;
> +	int i;
>  
>  	/* Apply the atomic update. */
>  	drm_atomic_helper_commit_modeset_disables(dev, old_state);
> @@ -253,6 +257,27 @@ static void rcar_du_atomic_commit_tail(struct drm_atomic_state *old_state)
>  					DRM_PLANE_COMMIT_ACTIVE_ONLY);
>  	drm_atomic_helper_commit_modeset_enables(dev, old_state);
>  
> +	/* Update gamma and ctm properties for all crtc in present
> +	 * state. Update is done only if there is a change
> +	 */
> +	for_each_crtc_in_state(old_state, crtc, crtc_state, i) {
> +		rcrtc = to_rcar_crtc(crtc);
> +
> +		if (rcrtc->lut_handle) {
> +			rcar_du_cmm_update_lut_and_free
> +			  (rcrtc->lut_handle,
> +			   (struct drm_color_lut *)crtc->state->gamma_lut->data,
> +			   (crtc->state->gamma_lut->length /
> +			   sizeof(struct drm_color_lut)));
> +			rcrtc->lut_handle = NULL;
> +		}
> +		if (rcrtc->clu_handle) {
> +			rcar_du_cmm_update_clu_and_free
> +			  (rcrtc->clu_handle,
> +			   (struct drm_color_ctm *)crtc->state->ctm->data);
> +			rcrtc->clu_handle = NULL;
> +		}
> +	}
>  	drm_atomic_helper_commit_hw_done(old_state);
>  	drm_atomic_helper_wait_for_flip_done(dev, old_state);

We're in the process of reworking the commit tail handler, so I expect
major changes will be needed here.

>  
> diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
> index 1e71315..d22ccd8 100644
> --- a/include/drm/drm_atomic.h
> +++ b/include/drm/drm_atomic.h
> @@ -693,6 +693,31 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p);
>  			     (new_connector_state) = (__state)->connectors[__i].new_state, 1))
>  
>  /**
> + * for_each_crtc_in_state - iterate over all connectors in an atomic update
> + * @__state: &struct drm_atomic_state pointer
> + * @crtc: &struct drm_crtc iteration cursor
> + * @crtc_state: &struct drm_crtc_state iteration cursor
> + * @__i: int iteration cursor, for macro-internal use
> + *
> + * This iterates over all CRTCs in an atomic update. Note that before the
> + * software state is committed (by calling drm_atomic_helper_swap_state(), this
> + * points to the new state, while afterwards it points to the old state. Due to
> + * this tricky confusion this macro is deprecated.
> + *
> + * FIXME:
> + *
> + * Replace all usage of this with one of the explicit iterators below and then
> + * remove this macro.

Then don't add it :-) In general you should look at the code you want to
upstream, this feels like it was a blind copy from a BSP without giving
it much consideration.

> + */
> +#define for_each_crtc_in_state(__state, crtc, crtc_state, __i)	\
> +	for ((__i) = 0;						\
> +	     ((__i) < ((__state)->dev->mode_config.num_crtc)) &&	\
> +	     ((crtc) = ((__state)->crtcs[__i].ptr),			\
> +	     (crtc_state) = ((__state)->crtcs[__i].state), 1);	\
> +	     (__i)++)						\
> +		for_each_if(crtc_state)
> +
> +/**
>   * for_each_oldnew_crtc_in_state - iterate over all CRTCs in an atomic update
>   * @__state: &struct drm_atomic_state pointer
>   * @crtc: &struct drm_crtc iteration cursor

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH 7/8] drm: rcar-du: update gamma and ctm properties in commit tail
@ 2019-04-04 10:19     ` Laurent Pinchart
  0 siblings, 0 replies; 36+ messages in thread
From: Laurent Pinchart @ 2019-04-04 10:19 UTC (permalink / raw)
  To: VenkataRajesh.Kalakodima
  Cc: devicetree, linux-kernel, dri-devel, linux-renesas-soc,
	Harsha M M, linux-clk

Hi Kalakodima,

Thank you for the patch.

On Wed, Apr 03, 2019 at 06:44:43PM +0530, VenkataRajesh.Kalakodima@in.bosch.com wrote:
> From: kalakodima venkata rajesh <venkatarajesh.kalakodima@in.bosch.com>
> 
> Update gamma and ctm properties if there is a change.
> 
> Signed-off-by: Harsha M M <harsha.manjulamallikarjun@in.bosch.com>
> 
>    - Fix compilation issues when for_each_crtc_in_state is not defined
>    - Resolved checkpatch errors
>    - Resolved merge conflicts according to latest version
> 
> Signed-off-by: kalakodima venkata rajesh <venkatarajesh.kalakodima@in.bosch.com>
> ---
>  drivers/gpu/drm/rcar-du/rcar_du_kms.c | 25 +++++++++++++++++++++++++
>  include/drm/drm_atomic.h              | 25 +++++++++++++++++++++++++
>  2 files changed, 50 insertions(+)
> 
> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_kms.c b/drivers/gpu/drm/rcar-du/rcar_du_kms.c
> index f0bc7cc..4d9a19c 100644
> --- a/drivers/gpu/drm/rcar-du/rcar_du_kms.c
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_kms.c
> @@ -246,6 +246,10 @@ static int rcar_du_atomic_check(struct drm_device *dev,
>  static void rcar_du_atomic_commit_tail(struct drm_atomic_state *old_state)
>  {
>  	struct drm_device *dev = old_state->dev;
> +	struct drm_crtc *crtc;
> +	struct drm_crtc_state *crtc_state;
> +	struct rcar_du_crtc *rcrtc;
> +	int i;
>  
>  	/* Apply the atomic update. */
>  	drm_atomic_helper_commit_modeset_disables(dev, old_state);
> @@ -253,6 +257,27 @@ static void rcar_du_atomic_commit_tail(struct drm_atomic_state *old_state)
>  					DRM_PLANE_COMMIT_ACTIVE_ONLY);
>  	drm_atomic_helper_commit_modeset_enables(dev, old_state);
>  
> +	/* Update gamma and ctm properties for all crtc in present
> +	 * state. Update is done only if there is a change
> +	 */
> +	for_each_crtc_in_state(old_state, crtc, crtc_state, i) {
> +		rcrtc = to_rcar_crtc(crtc);
> +
> +		if (rcrtc->lut_handle) {
> +			rcar_du_cmm_update_lut_and_free
> +			  (rcrtc->lut_handle,
> +			   (struct drm_color_lut *)crtc->state->gamma_lut->data,
> +			   (crtc->state->gamma_lut->length /
> +			   sizeof(struct drm_color_lut)));
> +			rcrtc->lut_handle = NULL;
> +		}
> +		if (rcrtc->clu_handle) {
> +			rcar_du_cmm_update_clu_and_free
> +			  (rcrtc->clu_handle,
> +			   (struct drm_color_ctm *)crtc->state->ctm->data);
> +			rcrtc->clu_handle = NULL;
> +		}
> +	}
>  	drm_atomic_helper_commit_hw_done(old_state);
>  	drm_atomic_helper_wait_for_flip_done(dev, old_state);

We're in the process of reworking the commit tail handler, so I expect
major changes will be needed here.

>  
> diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
> index 1e71315..d22ccd8 100644
> --- a/include/drm/drm_atomic.h
> +++ b/include/drm/drm_atomic.h
> @@ -693,6 +693,31 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p);
>  			     (new_connector_state) = (__state)->connectors[__i].new_state, 1))
>  
>  /**
> + * for_each_crtc_in_state - iterate over all connectors in an atomic update
> + * @__state: &struct drm_atomic_state pointer
> + * @crtc: &struct drm_crtc iteration cursor
> + * @crtc_state: &struct drm_crtc_state iteration cursor
> + * @__i: int iteration cursor, for macro-internal use
> + *
> + * This iterates over all CRTCs in an atomic update. Note that before the
> + * software state is committed (by calling drm_atomic_helper_swap_state(), this
> + * points to the new state, while afterwards it points to the old state. Due to
> + * this tricky confusion this macro is deprecated.
> + *
> + * FIXME:
> + *
> + * Replace all usage of this with one of the explicit iterators below and then
> + * remove this macro.

Then don't add it :-) In general you should look at the code you want to
upstream, this feels like it was a blind copy from a BSP without giving
it much consideration.

> + */
> +#define for_each_crtc_in_state(__state, crtc, crtc_state, __i)	\
> +	for ((__i) = 0;						\
> +	     ((__i) < ((__state)->dev->mode_config.num_crtc)) &&	\
> +	     ((crtc) = ((__state)->crtcs[__i].ptr),			\
> +	     (crtc_state) = ((__state)->crtcs[__i].state), 1);	\
> +	     (__i)++)						\
> +		for_each_if(crtc_state)
> +
> +/**
>   * for_each_oldnew_crtc_in_state - iterate over all CRTCs in an atomic update
>   * @__state: &struct drm_atomic_state pointer
>   * @crtc: &struct drm_crtc iteration cursor

-- 
Regards,

Laurent Pinchart
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH 8/8] drm: rcar-du: Add shutdown callback function in platform_driver
  2019-04-03 13:14   ` VenkataRajesh.Kalakodima
@ 2019-04-04 10:26     ` Laurent Pinchart
  -1 siblings, 0 replies; 36+ messages in thread
From: Laurent Pinchart @ 2019-04-04 10:26 UTC (permalink / raw)
  To: VenkataRajesh.Kalakodima
  Cc: linux-renesas-soc, devicetree, linux-kernel, linux-clk,
	dri-devel, Balasubramani Vivekanandan, Steve Longerbeam,
	Koji Matsuoka

Hi Kalakodima,

Thank you for the patch.

On Wed, Apr 03, 2019 at 06:44:44PM +0530, VenkataRajesh.Kalakodima@in.bosch.com wrote:
> From: kalakodima venkata rajesh <venkatarajesh.kalakodima@in.bosch.com>
> 
> When rebooting, the Display driver is accessing H/W (reading DDR).
> Therefore, there is a problem of hanging when setting DDR to self
> refresh mode.
> 
> This patch implement the shutdown function and solve this problem
> by stopping H/W access.
> 
> In addtion, on the ulcb board, since initial values of versaclock
> are used as they are, signals are not output when initializing to
> 0 with shutdown, so this patch excludes processing to initialize
> versaclock to 0.

This seems like it should be fixed in the VC5 driver, not here.

> drm: rcar-du: Add HDMI control clock when S2RAM
> 
> Signed-off-by: Koji Matsuoka <koji.matsuoka.xm@renesas.com>
> 
> (cherry picked from horms/renesas-bsp commit 3cfda6331c4069800dd4434427284aba8e6f1ed6)
> [slongerbeam: keep integer i in rcar_du_pm_shutdown(), needed because of
>  050e54d87f ("drm: rcar-du: drm: rcar-du: Add DU CMM support")]
> 
> Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
> 
> drm: rcar-du: cmm: lut and clu backup not required during
>  shutdown
> rcar_du_cmm_pm_suspend function copies LUT and CLU hardare
> register values to memory. In the patch which adds DU CMM
> support (https://github.com/renesas-rcar/du_cmm/commit/
> 9a65d02119e4ae405a89a850463a6a0d0f2c1ecb), the intention of
> the author was to backup the registers during suspend and
> restore it on resume. But rcar_du_cmm_pm_suspend was also
> called on system shutdown. Though it does not cause any harm,
> it is not required during shutdown as it does not make sense
> to backup. This patch ensures that rcar_du_cmm_pm_suspend is
> called only during suspend
> 
> Fixes: https://github.com/renesas-rcar/du_cmm/commit/9a65d02119e4ae405a89a850463a6a0d0f2c1ecb
> 
> Signed-off-by: Balasubramani Vivekanandan <balasubramani_vivekanandan@mentor.com>
> 
>       - Resolved checkpatch errors
>       - Resolved merge conflicts according to latest version
> 
> Signed-off-by: kalakodima venkata rajesh <venkatarajesh.kalakodima@in.bosch.com>
> ---
>  drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 35 ++++++++++++++++++++
>  drivers/gpu/drm/rcar-du/rcar_du_drv.c     | 54 +++++++++++++++++++++++++------
>  drivers/gpu/drm/rcar-du/rcar_du_encoder.c |  2 +-
>  drivers/gpu/drm/rcar-du/rcar_du_encoder.h |  1 +
>  include/drm/bridge/dw_hdmi.h              |  1 +
>  5 files changed, 83 insertions(+), 10 deletions(-)
> 
> diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> index 5971976..aa257d7 100644
> --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> @@ -2033,6 +2033,41 @@ static void dw_hdmi_bridge_enable(struct drm_bridge *bridge)
>  	mutex_unlock(&hdmi->mutex);
>  }
>  
> +/*
> + * This function controls clocks of dw_hdmi through drm_bridge
> + * at system suspend/resume.
> + * Arguments:
> + *  bridge: drm_bridge that contains dw_hdmi.
> + *  flag: controlled flag.
> + *		false: is used when suspend.
> + *		true: is used when resume.
> + */
> +void dw_hdmi_s2r_ctrl(struct drm_bridge *bridge, int flag)
> +{
> +	struct dw_hdmi *hdmi = bridge->driver_private;
> +
> +	if (!hdmi)
> +		return;
> +
> +	if (flag) { /* enable clk */
> +		if (hdmi->isfr_clk)
> +			clk_prepare_enable(hdmi->isfr_clk);
> +		if (hdmi->iahb_clk)
> +			clk_prepare_enable(hdmi->iahb_clk);
> +
> +		initialize_hdmi_ih_mutes(hdmi);
> +		dw_hdmi_setup_i2c(hdmi);
> +		dw_hdmi_i2c_init(hdmi);
> +		dw_hdmi_phy_setup_hpd(hdmi, NULL);
> +	} else { /* disable clk */
> +		if (hdmi->isfr_clk)
> +			clk_disable_unprepare(hdmi->isfr_clk);
> +		if (hdmi->iahb_clk)
> +			clk_disable_unprepare(hdmi->iahb_clk);
> +	}
> +}
> +EXPORT_SYMBOL_GPL(dw_hdmi_s2r_ctrl);
> +
>  static const struct drm_bridge_funcs dw_hdmi_bridge_funcs = {
>  	.attach = dw_hdmi_bridge_attach,
>  	.enable = dw_hdmi_bridge_enable,
> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
> index 838b7c9..9eb63b0 100644
> --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
> @@ -21,6 +21,7 @@
>  #include <linux/slab.h>
>  #include <linux/wait.h>
>  
> +#include <drm/bridge/dw_hdmi.h>
>  #include <drm/drmP.h>
>  #include <drm/drm_atomic_helper.h>
>  #include <drm/drm_crtc_helper.h>
> @@ -368,18 +369,14 @@ static struct drm_driver rcar_du_driver = {
>   */
>  
>  #ifdef CONFIG_PM_SLEEP
> -static int rcar_du_pm_suspend(struct device *dev)
> +static int rcar_du_pm_shutdown(struct device *dev)
>  {
>  	struct rcar_du_device *rcdu = dev_get_drvdata(dev);
>  	struct drm_atomic_state *state;
> -	int i;
> -
> -	if (rcar_du_has(rcdu, RCAR_DU_FEATURE_CMM)) {
> -		for (i = 0; i < rcdu->num_crtcs; ++i)
> -			rcar_du_cmm_pm_suspend(&rcdu->crtcs[i]);
> -	}
> -
> -	drm_kms_helper_poll_disable(rcdu->ddev);
> +#if IS_ENABLED(CONFIG_DRM_RCAR_DW_HDMI)
> +	struct drm_encoder *encoder;
> +#endif
> +		drm_kms_helper_poll_disable(rcdu->ddev);
>  	drm_fbdev_cma_set_suspend_unlocked(rcdu->fbdev, true);
>  
>  	state = drm_atomic_helper_suspend(rcdu->ddev);
> @@ -389,11 +386,43 @@ static int rcar_du_pm_suspend(struct device *dev)
>  		return PTR_ERR(state);
>  	}
>  
> +#if IS_ENABLED(CONFIG_DRM_RCAR_DW_HDMI)
> +	list_for_each_entry(encoder,
> +			    &rcdu->ddev->mode_config.encoder_list,
> +			    head) {
> +		struct rcar_du_encoder *renc = to_rcar_encoder(encoder);
> +
> +		if (renc->bridge && (renc->output == RCAR_DU_OUTPUT_HDMI0 ||
> +				     renc->output == RCAR_DU_OUTPUT_HDMI1))
> +			dw_hdmi_s2r_ctrl(encoder->bridge, false);

You can't call directly from the DU driver to the dw-hdmi driver, that's
a big layering violation. As Daniel reported, using the shutdown helper
will likely handle all this for you.

> +	}
> +#endif
>  	rcdu->suspend_state = state;
>  
>  	return 0;
>  }
>  
> +static int rcar_du_pm_suspend(struct device *dev)
> +{
> +	struct rcar_du_device *rcdu = dev_get_drvdata(dev);
> +
> +	int i, ret;
> +
> +	if (rcar_du_has(rcdu, RCAR_DU_FEATURE_CMM)) {
> +		for (i = 0; i < rcdu->num_crtcs; ++i)
> +			rcar_du_cmm_pm_suspend(&rcdu->crtcs[i]);
> +	}
> +
> +	ret = rcar_du_pm_shutdown(dev);
> +
> +	if (ret)
> +		return ret;
> +
> +	for (i = 0; i < rcdu->num_crtcs; ++i)
> +		clk_set_rate(rcdu->crtcs[i].extclock, 0);
> +	return 0;
> +}
> +
>  static int rcar_du_pm_resume(struct device *dev)
>  {
>  	struct rcar_du_device *rcdu = dev_get_drvdata(dev);
> @@ -504,6 +533,12 @@ static int rcar_du_probe(struct platform_device *pdev)
>  	return ret;
>  }
>  
> +static void rcar_du_shutdown(struct platform_device *pdev)
> +{
> +#ifdef CONFIG_PM_SLEEP
> +	rcar_du_pm_shutdown(&pdev->dev);
> +#endif
> +}
>  static struct platform_driver rcar_du_platform_driver = {
>  	.probe		= rcar_du_probe,
>  	.remove		= rcar_du_remove,
> @@ -512,6 +547,7 @@ static struct platform_driver rcar_du_platform_driver = {
>  		.pm	= &rcar_du_pm_ops,
>  		.of_match_table = rcar_du_of_table,
>  	},
> +	.shutdown       = rcar_du_shutdown,
>  };
>  
>  static int __init rcar_du_init(void)
> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_encoder.c b/drivers/gpu/drm/rcar-du/rcar_du_encoder.c
> index f9c933d..98df8a2 100644
> --- a/drivers/gpu/drm/rcar-du/rcar_du_encoder.c
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_encoder.c
> @@ -62,7 +62,7 @@ int rcar_du_encoder_init(struct rcar_du_device *rcdu,
>  
>  	dev_dbg(rcdu->dev, "initializing encoder %pOF for output %u\n",
>  		enc_node, output);
> -
> +	renc->bridge = bridge;
>  	/* Locate the DRM bridge from the encoder DT node. */
>  	bridge = of_drm_find_bridge(enc_node);
>  	if (!bridge) {
> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_encoder.h b/drivers/gpu/drm/rcar-du/rcar_du_encoder.h
> index 2d2abca..cc5bfcb 100644
> --- a/drivers/gpu/drm/rcar-du/rcar_du_encoder.h
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_encoder.h
> @@ -23,6 +23,7 @@ struct rcar_du_device;
>  struct rcar_du_encoder {
>  	struct drm_encoder base;
>  	enum rcar_du_output output;
> +	struct drm_bridge *bridge;
>  };
>  
>  #define to_rcar_encoder(e) \
> diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h
> index ccb5aa8..36383cf4 100644
> --- a/include/drm/bridge/dw_hdmi.h
> +++ b/include/drm/bridge/dw_hdmi.h
> @@ -171,5 +171,6 @@ enum drm_connector_status dw_hdmi_phy_read_hpd(struct dw_hdmi *hdmi,
>  void dw_hdmi_phy_update_hpd(struct dw_hdmi *hdmi, void *data,
>  			    bool force, bool disabled, bool rxsense);
>  void dw_hdmi_phy_setup_hpd(struct dw_hdmi *hdmi, void *data);
> +void dw_hdmi_s2r_ctrl(struct drm_bridge *bridge, int flag);
>  
>  #endif /* __IMX_HDMI_H__ */

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH 8/8] drm: rcar-du: Add shutdown callback function in platform_driver
@ 2019-04-04 10:26     ` Laurent Pinchart
  0 siblings, 0 replies; 36+ messages in thread
From: Laurent Pinchart @ 2019-04-04 10:26 UTC (permalink / raw)
  To: VenkataRajesh.Kalakodima
  Cc: linux-renesas-soc, devicetree, linux-kernel, linux-clk,
	dri-devel, Balasubramani Vivekanandan, Steve Longerbeam,
	Koji Matsuoka

Hi Kalakodima,

Thank you for the patch.

On Wed, Apr 03, 2019 at 06:44:44PM +0530, VenkataRajesh.Kalakodima@in.bosch.com wrote:
> From: kalakodima venkata rajesh <venkatarajesh.kalakodima@in.bosch.com>
> 
> When rebooting, the Display driver is accessing H/W (reading DDR).
> Therefore, there is a problem of hanging when setting DDR to self
> refresh mode.
> 
> This patch implement the shutdown function and solve this problem
> by stopping H/W access.
> 
> In addtion, on the ulcb board, since initial values of versaclock
> are used as they are, signals are not output when initializing to
> 0 with shutdown, so this patch excludes processing to initialize
> versaclock to 0.

This seems like it should be fixed in the VC5 driver, not here.

> drm: rcar-du: Add HDMI control clock when S2RAM
> 
> Signed-off-by: Koji Matsuoka <koji.matsuoka.xm@renesas.com>
> 
> (cherry picked from horms/renesas-bsp commit 3cfda6331c4069800dd4434427284aba8e6f1ed6)
> [slongerbeam: keep integer i in rcar_du_pm_shutdown(), needed because of
>  050e54d87f ("drm: rcar-du: drm: rcar-du: Add DU CMM support")]
> 
> Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
> 
> drm: rcar-du: cmm: lut and clu backup not required during
>  shutdown
> rcar_du_cmm_pm_suspend function copies LUT and CLU hardare
> register values to memory. In the patch which adds DU CMM
> support (https://github.com/renesas-rcar/du_cmm/commit/
> 9a65d02119e4ae405a89a850463a6a0d0f2c1ecb), the intention of
> the author was to backup the registers during suspend and
> restore it on resume. But rcar_du_cmm_pm_suspend was also
> called on system shutdown. Though it does not cause any harm,
> it is not required during shutdown as it does not make sense
> to backup. This patch ensures that rcar_du_cmm_pm_suspend is
> called only during suspend
> 
> Fixes: https://github.com/renesas-rcar/du_cmm/commit/9a65d02119e4ae405a89a850463a6a0d0f2c1ecb
> 
> Signed-off-by: Balasubramani Vivekanandan <balasubramani_vivekanandan@mentor.com>
> 
>       - Resolved checkpatch errors
>       - Resolved merge conflicts according to latest version
> 
> Signed-off-by: kalakodima venkata rajesh <venkatarajesh.kalakodima@in.bosch.com>
> ---
>  drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 35 ++++++++++++++++++++
>  drivers/gpu/drm/rcar-du/rcar_du_drv.c     | 54 +++++++++++++++++++++++++------
>  drivers/gpu/drm/rcar-du/rcar_du_encoder.c |  2 +-
>  drivers/gpu/drm/rcar-du/rcar_du_encoder.h |  1 +
>  include/drm/bridge/dw_hdmi.h              |  1 +
>  5 files changed, 83 insertions(+), 10 deletions(-)
> 
> diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> index 5971976..aa257d7 100644
> --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> @@ -2033,6 +2033,41 @@ static void dw_hdmi_bridge_enable(struct drm_bridge *bridge)
>  	mutex_unlock(&hdmi->mutex);
>  }
>  
> +/*
> + * This function controls clocks of dw_hdmi through drm_bridge
> + * at system suspend/resume.
> + * Arguments:
> + *  bridge: drm_bridge that contains dw_hdmi.
> + *  flag: controlled flag.
> + *		false: is used when suspend.
> + *		true: is used when resume.
> + */
> +void dw_hdmi_s2r_ctrl(struct drm_bridge *bridge, int flag)
> +{
> +	struct dw_hdmi *hdmi = bridge->driver_private;
> +
> +	if (!hdmi)
> +		return;
> +
> +	if (flag) { /* enable clk */
> +		if (hdmi->isfr_clk)
> +			clk_prepare_enable(hdmi->isfr_clk);
> +		if (hdmi->iahb_clk)
> +			clk_prepare_enable(hdmi->iahb_clk);
> +
> +		initialize_hdmi_ih_mutes(hdmi);
> +		dw_hdmi_setup_i2c(hdmi);
> +		dw_hdmi_i2c_init(hdmi);
> +		dw_hdmi_phy_setup_hpd(hdmi, NULL);
> +	} else { /* disable clk */
> +		if (hdmi->isfr_clk)
> +			clk_disable_unprepare(hdmi->isfr_clk);
> +		if (hdmi->iahb_clk)
> +			clk_disable_unprepare(hdmi->iahb_clk);
> +	}
> +}
> +EXPORT_SYMBOL_GPL(dw_hdmi_s2r_ctrl);
> +
>  static const struct drm_bridge_funcs dw_hdmi_bridge_funcs = {
>  	.attach = dw_hdmi_bridge_attach,
>  	.enable = dw_hdmi_bridge_enable,
> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
> index 838b7c9..9eb63b0 100644
> --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
> @@ -21,6 +21,7 @@
>  #include <linux/slab.h>
>  #include <linux/wait.h>
>  
> +#include <drm/bridge/dw_hdmi.h>
>  #include <drm/drmP.h>
>  #include <drm/drm_atomic_helper.h>
>  #include <drm/drm_crtc_helper.h>
> @@ -368,18 +369,14 @@ static struct drm_driver rcar_du_driver = {
>   */
>  
>  #ifdef CONFIG_PM_SLEEP
> -static int rcar_du_pm_suspend(struct device *dev)
> +static int rcar_du_pm_shutdown(struct device *dev)
>  {
>  	struct rcar_du_device *rcdu = dev_get_drvdata(dev);
>  	struct drm_atomic_state *state;
> -	int i;
> -
> -	if (rcar_du_has(rcdu, RCAR_DU_FEATURE_CMM)) {
> -		for (i = 0; i < rcdu->num_crtcs; ++i)
> -			rcar_du_cmm_pm_suspend(&rcdu->crtcs[i]);
> -	}
> -
> -	drm_kms_helper_poll_disable(rcdu->ddev);
> +#if IS_ENABLED(CONFIG_DRM_RCAR_DW_HDMI)
> +	struct drm_encoder *encoder;
> +#endif
> +		drm_kms_helper_poll_disable(rcdu->ddev);
>  	drm_fbdev_cma_set_suspend_unlocked(rcdu->fbdev, true);
>  
>  	state = drm_atomic_helper_suspend(rcdu->ddev);
> @@ -389,11 +386,43 @@ static int rcar_du_pm_suspend(struct device *dev)
>  		return PTR_ERR(state);
>  	}
>  
> +#if IS_ENABLED(CONFIG_DRM_RCAR_DW_HDMI)
> +	list_for_each_entry(encoder,
> +			    &rcdu->ddev->mode_config.encoder_list,
> +			    head) {
> +		struct rcar_du_encoder *renc = to_rcar_encoder(encoder);
> +
> +		if (renc->bridge && (renc->output == RCAR_DU_OUTPUT_HDMI0 ||
> +				     renc->output == RCAR_DU_OUTPUT_HDMI1))
> +			dw_hdmi_s2r_ctrl(encoder->bridge, false);

You can't call directly from the DU driver to the dw-hdmi driver, that's
a big layering violation. As Daniel reported, using the shutdown helper
will likely handle all this for you.

> +	}
> +#endif
>  	rcdu->suspend_state = state;
>  
>  	return 0;
>  }
>  
> +static int rcar_du_pm_suspend(struct device *dev)
> +{
> +	struct rcar_du_device *rcdu = dev_get_drvdata(dev);
> +
> +	int i, ret;
> +
> +	if (rcar_du_has(rcdu, RCAR_DU_FEATURE_CMM)) {
> +		for (i = 0; i < rcdu->num_crtcs; ++i)
> +			rcar_du_cmm_pm_suspend(&rcdu->crtcs[i]);
> +	}
> +
> +	ret = rcar_du_pm_shutdown(dev);
> +
> +	if (ret)
> +		return ret;
> +
> +	for (i = 0; i < rcdu->num_crtcs; ++i)
> +		clk_set_rate(rcdu->crtcs[i].extclock, 0);
> +	return 0;
> +}
> +
>  static int rcar_du_pm_resume(struct device *dev)
>  {
>  	struct rcar_du_device *rcdu = dev_get_drvdata(dev);
> @@ -504,6 +533,12 @@ static int rcar_du_probe(struct platform_device *pdev)
>  	return ret;
>  }
>  
> +static void rcar_du_shutdown(struct platform_device *pdev)
> +{
> +#ifdef CONFIG_PM_SLEEP
> +	rcar_du_pm_shutdown(&pdev->dev);
> +#endif
> +}
>  static struct platform_driver rcar_du_platform_driver = {
>  	.probe		= rcar_du_probe,
>  	.remove		= rcar_du_remove,
> @@ -512,6 +547,7 @@ static struct platform_driver rcar_du_platform_driver = {
>  		.pm	= &rcar_du_pm_ops,
>  		.of_match_table = rcar_du_of_table,
>  	},
> +	.shutdown       = rcar_du_shutdown,
>  };
>  
>  static int __init rcar_du_init(void)
> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_encoder.c b/drivers/gpu/drm/rcar-du/rcar_du_encoder.c
> index f9c933d..98df8a2 100644
> --- a/drivers/gpu/drm/rcar-du/rcar_du_encoder.c
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_encoder.c
> @@ -62,7 +62,7 @@ int rcar_du_encoder_init(struct rcar_du_device *rcdu,
>  
>  	dev_dbg(rcdu->dev, "initializing encoder %pOF for output %u\n",
>  		enc_node, output);
> -
> +	renc->bridge = bridge;
>  	/* Locate the DRM bridge from the encoder DT node. */
>  	bridge = of_drm_find_bridge(enc_node);
>  	if (!bridge) {
> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_encoder.h b/drivers/gpu/drm/rcar-du/rcar_du_encoder.h
> index 2d2abca..cc5bfcb 100644
> --- a/drivers/gpu/drm/rcar-du/rcar_du_encoder.h
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_encoder.h
> @@ -23,6 +23,7 @@ struct rcar_du_device;
>  struct rcar_du_encoder {
>  	struct drm_encoder base;
>  	enum rcar_du_output output;
> +	struct drm_bridge *bridge;
>  };
>  
>  #define to_rcar_encoder(e) \
> diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h
> index ccb5aa8..36383cf4 100644
> --- a/include/drm/bridge/dw_hdmi.h
> +++ b/include/drm/bridge/dw_hdmi.h
> @@ -171,5 +171,6 @@ enum drm_connector_status dw_hdmi_phy_read_hpd(struct dw_hdmi *hdmi,
>  void dw_hdmi_phy_update_hpd(struct dw_hdmi *hdmi, void *data,
>  			    bool force, bool disabled, bool rxsense);
>  void dw_hdmi_phy_setup_hpd(struct dw_hdmi *hdmi, void *data);
> +void dw_hdmi_s2r_ctrl(struct drm_bridge *bridge, int flag);
>  
>  #endif /* __IMX_HDMI_H__ */

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH 5/8] drm: rcar-du: Implement interfaces to set clu and lut using drm data structures
  2019-04-04  7:50   ` Daniel Vetter
@ 2019-04-04 15:40     ` Ville Syrjälä
  2019-04-05  8:39         ` Harsha Manjula Mallikarjun (RBEI/ECF3)
  0 siblings, 1 reply; 36+ messages in thread
From: Ville Syrjälä @ 2019-04-04 15:40 UTC (permalink / raw)
  To: VenkataRajesh.Kalakodima, linux-renesas-soc, devicetree,
	linux-kernel, linux-clk, dri-devel, Harsha M M

On Thu, Apr 04, 2019 at 09:50:47AM +0200, Daniel Vetter wrote:
> On Wed, Apr 03, 2019 at 06:44:41PM +0530, VenkataRajesh.Kalakodima@in.bosch.com wrote:
> > From: kalakodima venkata rajesh <venkatarajesh.kalakodima@in.bosch.com>
> > 
> > Impelement interfaces in cmm to set clu and lut tables using standard
> > drm data structures as input.
> > 
> > Signed-off-by: Harsha M M <harsha.manjulamallikarjun@in.bosch.com>
> > 
> >       - Resolved checkpatch errors
> >       - Resolved merge conflicts according to latest version
> > 
> > Signed-off-by: kalakodima venkata rajesh <venkatarajesh.kalakodima@in.bosch.com>
> > ---
> >  drivers/gpu/drm/rcar-du/rcar_du_cmm.c  | 256 +++++++++++++++++++++++++++++++--
> >  drivers/gpu/drm/rcar-du/rcar_du_crtc.h |  11 ++
> >  2 files changed, 254 insertions(+), 13 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/rcar-du/rcar_du_cmm.c b/drivers/gpu/drm/rcar-du/rcar_du_cmm.c
> > index 7983039..af4668f 100644
> > --- a/drivers/gpu/drm/rcar-du/rcar_du_cmm.c
> > +++ b/drivers/gpu/drm/rcar-du/rcar_du_cmm.c
> > @@ -114,6 +114,8 @@ struct rcar_du_cmm_pending_event {
> >  	struct drm_gem_object *gem_obj;
> >  	struct rcar_du_cmm *du_cmm;
> >  	struct rcar_du_cmm_file_priv *fpriv;
> > +	unsigned int *lut_buf;
> > +	unsigned int *clu_buf;
> >  };
> >  
> >  struct cmm_module_t {
> > @@ -238,14 +240,6 @@ static long long diff_timevals(struct timeval *start, struct timeval *end)
> >  }
> >  #endif
> >  
> > -static void du_cmm_clk(struct rcar_du_cmm *du_cmm, bool on)
> > -{
> > -	if (on)
> > -		clk_prepare_enable(du_cmm->clock);
> > -	else
> > -		clk_disable_unprepare(du_cmm->clock);
> > -}
> > -
> >  static void rcar_du_cmm_queue_lut_update(struct rcar_du_cmm_pending_event *p)
> >  {
> >  	mutex_lock(&cmm_event_lock);
> > @@ -284,6 +278,223 @@ static void rcar_du_cmm_queue_clu_update(struct rcar_du_cmm_pending_event *p)
> >  	drm_crtc_vblank_get(&p->du_cmm->rcrtc->crtc);
> >  }
> >  
> > +static s64 rcar_du_cmm_multiply_coeff(unsigned int color, s64 coeff)
> > +{
> > +	s64 r_val;
> > +	bool is_neg = false;
> > +
> > +	if (coeff & BIT_ULL(63)) {
> > +		is_neg = true;
> > +		coeff &= ~BIT_ULL(63);
> > +	}
> > +
> > +	r_val = DIV_ROUND_CLOSEST(((s64)(color * coeff)), BIT_ULL(32));
> > +
> > +	if (is_neg)
> > +		return -r_val;
> > +
> > +	return r_val;
> > +}
> > +
> > +static unsigned int rcar_du_cmm_scalar_product(unsigned int r, unsigned int g,
> > +					       unsigned int b, s64 coeff1,
> > +					       s64 coeff2, s64 coeff3)
> > +{
> > +	s64 product;
> > +
> > +	product = rcar_du_cmm_multiply_coeff(r, coeff1)
> > +			+ rcar_du_cmm_multiply_coeff(g, coeff2)
> > +			+ rcar_du_cmm_multiply_coeff(b, coeff3);
> > +
> > +	return (unsigned int)clamp_val(product, 0, U8_MAX);
> > +}
> > +
> > +#ifdef DEBUG_PROCE_TIME
> > +static long long diff_timevals(struct timeval *start, struct timeval *end)
> > +{
> > +	return (end->tv_sec * 1000000LL + end->tv_usec) -
> > +		(start->tv_sec * 1000000LL + start->tv_usec);
> > +}
> > +#endif
> > +
> > +void *rcar_du_cmm_alloc_lut(void *cmm_handle)
> > +{
> > +	struct rcar_du_cmm_pending_event *p;
> > +
> > +	if (!cmm_handle)
> > +		return NULL;
> > +
> > +	p = kzalloc(sizeof(*p), GFP_KERNEL);
> > +	if (!p)
> > +		return NULL;
> > +
> > +	p->gem_obj = NULL;
> > +	p->event = CMM_EVENT_LUT_DONE;
> > +	p->stat = QUE_STAT_PENDING;
> > +	p->callback_data = 0;
> > +	p->du_cmm = cmm_handle;
> > +	p->fpriv = NULL;
> > +	p->lut_buf = kmalloc(CMM_LUT_NUM * 4, GFP_KERNEL);
> > +	if (!p->lut_buf) {
> > +		kfree(p);
> > +		return NULL;
> > +	}
> > +
> > +	return p;
> > +}
> > +
> > +void rcar_du_cmm_free_lut(void *lut_handle)
> > +{
> > +	struct rcar_du_cmm_pending_event *p =
> > +			(struct rcar_du_cmm_pending_event *)lut_handle;
> > +
> > +	kfree(p->lut_buf);
> > +	kfree(p);
> > +}
> > +
> > +int rcar_du_cmm_lut_valid(unsigned int lut_length)
> > +{
> > +	return (lut_length == CMM_LUT_NUM) ? 0 : -EINVAL;
> > +}
> > +
> > +void rcar_du_cmm_update_lut_and_free(void *lut_handle,
> > +				     struct drm_color_lut *lut,
> > +				     unsigned int lut_length)
> > +{
> > +	struct rcar_du_cmm_pending_event *p =
> > +			(struct rcar_du_cmm_pending_event *)lut_handle;
> > +	unsigned int color;
> > +
> > +	if (!p)
> > +		return;
> > +
> > +	if (rcar_du_cmm_lut_valid(lut_length))
> > +		return;
> > +
> > +	/* Convert drm_color_lut to the format handled by hardware */
> > +	for (color = 0; color < lut_length; color++) {
> > +		p->lut_buf[color] = 0;
> > +		p->lut_buf[color] |= drm_color_lut_extract(lut[color].red, 8)
> > +					<< 16;
> > +		p->lut_buf[color] |= drm_color_lut_extract(lut[color].green, 8)
> > +					<< 8;
> > +		p->lut_buf[color] |= drm_color_lut_extract(lut[color].blue, 8);
> > +	}
> > +	rcar_du_cmm_queue_lut_update(p);
> > +}
> > +
> > +void *rcar_du_cmm_alloc_clu(void *cmm_handle)
> > +{
> > +	struct rcar_du_cmm_pending_event *p;
> > +
> > +	if (!cmm_handle)
> > +		return NULL;
> > +
> > +	p = kzalloc(sizeof(*p), GFP_KERNEL);
> > +	if (!p)
> > +		return NULL;
> > +
> > +	p->gem_obj = NULL;
> > +	p->event = CMM_EVENT_CLU_DONE;
> > +	p->stat = QUE_STAT_PENDING;
> > +	p->callback_data = 0;
> > +	p->du_cmm = cmm_handle;
> > +	p->fpriv = NULL;
> > +	p->clu_buf = kmalloc(CMM_CLU_NUM * 4, GFP_KERNEL);
> > +	if (!p->clu_buf) {
> > +		kfree(p);
> > +		return NULL;
> > +	}
> > +
> > +	return p;
> > +}
> > +
> > +void rcar_du_cmm_free_clu(void *clu_handle)
> > +{
> > +	struct rcar_du_cmm_pending_event *p =
> > +			(struct rcar_du_cmm_pending_event *)clu_handle;
> > +
> > +	kfree(p->clu_buf);
> > +	kfree(p);
> > +}
> > +
> > +void rcar_du_cmm_update_clu_and_free(void *clu_handle,
> > +				     struct drm_color_ctm *ctm)
> > +{
> > +	struct rcar_du_cmm_pending_event *p =
> > +			(struct rcar_du_cmm_pending_event *)clu_handle;
> > +	unsigned int r_loop;
> > +	unsigned int g_loop;
> > +	unsigned int b_loop;
> > +	unsigned int step_size;
> > +	unsigned int step_fraction;
> > +	unsigned int clu_index = 0;
> > +
> > +	if (!p)
> > +		return;
> > +
> > +	step_size = U8_MAX / (CMM_CLU_SAMPLES - 1);
> > +	step_fraction = U8_MAX % (CMM_CLU_SAMPLES - 1);
> > +
> > +	/*Update clu table*/
> > +	for (b_loop = 0; b_loop < CMM_CLU_SAMPLES; b_loop++) {
> > +		unsigned int b;
> > +
> > +		b = (b_loop * step_size) +
> > +		    DIV_ROUND_CLOSEST((b_loop * step_fraction),
> > +				      (CMM_CLU_SAMPLES - 1));
> > +
> > +		for (g_loop = 0; g_loop < CMM_CLU_SAMPLES; g_loop++) {
> > +			unsigned int g;
> > +
> > +			g = (g_loop * step_size) +
> > +			    DIV_ROUND_CLOSEST((g_loop * step_fraction),
> > +					      (CMM_CLU_SAMPLES - 1));
> > +
> > +			for (r_loop = 0; r_loop < CMM_CLU_SAMPLES; r_loop++) {
> > +				unsigned int r;
> > +				unsigned int r_val;
> > +				unsigned int g_val;
> > +				unsigned int b_val;
> > +
> > +				r = (r_loop * step_size) +
> > +				    DIV_ROUND_CLOSEST((r_loop * step_fraction),
> > +						      (CMM_CLU_SAMPLES - 1));
> > +
> > +				p->clu_buf[clu_index] = 0;
> > +
> > +				r_val =	rcar_du_cmm_scalar_product
> > +						(r, g, b,
> > +						 ctm->matrix[0], ctm->matrix[1],
> > +						 ctm->matrix[2]);
> > +
> > +				g_val =	rcar_du_cmm_scalar_product
> > +						(r, g, b,
> > +						 ctm->matrix[3], ctm->matrix[4],
> > +						 ctm->matrix[5]);
> > +
> > +				b_val =	rcar_du_cmm_scalar_product
> > +						(r, g, b,
> > +						 ctm->matrix[6], ctm->matrix[7],
> > +						 ctm->matrix[8]);
> > +
> > +				p->clu_buf[clu_index++] = (r_val << 16) |
> > +							  (g_val << 8) | b_val;
> > +			}
> > +		}
> > +	}
> > +
> > +	rcar_du_cmm_queue_clu_update(p);
> > +}
> 
> Just quick drive-by: I think there's some interested (definitely from
> intel, I pinged the relevant people from our team) to expose a 3D LUT
> directly to userspace. I'm not sure whether we can do both 3D-LUT and
> color matrix, and I'm also not sure whether remapping the ctm to a 3d-lut
> is the best thing to do. Otoh adding new uapi is always a bunch more work.

We're already thinking about extending the uapi a bit, so I
don't think including a 3D LUT in there would be too hard.

Couple of things we'd need to figure out:
- is a single 3D LUT attachment point sufficient? On our hw I
  believe the 3D LUT sits after the gamma LUT in the pipeline
- is a cube sufficient or would some hardware have different
  number of entries for each dimension (not sure why that would be)?
- need to agree in which order the entries would be stored in the
  blob
- and of course the big question: is anyone going to work on
  userspace that would make use of this?

-- 
Ville Syrjälä
Intel

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

* RE: [PATCH 5/8] drm: rcar-du: Implement interfaces to set clu and lut using drm data structures
  2019-04-04 15:40     ` Ville Syrjälä
@ 2019-04-05  8:39         ` Harsha Manjula Mallikarjun (RBEI/ECF3)
  0 siblings, 0 replies; 36+ messages in thread
From: Harsha Manjula Mallikarjun (RBEI/ECF3) @ 2019-04-05  8:39 UTC (permalink / raw)
  To: Ville Syrjälä, Kalakodima Venkata Rajesh (RBEI/ECF3),
	linux-renesas-soc, devicetree, linux-kernel, linux-clk,
	dri-devel
  Cc: Friedrich Eugen (ADITG/ESB), Ucan Ahmet Emre (ADITG/ESB)

> 
> On Thu, Apr 04, 2019 at 09:50:47AM +0200, Daniel Vetter wrote:
> > On Wed, Apr 03, 2019 at 06:44:41PM +0530,
> VenkataRajesh.Kalakodima@in.bosch.com wrote:
> > > From: kalakodima venkata rajesh
> > > <venkatarajesh.kalakodima@in.bosch.com>
> > >
> > > Impelement interfaces in cmm to set clu and lut tables using
> > > standard drm data structures as input.
> > >
> > > Signed-off-by: Harsha M M <harsha.manjulamallikarjun@in.bosch.com>
> > >
> > >       - Resolved checkpatch errors
> > >       - Resolved merge conflicts according to latest version
> > >
> > > Signed-off-by: kalakodima venkata rajesh
> > > <venkatarajesh.kalakodima@in.bosch.com>
> > > ---
> > >  drivers/gpu/drm/rcar-du/rcar_du_cmm.c  | 256
> > > +++++++++++++++++++++++++++++++--
> > > drivers/gpu/drm/rcar-du/rcar_du_crtc.h |  11 ++
> > >  2 files changed, 254 insertions(+), 13 deletions(-)
> > >
> > > diff --git a/drivers/gpu/drm/rcar-du/rcar_du_cmm.c
> > > b/drivers/gpu/drm/rcar-du/rcar_du_cmm.c
> > > index 7983039..af4668f 100644
> > > --- a/drivers/gpu/drm/rcar-du/rcar_du_cmm.c
> > > +++ b/drivers/gpu/drm/rcar-du/rcar_du_cmm.c
> > > @@ -114,6 +114,8 @@ struct rcar_du_cmm_pending_event {
> > >  	struct drm_gem_object *gem_obj;
> > >  	struct rcar_du_cmm *du_cmm;
> > >  	struct rcar_du_cmm_file_priv *fpriv;
> > > +	unsigned int *lut_buf;
> > > +	unsigned int *clu_buf;
> > >  };
> > >
> > >  struct cmm_module_t {
> > > @@ -238,14 +240,6 @@ static long long diff_timevals(struct timeval
> > > *start, struct timeval *end)  }  #endif
> > >
> > > -static void du_cmm_clk(struct rcar_du_cmm *du_cmm, bool on) -{
> > > -	if (on)
> > > -		clk_prepare_enable(du_cmm->clock);
> > > -	else
> > > -		clk_disable_unprepare(du_cmm->clock);
> > > -}
> > > -
> > >  static void rcar_du_cmm_queue_lut_update(struct
> > > rcar_du_cmm_pending_event *p)  {
> > >  	mutex_lock(&cmm_event_lock);
> > > @@ -284,6 +278,223 @@ static void rcar_du_cmm_queue_clu_update(struct
> rcar_du_cmm_pending_event *p)
> > >  	drm_crtc_vblank_get(&p->du_cmm->rcrtc->crtc);
> > >  }
> > >
> > > +static s64 rcar_du_cmm_multiply_coeff(unsigned int color, s64
> > > +coeff) {
> > > +	s64 r_val;
> > > +	bool is_neg = false;
> > > +
> > > +	if (coeff & BIT_ULL(63)) {
> > > +		is_neg = true;
> > > +		coeff &= ~BIT_ULL(63);
> > > +	}
> > > +
> > > +	r_val = DIV_ROUND_CLOSEST(((s64)(color * coeff)), BIT_ULL(32));
> > > +
> > > +	if (is_neg)
> > > +		return -r_val;
> > > +
> > > +	return r_val;
> > > +}
> > > +
> > > +static unsigned int rcar_du_cmm_scalar_product(unsigned int r, unsigned int
> g,
> > > +					       unsigned int b, s64 coeff1,
> > > +					       s64 coeff2, s64 coeff3) {
> > > +	s64 product;
> > > +
> > > +	product = rcar_du_cmm_multiply_coeff(r, coeff1)
> > > +			+ rcar_du_cmm_multiply_coeff(g, coeff2)
> > > +			+ rcar_du_cmm_multiply_coeff(b, coeff3);
> > > +
> > > +	return (unsigned int)clamp_val(product, 0, U8_MAX); }
> > > +
> > > +#ifdef DEBUG_PROCE_TIME
> > > +static long long diff_timevals(struct timeval *start, struct
> > > +timeval *end) {
> > > +	return (end->tv_sec * 1000000LL + end->tv_usec) -
> > > +		(start->tv_sec * 1000000LL + start->tv_usec); } #endif
> > > +
> > > +void *rcar_du_cmm_alloc_lut(void *cmm_handle) {
> > > +	struct rcar_du_cmm_pending_event *p;
> > > +
> > > +	if (!cmm_handle)
> > > +		return NULL;
> > > +
> > > +	p = kzalloc(sizeof(*p), GFP_KERNEL);
> > > +	if (!p)
> > > +		return NULL;
> > > +
> > > +	p->gem_obj = NULL;
> > > +	p->event = CMM_EVENT_LUT_DONE;
> > > +	p->stat = QUE_STAT_PENDING;
> > > +	p->callback_data = 0;
> > > +	p->du_cmm = cmm_handle;
> > > +	p->fpriv = NULL;
> > > +	p->lut_buf = kmalloc(CMM_LUT_NUM * 4, GFP_KERNEL);
> > > +	if (!p->lut_buf) {
> > > +		kfree(p);
> > > +		return NULL;
> > > +	}
> > > +
> > > +	return p;
> > > +}
> > > +
> > > +void rcar_du_cmm_free_lut(void *lut_handle) {
> > > +	struct rcar_du_cmm_pending_event *p =
> > > +			(struct rcar_du_cmm_pending_event *)lut_handle;
> > > +
> > > +	kfree(p->lut_buf);
> > > +	kfree(p);
> > > +}
> > > +
> > > +int rcar_du_cmm_lut_valid(unsigned int lut_length) {
> > > +	return (lut_length == CMM_LUT_NUM) ? 0 : -EINVAL; }
> > > +
> > > +void rcar_du_cmm_update_lut_and_free(void *lut_handle,
> > > +				     struct drm_color_lut *lut,
> > > +				     unsigned int lut_length)
> > > +{
> > > +	struct rcar_du_cmm_pending_event *p =
> > > +			(struct rcar_du_cmm_pending_event *)lut_handle;
> > > +	unsigned int color;
> > > +
> > > +	if (!p)
> > > +		return;
> > > +
> > > +	if (rcar_du_cmm_lut_valid(lut_length))
> > > +		return;
> > > +
> > > +	/* Convert drm_color_lut to the format handled by hardware */
> > > +	for (color = 0; color < lut_length; color++) {
> > > +		p->lut_buf[color] = 0;
> > > +		p->lut_buf[color] |= drm_color_lut_extract(lut[color].red, 8)
> > > +					<< 16;
> > > +		p->lut_buf[color] |= drm_color_lut_extract(lut[color].green, 8)
> > > +					<< 8;
> > > +		p->lut_buf[color] |= drm_color_lut_extract(lut[color].blue, 8);
> > > +	}
> > > +	rcar_du_cmm_queue_lut_update(p);
> > > +}
> > > +
> > > +void *rcar_du_cmm_alloc_clu(void *cmm_handle) {
> > > +	struct rcar_du_cmm_pending_event *p;
> > > +
> > > +	if (!cmm_handle)
> > > +		return NULL;
> > > +
> > > +	p = kzalloc(sizeof(*p), GFP_KERNEL);
> > > +	if (!p)
> > > +		return NULL;
> > > +
> > > +	p->gem_obj = NULL;
> > > +	p->event = CMM_EVENT_CLU_DONE;
> > > +	p->stat = QUE_STAT_PENDING;
> > > +	p->callback_data = 0;
> > > +	p->du_cmm = cmm_handle;
> > > +	p->fpriv = NULL;
> > > +	p->clu_buf = kmalloc(CMM_CLU_NUM * 4, GFP_KERNEL);
> > > +	if (!p->clu_buf) {
> > > +		kfree(p);
> > > +		return NULL;
> > > +	}
> > > +
> > > +	return p;
> > > +}
> > > +
> > > +void rcar_du_cmm_free_clu(void *clu_handle) {
> > > +	struct rcar_du_cmm_pending_event *p =
> > > +			(struct rcar_du_cmm_pending_event *)clu_handle;
> > > +
> > > +	kfree(p->clu_buf);
> > > +	kfree(p);
> > > +}
> > > +
> > > +void rcar_du_cmm_update_clu_and_free(void *clu_handle,
> > > +				     struct drm_color_ctm *ctm) {
> > > +	struct rcar_du_cmm_pending_event *p =
> > > +			(struct rcar_du_cmm_pending_event *)clu_handle;
> > > +	unsigned int r_loop;
> > > +	unsigned int g_loop;
> > > +	unsigned int b_loop;
> > > +	unsigned int step_size;
> > > +	unsigned int step_fraction;
> > > +	unsigned int clu_index = 0;
> > > +
> > > +	if (!p)
> > > +		return;
> > > +
> > > +	step_size = U8_MAX / (CMM_CLU_SAMPLES - 1);
> > > +	step_fraction = U8_MAX % (CMM_CLU_SAMPLES - 1);
> > > +
> > > +	/*Update clu table*/
> > > +	for (b_loop = 0; b_loop < CMM_CLU_SAMPLES; b_loop++) {
> > > +		unsigned int b;
> > > +
> > > +		b = (b_loop * step_size) +
> > > +		    DIV_ROUND_CLOSEST((b_loop * step_fraction),
> > > +				      (CMM_CLU_SAMPLES - 1));
> > > +
> > > +		for (g_loop = 0; g_loop < CMM_CLU_SAMPLES; g_loop++) {
> > > +			unsigned int g;
> > > +
> > > +			g = (g_loop * step_size) +
> > > +			    DIV_ROUND_CLOSEST((g_loop * step_fraction),
> > > +					      (CMM_CLU_SAMPLES - 1));
> > > +
> > > +			for (r_loop = 0; r_loop < CMM_CLU_SAMPLES; r_loop++)
> {
> > > +				unsigned int r;
> > > +				unsigned int r_val;
> > > +				unsigned int g_val;
> > > +				unsigned int b_val;
> > > +
> > > +				r = (r_loop * step_size) +
> > > +				    DIV_ROUND_CLOSEST((r_loop *
> step_fraction),
> > > +						      (CMM_CLU_SAMPLES - 1));
> > > +
> > > +				p->clu_buf[clu_index] = 0;
> > > +
> > > +				r_val =	rcar_du_cmm_scalar_product
> > > +						(r, g, b,
> > > +						 ctm->matrix[0], ctm->matrix[1],
> > > +						 ctm->matrix[2]);
> > > +
> > > +				g_val =	rcar_du_cmm_scalar_product
> > > +						(r, g, b,
> > > +						 ctm->matrix[3], ctm->matrix[4],
> > > +						 ctm->matrix[5]);
> > > +
> > > +				b_val =	rcar_du_cmm_scalar_product
> > > +						(r, g, b,
> > > +						 ctm->matrix[6], ctm->matrix[7],
> > > +						 ctm->matrix[8]);
> > > +
> > > +				p->clu_buf[clu_index++] = (r_val << 16) |
> > > +							  (g_val << 8) | b_val;
> > > +			}
> > > +		}
> > > +	}
> > > +
> > > +	rcar_du_cmm_queue_clu_update(p);
> > > +}
> >
> > Just quick drive-by: I think there's some interested (definitely from
> > intel, I pinged the relevant people from our team) to expose a 3D LUT
> > directly to userspace. 
[Harsha Manjula Mallikarjun (RBEI/ECF3)] 
Thanks Daniel for mentioning this.
>> I'm not sure whether we can do both 3D-LUT and
> > color matrix, and I'm also not sure whether remapping the ctm to a
> > 3d-lut is the best thing to do.
[Harsha Manjula Mallikarjun (RBEI/ECF3)] : 
It is not the best thing to do compared to the HW (e.g. i.Mx6) which readily supports CTM matrix.
Also remapping limits the flexibility with which user space can make use of 3D LUT.
Our use case was to apply hue, saturation and brightness properties to display out.
Conversion between RGB and HSV color space is non-linear. However, a close linear approximation
can be done and this can be applied via CTM. I do not know about other use cases where
3D LUT can be made use of.

>> Otoh adding new uapi is always a bunch more
[Harsha Manjula Mallikarjun (RBEI/ECF3)] 
I think adding a 3D LUT property blob, is better than re-mapping. Then user space can make full use of it.

> work.
> 
> We're already thinking about extending the uapi a bit, so I don't think including a
> 3D LUT in there would be too hard.
> 
> Couple of things we'd need to figure out:
> - is a single 3D LUT attachment point sufficient? On our hw I
>   believe the 3D LUT sits after the gamma LUT in the pipeline
> - is a cube sufficient or would some hardware have different
>   number of entries for each dimension (not sure why that would be)?
> - need to agree in which order the entries would be stored in the
>   blob
> - and of course the big question: is anyone going to work on
>   userspace that would make use of this?
> 
[Harsha Manjula Mallikarjun (RBEI/ECF3)] 
Following patch adds CTM support to Weston. I am planning to fix review comments. 
https://patchwork.freedesktop.org/patch/233391/
If 3D LUT interface is available, similar support can be added in Weston. If CTM is not supported,
Instead 3D LUT is supported, similar functionality can be realized using 3D LUT. User space can
decide this.

> --
> Ville Syrjälä
> Intel

Regards,
Harsha

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

* RE: [PATCH 5/8] drm: rcar-du: Implement interfaces to set clu and lut using drm data structures
@ 2019-04-05  8:39         ` Harsha Manjula Mallikarjun (RBEI/ECF3)
  0 siblings, 0 replies; 36+ messages in thread
From: Harsha Manjula Mallikarjun (RBEI/ECF3) @ 2019-04-05  8:39 UTC (permalink / raw)
  To: Ville Syrjälä, Kalakodima Venkata Rajesh (RBEI/ECF3),
	linux-renesas-soc, devicetree, linux-kernel, linux-clk,
	dri-devel
  Cc: Friedrich Eugen (ADITG/ESB), Ucan Ahmet Emre (ADITG/ESB)

> 
> On Thu, Apr 04, 2019 at 09:50:47AM +0200, Daniel Vetter wrote:
> > On Wed, Apr 03, 2019 at 06:44:41PM +0530,
> VenkataRajesh.Kalakodima@in.bosch.com wrote:
> > > From: kalakodima venkata rajesh
> > > <venkatarajesh.kalakodima@in.bosch.com>
> > >
> > > Impelement interfaces in cmm to set clu and lut tables using
> > > standard drm data structures as input.
> > >
> > > Signed-off-by: Harsha M M <harsha.manjulamallikarjun@in.bosch.com>
> > >
> > >       - Resolved checkpatch errors
> > >       - Resolved merge conflicts according to latest version
> > >
> > > Signed-off-by: kalakodima venkata rajesh
> > > <venkatarajesh.kalakodima@in.bosch.com>
> > > ---
> > >  drivers/gpu/drm/rcar-du/rcar_du_cmm.c  | 256
> > > +++++++++++++++++++++++++++++++--
> > > drivers/gpu/drm/rcar-du/rcar_du_crtc.h |  11 ++
> > >  2 files changed, 254 insertions(+), 13 deletions(-)
> > >
> > > diff --git a/drivers/gpu/drm/rcar-du/rcar_du_cmm.c
> > > b/drivers/gpu/drm/rcar-du/rcar_du_cmm.c
> > > index 7983039..af4668f 100644
> > > --- a/drivers/gpu/drm/rcar-du/rcar_du_cmm.c
> > > +++ b/drivers/gpu/drm/rcar-du/rcar_du_cmm.c
> > > @@ -114,6 +114,8 @@ struct rcar_du_cmm_pending_event {
> > >  	struct drm_gem_object *gem_obj;
> > >  	struct rcar_du_cmm *du_cmm;
> > >  	struct rcar_du_cmm_file_priv *fpriv;
> > > +	unsigned int *lut_buf;
> > > +	unsigned int *clu_buf;
> > >  };
> > >
> > >  struct cmm_module_t {
> > > @@ -238,14 +240,6 @@ static long long diff_timevals(struct timeval
> > > *start, struct timeval *end)  }  #endif
> > >
> > > -static void du_cmm_clk(struct rcar_du_cmm *du_cmm, bool on) -{
> > > -	if (on)
> > > -		clk_prepare_enable(du_cmm->clock);
> > > -	else
> > > -		clk_disable_unprepare(du_cmm->clock);
> > > -}
> > > -
> > >  static void rcar_du_cmm_queue_lut_update(struct
> > > rcar_du_cmm_pending_event *p)  {
> > >  	mutex_lock(&cmm_event_lock);
> > > @@ -284,6 +278,223 @@ static void rcar_du_cmm_queue_clu_update(struct
> rcar_du_cmm_pending_event *p)
> > >  	drm_crtc_vblank_get(&p->du_cmm->rcrtc->crtc);
> > >  }
> > >
> > > +static s64 rcar_du_cmm_multiply_coeff(unsigned int color, s64
> > > +coeff) {
> > > +	s64 r_val;
> > > +	bool is_neg = false;
> > > +
> > > +	if (coeff & BIT_ULL(63)) {
> > > +		is_neg = true;
> > > +		coeff &= ~BIT_ULL(63);
> > > +	}
> > > +
> > > +	r_val = DIV_ROUND_CLOSEST(((s64)(color * coeff)), BIT_ULL(32));
> > > +
> > > +	if (is_neg)
> > > +		return -r_val;
> > > +
> > > +	return r_val;
> > > +}
> > > +
> > > +static unsigned int rcar_du_cmm_scalar_product(unsigned int r, unsigned int
> g,
> > > +					       unsigned int b, s64 coeff1,
> > > +					       s64 coeff2, s64 coeff3) {
> > > +	s64 product;
> > > +
> > > +	product = rcar_du_cmm_multiply_coeff(r, coeff1)
> > > +			+ rcar_du_cmm_multiply_coeff(g, coeff2)
> > > +			+ rcar_du_cmm_multiply_coeff(b, coeff3);
> > > +
> > > +	return (unsigned int)clamp_val(product, 0, U8_MAX); }
> > > +
> > > +#ifdef DEBUG_PROCE_TIME
> > > +static long long diff_timevals(struct timeval *start, struct
> > > +timeval *end) {
> > > +	return (end->tv_sec * 1000000LL + end->tv_usec) -
> > > +		(start->tv_sec * 1000000LL + start->tv_usec); } #endif
> > > +
> > > +void *rcar_du_cmm_alloc_lut(void *cmm_handle) {
> > > +	struct rcar_du_cmm_pending_event *p;
> > > +
> > > +	if (!cmm_handle)
> > > +		return NULL;
> > > +
> > > +	p = kzalloc(sizeof(*p), GFP_KERNEL);
> > > +	if (!p)
> > > +		return NULL;
> > > +
> > > +	p->gem_obj = NULL;
> > > +	p->event = CMM_EVENT_LUT_DONE;
> > > +	p->stat = QUE_STAT_PENDING;
> > > +	p->callback_data = 0;
> > > +	p->du_cmm = cmm_handle;
> > > +	p->fpriv = NULL;
> > > +	p->lut_buf = kmalloc(CMM_LUT_NUM * 4, GFP_KERNEL);
> > > +	if (!p->lut_buf) {
> > > +		kfree(p);
> > > +		return NULL;
> > > +	}
> > > +
> > > +	return p;
> > > +}
> > > +
> > > +void rcar_du_cmm_free_lut(void *lut_handle) {
> > > +	struct rcar_du_cmm_pending_event *p =
> > > +			(struct rcar_du_cmm_pending_event *)lut_handle;
> > > +
> > > +	kfree(p->lut_buf);
> > > +	kfree(p);
> > > +}
> > > +
> > > +int rcar_du_cmm_lut_valid(unsigned int lut_length) {
> > > +	return (lut_length == CMM_LUT_NUM) ? 0 : -EINVAL; }
> > > +
> > > +void rcar_du_cmm_update_lut_and_free(void *lut_handle,
> > > +				     struct drm_color_lut *lut,
> > > +				     unsigned int lut_length)
> > > +{
> > > +	struct rcar_du_cmm_pending_event *p =
> > > +			(struct rcar_du_cmm_pending_event *)lut_handle;
> > > +	unsigned int color;
> > > +
> > > +	if (!p)
> > > +		return;
> > > +
> > > +	if (rcar_du_cmm_lut_valid(lut_length))
> > > +		return;
> > > +
> > > +	/* Convert drm_color_lut to the format handled by hardware */
> > > +	for (color = 0; color < lut_length; color++) {
> > > +		p->lut_buf[color] = 0;
> > > +		p->lut_buf[color] |= drm_color_lut_extract(lut[color].red, 8)
> > > +					<< 16;
> > > +		p->lut_buf[color] |= drm_color_lut_extract(lut[color].green, 8)
> > > +					<< 8;
> > > +		p->lut_buf[color] |= drm_color_lut_extract(lut[color].blue, 8);
> > > +	}
> > > +	rcar_du_cmm_queue_lut_update(p);
> > > +}
> > > +
> > > +void *rcar_du_cmm_alloc_clu(void *cmm_handle) {
> > > +	struct rcar_du_cmm_pending_event *p;
> > > +
> > > +	if (!cmm_handle)
> > > +		return NULL;
> > > +
> > > +	p = kzalloc(sizeof(*p), GFP_KERNEL);
> > > +	if (!p)
> > > +		return NULL;
> > > +
> > > +	p->gem_obj = NULL;
> > > +	p->event = CMM_EVENT_CLU_DONE;
> > > +	p->stat = QUE_STAT_PENDING;
> > > +	p->callback_data = 0;
> > > +	p->du_cmm = cmm_handle;
> > > +	p->fpriv = NULL;
> > > +	p->clu_buf = kmalloc(CMM_CLU_NUM * 4, GFP_KERNEL);
> > > +	if (!p->clu_buf) {
> > > +		kfree(p);
> > > +		return NULL;
> > > +	}
> > > +
> > > +	return p;
> > > +}
> > > +
> > > +void rcar_du_cmm_free_clu(void *clu_handle) {
> > > +	struct rcar_du_cmm_pending_event *p =
> > > +			(struct rcar_du_cmm_pending_event *)clu_handle;
> > > +
> > > +	kfree(p->clu_buf);
> > > +	kfree(p);
> > > +}
> > > +
> > > +void rcar_du_cmm_update_clu_and_free(void *clu_handle,
> > > +				     struct drm_color_ctm *ctm) {
> > > +	struct rcar_du_cmm_pending_event *p =
> > > +			(struct rcar_du_cmm_pending_event *)clu_handle;
> > > +	unsigned int r_loop;
> > > +	unsigned int g_loop;
> > > +	unsigned int b_loop;
> > > +	unsigned int step_size;
> > > +	unsigned int step_fraction;
> > > +	unsigned int clu_index = 0;
> > > +
> > > +	if (!p)
> > > +		return;
> > > +
> > > +	step_size = U8_MAX / (CMM_CLU_SAMPLES - 1);
> > > +	step_fraction = U8_MAX % (CMM_CLU_SAMPLES - 1);
> > > +
> > > +	/*Update clu table*/
> > > +	for (b_loop = 0; b_loop < CMM_CLU_SAMPLES; b_loop++) {
> > > +		unsigned int b;
> > > +
> > > +		b = (b_loop * step_size) +
> > > +		    DIV_ROUND_CLOSEST((b_loop * step_fraction),
> > > +				      (CMM_CLU_SAMPLES - 1));
> > > +
> > > +		for (g_loop = 0; g_loop < CMM_CLU_SAMPLES; g_loop++) {
> > > +			unsigned int g;
> > > +
> > > +			g = (g_loop * step_size) +
> > > +			    DIV_ROUND_CLOSEST((g_loop * step_fraction),
> > > +					      (CMM_CLU_SAMPLES - 1));
> > > +
> > > +			for (r_loop = 0; r_loop < CMM_CLU_SAMPLES; r_loop++)
> {
> > > +				unsigned int r;
> > > +				unsigned int r_val;
> > > +				unsigned int g_val;
> > > +				unsigned int b_val;
> > > +
> > > +				r = (r_loop * step_size) +
> > > +				    DIV_ROUND_CLOSEST((r_loop *
> step_fraction),
> > > +						      (CMM_CLU_SAMPLES - 1));
> > > +
> > > +				p->clu_buf[clu_index] = 0;
> > > +
> > > +				r_val =	rcar_du_cmm_scalar_product
> > > +						(r, g, b,
> > > +						 ctm->matrix[0], ctm->matrix[1],
> > > +						 ctm->matrix[2]);
> > > +
> > > +				g_val =	rcar_du_cmm_scalar_product
> > > +						(r, g, b,
> > > +						 ctm->matrix[3], ctm->matrix[4],
> > > +						 ctm->matrix[5]);
> > > +
> > > +				b_val =	rcar_du_cmm_scalar_product
> > > +						(r, g, b,
> > > +						 ctm->matrix[6], ctm->matrix[7],
> > > +						 ctm->matrix[8]);
> > > +
> > > +				p->clu_buf[clu_index++] = (r_val << 16) |
> > > +							  (g_val << 8) | b_val;
> > > +			}
> > > +		}
> > > +	}
> > > +
> > > +	rcar_du_cmm_queue_clu_update(p);
> > > +}
> >
> > Just quick drive-by: I think there's some interested (definitely from
> > intel, I pinged the relevant people from our team) to expose a 3D LUT
> > directly to userspace. 
[Harsha Manjula Mallikarjun (RBEI/ECF3)] 
Thanks Daniel for mentioning this.
>> I'm not sure whether we can do both 3D-LUT and
> > color matrix, and I'm also not sure whether remapping the ctm to a
> > 3d-lut is the best thing to do.
[Harsha Manjula Mallikarjun (RBEI/ECF3)] : 
It is not the best thing to do compared to the HW (e.g. i.Mx6) which readily supports CTM matrix.
Also remapping limits the flexibility with which user space can make use of 3D LUT.
Our use case was to apply hue, saturation and brightness properties to display out.
Conversion between RGB and HSV color space is non-linear. However, a close linear approximation
can be done and this can be applied via CTM. I do not know about other use cases where
3D LUT can be made use of.

>> Otoh adding new uapi is always a bunch more
[Harsha Manjula Mallikarjun (RBEI/ECF3)] 
I think adding a 3D LUT property blob, is better than re-mapping. Then user space can make full use of it.

> work.
> 
> We're already thinking about extending the uapi a bit, so I don't think including a
> 3D LUT in there would be too hard.
> 
> Couple of things we'd need to figure out:
> - is a single 3D LUT attachment point sufficient? On our hw I
>   believe the 3D LUT sits after the gamma LUT in the pipeline
> - is a cube sufficient or would some hardware have different
>   number of entries for each dimension (not sure why that would be)?
> - need to agree in which order the entries would be stored in the
>   blob
> - and of course the big question: is anyone going to work on
>   userspace that would make use of this?
> 
[Harsha Manjula Mallikarjun (RBEI/ECF3)] 
Following patch adds CTM support to Weston. I am planning to fix review comments. 
https://patchwork.freedesktop.org/patch/233391/
If 3D LUT interface is available, similar support can be added in Weston. If CTM is not supported,
Instead 3D LUT is supported, similar functionality can be realized using 3D LUT. User space can
decide this.

> --
> Ville Syrjälä
> Intel

Regards,
Harsha

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

end of thread, other threads:[~2019-04-05  8:39 UTC | newest]

Thread overview: 36+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-04-03 13:14 [PATCH 0/8] v4.19.0 Added Color Management Module VenkataRajesh.Kalakodima
2019-04-03 13:14 ` VenkataRajesh.Kalakodima
2019-04-03 13:14 ` [PATCH 1/8] drm: Add DU CMM support functions VenkataRajesh.Kalakodima
2019-04-03 13:14   ` VenkataRajesh.Kalakodima
2019-04-04 10:09   ` Laurent Pinchart
2019-04-04 10:09     ` Laurent Pinchart
2019-04-03 13:14 ` [PATCH 2/8] drm: Add DU CMM support boot and clk changes VenkataRajesh.Kalakodima
2019-04-03 13:14   ` VenkataRajesh.Kalakodima
2019-04-04 10:12   ` Laurent Pinchart
2019-04-03 13:14 ` [PATCH 3/8] drm: rcar-du: Give a name to clu table samples VenkataRajesh.Kalakodima
2019-04-03 13:14   ` VenkataRajesh.Kalakodima
2019-04-04 10:15   ` Laurent Pinchart
2019-04-03 13:14 ` [PATCH 4/8] drm: rcar-du: Refactor the code with new functions VenkataRajesh.Kalakodima
2019-04-03 13:14   ` VenkataRajesh.Kalakodima
2019-04-03 13:14 ` [PATCH 5/8] drm: rcar-du: Implement interfaces to set clu and lut using drm data structures VenkataRajesh.Kalakodima
2019-04-03 13:14   ` VenkataRajesh.Kalakodima
2019-04-04  7:50   ` Daniel Vetter
2019-04-04 15:40     ` Ville Syrjälä
2019-04-05  8:39       ` Harsha Manjula Mallikarjun (RBEI/ECF3)
2019-04-05  8:39         ` Harsha Manjula Mallikarjun (RBEI/ECF3)
2019-04-03 13:14 ` [PATCH 6/8] drm: rcar-du: Implement atomic_check to check for gamma and ctm properties VenkataRajesh.Kalakodima
2019-04-03 13:14   ` VenkataRajesh.Kalakodima
2019-04-03 13:14 ` [PATCH 7/8] drm: rcar-du: update gamma and ctm properties in commit tail VenkataRajesh.Kalakodima
2019-04-03 13:14   ` VenkataRajesh.Kalakodima
2019-04-04 10:19   ` Laurent Pinchart
2019-04-04 10:19     ` Laurent Pinchart
2019-04-03 13:14 ` [PATCH 8/8] drm: rcar-du: Add shutdown callback function in platform_driver VenkataRajesh.Kalakodima
2019-04-03 13:14   ` VenkataRajesh.Kalakodima
2019-04-04  7:47   ` Daniel Vetter
2019-04-04  7:47     ` Daniel Vetter
2019-04-04 10:26   ` Laurent Pinchart
2019-04-04 10:26     ` Laurent Pinchart
2019-04-04  9:45 ` [PATCH 0/8] v4.19.0 Added Color Management Module Laurent Pinchart
2019-04-04  9:45   ` Laurent Pinchart
2019-04-04  9:46   ` Laurent Pinchart
2019-04-04  9:46     ` Laurent Pinchart

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.