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
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/2d8ea2b667ad4616aa639c54ecc11f...
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
Hi Kalakodima,
Thank you for the patch.
On Wed, Apr 03, 2019 at 06:44:37PM +0530, VenkataRajesh.Kalakodima@in.bosch.com wrote:
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.
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.
drmP.h is deprecated, please include the DRM headers you need directly.
Please sort headers alphabetically, with the linux/ headers first, then drm/, then the local headers.
Please remove all commented-out code.
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.
I don't know what this is for, but a pid_t field here is most probably a sign that something is wrong.
No global variables please.
And no forward declarations for functions when possible.
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.
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.
I think you need to figure out all the places where you pulled in BSP code completely unrelated to the series :-)
The last define is not used here, and clearly unrelated to this patch series. I think the series needs major cleanup.
There's already a way in the driver to count CRTCs, no need to duplicate this in the rcar_du_device_info structure.
Why do you need an alias here (and for CM2_CTL1 below) ?
No need for parentheses. Hex constants in the DU code base use lowercase.
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.
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.
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/2d8ea2b667ad4616aa639c54ecc11f...
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)),
Hello Kalakodima,
Thank you for the patch.
On Wed, Apr 03, 2019 at 06:44:38PM +0530, VenkataRajesh.Kalakodima@in.bosch.com wrote:
As for patch 1/8, and all other patches in this series, the commit message needs an overhaul.
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.
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.
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/53973b806881ed8f54500b0d42bdc4...
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;
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
- 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;
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);
On Wed, Apr 03, 2019 at 06:44:41PM +0530, VenkataRajesh.Kalakodima@in.bosch.com wrote:
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
On Thu, Apr 04, 2019 at 09:50:47AM +0200, Daniel Vetter wrote:
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)] Thanks Daniel for mentioning this.
[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.
[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.
Regards, Harsha
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)
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
Hi Kalakodima,
Thank you for the patch.
On Wed, Apr 03, 2019 at 06:44:43PM +0530, VenkataRajesh.Kalakodima@in.bosch.com wrote:
We're in the process of reworking the commit tail handler, so I expect major changes will be needed here.
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.
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/9a65d02119e4ae405a89a850463a6a...
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__ */
On Wed, Apr 03, 2019 at 06:44:44PM +0530, VenkataRajesh.Kalakodima@in.bosch.com wrote:
Maybe look into drm_atomic_helper_shutdown instead of hand-rolling? That should disable all display related stuff for you. -Daniel
Hi Kalakodima,
Thank you for the patch.
On Wed, Apr 03, 2019 at 06:44:44PM +0530, VenkataRajesh.Kalakodima@in.bosch.com wrote:
This seems like it should be fixed in the VC5 driver, not here.
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.
Hi Kalakodima,
Thank you for the patch.
On Wed, Apr 03, 2019 at 06:44:36PM +0530, VenkataRajesh.Kalakodima@in.bosch.com wrote:
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.
dri-devel@lists.freedesktop.org